rdos/rom/uartctrl.asm

395 lines
9.0 KiB
NASM

cpu 8086
org 0x0000
; configuration for the uart chip for i/o
%define uart 0x3F8
%define irq 4
%define clock 115200
%define baud 9600
%ifndef CODEPAGE
%define CODEPAGE 437
%endif
data equ (uart + 0) ; data register
ier equ (uart + 1)
fcr equ (uart + 2)
isr equ (uart + 2)
lcr equ (uart + 3)
mcr equ (uart + 4)
lsr equ (uart + 5) ; line status register
msr equ (uart + 6)
absolute 0xE0 ; data in bios data area
pstate resw 1 ; parser resume offset
parg resb 1 ; accumulator for numerical CSI arguments
curcs resb 1 ; current charset we put remote term in
section .text
db 0x55, 0xAA
db 0x00
jmp init
%defstr uart_s uart
%defstr baud_s baud
banner db "nero uartctrl: port ", uart_s, " irq ", irq + 0x30," baud ", baud_s, 0x0A, 0x0D, 0
init push ax
push dx
push bx
push si
push ds
; set dlab
mov dx, lcr
in al, dx
or al, 0x80
out dx, al
; set divisor
mov cx, (clock / baud)
; low byte
mov dx, (uart + 0)
mov al, cl
out dx, al
; high byte
mov dx, (uart + 1)
mov al, ch
out dx, al
; disable dlab
mov dx, lcr
in al, dx
and al, 0x7F
out dx, al
; disable fifo
mov dx, fcr
mov al, 0
out dx, al
; enable RX interrupt
mov dx, ier
mov al, 1
out dx, al
; set line modes (8 bits, no parity, 1 stopbit)
mov dx, lcr
mov al, 3
out dx, al
; set modem control lines (unused)
mov dx, mcr
mov al, 8
out dx, al
; DS = interrupt table
xor ax, ax
mov ds, ax
; hook video services
; keep original ptr in intvec 47h for chaining
mov ax, int10
mov bx, cs
xchg word [4*0x10], ax
xchg word [4*0x10+2], bx
mov word [4*0x47], ax
mov word [4*0x47+2], bx
; reset parser state
mov word [0x400+pstate], parse.start
; hook uart irq
mov word [4*(0x08+irq)], intu
mov word [4*(0x08+irq)+2], cs
; enable IRQ in PIC
mov dx, 0x21
in al, dx
and al, ~(1 << irq)
out dx, al
call greet
pop ds
pop si
pop bx
pop dx
pop ax
retf
greet mov si, banner
xor bx, bx
.loop mov al, [cs:si]
test al, al
jz .exit
mov ah, 0x0e
int 0x10
inc si
jmp .loop
.exit ret
putc mov ah, al
; check if transmit buffer empty
.l01 mov dx, lsr
in al, dx
test al, 0x20
jz .l01
mov al, ah
; send char to uart
mov dx, data
out dx, al
ret
; set charset
; IN AL '0', 'A' or 'B'
setcs test al, al
jz .fret
push ds
; set DS
mov dx, 0x40
mov ds, dx
cmp al, [curcs]
je .ret
mov [curcs], al
mov al, 0x1B
call putc
mov al, '('
call putc
mov al, [curcs]
call putc
.ret pop ds
.fret ret
pdx: ; this double-call is essentially a 4 times repeating loop
call .l1
.l1: call .l2
.l2: ; set up cl for bit shifts
mov cl, 4
; grab highest nibble from dx
mov al, dh
; remove highest nibble from dx
shl dx, cl
; shift away second-highest nibble that we accidentally copied
shr al, cl
; map 0-9 to ascii codes for '0' to '9'
add al, 0x30
; if result is larger than '9', ...
cmp al, 0x3a
jl pputc
; ... add 7 so we continue at 'A'
add al, 7
pputc mov ah, 0x0e
xor bx, bx
int 0x10
ret
; video services
int10 cmp ah, 0x0e
jne .chain
push bx
push dx
push ax
; activate character set for current char
mov bx, csmap
cs xlatb
call setcs
pop ax
push ax
; look up what we need to write out
mov bx, ecmap
cs xlatb
call putc
pop ax
pop dx
pop bx
.chain sub sp, 4
push bp
mov bp, sp
; stack: BP IP:CS IP:CS FL
push ax
push ds
xor ax, ax
mov ds, ax
; copy offset
mov ax, [4*0x47]
mov [bp+2], ax
; copy segment
mov ax, [4*0x47+2]
mov [bp+4], ax
pop ds
pop ax
pop bp
retf
; uart controller irq
intu push ax
push dx
; check if we controller has data ready
mov dx, isr
in al, dx
and al, 0xF
cmp al, 4
jne ugetc.ret
; set DS to bios data area
push bx
push ds
mov ax, 0x40
mov ds, ax
; receive data
mov dx, data
in al, dx
jmp near [pstate] ; load parser state
ugetc pop word [pstate] ; save parser state
pop ds
pop bx
; send non-specific EOI signal
.ret mov al, 0x20
out 0x20, al
pop dx
pop ax
iret
; parse loop
; this is called from inside the uart interrupt
; only call ugetc when nothing on stack, so no nested funcs
parse call ugetc
.start cmp al, 0x1B
je .esc
cmp al, 0x7F
je .bs
.ascii mov dl, al
mov bx, kmap
cs xlatb
mov dh, al
; insert key code into buffer in bios data area
.insert mov bx, [0x1C] ; get next empty slot
mov [bx], dx ; store key code
add bx, 2
cmp bx, 0x3E ; are we beyond last pos?
jc .nowrap
mov bx, 0x1E ; first position
.nowrap cmp bx, [0x1A] ; next to-read slot
je parse
mov [0x1C], bx ; commit if not full
jmp parse
.bs mov dx, 0x0E08
jmp .insert
.esc call ugetc
cmp al, 0x5B
je .csi
cmp al, 'O'
je .vt_o
jmp parse
.csi mov byte [parg], 0 ; reset argument
.csicon call ugetc ; number parsing
cmp al, 0x30
jc parse
cmp al, 0x3A
jnc .nonum
sub al, 0x30
mov dl, al
mov al, 0xA
mul byte [parg]
add al, dl
mov [parg], al
jmp .csicon
.nonum cmp al, '~' ; \e[...$c handling
jne .letter
mov al, [parg] ; \e[$n~ lookup $n
mov bx, fkeysn
jmp .lookup
.vt_o call ugetc ; VT100 \eO... sequences
.letter sub al, 0x40 ; look up special key by letter
mov bx, fkeysc
.lookup cmp al, 0x40 ; special key lookup, bx assumed
jnc parse
cs xlatb
cmp al, 0
je parse
mov dh, al
mov dl, 0
jmp .insert
align 128
; ascii -> XT scancode map
%if CODEPAGE = 437
; US Keyboard layout
kmap db 0x00,0x1E,0x30,0x2E, 0x20,0x12,0x21,0x22, 0x23,0x0F,0x24,0x25, 0x26,0x1C,0x31,0x18
db 0x19,0x10,0x13,0x1F, 0x14,0x16,0x2F,0x11, 0x2D,0x15,0x2C,0x01, 0x2B,0x1B,0x07,0x0C
db 0x39,0x02,0x03,0x04, 0x05,0x06,0x08,0x28, 0x0A,0x0B,0x09,0x0D, 0x33,0x0C,0x34,0x35
db 0x0B,0x02,0x03,0x04, 0x05,0x06,0x07,0x08, 0x09,0x0A,0x27,0x27, 0x33,0x0D,0x34,0x35
db 0x03,0x1E,0x30,0x2E, 0x20,0x12,0x21,0x22, 0x23,0x17,0x24,0x25, 0x26,0x32,0x31,0x18
db 0x19,0x10,0x13,0x1F, 0x14,0x16,0x2F,0x11, 0x2D,0x15,0x2C,0x1A, 0x2B,0x1B,0x07,0x0C
db 0x29,0x1E,0x30,0x2E, 0x20,0x12,0x21,0x22, 0x23,0x17,0x24,0x25, 0x26,0x32,0x31,0x18
db 0x19,0x10,0x13,0x1F, 0x14,0x16,0x2F,0x11, 0x2D,0x15,0x2C,0x1A, 0x2B,0x1B,0x29,0x70
; character map
; resolves codepage character to character in charset (see next table)
ecmap db 0x00,0x01,0x02,0x03, 0x60,0x05,0x06,0x07, 0x08,0x09,0x0A,0x0B, 0x0C,0x0D,0x0E,0x0F
db 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1A,0x1B, 0x1C,0x1D,0x1E,0x1F
db 0x20,0x21,0x22,0x23, 0x24,0x25,0x26,0x27, 0x28,0x29,0x2A,0x2B, 0x2C,0x2D,0x2E,0x2F
db 0x30,0x31,0x32,0x33, 0x34,0x35,0x36,0x37, 0x38,0x39,0x3A,0x3B, 0x3C,0x3D,0x3E,0x3F
db 0x40,0x41,0x42,0x43, 0x44,0x45,0x46,0x47, 0x48,0x49,0x4A,0x4B, 0x4C,0x4D,0x4E,0x4F
db 0x50,0x51,0x52,0x53, 0x54,0x55,0x56,0x57, 0x58,0x59,0x5A,0x5B, 0x5C,0x5D,0x5E,0x5F
db 0x60,0x61,0x62,0x63, 0x64,0x65,0x66,0x67, 0x68,0x69,0x6A,0x6B, 0x6C,0x6D,0x6E,0x6F
db 0x70,0x71,0x72,0x73, 0x74,0x75,0x76,0x77, 0x78,0x79,0x7A,0x7B, 0x7C,0x7D,0x7E,0x7F
db 0x47,0x7c,0x69,0x62, 0x64,0x60,0x65,0x67, 0x6A,0x6B,0x68,0x6f, 0x6e,0x6c,0x44,0x45
db 0x49,0x66,0x46,0x74, 0x76,0x72,0x7b,0x79, 0x7d,0x56,0x5C,0x22, 0x23,0x25,'P' ,'f'
db 0x61,0x6D,0x73,0x7a, 0x71,0x51,0x2A,0x3A, 0x3F,0x2C,0x2C,0x3d, 0x3c,0x21,0x2b,0x3b
db 0x61,0x61,0x61,0x78, 0x75,0x75,0x75,0x6B, 0x6B,0x75,0x78,0x6B, 0x6a,0x6a,0x6a,0x6b
db 0x6D,0x76,0x77,0x74, 0x71,0x6E,0x74,0x74, 0x6D,0x6C,0x76,0x77, 0x74,0x71,0x6E,0x76
db 0x76,0x77,0x77,0x6D, 0x6D,0x6C,0x6C,0x6E, 0x6E,0x6A,0x6C,0x61, 0x61,0x61,0x61,0x61
db 0x61,0x62,0x47,0x70, 0x53,0x73,0x35,0x74, 0x46,0x6A,0x57,0x64, 0x42,0x66,0x65,0x5C
db 0x4F,0x67,0x7A,0x79, 0x24,0x25,0x43,0x49, 0x66,0x7E,0x7E,0x21, 0x32,0x32,0x61,0x5F
; character set map
; resolves codepage character to DEC charset (A,B,0,1,<)
csmap db 0,0,0,0, '0',0,0,0, 0,0,0,0, 0,0,0,0
db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
db 0,'B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B','B'
db 'B','B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B','B'
db 'B','B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B','B'
db 'B','B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B','B'
db 'B','B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B','B'
db 'B','B','B','B', 'B','B','B','B', 'B','B','B','B', 'B','B','B',0
db 'A','A','A','A', 'A','A','A','A', 'A','A','A','A', 'A','A','A','A'
db 'A','A','A','A', 'A','A','A','A', 'A','A','A','A', 'A','A','B','B'
db 'A','A','A','A', 'A','A','A','A', 'A','A','A','A', 'A','A','A','A'
db '0','0','0','0', '0','0','0','0', '0','0','0','0', '0','0','0','0'
db '0','0','0','0', '0','0','0','0', '0','0','0','0', '0','0','0','0'
db '0','0','0','0', '0','0','0','0', '0','0','0','0', '0','0','0','0'
db '>','>','>','>', '>','>','A','>', '>','>','>','>', '>','>','>','>'
db '>','0','0','0', '>','>','>','>', '0','0','0','>', 'A','A','0','0'
%endif
; function keys by character
; \eO$c, looks up $c to XT scancode
; table is like ascii, except it starts at 0x40 '@'
fkeysc db 0,0x48,0x50,0x4D, 0x4B,0,0x4F,0, 0x47,0,0,0, 0,0,0,0
db 0x3B,0x3C,0x3D,0x3E, 0,0,0,0, 0,0,0,0, 0,0,0,0
db 0,0,0,0, 0,0,0,0, 0,0,0,0, 0x42,0,0,0
db 0,0,0,0, 0x3F,0x40,0x41,0x43, 0x44,0,0,0, 0,0,0,0
; function keys by numbers
; 10 entries per line
; \e[$n~, looks up $n to XT scancode
fkeysn db 0,0x47,0x52,0x53,0, 0x49,0x51,0x47,0x4F,0 ; 0-9
db 0,0x3B,0x3C,0x3D,0x3E, 0x3F,0,0x40,0x41,0x42 ; 10-19
db 0x43,0x44,0,0x85,0x86, 0,0,0,0,0 ; 20-29
db 0,0,0,0,0, 0,0,0,0,0 ; 30-39
align 512