見出し画像

RISC-V(RV32IM)を活用した論理回路の制御例

背景

前回まで

こんな感じを目指そう。
Logicが求めるべき素数の最大値をRISC-Vに渡して、RISC-Vがその範囲内の最大の素数を返す。

FPGA

RISC-Vの改変

GPIOを作るべきですが、簡単に改変するとして、
x31レジスタに求める素数の最大範囲
x32レジスタに出力するように変更しました

コード

RTL
RV32IM_KAI.v

テストベンチ

アセンブラ

.section .data
    # データセクションは必要ない場合もあるので、ここでは空です

.section .text
.global _start

_start:
    # レジスタ初期化
    #li x11, 0x02               # x11 = 2 (テストする数)
    li x12, 0x02               # x12 = 2 (除数の初期値)
    mv x11, x30                # テストする数は入力値
    sub x11, x11, x12          # マイナス2(x12を使う)する
    li x13, 0x00               # x13 = 素数フラグ (0 = 素数, 1 = 素数でない)
    #li x14, 0x64               # x14 = 上限 (100)
    mv x14, x30                # x30レジスタが入力
    li x15, 0x00               # x15 = メモリ書き込み用のオフセット (0x00)

next_number:
    li x12, 0x02               # 除数を2にリセット
    li x13, 0x00               # 素数フラグをリセット

check_prime:
    # 除数がテストする数未満の間、割り算を繰り返す
    mv x16, x11                # x16 = x11 (割られる数)

calc_remainder:
    beq x16, x0, not_prime     # 割り切れた場合は素数ではない
    blt x16, x12, end_check    # 余りが割る数より小さくなったら次の数をチェック

    sub x16, x16, x12          # x16 = x16 - x12 (余りを計算)
    j calc_remainder           # 繰り返し

not_prime:
    li x13, 0x01               # 素数フラグを1に設定 (素数でない)

end_check:
    addi x12, x12, 1           # 除数を1増やす
    blt x12, x11, check_prime  # 除数がテストする数未満なら再チェック
    beq x13, x0, store_prime   # フラグが0なら素数なのでメモリに保存

    addi x11, x11, 1           # 次の数をチェック
    bge x11, x14, end_program  # 36までチェックしたら終了
    j next_number              # 次の数をチェック

store_prime:
    # メモリアドレスに素数を書き込む (1バイト単位)
    lui  x4, 0x0001            # 上位ビットを設定 (メモリのベースアドレス)
    add  x4, x4, x15           # x15をアドレスに加える
    sb   x11, 0(x4)            # 素数をメモリに1バイトで書き込む
    mv   x31, x11              # x31レジスタが出力
    addi x15, x15, 1           # 次のメモリアドレスへ (1バイト進める)

    addi x11, x11, 1           # 次の数をチェック
    bge x11, x14, end_program  # 36までチェックしたら終了
    j next_number              # 次の数をチェック

end_program:
    # 無限ループでプログラムを停止
loop_end:
    j loop_end                 # 無限ループ

実行結果

以下を実行

riscv64-unknown-elf-as -march=rv64im -o prime.o prime.s
riscv64-unknown-elf-ld -T linker.ld -o prime.elf prime.o
riscv64-unknown-elf-objcopy -O verilog prime.elf mem_data.hex
iverilog -o tb_RV32IM.vvp tb_RV32IM.v RV32IM_KAI.v
vvp tb_RV32IM.vvp

入力値=200では?

out_number =        199
tb_RV32IM.v:57: $finish called at 300020 (1s)

200までで最大の素数は199
合っているようです。

所感

個人で電子回路を組むなら、専用ロジックまでは使わないでも速度的に問題は起きないと思いますが。
個人レベルで専用ロジックが必要な場合って?IOが特殊とか?

次は、、何をしようか。
リアルタイムOS?
ファイルシステム?


この記事が気に入ったらサポートをしてみませんか?