1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-07 17:29:31 +00:00

caspr inline assembly with __asm

This commit is contained in:
Steven Hugg 2018-02-14 18:26:40 -06:00
parent 6b4c3bdbc2
commit 56ed79c14f
11 changed files with 299 additions and 205 deletions

View File

@ -0,0 +1,33 @@
DEST=/Users/sehugg/PuzzlingPlans/8bitworkshop/src/worker
TARGETS=js/caspr.js wasm/caspr.js
all: $(TARGETS)
cp js/caspr.js $(DEST)
cp wasm/caspr.* $(DEST)/wasm
clean:
rm -f $(TARGETS)
js/%.js: %.bc
emcc -Oz --memory-init-file 0 \
-s ASM_JS=1 \
-s MODULARIZE=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \
wasm/%.js: %.bc
emcc -Oz --memory-init-file 0 \
-s WASM=1 \
-s MODULARIZE=1 \
-s ALLOW_MEMORY_GROWTH=1 \
-s NO_EXIT_RUNTIME=1 \
-s BINARYEN_ASYNC_COMPILATION=0 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \

View File

@ -0,0 +1,48 @@
all: js/verilator_bin.js wasm/verilator_bin.js
js/%.js: js/%.bc
emcc -Oz --memory-init-file 0 \
-s ASM_JS=1 \
-s MODULARIZE=1 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \
wasm/%.js: js/%.bc
emcc -Oz --memory-init-file 0 \
-s WASM=1 \
-s MODULARIZE=1 \
-s BINARYEN_ASYNC_COMPILATION=0 \
-s TOTAL_MEMORY=256MB \
-s NO_EXIT_RUNTIME=1 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \
mainwasm/%.js: js/%.bc
emcc -Oz --memory-init-file 0 \
-s WASM=1 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \
debugjs/%.js: js/%.bc
emcc -O1 --memory-init-file 0 \
-s ASM_JS=1 \
-s MODULARIZE=1 \
-s EXPORT_NAME=\"'$*'\" \
-s 'EXTRA_EXPORTED_RUNTIME_METHODS=["FS"]' \
-s FORCE_FILESYSTEM=1 \
$< -o $@ $(ARGS_$*) \
js/fssdcc.js:
ln -s ./sdcc/device/include include
ln -s ./sdcc/device/lib/build lib
python $(EMSCRIPTEN)/tools/file_packager.py js/fssdcc.data \
--preload include lib/z80 \
--separate-metadata --js-output=js/fssdcc.js

View File

@ -1,87 +0,0 @@
.arch nano8
.org 128
.define PADDLE_X 0
.define PADDLE_Y 1
.define PLAYER_X 2
.define PLAYER_Y 3
.define ENEMY_X 4
.define ENEMY_Y 5
.define ENEMY_DIR 6
.define SPEED 7
.define TRACKPOS_LO 8
.define TRACKPOS_HI 9
.define IN_HPOS $40
.define IN_VPOS $41
.define IN_FLAGS $42
.define F_DISPLAY 1
.define F_HPADDLE 2
.define F_VPADDLE 4
.define F_HSYNC 8
.define F_VSYNC 16
.define F_COLLIDE 32
Start:
lda 128
sta PLAYER_X
sta ENEMY_X
sta ENEMY_Y
lda 180
sta PLAYER_Y
zero A
sta SPEED
; test hpaddle flag
DisplayLoop:
lda F_HPADDLE
ldb IN_FLAGS
andrb NOP
bz DisplayLoop
; [vpos] -> paddle_x
ldb IN_VPOS
movrb A
sta PLAYER_X
; wait for vsync=1 then vsync=0
lda F_VSYNC
ldb IN_FLAGS
WaitForVsyncOn:
andrb NOP
bz WaitForVsyncOn
WaitForVsyncOff:
andrb NOP
bnz WaitForVsyncOff
; check collision
lda F_COLLIDE
ldb IN_FLAGS
andrb NOP
bz NoCollision
; load slow speed
lda 16
sta SPEED
NoCollision:
; update speed
ldb SPEED
movrb A
inc A
; don't store if == 0
bz MaxSpeed
sta SPEED
MaxSpeed:
movrb A
lsr A
lsr A
lsr A
lsr A
; add to lo byte of track pos
ldb TRACKPOS_LO
addrb B
swapab
sta TRACKPOS_LO
swapab
; update enemy vert pos
ldb ENEMY_Y
addrb A
sta ENEMY_Y
jmp DisplayLoop
reset

