FPGA開発日記

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

ISSのシステムレジスタ値を設定できるようにする

xv6の解析中に、システムレジスタの初期値によって割り込みを発生させたりさせなかったりする設定が間違っており、うまく動作していない点があった。 そう考えてみると、今のISSにはシステムレジスタの初期値を設定できていないので、システムレジスタテーブルを利用して、自動的に生成してみるようにした。

システムレジスタテーブルの拡張により、初期化ルーチンを自動生成する。

現在の、MIPSのシステムレジスタアクセスのルーチンを生成するためのテーブルは、以下のようになっている。

#                        ['Number', 'Privilege', 'Name']
$sysreg_table[ 0] = Array[0x00, 'RW', 'Index',         Array[Array[31,31,'P','R'],
                                                             Array[ 4, 0,'Index','RW']]]
$sysreg_table[ 1] = Array[0x10, 'R' , 'Random',        Array[Array[ 4, 0,'Index','R']]]
$sysreg_table[ 2] = Array[0x20, 'RW', 'EntryLo0',      Array[Array[31,30,'Fill','R'],
                                                             Array[29, 6,'PFN','R'],
                                                             Array[ 5, 3,'C', 'RW'],
                                                             Array[ 2, 2,'D', 'RW'],
                                                             Array[ 1, 1,'V', 'RW'],
                                                             Array[ 0, 0,'G', 'RW']]]
$sysreg_table[ 3] = Array[0x30, 'RW', 'EntryLo1',      Array[Array[31,30,'Fill','R'],
                                                             Array[29, 6,'PFN','R'],
                                                             Array[ 5, 3,'C', 'RW'],
                                                             Array[ 2, 2,'D', 'RW'],
                                                             Array[ 1, 1,'V', 'RW'],
                                                             Array[ 0, 0,'G', 'RW']]]
$sysreg_table[ 4] = Array[0x40, 'RW', 'Context',       Array[Array[31,23,'PTEBase','RW'],
                                                             Array[22, 4,'BadVPN2','R']]]
$sysreg_table[ 5] = Array[0x41, 'RW', 'ContextConfig', Array[Array[31, 0,'VirtualIndex','RW']]]
$sysreg_table[ 6] = Array[0x42, 'RW', 'UserLocal',     Array[Array[31, 0,'UserInformation','RW']]]
$sysreg_table[ 7] = Array[0x50, 'RW', 'PageMask',      Array[Array[29,13,'Mask','RW'],
                                                             Array[12,11,'MaskX','RW']]]
...

システムレジスタのビットフィールドをそれぞれ記述し、名前とビット位置、書き込みの許可などを設定できるようにしている。 これを以下のように拡張し、初期値を設定した。

#                        ['Number', 'Privilege', 'Name']
$sysreg_table[ 0] = Array[0x00, 'RW', 'Index',         Array[Array[31,31,'P',    'R',  0],
                                                             Array[ 4, 0,'Index','RW', 0]]]
$sysreg_table[ 1] = Array[0x10, 'R' , 'Random',        Array[Array[ 4, 0,'Index','R', 0]]]
$sysreg_table[ 2] = Array[0x20, 'RW', 'EntryLo0',      Array[Array[31,30,'Fill','R',  0],
                                                             Array[29, 6,'PFN', 'R',  0],
                                                             Array[ 5, 3,'C',   'RW', 0],
                                                             Array[ 2, 2,'D',   'RW', 0],
                                                             Array[ 1, 1,'V',   'RW', 0],
                                                             Array[ 0, 0,'G',   'RW', 0]]]
$sysreg_table[ 3] = Array[0x30, 'RW', 'EntryLo1',      Array[Array[31,30,'Fill','R' , 0],
                                                             Array[29, 6,'PFN', 'R' , 0],
                                                             Array[ 5, 3,'C',   'RW', 0],
                                                             Array[ 2, 2,'D',   'RW', 0],
                                                             Array[ 1, 1,'V',   'RW', 0],
                                                             Array[ 0, 0,'G',   'RW', 0]]]
$sysreg_table[ 4] = Array[0x40, 'RW', 'Context',       Array[Array[31,23,'PTEBase','RW', 0],
                                                             Array[22, 4,'BadVPN2','R' , 0]]]
$sysreg_table[ 5] = Array[0x41, 'RW', 'ContextConfig', Array[Array[31, 0,'VirtualIndex', 'RW', 0x007ffff0]]]
$sysreg_table[ 6] = Array[0x42, 'RW', 'UserLocal',     Array[Array[31, 0,'UserInformation','RW', 0]]]
...

github.com

このように各ビットフィールドの初期値を設定するようにした。これに伴い、システムレジスタの初期化ルーチンを以下のように作成する。

  sysreg_bitfields.each {|sysreg_bitfield|
    msb = sysreg_bitfield[SYSREG_BITFIELD::MAX]
    lsb = sysreg_bitfield[SYSREG_BITFIELD::MIN]
    bitwidth = msb - lsb + 1

    value = ((1 << bitwidth) - 1) && sysreg_bitfield[SYSREG_BITFIELD::INIT].to_i
    field = value << lsb

    init_val = init_val | field
  }
  sysreg_init_c_fp.printf("%08x;\n", init_val)

つまり、ビットフィールドを一つづつ取り出し、それぞれをシフトしてORを取ることで、システムレジスタの初期値を作り出すようにしている。 これにより、mips_sysreg_init.cppは以下のように生成される。

void CsrEnv::MIPS_CSR_Init (void)
{
    m_csr_index.Index = 0x00000000;
    m_csr_random.Random = 0x00000000;
    m_csr_entrylo0.EntryLo0 = 0x00000000;
    m_csr_entrylo1.EntryLo1 = 0x00000000;
    m_csr_context.Context = 0x00000000;
    m_csr_contextconfig.VirtualIndex = 0x007ffff0;
    m_csr_userlocal.UserInformation = 0x00000000;
    m_csr_pagemask.PageMask = 0x00000000;
    m_csr_pagegrain.PageGrain = 0x00000000;
    m_csr_segctl0.SegCtl0 = 0x00000000;
    m_csr_segctl1.SegCtl1 = 0x00000000;
    m_csr_segctl2.SegCtl2 = 0x00000000;
    m_csr_pwbase.PWBase = 0x00000000;
    m_csr_pwfield.PWField = 0x00000000;
    m_csr_pwsize.PWSize = 0x00000000;
    m_csr_wired.Wired = 0x00000000;
    m_csr_pwctl.PWCtl = 0x00000000;
    m_csr_hwrena.HWRena = 0x00000000;
    m_csr_badvaddr.BadVAddr = 0x00000000;
    m_csr_badinstr.BadInstr = 0x00000000;
...

これをコンストラクタから呼び出すことにより、システムレジスタを初期化できるようにした。 これにより、xv6のシステムレジスタを参照し、割り込みのモードを制御できるようになったので、解析を進めていこう。