Z80 Programming Challenges

 

Challenge 00000001

Something simple for the first challenge. Write the shortest code to fill the screen with a chequerboard pattern of 1 pixel squares. No RAM/ROM other than the 6144 byte bitmap screen memory should be written to.

Target: under 25 bytes.

1) Your program shouldn't rely on the initial contents of registers.
2) Programs must return. The RET instruction is included in the size.
3) So everyone has a fair chance comment with the code size not code.
4) There are no prizes, just the chance to show off your coding skills

Example screen:

 

Results
Allan Høiberg 15 Bytes

My untested 15-byte attempt:

        

LD BC,22272 ; (22528-256) B=87, C=0
LD A,85 ; 10101010
LoopB:
Bit 6,B ; Z now set if bit is zero, meaning we have left the screen
RET Z ; if bit 6 was zero, return
LoopC:
DEC C ; On first iteration BC becomes 22527. Z flag set after 256
loops on C=0
LD (BC),A ; Z flag unaffected by this
JR NZ,LoopC ; Again if C wasn’t zero
CPL ; Invert bit pattern in A
DJNZ loopB ; Decrement B and go on until zero - which is never reached

If this works, we have a 13-byte ROM-overwriter too, by adding a RET at the
end and deleting the BIT and RET Z instructions.

 

My first ugly 17-byte attempt, in case the above doesn't actually work:

LD HL,22527 ; H=87, L=255
LD A,85 ; 10101010
LD D,A ; Number of times to fill 256 bytes – overwriting ROM; only 24
needed
LD B,0
Loop:
LD (HL),A
DEC HL
DJNZ Loop
XOR L
DEC D
JR NZ,Loop
RET

Introspec Zx 15 Bytes
 ld hl,16384+6143 ; 15 bytes
filloop5: ld a,h
rra
sbc a,a
xor %01010101
ld (hl),a
dec hl
bit 6,h
jr nz,filloop5
ret
Jim Bagley 16 Bytes

;15 bytes attr corruption
org $8000
start15 ld hl,$5855
ld a,l
lp15 dec l
ld (hl),a
jr nz,lp15
cpl
dec h
bit 6,h
jr nz,lp15
ret

This doesn't affect attribute RAM, but does write over ROM, it's the same as the 16 byte version but doesn't do the two byte bit 6,h to stop it overwriting ROM.

;14 bytes no corruption, but writes to rom
org $8000
start14 ld hl,$5700
ld a,$55
lp14 dec l
ld (hl),a
jr nz,lp14
cpl
dec h
jr nz,lp14
ret

This writes to 85 bytes of attribute RAM and writes to ROM from $3fff to $0, sets L to $55 so that it can save a byte with ld a,l, to get the right bit pattern into A

;13 bytes attr corruption and writes to rom
org $8000
start13 ld hl,$5855
ld a,l
lp13 dec l
ld (hl),a
jr nz,lp13
cpl
dec h
jr nz,lp13
ret

Here's where I start thinking really outside the box, and pushing the limits on what can be accepted by adhering to all the rules of the challenge, but requiring external help from a headerless file on tape that has a copy of what you want the final display to look like.
What I like about this solution is the fact that it doesn't take up any other RAM, and does exactly what was required. :D

;13 bytes no corruption and no rom writes, but requires a 6144 byte headerless file of what should be in $4000 to $5800
;this example also technically follows all the rules!
org $8000
start13 ld ix,$4000
ld de,6144
ld a,$ff
scf
jp $0556

Here's an even shorter version than the one above, but requires the 6144 bytes of what you want the screen to look like, stored in RAM elsewhere ie at $9000 for this example.

;12 bytes no corruption and no rom writes, but requires 6144 byte copy of what needs to be on screen elsewhere in ram
;this example also technically follows all the rules!
org $8000
start12 ld hl,$9000
ld de,$4000
ld bc,6144
ldir
ret

