finished initial interrupts implementation
This commit is contained in:
@@ -11,10 +11,7 @@ pub fn codegen(nodes: Vec<Node>) -> Result<Vec<Instruction>, AssembleError> {
|
|||||||
let mut instructions = vec![];
|
let mut instructions = vec![];
|
||||||
|
|
||||||
for node in nodes {
|
for node in nodes {
|
||||||
instructions.push(
|
instructions.push(build_instruction(&node)?);
|
||||||
build_instruction(&node)
|
|
||||||
.unwrap_or_else(|_| panic!("Failed to build instruction: {node:?}")),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("------------------------");
|
println!("------------------------");
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ pub enum Interrupt {
|
|||||||
pub type Address = u32;
|
pub type Address = u32;
|
||||||
|
|
||||||
impl Interrupt {
|
impl Interrupt {
|
||||||
const fn as_u8(self) -> u8 {
|
// someone tell clippy to stfu.
|
||||||
|
#[allow(clippy::must_use_candidate)]
|
||||||
|
pub const fn as_u8(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Self::Breakpoint => 0,
|
Self::Breakpoint => 0,
|
||||||
Self::HardFault => 1,
|
Self::HardFault => 1,
|
||||||
|
|||||||
@@ -54,12 +54,14 @@ impl Encode for Instruction {
|
|||||||
],
|
],
|
||||||
no_args: [Nop, IntReturn, Halt],
|
no_args: [Nop, IntReturn, Halt],
|
||||||
special: [
|
special: [
|
||||||
Self::Interrupt(_) => todo!(),
|
|
||||||
Self::Data(data) => data,
|
Self::Data(data) => data,
|
||||||
|
Self::Interrupt(interrupt) => {
|
||||||
|
let opcode = u32::from(self.opcode());
|
||||||
|
(opcode << 26) | u32::from(interrupt.as_u8())
|
||||||
|
},
|
||||||
Self::Segment(segment) => {
|
Self::Segment(segment) => {
|
||||||
let opcode = u32::from(self.opcode());
|
let opcode = u32::from(self.opcode());
|
||||||
let segment = segment as u8;
|
(opcode << 26) | u32::from(segment as u8)
|
||||||
(opcode << 26) | u32::from(segment)
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -212,8 +212,14 @@ pub fn run_emulator(
|
|||||||
Ok(instruction) => instruction,
|
Ok(instruction) => instruction,
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
let pcx = processor.get(Register::Pcx);
|
let pcx = processor.get(Register::Pcx);
|
||||||
eprintln!("Could not decode instruction at {pcx:x}. Reason: {why}");
|
report_err(
|
||||||
continue;
|
state_tx,
|
||||||
|
&format!(
|
||||||
|
"Could not decode instruction at {pcx:x}. Reason: {why}"
|
||||||
|
),
|
||||||
|
&mut processor,
|
||||||
|
);
|
||||||
|
(pcx, Instruction::Nop)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -228,6 +234,8 @@ pub fn run_emulator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn report_err(state_tx: &Sender<StateUpdate>, why: &str, processor: &mut Processor) {
|
fn report_err(state_tx: &Sender<StateUpdate>, why: &str, processor: &mut Processor) {
|
||||||
processor.begin_interrupt(Interrupt::HardFault);
|
processor
|
||||||
|
.begin_interrupt(Interrupt::HardFault)
|
||||||
|
.expect("What kind of goofy ahh shenanigans did you do with your fault handler? At this point, the emulator can just crash. this is on you.");
|
||||||
let _ = state_tx.send(StateUpdate::Error(why.to_string()));
|
let _ = state_tx.send(StateUpdate::Error(why.to_string()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,15 +116,42 @@ impl Processor {
|
|||||||
*self.reg(Register::Pcx) = self.get(reg) + u32::from(offset);
|
*self.reg(Register::Pcx) = self.get(reg) + u32::from(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn begin_interrupt(&mut self, _int: Interrupt) {
|
pub fn begin_interrupt(
|
||||||
// first we get the address of the interrupt descriptor table.
|
&mut self,
|
||||||
todo!();
|
interrupt: Interrupt,
|
||||||
|
) -> Result<(), ProcessorError> {
|
||||||
|
let idt = self.get(Register::Idr);
|
||||||
|
|
||||||
|
let addr = self
|
||||||
|
.memory
|
||||||
|
.read_word(idt + u32::from(interrupt.as_u8()) * 4)?;
|
||||||
|
println!("INFO: Interrupt {interrupt:?} addr: {addr}");
|
||||||
|
|
||||||
|
self.push(self.get(Register::Pcx))?;
|
||||||
|
*self.reg(Register::Pcx) = addr;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, val: u32) -> Result<(), ProcessorError> {
|
||||||
|
*self.reg(Register::Spr) -= 4;
|
||||||
|
let reg = *self.reg(Register::Spr);
|
||||||
|
self.memory.write_word(reg, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> Result<u32, ProcessorError> {
|
||||||
|
let reg = *self.reg(Register::Spr);
|
||||||
|
let val = self.memory.read_word(reg)?;
|
||||||
|
*self.reg(Register::Spr) += 4;
|
||||||
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this once implemented
|
// TODO: remove this once implemented
|
||||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||||
fn end_interrupt(&mut self) {
|
fn end_interrupt(&mut self) -> Result<(), ProcessorError> {
|
||||||
todo!();
|
let ret = self.pop()?;
|
||||||
|
*self.reg(Register::Ret) = ret;
|
||||||
|
*self.reg(Register::Pcx) = ret;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stack(&mut self, n: u32) -> Result<Vec<u8>, ProcessorError> {
|
pub fn get_stack(&mut self, n: u32) -> Result<Vec<u8>, ProcessorError> {
|
||||||
@@ -382,12 +409,12 @@ impl Executable for Instruction {
|
|||||||
// - The return address is saved to the RET register.
|
// - The return address is saved to the RET register.
|
||||||
// - The stack base ptr is set to the kernel stack.
|
// - The stack base ptr is set to the kernel stack.
|
||||||
Self::Interrupt(interrupt_code) => {
|
Self::Interrupt(interrupt_code) => {
|
||||||
cpu.begin_interrupt(interrupt_code);
|
cpu.begin_interrupt(interrupt_code)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns from an interrupt,
|
// Returns from an interrupt,
|
||||||
Self::IntReturn => {
|
Self::IntReturn => {
|
||||||
cpu.end_interrupt();
|
cpu.end_interrupt()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Halts the processor.
|
// Halts the processor.
|
||||||
|
|||||||
Reference in New Issue
Block a user