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 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