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

more Verilog code; inline asm for depends; fixed tank

This commit is contained in:
Steven Hugg 2018-02-21 13:32:11 -06:00
parent 7e04a15670
commit b2beb2670c
16 changed files with 697 additions and 99 deletions

View File

@ -1,5 +1,17 @@
`include "hvsync_generator.v"
/*
Segment bit indices:
6666
1 5
1 5
0000
2 4
2 4
3333
*/
module seven_segment_decoder(digit, segments);
input [3:0] digit;

View File

@ -1,6 +1,7 @@
`ifndef CPU16_H
`define CPU16_H
// include ALU module
`include "cpu8.v"
/*
@ -17,34 +18,35 @@
11+++aaa ######## immediate binary operation
*/
module CPU16(clk, reset, halt, busy,
module CPU16(clk, reset, hold, busy,
address, data_in, data_out, write);
input clk;
input reset;
input halt;
input hold;
output busy;
output [15:0] address;
input [15:0] data_in;
output [15:0] data_out;
output write;
reg [15:0] regs[0:7];
reg [2:0] state;
reg [15:0] regs[0:7]; // 8 16-bit registers
reg [2:0] state; // CPU state
reg carry;
reg zero;
reg neg;
wire [2:0] flags = { neg, zero, carry };
reg carry; // carry flag
reg zero; // zero flag
reg neg; // negative flag
reg [15:0] opcode;
wire [16:0] Y;
reg [3:0] aluop;
wire [2:0] rdest = opcode[10:8];
wire [2:0] rsrc = opcode[2:0];
wire Bconst = opcode[15]; // TODO
wire Bload = opcode[11]; // TODO
wire [16:0] Y; // ALU 16-bit + carry output
reg [3:0] aluop; // ALU operation
reg [15:0] opcode; // used to decode ALU inputs
wire [2:0] rdest = opcode[10:8]; // ALU A input reg.
wire [2:0] rsrc = opcode[2:0]; // ALU B input reg.
wire Bconst = opcode[15]; // ALU B = 8-bit constant
wire Bload = opcode[11]; // ALU B = data bus
// CPU states
localparam S_RESET = 0;
localparam S_SELECT = 1;
localparam S_DECODE = 2;
@ -77,7 +79,7 @@ module CPU16(clk, reset, halt, busy,
// state 1: select opcode address
S_SELECT: begin
write <= 0;
if (halt) begin
if (hold) begin
busy <= 1;
state <= S_SELECT;
end else begin
@ -89,7 +91,6 @@ module CPU16(clk, reset, halt, busy,
end
// state 2: read/decode opcode
S_DECODE: begin
opcode <= data_in; // (only use opcode next cycle)
casez (data_in)
// 00000aaa0++++bbb operation A+B->A
16'b00000???0???????: begin
@ -180,6 +181,7 @@ module CPU16(clk, reset, halt, busy,
state <= S_RESET; // reset
end
endcase
opcode <= data_in; // (only use opcode next cycle)
end
// state 3: compute ALU op and flags
S_COMPUTE: begin
@ -198,6 +200,8 @@ module CPU16(clk, reset, halt, busy,
endmodule
`ifdef TOPMOD__test_CPU16_top
module test_CPU16_top(
input clk,
input reset,
@ -221,7 +225,7 @@ module test_CPU16_top(
CPU16 cpu(
.clk(clk),
.reset(reset),
.halt(0),
.hold(0),
.busy(busy),
.address(address_bus),
.data_in(to_cpu),
@ -271,3 +275,5 @@ Loop:
endmodule
`endif
`endif

View File

@ -233,6 +233,8 @@ module CPU(clk, reset, address, data_in, data_out, write);
endmodule
`ifdef TOPMOD__test_CPU_top
module test_CPU_top(
input clk,
input reset,
@ -275,29 +277,31 @@ module test_CPU_top(
to_cpu = rom[address_bus[6:0]];
initial begin
`ifdef EXT_INLINE_ASM
// example code: Fibonacci sequence
rom = '{
`I_CLEAR_CARRY,
`I_ZERO_A,
`I_CONST_IMM_B,
1,
`I_COMPUTE(`DEST_A, `OP_ADC), // addr 4
`I_SWAP_AB,
`I_BRANCH_IF_CARRY(1'b0),
4 + 'h80, // correct for ROM offset
`I_STORE_A(4'd0),
`I_RESET,
// leftover elements
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
0,0,0,0, 0,0
__asm
.arch femto8
.org 128
.len 128
Start:
zero A ; A <= 0
ldb #1 ; B <= 1
Loop:
add A,B ; A <= A + B
swapab ; swap A,B
bcc Loop ; repeat until carry set
reset ; end of loop; reset CPU
__endasm
};
`endif
end
endmodule
`endif
`endif

View File

@ -0,0 +1,29 @@
{
"name":"femto8",
"vars":{
"reg":{"bits":2, "toks":["a", "b", "ip", "none"]},
"unop":{"bits":3, "toks":["zero","loada","inc","dec","asl","lsr","rol","ror"]},
"binop":{"bits":3, "toks":["or","and","xor","mov","add","sub","adc","sbb"]},
"const4":{"bits":4},
"imm8":{"bits":8}
},
"rules":[
{"fmt":"~binop ~reg,b", "bits":["00",1,"1",0]},
{"fmt":"~binop ~reg,#~imm8", "bits":["01",1,"1",0,2]},
{"fmt":"~binop ~reg,[b]", "bits":["11",1,"1",0]},
{"fmt":"~unop ~reg", "bits":["00",1,"0",0]},
{"fmt":"mov ~reg,[b]", "bits":["11",0,"1011"]},
{"fmt":"zero ~reg", "bits":["00",0,"1011"]},
{"fmt":"lda #~imm8", "bits":["01","00","1011",0]},
{"fmt":"ldb #~imm8", "bits":["01","01","1011",0]},
{"fmt":"jmp ~imm8", "bits":["01","10","1011",0]},
{"fmt":"sta ~const4", "bits":["1001",0]},
{"fmt":"bcc ~imm8", "bits":["1010","0001",0]},
{"fmt":"bcs ~imm8", "bits":["1010","0011",0]},
{"fmt":"bz ~imm8", "bits":["1010","1100",0]},
{"fmt":"bnz ~imm8", "bits":["1010","0100",0]},
{"fmt":"clc", "bits":["10001000"]},
{"fmt":"swapab", "bits":["10000001"]},
{"fmt":"reset", "bits":["10001111"]}
]
}

View File

@ -1,8 +1,6 @@
`undef EXT_INLINE_ASM
`include "hvsync_generator.v"
`include "cpu8.v"
`include "cpu16.v"
`define EXT_INLINE_ASM
// uncomment to see scope view
//`define DEBUG

View File

@ -1,15 +1,18 @@
`include "hvsync_generator.v"
`include "digits10.v"
module RAM_1KB(clk, addr, din, dout, we);
module RAM(clk, addr, din, dout, we);
parameter A = 10; // # of address bits
parameter D = 8; // # of data bits
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 [A-1:0] addr; // 10-bit address
input [D-1:0] din; // 8-bit data input
output [D-1:0] dout; // 8-bit data output
input we; // write enable
reg [7:0] mem [0:1023]; // 1024x8 bit memory
reg [D-1:0] mem [0:(1<<A)-1]; // 1024x8 bit memory
always @(posedge clk) begin
if (we) // if write enabled
@ -34,7 +37,8 @@ module test_ram1_top(clk, reset, hsync, vsync, rgb);
reg [7:0] ram_write;
reg ram_writeenable = 0;
RAM_1KB ram(
// RAM to hold 32x32 array of bytes
RAM ram(
.clk(clk),
.dout(ram_read),
.din(ram_write),
@ -51,35 +55,45 @@ module test_ram1_top(clk, reset, hsync, vsync, rgb);
.hpos(hpos),
.vpos(vpos)
);
wire [4:0] row = vpos[7:3]; // 5-bit row, vpos / 8
wire [4:0] col = hpos[7:3]; // 5-bit column, hpos / 8
wire [2:0] rom_yofs = vpos[2:0]; // scanline of cell
wire [4:0] rom_bits; // 5 pixels per scanline
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};
wire [3:0] digit = ram_read[3:0]; // read digit from RAM
wire [2:0] xofs = hpos[2:0]; // which pixel to draw (0-7)
assign ram_addr = {row,col}; // 10-bit RAM address
// digits ROM
digits10_case numbers(
.digit(digit),
.yofs(yofs),
.bits(bits)
.yofs(rom_yofs),
.bits(rom_bits)
);
// extract bit from ROM output
wire r = display_on && 0;
wire g = display_on && bits[~xofs];
wire g = display_on && rom_bits[~xofs];
wire b = display_on && 0;
assign rgb = {b,g,r};
// increment the current RAM cell
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
case (hpos[2:0])
// on 7th pixel of cell
6: begin
// increment RAM cell
ram_write <= (ram_read + 1);
// only enable write on last scanline of cell
ram_writeenable <= (vpos[2:0] == 7);
end
// on 8th pixel of cell
7: begin
// disable write
ram_writeenable <= 0;
end
endcase
endmodule

View File

@ -0,0 +1,175 @@
`include "hvsync_generator.v"
`include "cpu8.v"
`include "cpu16.v"
// uncomment to see scope view
//`define DEBUG
module shared_framebuffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle,
address_bus, to_cpu, from_cpu, write_enable
`ifdef DEBUG
, output [15:0] IP
, output carry
, output zero
`else
, rgb
`endif
);
input clk, reset;
input hpaddle, vpaddle;
output hsync, vsync;
wire display_on;
wire [8:0] hpos;
wire [8:0] vpos;
`ifdef DEBUG
assign IP = cpu.regs[cpu.IP];
assign carry = cpu.carry;
assign zero = cpu.zero;
`else
output [3:0] rgb;
`endif
parameter IN_HPOS = 8'b01000000;
parameter IN_VPOS = 8'b01000001;
parameter IN_FLAGS = 8'b01000010;
reg [15:0] ram[0:32767];
reg [15:0] rom[0:1023];
output wire [15:0] address_bus;
output reg [15:0] to_cpu;
output wire [15:0] from_cpu;
output wire write_enable;
CPU16 cpu(.clk(clk),
.reset(reset),
.hold(hold),
.busy(busy),
.address(address_bus),
.data_in(to_cpu),
.data_out(from_cpu),
.write(write_enable));
always @(posedge clk)
if (write_enable) begin
ram[address_bus[14:0]] <= from_cpu;
end
always @(*)
if (address_bus[15])
to_cpu = rom[address_bus[9:0]];
else if (&address_bus[14:8]) begin
casez (address_bus[7:0])
// special read registers
IN_HPOS: to_cpu = {8'b0, hpos[7:0]};
IN_VPOS: to_cpu = {8'b0, vpos[7:0]};
IN_FLAGS: to_cpu = {11'b0,
vsync, hsync, vpaddle, hpaddle, display_on};
default: to_cpu = 0;
endcase
end else
to_cpu = ram[address_bus[14:0]];
hvsync_generator hvsync_gen(
.clk(clk),
.reset(0),
.hsync(hsync),
.vsync(vsync),
.display_on(display_on),
.hpos(hpos),
.vpos(vpos)
);
// video DMA access
reg hold;
wire busy;
reg [15:0] vline[0:31]; // 32x16 bits = 256 4-color pixels
reg [4:0] vindex;
reg [15:0] vshift;
//wire [15:0] scanread = scanline[hpos[7:3]];
//wire [2:0] scanpixel = hpos[2:0];
always @(posedge clk) begin
// has CPU released the bus?
if (busy) begin
// write from main RAM -> scanline RAM
vline[vindex] <= ram[{2'b10,vpos[7:0],vindex}];
// end of scanline read?
if (&vindex)
hold <= 0; // release CPU
vindex <= vindex + 1; // next address
end else if (hpos >= 256 && hpos < 256+4 && vpos < 240) begin
hold <= 1; // start DMA mode, hold CPU
end else if (!hpos[8]) begin
// load next word from vline buffer
if (!&hpos[2:0]) begin
vshift <= vline[vindex];
vindex <= vindex + 1;
end else
vshift <= {2'b0, vshift[15:2]};
// decode scanline RAM to RGB output
rgb <= vshift[3:0];
end else
rgb <= 0;
end
/*
reg [14:0] vpu_read;
reg [15:0] vpu_buffer;
reg [3:0] rgb;
always @(posedge clk) begin
if (!hpos[8] && !vpos[8]) begin
if (hpos[1:0] == 0) begin
vpu_buffer <= ram[vpu_read];
vpu_read <= vpu_read + 1;
end
//rgb <= ram[{vpos[6:0],hpos[7:0]}][3:0];
case (hpos[1:0])
0: rgb <= vpu_buffer[3:0];
1: rgb <= vpu_buffer[7:4];
2: rgb <= vpu_buffer[11:8];
3: rgb <= vpu_buffer[15:12];
endcase
end else begin
rgb <= 0;
if (vpos[8])
vpu_read <= 0;
end
end
*/
`ifdef EXT_INLINE_ASM
initial begin
rom = '{
__asm
.arch femto16
.org 32768
.len 1024
.define IN_HPOS $7f00
.define IN_VPOS $7f01
.define IN_FLAGS $7f02
.define F_DISPLAY 1
.define F_HPADDLE 2
.define F_VPADDLE 4
.define F_HSYNC 8
.define F_VSYNC 16
Start:
mov ax,#0
mov bx,ax
Loop:
mov [bx],ax
inc bx
inc ax
bnz Loop
reset
__endasm
};
end
`endif
endmodule

View File

@ -0,0 +1,104 @@
`include "hvsync_generator.v"
`include "lfsr.v"
module sound_generator(clk, reset, spkr,
lfo_freq,noise_freq, vco_freq,
vco_select, noise_select, lfo_shift, mixer);
input clk, reset;
output reg spkr = 0; // module output
input [9:0] lfo_freq; // LFO frequency (10 bits)
input [11:0] noise_freq; // noise frequency (12 bits)
input [11:0] vco_freq; // VCO frequency (12 bits)
input vco_select; // 1 = LFO modulates VCO
input noise_select; // 1 = LFO modulates Noise
input [2:0] lfo_shift; // LFO modulation depth
input [2:0] mixer; // mix enable {LFO, Noise, VCO}
reg [3:0] div16; // divide-by-16 counter
reg [17:0] lfo_count; // LFO counter (18 bits)
reg lfo_state; // LFO output
reg [12:0] noise_count; // Noise counter (13 bits)
reg noise_state; // Noise output
reg [12:0] vco_count; // VCO counter (12 bits)
reg vco_state; // VCO output
reg [15:0] lfsr; // LFSR output
LFSR #(16,16'b1000000001011,0) lfsr_gen(
.clk(clk),
.reset(reset),
.enable(div16 == 0 && noise_count == 0),
.lfsr(lfsr)
);
// create triangle waveform from LFO
wire [11:0] lfo_triangle = lfo_count[17] ? ~lfo_count[17:6] : lfo_count[17:6];
wire [11:0] vco_delta = lfo_triangle >> lfo_shift;
always @(posedge clk) begin
// divide clock by 64
div16 <= div16 + 1;
if (div16 == 0) begin
// VCO oscillator
if (reset || vco_count == 0) begin
vco_state <= ~vco_state;
if (vco_select)
vco_count <= vco_freq + vco_delta;
else
vco_count <= vco_freq + 0;
end else
vco_count <= vco_count - 1;
// LFO oscillator
if (reset || lfo_count == 0) begin
lfo_state <= ~lfo_state;
lfo_count <= {lfo_freq, 8'b0};
end else
lfo_count <= lfo_count - 1;
// Noise oscillator
if (reset || noise_count == 0) begin
if (lfsr[0])
noise_state <= ~noise_state;
if (noise_select)
noise_count <= noise_freq + vco_delta;
else
noise_count <= noise_freq + 0;
end else
noise_count <= noise_count - 1;
// Mixer
spkr <= (lfo_state | ~mixer[2])
& (noise_state | ~mixer[1])
& (vco_state | ~mixer[0]);
end
end
endmodule
module test_snchip_top(clk, reset, hsync, vsync, rgb, spkr);
input clk, reset;
output hsync;
output vsync;
output spkr;
output [2:0] rgb;
// don't output a valid sync signal
assign hsync = 0;
assign vsync = 0;
assign rgb = {spkr,1'b0,1'b0};
sound_generator sndgen(
.clk(clk),
.reset(reset),
.spkr(spkr),
.lfo_freq(1000),
.noise_freq(90),
.vco_freq(250),
.vco_select(1),
.noise_select(1),
.lfo_shift(1),
.mixer(3)
);
endmodule

View File

@ -295,10 +295,10 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
reg collision_detected;
always @(posedge clk)
if (collision_gfx)
collision_detected <= collision_gfx;
else if (vsync)
if (vstart)
collision_detected <= 0;
else if (collision_gfx)
collision_detected <= 1;
// sine lookup (4 bits input, 4 signed bits output)
@ -325,7 +325,7 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync,
player_y_fixed <= initial_y << 4;
end else begin
// movement
if (collision_detected && vpos[1]) begin
if (collision_detected && vpos[3:1] == 0) begin
if (vpos[0])
player_x_fixed <= player_x_fixed + 12'(sin_16x4(player_rot+8));
else

View File

@ -0,0 +1,206 @@
`include "hvsync_generator.v"
module example_bitmap_rom(addr, data);
input [15:0] addr;
output [15:0] data;
reg [15:0] bitarray[0:255];
assign data = bitarray[addr & 15];
initial begin/*{w:16,h:16,bpw:16,count:1}*/
bitarray[8'h00] = 16'b11110000000;
bitarray[8'h01] = 16'b100001000000;
bitarray[8'h02] = 16'b1111111100000;
bitarray[8'h03] = 16'b1111111100000;
bitarray[8'h04] = 16'b11110000000;
bitarray[8'h05] = 16'b11111111110000;
bitarray[8'h06] = 16'b111100001111000;
bitarray[8'h07] = 16'b1111101101111100;
bitarray[8'h08] = 16'b1101100001101111;
bitarray[8'h09] = 16'b1101111111100110;
bitarray[8'h0a] = 16'b1001111111100000;
bitarray[8'h0b] = 16'b1111111100000;
bitarray[8'h0c] = 16'b1110011100000;
bitarray[8'h0d] = 16'b1100001100000;
bitarray[8'h0e] = 16'b1100001100000;
bitarray[8'h0f] = 16'b11100001110000;
end
endmodule
module sprite_scanline_renderer(clk, reset, hpos, vpos, rgb,
rom_addr, rom_data);
parameter NB = 5;
parameter MB = 2;
localparam N = 1<<NB;
localparam M = 1<<MB;
input clk, reset;
input [8:0] hpos;
input [8:0] vpos;
output [3:0] rgb;
output [15:0] rom_addr;
input [15:0] rom_data;
reg [7:0] sprite_xpos[0:N-1];
reg [7:0] sprite_ypos[0:N-1];
reg [7:0] sprite_attr[0:N-1];
reg [NB-1:0] sprite_to_line[0:M-1];
reg [7:0] line_xpos[0:M-1];
reg [7:0] line_yofs[0:M-1];
reg [7:0] line_attr[0:M-1];
reg line_active[0:M-1];
reg [3:0] scanline[0:511];
reg [NB-1:0] i; // 0..N-1
reg [MB-1:0] j; // 0..M-1
reg [MB-1:0] k; // 0..M-1
reg [7:0] z;
reg [8:0] write_ofs;
wire [8:0] read_bufidx = {vpos[0], hpos[7:0]};
reg [15:0] out_bitmap;
reg [7:0] out_attr;
wire [NB-1:0] move_index = hpos[NB-1:0];
/*
0: read sprite_ypos[i]
1: check ypos, write line_ypos[j]
...
0: read line_xpos[0]
1: store xpos
2: read line_ypos[0]
3: store ypos
4: read line_attr[0]
5: store attr
8: write 16 pixels
*/
always @(posedge clk) begin
// reset every frame, don't draw vpos >= 256
if (reset || vpos[8]) begin
// initialize counters, even though it works w/o it
i <= 0;
j <= 0;
k <= 0;
// wiggle sprites randomly once per frame
if (vpos == 256 && hpos < N) begin
sprite_xpos[move_index] <= sprite_xpos[move_index] + 8'(($random&3)-1);
sprite_ypos[move_index] <= sprite_ypos[move_index] + 8'(($random&3)-1);
end
end else
if (hpos < N*2) begin
// select the sprites that will appear in this scanline
case (hpos[0])
// compute Y offset of sprite relative to scanline
0: z <= 8'(vpos - sprite_ypos[i]);
// sprite is active if Y offset is 0..15
1: begin
if (z < 16) begin
line_yofs[j] <= z; // save Y offset
sprite_to_line[j] <= i; // save main array index
line_active[j] <= 1; // mark sprite active
j <= j + 1; // inc counter
end
i <= i + 1; // inc main array counter
end
endcase
end else if (hpos < N*2+M*4) begin
// copy sprites from main array to local array
case (hpos[1:0])
0: i <= sprite_to_line[j];
// transfer sprite X pos to line array
1: line_xpos[j] <= sprite_xpos[i];
// transfer sprite attribte to line array
2: line_attr[j] <= sprite_attr[i];
// increment 2nd array counter
3: j <= j + 1;
endcase
end else if (hpos < N*2+M*4+M*32) begin
i <= 0;
j <= 0;
if (hpos[4:0] < 16) begin
// render sprites into write buffer
case (hpos[4:0])
// load scanline buffer offset to write
0: write_ofs <= {~vpos[0], line_xpos[k]};
// set ROM address and fetch bitmap
1: rom_addr <= {4'b0, line_attr[k][7:4], line_yofs[k]};
// fetch 0 if sprite is inactive
2: out_bitmap <= line_active[k] ? rom_data : 0;
// load attribute for sprite
3: out_attr <= line_attr[k];
// disable sprite for next scanline
6: line_active[k] <= 0;
// go to next sprite in 2ndary buffer
7: k <= k + 1;
endcase
end else begin
// write color to scanline buffer if low bit == 1
if (out_bitmap[0])
scanline[write_ofs] <= out_attr[3:0];
// shift bits right
out_bitmap <= out_bitmap >> 1;
// increment to next scanline pixel
write_ofs <= write_ofs + 1;
end
end
// read and clear buffer
rgb <= scanline[read_bufidx];
scanline[read_bufidx] <= 0;
end
initial
begin
sprite_xpos[0] = 0;
sprite_ypos[0] = 0;
sprite_attr[0] = 1;
end
endmodule
module test_scanline_render_top(clk, reset, hsync, vsync, rgb);
input clk, reset;
output hsync, vsync;
output [3: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 [15:0] rom_addr;
wire [15:0] rom_data;
example_bitmap_rom bitmap_rom(
.addr(rom_addr),
.data(rom_data)
);
sprite_scanline_renderer ssr(
.clk(clk),
.reset(reset),
.hpos(hpos),
.vpos(vpos),
.rgb(rgb),
.rom_addr(rom_addr),
.rom_data(rom_data)
);
endmodule

View File

@ -1,4 +1,5 @@
`include "hvsync_generator.v"
`include "digits10.v"
`include "sprite_rotation.v"
module minefield(hpos, vpos, mine_gfx);
@ -100,7 +101,7 @@ module playfield(hpos, vpos, playfield_gfx);
endmodule
module mine_test_top(clk, reset, hsync, vsync, rgb, switches_p1, switches_p2);
module tank_game_top(clk, reset, hsync, vsync, rgb, switches_p1, switches_p2);
input clk, reset;
input [7:0] switches_p1;
@ -114,7 +115,7 @@ module mine_test_top(clk, reset, hsync, vsync, rgb, switches_p1, switches_p2);
wire mine_gfx;
wire playfield_gfx;
wire tank1_gfx, tank2_gfx;
hvsync_generator hvsync_gen(
.clk(clk),
.reset(0),

View File

@ -228,7 +228,12 @@ var AnimationTimer = function(frequencyHz, callback) {
}
if (!useReqAnimFrame || ts - lastts > intervalMsec/2) {
if (running) {
callback();
try {
callback();
} catch (e) {
running = false;
throw e;
}
}
if (ts - lastts < intervalMsec*30) {
lastts += intervalMsec;

View File

@ -4,23 +4,24 @@ var VERILOG_PRESETS = [
{id:'clock_divider.v', name:'Clock Divider'},
{id:'hvsync_generator.v', name:'Video Sync Generator'},
{id:'test_hvsync.v', name:'Test Pattern'},
{id:'digits10.v', name:'Bitmapped Digits'},
{id:'7segment.v', name:'7-Segment Decoder'},
{id:'digits10.v', name:'Bitmapped Digits'},
{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:'tank.v', name:'Tank Game'},
{id:'cpu8.v', name:'Simple 8-Bit CPU'},
{id:'racing_game_cpu.v', name:'Racing Game With CPU'},
{id:'music.v', name:'3-Voice Music'},
{id:'sound_generator.v', name:'Sound Generator'},
{id:'lfsr.v', name:'Linear Feedback Shift Register'},
{id:'starfield.v', name:'Scrolling Starfield'},
{id:'racing_game.v', name:'Racing Game'},
{id:'cpu8.v', name:'Simple 8-Bit CPU'},
{id:'racing_game_cpu.v', name:'Racing Game with CPU'},
{id:'framebuffer.v', name:'Frame Buffer'},
{id:'sprite_scanline_renderer.v', name:'Sprite Scanline Renderer'},
];
var VERILOG_KEYCODE_MAP = makeKeycodeMap([
@ -80,6 +81,9 @@ var vl_stopped = false;
var VL_MODDIV_III = this.VL_MODDIV_III = function(lbits,lhs,rhs) {
return (((rhs)==0)?0:(lhs)%(rhs)); }
var VL_MODDIVS_III = this.VL_MODDIVS_III = function(lbits,lhs,rhs) {
return (((rhs)==0)?0:(lhs)%(rhs)); }
var VL_REDXOR_32 = this.VL_REDXOR_32 = function(r) {
r=(r^(r>>1)); r=(r^(r>>2)); r=(r^(r>>4)); r=(r^(r>>8)); r=(r^(r>>16));
return r;
@ -98,6 +102,8 @@ var vl_stopped = false;
var VL_RAND_RESET_I = this.VL_RAND_RESET_I = function(bits) { return 0 | Math.floor(Math.random() * (1<<bits)); }
var VL_RANDOM_I = this.VL_RANDOM_I = function(bits) { return 0 | Math.floor(Math.random() * (1<<bits)); }
//
function VerilatorBase() {
@ -182,7 +188,7 @@ var VerilogPlatform = function(mainElement, options) {
var useAudio = false;
var videoWidth = 256+20;
var videoHeight = 240+20;
var maxVideoBlankLines = 40; // vertical hold
var maxVideoLines = 262+40; // vertical hold
var idata, timer;
var gen;
var frameRate = 60;
@ -218,6 +224,14 @@ var VerilogPlatform = function(mainElement, options) {
0xffff22ff,
0xffffff22,
0xffffffff,
0xff999999,
0xff9999ff,
0xff99ff99,
0xff99ffff,
0xffff9999,
0xffff99ff,
0xffffff99,
0xff666666,
];
var debugCond;
@ -233,8 +247,8 @@ var VerilogPlatform = function(mainElement, options) {
function updateInspectionFrame() {
useAudio = false;
if (inspect_obj && inspect_sym) {
var COLOR_BIT_OFF = 0xffff3333;
var COLOR_BIT_ON = 0xffffffff;
var COLOR_BIT_OFF = 0xffff6666;
var COLOR_BIT_ON = 0xffff9999;
/*
for (var y=0; y<videoHeight; y++) {
var val = inspect_data[y * videoWidth];
@ -275,6 +289,7 @@ var VerilogPlatform = function(mainElement, options) {
gen.switches_p1 = switches[0];
gen.switches_p2 = switches[1];
gen.switches_gen = switches[2];
var totalz = 0;
for (var y=0; y<videoHeight; y++) {
gen.hpaddle = y > paddle_x ? 1 : 0;
gen.vpaddle = y > paddle_y ? 1 : 0;
@ -283,15 +298,16 @@ var VerilogPlatform = function(mainElement, options) {
if (trace) {
inspect_data[i] = inspect_obj[inspect_sym];
}
idata[i++] = RGBLOOKUP[gen.rgb & 7];
idata[i++] = RGBLOOKUP[gen.rgb & 15];
}
var z=0;
while (!gen.hsync && z++<videoWidth) vidtick();
while (gen.hsync && z++<videoWidth) vidtick();
totalz += z;
}
var z=0;
while (!gen.vsync && z++<videoWidth*maxVideoBlankLines) vidtick();
while (gen.vsync && z++<videoWidth*maxVideoBlankLines) vidtick();
var maxz = videoWidth*maxVideoLines;
while (!gen.vsync && totalz++ < maxz) vidtick();
while (gen.vsync && totalz++ < maxz) vidtick();
updateInspectionFrame();
video.updateFrame();
updateInspectionPostFrame();

View File

@ -207,7 +207,7 @@ var Assembler = function(spec) {
if (line == '')
return; // empty line
// look at each rule in order
if (!spec) { fatal("Need to load .spec first"); return; }
if (!spec) { fatal("Need to load .arch first"); return; }
var lastError;
for (var i=0; i<spec.rules.length; i++) {
var rule = spec.rules[i];
@ -277,3 +277,20 @@ var Assembler = function(spec) {
output:outwords, asmlines:asmlines, errors:errors, fixups:fixups};
}
}
// Main
if (typeof module !== 'undefined' && require.main === module) {
var fs = require('fs');
var stdinBuffer = fs.readFileSync(0);
var code = stdinBuffer.toString();
var asm = new Assembler();
asm.loadFile = function(filename) {
return fs.readFileSync(filename, 'utf8');
};
var out = asm.assembleFile(code);
if (out.errors) {
console.log(out.errors);
} else {
console.log(out.outwords);
}
}

View File

@ -1043,12 +1043,13 @@ function detectTopModuleName(code) {
return topmod;
}
function writeDependencies(depends, FS, errors) {
function writeDependencies(depends, FS, errors, callback) {
if (depends) {
for (var i=0; i<depends.length; i++) {
var d = depends[i];
var text;
if (d.text) {
FS.writeFile(d.filename, d.text, {encoding:'utf8'});
text = d.text;
} else {
// load from network (hopefully cached)
// TODO: get from indexeddb?
@ -1057,11 +1058,15 @@ function writeDependencies(depends, FS, errors) {
xhr.open("GET", path, false); // synchronous request
xhr.send(null);
if (xhr.response) {
FS.writeFile(d.filename, xhr.response, {encoding:'utf8'});
text = xhr.response;
} else {
console.log("Could not load " + path);
}
}
if (callback)
text = callback(d, text);
if (text)
FS.writeFile(d.filename, text, {encoding:'utf8'});
}
}
}
@ -1129,20 +1134,15 @@ function compileASM(asmcode, platform, options) {
return result;
}
function compileVerilator(code, platform, options) {
loadNative("verilator_bin");
load("verilator2js");
var errors = [];
var asmlines = [];
// compile inline asm
// TODO: keep line numbers
function compileInlineASM(code, platform, options, errors, asmlines) {
code = code.replace(/__asm\b([\s\S]+?)\b__endasm\b/g, function(s,asmcode,index) {
var firstline = code.substr(0,index).match(/\n/g).length;
var asmout = compileASM(asmcode, platform, options);
if (asmout.errors && asmout.errors.length) {
errors = asmout.errors;
for (var i=0; i<errors.length; i++)
errors[i].line += firstline;
for (var i=0; i<asmout.errors.length; i++) {
asmout.errors[i].line += firstline;
errors.push(asmout.errors[i]);
}
return "";
} else if (asmout.output) {
var s = "";
@ -1157,6 +1157,15 @@ function compileVerilator(code, platform, options) {
return s;
}
});
return code;
}
function compileVerilator(code, platform, options) {
loadNative("verilator_bin");
load("verilator2js");
var errors = [];
var asmlines = [];
code = compileInlineASM(code, platform, options, errors, asmlines);
var match_fn = makeErrorMatcher(errors, /%(.+?): (.+?:)?(\d+)?[:]?\s*(.+)/i, 3, 4);
var verilator_mod = verilator_bin({
wasmBinary:wasmBlob['verilator_bin'],
@ -1167,9 +1176,11 @@ function compileVerilator(code, platform, options) {
var topmod = detectTopModuleName(code);
var FS = verilator_mod['FS'];
FS.writeFile(topmod+".v", code);
writeDependencies(options.dependencies, FS, errors);
writeDependencies(options.dependencies, FS, errors, function(d, code) {
return compileInlineASM(code, platform, options, errors, asmlines);
});
starttime();
verilator_mod.callMain(["--cc", "-O3", "-DEXT_INLINE_ASM",
verilator_mod.callMain(["--cc", "-O3", "-DEXT_INLINE_ASM", "-DTOPMOD__"+topmod,
"-Wall", "-Wno-DECLFILENAME", "-Wno-UNUSED", '--report-unoptflat',
"--x-assign", "fast", "--noassert", "--pins-bv", "33",
"--top-module", topmod, topmod+".v"]);