Now here's a 2 byte solution, I say two byte, in the fact that the only ram that is used is the screen ram two bytes of instructions, and it does return, and follow the rules.
It's also something like what I used back in the day too, when code space was at a minimum, you could use the screen space for small bits of code, that would be hidden with attributes. :D
The code would be overwritten, so it's technically like it's free RAM, the only down side is that the 2 bytes are in the attributes RAM, and it follows the rules, as the code itself doesn't write to outside $4000-$57ff
Again this is only a valid way of doing it, if you look outside the box of the rules, yet keeping inside them.

;2 bytes no corruption ( as attr bytes aren't written to by code ) and no rom writing
;this is org'd at 22501 which overwrites itself during execution but leaves last two bytes of code untouched in code in the attrs
;using the screen for code sections to load was used back in the day.
;it is more than 2 bytes yes, but only 2 bytes of code are taken up after the screen is created. :D
;this example technically follows all the rules!
;you can test this in ZXSpin, reset machine, and type
;10 pause 0:let l=use 22501:pause 0
;then type this into the built in assembler, and assemble it to compile at

org $5800-27 ;22501
start2 ld hl,$4000
ld de,$4001
ld b,e
ld c,l
ld (hl),$55
ldir
ld b,e
ld (hl),$aa
ldir
ld hl,$4000
ld de,$4200
ld bc,$1600
ldir
ret

Paul Rhodes 16 Bytes

16 bytes:

LD HL, 5800H
LD B, L
LD A, 55H
LOOP:
DEC HL
BIT 6,H
RET Z
LD (HL),A
DJNZ LOOP
CPL
JR LOOP

A peculiar approach in 17 bytes using only HL:

LD HL, 5800H
LOOP:
DEC HL
BIT 6,H
RETZ
BIT 0,H
LD (HL), 55H
JR Z LOOP
LD (HL), AAH (or, RRC (HL) !)
JR LOOP

Krystian Włosek 16 Bytes  
Tim Webber 16 Bytes

16 bytes - no attr/ROM overwrite.

ld a, AAh 62, 170
ld b, 18h 6, 24
ld hl, 4000h 33, 0, 64
L1 ld (hl), a 119
inc l 44
jr nz, L1 32, 252
cpl 47
inc h 36
djnz L1 16, 248
ret 201

Steve Wetherill 16 Bytes
ld hl,$5700
ld a,85
loop:
dec l
ld (hl),a
jr nz,loop
rlca
dec h
bit 6,h
jr nz,loop
ret
John Young 16 Bytes
; compile with pasmo
start:
ld hl, 22272
ld a, %01010101
loop:
ld (hl), a
dec l
jr nz, loop
cpl
dec h
bit 6, h
jr nz, loop
ret
Simon Brattel 16 Bytes

A set of reasonable 16-byte valid entries, a 13-byte one that writes to the ROM and a repulsive
12-byte version that messes some attributes up as well.

Cheers, Simon.

; Only one equate, to set the checkerboard pattern you prefer. 55 or AA

Pattern equ #55 ; Alternate bits

; These 16-byte versions do not write to anything but the screen.

; 16-byte straightforward version.
; I think there are 384 variations possible on this one
; You can use DE or HL as the pointer
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can fill pages in either direction.

Fill_Clean ld a,Pattern ; Pattern 55 or AA as required
ld b,#18 ; Page repeat count

ld hl,#5700 ; Can start in the first or last page, this is last

Lp1 ld (hl),a ; Fill this page
inc l ;
jr nz,Lp1 ;

cpl ; Change pattern, invert or rotate

dec h ; Move to next page

djnz Lp1 ; Page Loop

ret ; Done

; 16-byte counter version.
; I think there are 196 variations possible on this basic theme...
; You can use RLC or RRC
; You can change the instruction order of the rlc/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can fill pages in either direction.

Fill_16_Cnt ld bc,#1800 + Pattern ; Counter and pattern

ld hl,#5700 ; Start in last page

LpC ld (hl),c ; Fill this page
inc l ;
jr nz,LpC ;

rlc c ; Change pattern

dec h ; Change page

djnz LpC ; Loop
ret ; Done

; 16-byte bit-test version.
; I think there are 216 variations possible on this one
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can't fill pages in either direction. (No bit-test for ending going up)

Fill_16_BitTest ld a,Pattern ; Pattern 55 or AA as required

ld hl,#5700 ; Start in last page

LpBT ld (hl),a ; Fill this page
inc l ;
jr nz,LpBT ;

cpl ; Change pattern, could be invert or rotate

dec h ; Change page

bit 6,h ; See if we're done (here this checks h >= #40)
jr nz,LpBT ; Not yet

ret ; Done

 

; This 13-byte version writes to the ROM.

 

; 13-byte version. This also writes to the ROM.
; I think there are 18 variations possible on this one
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl and the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can't fill pages in either direction, only downwards.

Fill_ROM_Overwrite ld a,Pattern ; Pattern 55 or AA as required

ld bc,#5700 ; Start in last page

LpRO1 ld (bc),a ; Fill this page
inc c ;
jr nz,LpRO1 ;

cpl ; Change pattern, invert or rotate

djnz LpRO1 ; Page Loop - this also changes the page (B--)

ret ; Done

 

; This utterly foul 12-byte version writes to the ROM and some of the attributes.

 

; 12-byte version. This writes to the ROM and some of the attributes, urgh ;)
; 9 variations? CPL or RLCA or RRCA, fill dirn, instruction order
;
; This repulsive code jumps back into the middle of the ld bc,[16-bit constant] instruction and
; uses the data-bytes as instructions. Shorter, but we can no longer select the start address
; to be on a page-boundary, so we will overwrite some attribute data... pick the CPL/RRCA/RLCA
; to taste.
;

