さて、そろそろ自作CPUのシミュレーション環境を構築しよう。 コアの共通部はVerilog-HDLで記述し、デコーダのようなISSと共用できる部分はRubyから自動生成する。
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]};
これで、一応シミュレーション環境が生成されるようになった。とりあえずは、ベンチマークを動かして動作検証できるようにしよう。