FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MIPS用ISSの実装とRISC-Vとの共用

RISC-V用のISSを実装しているが、それをMIPS用にも活用したい。C++で記述しているので、継承を利用すれば、筋が良く実装することができそうだ。

github.com

MIPS用のVerilog-HDLハードウェアデコーダを生成していたので、それに合わせてISS用のデコーダも生成する。

テーブルは、全てRubyで記述した命令テーブルに格納している。

github.com

#                       ['BITFIELD'                                        31-26,    25-21,   20-16    15-11    10-06     05-00                                                                    ]
#                       ['DECODE-KEY',                                     'OPCODE', 'RS'     'RT',    'RD',    'SHAMT',  'FUNCT'   'TYPE'    'KEY_TABLE'                                          ]
$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']]
...

デコードテーブルと、デコードに必要な情報、ハードウェア制御信号の生成に必要な情報を格納している。 これによって、ある程度の命令のテンプレートを自動生成する。

class MipsEnv;

class InstEnv {

private:
    MipsEnv *m_env;

public:
    InstEnv (MipsEnv *env);

    typedef void (InstEnv::*InstFunc) (Word_t inst_hex);
    static const InstFunc m_inst_exec_func[];

    void MIPS_Inst_Exec (uint32_t index, Word_t inst_hex);

    void MIPS_INST_ADD (Word_t inst_hex);
    void MIPS_INST_ADDI (Word_t inst_hex);
    void MIPS_INST_ADDIU (Word_t inst_hex);
    void MIPS_INST_ADDU (Word_t inst_hex);
    void MIPS_INST_CLO (Word_t inst_hex);
    void MIPS_INST_CLZ (Word_t inst_hex);
    void MIPS_INST_DIV (Word_t inst_hex);
    void MIPS_INST_DIVU (Word_t inst_hex);
    void MIPS_INST_MADD (Word_t inst_hex);
    void MIPS_INST_MADDU (Word_t inst_hex);
    void MIPS_INST_MSUB (Word_t inst_hex);
    void MIPS_INST_MSUBU (Word_t inst_hex);
...

実装は、自分で行わなければならない。

void InstEnv::MIPS_INST_ADD (Word_t inst_hex)
{
    RegAddr_t rs1_addr = ExtractRSField (inst_hex);
    RegAddr_t rs2_addr = ExtractRTField (inst_hex);
    RegAddr_t rd_addr  = ExtractRDField (inst_hex);

    Word_t  rs1_val  = m_env->GRegRead (rs1_addr);
    Word_t  rs2_val  = m_env->GRegRead (rs2_addr);
    Word_t  res      = rs1_val + rs2_val;
    m_env->GRegWrite (rd_addr, res);
}

という訳で、MIPSの命令を出来るところから実装していき、何とかビルドできるようになった。。。これからは、このISSを利用してテストしていく。