top of page

"Xmas GIFT" - VC³ 2024 coding tips

  • Writer: Overflow
    Overflow
  • 2 days ago
  • 4 min read

Updated: 11 minutes ago


A few months ago, I participated in the Vintage Computing Christmas Challenge 2024.

I also took part, last year, in 2023 edition - you can check out the details on Logon System's blog. Recently, I was urged to share some explanations about the tricks I used, so here they are.


By the way, the Amstrad team did exceptionally well this year, as noted on the official results page.


The best part? By combining my ideas with those of others, we managed to optimize our code even further, reducing it to just 38 bytes! You can download the final dsk or source  code from the site.


Animated GIF to show algorithm & main idea


Main source/code map


(A) CALL <nnnn> from Basic initializes DE

CALL <nnnn> from Basic sets Z80 DE register to <nnnn>.

This saves some bytes for initializing DE to value #0901 at start.


(B) MAIN MEMORY full of 00/NOP

The call from Basic starts at #0901. It is assumed that the memory area from #0901 to #2100 is filled with NOPs. Thus, even if the call starts at #0901, the main code (beginning at #2100) will execute after running through many NOPs.


			0901		00	NOP
			...		00	NOP
			2100			; main code starts here
						; assuming DE=#0901

(C) RST LO_SIDE_CALL : DEFW BASIC_PRINT_STRING

Credit for finding this gem goes to lightforce6128.

This call within Basic ROM prints characters or control codes starting from HL until (HL) is 0.

This avoids to lose some bytes to loop on CALL #BB5A (prints character or control code from A register).

			2100	  		LD HL,data_ctrl
			2103			RST #10:DW #C38B
			...
data_ctrl	211F			; list of characters / control codes	

(D) MAIN MEMORY full of 00/NOP

The RST LO_SIDE_CALL : DEFW BASIC_PRINT_STRING ends when it encounters a 0 in the list. There's no need to explicitly set a final 0 within the list since the main memory defaults to 0.

			2126		00

(E) COUNTER for line/y at #2121

This allows to set HL with ease since H=L=#21

			2106			LD L,H

(F) COUNTER for line/y is NEGATIVE COUNTER

The counter runs from -#14 to -#01 and stops at #00. As we'll see later, this negative value will be useful later in this algorithm.

			2107 		INC (HL)
			...
			2121		EC	; = -#14

(G) RET to Basic is at half-loop

First half of the loop draws the knot "\o/".

Second half of the loop draws one line from the box,

either "+--------+--------+" or "! ! !".

At each loop (except the last one) the second half deletes the knot.

This algorithm shows some nice optimization.

This is also a stylish way of rising the gfx as a cathedral rising from the ground.

			2108			RET Z 

(H) HL set to "! "

Thanks to the charset, this saves 1 or 2 bytes. Since " " equals "!" -1, (or #20 equals #21 -1), DEC HL transforms "!!" into "! " as expected.

			210F			DEC HL

(I) DEC HL is part of ANOTHER OPCODE

The last byte from LD HL,"+-" is #2B, which is the binary code for DEC HL. This saves one byte thanks to a clever JR jr_y_std.

						JR NZ,jr_y_std
			...
			210D		21	LD HL,"+-" ; counts for 3 bytes 21 2D 2B
			210E		2D
jr_y_std		210F		2B	DEC HL

(J) JP loop_y is part of DATA used elsewhere

This saves 1 or 2 bytes since the address for the jump is also used as data.

			211E		C3	JP #091F ; counts for 3 bytes C3 1F 09
data_ctrl	211F		1F	; 1st character / control code
			2120		09	; 2nd character / control code
			...

(K) MAIN MEMORY full of 00/NOP

It is assumed then #091F to #2100 is full of NOPs.

This allows at each loop_y to run plenty of NOPs without care.

loop_y		091F		00	NOP
			...		00	NOP
			2100			; code for loop starts here
			...
			211E		C3	JP loop_y ; JP #091F 
			211F		1F
			2120		09

(L) LOCATE 9,y (with y<0) scrolls SCREEN DOWN

When using contol code to LOCATE <x,y> at a given character place, if y<0 then screen scrolls down 1 character - and located y/line is the upper one. This allows the algorithm to scroll the screen down and build the 'cathedral' gfx.

data_ctrl	211F		1F	; 1st character / control code
			2120		09	; 2nd character / control code
			2121		EC	; 3rd character / control code
						; = LOCATE #09,-#14

(M) COUNTER for line/y is also used as other DATA

That y value for LOCATE is also used as a variable ranging from #EC to #FF.

Saving 1 byte - no need to have a fixed negative value there.

data_ctrl	211F		1F	; 1st character / control code
			2120		09	; 2nd character / control code
cpt_y		2121		<-y>	; 3rd character / control code 
						; = LOCATE #09, <from #EC to #FF>

Overflow / Logon System

Tuesday, April 15th 2025

Gameboy from LOGON'S RUN

 Overflow's RAndom Memory

bottom of page