Add example project, devcontainer config and debugger config

This commit is contained in:
Neil McPhail 2025-04-26 23:30:03 +01:00
parent 5ffbe818b6
commit 0a5cf0d943
7 changed files with 376 additions and 0 deletions

View File

@ -0,0 +1,21 @@
{
"name": "ZX Spectrum dev tools",
"image": "boarstone.mcphail.uk/mcphail/speccydev",
"remoteUser": "ubuntu",
"runArgs": [
"--network=host"
],
"customizations": {
"vscode": {
"extensions": [
"maziac.dezog",
"maziac.asm-code-lens",
"maziac.z80-instruction-set",
"maziac.hex-hover-converter",
"maziac.sna-fileviewer",
"maziac.nex-fileviewer",
"ms-vscode.makefile-tools"
]
}
}
}

110
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,110 @@
{
"configurations": [
{
"type": "dezog",
"request": "launch",
"name": "Simulator - ZX81 56k RAM",
"remoteType": "zsim",
"zsim": {
"visualMemory": true,
"preset": "zx81",
"memoryModel": "ZX81-56K"
},
"sjasmplus": [
{
"path": "myprog.sld"
}
],
"commandsAfterLaunch": [],
"history": {
"reverseDebugInstructionCount": 1000000,
"spotCount": 10,
"codeCoverageEnabled": true
},
"startAutomatically": false,
"rootFolder": "${workspaceFolder}",
"load": "myprog.p"
},
{
"type": "dezog",
"request": "launch",
"name": "Simulator - ZX128K Spectrum",
"remoteType": "zsim",
"zsim": {
"visualMemory": true,
"preset": "spectrum",
"memoryModel": "ZX128K"
},
"sjasmplus": [
{
"path": "myprog.sld"
}
],
"commandsAfterLaunch": [],
"history": {
"reverseDebugInstructionCount": 1000000,
"spotCount": 10,
"codeCoverageEnabled": true
},
"startAutomatically": false,
"rootFolder": "${workspaceFolder}",
"load": "myprog.sna",
"topOfStack": "0x5d58"
},
{
"type": "dezog",
"request": "launch",
"name": "CSpect",
"remoteType": "cspect",
"sjasmplus": [
{
"path": "myprog.sld"
}
],
"commandsAfterLaunch": [],
"history": {
"reverseDebugInstructionCount": 1000000,
"spotCount": 10,
"codeCoverageEnabled": false
},
"startAutomatically": false,
"rootFolder": "${workspaceFolder}",
"load": "myprog.sna",
"topOfStack": "0x5d58",
"cspect": {
"hostname": "host.docker.internal"
},
"linux": {
"cspect": {
"hostname": "localhost"
}
}
},
{
"type": "dezog",
"request": "launch",
"name": "Simulator - ZX48K Spectrum",
"remoteType": "zsim",
"zsim": {
"visualMemory": true,
"preset": "spectrum",
"memoryModel": "ZX48K"
},
"sjasmplus": [
{
"path": "myprog.sld"
}
],
"commandsAfterLaunch": [],
"history": {
"reverseDebugInstructionCount": 1000000,
"spotCount": 10,
"codeCoverageEnabled": true
},
"startAutomatically": false,
"rootFolder": "${workspaceFolder}",
"load": "myprog.sna",
"topOfStack": "0x5d58"
}
]
}

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
myprog.sna myprog.tap myprog.sld: main.asm loader.asm print.asm
sjasmplus --sld=myprog.sld --fullpath main.asm
clean:
rm -f *.tap
rm -f *.sna
rm -f *.sld
rm -rf .tmp/
.PHONY: clean

View File

@ -1 +1,9 @@
Development tools for the ZX Spectrum
The Dockerfile is the basis of the devcontainer.
The devcontainer contains various assemblers etc.
Build the example project by running `make` from the terminal or the VSCode extension.
Debug in the build in simulator or in CSpect externally (example CSpect invocation on Windows would be `CSpect.exe -w2 -debug -remote`).

25
loader.asm Normal file
View File

