;- 5 Snowflake (Amstrad CPC/Z80 Assembler) by Overflow/Logon System (37)
org #0A02
db %01000000
db %10001010
db %00001100
db %01001110
db %10010000
db %00100000
db %01001001
db %10010010
; from basic CALL &0A0A=DE
ld l,e
loop_l ld h,d
ld e,(hl)
loop_h_b ld a,20
sub l
ld l,h
ld h,a
ld (#B726),hl
ld a,"*"
call #BB5A
djnz loop_h_b
no_star sla e
dec h
jr c,loop_h_b
jr nz,no_star
dec l
jr nz,loop_l
ret
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 8 Snowflake (Amstrad CPC/Z80 Assembler) by Longshot / Logon System (45)
;;=======================================================================
;; Vintage Computing Christmas Challenge 2025 (VC3 2025)
;; Amstrad CPC / Longshot (Logon System)
;; December 2025
;; 45 bytes
;; Brute Force Mode!
;; run from basic : memory &1f00:mode 0:load "vcc2025.bin":call #abe
;; or type : run "STUB" with the same content
;;=======================================================================
_size_code equ _end_code-_start_code
org_code equ #2100-47 ; Raw_Pattern end at #20fe (bc=20ff)
hirom_display equ #c38b ; Rom string display (input hl=ptr string)
firm_display equ #bb5a ; Firmware Display Char (input acc=ascii char)
; Register de=#0abe / bc=#20ff / hl=00xx / Zf=1 Cf=0
org org_code
run $
_start_code ; adr of call=>>DE >> #0abe (#0a=calc char "*", #be>>end of buffer)
ld h,b ; h=#20xx (xx=b for up ptr, de=down ptr)
byte_roll
dec c ; #20fe start of pattern table
scf ; Cf=1 injected in pattern rolled byte to test reload condition
bit_roll
ld l,c ; hl=ptr on Raw pattern corrected
rl (hl) ; Get Cf from pattern (1=star;0=space)
jr z,byte_roll ; if (hl)==0 last bit was treated, reload
sbc a,a ; if Cf=1, acc=#ff , else acc=0
and d ; acc=#0a if #ff, else 0
add a,h ; acc=#2a ("*") if Cf was 1, else #20 (" ")
dec e ; Ptrbuf--
ld l,e ;
ld (hl),a ; store char
call nz,#bb5a ; Don't display the last char
jr nz,bit_roll ;
rst #10 ; Try to display (but fail a lot..)
defw hirom_display ; Display the "reverse" buffer
Raw_Pattern ; start at x=10 >> pattern byte #ff became #e0=ret po
db #ff,#8f ; Pattern 20 bits / line
db #e4,#24
db #24,#95
db #04,#48
db #02,#40
db #4e,#80
db #53,#39
db #30,#84
db #81,#e2
db #28,0
db #15,0
db #40
_end_code
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 9 Snowflake (Amstrad CPC/Z80 Assembler) by Arnolde of Leosoft (48)
;execution:
;CALL #140A
begin equ #1402
;CPC 6128 values:
TXT_CURSOR equ #B726
TXT_OUTPUT equ #BB5A
;SNOWFLAKE BITMAP:
;db 00000000* ;this one is used but not explicitly stored
org begin
db %00000010; *
db %01010001;* * *
db %00110000; **
db %01110010; * ***
db %00001001;* *
db %00000100; *
db %10010010; * * *
db %01001001;* * *
db %11111111;********* ;the execution begins here with a harmless RST#38
; * * *** * *
; * * * * * * *
; * * *
; * *** *
; *** * * * ***
; ** * **
; * * *** * *
; * * *
; *
;the flake is plotted around the center 10,10 (locate 11,11 in basic)
;initial conditions:
;DE=#140A (calling address from basic)
;D=20 used to mirror the coordinates, E=10 used for initialization of loops
;H=1 because called from basic
;set coords for the 2 right/leftmost points
ld l,e ;y = 10
call plot_two_stars ;draw right/leftmost points
;run through y and x from 10 to 1
loop_y:
ld b,e ;x = 10
scf ;first one (x=10) is always plotted (vertical axis)
loop_x:
ld h,b ;h = x for plotting
call c,plot_four_stars
ld h,d ;h = highbyte of the bitmap table
srl (hl) ;shift next bit, replace by 0 for outer edges
djnz loop_x
dec l
jr nz,loop_y
ret
plot_four_stars:
call mirror_y_and_plot_two_stars
mirror_y_and_plot_two_stars:
ld a,d
sub l
ld l,a
plot_two_stars:
call mirror_x_and_plot_one_star
mirror_x_and_plot_one_star:
ld a,d
sub h
ld h,a
;plot one star
ld (TXT_CURSOR),hl ;locate
ld a,"*"
jp TXT_OUTPUT ;plot
length equ $-begin ;48 bytes
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 23 Snowflake (Amstrad CPC/Z80 Assembler) by Gallegux (62)
;; Snowflake62 by Gallegux
;; size: 62 bytes
;; execution from basic: CALL &173E
;; A=0 B=20 C=FF D=17 E=3E H=00 L=4?
org #9900
ld a,b
ld c,d
ld ix, eliro+360
ld hl, enirejo
ld d,h
.py
ld b,8
.pi
rlc (hl)
jr nc, konservi
xor a, #A
.konservi
ld (de),a
inc de
ld (ix),a
dec ix
djnz pi
inc hl
dec c
jr nz, py
rst #28
dw #6fc
enirejo
db #00,#60,#00,#3F,#00,#F2,#4F,#0A
db #31,#42,#5F,#A4,#0D,#2C,#00,#DB
db #03,#6F,#DB,#36,#96,#D0,#00
db #1A,#15,#27,#01,#19
eliro
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 28 Snowflake (Amstrad CPC/Z80 Assembler) by gurneyh (65)
; VCCC 2025 - Amstrad CPC - 65 bytes - CALL #1314
TXT_OUTPUT equ #BB5A
org #1300
bitmap db #00,#40,#01,#40,#28,#C0,#18,#40,#39,#40
db #04,#C0,#02,#40,#49,#40,#24,#C0,#FF,#C0
start ld h,d : ld c,d : ld e,10
lines ld a,d : sub c : cp e : jr c,ul : ld a,c : dec a
ul add a,a : ld l,a : ld a,(hl) : inc l : ld l,(hl) : ld h,a
ld a,' ' : push af : ld b,e
left add hl,hl : sbc a,a : and e : add a,' ' : push af : call TXT_OUTPUT : djnz left
pop af : ld b,e
right pop af : call TXT_OUTPUT : djnz right
ld h,d : dec c : jr nz,lines : ret
print "SIZE: ", $ - bitmap, " bytes"
save "vccc.bin", bitmap, $ - bitmap, DSK, "vccc.dsk"
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 42 Snowflake (Amstrad CPC/Z80 Assembler) by issalig (77)
; *
; * * *
; * * *** * *
; ** * **
; *** * * * ***
; * *** *
; * * *
; * * * * * * *
; * * *** * *
;*******************
; * * *** * *
; * * * * * * *
; * * *
; * *** *
; *** * * * ***
; ** * **
; * * *** * *
; * * *
; *
; =============================================================================
; Vintage Computing Christmas Challenge 2025 (VCCC 2025)
; Z80 assembly for Amstrad CPC - Snowflake
; works with pasmo or winape
; size. 77 bytes
; author. issalig
; =============================================================================
;write "vc3.bin"
ORG #8000
PRINT_CHAR EQU #BB5A
START:
; Initialize Y counter to -9 (Top of the grid)
LD C, -9
Y_LOOP:
; Initialize X counter to -9 (Left of the grid)
LD B, -9
X_LOOP:
; --- 1. Calculate Absolute Coordinates for Symmetry ---
; The snowflake is symmetric. We map (-9..9) to (9..0..9).
; This allows us to store data for only one quadrant.
LD A, C
CALL ABS
LD E, A ; E = ABS(Y) = Row Index (0-9)
LD A, B
CALL ABS
LD D, A ; D = ABS(X) = Column Index (0-9)
; --- 2. The Center Cross Rule ---
; If we are on the X axis (Y=0) or Y axis (X=0), always print '*'
; Check if D (ABS(X)) is zero
OR A ; A currently holds D from previous block
JR Z, STAR ; If X=0, jump to print star
; Check if E (ABS(Y)) is zero
LD A, E
OR A
JR Z, STAR ; If Y=0, jump to print star
; --- 3. Data Lookup ---
; We need to check the pattern for the current row E.
; DATA_TABLE stores patterns for rows 1 to 9.
; We calculate address HL = DATA_TABLE + (E - 1)
LD HL, DATA_TABLE-1 ; Base address minus 1
ADD A, L ; Add E (in A) to L
LD L, A ; HL now points to the byte for this row
; --- 4. Bitmask Generation ---
; We need to check if the bit corresponding to column D is set.
; We generate a mask 2^(D-1) efficiently.
; Example If D=1, mask=1. If D=3, mask=4.
XOR A ; A = 0
SCF ; Set Carry Flag = 1
SHIFT: ADC A, A ; Shift Left Bit 0 gets Carry (1), others 0
DEC D ; Loop D times
JR NZ, SHIFT
; Now A contains the bitmask (e.g., 00000100)
; --- 5. Pixel Decision ---
AND (HL) ; Check if the bit is set in the data byte
LD A, ' ' ; Default to Space
JR Z, PRNT ; If result is 0, print Space
STAR: LD A, '*' ; Otherwise, load Star
PRNT: CALL PRINT_CHAR ; Print the character
; --- 6. Loop Control (X Axis) ---
INC B ; Move to next column
LD A, B
CP 10 ; Have we reached the end (+9)?
JR NZ, X_LOOP ; If not, continue row
; --- 7. Newline ---
;LD A, 10 ; LF (Line Feed) not needed as after CP 10 A is 10
CALL PRINT_CHAR
LD A, 13 ; CR (Carriage Return)
CALL PRINT_CHAR
; --- 8. Loop Control (Y Axis) ---
INC C ; Move to next row
LD A, C
CP 10 ; Have we reached the bottom (+9)?
JR NZ, Y_LOOP ; If not, continue grid
RET
; --- Helper Function Absolute Value ---
; Input A (signed 8-bit)
; Output A (positive 8-bit)
ABS: OR A ; Update flags based on A
RET P ; Return if Positive (Sign bit clear)
NEG ; Negate (Two's complement) if Negative
RET
; --- Data Table ---
; Bit patterns for rows 1 to 9 (Row 0 is handled by logic).
; Each bit represents a star position.
; 73 = 01001001 -> Stars at positions 1, 4, 7
DATA_TABLE:
DB 73, 146, 4, 9, 114, 48, 81, 2, 0
END
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 44 Snowflake (Amstrad CPC/Z80 Assembler) by BSC (79)
;
; DEFINES
;
txtout equ $bb5a
ROW1 equ %00000010 ; = 2
ROW2 equ %01010001
ROW3 equ %00110000
ROW4 equ %01110010
ROW5 equ %00001001
ROW6 equ %00000100
ROW7 equ %10010010
ROW8 equ %01001001
org BASE ; see Makefile
db 0 ; this can be stored implicitly
; i.e. it does not have to be part of the file/data generator
rows:
db ROW1,ROW2,ROW3,ROW4,ROW5,ROW6,ROW7,ROW8
;
; IDEAS
;
; Use H and L as indices into the patterns
; and D and E as offsets to add to HL after
; each row.
; can we use the RES b,r trick (see dancedance.z80 aka heartbel)
;
; CODE
;
; CALL <nnnn> from Basic sets Z80 DE register to <nnnn>.
; i.e. DE=&202a
; HL = 68 = 0x0044
; regs:
; A=char, B=column counter, C=pattern bitmap, D=row counter, E=&2a = '*'
; HL=pattern ptr where H=&20 = ' '
; D and H are both $20 here
; print upper part
ld hl, rows-1 ; the byte before "rows" must be zero!
call print_rows
call long_line
; print lower part
ld a,$2b ; dec hl
ld (inc_or_dec),a
dec hl
print_rows:
ld d,9
rows_loop:
; load pattern
ld c,(hl)
; print left part with leading space
ld a,h ; $20
call print_row_half
; inject RR C to print reversed
ld a,$19
ld (rotate+1),a
; prints middle column: '*'
; and right part (=left part reversed)
ld a,e ; star
call print_row_half
call crlf
; inject RL C again
ld a,$11
ld (rotate+1),a
; next/previous row
inc_or_dec:
inc hl ; or dec hl
dec d
jr nz,rows_loop
ret
long_line:
; print long middle line
ld a,e ; $2a
ld b,19 ; = 0x13
middle_line:
call $bb5a
djnz middle_line
crlf:
rst $18
dw rom_addr_crlf
ret
; ' ' = 32 = 0x20 = %00100000
; '*' = 42 = 0x2a = %00101010
; prints the pattern once, making half a row (without the middle column)
print_row_half:
; print what was in A
; A=char, B=loop cnt, C=bitmap, D=outer loop cnt, E='*', H=' ', L=pattern ptr
ld b,9
print_loop:
call $bb5a
ld a,h ; = 32 = 0x20 = %00100000
rotate:
rl c ; cb 11
jr nc,skip
ld a,e; = 42 = 0x2a = %00101010 = '*'
skip:
djnz print_loop
ret
;
; DATA
;
rom_addr_crlf:
dw $c3e2 ; = print CRLF
; db 0 ; this can be stored implicitly, see above
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;- 60 Snowflake (Amstrad CPC/Z80 Assembler) by lightforce6128 (87)
NOLIST
SCR_SET_MODE EQU #BC0E ;; A=mode
TXT_OUTPUT EQU #BB5A ;; A=character
EXPECTED_ADDRESS EQU #5204
ORG EXPECTED_ADDRESS
RUN winape_entry
program_begin:
;; Store a pattern that is used multiple times.
;;
;; Input:
;; A - Symbol to store.
;; HL - Row and column of upper left symbol.
;;
;; Changes:
;; H - Incremented by one.
print_pattern:
IF2 : IF $ - EXPECTED_ADDRESS
PRINT "Routine 'print_pattern' needs to be located at #$EXPECTED_ADDRESS, but is at #$print_pattern."
STOP
ENDIF : ENDIF
LD (HL),A : INC H : INC L ;; 3 ;; 1
LD (HL),A : INC H : INC L ;; 3 ;; |\
LD (HL),A : DEC L ;; 2 ;; | 2
LD (HL),A : DEC L ;; 2 ;; | \
LD (HL),A : DEC H : DEC H ;; 3 ;; 5-4-3
RET ;; 1 ;;
;; ;; -- ;;
;; ;; 14 ;;
program_entry:
;; AF:FFA4 HL:ABFF DE:0040 BC:B0FF IX:B0A0 IY:0000
;; ^^^^
;; Redirect (in this program) unused restart 5/#28 to pattern printing routine.
LD HL,print_pattern : LD (#29),HL ;; 6 ;; Only store address, jump command is already there.
;; ;; -- ;;
;; ;; 6 ;;
;; Prepare octant (upper left quarter, lower triangle).
;; The range #xxyy with xx,yy from [1,19] is filled with zeros.
ASTERISK EQU #2A ;; - ;;
LD A,ASTERISK ;; 2 ;; Store character to print in A.
ADD HL,BC : RST #28 ;; 2 ;; Store pattern for position 3|3. (HL+BC=#0303)
ADD HL,HL : LD (HL),A ;; 2 ;; Store single star for position 6|6.
INC H : INC L : LD (HL),A ;; 3 ;; Store single star for position 7|7.
INC H : INC L : RST #28 ;; 4 ;; Store pattern for position 8|8.
LD L,5 : RST #28 ;; 3 ;; Store pattern for position 8|5.
LD L,2 : RST #28 ;; 3 ;; Store pattern for position 8|2.
LD HL,#0A01 : LD (HL),A ;; 4 ;; Store single star for position 10|1.
;; ;; -- ;;
;; ;; 23 ;;
;; AF:2A0A HL:0A01 DE:0040 BC:B0FF IX:B0A0 IY:0000
;; (^^) ^^ (^^)
;; Mirror prepared octant to other octants and quadrants.
;; The order is important: Because the loop runs backwards,
;; the needed parts of the upper triangle are available.
LD D,H ;; 1 ;; Store constant #0A.
LD B,D ;; 1 ;; Row in upper left quadrant.
m__y_loop: ;; - ;;
LD C,D ;; 1 ;; Column in upper left quadrant.
m__x_loop: ;; - ;;
LD A,C : CP A,B ;; 2 ;; Lower or upper triangle?
LD A,(BC) ;; 1 ;; Already load stored value to A.
JR NC,m__skip ;; 2 ;;
LD H,C : LD L,B : LD (HL),A ;; 3 ;; If in lower triangle, mirror to upper triangle.
m__skip: ;; - ;;
LD H,D : LD L,D : ADD HL,HL : SBC HL,BC ;; 5 ;; Calculate inverse row and column in HL.
LD (HL),A ;; 1 ;; Mirror to lower right quadrant.
PUSH HL : LD H,B : LD (HL),A : POP HL ;; 4 ;; Mirror to upper right quadrant.
LD L,C : LD (HL),A ;; 2 ;; Mirror to lower left quadrant.
DEC C : JR NZ,m__x_loop ;; 3 ;;
DJNZ m__y_loop ;; 2 ;;
;; ;; -- ;;
;; ;; 28 ;;
;; AF:0042 HL:1301 DE:0A40 BC:0000 IX:B0A0 IY:0000
;; ^^
;; Transfer completed pattern from memory to screen.
LD B,H ;; 1 ;; Row in all quadrants.
t__y_loop: ;; - ;;
LD C,H ;; 1 ;; Column in all quadrants.
t__x_loop: ;; - ;;
LD (#B726),BC ;; 4 ;; Position cursor.
LD A,(BC) : CALL TXT_OUTPUT ;; 4 ;; Print star on screen.
DEC C : JR NZ,t__x_loop ;; 3 ;;
DJNZ t__y_loop ;; 2 ;;
;; ;; -- ;;
;; ;; 15 ;;
;; A:0042 HL:1301 DE:0A40 BC:0000 IX:B0A0 IY:0000
;;
;; Wait forever.
JR $ ;; 2 ;;
;; ;; -- ;;
;; ;; 2 ;;
program_end:
;; Entry point for WinAPE assembler.
winape_entry:
;; Clear screen. This is automatically done when program was loaded from file.
LD A,1 : CALL SCR_SET_MODE
;; Set second register set as it is set when loaded from file.
;; NOTE: As long as interrupts are running, this cannot be used.
;;EX AF,AF' : EXX
;; LD HL,8D8C : PUSH HL : POP AF
;; LD HL,#B8D9
;; LD DE,#8020
;; LD BC,#7F8D
;;EX AF,AF' : EXX
;; Set first register set as it is set when loaded from file.
LD HL,#FFA4 : PUSH HL : POP AF
LD HL,#ABFF
LD DE,#0040
LD BC,#B0FF
LD IX,#B0A0
LD IY,#0000
;;LD SP,#BFFA
CALL program_entry
;; If the program returns, the computer will be reset.
RST #00
IF2
program_size EQU program_end - program_begin
PRINT "Program size: &program_size bytes"
PRINT 'SAVE"snow.bin",B,&program_begin,&program_size,&program_entry'
ENDIF