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
bcc 8 { 1010 0001 (0) }
bcs 8 { 1010 0011 (0) }
bz 8 { 1010 0100 (0) }
bnz 8 { 1010 1100 (0) }
bz 8 { 1010 1100 (0) }
bnz 8 { 1010 0100 (0) }
; 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;
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 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,
vsync, hsync, vpaddle, hpaddle, display_on};
// ROM
8'b1???????: to_cpu = rom[address_bus[6:0]];
8'b1???????: to_cpu = rom[address_bus[6:0] + 128];
default: ;
endcase
@ -128,120 +128,113 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
.gfx(enemy_gfx),
.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
rom = '{
// initialize registers
`I_CONST_IMM_A,
128,
`I_STORE_A(PLAYER_X),
`I_STORE_A(ENEMY_X),
`I_STORE_A(ENEMY_Y),
`I_CONST_IMM_A,
180,
`I_STORE_A(PLAYER_Y),
`I_ZERO_A,
`I_STORE_A(SPEED),
// test hpaddle flag
`I_CONST_IMM_A,
8'b00000010,
`I_CONST_IMM_B,
IN_FLAGS,
`I_COMPUTE_READB(DEST_NOP, OP_AND),
`I_BRANCH_IF_ZERO(1),
128+10,
// [vpos] -> paddle_x
`I_CONST_IMM_B,
IN_VPOS,
`I_COMPUTE_READB(DEST_A, OP_LOAD_B),
`I_STORE_A(PLAYER_X),
// wait for vsync=1 then vsync=0
`I_CONST_IMM_A,
8'b00010000,
`I_CONST_IMM_B,
IN_FLAGS,
`I_COMPUTE_READB(DEST_NOP, OP_AND),
`I_BRANCH_IF_ZERO(1),
128+25,
`I_COMPUTE_READB(DEST_NOP, OP_AND),
`I_BRANCH_IF_ZERO(0),
128+28,
// check collision
`I_CONST_IMM_A,
8'b00100000,
`I_CONST_IMM_B,
IN_FLAGS,
`I_COMPUTE_READB(DEST_NOP, OP_AND),
`I_BRANCH_IF_ZERO(1),
128+41,
// load slow speed
`I_CONST_IMM_A,
16,
`I_STORE_A(SPEED),
// update speed
`I_CONST_IMM_B,
SPEED,
`I_COMPUTE_READB(DEST_A, OP_LOAD_B),
`I_COMPUTE(DEST_A, OP_INC),
// don't store if == 0
`I_BRANCH_IF_ZERO(1),
128+48,
`I_STORE_A(SPEED),
// branch target
`I_COMPUTE_READB(DEST_A, OP_LOAD_B),
`I_COMPUTE(DEST_A, OP_LSR),
`I_COMPUTE(DEST_A, OP_LSR),
`I_COMPUTE(DEST_A, OP_LSR),
`I_COMPUTE(DEST_A, OP_LSR),
// add to lo byte of track pos
`I_CONST_IMM_B,
TRACKPOS_LO,
`I_COMPUTE_READB(DEST_B, OP_ADD),
`I_SWAP_AB,
`I_STORE_A(TRACKPOS_LO),
`I_SWAP_AB,
// update enemy vert pos
`I_CONST_IMM_B,
ENEMY_Y,
`I_COMPUTE_READB(DEST_A, OP_ADD),
`I_STORE_A(ENEMY_Y),
// repeat main loop
`I_JUMP_IMM,
128+10,
// leftover elements
63{0}
__asm
.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
inc A
sta ENEMY_DIR
; 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
; 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

View File

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

View File

@ -822,7 +822,7 @@ function updateDisassembly() {
disasmview.setValue(text);
disasmview.setCursor(selline, 0);
jumpToLine(disasmview, selline);
} else if (current_output.code) {
} else if (current_output && current_output.code) {
// show verilog javascript
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) {
loadNative("verilator_bin");
load("verilator2js");
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 verilator_mod = verilator_bin({
wasmBinary:wasmBlob['verilator_bin'],
@ -1155,6 +1218,7 @@ var TOOLS = {
'naken': assembleNAKEN,
'verilator': compileVerilator,
'yosys': compileYosys,
'caspr': compileCASPR,
}
var TOOL_PRELOADFS = {