Monday 15 December 2014

Z80 Size Programming Challenge #2

Last week I issued the second Z80 programming challenge:

Something slightly more complex this time. Write the shortest code to mirror the entire Sinclair Spectrum screen (256×192 pixels) left to right including the colours / attributes. The deadline is Monday 15th, midday (GMT).

Target: under 50 bytes.

  1. Your program shouldn't rely on the initial contents of registers.
  2. No RAM/ROM other than the screen memory should be written to.
  3. Programs must return. The RET instruction is included in the size.
  4. So everyone has a fair chance comment with the code size not code.
  5. There are no prizes, just the chance to show off your coding skills.

Final Results

We stepped up the difficultly for the second challenge so congratulations to everyone who entered. Introspec ZX and Tim Webber discovered the shortest solutions. Here are the final results:

CoderSize
Introspec Zx34
Tim Webber34
John Metcalf34
Paul Rhodes35
Simon Brattel35
Jim Bagley36
Steve Wetherill38
John Young49
Chris Walsh49
Dariusz EM50

Winning Entries

Introspec submitted the first 34 byte solution using a couple of neat tricks. Note the use of CP L to check which side of the screen it's working on and the byte saved by setting B to #58:

                ld hl,16384+6912

screenflip:     ld d,h
                ld a,l
                xor #1F
                ld e,a
                cp l
                jr nc,noflip

                ld a,(de)
                ld c,(hl)
                ld (hl),a
                ld a,c
                ld (de),a

noflip:         ld b,#58
                ld a,h
                cp b
                jr nc,skipattr

byteflip:       rlc (hl)
                rra
                djnz byteflip
                ld (hl),a

skipattr:       dec hl
                bit 6,h
                jr nz,screenflip
                ret

Tim Webber's solution saves a series of addresses on the stack to be used later:

start:          ld hl,23296
loop1:          dec hl
                bit 6, h
                ret z
                ld a, 87
                cp h
                jr c, noinv
                ld b,8
doinv:          rl (hl)
                rra
                djnz doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Although I didn't enter I also found a couple of 34 byte solutions. The first mirrors two bytes in the inner loop:

                ld hl,16384
mirror:         ld d,h
                ld a,l
                xor 31
                ld e,a
                ld a,h
                cp 91
                ret z
                cp 88
                ld a,(de)
                ld c,a
                jr nc,attrib
                ld b,8
                rrca
mirrorbits:     rl (hl)
                rra
                djnz mirrorbits
                db 1 ; skip the next two instructions
attrib:         ld a,(hl)
                ld (hl),c
                ld (de),a
                inc l
                inc hl
                jr mirror

My second has two separate loops. The first loop mirrors bytes, the second mirrors the screen:

                ld hl,22527
mir:            ld a,128
mirrorbits:     rl (hl)
                rra
                jr nc,mirrorbits
                ld (hl),a
                dec hl
                bit 6,h
                jr nz,mir
mirror:         inc hl
                ld d,h
                ld a,l
                xor 31
                ld e,a
                ld a,h
                cp 91
                ret z
                ld a,(de)
                ld c,a
                ld a,(hl)
                ld (hl),c
                ld (de),a
                inc l
                jr mirror

Is 34 Bytes Optimal?

Definitely not! After the deadline a solution was discovered that combines code from Tim Webber and Introspec's entries to mirror the screen in 33 bytes:

start:          ld hl,23296 ; Tim Webber/Introspec
loop1:          dec hl
                bit 6, h
                ret z
                ld a, h
                ld b,88
                cp b
                jr nc, noinv
doinv:          rlc (hl)
                rra
                djnz doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Another 33 byte solution combines the code from Tim Webber and Simon Brattel's entries:

start:          ld hl,23296 ; Tim Webber/Simon Brattel
loop1:          dec hl
                ld a,h
                cp 88
                jr nc, noinv
                and 64
                ret z
                add a,a
doinv:          rlc (hl)
                rra
                jr nc,doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Entries will be available shortly on John Young's website. Thanks to everyone who entered for making the contest a success :-)

Monday 8 December 2014

Z80 Size Programming Challenge #1

A few days ago I issued a Z80 programming challenge for the ZX Spectrum:

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 skill.

Final Results

Congratulations to all who entered, especially Allan Høiberg and Introspec Zx who both discovered a 15-byte solution. The final results are as follows:

