Project: dsim2

John Loomis

Contents

Verilog Files

dsim2.v
alu.v
regfile.v
single_port_ram.v

Quartus Files

fit.summary
tan.summary

Verilog Files

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

Quartus Compilation Summary

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