// Copyright (c) 2025 taitep // SPDX-License-Identifier: MIT // // This file is part of TRVE (https://gitea.taitep.se/taitep/trve) // See LICENSE file in the project root for full license text. use crate::{ consts::{Addr, RegId, RegValue}, decode::Instruction, instructions::find_and_exec, mem::MemConfig, }; // placeholder - change when exception system is in place pub(crate) type Exception = (); pub(crate) enum InstructionResult { Normal, Exception(Exception), Pause, } pub struct Core { pub(crate) x_regs: [RegValue; 32], pub(crate) pc: Addr, pub(crate) mem: MemConfig, } impl Core { pub fn new(mem: MemConfig) -> Self { Self { x_regs: [0; 32], pc: 0, mem, } } pub fn run(&mut self) { loop { let page = (self.pc / 4096) as usize; let offset = (self.pc / 4) as u16; if !self.pc.is_multiple_of(4) { //replace eprint with logging, replace break with exception eprintln!("PC not aligned"); break; } let instr = match self.mem.read_word(page, offset) { Ok(i) => i, Err(_) => { eprintln!("Memory access fault while fetching instruction"); break; } }; assert_eq!(instr & 3, 3, "Compressed instructions not supported"); let instr = Instruction(instr); let res = find_and_exec(instr, self); if let Some(res) = res { match res { InstructionResult::Normal => {} InstructionResult::Exception(_e) => { eprintln!("Exception from instruction"); eprintln!("PC: {:016X}, instr: {:08X}", self.pc, instr.0); break; } InstructionResult::Pause => { eprintln!("Instruction asked for pause"); break; } } } else { eprintln!("Invalid Instruction 0x{:08x} 0b{:032b}", instr.0, instr.0); break; } } } pub fn reset(&mut self, pc: Addr) { self.pc = pc; } pub(crate) fn reg_read(&self, id: RegId) -> RegValue { self.x_regs[id as usize] } pub(crate) fn reg_write(&mut self, id: RegId, value: RegValue) { if id == 0 { return; } self.x_regs[id as usize] = value; } pub(crate) fn advance_pc(&mut self) { self.pc = self.pc.wrapping_add(4); } }