CoderSize
Allan Høiberg15
Introspec Zx15
Jim Bagley16
Paul Rhodes16
Krystian Włosek16
Tim Webber16
Steve Wetherill16
John Young16
Simon Brattel16
John Metcalf16
Dariusz EM17
Chris Walsh23

Winning Entries

Allan was the first to discover a 15-byte solution:

                LD BC,22272
                LD A,85
LoopB:          BIT 6,B
                RET Z
LoopC:          DEC C
                LD (BC),A
                JR NZ,LoopC
                CPL
                DJNZ loopB

Introspec found a 15-byte solution with only one loop:

                ld hl,16384+6143
filloop5:       ld a,h
                rra
                sbc a,a
                xor %01010101
                ld (hl),a
                dec hl
                bit 6,h
                jr nz,filloop5
                ret

My own attempts all fell short at 16 bytes:

                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

Entries are archived on John Young's website. Thanks to everyone who entered or otherwise supported the challenge. :-)

Saturday 15 March 2014

Plotting the Mandelbrot Set on the ZX Spectrum

ZX Spectrum MandelbrotZX Spectrum Mandelbrot

The Mandelbrot set is a fractal which iterates the equation zn+1 = zn² + c in the complex plane and plots which points tend to infinity. Plotting the set with Sinclair BASIC takes over 24 hours so I was curious how much faster it would be in assembly.

It turns out if we use fast 16-bit fixed-point arithmetic we can plot the Mandelbrot in about 5 minutes. To minimise multiplications each iteration is calculated as:

rn+1 = ( rn + in ) × ( rn - in ) + x

in+1 = 2 × in × rn + y

The following test is used to detect points which tend to infinity:

|in| + |rn| ≥ 2 × √ 2.
  org 60000
  ld de,255*256+191
XLOOP:
  push de
  ld hl,-180   ; x-coordinate
  ld e,d
  call SCALE
  ld (XPOS),bc
  pop de
YLOOP:
  push de
  ld hl,-96    ; y-coordinate
  call SCALE
  ld (YPOS),bc
  ld hl,0
  ld (IMAG),hl
  ld (REAL),hl
  ld b,15      ; iterations
ITER:
  push bc
  ld bc,(IMAG)
  ld hl,(REAL)
  or a
  sbc hl,bc
  ld d,h
  ld e,l
  add hl,bc
  add hl,bc
  call FIXMUL
  ld de,(XPOS)
  add hl,de
  ld de,(REAL)
  ld (REAL),hl
  ld hl,(IMAG)
  call FIXMUL
  rla
  adc hl,hl
  ld de,(YPOS)
  add hl,de
  ld (IMAG),hl
  call ABSVAL
  ex de,hl
  ld hl,(REAL)
  call ABSVAL
  add hl,de
  ld a,h
  cp 46        ; 46 ≅ 2 × √ 2 << 4
  pop bc
  jr nc,ESCAPE
  djnz ITER
  pop de
  call PLOT
  db 254       ; trick to skip next instruction
ESCAPE:
  pop de
  dec e
  jr nz,YLOOP
  dec d
  jr nz,XLOOP
  ret

FIXMUL:        ; hl = hl × de >> 24
  call MULT16BY16
  ld a,b
  ld b,4
FMSHIFT:
  rla
  adc hl,hl
  djnz FMSHIFT 
  ret

SCALE:         ; bc = (hl + e) × zoom
  ld d,0
  add hl,de
  ld de,48     ; zoom

MULT16BY16:    ; hl:bc (signed 32 bit) = hl × de
  xor a
  call ABSVAL
  ex de,hl
  call ABSVAL
  push af
  ld c,h
  ld a,l
  call MULT8BY16
  ld b,a
  ld a,c
  ld c,h
  push bc
  ld c,l
  call MULT8BY16
  pop de
  add hl,de
  adc a,b
  ld b,l
  ld l,h
  ld h,a
  pop af
  rra
  ret nc
  ex de,hl
  xor a
  ld h,a
  ld l,a
  sbc hl,bc
  ld b,h
  ld c,l
  ld h,a
  ld l,a
  sbc hl,de
  ret

MULT8BY16:     ; returns a:hl (24 bit) = a × de
  ld hl,0
  ld b,8
M816LOOP:
  add hl,hl
  rla
  jr nc,M816SKIP
  add hl,de
  adc a,0
M816SKIP:
  djnz M816LOOP
  ret

