; Hello World + Logo example
; Pure Z80 assembly for Amstrad CPC
; Firmware routines
print_char equ &BB5A ; Char printing
scr_set_mode equ &BC0E ; Set screen mode
scr_set_ink equ &BC32 ; Set ink color
wait_key equ &BB18 ; Wait for key press
wait_vsync equ &BD19 ; Wait for vertical sync
main:
; Set mode 1 (320x200, 4 colors)
ld a, 1
call scr_set_mode
; Configure palette for devcpc sprite
ld a, 0
ld b, 0
ld c, 0 ; INK 0 = Black
call scr_set_ink
ld a, 1
ld b, 1
ld c, 24 ; INK 1 = Yellow
call scr_set_ink
ld a, 2
ld b, 2
ld c, 6 ; INK 2 = Red
call scr_set_ink
; Wait for VSYNC to avoid flicker
call wait_vsync
; Draw sprite centered
; Mode 1 screen: 320 pixels = 80 bytes wide, 200 pixels tall
; Sprite: 120 pixels = 30 bytes wide, 40 pixels tall
; Center X: (320 - 120) / 2 = 100 pixels = 25 bytes
; Center Y: (200 - 40) / 2 = 80 pixels
ld hl, devcpc
ld c, (hl) ; C = width in bytes
inc hl
ld b, (hl) ; B = height in pixels
inc hl ; HL = sprite data pointer
push hl
; Calculate centered video address
push bc
ld a, 200
sub b
srl a
ld d, a ; D = centered Y
ld a, 80
sub c
srl a
ld e, a ; E = centered X in bytes
; Calculate video memory address
; Base: &C000
; Add X offset
ld hl, &C000
ld a, l
add a, e
ld l, a
jr nc, ps_x_ok
inc h
ps_x_ok:
; Add &0800 * (Y % 8)
ld a, d
and 7
ld b, a
ps_y_mod_loop:
ld a, b
or a
jr z, ps_y_mod_done
ld de, &0800
add hl, de
dec b
jr ps_y_mod_loop
ps_y_mod_done:
; Add &0050 * (Y / 8)
ld a, d
srl a
srl a
srl a
ld c, a
ps_y_div_loop:
ld a, c
or a
jr z, ps_y_div_done
ld de, &0050
add hl, de
dec c
jr ps_y_div_loop
ps_y_div_done:
pop bc
pop de ; DE = sprite data pointer
call putsprite
; Position cursor and show message
ld h, 15 ; Row
ld l, 10 ; Column
ld a, 1
call &BB75 ; TXT SET CURSOR
; Print message
ld hl, message
call print_string
; Wait for key
call wait_key
loop:
jp loop
message: db "SDK from Amstrad CPC",&FF
; CPCRSLIB-inspired sprite routine
; Inputs:
; HL = video RAM address
; DE = sprite data pointer
; B = height in bytes
; C = width in bytes
putsprite:
ld a, c
ld (ps_width+1), a ; Self-modifying code
ld a, c
neg
ld (ps_nextline+1), a
ld a, b
ld iyh, a ; Use IY as height counter
ld b, 7 ; Lines within block
ps_line_loop:
ps_width:
ld c, 0 ; Width (modified above)
ps_byte_loop:
ld a, (de) ; Read sprite byte
ld (hl), a ; Write to video RAM
inc de
inc hl
dec c
jr nz, ps_byte_loop
; Next line
dec iyh
ret z
ps_nextline:
ld c, 0 ; Line skip (modified above)
add hl, bc
jr nc, ps_line_loop
; Crossed 8-line block boundary
ld bc, &C050
add hl, bc
ld b, 7
jr ps_line_loop
print_string:
ld a, (hl)
cp &FF
ret z
inc hl
call print_char
jr print_string
; Include sprite data
READ "sprites.asm"