0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PythonでRISC-Vの簡単な仮想マシン

Last updated at Posted at 2025-03-20

このPythonコードは、簡単なRISC-V仮想マシン(VM)を実装したものです。この仮想マシンは、メモリ、レジスタ、プログラムカウンタを持ち、いくつかの基本的なRISC-V命令(ADD, ADDI, BEQ, JAL, HALT)を実行できます。

riscv_vm.py

class RISCV_VM:
    def __init__(self, memory_size=256):
        self.registers = [0] * 32  # 32個の整数レジスタ
        self.memory = [0] * memory_size  # メモリ領域
        self.pc = 0  # プログラムカウンタ
        self.running = True
  
    def load_program(self, program):
       self.memory[:len(program)] = program
    
    def fetch(self):
        instr = self.memory[self.pc]
        self.pc += 1
        return instr
    
    def decode_execute(self, instr):
        opcode = instr & 0x7F  # 7ビットのオペコード
        rd = (instr >> 7) & 0x1F
        rs1 = (instr >> 15) & 0x1F
        rs2 = (instr >> 20) & 0x1F
        imm = (instr >> 20)  # 即値
        
        if opcode == 0x33:  # ADD命令 (rd = rs1 + rs2)
            self.registers[rd] = self.registers[rs1] + self.registers[rs2]
        elif opcode == 0x13:  # ADDI命令 (rd = rs1 + imm)
            self.registers[rd] = self.registers[rs1] + imm
        elif opcode == 0x63:  # BEQ命令 (if rs1 == rs2 then PC += imm)
            if self.registers[rs1] == self.registers[rs2]:
                self.pc += imm
        elif opcode == 0x6F:  # JAL命令 (jump and link)
            self.registers[rd] = self.pc
            self.pc += imm
        elif opcode == 0x67:  # HALT (仮の命令として設定)
            self.running = False
        else:
            print(f"Unknown instruction: {instr}")
    
    def run(self):
        while self.running:
            instr = self.fetch()
            self.decode_execute(instr)
            print(f"PC: {self.pc}, Registers: {self.registers}")

# サンプルプログラム (ADDI x1, x0, 5; ADDI x2, x0, 10; ADD x3, x1, x2; HALT)
program = [
    (0x13 | (1 << 7) | (0 << 15) | (5 << 20)),  # ADDI x1, x0, 5
    (0x13 | (2 << 7) | (0 << 15) | (10 << 20)), # ADDI x2, x0, 10
    (0x33 | (3 << 7) | (1 << 15) | (2 << 20)),  # ADD x3, x1, x2
    0x67  # HALT
]

vm = RISCV_VM()
vm.load_program(program)
vm.run()

コードの構成

RISCV_VM クラス: 仮想マシンの主要なコンポーネントをカプセル化します。
init: 仮想マシンの初期化を行います。32個のレジスタ、メモリ、プログラムカウンタ(pc)、実行フラグ(running)を準備します。

load_program: メモリにプログラムをロードします。
fetch: 現在のpcが指すメモリ位置から命令をフェッチ(読み込み)します。その後、pcをインクリメントします。

decode_execute: フェッチされた命令をデコード(解釈)し、実行します。命令のオペコードとオペランド(レジスタ番号、即値)を抽出し、それに応じてレジスタの値を変更したり、pcを更新したりします。
run: 仮想マシンの実行ループです。runningフラグがTrueの間、命令をフェッチ、デコード、実行し続けます。命令の実行後、pcとレジスタの内容を出力します。

サンプルプログラム:
program: 仮想マシンが実行する命令をリストで定義しています。各命令は整数で表され、RISC-Vの命令フォーマットに従ってエンコードされています。
ADDI x1, x0, 5 : x1レジスタにx0レジスタの値+5を代入(x1=5)
ADDI x2, x0, 10 : x2レジスタにx0レジスタの値+10を代入(x2=10)
ADD x3, x1, x2 : x3レジスタにx1レジスタの値+x2レジスタの値を代入(x3=15)
HALT: プログラムを停止します。

実行部分:
vm = RISCV_VM(): RISCV_VMクラスのインスタンスを作成します。
vm.load_program(program): サンプルプログラムを仮想マシンのメモリにロードします。
vm.run(): 仮想マシンの実行を開始します。

プログラムコードの説明:
(0x13 | (1 << 7) | (0 << 15) | (5 << 20)) # ADDI x1, x0, 5

0x13:これはADDI(即値追加)命令のオペコードである。RISC-V ISAでは、オペコードは7ビット・フィールドである。16進数の0x13は2進数では0b0010011であり、これがADDIの正しいオペコードである。
(1 << 7): この部分はデスティネーション・レジスタ(rd)をエンコードする。
1: レジスタ番号。この場合はx1(レジスタ番号1)。
<< 7: 左シフト演算子。RISC-V命令形式のrdフィールドがビット7から11(合計5ビット)を占めるため、1を7ビット左にシフトする。
1 << 7の結果は、0b10000000(10進数128)となる。これにより、レジスタ番号1がrdの正しいビット位置に配置される。

(0 << 15): この部分は最初のソース・レジスタ(rs1)をエンコードする。
0: レジスタ番号。x0は常に値0を保持する特別なレジスタである。
<< 15: rs1フィールドが15ビットから19ビットを占めるので、0を15ビット左にシフトする。
0 << 15の結果は0b0(10進数の0)である。

(5 << 20): この部分は即値(imm)を符号化する。
5:即値。rs1の値(x0)に5を加えたい。

実行
コマンドラインまたはターミナルで、保存したファイルがあるディレクトリに移動します。
python riscv_vm.py と入力して実行します。
結果確認:
実行結果として、各命令実行後のPCの値とレジスタの内容が出力されます。
最終的に、x3レジスタに15(5 + 10)が格納されていることが確認できるはずです。

$ python riscv_vm.py

結果
PC: 1, Registers: [0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
PC: 2, Registers: [0, 5, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
PC: 3, Registers: [0, 5, 10, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
PC: 4, Registers: [0, 5, 10, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?