View File

@ -76,8 +76,8 @@ jmp 8 { 01 10 0001 (0) }
; conditional branch ; conditional branch
bcc 8 { 1010 0001 (0) } bcc 8 { 1010 0001 (0) }
bcs 8 { 1010 0011 (0) } bcs 8 { 1010 0011 (0) }
bz 8 { 1010 0100 (0) } bz 8 { 1010 1100 (0) }
bnz 8 { 1010 1100 (0) } bnz 8 { 1010 0100 (0) }
; allow raw byte positioning ; allow raw byte positioning

View File

@ -49,7 +49,7 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
parameter IN_FLAGS = 8'b01000010; parameter IN_FLAGS = 8'b01000010;
reg [7:0] ram[0:63]; reg [7:0] ram[0:63];
reg [7:0] rom[0:127]; reg [7:0] rom[0:255];
output wire [7:0] address_bus; output wire [7:0] address_bus;
output reg [7:0] to_cpu; output reg [7:0] to_cpu;
@ -77,7 +77,7 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
IN_FLAGS: to_cpu = {2'b0, frame_collision, IN_FLAGS: to_cpu = {2'b0, frame_collision,
vsync, hsync, vpaddle, hpaddle, display_on}; vsync, hsync, vpaddle, hpaddle, display_on};
// ROM // ROM
8'b1???????: to_cpu = rom[address_bus[6:0]]; 8'b1???????: to_cpu = rom[address_bus[6:0] + 128];
default: ; default: ;
endcase endcase
@ -128,120 +128,113 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.gfx(enemy_gfx), .gfx(enemy_gfx),
.in_progress(player_is_drawing)); .in_progress(player_is_drawing));
/*
always @(posedge hsync)
begin
if (!hpaddle) ram[PADDLE_X] <= vpos[7:0];
if (!vpaddle) ram[PADDLE_Y] <= vpos[7:0];
end
wire enemy_hit_left = (enemy_x == 64);
wire enemy_hit_right = (enemy_x == 192);
wire enemy_hit_edge = enemy_hit_left || enemy_hit_right;
always @(posedge vsync)
begin
player_x <= paddle_x;
player_y <= 180;
track_pos <= track_pos + {11'b0,speed[7:4]};
enemy_y <= enemy_y + {3'b0, speed[7:4]};
if (enemy_hit_edge)
enemy_dir <= !enemy_dir;
if (enemy_dir ^ enemy_hit_edge)
enemy_x <= enemy_x + 1;
else
enemy_x <= enemy_x - 1;
// collision check?
if (frame_collision)
speed <= 16;
else if (speed < ~paddle_y)
speed <= speed + 1;
else
speed <= speed - 1;
end
*/
initial begin initial begin
rom = '{ rom = '{
// initialize registers __asm
`I_CONST_IMM_A, .arch nano8
128, .org 128
`I_STORE_A(PLAYER_X),
`I_STORE_A(ENEMY_X), .define PADDLE_X 0
`I_STORE_A(ENEMY_Y), .define PADDLE_Y 1
`I_CONST_IMM_A, .define PLAYER_X 2
180, .define PLAYER_Y 3
`I_STORE_A(PLAYER_Y), .define ENEMY_X 4
`I_ZERO_A, .define ENEMY_Y 5
`I_STORE_A(SPEED), .define ENEMY_DIR 6
// test hpaddle flag .define SPEED 7
`I_CONST_IMM_A, .define TRACKPOS_LO 8
8'b00000010, .define TRACKPOS_HI 9
`I_CONST_IMM_B,
IN_FLAGS, .define IN_HPOS $40
`I_COMPUTE_READB(DEST_NOP, OP_AND), .define IN_VPOS $41
`I_BRANCH_IF_ZERO(1), .define IN_FLAGS $42
128+10,
// [vpos] -> paddle_x .define F_DISPLAY 1
`I_CONST_IMM_B, .define F_HPADDLE 2
IN_VPOS, .define F_VPADDLE 4
`I_COMPUTE_READB(DEST_A, OP_LOAD_B), .define F_HSYNC 8
`I_STORE_A(PLAYER_X), .define F_VSYNC 16
// wait for vsync=1 then vsync=0 .define F_COLLIDE 32
`I_CONST_IMM_A,
8'b00010000, Start:
`I_CONST_IMM_B, lda 128
IN_FLAGS, sta PLAYER_X
`I_COMPUTE_READB(DEST_NOP, OP_AND), sta ENEMY_X
`I_BRANCH_IF_ZERO(1), sta ENEMY_Y
128+25, lda 180
`I_COMPUTE_READB(DEST_NOP, OP_AND), sta PLAYER_Y
`I_BRANCH_IF_ZERO(0), zero A
128+28, sta SPEED
// check collision inc A
`I_CONST_IMM_A, sta ENEMY_DIR
8'b00100000, ; test hpaddle flag
`I_CONST_IMM_B, DisplayLoop:
IN_FLAGS, lda F_HPADDLE
`I_COMPUTE_READB(DEST_NOP, OP_AND), ldb IN_FLAGS
`I_BRANCH_IF_ZERO(1), andrb NOP
128+41, bz DisplayLoop
// load slow speed ; [vpos] -> paddle_x
`I_CONST_IMM_A, ldb IN_VPOS
16, movrb A
`I_STORE_A(SPEED), sta PLAYER_X
// update speed ; wait for vsync=1 then vsync=0
`I_CONST_IMM_B, lda F_VSYNC
SPEED, ldb IN_FLAGS
`I_COMPUTE_READB(DEST_A, OP_LOAD_B), WaitForVsyncOn:
`I_COMPUTE(DEST_A, OP_INC), andrb NOP
// don't store if == 0 bz WaitForVsyncOn
`I_BRANCH_IF_ZERO(1), WaitForVsyncOff:
128+48, andrb NOP
`I_STORE_A(SPEED), bnz WaitForVsyncOff
// branch target ; check collision
`I_COMPUTE_READB(DEST_A, OP_LOAD_B), lda F_COLLIDE
`I_COMPUTE(DEST_A, OP_LSR), ldb IN_FLAGS
`I_COMPUTE(DEST_A, OP_LSR), andrb NOP
`I_COMPUTE(DEST_A, OP_LSR), bz NoCollision
`I_COMPUTE(DEST_A, OP_LSR), ; load slow speed
// add to lo byte of track pos lda 16
`I_CONST_IMM_B, sta SPEED
TRACKPOS_LO, NoCollision:
`I_COMPUTE_READB(DEST_B, OP_ADD), ; update speed
`I_SWAP_AB, ldb SPEED
`I_STORE_A(TRACKPOS_LO), movrb A
`I_SWAP_AB, inc A
// update enemy vert pos ; don't store if == 0
`I_CONST_IMM_B, bz MaxSpeed
ENEMY_Y, sta SPEED
`I_COMPUTE_READB(DEST_A, OP_ADD), MaxSpeed:
`I_STORE_A(ENEMY_Y), movrb A
// repeat main loop lsr A
`I_JUMP_IMM, lsr A
128+10, lsr A
// leftover elements lsr A
63{0} ; add to lo byte of track pos
ldb TRACKPOS_LO
addrb B
swapab
sta TRACKPOS_LO
swapab
; update enemy vert pos
ldb ENEMY_Y
addrb A
sta ENEMY_Y
; update enemy horiz pos
ldb ENEMY_X
movrb A
ldb ENEMY_DIR
addrb A
sta ENEMY_X
subi A 64
andi A 127
bnz SkipXReverse
; load ENEMY_DIR and negate
zero A
subrb A
sta ENEMY_DIR
; back to display loop
SkipXReverse:
jmp DisplayLoop
__endasm
}; };
end end

