567 lines
14 KiB
NASM
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"
|