nascom basic compiles and works

This commit is contained in:
Joppe Blondel
2026-10-06 15:59:02 +02:00
parent 0ca388c1d0
commit 65e71d024c
7 changed files with 13791 additions and 6 deletions
+21 -6
View File
@@ -25,6 +25,8 @@ TINYBASIC_SRC := apps/tinybasic/tinybasic.asm
TINYBASIC_BUILD := $(BUILDDIR)/tinybasic TINYBASIC_BUILD := $(BUILDDIR)/tinybasic
TAPE_LOADER_SRC := apps/casette/tape_loader.asm TAPE_LOADER_SRC := apps/casette/tape_loader.asm
TAPE_LOADER_BUILD := $(BUILDDIR)/casette TAPE_LOADER_BUILD := $(BUILDDIR)/casette
NASCOM_BASIC_SRC := apps/nascom_basic/basic.asm
NASCOM_BASIC_BUILD := $(BUILDDIR)/nascom_basic
.DEFAULT_GOAL := metal .DEFAULT_GOAL := metal
@@ -48,6 +50,9 @@ metal: $(BUILDDIR)/metal/$(TARGET).ihx $(BUILDDIR)/metal/$(TARGET).bin $(BUILDDI
@printf " Tape loader: %5u ROM bytes at %04X\n" \ @printf " Tape loader: %5u ROM bytes at %04X\n" \
$$(wc -c < $(TAPE_LOADER_BUILD)/tape_loader.bin) \ $$(wc -c < $(TAPE_LOADER_BUILD)/tape_loader.bin) \
$$(( $(TAPE_LOADER_ROM_ADDRESS) )) $$(( $(TAPE_LOADER_ROM_ADDRESS) ))
@printf " NASCOM BASIC: %5u ROM bytes at %04X\n" \
$$(wc -c < $(NASCOM_BASIC_BUILD)/nascom_basic.bin) \
$$(( $(NASCOM_BASIC_ROM_ADDRESS) ))
$(BUILDDIR)/metal/$(TARGET).ihx: $(METAL_RELFILES) $(BUILDDIR)/metal/$(TARGET).ihx: $(METAL_RELFILES)
@mkdir -p $(@D) @mkdir -p $(@D)
@@ -56,13 +61,14 @@ $(BUILDDIR)/metal/$(TARGET).ihx: $(METAL_RELFILES)
$(BUILDDIR)/metal/$(TARGET).flat.bin: $(BUILDDIR)/metal/$(TARGET).ihx $(BUILDDIR)/metal/$(TARGET).flat.bin: $(BUILDDIR)/metal/$(TARGET).ihx
$(METAL_MAKEBIN) -s $(METAL_IMAGE_SIZE) $< $@ $(METAL_MAKEBIN) -s $(METAL_IMAGE_SIZE) $< $@
$(BUILDDIR)/metal/$(TARGET).prog.bin: $(BUILDDIR)/metal/$(TARGET).flat.bin $(TINYBASIC_BUILD)/tinybasic.bin $(TAPE_LOADER_BUILD)/tape_loader.bin $(BUILDDIR)/metal/$(TARGET).prog.bin: $(BUILDDIR)/metal/$(TARGET).flat.bin $(TINYBASIC_BUILD)/tinybasic.bin $(TAPE_LOADER_BUILD)/tape_loader.bin $(NASCOM_BASIC_BUILD)/nascom_basic.bin
@set -e; \ @set -e; \
payload_end=$$(awk '$$1 == "DEF" && $$2 == "resident_image_end" { print $$3 }' $(BUILDDIR)/metal/$(TARGET).noi); \ payload_end=$$(awk '$$1 == "DEF" && $$2 == "resident_image_end" { print $$3 }' $(BUILDDIR)/metal/$(TARGET).noi); \
payload_size=$$((payload_end - $(RESIDENT_RAM_BASE))); \ payload_size=$$((payload_end - $(RESIDENT_RAM_BASE))); \
payload_rom_end=$$(( $(RESIDENT_ROM_OFFSET) + payload_size )); \ payload_rom_end=$$(( $(RESIDENT_ROM_OFFSET) + payload_size )); \
tiny_size=$$(wc -c < $(TINYBASIC_BUILD)/tinybasic.bin); \ tiny_size=$$(wc -c < $(TINYBASIC_BUILD)/tinybasic.bin); \
tape_size=$$(wc -c < $(TAPE_LOADER_BUILD)/tape_loader.bin); \ tape_size=$$(wc -c < $(TAPE_LOADER_BUILD)/tape_loader.bin); \
nascom_size=$$(wc -c < $(NASCOM_BASIC_BUILD)/nascom_basic.bin); \
if test $$payload_size -le 0; then \ if test $$payload_size -le 0; then \
echo "error: resident image is empty or has an invalid end symbol" >&2; exit 1; \ echo "error: resident image is empty or has an invalid end symbol" >&2; exit 1; \
fi; \ fi; \
@@ -74,14 +80,19 @@ $(BUILDDIR)/metal/$(TARGET).prog.bin: $(BUILDDIR)/metal/$(TARGET).flat.bin $(TIN
printf "error: Tiny BASIC ends at %04X, beyond tape-loader origin %04X\n" \ printf "error: Tiny BASIC ends at %04X, beyond tape-loader origin %04X\n" \
$$(( $(TINYBASIC_ROM_ADDRESS) + tiny_size )) $$(( $(TAPE_LOADER_ROM_ADDRESS) )) >&2; exit 1; \ $$(( $(TINYBASIC_ROM_ADDRESS) + tiny_size )) $$(( $(TAPE_LOADER_ROM_ADDRESS) )) >&2; exit 1; \
fi; \ fi; \
if test $$(( $(TAPE_LOADER_ROM_ADDRESS) + tape_size )) -gt $$(( $(ROM_SIZE) )); then \ if test $$(( $(TAPE_LOADER_ROM_ADDRESS) + tape_size )) -gt $$(( $(NASCOM_BASIC_ROM_ADDRESS) )); then \
printf "error: tape loader ends at %04X, beyond ROM size %04X\n" \ printf "error: tape loader ends at %04X, beyond NASCOM BASIC origin %04X\n" \
$$(( $(TAPE_LOADER_ROM_ADDRESS) + tape_size )) $$(( $(ROM_SIZE) )) >&2; exit 1; \ $$(( $(TAPE_LOADER_ROM_ADDRESS) + tape_size )) $$(( $(NASCOM_BASIC_ROM_ADDRESS) )) >&2; exit 1; \
fi; \ fi; \
dd if=$< of=$@ bs=1 count=$$(( $(TAPE_LOADER_ROM_ADDRESS) )) status=none; \ if test $$(( $(NASCOM_BASIC_ROM_ADDRESS) + nascom_size )) -gt $$(( $(ROM_SIZE) )); then \
printf "error: NASCOM BASIC ends at %04X, beyond ROM size %04X\n" \
$$(( $(NASCOM_BASIC_ROM_ADDRESS) + nascom_size )) $$(( $(ROM_SIZE) )) >&2; exit 1; \
fi; \
dd if=$< of=$@ bs=1 count=$$(( $(NASCOM_BASIC_ROM_ADDRESS) )) status=none; \
dd if=$< of=$@ bs=1 skip=$$(( $(RESIDENT_RAM_BASE) )) seek=$$(( $(RESIDENT_ROM_OFFSET) )) count=$$payload_size conv=notrunc status=none; \ dd if=$< of=$@ bs=1 skip=$$(( $(RESIDENT_RAM_BASE) )) seek=$$(( $(RESIDENT_ROM_OFFSET) )) count=$$payload_size conv=notrunc status=none; \
dd if=$(TINYBASIC_BUILD)/tinybasic.bin of=$@ bs=1 seek=$$(( $(TINYBASIC_ROM_ADDRESS) )) conv=notrunc status=none; \ dd if=$(TINYBASIC_BUILD)/tinybasic.bin of=$@ bs=1 seek=$$(( $(TINYBASIC_ROM_ADDRESS) )) conv=notrunc status=none; \
dd if=$(TAPE_LOADER_BUILD)/tape_loader.bin of=$@ bs=1 seek=$$(( $(TAPE_LOADER_ROM_ADDRESS) )) conv=notrunc status=none dd if=$(TAPE_LOADER_BUILD)/tape_loader.bin of=$@ bs=1 seek=$$(( $(TAPE_LOADER_ROM_ADDRESS) )) conv=notrunc status=none; \
dd if=$(NASCOM_BASIC_BUILD)/nascom_basic.bin of=$@ bs=1 seek=$$(( $(NASCOM_BASIC_ROM_ADDRESS) )) conv=notrunc status=none
$(BUILDDIR)/metal/$(TARGET).bin: $(BUILDDIR)/metal/$(TARGET).flat.bin $(BUILDDIR)/metal/$(TARGET).prog.bin $(BUILDDIR)/metal/$(TARGET).bin: $(BUILDDIR)/metal/$(TARGET).flat.bin $(BUILDDIR)/metal/$(TARGET).prog.bin
dd if=$< of=$@ bs=$(METAL_BIN_SIZE) count=1 status=none dd if=$< of=$@ bs=$(METAL_BIN_SIZE) count=1 status=none
@@ -125,6 +136,10 @@ $(TAPE_LOADER_BUILD)/tape_loader.bin: $(TAPE_LOADER_BUILD)/tape_loader.flat.bin
test $$loader_size -gt 0; \ test $$loader_size -gt 0; \
dd if=$< of=$@ bs=1 skip=$$(( $(TAPE_LOADER_ROM_ADDRESS) )) count=$$loader_size status=none dd if=$< of=$@ bs=1 skip=$$(( $(TAPE_LOADER_ROM_ADDRESS) )) count=$$loader_size status=none
$(NASCOM_BASIC_BUILD)/nascom_basic.bin: $(NASCOM_BASIC_SRC)
@mkdir -p $(@D)
zasm --z80 $< -o $@ -l0
$(LAYOUT_HEADER): $(LAYOUT_CONFIG) $(LAYOUT_HEADER): $(LAYOUT_CONFIG)
@mkdir -p $(@D) @mkdir -p $(@D)
@awk 'BEGIN { print "#ifndef ROM_LAYOUT_H"; print "#define ROM_LAYOUT_H"; print "" } \ @awk 'BEGIN { print "#ifndef ROM_LAYOUT_H"; print "#define ROM_LAYOUT_H"; print "" } \
+2
View File
@@ -0,0 +1,2 @@
*.bin
*.lst
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
+1
View File
@@ -13,3 +13,4 @@ RESIDENT_DATA_BASE := 0xF000
TINYBASIC_ROM_ADDRESS := 0x1400 TINYBASIC_ROM_ADDRESS := 0x1400
TAPE_LOADER_ROM_ADDRESS := 0x3000 TAPE_LOADER_ROM_ADDRESS := 0x3000
NASCOM_BASIC_ROM_ADDRESS := 0x4000