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)