@ -0,0 +1,25 @@
MODULE basic_loader
ORG #5c00
basic_start:
db 0, 0 ; line number
dw line_length
line_start:
db #fd, '0', #0e, 0, 0 ; CLEAR
dw code_start_addr - 1
db 0, ':'
db #ef, '"' ; LOAD "
db "code"
db '"', #af, ':' ; name"CODE
db #f5, #c0 ; PRINT USR
db '0', #0e, 0, 0
dw code_run_addr
db 0, #0d
line_length EQU $ - line_start
basic_length EQU $ - basic_start
EMPTYTAP "myprog.tap"
SAVETAP "myprog.tap", BASIC, "myprog", basic_start, basic_length, 0
SAVETAP "myprog.tap", CODE, "code", code_start_addr, code_length
ENDMODULE

22
main.asm Normal file
View File

@ -0,0 +1,22 @@
code_start_addr EQU #8000
ORG code_start_addr
MODULE main
@code_run_addr:
ld a, 57
ld bc, 64
ld hl, 0
call print_string
db "Hello, world!", 0
ret
ENDMODULE
INCLUDE print.asm
code_length EQU $ - code_start_addr
DEVICE ZXSPECTRUM48
SLDOPT COMMENT WPMEM, LOGPOINT, ASSERTION
SAVESNA "myprog.sna", code_run_addr
INCLUDE loader.asm

180
print.asm Normal file
View File

@ -0,0 +1,180 @@
ink_black EQU 0
ink_blue EQU 1
ink_red EQU 2
ink_magenta EQU 3
ink_green EQU 4
ink_cyan EQU 5
ink_yellow EQU 6
ink_white EQU 7
black EQU ink_black
blue EQU ink_blue
red EQU ink_red
magenta EQU ink_magenta
green EQU ink_green
cyan EQU ink_cyan
yellow EQU ink_yellow
white EQU ink_white
paper_black EQU 0
paper_blue EQU 8
paper_red EQU 16
paper_magenta EQU 24
paper_green EQU 32
paper_cyan EQU 40
paper_yellow EQU 48
paper_white EQU 56
bright EQU 64
flash EQU 128
attr_list_end EQU flash | bright | ink_black | paper_black
MODULE print
bm_start EQU #4000
attr_area EQU #5800
bm_len EQU 6144
attr_len EQU 768
CHARS EQU #5c36
char_posn:
dw #4000
MODULE print_string
; Set HL to be row and column and follow the call with a null-terminated string
; All registers preserved
; char_posn will have been moved to after string, but HL will still have coordinates of string start
@print_string:
call set_char_posn
ex (sp), hl
push af
loop:
ld a, (hl)
inc hl
or a
jr z, exit
call print_char
jr loop
exit:
pop af
ex (sp), hl
ret
ENDMODULE
MODULE print_char
; Prints the single character from the A register
; All registers preserved
; char_posn will point to next square
@print_char:
push hl
push de
push af
ld h, 0
ld l, a
add hl, hl
add hl, hl
add hl, hl
ld d, h
ld e, l
ld hl, (print.CHARS)
add hl, de
ld d, h
ld e, l
ld hl, (print.char_posn)
push bc
ld b, 8
loop:
ld a, (de)
ld (hl), a
inc h
inc de
djnz loop
ld hl, (print.char_posn)
inc l
jr nz, update_char_posn
ld a, #50
cp h
jr nz, next_third
ld hl, print.bm_start
jr update_char_posn
next_third:
ld a, 8
add a, h
ld h, a
update_char_posn:
ld (print.char_posn), hl
pop bc
pop af
pop de
pop hl
ret
ENDMODULE
MODULE set_char_posn
; Pass row and column, in that order, in HL
@set_char_posn:
push hl
push af
ld a, h
; check for top third
ld h, %01000000
sub 8
jr c, set_column
; check for middle third
ld h, %01001000
sub 8
jr c, set_column
; must be bottom third
ld h, %01010000
sub 8
set_column:
; restore the row offset of the third and shift it into upper 3 bits of L
add a, 8
sla a
sla a
sla a
sla a
sla a
or l
ld l, a
ld (print.char_posn), hl
pop af
pop hl
ret
ENDMODULE
MODULE set_attributes
; Row and column in HL
; db list of attributes follows call
; terminate with attr_list_end byte (bright flashing black on black)
@set_attributes:
ex de, hl
ex (sp), hl
push de
push hl
ld h, 0
ld l, d
ld d, h
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, de
ld de, print.attr_area
add hl, de
pop de
ex de, hl
push af
loop:
ld a, (hl)
inc hl
cp attr_list_end
jr z, exit
ld (de), a
inc de
jr loop
exit:
pop af
pop de
ex (sp), hl
ex de, hl
ret
ENDMODULE
ENDMODULE