I'm trying to write two bytes (color values) to the VRAM of my TI-84 Plus CE-T calculator, which uses the Zilog eZ80 CPU. The VRAM starts at 0xD40000 and is 0x25800 bytes long. The calculator has a built in syscall called MemSet
, which fills a chunk of memory with one byte, but I want it to alternate between two different values and store these in memory. I tried using the following code:
#include "includes\ti84pce.inc"
.assume ADL=1
.org userMem-2
.db tExtTok,tAsm84CeCmp
call _homeup
call _ClrScrnFull
ld hl,13893632 ; = D40000, vram start
ld bc,153600 ; = 025800, count/vram length
j1:
ld (hl),31 ; set first byte
inc hl
dec bc
jr z,j2 ; jump to end if count==0
ld (hl),0 ; set second byte
inc hl
dec bc
jr z,j2 ; jump to end if count==0
jp j1 ; loop
j2:
call _GetKey
call _ClrScrnFull
ret
I want it to output 31 00 31 00 31 00... into memory starting at 0xD40000, but instead it seems to change only the first byte and jump to the end after doing so. Any ideas on how to fix this?
First of all, if you're going to move SP, you need to save and restore it. Second, you need to disable interrupts or else you'll have a race condition bug: if an interrupt triggers near the end of the copy, the stack will grow down into whatever is below it, which happens to be the VAT.
; Index registers are actually fast on the eZ80
ld ix, 0
add ix, sp
di
; Do some hack using SP here
ld sp, ix
ei
@Ped7g The eZ80 will cache any -IR/-DR suffix instruction; unlike the Z80, it doesn't reread the opcode from memory on each iteration. Consequently, instructions like LDIR can execute each iteration in just 2 bus cycles, one read and one write. The SP hack is therefore not only needlessly complicated, but actually slower. The SP hack still best left to more experienced programmers.
The eZ80 is very well pipelined and its performance is limited by its lack of any cache and 1-byte-wide bus. The only instruction that runs slower than the bus is MLT, a 2-bus-cycle instruction that needs 5 clock cycles. For every other instruction, just count the number of bytes in the opcode, and the number of read and write cycles, and you've got its execution time. It's a huge pity that in the TI-84+CE series, TI decided to pair the fast eZ80 with an SRAM that somehow needs four clock cycles for each read and write (at 48 MHz)! Yes, TI, a world leader in semiconductor design, managed to design a slow SRAM. Getting on-die SRAM to perform poorly is an engineering feat.
@harold has the right answer, though I prefer optimizing for size instead of speed outside of inner loops.
#include "includes\ti84pce.inc"
.assume ADL=1
.org userMem-2
.db tExtTok,tAsm84CeCmp
call _homeup
call _ClrScrnFull
; Initialize registers
ld hl, vRam
ld bc, lcdWidth * lcdHeight * 2 - 2
push hl
pop de
; Write initial 2-byte value
ld (hl), 31
inc hl
ld (hl), 0
inc hl
ex de, hl
; Copy everything all at once. Interrupts may trigger while this instruction is processing.
ldir
call _GetKey
call _ClrScrnFull
ret
On EFnet, #ez80-dev is a good place to ask questions. cemetech.net is also a good place.
This does not work:
dec bc
jr z,j2
Only 8 bit dec
and inc
modify the flags. It could be fixed by properly detecting whether bc
is zero.
Here is a different technique without manual looping:
ld hl,$D40000
ld (hl),31
inc hl
ld (hl),0
dec hl
ld de,$D40002
ld bc,$25800 - 2
ldir
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With