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
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to