【问题标题】:Simple pipelined processor designing issues简单的流水线处理器设计问题
【发布时间】:2014-05-15 14:23:24
【问题描述】:

我正在练习 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

【问题讨论】:

  • 您能谈谈您面临的问题吗?这将使您的问题更加具体。当然,它也会有效地展示你的努力。

标签: mips verilog


【解决方案1】:

一般你不使用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 

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

// 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 块中混合阻塞 (=) 和非阻塞 (&lt;=),但在您更好地理解这样编码的含义之前,我会避免使用。我个人从不混用这两种风格,这样代码更容易阅读。

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

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

always @(posedge CLK) begin
end

【讨论】:

  • “通常你不使用寄存器赋值”有没有一个地方你使用assign 和寄存器?我的印象是,assign 只能用于连续赋值,而不能用于过程(如 always 块)。
  • @Russell,这是一个非常好的问题。帖子本身就是一个问题,我会给你一个答案。
  • 对不可合成的代码有效。它在 IEEE 1364-1995 和顺序版本中称为“程序连续分配”。它正在考虑在未来的 IEEE 1800 版本中贬值。
  • @Morgan 你能不能通过编辑我的代码来展示它?我无法理解你的回答。
猜你喜欢
  • 2014-01-05
  • 2014-08-04
  • 2020-08-07
  • 1970-01-01
  • 2023-01-22
  • 2013-07-10
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多