-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
create interpreter implementation and adding instruction decoder for riscvi32 #2753
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
35796f7
create interpreter implementation and adding instruction decoder
svv232 47eacb0
correcting instruction decoding to follow spec
svv232 7e6756f
correcting more instruction implementations in display
svv232 359d565
adding step function and test_no_action test
svv232 c94c9f2
fixing imports and removing tests so o1vmtest can be imported in the …
svv232 0681bf0
reformat import in test
svv232 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,12 +2,15 @@ | |
// to the SAME register/memory addrss? | ||
use super::{ | ||
column::Column, | ||
interpreter::{Instruction, InterpreterEnv}, | ||
interpreter::{ | ||
self, IInstruction, Instruction, InterpreterEnv, RInstruction, SBInstruction, SInstruction, | ||
SyscallInstruction, UInstruction, UJInstruction, | ||
}, | ||
registers::Registers, | ||
INSTRUCTION_SET_SIZE, SCRATCH_SIZE, | ||
}; | ||
use crate::{ | ||
cannon::{PAGE_ADDRESS_MASK, PAGE_ADDRESS_SIZE, PAGE_SIZE}, | ||
cannon::{State, PAGE_ADDRESS_MASK, PAGE_ADDRESS_SIZE, PAGE_SIZE}, | ||
lookups::Lookup, | ||
}; | ||
use ark_ff::Field; | ||
|
@@ -567,6 +570,201 @@ impl<Fp: Field> InterpreterEnv for Env<Fp> { | |
} | ||
|
||
impl<Fp: Field> Env<Fp> { | ||
pub fn create(page_size: usize, state: State) -> Self { | ||
let initial_instruction_pointer = state.pc; | ||
let next_instruction_pointer = state.next_pc; | ||
|
||
let selector = INSTRUCTION_SET_SIZE; | ||
|
||
let mut initial_memory: Vec<(u32, Vec<u8>)> = state | ||
.memory | ||
.into_iter() | ||
// Check that the conversion from page data is correct | ||
.map(|page| (page.index, page.data)) | ||
.collect(); | ||
|
||
for (_address, initial_memory) in initial_memory.iter_mut() { | ||
initial_memory.extend((0..(page_size - initial_memory.len())).map(|_| 0u8)); | ||
assert_eq!(initial_memory.len(), page_size); | ||
} | ||
|
||
let memory_offsets = initial_memory | ||
.iter() | ||
.map(|(offset, _)| *offset) | ||
.collect::<Vec<_>>(); | ||
|
||
let initial_registers = { | ||
Registers { | ||
general_purpose: state.registers, | ||
current_instruction_pointer: initial_instruction_pointer, | ||
next_instruction_pointer, | ||
heap_pointer: state.heap, | ||
} | ||
}; | ||
|
||
let mut registers = initial_registers.clone(); | ||
registers[2] = 0x408004f0; | ||
// set the stack pointer to the top of the stack | ||
|
||
Env { | ||
instruction_counter: state.step, | ||
memory: initial_memory.clone(), | ||
last_memory_accesses: [0usize; 3], | ||
memory_write_index: memory_offsets | ||
.iter() | ||
.map(|offset| (*offset, vec![0u64; page_size])) | ||
.collect(), | ||
last_memory_write_index_accesses: [0usize; 3], | ||
registers, | ||
registers_write_index: Registers::default(), | ||
scratch_state_idx: 0, | ||
scratch_state: fresh_scratch_state(), | ||
halt: state.exited, | ||
selector, | ||
} | ||
} | ||
|
||
pub fn next_instruction_counter(&self) -> u64 { | ||
(self.normalized_instruction_counter() + 1) * MAX_ACC | ||
} | ||
|
||
pub fn decode_instruction(&mut self) -> (Instruction, u32) { | ||
/* https://www.cs.cornell.edu/courses/cs3410/2024fa/assignments/cpusim/riscv-instructions.pdf */ | ||
let instruction = | ||
((self.get_memory_direct(self.registers.current_instruction_pointer) as u32) << 24) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we not avoid |
||
| ((self.get_memory_direct(self.registers.current_instruction_pointer + 1) as u32) | ||
<< 16) | ||
| ((self.get_memory_direct(self.registers.current_instruction_pointer + 2) as u32) | ||
<< 8) | ||
| (self.get_memory_direct(self.registers.current_instruction_pointer + 3) as u32); | ||
let instruction = instruction.to_be(); // convert to big endian for more straightforward decoding | ||
println!( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use a debug! instead? |
||
"Decoding instruction at address {:x} with value {:b}, with opcode", | ||
self.registers.current_instruction_pointer, instruction | ||
); | ||
|
||
let opcode = { | ||
match instruction & 0b1111111 // bits 0-6 | ||
{ | ||
0b0110111 => Instruction::UType(UInstruction::LoadUpperImmediate), | ||
0b0010111 => Instruction::UType(UInstruction::AddUpperImmediate), | ||
0b1101111 => Instruction::UJType(UJInstruction::JumpAndLink), | ||
0b1100011 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => Instruction::SBType(SBInstruction::BranchEq), | ||
0b001 => Instruction::SBType(SBInstruction::BranchNeq), | ||
0b100 => Instruction::SBType(SBInstruction::BranchLessThan), | ||
0b101 => Instruction::SBType(SBInstruction::BranchGreaterThanEqual), | ||
0b110 => Instruction::SBType(SBInstruction::BranchLessThanUnsigned), | ||
0b111 => Instruction::SBType(SBInstruction::BranchGreaterThanEqualUnsigned), | ||
_ => panic!("Unknown SBType instruction with full inst {}", instruction), | ||
}, | ||
0b1100111 => Instruction::IType(IInstruction::JumpAndLinkRegister), | ||
0b0000011 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => Instruction::IType(IInstruction::LoadByte), | ||
0b001 => Instruction::IType(IInstruction::LoadHalf), | ||
0b010 => Instruction::IType(IInstruction::LoadWord), | ||
0b100 => Instruction::IType(IInstruction::LoadByteUnsigned), | ||
0b101 => Instruction::IType(IInstruction::LoadHalfUnsigned), | ||
_ => panic!("Unknown IType instruction with full inst {}", instruction), | ||
}, | ||
0b0100011 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => Instruction::SType(SInstruction::StoreByte), | ||
0b001 => Instruction::SType(SInstruction::StoreHalf), | ||
0b010 => Instruction::SType(SInstruction::StoreWord), | ||
_ => panic!("Unknown SType instruction with full inst {}", instruction), | ||
}, | ||
0b0010011 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => Instruction::IType(IInstruction::AddImmediate), | ||
0b010 => Instruction::IType(IInstruction::SetLessThanImmediate), | ||
0b011 => Instruction::IType(IInstruction::SetLessThanImmediateUnsigned), | ||
0b100 => Instruction::IType(IInstruction::XorImmediate), | ||
0b110 => Instruction::IType(IInstruction::OrImmediate), | ||
0b111 => Instruction::IType(IInstruction::AndImmediate), | ||
0b001 => Instruction::IType(IInstruction::ShiftLeftLogicalImmediate), | ||
0b101 => | ||
match (instruction >> 30) & 0x1 // bit 30 in simm component of IType | ||
{ | ||
0b0 => Instruction::IType(IInstruction::ShiftRightLogicalImmediate), | ||
0b1 => Instruction::IType(IInstruction::ShiftRightArithmeticImmediate), | ||
_ => panic!("Unknown IType in shift right instructions with full inst {}", instruction), | ||
}, | ||
_ => panic!("Unknown IType instruction with full inst {}", instruction), | ||
}, | ||
0b0110011 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => | ||
match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType | ||
{ | ||
0b0 => Instruction::RType(RInstruction::Add), | ||
0b1 => Instruction::RType(RInstruction::Sub), | ||
_ => panic!("Unknown RType in add/sub instructions with full inst {}", instruction), | ||
}, | ||
0b001 => Instruction::RType(RInstruction::ShiftLeftLogical), | ||
0b010 => Instruction::RType(RInstruction::SetLessThan), | ||
0b011 => Instruction::RType(RInstruction::SetLessThanUnsigned), | ||
0b100 => Instruction::RType(RInstruction::Xor), | ||
0b101 => | ||
match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType | ||
{ | ||
0b0 => Instruction::RType(RInstruction::ShiftRightLogical), | ||
0b1 => Instruction::RType(RInstruction::ShiftRightArithmetic), | ||
_ => panic!("Unknown RType in shift right instructions with full inst {}", instruction), | ||
}, | ||
0b110 => Instruction::RType(RInstruction::Or), | ||
0b111 => Instruction::RType(RInstruction::And), | ||
_ => panic!("Unknown RType 0110011 instruction with full inst {}", instruction), | ||
}, | ||
0b0001111 => | ||
match (instruction >> 12) & 0x7 // bits 12-14 for func3 | ||
{ | ||
0b000 => Instruction::RType(RInstruction::Fence), | ||
0b001 => Instruction::RType(RInstruction::FenceI), | ||
_ => panic!("Unknown RType 0001111 (Fence) instruction with full inst {}", instruction), | ||
}, | ||
// FIXME: we should implement more syscalls here, and check the register state. | ||
// Even better, only one constructor call ecall, and in the | ||
// interpreter, we do the action depending on it | ||
0b1110011 => Instruction::SyscallType(SyscallInstruction::SyscallSuccess), | ||
_ => panic!("Unknown instruction with full inst {:b}, and opcode {:b}", instruction, instruction & 0b1111111), | ||
} | ||
}; | ||
// display the opcode | ||
println!( | ||
"Decoded instruction {:?} with opcode {:?}", | ||
instruction, opcode | ||
); | ||
(opcode, instruction) | ||
} | ||
|
||
/// Execute a single step in the RISCV32i program | ||
pub fn step(&mut self) -> Instruction { | ||
self.reset_scratch_state(); | ||
let (opcode, _instruction) = self.decode_instruction(); | ||
|
||
interpreter::interpret_instruction(self, opcode); | ||
|
||
self.instruction_counter = self.next_instruction_counter(); | ||
|
||
// Integer division by MAX_ACC to obtain the actual instruction count | ||
if self.halt { | ||
println!( | ||
"Halted at step={} instruction={:?}", | ||
self.normalized_instruction_counter(), | ||
opcode | ||
); | ||
} | ||
opcode | ||
} | ||
|
||
pub fn reset_scratch_state(&mut self) { | ||
self.scratch_state_idx = 0; | ||
self.scratch_state = fresh_scratch_state(); | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a follow up pr needs to be made to dynamically set the stack ptr based on the loader, this should be fine for now in the vms memory implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linking comment #2741