diff --git a/presets/verilog/cpu8.v b/presets/verilog/cpu8.v index 4d786dd0..d24db186 100644 --- a/presets/verilog/cpu8.v +++ b/presets/verilog/cpu8.v @@ -10,6 +10,7 @@ `define OP_OR 4'h8 `define OP_AND 4'h9 `define OP_XOR 4'ha +`define OP_NOP 4'hf module ALU( input [7:0] A, @@ -26,7 +27,7 @@ module ALU( `OP_SUB: Y = A - B; `OP_INC: Y = A + 1; `OP_DEC: Y = A - 1; - `OP_ASL: Y = {A[7], A + A}; + `OP_ASL: Y = A + A; `OP_LSR: Y = {A[0], A >> 1}; `OP_OR: Y = {1'b0, A | B}; `OP_AND: Y = {1'b0, A & B}; @@ -36,13 +37,17 @@ module ALU( endmodule -`define REG_A 1'b0 -`define REG_B 1'b1 -`define I_CONST(r,x) { 2'b00, r, x } -`define I_LOAD_ADDR(r,addr) { 3'b010, r, addr } -`define I_STORE_ADDR(r,addr) { 3'b011, r, addr } -`define I_COMPUTE(r,op) { 3'b100, r, op } -`define I_RESET 8'hff +`define DEST_A 2'b00 +`define DEST_B 2'b01 +`define DEST_IP 2'b10 +`define DEST_NOP 2'b11 +`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) } +`define I_LOAD_IMM_A { 2'b01, `DEST_A, `OP_LOAD_A } +`define I_LOAD_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B } +`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_NOP } +`define I_STORE_B(op) { 4'b01100, 4'(op) } +`define I_STORE_IMM(op) { 4'b01101, 4'(op) } +`define I_RESET { 8'hff } module CPU( input clk, @@ -53,9 +58,7 @@ module CPU( output write ); - reg [7:0] ip; - reg [7:0] opcode; - reg [3:0] aluop; + reg [7:0] IP; reg [7:0] A, B; reg [8:0] Y; reg [2:0] state; @@ -63,7 +66,11 @@ module CPU( reg carry; reg zero; wire [1:0] flags = { zero, carry }; - + + reg [7:0] opcode; + wire [3:0] aluop = opcode[3:0]; + wire [1:0] opdest = opcode[5:4]; + localparam S_RESET = 0; localparam S_SELECT = 1; localparam S_DECODE = 2; @@ -71,8 +78,6 @@ module CPU( localparam S_STORE_ADDR = 4; localparam S_COMPUTE = 5; - wire load_const = opcode[3:1] == 3'b111; - ALU alu(.A(A), .B(B), .Y(Y), .aluop(aluop)); always @(posedge clk) @@ -83,68 +88,82 @@ module CPU( case (state) // state 0: reset S_RESET: begin - ip <= 8'h80; + IP <= 8'h80; write <= 0; state <= S_SELECT; end // state 1: select opcode address S_SELECT: begin - address <= ip; - ip <= ip + 1; + address <= IP; + IP <= IP + 1; write <= 0; state <= S_DECODE; end // state 2: read/decode opcode S_DECODE: begin + opcode <= data_in; casez (data_in) + // ALU A + B -> dest 8'b00??????: begin - if (data_in[5]) - B <= {3'b0, data_in[4:0]}; - else - A <= {3'b0, data_in[4:0]}; - state <= S_SELECT; - end - 8'b010?????: begin - address <= {4'b0, data_in[3:0]}; - state <= S_LOAD_ADDR; - end - 8'b011?????: begin - address <= {4'b0, data_in[3:0]}; - state <= S_STORE_ADDR; - end - 8'b100?????: begin - aluop <= data_in[3:0]; state <= S_COMPUTE; end + // ALU A + immediate -> dest + 8'b01??????: begin + address <= IP; + IP <= IP + 1; + state <= S_LOAD_ADDR; + end + // read[B] -> dest, ALU A + B -> dest + 8'b10??????: begin + address <= B; + state <= S_LOAD_ADDR; + end + // ALU A + B -> write [B] -> dest + 8'b1100????: begin + address <= B; + state <= S_STORE_ADDR; + end + // ALU A + B -> write [immediate] -> dest + 8'b1101????: begin + address <= IP; + IP <= IP + 1; + state <= S_STORE_ADDR; + end + // fall-through RESET default: begin state <= S_RESET; // reset end endcase - opcode <= data_in; end // state 3: load address S_LOAD_ADDR: begin - if (opcode[4]) - B <= data_in; - else - A <= data_in; - state <= S_SELECT; + case (opdest) + `DEST_A: A <= data_in; + `DEST_B: B <= data_in; + `DEST_IP: IP <= data_in; + // use ALU-op for conditional branch + `DEST_NOP: if ( + (aluop[0] && (aluop[1] ^ carry)) || + (aluop[2] && (aluop[3] ^ zero))) + IP <= data_in; + endcase + // short-circuit ALU for branches + state <= opdest[1] ? S_SELECT : S_COMPUTE; end // state 4: store address S_STORE_ADDR: begin - if (opcode[4]) - data_out <= B; - else - data_out <= A; + data_out <= Y[7:0]; write <= 1; state <= S_SELECT; end // state 5: compute ALU op and flags S_COMPUTE: begin - if (opcode[4]) - B <= Y[7:0]; - else - A <= Y[7:0]; + case (opdest) + `DEST_A: A <= Y[7:0]; + `DEST_B: B <= Y[7:0]; + `DEST_IP: IP <= Y[7:0]; + `DEST_NOP: ; + endcase carry <= Y[8]; zero <= ~|Y; state <= S_SELECT; @@ -160,12 +179,19 @@ module test_CPU_top( output [7:0] address_bus, output reg [7:0] to_cpu, output [7:0] from_cpu, - output write_enable + output write_enable, + output [7:0] IP, + output [7:0] A, + output [7:0] B ); reg [7:0] ram[127:0]; reg [7:0] rom[127:0]; + assign IP = cpu.IP; + assign A = cpu.A; + assign B = cpu.B; + CPU cpu(.clk(clk), .reset(reset), .address(address_bus), @@ -184,15 +210,12 @@ module test_CPU_top( initial begin // address 0x80 - rom['h00] = `I_CONST(`REG_A, 5'h1f); - rom['h01] = `I_COMPUTE(`REG_A, `OP_ASL); - rom['h02] = `I_COMPUTE(`REG_A, `OP_ASL); - rom['h03] = `I_COMPUTE(`REG_A, `OP_ASL); - rom['h04] = `I_COMPUTE(`REG_A, `OP_ASL); - rom['h05] = `I_COMPUTE(`REG_B, `OP_LOAD_A); - rom['h06] = `I_STORE_ADDR(`REG_B, 4'd1); - rom['h07] = `I_LOAD_ADDR(`REG_B, 4'd1); - rom['h08] = `I_RESET; + rom['h00] = `I_LOAD_IMM_A; + rom['h01] = 42; + rom['h02] = `I_COMPUTE(`DEST_A, `OP_ASL); + rom['h03] = `I_COMPUTE(`DEST_B, `OP_INC); + rom['h04] = `I_STORE_B(`OP_LOAD_B); + rom['h05] = `I_RESET; end endmodule diff --git a/presets/verilog/simplecpu.v b/presets/verilog/simplecpu.v new file mode 100644 index 00000000..e8c6118f --- /dev/null +++ b/presets/verilog/simplecpu.v @@ -0,0 +1,203 @@ + +`define OP_LOAD_A 4'h0 +`define OP_LOAD_B 4'h1 +`define OP_ADD 4'h2 +`define OP_SUB 4'h3 +`define OP_INC 4'h4 +`define OP_DEC 4'h5 +`define OP_ASL 4'h6 +`define OP_LSR 4'h7 +`define OP_OR 4'h8 +`define OP_AND 4'h9 +`define OP_XOR 4'ha + +module ALU( + input [7:0] A, + input [7:0] B, + output [8:0] Y, + input [3:0] aluop +); + + always @(*) + case (aluop) + `OP_LOAD_A: Y = {1'b0, A}; + `OP_LOAD_B: Y = {1'b0, B}; + `OP_ADD: Y = A + B; + `OP_SUB: Y = A - B; + `OP_INC: Y = A + 1; + `OP_DEC: Y = A - 1; + `OP_ASL: Y = {A[7], A + A}; + `OP_LSR: Y = {A[0], A >> 1}; + `OP_OR: Y = {1'b0, A | B}; + `OP_AND: Y = {1'b0, A & B}; + `OP_XOR: Y = {1'b0, A ^ B}; + default: Y = 9'bx; + endcase + +endmodule + +`define REG_A 1'b0 +`define REG_B 1'b1 +`define I_CONST(r,x) { 2'b00, r, x } +`define I_LOAD_ADDR(r,addr) { 3'b010, r, addr } +`define I_STORE_ADDR(r,addr) { 3'b011, r, addr } +`define I_COMPUTE(r,op) { 3'b100, r, op } +`define I_RESET 8'hff + +module CPU( + input clk, + input reset, + output [7:0] address, + input [7:0] data_in, + output [7:0] data_out, + output write +); + + reg [7:0] ip; + reg [7:0] opcode; + reg [3:0] aluop; + reg [7:0] A, B; + reg [8:0] Y; + reg [2:0] state; + + reg carry; + reg zero; + wire [1:0] flags = { zero, carry }; + + localparam S_RESET = 0; + localparam S_SELECT = 1; + localparam S_DECODE = 2; + localparam S_LOAD_ADDR = 3; + localparam S_STORE_ADDR = 4; + localparam S_COMPUTE = 5; + + wire load_const = opcode[3:1] == 3'b111; + + ALU alu(.A(A), .B(B), .Y(Y), .aluop(aluop)); + + always @(posedge clk) + if (reset) begin + state <= 0; + write <= 0; + end else begin + case (state) + // state 0: reset + S_RESET: begin + ip <= 8'h80; + write <= 0; + state <= S_SELECT; + end + // state 1: select opcode address + S_SELECT: begin + address <= ip; + ip <= ip + 1; + write <= 0; + state <= S_DECODE; + end + // state 2: read/decode opcode + S_DECODE: begin + casez (data_in) + 8'b00??????: begin // load constant + if (data_in[5]) + B <= {3'b0, data_in[4:0]}; + else + A <= {3'b0, data_in[4:0]}; + state <= S_SELECT; + end + 8'b010?????: begin // read memory + address <= {4'b0, data_in[3:0]}; + state <= S_LOAD_ADDR; + end + 8'b011?????: begin // write memory + address <= {4'b0, data_in[3:0]}; + state <= S_STORE_ADDR; + end + 8'b100?????: begin // compute w/ ALU + aluop <= data_in[3:0]; + state <= S_COMPUTE; + end + 8'b101000??: begin // branch if flag set/clear + if ((data_in[0] ? carry : zero) ^ data_in[1]) + ip <= A; + state <= S_SELECT; + end + default: begin + state <= S_RESET; // reset + end + endcase + opcode <= data_in; + end + // state 3: load address + S_LOAD_ADDR: begin + if (opcode[4]) + B <= data_in; + else + A <= data_in; + state <= S_SELECT; + end + // state 4: store address + S_STORE_ADDR: begin + if (opcode[4]) + data_out <= B; + else + data_out <= A; + write <= 1; + state <= S_SELECT; + end + // state 5: compute ALU op and flags + S_COMPUTE: begin + if (opcode[4]) + B <= Y[7:0]; + else + A <= Y[7:0]; + carry <= Y[8]; + zero <= ~|Y; + state <= S_SELECT; + end + endcase + end + +endmodule + +module test_CPU_top( + input clk, + input reset, + output [7:0] address_bus, + output reg [7:0] to_cpu, + output [7:0] from_cpu, + output write_enable +); + + reg [7:0] ram[127:0]; + reg [7:0] rom[127:0]; + + CPU cpu(.clk(clk), + .reset(reset), + .address(address_bus), + .data_in(to_cpu), + .data_out(from_cpu), + .write(write_enable)); + + // does not work as (posedge clk) + always @(*) + if (write_enable) + ram[address_bus[6:0]] = from_cpu; + else if (address_bus[7] == 0) + to_cpu = ram[address_bus[6:0]]; + else + to_cpu = rom[address_bus[6:0]]; + + initial begin + // address 0x80 + rom['h00] = `I_CONST(`REG_A, 5'h1f); + rom['h01] = `I_COMPUTE(`REG_A, `OP_ASL); + rom['h02] = `I_COMPUTE(`REG_A, `OP_ASL); + rom['h03] = `I_COMPUTE(`REG_A, `OP_ASL); + rom['h04] = `I_COMPUTE(`REG_A, `OP_ASL); + rom['h05] = `I_COMPUTE(`REG_B, `OP_LOAD_A); + rom['h06] = `I_STORE_ADDR(`REG_B, 4'd1); + rom['h07] = `I_LOAD_ADDR(`REG_B, 4'd1); + rom['h08] = `I_RESET; + end + +endmodule diff --git a/presets/verilog/skeleton.verilator b/presets/verilog/skeleton.verilator index bf564df9..972db69d 100644 --- a/presets/verilog/skeleton.verilator +++ b/presets/verilog/skeleton.verilator @@ -1,8 +1,8 @@ `include "hvsync_generator.v" -module top(clk, hsync, vsync, rgb); +module top(clk, reset, hsync, vsync, rgb); - input clk; + input clk, reset; output hsync, vsync; output [2:0] rgb; wire display_on; @@ -11,6 +11,7 @@ module top(clk, hsync, vsync, rgb); hvsync_generator hvsync_gen( .clk(clk), + .reset(reset), .hsync(hsync), .vsync(vsync), .display_on(display_on), diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v index ecee0861..fea93c6c 100644 --- a/presets/verilog/sprite_rotation.v +++ b/presets/verilog/sprite_rotation.v @@ -175,7 +175,7 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, endmodule module rotation_selector(rotation, bitmap_num, hmirror, vmirror); - input [4:0] rotation; + input [3:0] rotation; output [2:0] bitmap_num; output hmirror, vmirror; @@ -205,8 +205,26 @@ 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); + sprite_addr, sprite_bits, gfx, + switch_left, switch_right, switch_up); input clk; input reset; @@ -216,14 +234,23 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, input [8:0] vpos; output [7:0] sprite_addr; input [7:0] sprite_bits; - reg hmirror; - reg vmirror; output gfx; + input switch_left, switch_right, switch_up; + + wire hmirror, vmirror; wire busy; - reg [7:0] player_x = 64; - reg [7:0] player_y = 64; - reg [4:0] player_rot = 0; + reg [11:0] player_x_fixed; + wire [7:0] player_x = player_x_fixed[11:4]; + wire [3:0] player_x_frac = player_x_fixed[3:0]; + + reg [11:0] player_y_fixed; + wire [7:0] player_y = player_y_fixed[11:4]; + wire [3:0] player_y_frac = player_y_fixed[3:0]; + + reg [3:0] player_rot; + reg [3:0] player_speed = 0; + reg [3:0] frame = 0; wire vstart = {1'b0,player_y} == vpos; wire hstart = {1'b0,player_x} == hpos; @@ -245,19 +272,53 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, .bitmap_num(sprite_addr[7:5]), .hmirror(hmirror), .vmirror(vmirror)); + + always @(posedge vsync or posedge reset) + if (reset) begin + player_rot <= 0; + end else begin + frame <= frame + 1; + // rotation + if (frame[0]) begin + if (switch_left) + player_rot <= player_rot - 1; + else if (switch_right) + player_rot <= player_rot + 1; + if (switch_up) begin + if (player_speed != 15) + player_speed <= player_speed + 1; + end else + player_speed <= 0; + end + end - always @(posedge vsync) - player_rot <= player_rot + 1; + always @(posedge hsync or posedge reset) + if (reset) begin + player_x_fixed <= 128<<4; + player_y_fixed <= 120<<4; + end else begin + // movement + if (vpos < 9'(player_speed)) begin + if (vpos[0]) + player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot)); + else + player_y_fixed <= player_y_fixed - 12'(sin_16x4(player_rot+4)); + end + end endmodule -module test_top(clk, reset, hsync, vsync, rgb); +//TODO: debouncing + +module test_top(clk, reset, hsync, vsync, rgb, switches_p1); input clk; input reset; output hsync; output vsync; output [2:0] rgb; + input [7:0] switches_p1; + wire display_on; wire [8:0] hpos; wire [8:0] vpos; @@ -291,7 +352,10 @@ module test_top(clk, reset, hsync, vsync, rgb); .vsync(vsync), .sprite_addr(tank_sprite_addr), .sprite_bits(tank_sprite_bits), - .gfx(tank1_gfx) + .gfx(tank1_gfx), + .switch_left(switches_p1[0]), + .switch_right(switches_p1[1]), + .switch_up(switches_p1[2]) ); wire tank1_gfx; diff --git a/src/platform/verilog.js b/src/platform/verilog.js index 59600605..13dab3c0 100644 --- a/src/platform/verilog.js +++ b/src/platform/verilog.js @@ -253,6 +253,9 @@ var VerilogPlatform = function(mainElement, options) { debugCond = self.getDebugCallback(); var i=4; // TODO, start @ 0? var trace=inspect_obj && inspect_sym; + gen.switches_p1 = switches[0]; + gen.switches_p2 = switches[1]; + gen.switches_gen = switches[2]; for (var y=0; y paddle_x ? 1 : 0; gen.vpaddle = y > paddle_y ? 1 : 0; diff --git a/tools/sintbl.py b/tools/sintbl.py index 92597254..924bea7b 100644 --- a/tools/sintbl.py +++ b/tools/sintbl.py @@ -4,10 +4,11 @@ import math #n = 8 #m = 127 -n = 64 +n = 32 m = 127 -n=32 +n = 4 +m = 7 for i in range(0,n*4): print '%d,' % int(round(math.sin(i*math.pi/2/n)*m)),