Skip to content

Instantly share code, notes, and snippets.

@mistificator
Last active August 7, 2023 10:49
Show Gist options
  • Save mistificator/bc97af0f52d9cf84a870b9a4067cad0c to your computer and use it in GitHub Desktop.
Save mistificator/bc97af0f52d9cf84a870b9a4067cad0c to your computer and use it in GitHub Desktop.
Sample ASM code for ZX Spectrum +3 that loads 48BASIC code from CP/M (and then switch back to CP/M)
; switch to 48BASIC ROM from CP/M (and then switch back)
; to run test from 48BASIC enter "RANDOMIZE USR 32768"
#define CPM_ORG $100
#define LOADER_ORG $C000 - $200 ; RAM bank 2
#define BASIC_ORG $8000 ; RAM bank 2
.org CPM_ORG
Cpm_Start:
ld de, Message_Start_Test
call Print_CPM
; move loader to RAM bank 2
ld de, LOADER_ORG
ld hl, Cpm_End
ld bc, Loader_Image_End - Loader_Image_Start
ldir
; move 48BASIC code to RAM bank 2
ld de, BASIC_ORG
ld hl, Loader_Image_End - Loader_Image_Start + Cpm_End
ld bc, Basic_Image_End - Basic_Image_Start
ldir
ld de, Message_Images_Copied
call Print_CPM
jp Loader_Start
Print_CPM:
ld c, $09 ; CP/M BIOS function 0x09 - print string, https://www.seasip.info/Cpm/bdos.html#9
call $0005 ; call CP/M BIOS entry point at 0x0005
ret
Message_Start_Test:
.db "Start RAM switch test",13,10,'$'
Message_Images_Copied:
.db "Images copied to bank 2",13,10,'$'
Cpm_End:
.org LOADER_ORG
Loader_Image_Start:
Loader_Start:
; switch banks to ROM3 - RAM5 - RAM2 - RAM4
di
ld a, 4 ; switch ROM vertical (D2)
ld bc, $1FFD
out (c), a
ld a, 16 + 4 ; switch ROM horizontal (D4)
ld bc, $7FFD
out (c), a
; ei
; fill video RAM and system variables area (second RAM bank, bank 5)
Zero_Memory: ; from http://www.cpcwiki.eu/index.php/Programming:Filling_memory_with_a_byte
ld hl, $4000
ld bc,$5D00 - $4000
ld (hl),$00
dec bc
ld e,l
ld d,h
inc de
ldir
; initialize 48BASIC ROM
; di
xor a
ld b, a
ld a, $3f
ld i, a
ld hl,$ffff ; Top of physical RAM (P-RAMT).
jp $11f0 ; start without fill RAM
; prepare to initialize 48BASIC ROM more hacked way
; ld a, $3f
; ld i, a
; ld hl,$3C00
; ld ($5C36),hl ; Initialise the system variable CHARS.
; ld bc,$0040
; ld ($5C38),bc ;Set the system variables RASP and PIP.
; ld hl,$ffff
; ld ($5CB4),hl ; Top of physical RAM (P-RAMT).
; LD ($5C7B),hl ; Now set UDG (fake).
; ld ($5CB2),hl ; Set RAMTOP.
; ld hl, ($5CB2)
; ld (hl),$3E ; The top location (RAMTOP) is made to hold +3E
; dec hl
; ld sp, hl
; dec hl
; dec hl
; ld ($5C3D),hl ; Step down two locations to find the correct value for ERR-SP.
; im 1
; ld iy,$5C3A ;IY holds +ERR-NR always.
; ei
; jp $1235 ; jump in the middle, without fill RAM and UDG
Loader_Image_End:
#define ROM_PR_STRING $203C
#define ROM_OUT_NUM1 $1A1B
#define ROM_CHAN_OPEN $1601
#define ROM_CLS $0D6B
#define SYSVAR_7FFD_STATE $5B5C ;system variable that holds the last value output to 7FFDh, from https://www.worldofspectrum.org/ZXSpectrum128+3Manual/chapter8pt26.html
#define SYSVAR_1FFD_STATE $5B67 ;system variable that holds the last value output to 1FFDh, from http://www.hal.varese.it/filesmuseo/sinclair/spectrumfaq/tech_128.html
#define SYSVAR_LAST_K $5C08
.org BASIC_ORG
Basic_Image_Start:
push bc
push de
push hl
push af
jp Start
Select_Screen: ;from https://zxpress.ru/book_articles.php?id=1150
push hl
ld a,2
call ROM_CHAN_OPEN ;from https://skoolkid.github.io/rom/asm/1601.html
pop hl
ret
Print:
call Select_Screen
Print_Loop: ;from https://www.worldofspectrum.org/ZXSpectrum128+3Manual/chapter8pt26.html
ld a,(hl) ;this just loops printing characters
cp '$' ;until if finds 0x24 ($)
ret z
push hl
rst $10 ;with 48K ROM in, this will print char in A
pop hl
inc hl
jp Print_Loop
Print_NewLine:
ld a,13
push hl
rst $10
pop hl
ret
Set_Border_Color:
push de
push bc
ld d,b
ld bc, $FFFE
out (c),d
pop bc
pop de
ret
Start:
xor a
ld (SYSVAR_LAST_K),a ; reset last key
call ROM_CLS
Print_Message:
call Select_Screen
ld de,Message1_Start
ld bc,Message1_End-Message1_Start
call ROM_PR_STRING ; print by ROM, as described in https://zxpress.ru/book_articles.php?id=1150
call Print_NewLine
ld hl,Message2
call Print
call Print_NewLine
ld hl,Message_MemoryBank
call Print
ld bc,(SYSVAR_7FFD_STATE) ; current memory bank
call ROM_OUT_NUM1 ; print number by ROM
ld a,'/'
rst $10
ld bc,(SYSVAR_1FFD_STATE) ; current memory bank
call ROM_OUT_NUM1 ; print number by ROM
call Print_NewLine
ld hl,Message_AnyKey
call Print
Reset_Main_Loop:
ld b, 8
Main_Loop:
ld a,(SYSVAR_LAST_K) ; read keyboard
cp 0
jp nz,End ; key pressed, go to exit
call Set_Border_Color ; change border color to b value
djnz Main_Loop
jp Reset_Main_Loop
Message1_Start:
.db "Hello, world!"
Message1_End:
Message2:
.db "It's Z80 assembler test!$"
Message_MemoryBank:
.db "Control ports 7FFD/1FFD: $"
Message_AnyKey:
.db 13,13,"Press any key to exit to CP/M",13,'$'
End:
pop bc
pop de
pop hl
pop af
; ret
; switch banks BACK LOL, RAM0 - RAM1 - RAM2 - RAM3
di
ld a, 1 ; switch ROM vertical (D2)
ld bc, $1FFD
out (c), a
ld a, 0 + 0 ; switch ROM horizontal (D4)
ld bc, $7FFD
out (c), a
ei
rst $0 ; CP/M warm boot
Basic_Image_End:
@mistificator
Copy link
Author

@mistificator
Copy link
Author

back_to_cpm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment