// basic sizes of things `define DATA [15:0] `define ADDR [15:0] `define SIZE [65535:0] `define INST [15:0] `define CC [15:14] `define OP [14:9] `define IORR [8] `define RD [7:4] `define RN [3:0] `define STATE [4:0] `define REGS [15:0] `define PC r[15] // CC values `define AL 0 `define S 1 `define NE 2 `define EQ 3 // opcode values, also state numbers `define OPPRE 5'h00 `define OPADD 5'h08 `define OPAND 5'h09 `define OPBIC 5'h0a `define OPEOR 5'h0b `define OPMUL 5'h0c `define OPORR 5'h0d `define OPSHA 5'h0e `define OPSLT 5'h0f `define OPSUB 5'h10 `define OPADDF 5'h11 `define OPFTOI 5'h12 `define OPITOF 5'h13 `define OPMULF 5'h14 `define OPRECF 5'h15 `define OPSUBF 5'h16 `define OPMOV 5'h17 `define OPNEG 5'h18 `define OPLDR 5'h19 `define OPSTR 5'h1a `define OPSYS 5'h1f // state numbers (unused OP values) `define Start 5'h01 // not used as opcode `define Decode 5'h02 // not used as opcode `define Done 5'h03 // not used as opcode module processor(halt, reset, clk); output reg halt; input reset, clk; reg `DATA r `REGS; // register file reg `DATA d `SIZE; // data memory reg `INST i `SIZE; // instruction memory reg `INST ir; reg `STATE s; reg [11:0] prefix; reg sex; // sign extend immediates? wire `DATA immed; wire `STATE op2state; reg zero; reg `DATA op2; reg `ADDR nextpc; always @(reset) begin halt <= 0; `PC <= 0; sex <= 1; s <= `Start; // use the following with dollars to initialize //readmemh0(r); // register file //readmemh1(d); // data memory //readmemh2(i); // instruction memory end assign immed = {(sex ? {12{ir[3]}} : prefix), ir `RN}; assign op2state = {ir[13:12] ? ir `OP : OPPRE}; always @(posedge clk) begin case (s) `Start: begin ir <= i[`PC]; s <= `Decode; end `Decode: begin case (ir `CC) `AL: s <= op2state; `S: s <= op2state; `NE: if (zero) begin `PC <= `PC + 1; s <= `Start; end else s <= op2state; `EQ: if (!zero) begin `PC <= `PC + 1; s <= `Start; end else s <= op2state; endcase op2 <= (ir `IORR ? immed : r[ir `RN]); sex <= (ir `IORR ? 1 : sex); end `OPPRE: begin prefix <= ir[11:0]; sex <= 0; `PC = `PC + 1; s <= `Start; end `OPADD: begin r[ir `RD] <= r[ir `RD] + op2; s <= `Done; end `OPAND: begin r[ir `RD] <= r[ir `RD] & op2; s <= `Done; end `OPBIC: begin r[ir `RD] <= r[ir `RD] & ~op2; s <= `Done; end `OPEOR: begin r[ir `RD] <= r[ir `RD] ^ op2; s <= `Done; end `OPMUL: begin r[ir `RD] <= r[ir `RD] * op2; s <= `Done; end `OPORR: begin r[ir `RD] <= r[ir `RD] | op2; s <= `Done; end `OPSHA: begin r[ir `RD] <= (op2[15] ? (r[ir `RD] >> -op2) : (r[ir `RD] << op2)); s <= `Done; end `OPSLT: begin r[ir `RD] <= r[ir `RD] < op2; s <= `Done; end `OPSUB: begin r[ir `RD] <= r[ir `RD] - op2; s <= `Done; end `OPMOV: begin r[ir `RD] <= op2; s <= `Done; end `OPNEG: begin r[ir `RD] <= -op2; s <= `Done; end `OPLDR: begin r[ir `RD] <= d[op2]; s <= `Done; end `OPSTR: begin d[op2] <= r[ir `RD]; s <= `Done; end `Done: begin if (ir `CC == `S) zero <= (r[ir `RD] == 0); if (ir `RD != 15) `PC <= `PC + 1; s <= `Start; end default: begin halt <= 1; end // SYS, etc. endcase end endmodule module testbench; reg reset = 0; reg clk = 0; wire halted; processor PE(halted, reset, clk); initial begin $dumpfile; $dumpvars(0, PE); #10 reset = 1; #10 reset = 0; while (!halted) begin #10 clk = 1; #10 clk = 0; end $finish; end endmodule