読者です 読者をやめる 読者になる 読者になる

FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

HDLのシミュレーション環境の構築

さて、そろそろ自作CPUのシミュレーション環境を構築しよう。 コアの共通部はVerilog-HDLで記述し、デコーダのようなISSと共用できる部分はRubyから自動生成する。

github.com

Verilog-HDLの部分を構築し、デコーダISSから生成させる。

$arch_table[  0] = Array['add     d[15:11],d[25:21],d[20:16]',             '000000', 'XXXXX', 'XXXXX', 'XXXXX', '00000',  '100000', 'ALU',    Array[            'DST_RD', 'R1_RS', 'R2_RT',                    'OP_SIGN_ADD'  ], Array['OPCODE', 'FUNCT', 'SHAMT'], ]
$arch_table[  1] = Array['addi    d[20:16],d[25:21],h[15:0]',              '001000', 'XXXXX', 'XXXXX', 'XXXXX', 'XXXXX',  'XXXXXX', 'ALU',    Array[            'DST_RT', 'R1_RS',            'IMM',           'OP_SIGN_ADD'  ], Array['OPCODE']]
$arch_table[  2] = Array['addiu   d[20:16],d[25:21],h[15:0]',              '001001', 'XXXXX', 'XXXXX', 'XXXXX', 'XXXXX',  'XXXXXX', 'ALU',    Array[            'DST_RT', 'R1_RS',            'IMM',           'OP_USIGN_ADD' ], Array['OPCODE']]
$arch_table[  3] = Array['addu    d[15:11],d[25:21],d[20:16]',             '000000', 'XXXXX', 'XXXXX', 'XXXXX', '00000',  '100001', 'ALU',    Array[            'DST_RD', 'R1_RS', 'R2_RT',                    'OP_USIGN_ADD' ], Array['OPCODE', 'FUNCT', 'SHAMT']]
$arch_table[  4] = Array['clo     d[15:11],d[25:21]',                      '011100', 'XXXXX', 'XXXXX', 'XXXXX', '00000',  '100001', 'ALU',    Array[            'DST_RD', 'R1_RS',                             'OP_COUNT_ONE' ], Array['OPCODE', 'FUNCT', 'SHAMT']]
...

このようなテーブルを記述しておけば、Verilog-HDLを生成する。

