|
2 | 2 | // to the SAME register/memory addrss?
|
3 | 3 | use super::{
|
4 | 4 | column::Column,
|
5 |
| - interpreter::{Instruction, InterpreterEnv}, |
| 5 | + interpreter::{ |
| 6 | + self, IInstruction, Instruction, InterpreterEnv, RInstruction, SBInstruction, SInstruction, |
| 7 | + SyscallInstruction, UInstruction, UJInstruction, |
| 8 | + }, |
6 | 9 | registers::Registers,
|
7 | 10 | INSTRUCTION_SET_SIZE, SCRATCH_SIZE,
|
8 | 11 | };
|
9 | 12 | use crate::{
|
10 |
| - cannon::{PAGE_ADDRESS_MASK, PAGE_ADDRESS_SIZE, PAGE_SIZE}, |
| 13 | + cannon::{State, PAGE_ADDRESS_MASK, PAGE_ADDRESS_SIZE, PAGE_SIZE}, |
11 | 14 | lookups::Lookup,
|
12 | 15 | };
|
13 | 16 | use ark_ff::Field;
|
@@ -567,6 +570,201 @@ impl<Fp: Field> InterpreterEnv for Env<Fp> {
|
567 | 570 | }
|
568 | 571 |
|
569 | 572 | impl<Fp: Field> Env<Fp> {
|
| 573 | + pub fn create(page_size: usize, state: State) -> Self { |
| 574 | + let initial_instruction_pointer = state.pc; |
| 575 | + let next_instruction_pointer = state.next_pc; |
| 576 | + |
| 577 | + let selector = INSTRUCTION_SET_SIZE; |
| 578 | + |
| 579 | + let mut initial_memory: Vec<(u32, Vec<u8>)> = state |
| 580 | + .memory |
| 581 | + .into_iter() |
| 582 | + // Check that the conversion from page data is correct |
| 583 | + .map(|page| (page.index, page.data)) |
| 584 | + .collect(); |
| 585 | + |
| 586 | + for (_address, initial_memory) in initial_memory.iter_mut() { |
| 587 | + initial_memory.extend((0..(page_size - initial_memory.len())).map(|_| 0u8)); |
| 588 | + assert_eq!(initial_memory.len(), page_size); |
| 589 | + } |
| 590 | + |
| 591 | + let memory_offsets = initial_memory |
| 592 | + .iter() |
| 593 | + .map(|(offset, _)| *offset) |
| 594 | + .collect::<Vec<_>>(); |
| 595 | + |
| 596 | + let initial_registers = { |
| 597 | + Registers { |
| 598 | + general_purpose: state.registers, |
| 599 | + current_instruction_pointer: initial_instruction_pointer, |
| 600 | + next_instruction_pointer, |
| 601 | + heap_pointer: state.heap, |
| 602 | + } |
| 603 | + }; |
| 604 | + |
| 605 | + let mut registers = initial_registers.clone(); |
| 606 | + registers[2] = 0x408004f0; |
| 607 | + // set the stack pointer to the top of the stack |
| 608 | + |
| 609 | + Env { |
| 610 | + instruction_counter: state.step, |
| 611 | + memory: initial_memory.clone(), |
| 612 | + last_memory_accesses: [0usize; 3], |
| 613 | + memory_write_index: memory_offsets |
| 614 | + .iter() |
| 615 | + .map(|offset| (*offset, vec![0u64; page_size])) |
| 616 | + .collect(), |
| 617 | + last_memory_write_index_accesses: [0usize; 3], |
| 618 | + registers, |
| 619 | + registers_write_index: Registers::default(), |
| 620 | + scratch_state_idx: 0, |
| 621 | + scratch_state: fresh_scratch_state(), |
| 622 | + halt: state.exited, |
| 623 | + selector, |
| 624 | + } |
| 625 | + } |
| 626 | + |
| 627 | + pub fn next_instruction_counter(&self) -> u64 { |
| 628 | + (self.normalized_instruction_counter() + 1) * MAX_ACC |
| 629 | + } |
| 630 | + |
| 631 | + pub fn decode_instruction(&mut self) -> (Instruction, u32) { |
| 632 | + /* https://www.cs.cornell.edu/courses/cs3410/2024fa/assignments/cpusim/riscv-instructions.pdf */ |
| 633 | + let instruction = |
| 634 | + ((self.get_memory_direct(self.registers.current_instruction_pointer) as u32) << 24) |
| 635 | + | ((self.get_memory_direct(self.registers.current_instruction_pointer + 1) as u32) |
| 636 | + << 16) |
| 637 | + | ((self.get_memory_direct(self.registers.current_instruction_pointer + 2) as u32) |
| 638 | + << 8) |
| 639 | + | (self.get_memory_direct(self.registers.current_instruction_pointer + 3) as u32); |
| 640 | + let instruction = instruction.to_be(); // convert to big endian for more straightforward decoding |
| 641 | + println!( |
| 642 | + "Decoding instruction at address {:x} with value {:b}, with opcode", |
| 643 | + self.registers.current_instruction_pointer, instruction |
| 644 | + ); |
| 645 | + |
| 646 | + let opcode = { |
| 647 | + match instruction & 0b1111111 // bits 0-6 |
| 648 | + { |
| 649 | + 0b0110111 => Instruction::UType(UInstruction::LoadUpperImmediate), |
| 650 | + 0b0010111 => Instruction::UType(UInstruction::AddUpperImmediate), |
| 651 | + 0b1101111 => Instruction::UJType(UJInstruction::JumpAndLink), |
| 652 | + 0b1100011 => |
| 653 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 654 | + { |
| 655 | + 0b000 => Instruction::SBType(SBInstruction::BranchEq), |
| 656 | + 0b001 => Instruction::SBType(SBInstruction::BranchNeq), |
| 657 | + 0b100 => Instruction::SBType(SBInstruction::BranchLessThan), |
| 658 | + 0b101 => Instruction::SBType(SBInstruction::BranchGreaterThanEqual), |
| 659 | + 0b110 => Instruction::SBType(SBInstruction::BranchLessThanUnsigned), |
| 660 | + 0b111 => Instruction::SBType(SBInstruction::BranchGreaterThanEqualUnsigned), |
| 661 | + _ => panic!("Unknown SBType instruction with full inst {}", instruction), |
| 662 | + }, |
| 663 | + 0b1100111 => Instruction::IType(IInstruction::JumpAndLinkRegister), |
| 664 | + 0b0000011 => |
| 665 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 666 | + { |
| 667 | + 0b000 => Instruction::IType(IInstruction::LoadByte), |
| 668 | + 0b001 => Instruction::IType(IInstruction::LoadHalf), |
| 669 | + 0b010 => Instruction::IType(IInstruction::LoadWord), |
| 670 | + 0b100 => Instruction::IType(IInstruction::LoadByteUnsigned), |
| 671 | + 0b101 => Instruction::IType(IInstruction::LoadHalfUnsigned), |
| 672 | + _ => panic!("Unknown IType instruction with full inst {}", instruction), |
| 673 | + }, |
| 674 | + 0b0100011 => |
| 675 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 676 | + { |
| 677 | + 0b000 => Instruction::SType(SInstruction::StoreByte), |
| 678 | + 0b001 => Instruction::SType(SInstruction::StoreHalf), |
| 679 | + 0b010 => Instruction::SType(SInstruction::StoreWord), |
| 680 | + _ => panic!("Unknown SType instruction with full inst {}", instruction), |
| 681 | + }, |
| 682 | + 0b0010011 => |
| 683 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 684 | + { |
| 685 | + 0b000 => Instruction::IType(IInstruction::AddImmediate), |
| 686 | + 0b010 => Instruction::IType(IInstruction::SetLessThanImmediate), |
| 687 | + 0b011 => Instruction::IType(IInstruction::SetLessThanImmediateUnsigned), |
| 688 | + 0b100 => Instruction::IType(IInstruction::XorImmediate), |
| 689 | + 0b110 => Instruction::IType(IInstruction::OrImmediate), |
| 690 | + 0b111 => Instruction::IType(IInstruction::AndImmediate), |
| 691 | + 0b001 => Instruction::IType(IInstruction::ShiftLeftLogicalImmediate), |
| 692 | + 0b101 => |
| 693 | + match (instruction >> 30) & 0x1 // bit 30 in simm component of IType |
| 694 | + { |
| 695 | + 0b0 => Instruction::IType(IInstruction::ShiftRightLogicalImmediate), |
| 696 | + 0b1 => Instruction::IType(IInstruction::ShiftRightArithmeticImmediate), |
| 697 | + _ => panic!("Unknown IType in shift right instructions with full inst {}", instruction), |
| 698 | + }, |
| 699 | + _ => panic!("Unknown IType instruction with full inst {}", instruction), |
| 700 | + }, |
| 701 | + 0b0110011 => |
| 702 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 703 | + { |
| 704 | + 0b000 => |
| 705 | + match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType |
| 706 | + { |
| 707 | + 0b0 => Instruction::RType(RInstruction::Add), |
| 708 | + 0b1 => Instruction::RType(RInstruction::Sub), |
| 709 | + _ => panic!("Unknown RType in add/sub instructions with full inst {}", instruction), |
| 710 | + }, |
| 711 | + 0b001 => Instruction::RType(RInstruction::ShiftLeftLogical), |
| 712 | + 0b010 => Instruction::RType(RInstruction::SetLessThan), |
| 713 | + 0b011 => Instruction::RType(RInstruction::SetLessThanUnsigned), |
| 714 | + 0b100 => Instruction::RType(RInstruction::Xor), |
| 715 | + 0b101 => |
| 716 | + match (instruction >> 30) & 0x1 // bit 30 of funct5 component in RType |
| 717 | + { |
| 718 | + 0b0 => Instruction::RType(RInstruction::ShiftRightLogical), |
| 719 | + 0b1 => Instruction::RType(RInstruction::ShiftRightArithmetic), |
| 720 | + _ => panic!("Unknown RType in shift right instructions with full inst {}", instruction), |
| 721 | + }, |
| 722 | + 0b110 => Instruction::RType(RInstruction::Or), |
| 723 | + 0b111 => Instruction::RType(RInstruction::And), |
| 724 | + _ => panic!("Unknown RType 0110011 instruction with full inst {}", instruction), |
| 725 | + }, |
| 726 | + 0b0001111 => |
| 727 | + match (instruction >> 12) & 0x7 // bits 12-14 for func3 |
| 728 | + { |
| 729 | + 0b000 => Instruction::RType(RInstruction::Fence), |
| 730 | + 0b001 => Instruction::RType(RInstruction::FenceI), |
| 731 | + _ => panic!("Unknown RType 0001111 (Fence) instruction with full inst {}", instruction), |
| 732 | + }, |
| 733 | + // FIXME: we should implement more syscalls here, and check the register state. |
| 734 | + // Even better, only one constructor call ecall, and in the |
| 735 | + // interpreter, we do the action depending on it |
| 736 | + 0b1110011 => Instruction::SyscallType(SyscallInstruction::SyscallSuccess), |
| 737 | + _ => panic!("Unknown instruction with full inst {:b}, and opcode {:b}", instruction, instruction & 0b1111111), |
| 738 | + } |
| 739 | + }; |
| 740 | + // display the opcode |
| 741 | + println!( |
| 742 | + "Decoded instruction {:?} with opcode {:?}", |
| 743 | + instruction, opcode |
| 744 | + ); |
| 745 | + (opcode, instruction) |
| 746 | + } |
| 747 | + |
| 748 | + /// Execute a single step in the RISCV32i program |
| 749 | + pub fn step(&mut self) -> Instruction { |
| 750 | + self.reset_scratch_state(); |
| 751 | + let (opcode, _instruction) = self.decode_instruction(); |
| 752 | + |
| 753 | + interpreter::interpret_instruction(self, opcode); |
| 754 | + |
| 755 | + self.instruction_counter = self.next_instruction_counter(); |
| 756 | + |
| 757 | + // Integer division by MAX_ACC to obtain the actual instruction count |
| 758 | + if self.halt { |
| 759 | + println!( |
| 760 | + "Halted at step={} instruction={:?}", |
| 761 | + self.normalized_instruction_counter(), |
| 762 | + opcode |
| 763 | + ); |
| 764 | + } |
| 765 | + opcode |
| 766 | + } |
| 767 | + |
570 | 768 | pub fn reset_scratch_state(&mut self) {
|
571 | 769 | self.scratch_state_idx = 0;
|
572 | 770 | self.scratch_state = fresh_scratch_state();
|
|
0 commit comments