Files
z80_monitor/bios.asm
T

567 lines
14 KiB
NASM

#target bin
#include "build/memory.inc"
#include "hardware.inc"
#include "bios.inc"
CTC_BASE .equ 020h
CTC_CHANNEL_0 .equ CTC_BASE+000h
CTC_CHANNEL_1 .equ CTC_BASE+001h
CTC_CHANNEL_2 .equ CTC_BASE+002h
CTC_CHANNEL_3 .equ CTC_BASE+003h
UART_BASE .equ 024h
UART_CONTROL .equ UART_BASE+000h
UART_DATA .equ UART_BASE+001h
BUF_SIZE .equ 16
BUF_SIZE_MASK .equ 00fh
WORKSPACE .equ BIOS_WP_RAM_START
TX_HEAD .equ WORKSPACE+000h
TX_TAIL .equ WORKSPACE+001h
TX_COUNT .equ WORKSPACE+002h
RX_HEAD .equ WORKSPACE+003h
RX_TAIL .equ WORKSPACE+004h
RX_COUNT .equ WORKSPACE+005h
TX_BUSY .equ WORKSPACE+006h
TX_BUF .equ WORKSPACE+007h
RX_BUF .equ TX_BUF+BUF_SIZE
SYSREG_VALUE .equ RX_BUF+BUF_SIZE
END_OF_BIOS_WS .equ SYSREG_VALUE+001h
; -------------------------------------------------------
; entry
; -------------------------------------------------------
#code BIOS_BOOT, ROM_START, (BIOS_ROM_START-ROM_START)
.org 00000h
jp boot_copy
.org 00008h
boot_copy:
di
; Make sure system reg is in its default state
; banking enabled
; bank 1 selected
ld a,BOOT_BANK_MAPPING
out (SYSTEM_REGISTER),a
ld sp,BIOS_STACK_TOP
; copy bios to top 16k
ld hl,BIOS_ROM_START
ld de,SHARED_MEM_START
ld bc,BIOS_size
ldir
; copy basic to top 16k
ld hl,BASIC_ROM_START
ld de,BASIC_RAM_START
ld bc,BASIC_ROM_SIZE
ldir
jp init
#code BIOS, SHARED_MEM_START
#assert BIOS_size <= BIOS_ROM_SIZE
; -------------------------------------------------------
; Interrupt vector table
; -------------------------------------------------------
.org SHARED_MEM_START+000h
jp init
.org SHARED_MEM_START+008h
reti
.org SHARED_MEM_START+010h
reti
.org SHARED_MEM_START+018h
reti
.org SHARED_MEM_START+020h
reti
.org SHARED_MEM_START+028h
reti
.org SHARED_MEM_START+030h
reti
.org SHARED_MEM_START+038h
reti
.org SHARED_MEM_START+040h
.dw ctc_isr
.dw ctc_isr
.dw ctc_isr
.dw uart_isr
; -------------------------------------------------------
; BIOS JUMP TABLE
; -------------------------------------------------------
.org BIOS_PUTC
jp putc
.org BIOS_GETC
jp getc
.org BIOS_TRY_GETC
jp try_getc
.org BIOS_PUTS
jp puts
.org BIOS_FLUSH
jp flush
.ORG BIOS_ROM
jp setrom
.ORG BIOS_BANK
jp bank
.ORG BIOS_CAS_READ_BLOCK
jp read_block
.ORG BIOS_CAS_WAIT_SILENCE
jp wait_silence
.ORG BIOS_CAS_READ_BLOCK_DRY
jp read_block_dry
.ORG BIOS_CAS_GET_BUFFER
jp get_buffer
.ORG BIOS_CAS_WRITE_BLOCK
jp write_block
.ORG BIOS_DELAY_MS
jp delay_ms
; -------------------------------------------------------
; BIOS ENTRY
; -------------------------------------------------------
init:
di
ld sp,SHARED_MEM_END
; Some im2 mode peripherals may still be 'in service'
; force some irets to clear them
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
call release_daisy_chain
; Setup interrupts
ld a,0c0h ; load interrupt table
ld i,a
im 2
; Set boot bank mapping to sysreg shadow copy
ld a,BOOT_BANK_MAPPING
ld (SYSREG_VALUE),a
out (SYSTEM_REGISTER),a
; Initialize tx and rx buffers
call buffers_init
; Initialize peripherals
call ctc_uart_init
ei
; Print header message
ld hl,msg_header
call puts
; Enter bios
jp BASIC_RAM_START
; Shouldnt come here
; just to be safe an endless loop
ei
0$:
call getc
call putc
jr 0$
; -------------------------------------------------------
; CTC interrupt
; -------------------------------------------------------
ctc_isr:
ei
reti
; -------------------------------------------------------
; UART INTERRUPT
; -------------------------------------------------------
uart_isr:
push af
push bc
push de
push hl
; Load status byte
in a,(UART_CONTROL)
ld b,a
; Check status for rx interrupt
ld a,b
and 021h
jr nz,3$ ; rx interrupt
101$:
; Check status for tx interrupt
ld a,b
and 002h
jr nz,1$ ; tx interrupt
100$:
pop hl
pop de
pop bc
pop af
ei
reti
1$:
; tx interrupt, dequeue byte and transmit
ld a,(TX_BUSY)
cp 1
jr nz,100$ ; not actively txing, return
ld a,(TX_COUNT)
cp 0
jr z,2$ ; nothing to transmit
; something in queue, dequeue
ld hl,TX_BUF
ld a,(TX_TAIL)
ld e,a
ld d,0
add hl,de
; hl contains tail of queue
ld a,(hl)
ld d,a
; d contains data to transmit
; do (tail+1)%BUF_SIZE
ld a,e
inc a
and BUF_SIZE_MASK
ld (TX_TAIL),a
ld hl,TX_COUNT ; decrease tx count
dec (hl)
; transmit the byte
ld a,d
out (UART_DATA),a
jr 100$
2$:
; Queue is empty, stop tx interrupts
ld a,10010101b
out (UART_CONTROL),a
; clear tx busy flag
ld a,0
ld (TX_BUSY),a
jr 100$
3$:
; rx interrupt
in a,(UART_DATA)
ld c,a
ld a,b
and 001h ; check status bit 0
jr z,101$ ; status bit 0 is clear, return
ld a,(RX_COUNT)
cp BUF_SIZE
jr z,101$ ; rx queue is full, return
; enqueue byte
ld hl,RX_BUF
ld a,(RX_HEAD)
ld e,a
ld d,0
add hl,de
; hl contains head of queue
ld (hl),c
; Do (head+1)%BUFSIZE
ld a,e
inc a
and BUF_SIZE_MASK
ld (RX_HEAD),a ; Increase rx count
ld hl,RX_COUNT
inc (hl)
jr 101$
; -------------------------------------------------------
; Force IRET
; -------------------------------------------------------
release_daisy_chain:
reti
; -------------------------------------------------------
; Initialize CTC and UART
; -------------------------------------------------------
ctc_uart_init:
; Reset CTC channels
ld a,003h
out (CTC_CHANNEL_0),a
out (CTC_CHANNEL_1),a
out (CTC_CHANNEL_2),a
out (CTC_CHANNEL_3),a
; Reset UART
ld a,00000011b
out (UART_CONTROL),a
; CTC channel 0 is timesource for uart
ld a,057h
out (CTC_CHANNEL_0),a
ld a,13
out (CTC_CHANNEL_0),a
; CTC channel 3 is interrupt source for handler
ld a,11001111b
out (CTC_CHANNEL_3),a
ld a ,1
out (CTC_CHANNEL_3),a
; set im2 vector for CTC
ld a,000h
out (CTC_CHANNEL_0),a
ld a,040h
out (CTC_CHANNEL_0),a
; Initialise UART
ld a,10010101b
out (UART_CONTROL),a
ret
; -------------------------------------------------------
; Initialize TX and RX queues
; -------------------------------------------------------
buffers_init:
ld a,00h
ld (TX_HEAD),a
ld (TX_TAIL),a
ld (TX_COUNT),a
ld (RX_HEAD),a
ld (RX_TAIL),a
ld (RX_COUNT),a
ld (TX_BUSY),a
ret
; -------------------------------------------------------
; Kick uart to start transmission
; uses a
; -------------------------------------------------------
uart_kick:
di
push de
push hl
ld a,(TX_BUSY)
cp 0
jr z,100$ ; not actively transmitting yet
1$:
pop hl
pop de
ei
ret
100$:
ld a,(TX_COUNT)
cp 0
jr z,1$ ; tx queue empty, return
ld hl,TX_BUF
ld a,(TX_TAIL)
ld e,a
ld d,0
add hl,de
; hl contains tail of queue
ld a,(hl)
ld d,a
; Do (tail+1)%BUFSIZE
ld a,e
inc a
and BUF_SIZE_MASK
ld (TX_TAIL),a
ld hl,TX_COUNT ; Decrement tx count
dec (hl)
ld a,1 ; set busy flag
ld (TX_BUSY),a
; transmit actual data
ld a,d
out (UART_DATA),a
; Enable tx interrupts
ld a,10110101b
out (UART_CONTROL),a
jr 1$
; -------------------------------------------------------
; Write a byte to uart
; needs a (byte to tx)
; -------------------------------------------------------
putc:
push af
push de
push bc
push hl
ld c,a
100$:
di
ld b,0
ld a,(TX_COUNT)
cp BUF_SIZE
jr z,1$ ; tx queue full, wait
; enqueue data
ld hl,TX_BUF
ld a,(TX_HEAD)
ld e,a
ld d,0
add hl,de
; hl contains head of queue
ld (hl),c
; Do (head+1)%BUF_SIZE
ld a,e
inc a
and BUF_SIZE_MASK
ld (TX_HEAD),a
ld hl,TX_COUNT ; Increment tx count
inc (hl)
ld b,1 ; set succeeded flag
1$:
ei
ld a,b
cp 1 ; Check if succeeded
jr z,2$ ; tx done, kick and return
; not succeeded, try again
call uart_kick
jr 100$
2$:
call uart_kick
pop hl
pop bc
pop de
pop af
ret
; -------------------------------------------------------
; Try to receive a byte
; returns a (byte)
; carry == not succeeded
; -------------------------------------------------------
try_getc:
di
push bc
push de
push hl
ld a,(RX_COUNT)
cp 0
jr z,1$ ; rx queue empty, return
; dequeue
ld hl,RX_BUF
ld a,(RX_TAIL)
ld e,a
ld d,0
add hl,de
; hl contains tail of queue
ld a,(hl)
ld d,a
; Do (tail+1)%BUF_SIZE
ld a,e
inc a
and BUF_SIZE_MASK
ld (RX_TAIL),a
ld hl,RX_COUNT ; decrement rx count
dec (hl)
ld a,d
or a,a ; clear carry
100$:
pop hl
pop de
pop bc
ei
ret
1$:
scf
jr 100$
; -------------------------------------------------------
; Print a string
; needs hl (pointer to string)
; uses a
; -------------------------------------------------------
puts:
ld a,(hl)
cp 0
ret z ; encountered a 0, end of string
call putc
inc hl
jr puts
; -------------------------------------------------------
; Get a byte, block if unavailable
; returns a (byte)
; -------------------------------------------------------
getc:
call try_getc
jr c,getc
ret
; -------------------------------------------------------
; Wait till full tx buffer is empty
; uses a
; -------------------------------------------------------
flush:
ld a,(TX_COUNT)
cp 0
jr nz,flush
ld a,(TX_BUSY)
cp 0
jr nz,flush
ret
; -------------------------------------------------------
; ROM enable/disable
; needs a (nonzero is enable, zero is disable)
; -------------------------------------------------------
setrom:
cp 0
jr z,1$
; nonzero -> enable
push bc
ld a,ROM_DISABLE_BIT
cpl ; get mask
ld b,a
ld a,(SYSREG_VALUE)
and b
ld (SYSREG_VALUE),a
out (SYSTEM_REGISTER),a
pop bc
2$:
ret
1$:
; zero -> disable
ld a,(SYSREG_VALUE)
or ROM_DISABLE_BIT
ld (SYSREG_VALUE),a
out (SYSTEM_REGISTER),a
jr 2$
; -------------------------------------------------------
; Select bank
; needs a (nonzero is bank 1, zero is bank 0)
; -------------------------------------------------------
bank:
cp 0
jr nz,1$
; zero -> bank 0
push bc
ld a,BANK_SELECT_BIT
cpl ; get mask
ld b,a
ld a,(SYSREG_VALUE)
and b
ld (SYSREG_VALUE),a
out (SYSTEM_REGISTER),a
pop bc
2$:
ret
1$:
; non zero -> bank 1
ld a,(SYSREG_VALUE)
or BANK_SELECT_BIT
ld (SYSREG_VALUE),a
out (SYSTEM_REGISTER),a
jr 2$
; -------------------------------------------------------
; Delay a certain miliseconds
; needs a (ms, zero returns immediately)
; uses b,c
; @1MHz each iteration takes 1000T plus 23T overhead
; -------------------------------------------------------
delay_ms:
or a ; 4T
ret z ; 5T when not taken
ld b,a ; 4T
1$:
ld c,61 ; 7T
2$:
dec c ; 4T
jr nz,2$ ; 12/7T, loop takes 971T
nop ; 4T
nop ; 4T
dec b ; 4T
jp nz,1$ ; 10T
ret
; -------------------------------------------------------
; Strings
; -------------------------------------------------------
msg_header: .db "BIOS v1.0 - Joppe Blondel",00dh,00ah,000h
; -------------------------------------------------------
; Other files
; -------------------------------------------------------
#include "tape.asm"