#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 SHARED_MEM_START+00400h 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 ; ------------------------------------------------------- ; 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 ld (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 ; ------------------------------------------------------- ; 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 ; 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 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 ; ------------------------------------------------------- ; Strings ; ------------------------------------------------------- msg_header: .db "BIOS v1.0 - Joppe Blondel",00dh,00ah,000h