Last active
August 7, 2023 10:49
-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Video demo - YouTube