summaryrefslogtreecommitdiff
path: root/system/shard-x86-at/7/src/I8250.ASM
diff options
context:
space:
mode:
authorLars-Dominik Braun <lars@6xq.net>2019-02-11 11:49:19 +0100
committerLars-Dominik Braun <lars@6xq.net>2019-02-11 11:49:39 +0100
commit98cab31fc3659e33aef260efca55bf9f1753164c (patch)
treef1affa84049ef9b268e6c4f521f000478b0f3a8e /system/shard-x86-at/7/src/I8250.ASM
parent71e2b36ccd05ea678e62e32ee6245df2b8d6ac17 (diff)
downloadeumel-src-98cab31fc3659e33aef260efca55bf9f1753164c.tar.gz
eumel-src-98cab31fc3659e33aef260efca55bf9f1753164c.tar.bz2
eumel-src-98cab31fc3659e33aef260efca55bf9f1753164c.zip
Add source files from Michael
Diffstat (limited to 'system/shard-x86-at/7/src/I8250.ASM')
-rw-r--r--system/shard-x86-at/7/src/I8250.ASM437
1 files changed, 437 insertions, 0 deletions
diff --git a/system/shard-x86-at/7/src/I8250.ASM b/system/shard-x86-at/7/src/I8250.ASM
new file mode 100644
index 0000000..19f584d
--- /dev/null
+++ b/system/shard-x86-at/7/src/I8250.ASM
@@ -0,0 +1,437 @@
+;***************************************************************************
+;*======= Copyright (C) 1985,86 Martin Schoenbeck, Spenge =================*
+;* *
+;* Routinen fuer 8250 UART im EUMEL - System *
+;* *
+;* *
+;***************************************************************************
+
+i8250_data equ 0
+i8250_ier equ 1 ;interrupt enable register
+i8250_iir equ 2 ;interrupt indicator register
+i8250_lcr equ 3 ;line control register
+i8250_mcr equ 4 ;modem control register
+i8250_lsr equ 5 ;line status register
+i8250_msr equ 6 ;modem status register
+
+ device i8250
+
+ dtcbroutines iocontrol
+ routine 1,i8250_devicetype
+ routine 2,frout
+ routine 3,i8250_stop
+ routine 4,i8250_weiter
+ routine 5,nil_size
+ routine 6,priv_op_question
+ routine 8,priv_op_question
+ routine 9,priv_op_question
+ routine -2,frout
+ routine -3,i8250_status
+ routine -4,stream_in_count
+ routine -5,stream_out_count
+ routine -6,i8250_sendbreak
+ routine -10,i8250_i_stop
+ routine -11,i8250_i_weiter
+ routine -1,unknowncontrol
+
+ dtcbroutines control32
+ routine 6,i8250_flow
+ routine 8,i8250_baud
+ routine 9,i8250_bits
+ routine -2,i8250_init
+ routine -3,i8250_test
+ routine -1,no_channel_setup
+
+ dtcbroutines blockin
+ dtcbroutines blockout
+ routine -1,unknowncontrol
+
+ dtcbparams i8250_output,3 ;typ = nur stream io
+
+
+;******************************************************************
+;* der macro i8250_ccb muss fuer jeden 8250 im system einmal
+;* aufgerufen werden
+;*
+;* parameter:
+
+i8250_ccb macro i8250,kanal
+i8250&buf db 100 DUP (0ffh)
+ startccb i8250&ccb,kanal
+ stream 100,i8250&buf ;;die 8250 routinen benutzen stream routinen
+ccbentry i8250_stat
+ db 0
+ccbentry i8250_statusandmask
+ db 0 ;;keine statusleitungen abfragen
+ccbentry i8250_statusxormask
+ db 0
+ccbentry i8250_errmask
+ db 0 ;;keine fehler auswerten
+ccbentry i8250_errflags
+ db 0
+ccbentry i8250_irq_line
+ db i8250&irq
+ccbentry i8250_base
+ dw i8250&base
+ccbentry i8250_next_ccb
+ dw 0
+ccbentry i8250_int_entry
+ call i8250_interrupt
+ endm
+
+;*** bits in i8250_stat:
+i8250_rtscts equ 1
+i8250_exists equ 2
+
+i8250_baud_table:
+ dw 2304 ;50
+ dw 1536 ;75
+ dw 1047 ;110
+ dw 857 ;134.5
+ dw 768 ;150
+ dw 384 ;300
+ dw 192 ;600
+ dw 96 ;1200
+ dw 64 ;1800
+ dw 48 ;2400
+ dw 32 ;3600
+ dw 24 ;4800
+ dw 16 ;7200
+ dw 12 ;9600
+
+
+i8250_devicetype:
+ mov cx,0 ;erstmal 0 setzen
+ test byte ptr [di+i8250_stat],i8250_exists ;ist da einer
+ ifnz <mov cl,shard:(si+devtype)> ;type dazu
+ ret
+
+
+
+
+i8250_test:
+ cmp bh,0 ;abfrage
+ ifnz <int 0bh>
+ mov dx,(di+i8250_base)
+ add dx,i8250_iir ;auf interrupt indicator register
+ in al,(dx)
+ mov cl,al
+ mov ch,1
+ ret
+
+i8250_init:
+ mov ax,0
+ mov es,ax
+; pruefen, ob ueberhaupt vorhanden
+ mov dx,(di+i8250_base)
+ add dx,i8250_iir ;interrupt indicate register holen
+ jmp short $+2
+ in al,dx
+ nop ;der in befehl erwischt einen von diesen
+ nop ;codes, wenn auf der adresse kein port ist
+ nop
+ nop
+ nop
+ test al,0f8h ;alle bits weg, die nicht da sein koennen
+ ifnz <ret> ;keine schnittstelle da
+ or byte ptr [di+i8250_stat],i8250_exists ;da ist einer
+
+ mov bx,first_ictlr_int
+ add bl,(di+i8250_irq_line) ;an welchem pin des controllers haengt er
+ ;carry kann hier nicht auftreten
+ mov byte ptr i8250_initint,bl ;fuer passenden initialisierungsint basteln
+ add bx,bx ;*2 als wortadresse
+ mov dx,word ptr (i8250_i_tab-((3+first_ictlr_int)*2))[bx] ;letzten ccb holen
+ mov word ptr (i8250_i_tab-((3+first_ictlr_int)*2))[bx],di ;neuen eintragen
+ mov (di+i8250_next_ccb),dx ;alten selbst merken
+ add bx,bx ;*4
+ mov word ptr es:[bx+2],cs
+ mov dx,di ;adresse ccb holen
+ add dx,i8250_int_entry ;adresse interrupt routine errechnen
+ mov word ptr es:[bx],dx ;eintragen
+ mov cl,(di+i8250_irq_line) ;nochmal bit im controller
+ inc cl ;mindestens einmal shiften
+ stc
+ mov ch,0 ;mit nichts anfangen
+ rcl ch,cl
+ in al,int_ctlr+1 ;interrupt enable register holen
+ or al,ch ;bit fuer i8250 setzen
+ xor al,ch ;und freigeben
+ out int_ctlr+1,al
+ mov dx,(di+i8250_base)
+ add dx,i8250_ier ;auf interrupt enable register
+ mov al,0fh ;alle interrupts an
+ out dx,al ;interrupt enable
+ add dx,i8250_mcr-i8250_ier ;auf modem control register
+ mov al,0bh ;rts, dtr, int enable
+ out dx,al
+; ret
+i8250_initint = $+1
+ int 12
+ ret
+
+i8250_i_tab:
+ dw 0 ;int 3
+ dw 0 ;int 4
+ dw 0 ;int 5
+ dw 0 ;int 6
+ dw 0 ;int 7
+
+i8250_interrupt:
+ push ds
+ push cx
+ push di
+ push bx
+ push dx
+ push ax
+ mov ax,cs
+ mov ds,ax ;ds = cs setzen
+ mov bx,sp ;auf stack zeigen
+ mov di,ss:[bx+12] ;return adresse im ccb holen
+ sub di,i8250_int_entry+3 ;auf anfang ccb rechnen
+i8250_to_first_ccb:
+ push di ;ersten ccb merken
+ mov ah,1 ;bis jetzt keinen port gefunden
+i8250_check_same_int:
+ mov dx,(di+i8250_base)
+ add dx,i8250_iir ;interrupt indicate register lesen
+ in al,(dx)
+ test al,1 ;war interrupt auf diesem kanal
+ jnz i8250_int_end
+ mov ah,0 ;ax als index, gleichzeitig ah loeschen
+ push ax
+ mov bx,ax
+ call word ptr i8250_int_table[bx] ;passende service routine aufrufen
+ pop ax
+ jmp i8250_check_same_int
+
+i8250_int_end:
+ mov di,(di+i8250_next_ccb) ;naechsten port fuer diesen vektor holen
+ or di,di ;ende eintrag?
+ jnz i8250_check_same_int
+ pop di ;ersten ccb holen
+ or ah,ah ;haben wir im letzten durchlauf einen gefunden
+ jz i8250_to_first_ccb ;ja, dann weiter suchen
+ mov al,20h ;end of interrupt
+ out int_ctlr,al
+ pop ax
+ pop dx
+ pop bx
+ pop di
+ pop cx
+ pop ds
+ pop cs:[i8250_ret_dummy] ;return adresse im ccb vergessen
+ iret ;fertig
+
+i8250_ret_dummy dw 0
+
+i8250_int_table:
+ dw offset i8250_out_restart ;bei ext. status wechsel oder bei tx empty
+ dw offset i8250_out_restart ;nur output ggf. neu starten
+ dw offset i8250_rec_int
+ dw offset i8250_error_int
+
+
+i8250_baud:
+ cmp bh,15 ;negativer wert oder > 15
+ jnc i8250_not_ok
+ cmp bh,0
+ jz i8250_not_ok
+ test bl,1 ;abfage?
+ jnz i8250_ok ;ja, wir koennen alles
+ mov dx,(di+i8250_base)
+ add dx,i8250_lcr ;line control register
+ cli ;nichts dazwischen lassen
+ in al,dx ;alten wert holen
+ push ax
+ mov al,80h
+ out dx,al ;auf baudrate register schalten
+ sub dx,i8250_lcr ;wieder auf base
+ mov bl,bh ;baudrate schluessel nach bx ausdehnen
+ mov bh,0
+ sal bx,1 ;ein baudrate eintrag ist zwei byte
+ mov ax,word ptr i8250_baud_table-2[bx] ;passenden baudrate eintrag holen
+ out dx,al ;low byte raus
+ mov al,ah
+ inc dx
+ out dx,al ;high byte raus
+ pop ax
+ add dx,i8250_lcr-1 ;wieder auf lcr
+ out dx,al ;alte lcr wieder setzen
+ sti ;jetzt darf er wieder
+ jmp short i8250_ok ;alles klar
+ ret
+
+i8250_bits:
+ test bh,0a0h ;negativer wert oder 1.5 Stopbits
+ jnz i8250_not_ok
+ test bh,4 ;bitzahl >= 5
+ jz i8250_not_ok ;nein, muss aber
+ test bl,1 ;abfrage
+ jnz i8250_ok
+ mov al,bh ;anfoderung nach al
+ test al,10h ;gerade paritaet?
+ jz i8250_not_even
+ or al,8 ;dann paritaet auch enablen
+i8250_not_even:
+ test al,40h ;2 stopbits
+ jnz i8250_not_two ;nein, das bit steht schon
+ and al,0ffh-4 ;bit ausknipsen
+i8250_not_two:
+ and al,1fh ;alle unbenutzten loeschen
+ mov dx,(di+i8250_base)
+ add dx,i8250_lcr ;auf line control register
+ out dx,al
+ mov cl,bh ;anzahl bits nach cl
+ and cl,7 ;ausblenden
+ inc cl ;aus 0-7 1-8 machen
+ mov dx,0ffh ;von 0 bits ausgehen
+ shl dl,cl ;bits anzahl nullen reinziehen
+ xor dl,0ffh ;und 1 und 0 tauschen
+ call set_out_mask
+ call set_inp_mask
+ call set_inp_errmask
+i8250_ok:
+ mov cx,0
+ ret
+
+i8250_not_ok:
+ mov cx,1
+ ret
+
+i8250_flow:
+ test bh,80h ;negativer wert?
+ jnz i8250_not_ok
+ cmp bh,3
+ jnc i8250_not_ok ;oder > 2
+ test bl,1 ;abfrage
+ jnz i8250_ok ;ja
+ cli
+ mov byte ptr (di+i8250_statusxormask),0 ;beim status nichts abfragen
+ mov byte ptr (di+i8250_statusandmask),0
+ and byte ptr (di+i8250_stat),0ffh-i8250_rtscts ;handshake ausschalten
+ dec bh
+ jnz i8250_not_xonxoff
+ call enablexon
+ jmp i8250_flow_end
+i8250_not_xonxoff:
+ call disablexon
+ dec bh
+ jnz i8250_flow_end
+ mov byte ptr (di+i8250_statusandmask),10h ;cts abfragen
+ mov byte ptr (di+i8250_statusxormask),10h ;auf gesetzt
+ or byte ptr (di+i8250_stat),i8250_rtscts
+i8250_flow_end:
+ call i8250_out_restart ;immer probieren, ob jetzt output moeglich
+ sti
+ jmp i8250_ok
+
+i8250_output:
+ call fillbuffer
+ pushf
+ jz i8250_no_orest
+ call i8250_out_restart
+i8250_no_orest:
+ popf
+ ret
+
+;* out_restart kann jederzeit aufgerufen werden, da der status jedesmal
+;* abgefragt wird
+i8250_out_restart:
+ mov dx,(di+i8250_base) ;commandport laden
+ add dx,i8250_lsr ;adresse line status register
+ cli
+ in al,(dx) ;status holen
+ test al,20h ;tx buffer empty
+ lahf ;modem status register immer lesen
+ inc dx ;auf modem status register
+ in al,(dx) ;holen
+ sahf
+ jz i8250_stiret ;nein, sti und zurueck
+ and al,(di+i8250_statusandmask) ;gewuenschte bits ausblenden
+ xor al,(di+i8250_statusxormask)
+ jnz i8250_stiret
+ call getnextchar ;zeichen holen, xon/xoff etc. abhandeln
+ mov dx,(di+i8250_base) ;port holen
+ ifnz <out (dx),al> ;wenn was da, ausgeben
+i8250_stiret:
+ sti
+ ret ;fertig
+
+i8250_rec_int:
+ mov dx,(di+i8250_base)
+ in al,(dx) ;zeichen holen
+ call input ;zeichen uebergeben, xon/xoff etc. abhandeln
+ jz i8250_out_restart ;ggf. output neu starten
+ ret
+
+i8250_error_int:
+ mov dx,(di+i8250_base)
+ add dx,i8250_lsr ;line status register holen
+ in al,(dx)
+ or (di+i8250_errflags),al ;alte errorflags dazu
+ test al,10h ;break detected
+ jnz i8250_break
+ and al,(di+i8250_errmask) ;welche fehlerbits sollen behandelt werden
+ jz i8250_rec_int ;keine, normal einlesen
+ mov dx,(di+i8250_base)
+ in al,(dx) ;zeichen holen
+ call errorinput ;uebergeben
+ jz i8250_out_restart
+ ret
+
+i8250_break:
+ call breakinput ;break zeichen uebergeben
+ jz i8250_out_restart
+ ret
+
+i8250_stop:
+ call stream_stop
+ ifnz <call i8250_out_restart> ;output ggf neu starten
+ test byte ptr (di+i8250_stat),i8250_rtscts
+ jz i8250_stop_end
+i8250_i_stop:
+ mov dx,(di+i8250_base)
+ add dx,i8250_mcr ;auf modem control register
+ mov al,9 ;rts wegnehmen
+ out (dx),al
+i8250_stop_end:
+ ret
+
+i8250_weiter:
+ call stream_weiter
+ ifnz <call i8250_out_restart> ;output ggf. neu starten
+ test byte ptr (di+i8250_stat),i8250_rtscts
+ jz i8250_stop_end
+i8250_i_weiter:
+ mov dx,(di+i8250_base)
+ add dx,i8250_mcr ;auf modem control register
+ mov al,0bh ;rts wieder setzen
+ out (dx),al
+ ret
+
+i8250_status:
+ cli
+ mov cl,(di+i8250_errflags) ;fehler holen
+ mov byte ptr (di+i8250_errflags),0 ;loeschen
+ mov dx,(di+i8250_base)
+ add dx,i8250_lsr
+ in al,dx
+ mov ch,al
+ sti
+ ret
+
+i8250_sendbreak:
+ cli
+ mov dx,(di+i8250_base)
+ add dx,i8250_lcr
+ in al,dx
+ and al,10111111b ;switch breakbit off
+ and bl,1 ;nur ein bit behalten
+ ror bl,1
+ ror bl,1 ;auf bit 6 position
+ or al,bl ;send break or not
+ out dx,al
+ sti
+ ret
+ \ No newline at end of file