verilog: 2d array; digits; score; reset w/ no init; more warnings

This commit is contained in:
Steven Hugg 2017-11-18 14:51:25 -05:00
parent e4fd886c94
commit 27a9076cb5
6 changed files with 330 additions and 31 deletions

View File

@ -1,4 +1,36 @@
`include "hvsync_generator.v"
`include "digits10.v"
module player_stats(reset, score, lives, incscore, declives);
input reset;
output [3:0] score[2];
input incscore;
output [3:0] lives;
input declives;
always @(posedge incscore or posedge reset)
begin
if (reset) begin
score[0] <= 0;
score[1] <= 0;
end else if (score[0] == 9) begin
score[0] <= 0;
score[1] <= score[1] + 1;
end else begin
score[0] <= score[0] + 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);
@ -20,6 +52,11 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
reg ball_dir_y;
reg brick_array [BRICKS_H * BRICKS_V];
wire [3:0] score[2];
wire [3:0] lives;
reg incscore;
reg declives;
localparam BRICKS_H = 16;
localparam BRICKS_V = 8;
@ -41,6 +78,32 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
.hpos(hpos),
.vpos(vpos)
);
// scoreboard
player_stats stats(.reset(reset), .score(score), .lives(lives),
.incscore(incscore), .declives(declives));
wire [3:0] score_digit;
wire [4:0] score_bits;
always @(*)
begin
case (hpos[7:5])
1: score_digit = score[1];
2: score_digit = score[0];
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];
// TODO: only works when paddle at bottom of screen!
always @(posedge hsync)
@ -54,27 +117,32 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
// TODO: unsigned compare doesn't work in JS
wire [8:0] paddle_rel_x = ((hpos-paddle_pos) & 9'h1ff);
wire paddle_gfx = (vcell == 28) && (paddle_rel_x < PADDLE_WIDTH);
wire [8:0] ball_rel_x = (hpos-ball_x);
wire [8:0] ball_rel_y = (vpos-ball_y);
wire ball_gfx = ball_rel_x < BALL_SIZE
&& ball_rel_y < BALL_SIZE;
reg main_gfx;
reg brick_present;
reg [6:0] brick_index;
// compute main_gfx and locate bricks
always @(posedge clk)
begin
if (vpos[8:6] == 1 && !lr_border) // 8 rows
// see if we are scanning brick area
if (vpos[8:6] == 1 && !lr_border)
begin
// compute brick index
// every 16th pixel, starting at 8
if (hpos[3:0] == 8) begin
// compute brick index
brick_index <= {vpos[5:3], hpos[7:4]};
main_gfx <= 0; // 2 pixel horiz spacing between bricks
// load brick bit from array
end else if (hpos[3:0] == 9) begin
end
// every 17th pixel
else if (hpos[3:0] == 9) begin
// load brick bit from array
brick_present <= brick_array[brick_index];
end else begin
main_gfx <= brick_present && vpos[2:0] != 0; // 1 pixel vert. spacing
@ -82,6 +150,10 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
end else begin
brick_present <= 0;
case (vpos[8:3])
0: main_gfx <= score_gfx; // scoreboard
1: main_gfx <= score_gfx;
2: main_gfx <= score_gfx;
3: main_gfx <= 0;
4: main_gfx <= 1; // top border
//14: main_gfx <= hpos[4];
//21: main_gfx <= hpos[5];
@ -98,26 +170,40 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
reg [5:0] ball_collide_bits = 0;
/* verilator lint_on MULTIDRIVEN */
// compute ball collisions with paddle and playfield
always @(posedge clk)
if (ball_pixel_collide) begin
if (paddle_gfx) // did we collide w/ paddle?
ball_collide_bits[4] <= 1;
else if (brick_present)
brick_array[brick_index] <= 0;
// ball has 4 collision quadrants
if (!ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[0] <= 1;
if (ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[1] <= 1;
if (!ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[2] <= 1;
if (ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[3] <= 1;
if (paddle_gfx) begin
// did we collide w/ paddle?
ball_collide_bits[4] <= 1; // bit 4 == paddle collide
end else begin
// ball has 4 collision quadrants
if (!ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[0] <= 1;
if (ball_rel_x[2] & !ball_rel_y[2]) ball_collide_bits[1] <= 1;
if (!ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[2] <= 1;
if (ball_rel_x[2] & ball_rel_y[2]) ball_collide_bits[3] <= 1;
end
end
// compute ball collisions with brick
always @(posedge clk)
if (ball_pixel_collide && brick_present) begin
brick_array[brick_index] <= 0;
incscore <= 1; // increment score
end else begin
incscore <= 0; // reset incscore
end
wire signed [8:0] ball_paddle_dx = ball_x - paddle_pos + 8;
// compute ball new position and velocity
always @(posedge vsync or posedge reset)
begin
if (reset) begin
ball_dir_y <= BALL_DIR_DOWN;
end else
if (ball_collide_bits[4]) begin // collided with paddle?
reg signed [8:0] ball_paddle_dx = ball_x - paddle_pos + 8;
// ball collided with paddle?
if (ball_collide_bits[4]) begin
// bounces upward off of paddle
ball_dir_y <= BALL_DIR_UP;
// which side of paddle, left/right?
@ -127,6 +213,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
end else begin
// collided with playfield
// TODO: can still slip through corners
// compute left/right bounce
casez (ball_collide_bits[3:0])
4'b01?1: ball_dir_x <= BALL_DIR_RIGHT; // left edge/corner
4'b1101: ball_dir_x <= BALL_DIR_RIGHT; // left corner
@ -134,6 +221,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
4'b1110: ball_dir_x <= BALL_DIR_LEFT; // right corner
default: ;
endcase
// compute top/bottom bounce
casez (ball_collide_bits[3:0])
4'b1011: ball_dir_y <= BALL_DIR_DOWN;
4'b0111: ball_dir_y <= BALL_DIR_DOWN;
@ -146,7 +234,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
default: ;
endcase
end
ball_collide_bits <= 0;
ball_collide_bits <= 0; // clear all collide bits for frame
end
always @(negedge vsync or posedge reset)
@ -164,10 +252,10 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb);
end
wire grid_gfx = (((hpos&7)==0) || ((vpos&7)==0));
wire r = display_on && (grid_gfx | ball_gfx);
wire r = display_on && (ball_gfx | paddle_gfx);
wire g = display_on && (main_gfx | ball_gfx);
wire b = display_on && (ball_gfx | brick_present);
wire b = display_on && (grid_gfx | ball_gfx | brick_present);
assign rgb = {b,g,r};
endmodule

184
presets/verilog/digits10.v Normal file
View File

@ -0,0 +1,184 @@
`include "hvsync_generator.v"
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)
7'o00: bits = 5'b11111;
7'o01: bits = 5'b10001;
7'o02: bits = 5'b10001;
7'o03: bits = 5'b10001;
7'o04: bits = 5'b11111;
7'o10: bits = 5'b01100;
7'o11: bits = 5'b00100;
7'o12: bits = 5'b00100;
7'o13: bits = 5'b00100;
7'o14: bits = 5'b11111;
7'o20: bits = 5'b11111;
7'o21: bits = 5'b00001;
7'o22: bits = 5'b11111;
7'o23: bits = 5'b10000;
7'o24: bits = 5'b11111;
7'o30: bits = 5'b11111;
7'o31: bits = 5'b00001;
7'o32: bits = 5'b11111;
7'o33: bits = 5'b00001;
7'o34: bits = 5'b11111;
7'o40: bits = 5'b10001;
7'o41: bits = 5'b10001;
7'o42: bits = 5'b11111;
7'o43: bits = 5'b00001;
7'o44: bits = 5'b00001;
7'o50: bits = 5'b11111;
7'o51: bits = 5'b10000;
7'o52: bits = 5'b11111;
7'o53: bits = 5'b00001;
7'o54: bits = 5'b11111;
7'o60: bits = 5'b11111;
7'o61: bits = 5'b10000;
7'o62: bits = 5'b11111;
7'o63: bits = 5'b10001;
7'o64: bits = 5'b11111;
7'o70: bits = 5'b11111;
7'o71: bits = 5'b00001;
7'o72: bits = 5'b00001;
7'o73: bits = 5'b00001;
7'o74: bits = 5'b00001;
7'o100: bits = 5'b11111;
7'o101: bits = 5'b10001;
7'o102: bits = 5'b11111;
7'o103: bits = 5'b10001;
7'o104: bits = 5'b11111;
7'o110: bits = 5'b11111;
7'o111: bits = 5'b10001;
7'o112: bits = 5'b11111;
7'o113: bits = 5'b00001;
7'o114: bits = 5'b11111;
default: bits = 0;
endcase
endmodule
module digits10_array(digit, yofs, bits);
input [3:0] digit;
input [2:0] yofs;
output [4:0] bits;
reg [4:0] bitarray[10][5];
always @(*)
bits = bitarray[digit][yofs];
initial
begin
bitarray[0][0] = 5'b11111;
bitarray[0][1] = 5'b10001;
bitarray[0][2] = 5'b10001;
bitarray[0][3] = 5'b10001;
bitarray[0][4] = 5'b11111;
bitarray[1][0] = 5'b01100;
bitarray[1][1] = 5'b00100;
bitarray[1][2] = 5'b00100;
bitarray[1][3] = 5'b00100;
bitarray[1][4] = 5'b11111;
bitarray[2][0] = 5'b11111;
bitarray[2][1] = 5'b00001;
bitarray[2][2] = 5'b11111;
bitarray[2][3] = 5'b10000;
bitarray[2][4] = 5'b11111;
bitarray[3][0] = 5'b11111;
bitarray[3][1] = 5'b00001;
bitarray[3][2] = 5'b11111;
bitarray[3][3] = 5'b00001;
bitarray[3][4] = 5'b11111;
bitarray[4][0] = 5'b10001;
bitarray[4][1] = 5'b10001;
bitarray[4][2] = 5'b11111;
bitarray[4][3] = 5'b00001;
bitarray[4][4] = 5'b00001;
bitarray[5][0] = 5'b11111;
bitarray[5][1] = 5'b10000;
bitarray[5][2] = 5'b11111;
bitarray[5][3] = 5'b00001;
bitarray[5][4] = 5'b11111;
bitarray[6][0] = 5'b11111;
bitarray[6][1] = 5'b10000;
bitarray[6][2] = 5'b11111;
bitarray[6][3] = 5'b10001;
bitarray[6][4] = 5'b11111;
bitarray[7][0] = 5'b11111;
bitarray[7][1] = 5'b00001;
bitarray[7][2] = 5'b00001;
bitarray[7][3] = 5'b00001;
bitarray[7][4] = 5'b00001;
bitarray[8][0] = 5'b11111;
bitarray[8][1] = 5'b10001;
bitarray[8][2] = 5'b11111;
bitarray[8][3] = 5'b10001;
bitarray[8][4] = 5'b11111;
bitarray[9][0] = 5'b11111;
bitarray[9][1] = 5'b10001;
bitarray[9][2] = 5'b11111;
bitarray[9][3] = 5'b00001;
bitarray[9][4] = 5'b11111;
end
endmodule
module test_numbers_top(clk, hsync, vsync, rgb);
input clk;
output hsync, vsync;
output [2:0] rgb;
wire display_on;
wire [8:0] hpos;
wire [8:0] vpos;
hvsync_generator hvsync_gen(
.clk(clk),
.hsync(hsync),
.vsync(vsync),
.display_on(display_on),
.hpos(hpos),
.vpos(vpos)
);
wire [3:0] digit = hpos[6:3];
wire [2:0] yofs = vpos[2:0];
wire [4:0] bits;
digits10_array numbers(
.digit(digit),
.yofs(yofs),
.bits(bits)
);
wire r = display_on && 0;
wire g = display_on && bits[hpos[2:0] ^ 3'b111];
wire b = display_on && 0;
assign rgb = {b,g,r};
endmodule

View File

@ -1,3 +1,5 @@
`ifndef HVSYNC_GENERATOR_H
`define HVSYNC_GENERATOR_H
module hvsync_generator(
clk, hsync, vsync, display_on, hpos, vpos);
@ -57,3 +59,5 @@ module hvsync_generator(
assign vsync = ~vga_VS;
endmodule
`endif

View File

@ -5,6 +5,7 @@ var VERILOG_PRESETS = [
{id:'hvsync_generator.v', name:'Video Sync Generator'},
{id:'test_hvsync.v', name:'Test Pattern'},
{id:'lfsr.v', name:'Linear Feedback Shift Register'},
{id:'digits10.v', name:'Digits'},
{id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'},
{id:'ball_paddle.v', name:'Brick Smash Game'},
//{id:'pong.v', name:'Pong'},
@ -69,6 +70,8 @@ function VerilatorBase() {
this.reset2 = function() {
if (this.reset !== undefined) {
this.reset = 0;
this.tick2();
this.reset = 1;
for (var i=0; i<RESET_TICKS; i++)
this.tick2();

View File

@ -18,11 +18,22 @@ function parseDecls(text, arr, name, bin, bout) {
arr.push({
wordlen:parseInt(m[1]),
name:m[2],
arrlen:parseInt(m[3]),
arrdim:[parseInt(m[3])],
len:parseInt(m[4]),
ofs:parseInt(m[5]),
});
}
re = new RegExp(name + "(\\d+)[(](\\w+)\\[(\\d+)\\]\\[(\\d+)\\],(\\d+),(\\d+)[)]", 'gm');
var m;
while ((m = re.exec(text))) {
arr.push({
wordlen:parseInt(m[1]),
name:m[2],
arrdim:[parseInt(m[3]), parseInt(m[4])],
len:parseInt(m[5]),
ofs:parseInt(m[6]),
});
}
}
function buildModule(o) {
@ -33,10 +44,17 @@ function buildModule(o) {
m += "\tself." + o.ports[i].name + ";\n";
}
for (var i=0; i<o.signals.length; i++) {
if (o.signals[i].arrlen)
m += "\tvar " + o.signals[i].name + " = self." + o.signals[i].name + " = [];\n";
else
m += "\tself." + o.signals[i].name + ";\n";
var sig = o.signals[i];
if (sig.arrdim) {
if (sig.arrdim.length == 1) {
m += "\tvar " + sig.name + " = self." + sig.name + " = [];\n";
} else if (sig.arrdim.length == 2) {
m += "\tvar " + sig.name + " = self." + sig.name + " = [];\n";
m += "\tfor(var i=0; i<" + sig.arrdim[0] + "; i++) { " + sig.name + "[i] = []; }\n";
}
} else {
m += "\tself." + sig.name + ";\n";
}
}
for (var i=0; i<o.funcs.length; i++) {
m += o.funcs[i];
@ -56,9 +74,9 @@ function translateFunction(text) {
text = text.replace(/[(]IData[)]/g, '');
text = text.replace(/\b(0x[0-9a-f]+)U/gi, '$1');
text = text.replace(/\b([0-9]+)U/gi, '$1');
text = text.replace(/\bQData /, 'var ');
text = text.replace(/\bbool /, '');
text = text.replace(/\bint /, 'var ');
text = text.replace(/\bQData /g, 'var ');
text = text.replace(/\bbool /g, '');
text = text.replace(/\bint /g, 'var ');
text = text.replace(/(\w+ = VL_RAND_RESET_I)/g, 'self.$1');
//text = text.replace(/(\w+\[\w+\] = VL_RAND_RESET_I)/g, 'self.$1');
text = text.replace(/^#/gm, '//#');

View File

@ -1058,7 +1058,9 @@ function compileVerilator(code, platform, options) {
FS.writeFile(topmod+".v", code);
writeDependencies(options.dependencies, FS, errors);
starttime();
verilator_mod.callMain(["--cc", "-O3", "--x-assign", "fast", "--noassert", "--pins-bv", "33",
verilator_mod.callMain(["--cc", "-O3",
"-Wall", "-Wno-DECLFILENAME", "-Wno-UNUSED",
"--x-assign", "fast", "--noassert", "--pins-bv", "33",
"--top-module", topmod, topmod+".v"]);
endtime("compile");
if (errors.length) return {errors:errors};