arch z80
include "msx.oc"
include "msx/romram.oc"
optimize flow
msx:link-as-rom main _
module device {
data fonts = word @ <reserved>
data cursor = word @ <reserved>
data color = byte @ <reserved>
data bold = byte @ <reserved>
const t32cgp(x: 0 y: 0) = msx:T32CGP/INI + (x * 8) + (y * 32 * 8)
macro locate(x y) {
HL@(0x4000 | device:t32cgp(%=x %=y)) -> [device:cursor]
}
macro locate-x(x) {
A@%=x . device:cursor/set-x(A)
}
macro set-color(fg bg) {
@(%=fg << 4 | %=bg) -> [device:color]
}
macro set-bold() {
@opcode("RRA") -> [device:bold]
}
macro set-unbold() {
@opcode("NOP") -> [device:bold]
}
macro print(s) {
DE@message . device:put-stringz(DE !)
data message = byte [%=s 0] : rodata
}
proc cursor/set-x(A) {
A <* 3 -> [cursor]
return
}
proc cursor/lf() {
[HL@(cursor + 1)] ++
return
}
proc init() {
HL@[msx:CGTABL] -> [fonts]
msx:inigrp(!)
clear-screen()
return
}
proc clear-screen() {
msx:set-vdp-write-addr msx:T32NAM/INI
A - A
BC <- asword(0 3)
loop {
A -out msx:VDP_DATA ++
} while/B-C-
msx:set-vdp-write-addr msx:T32CGP/INI
msx:fill-vdp-data/wide 0 (8 * 256 * 3)
msx:set-vdp-write-addr msx:T32COL/INI
msx:fill-vdp-data/wide 0x11 (8 * 256 * 3)
return
}
proc put-stringz(DE !) {
DE -push
HL <- 0; *patch* cursor word
di/ei { out/HL msx:VDP_ADDR }
loop {
A <- [DE] | A; break-if Z?
DE ++
BC <- 0 : A
expand-loop 3 { C << 1; B <*$ 1 } // BC << 3
HL <- 0; *patch* fonts word
HL + BC
B <- 8
loop {
A <- [HL] -> C; HL ++
*patch* bold; NOP // or RRA
A | C -out msx:VDP_DATA
} while/B-
}
HL -pop <-> DE - DE // HL = length
expand-loop 3 { L << 1; H <*$ 1 } // HL << 3
HL -> BC + DE@[cursor] -> [cursor]
D -set 5 // DE | 0x2000(GRPCGP/INI)
di/ei { out/DE msx:VDP_ADDR }
optimize-loop-count(-* BC => BC)
A <- 0; *patch* color byte
msx:fill-vdp-data/wide _ _
return
proc optimize-loop-count(-* BC => BC) {
BC --
B ++ -> A
C ++ -> B <- A
return
}
}
proc copy-line(D E !) {
data buf = [256]byte : bss
HL <- D : 0
di/ei { out/HL msx:VDP_ADDR }
HL@buf . BC@asword(0 msx:VDP_DATA)
loop { INI } while not-zero?
HL <- E : 0 . {H -set 6} // HL | 0x4000
di/ei { out/HL msx:VDP_ADDR }
HL@buf . BC@asword(0 msx:VDP_DATA)
msx:otir-vdp-data
HL <- D : 0 . {H -set 5}
di/ei { out/HL msx:VDP_ADDR }
HL@buf . BC@asword(0 msx:VDP_DATA)
loop { INI } while not-zero?
@E | (0x40 | 0x20) -> H . L@0
di/ei { out/HL msx:VDP_ADDR }
HL@buf . BC@asword(0 msx:VDP_DATA)
msx:otir-vdp-data
return
}
proc fill-line(D !) {
E <- 0 . {D -set 6} // DE | 0x4000
di/ei { out/DE msx:VDP_ADDR }
A - A . B@0
msx:out-vdp-data/while/B-
E <- 0 . {D -set 6 -set 5} // DE | 0x4000 | 0x2000
di/ei { out/DE msx:VDP_ADDR }
@0x11 . B@0
msx:out-vdp-data/while/B-
return
}
proc scroll(B C !) {
loop {
C -> E ++ -> D
push/pop BC {
copy-line(D E !)
}
} while/B-
return
}
}
module main {
proc main() {
romram:boot
device:init()
fallthrough
}
proc main/loop() {
device:locate 0 4
B <- 8
loop {
push/pop BC {
B -bit? 0; if zero? {
device:set-unbold
} else {
device:set-bold
}
msx:sleep 6
device:locate-x 3
device:set-color 15 8; device:print "THE QUICK "
device:set-color 1 11; device:print "BROWN FOX "
device:cursor/lf()
device:locate-x 6
device:set-color 3 1; device:print "JUMPS OVER "
device:set-color 6 14; device:print "THE LAZY DOG"
device:cursor/lf()
}
} while/B-
B <- 16
loop {
push/pop BC {
BC@asword(15 4) . device:scroll(B C !)
D@19 . device:fill-line(D !)
}
} while/B-
recur
}
}