diff --git a/presets/verilog/7segment.v b/presets/verilog/7segment.v index e3aa9d43..c51549b1 100644 --- a/presets/verilog/7segment.v +++ b/presets/verilog/7segment.v @@ -1,6 +1,7 @@ `include "hvsync_generator.v" module seven_segment_decoder(digit, segments); + input [3:0] digit; output [6:0] segments; @@ -18,29 +19,41 @@ module seven_segment_decoder(digit, segments); 9: segments = 7'b1111011; default: segments = 7'b0000000; endcase + endmodule module segments_to_bitmap(segments, line, bits); + input [6:0] segments; input [2:0] line; output [4:0] bits; always @(*) case (line) - 0:bits = (segments[6]?5'b11111:0) ^ (segments[5]?5'b00001:0) ^ (segments[1]?5'b10000:0); - 1:bits = (segments[1]?5'b10000:0) ^ (segments[5]?5'b00001:0); - 2:bits = (segments[0]?5'b11111:0) ^ (|segments[5:4]?5'b00001:0) ^ (|segments[2:1]?5'b10000:0); - 3:bits = (segments[2]?5'b10000:0) ^ (segments[4]?5'b00001:0); - 4:bits = (segments[3]?5'b11111:0) ^ (segments[4]?5'b00001:0) ^ (segments[2]?5'b10000:0); + 0:bits = (segments[6]?5'b11111:0) + ^ (segments[5]?5'b00001:0) + ^ (segments[1]?5'b10000:0); + 1:bits = (segments[1]?5'b10000:0) + ^ (segments[5]?5'b00001:0); + 2:bits = (segments[0]?5'b11111:0) + ^ (|segments[5:4]?5'b00001:0) + ^ (|segments[2:1]?5'b10000:0); + 3:bits = (segments[2]?5'b10000:0) + ^ (segments[4]?5'b00001:0); + 4:bits = (segments[3]?5'b11111:0) + ^ (segments[4]?5'b00001:0) + ^ (segments[2]?5'b10000:0); default:bits = 0; endcase + endmodule -module test_numbers_top( - input clk, reset, - output hsync, vsync, - output [2:0] rgb -); +module test_numbers_top(clk, reset, hsync, vsync, rgb); + + input clk, reset; + output hsync, vsync; + output [2:0] rgb; + wire display_on; wire [8:0] hpos; wire [8:0] vpos; diff --git a/presets/verilog/ball_absolute.v b/presets/verilog/ball_absolute.v new file mode 100644 index 00000000..8a64041c --- /dev/null +++ b/presets/verilog/ball_absolute.v @@ -0,0 +1,75 @@ +`include "hvsync_generator.v" + +module ball_paddle_top(clk, reset, hsync, vsync, rgb); + + input clk; + input reset; + output hsync, vsync; + output [2:0] rgb; + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + reg [8:0] ball_hpos; + reg [8:0] ball_vpos; + + reg [8:0] ball_horiz_initial = 128; + reg [8:0] ball_horiz_move = -2; + reg [8:0] ball_vert_initial = 128; + reg [8:0] ball_vert_move = 2; + + localparam BALL_SIZE = 8; + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + // update horizontal timer + always @(posedge vsync or posedge reset) + begin + if (reset) begin + ball_hpos <= ball_horiz_initial; + ball_vpos <= ball_vert_initial; + end else begin + ball_hpos <= ball_hpos + ball_horiz_move; + ball_vpos <= ball_vpos + ball_vert_move; + end + end + + // vertical bounce + always @(posedge ball_vert_collide) + begin + ball_vert_move <= -ball_vert_move; + end + + // horizontal bounce + always @(posedge ball_horiz_collide) + begin + ball_horiz_move <= -ball_horiz_move; + end + + wire [8:0] ball_hdiff = ball_hpos - hpos; + wire [8:0] ball_vdiff = ball_vpos - vpos; + + wire ball_hgfx = ball_hdiff < BALL_SIZE; + wire ball_vgfx = ball_vdiff < BALL_SIZE; + wire ball_gfx = ball_hgfx && ball_vgfx; + + // collide with vertical and horizontal boundaries + wire ball_vert_collide = ball_vgfx && (vpos==V_DISPLAY || vpos==0); + wire ball_horiz_collide = ball_hgfx && vpos==0 && (hpos==H_DISPLAY || hpos==0); + + wire grid_gfx = (((hpos&7)==0) && ((vpos&7)==0)); + + wire r = display_on && (ball_hgfx | ball_gfx); + wire g = display_on && (grid_gfx | ball_gfx); + wire b = display_on && (ball_vgfx | ball_gfx); + assign rgb = {b,g,r}; + +endmodule diff --git a/presets/verilog/ball_paddle.v b/presets/verilog/ball_paddle.v index 2afd5f12..9b3f40c2 100644 --- a/presets/verilog/ball_paddle.v +++ b/presets/verilog/ball_paddle.v @@ -1,37 +1,6 @@ `include "hvsync_generator.v" `include "digits10.v" - -module player_stats(reset, score0, score1, lives, incscore, declives); - - input reset; - output [3:0] score0; - output [3:0] score1; - input incscore; - output [3:0] lives; - input declives; - - always @(posedge incscore or posedge reset) - begin - if (reset) begin - score0 <= 0; - score1 <= 0; - end else if (score0 == 9) begin - score0 <= 0; - score1 <= score1 + 1; - end else begin - score0 <= score0 + 1; - end - end - - always @(posedge declives or posedge reset) - begin - if (reset) - lives <= 3; - else if (lives != 0) - lives <= lives - 1; - end - -endmodule +`include "scoreboard.v" module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb); @@ -88,26 +57,12 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb); .score0(score0), .score1(score1), .incscore(incscore), .lives(lives), .declives(declives)); - wire [3:0] score_digit; - wire [4:0] score_bits; + wire score_gfx; - always @(*) - begin - case (hpos[7:5]) - 1: score_digit = score1; - 2: score_digit = score0; - 6: score_digit = lives; - default: score_digit = 15; // no digit - endcase - end - - digits10_case numbers( - .digit(score_digit), - .yofs(vpos[4:2]), - .bits(score_bits) - ); - - wire score_gfx = display_on && score_bits[hpos[4:2] ^ 3'b111]; + scoreboard_generator score_gen( + .score0(score0), .score1(score1), .lives(lives), + .vpos(vpos), .hpos(hpos), + .board_gfx(score_gfx)); wire [5:0] hcell = hpos[8:3]; wire [5:0] vcell = vpos[8:3]; diff --git a/presets/verilog/clock_divider.v b/presets/verilog/clock_divider.v index b2cc5032..227947e3 100644 --- a/presets/verilog/clock_divider.v +++ b/presets/verilog/clock_divider.v @@ -1,5 +1,6 @@ module clock_divider( input clk, + input reset, output reg clk_div2, output reg clk_div4, output reg clk_div8, @@ -27,8 +28,11 @@ module clock_divider( // use bits of (4-bit) counter to divide clocks - always @(posedge clk) - counter <= counter + 1; + always @(posedge clk or posedge reset) + if (reset) + counter <= 0; + else + counter <= counter + 1; assign cntr_div2 = counter[0]; assign cntr_div4 = counter[1]; diff --git a/presets/verilog/cpu8.v b/presets/verilog/cpu8.v index d24db186..95954e48 100644 --- a/presets/verilog/cpu8.v +++ b/presets/verilog/cpu8.v @@ -1,16 +1,17 @@ `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 -`define OP_NOP 4'hf +`define OP_OR 4'h2 +`define OP_AND 4'h3 +`define OP_XOR 4'h4 +`define OP_INC 4'h5 +`define OP_DEC 4'h6 +`define OP_NOP 4'h7 +// operations that generate carry +`define OP_ADD 4'h8 +`define OP_SUB 4'h9 +`define OP_ASL 4'ha +`define OP_LSR 4'hb module ALU( input [7:0] A, @@ -42,12 +43,16 @@ endmodule `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 } +`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) } +`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) } +`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B } +`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B } +`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B } +`define I_STORE_A_TO_B { 8'b10000000 } +`define I_CONST_SHORT_A(addr) { 4'b01010, 4'(addr) } +`define I_CONST_SHORT_B(addr) { 4'b01011, 4'(addr) } +`define I_BRANCH_IF_CARRY(carry) { 6'b100100, 1'(carry), 1'b1 } +`define I_RESET { 8'b10000001 } module CPU( input clk, @@ -70,15 +75,15 @@ module CPU( reg [7:0] opcode; wire [3:0] aluop = opcode[3:0]; wire [1:0] opdest = opcode[5:4]; + wire memalu = opcode[6]; 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; + localparam S_COMPUTE = 3; + localparam S_READ_IP = 4; - ALU alu(.A(A), .B(B), .Y(Y), .aluop(aluop)); + ALU alu(.A(A), .B(memalu?data_in:B), .Y(Y), .aluop(aluop)); always @(posedge clk) if (reset) begin @@ -111,23 +116,42 @@ module CPU( 8'b01??????: begin address <= IP; IP <= IP + 1; - state <= S_LOAD_ADDR; + state <= S_COMPUTE; end - // read[B] -> dest, ALU A + B -> dest - 8'b10??????: begin + // ALU A + [B] -> dest + 8'b11??????: begin address <= B; - state <= S_LOAD_ADDR; + state <= S_COMPUTE; end - // ALU A + B -> write [B] -> dest - 8'b1100????: begin + // A -> write [B] + 8'b10000000: begin address <= B; - state <= S_STORE_ADDR; + data_out <= A; + write <= 1; + state <= S_SELECT; end - // ALU A + B -> write [immediate] -> dest - 8'b1101????: begin - address <= IP; - IP <= IP + 1; - state <= S_STORE_ADDR; + // conditional branch + 8'b1001????: begin + if ( + (data_in[0] && (data_in[1] == carry)) || + (data_in[2] && (data_in[3] == zero))) + begin + address <= IP; + state <= S_READ_IP; + end else begin + state <= S_SELECT; + end + IP <= IP + 1; // skip immediate + end + // aluop -> A + 8'b1010????: begin + A <= {4'b0, data_in[3:0]}; + state <= S_SELECT; + end + // aluop -> B + 8'b1011????: begin + B <= {4'b0, data_in[3:0]}; + state <= S_SELECT; end // fall-through RESET default: begin @@ -135,37 +159,25 @@ module CPU( end endcase end - // state 3: load address - S_LOAD_ADDR: begin - 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 - data_out <= Y[7:0]; - write <= 1; - state <= S_SELECT; - end - // state 5: compute ALU op and flags + // state 3: compute ALU op and flags S_COMPUTE: begin + // transfer ALU output to destination 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]; + // set carry for certain operations (code >= 8) + if (aluop[3]) carry <= Y[8]; + // set zero flag zero <= ~|Y; + // repeat CPU loop + state <= S_SELECT; + end + // state 4: read new IP from memory (immediate mode) + S_READ_IP: begin + IP <= data_in; state <= S_SELECT; end endcase @@ -209,13 +221,17 @@ module test_CPU_top( to_cpu = rom[address_bus[6:0]]; initial begin - // address 0x80 - 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; + // ROM starts at address 0x80 + rom['h00] = `I_CONST_IMM_A; + rom['h01] = 1; + rom['h02] = `I_CONST_SHORT_B(0); + rom['h03] = `I_COMPUTE(`DEST_A, `OP_ADD); + rom['h04] = `I_COMPUTE(`DEST_B, `OP_ADD); + rom['h05] = `I_STORE_A_TO_B; + //rom['h06] = `I_JUMP_IMM; + rom['h06] = `I_BRANCH_IF_CARRY(0); + rom['h07] = 3 + 'h80; // correct for ROM offset + rom['h08] = `I_RESET; end endmodule diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v index b560914f..7785c424 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -1,10 +1,14 @@ +`ifndef DIGITS10_H +`define DIGITS10_H + `include "hvsync_generator.v" -module digits10_case( - input [3:0] digit, - input [2:0] yofs, - output [4:0] bits -); +module digits10_case(digit, yofs, bits); + + input [3:0] digit; + input [2:0] yofs; + output [4:0] bits; + wire [6:0] caseexpr = {digit,yofs}; always @(*) case (caseexpr)/*{w:5,h:5,count:10}*/ @@ -72,11 +76,12 @@ module digits10_case( endcase endmodule -module digits10_array( - input [3:0] digit, - input [2:0] yofs, - output [4:0] bits -); +module digits10_array(digit, yofs, bits); + + input [3:0] digit; + input [2:0] yofs; + output [4:0] bits; + reg [4:0] bitarray[16][5]; assign bits = bitarray[digit][yofs]; @@ -142,17 +147,19 @@ module digits10_array( bitarray[9][3] = 5'b00001; bitarray[9][4] = 5'b11111; + // clear unused array entries for (int i = 10; i <= 15; i++) for (int j = 0; j <= 4; j++) bitarray[i][j] = 0; end endmodule -module test_numbers_top( - input clk, reset, - output hsync, vsync, - output [2:0] rgb -); +module test_numbers_top(clk, reset, hsync, vsync, rgb); + + input clk, reset; + output hsync, vsync; + output [2:0] rgb; + wire display_on; wire [8:0] hpos; wire [8:0] vpos; @@ -167,8 +174,9 @@ module test_numbers_top( .vpos(vpos) ); - wire [3:0] digit = hpos[6:3]; - wire [2:0] yofs = vpos[2:0]; + wire [3:0] digit = hpos[7:4]; + wire [2:0] xofs = hpos[3:1]; + wire [2:0] yofs = vpos[3:1]; wire [4:0] bits; digits10_array numbers( @@ -178,8 +186,10 @@ module test_numbers_top( ); wire r = display_on && 0; - wire g = display_on && bits[hpos[2:0] ^ 3'b111]; + wire g = display_on && bits[xofs ^ 3'b111]; wire b = display_on && 0; assign rgb = {b,g,r}; endmodule + +`endif diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v index 5cc07ec1..feb74c68 100644 --- a/presets/verilog/hvsync_generator.v +++ b/presets/verilog/hvsync_generator.v @@ -2,6 +2,7 @@ `define HVSYNC_GENERATOR_H // constant declarations for TV-simulator sync parameters +// horizontal localparam H_DISPLAY = 256; // horizontal display width localparam H_BACK = 23; // horizontal left border (back porch) localparam H_FRONT = 7; // horizontal right border (front porch) @@ -9,7 +10,7 @@ localparam H_SYNC = 23; // horizontal sync width localparam H_SYNC_START = H_DISPLAY + H_FRONT; localparam H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1; localparam H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1; - +// vertical localparam V_DISPLAY = 240; // vertical display height localparam V_TOP = 5; // vertical top border localparam V_BOTTOM = 14; // vertical bottom border @@ -18,14 +19,14 @@ localparam V_SYNC_START = V_DISPLAY + V_BOTTOM; localparam V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1; localparam V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1; -module hvsync_generator( - input clk, - input reset, - output hsync, vsync, - output display_on, - output [8:0] hpos, - output [8:0] vpos -); +module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos); + + input clk; + input reset; + output hsync, vsync; + output display_on; + output [8:0] hpos; + output [8:0] vpos; wire hmaxxed = (hpos == H_MAX) || reset; wire vmaxxed = (vpos == V_MAX) || reset; diff --git a/presets/verilog/ram1.v b/presets/verilog/ram1.v index 4ad7fa65..9d23a185 100644 --- a/presets/verilog/ram1.v +++ b/presets/verilog/ram1.v @@ -2,6 +2,7 @@ `include "digits10.v" module RAM_1KB(clk, addr, din, dout, we); + input clk; // clock input [9:0] addr; // 10-bit address input [7:0] din; // 8-bit data input @@ -15,13 +16,15 @@ module RAM_1KB(clk, addr, din, dout, we); mem[addr] <= din; // write memory from din dout <= mem[addr]; // read memory to dout end + endmodule -module test_framebuf_top( - input clk, reset, - output hsync, vsync, - output [2:0] rgb -); +module test_framebuf_top(clk, reset, hsync, vsync, rgb); + + input clk, reset; + output hsync, vsync; + output [2:0] rgb; + wire display_on; wire [8:0] hpos; wire [8:0] vpos; diff --git a/presets/verilog/scoreboard.v b/presets/verilog/scoreboard.v new file mode 100644 index 00000000..0190011e --- /dev/null +++ b/presets/verilog/scoreboard.v @@ -0,0 +1,103 @@ +`include "hvsync_generator.v" +`include "digits10.v" + +module player_stats(reset, score0, score1, lives, incscore, declives); + + input reset; + output [3:0] score0; + output [3:0] score1; + input incscore; + output [3:0] lives; + input declives; + + always @(posedge incscore or posedge reset) + begin + if (reset) begin + score0 <= 0; + score1 <= 0; + end else if (score0 == 9) begin + score0 <= 0; + score1 <= score1 + 1; + end else begin + score0 <= score0 + 1; + end + end + + always @(posedge declives or posedge reset) + begin + if (reset) + lives <= 3; + else if (lives != 0) + lives <= lives - 1; + end + +endmodule + +module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx); + + input [3:0] score0; + input [3:0] score1; + input [3:0] lives; + input [8:0] vpos; + input [8:0] hpos; + output board_gfx; + + wire [3:0] score_digit; + wire [4:0] score_bits; + + always @(*) + begin + case (hpos[7:5]) + 1: score_digit = score1; + 2: score_digit = score0; + 6: score_digit = lives; + default: score_digit = 15; // no digit + endcase + end + + digits10_array digits( + .digit(score_digit), + .yofs(vpos[4:2]), + .bits(score_bits) + ); + + assign board_gfx = score_bits[hpos[4:2] ^ 3'b111]; + +endmodule + +module top(clk, reset, hsync, vsync, rgb); + + input clk, reset; + output hsync, vsync; + output [2:0] rgb; + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + wire board_gfx; + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + scoreboard_generator scoreboard_gen( + .score0(0), + .score1(1), + .lives(3), + .vpos(vpos), + .hpos(hpos), + .board_gfx(board_gfx) + ); + + wire r = display_on && board_gfx; + wire g = display_on && board_gfx; + wire b = display_on && board_gfx; + assign rgb = {b,g,r}; + +endmodule diff --git a/presets/verilog/sprite_bitmap.v b/presets/verilog/sprite_bitmap.v index eadafd5a..1c0022cb 100644 --- a/presets/verilog/sprite_bitmap.v +++ b/presets/verilog/sprite_bitmap.v @@ -1,9 +1,10 @@ `include "hvsync_generator.v" -module car_bitmap( - input [3:0] yofs, - output [7:0] bits -); +module car_bitmap(yofs, bits); + + input [3:0] yofs; + output [7:0] bits; + reg [7:0] bitarray[16]; assign bits = bitarray[yofs]; initial begin/*{w:8,h:16}*/ @@ -24,6 +25,7 @@ module car_bitmap( bitarray[14] = 8'b11001100; bitarray[15] = 8'b1100; end + endmodule module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v index fea93c6c..073bc783 100644 --- a/presets/verilog/sprite_rotation.v +++ b/presets/verilog/sprite_rotation.v @@ -10,90 +10,90 @@ module tank_bitmap(addr, bits); assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0]; initial begin/*{w:16,h:16,bpw:16,count:5}*/ - bitarray[0'h00] = 16'b11110000000; - bitarray[0'h01] = 16'b11110000000; - bitarray[0'h02] = 16'b1100000000; - bitarray[0'h03] = 16'b1100000000; - bitarray[0'h04] = 16'b111101101111000; - bitarray[0'h05] = 16'b111101101111000; - bitarray[0'h06] = 16'b111111111111000; - bitarray[0'h07] = 16'b111111111111000; - bitarray[0'h08] = 16'b111111111111000; - bitarray[0'h09] = 16'b111111111111000; - bitarray[0'h0a] = 16'b111111111111000; - bitarray[0'h0b] = 16'b111100001111000; - bitarray[0'h0c] = 16'b111100001111000; - bitarray[0'h0d] = 16'b0; - bitarray[0'h0e] = 16'b0; - bitarray[0'h0f] = 16'b0; + bitarray[8'h00] = 16'b11110000000; + bitarray[8'h01] = 16'b11110000000; + bitarray[8'h02] = 16'b1100000000; + bitarray[8'h03] = 16'b1100000000; + bitarray[8'h04] = 16'b111101101111000; + bitarray[8'h05] = 16'b111101101111000; + bitarray[8'h06] = 16'b111111111111000; + bitarray[8'h07] = 16'b111111111111000; + bitarray[8'h08] = 16'b111111111111000; + bitarray[8'h09] = 16'b111111111111000; + bitarray[8'h0a] = 16'b111111111111000; + bitarray[8'h0b] = 16'b111100001111000; + bitarray[8'h0c] = 16'b111100001111000; + bitarray[8'h0d] = 16'b0; + bitarray[8'h0e] = 16'b0; + bitarray[8'h0f] = 16'b0; - bitarray[0'h10] = 16'b111000000000; - bitarray[0'h11] = 16'b1111000000000; - bitarray[0'h12] = 16'b1111000000000; - bitarray[0'h13] = 16'b11000000000; - bitarray[0'h14] = 16'b11101110000; - bitarray[0'h15] = 16'b1101110000; - bitarray[0'h16] = 16'b111101111110000; - bitarray[0'h17] = 16'b111101111111000; - bitarray[0'h18] = 16'b111111111111000; - bitarray[0'h19] = 16'b11111111111000; - bitarray[0'h1a] = 16'b11111111111100; - bitarray[0'h1b] = 16'b11111111111100; - bitarray[0'h1c] = 16'b11111001111100; - bitarray[0'h1d] = 16'b1111001110000; - bitarray[0'h1e] = 16'b1111000000000; - bitarray[0'h1f] = 16'b1100000000000; + bitarray[8'h10] = 16'b111000000000; + bitarray[8'h11] = 16'b1111000000000; + bitarray[8'h12] = 16'b1111000000000; + bitarray[8'h13] = 16'b11000000000; + bitarray[8'h14] = 16'b11101110000; + bitarray[8'h15] = 16'b1101110000; + bitarray[8'h16] = 16'b111101111110000; + bitarray[8'h17] = 16'b111101111111000; + bitarray[8'h18] = 16'b111111111111000; + bitarray[8'h19] = 16'b11111111111000; + bitarray[8'h1a] = 16'b11111111111100; + bitarray[8'h1b] = 16'b11111111111100; + bitarray[8'h1c] = 16'b11111001111100; + bitarray[8'h1d] = 16'b1111001110000; + bitarray[8'h1e] = 16'b1111000000000; + bitarray[8'h1f] = 16'b1100000000000; - bitarray[0'h20] = 16'b0; - bitarray[0'h21] = 16'b0; - bitarray[0'h22] = 16'b11000011000000; - bitarray[0'h23] = 16'b111000111100000; - bitarray[0'h24] = 16'b111101111110000; - bitarray[0'h25] = 16'b1110111111000; - bitarray[0'h26] = 16'b111111111100; - bitarray[0'h27] = 16'b11111111110; - bitarray[0'h28] = 16'b11011111111110; - bitarray[0'h29] = 16'b111111111111100; - bitarray[0'h2a] = 16'b111111111001000; - bitarray[0'h2b] = 16'b11111110000000; - bitarray[0'h2c] = 16'b1111100000000; - bitarray[0'h2d] = 16'b111110000000; - bitarray[0'h2e] = 16'b11110000000; - bitarray[0'h2f] = 16'b1100000000; + bitarray[8'h20] = 16'b0; + bitarray[8'h21] = 16'b0; + bitarray[8'h22] = 16'b11000011000000; + bitarray[8'h23] = 16'b111000111100000; + bitarray[8'h24] = 16'b111101111110000; + bitarray[8'h25] = 16'b1110111111000; + bitarray[8'h26] = 16'b111111111100; + bitarray[8'h27] = 16'b11111111110; + bitarray[8'h28] = 16'b11011111111110; + bitarray[8'h29] = 16'b111111111111100; + bitarray[8'h2a] = 16'b111111111001000; + bitarray[8'h2b] = 16'b11111110000000; + bitarray[8'h2c] = 16'b1111100000000; + bitarray[8'h2d] = 16'b111110000000; + bitarray[8'h2e] = 16'b11110000000; + bitarray[8'h2f] = 16'b1100000000; - bitarray[0'h30] = 16'b0; - bitarray[0'h31] = 16'b0; - bitarray[0'h32] = 16'b110000000; - bitarray[0'h33] = 16'b100001111000000; - bitarray[0'h34] = 16'b1110001111110000; - bitarray[0'h35] = 16'b1111010111111100; - bitarray[0'h36] = 16'b1111111111111111; - bitarray[0'h37] = 16'b1111111111111; - bitarray[0'h38] = 16'b11111111110; - bitarray[0'h39] = 16'b101111111110; - bitarray[0'h3a] = 16'b1111111101100; - bitarray[0'h3b] = 16'b11111111000000; - bitarray[0'h3c] = 16'b1111111100000; - bitarray[0'h3d] = 16'b11111110000; - bitarray[0'h3e] = 16'b111100000; - bitarray[0'h3f] = 16'b1100000; + bitarray[8'h30] = 16'b0; + bitarray[8'h31] = 16'b0; + bitarray[8'h32] = 16'b110000000; + bitarray[8'h33] = 16'b100001111000000; + bitarray[8'h34] = 16'b1110001111110000; + bitarray[8'h35] = 16'b1111010111111100; + bitarray[8'h36] = 16'b1111111111111111; + bitarray[8'h37] = 16'b1111111111111; + bitarray[8'h38] = 16'b11111111110; + bitarray[8'h39] = 16'b101111111110; + bitarray[8'h3a] = 16'b1111111101100; + bitarray[8'h3b] = 16'b11111111000000; + bitarray[8'h3c] = 16'b1111111100000; + bitarray[8'h3d] = 16'b11111110000; + bitarray[8'h3e] = 16'b111100000; + bitarray[8'h3f] = 16'b1100000; - bitarray[0'h40] = 16'b0; - bitarray[0'h41] = 16'b0; - bitarray[0'h42] = 16'b0; - bitarray[0'h43] = 16'b111111111000; - bitarray[0'h44] = 16'b111111111000; - bitarray[0'h45] = 16'b111111111000; - bitarray[0'h46] = 16'b111111111000; - bitarray[0'h47] = 16'b1100001111100000; - bitarray[0'h48] = 16'b1111111111100000; - bitarray[0'h49] = 16'b1111111111100000; - bitarray[0'h4a] = 16'b1100001111100000; - bitarray[0'h4b] = 16'b111111111000; - bitarray[0'h4c] = 16'b111111111000; - bitarray[0'h4d] = 16'b111111111000; - bitarray[0'h4e] = 16'b111111111000; - bitarray[0'h4f] = 16'b0; + bitarray[8'h40] = 16'b0; + bitarray[8'h41] = 16'b0; + bitarray[8'h42] = 16'b0; + bitarray[8'h43] = 16'b111111111000; + bitarray[8'h44] = 16'b111111111000; + bitarray[8'h45] = 16'b111111111000; + bitarray[8'h46] = 16'b111111111000; + bitarray[8'h47] = 16'b1100001111100000; + bitarray[8'h48] = 16'b1111111111100000; + bitarray[8'h49] = 16'b1111111111100000; + bitarray[8'h4a] = 16'b1100001111100000; + bitarray[8'h4b] = 16'b111111111000; + bitarray[8'h4c] = 16'b111111111000; + bitarray[8'h4d] = 16'b111111111000; + bitarray[8'h4e] = 16'b111111111000; + bitarray[8'h4f] = 16'b0; end endmodule @@ -224,6 +224,7 @@ endfunction module tank_controller(clk, reset, hpos, vpos, hsync, vsync, sprite_addr, sprite_bits, gfx, + playfield, switch_left, switch_right, switch_up); input clk; @@ -235,10 +236,16 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, output [7:0] sprite_addr; input [7:0] sprite_bits; output gfx; + input playfield; input switch_left, switch_right, switch_up; + parameter initial_x = 128; + parameter initial_y = 120; + parameter initial_rot = 0; + wire hmirror, vmirror; wire busy; + wire collision_gfx = gfx && playfield; reg [11:0] player_x_fixed; wire [7:0] player_x = player_x_fixed[11:4]; @@ -249,7 +256,7 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, 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] player_speed; reg [3:0] frame = 0; wire vstart = {1'b0,player_y} == vpos; @@ -274,8 +281,10 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, .vmirror(vmirror)); always @(posedge vsync or posedge reset) + begin if (reset) begin - player_rot <= 0; + player_rot <= initial_rot; + player_speed <= 0; end else begin frame <= frame + 1; // rotation @@ -291,13 +300,24 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, player_speed <= 0; end end + end + + reg collision_detected; + always @(posedge collision_gfx or posedge vsync or posedge reset) + collision_detected <= collision_gfx; always @(posedge hsync or posedge reset) if (reset) begin - player_x_fixed <= 128<<4; - player_y_fixed <= 120<<4; + player_x_fixed <= initial_x << 4; + player_y_fixed <= initial_y << 4; end else begin // movement + if (collision_detected && vpos[1]) begin + if (vpos[0]) + player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot+8)); + else + player_y_fixed <= player_y_fixed - 12'(sin_16x4(player_rot+12)); + end else if (vpos < 9'(player_speed)) begin if (vpos[0]) player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot)); @@ -310,7 +330,7 @@ endmodule //TODO: debouncing -module test_top(clk, reset, hsync, vsync, rgb, switches_p1); +module control_test_top(clk, reset, hsync, vsync, rgb, switches_p1); input clk; input reset; @@ -353,17 +373,18 @@ module test_top(clk, reset, hsync, vsync, rgb, switches_p1); .sprite_addr(tank_sprite_addr), .sprite_bits(tank_sprite_bits), .gfx(tank1_gfx), + .playfield(playfield_gfx), .switch_left(switches_p1[0]), .switch_right(switches_p1[1]), .switch_up(switches_p1[2]) ); wire tank1_gfx; - wire unused; + wire playfield_gfx = hpos[5] && vpos[5]; wire r = display_on && tank1_gfx; wire g = display_on && tank1_gfx; - wire b = display_on && tank1_gfx; + wire b = display_on && (tank1_gfx || playfield_gfx); assign rgb = {b,g,r}; endmodule diff --git a/presets/verilog/tank.v b/presets/verilog/tank.v index de1a388b..c01e06b6 100644 --- a/presets/verilog/tank.v +++ b/presets/verilog/tank.v @@ -1,4 +1,5 @@ `include "hvsync_generator.v" +`include "sprite_rotation.v" module minefield(hpos, vpos, mine_gfx); @@ -72,43 +73,47 @@ module playfield(hpos, vpos, playfield_gfx); maze[2] = 32'b10000000000100000000001000000001; maze[3] = 32'b10000000000100000000000000000001; maze[4] = 32'b10011110000000000000000000000001; - maze[5] = 32'b10000000000000000000000011111001; - maze[6] = 32'b10000000001000000000000000100001; + maze[5] = 32'b10000000000000000000000000000001; + maze[6] = 32'b10000000001000000000000011110001; maze[7] = 32'b11100010000000000000000000100001; - maze[8] = 32'b10000010000000000000000000000001; + maze[8] = 32'b10000010000000000000000000100001; maze[9] = 32'b10000011100000000000000000000001; maze[10] = 32'b10000000000000000000000000000001; maze[11] = 32'b10000000000000000000000000000001; maze[12] = 32'b11111000001000000000000000000001; maze[13] = 32'b10001000001000000000000111100001; - maze[14] = 32'b10001110001000000000000000000001; + maze[14] = 32'b10001000001000000000000000000001; maze[15] = 32'b10000000001000000000000000000001; maze[16] = 32'b10000000001000000000000000000001; - maze[17] = 32'b10001111000000000000000000000001; - maze[18] = 32'b10000000000000000000000100011001; - maze[19] = 32'b10000000000000000000000100010001; - maze[20] = 32'b10000001001000000000000100010001; - maze[21] = 32'b10000001001110000000000100000001; - maze[22] = 32'b10000001000000000010001100000001; - maze[23] = 32'b10001000000000000000000000000001; - maze[24] = 32'b10001000000111100000000000010001; - maze[25] = 32'b10001000000000100000000000010001; - maze[26] = 32'b10001000000000000010000000010001; + maze[17] = 32'b10000000000000000000000000000001; + maze[18] = 32'b10000010000000000000000100011001; + maze[19] = 32'b10001110000000000000000100010001; + maze[20] = 32'b10000000001000000000000100010001; + maze[21] = 32'b10000000001110000000000100000001; + maze[22] = 32'b10000000000000000010001100000001; + maze[23] = 32'b10000000000000000000000000000001; + maze[24] = 32'b10000010000111100000000000010001; + maze[25] = 32'b10000010000000100000000000010001; + maze[26] = 32'b10000010000000000010000000010001; maze[27] = 32'b11111111111111111111111111111111; end endmodule -module mine_test_top(clk, hsync, vsync, rgb); +module mine_test_top(clk, reset, hsync, vsync, rgb, switches_p1, switches_p2); - input clk; + input clk, reset; + input [7:0] switches_p1; + input [7:0] switches_p2; output hsync, vsync; output [2:0] rgb; + wire display_on; wire [8:0] hpos; wire [8:0] vpos; wire mine_gfx; wire playfield_gfx; + wire tank1_gfx, tank2_gfx; hvsync_generator hvsync_gen( .clk(clk), @@ -132,9 +137,54 @@ module mine_test_top(clk, hsync, vsync, rgb); .playfield_gfx(playfield_gfx) ); - wire r = display_on && mine_gfx; - wire g = display_on && playfield_gfx; - wire b = display_on && 0; + // multiplex player 1 and 2 load times during hsync + wire p2sel = hpos[3]; + // sprite ROM inputs for each player + wire [7:0] tank1_sprite_addr; + wire [7:0] tank2_sprite_addr; + // multiplex sprite ROM output + wire [7:0] tank_sprite_bits; + + // bitmap ROM is shared between tank 1 and 2 + tank_bitmap tank_bmp( + .addr(p2sel ? tank2_sprite_addr : tank1_sprite_addr), + .bits(tank_sprite_bits)); + + tank_controller #(16,36,4) tank1( + .clk(clk), + .reset(reset), + .hpos(hpos), + .vpos(vpos), + .hsync(hsync && !p2sel), + .vsync(vsync), + .sprite_addr(tank1_sprite_addr), + .sprite_bits(tank_sprite_bits), + .gfx(tank1_gfx), + .playfield(playfield_gfx), + .switch_left(switches_p1[0]), + .switch_right(switches_p1[1]), + .switch_up(switches_p1[2]) + ); + + tank_controller #(220,190,12) tank2( + .clk(clk), + .reset(reset), + .hpos(hpos), + .vpos(vpos), + .hsync(hsync && p2sel), + .vsync(vsync), + .sprite_addr(tank2_sprite_addr), + .sprite_bits(tank_sprite_bits), + .gfx(tank2_gfx), + .playfield(playfield_gfx), + .switch_left(switches_p2[0]), + .switch_right(switches_p2[1]), + .switch_up(switches_p2[2]) + ); + + wire r = display_on && (mine_gfx || tank2_gfx); + wire g = display_on && tank1_gfx; + wire b = display_on && (playfield_gfx || tank2_gfx); assign rgb = {b,g,r}; endmodule diff --git a/presets/verilog/test_hvsync.v b/presets/verilog/test_hvsync.v index 10b132c8..ee33041d 100644 --- a/presets/verilog/test_hvsync.v +++ b/presets/verilog/test_hvsync.v @@ -1,12 +1,10 @@ `include "hvsync_generator.v" -module test_hvsync_top( - input clk, - output hsync, - output vsync, - output [2:0] rgb -); - +module test_hvsync_top(clk, reset, hsync, vsync, rgb); + + input clk, reset; + output hsync, vsync; + output [2:0] rgb; wire display_on; wire [8:0] hpos; wire [8:0] vpos; diff --git a/src/platform/verilog.js b/src/platform/verilog.js index 13dab3c0..e9799726 100644 --- a/src/platform/verilog.js +++ b/src/platform/verilog.js @@ -7,13 +7,14 @@ var VERILOG_PRESETS = [ {id:'lfsr.v', name:'Linear Feedback Shift Register'}, {id:'digits10.v', name:'Bitmapped Digits'}, {id:'7segment.v', name:'7-Segment Decoder'}, + {id:'scoreboard.v', name:'Scoreboard'}, {id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'}, {id:'ball_paddle.v', name:'Brick Smash Game'}, + {id:'ram1.v', name:'RAM Text Display'}, {id:'sprite_bitmap.v', name:'Sprite Bitmaps'}, {id:'sprite_renderer.v', name:'Sprite Rendering'}, {id:'sprite_multiple.v', name:'Multiple Sprites'}, {id:'sprite_rotation.v', name:'Sprite Rotation'}, - {id:'ram1.v', name:'RAM Text Display'}, {id:'tank.v', name:'Tank Game'}, {id:'cpu8.v', name:'Simple 8-Bit CPU'}, ]; diff --git a/src/worker/workermain.js b/src/worker/workermain.js index e1ab64a1..1692ea91 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -1047,8 +1047,9 @@ function writeDependencies(depends, FS, errors) { if (depends) { for (var i=0; i