简单的流水线处理器设计问题

时间:2014-05-15 14:23:25

标签: mips verilog

我正在练习Verilog HDL编程,我无法解决这个简单的5阶段流水线处理器的问题。 我面临的问题是在LD指令中,它将来自存储器的双字加载到寄存器中。我无法保存每个阶段的输出数据。如何保存下一阶段的输出数据? 你能否在下面的代码中指出我的错误:

module Processor(
    input CLK,
    input [31:0] Instruction,
    input [63:0] Data_In,
    output [31:0] Inst_Addr,
    output [31:0] Data_Addr,
    output [63:0] Data_Out,
    output Mem_Read,
    output Mem_Write
);

////////////////////////////////////////////

reg[31:0] pc;
reg[31:0] regs[0:31];

reg[31:0] stage1;

reg[31:0] data_addr;
reg[63:0] data_out;
reg[63:0] data_in;
reg[31:0] inst;

reg [5:0] funct;
reg [5:0] opcode;
reg [4:0] rs;
reg [4:0] rt;
reg [4:0] rd;
reg [15:0] imm;
reg [4:0] shamt;    
reg [1:0] inst_type;

reg [31:0] rs_value;
reg [31:0] rt_value;
reg [31:0] rd_value;
reg mem_read, mem_write;

initial begin
    pc = 0;
end

assign Inst_Addr = pc;

always @ (posedge CLK) begin    
    /////////////IF//////////////////////////////
    pc = pc + 4;
    $display("%h Fetched instruction: %h", Inst_Addr, Instruction);
    stage1 = Instruction;
    //////////////ID//////////////////////////////  

    opcode[5:0] = stage1[31:26];

    case(opcode)
        0:
            begin /* R-type */
                assign rs = stage1[25:21];
                assign rt = stage1[20:16];
                assign rd = stage1[15:11];
                assign shamt = stage1[10:6];
                assign inst_type = 2'b00;
            end
        default:
            begin /* I type */
                assign rs = stage1[25:21];
                assign rt = stage1[20:16];
                assign shamt = stage1[10:6];
                assign imm = stage1[15:0];
                assign inst_type = 2'b01;
            end
    endcase

    assign funct = stage1[5:0];

    /////////////EX////////////////////////////////




    // Fetching operands
    assign rs_value = regs[rs];
    assign rt_value = regs[rt]; 

    // Performing operations
    assign data_in = Data_In; // LD 

    case(inst_type)
        2'b00: /* R-type */
            begin
                case(funct)
                    6'h20: /* DADD */
                        begin
                            assign rd_value = rs_value + rt_value;
                        end
                    6'h22: /* DSUB */
                        begin
                            assign rd_value = rs_value - rt_value;
                        end
                    6'h26: /* XOR */
                        begin
                            assign rd_value = ~ (rs_value | rt_value);
                        end
                endcase
            end
        2'b01: /* I-type */
            begin
                case(opcode)
                    6'b110111: /* LD */
                        begin
                            assign data_addr = rs + imm;
                            assign rt_value = data_in;                      
                            assign mem_read = 1;
                            assign mem_write = 0;
                        end
                    6'b111111: /* SD */
                        begin
                            assign data_out = rt_value;
                            assign data_addr = rs + imm;
                            assign mem_write = 1;
                            assign mem_read = 0;
                        end
                    6'b011000: /* DADDI */
                        begin
                            assign rt_value = rs_value + imm;
                        end
                endcase
            end
    endcase

    //LD, SD,DADD, DSUB, XOR, DADDI, HALT           



    ///////////////WB///////////////////////////////

    case(inst_type)
        2'b00: /* R-type */
            begin
                regs[rd] = rd_value;
            end
        2'b01: /* I-type */
            begin
                case(opcode)    
                    6'b110111: /* LD */
                        begin
                            regs[rt] = rt_value;
                        end
                    6'b011000: /* DADDI */
                        begin
                            regs[rt] = rt_value;
                        end
                endcase
            end
    endcase
end

//////////////MEM//////////////////////////////

    assign Data_Addr = data_addr;

    assign Data_Out = data_out; // SD
    assign Mem_Write = mem_write; 


    assign Mem_Read = mem_read; 


////////////////////////////////////////////////
endmodule

1 个答案:

答案 0 :(得分:2)

通常,您不会将assign与寄存器一起使用,而是valid cases explained here。以下不是其中之一:

reg data_in;
always @* begin 
  assign data_in = Data_In; // LD 
end

应该是:

reg data_in;
always @* begin 
  data_in = Data_In; // LD 
end 

您的大多数变量赋值都发生在边缘触发的块内(隐含的触发器)。在这种情况下,您应该使用非阻塞分配(<=)。你最终得到的是:

reg data_in;
always @(posedge clk) begin 
  data_in <= Data_In; // LD 
end 

我怀疑设计的某些部分(下方)应放入一个单独的组合部分,以便它们与地址解码器并行工作,而不会受到延迟的影响。

// Fetching operands
assign rs_value = regs[rs];
assign rt_value = regs[rt]; 

以下是更详细的内容

always @ (posedge CLK) begin    
//...

case(opcode)
  0: begin /* R-type */
    assign rs        = stage1[25:21];
    assign rt        = stage1[20:16];
    assign rd        = stage1[15:11];
    assign shamt     = stage1[10:6];
    assign inst_type = 2'b00;
  end
  default: begin /* I type */
    assign rs        = stage1[25:21];
    assign rt        = stage1[20:16];
    assign shamt     = stage1[10:6];
    assign imm       = stage1[15:0];
    assign inst_type = 2'b01;
  end
endcase
//...

应该是:

always @ (posedge CLK) begin    
//..

case(opcode)
  0: begin /* R-type */
    rs        <= stage1[25:21];
    rt        <= stage1[20:16];
    rd        <= stage1[15:11];
    shamt     <= stage1[10:6];
    inst_type <= 2'b00;
  end
  default: begin /* I type */
    rs        <= stage1[25:21];
    rt        <= stage1[20:16];
    shamt     <= stage1[10:6];
    imm       <= stage1[15:0];
    inst_type <= 2'b01;
  end
endcase
//...

虽然可以在边缘触发=块中混合阻塞(<=)和非阻塞(always),但我会避免直到你更好地理解这样编码的含义。我个人从不混合这两种风格,以便代码更容易阅读。

因此,我将分离出在同一周期(组合)中发生的任何代码。这方面的一个例子是将以下内容与时钟进程并行添加。

always @* begin
  // Fetching operands
  rs_value = regs[rs];
  rt_value = regs[rt];
end

always @(posedge CLK) begin
end