Add uartctrl.rom: Control PC via COM1 attached terminal

This commit is contained in:
Nero 2021-04-04 21:41:22 +00:00
parent b617709684
commit 963aebd948
2 changed files with 328 additions and 0 deletions

View File

@ -82,3 +82,6 @@ qemu-floppy5: fd360.img $(ROMS)
qemu-hdd: hdd.img $(ROMS) qemu-hdd: hdd.img $(ROMS)
$(QEMU) $(QEMU_ARGS) -boot c -hda hdd.img $(QEMU) $(QEMU_ARGS) -boot c -hda hdd.img
qemu-uartctrl: uartctrl.rom
$(QEMU) $(QEMU_ARGS) -option-rom uartctrl.rom -serial stdio

325
rom/uartctrl.asm Normal file
View File

@ -0,0 +1,325 @@
cpu 8086
org 0x0000
; configuration for the uart chip for i/o
%define uart 0x3F8
%define irq 4
%define clock 115200
%define baud 9600
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
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
; hook boot interrupt
xor ax, ax
mov ds, ax
mov word [4*0x19], int19
mov word [4*0x19+2], cs
; 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
; 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
; reset parser state
mov word [0x400+pstate], parse.start
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
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
; system bootstrap
int19 sti
xor ax, ax
int 0x16
mov dx, ax
call pdx
mov al, 0x0A
call pputc
mov al, 0x0D
call pputc
jmp int19
; video services
int10 cmp ah, 0x0e
jne .chain
push ax
push dx
call putc
pop dx
pop ax
.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
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, '~'
jne .letter
mov al, [parg]
mov bx, fkeysn
jmp .lookup
.vt_o call ugetc ; VT100 \eO... sequences
.letter sub al, 0x40
mov bx, fkeysc
.lookup cs xlatb
cmp al, 0
je parse
mov dh, al
mov dl, 0
jmp .insert
align 128
; ascii -> XT scancode map
; this assumes US querty 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
; 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