【问题标题】:Simulating MIPS processor on FPGA using Verilog使用 Verilog 在 FPGA 上模拟 MIPS 处理器
【发布时间】:2012-04-08 15:02:32
【问题描述】:

我正在尝试使用 Verilog 在 FPGA 上模拟一个简单的 MIPS 处理器。这是我的代码:

module MIPS_Processor(output reg[7:0] LEDs, input[7:0] Switches);
    reg [31:0] memory[0:4095];   // 4K memory cells that are 32 bits wide
    reg [31:0] code[0:1023];     // 1K memory cells that are 32 bits wide
    reg [31:0] registers[0:31];  // 32 registers that are 32 bits wide
    reg [31:0] PC;               // The program counter

    reg [31:0] instruction;
    reg [5 :0] op;
    reg [4 :0] rs;
    reg [4 :0] rt;
    reg [4 :0] rd;
    reg [4 :0] shamt;
    reg [5 :0] funct;
    reg signed [15:0] immediate_offset;
    reg [25:0] target;

    reg [1:0] instruction_type; // 00 --> R | 01 --> I | 10 --> J | 11 --> EXTRA

    reg [31:0] rs_value;
    reg [31:0] rt_value;
    reg [31:0] rd_value;

    initial
        begin
            PC = 0;

            /* Here we insert the code in the code array */
            code[0] = 32'b00010010000000000000000000000000; // start : input  s0   # read switches.
            code[1] = 32'b00010010000000000000000000000001; //         output s0   # write leds.
            code[2] = 32'b00001000000000000000000000000000; //         j      start
            code[3] = 32'b00000100000000000000000000000000; // END OF CODE
        end

    always
        begin : loop_block
            // 1. Fetch an instruction from memory
            instruction = code[PC];

            // 2. Increment the program counter register (by the instruction length)
            PC = PC + 1;

            // 3. Decode the instruction
            /*
                The instructions are:
                                            6   5    5    5    5    6
                                           _____________________________
                or    rd, rs, rt           | 0 | rs | rt | rd | 0 | 0x25 |

                                             6    5    5        16
                                           _____________________________
                ori  rt, rs, immediate    | 0xd | rs | rt |  immediate  |

                                            6   5    5    5    5    6
                                           _____________________________
                and  rd, rs, rt           | 0 | rs | rt | rd | 0 | 0x24 |

                                             6    5    5        16
                                           _____________________________
                andi rt, rs, immediate    | 0xc | rs | rt |  immediate  |

                                            6   5    5         16
                                           _____________________________
                beq  rs, rt, offset       | 4 | rs | rt |    offset     |

                                            6   5    5    5    5    6
                                           _____________________________
                sub  rd, rs, rt           | 0 | rs | rt | rd | 0 | 0x22 |

                                            6   5    5    5    5    6
                                           _____________________________
                add  rd, rs, rt           | 0 | rs | rt | rd | 0 | 0x20 |

                                            6    5    5       16
                                           _____________________________
                addi rt, rs, immediate    | 8 | rs | rt |   immediate   |

                                            6             26
                                           _____________________________
                j    target               | 2 |         target          |

                                            6   5    5    5    5    6
                                           _____________________________
                slt  rd, rs, rt           | 0 | rs | rt | rd | 0 | 0x2a |

                                             6     5    5        16
                                           _____________________________
                lw   rt, rs[offset]       | 0x23 | rs | rt |   offset   |

                                             6     5    5        16
                                           _____________________________
                sw   rt, rs[offset]       | 0x2b | rs | rt |   offset   |


                ::EXTRA INSTRUCTIONS::

                                            6    5            21
                                           _____________________________
                input  rs                 | 4 |  rs  |        0         |

                                            6    5            21
                                           _____________________________
                output rs                 | 4 |  rs  |        1         |

            */
            op[5:0] = instruction[31:26];
            case(op)
                0: /* R-type */
                    begin
                        rs = instruction[25:21];
                        rt = instruction[20:16];
                        rd = instruction[15:11];
                        shamt = instruction[10:6];
                        funct = instruction[5:0];
                        instruction_type = 2'b00;
                    end

                1: /* END OF CODE */
                    begin
                        disable loop_block;
                    end

                2: /* J-type */
                    begin
                        target = instruction[25:0];
                        instruction_type = 2'b10;
                    end

                4: /* EXTRA */
                   begin
                        rs = instruction[25:21];
                        funct = instruction[20:0];
                        instruction_type = 2'b11;
                    end

                default: /* I-type */
                    begin
                        rs = instruction[25:21];
                        rt = instruction[20:16];
                        immediate_offset = instruction[15:0];
                        instruction_type = 2'b01;
                    end
            endcase


            // 4. Fetch operands, if any, usually from registers
            case(instruction_type)
                2'b00: /* R-type */
                    begin
                        rs_value = registers[rs];
                        rt_value = registers[rt];
                    end

                2'b01: /* I-type */
                    begin
                        rs_value = registers[rs];
                    end
                2'b11: /* EXTRA */
                    begin
                        if(funct == 1) rs_value = registers[rs];
                    end
            endcase

            // 5. Perform the operation
            case(instruction_type)
                2'b00: /* R-type */
                    begin
                        case(funct)
                            2'h20: /* add  rd, rs, rt */
                                begin
                                    rd_value = rs_value + rt_value;
                                end
                            2'h22: /* sub  rd, rs, rt */
                                begin
                                    rd_value = rs_value - rt_value;
                                end
                            2'h24: /* and  rd, rs, rt */
                                begin
                                    rd_value = rs_value & rt_value;
                                end
                            2'h25: /* or    rd, rs, rt */
                                begin
                                    rd_value = rs_value | rt_value;
                                end
                            2'h2a: /* slt  rd, rs, rt */
                                begin
                                    rd_value = rs_value < rt_value? 1 : 0;
                                end
                        endcase
                    end

                2'b01: /* I-type */
                    begin
                        case(op)
                            4: /* beq  rs, rt, offset */
                                begin
                                    if(rs_value < rt_value) PC = immediate_offset;
                                end
                            8: /* addi rt, rs, immediate */
                                begin
                                    rt_value = rs_value + immediate_offset;
                                end
                            1'hc: /* andi rt, rs, immediate */
                                begin
                                    rt_value = rs_value & immediate_offset;
                                end
                            1'hd: /* ori  rt, rs, immediate */
                                begin
                                    rt_value = rs_value | immediate_offset;
                                end
                            2'h23: /* lw   rt, rs[offset] */
                                begin
                                    rt_value = memory[rs + immediate_offset];
                                end
                            2'h2b: /* sw   rt, rs[offset] */
                                begin
                                    memory[rs + immediate_offset] = rt_value;
                                end
                        endcase
                    end

                2'b10: /* J-type */
                    begin
                        case(op)
                            2: /* j    target */
                                begin
                                    PC = target;
                                end
                        endcase
                    end

                2'b11: /* EXTRA */
                    begin
                        case(funct)
                            0: /* input  rs */
                                begin
                                    rs_value[7:0] = Switches;
                                end

                            1: /* output rs */
                                begin
                                    LEDs = rs_value[7:0];
                                end
                        endcase
                        if(funct == 1) rs_value = registers[rs];
                    end
            endcase

            // 6. Store the results
            case(instruction_type)
                2'b00: /* R-type */
                    begin
                        registers[rd] = rd_value;
                    end
                2'b01: /* I-type */
                    begin
                        case(op)
                            8: /* addi rt, rs, immediate */
                                begin
                                    registers[rt] = rt_value;
                                end
                            1'hc: /* andi rt, rs, immediate */
                                begin
                                    registers[rt] = rt_value;
                                end
                            1'hd: /* ori  rt, rs, immediate */
                                begin
                                    registers[rt] = rt_value;
                                end
                            2'h23: /* lw   rt, rs[offset] */
                                begin
                                    registers[rt] = rt_value;
                                end
                        endcase
                    end
                2'b11: /* EXTRA */
                    begin
                        if(funct == 0) registers[rs] = rs_value;
                    end
            endcase

            #100; /* Delay */

        end
