1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-12-22 12:30:01 +00:00

more presets

This commit is contained in:
Steven Hugg 2018-02-06 18:07:40 -06:00
parent 122e462c9f
commit 11992645d6
15 changed files with 529 additions and 276 deletions

View File

@ -1,6 +1,7 @@
`include "hvsync_generator.v" `include "hvsync_generator.v"
module seven_segment_decoder(digit, segments); module seven_segment_decoder(digit, segments);
input [3:0] digit; input [3:0] digit;
output [6:0] segments; output [6:0] segments;
@ -18,29 +19,41 @@ module seven_segment_decoder(digit, segments);
9: segments = 7'b1111011; 9: segments = 7'b1111011;
default: segments = 7'b0000000; default: segments = 7'b0000000;
endcase endcase
endmodule endmodule
module segments_to_bitmap(segments, line, bits); module segments_to_bitmap(segments, line, bits);
input [6:0] segments; input [6:0] segments;
input [2:0] line; input [2:0] line;
output [4:0] bits; output [4:0] bits;
always @(*) always @(*)
case (line) case (line)
0:bits = (segments[6]?5'b11111:0) ^ (segments[5]?5'b00001:0) ^ (segments[1]?5'b10000:0); 0:bits = (segments[6]?5'b11111:0)
1:bits = (segments[1]?5'b10000:0) ^ (segments[5]?5'b00001: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); ^ (segments[1]?5'b10000:0);
3:bits = (segments[2]?5'b10000:0) ^ (segments[4]?5'b00001:0); 1:bits = (segments[1]?5'b10000:0)
4:bits = (segments[3]?5'b11111:0) ^ (segments[4]?5'b00001:0) ^ (segments[2]?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; default:bits = 0;
endcase endcase
endmodule endmodule
module test_numbers_top( module test_numbers_top(clk, reset, hsync, vsync, rgb);
input clk, reset,
output hsync, vsync, input clk, reset;
output [2:0] rgb output hsync, vsync;
); output [2:0] rgb;
wire display_on; wire display_on;
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;

View File

@ -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

View File

@ -1,37 +1,6 @@
`include "hvsync_generator.v" `include "hvsync_generator.v"
`include "digits10.v" `include "digits10.v"
`include "scoreboard.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 ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb); 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), .score0(score0), .score1(score1), .incscore(incscore),
.lives(lives), .declives(declives)); .lives(lives), .declives(declives));
wire [3:0] score_digit; wire score_gfx;
wire [4:0] score_bits;
always @(*) scoreboard_generator score_gen(
begin .score0(score0), .score1(score1), .lives(lives),
case (hpos[7:5]) .vpos(vpos), .hpos(hpos),
1: score_digit = score1; .board_gfx(score_gfx));
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];
wire [5:0] hcell = hpos[8:3]; wire [5:0] hcell = hpos[8:3];
wire [5:0] vcell = vpos[8:3]; wire [5:0] vcell = vpos[8:3];

View File

@ -1,5 +1,6 @@
module clock_divider( module clock_divider(
input clk, input clk,
input reset,
output reg clk_div2, output reg clk_div2,
output reg clk_div4, output reg clk_div4,
output reg clk_div8, output reg clk_div8,
@ -27,7 +28,10 @@ module clock_divider(
// use bits of (4-bit) counter to divide clocks // use bits of (4-bit) counter to divide clocks
always @(posedge clk) always @(posedge clk or posedge reset)
if (reset)
counter <= 0;
else
counter <= counter + 1; counter <= counter + 1;
assign cntr_div2 = counter[0]; assign cntr_div2 = counter[0];

View File

@ -1,16 +1,17 @@
`define OP_LOAD_A 4'h0 `define OP_LOAD_A 4'h0
`define OP_LOAD_B 4'h1 `define OP_LOAD_B 4'h1
`define OP_ADD 4'h2 `define OP_OR 4'h2
`define OP_SUB 4'h3 `define OP_AND 4'h3
`define OP_INC 4'h4 `define OP_XOR 4'h4
`define OP_DEC 4'h5 `define OP_INC 4'h5
`define OP_ASL 4'h6 `define OP_DEC 4'h6
`define OP_LSR 4'h7 `define OP_NOP 4'h7
`define OP_OR 4'h8 // operations that generate carry
`define OP_AND 4'h9 `define OP_ADD 4'h8
`define OP_XOR 4'ha `define OP_SUB 4'h9
`define OP_NOP 4'hf `define OP_ASL 4'ha
`define OP_LSR 4'hb
module ALU( module ALU(
input [7:0] A, input [7:0] A,
@ -42,12 +43,16 @@ endmodule
`define DEST_IP 2'b10 `define DEST_IP 2'b10
`define DEST_NOP 2'b11 `define DEST_NOP 2'b11
`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) } `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_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) }
`define I_LOAD_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B } `define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) }
`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_NOP } `define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B }
`define I_STORE_B(op) { 4'b01100, 4'(op) } `define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B }
`define I_STORE_IMM(op) { 4'b01101, 4'(op) } `define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B }
`define I_RESET { 8'hff } `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( module CPU(
input clk, input clk,
@ -70,15 +75,15 @@ module CPU(
reg [7:0] opcode; reg [7:0] opcode;
wire [3:0] aluop = opcode[3:0]; wire [3:0] aluop = opcode[3:0];
wire [1:0] opdest = opcode[5:4]; wire [1:0] opdest = opcode[5:4];
wire memalu = opcode[6];
localparam S_RESET = 0; localparam S_RESET = 0;
localparam S_SELECT = 1; localparam S_SELECT = 1;
localparam S_DECODE = 2; localparam S_DECODE = 2;
localparam S_LOAD_ADDR = 3; localparam S_COMPUTE = 3;
localparam S_STORE_ADDR = 4; localparam S_READ_IP = 4;
localparam S_COMPUTE = 5;
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) always @(posedge clk)
if (reset) begin if (reset) begin
@ -111,23 +116,42 @@ module CPU(
8'b01??????: begin 8'b01??????: begin
address <= IP; address <= IP;
IP <= IP + 1; IP <= IP + 1;
state <= S_LOAD_ADDR; state <= S_COMPUTE;
end end
// read[B] -> dest, ALU A + B -> dest // ALU A + [B] -> dest
8'b10??????: begin 8'b11??????: begin
address <= B; address <= B;
state <= S_LOAD_ADDR; state <= S_COMPUTE;
end end
// ALU A + B -> write [B] -> dest // A -> write [B]
8'b1100????: begin 8'b10000000: begin
address <= B; address <= B;
state <= S_STORE_ADDR; data_out <= A;
write <= 1;
state <= S_SELECT;
end end
// ALU A + B -> write [immediate] -> dest // conditional branch
8'b1101????: begin 8'b1001????: begin
if (
(data_in[0] && (data_in[1] == carry)) ||
(data_in[2] && (data_in[3] == zero)))
begin
address <= IP; address <= IP;
IP <= IP + 1; state <= S_READ_IP;
state <= S_STORE_ADDR; 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 end
// fall-through RESET // fall-through RESET
default: begin default: begin
@ -135,37 +159,25 @@ module CPU(
end end
endcase endcase
end end
// state 3: load address // state 3: compute ALU op and flags
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
S_COMPUTE: begin S_COMPUTE: begin
// transfer ALU output to destination
case (opdest) case (opdest)
`DEST_A: A <= Y[7:0]; `DEST_A: A <= Y[7:0];
`DEST_B: B <= Y[7:0]; `DEST_B: B <= Y[7:0];
`DEST_IP: IP <= Y[7:0]; `DEST_IP: IP <= Y[7:0];
`DEST_NOP: ; `DEST_NOP: ;
endcase endcase
carry <= Y[8]; // set carry for certain operations (code >= 8)
if (aluop[3]) carry <= Y[8];
// set zero flag
zero <= ~|Y; 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; state <= S_SELECT;
end end
endcase endcase
@ -209,13 +221,17 @@ module test_CPU_top(
to_cpu = rom[address_bus[6:0]]; to_cpu = rom[address_bus[6:0]];
initial begin initial begin
// address 0x80 // ROM starts at address 0x80
rom['h00] = `I_LOAD_IMM_A; rom['h00] = `I_CONST_IMM_A;
rom['h01] = 42; rom['h01] = 1;
rom['h02] = `I_COMPUTE(`DEST_A, `OP_ASL); rom['h02] = `I_CONST_SHORT_B(0);
rom['h03] = `I_COMPUTE(`DEST_B, `OP_INC); rom['h03] = `I_COMPUTE(`DEST_A, `OP_ADD);
rom['h04] = `I_STORE_B(`OP_LOAD_B); rom['h04] = `I_COMPUTE(`DEST_B, `OP_ADD);
rom['h05] = `I_RESET; 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 end
endmodule endmodule

View File

@ -1,10 +1,14 @@
`ifndef DIGITS10_H
`define DIGITS10_H
`include "hvsync_generator.v" `include "hvsync_generator.v"
module digits10_case( module digits10_case(digit, yofs, bits);
input [3:0] digit,
input [2:0] yofs, input [3:0] digit;
output [4:0] bits input [2:0] yofs;
); output [4:0] bits;
wire [6:0] caseexpr = {digit,yofs}; wire [6:0] caseexpr = {digit,yofs};
always @(*) always @(*)
case (caseexpr)/*{w:5,h:5,count:10}*/ case (caseexpr)/*{w:5,h:5,count:10}*/
@ -72,11 +76,12 @@ module digits10_case(
endcase endcase
endmodule endmodule
module digits10_array( module digits10_array(digit, yofs, bits);
input [3:0] digit,
input [2:0] yofs, input [3:0] digit;
output [4:0] bits input [2:0] yofs;
); output [4:0] bits;
reg [4:0] bitarray[16][5]; reg [4:0] bitarray[16][5];
assign bits = bitarray[digit][yofs]; assign bits = bitarray[digit][yofs];
@ -142,17 +147,19 @@ module digits10_array(
bitarray[9][3] = 5'b00001; bitarray[9][3] = 5'b00001;
bitarray[9][4] = 5'b11111; bitarray[9][4] = 5'b11111;
// clear unused array entries
for (int i = 10; i <= 15; i++) for (int i = 10; i <= 15; i++)
for (int j = 0; j <= 4; j++) for (int j = 0; j <= 4; j++)
bitarray[i][j] = 0; bitarray[i][j] = 0;
end end
endmodule endmodule
module test_numbers_top( module test_numbers_top(clk, reset, hsync, vsync, rgb);
input clk, reset,
output hsync, vsync, input clk, reset;
output [2:0] rgb output hsync, vsync;
); output [2:0] rgb;
wire display_on; wire display_on;
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;
@ -167,8 +174,9 @@ module test_numbers_top(
.vpos(vpos) .vpos(vpos)
); );
wire [3:0] digit = hpos[6:3]; wire [3:0] digit = hpos[7:4];
wire [2:0] yofs = vpos[2:0]; wire [2:0] xofs = hpos[3:1];
wire [2:0] yofs = vpos[3:1];
wire [4:0] bits; wire [4:0] bits;
digits10_array numbers( digits10_array numbers(
@ -178,8 +186,10 @@ module test_numbers_top(
); );
wire r = display_on && 0; 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; wire b = display_on && 0;
assign rgb = {b,g,r}; assign rgb = {b,g,r};
endmodule endmodule
`endif

View File

@ -2,6 +2,7 @@
`define HVSYNC_GENERATOR_H `define HVSYNC_GENERATOR_H
// constant declarations for TV-simulator sync parameters // constant declarations for TV-simulator sync parameters
// horizontal
localparam H_DISPLAY = 256; // horizontal display width localparam H_DISPLAY = 256; // horizontal display width
localparam H_BACK = 23; // horizontal left border (back porch) localparam H_BACK = 23; // horizontal left border (back porch)
localparam H_FRONT = 7; // horizontal right border (front 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_START = H_DISPLAY + H_FRONT;
localparam H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1; localparam H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1;
localparam H_MAX = H_DISPLAY + H_BACK + 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_DISPLAY = 240; // vertical display height
localparam V_TOP = 5; // vertical top border localparam V_TOP = 5; // vertical top border
localparam V_BOTTOM = 14; // vertical bottom 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_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1;
localparam V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1; localparam V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1;
module hvsync_generator( module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos);
input clk,
input reset, input clk;
output hsync, vsync, input reset;
output display_on, output hsync, vsync;
output [8:0] hpos, output display_on;
output [8:0] vpos output [8:0] hpos;
); output [8:0] vpos;
wire hmaxxed = (hpos == H_MAX) || reset; wire hmaxxed = (hpos == H_MAX) || reset;
wire vmaxxed = (vpos == V_MAX) || reset; wire vmaxxed = (vpos == V_MAX) || reset;

View File

@ -2,6 +2,7 @@
`include "digits10.v" `include "digits10.v"
module RAM_1KB(clk, addr, din, dout, we); module RAM_1KB(clk, addr, din, dout, we);
input clk; // clock input clk; // clock
input [9:0] addr; // 10-bit address input [9:0] addr; // 10-bit address
input [7:0] din; // 8-bit data input 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 mem[addr] <= din; // write memory from din
dout <= mem[addr]; // read memory to dout dout <= mem[addr]; // read memory to dout
end end
endmodule endmodule
module test_framebuf_top( module test_framebuf_top(clk, reset, hsync, vsync, rgb);
input clk, reset,
output hsync, vsync, input clk, reset;
output [2:0] rgb output hsync, vsync;
); output [2:0] rgb;
wire display_on; wire display_on;
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;

View File

@ -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

View File

@ -1,9 +1,10 @@
`include "hvsync_generator.v" `include "hvsync_generator.v"
module car_bitmap( module car_bitmap(yofs, bits);
input [3:0] yofs,
output [7:0] bits input [3:0] yofs;
); output [7:0] bits;
reg [7:0] bitarray[16]; reg [7:0] bitarray[16];
assign bits = bitarray[yofs]; assign bits = bitarray[yofs];
initial begin/*{w:8,h:16}*/ initial begin/*{w:8,h:16}*/
@ -24,6 +25,7 @@ module car_bitmap(
bitarray[14] = 8'b11001100; bitarray[14] = 8'b11001100;
bitarray[15] = 8'b1100; bitarray[15] = 8'b1100;
end end
endmodule endmodule
module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); module sprite_bitmap_top(clk, reset, hsync, vsync, rgb);

View File

@ -10,90 +10,90 @@ module tank_bitmap(addr, bits);
assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0]; assign bits = (addr[0]) ? bitarray[addr>>1][15:8] : bitarray[addr>>1][7:0];
initial begin/*{w:16,h:16,bpw:16,count:5}*/ initial begin/*{w:16,h:16,bpw:16,count:5}*/
bitarray[0'h00] = 16'b11110000000; bitarray[8'h00] = 16'b11110000000;
bitarray[0'h01] = 16'b11110000000; bitarray[8'h01] = 16'b11110000000;
bitarray[0'h02] = 16'b1100000000; bitarray[8'h02] = 16'b1100000000;
bitarray[0'h03] = 16'b1100000000; bitarray[8'h03] = 16'b1100000000;
bitarray[0'h04] = 16'b111101101111000; bitarray[8'h04] = 16'b111101101111000;
bitarray[0'h05] = 16'b111101101111000; bitarray[8'h05] = 16'b111101101111000;
bitarray[0'h06] = 16'b111111111111000; bitarray[8'h06] = 16'b111111111111000;
bitarray[0'h07] = 16'b111111111111000; bitarray[8'h07] = 16'b111111111111000;
bitarray[0'h08] = 16'b111111111111000; bitarray[8'h08] = 16'b111111111111000;
bitarray[0'h09] = 16'b111111111111000; bitarray[8'h09] = 16'b111111111111000;
bitarray[0'h0a] = 16'b111111111111000; bitarray[8'h0a] = 16'b111111111111000;
bitarray[0'h0b] = 16'b111100001111000; bitarray[8'h0b] = 16'b111100001111000;
bitarray[0'h0c] = 16'b111100001111000; bitarray[8'h0c] = 16'b111100001111000;
bitarray[0'h0d] = 16'b0; bitarray[8'h0d] = 16'b0;
bitarray[0'h0e] = 16'b0; bitarray[8'h0e] = 16'b0;
bitarray[0'h0f] = 16'b0; bitarray[8'h0f] = 16'b0;
bitarray[0'h10] = 16'b111000000000; bitarray[8'h10] = 16'b111000000000;
bitarray[0'h11] = 16'b1111000000000; bitarray[8'h11] = 16'b1111000000000;
bitarray[0'h12] = 16'b1111000000000; bitarray[8'h12] = 16'b1111000000000;
bitarray[0'h13] = 16'b11000000000; bitarray[8'h13] = 16'b11000000000;
bitarray[0'h14] = 16'b11101110000; bitarray[8'h14] = 16'b11101110000;
bitarray[0'h15] = 16'b1101110000; bitarray[8'h15] = 16'b1101110000;
bitarray[0'h16] = 16'b111101111110000; bitarray[8'h16] = 16'b111101111110000;
bitarray[0'h17] = 16'b111101111111000; bitarray[8'h17] = 16'b111101111111000;
bitarray[0'h18] = 16'b111111111111000; bitarray[8'h18] = 16'b111111111111000;
bitarray[0'h19] = 16'b11111111111000; bitarray[8'h19] = 16'b11111111111000;
bitarray[0'h1a] = 16'b11111111111100; bitarray[8'h1a] = 16'b11111111111100;
bitarray[0'h1b] = 16'b11111111111100; bitarray[8'h1b] = 16'b11111111111100;
bitarray[0'h1c] = 16'b11111001111100; bitarray[8'h1c] = 16'b11111001111100;
bitarray[0'h1d] = 16'b1111001110000; bitarray[8'h1d] = 16'b1111001110000;
bitarray[0'h1e] = 16'b1111000000000; bitarray[8'h1e] = 16'b1111000000000;
bitarray[0'h1f] = 16'b1100000000000; bitarray[8'h1f] = 16'b1100000000000;
bitarray[0'h20] = 16'b0; bitarray[8'h20] = 16'b0;
bitarray[0'h21] = 16'b0; bitarray[8'h21] = 16'b0;
bitarray[0'h22] = 16'b11000011000000; bitarray[8'h22] = 16'b11000011000000;
bitarray[0'h23] = 16'b111000111100000; bitarray[8'h23] = 16'b111000111100000;
bitarray[0'h24] = 16'b111101111110000; bitarray[8'h24] = 16'b111101111110000;
bitarray[0'h25] = 16'b1110111111000; bitarray[8'h25] = 16'b1110111111000;
bitarray[0'h26] = 16'b111111111100; bitarray[8'h26] = 16'b111111111100;
bitarray[0'h27] = 16'b11111111110; bitarray[8'h27] = 16'b11111111110;
bitarray[0'h28] = 16'b11011111111110; bitarray[8'h28] = 16'b11011111111110;
bitarray[0'h29] = 16'b111111111111100; bitarray[8'h29] = 16'b111111111111100;
bitarray[0'h2a] = 16'b111111111001000; bitarray[8'h2a] = 16'b111111111001000;
bitarray[0'h2b] = 16'b11111110000000; bitarray[8'h2b] = 16'b11111110000000;
bitarray[0'h2c] = 16'b1111100000000; bitarray[8'h2c] = 16'b1111100000000;
bitarray[0'h2d] = 16'b111110000000; bitarray[8'h2d] = 16'b111110000000;
bitarray[0'h2e] = 16'b11110000000; bitarray[8'h2e] = 16'b11110000000;
bitarray[0'h2f] = 16'b1100000000; bitarray[8'h2f] = 16'b1100000000;
bitarray[0'h30] = 16'b0; bitarray[8'h30] = 16'b0;
bitarray[0'h31] = 16'b0; bitarray[8'h31] = 16'b0;
bitarray[0'h32] = 16'b110000000; bitarray[8'h32] = 16'b110000000;
bitarray[0'h33] = 16'b100001111000000; bitarray[8'h33] = 16'b100001111000000;
bitarray[0'h34] = 16'b1110001111110000; bitarray[8'h34] = 16'b1110001111110000;
bitarray[0'h35] = 16'b1111010111111100; bitarray[8'h35] = 16'b1111010111111100;
bitarray[0'h36] = 16'b1111111111111111; bitarray[8'h36] = 16'b1111111111111111;
bitarray[0'h37] = 16'b1111111111111; bitarray[8'h37] = 16'b1111111111111;
bitarray[0'h38] = 16'b11111111110; bitarray[8'h38] = 16'b11111111110;
bitarray[0'h39] = 16'b101111111110; bitarray[8'h39] = 16'b101111111110;
bitarray[0'h3a] = 16'b1111111101100; bitarray[8'h3a] = 16'b1111111101100;
bitarray[0'h3b] = 16'b11111111000000; bitarray[8'h3b] = 16'b11111111000000;
bitarray[0'h3c] = 16'b1111111100000; bitarray[8'h3c] = 16'b1111111100000;
bitarray[0'h3d] = 16'b11111110000; bitarray[8'h3d] = 16'b11111110000;
bitarray[0'h3e] = 16'b111100000; bitarray[8'h3e] = 16'b111100000;
bitarray[0'h3f] = 16'b1100000; bitarray[8'h3f] = 16'b1100000;
bitarray[0'h40] = 16'b0; bitarray[8'h40] = 16'b0;
bitarray[0'h41] = 16'b0; bitarray[8'h41] = 16'b0;
bitarray[0'h42] = 16'b0; bitarray[8'h42] = 16'b0;
bitarray[0'h43] = 16'b111111111000; bitarray[8'h43] = 16'b111111111000;
bitarray[0'h44] = 16'b111111111000; bitarray[8'h44] = 16'b111111111000;
bitarray[0'h45] = 16'b111111111000; bitarray[8'h45] = 16'b111111111000;
bitarray[0'h46] = 16'b111111111000; bitarray[8'h46] = 16'b111111111000;
bitarray[0'h47] = 16'b1100001111100000; bitarray[8'h47] = 16'b1100001111100000;
bitarray[0'h48] = 16'b1111111111100000; bitarray[8'h48] = 16'b1111111111100000;
bitarray[0'h49] = 16'b1111111111100000; bitarray[8'h49] = 16'b1111111111100000;
bitarray[0'h4a] = 16'b1100001111100000; bitarray[8'h4a] = 16'b1100001111100000;
bitarray[0'h4b] = 16'b111111111000; bitarray[8'h4b] = 16'b111111111000;
bitarray[0'h4c] = 16'b111111111000; bitarray[8'h4c] = 16'b111111111000;
bitarray[0'h4d] = 16'b111111111000; bitarray[8'h4d] = 16'b111111111000;
bitarray[0'h4e] = 16'b111111111000; bitarray[8'h4e] = 16'b111111111000;
bitarray[0'h4f] = 16'b0; bitarray[8'h4f] = 16'b0;
end end
endmodule endmodule
@ -224,6 +224,7 @@ endfunction
module tank_controller(clk, reset, hpos, vpos, hsync, vsync, module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
sprite_addr, sprite_bits, gfx, sprite_addr, sprite_bits, gfx,
playfield,
switch_left, switch_right, switch_up); switch_left, switch_right, switch_up);
input clk; input clk;
@ -235,10 +236,16 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
output [7:0] sprite_addr; output [7:0] sprite_addr;
input [7:0] sprite_bits; input [7:0] sprite_bits;
output gfx; output gfx;
input playfield;
input switch_left, switch_right, switch_up; input switch_left, switch_right, switch_up;
parameter initial_x = 128;
parameter initial_y = 120;
parameter initial_rot = 0;
wire hmirror, vmirror; wire hmirror, vmirror;
wire busy; wire busy;
wire collision_gfx = gfx && playfield;
reg [11:0] player_x_fixed; reg [11:0] player_x_fixed;
wire [7:0] player_x = player_x_fixed[11:4]; 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]; wire [3:0] player_y_frac = player_y_fixed[3:0];
reg [3:0] player_rot; reg [3:0] player_rot;
reg [3:0] player_speed = 0; reg [3:0] player_speed;
reg [3:0] frame = 0; reg [3:0] frame = 0;
wire vstart = {1'b0,player_y} == vpos; wire vstart = {1'b0,player_y} == vpos;
@ -274,8 +281,10 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
.vmirror(vmirror)); .vmirror(vmirror));
always @(posedge vsync or posedge reset) always @(posedge vsync or posedge reset)
begin
if (reset) begin if (reset) begin
player_rot <= 0; player_rot <= initial_rot;
player_speed <= 0;
end else begin end else begin
frame <= frame + 1; frame <= frame + 1;
// rotation // rotation
@ -291,13 +300,24 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
player_speed <= 0; player_speed <= 0;
end end
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) always @(posedge hsync or posedge reset)
if (reset) begin if (reset) begin
player_x_fixed <= 128<<4; player_x_fixed <= initial_x << 4;
player_y_fixed <= 120<<4; player_y_fixed <= initial_y << 4;
end else begin end else begin
// movement // 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 < 9'(player_speed)) begin
if (vpos[0]) if (vpos[0])
player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot)); player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot));
@ -310,7 +330,7 @@ endmodule
//TODO: debouncing //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 clk;
input reset; input reset;
@ -353,17 +373,18 @@ module test_top(clk, reset, hsync, vsync, rgb, switches_p1);
.sprite_addr(tank_sprite_addr), .sprite_addr(tank_sprite_addr),
.sprite_bits(tank_sprite_bits), .sprite_bits(tank_sprite_bits),
.gfx(tank1_gfx), .gfx(tank1_gfx),
.playfield(playfield_gfx),
.switch_left(switches_p1[0]), .switch_left(switches_p1[0]),
.switch_right(switches_p1[1]), .switch_right(switches_p1[1]),
.switch_up(switches_p1[2]) .switch_up(switches_p1[2])
); );
wire tank1_gfx; wire tank1_gfx;
wire unused; wire playfield_gfx = hpos[5] && vpos[5];
wire r = display_on && tank1_gfx; wire r = display_on && tank1_gfx;
wire g = 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}; assign rgb = {b,g,r};
endmodule endmodule

View File

@ -1,4 +1,5 @@
`include "hvsync_generator.v" `include "hvsync_generator.v"
`include "sprite_rotation.v"
module minefield(hpos, vpos, mine_gfx); module minefield(hpos, vpos, mine_gfx);
@ -72,43 +73,47 @@ module playfield(hpos, vpos, playfield_gfx);
maze[2] = 32'b10000000000100000000001000000001; maze[2] = 32'b10000000000100000000001000000001;
maze[3] = 32'b10000000000100000000000000000001; maze[3] = 32'b10000000000100000000000000000001;
maze[4] = 32'b10011110000000000000000000000001; maze[4] = 32'b10011110000000000000000000000001;
maze[5] = 32'b10000000000000000000000011111001; maze[5] = 32'b10000000000000000000000000000001;
maze[6] = 32'b10000000001000000000000000100001; maze[6] = 32'b10000000001000000000000011110001;
maze[7] = 32'b11100010000000000000000000100001; maze[7] = 32'b11100010000000000000000000100001;
maze[8] = 32'b10000010000000000000000000000001; maze[8] = 32'b10000010000000000000000000100001;
maze[9] = 32'b10000011100000000000000000000001; maze[9] = 32'b10000011100000000000000000000001;
maze[10] = 32'b10000000000000000000000000000001; maze[10] = 32'b10000000000000000000000000000001;
maze[11] = 32'b10000000000000000000000000000001; maze[11] = 32'b10000000000000000000000000000001;
maze[12] = 32'b11111000001000000000000000000001; maze[12] = 32'b11111000001000000000000000000001;
maze[13] = 32'b10001000001000000000000111100001; maze[13] = 32'b10001000001000000000000111100001;
maze[14] = 32'b10001110001000000000000000000001; maze[14] = 32'b10001000001000000000000000000001;
maze[15] = 32'b10000000001000000000000000000001; maze[15] = 32'b10000000001000000000000000000001;
maze[16] = 32'b10000000001000000000000000000001; maze[16] = 32'b10000000001000000000000000000001;
maze[17] = 32'b10001111000000000000000000000001; maze[17] = 32'b10000000000000000000000000000001;
maze[18] = 32'b10000000000000000000000100011001; maze[18] = 32'b10000010000000000000000100011001;
maze[19] = 32'b10000000000000000000000100010001; maze[19] = 32'b10001110000000000000000100010001;
maze[20] = 32'b10000001001000000000000100010001; maze[20] = 32'b10000000001000000000000100010001;
maze[21] = 32'b10000001001110000000000100000001; maze[21] = 32'b10000000001110000000000100000001;
maze[22] = 32'b10000001000000000010001100000001; maze[22] = 32'b10000000000000000010001100000001;
maze[23] = 32'b10001000000000000000000000000001; maze[23] = 32'b10000000000000000000000000000001;
maze[24] = 32'b10001000000111100000000000010001; maze[24] = 32'b10000010000111100000000000010001;
maze[25] = 32'b10001000000000100000000000010001; maze[25] = 32'b10000010000000100000000000010001;
maze[26] = 32'b10001000000000000010000000010001; maze[26] = 32'b10000010000000000010000000010001;
maze[27] = 32'b11111111111111111111111111111111; maze[27] = 32'b11111111111111111111111111111111;
end end
endmodule 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 hsync, vsync;
output [2:0] rgb; output [2:0] rgb;
wire display_on; wire display_on;
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;
wire mine_gfx; wire mine_gfx;
wire playfield_gfx; wire playfield_gfx;
wire tank1_gfx, tank2_gfx;
hvsync_generator hvsync_gen( hvsync_generator hvsync_gen(
.clk(clk), .clk(clk),
@ -132,9 +137,54 @@ module mine_test_top(clk, hsync, vsync, rgb);
.playfield_gfx(playfield_gfx) .playfield_gfx(playfield_gfx)
); );
wire r = display_on && mine_gfx; // multiplex player 1 and 2 load times during hsync
wire g = display_on && playfield_gfx; wire p2sel = hpos[3];
wire b = display_on && 0; // 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}; assign rgb = {b,g,r};
endmodule endmodule

View File

@ -1,12 +1,10 @@
`include "hvsync_generator.v" `include "hvsync_generator.v"
module test_hvsync_top( module test_hvsync_top(clk, reset, hsync, vsync, rgb);
input clk,
output hsync,
output vsync,
output [2:0] rgb
);
input clk, reset;
output hsync, vsync;
output [2:0] rgb;
wire display_on; wire display_on;
wire [8:0] hpos; wire [8:0] hpos;
wire [8:0] vpos; wire [8:0] vpos;

View File

@ -7,13 +7,14 @@ var VERILOG_PRESETS = [
{id:'lfsr.v', name:'Linear Feedback Shift Register'}, {id:'lfsr.v', name:'Linear Feedback Shift Register'},
{id:'digits10.v', name:'Bitmapped Digits'}, {id:'digits10.v', name:'Bitmapped Digits'},
{id:'7segment.v', name:'7-Segment Decoder'}, {id:'7segment.v', name:'7-Segment Decoder'},
{id:'scoreboard.v', name:'Scoreboard'},
{id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'}, {id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'},
{id:'ball_paddle.v', name:'Brick Smash Game'}, {id:'ball_paddle.v', name:'Brick Smash Game'},
{id:'ram1.v', name:'RAM Text Display'},
{id:'sprite_bitmap.v', name:'Sprite Bitmaps'}, {id:'sprite_bitmap.v', name:'Sprite Bitmaps'},
{id:'sprite_renderer.v', name:'Sprite Rendering'}, {id:'sprite_renderer.v', name:'Sprite Rendering'},
{id:'sprite_multiple.v', name:'Multiple Sprites'}, {id:'sprite_multiple.v', name:'Multiple Sprites'},
{id:'sprite_rotation.v', name:'Sprite Rotation'}, {id:'sprite_rotation.v', name:'Sprite Rotation'},
{id:'ram1.v', name:'RAM Text Display'},
{id:'tank.v', name:'Tank Game'}, {id:'tank.v', name:'Tank Game'},
{id:'cpu8.v', name:'Simple 8-Bit CPU'}, {id:'cpu8.v', name:'Simple 8-Bit CPU'},
]; ];

View File

@ -1047,10 +1047,11 @@ function writeDependencies(depends, FS, errors) {
if (depends) { if (depends) {
for (var i=0; i<depends.length; i++) { for (var i=0; i<depends.length; i++) {
var d = depends[i]; var d = depends[i];
if (d.text) if (d.text) {
FS.writeFile(d.filename, d.text, {encoding:'utf8'}); FS.writeFile(d.filename, d.text, {encoding:'utf8'});
} }
} }
}
} }
function compileVerilator(code, platform, options) { function compileVerilator(code, platform, options) {