A few days ago I issued the third Z80 programming challenge for the ZX Spectrum:
Friday, 20 March 2015
Monday, 15 December 2014
Last week I issued the second Z80 programming challenge:
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:
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
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
A few days ago I issued a Z80 programming challenge for the ZX Spectrum:
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:
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
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
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.
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.
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
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:
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
Monday, 11 November 2013
The Centre for Computing History is a short walk from Cambridge city centre and is home to a sizeable collection of computers. The museum actively encourages visitors to sit down, try out a few games and even have a go at BASIC programming.
The museum's collection ranges from mechanical calculators and mainframes to home computers and games consoles. Most of the home computers and consoles are switched on and running classic games.
If you're interested in the history of computing (particularly home computing), the centre is the perfect place for a day out.
Relaxen und watschen der Blinkenlights - the MITS Altair 8800
PRINT CHR$(205.5+RND(1)); - Commodore PET 2001
PLOT 48,56:DRAW 160,0,65536 - ZX Spectrum 48K
Intel MDS 80 Microprocessor Development System
HP1000 F Series minicomputer