Start of new fw

This commit is contained in:
Joppe Blondel
2026-10-07 13:20:33 +02:00
parent 65e71d024c
commit ae419aa2f5
11 changed files with 14305 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
build
+40
View File
@@ -0,0 +1,40 @@
.SILENT:
ASM := zasm
ASMFLAGS := -w -b
BUILDDIR := build
FILES := bios
SUBDIRS := apps/basic
SOURCES := $(addprefix ./, $(addsuffix .asm, $(FILES)))
TARGETS := $(addprefix $(BUILDDIR)/, $(addsuffix .bin, $(FILES)))
TOPTARGETS := all clean size
$(TOPTARGETS): $(SUBDIRS)
all: $(BUILDDIR) $(TARGETS) size
clean:
rm -rf $(BUILDDIR)
$(BUILDDIR):
mkdir -p $(BUILDDIR)
$(BUILDDIR)/%.bin: ./%.asm
echo '>$<'
$(ASM) $(ASMFLAGS) $< $@
size:
@for file in $(TARGETS); do \
if [ -f "$$file" ]; then \
echo "$$file: $$(wc -c < "$$file") bytes"; \
else \
echo "$$file: Not built yet (run 'make')"; \
fi \
done
$(SUBDIRS):
$(MAKE) -C $@ $(or $(MAKECMDGOALS),all) --no-print-directory
.PHONY: $(TOPTARGETS) $(SUBDIRS)
+40
View File
@@ -0,0 +1,40 @@
.SILENT:
ASM := zasm
ASMFLAGS := -w -b
BUILDDIR := ../../build/basic
FILES := basic
SUBDIRS :=
SOURCES := $(addprefix ./, $(addsuffix .asm, $(FILES)))
TARGETS := $(addprefix $(BUILDDIR)/, $(addsuffix .bin, $(FILES)))
TOPTARGETS := all clean size
$(TOPTARGETS): $(SUBDIRS)
all: $(BUILDDIR) $(TARGETS) size
clean:
rm -rf $(BUILDDIR)
$(BUILDDIR):
mkdir -p $(BUILDDIR)
$(BUILDDIR)/%.bin: ./%.asm
echo '>$<'
$(ASM) $(ASMFLAGS) $< $@
size:
@for file in $(TARGETS); do \
if [ -f "$$file" ]; then \
echo "$$file: $$(wc -c < "$$file") bytes"; \
else \
echo "$$file: Not built yet (run 'make')"; \
fi \
done
$(SUBDIRS):
$(MAKE) -C $@ $(or $(MAKECMDGOALS),all) --no-print-directory
.PHONY: $(TOPTARGETS) $(SUBDIRS)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+202
View File
@@ -0,0 +1,202 @@
;==================================================================================
; Contents of this file are copyright Grant Searle
;
; You have permission to use this for NON COMMERCIAL USE ONLY
; If you wish to use it elsewhere, please include an acknowledgement to myself.
;
; http://searle.hostei.com/grant/index.html
;
; eMail: home.micros01@btinternet.com
;
; If the above don't work, please perform an Internet search to see if I have
; updated the web page hosting service.
;
;==================================================================================
; Minimum 6850 ACIA interrupt driven serial I/O to run modified NASCOM Basic 4.7
; Full input buffering with incoming data hardware handshaking
; Handshake shows full before the buffer is totally filled to allow run-on from the sender
SER_BUFSIZE .EQU 3FH
SER_FULLSIZE .EQU 30H
SER_EMPTYSIZE .EQU 5
RTS_HIGH .EQU 0D6H
RTS_LOW .EQU 096H
serBuf .EQU $2000
serInPtr .EQU serBuf+SER_BUFSIZE
serRdPtr .EQU serInPtr+2
serBufUsed .EQU serRdPtr+2
basicStarted .EQU serBufUsed+1
TEMPSTACK .EQU $20ED ; Top of BASIC line input buffer so is "free ram" when BASIC resets
CR .EQU 0DH
LF .EQU 0AH
CS .EQU 0CH ; Clear screen
.ORG $0000
;------------------------------------------------------------------------------
; Reset
RST00 DI ;Disable interrupts
JP INIT ;Initialize Hardware and go
;------------------------------------------------------------------------------
; TX a character over RS232
.ORG 0008H
RST08 JP TXA
;------------------------------------------------------------------------------
; RX a character over RS232 Channel A [Console], hold here until char ready.
.ORG 0010H
RST10 JP RXA
;------------------------------------------------------------------------------
; Check serial status
.ORG 0018H
RST18 JP CKINCHAR
;------------------------------------------------------------------------------
; RST 38 - INTERRUPT VECTOR [ for IM 1 ]
.ORG 0038H
RST38 JR serialInt
;------------------------------------------------------------------------------
serialInt: PUSH AF
PUSH HL
IN A,($80)
AND $01 ; Check if interupt due to read buffer full
JR Z,rts0 ; if not, ignore
IN A,($81)
PUSH AF
LD A,(serBufUsed)
CP SER_BUFSIZE ; If full then ignore
JR NZ,notFull
POP AF
JR rts0
notFull: LD HL,(serInPtr)
INC HL
LD A,L ; Only need to check low byte becasuse buffer<256 bytes
CP (serBuf+SER_BUFSIZE) & $FF
JR NZ, notWrap
LD HL,serBuf
notWrap: LD (serInPtr),HL
POP AF
LD (HL),A
LD A,(serBufUsed)
INC A
LD (serBufUsed),A
CP SER_FULLSIZE
JR C,rts0
LD A,RTS_HIGH
OUT ($80),A
rts0: POP HL
POP AF
EI
RETI
;------------------------------------------------------------------------------
RXA:
waitForChar: LD A,(serBufUsed)
CP $00
JR Z, waitForChar
PUSH HL
LD HL,(serRdPtr)
INC HL
LD A,L ; Only need to check low byte becasuse buffer<256 bytes
CP (serBuf+SER_BUFSIZE) & $FF
JR NZ, notRdWrap
LD HL,serBuf
notRdWrap: DI
LD (serRdPtr),HL
LD A,(serBufUsed)
DEC A
LD (serBufUsed),A
CP SER_EMPTYSIZE
JR NC,rts1
LD A,RTS_LOW
OUT ($80),A
rts1:
LD A,(HL)
EI
POP HL
RET ; Char ready in A
;------------------------------------------------------------------------------
TXA: PUSH AF ; Store character
conout1: IN A,($80) ; Status byte
BIT 1,A ; Set Zero flag if still transmitting character
JR Z,conout1 ; Loop until flag signals ready
POP AF ; Retrieve character
OUT ($81),A ; Output the character
RET
;------------------------------------------------------------------------------
CKINCHAR LD A,(serBufUsed)
CP $0
RET
PRINT: LD A,(HL) ; Get character
OR A ; Is it $00 ?
RET Z ; Then RETurn on terminator
RST 08H ; Print it
INC HL ; Next Character
JR PRINT ; Continue until $00
RET
;------------------------------------------------------------------------------
INIT:
LD HL,TEMPSTACK ; Temp stack
LD SP,HL ; Set up a temporary stack
LD HL,serBuf
LD (serInPtr),HL
LD (serRdPtr),HL
XOR A ;0 to accumulator
LD (serBufUsed),A
LD A,RTS_LOW
OUT ($80),A ; Initialise ACIA
IM 1
EI
LD HL,SIGNON1 ; Sign-on message
CALL PRINT ; Output string
LD A,(basicStarted); Check the BASIC STARTED flag
CP 'Y' ; to see if this is power-up
JR NZ,COLDSTART ; If not BASIC started then always do cold start
LD HL,SIGNON2 ; Cold/warm message
CALL PRINT ; Output string
CORW:
CALL RXA
AND %11011111 ; lower to uppercase
CP 'C'
JR NZ, CHECKWARM
RST 08H
LD A,$0D
RST 08H
LD A,$0A
RST 08H
COLDSTART: LD A,'Y' ; Set the BASIC STARTED flag
LD (basicStarted),A
JP $0150 ; Start BASIC COLD
CHECKWARM:
CP 'W'
JR NZ, CORW
RST 08H
LD A,$0D
RST 08H
LD A,$0A
RST 08H
JP $0153 ; Start BASIC WARM
SIGNON1: .BYTE CS
.BYTE "Z80 SBC By Grant Searle",CR,LF,0
SIGNON2: .BYTE CR,LF
.BYTE "Cold or warm start (C or W)? ",0
.END
+433
View File
@@ -0,0 +1,433 @@
#target bin
#include "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+01000h
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:
; copy bios to top 16k
di
ld a,BOOT_BANK_MAPPING
ld (SYSTEM_REGISTER),a
ld sp,BIOS_STACK_TOP
ld hl,BIOS_ROM_START
ld de,SHARED_MEM_START
ld bc,BIOS_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
; -------------------------------------------------------
; 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
; 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 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
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
; -------------------------------------------------------
getc:
call try_getc
jr c,getc
ret
; -------------------------------------------------------
; Strings
; -------------------------------------------------------
msg_header: .db "BIOS v1.0 - Joppe Blondel",00dh,00ah,000h
+4
View File
@@ -0,0 +1,4 @@
BIOS_PUTC .equ 0c050h
BIOS_GETC .equ 0c053h
BIOS_TRY_GETC .equ 0c056h
BIOS_PUTS .equ 0c059h
+6
View File
@@ -0,0 +1,6 @@
SYSTEM_REGISTER .equ 000h
BOOT_BANK_MAPPING .equ 006h
ROM_DISABLE_BIT .equ 001h
BANK_SELECT_BIT .equ 002h
BANK_ENABLE_BIT .equ 004h
BANK_MODE_CLEAR_MASK .equ 0f9h
+14
View File
@@ -0,0 +1,14 @@
ROM_START .equ 00000h
ROM_SIZE .equ 08000h
ROM_END .equ 07fffh
RAM_START .equ 08000h
RAM_SIZE .equ 08000h
RAM_END .equ 0ffffh
SHARED_MEM_START .equ 0c000h
SHARED_MEM_SIZE .equ 04000h
SHARED_MEM_END .equ 0ffffh
BIOS_STACK_TOP .equ SHARED_MEM_END
BIOS_ROM_START .equ ROM_START+0080h
BIOS_ROM_SIZE .equ 00f80h