PLOT:          ; plot d = x-axis, e = y-axis
  ld a,7
  and d
  ld b,a
  inc b
  ld a,e
  rra
  scf
  rra
  or a
  rra
  ld l,a
  xor e
  and 248
  xor e
  ld h,a
  ld a,d
  xor l
  and 7
  xor d
  rrca
  rrca
  rrca
  ld l,a
  ld a,1
PLOTBIT:
  rrca
  djnz PLOTBIT
  or (hl)
  ld (hl),a
  ret

ABSVAL:        ; returns hl = |hl| and increments
  bit 7,h      ; a if the sign bit changed
  ret z
  ld b,h
  ld c,l
  ld hl,0
  or a
  sbc hl,bc
  inc a
  ret

XPOS:dw 0
YPOS:dw 0
REAL:dw 0
IMAG:dw 0

Sunday 9 February 2014

The Spring 2014 Core War Tournament

In May 1984 A K Dewdney introduced Core War, a game played between two or more computer programs in the memory of a virtual computer. The aim of the game is to disable all opponents and survive the longest. A variety of strategies have evolved for Core War, each with their own strengths and weaknesses.

To celebrate the 30th anniversary in May, The Spring Core War Tournament will be held at The Centre for Computing History in Cambridge UK. The Centre was established to tell the story of the Information Age and presents an interactive collection of computers and artifacts.

Entries can be up to 25 instructions and will compete in three different core sizes, 800 (tiny), 8000 (standard) and 55440 (large). A program's final score will be calculated as follows:

    final_score = 2 × standard_score + tiny_score + large_score

The program with the highest final score will be awarded the first prize, $50 and a signed copy of The Armchair Universe by A K Dewdney. The top program in each core size will be awarded a signed copy of Life As It Could Be by Thure Etzold, a technothriller which explores the possibility of programs escaping the confines of the Core War virtual computer.

Entries can be sent via email or delivered to The Centre on the day of the tournament (date tbc). Players can submit up to two entries. All entries will be published at the end of the tournament.

The provisional deadline is 01 May 2014. Updates will be posted on news:rec.games.corewar, http://corewar.eu, #corewars on irc.freenode.net and on twitter using the hashtag #corewar. Good Luck!

Technical Details:

Players may enter up to two programs. Programs face each other in a one-on-one round robin, no p-space, no self-fights, no read/write limits. Entries must be your own work. Extended ICWS'94 Draft Redcode applies with the following settings:

  • pmars -s 800 -p 800 -c 8000 -l 25 -d 25
  • pmars -s 8000 -p 8000 -c 80000 -l 25 -d 100
  • pmars -s 55440 -p 10000 -c 500000 -l 25 -d 200

Entries may use the run-time variables (CORESIZE, MAXPROCESSES, etc) to tailor the program for each core size, but the program must still behave essentially the same. Some allowed examples include:

  • tweaking the steps / constants
  • adding an extra bombing line to the core clear
  • including an extra SPL/MOV pair to a paper

Completely changing the program's behaviour or swapping / adding extra components for each core size is not allowed.

Further Details:

More information about Core War can be found at:

Software is available from:

Core War can be played online at:

For help, advice and updates see:

The Centre for Computing History has a website at:

Friday 3 January 2014

Fast Z80 Bit Reversal

For years I've been using the following simple code to reverse the bits in the A register by rotating the bits left out of one register and right into another:

; reverse bits in A
; 8 bytes / 206 cycles

  ld b,8
  ld l,a
REVLOOP:
  rl l
  rra
  djnz REVLOOP

Recently I wondered if it's possible to save a few cycles. It turns out the bits are at most 3 rotations away from their position in the reverse:

76543210
⇐1⇐33⇒1⇒⇐1⇐33⇒1⇒
01234567

With this in mind I devised a bit-twiddling hack to reverse the bits in about a third of the time using only 6 rotates and a bit of logic to recombine the rotated bits. Here's the code, which no doubt has been done many times before:

; reverse bits in A
; 17 bytes / 66 cycles

  ld l,a    ; a = 76543210
  rlca
  rlca      ; a = 54321076
  xor l
  and 0xAA
  xor l     ; a = 56341270
  ld l,a
  rlca
  rlca
  rlca      ; a = 41270563
  rrc l     ; l = 05634127
  xor l
  and 0x66
  xor l     ; a = 01234567