Verilog:if语句意外行为

时间:2015-11-14 11:29:32

标签: if-statement mips verilog

我正在Verilog中实现MIPS数据路径(行为),当我模拟我的代码时,行为是出乎意料的。 这里显示了BEQ和BNE(如果相等/不相等的分支)指令的情况。 ALU_Out确定两个寄存器是否相等。其中没有这些真正重要,因为我的问题基本上是如何真实地跳过我的状况。所以,我从波形信号中,ALU_out 为零,但 if(ALU_Out == 32'd1)内部发生的任何事情都执行一次。这样我的PC就变成了PC + 6。现在,如果我的ALU_Out实际上等于1,则PC变为PC + 6 + 6(它的1 ==>变为13)我还在if语句中集成了一些kinna标志,并确保它执行一次。 即使我将 else 添加到此,我的标记也清楚地表明如果已经执行了一次。 在BNE的情况下发生同样的事情,并且在if语句执行一次之后检查期望的条件。 你能告诉我这段代码有什么问题吗? 非常感谢提前。

            if (ALU_op == 6'd30)        //BEQ
            begin
                ALU_out = ((ALU_in1) == (ALU_in2));
                if (ALU_out == 32'd1)
                    begin
                        PC = PC + Imm_32;
                    end
            end


        if (ALU_op == 6'd31)        //BNE
            begin
                ALU_out = ((ALU_in1) == (ALU_in2));
                if (ALU_out == 0)
                    begin
                        PC = PC + Imm_32;
                    end
            end

a screen shot of my waveform

UPDATE:仍然没有做任何关于非阻塞分配的事情,但我确实通过在我的代码中添加next_PC来修改我更新PC的方式.If语句问题消失了。然而,问题是当跳转或分支发生时,下一台PC被正确计算但是分支目标处的指令不会被取出相同的时钟! please look at this photo

这应该是一个单周期MIPS处理器,因此应该在一个周期取出并执行一条指令。这就是为什么不希望由非阻塞分配引起的延迟!

always @(*)
    begin
        IR <= Instruction;
    end
always @(posedge clk)
    begin

        PC = next_PC;

        OverFlow = 0;

    end

// Decode + Operand Fetch //    
always @ (IR)
    begin
        Op_code = IR[31:26];
        if (Op_code == 6'd0)        //R-type Instructions
            begin
                Func = IR[5:0];


                if (Func == 6'b100000)  //ADD
                    begin
                        ALU_op = 6'd1;          //as numbered in LAB manual
                        read_addr1 = IR [25:21];    //Rs
                        read_addr2 = IR [20:16];    //Rt

                    end     //end of ADD


                if (Func == 6'b100001)  //ADDU
                    begin
                        ALU_op = 6'd2;          //as numbered in LAB manual
                        read_addr1 = IR [25:21];    //Rs
                        read_addr2 = IR [20:16];    //Rt
                    end     //end of ADDU


                /* some code here skipped to make the code shorter*/

            if (Op_code == 6'b000100)   //BEQ (Branch if Equal)
                begin
                    ALU_op = 6'd30;         //as numbered in LAB manual
                    read_addr1 = IR [25:21];    //Rs
                    read_addr2 = IR [20:16];    //Rt
                    Imm_32 = {{16{IR[15]}},IR [15:0]};  //Offset 2nd operand: imm-32 (Sign Extended Imm_16) 
                    //BT =  PC + Imm_32;
                end


            if (Op_code == 6'b000101)   //BNE (Branch if NOT Equal)
                begin
                    ALU_op = 6'd31;         //as numbered in LAB manual
                    read_addr1 = IR [25:21];    //Rs
                    read_addr2 = IR [20:16];    //Rt 
                    Imm_32 = {{16{IR[15]}},IR [15:0]};  //Offset 2nd operand: imm-32 (Sign Extended Imm_16)  
                end


            if (Op_code == 6'b000001)   
                begin
                    if ( IR [20:16] == 5'b00001)    //BGEZ (Branch on Greater than or Equal to Zero)
                        begin
                            ALU_op = 6'd33;         //as numbered in LAB manual
                            read_addr1 = IR [25:21];    //Rs
                            Imm_32 = {{16{IR[15]}},IR [15:0]};  //Offset 2nd operand: imm-32 (Sign Extended Imm_16)  
                        end


                    if (IR [20:16] == 5'b10000)     //BLTZAL (Branch on less than Zero And Link)
                        begin
                            ALU_op = 6'd34;         //as numbered in LAB manual
                            read_addr1 = IR [25:21];    //Rs
                            Imm_32 = {{16{IR[15]}},IR [15:0]};  //Offset 2nd operand: imm-32 (Sign Extended Imm_16)  
                        end
                end


            if (Op_code == 6'b000010)   //J (Jump)
                begin
                    ALU_op = 6'd35;         //as numbered in LAB manual
                    Imm_32 = {PC [31:26],IR [25:0]};    //Jump Address  
                end


            if (Op_code == 6'b000011)   //JAL (Jump And Link)
                begin
                    ALU_op = 6'd36;         //as numbered in LAB manual
                    Imm_32 = {PC [31:26],IR [25:0]};    //Jump Address  
                end                     


    end // end of DECODE

// Execution & Write Back//

always @ (ALU_op, ALU_in1, ALU_in2)
    begin
        next_PC = PC+1;
        wr_En = 0;  
        DM_wrEn_0 = 0;
        DM_wrEn_1 = 0;
        DM_wrEn_2 = 0;
        DM_wrEn_3 = 0;

        if (ALU_op == 6'd1)     //ADD
            begin
                ALU_out = ALU_in1 + ALU_in2;
                write_addr = IR [15:11];    //Rd
                if( ( (ALU_in1[31]) && (ALU_in2[31]) && (!ALU_out[31]) )||( (!ALU_in1[31]) && (!ALU_in2[31]) && (ALU_out[31]) ) )
                    OverFlow = 1'b1;
                wr_En = 1;
                write_data = ALU_out;                       
            end

        if (ALU_op == 6'd2)     //ADDU
            begin
                ALU_out = ALU_in1 + ALU_in2;
                write_addr = IR [15:11];    //Rd
                wr_En = 1;
                write_data = ALU_out;                   
            end


        /* some code here skipped to make it shorter*/



        if (ALU_op == 6'd30)        //BEQ
            begin
                ALU_out = ((ALU_in1) == (ALU_in2));
                if (ALU_out == 32'd1)
                    begin
                        //PC = PC + Imm_32;
                        next_PC = PC + Imm_32;
                        BT = 32'd56;
                        //PC = BT;
                    end
            end


        if (ALU_op == 6'd31)        //BNE
            begin
                ALU_out = ((ALU_in1) == (ALU_in2));
                if (ALU_out == 0)
                    begin
                        //PC = PC + Imm_32;
                        next_PC = PC + Imm_32;
                        BT = 32'd90;
                    end
            end


        if (ALU_op == 6'd33)        //BGZE
            begin
                ALU_out = ((ALU_in1) >= 0);
                if (ALU_out)
                    begin
                        //PC = PC + Imm_32;
                        next_PC = PC + Imm_32;
                    end
            end


        if (ALU_op == 6'd34)        //BLTZAL
            begin
                ALU_out = ((ALU_in1) < 0);
                if (ALU_out)
                    begin
                        write_addr = 5'd31; //$ra ($31)
                        write_data = PC;
                        wr_En = 1;
                        //PC = PC + Imm_32;
                        next_PC = PC + Imm_32;
                    end
            end


        if (ALU_op == 6'd32)        //JR
            begin
                //PC = ALU_in1;
                next_PC = ALU_in1;
            end


        if (ALU_op == 6'd35)        //J
            begin
                //PC = Imm_32;
                next_PC = Imm_32;
            end


        if (ALU_op == 6'd36)        //JAL
            begin
                write_addr = 5'd31; //$ra
                wr_En = 1;
                write_data = PC;
                //PC = Imm_32;
                next_PC = Imm_32;
            end

    end  //end of EXE and WB always block

1 个答案:

答案 0 :(得分:0)

现在我们知道你希望它是单循环,这可以澄清很多。

首先,您需要确定您的寄存器是否与存储器通信,您是否将地址用于访问寄存器中的指令存储器或生成的指令,因为现在您的always @(*) IR <= Instruction; end和{{1你正在做两者的奇怪组合。你需要做任何一件事:

always @(posedge clk) begin PC = nextPC end

使用always @(posedge clk) begin IR <= Instruction; PC <= nextPC; end 或:

寻址指令存储器
nextPC

always @(posedge clk) begin PC <= nextPC; end assign IR = Instruction; 寻址指令存储器。请注意,Morgan评论从内存中读取应该花费一个周期通常是正确的,但是,我们假设您有某种组合读取内存,不需要锁存地址和输出/输入。在实际系统中,您确实应该准备好将地址和输入/输出总线上的寄存器存储到存储器中。

其他一些风格笔记:

  • 最好不要编写自己的敏感度列表,使用PC,而不是always @(*)用于组合逻辑(使用always @(IR)进行顺序逻辑。
  • always @(posedge clk)(连续)区块中使用阻止分配(=)和always @(*)(连续)区块中的NBA(<=)。
  • 使用案例语句而不是always @(posedge clk)的长列表来解码操作码。它更容易阅读
  • 我建议用参数或宏替换操作码,以便代码读取更容易(比如if .. if .. if ..而不是if (op == 6'b001001),你得到parameter ALU_ADD = 6'b001001; ... if (op == ALU_ADD),它更清晰;在案例中更好case (op) ALU_ADD: ... ALU_SUB: ... ALU_OR: ... endcase