From f0f6783f6b56ed92add54c883b3eca74f62d73b7 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 3 Feb 2018 14:20:56 -0600 Subject: [PATCH] more verilog presets --- presets/verilog/7segment.v | 80 ++++++++ presets/verilog/ball_slip_counter.v | 24 ++- presets/verilog/cpu8.v | 198 ++++++++++++++++++ presets/verilog/digits10.v | 40 ++-- presets/verilog/gates.v | 16 ++ presets/verilog/hvsync_generator.v | 38 ++-- presets/verilog/ram1.v | 82 ++++++++ presets/verilog/ram2.v | 77 +++++++ presets/verilog/sprite_bitmap.v | 39 ++-- presets/verilog/sprite_rotation.v | 305 ++++++++++++++++++++++++++++ presets/verilog/test_hvsync.v | 12 +- src/platform/verilog.js | 8 +- src/worker/workermain.js | 1 + tools/parsebdf3x5.py | 3 + tools/parsebdf8.py | 12 +- 15 files changed, 856 insertions(+), 79 deletions(-) create mode 100644 presets/verilog/7segment.v create mode 100644 presets/verilog/cpu8.v create mode 100644 presets/verilog/gates.v create mode 100644 presets/verilog/ram1.v create mode 100644 presets/verilog/ram2.v create mode 100644 presets/verilog/sprite_rotation.v diff --git a/presets/verilog/7segment.v b/presets/verilog/7segment.v new file mode 100644 index 00000000..e3aa9d43 --- /dev/null +++ b/presets/verilog/7segment.v @@ -0,0 +1,80 @@ +`include "hvsync_generator.v" + +module seven_segment_decoder(digit, segments); + input [3:0] digit; + output [6:0] segments; + + always @(*) + case(digit) + 0: segments = 7'b1111110; + 1: segments = 7'b0110000; + 2: segments = 7'b1101101; + 3: segments = 7'b1111001; + 4: segments = 7'b0110011; + 5: segments = 7'b1011011; + 6: segments = 7'b1011111; + 7: segments = 7'b1110000; + 8: segments = 7'b1111111; + 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); + default:bits = 0; + endcase +endmodule + +module test_numbers_top( + input clk, reset, + output hsync, vsync, + output [2:0] rgb +); + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + 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; + wire [6:0] segments; + + seven_segment_decoder decoder( + .digit(digit), + .segments(segments) + ); + + segments_to_bitmap numbers( + .segments(segments), + .line(yofs), + .bits(bits) + ); + + wire r = display_on && 0; + wire g = display_on && bits[~xofs]; + wire b = display_on && 0; + assign rgb = {b,g,r}; + +endmodule diff --git a/presets/verilog/ball_slip_counter.v b/presets/verilog/ball_slip_counter.v index 06402cec..6a35c760 100644 --- a/presets/verilog/ball_slip_counter.v +++ b/presets/verilog/ball_slip_counter.v @@ -13,11 +13,12 @@ module ball_paddle_top(clk, reset, hsync, vsync, rgb); reg [8:0] ball_htimer; reg [8:0] ball_vtimer; - reg [8:0] ball_horiz_stop = 204; reg [8:0] ball_horiz_move = -2; - reg [8:0] ball_vert_stop = 251; reg [8:0] ball_vert_move = 2; + localparam ball_horiz_stop = 204; + localparam ball_vert_stop = 251; + hvsync_generator hvsync_gen( .clk(clk), .reset(reset), @@ -40,7 +41,7 @@ module ball_paddle_top(clk, reset, hsync, vsync, rgb); ball_htimer <= ball_horiz_stop; end else ball_htimer <= ball_htimer + 1; - end; + end // update vertical timer always @(posedge hsync or posedge reset) @@ -51,30 +52,33 @@ module ball_paddle_top(clk, reset, hsync, vsync, rgb); ball_vtimer <= ball_vert_stop + ball_vert_move; else ball_vtimer <= ball_vtimer + 1; - end; + end + + // collide with vertical and horizontal boundaries + wire ball_vert_collide = ball_vgfx && vpos >= 240; + wire ball_horiz_collide = ball_hgfx && hpos >= 256 && vpos == 255; // vertical bounce always @(posedge ball_vert_collide) begin ball_vert_move <= -ball_vert_move; - end; + end // horizontal bounce always @(posedge ball_horiz_collide) begin ball_horiz_move <= -ball_horiz_move; - end; + end + // compute ball display wire ball_hgfx = ball_htimer >= 508; wire ball_vgfx = ball_vtimer >= 508; wire ball_gfx = ball_hgfx && ball_vgfx; - // collide with vertical and horizontal boundaries - wire ball_vert_collide = ball_vgfx && vpos >= 240; - wire ball_horiz_collide = ball_hgfx && hpos >= 256 && vpos == 255; - + // compute grid display wire grid_gfx = (((hpos&7)==0) && ((vpos&7)==0)); + // combine into RGB signals wire r = display_on && (ball_hgfx | ball_gfx); wire g = display_on && (grid_gfx | ball_gfx); wire b = display_on && (ball_vgfx | ball_gfx); diff --git a/presets/verilog/cpu8.v b/presets/verilog/cpu8.v new file mode 100644 index 00000000..4d786dd0 --- /dev/null +++ b/presets/verilog/cpu8.v @@ -0,0 +1,198 @@ + +`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 + 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 + 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/digits10.v b/presets/verilog/digits10.v index 9820afcf..b560914f 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -1,11 +1,10 @@ `include "hvsync_generator.v" -module digits10_case(digit, yofs, bits); - - input [3:0] digit; - input [2:0] yofs; - output [4:0] bits; - +module digits10_case( + 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}*/ @@ -73,13 +72,12 @@ module digits10_case(digit, yofs, bits); 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]; +module digits10_array( + input [3:0] digit, + input [2:0] yofs, + output [4:0] bits +); + reg [4:0] bitarray[16][5]; assign bits = bitarray[digit][yofs]; @@ -143,21 +141,25 @@ module digits10_array(digit, yofs, bits); bitarray[9][2] = 5'b11111; bitarray[9][3] = 5'b00001; bitarray[9][4] = 5'b11111; + + for (int i = 10; i <= 15; i++) + for (int j = 0; j <= 4; j++) + bitarray[i][j] = 0; end endmodule -module test_numbers_top(clk, hsync, vsync, rgb); - - input clk; - output hsync, vsync; - output [2:0] rgb; +module test_numbers_top( + input clk, reset, + output hsync, vsync, + output [2:0] rgb +); wire display_on; wire [8:0] hpos; wire [8:0] vpos; hvsync_generator hvsync_gen( .clk(clk), - .reset(0), + .reset(reset), .hsync(hsync), .vsync(vsync), .display_on(display_on), diff --git a/presets/verilog/gates.v b/presets/verilog/gates.v new file mode 100644 index 00000000..5ce740cb --- /dev/null +++ b/presets/verilog/gates.v @@ -0,0 +1,16 @@ +module gates(clk, out_not, out_and, out_or, out_xor, in); + + input clk; + output out_not, out_and, out_or, out_xor; + output reg [3:0] in; + + not U1(out_not,in[0]); + and U2(out_and,in[0],in[1],in[2],in[3]); + or U3(out_or,in[0],in[1],in[2],in[3]); + xor U4(out_xor,in[0],in[1],in[2]); + + always @(posedge clk) begin + in <= in + 1; + end + +endmodule; diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v index 358a41ea..5cc07ec1 100644 --- a/presets/verilog/hvsync_generator.v +++ b/presets/verilog/hvsync_generator.v @@ -1,6 +1,23 @@ `ifndef HVSYNC_GENERATOR_H `define HVSYNC_GENERATOR_H +// constant declarations for TV-simulator sync parameters +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) +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; + +localparam V_DISPLAY = 240; // vertical display height +localparam V_TOP = 5; // vertical top border +localparam V_BOTTOM = 14; // vertical bottom border +localparam V_SYNC = 3; // vertical sync # lines +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, @@ -10,23 +27,6 @@ module hvsync_generator( output [8:0] vpos ); - // constant declarations for TV-simulator sync parameters - 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) - 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; - - localparam V_DISPLAY = 240; // vertical display height - localparam V_TOP = 5; // vertical top border - localparam V_BOTTOM = 14; // vertical bottom border - localparam V_SYNC = 3; // vertical sync # lines - 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; - wire hmaxxed = (hpos == H_MAX) || reset; wire vmaxxed = (vpos == V_MAX) || reset; @@ -37,7 +37,7 @@ module hvsync_generator( hpos <= 0; else hpos <= hpos + 1; - end; + end // increment vertical position counter always @(posedge clk) @@ -47,7 +47,7 @@ module hvsync_generator( vpos <= vpos + 1; else vpos <= 0; - end; + end // compute hsync + vsync + display_on signals always @(posedge clk) diff --git a/presets/verilog/ram1.v b/presets/verilog/ram1.v new file mode 100644 index 00000000..4ad7fa65 --- /dev/null +++ b/presets/verilog/ram1.v @@ -0,0 +1,82 @@ +`include "hvsync_generator.v" +`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 + output [7:0] dout; // 8-bit data output + input we; // write enable + + reg [7:0] mem [1024]; // 1024x8 bit memory + + always @(posedge clk) begin + if (we) // if write enabled + 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 +); + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + wire [9:0] ram_addr; + wire [7:0] ram_read; + reg [7:0] ram_write; + reg ram_writeenable = 0; + + RAM_1KB ram( + .clk(clk), + .dout(ram_read), + .din(ram_write), + .addr(ram_addr), + .we(ram_writeenable) + ); + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + wire [4:0] row = vpos[7:3]; + wire [4:0] col = hpos[7:3]; + wire [3:0] digit = ram_read[3:0]; + wire [2:0] yofs = vpos[2:0]; + wire [2:0] xofs = hpos[2:0]; + wire [4:0] bits; + + assign ram_addr = {row,col}; + + digits10_case numbers( + .digit(digit), + .yofs(yofs), + .bits(bits) + ); + + wire r = display_on && 0; + wire g = display_on && bits[~xofs]; + wire b = display_on && 0; + assign rgb = {b,g,r}; + + always @(posedge clk) + if (display_on && vpos[2:0] == 7) + case (hpos[2:0]) + 6: begin + ram_write <= (ram_read + 1); + ram_writeenable <= 1; + end + 7: ram_writeenable <= 0; + endcase + +endmodule diff --git a/presets/verilog/ram2.v b/presets/verilog/ram2.v new file mode 100644 index 00000000..48927fe9 --- /dev/null +++ b/presets/verilog/ram2.v @@ -0,0 +1,77 @@ +`include "hvsync_generator.v" +`include "digits10.v" + +module RAM_1KB_tri(clk, addr, data, we); + input clk; + input [9:0] addr; + inout [7:0] data; + input we; + + reg [7:0] mem [1023:0]; + assign data = !we ? mem[addr] : 8'bz; + always @(posedge clk) begin + if (we) + mem[addr] <= data; + end +endmodule + +module test_framebuf_top( + input clk, reset, + output hsync, vsync, + output [2:0] rgb +); + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + reg ram_writeenable = 0; + wire [9:0] ram_addr = {row,col}; + wire [7:0] ram_data = ram_writeenable ? ram_write : 8'bz; + wire [7:0] ram_read = ram_writeenable ? 8'bz : ram_data; + reg [7:0] ram_write; + + RAM_1KB_tri ram( + .clk(clk), + .data(ram_data), + .addr(ram_addr), + .we(ram_writeenable) + ); + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + wire [4:0] row = vpos[7:3]; + wire [4:0] col = hpos[7:3]; + wire [3:0] digit = ram_read[3:0]; + 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}; + + always @(posedge clk) + if (display_on && vpos[2:0] == 7) + case (hpos[2:0]) + 6: begin + ram_write <= ram_read + 1; + ram_writeenable <= 1; + end + 7: ram_writeenable <= 0; + endcase + +endmodule diff --git a/presets/verilog/sprite_bitmap.v b/presets/verilog/sprite_bitmap.v index bda742a6..eadafd5a 100644 --- a/presets/verilog/sprite_bitmap.v +++ b/presets/verilog/sprite_bitmap.v @@ -1,14 +1,11 @@ `include "hvsync_generator.v" -module car_bitmap(yofs, bits); - - input [3:0] yofs; - output [7:0] bits; - +module car_bitmap( + input [3:0] yofs, + output [7:0] bits +); reg [7:0] bitarray[16]; - assign bits = bitarray[yofs]; - initial begin/*{w:8,h:16}*/ bitarray[0] = 8'b0; bitarray[1] = 8'b101110; @@ -29,10 +26,9 @@ module car_bitmap(yofs, bits); end endmodule -module sprite_bitmap_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); +module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); - input clk; - input hpaddle, vpaddle; + input clk, reset; output hsync, vsync; output [2:0] rgb; wire display_on; @@ -44,12 +40,12 @@ module sprite_bitmap_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); reg [3:0] car_sprite_yofs; wire [7:0] car_sprite_bits; - reg [7:0] player_x = 128; - reg [7:0] player_y = 128; + reg [8:0] player_x = 128; + reg [8:0] player_y = 128; hvsync_generator hvsync_gen( .clk(clk), - .reset(0), + .reset(reset), .hsync(hsync), .vsync(vsync), .display_on(display_on), @@ -63,23 +59,22 @@ module sprite_bitmap_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); always @(posedge hsync) // start sprite? - if (vpos == {1'0,player_y}) + if (vpos == player_y) car_sprite_yofs <= 15; else if (car_sprite_yofs != 0) car_sprite_yofs <= car_sprite_yofs - 1; always @(posedge clk) - if (display_on) begin - if (hpos == {1'0,player_x}) - car_sprite_xofs <= 15; - else if (car_sprite_xofs != 0) - car_sprite_xofs <= car_sprite_xofs - 1; - end + if (hpos == player_x) + car_sprite_xofs <= 15; + else if (car_sprite_xofs != 0) + car_sprite_xofs <= car_sprite_xofs - 1; // mirror sprite in X direction - wire car_gfx = car_sprite_bits[car_sprite_xofs>=8 ? + wire [3:0] car_bit = car_sprite_xofs>=8 ? 15-car_sprite_xofs: - car_sprite_xofs]; + car_sprite_xofs; + wire car_gfx = car_sprite_bits[3'(car_bit)]; wire r = display_on && car_gfx; wire g = display_on && car_gfx; diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v new file mode 100644 index 00000000..ecee0861 --- /dev/null +++ b/presets/verilog/sprite_rotation.v @@ -0,0 +1,305 @@ +`include "hvsync_generator.v" + +module tank_bitmap(addr, bits); + + input [7:0] addr; + output [7:0] bits; + + reg [15:0] bitarray[256]; + + 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[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[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[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[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; + end +endmodule + +module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, + hmirror, vmirror, + gfx, busy); + + input clk, vstart, load, hstart; + input hmirror, vmirror; + output [4:0] rom_addr; + input [7:0] rom_bits; + output gfx; + output busy = state != WAIT_FOR_VSTART; + + reg [2:0] state; + reg [3:0] ycount; + reg [3:0] xcount; + + reg [15:0] outbits; + + localparam WAIT_FOR_VSTART = 0; + localparam WAIT_FOR_LOAD = 1; + localparam LOAD1_SETUP = 2; + localparam LOAD1_FETCH = 3; + localparam LOAD2_SETUP = 4; + localparam LOAD2_FETCH = 5; + localparam WAIT_FOR_HSTART = 6; + localparam DRAW = 7; + + always @(posedge clk) + begin + case (state) + WAIT_FOR_VSTART: begin + ycount <= 0; + // set a default value (blank) for pixel output + // note: multiple non-blocking assignments are vendor-specific + gfx <= 0; + if (vstart) state <= WAIT_FOR_LOAD; + end + WAIT_FOR_LOAD: begin + xcount <= 0; + gfx <= 0; + if (load) state <= LOAD1_SETUP; + end + LOAD1_SETUP: begin + rom_addr <= {vmirror?~ycount:ycount, 1'b0}; + state <= LOAD1_FETCH; + end + LOAD1_FETCH: begin + outbits[7:0] <= rom_bits; + state <= LOAD2_SETUP; + end + LOAD2_SETUP: begin + rom_addr <= {vmirror?~ycount:ycount, 1'b1}; + state <= LOAD2_FETCH; + end + LOAD2_FETCH: begin + outbits[15:8] <= rom_bits; + state <= WAIT_FOR_HSTART; + end + WAIT_FOR_HSTART: begin + if (hstart) state <= DRAW; + end + DRAW: begin + // mirror graphics left/right + gfx <= outbits[hmirror ? ~xcount[3:0] : xcount[3:0]]; + xcount <= xcount + 1; + if (xcount == 15) begin // pre-increment value + ycount <= ycount + 1; + if (ycount == 15) // pre-increment value + state <= WAIT_FOR_VSTART; // done drawing sprite + else + state <= WAIT_FOR_LOAD; // done drawing this scanline + end + end + endcase + end + +endmodule + +module rotation_selector(rotation, bitmap_num, hmirror, vmirror); + input [4:0] rotation; + output [2:0] bitmap_num; + output hmirror, vmirror; + + always @(*) + case (rotation[3:2]) + 0: begin + bitmap_num = {1'b0, rotation[1:0]}; + hmirror = 0; + vmirror = 0; + end + 1: begin + bitmap_num = -rotation[2:0]; + hmirror = 0; + vmirror = 1; + end + 2: begin + bitmap_num = {1'b0, rotation[1:0]}; + hmirror = 1; + vmirror = 1; + end + 3: begin + bitmap_num = -rotation[2:0]; + hmirror = 1; + vmirror = 0; + end + endcase + +endmodule + +module tank_controller(clk, reset, hpos, vpos, hsync, vsync, + sprite_addr, sprite_bits, gfx); + + input clk; + input reset; + input hsync; + input vsync; + input [8:0] hpos; + input [8:0] vpos; + output [7:0] sprite_addr; + input [7:0] sprite_bits; + reg hmirror; + reg vmirror; + output gfx; + wire busy; + + reg [7:0] player_x = 64; + reg [7:0] player_y = 64; + reg [4:0] player_rot = 0; + + wire vstart = {1'b0,player_y} == vpos; + wire hstart = {1'b0,player_x} == hpos; + + sprite_renderer renderer( + .clk(clk), + .vstart(vstart), + .load(hsync), + .hstart(hstart), + .hmirror(hmirror), + .vmirror(vmirror), + .rom_addr(sprite_addr[4:0]), + .rom_bits(sprite_bits), + .gfx(gfx), + .busy(busy)); + + rotation_selector rotsel( + .rotation(player_rot), + .bitmap_num(sprite_addr[7:5]), + .hmirror(hmirror), + .vmirror(vmirror)); + + always @(posedge vsync) + player_rot <= player_rot + 1; + +endmodule + +module test_top(clk, reset, hsync, vsync, rgb); + + input clk; + input reset; + output hsync; + output vsync; + output [2:0] rgb; + wire display_on; + wire [8:0] hpos; + wire [8:0] vpos; + + reg [7:0] paddle_x; + reg [7:0] paddle_y; + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(reset), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + wire [7:0] tank_sprite_addr; + wire [7:0] tank_sprite_bits; + + tank_bitmap tank_bmp( + .addr(tank_sprite_addr), + .bits(tank_sprite_bits)); + + tank_controller tank1( + .clk(clk), + .reset(reset), + .hpos(hpos), + .vpos(vpos), + .hsync(hsync), + .vsync(vsync), + .sprite_addr(tank_sprite_addr), + .sprite_bits(tank_sprite_bits), + .gfx(tank1_gfx) + ); + + wire tank1_gfx; + wire unused; + + wire r = display_on && tank1_gfx; + wire g = display_on && tank1_gfx; + wire b = display_on && tank1_gfx; + assign rgb = {b,g,r}; + +endmodule diff --git a/presets/verilog/test_hvsync.v b/presets/verilog/test_hvsync.v index 55c6b8b9..10b132c8 100644 --- a/presets/verilog/test_hvsync.v +++ b/presets/verilog/test_hvsync.v @@ -1,10 +1,12 @@ `include "hvsync_generator.v" -module test_hvsync_top(clk, hsync, vsync, rgb); - - input clk; - output hsync, vsync; - output [2:0] rgb; +module test_hvsync_top( + input clk, + output hsync, + output 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 daa9478c..59600605 100644 --- a/src/platform/verilog.js +++ b/src/platform/verilog.js @@ -5,12 +5,16 @@ 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:'digits10.v', name:'Bitmapped Digits'}, + {id:'7segment.v', name:'7-Segment Decoder'}, {id:'ball_slip_counter.v', name:'Ball Motion (slipping counter)'}, {id:'ball_paddle.v', name:'Brick Smash Game'}, {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'}, ]; @@ -568,7 +572,7 @@ var VerilogPlatform = function(mainElement, options) { this.runToVsync = function() { var self = this; this.setDebugCondition(function() { - if (gen.vsync && gen.ticks() > debugTargetClock+1000) { + if (gen.vsync && gen.ticks() > debugTargetClock+2000) { self.breakpointHit(gen.ticks()); return true; } diff --git a/src/worker/workermain.js b/src/worker/workermain.js index 23a50120..e1ab64a1 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -1114,6 +1114,7 @@ function compileYosys(code, platform, options) { return {errors:errors}; } endtime("compile"); + //TODO: filename in errors if (errors.length) return {errors:errors}; try { var json_file = FS.readFile(topmod+".json", {encoding:'utf8'}); diff --git a/tools/parsebdf3x5.py b/tools/parsebdf3x5.py index 1f33ad51..16d1c7a5 100755 --- a/tools/parsebdf3x5.py +++ b/tools/parsebdf3x5.py @@ -60,10 +60,13 @@ def tohex(v): return '%02x'%v def tohex2(v): return '0x%02x'%v +def tobin(v): + return "bitarray[0][0]=3'b{0:3b};\n".format(v) print '\thex ' + string.join(map(tohex,output),'') print string.join(map(tohex2,output),',') print '\thex ' + string.join(map(tohex,outputlo),'') print '\thex ' + string.join(map(tohex,outputhi),'') +print string.join(map(tobin,output),'') print len(output),len(outputlo),len(outputhi) diff --git a/tools/parsebdf8.py b/tools/parsebdf8.py index 2d886b13..33facc66 100755 --- a/tools/parsebdf8.py +++ b/tools/parsebdf8.py @@ -17,6 +17,7 @@ outfmtgroup.add_argument("-A", "--asmhex", action="store_true", help="DASM-compa outfmtgroup.add_argument("-B", "--asmdb", action="store_true", help="Z80ASM-compatible hex") outfmtgroup.add_argument("-C", "--carray", action="store_true", help="Nested C array") outfmtgroup.add_argument("-F", "--flatcarray", action="store_true", help="Flat C array") +outfmtgroup.add_argument("-V", "--verilog", action="store_true", help="Verilog-compatible hex") parser.add_argument('bdffile', help="BDF bitmap file") args = parser.parse_args() @@ -98,5 +99,12 @@ for arr in [output]: print "static char FONT[%d] = {" % ((hichar-lochar+1) * height) print string.join(map(tohex2,arr),',') print "}"; - - + if args.verilog: + j = 0 + for i in range(0,len(output),height): + #print "rom["+str(j)+"] = 32'h" + string.join(map(tohex,arr[i:i+height/2]),'') + ";" + #j += 1 + #print "rom["+str(j)+"] = 32'h" + string.join(map(tohex,arr[i+height/2:i+height]),'') + ";" + #j += 1 + print "rom["+str(j)+"] = 64'h" + string.join(map(tohex,arr[i:i+height]),'') + ";" + j += 1