scroll down works on CHIP-8 and High-Res modes

scroll left and right work in stdef and hidef
adds octo test roms
adds schip fonts to memory
This commit is contained in:
2024-10-25 08:19:03 -04:00
parent a978ddc41e
commit e29ac45c84
65 changed files with 13342 additions and 230 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+393
View File
@@ -0,0 +1,393 @@
###########################################
#
# Deep8
#
# A stripped down port of the Mako game
# "Deep" for Chip8.
# Move your boat left and right with A/D
# Press S to drop a bomb and release S
# to detonate it. Destroy incoming
# squid before they tip your boat!
#
# This game was one of the earliest
# programs written using Octo.
#
###########################################
: waves
0b00110011
0b11101110
: boat
0b00000100
0b00000100
0b11111111
0b11111111
0b01111101
: boat-flip
0b00000000
0b00000000
0b01111101
0b11111111
0b11111111
: bomb
0b00001000
0b00010100
0b00010000
0b00111000
0b00111000
0b00111000
: fall
0b01000000
0b01010000
0b01100000
0b11110000
0b01100000
0b01000000
: squid-0
0b00111100
0b00111100
0b01011010
0b01011010
: squid-1
0b00111100
0b00111100
0b11011011
0b00100100
: boom
0b10010000
0b00010010
0b01100000
0b00000000
0b10000011
0b00100100
0b00100001
: title-0
0b00010000
0b00010000
0b00010000
0b00010000
0b01110000
0b10010000
0b10010000
0b10010000
0b10010000
0b01110000
: title-1
0b01100000
0b10010000
0b11110000
0b10000000
0b10000000
0b01110000
: title-2
0b11100000
0b10010000
0b10010000
0b10010000
0b10010000
0b11100010
0b10000000
0b10000000
0b10000000
0b10000000
: end-0
0b11101010
0b01001110
0b01001010
0b01001010
: end-1
0b11100111
0b11000110
0b10000100
0b11100111
: end-2
0b01100110
0b01010101
0b01010101
0b01010110
# register scratchpad:
: scratch 0 0 0 0
# storage for BCD decoding:
: score-digits 0 0 0
# enemy data:
: e1 1 0 0
: e2 20 0 0
: e3 40 0 0
: e4 90 0 0
###########################################
#
# Introduction
#
###########################################
: draw-waves
i := waves
v0 := 0 # x
v1 := 7 # y
loop
sprite v0 v1 2
v0 += 8
while v0 != 64
again
;
: title
draw-waves
i := title-0
v0 := 16
v1 := 12
sprite v0 v1 10
i := title-1
v0 += 8
v1 += 4
sprite v0 v1 6
v0 += 8
sprite v0 v1 6
i := title-2
v0 += 8
sprite v0 v1 10
v0 := key
;
: draw-score
i := score-digits
load v2
i := hex v0
v0 := 49
v3 := 1
sprite v0 v3 5
i := hex v1
v0 += 5
sprite v0 v3 5
i := hex v2
v0 += 5
sprite v0 v3 5
;
: inc-score
i := scratch
save v3
draw-score
v9 += 1
i := score-digits
bcd v9
draw-score
i := scratch
load v3
;
: init-game
clear
draw-waves
v8 := 0 # enemy tick timer
v9 := 0 # player score
va := 32 # player horizontal position
vb := 1 # player vertical position
vc := 10 # bomb horizontal position
vd := 10 # bomb vertical position
ve := 0 # bomb state (0=invisible, 1=falling, 2+=exploding)
# draw initial boat
i := boat
sprite va vb 5
# draw initial score
draw-score
;
###########################################
#
# Game Over
#
###########################################
: delay-loop
v0 := 0
loop
v0 += 1
while v0 != 32
again
;
: game-over
# erase player
i := boat
sprite va vb 5
# flip boat
i := boat-flip
sprite va vb 5
# animate the player sinking
i := fall
vb := 8
sprite va vb 6
loop
delay-loop
sprite va vb 6
vb += 1
sprite va vb 6
while vb != 26
again
sprite va vb 6
# show 'the end'
va := 20
vb := 14
i := end-0
sprite va vb 4
i := end-1
va += 8
sprite va vb 4
i := end-2
va += 8
sprite va vb 4
loop again
###########################################
#
# Enemy Logic
#
###########################################
# v0 - enemy timer. (0=swim, >0=time until next spawn)
# v1 - horizontal position
# v2 - vertical position
: enemy-sprite
v4 := 1
v4 &= v2
i := squid-0
if v4 == 1 then i := squid-1
;
: spawn-enemy
v1 := random 63
v2 := 28
enemy-sprite
sprite v1 v2 4
;
: count-enemy
v0 -= v3
if v0 == 0 then spawn-enemy
;
: update-enemy
if v0 != 0 then jump count-enemy
enemy-sprite
sprite v1 v2 4
v2 -= v3
# kill the player if
# an enemy reaches the surface:
if v2 == 8 then jump game-over
enemy-sprite
sprite v1 v2 4
# die on collision:
if vf == 0 then return
sprite v1 v2 4
v0 := random 31
v0 += 10
inc-score
;
: update-enemies
v3 := 1
v8 ^= v3
if v8 == 0 then return
i := e1 load v2 update-enemy i := e1 save v2
i := e2 load v2 update-enemy i := e2 save v2
i := e3 load v2 update-enemy i := e3 save v2
i := e4 load v2 update-enemy i := e4 save v2
;
###########################################
#
# Player/Bomb Logic
#
###########################################
: bomb-fire
if ve != 0 then return
vc := va
vd := 10
ve := 1
i := bomb
sprite vc vd 6
;
: update-player
v2 := 3
v1 := va
v0 := 7
if v0 key then va -= v2
v0 := 9
if v0 key then va += v2
v0 := 8
if v0 key then bomb-fire
if v1 == va then return
i := boat
sprite v1 vb 5
sprite va vb 5
;
: bomb-explode
ve := 2
i := boom
sprite vc vd 7
;
: bomb-falling
i := bomb
sprite vc vd 6
vd += 1
if vd == 25 then jump bomb-explode
v0 := 8
if v0 -key then jump bomb-explode
sprite vc vd 6
;
: bomb-exploding
ve += 1
if ve != 4 then return
ve := 0
i := boom
sprite vc vd 7
;
: update-bomb
if ve == 1 then jump bomb-falling
if ve != 0 then jump bomb-exploding
;
###########################################
#
# Main Loop
#
###########################################
: main
title
init-game
loop
update-player
update-bomb
update-enemies
again
+34
View File
@@ -0,0 +1,34 @@
# Chip8 is a virtual machine designed in 1977 for programming video games.
# Octo is a high level assembler, disassembler and simulator for Chip8.
# Click 'Run' and then press ASWD to move the sprite around the screen.
# Click the Octo logo for source, documentation and examples.
:alias px v1
:alias py v2
: main
px := random 0b0011111
py := random 0b0001111
i := person
sprite px py 8
loop
# erase the player, update its position and then redraw:
sprite px py 8
v0 := OCTO_KEY_W if v0 key then py += -1
v0 := OCTO_KEY_S if v0 key then py += 1
v0 := OCTO_KEY_A if v0 key then px += -1
v0 := OCTO_KEY_D if v0 key then px += 1
sprite px py 8
# lock the framerate of this program via the delay timer:
loop
vf := delay
if vf != 0 then
again
vf := 3
delay := vf
again
: person
0x70 0x70 0x20 0x70 0xA8 0x20 0x50 0x50
+310
View File
@@ -0,0 +1,310 @@
###########################################
#
# Chipenstein 3D
#
# A work-in-progress experiment
# in creating a raycast 2.5d shooter.
# Uses PWM techniques to simulate extra
# colors and must run at 1000 cycles/frame.
# Epilepsy warning!
#
###########################################
# The largest a map for this approach could be is 16x16.
# Technically we don't have to surround all sides with
# walls due to wraparound, but if there is a ray path
# around the map without hitting a wall our raycast
# routine will get stuck in an infinite loop:
: map-data
0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF
0xFF 0xFF 0x01 0xFF 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF
0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0x00 0xFF 0x01 0x00 0x00 0x00 0xFF 0x00 0xFF
0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01
0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF 0x01 0xFF
: collision-test
# take whole x/y in vc/vd, return map color in v0
i := map-data
vF := 0b111
vc &= vF
i += vc # + (x % 8)
vd &= vF
v0 <<= vd
v0 <<= v0
v0 <<= v0
i += v0 # + (y % 8)*8
load v0 # the current map color
;
: player-position
0 0 0 0 # scratchpad
: save-position
v0 := va
v1 := vb
v2 := vc
v3 := vd
i := player-position
save v3
;
: restore-position
i := player-position
load v3
va := v0
vb := v1
vc := v2
vd := v3
;
###########################################
#
# Raycasting
#
###########################################
# This is a table of the deltas and magnitudes for a fixed-point representation
# of a cosine function. 64 entries correspond to ~5.6 degrees each.
# deltas are interleaved with magnitudes- 0 for positive and 1 for negative.
# deltas are normalized to slightly over half a step to make the distance calculations
# come up with a maximum distance of roughly 15. Generated like so:
#
# for(int x = 0; x < 64; x++) {
# double s = Math.cos(Math.PI*2/64*x);
# System.out.format("0x%02X 0x%02X ", (int)(140 * Math.abs(s)), (s>=0) ?0 : 1);
# if (x % 8 == 7) { System.out.println(); }
# }
: cosine-table
0x8C 0x00 0x8B 0x00 0x89 0x00 0x85 0x00 0x81 0x00 0x7B 0x00 0x74 0x00 0x6C 0x00
0x62 0x00 0x58 0x00 0x4D 0x00 0x41 0x00 0x35 0x00 0x28 0x00 0x1B 0x00 0x0D 0x00
0x00 0x00 0x0D 0x01 0x1B 0x01 0x28 0x01 0x35 0x01 0x41 0x01 0x4D 0x01 0x58 0x01
0x62 0x01 0x6C 0x01 0x74 0x01 0x7B 0x01 0x81 0x01 0x85 0x01 0x89 0x01 0x8B 0x01
0x8C 0x01 0x8B 0x01 0x89 0x01 0x85 0x01 0x81 0x01 0x7B 0x01 0x74 0x01 0x6C 0x01
0x62 0x01 0x58 0x01 0x4D 0x01 0x41 0x01 0x35 0x01 0x28 0x01 0x1B 0x01 0x0D 0x01
0x00 0x01 0x0D 0x00 0x1B 0x00 0x28 0x00 0x35 0x00 0x41 0x00 0x4D 0x00 0x58 0x00
0x62 0x00 0x6C 0x00 0x74 0x00 0x7B 0x00 0x81 0x00 0x85 0x00 0x89 0x00 0x8B 0x00
: get-cosine
# takes angle in v0,
# returns delta, magnitude in v0, v1
vf := 0b111111
v0 &= vf # mod 64
v0 <<= v0
i := cosine-table
i += v0
load v1
;
: get-angles
# takes angle in v3,
# unpacks x/y delta/mag into v4-v7
# cos(a) = cosine-table[(a % 64) << 1]
v0 := v3
get-cosine
v4 := v0 # x delta
v5 := v1 # x magnitude
# sin(a) = cosine-table[(a+16 % 64) << 1]
v0 := v3
v0 += 16
get-cosine
v6 := v0 # y delta
v7 := v1 # y magnitude
;
: delta-step
vf := 0
if v5 == 0 then va += v4 # positive x delta
if vf == 1 then vc += 1 # carry in
vf := 0
if v5 == 1 then va -= v4 # negative x delta
if vf == 0 then vc += -1 # borrow out
vf := 0
if v7 == 0 then vb += v6 # positive y delta
if vf == 1 then vd += 1 # carry in
vf := 0
if v7 == 1 then vb -= v6 # negative y delta
if vf == 0 then vd += -1 # borrow out
;
: heights
# {height, color}
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
: raycast
save-position
#v0-v1 are available as scratch.
v8 := 0 # loop index * 2
v3 := v9 # scan angle
v3 += -8
loop
get-angles
v2 := 16 # height+1
loop
delta-step
v2 += -1 # count down height
collision-test # returns result in v0
while v2 != 0
if v0 == 0 then
again
# save height and color in heights table:
i := heights
i += v8
v1 := v0
v0 := v2
save v1
vf := v3
restore-position
v3 := vf
v8 += 2
v3 += 1 # 16 slices * 5.625 = 90 degree FoV
if v8 != 32 then
again
;
###########################################
#
# Rendering
#
###########################################
# this 45-byte table allows me to construct all the necessary vertical
# strips using only immediate i and a height offset:
: top 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: btm 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0 0xF0
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: sync
# take advantage of the fact that vf
# is always a free register if we aren't
# doing any operations that can carry:
loop
vf := delay
if vf != 0 then
again
vf := 1
delay := vf
;
: draw-heights
# registers for draw loop:
# v0 is used to store the current height
# v1 stores the 'color' bitmask
v2 := 0 # heightmap index
v3 := 1 # upward strip Y
v4 := 16 # down strip Y
v5 := 0 # strip X (avoid shifting v1 in loop)
v6 := 15 # constant
sync clear
loop
# fetch height of column
i := heights
i += v2
load v1
# apply PWM duty cycle for 'color'
v1 &= ve
if v1 == 0 then v0 := 0
# draw upward strip
i := top
i += v0
v0 =- v6
sprite v5 v3 15
# draw downward strip
i := btm
i += v0
sprite v5 v4 15
# draw 16 columns
v2 += 2
v5 += 4
if v2 != 32 then
again
;
###########################################
#
# Main Loop
#
###########################################
: gun
0x10 0x18 0x24 0x24 0x24 0x24 0x5A 0xC2 0xE7 0x7F 0x3E 0x21 0x41 0x41
: spin-left
v9 += -1
raycast
;
: spin-right
v9 += 1
raycast
;
: walk-forward
v3 := v9
get-angles
delta-step
raycast
;
: walk-backward
v3 := v9
get-angles
vf := 1
v5 ^= vf
v7 ^= vf
delta-step
raycast
;
: main
# global state:
v9 := 30 # player angle
va := 128 # x position (fractional)
vb := 128 # y position (fractional)
vc := 5 # x position (whole)
vd := 5 # y position (whole)
ve := 0 # rolling frame counter
raycast
loop
draw-heights
i := gun
v0 := 38
v1 := 18
sprite v0 v1 14
ve += 1
v0 := 7
if v0 key then spin-left
v0 := 9
if v0 key then spin-right
v0 := 5
if v0 key then walk-forward
v0 := 8
if v0 key then walk-backward
again
+83
View File
@@ -0,0 +1,83 @@
###########################################
#
# Sprite scrolling demo:
#
# Draw a computer monitor with a scrolling
# image by using two copies of its sprites
# and adjusting an offset into that data
# before each draw.
#
###########################################
: main
# draw the background:
v0 := 16
v1 := 4
i := comp-LT
sprite v0 v1 11
v0 += 8
i := comp-T
sprite v0 v1 3
v0 += 8
sprite v0 v1 3
v0 += 8
i := comp-RT
sprite v0 v1 11
v0 := 16
v1 += 11
i := comp-LB
sprite v0 v1 15
v0 += 8
v1 += 7
i := comp-B
sprite v0 v1 8
v0 += 8
sprite v0 v1 8
v0 += 8
v1 += -7
i := comp-RB
sprite v0 v1 15
# main animation loop:
va := 24 # left x
vb := 32 # right x
vc := 7 # common y
v9 := 0 # scroll offset
v8 := 0b1111 # constant
draw-texture
loop
draw-texture
v9 += 1
v9 &= v8
draw-texture
vF := 4
delay := vF
loop
vF := delay
if vF != 0 then
again
again
: draw-texture
i := grenade-L
i += v9
sprite va vc 15
i := grenade-R
i += v9
sprite vb vc 15
;
: grenade-L 0x0F 0x30 0x7C 0x7C 0xF8 0xF4 0xE0 0xE8 0xF0 0xE8 0xE0 0x68 0x70 0x34 0x08 0x00
0x0F 0x30 0x7C 0x7C 0xF8 0xF4 0xE0 0xE8 0xF0 0xE8 0xE0 0x68 0x70 0x34 0x08 0x00
: grenade-R 0xF0 0x0C 0x46 0x66 0x33 0x13 0x0B 0x0B 0x1F 0x0F 0x0F 0x1E 0x1E 0x1C 0x30 0x00
0xF0 0x0C 0x46 0x66 0x33 0x13 0x0B 0x0B 0x1F 0x0F 0x0F 0x1E 0x1E 0x1C 0x30 0x00
: comp-LT 0x3F 0x3F 0x3F 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C
: comp-RT 0xFC 0xFC 0xFC 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C
: comp-T 0xFF 0xFF 0xFF
: comp-LB 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3F 0x3F 0x3F 0x00 0x07 0x1C 0x73 0x7F
: comp-RB 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0xFC 0xFC 0xFC 0x00 0xE0 0xD8 0x26 0xFE
: comp-B 0xFF 0xFF 0xFF 0xFF 0x33 0xCC 0x33 0xFF
+23
View File
@@ -0,0 +1,23 @@
###########################################
#
# Key input test program.
# Move a dot around the screen in response
# to keypresses.
#
###########################################
: dot
0b10000000
: main
v0 := 10
v1 := 10
i := dot
loop
sprite v0 v1 1
v2 := 7 if v2 key then v0 += -1 # left
v2 := 9 if v2 key then v0 += 1 # right
v2 := 5 if v2 key then v1 += -1 # up
v2 := 8 if v2 key then v1 += 1 # down
again
+30
View File
@@ -0,0 +1,30 @@
###########################################
#
# Smile
#
# Draw smiley faces on the screen randomly
# and periodically clear the display.
#
###########################################
: smile
0b00100100
0b00100100
0b00000000
0b10000001
0b01000010
0b00111100
: main
i := smile
loop
v2 := 0
loop
v0 := random 0b00111111
v1 := random 0b00011111
sprite v0 v1 6
v2 += 1
if v2 != 32 then
again
clear
again
+73
View File
@@ -0,0 +1,73 @@
###########################################
#
# An Octo implementation of an in-place
# selection sort capable of operating on
# arrays of a fixed size up to 256 elements.
#
###########################################
:const SIZE 16
:calc SIZE-1 { SIZE - 1 }
:alias here v1
:alias rest v2
:alias min-index v3
:alias min-value v4
:alias here-value v5
: selection-sort
here := 0
loop
min-index := here
i := data
i += here
load v0
min-value := v0
here-value := v0
rest := here
rest += 1
i := data
i += rest
loop
load v0
if v0 < min-value begin
min-index := rest
min-value := v0
end
rest += 1
if rest != SIZE then
again
if min-index != here begin
v0 := here-value
i := data
i += min-index
save v0
v0 := min-value
i := data
i += here
save v0
end
here += 1
if here != SIZE-1 then
again
;
###########################################
#
# Usage Example
#
###########################################
: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12
: main
selection-sort
i := data
load vf
:breakpoint sort-complete
;
+116
View File
@@ -0,0 +1,116 @@
###########################################
#
# An Octo implementation of an in-place
# heap sort capable of operating on
# arrays of a fixed size up to 255 elements.
#
###########################################
:const SIZE 16
:calc SIZE-1 { SIZE - 1 }
:calc LIMIT { ( SIZE / 2 ) + 1 }
:alias left-val v0
:alias right-val v1
:alias start v2
:alias root v3
:alias last v4
:alias best v5
:alias left v6
:alias best-val v7
:alias root-val v8
: heap-sort
start := LIMIT
last := SIZE
loop
root := start
sift-down
start += -1
if start != -1 then
again
start := SIZE-1
loop
# swap data[0] with data[start]:
i := data
load v0
vf := v0
i := data
i += start
load v0
i := data
save v0
i := data
i += start
v0 := vf
save v0
start += -1
root := 0
last := start
sift-down
if start != 0 then
again
;
: assign-best
best := left
best-val := left-val
jump found-best
: sift-down
i := data
i += root
load v0
root-val := v0
loop
left <<= root
if left > last then return
i := data
i += left
load v1
best := left
best += 1
best-val := right-val
if left-val > right-val then jump assign-best
if left == last then jump assign-best
: found-best
if root-val >= best-val then return
i := data
i += root
v0 := best-val
save v0
i := data
i += best
v0 := root-val
save v0
root := best
again
###########################################
#
# Usage Example
#
###########################################
: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12
: main
heap-sort
i := data
load vf
:breakpoint sort-complete
;
+131
View File
@@ -0,0 +1,131 @@
###########################################
#
# An Octo implementation of an unusual
# sorting algorithm which combines an
# optimal sorting network and a merge pass.
# This implementation is designed to sort
# exactly 16 items. The 'sort-8' subroutine
# can be used alone to sort the values
# stored in the bottom 8 registers.
#
###########################################
: sort-8
# compare-and-swap:
:macro cas A B {
if A > B begin
vf := A
A := B
B := vf
end
}
cas v0 v1
cas v2 v3
cas v4 v5
cas v6 v7
cas v0 v2
cas v4 v6
cas v1 v3
cas v0 v4
cas v5 v7
cas v3 v7
cas v1 v5
cas v3 v5
cas v2 v6
cas v2 v4
cas v1 v2
cas v3 v6
cas v2 v4
cas v5 v6
cas v3 v4
;
: heap1 0 0 0 0 0 0 0 0
: heap2 0 0 0 0 0 0 0 0
:alias val1 v8
:alias val2 v9
:alias dest va
:alias index1 vb
:alias index2 vc
: fused-sort
i := data
load v7
sort-8
val1 := v0
i := heap1
save v7
i := data
load v7
load v7 # cheaper than adding an offset of 8
sort-8
val2 := v0
i := heap2
save v7
index1 := 1
index2 := 1
dest := 0
: merge
if val1 > val2 then jump merge-2
append-1
if index1 != 9 then jump merge
loop
append-2
if dest == 16 then return
again
: merge-2
append-2
if index2 != 9 then jump merge
loop
append-1
if dest == 16 then return
again
: append-1
v0 := val1
i := data
i += dest
save v0
dest += 1
i := heap1
i += index1
load v0
val1 := v0
index1 += 1
;
: append-2
v0 := val2
i := data
i += dest
save v0
dest += 1
i := heap2
i += index2
load v0
val2 := v0
index2 += 1
;
###########################################
#
# Usage Example
#
###########################################
: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12
: main
fused-sort
i := data
load vf
:breakpoint sort-complete
;
+90
View File
@@ -0,0 +1,90 @@
###########################################
#
# An Octo implementation of a
# bucket sort capable of operating on
# arrays of a fixed size up to 256 elements,
# with values ranging 0-15.
# This technique could be generalized
# for full-byte values given a larger
# bucket array.
#
###########################################
:const SIZE 16
:const MAX_VAL 16
: empty
0 0 0 0 0 0 0 0
: buckets
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
: bucket-sort
# zero bucket array
i := empty
load v7
save v7 # unrolled loop to zero bucket array
save v7 # and initialize loop counters for later.
# bucket the elements
# v1 is data index (already 0)
loop
# load data
i := data
i += v1
load v0
vf := v0
# increment bucket
i := buckets
i += vf
load v0
v0 += 1
i := buckets
i += vf
save v0
v1 += 1
if v1 != SIZE then
again
# unpack bucket counts
# v1 is temporary count
# v2 is data index (already 0)
# v3 is bucket index (already 0)
loop
i := buckets
i += v3
load v0
if v0 != 0 begin
v1 := v0
v0 := v3
i := data
i += v2
v2 += v1
loop
save v0
v1 += -1
if v1 != 0 then
again
end
v3 += 1
if v3 != MAX_VAL then
again
;
###########################################
#
# Usage Example
#
###########################################
: data 14 5 15 6 1 3 10 7 0 9 11 4 2 13 8 12
: main
bucket-sort
i := data
load vf
:breakpoint sort-complete
;
+74
View File
@@ -0,0 +1,74 @@
###########################################
#
# A modular stack data structure using
# a v0-based calling convention.
# vf is used as a working temporary
# register because it is "fragile".
# maximum stack size is 256 bytes.
#
###########################################
# the first value is the pointer index
: stack 0 0 0 0 0 0 0 0 0
: push
# modifies vf, v0
# takes argument in v0
# stack[++stack[0] + 1] := v0
i := stack
vf := v0
load v0
i += v0
v0 := vf
save v0
i := stack
load v0
v0 += 1
i := stack
save v0
;
: pop
# modifies vf, v0
# returns result in v0
# v0 := stack[stack[0]-- + 1]
i := stack
load v0
v0 += -1
vf := v0
i := stack
save v0
i += vf
load v0
;
###########################################
#
# Usage Example:
#
###########################################
: print
# takes an arg in v0
i := hex v0
sprite va vb 5
va += 6
;
: main
va := 3
vb := 3
v0 := 5 push
v0 := 3 push
v0 := 1 push
pop print
v0 := 9 push
pop print
pop print
pop print
# should print '1935'
+80
View File
@@ -0,0 +1,80 @@
###########################################
#
# A modular stack data structure using
# a vf-based calling convention.
# This approach can only be extended up to
# a size 16 stack.
#
###########################################
: scratch 0 0 0 0 0 0 0 0
: under 0
: stack 0
: over 0 0 0 0 0 0 0
: push
# here we take our argument from vf.
# and do not corrupt any other registers.
# we can eliminate the scratch saving
# and restoring if low registers don't
# need to be preserved.
i := scratch
save v6
i := stack
load v6
i := over
save v6
i := stack
v0 := vf
save v0
i := scratch
load v6
;
: pop
# result is left in vf.
# again, we don't corrupt any other registers.
i := scratch
save v7
i := stack
load v7
vf := v0
i := under
save v7
i := scratch
load v7
;
###########################################
#
# Usage Example:
#
###########################################
: print
# takes an arg in vf
i := hex vf
sprite va vb 5
va += 6
;
: main
va := 3
vb := 3
vf := 5 push
vf := 3 push
vf := 1 push
pop print
vf := 9 push
pop print
pop print
pop print
# should print '1935'
+55
View File
@@ -0,0 +1,55 @@
###########################################
#
# A modular stack data structure using
# a v0-based calling convention.
# This approach reserves a dedicated
# register for a stack pointer and as
# a result is very simple and fast.
# maximum stack size is 256 bytes.
#
###########################################
:alias stack-ptr vd
: stack 0 0 0 0 0 0 0 0
: push
i := stack
i += stack-ptr
save v0
stack-ptr += 1
;
: pop
stack-ptr += -1
i := stack
i += stack-ptr
load v0
;
###########################################
#
# Usage Example:
#
###########################################
: print
# takes an arg in v0
i := hex v0
sprite va vb 5
va += 6
;
: main
va := 3
vb := 3
v0 := 5 push
v0 := 3 push
v0 := 1 push
pop print
v0 := 9 push
pop print
pop print
pop print
# should print '1935'
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
###########################################
#
# F8Z: a chip8/Octo tech demo
#
# A/D move gomez left and right.
# Q/E rotate the world around him.
# Runs best at 100 cycles/frame.
#
###########################################
: letter-F 0x07 0x19 0x61 0x81 0x87 0x99 0x81 0x81 0x87 0x9E 0x98 0x90 0x90 0xF0 0xE0
: letter-8 0x0E 0x33 0x41 0x89 0x99 0x93 0x81 0xC1 0x89 0x99 0x91 0x83 0xCE 0x78 0x60
: letter-Z 0x07 0x19 0x61 0x81 0x91 0xE1 0x43 0x86 0x89 0x81 0x81 0x87 0x9E 0xF8 0x60
: cloud1 0x07 0x0F 0x7F 0xFF
: cloud2 0xC0 0xE0 0xFE 0xFF
: cloud3 0x30 0x7E 0xFF
: pillar # (padded to 16 bytes/side)
0x06 0x1B 0x65 0x8F 0xD5 0xBD 0xFB 0x7E 0x83 0xBB 0xBB 0xBB 0x83 0x7F 0xFD 0x00
0x78 0xD6 0xFE 0xFD 0xBF 0xFF 0xFE 0xFF 0x83 0xAB 0xAB 0xBB 0x82 0xFF 0xBF 0x00
0x60 0xB8 0xFE 0xFB 0x7B 0x7F 0xFF 0xDF 0x83 0xBA 0xA3 0xBB 0x83 0x7F 0xFD 0x00
0x16 0xD9 0xA6 0xBB 0xFB 0xFF 0xDF 0xFE 0x82 0xBB 0xAB 0xAB 0x83 0x7F 0xF9 0x00
: floors # (padded to 8 bytes/tile)
0xFE 0xFE 0xFE 0xE0 0xEF 0xEF 0xEF 0x00
0xEF 0xEF 0xEF 0xE0 0xFE 0xFE 0xFE 0x00
0xEF 0xEF 0xEF 0xE0 0xEE 0xEE 0xEE 0x00
0xFE 0xFE 0xFE 0xE0 0xEE 0xEE 0xEE 0x00
: gomez # (padded to 16 bytes/frame)
0x00 0x00 0x60 0xE0 0x7E 0xFF 0xBD 0xF7 0x7E 0x18 0x3C 0x5E 0x3C 0x3C 0x24 0x00 # facing right
0x00 0x60 0x60 0xFE 0xFF 0xBD 0xF7 0x7E 0x18 0x3C 0x5E 0x3C 0x3C 0x48 0x00 0x00
0x00 0x60 0x60 0xFE 0xFF 0xBD 0xF7 0x7E 0x18 0x7E 0x1C 0x3C 0x3C 0x24 0x00 0x00
0x00 0x00 0x60 0xFE 0xFF 0xFF 0xBD 0x76 0x18 0x3C 0x5E 0x3C 0x3C 0x12 0x00 0x00
0x00 0x00 0x06 0x07 0x7E 0xFF 0xBD 0xEF 0x7E 0x18 0x3C 0x7A 0x3C 0x3C 0x24 0x00 # facing left
0x00 0x06 0x06 0x7F 0xFF 0xBD 0xEF 0x7E 0x18 0x3C 0x7A 0x3C 0x3C 0x12 0x00 0x00
0x00 0x06 0x06 0x7F 0xFF 0xBD 0xEF 0x7E 0x18 0x7E 0x38 0x3C 0x3C 0x24 0x00 0x00
0x00 0x00 0x06 0x7F 0xFF 0xFF 0xBD 0x6E 0x18 0x3C 0x7A 0x3C 0x3C 0x48 0x00 0x00
: pillar-pos
46 10 16 46
: cloud-delta
254 255 254 255 2 1 2 1
: sync
v2 := 4
delay := v2
loop
v2 := delay
if v2 != 0 then
again
;
: draw-objects
v0 := 2
v1 := vd
v1 += 8
v2 := 1
i := gomez
i += vc # animation frame
i += v8 # direction facing
sprite va vb 15
# clouds
i := cloud1
sprite vd v0 4
i := cloud2
sprite v1 v0 4
i := cloud3
sprite ve v2 3
# pillar
i := pillar-pos # get x coord
i += v5
load v0
v1 := 9
i := pillar
v2 <<= v5 # add (rotation * 16)
v2 <<= v2
v2 <<= v2
v2 <<= v2
i += v2
sprite v0 v1 15
;
: draw-background
v0 := 0
v1 := 25
loop
i := floors
v2 := random 0b11000
i += v2
sprite v0 v1 7
v0 += 8
if v0 != 64 then
again
;
###########################################
#
# Wipe Effects
#
###########################################
: wipe-common
v1 := 16
buzzer := v1
v1 := 0b11 # wrap rotation modulo 4
v5 &= v1
i := gomez
loop
i += v1
v1 := 1
sprite v0 v1 15
v1 := 16
sprite v0 v1 15
sync
v1 := 1
sprite v0 v1 15
v1 := 16
sprite v0 v1 15
v2 := v0
v0 += v3
v1 := 0b111111
v2 := v0
v2 &= v1
if v2 != 0 then
again
clear
draw-background
;
: wipe-left
# rotate player's position
v0 := va
va := v7
v7 := 64
v7 -= v0
v5 += -1
v0 := 64
v3 := -16
jump wipe-common
: wipe-right
# rotate player's position
v0 := va
va := v7
v7 := 64
v7 += v0
v5 += 1
v0 := 0
v3 := 16
jump wipe-common
###########################################
#
# Movement and Animation
#
###########################################
: walk
v9 += -1 # count down anim timer
vc += 16 # advance frame
v0 := 0b0110000
vc &= v0
if v8 == 0 then va += 1 # move
if v8 != 0 then va += -1
;
: face-left v8 := 64 ;
: move-left if v8 == 0 then jump face-left v9 := 4 ;
: face-right v8 := 0 ;
: move-right if v8 == 64 then jump face-right v9 := 4 ;
: move-player
if v9 != 0 then jump walk
v0 := 7
if v0 key then jump move-left
v0 := 9
if v0 key then jump move-right
v0 := 4
if v0 key then jump wipe-left
v0 := 6
if v0 key then jump wipe-right
;
###########################################
#
# Main Loop
#
###########################################
: main
# title screen
v0 := 15
v1 := 13
i := letter-F
sprite v0 v1 15
v0 += 12
v1 += -5
i := letter-8
sprite v0 v1 15
v0 += 12
v1 += -5
i := letter-Z
sprite v0 v1 15
v0 := 16
loop
sync
v0 += -1
if v0 != 0 then
again
clear
# v0-v3 are used extensively as temporaries
# v4 is still free
v5 := 0 # rotation index
v6 := 0 # real x
v7 := 0 # real y
v8 := 0 # 0 - right, 64 - left
v9 := 0 # moving?
va := 10 # player x position
vb := 10 # player y position
vc := 0 # player anim frame
vd := 10 # big cloud x
ve := 40 # small cloud x
draw-background
draw-objects
loop
draw-objects
move-player
i := cloud-delta
i += v5
i += v5
load v1
vd += v0
ve += v1
draw-objects
sync
again
+231
View File
@@ -0,0 +1,231 @@
###########################################
#
# Fuse
#
# A minimalist reinterpretation of
# the classic Pipe Dream. Assemble lines
# to guide a burning fuse. Don't let it
# burn out!
#
# Press WASD to move the current line
# fragments and E to lay them down.
# You cannot lay down a line overlapping
# any existing lines.
#
# Runs best at 7 cycles/frame.
#
# John Earnest
#
###########################################
:alias ex vd # fuse position x
:alias ey vc # fuse position y
:alias px vb # cursor position x
:alias py va # cursor position y
:alias tile v9 # selected tile
:alias timer-0 v8 # fuse movement cookoff
:alias timer-1 v7 # score (low digits)
:alias timer-2 v6 # score (high digits)
:const tile-mask 0b111000
:const fuse-speed 3 # higher is slower
: main
init-game
# draw starting cursor:
i := tiles
i += tile
sprite px py 8
# wait for an initial key press:
show-title
v0 := key
show-title
loop
i := tiles
i += tile
v0 := 6 if v0 key begin # keyboard E
# wait for key release:
loop if v0 key then again
# we can't drop a tile overlapping
# any existing lines:
sprite px py 8 # erase
sprite px py 8 # redraw
if vf == 0 begin
# drop a tile:
tile := random tile-mask
i := tiles
i += tile
sprite px py 8
end
else
# erase the cursor:
sprite px py 8
# move cursor:
v0 := 5 if v0 key then py += -1 # keyboard W
v0 := 8 if v0 key then py += 1 # keyboard S
v0 := 7 if v0 key then px += -1 # keyboard A
v0 := 9 if v0 key then px += 1 # keyboard D
# handle fuse movement without
# the cursor drawn, to avoid
# extreme weirdness:
move-fuse
# redraw cursor:
i := tiles
i += tile
sprite px py 8
end
# sync framerate
loop
vf := delay
if vf != 0 then
again
vf := 6
delay := vf
again
: init-game
clear
# set up a random starting position:
ex := random 15
ex += 8
ey := random 31
ey += 16
v0 := random 0b11000
i := starts
i += v0
sprite ex ey 8
# initialize the cursor:
tile := random tile-mask
px := 1
py := 1
# reset score:
timer-0 := 0
timer-1 := 0
timer-2 := 0
;
: move-fuse
# don't move every single frame:
timer-0 += 1
if timer-0 != fuse-speed then return
timer-0 := 0
# increment score:
timer-1 += 1
if timer-1 == 100 begin
timer-1 := 0
timer-2 += 1
end
:macro try-move SPRITE REG DELTA {
i := SPRITE
sprite ex ey 5
if vf != 0 begin
REG += DELTA
return
end
sprite ex ey 5
}
try-move dot-n ey -1 # north
try-move dot-e ex 1 # east
try-move dot-s ey 1 # south
try-move dot-w ex -1 # west
: game-over
# no trail, so we've failed!
i := dot
v0 := 6 # keyboard E
loop
sprite ex ey 5
if v0 -key then # key down
again
loop
if v0 key then # key up
again
clear
: show-score
v3 := 37 # x position
v4 := 10 # y position
# draw low two digits:
i := digit-buffer
bcd timer-1
show-score-byte
# draw high two digits:
i := digit-buffer
bcd timer-2
show-score-byte
# wait for any key:
v0 := key
init-game
;
: show-score-byte
load v2
i := hex v2
sprite v3 v4 5
v3 += -5
i := hex v1
sprite v3 v4 5
v3 += -5
;
: show-title
v0 := 52
v1 := 2
v2 := 1
i := title
loop
sprite v0 v1 1
v1 += 1
i += v2
if v1 != 30 then
again
;
: digit-buffer 0 0 0
: title
0x7F 0xFF 0xC0 0xFC 0xC0 0xC0 0x00 0xC3
0xC3 0xC3 0xFF 0x7E 0x00 0x7F 0xFF 0xC0
0xFF 0x03 0xFF 0xFE 0x00 0x7F 0xFF 0xC0
0xFC 0xC0 0xFF 0x7F
: dot 0x00 0x00 0x00 0x10 0x00
: dot-n 0x00 0x00 0x10 0x00 0x00
: dot-s 0x00 0x00 0x00 0x00 0x10
: dot-e 0x00 0x00 0x00 0x08 0x00
: dot-w 0x00 0x00 0x00 0x20 0x00
: starts
0x40 0x5C 0x54 0x44 0x44 0x7C 0x00 0x00 # N
0x00 0x7F 0x40 0x4C 0x44 0x7C 0x00 0x00 # E
0x00 0x7C 0x44 0x44 0x54 0x74 0x04 0x00 # S
0x00 0x3C 0x24 0x24 0x04 0xFC 0x00 0x00 # W
: tiles
0x20 0x20 0xE0 0x00 0x0F 0x08 0x08 0x08 # cross 1
0x04 0x04 0x0C 0x08 0xEF 0x20 0x20 0x20 # cross 2
0x02 0x7E 0x40 0x7E 0x02 0x7E 0x40 0x7E # zig n-s
0xC0 0x5C 0x54 0x55 0x55 0x55 0x57 0x70 # zig e-w
0x14 0x14 0x34 0xE7 0x00 0x7E 0xC3 0x00 # tee N
0x40 0x5F 0x50 0x57 0x54 0x54 0x54 0x54 # tee E
0x00 0xF0 0x1F 0xC0 0x6E 0x2A 0x2B 0x28 # tee S
0x22 0xE2 0x02 0x72 0x56 0x54 0xD4 0x14 # tee W
+215
View File
@@ -0,0 +1,215 @@
###########################################
#
# Grad School Simulator 2014
#
# "Welcome to the sunless depths of my ennui."
#
###########################################
: main
hires
draw-background
loop
do-behavior
again
: do-behavior
# by AND masking an 8 bit value with 0b1110
# we can create the numbers 0,2,4,8,10,12,14,16:
v0 := random 0b1110
jump0 behavior-table
: behavior-table
# this is a jump table. Each entry
# is 1 instruction long, or 2 bytes:
jump blink
jump blink
jump idle
jump idle
jump grimace
jump show-icon
jump show-icon
jump show-icon
# here I've overlapped two subroutines,
# since they share the same ending instructions:
: blink
blink-toggle
vf := 10 wait
blink-toggle
: idle
vf := 45 wait
;
: blink-toggle
i := blink-mask
v0 := 55
v1 := 26
sprite v0 v1 3
v0 := 65
v1 := 26
sprite v0 v1 3
;
: wait
# takes a time argument in vf.
# vf gets destroyed by +/-/>>/<</sprite
# so we can freely use it as a temp value.
delay := vf
loop
vf := delay
if vf != 0 then
again
;
: grimace
i := grimace-mask
v0 := 59
v1 := 37
sprite v0 v1 1
jump idle
: blink-mask
# this is carefully designed to xor with
# the base image and toggle eye blinks:
0x60 0x60 0xF0
: grimace-mask
# same idea as blink-mask:
0x1C
: show-icon
icon-setup
draw-icon
v1 += -1
draw-icon
v1 += 1
draw-icon
v1 += -1
draw-icon
jump idle
: draw-icon
sprite v1 v2 0
vf := 10 wait
sprite v1 v2 0
;
: icon-setup
# by AND masking an 8 bit value with 0b11000
# we can create the numbers 0, 8, 16 or 24:
v0 := random 0b11000
jump0 icon-setup-table
: icon-setup-table
# this is a jump table. Each entry
# is 4 instructions long, or 8 bytes:
v1 := 27 v2 := 16 i := hungry ;
v1 := 27 v2 := 16 i := cold ;
v1 := 80 v2 := 16 i := tired ;
v1 := 80 v2 := 16 i := busy ;
: hungry # (left side)
0x1F 0x20 0x20 0xD8 0x50 0x06 0xC0 0x02
0x95 0x24 0x95 0x62 0x9F 0x64 0x4E 0x63
0x84 0x21 0x84 0x22 0xC4 0x24 0x84 0x24
0x81 0x02 0x58 0xD2 0x27 0x24 0x00 0x38
: cold # (left side)
0x3F 0xE0 0x40 0x10 0x8C 0x68 0x92 0x08
0x92 0x68 0x92 0x08 0x92 0x68 0x92 0x08
0x92 0x68 0x92 0x08 0xA1 0x68 0xBF 0x08
0xBF 0x08 0x9E 0x07 0x40 0x02 0x3F 0xFC
: tired # (right side)
0x3F 0x80 0x40 0x4C 0xBF 0x2A 0x9F 0x24
0x46 0x10 0x4C 0x0C 0x9F 0x02 0xBF 0x02
0x80 0x79 0x84 0x31 0xA0 0x61 0x82 0xF9
0x40 0x02 0x26 0x3C 0x29 0xC0 0x70 0x00
: busy # (right side)
0x0F 0xE0 0x30 0x10 0x47 0x88 0x47 0x84
0x88 0x44 0x91 0x24 0x91 0x24 0x97 0x24
0x90 0x24 0x88 0x44 0x47 0x88 0x47 0x88
0x20 0x10 0x27 0xE0 0x28 0x00 0x70 0x00
: draw-background
i := background
v0 := 1 # sprite stride
v1 := 0 # sprite x
v2 := 0 # sprite y
loop
# I could draw this in larger chunks by packing
# the data differently, but I like vertical wipes:
sprite v1 v2 1
i += v0
v1 += 8
if v1 == 128 then v2 += 1
if v1 == 128 then v1 := 0
if v2 != 64 then
again
;
: background
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x7C 0x00 0x00 0x00 0x78 0x00 0x00 0x00 0x07 0x80 0x00 0x00 0x00 0x00 0x00
0x00 0xFE 0x00 0x00 0x00 0xFC 0x06 0x00 0x00 0x0F 0xD8 0x00 0x00 0x00 0x00 0x00
0x01 0xC6 0x00 0x00 0x00 0xCC 0x06 0x00 0x06 0x0C 0xD8 0x00 0x0C 0x00 0x00 0x00
0x01 0x86 0x00 0x00 0xE0 0xC0 0x0C 0x00 0x06 0x0C 0x00 0x00 0x0C 0x03 0x00 0x00
0x03 0x80 0xE3 0xC0 0xC0 0xE1 0x8E 0x18 0xCC 0x0E 0x37 0x66 0xD9 0xE3 0x31 0xC0
0x03 0x3C 0xF0 0xE7 0xC0 0x73 0xDF 0x3D 0xEC 0x07 0x37 0xF6 0xD8 0x7F 0xF9 0xE0
0x03 0x3D 0xB7 0xEB 0x80 0x37 0x1B 0x2D 0x78 0x03 0x6D 0x6C 0xB3 0xF6 0x5B 0x60
0x03 0x19 0xBC 0xDB 0x83 0x36 0x3B 0x6F 0x78 0x33 0x6D 0x6D 0xB6 0x66 0xDB 0x60
0x03 0xFB 0x0F 0xDF 0x03 0xF7 0xB6 0x7B 0xD8 0x3F 0xD8 0xCD 0xB7 0xEC 0xF6 0x00
0x01 0xF3 0x07 0x8F 0x01 0xE3 0x37 0x31 0x9C 0x1E 0xD8 0xCF 0x3B 0xCE 0xE6 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xE4 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x03 0xFF 0xF8 0x20 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x07 0xFF 0xFF 0xC0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x07 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x1F 0xFF 0xFF 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x3F 0xFF 0xFF 0xC0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x7F 0xFF 0xFF 0xE0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0xBC 0xFF 0x87 0xF0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x7C 0x3F 0xE7 0xF0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x78 0x03 0xE3 0xB0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x78 0x00 0x03 0xA0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x78 0x09 0x03 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0xF1 0xF1 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0xF0 0xFE 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0xDC 0xDF 0xB2 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x5C 0xD0 0xB2 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x54 0x10 0x82 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x74 0x30 0xC3 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x37 0xF0 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x11 0xD0 0xBA 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x10 0x82 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x0F 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x04 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x03 0xFC 0x00 0x07 0x80 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x06 0xAA 0x00 0x06 0xC0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x0D 0x55 0x1C 0x0D 0x60 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x1A 0xAF 0xC0 0x3A 0xB0 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x1D 0x7F 0x7F 0xFD 0x70 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x3A 0xFA 0x31 0xFE 0xB8 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x35 0xD0 0x5F 0x57 0x58 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x2B 0xA4 0x20 0x83 0xA8 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x75 0x00 0x1F 0x0B 0x5C 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x6B 0xA0 0x0E 0x02 0xAC 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x77 0x00 0x04 0x00 0xDC 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x6A 0x00 0x00 0x01 0xAC 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xF7 0x00 0x00 0x00 0x5E 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xEC 0x00 0x00 0x00 0xFE 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xF4 0x02 0x00 0x00 0x3E 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xF9 0xC0 0x00 0x0D 0xDE 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xFE 0x30 0x00 0x12 0x36 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0xF8 0x50 0x00 0x53 0x9E 0x00 0x00 0x00 0x00 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xE0 0xC9 0x00 0x24 0x43 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0x00 0x00 0x84 0x00 0x00 0xD9 0x48 0x01 0x24 0xC0 0x80 0x00 0x10 0x00 0x00 0x00
0x00 0x20 0x00 0x03 0xC1 0xB3 0x24 0x00 0x29 0x22 0x40 0x60 0x00 0x80 0x00 0x04
0x00 0x00 0x00 0x04 0x21 0x76 0xA7 0xFF 0xF2 0x31 0xA0 0x00 0x00 0x00 0x00 0x40
0x00 0x00 0x7F 0xFB 0x1F 0xFE 0x9D 0x99 0x9E 0xF8 0xFF 0xFF 0xF0 0x00 0x00 0x00
0x55 0x55 0x80 0xDA 0xB8 0x7E 0x7A 0x66 0x67 0xFF 0xE0 0x08 0x0E 0xAA 0xAA 0xAA
0xFF 0xFE 0x61 0x17 0xF0 0xF5 0x9D 0x99 0x99 0xB4 0x07 0xFE 0x7B 0xFF 0xFF 0xFF
0xFF 0xF8 0x32 0x20 0x01 0x08 0x00 0x00 0x00 0x02 0x78 0x01 0x8C 0xFF 0xFF 0xFF
0xFF 0xE1 0x04 0x20 0x06 0x47 0xFF 0xFF 0xFF 0xFC 0x23 0xFC 0xE3 0x3F 0xFF 0xFF
0xFF 0x80 0x83 0xFF 0xF9 0xC0 0x14 0x00 0x08 0x00 0x18 0x00 0x19 0x0F 0xFF 0xFF
0xFF 0xF8 0x00 0x04 0x03 0x80 0x28 0x07 0xFF 0xE2 0x04 0xBF 0x8E 0xDF 0xFF 0xFF
+73
View File
@@ -0,0 +1,73 @@
###########################################
#
# Keyboard Test
#
# A simple live display of which CHIP-8
# keys appear to be held down at any given time.
# useful for testing alternative Keyboard
# layouts or input routines.
#
###########################################
: held 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
: keymap 0x1 0x2 0x3 0xC 0x4 0x5 0x6 0xD 0x7 0x8 0x9 0xE 0xA 0x0 0xB 0xF
: button 0x7E 0xFF 0xFF 0xFF 0xFF 0xFF 0x7E
: main
:const cell 8
:calc start-x { 2 + 32 - ( cell * 4 ) / 2 }
:calc start-y { 1 + 0 }
:calc end-x { start-x + cell * 4 }
:calc end-y { start-y + cell * 4 }
v1 := start-x
v2 := start-y
v3 := 0
loop
i := keymap
i += v3
load v0
i := hex v0
sprite v1 v2 5
v1 += cell
if v1 == end-x then v2 += cell
if v1 == end-x then v1 := start-x
v3 += 1
if v3 != 16 then
again
loop
# unroll this loop fully to try to
# minimize input lag:
:macro scan {
:calc keycode { @ keymap + CALLS }
:calc heldaddr { held + CALLS }
:calc kx { -2 + start-x + cell * floor CALLS % 4 }
:calc ky { -1 + start-y + cell * floor CALLS / 4 }
v1 := keycode
v2 := kx
v3 := ky
i := heldaddr
load v0
if v0 == 0 begin
if v1 key begin
v0 := 1
i := button
sprite v2 v3 7
end
else
if v1 -key begin
v0 := 0
i := button
sprite v2 v3 7
end
end
i := heldaddr
save v0
}
scan scan scan scan
scan scan scan scan
scan scan scan scan
scan scan scan scan
again
+35
View File
@@ -0,0 +1,35 @@
###########################################
#
# MacroMirror
#
# Statically compute vertically or
# horizontally mirrored copies of 8x8 sprites
# using macros and the '@' operator.
# These techniques generalize readily to
# arbitrary-sized memory blocks.
#
# John Earnest
#
###########################################
: main
v1 := 10
i := sprite-1 sprite v0 v0 8
i := sprite-2 sprite v0 v1 8
i := sprite-3 sprite v1 v0 8
i := sprite-4 sprite v1 v1 8
loop again
# see http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits
:macro rev8 X { :byte { 0xFF & ( 0x10101 * ( 0x22110 & 0x0802 * X ) | 0x88440 & 0x8020 * X ) >> 16 } }
:macro mirror-v_ { :byte { @ from + 7 - HERE - to } }
:macro mirror-h_ { :calc t { @ from + HERE - to } rev8 t }
:macro mirror-8 BASE OP { :calc to { HERE } :calc from { BASE } OP OP OP OP OP OP OP OP }
:macro mirror-v BASE { mirror-8 BASE mirror-v_ }
:macro mirror-h BASE { mirror-8 BASE mirror-h_ }
: sprite-1 0x18 0x2C 0x46 0x83 0xEF 0x2C 0x2C 0x3C
: sprite-3 0x18 0x14 0xF2 0x81 0xF3 0xF6 0x1C 0x18
: sprite-2 mirror-v sprite-1
: sprite-4 mirror-h sprite-3
+80
View File
@@ -0,0 +1,80 @@
###########################################
#
# Mondri8
#
# Draw random compositions in the style
# of Piet Mondrian. When drawing completes,
# press any Chip8 key to draw another.
#
###########################################
:const LINE_COUNT 10
:const FILL_COUNT 5
:alias x v0
:alias y v1
:alias px v2 # x position when scanning
:alias py v3 # y position when scanning
:alias dx v4 # change (delta) in x position when scanning
:alias dy v5 # change (delta) in y position when scanning
:alias counter v6
: main
hires
i := point
loop
counter := LINE_COUNT
loop
somewhere h-line
somewhere v-line
counter += -1
if counter != 0 then
again
counter := FILL_COUNT
loop
somewhere fill
counter += -1
if counter != 0 then
again
v0 := key
clear
again
: somewhere
x := random 0xFF
y := random 0xFF
;
: scan
loop
sprite px py 1
while vf == 0
px += dx
py += dy
again
sprite px py 1
;
: v-line
px := x dx := 0
py := y dy := -1 scan
py := y dy := 1 py += dy scan
;
: h-line
py := y dy := 0
px := x dx := -1 scan
px := x dx := 1 px += dx scan
;
: fill
loop
h-line
y += 1
sprite x y 1
while vf == 0
again
sprite x y 1
;
: point 0x80
File diff suppressed because it is too large Load Diff
+295
View File
@@ -0,0 +1,295 @@
###########################################
#
# Outlaw
#
# An adaptation of the Atari 2600 game
# "Outlaw" for the Chip8.
#
# Move with ASWD and fire with E.
# Holding a direction while firing will
# fire an angled shot, which ricochets.
# Plays fairly well at 30 cycles/frame
#
###########################################
: cactus 0x38 0x38 0x3B 0x1B 0x1B 0x1B 0xDF 0xDE 0xD8 0xD8 0xF8 0x78 0x18 0x1C 0x0C
: left 0x00 0x00 0x70 0xF8 0x70 0x67 0x7C 0x60 0x60 0x78 0x28 0xEC
: lwalk1 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3
: lwalk2 0x18 0x3E 0x1C 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x36
: right 0x00 0x00 0x06 0x1F 0x0E 0xE6 0x3E 0x06 0x06 0x1E 0x14 0x37
: rwalk1 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x66 0xC3
: rwalk2 0x18 0x7C 0x38 0x18 0x7E 0x99 0x99 0x99 0x5A 0x3C 0x24 0x6C
: edge 0xFF 0xFF
: bullet 0x80
###########################################
#
# Register map
#
###########################################
:alias leftx ve
:alias lefty vd
:alias leftframe vc
:alias leftbx vb
:alias leftby va
:alias leftfire v9
:alias rightx v8
:alias righty v7
:alias rightframe v6
:alias rightbx v5
:alias rightby v4
:alias rightfire v3
:const FIRE_ST 1
:const FIRE_UP 2
:const FIRE_DN 3
# v0-v2 and vf are left as temporaries
###########################################
#
# Bullets
#
###########################################
: fire-left-bullet
v0 := 6
if v0 -key then return
leftfire := FIRE_ST
v0 := 5
if v0 key then leftfire := FIRE_UP
v0 := 8
if v0 key then leftfire := FIRE_DN
# spawn bullet
leftbx := leftx
leftbx += 9
leftby := lefty
leftby += 5
# draw initial bullet frame
i := bullet
sprite leftbx leftby 1
;
: move-left-bullet
sprite leftbx leftby 1
leftbx += 1
if leftfire == FIRE_UP then leftby += -1
if leftfire == FIRE_DN then leftby += 1
# bounce off top and bottom edge
if leftby == 1 then leftfire := FIRE_DN
if leftby == 30 then leftfire := FIRE_UP
# despawn on right edge
if leftbx == 63 then leftfire := 0
if leftfire == 0 then return
sprite leftbx leftby 1
# collide with obstacles
if vf == 0 then return
leftfire := 0
;
: fire-right-bullet
if rightfire != 0 then return
rightfire := FIRE_ST
v0 := random 0b11
if v0 == 1 then rightfire := FIRE_UP
if v0 == 2 then rightfire := FIRE_DN
# spawn bullet
rightbx := rightx
rightbx += -1
rightby := righty
rightby += 5
# draw initial bullet frame
i := bullet
sprite rightbx rightby 1
;
: move-right-bullet
sprite rightbx rightby 1
rightbx += -1
if rightfire == FIRE_UP then rightby += -1
if rightfire == FIRE_DN then rightby += 1
# bounce off top and bottom edge
if rightby == 1 then rightfire := FIRE_DN
if rightby == 30 then rightfire := FIRE_UP
# despawn on right edge
if rightbx == 0 then rightfire := 0
if rightfire == 0 then return
sprite rightbx rightby 1
# collide with obstacles
if vf == 0 then return
rightfire := 0
;
###########################################
#
# Gunslingers
#
###########################################
: move-left-player
v1 := leftx
v2 := lefty
# process movement keys
v0 := 7
if v0 key then v1 += -1
v0 := 9
if v0 key then v1 += 1
v0 := 5
if v0 key then v2 += -1
v0 := 8
if v0 key then v2 += 1
# animate player movement
v0 := 0
if v1 != leftx then v0 := 24
if v2 != lefty then v0 := 24
if leftframe == 24 then v0 := 12
vf := 6
if vf key then v0 := 0
# clamp position within left side
if v1 == 0 then v1 := 1
if v1 == 21 then v1 := 20
if v2 == 0 then v2 := 1
if v2 == 18 then v2 := 17
# update position
i := left
i += leftframe
sprite leftx lefty 12
leftx := v1
lefty := v2
leftframe := v0
i := left
i += leftframe
sprite leftx lefty 12
;
: brain-table
v1 += -1 return
v1 += 1 return
v2 += -1 return # vertical movement is 2x as likely
v2 += -1 return # as horizontal movement
v2 += 1 return
v2 += 1 return
v0 := v0 return # do nothing
fire-right-bullet return
: do-brain
v0 := random 0b11100 # entries are 4 bytes each
jump0 brain-table
: move-right-player
v1 := rightx
v2 := righty
# process (random) movement
do-brain
# animate movement
v0 := 0
if v1 != rightx then v0 := 24
if v2 != righty then v0 := 24
if rightframe == 24 then v0 := 12
# clamp position within right side
if v1 == 35 then v1 := 36
if v1 == 56 then v1 := 55
if v2 == 0 then v2 := 1
if v2 == 18 then v2 := 17
# update position
i := right
i += rightframe
sprite rightx righty 12
rightx := v1
righty := v2
rightframe := v0
i := right
i += rightframe
sprite rightx righty 12
;
###########################################
#
# Main
#
###########################################
: rightdead
sprite rightx righty 12
i := bullet
sprite leftbx leftby 1
: gameover
v0 := 32
buzzer := v0
delay := v0
loop
v0 := delay
if v0 != 0 then
again
jump main
: leftdead
sprite leftx lefty 12
i := bullet
sprite rightbx rightby 1
jump gameover
: main
# initialize state
leftx := 5
lefty := 10
leftframe := 0
rightx := 51
righty := 10
rightframe := 0
leftfire := 0
rightfire := 0
# draw background
clear
i := cactus
v0 := 28
v1 := 9
sprite v0 v1 15
i := edge
v0 := 0
v1 := 31
loop
sprite v0 v1 2
v0 += 8
if v0 != 64 then
again
i := left
sprite leftx lefty 12
i := right
sprite rightx righty 12
# main game loop
loop
move-left-player
if vf != 0 then jump leftdead
move-right-player
if vf != 0 then jump rightdead
i := bullet
if leftfire != 0 then move-left-bullet
if leftfire == 0 then fire-left-bullet
if rightfire != 0 then move-right-bullet
again
+39
View File
@@ -0,0 +1,39 @@
###########################################
#
# Sinusoid
#
# Demonstrate :calc and :macro by computing
# a sinusoidal lookup table at compile time.
#
# John Earnest
#
###########################################
: main
hires
loop
scroll-down 2
i := table
i += v2
load v1
i := thin
sprite v0 v3 2
i := thick
sprite v1 v3 2
v2 += 2
again
: thin 0x0F 0x0F
: thick 0xFF 0xFF
: table
:macro S2 {
:calc rads { ( HERE - table ) * ( 2 * PI ) / 256 }
:byte { 56 + 38 * sin rads }
:byte { 56 + 16 * cos rads }
}
# expand S2 2*8*8 times for a 256-byte table:
:macro S1 { S2 S2 S2 S2 S2 S2 S2 S2 }
:macro S0 { S1 S1 S1 S1 S1 S1 S1 S1 }
S0 S0
+805
View File
@@ -0,0 +1,805 @@
###########################################
#
# Slippery Slope
#
# built for Octojam 2018.
# level editor: http://beyondloom.com/tools/slipedit.html
#
# John Earnest
#
###########################################
:const MODE-INPUT 0
:const MODE-MOVE 1
:const MODE-NEXT 2
:const MODE-RESET 3
:const FINAL_LEVEL 0xA
# v0-v2 are reserved as temporaries.
:alias px vD # player x position (tiles)
:alias py vC # player y position (tiles)
:alias pdir vB # player direction ( E N W S )
:alias pmode vA # see MODE-XXX
:alias gx v9 # goal x position
:alias gy v8 # goal y position
:alias gf v7 # goal frame (0,5,10,15)
:alias level v6 # current level no.
:alias move-dx v5 # x amount player moved this step
:alias move-dy v4 # y amount player moved this step
:alias move-dir v3 # temporary direction
:alias load-ti vD # tile index
:alias load-tx vC # x position
:alias load-ty vB # y position
:alias copy-off vE # when unpacking, offset
:alias copy-lvl vD # when unpacking, level index
###########################################
#
# Utilities
#
###########################################
:macro temp-begin { :calc there { HERE } :org 0 }
:macro temp-end { :org there }
:macro xor_ { :byte { ( @ a + HERE - to ) ^ @ b + HERE - to } }
:macro xor A B { :calc to { HERE } :calc a { A } :calc b { B }
xor_ xor_ xor_ xor_ xor_ }
:macro sync N {
loop
vf := delay
if vf != 0 then
again
vf := N
delay := vf
}
:macro copy-2 SRC DST {
i := SRC load v1
i := DST save v1
}
:macro times-5 SRC DST {
DST := SRC
DST <<= DST
DST <<= DST
DST += SRC
}
:macro times-6 SRC DST {
DST := SRC
DST += SRC
DST += SRC
DST += DST
}
:macro to-tile SX SY DX DY {
times-5 SX DX DX += 2
times-5 SY DY DY += 1
}
###########################################
#
# Step Counter
#
###########################################
: step-total 0 0 # high 2 digits, low 2 digits
: step-level 0 0
: step-bcd 0 0 0
:macro steps-clear {
v0 := 0
v1 := 0
i := step-total
save v1
i := step-level
save v1
}
:macro steps-inc {
i := step-level
load v1
v1 += 1
if v1 == 100 begin
v0 += 1
v1 := 0
end
if v0 == 100 begin
# cap at 9999
v1 := 99
v0 := 99
end
i := step-level
save v1
}
:macro steps-reset-level { copy-2 step-total step-level }
:macro steps-next-level { copy-2 step-level step-total }
:macro steps-show-digits SRC {
i := SRC
load v0
i := step-bcd
bcd v0
load v2
i := hex v1
sprite v3 v4 5
v3 += 5
i := hex v2
sprite v3 v4 5
v3 += 5
}
:macro steps-show { # at v3,v4
steps-show-digits step-level
:calc low-digits { 1 + step-level }
steps-show-digits low-digits
}
###########################################
#
# Level Representation
#
###########################################
:const board-rows 6
:const board-cols 12
:calc board-size { board-rows * board-cols }
: board
00 00 00 00 00 00
00 00 00 05 00 00
00 00 05 00 05 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
: goal-position 10 03 # (x tiles, y tiles)
: start-position 02 03 # (x tiles, y tiles)
: level-unpack-stash
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
:macro level-base-addr {
v0 := copy-lvl
i := level-data
loop
while v0 != 1
v0 += -1
vf := 76
i += vf
again
}
: level-unpack
# we need most of the registers for bulk copying,
# so stash the entire register file in a buffer:
vf := level
i := level-unpack-stash
save vf
# copy tile data
copy-off := 0 # source/dest offset
copy-lvl := vf # level index
loop
level-base-addr
i += copy-off
load vb
i := board
i += copy-off
save vb
copy-off += 12
if copy-off != 72 then
again
# copy goal/start positions
level-base-addr
i += copy-off
load v3
i := goal-position
save v3
i := level-unpack-stash
load vf
;
###########################################
#
# Text
#
###########################################
: let-A 0xF0 0xB0 0xF0 0xB0
: let-D 0xE0 0xB0 0xB0 0xE0
: let-E 0xF0 0xE0 0xC0 0xF0
: let-G 0xF0 0xC0 0xD0 0xF0
: let-H 0xB0 0xF0 0xB0 0xB0
: let-I 0xC0 0x00 0xC0 0xC0
: let-L 0xC0 0xC0 0xC0 0xE0
: let-M 0xD8 0xE8 0xC8 0xC8
: let-N 0xE0 0xF0 0xD0 0xD0
: let-O 0xF0 0xB0 0xB0 0xF0
: let-P 0xF0 0xB0 0xF0 0x80
: let-R 0xF0 0xF0 0xA0 0x90
: let-S 0xF0 0xE0 0x30 0xF0
: let-T 0xF0 0x60 0x60 0x60
: let-V 0xB0 0xB0 0xB0 0x60
: let-Y 0xB0 0xF0 0x30 0xF0
:stringmode print " " {
v0 += 4
}
:stringmode print "ADEGHILMNOPRSTVY" {
:calc S { let-A + VALUE * 4 }
i := S
sprite v0 v1 4
# compute the width of each glyph statically:
:calc p { ( @ S ) | ( @ 1 + S ) | ( @ 2 + S ) | ( @ 3 + S ) }
:calc w { 9 - ( log p & - p ) / log 2 }
v0 += w
}
:macro draw-title {
v0 := 14
v1 := 4
print "SLIPPERY"
v0 := 20
v1 := 24
print "SLOPE"
}
:macro draw-gameover {
v0 := 15
v1 := 12
print "THE END"
v3 := 8
v4 := 20
steps-show
v0 := v3
v1 := v4
print " STEPS"
}
:macro draw-levelno {
v0 := 17
v1 := 12
print "LEVEL "
i := hex level
sprite v0 v1 5
}
###########################################
#
# Player And Movement
#
###########################################
: stand 0x20 0x70 0x70 0x30 0x20
0x20 0x70 0x70 0x70 0x50
0x20 0x70 0x70 0x60 0x20
0x20 0x70 0xF8 0x70 0x50
: slide 0x20 0x38 0x30 0x38 0x48
0x20 0xF0 0x78 0xB0 0x90
0x20 0xE0 0x60 0xE0 0x90
0x20 0xF8 0x70 0x70 0x48
:macro draw-player {
times-5 pdir v0
i += v0
to-tile px py v0 v1
sprite v0 v1 5
}
:macro draw-stand { i := stand draw-player }
:macro draw-slide { i := slide draw-player }
: deltas 1 0 0 -1 -1 0 0 1
: dirs-\ 3 2 1 0
: dirs-/ 1 0 3 2
:macro at-edge REG DELTA VAL {
if REG == VAL begin
REG -= DELTA
pmode := MODE-INPUT
end
}
:macro get-current-tile {
times-6 px v0
v0 += py
i := board
i += v0
load v0
v1 := v0
}
:macro set-current-tile {
times-6 px v0
v0 += py
i := board
i += v0
v0 := v1
save v0
}
:macro draw-current-tile {
i := tiles
i += v1
times-5 px v0
times-5 py v1
v0 += 2
v1 += 1
sprite v0 v1 5
}
:macro change-dir TABLE {
i := TABLE
i += pdir
load v0
pdir := v0
}
:macro move-player {
loop
# move in facing direction
i := deltas
i += pdir
i += pdir
load v1
move-dx := v0
move-dy := v1
px += move-dx
py += move-dy
# out of bounds?
at-edge px move-dx -1
at-edge px move-dx 12
at-edge py move-dy -1
at-edge py move-dy 6
# at goal?
to-tile px py v0 v1
v0 ^= gx
v1 ^= gy
v0 |= v1
if v0 == 0 then pmode := MODE-NEXT
# check current cell (into v1)
get-current-tile
if v1 == tile-wall begin
px -= move-dx
py -= move-dy
pmode := MODE-INPUT
end
if v1 == tile-hole begin
pmode := MODE-RESET
end
if v1 == tile-mir-\ begin
change-dir dirs-\
end
if v1 == tile-mir-/ begin
change-dir dirs-/
end
if v1 == tile-flip-\ begin
change-dir dirs-\
draw-current-tile
v1 := tile-flop-/
set-current-tile
draw-current-tile
v1 := 0 # avoid fallthrough!
end
if v1 == tile-flop-/ begin
change-dir dirs-/
draw-current-tile
v1 := tile-flip-\
set-current-tile
draw-current-tile
v1 := 0 # avoid fallthrough!
end
if v1 >= tile-ground begin
draw-current-tile
pmode := MODE-INPUT
end
while pmode == MODE-MOVE
draw-slide
animate-goal
sync 5
draw-slide
again
}
:macro poll-key KEY DIR {
vf := KEY if vf key begin
pmode := MODE-MOVE
move-dir := DIR
end
}
:macro poll-player {
poll-key OCTO_KEY_D 0
poll-key OCTO_KEY_W 1
poll-key OCTO_KEY_A 2
poll-key OCTO_KEY_S 3
if pmode == MODE-MOVE begin
steps-inc
draw-stand
get-current-tile
if v1 >= tile-ground begin
draw-current-tile
end
pdir := move-dir
move-player
draw-stand
end
if level != 0 begin
vf := OCTO_KEY_E
if vf key then pmode := MODE-RESET
end
}
###########################################
#
# Level Display
#
###########################################
: line 0xFF # top and bottom edge
: corner 0x80 # 1px
: wall 0xC0 0xC0 0xC0 0xC0 0xC0 # 2x15 pixels
0xC0 0xC0 0xC0 0xC0 0xC0
0xC0 0xC0 0xC0 0xC0 0xC0
:macro draw-border {
i := wall
v0 := 0
v1 := 62
v2 := 1
sprite v0 v2 15
sprite v1 v2 15
v2 := 16
sprite v0 v2 15
sprite v1 v2 15
i := line
v1 := 0
v2 := 31
loop
sprite v0 v1 1
sprite v0 v2 1
v0 += 8
if v0 != 64 then
again
i := corner
v0 := 2
v1 := 61
v2 := 1
sprite v0 v2 1
sprite v1 v2 1
v2 := 30
sprite v0 v2 1
sprite v1 v2 1
}
temp-begin
: tgoal-1 0x50 0x80 0x08 0x80 0x50
: tgoal-2 0x50 0x88 0x00 0x88 0x20
: tgoal-3 0x50 0x08 0x80 0x08 0x50
temp-end
: goal-0 0x20 0x88 0x00 0x88 0x50
: goal-1 xor goal-0 tgoal-1
: goal-2 xor tgoal-1 tgoal-2
: goal-3 xor tgoal-2 tgoal-3
: goal-4 xor tgoal-3 goal-0
:macro init-goal {
gf := 0
i := goal-0
sprite gx gy 5
}
:macro animate-goal {
i := goal-1
i += gf
sprite gx gy 5
gf += 5
if gf == 20 then gf := 0
}
: tiles 0x00 0x00 0x00 0x00 0x00 # empty space
0xF8 0xF8 0xF8 0xF8 0xF8 :const tile-wall 5
0x88 0x50 0x20 0x50 0x88 :const tile-hole 10
0x80 0x40 0x20 0x10 0x08 :const tile-mir-\ 15
0x08 0x10 0x20 0x40 0x80 :const tile-mir-/ 20
0x80 0x60 0x50 0x30 0x08 :const tile-flip-\ 25
0x08 0x30 0x70 0x60 0x80 :const tile-flop-/ 30
0x50 0x88 0x88 0x88 0x70 :const tile-ground 35
0x58 0x80 0x80 0x80 0x78
0x88 0x88 0x88 0x88 0x70
0x80 0x80 0x80 0x80 0x78
0x50 0x08 0x08 0x08 0xF0
0x58 0x00 0x00 0x00 0xF8
0x08 0x08 0x08 0x08 0xF0
0x00 0x00 0x00 0x00 0xF8
0x50 0x88 0x88 0x88 0x88
0x58 0x80 0x80 0x80 0x80
0x88 0x88 0x88 0x88 0x88
0x80 0x80 0x80 0x80 0x80
0x50 0x08 0x08 0x08 0x08
0x58 0x00 0x00 0x00 0x00
0x08 0x08 0x08 0x08 0x08
0x00 0x00 0x00 0x00 0x00
:macro load-tile REG Y {
i := tiles
i += REG
load-ty := Y
sprite load-tx load-ty 5
}
: load-level
clear
draw-border
load-ti := 0
load-tx := 2
loop
i := board
i += load-ti
load v5
load-tile v0 1
load-tile v1 6
load-tile v2 11
load-tile v3 16
load-tile v4 21
load-tile v5 26
load-tx += 5
load-ti += board-rows
if load-ti != board-size then
again
i := goal-position
load v3
to-tile v0 v1 gx gy
init-goal
px := v2
py := v3
pdir := 3
pmode := MODE-INPUT
draw-stand
;
:macro try-key KEY {
vf := KEY
while vf -key
}
:macro wait-key {
v4 := random 3
i := deltas
i += v4
i += v4
load v1
v0 += v0
v2 := random 63
v3 := random 31
i := slide
i += v4
i += v4
i += v4
i += v4
i += v4
sprite v2 v3 5
loop
sprite v2 v3 5
v2 += v0
v3 += v1
sprite v2 v3 5
try-key OCTO_KEY_E
try-key OCTO_KEY_A
try-key OCTO_KEY_S
try-key OCTO_KEY_W
try-key OCTO_KEY_D
again
}
###########################################
#
# Main
#
###########################################
: main
load-level
draw-title
loop
loop
poll-player
while pmode == MODE-INPUT
animate-goal
sync 5
again
if pmode == MODE-RESET begin
steps-reset-level
level-unpack
load-level
end
if pmode == MODE-NEXT begin
clear
if level == FINAL_LEVEL begin
level := 1
draw-gameover
steps-clear
steps-inc # start screen takes 1 move
else
level += 1
draw-levelno
end
steps-next-level
level-unpack
wait-key
load-level
end
again
###########################################
#
# Level Data
#
###########################################
: level-data
: level-1 # just walls and sliding
05 05 05 00 00 00
05 00 00 00 00 00
05 00 00 00 00 00
00 00 05 00 00 05
00 00 05 00 00 05
05 05 05 00 00 05
00 00 00 00 00 05
00 00 00 05 05 05
00 00 00 00 00 05
05 00 00 00 00 00
05 00 00 00 05 00
05 05 05 05 05 00
10 03 04 01
: level-2 # more walls and sliding
00 00 00 00 00 05
00 05 00 00 00 05
05 00 00 00 00 05
05 00 00 00 05 05
05 05 00 00 05 05
00 00 00 00 00 05
05 05 00 00 00 05
05 00 00 00 00 05
05 00 00 00 05 05
05 00 00 00 00 05
00 00 00 00 00 05
00 00 00 00 05 05
05 00 01 04
: level-3 # introduce mirrors
05 05 05 05 05 05
05 05 00 00 00 05
05 05 00 00 00 05
05 00 00 00 00 05
05 00 00 20 00 00
05 00 00 00 00 00
05 05 00 00 00 05
05 05 05 00 05 05
05 05 00 00 00 05
05 05 00 00 00 05
05 05 00 00 00 05
05 05 05 05 05 05
09 03 02 03
: level-4 # many mirrors
00 00 00 00 00 00
00 00 00 00 00 20
15 00 00 00 00 00
00 05 00 00 00 00
00 00 00 00 15 00
00 20 00 00 00 00
00 00 00 00 00 00
00 00 00 00 00 00
15 00 00 05 00 20
00 15 00 00 00 00
00 00 00 00 00 00
00 00 00 15 00 00
10 03 01 01
: level-5 # mild mirror maze
00 20 00 00 15 00
00 00 00 00 00 00
00 00 00 00 00 20
15 00 00 00 00 00
20 00 00 00 00 00
15 00 15 00 00 20
20 20 15 20 00 15
15 00 00 00 00 20
20 20 00 00 00 15
15 00 00 15 00 20
10 20 15 00 00 15
00 20 15 20 15 20
11 00 00 02
: level-6 # introduce ground
10 10 10 10 10 10
10 00 00 00 00 10
10 00 00 00 00 10
10 00 00 00 00 10
10 00 00 00 00 10
10 00 80 50 00 10
10 00 95 65 00 10
10 00 00 00 00 10
10 00 00 00 00 10
10 00 00 00 00 10
10 00 00 00 00 10
10 10 10 10 10 10
09 03 02 02
: level-7 # good clean fun with ground + mirrors
00 00 00 55 00 00
00 00 00 00 00 05
05 15 00 00 00 00
00 00 00 20 00 75
00 00 00 00 00 00
05 05 05 00 00 00
05 05 05 00 20 00
05 20 00 00 20 00
00 00 00 15 00 00
00 00 00 00 00 00
00 00 00 00 00 00
90 50 00 10 00 20
03 00 08 00
: level-8 # introduce flip-flops
05 05 05 05 05 05
05 05 05 05 05 05
05 05 05 00 05 05
05 05 05 00 05 05
05 00 00 30 00 00
05 05 00 00 05 05
05 05 00 00 05 05
00 00 25 00 00 05
05 05 00 05 05 05
05 05 00 05 05 05
05 05 05 05 05 05
05 05 05 05 05 05
09 02 02 03
: level-9 # mirror maze with a few flip-flops
15 20 00 00 20 15
00 00 15 00 35 00
20 00 00 00 00 20
00 15 00 00 00 15
00 30 00 20 00 00
45 00 00 00 00 20
00 20 15 20 00 00
00 00 00 00 25 00
20 00 20 00 00 20
00 00 00 20 35 00
00 00 00 00 15 00
20 15 00 20 00 20
02 02 10 01
: level-A # many flip-flops
00 00 10 05 05 00
00 00 00 10 05 00
05 05 00 00 00 00
50 00 25 00 00 20
70 00 30 00 00 15
70 00 30 30 00 20
70 00 30 30 00 15
70 00 25 00 00 20
70 00 30 25 00 15
65 00 30 00 00 20
00 00 05 00 00 00
00 00 05 00 00 00
00 05 11 01
+382
View File
@@ -0,0 +1,382 @@
###########################################
#
# Snow Daze
#
# Clear all the snow off your driveway
# before you're late for work!
# Press ASWD to move around the driveway
# and press E to shovel snow behind you.
# Runs best at 100 cycles/frame.
#
# Created for the 2015 CCP Game Jam
# Theme: Winter
#
###########################################
:alias px va
:alias py vb
:alias dir vc
:alias frame vd
:alias timer v9
:alias timerx v8
:alias endflag v7
:const LEFT 45
:const RIGHT 0
:const TICK_TIME 8
:const SNOWFALL 8
: draw-image
v0 := 0
v1 := 0
v2 := 32
loop
sprite v0 v1 0
i += v2
v0 += 16
if v0 == 128 begin
v0 := 0
v1 += 16
end
if v1 != 64 then
again
;
: draw-player
i := person-r
i += dir
i += frame
sprite px py 15
;
: do-snow
i := snow
v3 := 0
loop
v1 := random 0b111111
v1 += 32
v2 := random 0b11111
v2 += 16
sprite v1 v2 15
v0 := 5 wait
v3 += 1
if v3 != SNOWFALL then
again
;
: do-scoop
frame := 15
draw-player
v0 := 5 gamewait
draw-player
frame := 30
draw-player
v0 := 5 gamewait
draw-player
frame := 0
v1 := py
i := snow
:macro scoop DELTA1 DELTA2 {
v0 := px
v0 += DELTA1
sprite v0 v1 15
if vf == 0 begin
sprite v0 v1 15
else
v0 += DELTA2
sprite v0 v1 15
if vf == 1 then sprite v0 v1 15
end
}
if dir == LEFT begin
scoop -8 16
else
scoop 8 -16
end
;
: move-player
vf := 5 if vf key begin
if py != 10 then py += -1
end
vf := 8 if vf key begin
if py != 0x31 then py += 1
end
vf := 7 if vf key begin
px += -1
dir := LEFT
end
vf := 9 if vf key begin
px += 1
dir := RIGHT
end
vf := 6 if vf key then do-scoop
;
: countdown
if timer == 0 begin
timer := TICK_TIME
vf := 4
i := timeslice
sprite timerx vf 3
timerx += -1
if timerx == 3 then endflag := 1
else
timer += -1
end
;
: gamewait
loop
sync
countdown
v0 += -1
if v0 != 0 then
again
;
: wait
loop
sync
v0 += -1
if v0 != 0 then
again
;
: game-over
draw-player
v0 := 20 wait
v1 := 32
v2 := 15
v3 := 0
i := block
loop
sprite v1 v2 0
if vf != 0 then v3 += 1
v0 := 5 wait
sprite v1 v2 0
v1 += 16
if v1 == 96 begin
v1 := 32
v2 += 16
end
if v2 != 63 then
again
i := bighex v3
v1 := 60
v2 := 14
sprite v1 v2 10
v0 := 20 wait
v0 := key
setup
;
: sync
loop
vf := delay
if vf != 0 then
again
vf := 2
delay := vf
;
: intro-num
i := bighex v0
v1 := 60
v2 := 14
sprite v1 v2 10
v0 := 10 wait
sprite v1 v2 10
;
: setup
clear
i := background
draw-image
timerx := 123
timer := 0
px := 64
py := 32
endflag := 0
draw-player
do-snow
v0 := 10 wait
v0 := 3 intro-num
v0 := 2 intro-num
v0 := 1 intro-num
;
: main
hires
setup
loop
draw-player
move-player
draw-player
countdown
if endflag == 1 then game-over
sync
again
: timeslice
0x80 0x80 0x80
: block
0x00 0x00 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE
0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE
0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x7F 0xFE
0x7F 0xFE 0x7F 0xFE 0x7F 0xFE 0x00 0x00
: snow
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x7E 0x7E 0x7E 0x00
: person-r
0x38 0x38 0x28 0x3C 0x78 0x70 0x78 0x78
0xF8 0xF8 0xFB 0x7F 0x4F 0x4B 0x6C
: scoop1-r
0x00 0x1C 0x1C 0x14 0x1E 0x7C 0xF8 0xF8
0xFC 0xFC 0xFC 0x7F 0x4F 0x4F 0x6F
: scoop2-r
0xC0 0xCE 0x4E 0x6A 0x7F 0xFE 0x78 0x7E
0x7C 0xF8 0xF8 0xF8 0x38 0x48 0x6C
: person-l
0x1C 0x1C 0x14 0x3C 0x1E 0x0E 0x1E 0x1E
0x1F 0x1F 0xDF 0xFE 0xF2 0xD2 0x36
: scoop1-l
0x00 0x38 0x38 0x28 0x78 0x3E 0x1F 0x1F
0x3F 0x3F 0x3F 0xFE 0xF2 0xF2 0xF6
: scoop2-l
0x03 0x73 0x72 0x56 0xFE 0x7F 0x1E 0x7E
0x3E 0x1F 0x1F 0x1F 0x1C 0x12 0x36
: background # (1024 bytes)
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xE0 0x00
0xEF 0xFF 0xEF 0xFF 0xEF 0xFF 0xE0 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFE 0xFF 0xFE 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7F 0xFF 0x7F 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x00
0xFF 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 0x07
0xFF 0xF7 0xFF 0xF7 0xFF 0xF7 0x00 0x07
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFC 0xFF 0xFE
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x7F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFE
0xFF 0xFF 0xFF 0xFF 0xF8 0xFB 0x00 0x00
0xFF 0xFE 0xFF 0xFE 0xFF 0xFE 0xFF 0xFE
0xFF 0xFC 0xFF 0xFC 0xFF 0xEE 0xFF 0xFE
0xFF 0xFE 0xFF 0xFE 0xFF 0xFC 0xFF 0xF8
0xFF 0xB8 0xFF 0xF0 0x8F 0xC0 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x5F 0xFF 0x7F 0xFF 0x7F 0xFF 0x7F 0xFF
0x3F 0xFF 0x5F 0xFF 0x7F 0xFF 0x7F 0xFF
0x3F 0xFF 0x3E 0xFF 0x3F 0xFF 0x1F 0xFF
0x0F 0xDF 0x01 0xFF 0x00 0x3D 0x00 0x00
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x7F
0xFF 0xFF 0xFF 0xFF 0xFE 0x1F 0x00 0x00
+188
View File
@@ -0,0 +1,188 @@
###########################################
#
# Sw8 Copter
#
# An adaptation of "Swing Copters"
# for the Super Chip8.
# Runs best at 100 cycles/frame.
#
# Press E to start a game and then
# press E to switch directions.
# Avoid obstacles!
#
###########################################
:alias score v7
:alias collide v8
:alias player-key v9
:alias player-x va
:alias player-y vb
:alias player-frame vc
:alias player-dir vd
:const H_SPEED 3
:const BUTTON 6
: sync
loop
vf := delay
if vf != 0 then
again
vf := 2
delay := vf
;
: girders
i := girder
v0 := 88
v1 := 8
loop
sprite v0 v1 0
v0 += 16
if v0 != 168 then
again
;
: draw-copter
i := face-l
if player-dir == H_SPEED then i := face-r
collide := 0
sprite player-x player-y 0
collide |= vf
i := blade-0
if player-frame == 1 then i := blade-1
v0 := 16
v0 =- player-y
sprite player-x v0 0
collide |= vf
;
: wait-release
if v0 key then return
player-key := 0
;
: switch-dir
v0 := BUTTON
if player-key != 0 then jump wait-release
if v0 -key then return
player-key := 1
# (~x)+1 = -x
v0 := 0xFF
player-dir ^= v0
player-dir += 1
;
: move-up
player-y += -1
v0 := 63
v0 &= player-y
if v0 == 0 then score += 1
;
: move-copter
v0 := 1
player-frame ^= v0
move-up
v0 := random 1
if v0 == 1 then move-up
player-x += player-dir
switch-dir
;
: wait-key
v0 := 56
v1 := 18
i := tapbubble
sprite v0 v1 0
vf := BUTTON
loop
if vf -key then
again
sprite v0 v1 0
;
: game-over
vf := 16
buzzer := vf
delay := vf
loop
draw-copter
scroll-left
draw-copter
draw-copter
scroll-right
draw-copter
draw-copter
scroll-right
draw-copter
draw-copter
scroll-left
draw-copter
vf := delay
if vf != 0 then
again
: show-score
i := bcd-buffer
bcd score
load v2
i := bighex v1
v0 := 55
v1 := 30
sprite v0 v1 10
i := bighex v2
v0 += 9
sprite v0 v1 10
vf := BUTTON
loop
if vf -key then
again
clear
: main
hires
player-x := 56
player-y := 48
player-dir := H_SPEED
player-key := 0
score := 0
girders
draw-copter
wait-key
loop
draw-copter
move-copter
draw-copter
if collide != 0 then jump game-over
sync
again
: bcd-buffer 0 0 0
: blade-0
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x01 0x80 0x02 0x40 0x7A 0x5E 0x89 0x91 0xF0 0x0F 0x01 0x80 0x01 0x80 0x00 0x00
: blade-1
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x01 0x80 0x02 0x40 0x0E 0xF0 0x31 0x0C 0x3E 0xFC 0x01 0x80 0x01 0x80 0x00 0x00
: face-r
0x07 0xC0 0x18 0x30 0x20 0x08 0x23 0xB8 0x44 0x44 0x48 0x8A 0x48 0x02 0x48 0x02
0x34 0x44 0x23 0xB8 0x30 0x08 0x4B 0xF4 0x48 0x14 0x30 0x18 0x11 0x20 0x0F 0xC0
: face-l
0x03 0xE0 0x0C 0x18 0x10 0x04 0x1D 0xC4 0x22 0x22 0x51 0x12 0x40 0x12 0x40 0x12
0x22 0x2C 0x1D 0xC4 0x10 0x0C 0x2F 0x92 0x28 0x12 0x18 0x0C 0x04 0x88 0x03 0xF0
: girder
0xFF 0xFF 0x00 0x00 0xC3 0xC3 0x7E 0x7E 0x3C 0x3C 0x3C 0x3C 0x3C 0x3C 0x7E 0x7E
0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: tapbubble
0x3F 0xFC 0x7F 0xFE 0xFF 0xFF 0xF0 0x0F 0xF0 0x0F 0xF3 0xFF 0xF0 0x7F 0xF0 0x7F
0xF3 0xFF 0xF0 0x0F 0xF0 0x0F 0xFF 0xFF 0x7F 0xFE 0x3F 0xFC 0x00 0xC0 0x00 0x80
+39
View File
@@ -0,0 +1,39 @@
###########################################
#
# Tank
#
# Classic Chip8 program translated from
# VIPer Volume 1 Issue 1 (June 1978), pg 12-14
# https://github.com/mattmikolay/viper/blob/master/volume1/issue1.pdf
#
# Press 2/E/S/Q to move the tank.
#
###########################################
: tankup
0x10 0x54 0x7c 0x6c 0x7c 0x7c
: tankdown
0x44 0x7c 0x7c 0x6c 0x7c 0x54 0x10
: tankleft
0x0 0xfc 0x78 0x6e 0x78 0xfc
: tankright
0x0 0x3f 0x1e 0x76 0x1e 0x3f 0x0
: up v2 += -1 i := tankup ;
: down v2 += 1 i := tankdown ;
: right v1 += -1 i := tankright ;
: left v1 += 1 i := tankleft ;
: main
v1 := 0x20
v2 := 0x10
i := tankup
loop
sprite v1 v2 7
v0 := key
sprite v1 v2 7
if v0 == 2 then up
if v0 == 4 then right
if v0 == 6 then left
if v0 == 8 then down
again
+23
View File
@@ -0,0 +1,23 @@
###########################################
#
# Big Font
#
# High resolution font test program.
# Draw the complete SuperChip high res
# hex character set.
#
###########################################
: main
hires
loop
i := bighex v0
sprite v1 v2 10
v1 += 9
v0 += 1
if v0 == 8 then v1 := 0
if v0 == 8 then v2 += 11
if v0 != 16 then
again
loop again
+72
View File
@@ -0,0 +1,72 @@
###########################################
#
# Branch Test
#
# Tests the if...begin...else...then
# control structure.
# Should print "51368"
#
###########################################
: main
# simple taken branch
v0 := 1
v1 := 3
if v1 == 3 begin
v0 := 2
v0 += 3
end
print0
# simple not taken branch
v0 := 1
v1 := 3
if v1 != 3 begin
v0 := 2
v0 += 3
end
print0
# else taken
v0 := 2
v1 := 3
if v1 != v0 begin
v0 := 1
v0 += 2
else
v0 := 2
v0 += 4
end
print0
# else not taken
v0 := 2
v1 := 3
if v1 < v0 begin
v0 := 1
v0 += 2
else
v0 := 2
v0 += 4
end
print0
# nesting
v0 := 1
if v0 != 0 begin
if v0 != 2 begin
v0 := 7
else
v0 := 3
end
v0 += 1
end
print0
loop again
: print0
i := hex v0
sprite va vb 5
va += 5
;
+32
View File
@@ -0,0 +1,32 @@
###########################################
#
# Collision Detection Test
#
# Draws two overlapping sprites and
# displays the contents of the vF register.
# Should print "1".
#
###########################################
: square
0b11110000
0b11110000
0b11110000
0b11110000
: main
v0 := 20
v1 := 10
i := square
sprite v0 v1 4
v0 += 2
v1 += 2
sprite v0 v1 4
v2 := vf
v0 += 10
i := hex v2
sprite v0 v1 5
loop again
+70
View File
@@ -0,0 +1,70 @@
###########################################
#
# Numeric Comparison Tests
#
# Exercises all combinations of
# register-to-register and register-to-constant
# comparisons with the synthetic pseudo-ops
# < > <= and >=
#
###########################################
: print
i := hex v0
sprite va vb 5
va += 5
v0 := 0
;
: newline
va := 0
vb += 6
;
: greater? if v1 > v2 then v0 := 1 print ;
: greater5? if v1 > 5 then v0 := 1 print ;
: less? if v1 < v2 then v0 := 1 print ;
: less5? if v1 < 5 then v0 := 1 print ;
: greatere? if v1 >= v2 then v0 := 1 print ;
: greatere5? if v1 >= 5 then v0 := 1 print ;
: lesse? if v1 <= v2 then v0 := 1 print ;
: lesse5? if v1 <= 5 then v0 := 1 print ;
: main
# 001001
v1 := 3 v2 := 5 greater?
v1 := 3 v2 := 3 greater?
v1 := 5 v2 := 3 greater?
v1 := 3 greater5?
v1 := 5 greater5?
v1 := 7 greater5?
newline
# 100100
v1 := 3 v2 := 5 less?
v1 := 3 v2 := 3 less?
v1 := 5 v2 := 3 less?
v1 := 3 less5?
v1 := 5 less5?
v1 := 7 less5?
newline
# 011011
v1 := 3 v2 := 5 greatere?
v1 := 3 v2 := 3 greatere?
v1 := 5 v2 := 3 greatere?
v1 := 3 greatere5?
v1 := 5 greatere5?
v1 := 7 greatere5?
newline
# 110110
v1 := 3 v2 := 5 lesse?
v1 := 3 v2 := 3 lesse?
v1 := 5 v2 := 3 lesse?
v1 := 3 lesse5?
v1 := 5 lesse5?
v1 := 7 lesse5?
loop again
+66
View File
@@ -0,0 +1,66 @@
###########################################
#
# Loop Construct Tests
#
# Tests boundary conditions using `if`
# and `while` with simple and synthetic
# comparison operators.
# Should draw 5 vertical strips of 6 boxes.
#
###########################################
: main
# while with pseudo-op
v0 := 0
v1 := 0
loop
while v1 < 30
sprite v0 v1 5
v1 += 5
again
# while with simple comparison
v0 := 5
v1 := 0
loop
while v1 != 30
sprite v0 v1 5
v1 += 5
again
# if with pseudo-op
v0 := 10
v1 := 0
loop
if v1 >= 30 then jump done1
sprite v0 v1 5
v1 += 5
again
: done1
# if with simple comparison
v0 := 15
v1 := 0
loop
if v1 == 30 then jump done2
sprite v0 v1 5
v1 += 5
again
: done2
# nested loops with while
v0 := 20
v1 := 0
loop
while v1 != 25
sprite v0 v1 5
v1 += 5
v2 := 5
loop
v2 += -1
if v2 != 0 then
again
again
sprite v0 v1 5
loop again
+34
View File
@@ -0,0 +1,34 @@
###########################################
#
# Next Test
#
# Demonstrates the use of the :next
# operative to refer to the second byte
# of an instruction. Mainly used for
# writing self-modifying code.
#
###########################################
: lt v0 := -1 i := vx save v0 ;
: rt v0 := 1 i := vx save v0 ;
: up v0 := -1 i := vy save v0 ;
: dn v0 := 1 i := vy save v0 ;
: main
va := 2
vb := 8
loop
clear
i := hex vc
sprite va vb 5
:next vx va += 1
:next vy vb += 1
if va == 0 then rt
if va == 59 then lt
if vb == 0 then dn
if vb == 26 then up
again
+66
View File
@@ -0,0 +1,66 @@
###########################################
#
# Quirks Mode Tests
#
# Examines the behavior of operations
# which have multiple interpretations
# in the wild and demonstrates the
# distinction between Octo's defaults
# and quirks modes for each instruction.
#
###########################################
: buffer 0 3
: main
# Perform a shift where source and dest
# differ. The correct behavior will draw a 1
# while in-place vx modification will draw 2.
v0 := 4
v1 := 2
v0 >>= v1
i := hex v0
va := 5
sprite va va 5
# perform a repeated store and load.
# the correct behavior should print 3 due to i autoincrements.
# quirks mode will print 4.
i := buffer
v0 := 4
save v0
v0 := 9 # just clobber v0 in case
load v0
i := hex v0
vb := 12
sprite va vb 5
# perform an arithmetic operation which stores to vf.
# the correct behavior should write the carry flag last, resulting in 0.
# quirks mode will print 6.
vf := 3
vf <<= vf
i := hex vf
vb := 19
sprite va vb 5
# try a jump0 instruction.
# the correct behavior should respect the value of v0 as an offset, resulting in 7
# quirks mode will respect v2 instead (in this case), resulting in 8.
v0 := 8
v2 := 4
jump0 jump-table
: jump-table
0x00 0x00 0x00 0x00
vf := 8 jump show-jump0-result
vf := 7 jump show-jump0-result
0x00 0x00 0x00 0x00
: show-jump0-result
i := hex vf
va := 10
vb := 5
sprite va vb 5
loop again
+69
View File
@@ -0,0 +1,69 @@
###########################################
#
# Unpacking Tests
#
# Uses the :unpack operative to perform
# self-modification and rewrite an
# i := NNN instruction.
#
###########################################
: font
0x20 0x20 0x20 0x00 0x20 0xF0 0x10 0x70 0x00 0x40 0xE0 0x90 0xE0 0x90 0x90 0x90
0xE0 0x90 0xE0 0x90 0xE0 0x80 0x80 0xD0 0xB0 0xB0 0x90 0x90 0x90 0x90 0x60 0x60
0x90 0x90 0x90 0x60 0x90 0xD0 0xB0 0x90 0x90 0x90 0x50 0x20 0x40 0x00 0x00 0x00
0x00 0x00 0x60 0x90 0xF0 0x90 0x90 0xF0 0x90 0x90 0xF0 0x80 0xE0 0x80 0x80 0x80
0x80 0xF0 0x80 0xE0 0x80 0xF0 0x40 0x40 0x40 0xF0 0x20 0x40 0x80 0xF0 0x20 0x20
0x20 0xC0 0x60 0x90 0x80 0x90 0x60 0x90 0x90 0xB0 0x70 0x80 0xB0 0x90 0x70 0x80
0x60 0x10 0xE0 0x90 0xA0 0xC0 0xA0 0x90 0x90 0xB0 0xB0 0xD0 0xF0 0x40 0x40 0x40
0x40 0x90 0x90 0x70 0x10 0xE0
# draw and linewrap a string at an address given
# in the v0-v1 registers. The string will consist
# of a sequence of offsets into the font data:
: display-string
i := string-addr
save v1
v1 := 2 # character x
v2 := 1 # character y
v3 := 0 # byte index
# v4 contains string length
loop
: string-addr 0 0
i += v3
load v0
i := font
i += v0
sprite v1 v2 5
v1 += 5
if v1 == 62 then v2 += 6
if v1 == 62 then v1 := 2
v3 += 1
if v3 != v4 then
again
;
: demo-string
0x71 0x1F 0x1A 0x2D 0x35 0x41 0x32 0x0A 0x2D 0x2D 0x2D 0x2D 0x32 0x2D 0x0A 0x1A
0x17 0x10 0x3D 0x41 0x2D 0x45 0x24 0x2D 0x6C 0x35 0x41 0x2D 0x0C 0x45 0x5E 0x6C
0x32 0x24 0x52 0x41
:const demo-string-length 36
# these constants demonstrate all the valid opcodes
# which can be built with the high nybble in :unpack
:const JUMP 0x1 # jump <label>
:const CALL 0x2 # <label>
:const INDEX 0xA # i := <label>
:const JUMP0 0xB # jump0 <label>
# these aliases are defaults but can be overridden
# to unpack into alternate registers
:alias unpack-hi v0
:alias unpack-lo v1
: main
:unpack INDEX demo-string
v4 := demo-string-length
display-string
loop again
+18
View File
@@ -0,0 +1,18 @@
###########################################
#
# Key Input Test
#
# Prompt for a keypress,
# then display its hex digit onscreen.
#
###########################################
: main
v0 := 20
v1 := 10
loop
v2 := key
clear
i := hex v2
sprite v0 v1 5
again
+103
View File
@@ -0,0 +1,103 @@
###########################################
#
# XO-Chip Tests
#
# Perform basic exercises demonstrating
# the XO-Chip extended instructions
# to verify the behavior of the compiler,
# emulator and disassembler.
#
###########################################
: main
# demonstrate playing an audio sample:
i := long gurgle
audio
v0 := 3
loop
vf := 10
buzzer := vf
vf := 15
wait
v0 += -1
if v0 != 0 then
again
# demonstrate drawing a color sprite:
plane 3
i := long rocket
v2 := 24
sprite v2 v1 0
# demonstrate the ranged load instructions
# drawing hex characters to plane 2.
# should display F B A.
print-init
i := long data1
load vf - vf
print
i := long data2
load v1 - v0
vf := v0 print
vf := v1 print
# demonstrate vertical scrolling
# in both directions with one plane:
plane 1
loop
v0 := 0
loop
vf := 5 wait
scroll-down 1
v0 += 1
if v0 != 16 then
again
loop
vf := 5 wait
scroll-up 1
v0 += -1
if v0 != 0 then
again
vf := 20 wait
again
: wait
delay := vf
loop
vf := delay
if vf != 0 then
again
;
: print-init
plane 2
ve := 4
vd := 1
;
: print
i := hex vf
sprite ve vd 5
vd += 6
;
# place static data beyond normal addressing space:
:org 0x1000
: gurgle
0x55 0xAA 0x55 0xAA 0x55 0xAA 0x55 0xAA
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
: rocket
0x03 0xC0 0x05 0xE0 0x08 0x70 0x09 0xF0
0x13 0xF8 0x12 0xF8 0x11 0xB8 0x08 0x30
0x08 0xB0 0x04 0x60 0x04 0xE0 0x1E 0x78
0x2E 0x5C 0x26 0x4C 0x23 0xC4 0x3C 0x3C
0x03 0xC0 0x06 0x20 0x0F 0x90 0x0F 0x90
0x1E 0x48 0x1F 0x48 0x1F 0xC8 0x0F 0xD0
0x0F 0xD0 0x07 0xA0 0x07 0xA0 0x1B 0xD8
0x33 0xE4 0x3B 0xF4 0x3F 0xFC 0x3C 0x3C
: data1 0x0F
: data2 0x0A 0x0B
+104
View File
@@ -0,0 +1,104 @@
###########################################
#
# Vertical Clip
#
# Sprite drawing routines which are capable
# of clipping a sprite along the top and
# bottom edges of the screen.
#
# These routines are designed with 'lores'
# 64x32 pixel graphics in mind.
#
# Sprite y coordinates must range between
# 17 and 64- at either extreme the sprite
# is completely invisible. If only a partial
# clip along one edge is necessary or
# other constraints can be added these
# routines could be simplified.
#
###########################################
:const HEIGHT 15 # sprite height
:const N_EDGE 32
:calc N_LIMIT { N_EDGE - HEIGHT }
:const S_EDGE 64
:calc S_LIMIT { S_EDGE - HEIGHT }
:alias offset vd # could be a temp register
:alias height vc # could be a temp register
:alias y vb
:alias x va
: flower
0x3C 0x66 0x57 0xB7 0xFB 0x7A 0x1A
0xC4 0x64 0x79 0x12 0x26 0x2C 0x10 0x08
: draw-sprite
# If our sprite is below the north edge,
# we don't need to perform top clipping:
if y >= N_EDGE then jump clip-s
# Calculate the number of pixels we should
# draw and the corresponding offset into
# the sprite data which should be used:
offset := N_EDGE
offset -= y
height := HEIGHT
height -= offset
# If we're entirely off the top edge,
# we don't need to draw anything:
if height == 0 then return
# Overwrite the lowest nybble of the 'sprite instruction
# to reflect the desired height:
v0 := height
i := nrows
save v0
v0 := 0
i := flower
i += offset
:next nrows sprite x v0 HEIGHT
;
: clip-s
# Calculate the number of pixels we
# should draw based on the height of the screen:
height := S_EDGE
height -= y
# Drawing a 0-height sprite has the unintended
# consequence of drawing a SuperChip 16x16 sprite,
# so we must break if the sprite is fully offscreen:
if height == 0 then return
# On the other hand, if we're far enough away from the
# bottom edge we should display the full sprite.
# We could skip this step if the sprite was always
# against the bottom edge:
if y < S_LIMIT then height := HEIGHT
# Overwrite the lowest nybble of the 'sprite' instruction
# to parameterize the sprite height on the fly.
# We must also preserve the y register setting, but
# that is known statically:
v0 := 0xB0
v0 += height
i := srows
save v0
i := flower
:next srows sprite x y HEIGHT
;
: main
x := 28
y := 32
loop
clear
draw-sprite
v0 := key
if v0 == 5 then y += -1
if v0 == 8 then y += 1
again
+45
View File
@@ -0,0 +1,45 @@
###########################################
#
# Music Player
#
# A very simple music player based on
# the XO-Chip audio system playing
# a rendition of the Cave Story theme.
#
###########################################
: main
loop
cave-1
cave-2
cave-1
cave-3
again
: cave-1 D$4 --- G$4 --- D$4 --- G$4 ---
D-4 --- G$4 --- D-4 --- G$4 ---
C$4 --- G$4 --- C$4 --- G$4 --- ;
: cave-2 C-4 --- G$4 --- C-4 --- C$4 D-4 ;
: cave-3 B-4 --- A$4 --- G$4 --- --- --- ;
:macro sample { :calc t { 6 + HERE } i := t note ; }
: B-4 sample 0xF8 0x78 0x78 0x78 0x78 0x78 0x78 0x78 0x78 0x78 0x7C 0x3C 0x3C 0x3C 0x3C 0x3C # 494hz
: A$4 sample 0xF8 0x78 0x3C 0x3E 0x1E 0x1F 0x0F 0x07 0x87 0x83 0xC3 0xE1 0xE0 0xF0 0xF0 0x78 # 466hz
: G$4 sample 0xF8 0x3E 0x0F 0x87 0xC1 0xF0 0x7C 0x3E 0x0F 0x83 0xC1 0xF0 0x7C 0x1E 0x0F 0x83 # 415hz
: D$4 sample 0xFE 0x07 0xF0 0x3F 0x81 0xFC 0x0F 0xC0 0x7E 0x03 0xF0 0x1F 0x81 0xFC 0x0F 0xE0 # 311hz
: D-4 sample 0xFE 0x03 0xF8 0x0F 0xE0 0x7F 0x01 0xFC 0x07 0xF0 0x3F 0x80 0xFE 0x03 0xF8 0x1F # 293hz
: C$4 sample 0xFF 0x01 0xFC 0x07 0xF8 0x0F 0xE0 0x3F 0x80 0x7F 0x01 0xFC 0x03 0xF8 0x0F 0xE0 # 277hz
: C-4 sample 0xFF 0x00 0xFE 0x01 0xFE 0x03 0xFC 0x03 0xF8 0x07 0xF0 0x0F 0xF0 0x1F 0xE0 0x1F # 262hz
: --- sample 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # silence
: note
audio
vf := 6 # actual note duration
delay := vf
vf := 60 # prevent background flicker
buzzer := vf
loop
vf := delay
if vf != 0 then
again
;
+52
View File
@@ -0,0 +1,52 @@
###########################################
#
# Music Player 2
#
# A music player using the pitch register,
# instead of varying the pattern buffer.
#
###########################################
: main
loop
cave-1
cave-2
cave-1
cave-3
again
: cave-1 D$4 --- G$4 --- D$4 --- G$4 ---
D-4 --- G$4 --- D-4 --- G$4 ---
C$4 --- G$4 --- C$4 --- G$4 --- ;
: cave-2 C-4 --- G$4 --- C-4 --- C$4 D-4 ;
: cave-3 B-4 --- A$4 --- G$4 --- --- --- ;
: ---
i := silence
jump play
: note
pitch := vf
i := waveform
: play
audio
vf := 6 # actual note duration
delay := vf
vf := 60 # prevent background flicker
buzzer := vf
loop
vf := delay
if vf != 0 then
again
;
:macro def-note NAME PITCH { : NAME vf := PITCH jump note }
def-note B-4 159
def-note A$4 155
def-note G$4 147
def-note D$4 127
def-note D-4 123
def-note C$4 119
def-note C-4 115
: waveform 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF 0x00 0x00 0xFF 0xFF
: silence 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00