diff --git a/presets/verilog/7segment.v b/presets/verilog/7segment.v index 14fef1de..ce841ae0 100644 --- a/presets/verilog/7segment.v +++ b/presets/verilog/7segment.v @@ -3,7 +3,7 @@ module seven_segment_decoder(digit, segments); input [3:0] digit; - output [6:0] segments; + output reg [6:0] segments; always @(*) case(digit) @@ -26,7 +26,7 @@ module segments_to_bitmap(segments, line, bits); input [6:0] segments; input [2:0] line; - output [4:0] bits; + output reg [4:0] bits; always @(*) case (line) diff --git a/presets/verilog/cpu16.v b/presets/verilog/cpu16.v index 0468774f..98591897 100644 --- a/presets/verilog/cpu16.v +++ b/presets/verilog/cpu16.v @@ -5,20 +5,25 @@ /* 00000aaa 0++++bbb operation A+B->A -00001ttt ######## conditional branch -00100aaa ######## load constant -00101aaa ######## load memory -00110aaa ######## store memory -01000aaa #####bbb load [B+#] -> A +00001aaa 0++++bbb operation A+[B]->A +00011aaa 0++++000 operation A+imm16 -> A +00101aaa ######## load zero page +00110aaa ######## store zero page +01001aaa #####bbb load [B+#] -> A 01010aaa #####bbb store A -> [B+#] -10+++aaa 10+++aaa dual unary operation +01101aaa 0++++000 operation A+[imm16] -> A +01110aaa 00cccbbb store A -> [B+#], C -> IP +1000tttt ######## conditional branch 11+++aaa ######## immediate binary operation */ -module CPU16(clk, reset, address, data_in, data_out, write); +module CPU16(clk, reset, halt, busy, + address, data_in, data_out, write); input clk; input reset; + input halt; + output busy; output [15:0] address; input [15:0] data_in; output [15:0] data_out; @@ -37,26 +42,30 @@ module CPU16(clk, reset, address, data_in, data_out, write); reg [3:0] aluop; wire [2:0] rdest = opcode[10:8]; wire [2:0] rsrc = opcode[2:0]; - wire Bload = opcode[11]; // TODO + wire Bconst = opcode[15]; // TODO + wire Bload = opcode[11]; // TODO localparam S_RESET = 0; localparam S_SELECT = 1; localparam S_DECODE = 2; localparam S_COMPUTE = 3; + localparam SP = 6; // stack ptr = register 6 localparam IP = 7; // IP = register 7 ALU #(16) alu( .A(regs[rdest]), - .B(regs[rsrc]), + .B(Bconst ? {8'b0, opcode[7:0]} + : Bload ? data_in + : regs[rsrc]), .Y(Y), .aluop(aluop), .carry(carry)); always @(posedge clk) if (reset) begin - state <= 0; - write <= 0; + state <= S_RESET; + busy <= 1; end else begin case (state) // state 0: reset @@ -67,46 +76,102 @@ module CPU16(clk, reset, address, data_in, data_out, write); end // state 1: select opcode address S_SELECT: begin - address <= regs[IP]; - regs[IP] <= regs[IP] + 1; write <= 0; - state <= S_DECODE; + if (halt) begin + busy <= 1; + state <= S_SELECT; + end else begin + busy <= 0; + address <= regs[IP]; + regs[IP] <= regs[IP] + 1; + state <= S_DECODE; + end end // state 2: read/decode opcode S_DECODE: begin opcode <= data_in; // (only use opcode next cycle) casez (data_in) - // 00000aaa 0++++bbb operation A+B->A + // 00000aaa0++++bbb operation A+B->A 16'b00000???0???????: begin aluop <= data_in[6:3]; state <= S_COMPUTE; end - // 00100aaa ######## load constant - 16'b00100???????????: begin - regs[rdest] <= {8'b0, data_in[7:0]}; - state <= S_SELECT; + // 00001aaa01+++bbb operation A+[B]->A + 16'b00001???01??????: begin + address <= regs[data_in[2:0]]; + aluop <= data_in[6:3]; + state <= S_COMPUTE; + if (data_in[2:0] == SP) + regs[SP] <= regs[SP] + 1; end - // 00101aaa ######## load memory + // 00011aaa0++++000 operation A+imm16 -> A + 16'b00011???0????000: begin + address <= regs[IP]; + regs[IP] <= regs[IP] + 1; + aluop <= data_in[6:3]; + state <= S_COMPUTE; + end + // 11+++aaa######## immediate binary operation + 16'b11??????????????: begin + aluop <= data_in[14:11]; + state <= S_COMPUTE; + end + // 00101aaa######## load ZP memory 16'b00101???????????: begin address <= {8'b0, data_in[7:0]}; aluop <= `OP_LOAD_B; state <= S_COMPUTE; end - // 00110aaa ######## store memory + // 00110aaa######## store ZP memory 16'b00110???????????: begin address <= {8'b0, data_in[7:0]}; data_out <= regs[data_in[10:8]]; write <= 1; state <= S_SELECT; end - // 00001ttt ######## conditional branch - 16'b00001???????????: begin + // 01001aaa#####bbb [B+#] -> A + 16'b01001???????????: begin + address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3])); + aluop <= `OP_LOAD_B; + state <= S_COMPUTE; + if (data_in[2:0] == SP) + regs[SP] <= regs[SP] + 1; + end + // 01010aaa#####bbb store A -> [B+#] + 16'b01010???????????: begin + address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3])); + data_out <= regs[data_in[10:8]]; + write <= 1; + state <= S_SELECT; + if (data_in[2:0] == SP) + regs[SP] <= regs[SP] - 1; + end + // 01011aaa0++++000 operation A+[imm16] -> A + 16'b01011????????000: begin + address <= regs[IP]; + regs[IP] <= regs[IP] + 1; + aluop <= data_in[6:3]; + state <= S_COMPUTE; + end + // 01110aaa00cccbbb store A -> [B+#], C -> IP + 16'b01110???00??????: begin + address <= regs[data_in[2:0]] + 16'($signed(data_in[7:3])); + data_out <= regs[data_in[10:8]]; + write <= 1; + state <= S_SELECT; + if (data_in[2:0] == SP) + regs[SP] <= regs[SP] - 1; + regs[IP] <= regs[data_in[5:3]]; + end + // 1000????######## conditional branch + 16'b1000????????????: begin if ( - (data_in[8] && (data_in[10] == carry)) || - (data_in[9] && (data_in[10] == zero))) + (data_in[8] && (data_in[11] == carry)) || + (data_in[9] && (data_in[11] == zero)) || + (data_in[10] && (data_in[11] == neg))) begin // relative branch, sign extended - regs[IP] <= regs[IP] + { {8{data_in[7]}}, data_in[7:0]}; + regs[IP] <= regs[IP] + 16'($signed(data_in[7:0])); end state <= S_SELECT; end @@ -142,18 +207,22 @@ module test_CPU16_top( output write_enable, output [15:0] IP, output zero, - output carry + output carry, + output busy ); reg [15:0] ram[0:65535]; - reg [15:0] rom[0:65535]; + reg [15:0] rom[0:255]; assign IP = cpu.regs[7]; assign zero = cpu.zero; assign carry = cpu.carry; - CPU16 cpu(.clk(clk), + CPU16 cpu( + .clk(clk), .reset(reset), + .halt(0), + .busy(busy), .address(address_bus), .data_in(to_cpu), .data_out(from_cpu), @@ -168,8 +237,37 @@ module test_CPU16_top( if (address_bus[15] == 0) to_cpu = ram[address_bus]; else - to_cpu = rom[address_bus]; + to_cpu = rom[address_bus[7:0]]; +`ifdef EXT_INLINE_ASM + initial begin + rom = '{ + __asm +.arch femto16 +.org 0x8000 +.len 256 + mov dx,@Fib + jsr dx + reset +Fib: + mov ax,#1 + mov bx,#0 + mov sp,@$6fff +Loop: + mov cx,ax + add ax,bx + mov bx,cx + push ax + pop ax + mov [42],ax + mov ax,[42] + bcc Loop + rts + __endasm + }; + end +`endif + endmodule `endif diff --git a/presets/verilog/cpu8.v b/presets/verilog/cpu8.v index 774d0f5b..8dce2b86 100644 --- a/presets/verilog/cpu8.v +++ b/presets/verilog/cpu8.v @@ -2,8 +2,8 @@ `define ALU_H // ALU operations -`define OP_LOAD_A 4'h0 -`define OP_LOAD_B 4'h1 +`define OP_ZERO 4'h0 +`define OP_LOAD_A 4'h1 `define OP_INC 4'h2 `define OP_DEC 4'h3 `define OP_ASL 4'h4 @@ -13,7 +13,7 @@ `define OP_OR 4'h8 `define OP_AND 4'h9 `define OP_XOR 4'ha -`define OP_ZERO 4'hb +`define OP_LOAD_B 4'hb `define OP_ADD 4'hc `define OP_SUB 4'hd `define OP_ADC 4'he @@ -32,8 +32,8 @@ module ALU(A, B, Y, aluop, carry); always @(*) case (aluop) // unary operations + `OP_ZERO: Y = 0; `OP_LOAD_A: Y = {1'b0, A}; - `OP_LOAD_B: Y = {1'b0, B}; `OP_INC: Y = A + 1; `OP_DEC: Y = A - 1; // unary operations that generate and/or use carry @@ -45,7 +45,7 @@ module ALU(A, B, Y, aluop, carry); `OP_OR: Y = {1'b0, A | B}; `OP_AND: Y = {1'b0, A & B}; `OP_XOR: Y = {1'b0, A ^ B}; - `OP_ZERO: Y = 0; + `OP_LOAD_B: Y = {1'b0, B}; // binary operations that generate and/or use carry `OP_ADD: Y = A + B; `OP_SUB: Y = A - B; diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v index c7bf3316..e0f0f544 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -7,9 +7,10 @@ module digits10_case(digit, yofs, bits); input [3:0] digit; input [2:0] yofs; - output [4:0] bits; + output reg [4:0] bits; wire [6:0] caseexpr = {digit,yofs}; + always @(*) case (caseexpr)/*{w:5,h:5,count:10}*/ 7'o00: bits = 5'b11111; diff --git a/presets/verilog/femto16.json b/presets/verilog/femto16.json new file mode 100644 index 00000000..be99d5ca --- /dev/null +++ b/presets/verilog/femto16.json @@ -0,0 +1,38 @@ +{ + "name":"femto8", + "width":16, + "vars":{ + "reg":{"bits":3, "toks":["ax", "bx", "cx", "dx", "ex", "fx", "sp", "ip"]}, + "unop":{"bits":3, "toks":["zero","loada","inc","dec","asl","lsr","rol","ror"]}, + "binop":{"bits":3, "toks":["or","and","xor","mov","add","sub","adc","sbb"]}, + "imm8":{"bits":8}, + "imm16":{"bits":16}, + "rel8":{"bits":8, "iprel":true, "ipofs":1} + }, + "rules":[ + {"fmt":"~binop ~reg,~reg", "bits":["00000",1,"01",0,2]}, + {"fmt":"~unop ~reg", "bits":["00000",1,"00",0,"000"]}, + {"fmt":"~binop ~reg,[~reg]", "bits":["00001",1,"01",0,2]}, + {"fmt":"mov [~reg],~reg", "bits":["01010",1,"00000",0]}, + + {"fmt":"mov ~reg,[~imm8]", "bits":["00101",0,1]}, + {"fmt":"mov [~imm8],~reg", "bits":["00110",1,0]}, + {"fmt":"~binop ~reg,#~imm8", "bits":["11",0,1,2]}, + {"fmt":"~binop ~reg,@~imm16","bits":["00011",1,"01",0,"000",2]}, + {"fmt":"~binop ~reg,[~imm16]", "bits":["01011",1,"01",0,"000",2]}, + + {"fmt":"push ~reg", "bits":["01010",0,"00000","110"]}, + {"fmt":"pop ~reg", "bits":["01001",0,"00001","110"]}, + {"fmt":"rts", "bits":["01001","111","00001","110"]}, + {"fmt":"jsr ~reg", "bits":["01110","111","00",0,"110"]}, + + {"fmt":"bcc ~rel8", "bits":["10000001",0]}, + {"fmt":"bcs ~rel8", "bits":["10001001",0]}, + {"fmt":"bnz ~rel8", "bits":["10000010",0]}, + {"fmt":"bz ~rel8", "bits":["10001010",0]}, + {"fmt":"bpl ~rel8", "bits":["10000100",0]}, + {"fmt":"bmi ~rel8", "bits":["10001100",0]}, + + {"fmt":"reset", "bits":["1011100011111111"]} + ] +} diff --git a/presets/verilog/framebuffer.v b/presets/verilog/framebuffer.v index cd5d998f..69552adb 100644 --- a/presets/verilog/framebuffer.v +++ b/presets/verilog/framebuffer.v @@ -1,7 +1,8 @@ +`undef EXT_INLINE_ASM `include "hvsync_generator.v" -`include "sprite_bitmap.v" -`include "sprite_renderer.v" `include "cpu8.v" +`include "cpu16.v" +`define EXT_INLINE_ASM // uncomment to see scope view //`define DEBUG @@ -9,13 +10,11 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, address_bus, to_cpu, from_cpu, write_enable `ifdef DEBUG - , output [7:0] A - , output [7:0] B - , output [7:0] IP + , output [15:0] IP , output carry , output zero `else - ,rgb + , rgb `endif ); @@ -26,9 +25,7 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, wire [8:0] hpos; wire [8:0] vpos; `ifdef DEBUG - assign IP = cpu.IP; - assign A = cpu.A; - assign B = cpu.B; + assign IP = cpu.regs[cpu.IP]; assign carry = cpu.carry; assign zero = cpu.zero; `else @@ -38,18 +35,19 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, parameter IN_HPOS = 8'b01000000; parameter IN_VPOS = 8'b01000001; parameter IN_FLAGS = 8'b01000010; - parameter IN_VPU = 8'b01000011; - reg [7:0] ram[0:63]; - reg [7:0] rom[0:127]; + reg [15:0] ram[0:32767]; + reg [15:0] rom[0:1023]; - output wire [7:0] address_bus; - output reg [7:0] to_cpu; - output wire [7:0] from_cpu; + output wire [15:0] address_bus; + output reg [15:0] to_cpu; + output wire [15:0] from_cpu; output wire write_enable; - CPU cpu(.clk(clk), + CPU16 cpu(.clk(clk), .reset(reset), + .hold(hold), + .busy(busy), .address(address_bus), .data_in(to_cpu), .data_out(from_cpu), @@ -57,47 +55,23 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, always @(posedge clk) if (write_enable) begin - casez (address_bus) - // VPU lo byte - 8'b0001000: begin - vpu_write[15:8] <= from_cpu; - end - // VPU hi byte - 8'b0001001: begin - vpu_write[7:0] <= from_cpu; - end - // VPU write - 8'b0001010: begin - vpu_ram[vpu_write] <= from_cpu[7:4]; - vpu_ram[vpu_write+1] <= from_cpu[3:0]; - vpu_write <= vpu_write + 2; - end - // VPU move - 8'b0001011: begin - // sign extend - vpu_write <= { - vpu_write[15:8] + { {4{from_cpu[7]}}, from_cpu[7:4] }, - vpu_write[7:0] + { {4{from_cpu[3]}}, from_cpu[3:0] } - }; - end - default: ram[address_bus[5:0]] <= from_cpu; - endcase + ram[address_bus[14:0]] <= from_cpu; end always @(*) - casez (address_bus) - // RAM - 8'b00??????: to_cpu = ram[address_bus[5:0]]; - // special read registers - IN_HPOS: to_cpu = hpos[7:0]; - IN_VPOS: to_cpu = vpos[7:0]; - IN_FLAGS: to_cpu = {3'b0, - vsync, hsync, vpaddle, hpaddle, display_on}; - IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]}; - // ROM - 8'b1???????: to_cpu = rom[address_bus[7:0] + 128]; - default: ; - endcase + if (address_bus[15]) + to_cpu = rom[address_bus[9:0]]; + else if (&address_bus[14:8]) begin + casez (address_bus[7:0]) + // special read registers + IN_HPOS: to_cpu = {8'b0, hpos[7:0]}; + IN_VPOS: to_cpu = {8'b0, vpos[7:0]}; + IN_FLAGS: to_cpu = {11'b0, + vsync, hsync, vpaddle, hpaddle, display_on}; + default: to_cpu = 0; + endcase + end else + to_cpu = ram[address_bus[14:0]]; hvsync_generator hvsync_gen( .clk(clk), @@ -108,72 +82,67 @@ module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, .hpos(hpos), .vpos(vpos) ); - - reg [3:0] vpu_ram[0:65535]; - reg [15:0] vpu_read; - reg [15:0] vpu_write; - reg [3:0] rgb; + + // video DMA access + reg hold; + wire busy; + reg [15:0] vline[0:31]; // 32x16 bits = 256 4-color pixels + reg [4:0] vindex; + reg [15:0] vshift; + reg [3:0] palette[0:3] = '{0,1,4,7}; always @(posedge clk) begin - if (!hpos[8] && !vpos[8]) begin - rgb <= vpu_ram[vpu_read]; - vpu_read <= vpu_read + 1; - end else begin + // has CPU released the bus? + if (busy) begin + // write from main RAM -> scanline RAM + vline[vindex] <= ram[{2'b10,vpos[7:0],vindex}]; + // end of scanline read? + if (&vindex) + hold <= 0; // release CPU + vindex <= vindex + 1; // next address + end else if (hpos >= 256 && hpos < 256+4 && vpos < 240) begin + hold <= 1; // start DMA mode, hold CPU + end else if (!hpos[8] && vpos < 240) begin + // load next word from vline buffer + if (0 == hpos[2:0]) begin + vshift <= vline[vindex]; + vindex <= vindex + 1; + end else + vshift <= vshift >> 2; + // decode scanline RAM to RGB output + rgb <= palette[vshift[1:0]]; + end else rgb <= 0; - if (vpos[8]) - vpu_read <= 0; - end end `ifdef EXT_INLINE_ASM initial begin rom = '{ __asm -.arch femto8 -.org 128 -.len 128 +.arch femto16 +.org 32768 +.len 1024 -.define VPU_LO 8 -.define VPU_HI 9 -.define VPU_WRITE 10 -.define VPU_MOVE 11 - -.define IN_HPOS $40 -.define IN_VPOS $41 -.define IN_FLAGS $42 +.define IN_HPOS $7f00 +.define IN_VPOS $7f01 +.define IN_FLAGS $7f02 .define F_DISPLAY 1 .define F_HPADDLE 2 .define F_VPADDLE 4 .define F_HSYNC 8 .define F_VSYNC 16 - + Start: - zero A - sta VPU_LO - sta VPU_HI - sta 0 -DisplayLoop: - zero B - mov A,[b] - sta VPU_WRITE - sta VPU_MOVE - sta VPU_WRITE - sta VPU_MOVE - sta VPU_WRITE - sta VPU_MOVE - lda #F_VSYNC - ldb #IN_FLAGS - and none,[B] - bz DisplayLoop -WaitVsync: - and none,[B] - bnz WaitVsync - zero B - mov A,[b] - inc A - sta 0 - jmp DisplayLoop + mov ax,#0 + mov bx,ax +Loop: + xor ax,[bx] + mov [bx],ax + inc bx + inc ax + bnz Loop + reset __endasm }; end diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v index 1f9f4fd2..5c1f32bc 100644 --- a/presets/verilog/hvsync_generator.v +++ b/presets/verilog/hvsync_generator.v @@ -5,10 +5,10 @@ module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos); input clk; input reset; - output hsync, vsync; + output reg hsync, vsync; output display_on; - output [8:0] hpos; - output [8:0] vpos; + output reg [8:0] hpos; + output reg [8:0] vpos; // constant declarations for TV-simulator sync parameters // horizontal diff --git a/presets/verilog/scoreboard.v b/presets/verilog/scoreboard.v index c3b0f149..6a8b4742 100644 --- a/presets/verilog/scoreboard.v +++ b/presets/verilog/scoreboard.v @@ -7,10 +7,10 @@ module player_stats(reset, score0, score1, lives, incscore, declives); input reset; - output [3:0] score0; - output [3:0] score1; + output reg [3:0] score0; + output reg [3:0] score1; input incscore; - output [3:0] lives; + output reg [3:0] lives; input declives; always @(posedge incscore or posedge reset) @@ -45,8 +45,8 @@ module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx); input [8:0] hpos; output board_gfx; - wire [3:0] score_digit; - wire [4:0] score_bits; + reg [3:0] score_digit; + reg [4:0] score_bits; always @(*) begin diff --git a/presets/verilog/sprite_bitmap.v b/presets/verilog/sprite_bitmap.v index c4b1ffbd..64afc424 100644 --- a/presets/verilog/sprite_bitmap.v +++ b/presets/verilog/sprite_bitmap.v @@ -81,6 +81,7 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); wire [3:0] car_bit = car_sprite_xofs>=8 ? 15-car_sprite_xofs: car_sprite_xofs; + wire car_gfx = car_sprite_bits[car_bit[2:0]]; wire r = display_on && car_gfx; diff --git a/presets/verilog/sprite_multiple.v b/presets/verilog/sprite_multiple.v index 012d3417..15b86362 100644 --- a/presets/verilog/sprite_multiple.v +++ b/presets/verilog/sprite_multiple.v @@ -63,7 +63,7 @@ module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); sprite_renderer enemy_renderer( .clk(clk), .vstart(enemy_vstart), - .load(hpos == 257), + .load(hpos == 258), .hstart(enemy_hstart), .rom_addr(car_sprite_yofs), .rom_bits(car_sprite_bits), diff --git a/presets/verilog/sprite_renderer.v b/presets/verilog/sprite_renderer.v index 302c8638..1e2a6d5c 100644 --- a/presets/verilog/sprite_renderer.v +++ b/presets/verilog/sprite_renderer.v @@ -7,20 +7,24 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, gfx, in_progress); - input clk, vstart, load, hstart; - output [3:0] rom_addr; - input [7:0] rom_bits; - output gfx; - output in_progress; + input clk; + input vstart; // start drawing (top border) + input load; // ok to load sprite data? + input hstart; // start drawing scanline (left border) + output [3:0] rom_addr; // select ROM address + input [7:0] rom_bits; // input bits from ROM + output gfx; // output pixel + output in_progress; // 0 if waiting for vstart assign in_progress = state != WAIT_FOR_VSTART; - reg [2:0] state; - reg [3:0] ycount; - reg [3:0] xcount; + reg [2:0] state; // current state # + reg [3:0] ycount; // number of scanlines drawn so far + reg [3:0] xcount; // number of horiz. pixels in this line - reg [7:0] outbits; + reg [7:0] outbits; // register to store bits from ROM + // states localparam WAIT_FOR_VSTART = 0; localparam WAIT_FOR_LOAD = 1; localparam LOAD1_SETUP = 2; @@ -32,46 +36,49 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, begin case (state) WAIT_FOR_VSTART: begin - ycount <= 0; - // set a default value (blank) for pixel output - // note: multiple non-blocking assignments are vendor-specific - gfx <= 0; - if (vstart) state <= WAIT_FOR_LOAD; + ycount <= 0; // initialize vertical count + gfx <= 0; // default pixel value (off) + // wait for vstart, then next state + if (vstart) + state <= WAIT_FOR_LOAD; end WAIT_FOR_LOAD: begin - xcount <= 0; + xcount <= 0; // initialize horiz. count gfx <= 0; - if (load) state <= LOAD1_SETUP; + // wait for load, then next state + if (load) + state <= LOAD1_SETUP; end LOAD1_SETUP: begin - rom_addr <= ycount; - gfx <= 0; + rom_addr <= ycount; // load ROM address state <= LOAD1_FETCH; end LOAD1_FETCH: begin - outbits[7:0] <= rom_bits; - gfx <= 0; + outbits <= rom_bits; // latch bits from ROM state <= WAIT_FOR_HSTART; end WAIT_FOR_HSTART: begin - if (hstart) state <= DRAW; - gfx <= 0; + // wait for hstart, then start drawing + if (hstart) + state <= DRAW; end DRAW: begin - // mirror graphics left/right + // get pixel, mirroring graphics left/right gfx <= outbits[xcount<8 ? xcount[2:0] : ~xcount[2:0]]; xcount <= xcount + 1; + // finished drawing horizontal slice? if (xcount == 15) begin // pre-increment value ycount <= ycount + 1; + // finished drawing sprite? if (ycount == 15) // pre-increment value state <= WAIT_FOR_VSTART; // done drawing sprite else state <= WAIT_FOR_LOAD; // done drawing this scanline end end + // unknown state -- reset default: begin - state <= 0; // TODO: reset - gfx <= 0; + state <= WAIT_FOR_VSTART; end endcase end @@ -105,34 +112,34 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); .vpos(vpos) ); - wire [3:0] car_sprite_yofs; + wire [3:0] car_sprite_addr; wire [7:0] car_sprite_bits; car_bitmap car( - .yofs(car_sprite_yofs), + .yofs(car_sprite_addr), .bits(car_sprite_bits)); wire vstart = {1'd0,player_y} == vpos; wire hstart = {1'd0,player_x} == hpos; wire car_gfx; - wire unused; + wire in_progress; sprite_renderer renderer( .clk(clk), .vstart(vstart), .load(hsync), .hstart(hstart), - .rom_addr(car_sprite_yofs), + .rom_addr(car_sprite_addr), .rom_bits(car_sprite_bits), .gfx(car_gfx), - .in_progress(unused)); - - always @(posedge hsync) - begin - if (!hpaddle) paddle_x <= vpos[7:0]; - if (!vpaddle) paddle_y <= vpos[7:0]; - end - + .in_progress(in_progress)); + + always @(posedge hpaddle) + paddle_x <= vpos[7:0]; + + always @(posedge vpaddle) + paddle_y <= vpos[7:0]; + always @(posedge vsync) begin player_x <= paddle_x; @@ -141,7 +148,7 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); wire r = display_on && car_gfx; wire g = display_on && car_gfx; - wire b = display_on && car_gfx; + wire b = display_on && in_progress; assign rgb = {b,g,r}; endmodule diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v index 5930a562..2c96a730 100644 --- a/presets/verilog/sprite_rotation.v +++ b/presets/verilog/sprite_rotation.v @@ -8,7 +8,7 @@ module tank_bitmap(addr, bits); input [7:0] addr; output [7:0] bits; - reg [15:0] bitarray[256]; + reg [15:0] bitarray[0:255]; assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0]; @@ -109,7 +109,9 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits, output [4:0] rom_addr; input [7:0] rom_bits; output gfx; - output busy = state != WAIT_FOR_VSTART; + output busy; + + assign busy = state != WAIT_FOR_VSTART; reg [2:0] state; reg [3:0] ycount; @@ -178,6 +180,7 @@ module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits, endmodule module rotation_selector(rotation, bitmap_num, hmirror, vmirror); + input [3:0] rotation; output [2:0] bitmap_num; output hmirror, vmirror; @@ -208,23 +211,6 @@ module rotation_selector(rotation, bitmap_num, hmirror, vmirror); endmodule -function signed [7:0] sin_16x4; - input [3:0] in; - integer y; - case (in[1:0]) - 0: y = 0; - 1: y = 3; - 2: y = 5; - 3: y = 6; - endcase - case (in[3:2]) - 0: sin_16x4 = 8'(y); - 1: sin_16x4 = 8'(7-y); - 2: sin_16x4 = 8'(-y); - 3: sin_16x4 = 8'(y-7); - endcase -endfunction - module tank_controller(clk, reset, hpos, vpos, hsync, vsync, sprite_addr, sprite_bits, gfx, playfield, @@ -305,9 +291,33 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, end end - reg collision_detected; - always @(posedge collision_gfx or posedge vsync or posedge reset) - collision_detected <= collision_gfx; + // set if collision; cleared at vsync + reg collision_detected; + + always @(posedge clk) + if (collision_gfx) + collision_detected <= collision_gfx; + else if (vsync) + collision_detected <= 0; + + // sine lookup (4 bits input, 4 signed bits output) + + function signed [3:0] sin_16x4; + input [3:0] in; + integer y; + case (in[1:0]) + 0: y = 0; + 1: y = 3; + 2: y = 5; + 3: y = 6; + endcase + case (in[3:2]) + 0: sin_16x4 = 4'(y); + 1: sin_16x4 = 4'(7-y); + 2: sin_16x4 = 4'(-y); + 3: sin_16x4 = 4'(y-7); + endcase + endfunction always @(posedge hsync or posedge reset) if (reset) begin diff --git a/src/platform/verilog.js b/src/platform/verilog.js index 524e63c2..31a47661 100644 --- a/src/platform/verilog.js +++ b/src/platform/verilog.js @@ -180,13 +180,13 @@ var VerilogPlatform = function(mainElement, options) { var self = this; var video, audio; var useAudio = false; - var videoWidth = 256+16; - var videoHeight = 240+16; - var maxVideoBlankLines = 80; + var videoWidth = 256+20; + var videoHeight = 240+20; + var maxVideoBlankLines = 40; // vertical hold var idata, timer; var gen; var frameRate = 60; - var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480 + var AUDIO_FREQ = (256+23+7+23)*262*60; // 4857480 Hz var current_output; var paddle_x = 0; var paddle_y = 0; @@ -235,6 +235,7 @@ var VerilogPlatform = function(mainElement, options) { if (inspect_obj && inspect_sym) { var COLOR_BIT_OFF = 0xffff3333; var COLOR_BIT_ON = 0xffffffff; + /* for (var y=0; y>= 1; } while (val != 0); } + */ + var i = 0; + for (var y=0; y 8 ? ("...") : info.insns; + var insnstr = info.insns.length > 9 ? ("...") : info.insns; var textel = document.createTextNode(insnstr); editor.setGutterMarker(info.line-1, "gutter-bytes", textel); if (info.iscode) { diff --git a/src/worker/assembler.js b/src/worker/assembler.js index 1ea0491e..580b9c16 100644 --- a/src/worker/assembler.js +++ b/src/worker/assembler.js @@ -70,16 +70,18 @@ var Assembler = function(spec) { } function preprocessRules() { + if (spec.width) + width = spec.width|0; for (var i=0; i>3); - var shift = fix.bitofs&7; + var ofs = fix.ofs + Math.floor(fix.bitofs/width); + var shift = fix.bitofs & (width-1); var mask = ((1< mask || value < -mask) + warning("Symbol " + fix.sym + " (" + value + ") does not fit in " + fix.bitlen + " bits", fix.line); value &= mask; // TODO: check range // TODO: span multiple words? - outwords[ofs - origin] ^= value; + outwords[ofs - origin] ^= value; // TODO: << shift? } else { warning("Symbol '" + fix.sym + "' not found"); } diff --git a/test/cli/testasm.js b/test/cli/testasm.js index 8a3c549e..40d68696 100644 --- a/test/cli/testasm.js +++ b/test/cli/testasm.js @@ -23,12 +23,12 @@ describe('Assemble', function() { .define F_VSYNC 16 Start: - zero A + zero A ; comment sta VPU_LO sta VPU_HI sta 0 -DisplayLoop: - zero B + +DisplayLoop:zero B mov A,[b] sta VPU_WRITE sta VPU_MOVE