module mips_dec (
    input  wire [31: 0] IF_INST,
    output wire [`INST_MAX-1: 0] IF_INST_DEC
);
    assign IF_INST_DEC[`INST_MIPS_ADD] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100000);
    assign IF_INST_DEC[`INST_MIPS_ADDI] = (IF_INST[31:26] == 6'b001000);
    assign IF_INST_DEC[`INST_MIPS_ADDIU] = (IF_INST[31:26] == 6'b001001);
    assign IF_INST_DEC[`INST_MIPS_ADDU] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100001);
    assign IF_INST_DEC[`INST_MIPS_CLO] = (IF_INST[31:26] == 6'b011100) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100001);
    assign IF_INST_DEC[`INST_MIPS_CLZ] = (IF_INST[31:26] == 6'b011100) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100000);
    assign IF_INST_DEC[`INST_MIPS_DIV] = (IF_INST[31:26] == 6'b000000) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b011010);
    assign IF_INST_DEC[`INST_MIPS_DIVU] = (IF_INST[31:26] == 6'b000000) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b011011);
    assign IF_INST_DEC[`INST_MIPS_MADD] = (IF_INST[31:26] == 6'b011100) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b000000);
    assign IF_INST_DEC[`INST_MIPS_MADDU] = (IF_INST[31:26] == 6'b011100) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b000001);
    assign IF_INST_DEC[`INST_MIPS_MSUB] = (IF_INST[31:26] == 6'b011100) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b000100);
    assign IF_INST_DEC[`INST_MIPS_MSUBU] = (IF_INST[31:26] == 6'b011100) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b000101);
    assign IF_INST_DEC[`INST_MIPS_MUL] = (IF_INST[31:26] == 6'b011100) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b000010);
    assign IF_INST_DEC[`INST_MIPS_MULT] = (IF_INST[31:26] == 6'b000000) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b011000);
    assign IF_INST_DEC[`INST_MIPS_MULTU] = (IF_INST[31:26] == 6'b000000) & (IF_INST[15:11] == 5'b00000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b011001);
    assign IF_INST_DEC[`INST_MIPS_SEB] = (IF_INST[31:26] == 6'b011111) & (IF_INST[25:21] == 5'b00000) & (IF_INST[10: 6] == 5'b10000) & (IF_INST[ 5: 0] == 6'b100000);
    assign IF_INST_DEC[`INST_MIPS_SEH] = (IF_INST[31:26] == 6'b011111) & (IF_INST[25:21] == 5'b00000) & (IF_INST[10: 6] == 5'b11000) & (IF_INST[ 5: 0] == 6'b100000);
    assign IF_INST_DEC[`INST_MIPS_SLT] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b101010);
    assign IF_INST_DEC[`INST_MIPS_SLTI] = (IF_INST[31:26] == 6'b001010);
    assign IF_INST_DEC[`INST_MIPS_SLTIU] = (IF_INST[31:26] == 6'b001011);
    assign IF_INST_DEC[`INST_MIPS_SLTU] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b101011);
    assign IF_INST_DEC[`INST_MIPS_SUB] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100010);
    assign IF_INST_DEC[`INST_MIPS_SUBU] = (IF_INST[31:26] == 6'b000000) & (IF_INST[10: 6] == 5'b00000) & (IF_INST[ 5: 0] == 6'b100011);
    assign IF_INST_DEC[`INST_MIPS_B] = (IF_INST[31:26] == 6'b000100) & (IF_INST[25:21] == 5'b00000) & (IF_INST[20:16] == 5'b00000);
    assign IF_INST_DEC[`INST_MIPS_BAL] = (IF_INST[31:26] == 6'b000001) & (IF_INST[25:21] == 5'b00000) & (IF_INST[20:16] == 5'b10001);
    assign IF_INST_DEC[`INST_MIPS_BEQ] = (IF_INST[31:26] == 6'b000100);
    assign IF_INST_DEC[`INST_MIPS_BGEZ] = (IF_INST[31:26] == 6'b000001) & (IF_INST[20:16] == 5'b00001);
    assign IF_INST_DEC[`INST_MIPS_BGEZAL] = (IF_INST[31:26] == 6'b000001) & (IF_INST[20:16] == 5'b10001);
    assign IF_INST_DEC[`INST_MIPS_BGTZ] = (IF_INST[31:26] == 6'b000111) & (IF_INST[20:16] == 5'b00000);
    assign IF_INST_DEC[`INST_MIPS_BLEZ] = (IF_INST[31:26] == 6'b000110) & (IF_INST[20:16] == 5'b00000);
    assign IF_INST_DEC[`INST_MIPS_BLTZ] = (IF_INST[31:26] == 6'b000001) & (IF_INST[20:16] == 5'b00000);
    assign IF_INST_DEC[`INST_MIPS_BLTZAL] = (IF_INST[31:26] == 6'b000001) & (IF_INST[20:16] == 5'b10000);
    assign IF_INST_DEC[`INST_MIPS_BNE] = (IF_INST[31:26] == 6'b000101);
    assign IF_INST_DEC[`INST_MIPS_J] = (IF_INST[31:26] == 6'b000010);
...

制御部の部分も、同様に自動生成している。

module mips_ctrl (
    input wire  [`INST_MAX-1: 0]    IF_INST_DEC,
    input wire  [`INST_B]           IF_INST,
    output reg  [`INST_TYPE_W-1: 0] IF_INST_TYPE,
    output reg  [`INST_CTRL_W-1: 0] IF_INST_CTRL,
    output reg  [`REGADDR_W-1: 0]   IF_DST_ADDR,
    output reg  [`REGADDR_W-1: 0]   IF_R1_ADDR,
    output reg  [`REGADDR_W-1: 0]   IF_R2_ADDR,
    output reg  [`WORD_B]           IF_IMM
);

    always @ (*) begin
        case (1'b1)
          IF_INST_DEC[`INST_MIPS_ADD ] : begin  //ALU
              IF_INST_TYPE <= `INST_TYPE_ALU;
              IF_DST_ADDR  <= IF_INST[`FORMAT_RD_B];
              IF_R1_ADDR   <= IF_INST[`FORMAT_RS_B];
              IF_R2_ADDR   <= IF_INST[`FORMAT_RT_B];
              IF_IMM       <= `WORD_W'hxxxx_xxxx;
              IF_INST_CTRL <= {`CTRL_ALU_DST_RD, `CTRL_ALU_R1_RS, `CTRL_ALU_R2_RT, `CTRL_ALU_OP_SIGN_ADD, 1'b0, 1'b0, 3'b000, 1'b0};
          end
          IF_INST_DEC[`INST_MIPS_ADDI] : begin  //ALU
              IF_INST_TYPE <= `INST_TYPE_ALU;
              IF_DST_ADDR  <= IF_INST[`FORMAT_RT_B];
              IF_R1_ADDR   <= IF_INST[`FORMAT_RS_B];
              IF_R2_ADDR   <= `REGADDR_W'h0;
              IF_IMM       <= {{16{IF_INST[`IMM_W-1]}}, IF_INST[`IMM_B]};
              IF_INST_CTRL <= {`CTRL_ALU_DST_RT, `CTRL_ALU_R1_RS, 1'b0, `CTRL_ALU_OP_SIGN_ADD, `CTRL_ALU_IMM, 1'b0, 3'b000, 1'b0};
          end
          IF_INST_DEC[`INST_MIPS_ADDIU] : begin  //ALU
              IF_INST_TYPE <= `INST_TYPE_ALU;
              IF_DST_ADDR  <= IF_INST[`FORMAT_RT_B];
              IF_R1_ADDR   <= IF_INST[`FORMAT_RS_B];
              IF_R2_ADDR   <= `REGADDR_W'h0;
              IF_IMM       <= {{16{IF_INST[`IMM_W-1]}}, IF_INST[`IMM_B]};

これで、一応シミュレーション環境が生成されるようになった。とりあえずは、ベンチマークを動かして動作検証できるようにしよう。