diff --git a/presets/verilog/7segment.v b/presets/verilog/7segment.v index c51549b1..14fef1de 100644 --- a/presets/verilog/7segment.v +++ b/presets/verilog/7segment.v @@ -48,7 +48,7 @@ module segments_to_bitmap(segments, line, bits); endmodule -module test_numbers_top(clk, reset, hsync, vsync, rgb); +module test_7segment_top(clk, reset, hsync, vsync, rgb); input clk, reset; output hsync, vsync; diff --git a/presets/verilog/Makefile b/presets/verilog/Makefile new file mode 100644 index 00000000..d61a9fb6 --- /dev/null +++ b/presets/verilog/Makefile @@ -0,0 +1,7 @@ + +check: + verilator --top-module frame_buffer_top --lint-only *.v + iverilog -tnull *.v + +deps.dot: + grep \`include *.v | sed "s/:/ /g" | awk '{ print "\"" $1 "\" -> " $3 ";" }' diff --git a/presets/verilog/ball_absolute.v b/presets/verilog/ball_absolute.v index 8a64041c..634a62db 100644 --- a/presets/verilog/ball_absolute.v +++ b/presets/verilog/ball_absolute.v @@ -1,6 +1,6 @@ `include "hvsync_generator.v" -module ball_paddle_top(clk, reset, hsync, vsync, rgb); +module ball_absolute_top(clk, reset, hsync, vsync, rgb); input clk; input reset; diff --git a/presets/verilog/ball_paddle.v b/presets/verilog/ball_paddle.v index cee24975..a269268d 100644 --- a/presets/verilog/ball_paddle.v +++ b/presets/verilog/ball_paddle.v @@ -21,7 +21,7 @@ module ball_paddle_top(clk, reset, hpaddle, hsync, vsync, rgb); reg ball_speed_x; reg ball_dir_y; - reg brick_array [BRICKS_H * BRICKS_V]; + reg brick_array [0:BRICKS_H * BRICKS_V]; wire [3:0] score0; wire [3:0] score1; diff --git a/presets/verilog/ball_slip_counter.v b/presets/verilog/ball_slip_counter.v index 6a35c760..facdfd5d 100644 --- a/presets/verilog/ball_slip_counter.v +++ b/presets/verilog/ball_slip_counter.v @@ -1,6 +1,6 @@ `include "hvsync_generator.v" -module ball_paddle_top(clk, reset, hsync, vsync, rgb); +module ball_slip_counter_top(clk, reset, hsync, vsync, rgb); input clk; input reset; diff --git a/presets/verilog/cpu16.v b/presets/verilog/cpu16.v new file mode 100644 index 00000000..0468774f --- /dev/null +++ b/presets/verilog/cpu16.v @@ -0,0 +1,175 @@ +`ifndef CPU16_H +`define CPU16_H + +`include "cpu8.v" + +/* +00000aaa 0++++bbb operation A+B->A +00001ttt ######## conditional branch +00100aaa ######## load constant +00101aaa ######## load memory +00110aaa ######## store memory +01000aaa #####bbb load [B+#] -> A +01010aaa #####bbb store A -> [B+#] +10+++aaa 10+++aaa dual unary operation +11+++aaa ######## immediate binary operation +*/ + +module CPU16(clk, reset, address, data_in, data_out, write); + + input clk; + input reset; + 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 carry; + reg zero; + reg neg; + wire [2:0] flags = { neg, zero, carry }; + + 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 Bload = opcode[11]; // TODO + + localparam S_RESET = 0; + localparam S_SELECT = 1; + localparam S_DECODE = 2; + localparam S_COMPUTE = 3; + + localparam IP = 7; // IP = register 7 + + ALU #(16) alu( + .A(regs[rdest]), + .B(regs[rsrc]), + .Y(Y), + .aluop(aluop), + .carry(carry)); + + always @(posedge clk) + if (reset) begin + state <= 0; + write <= 0; + end else begin + case (state) + // state 0: reset + S_RESET: begin + regs[IP] <= 16'h8000; + write <= 0; + state <= S_SELECT; + end + // state 1: select opcode address + S_SELECT: begin + address <= regs[IP]; + regs[IP] <= regs[IP] + 1; + write <= 0; + state <= S_DECODE; + end + // state 2: read/decode opcode + S_DECODE: begin + opcode <= data_in; // (only use opcode next cycle) + casez (data_in) + // 00000aaa 0++++bbb operation A+B->A + 16'b00000???0???????: begin + aluop <= data_in[6:3]; + state <= S_COMPUTE; + end + // 00100aaa ######## load constant + 16'b00100???????????: begin + regs[rdest] <= {8'b0, data_in[7:0]}; + state <= S_SELECT; + end + // 00101aaa ######## load memory + 16'b00101???????????: begin + address <= {8'b0, data_in[7:0]}; + aluop <= `OP_LOAD_B; + state <= S_COMPUTE; + end + // 00110aaa ######## store memory + 16'b00110???????????: begin + address <= {8'b0, data_in[7:0]}; + data_out <= regs[data_in[10:8]]; + write <= 1; + state <= S_SELECT; + end + // 00001ttt ######## conditional branch + 16'b00001???????????: begin + if ( + (data_in[8] && (data_in[10] == carry)) || + (data_in[9] && (data_in[10] == zero))) + begin + // relative branch, sign extended + regs[IP] <= regs[IP] + { {8{data_in[7]}}, data_in[7:0]}; + end + state <= S_SELECT; + end + // fall-through RESET + default: begin + state <= S_RESET; // reset + end + endcase + end + // state 3: compute ALU op and flags + S_COMPUTE: begin + // transfer ALU output to destination + regs[rdest] <= Y[15:0]; + // set carry for certain operations (4-7,12-15) + if (aluop[2]) carry <= Y[16]; + // set zero flag + zero <= ~|Y[15:0]; + neg <= Y[15]; + // repeat CPU loop + state <= S_SELECT; + end + endcase + end + +endmodule + +module test_CPU16_top( + input clk, + input reset, + output [15:0] address_bus, + output reg [15:0] to_cpu, + output [15:0] from_cpu, + output write_enable, + output [15:0] IP, + output zero, + output carry +); + + reg [15:0] ram[0:65535]; + reg [15:0] rom[0:65535]; + + assign IP = cpu.regs[7]; + assign zero = cpu.zero; + assign carry = cpu.carry; + + CPU16 cpu(.clk(clk), + .reset(reset), + .address(address_bus), + .data_in(to_cpu), + .data_out(from_cpu), + .write(write_enable)); + + always @(posedge clk) + if (write_enable) begin + ram[address_bus] <= from_cpu; + end + + always @(*) + if (address_bus[15] == 0) + to_cpu = ram[address_bus]; + else + to_cpu = rom[address_bus]; + +endmodule + +`endif diff --git a/presets/verilog/cpu8.v b/presets/verilog/cpu8.v index 02289392..774d0f5b 100644 --- a/presets/verilog/cpu8.v +++ b/presets/verilog/cpu8.v @@ -1,52 +1,56 @@ +`ifndef ALU_H +`define ALU_H // ALU operations -parameter OP_LOAD_A = 4'h0; -parameter OP_LOAD_B = 4'h1; -parameter OP_INC = 4'h2; -parameter OP_DEC = 4'h3; -parameter OP_OR = 4'h4; -parameter OP_AND = 4'h5; -parameter OP_XOR = 4'h6; -parameter OP_ZERO = 4'h7; -// operations that generate carry -parameter OP_ADD = 4'h8; -parameter OP_SUB = 4'h9; -parameter OP_ASL = 4'ha; -parameter OP_LSR = 4'hb; -// operations that generate and use carry -parameter OP_ADC = 4'hc; -parameter OP_SBB = 4'hd; -parameter OP_ROL = 4'he; -parameter OP_ROR = 4'hf; +`define OP_LOAD_A 4'h0 +`define OP_LOAD_B 4'h1 +`define OP_INC 4'h2 +`define OP_DEC 4'h3 +`define OP_ASL 4'h4 +`define OP_LSR 4'h5 +`define OP_ROL 4'h6 +`define OP_ROR 4'h7 +`define OP_OR 4'h8 +`define OP_AND 4'h9 +`define OP_XOR 4'ha +`define OP_ZERO 4'hb +`define OP_ADD 4'hc +`define OP_SUB 4'hd +`define OP_ADC 4'he +`define OP_SBB 4'hf + module ALU(A, B, Y, aluop, carry); - input [7:0] A; - input [7:0] B; - output [8:0] Y; + parameter N = 8; + input [N-1:0] A; + input [N-1:0] B; + output [N:0] Y; input [3:0] aluop; input carry; always @(*) case (aluop) - OP_LOAD_A: Y = {1'b0, A}; - OP_LOAD_B: Y = {1'b0, B}; - OP_INC: Y = A + 1; - OP_DEC: Y = A - 1; - OP_OR: Y = {1'b0, A | B}; - OP_AND: Y = {1'b0, A & B}; - OP_XOR: Y = {1'b0, A ^ B}; - OP_ZERO: Y = 0; - - OP_ADD: Y = A + B; - OP_SUB: Y = A - B; - OP_ASL: Y = {A, 1'b0}; - OP_LSR: Y = {A[0], 1'b0, A[7:1]}; - - OP_ADC: Y = A + B + (carry?1:0); - OP_SBB: Y = A - B - (carry?1:0); - OP_ROL: Y = {A, carry}; - OP_ROR: Y = {A[0], carry, A[7:1]}; + // unary operations + `OP_LOAD_A: Y = {1'b0, A}; + `OP_LOAD_B: Y = {1'b0, B}; + `OP_INC: Y = A + 1; + `OP_DEC: Y = A - 1; + // unary operations that generate and/or use carry + `OP_ASL: Y = {A, 1'b0}; + `OP_LSR: Y = {A[0], 1'b0, A[N-1:1]}; + `OP_ROL: Y = {A, carry}; + `OP_ROR: Y = {A[0], carry, A[N-1:1]}; + // binary operations + `OP_OR: Y = {1'b0, A | B}; + `OP_AND: Y = {1'b0, A & B}; + `OP_XOR: Y = {1'b0, A ^ B}; + `OP_ZERO: Y = 0; + // binary operations that generate and/or use carry + `OP_ADD: Y = A + B; + `OP_SUB: Y = A - B; + `OP_ADC: Y = A + B + (carry?1:0); + `OP_SBB: Y = A - B - (carry?1:0); endcase endmodule @@ -68,31 +72,32 @@ tttt = flags test for conditional branch */ // destinations for COMPUTE instructions -parameter DEST_A = 2'b00; -parameter DEST_B = 2'b01; -parameter DEST_IP = 2'b10; -parameter DEST_NOP = 2'b11; +`define DEST_A 2'b00 +`define DEST_B 2'b01 +`define DEST_IP 2'b10 +`define DEST_NOP 2'b11 + // instruction macros -`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) } -`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) } -`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) } -`define I_CONST_IMM_A { 2'b01, DEST_A, OP_LOAD_B } -`define I_CONST_IMM_B { 2'b01, DEST_B, OP_LOAD_B } -`define I_JUMP_IMM { 2'b01, DEST_IP, OP_LOAD_B } -`define I_STORE_A(addr) { 4'b1001, 4'(addr) } -`define I_BRANCH_IF(zv,zu,cv,cu) { 4'b1010, 1'(zv), 1'(zu), 1'(cv), 1'(cu) } +`define I_COMPUTE(dest,op) { 2'b00, (dest), (op) } +`define I_COMPUTE_IMM(dest,op) { 2'b01, (dest), (op) } +`define I_COMPUTE_READB(dest,op) { 2'b11, (dest), (op) } +`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B } +`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B } +`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B } +`define I_STORE_A(addr) { 4'b1001, (addr) } +`define I_BRANCH_IF(zv,zu,cv,cu) { 4'b1010, (zv), (zu), (cv), (cu) } `define I_CLEAR_CARRY { 8'b10001000 } `define I_SWAP_AB { 8'b10000001 } `define I_RESET { 8'b10111111 } // convenience macros -`define I_ZERO_A `I_COMPUTE(DEST_A, OP_ZERO) -`define I_ZERO_B `I_COMPUTE(DEST_B, OP_ZERO) -`define I_BRANCH_IF_CARRY(carry) `I_BRANCH_IF(0,0,carry,1) -`define I_BRANCH_IF_ZERO(zero) `I_BRANCH_IF(zero,1,0,0) -`define I_CLEAR_ZERO `I_COMPUTE(DEST_NOP,OP_ZERO) +`define I_ZERO_A `I_COMPUTE(`DEST_A, `OP_ZERO) +`define I_ZERO_B `I_COMPUTE(`DEST_B, `OP_ZERO) +`define I_BRANCH_IF_CARRY(carry) `I_BRANCH_IF(1'b0, 1'b0, carry, 1'b1) +`define I_BRANCH_IF_ZERO(zero) `I_BRANCH_IF(zero, 1'b1, 1'b0, 1'b0) +`define I_CLEAR_ZERO `I_COMPUTE(`DEST_NOP, `OP_ZERO) module CPU(clk, reset, address, data_in, data_out, write); - + input clk; input reset; output [7:0] address; @@ -206,13 +211,13 @@ module CPU(clk, reset, address, data_in, data_out, write); S_COMPUTE: begin // transfer ALU output to destination case (opdest) - DEST_A: A <= Y[7:0]; - DEST_B: B <= Y[7:0]; - DEST_IP: IP <= Y[7:0]; - DEST_NOP: ; + `DEST_A: A <= Y[7:0]; + `DEST_B: B <= Y[7:0]; + `DEST_IP: IP <= Y[7:0]; + `DEST_NOP: ; endcase - // set carry for certain operations (code >= 8) - if (aluop[3]) carry <= Y[8]; + // set carry for certain operations (4-7,12-15) + if (aluop[2]) carry <= Y[8]; // set zero flag zero <= ~|Y[7:0]; // repeat CPU loop @@ -275,15 +280,24 @@ module test_CPU_top( `I_ZERO_A, `I_CONST_IMM_B, 1, - `I_COMPUTE(DEST_A, OP_ADC), // addr 4 + `I_COMPUTE(`DEST_A, `OP_ADC), // addr 4 `I_SWAP_AB, - `I_BRANCH_IF_CARRY(0), + `I_BRANCH_IF_CARRY(1'b0), 4 + 'h80, // correct for ROM offset - `I_STORE_A(0), + `I_STORE_A(4'd0), `I_RESET, // leftover elements - 118{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,0 }; end endmodule + +`endif diff --git a/presets/verilog/digits10.v b/presets/verilog/digits10.v index 7785c424..c7bf3316 100644 --- a/presets/verilog/digits10.v +++ b/presets/verilog/digits10.v @@ -82,10 +82,12 @@ module digits10_array(digit, yofs, bits); input [2:0] yofs; output [4:0] bits; - reg [4:0] bitarray[16][5]; + reg [4:0] bitarray[0:15][0:4]; assign bits = bitarray[digit][yofs]; + integer i,j; + initial begin/*{w:5,h:5,count:10}*/ bitarray[0][0] = 5'b11111; bitarray[0][1] = 5'b10001; @@ -148,8 +150,8 @@ module digits10_array(digit, yofs, bits); bitarray[9][4] = 5'b11111; // clear unused array entries - for (int i = 10; i <= 15; i++) - for (int j = 0; j <= 4; j++) + for (i = 10; i <= 15; i++) + for (j = 0; j <= 4; j++) bitarray[i][j] = 0; end endmodule diff --git a/presets/verilog/femto16.cfg b/presets/verilog/femto16.cfg new file mode 100644 index 00000000..73e17a68 --- /dev/null +++ b/presets/verilog/femto16.cfg @@ -0,0 +1,90 @@ +; Architecture file for the FEMTO-8 + +; default output format is a memory initialization file +.outfmt mif + +; mif file is this big +.mifwords 256 +.mifwidth 16 + +; Opcodes for core instruction set +.define r0 0 +.define r1 1 +.define r2 2 +.define r3 3 +.define r4 4 +.define r5 5 +.define r6 6 +.define r7 7 +.define ip 7 + +.define LOAD_A 0 +.define LOAD_B 1 +.define INC 2 +.define DEC 3 +.define ASL 4 +.define LSR 5 +.define ROL 6 +.define ROR 7 +.define OR 8 +.define AND 9 +.define XOR 10 +.define ZERO 11 +.define ADD 12 +.define SUB 13 +.define ADC 14 +.define SBB 15 + +; reg-reg op +reg 4 3 3 { 00000 (1) 0 (0) (2) } +mem 4 3 3 { 00001 (1) 0 (0) (2) } +imm 3 3 8 { 11 (0) (1) (2) } + +mov 3 3 { 00000 (0) 00001 (1) } +or 3 3 { 00000 (0) 01000 (1) } +and 3 3 { 00000 (0) 01001 (1) } +xor 3 3 { 00000 (0) 01010 (1) } +add 3 3 { 00000 (0) 01100 (1) } +sub 3 3 { 00000 (0) 01101 (1) } +adc 3 3 { 00000 (0) 01110 (1) } +sbb 3 3 { 00000 (0) 01111 (1) } + +inc 3 { 00000 (0) 00010 (0) } +dec 3 { 00000 (0) 00011 (0) } +asl 3 { 00000 (0) 00100 (0) } +lsr 3 { 00000 (0) 00101 (0) } +rol 3 { 00000 (0) 00110 (0) } +ror 3 { 00000 (0) 00111 (0) } +zero 3 { 00000 (0) 01011 (0) } + +load 3 3 { 00001 (0) 00001 (1) } +lor 3 3 { 00001 (0) 01000 (1) } +land 3 3 { 00001 (0) 01001 (1) } +lxor 3 3 { 00001 (0) 01010 (1) } +ladd 3 3 { 00001 (0) 01100 (1) } +lsub 3 3 { 00001 (0) 01101 (1) } +ladc 3 3 { 00001 (0) 01110 (1) } +lsbb 3 3 { 00001 (0) 01111 (1) } + +ior 3 8 { 11 000 (0) (1) } +iand 3 8 { 11 001 (0) (1) } +ixor 3 8 { 11 010 (0) (1) } +iadd 3 8 { 11 100 (0) (1) } +isub 3 8 { 11 101 (0) (1) } +iadc 3 8 { 11 110 (0) (1) } +isbb 3 8 { 11 111 (0) (1) } + +constb 3 8 { 00100 (0) (1) } +loadz 3 8 { 00101 (0) (1) } +storez 3 8 { 00110 (0) (1) } + +branch 3 8 { 10 (0) 111 (1) } +bcc 8 { 10 001 111 (0) } +bcs 8 { 10 101 111 (0) } +bnz 8 { 10 010 111 (0) } +bz 8 { 10 110 111 (0) } + +reset { 1011100011111111 } + +; allow raw byte positioning +byte 8 { (0) } ; One byte constant diff --git a/presets/verilog/femto8.cfg b/presets/verilog/femto8.cfg new file mode 100644 index 00000000..13daa452 --- /dev/null +++ b/presets/verilog/femto8.cfg @@ -0,0 +1,99 @@ +; Architecture file for the FEMTO-8 + +; default output format is a memory initialization file +.outfmt mif + +; mif file is this big +.mifwords 256 +.mifwidth 8 + +; Opcodes for core instruction set +.define A 0 +.define B 1 +.define IP 2 +.define NOP 3 + +.define LOAD_A 0000 +.define LOAD_B 0001 +.define INC 0010 +.define DEC 0011 +.define ASL 0100 +.define LSR 0101 +.define ROL 0110 +.define ROR 0111 +.define OR 1000 +.define AND 1001 +.define XOR 1010 +.define ZERO 1011 +.define ADD 1100 +.define SUB 1101 +.define ADC 1110 +.define SBB 1111 + +; ALU A + B -> dest +mova 2 { 00 (0) 0000 } +movb 2 { 00 (0) 0001 } +inc 2 { 00 (0) 0010 } +dec 2 { 00 (0) 0011 } +asl 2 { 00 (0) 0100 } +lsr 2 { 00 (0) 0101 } +rol 2 { 00 (0) 0110 } +ror 2 { 00 (0) 0111 } +or 2 { 00 (0) 1000 } +and 2 { 00 (0) 1001 } +xor 2 { 00 (0) 1010 } +zero 2 { 00 (0) 1011 } +add 2 { 00 (0) 1100 } +sub 2 { 00 (0) 1101 } +adc 2 { 00 (0) 1110 } +sbb 2 { 00 (0) 1111 } + +; ALU A + immediate -> dest +movi 2 8 { 01 (0) 0001 (1) } +asli 2 8 { 01 (0) 0100 (1) } +lsri 2 8 { 01 (0) 0101 (1) } +roli 2 8 { 01 (0) 0110 (1) } +rori 2 8 { 01 (0) 0111 (1) } +ori 2 8 { 01 (0) 1000 (1) } +andi 2 8 { 01 (0) 1001 (1) } +xori 2 8 { 01 (0) 1010 (1) } +addi 2 8 { 01 (0) 1100 (1) } +subi 2 8 { 01 (0) 1101 (1) } +adci 2 8 { 01 (0) 1110 (1) } +sbbi 2 8 { 01 (0) 1111 (1) } + +; ALU A + read [B] -> dest +movrb 2 { 11 (0) 0001 } +aslrb 2 { 11 (0) 0100 } +lsrrb 2 { 11 (0) 0101 } +rolrb 2 { 11 (0) 0110 } +rorrb 2 { 11 (0) 0111 } +orrb 2 { 11 (0) 1000 } +andrb 2 { 11 (0) 1001 } +xorrb 2 { 11 (0) 1010 } +addrb 2 { 11 (0) 1100 } +subrb 2 { 11 (0) 1101 } +adcrb 2 { 11 (0) 1110 } +sbbrb 2 { 11 (0) 1111 } + +; A -> write [nnnn] +sta 4 { 1001 (0) } + +; other insns +clc { 10001000 } +swapab { 10000001 } +reset { 10001111 } + +lia 8 { 01 00 0001 (0) } +lib 8 { 01 01 0001 (0) } +jmp 8 { 01 10 0001 (0) } + +; conditional branch +bcc 8 { 1010 0001 (0) } +bcs 8 { 1010 0011 (0) } +bz 8 { 1010 1100 (0) } +bnz 8 { 1010 0100 (0) } + + +; allow raw byte positioning +byte 8 { (0) } ; One byte constant diff --git a/presets/verilog/framebuffer.v b/presets/verilog/framebuffer.v new file mode 100644 index 00000000..50c02cdb --- /dev/null +++ b/presets/verilog/framebuffer.v @@ -0,0 +1,182 @@ +`include "hvsync_generator.v" +`include "sprite_bitmap.v" +`include "sprite_renderer.v" +`include "cpu8.v" + +// uncomment to see scope view +//`define DEBUG + +module frame_buffer_top(clk, reset, hsync, vsync, hpaddle, vpaddle, + address_bus, to_cpu, from_cpu, write_enable +`ifdef DEBUG + , output [7:0] A + , output [7:0] B + , output [7: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.IP; + assign A = cpu.A; + assign B = cpu.B; + 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; + parameter IN_VPU = 8'b01000011; + + reg [7:0] ram[0:63]; + reg [7:0] rom[0:255]; + + output wire [7:0] address_bus; + output reg [7:0] to_cpu; + output wire [7:0] from_cpu; + output wire write_enable; + + CPU cpu(.clk(clk), + .reset(reset), + .address(address_bus), + .data_in(to_cpu), + .data_out(from_cpu), + .write(write_enable)); + + always @(posedge clk) + if (write_enable) begin + casez (address_bus) + // VPU lo byte + 8'b0001000: begin + vpu_write[15:8] <= from_cpu; + end + // VPU hi byte + 8'b0001001: begin + vpu_write[7:0] <= from_cpu; + end + // VPU write + 8'b0001010: begin + vpu_ram[vpu_write] <= from_cpu[7:4]; + vpu_ram[vpu_write+1] <= from_cpu[3:0]; + vpu_write <= vpu_write + 2; + end + // VPU move + 8'b0001011: begin + // sign extend + vpu_write <= { + vpu_write[15:8] + { {4{from_cpu[7]}}, from_cpu[7:4] }, + vpu_write[7:0] + { {4{from_cpu[3]}}, from_cpu[3:0] } + }; + end + default: ram[address_bus[5:0]] <= from_cpu; + endcase + end + + always @(*) + casez (address_bus) + // RAM + 8'b00??????: to_cpu = ram[address_bus[5:0]]; + // special read registers + IN_HPOS: to_cpu = hpos[7:0]; + IN_VPOS: to_cpu = vpos[7:0]; + IN_FLAGS: to_cpu = {3'b0, + vsync, hsync, vpaddle, hpaddle, display_on}; + IN_VPU: to_cpu = {vpu_ram[vpu_write], vpu_ram[vpu_write+1]}; + // ROM + 8'b1???????: to_cpu = rom[address_bus[6:0] + 128]; + default: ; + endcase + + hvsync_generator hvsync_gen( + .clk(clk), + .reset(0), + .hsync(hsync), + .vsync(vsync), + .display_on(display_on), + .hpos(hpos), + .vpos(vpos) + ); + + reg [3:0] vpu_ram[0:65535]; + reg [15:0] vpu_read; + reg [15:0] vpu_write; + reg [3:0] rgb; + + always @(posedge clk) begin + if (!hpos[8] && !vpos[8]) begin + rgb <= vpu_ram[vpu_read]; + vpu_read <= vpu_read + 1; + end else begin + rgb <= 0; + if (vpos[8]) + vpu_read <= 0; + end + end + +`ifdef EXT_INLINE_ASM + initial begin + rom = '{ + __asm +.arch femto8 +.org 128 + +.define VPU_LO 8 +.define VPU_HI 9 +.define VPU_WRITE 10 +.define VPU_MOVE 11 + +.define IN_HPOS $40 +.define IN_VPOS $41 +.define IN_FLAGS $42 + +.define F_DISPLAY 1 +.define F_HPADDLE 2 +.define F_VPADDLE 4 +.define F_HSYNC 8 +.define F_VSYNC 16 + +Start: + zero A + sta VPU_LO + sta VPU_HI + sta 0 + sta 1 +DisplayLoop: + zero B + movrb A + sta VPU_WRITE + sta VPU_MOVE + sta VPU_WRITE + sta VPU_MOVE + sta VPU_WRITE + sta VPU_MOVE + lia F_VSYNC + lib IN_FLAGS + andrb NOP + bz DisplayLoop +WaitVsync: + andrb NOP + bnz WaitVsync + zero B + movrb A + inc A + sta 0 + jmp DisplayLoop + __endasm + }; + end +`endif + +endmodule diff --git a/presets/verilog/gates.v b/presets/verilog/gates.v index 5ce740cb..37f09018 100644 --- a/presets/verilog/gates.v +++ b/presets/verilog/gates.v @@ -13,4 +13,5 @@ module gates(clk, out_not, out_and, out_or, out_xor, in); in <= in + 1; end -endmodule; +endmodule + diff --git a/presets/verilog/hvsync_generator.v b/presets/verilog/hvsync_generator.v index 7693bb14..1f9f4fd2 100644 --- a/presets/verilog/hvsync_generator.v +++ b/presets/verilog/hvsync_generator.v @@ -1,24 +1,6 @@ `ifndef HVSYNC_GENERATOR_H `define HVSYNC_GENERATOR_H -// constant declarations for TV-simulator sync parameters -// horizontal -localparam H_DISPLAY = 256; // horizontal display width -localparam H_BACK = 23; // horizontal left border (back porch) -localparam H_FRONT = 7; // horizontal right border (front porch) -localparam H_SYNC = 23; // horizontal sync width -localparam H_SYNC_START = H_DISPLAY + H_FRONT; -localparam H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1; -localparam H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1; -// vertical -localparam V_DISPLAY = 240; // vertical display height -localparam V_TOP = 5; // vertical top border -localparam V_BOTTOM = 14; // vertical bottom border -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(clk, reset, hsync, vsync, display_on, hpos, vpos); input clk; @@ -28,6 +10,25 @@ module hvsync_generator(clk, reset, hsync, vsync, display_on, hpos, vpos); output [8:0] hpos; output [8:0] vpos; + // constant declarations for TV-simulator sync parameters + // horizontal + parameter H_DISPLAY = 256; // horizontal display width + parameter H_BACK = 23; // horizontal left border (back porch) + parameter H_FRONT = 7; // horizontal right border (front porch) + parameter H_SYNC = 23; // horizontal sync width + // vertical + parameter V_DISPLAY = 240; // vertical display height + parameter V_TOP = 5; // vertical top border + parameter V_BOTTOM = 14; // vertical bottom border + parameter V_SYNC = 3; // vertical sync # lines + // derived + parameter H_SYNC_START = H_DISPLAY + H_FRONT; + parameter H_SYNC_END = H_DISPLAY + H_FRONT + H_SYNC - 1; + parameter H_MAX = H_DISPLAY + H_BACK + H_FRONT + H_SYNC - 1; + parameter V_SYNC_START = V_DISPLAY + V_BOTTOM; + parameter V_SYNC_END = V_DISPLAY + V_BOTTOM + V_SYNC - 1; + parameter V_MAX = V_DISPLAY + V_TOP + V_BOTTOM + V_SYNC - 1; + wire hmaxxed = (hpos == H_MAX) || reset; wire vmaxxed = (vpos == V_MAX) || reset; diff --git a/presets/verilog/lfsr.v b/presets/verilog/lfsr.v index 14f6d8c1..bd551d2f 100644 --- a/presets/verilog/lfsr.v +++ b/presets/verilog/lfsr.v @@ -1,3 +1,5 @@ +`ifndef LFSR_V +`define LFSR_V module LFSR(clk,reset,enable,lfsr); @@ -19,5 +21,6 @@ module LFSR(clk,reset,enable,lfsr); lfsr <= {lfsr[NBITS-2:0], 1'b0} ^ (feedback ? TAPS : 0); end -endmodule; +endmodule +`endif diff --git a/presets/verilog/music.v b/presets/verilog/music.v index dcd145fc..dd502675 100644 --- a/presets/verilog/music.v +++ b/presets/verilog/music.v @@ -3,32 +3,44 @@ module sound_psg(clk, reset, out, reg_sel, reg_data, reg_write); input clk, reset; - input [3:0] reg_sel; - input [7:0] reg_data; - input reg_write; - output [7:0] out; + input [3:0] reg_sel; // select register # + input [7:0] reg_data; // data to write to register + input reg_write; // write enable + output [7:0] out; // output waveform parameter NVOICES = 4; - reg outputs[NVOICES]; - reg [17:0] count[NVOICES]; - reg [7:0] register[16]; + reg outputs[0:NVOICES-1]; + reg [11:0] count[0:NVOICES-1]; + reg [7:0] register[0:15]; + reg [5:0] div64; + integer i; always @(posedge clk) begin - out = 0; - for (i=0; i dest -mova 2 { 00 (0) 0000 } -movb 2 { 00 (0) 0001 } -inc 2 { 00 (0) 0010 } -dec 2 { 00 (0) 0011 } -or 2 { 00 (0) 0100 } -and 2 { 00 (0) 0101 } -xor 2 { 00 (0) 0110 } -zero 2 { 00 (0) 0111 } -add 2 { 00 (0) 1000 } -sub 2 { 00 (0) 1001 } -asl 2 { 00 (0) 1010 } -lsr 2 { 00 (0) 1011 } -adc 2 { 00 (0) 1100 } -sbb 2 { 00 (0) 1101 } -rol 2 { 00 (0) 1110 } -ror 2 { 00 (0) 1111 } - -; ALU A + immediate -> dest -movi 2 8 { 01 (0) 0001 (1) } -ori 2 8 { 01 (0) 0100 (1) } -andi 2 8 { 01 (0) 0101 (1) } -xori 2 8 { 01 (0) 0110 (1) } -addi 2 8 { 01 (0) 1000 (1) } -subi 2 8 { 01 (0) 1001 (1) } -asli 2 8 { 01 (0) 1010 (1) } -lsri 2 8 { 01 (0) 1011 (1) } -adci 2 8 { 01 (0) 1100 (1) } -sbbi 2 8 { 01 (0) 1101 (1) } -roli 2 8 { 01 (0) 1110 (1) } -rori 2 8 { 01 (0) 1111 (1) } - -; ALU A + read [B] -> dest -movrb 2 { 11 (0) 0001 } -orrb 2 { 11 (0) 0100 } -andrb 2 { 11 (0) 0101 } -xorrb 2 { 11 (0) 0110 } -addrb 2 { 11 (0) 1000 } -subrb 2 { 11 (0) 1001 } -aslrb 2 { 11 (0) 1010 } -lsrrb 2 { 11 (0) 1011 } -adcrb 2 { 11 (0) 1100 } -sbbrb 2 { 11 (0) 1101 } -rolrb 2 { 11 (0) 1110 } -rorrb 2 { 11 (0) 1111 } - -; A -> write [nnnn] -sta 4 { 1001 (0) } - -; other insns -clc { 10001000 } -swapab { 10000001 } -reset { 10001111 } - -lda 8 { 01 00 0001 (0) } -ldb 8 { 01 01 0001 (0) } -jmp 8 { 01 10 0001 (0) } - -; conditional branch -bcc 8 { 1010 0001 (0) } -bcs 8 { 1010 0011 (0) } -bz 8 { 1010 1100 (0) } -bnz 8 { 1010 0100 (0) } - - -; allow raw byte positioning -byte 8 { (0) } ; One byte constant diff --git a/presets/verilog/race_game_cpu.v b/presets/verilog/racing_game_cpu.v similarity index 92% rename from presets/verilog/race_game_cpu.v rename to presets/verilog/racing_game_cpu.v index 51cf4f9f..76f67c10 100644 --- a/presets/verilog/race_game_cpu.v +++ b/presets/verilog/racing_game_cpu.v @@ -1,11 +1,12 @@ `include "hvsync_generator.v" +`include "sprite_bitmap.v" `include "sprite_renderer.v" `include "cpu8.v" // uncomment to see scope view //`define DEBUG -module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle, +module racing_game_cpu_top(clk, reset, hsync, vsync, hpaddle, vpaddle, address_bus, to_cpu, from_cpu, write_enable `ifdef DEBUG , output [7:0] A @@ -14,7 +15,7 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle, , output carry , output zero `else - , output [2:0] rgb + , rgb `endif ); @@ -31,6 +32,8 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle, assign B = cpu.B; assign carry = cpu.carry; assign zero = cpu.zero; +`else + output [3:0] rgb; `endif parameter PADDLE_X = 0; @@ -128,10 +131,28 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle, .gfx(enemy_gfx), .in_progress(player_is_drawing)); + reg frame_collision; + + always @(posedge clk) + if (player_gfx && (enemy_gfx || track_gfx)) + frame_collision <= 1; + else if (vpos==0) + frame_collision <= 0; + + wire track_offside = (hpos[7:5]==0) || (hpos[7:5]==7); + wire track_shoulder = (hpos[7:3]==3) || (hpos[7:3]==28); + wire track_gfx = (vpos[5:1]!=ram[TRACKPOS_LO][5:1]) && track_offside; + + wire r = display_on && (player_gfx || enemy_gfx || track_shoulder); + wire g = display_on && (player_gfx || track_gfx); + wire b = display_on && (enemy_gfx || track_shoulder); + assign rgb = {1'b0,b,g,r}; + +`ifdef EXT_INLINE_ASM initial begin rom = '{ __asm -.arch nano8 +.arch femto8 .org 128 .define PADDLE_X 0 @@ -157,11 +178,11 @@ module sprite_multiple_top(clk, reset, hsync, vsync, hpaddle, vpaddle, .define F_COLLIDE 32 Start: - lda 128 + lia 128 sta PLAYER_X sta ENEMY_X sta ENEMY_Y - lda 180 + lia 180 sta PLAYER_Y zero A sta SPEED @@ -169,17 +190,17 @@ Start: sta ENEMY_DIR ; test hpaddle flag DisplayLoop: - lda F_HPADDLE - ldb IN_FLAGS + lia F_HPADDLE + lib IN_FLAGS andrb NOP bz DisplayLoop ; [vpos] -> paddle_x - ldb IN_VPOS + lib IN_VPOS movrb A sta PLAYER_X ; wait for vsync=1 then vsync=0 - lda F_VSYNC - ldb IN_FLAGS + lia F_VSYNC + lib IN_FLAGS WaitForVsyncOn: andrb NOP bz WaitForVsyncOn @@ -187,16 +208,16 @@ WaitForVsyncOff: andrb NOP bnz WaitForVsyncOff ; check collision - lda F_COLLIDE - ldb IN_FLAGS + lia F_COLLIDE + lib IN_FLAGS andrb NOP bz NoCollision ; load slow speed - lda 16 + lia 16 sta SPEED NoCollision: ; update speed - ldb SPEED + lib SPEED movrb A inc A ; don't store if == 0 @@ -209,19 +230,19 @@ MaxSpeed: lsr A lsr A ; add to lo byte of track pos - ldb TRACKPOS_LO + lib TRACKPOS_LO addrb B swapab sta TRACKPOS_LO swapab ; update enemy vert pos - ldb ENEMY_Y + lib ENEMY_Y addrb A sta ENEMY_Y ; update enemy horiz pos - ldb ENEMY_X + lib ENEMY_X movrb A - ldb ENEMY_DIR + lib ENEMY_DIR addrb A sta ENEMY_X subi A 64 @@ -237,22 +258,6 @@ SkipXReverse: __endasm }; end +`endif - reg frame_collision; - - always @(posedge clk) - if (player_gfx && (enemy_gfx || track_gfx)) - frame_collision <= 1; - else if (vpos==0) - frame_collision <= 0; - - wire track_offside = (hpos[7:5]==0) || (hpos[7:5]==7); - wire track_shoulder = (hpos[7:3]==3) || (hpos[7:3]==28); - wire track_gfx = (vpos[5:1]!=ram[TRACKPOS_LO][5:1]) && track_offside; - - wire r = display_on && (player_gfx || enemy_gfx || track_shoulder); - wire g = display_on && (player_gfx || track_gfx); - wire b = display_on && (enemy_gfx || track_shoulder); - assign rgb = {b,g,r}; - endmodule diff --git a/presets/verilog/ram1.v b/presets/verilog/ram1.v index 9d23a185..02e80d94 100644 --- a/presets/verilog/ram1.v +++ b/presets/verilog/ram1.v @@ -9,7 +9,7 @@ module RAM_1KB(clk, addr, din, dout, we); output [7:0] dout; // 8-bit data output input we; // write enable - reg [7:0] mem [1024]; // 1024x8 bit memory + reg [7:0] mem [0:1023]; // 1024x8 bit memory always @(posedge clk) begin if (we) // if write enabled @@ -19,7 +19,7 @@ module RAM_1KB(clk, addr, din, dout, we); endmodule -module test_framebuf_top(clk, reset, hsync, vsync, rgb); +module test_ram1_top(clk, reset, hsync, vsync, rgb); input clk, reset; output hsync, vsync; diff --git a/presets/verilog/ram2.v b/presets/verilog/ram2.v index 48927fe9..6d79463d 100644 --- a/presets/verilog/ram2.v +++ b/presets/verilog/ram2.v @@ -15,7 +15,7 @@ module RAM_1KB_tri(clk, addr, data, we); end endmodule -module test_framebuf_top( +module test_ram2_top( input clk, reset, output hsync, vsync, output [2:0] rgb diff --git a/presets/verilog/scoreboard.v b/presets/verilog/scoreboard.v index 0190011e..c3b0f149 100644 --- a/presets/verilog/scoreboard.v +++ b/presets/verilog/scoreboard.v @@ -1,3 +1,6 @@ +`ifndef SCOREBOARD_H +`define SCOREBOARD_H + `include "hvsync_generator.v" `include "digits10.v" @@ -65,7 +68,7 @@ module scoreboard_generator(score0, score1, lives, vpos, hpos, board_gfx); endmodule -module top(clk, reset, hsync, vsync, rgb); +module scoreboard_top(clk, reset, hsync, vsync, rgb); input clk, reset; output hsync, vsync; @@ -101,3 +104,5 @@ module top(clk, reset, hsync, vsync, rgb); assign rgb = {b,g,r}; endmodule + +`endif diff --git a/presets/verilog/simplecpu.v b/presets/verilog/simplecpu.v deleted file mode 100644 index 2d2a9469..00000000 --- a/presets/verilog/simplecpu.v +++ /dev/null @@ -1,251 +0,0 @@ - -`define OP_LOAD_A 4'h0 -`define OP_LOAD_B 4'h1 -`define OP_OR 4'h2 -`define OP_AND 4'h3 -`define OP_XOR 4'h4 -`define OP_INC 4'h5 -`define OP_DEC 4'h6 -`define OP_NOP 4'h7 -// operations that generate carry -`define OP_ADD 4'h8 -`define OP_SUB 4'h9 -`define OP_ASL 4'ha -`define OP_LSR 4'hb - -module ALU( - input [7:0] A, - 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_OR: Y = {1'b0, A | B}; - `OP_AND: Y = {1'b0, A & B}; - `OP_XOR: Y = {1'b0, A ^ B}; - `OP_INC: Y = A + 1; - `OP_DEC: Y = A - 1; - - `OP_ADD: Y = A + B; - `OP_SUB: Y = A - B; - `OP_ASL: Y = A + A; - `OP_LSR: Y = {A[0], A >> 1}; - default: Y = 9'bx; - endcase - -endmodule - -/* -Bits Description - -00ddaaaa A + B -> dest -01ddaaaa A + immediate -> dest -11ddaaaa A + read [B] -> dest -10000001 swap A <-> B -1001nnnn A -> write [nnnn] -1010tttt conditional branch - - dd = destination (00=A, 01=B, 10=IP, 11=none) -aaaa = ALU operation (replaces + operator) -nnnn = 4-bit constant -tttt = flags test for conditional branch -*/ - -`define DEST_A 2'b00 -`define DEST_B 2'b01 -`define DEST_IP 2'b10 -`define DEST_NOP 2'b11 -`define I_COMPUTE(dest,op) { 2'b00, 2'(dest), 4'(op) } -`define I_COMPUTE_IMM(dest,op) { 2'b01, 2'(dest), 4'(op) } -`define I_COMPUTE_READB(dest,op) { 2'b11, 2'(dest), 4'(op) } -`define I_CONST_IMM_A { 2'b01, `DEST_A, `OP_LOAD_B } -`define I_CONST_IMM_B { 2'b01, `DEST_B, `OP_LOAD_B } -`define I_JUMP_IMM { 2'b01, `DEST_IP, `OP_LOAD_B } -`define I_STORE_A(addr) { 4'b1001, 4'(addr) } -`define I_BRANCH_IF_CARRY(carry) { 4'b1010, 2'b00, 1'(carry), 1'b1 } -`define I_SWAP_AB { 8'b10000001 } -`define I_RESET { 8'b10111111 } - -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] A, B; - reg [8:0] Y; - reg [2:0] state; - - reg carry; - reg zero; - wire [1:0] flags = { zero, carry }; - - reg [7:0] opcode; - wire [3:0] aluop = opcode[3:0]; - wire [1:0] opdest = opcode[5:4]; - wire memalu = opcode[6]; - - localparam S_RESET = 0; - localparam S_SELECT = 1; - localparam S_DECODE = 2; - localparam S_COMPUTE = 3; - localparam S_READ_IP = 4; - - ALU alu(.A(A), .B(memalu?data_in: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 - opcode <= data_in; - casez (data_in) - // ALU A + B -> dest - 8'b00??????: begin - state <= S_COMPUTE; - end - // ALU A + immediate -> dest - 8'b01??????: begin - address <= IP; - IP <= IP + 1; - state <= S_COMPUTE; - end - // ALU A + read [B] -> dest - 8'b11??????: begin - address <= B; - state <= S_COMPUTE; - end - // A -> write [aluop] - 8'b1001????: begin - address <= {4'b0, aluop}; - data_out <= A; - write <= 1; - state <= S_SELECT; - end - // swap A,B - 8'b10000001: begin - A <= B; - B <= A; - state <= S_SELECT; - end - // conditional branch - 8'b1010????: begin - if ( - (data_in[0] && (data_in[1] == carry)) || - (data_in[2] && (data_in[3] == zero))) - begin - address <= IP; - state <= S_READ_IP; - end else begin - state <= S_SELECT; - end - IP <= IP + 1; // skip immediate - end - // fall-through RESET - default: begin - state <= S_RESET; // reset - end - endcase - end - // state 3: compute ALU op and flags - S_COMPUTE: begin - // transfer ALU output to destination - case (opdest) - `DEST_A: A <= Y[7:0]; - `DEST_B: B <= Y[7:0]; - `DEST_IP: IP <= Y[7:0]; - `DEST_NOP: ; - endcase - // set carry for certain operations (code >= 8) - if (aluop[3]) carry <= Y[8]; - // set zero flag - zero <= ~|Y; - // repeat CPU loop - state <= S_SELECT; - end - // state 4: read new IP from memory (immediate mode) - S_READ_IP: begin - IP <= data_in; - state <= S_SELECT; - end - endcase - 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, - output [7:0] IP, - output [7:0] A, - output [7:0] B -); - - reg [7:0] ram[0:127]; - reg [7:0] rom[0:127]; - - assign IP = cpu.IP; - assign A = cpu.A; - assign B = cpu.B; - - 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 - rom = '{ - `I_CONST_IMM_A, - 0, - `I_CONST_IMM_B, - 1, - `I_COMPUTE(`DEST_A, `OP_ADD), // addr 4 - `I_SWAP_AB, - `I_BRANCH_IF_CARRY(0), - 4 + 'h80, // correct for ROM offset - `I_RESET, - // leftover elements - 119{0} - }; - end - -endmodule diff --git a/presets/verilog/sprite_bitmap.v b/presets/verilog/sprite_bitmap.v index 1c0022cb..c4b1ffbd 100644 --- a/presets/verilog/sprite_bitmap.v +++ b/presets/verilog/sprite_bitmap.v @@ -1,3 +1,6 @@ +`ifndef SPRITE_BITMAP_H +`define SPRITE_BITMAP_H + `include "hvsync_generator.v" module car_bitmap(yofs, bits); @@ -5,25 +8,27 @@ module car_bitmap(yofs, bits); input [3:0] yofs; output [7:0] bits; - reg [7:0] bitarray[16]; + reg [7:0] bitarray[0:15]; + assign bits = bitarray[yofs]; + initial begin/*{w:8,h:16}*/ bitarray[0] = 8'b0; - bitarray[1] = 8'b101110; - bitarray[2] = 8'b11101110; - bitarray[3] = 8'b11111110; - bitarray[4] = 8'b11101110; - bitarray[5] = 8'b1101110; - bitarray[6] = 8'b110000; - bitarray[7] = 8'b110000; + bitarray[1] = 8'b1100; + bitarray[2] = 8'b11001100; + bitarray[3] = 8'b11111100; + bitarray[4] = 8'b11101100; + bitarray[5] = 8'b11100000; + bitarray[6] = 8'b1100000; + bitarray[7] = 8'b1110000; bitarray[8] = 8'b110000; - bitarray[9] = 8'b1110000; - bitarray[10] = 8'b1100000; - bitarray[11] = 8'b11100000; - bitarray[12] = 8'b11101100; - bitarray[13] = 8'b11111100; - bitarray[14] = 8'b11001100; - bitarray[15] = 8'b1100; + bitarray[9] = 8'b110000; + bitarray[10] = 8'b110000; + bitarray[11] = 8'b1101110; + bitarray[12] = 8'b11101110; + bitarray[13] = 8'b11111110; + bitarray[14] = 8'b11101110; + bitarray[15] = 8'b101110; end endmodule @@ -76,7 +81,7 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); wire [3:0] car_bit = car_sprite_xofs>=8 ? 15-car_sprite_xofs: car_sprite_xofs; - wire car_gfx = car_sprite_bits[3'(car_bit)]; + wire car_gfx = car_sprite_bits[car_bit[2:0]]; wire r = display_on && car_gfx; wire g = display_on && car_gfx; @@ -84,3 +89,5 @@ module sprite_bitmap_top(clk, reset, hsync, vsync, rgb); assign rgb = {b,g,r}; endmodule + +`endif diff --git a/presets/verilog/sprite_multiple.v b/presets/verilog/sprite_multiple.v index 998e91c1..012d3417 100644 --- a/presets/verilog/sprite_multiple.v +++ b/presets/verilog/sprite_multiple.v @@ -1,4 +1,5 @@ `include "hvsync_generator.v" +`include "sprite_bitmap.v" `include "sprite_renderer.v" module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); @@ -39,13 +40,13 @@ module sprite_multiple_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); .yofs(car_sprite_yofs), .bits(car_sprite_bits)); - wire player_vstart = {1'0,player_y} == vpos; - wire player_hstart = {1'0,player_x} == hpos; + wire player_vstart = {1'd0,player_y} == vpos; + wire player_hstart = {1'd0,player_x} == hpos; wire player_gfx; wire player_is_drawing; - wire enemy_vstart = {1'0,enemy_y} == vpos; - wire enemy_hstart = {1'0,enemy_x} == hpos; + wire enemy_vstart = {1'd0,enemy_y} == vpos; + wire enemy_hstart = {1'd0,enemy_x} == hpos; wire enemy_gfx; wire enemy_is_drawing; diff --git a/presets/verilog/sprite_renderer.v b/presets/verilog/sprite_renderer.v index fabf9978..302c8638 100644 --- a/presets/verilog/sprite_renderer.v +++ b/presets/verilog/sprite_renderer.v @@ -1,34 +1,8 @@ -`include "hvsync_generator.v" +`ifndef SPRITE_RENDERER_H +`define SPRITE_RENDERER_H -module car_bitmap(yofs, bits); - - input [3:0] yofs; - output [7:0] bits; - - reg [7:0] bitarray[16]; - - assign bits = bitarray[yofs]; - - initial begin/*{w:8,h:16}*/ - bitarray[0] = 8'b1100; - bitarray[1] = 8'b11001100; - bitarray[2] = 8'b11111100; - bitarray[3] = 8'b11101100; - bitarray[4] = 8'b11100000; - bitarray[5] = 8'b1100000; - bitarray[6] = 8'b1110000; - bitarray[7] = 8'b110000; - bitarray[8] = 8'b110000; - bitarray[9] = 8'b110000; - bitarray[10] = 8'b1100111; - bitarray[11] = 8'b11100110; - bitarray[12] = 8'b11111111; - bitarray[13] = 8'b11100110; - bitarray[14] = 8'b1110111; - bitarray[15] = 8'b110000; - end - -endmodule +`include "hvsync_generator.v" +`include "sprite_bitmap.v" module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, gfx, in_progress); @@ -37,7 +11,9 @@ module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, output [3:0] rom_addr; input [7:0] rom_bits; output gfx; - output in_progress = state != WAIT_FOR_VSTART; + output in_progress; + + assign in_progress = state != WAIT_FOR_VSTART; reg [2:0] state; reg [3:0] ycount; @@ -135,9 +111,9 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); car_bitmap car( .yofs(car_sprite_yofs), .bits(car_sprite_bits)); - - wire vstart = {1'0,player_y} == vpos; - wire hstart = {1'0,player_x} == hpos; + + wire vstart = {1'd0,player_y} == vpos; + wire hstart = {1'd0,player_x} == hpos; wire car_gfx; wire unused; @@ -169,3 +145,5 @@ module test_top(clk, hsync, vsync, rgb, hpaddle, vpaddle); assign rgb = {b,g,r}; endmodule + +`endif diff --git a/presets/verilog/sprite_rotation.v b/presets/verilog/sprite_rotation.v index 073bc783..5930a562 100644 --- a/presets/verilog/sprite_rotation.v +++ b/presets/verilog/sprite_rotation.v @@ -1,3 +1,6 @@ +`ifndef SPRITE_ROTATION_H +`define SPRITE_ROTATION_H + `include "hvsync_generator.v" module tank_bitmap(addr, bits); @@ -97,7 +100,7 @@ module tank_bitmap(addr, bits); end endmodule -module sprite_renderer(clk, vstart, load, hstart, rom_addr, rom_bits, +module sprite_renderer2(clk, vstart, load, hstart, rom_addr, rom_bits, hmirror, vmirror, gfx, busy); @@ -262,7 +265,7 @@ module tank_controller(clk, reset, hpos, vpos, hsync, vsync, wire vstart = {1'b0,player_y} == vpos; wire hstart = {1'b0,player_x} == hpos; - sprite_renderer renderer( + sprite_renderer2 renderer( .clk(clk), .vstart(vstart), .load(hsync), @@ -388,3 +391,5 @@ module control_test_top(clk, reset, hsync, vsync, rgb, switches_p1); assign rgb = {b,g,r}; endmodule + +`endif diff --git a/presets/verilog/starfield.v b/presets/verilog/starfield.v index 5fab5e1d..e271042b 100644 --- a/presets/verilog/starfield.v +++ b/presets/verilog/starfield.v @@ -1,7 +1,7 @@ `include "hvsync_generator.v" `include "lfsr.v" -module top(clk, reset, hsync, vsync, rgb); +module starfield_top(clk, reset, hsync, vsync, rgb); input clk, reset; output hsync, vsync; diff --git a/src/assembler.js b/src/assembler.js new file mode 100644 index 00000000..731cf0b9 --- /dev/null +++ b/src/assembler.js @@ -0,0 +1,189 @@ + +EXAMPLE_SPEC = { + vars:{ + reg:{bits:2, toks:['a', 'b', 'ip', 'none']}, + unop:{bits:3, toks:['mova','movb','inc','dec','asl','lsr','rol','ror']}, + binop:{bits:3, toks:['or','and','xor','zero','add','sub','adc','sbb']}, + imm4:{bits:4}, + imm8:{bits:8}, + rel:{bits:8, iprel:true, ipofs:1}, + }, + 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:'lda #~imm8', bits:['01','00','0001',0]}, + {fmt:'ldb #~imm8', bits:['01','01','0001',0]}, + {fmt:'jmp ~imm8', bits:['01','10','0001',0]}, + {fmt:'sta ~imm4', bits:['1001',0]}, + {fmt:'bcc ~rel', bits:['1010','0001',0]}, + {fmt:'bcs ~rel', bits:['1010','0011',0]}, + {fmt:'bz ~rel', bits:['1010','1101',0]}, + {fmt:'bnz ~rel', bits:['1010','0101',0]}, + {fmt:'clc', bits:['10001000']}, + {fmt:'swapab', bits:['10000001']}, + {fmt:'reset', bits:['10001111']}, + ] +} + +function rule2regex(rule, vars) { + var s = rule.fmt; + var varlist = []; + rule.prefix = s.split(/\s+/)[0]; + s = s.replace(/\s+/g, '\\s'); + s = s.replace(/\[/g, '\\['); + s = s.replace(/\]/g, '\\]'); + s = s.replace(/\./g, '\\.'); + s = s.replace(/~\w+/g, function(varname) { + varname = varname.substr(1); + var v = vars[varname]; + varlist.push(varname); + if (!v) + throw Error("Could not find rule for ~" + varname); + else if (v.toks) + return '(\\w+)'; + else + return '([0-9]+|[$][0-9a-f]+|\\w+)'; + }); + rule.re = new RegExp('^'+s+'$', 'i'); + rule.varlist = varlist; + // TODO: check rule constraints + return rule; +} + +var Assembler = function(spec) { + var self = this; + var ip = 0; + var linenum = 0; + var symbols = {}; + var errors = []; + var outwords = []; + var fixups = []; + var width = 8; + + for (var i=0; i> (nb-1-i)*width) & ((1<>3); + var shift = fix.bitofs&7; + var mask = ((1<