マルチサイクル RISC-V CPU を作成したい
https://gyazo.com/0d9c5448e09d85a03ad2ef2832e0a336
マルチサイクルな 32ビット RISC-V CPU の作成メモ。
シングルサイクルなCPUだと以下のような制限があるため、マルチサイクルなCPUを作ることにする。
プログラムメモリとデータメモリを共通化できない
ブロックRAM / SDRAM の読み込み待ちができない
浮動小数点数の計算待ちができない
リポジトリ
Odeeen
発表資料
「第5回 自作CPUを語る会」で発表した資料
発表内容検討メモ
CPUアーキテクチャ
32ビットRISC-V(RV32IF)
整数演算 + 単精度浮動小数点演算
コンパクト命令には非対応
実装した命令
整数命令
lw, sw, add, addi, sub, and, or, xor, slt, sltu, beq, bne, ble, bne, blt, bgt, bge, jal, jalr, lui, auipc, ori, srl, sra, sll
浮動小数点命令
flw, fsw, fadd_s, fsub_s, fmul_s, fdiv_s, fcvt_s_w, fcvt_w_s, fsgnj_s, fsgnjn_s, feq_s, flt_s, fle_s, fmv_x_w, fmv_w_x
バスインターフェース
メモリ構成
ROM(ブロックRAM):256KB
RAM(SDRAM):32MB
周辺機器(メモリマップトIO)
UART
LED(8ビット)
使用するFPGAボード
開発環境
レイトレを動かすのに必要なFPGAのスペック
LUT数
12K以上(必須)
自作CPUを載せるのに12K程度のLUTが必要
ECP5 85FのLUT数は85Kなので問題なし
Tang Nano 9Kには入らない
Tang Nano 20Kにはたぶん入りそう
SDRAMまたはHyperRAMのサイズ
5MB以上(必須)
128KB以上(必須)
スタック領域(1MB)+ ヒープ領域(4MB)
スタック領域(64KB)+ ヒープ領域(64KB)
ブロックRAMサイズ
250KB以上(推奨)
プログラムがブロックRAMに収まらない場合、SDカードなどからのローダが必要
メモリバス
今回のCPUはSDRAMに対応したい。SDRAMのデータの読み書きには複数クロックかかるので、SDRAMの読み書きが終わるまでCPU側が待機する必要がある。
以前作成したCPUのメモリバスは読み書きを待つための信号線を持たなかったので、今回のCPUでは、PicoRV32のメモリバスを参考にVALIDとREADYにより待ち合わせを行うインターフェースを採用する。 BRAMコントローラー
VALIDとREADYによる待ち合わせを行うメモリが必要なので、新たにBRAMコントローラーを作成した。
参考資料
シングルサイクルCPUのマルチサイクル化の手順については、以下が参考になりそう。
POCOのマルチサイクル化
MinCamlコンパイラ
MinCamlで書かれたレイトレーサーを動かすのが最終目標なので、MinCamlで書かれたプログラムを動かせるようにしたい。
MinCamlのプログラムのビルドには、去年RISC-Vへ移植したこちらを利用する。
MinCamlのRISC-Vへの移植についてはこちらを参照
開発記録
ステージ分割
1つのブロックRAMに「プログラムメモリ」と「データメモリ」の両方を格納したい。
「命令の取得」と「メモリへのデータの読み書き」を同時に行おうとすると、メモリバスで衝突が発生してしまうため、「命令を取得するステージ(IFステージ)」と「命令を実行するステージ(EXステージ)」とを分けることで、メモリバスの衝突を回避する。
IFステージ(命令フェッチ)
メインメモリ上の pc_reg が指す番地から命令を取得し、instr_reg へ格納
mem_addr に pc_reg の値をセット
pc_reg の更新はここでは行わない
EXステージ(実行)
instr_reg に格納した命令を実行
pc_reg の更新を行う
(追記)その後、データメモリへの読み書きの待ち合わせ用のステージが欲しくなったので、最終的に以下のようにステージ分けをおこなった。ステージの分け方については、デジタル回路設計とコンピュータアーキテクチャ(7章)が参考になった。
IFステージ(命令フェッチ)
EXステージ(実行)
MEMステージ(メモリアクセス)
WBステージ(レジスタ書き戻し、writeback)
https://gyazo.com/20646eff97e8edc11363d174ca80a49e
(さらに追記)その後、FPU導入にともない、以下のようになりました
code:verilog
typedef enum {
IF_STAGE,
EX_STAGE,
FP1_STAGE, // FPU へ入力を渡す
FP2_STAGE, // FPU からの出力を待機
FP3_STAGE, // FPU の出力をレジスタへ保存
MEM_STAGE,
WB_STAGE,
ERR_STAGE
} stage_t;
stage_t stage_reg, stage_next;
RISC-Vの命令セット
RISC-Vの命令セットについては以下が参考になる
実装予定の命令
当面は使う予定の無い以下の命令を除いた RV32I の命令を実装する
ecall
ebreak
lw 以外のロード系命令
sw 以外のストア系命令
最終的に実装した命令一覧はこちら
ビット列を浮動小数点数に変換するワンライナー
動作確認用のRubyのワンライナースクリプト。
code:ruby
指数部の最大値と最小値
0xFF
無限大 or NaN
0x00
ゼロ or 非正規数
最大
0xFE (指数 = 127)
仮数 * 170141183460469231731687303715884105728(2 ^ 127)
最小
0x01(指数 = -126)
仮数 * 1.1754943508222875e-38
Tang Nano 9K対応