-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Example: simple fire demo (<1Kb) for ZX Spectrum
- Loading branch information
Showing
3 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
all: | ||
sjasmplus --syntax=f fire.asm | ||
|
||
clean: | ||
rm fire.tap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
;; Busy soft ;; 26.11.2018 ;; Tape generating library ;; | ||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
|
||
;; Use: | ||
;; | ||
;; ................. | ||
;; ...your...code... | ||
;; ................. | ||
;; include "TapLib.asm" | ||
;; MakeTape <speccy_model>, <tape_file>, <program_name>, <start_address>, <code_length>, <call_address> | ||
|
||
MACRO MakeTape speccy_model, tape_file, prog_name, start_add, code_len, call_add | ||
DEVICE speccy_model | ||
|
||
CODE = #AF | ||
USR = #C0 | ||
LOAD = #EF | ||
CLEAR = #FD | ||
RANDOMIZE = #F9 | ||
|
||
org #5C00 | ||
baszac db 0,1 ;; Line number | ||
dw linlen ;; Line length | ||
linzac | ||
db CLEAR,'8',#0E,0,0 | ||
dw start_add-1 | ||
db 0,':' | ||
db LOAD,'"' | ||
codnam ds 10,32 | ||
org codnam | ||
db prog_name | ||
org codnam+10 | ||
db '"',CODE,':' | ||
db RANDOMIZE,USR,'8',#0E,0,0 | ||
dw call_add | ||
db 0,#0D | ||
linlen = $-linzac | ||
baslen = $-baszac | ||
|
||
EMPTYTAP tape_file | ||
SAVETAP tape_file,BASIC,prog_name,baszac,baslen,1 | ||
SAVETAP tape_file,CODE,prog_name,start_add,code_len,start_add | ||
|
||
ENDM |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,275 @@ | ||
;---------------------------------------------------------------------- | ||
;-- Z80 ASM test 2023 - fire.asm for the Sinclair ZX Spectrum. | ||
;-- A tribute to Jare's fire demo published on 1993 for PC/MSDOS. | ||
;-- Dec-2023 - Santiago Romero <[email protected]> | ||
;-- Last updated version at: https://github.com/sromeroi/zx-asm-fire | ||
;---------------------------------------------------------------------- | ||
|
||
ORG $8000 | ||
|
||
;---------------------------------------------------------------------- | ||
;-- Constants | ||
;---------------------------------------------------------------------- | ||
|
||
BORDCR EQU $5C48 ; Spectrum's system variable address: BORDER colour | ||
SEED EQU $5C76 ; Spectrum's system variable address: RND seed | ||
VRAM_PIXELS EQU $4000 ; VideoRam for pixels/bitmap starts here | ||
VRAM_ATTRIB EQU $5800 ; VideoRam for colours/attributes starts here | ||
|
||
FG_BLACK EQU 0 | ||
FG_BLUE EQU 1 | ||
FG_RED EQU 2 | ||
FG_MAGENTA EQU 3 | ||
FG_GREEN EQU 4 | ||
FG_CYAN EQU 5 | ||
FG_YELLOW EQU 6 | ||
FG_WHITE EQU 7 | ||
BG_BLACK EQU 0 | ||
BG_BLUE EQU (FG_BLUE << 3) | ||
BG_RED EQU (FG_RED << 3) | ||
BG_MAGENTA EQU (FG_MAGENTA << 3) | ||
BG_GREEN EQU (FG_GREEN << 3) | ||
BG_CYAN EQU (FG_CYAN << 3) | ||
BG_YELLOW EQU (FG_YELLOW << 3) | ||
BG_WHITE EQU (FG_WHITE << 3) | ||
COLOR_BRIGHT EQU 64 | ||
|
||
; Fire never reaches top, so it's ok to reduce the "fire" array and just | ||
; render the top-left corner of the fire on a lower Y screen coordinate | ||
FIRE_HEIGHT EQU 20 | ||
FIRE_START EQU (24-FIRE_HEIGHT)*32 | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- MAIN PROGRAM (ENTRY POINT) | ||
;---------------------------------------------------------------------- | ||
main: | ||
call set_black_border ; Prepare screen with black border, | ||
call clear_attributes ; black INK/PAPER, and a bg pattern by | ||
call fill_pattern ; alternating 01010101b/10101010b each line | ||
; to allow extra colors with "dithering" | ||
|
||
mainloop: | ||
call add_flames ; add flames to fire bottom | ||
call animate_fire ; animate the fire (calculate next frame) | ||
call render_fire ; render fire "array" to screen (attributes) | ||
jr mainloop ; you'll never return to BASIC :) | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Set border to black colour | ||
;---------------------------------------------------------------------- | ||
set_black_border: | ||
xor a | ||
ld (BORDCR), a | ||
out ($fe), a ; set border 0 (black) | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Set screen attributes to 0 (BLACK) | ||
;---------------------------------------------------------------------- | ||
clear_attributes: | ||
ld hl, VRAM_ATTRIB | ||
ld de, VRAM_ATTRIB+1 | ||
ld bc, (32*24)-1 | ||
xor a | ||
ld (hl), a | ||
ldir ; Clear entire attribute area (768 bytes) | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Fill the screen with a 10101010b pattern for even lines and | ||
;-- a 01010101b pattern for odd lines. | ||
;---------------------------------------------------------------------- | ||
fill_pattern: | ||
ld hl, VRAM_PIXELS | ||
ld b, 192 ; scanlines to draw | ||
|
||
.loop_line: | ||
ld a, 10101010b ; default value for EVEN lines | ||
bit 0, h ; bit 0 of H (Y's LSB) selects pattern value | ||
jr z, .draw_scanline | ||
ld a, 01010101b ; alternate value for ODD lines (when H's LSB is 1) | ||
|
||
.draw_scanline: | ||
ld c, 32 ; each scanline is 32 "pixels" (attributes) | ||
|
||
.draw_block | ||
ld (hl), a ; store A in HL (paint first 8 pixels of scanline) | ||
inc hl ; advance to next attribute | ||
|
||
dec c | ||
jr nz, .draw_block ; Repeat for all 32 horizontal "pixels" | ||
|
||
djnz .loop_line ; Repeat for 192 scanlines | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Add some "hot spots" at the bottom of the fire. | ||
;-- Fill the last line of the fire with random values. | ||
;---------------------------------------------------------------------- | ||
add_flames: | ||
ld hl, fire+(32*(FIRE_HEIGHT-1)) | ||
ld b, 32 | ||
|
||
.loop: | ||
call random ; Get a random number 0-256 | ||
|
||
REPT 4 | ||
rrca ; rotate right 4 times (divide by 16) | ||
ENDR | ||
|
||
and 00001111b ; Clears bits 7-4 (old LSB's) | ||
add 2 ; Increase a bit the resulting value | ||
cp 16 | ||
jr c, .is_within_palette_range | ||
ld a, 15 | ||
.is_within_palette_range | ||
ld (hl), a ; Add "flame" to our fire | ||
inc hl | ||
|
||
djnz .loop | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Calculate next fire frame: | ||
;-- Each pixel is calculated with its value and the 3 pixels below it, | ||
;-- calculating the average, and substracting some value (to make the | ||
;-- fire vanish slowly). We also ensure that "pixel" is <= 15 always. | ||
;---------------------------------------------------------------------- | ||
animate_fire: | ||
ld ix, fire ; use IX as the pointer to each fire "pixel" | ||
ld hl, fire ; use HL also for (IX+0) (7 cicles vs 19 cicles) | ||
ld b, FIRE_HEIGHT ; repeat for FIRE_HEIGHT lines -1 | ||
|
||
.loop_fire_line: | ||
ld c, 32 ; for each line, repeat for 32 characters | ||
|
||
.loop_fire_pixel: | ||
ld a, (hl) ; Get IX+0 using HL | ||
add a, (hl) ; Pixel next to current one (right) use IX+1 | ||
add a, (ix+32-1) ; For the pixels below use IX+N | ||
add a, (ix+32) | ||
add a, (ix+32+1) ; sum all 4 values | ||
rrca ; divide by 4 | ||
rrca | ||
and 00001111b | ||
cp 2 | ||
jr c, .skip_substract | ||
sub 2 ; if value >= 2, reduce fire | ||
|
||
.skip_substract: | ||
ld (hl), a ; Store calculated value | ||
inc ix | ||
inc hl | ||
dec c | ||
jr nz, .loop_fire_pixel | ||
|
||
djnz .loop_fire_line ; Repeat for the 23 lines | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Render Fire | ||
;---------------------------------------------------------------------- | ||
render_fire: | ||
|
||
; Calc BC for fast 16 bits loop (See https://map.grauw.nl/articles/fast_loops.php) | ||
ld de, 32*(FIRE_HEIGHT-1) | ||
ld b, e | ||
dec de | ||
inc d ; Calculate DE value (destroys B, D and E) | ||
ld c, d ; Now CB = 32*23 prepared for the 16 bits loop. | ||
|
||
ld hl, fire ; HL = source (fire) | ||
|
||
; DE = destination (attributes memory block), + jump 1 line | ||
ld de, VRAM_ATTRIB+FIRE_START | ||
|
||
halt ; VSYNC => enable if you want to limit framerate | ||
; Not really required on [email protected] | ||
|
||
.render_fire_line: | ||
ld a, (hl) ; Read "fire" value | ||
inc hl | ||
|
||
push de ; backup de | ||
|
||
ld de, palette ; de = points to palette[0] | ||
and 00001111b ; ensure A is <= 15 | ||
or e ; A = A + E | ||
ld e, a ; DE = points to palette[A] | ||
|
||
ld a, (de) ; A = palette[A] = palette[fire[n]] | ||
|
||
pop de ; restore de | ||
|
||
ld (de), a ; Write "pixel" (fire attribute) in the screen | ||
inc de | ||
|
||
; Loop for (32*23) times, with BC previously calculated for this "trick" | ||
djnz .render_fire_line | ||
dec c | ||
jr nz, .render_fire_line | ||
|
||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Generate a random number | ||
;-- Output: 0<=a<=255 | ||
;-- all registers are preserved except: af | ||
;-- Pseudorandom number generator featured in Ion by Joe Wingbermuehle | ||
;---------------------------------------------------------------------- | ||
random: | ||
push hl | ||
push de | ||
ld hl, (SEED) | ||
ld a, r | ||
ld d, a | ||
ld e, (hl) | ||
add hl, de | ||
add a, l | ||
xor h | ||
ld (SEED), hl | ||
pop de | ||
pop hl | ||
ret | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
;-- Variables | ||
;---------------------------------------------------------------------- | ||
|
||
fire DS (32*FIRE_HEIGHT), 0 ; Our fire representation (32x24) | ||
|
||
|
||
ALIGN 16 ; Align palette[0] to 16 to quick lookup | ||
palette: ; 16 colours black=>reds=>yellows=>white | ||
DB FG_BLACK + BG_BLACK | ||
DB FG_BLACK + BG_RED | ||
DB FG_BLACK + BG_RED | ||
DB FG_RED + BG_BLACK + COLOR_BRIGHT | ||
DB FG_RED + BG_BLACK + COLOR_BRIGHT | ||
DB FG_RED + BG_RED | ||
DB FG_RED + BG_RED | ||
DB FG_RED + BG_RED + COLOR_BRIGHT | ||
DB FG_RED + BG_RED + COLOR_BRIGHT | ||
DB FG_RED + BG_YELLOW | ||
DB FG_RED + BG_YELLOW + COLOR_BRIGHT | ||
DB FG_YELLOW + BG_YELLOW | ||
DB FG_YELLOW + BG_WHITE | ||
DB FG_YELLOW + BG_YELLOW + COLOR_BRIGHT | ||
DB FG_YELLOW + BG_WHITE + COLOR_BRIGHT | ||
DB FG_WHITE + BG_WHITE + COLOR_BRIGHT | ||
|
||
|
||
;---------------------------------------------------------------------- | ||
program_length = $-main | ||
|
||
include TapLib.asm | ||
MakeTape ZXSPECTRUM48, "fire.tap", "Fire", main, program_length, main |