I wanted to implement a XModem to incorporate into the Z80 monitor program for my CPUVille Z80. It needed to be small to fit in the 2K ROM monitor, the whole thing ends up being 264 additional bytes. Here is the code for that:
; based on 6502 version http://www.6502.org/source/io/xmodem/xmodem-receive.txt
; re-coded by Tom Lovie 2023-03-23
; sub write_string and put_chr are already in ROM
monitor_warm_start: equ 0450h
SOH equ 01h ; start block
EOT equ 04h ; end of text marker
ACK equ 06h ; good block acknowledged
NAK equ 15h ; bad block acknowledged
CAN equ 18h ; cancel (not standard, not supported)
CR equ 0dh ; carriage return
LF equ 0ah ; line feed
ESC equ 1bh ; ESC to exit
rbuff: equ 0c00h ; page aligned receive buffer
rbuffp: equ 0ch ; page of receive buffer
sbuff: equ 1000h ; storage buffer to place received data
sbuffp: equ 10h ; storage buffer page
org 0800h
call XModem
jp monitor_warm_start
XModem:
ld hl,msg
call write_string
ld hl,sbuff
ld (ptr),hl ; initialize the storage pointer
ld a,01h
ld (blkno),a ; start at block number 1
StartX: ld a,NAK ; Start in CRC mode - no fallback
call put_chr ; send it
ld a,00h ; loop counter in a
call GetByte ; try to get a byte
jr c,GotByte
jr nc,StartX ; if not try again
StartBlk: ld a,00h ; loop counter in a
call GetByte ; try to get a byte
jr nc,StartBlk
GotByte: cp ESC ; want to quit
ret z
cp SOH ; start of block?
jr z,BegBlk
cp EOT ; end of text
jr nz,BadCrc
jr Done
BegBlk: ld hl,rbuff ; start hl at the receive buffer
GetBlk: ld a,00h ; 3 second window to receive char
GetBlk1: call GetByte ; get next char
jr nc,BadCrc ; just sending NAK
GetBlk2: ld (hl),a ; store the character in buffer
inc hl ; increment the buffer
ld a,83h
cp l ; <01><FE><128 bytes><CHKSUM>
jr nz,GetBlk ; get 131 characters (0x83)
ld l,00h ; start at beginning of buffer
ld a,(blkno) ; actual block number
cp (hl) ; sent block number
jr z,GoodBlk1 ; block number is expected
jr ErrorOut ; error out of the xmodem routine
GoodBlk1: xor 0ffh ; compliment the actual block no
inc hl
cp (hl) ; compare to second byte
jr z,GoodBlk2 ; block number compliment
jr ErrorOut ; error out of the xmodem routine
GoodBlk2: ld h,rbuffp ; point hl at the receive buffer
ld l,81h ; last byte
ld a,00h ; initialize a
CalcCrc: add (hl) ; compute running total start 82h
dec l
jr nz,CalcCrc
add a,(hl) ; do the block number as well
inc a ; because blockno + cpl = 255.
ld l,82h ; (hl) is the checksum
cp (hl)
jr z,GoodCrc
BadCrc: call Flush ; flush serial buffer
ld a,NAK ; and send
call put_chr ; a NAK
jr StartBlk ; restart the block
GoodCrc: ld l,02h ; hl is now pointing data
ld de,(ptr) ; de is now pointing storage
ld c,80h ; 128 bytes
ld b,00h ;
ldir ; copy the block
ld (ptr),de ; store the current pos
ld a,(blkno) ; load the block number
inc a
ld (blkno),a ; store the block number back
ld a,ACK ; send ACK
call put_chr
jp StartBlk ; get next block
Done: ld a,ACK
call put_chr
call Flush
ld hl,good ; load success message
call write_string
ret
ErrorOut: ld hl,err ; print error message and exit
call write_string
call Flush ; discard remaining buffer
ret ; return after fatal error
; subroutine to wait a set amount of time to get a byte
; Byte will be in A, destroys BC (delay loop)
GetByte: ld b,a
ld c,a
GetByteLoop: call get_chr
ret c ; return if got chr (carry set)
dec c
jr nz,GetByteLoop
dec b
jr nz,GetByteLoop ; delay loop
or a ; clear carry flag
ret
; subroutine to flush the receive buffer
; destroys A
Flush: ld a,80h
call GetByte
jr c,Flush
ret
;Get one byte from the serial port if available.
;Returns with byte in A reg with carry flag set, if carry flag clear means no character available
get_chr: or a ;clear carry flag
in a,(3) ;get status
and 002h ;check RxRDY bit
ret z ;not ready, quit
in a,(2) ;get char
scf ;set carry flag we got a char
ret
ptr: dfw 0
blkno: dfb 0
err: dfb "Up Err!",CR,LF,0
good: dfb "Up Ok!",CR,LF,0
msg: dfb CR,LF,"X/CSUM <Esc> to q",CR,LF,0
Been researching how to use DRAM in a homebuilt computer. For interests sake of course, since SRAM is so readily accessable, and much easier to use. DRAM is challenging, considering building a Z80 to try it.
Up until now I was using raw serial output for console, but I think this is not the correct way.
write_char:
in a,(3)
and 001h
jp z, write_char
ld a,b
out (2),a
ret
now this works, but it does not work for cpm emulator yaze-ag. I suspect this is because I should be using the syscall to output to the console.
write_char: push de ; preserve register values
push bc
ld c,2 ; function 2
ld e,a ; char to write
call 5 ; call bios / syscall
pop bc ; restore register values
pop de
ret
I have not coded Conway’s life in many years – I thought it would be fun to try on the Z80. First I implemented it in C on the Raspberry Pi. It uses an array to both keep track of prior generations (to determine if the pattern is still evolving) and the same array to figure out the neighbour count.
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
unsigned char *grid;
const int rows=48, cols=160, maxt=3;
int same;
void* calc_grid(int *t) {
int i, j, q;
for (i=rows+rows-*t*rows/maxt-1; i>=rows+rows-(*t+1)*rows/maxt; i--) {
for (j=cols+cols-1; j>=cols; j--) {
if ( (grid[(i-rows)*cols+j-cols] & 64) ) { /* for each cell that is alive, add 1 to all the neighbours in every (8) adjacent cell */
grid[((i-1) % rows)*cols + (j-1) % cols] += 1;
grid[((i-1) % rows)*cols + (j ) % cols] += 1;
grid[((i-1) % rows)*cols + (j+1) % cols] += 1;
grid[((i ) % rows)*cols + (j-1) % cols] += 1;
grid[((i ) % rows)*cols + (j+1) % cols] += 1;
grid[((i+1) % rows)*cols + (j-1) % cols] += 1;
grid[((i+1) % rows)*cols + (j ) % cols] += 1;
grid[((i+1) % rows)*cols + (j+1) % cols] += 1;
}
}
}
}
void* shift_grid(int *t) {
int i, j;
for (i=*t*rows/maxt; i<(*t+1)*rows/maxt; i++) {
for (j=0; j<cols; j++) { /* for every cell take the 7th bit and the lower 4 bits (total) - empty cell =3 - live cell = 64+2 or 64+3 - then mark the 8th bit as live for next gen*/
if ((grid[i*cols+j] & 79) == 3 || (grid[i*cols+j] & 79) == 66 || (grid[i*cols+j] & 79) == 67) grid[i*cols+j] |= 128;
grid[i*cols+j] = (grid[i*cols+j] >> 1) & 240; /* shift to the right one bit, and keep the top 4 bits 128+64+32+16 to see what was going on in prior gens */
if ( same == 1 && ((grid[i*cols+j] & 64)>>2) != (grid[i*cols+j] & 16) ) /* compare the 7th bit to the 5th bit- if those are not the same, then the pattern is changing */
same=0;
}
}
}
int main() {
time_t qt;
srand((unsigned) time(&qt));
pthread_t thr[maxt];
int c, x, y, i, j, gen, t, rc;
grid = malloc(rows*cols*sizeof(char));
for ( c=0; c<1000; c++) {
// printf("Try: %d\n", c);
for (i=0; i<rows; i++)
for (j=0; j<cols; j++)
grid[i*cols+j] = 64 * (rand() % 2); /* initialize the array with random numbers in the 7th bit */
for (gen=0; gen<20000; gen++) {
for (t=0; t<maxt; t++) {
calc_grid(&t);
}
same=1;
for (t=0; t<maxt; t++) {
shift_grid(&t);
}
//if (same==1) break;
printf("Gen: %d\n", gen );
for (i=0; i<rows; i++) {
for (j=0; j<cols; j++)
putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
putc('\n', stdout);
}
getc(stdin);
}
}
/* print out survivor */
printf("Gen: %d\n", gen );
for (i=0; i<rows; i++) {
for (j=0; j<cols; j++)
putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
putc('\n', stdout);
}
free(grid);
}
I’ve made it very similar on the z80 in terms of the algorithm that is implemented. The grid it uses is smaller.
org 0100h
; to do a given cell, we need to do IX-1, IX+1, IX-81, IX-80, IX-79, IX+79, IX+80, IX+81
; board is 78x24 with an extra space all around so 80x26 - 2080 elements
ld a,0ffh ; do at most 255 generations
top: push af
ld hl,c_home
call my_write_string
call print_board
call calc_n
call calc_g
pop af
dec a
jr nz,top
ld hl,c_home
call my_write_string
call print_board
ret
calc_g: ; calculate the next generation
ld de, board
calc_g_loop:
ld b, 080h
ld a,(de)
ld c,a
and b
jr z,no_128
ld (de),a
jr end_calc_g
no_128: ; continue with calcs
ld a,c
ld b,79
and b
ld b,3
cp b
jr z, set_128
ld b,66
cp b
jr z, set_128
ld b,67
cp b
jr z, set_128
ld a,c
jr shift_mask
set_128:
ld a,c
ld b,128
or b
shift_mask:
ld b,224
and b
srl a
ld (de), a
end_calc_g:
inc de
ld hl,b_done
sbc hl,de
ret z
jr calc_g_loop
calc_n:
ld ix, board
ld de, board
ld c,040h
ld b,080h
calc_n_loop:
ld a,(ix+0)
and b
jr nz,calc_x ; found a 128 - skip calc
ld a,(ix+0)
and c
jr z,calc_x ; only increment if its currently alive
inc (ix-1)
inc (ix+1)
inc (ix-79)
inc (ix-80)
inc (ix-81)
inc (ix+79)
inc (ix+80)
inc (ix+81)
calc_x: inc ix
inc de
ld hl,b_done
sbc hl,de
ret z
jr calc_n_loop
; print_board: routine to print out board - uses a, bc, de, hl
print_board:
ld de, board
print_nl:
ld c, 00h
print_loop:
ld a,(de)
ld b,040h
and b
jr z,space_char
ld b,'@'
jr end_char
space_char:
ld b,' '
end_char:
call my_write_char
inc de
inc c
ld a,80
sub c
jr nz,print_loop
ld hl,crlf
call my_write_string
ld hl,b_done
sbc hl,de
ret z
jr print_nl
; puts a single char (byte value) on serial output
; call with char to send in B register; also uses A register
my_write_char:
in a,(3)
and 001h
jp z, my_write_char
ld a,b
out (2),a
ret
my_write_string:
in a,(3)
and 001h
jr z,my_write_string
ld a,(hl)
and a
ret z
out (2),a
inc hl
jr my_write_string
crlf: defm 0dh,0ah,0h
c_home: defm 01bh,"[H",0h
b_junk: defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
board: defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,64,00,64,64,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
b_done: defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
end
I’ve been trying to learn z80 assembler, and one of the programs that I typically do for that is writing a version of the Sieve of Eratosthenes. My version runs under CP/M on my CPUVILLE z80 computer.
; this program implements the sieve of eratosthenes on the z80
monitor: equ 046fh
cpm: equ 0fa00h
data_start: equ 1000h
data_end: equ 3000h
current_location: equ 0x3000 ;word variable in RAM
line_count: equ 0x3002 ;byte variable in RAM
byte_count: equ 0x3003 ;byte variable in RAM
value_pointer: equ 0x3004 ;word variable in RAM
current_value: equ 0x3006 ;word variable in RAM
buffer: equ 0x3008 ;buffer in RAM -- up to stack area
var_c: equ 0ffeh
org 0100h ; set origin of execution
ld de,data_start
ld a,00h
zero_loop:
ld (de),a
inc de
ld hl,data_end
sbc hl,de
jp nz,zero_loop
ld de,02 ; start sieve at c=2
main_sieve_loop: ; we are using de for this loop
ld (var_c),de ; store in ram too
ld h,d ; ld hl,de
ld l,e ; use hl to figure out memory location
srl h ; since we can store 8 bits in each memory loc
rr l ; we need to shift left (16 bit) 3 times
srl h ; https://chilliant.com/z80shift.html
rr l ; 2
srl h
rr l ; 3
ld a,10h
add a,h ; add 1000h to hl to get actual location
ld h,a ; here is the data in (hl)
ld a,00000111b
and e ; last 3 bits of de into a - will need srl a times
ld b,(hl) ; load the data into b
cp 0b ; compare a to 0
shift_a_times_1:
jp z,done_shift_1
srl b
dec a
jp shift_a_times_1
done_shift_1: ; a is garbage, b has the bit in the lsb position
ld a,00000001b
and b ; Z flag will be correct here if zero
ld (var_c),de ; store de in memory
jp nz,end_main_sieve_loop ; non zero - just inc loop and get out
; we found a zero, now need to loop and mark composites
ld h,d
ld l,e ; ld hl,de
ld b,d
ld c,e
start_composite_loop: ; de stores the value in this loop
add hl,bc ; start at 2 * de to mark composites
jp c,end_main_sieve_loop ; get out if overflow 16 bit
ld d,h
ld e,l ; ld de,hl
srl h
rr l
srl h
rr l
srl h
rr l
ld a,10h
add a,h
ld h,a ; here is the data in (hl)
ld a,00000111b
and e ; a has which bit to set
ld b,00000001b ; start with lsb
cp 0b ; is a zero?
shift_a_times_2:
jp z,done_shift_2
sla b
dec a
jp shift_a_times_2
done_shift_2:
ld a,(hl) ; retreive what is in memory
or b ; mark the bit
ld (hl),a ; write back to memory
ld h,d
ld l,e ; put hl back to where we were
ld bc,(var_c) ; put step into bc
jp start_composite_loop
end_main_sieve_loop:
ld de,(var_c)
inc de
jp nz,main_sieve_loop
ld hl,data_start
call memory_dump
ld hl,2f00h
call memory_dump
ret
Some time back I built a CPUVILLE Z80 single board computer. I used a USB serial cable to connect it to one of my Raspberry Pi computers. The issue that I faced is that my assembler skills are pretty sus at this point, and I would need to go to the computer to hit the reset switch. I made a simple circuit to allow using a GPIO pin on the Pi to reset the computer.