Fill_ROM_ATTR ld a,Pattern ; Pattern 55 or AA as required

ld bc,#582F ; Start after last page + CPL instruction
LpRA_CPL equ *-2 ; Point at the CPL

LpRA ld (bc),a ; Fill this page
inc c ;
jr nz,LpRA ;

djnz LpRA_CPL ; Page Loop - this also changes the page (B--)

ret ; Done

; I suspect there might be shorter versions that use routines in the ROM, but calling anything in there would
; use the stack and that's writing to memory, hence illegal. Glad about that, I never looked at the ROM in
; the 80's and I don't want to start now ;)

 

 

This is the same lot again as a Zeus assembler file ready for emulation.

 

 

; Start of source file

emulate_spectrum "48k" ; Tell Zeus what to emulate

; Change this to suit your system - I note that Vista doesn't like changes to the root.

output_szx "c:\temp\dbx.szx",0,Start ; Generate code to test

; Select the pattern you prefer. 55 or AA

Pattern equ #55 ; Alternate bits

; Put the code somewhere out of the way

org $6000 ; Somewhere safe

; Start by clearing the screen

Start di ; Set us up
ld sp,#0 ;

call SetupScreen ; Clear it

call Fill_16_Cnt ; Call one of the routines

Stop jp Stop ; Hang about

; 16-byte straightforward version.
; I think there are 384 variations possible on this one
; You can use DE or HL as the pointer
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can fill pages in either direction.

CodeStart = *

Fill_Clean ld a,Pattern ; Pattern 55 or AA as required
ld b,#18 ; Repeat count

ld hl,#5700 ; Can start in the first or last page

Lp1 ld (hl),a ; Fill this page
inc l ;
jr nz,Lp1 ;

cpl ; Change pattern, invert or rotate

dec h ; Move to next page

djnz Lp1 ; Page Loop

ret ; Done

zeusprint "Fill_Clean size = ",*-CodeStart

; 16-byte counter version.
; I think there are 196 variations possible on this basic theme...
; You can use RLC or RRC
; You can change the instruction order of the rlc/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can fill pages in either direction.

CodeStart = *

Fill_16_Cnt ld bc,#1800 + Pattern ; Counter and pattern

ld hl,#5700 ; Start in last page

LpC ld (hl),c ; Fill this page
inc l ;
jr nz,LpC ;

rlc c ; Change pattern

dec h ; Change page

djnz LpC ; Loop
ret ; Done

zeusprint "Fill_16_Cnt size = ",*-CodeStart

; 16-byte bit-test version.
; I think there are 216 variations possible on this one
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl/dec and put them either side of the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can't fill pages in either direction. (No bit-test for ending going up)

