dsim2.v
module dsim2
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=8)
(
input clk, reset_n, recycle,
output [(ADDR_WIDTH-1):0] addr,
output we,
output [2:0] rd,
output [(DATA_WIDTH-1):0] q, qd,
output reg [7:0] pc,
output [(DATA_WIDTH-1):0] qi,
output ma, rwe
);
wire [2:0] ra, rb;
wire [(DATA_WIDTH-1):0] qa, qb;
single_port_ram dev1(
.data(qa),
.addr(addr[6:0]),
.we(we),
.clk(clk),
.q(q)
);
regfile dev2(
.clk(clk),
.ra(ra), .rb(rb), .rd(rd),
.qa(qa), .qb(qb), .qd(qd),
.we(rwe)
);
//reg [7:0] pc;
assign rwe = state==WB;
wire [4:0] opcode;
reg [15:0] inst;
assign qi = (state==ID? q: inst);
assign opcode = qi[15:11];
wire [7:0] immed = qi[7:0];
reg [2:0] state;
localparam
IF = 3'h0,
ID = 3'h1,
EX = 3'h2,
MEM = 3'h3,
WB = 3'h4,
HALT = 3'h7;
`include "opcodes.txt"
wire op_sw = opcode==SW || opcode==SWI;
wire op_lw = opcode==LW || opcode==LWI;
wire op_lui = opcode==LUI;
wire op_bne = opcode==BNE;
wire op_jalr = opcode==JALR;
assign we = (state==MEM) && op_sw;
assign ma = (op_sw || op_lw); // memory_access
assign rd = (op_sw||op_bne? 3'h0: qi[10:8]);
assign ra = (op_lui||op_bne? qi[10:8]: qi[7:5]);
assign rb = (op_sw? qi[10:8]: op_bne? qi[7:5]: qi[4:2]);
wire do_branch = op_bne && (qa!=qb);
reg [7:0] jump;
wire [7:0] nextpc = pc + 1'b1;
wire [7:0] newpc = (op_jalr||do_branch? jump: nextpc);
assign addr = (state==MEM? qt[7:0]: newpc);
// ALU
wire [15:0] qt;
alu dev3(
.a(qa),
.b(qb),
.nextpc(nextpc),
.imm8(immed),
.d(qt),
.opcode(opcode)
);
// writeback register multiplexer
assign qd = (op_lw? q: qt);
always @(posedge clk, negedge reset_n)
begin
if (!reset_n)
begin
pc <= 8'hFF;
state <= IF;
end
else
case (state)
IF:
begin
state <= ID;
pc <= addr;
end
ID:
begin
// save results of IF phase
inst <= q;
state <= EX;
end
EX:
begin
jump <= op_jalr? qa[7:0]: qt[7:0];
if (inst == 16'h0000) state <= HALT;
else if (ma)
state <= MEM;
else
state <= WB;
end
MEM:
begin
state <= WB;
end
WB:
begin
state <= IF;
end
HALT:
begin
if (recycle)
begin
pc <= 8'hFF;
state <= IF;
end
else state <= HALT;
end
default:
state <= HALT;
endcase
end
endmodule
alu.v
module alu(
input [15:0] a, b,
input [7:0] nextpc,
input [7:0] imm8,
output reg [15:0] d,
input [4:0] opcode
);
`include "opcodes.txt"
wire [15:0] immse = imm8[7]? {8'hFF,imm8}:{8'h00,imm8};
wire [15:0] imm = {8'h00,imm8};
//wire [15:0] sum1 = a + immse;
wire [15:0] seim = imm8[4]? {11'h7FF, imm8[4:0]} : {11'h000, imm8[4:0]};
wire [15:0] sum = a + seim;
wire [1:0] opx = imm8[1:0];
reg [15:0] alu1, alu2;
always
case (opx)
0: alu1 <= a + b;
1: alu1 <= a - b;
default: alu1 <= 16'h0;
endcase
always
case (opx)
0: alu2 = a & b;
1: alu2 = a | b;
2: alu2 = a ^ b;
3: alu2 = ~(a|b);
endcase
always
case (opcode)
LWI:
d <= imm;
SWI:
d <= imm;
LI:
d <= immse;
LUI:
d <= {imm8, a[7:0]};
LW:
d <= sum;
SW:
d <= sum;
ADDI:
d <= sum;
ALU1:
d <= alu1;
ALU2:
d <= alu2;
BNE:
d <= {8'h00, nextpc+seim[7:0]};
JALR:
d <= {8'h00, nextpc};
default:
d <= 16'h0000;
endcase
endmodule
regfile.v
// The register file is a triple-port RAM
// with two read addresses and a write address.
// It is implemented with two double-port RAMs
module regfile
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=3)
(
input clk,
input [(ADDR_WIDTH-1):0] ra, rb, rd,
output [(DATA_WIDTH-1):0] qa, qb,
input [(DATA_WIDTH-1):0] qd,
input we
);
double_port port1(
.clk(clk),
.we(we),
.ra(ra),
.rd(rd),
.qa(qa),
.qd(qd)
);
double_port port2(
.clk(clk),
.we(we),
.ra(rb),
.rd(rd),
.qa(qb),
.qd(qd)
);
endmodule
module double_port
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=3)
(
input [(DATA_WIDTH-1):0] qd,
input [(ADDR_WIDTH-1):0] ra, rd,
input we, clk,
output [(DATA_WIDTH-1):0] qa
);
// Declare the RAM variable
reg [DATA_WIDTH-1:0] ram[0:2**ADDR_WIDTH-1];
// Initialize the RAM with $readmemb. Put the memory contents
// in the data file. Without this file,
// this design will not compile.
// See Verilog LRM 1364-2001 Section 17.2.8 for details on the
// format of this file.
initial
begin
$readmemh("registers.txt", ram);
end
// Variable to hold the registered read address
reg [ADDR_WIDTH-1:0] ra_reg;
always @ (posedge clk)
begin
// Write
if (we)
ram[rd] <= qd;
end
always @ (posedge clk)
ra_reg <= ra;
// Continuous assignment implies read returns NEW data.
// This is the natural behavior of the TriMatrix memory
// blocks in Single Port mode.
assign qa = (ra_reg? ram[ra_reg]:16'h0000);
endmodule
single_port_ram.v
// Quartus II Verilog Template
// Single port RAM with single read/write address
module single_port_ram
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=7)
(
input [(DATA_WIDTH-1):0] data,
input [(ADDR_WIDTH-1):0] addr,
input we, clk,
output [(DATA_WIDTH-1):0] q
);
// Declare the RAM variable
reg [DATA_WIDTH-1:0] ram[0:2**ADDR_WIDTH-1];
// Initialize the RAM with $readmemb. Put the memory contents
// in the file single_port_rom_init.txt. Without this file,
// this design will not compile.
// See Verilog LRM 1364-2001 Section 17.2.8 for details on the
// format of this file.
initial
begin
$readmemh("ram_init.txt", ram);
end
// Variable to hold the registered read address
reg [ADDR_WIDTH-1:0] addr_reg;
always @ (posedge clk)
begin
// Write
if (we)
ram[addr] <= data;
addr_reg <= addr;
end
// Continuous assignment implies read returns NEW data.
// This is the natural behavior of the TriMatrix memory
// blocks in Single Port mode.
assign q = ram[addr_reg];
endmodule
fit.summary
Fitter Status : Successful - Wed Apr 06 22:21:59 2011
Quartus II Version : 9.0 Build 235 06/17/2009 SP 2 SJ Web Edition
Revision Name : dsim2
Top-level Entity Name : dsim2
Family : Cyclone II
Device : EP2C35F672C6
Timing Models : Final
Total logic elements : 520 / 33,216 ( 2 % )
Total combinational functions : 504 / 33,216 ( 2 % )
Dedicated logic registers : 172 / 33,216 ( < 1 % )
Total registers : 172
Total pins : 73 / 475 ( 15 % )
Total virtual pins : 0
Total memory bits : 2,048 / 483,840 ( < 1 % )
Embedded Multiplier 9-bit elements : 0 / 70 ( 0 % )
Total PLLs : 0 / 4 ( 0 % )
tan.summary-------------------------------------------------------------------------------------- Timing Analyzer Summary -------------------------------------------------------------------------------------- Type : Worst-case tsu Slack : N/A Required Time : None Actual Time : 3.358 ns From : reset_n To : jump[5] From Clock : -- To Clock : clk Failed Paths : 0 Type : Worst-case tco Slack : N/A Required Time : None Actual Time : 17.486 ns From : single_port_ram:dev1|altsyncram:ram_rtl_0|altsyncram_rjb1:auto_generated|ram_block1a0~porta_address_reg6 To : qd[10] From Clock : clk To Clock : -- Failed Paths : 0 Type : Worst-case th Slack : N/A Required Time : None Actual Time : -0.292 ns From : reset_n To : inst[13] From Clock : -- To Clock : clk Failed Paths : 0 Type : Clock Setup: 'clk' Slack : N/A Required Time : None Actual Time : 87.84 MHz ( period = 11.384 ns ) From : single_port_ram:dev1|altsyncram:ram_rtl_0|altsyncram_rjb1:auto_generated|ram_block1a0~porta_address_reg6 To : regfile:dev2|double_port:port1|ram~75 From Clock : clk To Clock : clk Failed Paths : 0 Type : Total number of failed paths Slack : Required Time : Actual Time : From : To : From Clock : To Clock : Failed Paths : 0 --------------------------------------------------------------------------------------
Maintained by John Loomis, last updated Wed Apr 06 22:44:14 2011