jsim3.v
`define OP 2:0
`define PC 11:4
`define RD 14:12
`define RA 18:16
`define RB 22:20
`define IM 35:24
`define OPHALT 3
`define OPLW 41
`define OPSW 42
module jsim3
#(parameter DATA_WIDTH=16, parameter ADDR_WIDTH=5)
(
input clk, reset_n,
output [(ADDR_WIDTH-1):0] addr,
output [2:0] ra, rb, rd,
output [(DATA_WIDTH-1):0] q, qi, qa, qb, qd,
output [47:0] IF,
output reg [47:0] ID,
output reg [(DATA_WIDTH-1):0] ncycles
);
reg we;
single_port_ram dev1(
.data(qb),
.addr(addr),
.we(we),
.clk(clk),
.q(q)
);
reg [(DATA_WIDTH-1):0] ID_qa, ID_qb;
regfile dev2(
.clk(clk),
.we(state==IFE),
.ra(ra),
.qa(qa),
.rb(rb),
.qb(qb),
.rd(rd),
.qd(qd)
);
reg [4:0] pc;
//wire [(DATA_WIDTH-1):0] q;
wire [2:0] opcode;
// Instruction Fetch (IF)
reg [15:0] inst;
reg active;
wire ma2 = (ID[`OPSW] || ID[`OPLW]);
//wire [15:0] qi;
assign qi = (active? (ma2? inst: q): 16'h0000);
assign opcode = qi[15:13];
// opcodes
`include "opcodes.txt"
wire op_add = opcode==ADD;
wire op_nand = opcode==NAND;
wire op_sw = opcode==SW;
wire op_lw = opcode==LW;
wire op_bne = opcode==BNE;
wire op_jalr = opcode==JALR;
wire flag1 = op_sw||op_bne; // no write-back
wire flag2 = op_add||op_nand; // RRR format
wire [2:0] rd1 = flag1? 3'h0: qi[12:10];
assign ra = qi[9:7];
assign rb = flag2? qi[2:0]: (flag1? qi[12:10]: 3'h0);
assign IF[`OP] = opcode;
assign IF[`OPHALT] = (qi==16'he071); // is halt
assign IF[`PC] = pc;
assign IF[`RD] = rd1;
assign IF[`RA] = ra;
assign IF[`RB] = rb;
assign IF[`IM] = qi[9:0];
assign IF[`OPLW] = op_lw;
assign IF[`OPSW] = op_sw;
reg [(ADDR_WIDTH-1):0] jump;
wire memory_access = (IF[`OPSW] || IF[`OPLW]);
wire do_branch = op_bne && (qa!=qb);
wire [4:0] nextpc = pc + 1'b1;
wire [4:0] newpc = nextpc;
//wire [4:0] newpc = (op_jalr||do_branch? jump: nextpc);
reg [4:0] maddr;
assign addr = (state==MEM? d1: newpc );
wire [15:0] d1;
wire [4:0] npc = IF[`PC] + 1'b1;
assign rd = ID[`RD];
alu dev3(
.a(qa),
.b(qb),
.pc({11'h000,npc}),
.im10(ID[`IM]),
.d(d1),
.opcode(ID[`OP])
);
// writeback register multiplexer
assign qd = (ID[`OPLW]? q: d1);
reg [1:0] state;
localparam
RESET = 2'h0,
IFE = 2'h1,
MEM = 2'h2,
HALT = 2'h3;
wire [47:0] BLANK = 48'h0000_0000_0000;
always @(posedge clk, negedge reset_n)
begin
if (!reset_n)
begin
active <= 1'b0;
inst <= 16'h0000;
pc <= 5'h1F;
ID <= BLANK;
state <= RESET;
end
else
case (state)
RESET:
begin
active <= 1'b0;
state <= IFE;
end
IFE:
begin
active <= 1'b1;
pc <= addr;
ID <= IF;
ID_qa <= qa;
ID_qb <= qb;
if (memory_access)
begin
state <= MEM;
//maddr <= d1;
we <= IF[`OPSW];
end
//jump <= op_jalr? qa[(ADDR_WIDTH-1):0]: d1[(ADDR_WIDTH-1):0];
if (ID[`OPHALT]) state <= HALT;
end
MEM:
begin
state <= IFE;
inst <= q;
we <= 1'b0;
end
default:
begin
active <= 1'b0;
state <= HALT;
end
endcase
end
always @(posedge clk or negedge reset_n)
begin
if (!reset_n) ncycles <= 16'h0000;
else if (state==IFE || state==MEM) ncycles <= ncycles + 1'b1;
end
endmodule
alu.v
module alu(
input [15:0] a, b, pc,
input [9:0] im10,
output reg [15:0] d,
input [2:0] opcode
);
`include "opcodes.txt"
wire [15:0] seim = im10[6]? {9'h1FF,im10[6:0]}:{9'h000,im10[6:0]};
wire [15:0] sum = a + seim;
always
case (opcode)
ADD:
d <= a + b;
ADDI:
d <= sum;
NAND:
d <= ~(a&b);
LUI:
d <= {im10,6'h00};
SW:
d <= sum;
LW:
d <= sum;
BNE:
d <= pc+seim;
JALR:
d <= pc;
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=5)
(
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("prog1.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 14 13:47:07 2010
Quartus II Version : 9.0 Build 235 06/17/2009 SP 2 SJ Web Edition
Revision Name : jsim3
Top-level Entity Name : jsim3
Family : Cyclone II
Device : EP2C35F672C6
Timing Models : Final
Total logic elements : 271 / 33,216 ( < 1 % )
Total combinational functions : 258 / 33,216 ( < 1 % )
Dedicated logic registers : 99 / 33,216 ( < 1 % )
Total registers : 99
Total pins : 208 / 475 ( 44 % )
Total virtual pins : 0
Total memory bits : 768 / 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 : 0.275 ns From : reset_n To : we From Clock : -- To Clock : clk Failed Paths : 0 Type : Worst-case tco Slack : N/A Required Time : None Actual Time : 17.235 ns From : regfile:dev2|double_port:port1|altsyncram:ram_rtl_1|altsyncram_eui1:auto_generated|ram_block1a0~portb_address_reg2 To : qd[9] From Clock : clk To Clock : -- Failed Paths : 0 Type : Worst-case th Slack : N/A Required Time : None Actual Time : -0.045 ns From : reset_n To : we From Clock : -- To Clock : clk Failed Paths : 0 Type : Clock Setup: 'clk' Slack : N/A Required Time : None Actual Time : 101.09 MHz ( period = 9.892 ns ) From : regfile:dev2|double_port:port1|altsyncram:ram_rtl_1|altsyncram_eui1:auto_generated|ram_block1a0~portb_address_reg2 To : regfile:dev2|double_port:port2|altsyncram:ram_rtl_0|altsyncram_eui1:auto_generated|ram_block1a0~porta_datain_reg15 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 14 14:10:56 2010