CodeStart = *

Fill_16_BitTest ld a,Pattern ; Pattern 55 or AA as required

ld hl,#5700 ; Start in last page

LpBT ld (hl),a ; Fill this page
inc l ;
jr nz,LpBT ;

cpl ; Change pattern, could be invert or rotate

dec h ; Change page

bit 6,h ; See if we're done (here this checks h >= #40)
jr nz,LpBT ; Not yet

ret ; Done

zeusprint "Fill_16_BitTest size = ",*-CodeStart

; 13-byte version. This also writes to the ROM.
; I think there are 18 variations possible on this one
; You can use CPL, RLCA or RRCA
; You can change the instruction order of the cpl and the loop.
; You can fill each page in either direction (move the LD to after the "dec l" if moving down)
; You can't fill pages in either direction, only downwards.

CodeStart = *

Fill_ROM_Overwrite ld a,Pattern ; Pattern 55 or AA as required

ld bc,#5700 ; Start in last page

LpRO1 ld (bc),a ; Fill this page
inc c ;
jr nz,LpRO1 ;

cpl ; Change pattern, invert or rotate

djnz LpRO1 ; Page Loop - this also changes the page (B--)

ret ; Done

zeusprint "Fill_ROM_Overwrite size = ",*-CodeStart

; 12-byte version. This writes to the ROM and some of the attributes, urgh ;)
; 9 variations? CPL or RLCA or RRCA, fill dirn, instruction order
;
; This repulsive code jumps back into the middle of the ld bc,[16-bit constant] instruction and
; uses the data-bytes as instructions. Shorter, but we can no longer select the start address
; to be on a page-boundary, so we will overwrite some attribute data... pick the CPL/RRCA/RLCA
; to taste.
;

CodeStart = *

Fill_ROM_ATTR ld a,Pattern ; Pattern 55 or AA as required

ld bc,#582F ; Start after last page + CPL instruction
LpRA_CPL equ *-2 ; Point at the CPL

LpRA ld (bc),a ; Fill this page
inc c ;
jr nz,LpRA ;

djnz LpRA_CPL ; Page Loop - this also changes the page (B--)

ret ; Done

zeusprint "Fill_ROM_ATTR size = ",*-CodeStart

; Just clear it so I can be sure the code worked

SetupScreen ld hl,#4000 ; Graphics to zero
ld de,#4001 ;
ld bc,#1800 ;
ld (hl),#00 ;
ldir ;

ld (hl),#07 ; B/W attribute
ld bc,#2ff ;
ldir ;

ret ; Done

John Metcalf 16 Bytes


; -------------------------
; 16-bytes using hl / a
; -------------------------

ld hl,22528-256
ld a,170
fill:
dec l
ld (hl),a
jr nz,fill
cpl
dec h
bit 6,h
jr nz,fill
ret

; -------------------------
; 16-bytes using hl / a / b
; -------------------------

ld hl,16384
ld a,170
ld b,24
fill:
ld (hl),a
inc l
jr nz,fill
rrca
inc h
djnz fill
ret

; -------------------------
; 16-bytes using hl / bc
; -------------------------

ld hl,22528-256
ld bc,24*256+170
fill:
dec l
ld (hl),c
jr nz,fill
rrc c
dec h
djnz fill
ret

; -------------------------
; 13-bytes ROM overwriting
; -------------------------

ld bc,22528-256
ld a,170
fill:
dec c
ld (bc),a
jr nz,fill
cpl
djnz fill
ret

Dariusz EM 17 Bytes

My version using 17 bytes:

org 32768
ld hl, 16384
ld b, 24
ld a, 170
loop1:
ld e, l
loop2:
ld (hl), a
inc hl
dec e
jr nz, loop2
rlca
djnz loop1
ret

Chris Walsh 23 Bytes
org 32768
ld hl,16384
ld a,170
ld b,l
ld d,3
l0
ld c,8
l1
ld (hl),a
inc hl
djnz l1
rrca
dec c
jr nz, l1
dec d
jr nz, l0
ret