View File

@ -505,7 +505,10 @@ var VerilogPlatform = function(mainElement, options) {
gen.tick2(); gen.tick2();
} }
this.getToolForFilename = function(fn) { this.getToolForFilename = function(fn) {
return "verilator"; if (fn.endsWith("asm"))
return "caspr";
else
return "verilator";
} }
this.getDefaultExtension = function() { return ".v"; }; this.getDefaultExtension = function() { return ".v"; };

View File

@ -822,7 +822,7 @@ function updateDisassembly() {
disasmview.setValue(text); disasmview.setValue(text);
disasmview.setCursor(selline, 0); disasmview.setCursor(selline, 0);
jumpToLine(disasmview, selline); jumpToLine(disasmview, selline);
} else if (current_output.code) { } else if (current_output && current_output.code) {
// show verilog javascript // show verilog javascript
disasmview.setValue(current_output.code); disasmview.setValue(current_output.code);
} }

26
src/worker/caspr.js Normal file

File diff suppressed because one or more lines are too long

14
src/worker/wasm/caspr.js Normal file

File diff suppressed because one or more lines are too long

BIN
src/worker/wasm/caspr.wasm Normal file

Binary file not shown.

View File

@ -1066,10 +1066,73 @@ function writeDependencies(depends, FS, errors) {
} }
} }
function parseMIF(s) {
var lines = s.split('\n');
var words = [];
for (var i=0; i<lines.length; i++) {
var l = lines[i];
var toks = l.split(/[;\s+]+/);
if (toks.length == 5 && toks[2] == ":") {
var addr = parseInt(toks[1], 16);
var value = parseInt(toks[3], 16);
words[addr] = value;
}
}
return words;
}
function compileCASPR(code, platform, options) {
loadNative("caspr");
var errors = [];
var match_fn = makeErrorMatcher(errors, /(ERROR|FATAL) - (.+)/, 2, 2);
var caspr_mod = caspr({
wasmBinary:wasmBlob['caspr'],
noInitialRun:true,
print:print_fn,
printErr:match_fn,
});
var FS = caspr_mod['FS'];
FS.writeFile("main.asm", code);
var deps = [{prefix:'verilog',filename:'nano8.cfg'}]; // TODO
writeDependencies(deps, FS, errors);
try {
starttime();
caspr_mod.callMain(["main.asm"]);
endtime("compile");
var miffile = FS.readFile("main.mif", {encoding:'utf8'});
return {
errors:errors,
output:parseMIF(miffile),
intermediate:{listing:miffile},
lines:[]};
} catch(e) {
console.log(e);
errors.push({line:0,msg:e.message});
return {errors:errors}; // TODO
}
}
function compileVerilator(code, platform, options) { function compileVerilator(code, platform, options) {
loadNative("verilator_bin"); loadNative("verilator_bin");
load("verilator2js"); load("verilator2js");
var errors = []; var errors = [];
// compile inline asm
code = code.replace(/__asm\b([\s\S]+?)\b__endasm\b/g, function(s,asmcode) {
var asmout = compileCASPR(asmcode, platform, options);
if (asmout.errors && asmout.errors.length) {
errors = asmout.errors;
return "";
} else if (asmout.output) {
var s = "";
var out = asmout.output;
for (var i=0; i<out.length; i++) {
if (i>0) s += ",";
s += out[i];
}
//console.log(s);
return s;
}
});
var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4); var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4);
var verilator_mod = verilator_bin({ var verilator_mod = verilator_bin({
wasmBinary:wasmBlob['verilator_bin'], wasmBinary:wasmBlob['verilator_bin'],
@ -1155,6 +1218,7 @@ var TOOLS = {
'naken': assembleNAKEN, 'naken': assembleNAKEN,
'verilator': compileVerilator, 'verilator': compileVerilator,
'yosys': compileYosys, 'yosys': compileYosys,
'caspr': compileCASPR,
} }
var TOOL_PRELOADFS = { var TOOL_PRELOADFS = {