Compare commits

..

No commits in common. "9a0aa7a431eab468c340679658251fa8322ce72d" and "def08c6c94485247ff057ce90075707917e6ba0d" have entirely different histories.

8 changed files with 1 additions and 700 deletions

1
.gitignore vendored
View file

@ -5,7 +5,6 @@ tests/*.s
examples/*.s
!runtime.s
!stdlibwrap.s
!sprites.s
*.o
*.exe
*.bin

Binary file not shown.

View file

@ -1,5 +0,0 @@
type SpritePixels = array[0..31] of integer;
type BackgroundPixels = array[0..31999] of integer;
procedure PutSprite(x,y:integer; var sprite: SpritePixels); external;
procedure UndrawSprite(x,y:integer; var background: BackgroundPixels); external;

View file

@ -1,363 +0,0 @@
.EQU SPRITE_HEIGHT 16
.EQU WORDS_PER_LINE 80
.EQU FB_RA $900
.EQU FB_WA $901
.EQU FB_IO $902
.EQU FB_PS $903
; calculate mask for a word of pixels
; args: word of pixels with four bits per pixel
; returns: value that masks out all pixels that are set
CALC_MASK:
LOADC $F ; pixel mask
C_M_L0:
SWAP ; swap mask and pixels value
AND.S1.X2Y ; isolate one pixel, keep args
CBRANCH.Z C_M_L1 ; if pixel is zero, dont set mask bits
OVER ; copy current mask
OR ; or into pixels value
C_M_L1:
SWAP ; swap back, ToS is now mask bits
SHL 2 ; shift mask for next pixel to the left
SHL 2
DUP
CBRANCH.NZ C_M_L0 ; if mask is zero, we are done
DROP ; remove mask bits
NOT ; invert result
RET
; calculate vmem address from coordinates
; args: x,y
; returns: vmem word number
CALC_VMEM_ADDR:
; only works if WORDS_PER_LINE is 80
; and pixels per word is 8
DUP
; y
SHL 2
SHL 2
SHL 2 ; * 64
SWAP
; + y
SHL 2
SHL 2 ; * 16
ADD
SWAP
; word offset = X/8
SHR
SHR
SHR
ADD
RET
; put a sprite on screen
; arg: x,y pointer to sprite data
.EQU PS_VMEM_ADDR 0
.EQU PS_SPRITE_DATA 4
.EQU PS_SPRITE_LINES 8
.EQU PS_X 12
.EQU PS_Y 16
.EQU PS_SHIFT_C 20
.EQU PS_SPILL 24
.EQU PS_FS 28
PUTSPRITE:
FPADJ -PS_FS
STORE PS_SPRITE_DATA
STORE PS_Y
STORE PS_X
; calculate vmem address
LOAD PS_X
LOAD PS_Y
LOADCP CALC_VMEM_ADDR
CALL
STORE PS_VMEM_ADDR
LOAD PS_X ; shift count = x mod 8
LOADC 7
AND
STORE PS_SHIFT_C
LOADC SPRITE_HEIGHT
STORE PS_SPRITE_LINES
; loop over each line of the sprite
PS_LOOP1:
; set read and write address
; in the vga controller
LOADC FB_RA ; read address register
LOAD PS_VMEM_ADDR
STOREI 1 ; use autoincrement to get to the next register
LOAD PS_VMEM_ADDR
STOREI
DROP
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
INC 4 ; increment pointer
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
LOADC 0
STORE PS_SPILL
; loop to shift pixel data to right
LOAD PS_SHIFT_C ; load shift count
PS_LOOP2:
DUP ; test it for zero
CBRANCH.Z PS_LOOP2_X
SWAP ; swap count with pixels
; save the pixel that is shifted out
LOADC $F ; mask the four bits
AND.S0 ; keep original value on stack
BROT ; and move them to MSB
BROT
BROT
SHL 2
SHL 2 ; shift by 28 in total
LOAD PS_SPILL ; load spill bits
SHR ; shift by four to make space
SHR
SHR
SHR
OR ; or with orig value
STORE PS_SPILL ; store new value
SHR ; shift pixels right
SHR ; four bits per pixel
SHR
SHR
SWAP ; swap back, count now ToS
DEC 1
BRANCH PS_LOOP2
PS_LOOP2_X:
DROP ; remove shift count, shifted pixels now in ToS
DUP
LOADCP CALC_MASK ; calculate sprite mask for this word
CALL
LOADCP FB_IO ; address of the i/o register
LOADI ; read word from video mem
AND ; and word with mask
OR ; OR sprite data with original pixels
LOADCP FB_IO
SWAP
STOREI ; store result into i/o reg
DROP
;
; process spilled bits and right half of sprite data
;
; put spill bits on stack for later
LOAD PS_SPILL
LOAD PS_SPRITE_DATA ; address of sprite data
DUP
INC 4 ; increment pointer
STORE PS_SPRITE_DATA ; and store it again
LOADI ; load word from orig. address
; reset spill bits
LOADC 0
STORE PS_SPILL
; shift pixel data to right
LOAD PS_SHIFT_C ; load shift count
PS_LOOP3: ; test it for zero
DUP
CBRANCH.Z PS_LOOP3_X
SWAP ; swap count with pixels
; save the pixel that is shifted out
LOADC $F ; mask the four bits
AND.S0 ; keep original value on stack
BROT ; and move them to MSB
BROT
BROT
SHL 2
SHL 2 ; shift by 28 in total
LOAD PS_SPILL ; load spill bits
SHR ; shift by four to make space
SHR
SHR
SHR
OR ; or with orig value
STORE PS_SPILL ; store new value
SHR ; shift pixels right
SHR ; four bits per pixel
SHR
SHR
SWAP ; swap back, count now ToS
DEC 1
BRANCH PS_LOOP3
PS_LOOP3_X:
DROP ; remove shift count, shifted pixels now in ToS
OR ; or together with spill bits
DUP
LOADCP CALC_MASK ; calculate sprite mask
CALL
LOADCP FB_IO ; load original pixels
LOADI
AND ; and with mask
OR ; or together with original pixels
LOADCP FB_IO
SWAP
STOREI
DROP
; write spilled bits into next vmem word
LOAD PS_SPILL ; get spill bits
DUP
LOADCP CALC_MASK ; calculate sprite mask for spill bits
CALL
LOADCP FB_IO
LOADI ; load next vmem word
AND ; apply sprite mask
OR ; OR in spill bits
LOADCP FB_IO
SWAP ; swap pixels and addr
STOREI ; write back
DROP
LOAD PS_SPRITE_LINES ; decrement lines count
DEC 1
DUP
CBRANCH.Z PS_L_XT ; exit if zero
STORE PS_SPRITE_LINES
; prepare next line
LOAD PS_VMEM_ADDR
LOADC WORDS_PER_LINE ; increment to next screen line
ADD
STORE PS_VMEM_ADDR
BRANCH PS_LOOP1
PS_L_XT:
DROP
FPADJ PS_FS
RET
; undraw a sprite, i.e. draw background data
; over a sprite location
; args: x,y, ptr to background data
.EQU UD_S_X 0
.EQU UD_S_Y 4
.EQU UD_S_PXS 8
.EQU UD_S_BGDATA 12
.EQU UD_S_OFFSET 16
.EQU UD_S_BGORIG 20
.EQU UD_S_FS 24
UNDRAWSPRITE:
FPADJ -UD_S_FS
STORE UD_S_BGORIG
STORE UD_S_Y
STORE UD_S_X
; calculate pixel shift
LOAD UD_S_X
LOADC $7
AND
STORE UD_S_PXS
; calculate vmem offset
LOAD UD_S_X
LOAD UD_S_Y
LOADCP CALC_VMEM_ADDR
CALL
DUP
STORE UD_S_OFFSET
; calculate background data address from offset
SHL 2
LOAD UD_S_BGORIG
ADD
STORE UD_S_BGDATA
LOADC SPRITE_HEIGHT ; line count
UD_S_L1:
; store vmem offset into write addr reg
LOADCP FB_WA
LOAD UD_S_OFFSET
STOREI 1 ; ugly but fast: reuse addr
; with postincrement to
; get to FB_IO for STOREI below
; load a word of background data
LOAD UD_S_BGDATA
LOADI
; and write it to vmem
STOREI
; reuse addr from STOREI
; load 2nd word of background data
LOAD UD_S_BGDATA
INC 4
DUP
STORE UD_S_BGDATA
LOADI
STOREI ; and write it to vmem
DROP
; if pixel shift is zero, no 3rd word
LOAD UD_S_PXS
CBRANCH.Z UD_S_L2
; load 3rd word of background data
LOADCP FB_IO
LOAD UD_S_BGDATA
INC 4
DUP
STORE UD_S_BGDATA
LOADI
STOREI ; and write it to vmem
DROP
UD_S_L2:
LOAD UD_S_OFFSET
LOADCP WORDS_PER_LINE
ADD
DUP
STORE UD_S_OFFSET
SHL 2
LOAD UD_S_BGORIG
ADD
STORE UD_S_BGDATA
DEC 1 ; decrement counter
DUP
CBRANCH.NZ UD_S_L1 ; check for zero
DROP ; remove counter
FPADJ UD_S_FS
RET

Binary file not shown.

View file

@ -1,220 +0,0 @@
program XmasAnimation;
uses sprites;
type PictData = record
magic, mode:integer;
palette: array [0..15] of integer;
pixeldata: array [0..31999] of integer;
end;
Sprite = record
x,y:integer;
oldX,oldY:integer;
xdelta,ydelta:integer;
curFrame:integer;
frameCount:integer;
frameTime:integer;
frameLeft:integer;
changed:boolean;
frame:array [0..3] of SpritePixels;
end;
var pic:PictData;
filename:string;
infile:file;
ch:char;
santaSprite: Sprite;
deerSprite: Sprite;
ohDeerSprite: Sprite;
rudolfSprite: Sprite;
smokeSprite: Sprite;
procedure WaitVSync; external;
procedure loadPalette(var pic:PictData);
var i:integer;
begin
for i := 0 to 15 do
setpalette(i, pic.palette[i]);
end;
procedure showPic(var pic:PictData);
begin
PutScreen(pic.pixeldata);
end;
procedure loadSpriteFrame(var aSprite:Sprite;spriteIndex:integer;
var sheetFile:file;sheetIndex:integer);
begin
seek(sheetFile, 8 + sheetIndex * 128);
read(sheetFile, aSprite.frame[spriteIndex]);
if aSprite.frameCount <= spriteIndex then
aSprite.frameCount := spriteIndex + 1;
aSprite.curFrame := 0;
writeln('loaded sprite frame ', spriteIndex, ' from ', sheetIndex);
end;
procedure animateSprite(var aSprite:Sprite);
var frameIndex:integer;
frameTime,frameLeft:integer;
ydelta:integer;
oldX,oldY:integer;
begin
ydelta := aSprite.ydelta;
frameIndex := aSprite.curFrame;
frameTime := aSprite.frameTime;
frameLeft := aSprite.frameLeft;
oldX := aSprite.x; oldY := aSprite.y;
aSprite.oldX := oldX; aSprite.oldY := oldY;
frameLeft := frameLeft - 1;
if frameLeft <= 0 then
begin
frameIndex := frameIndex + 1;
frameLeft := aSprite.frameTime;
aSprite.frameLeft := frameLeft;
aSprite.curFrame := frameIndex;
if frameIndex >= aSprite.frameCount
then
aSprite.curFrame := 0;
if frameIndex = 1 then
begin
ydelta := - ydelta;
aSprite.ydelta := ydelta;
end;
aSprite.y := aSprite.y + ydelta;
end;
aSprite.frameLeft := frameLeft;
aSprite.x := aSprite.x + aSprite.xdelta;
if aSprite.x > 620 then aSprite.x := 0;
end;
procedure animate;
var i:integer;
ydelta:integer;
frameIndex:integer;
frameTime:integer;
oldX,oldY:integer;
begin
santaSprite.x := 0;
santaSprite.y := 60;
santaSprite.frameTime := 10;
santaSprite.xdelta := 2;
santaSprite.ydelta := 1;
smokeSprite.x := 434;
smokeSprite.y := 252;
smokeSprite.frameTime := 20;
deerSprite.x := 18;
deerSprite.y := 60;
deerSprite.frameTime := 10;
deerSprite.xdelta := 2;
deerSprite.ydelta := 1;
ohDeerSprite.x := 33;
ohDeerSprite.y := 61;
ohDeerSprite.frameTime := 10;
ohDeerSprite.xdelta := 2;
ohDeerSprite.ydelta := 1;
rudolfSprite.x := 49;
rudolfSprite.y := 60;
rudolfSprite.frameTime := 10;
rudolfSprite.xdelta := 2;
rudolfSprite.ydelta := 1;
ydelta := 1;
frameTime := santaSprite.frameTime;
while not ConAvail do
begin
frameIndex := santaSprite.curFrame;
oldX := santaSprite.x; oldY := santaSprite.y;
PutSprite(oldX, oldY, santaSprite.frame[frameIndex]);
i := i + 1;
frameTime := frameTime - 1;
if frameTime = 0 then
begin
frameTime := santaSprite.frameTime;
santaSprite.curFrame := frameIndex + 1;
if frameIndex >= santaSprite.frameCount
then
santaSprite.curFrame := 0;
if frameIndex = 0 then ydelta := - ydelta;
santaSprite.y := santaSprite.y + ydelta;
end;
santaSprite.x := santaSprite.x + 2;
if santaSprite.x > 620 then santaSprite.x := 0;
PutSprite(deerSprite.x, deerSprite.y,
deerSprite.frame[deerSprite.curFrame]);
PutSprite(ohDeerSprite.x, ohDeerSprite.y,
ohDeerSprite.frame[ohDeerSprite.curFrame]);
PutSprite(rudolfSprite.x, rudolfSprite.y,
rudolfSprite.frame[rudolfSprite.curFrame]);
PutSprite(smokeSprite.x, smokeSprite.y,
smokeSprite.frame[smokeSprite.curFrame]);
animateSprite(deerSprite);
animateSprite(ohDeerSprite);
animateSprite(rudolfSprite);
animateSprite(smokeSprite);
Delay(10);
WaitVSync;
UndrawSprite(oldX, oldY, pic.pixeldata);
UndrawSprite(deerSprite.oldX, deerSprite.oldY, pic.pixeldata);
UndrawSprite(ohDeerSprite.oldX, ohDeerSprite.oldY, pic.pixeldata);
UndrawSprite(rudolfSprite.oldX, rudolfSprite.oldY, pic.pixeldata);
UndrawSprite(smokeSprite.oldX, smokeSprite.oldY, pic.pixeldata);
end;
end;
begin
filename := 'background.pict';
open(infile, filename, ModeReadonly);
read(infile, pic);
close(infile);
writeln('magic: ', pic.magic, ' mode:', pic.mode);
loadPalette(pic);
showPic(pic);
open(infile, 'sprites.sprt', ModeReadOnly);
loadSpriteFrame(santaSprite, 0, infile, 0);
loadSpriteFrame(santaSprite, 1, infile, 1);
loadSpriteFrame(deerSprite, 0, infile, 5);
loadSpriteFrame(deerSprite, 1, infile, 6);
loadSpriteFrame(deerSprite, 2, infile, 7);
loadSpriteFrame(ohDeerSprite, 0, infile, 7);
loadSpriteFrame(ohDeerSprite, 1, infile, 5);
loadSpriteFrame(ohDeerSprite, 2, infile, 6);
loadSpriteFrame(rudolfSprite, 0, infile, 3);
loadSpriteFrame(rudolfSprite, 1, infile, 4);
loadSpriteFrame(rudolfSprite, 2, infile, 2);
loadSpriteFrame(smokeSprite, 0, infile, 8);
loadSpriteFrame(smokeSprite, 1, infile, 9);
loadSpriteFrame(smokeSprite, 2, infile, 10);
loadSpriteFrame(smokeSprite, 3, infile, 11);
close(infile);
animate;
end.

View file

@ -25,7 +25,7 @@
<Option Name="SimulatorInstallDirRiviera" Val=""/>
<Option Name="SimulatorInstallDirActiveHdl" Val=""/>
<Option Name="BoardPart" Val="digilentinc.com:arty-a7-35:part0:1.0"/>
<Option Name="BoardPartRepoPaths" Val="$PPRDIR/../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store"/>
<Option Name="BoardPartRepoPaths" Val="$PPRDIR/../../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store"/>
<Option Name="SourceMgmtMode" Val="DisplayOnly"/>
<Option Name="ActiveSimSet" Val="sim_sdspi"/>
<Option Name="DefaultLib" Val="xil_defaultlib"/>

View file

@ -1,110 +0,0 @@
#!/usr/bin/python3
import sys
import png
def process_pixdata(outfile, pixdata, frameindex = 0, pix_w=640, pix_h=400):
pixmask = 15
y = pix_h * frameindex
max_y = y + pix_h - 1
while y <= max_y:
x = 0
max_x = pix_w - 1
pixline = pixdata[y]
while x <= max_x:
px1 = pixline[x+0] & pixmask
px2 = pixline[x+1] & pixmask
px3 = pixline[x+2] & pixmask
px4 = pixline[x+3] & pixmask
px5 = pixline[x+4] & pixmask
px6 = pixline[x+5] & pixmask
px7 = pixline[x+6] & pixmask
px8 = pixline[x+7] & pixmask
vmem_word = (px1 << 28) | (px2 << 24) | (px3 << 20) | (px4 << 16) | \
(px5 << 12) | (px6 << 8) | (px7 << 4) | px8
outfile.write(vmem_word.to_bytes(4, 'big'))
x += 8
y += 1
def process_palette(outfile, palette):
for r,g,b in palette:
r4 = r >> 4
g4 = g >> 4
b4 = b >> 4
c12 = r4 << 8 | g4 << 4 | b4
outfile.write(c12.to_bytes(4, 'big'))
def write_header(outfile):
magic = b'PIct'
mode = 1
outfile.write(magic);
outfile.write(mode.to_bytes(4, 'big'))
def write_sprite_header(outfile):
magic = b'SPRT'
mode = 1
outfile.write(magic);
outfile.write(mode.to_bytes(4, 'big'))
def write_pict_file(width, height, px, metadata, outfile):
print("processing as PICT file...")
if width != 640:
print("width must be 640, aborting")
sys.exit(1)
pixdata = list(px)
palette = metadata['palette']
if len(palette) != 16:
print("palette must have 16 colors, aborting")
sys.exit(0)
with open(outfile,'wb') as f:
write_header(f)
process_palette(f, palette)
process_pixdata(f, pixdata)
def write_sprite_file(width, height, px, metadata, outfile):
sprite_height=16
print("processing as SPRT file with {} sprites...".format(height//sprite_height))
if width != 16:
print("width must be 16, aborting")
sys.exit(1)
pixdata = list(px)
palette = metadata['palette']
if len(palette) != 16:
print("palette must have 16 colors, aborting")
sys.exit(0)
with open(outfile,'wb') as f:
write_sprite_header(f)
process_pixdata(f, pixdata, pix_w=16, pix_h=height)
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: {} <infile> <outfile>".format(sys.argv[0]))
sys.exit(1)
infile = sys.argv[1]
outfile = sys.argv[2]
r = png.Reader(infile)
p = r.read()
width, height, px, metadata = p
if width == 640:
write_pict_file(width, height, px, metadata, outfile)
elif width == 16:
write_sprite_file(width, height, px, metadata, outfile)
else:
print("Can't handle this file, need a width of\n640 or 16 pixels with 16 color palette.")