endmodule

我已将output reg[7:0] LEDs 连接到 FPGA 设备上的 8 个 LED 上,并将input[7:0] Switches 连接到 FPGA 的 8 个开关上。代码编译没有任何错误。但不幸的是,它不起作用。 LED 应显示开关的状态,但它们始终处于关闭状态。

但是,当我尝试在 initial 块内硬编码 LED 状态(如 LEDs[7:0] = 8'b11111111;)时,LED 一直保持打开状态。当我将LEDs[7:0] = 8'b11111111; 放在always 块内时,LED 一直保持关闭状态。 FPGA 似乎没有执行always 块内的代码,这是怎么回事?我是否以错误的方式实施设计?

【问题讨论】:

  • 如果我理解您的意思,您是在尝试将其放入实际的 FPGA 中……我不是硬件工程师,但是 -- 你的时钟在哪里来驱动 always 块?您使用 #100 但这不是可合成的......所以我认为您的 always 块不能在硬件中运行。 (再说一遍——我不是硬件工程师,而且我的 Verilog 经验是有限且古老的。)除此之外,如果我站在你的立场上,我会将instruction 寄存器附加到我将逻辑分析仪附加到的输出上,所以代码甚至被加载到处理器中,我感到很舒服。
  • @mah 我忘了提到我正在尝试实现行为设计,所以我虽然不需要时钟。
  • 看看this。行为设计意味着您可以处理通过模块的数据流,而不是简单地将门和电线连接在一起,并自动推断出必要的电路。但对于 CPU 设计,该数据通常由时钟信号驱动。

标签: simulation mips verilog fpga hdl


【解决方案1】:

您可以使用 Verilog 模拟器来模拟此代码,但您将无法合成此代码并将其加载到 FPGA 上。正如 cmets 所说,用于 FPGA 的可综合 Verilog 代码将具有时钟。它应该有这样的结构

always @* begin : combinational_logic
    //...
end

always @(posedge clk) begin : sequential_logic
    //...
end

【讨论】:

    【解决方案2】:

    您的代码数组的内容看起来也有问题。数组反汇编为:

    BEQ     $16, $0, 0x4
    BEQ     $16, $0, 0x8
    J       0x0
    BLTZ    $0, 0x4
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多