[Open-graphics] CPU fetch stage

Timothy Normand Miller theosib at gmail.com
Tue Mar 20 10:24:45 EDT 2007


This is all going to evolve quite a lot, but I thought so that we can
avoid getting overwhelmed with too many details, we'd take this one
stage at a time.  Below is a "draft" of Verilog source to the fetch
stage.  If there is anything you don't understand, ask, because that's
what I need to know to comment it properly.

For the timing diagram, next_pc is indented to indicate that it's a
combinatorial result of other values.  The diagram is best viewed with
a fixed font.

// The fetch module loads instructions from the program file.
// It also accepts a branch signal from the decode block
// (Single delay slot)
// Program is only loadable via host interface

/*
Fetch timing diagram:
cycle   0       1       2       3       4

braddr  n/a     n/a     n/a     10      n/a
pc      0       1       2       3       11
next_pc  0       1       2       10      11

instr   (nop)   nop     bsr     filler  ret_addr
insaddr junk    0       1       2       3
retaddr junk    2       3       4       5
*/

module fetch(
    clock,
    reset,

    // Ports for loading a program
    p_load,
    p_addr,
    p_data,

    // Feedback from decode_wb
    branch_reg_val,
    branch_condition,
    branch_address,

    // Forward instruction to decode_wb
    ins_out,
    return_address);

input clock, reset;

// Cause branch
input [1:0] branch_condition;
input [31:0] branch_reg_val;
input [10:0] branch_address;

// Next instruction
output [31:0] ins_out;
output [10:0] return_address;

// Load program from host
input p_load;
input [8:0] p_addr;
input [31:0] p_data;


// Decide if we're going to do a branch
reg do_branch;
wire beqz = branch_reg_val == 0;
wire bneg = branch_reg_val[31];
always @() begin
    // Branch conditions; may alternatively be decoded from a longer
    // opcode word
    // This is for documentation purposes... we can optimize the logic later
    case (branch_condition)
        0: do_branch = 0;                       // no branch
        1: do_branch = 1;                       // unconditional
        2: do_branch = beqz;                    // reg == 0
        3: do_branch = !beqz;                   // reg != 0
        4: do_branch = bneg;                    // reg < 0
        5: do_branch = !bneg;                   // reg >= 0
        6: do_branch = bneg || beqz;            // reg <= 0
        7: do_branch = !bneg && !beqz;          // reg > 0
    endcase
end

reg [8:0] pc;
wire [8:0] next_pc = do_branch ? branch_address : pc;

// Next instruction (ins_out) appears one cycle after its corresponding
// address from next_pc.
RAMB16_S36_S36 dlist_ram (
    .DOA(ins_out), .DOPA(),
    .DOB(), .DOPB(),
    .ADDRA(next_pc),  .CLKA(clock),
    .DIA(32'b0),  .DIPA(4'b0),
    .DIB(p_data),  .DIPB(4'b0),
    .ADDRB(p_addr[8:0]),  .CLKB(clock),
    .ENA(1'b1), .SSRA(1'b0),
    .ENB(1'b1), .SSRB(1'b0),
    .WEA(1'b0), .WEB(p_load));

// Store the PC address we just used (advancing it by one).
always @(posedge clock) pc <= next_pc + 1;

// If this is a subroutine call, we need to pass the return address
// down the pipeline
always @(posedge clock) return_address <= pc + 2;

endmodule

-- 
Timothy Normand Miller
http://www.cse.ohio-state.edu/~millerti
Favorite book:  The Design of Everyday Things, Donald A. Norman, ISBN
0-465-06710-7


More information about the Open-graphics mailing list