Skip to content

Commit

Permalink
Refactor the parser to better handle instructions that have labels.
Browse files Browse the repository at this point in the history
The parser will handle instructions that have labels better now, and these instructions will use the label rather than the pseudo address when displayed.

In addition to this the code to calculate the destination addresses for local (relative) jumps has been removed, this will be added to the compiler instead.
  • Loading branch information
sciguyryan committed Jan 30, 2024
1 parent 6ea72fd commit 57dacfe
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 172 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ bitflags = "2.4.2"
criterion = "0.5.1"
float-cmp = "0.9.0"
hashbrown = "0.14.3"
itertools = "0.12.0"
itertools = "0.12.1"
num-traits = "0.2.17"
num-derive = "0.4.1"
prettytable = "0.10.0"
Expand Down
8 changes: 4 additions & 4 deletions redox-core/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ pub fn criterion_vm_complex_program(c: &mut Criterion) {
Instruction::PushU32Imm(3), // Starts at [base]. Length = 8. This should remain in place.
Instruction::PushU32Imm(2), // Starts at [base + 8]. Length = 8. Subroutine argument 1.
Instruction::PushU32Imm(1), // Starts at [base + 16]. Length = 8. The number of arguments.
Instruction::CallAbsU32Imm(base_offset + 36), // Starts at [base + 24]. Length = 8.
Instruction::Halt, // Starts at [base + 32]. Length = 4.
Instruction::CallAbsU32Imm(base_offset + 36, String::default()), // Starts at [base + 24]. Length = 8.
Instruction::Halt, // Starts at [base + 32]. Length = 4.
/***** FUNC_AAAA - Subroutine 1 starts here. *****/
Instruction::PushU32Imm(0), // Starts at [base + 36]. Length = 8. The number of arguments.
Instruction::CallAbsU32Imm(base_offset + 65), // Starts at [base + 44]. Length = 8.
Instruction::CallAbsU32Imm(base_offset + 65, String::default()), // Starts at [base + 44]. Length = 8.
Instruction::AddU32ImmU32Reg(5, RegisterId::EAX), // Starts at [base + 52]. Length = 9.
Instruction::RetArgsU32, // Starts at [base + 61]. Length = 4.
Instruction::RetArgsU32, // Starts at [base + 61]. Length = 4.
/***** FUNC_BBBB - Subroutine 2 starts here. *****/
Instruction::PushU32Imm(100), // Starts at [base + 65]. Length = 8. This should NOT be preserved.
Instruction::PopU32ToU32Reg(RegisterId::EAX),
Expand Down
7 changes: 4 additions & 3 deletions redox-core/src/boot_rom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl BootRom {
// Call the setup code for the interrupt vector table.
// This is a placeholder and it will be replaced further in this method.
Instruction::PushU32Imm(0x0),
Instruction::CallAbsU32Imm(0xffffffff),
Instruction::CallAbsU32Imm(0xffffffff, String::from("")),
// Load the interrupt descriptor table register with the IVT location in memory.
Instruction::LoadIVTAddrU32Imm(DEFAULT_IVT_ADDRESS),
// Enable CPU interrupts.
Expand Down Expand Up @@ -119,12 +119,13 @@ impl BootRom {
// update that in our earlier call code. It will directly follow the last IVT handler.
let index = final_instructions
.iter()
.position(|e| *e == Instruction::CallAbsU32Imm(0xffffffff))
.position(|e| *e == Instruction::CallAbsU32Imm(0xffffffff, String::from("")))
.expect("failed to find correct instruction");

// Replace the dummy call instruction with one that has the correct
// subroutine address.
final_instructions[index] = Instruction::CallAbsU32Imm(next_handler_pos as u32);
final_instructions[index] =
Instruction::CallAbsU32Imm(next_handler_pos as u32, String::from(""));

// Return the compiled bytecode.
Compiler::new().compile(&final_instructions).to_vec()
Expand Down
10 changes: 4 additions & 6 deletions redox-core/src/compiling/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ impl Compiler {
I::MulU32Imm(imm)
| I::DivU32Imm(imm)
| I::PushU32Imm(imm)
| I::CallAbsU32Imm(imm)
| I::CallRelCSU32Offset(imm)
| I::CallAbsU32Imm(imm, _)
| I::CallRelCSU32Offset(imm, _)
| I::JumpAbsU32Imm(imm)
| I::LoadIVTAddrU32Imm(imm) => {
self.write_u32(imm);
Expand Down Expand Up @@ -137,7 +137,6 @@ impl Compiler {
| I::PushU32Reg(reg)
| I::PopU32ToU32Reg(reg)
| I::CallAbsU32Reg(reg)
| I::CallRelCSU32RegOffset(reg)
| I::PopF32ToF32Reg(reg) => {
self.write_register_id(&reg);
}
Expand Down Expand Up @@ -313,11 +312,10 @@ mod tests_compiler {
O::RightShiftU32RegU32Reg => I::RightShiftU32RegU32Reg(EBX, ECX),
O::ArithRightShiftU8ImmU32Reg => I::ArithRightShiftU8ImmU32Reg(31, EBX),
O::ArithRightShiftU32RegU32Reg => I::ArithRightShiftU32RegU32Reg(EBX, ECX),
O::CallAbsU32Imm => I::CallAbsU32Imm(0xdeadbeef),
O::CallAbsU32Imm => I::CallAbsU32Imm(0xdeadbeef, String::default()),
O::CallAbsU32Reg => I::CallAbsU32Reg(RegisterId::EBX),
O::CallRelU32RegU32Offset => I::CallRelU32RegU32Offset(0xdeadbeef, RegisterId::EBX),
O::CallRelCSU32Offset => I::CallRelCSU32Offset(0xdeadbeef),
O::CallRelCSU32RegOffset => I::CallRelCSU32RegOffset(RegisterId::EBX),
O::CallRelCSU32Offset => I::CallRelCSU32Offset(0xdeadbeef, String::default()),
O::RetArgsU32 => I::RetArgsU32,
O::Int => I::Int(0xff),
O::IntRet => I::IntRet,
Expand Down
31 changes: 10 additions & 21 deletions redox-core/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@ impl Cpu {
}

/******** [Branching Instructions] ********/
I::CallAbsU32Imm(addr) => {
I::CallAbsU32Imm(addr, _) => {
// call 0xdeafbeef
self.perform_call_jump(&mut com_bus.mem, *addr);
}
Expand All @@ -996,7 +996,7 @@ impl Cpu {
// callr &[reg + 0xdeadbeef]
self.perform_call_offset_jump(&mut com_bus.mem, base_reg, *offset, privilege);
}
I::CallRelCSU32Offset(offset) => {
I::CallRelCSU32Offset(offset, _) => {
// call :label - calls to labels within the bounds of the program code block will automatically be converted.
// callr 0xdeadbeef
self.perform_call_offset_jump(
Expand All @@ -1006,17 +1006,6 @@ impl Cpu {
privilege,
);
}
I::CallRelCSU32RegOffset(reg) => {
// callr ebx
let offset = self.registers.read_reg_u32(reg, privilege);

self.perform_call_offset_jump(
&mut com_bus.mem,
&RegisterId::ECS,
offset,
privilege,
);
}
I::RetArgsU32 => {
// iret
// Restore the state of the last stack frame.
Expand Down Expand Up @@ -2275,9 +2264,9 @@ mod tests_cpu {
Instruction::PushU32Imm(3), // Starts at [ECS]. Length = 8. This should remain in place.
Instruction::PushU32Imm(2), // Starts at [ECS + 8]. Length = 8. Subroutine argument 1.
Instruction::PushU32Imm(1), // Starts at [ECS + 16]. Length = 8. The number of arguments.
Instruction::CallRelCSU32Offset(45), // Starts at [ECS + 24]. Length = 8.
Instruction::CallRelCSU32Offset(45, String::default()), // Starts at [ECS + 24]. Length = 8.
Instruction::AddU32ImmU32Reg(100, RegisterId::EAX), // Starts at [ECS + 32]. Length = 9.
Instruction::Halt, // Starts at [ECS + 41]. Length = 4.
Instruction::Halt, // Starts at [ECS + 41]. Length = 4.
/***** FUNC_AAAA - Subroutine starts here. *****/
Instruction::PushU32Imm(5), // Starts at [ECS + 45].
Instruction::PopU32ToU32Reg(RegisterId::EAX),
Expand Down Expand Up @@ -2440,8 +2429,8 @@ mod tests_cpu {
Instruction::MovU32ImmU32Reg(test_registers[6].1, test_registers[6].0), // Starts at [base + 54]. Length = 9.
// The number of arguments for the subroutine.
Instruction::PushU32Imm(0), // Starts at [base + 63]. Length = 8. The number of arguments.
Instruction::CallAbsU32Imm(base_offset + 83), // Starts at [base + 71]. Length = 8.
Instruction::Halt, // Starts at [base + 79]. Length = 4.
Instruction::CallAbsU32Imm(base_offset + 83, String::from("")), // Starts at [base + 71]. Length = 8.
Instruction::Halt, // Starts at [base + 79]. Length = 4.
/***** FUNC_AAAA - Subroutine starts here. *****/
Instruction::MovU32ImmU32Reg(0, RegisterId::EBX), // Starts at [base + 83].
Instruction::MovU32ImmU32Reg(0, RegisterId::ECX),
Expand Down Expand Up @@ -2485,13 +2474,13 @@ mod tests_cpu {
Instruction::PushU32Imm(3), // Starts at [base]. Length = 8. This should remain in place.
Instruction::PushU32Imm(2), // Starts at [base + 8]. Length = 8. Subroutine argument 1.
Instruction::PushU32Imm(1), // Starts at [base + 16]. Length = 8. The number of arguments.
Instruction::CallAbsU32Imm(base_offset + 36), // Starts at [base + 24]. Length = 8.
Instruction::Halt, // Starts at [base + 32]. Length = 4.
Instruction::CallAbsU32Imm(base_offset + 36, String::from("")), // Starts at [base + 24]. Length = 8.
Instruction::Halt, // Starts at [base + 32]. Length = 4.
/***** FUNC_AAAA - Subroutine 1 starts here. *****/
Instruction::PushU32Imm(0), // Starts at [base + 36]. Length = 8. The number of arguments.
Instruction::CallAbsU32Imm(base_offset + 65), // Starts at [base + 44]. Length = 8.
Instruction::CallAbsU32Imm(base_offset + 65, String::from("")), // Starts at [base + 44]. Length = 8.
Instruction::AddU32ImmU32Reg(5, RegisterId::EAX), // Starts at [base + 52]. Length = 9.
Instruction::RetArgsU32, // Starts at [base + 61]. Length = 4.
Instruction::RetArgsU32, // Starts at [base + 61]. Length = 4.
/***** FUNC_BBBB - Subroutine 2 starts here. *****/
Instruction::PushU32Imm(100), // Starts at [base + 65]. Length = 8. This should NOT be preserved.
Instruction::PopU32ToU32Reg(RegisterId::EAX),
Expand Down
27 changes: 14 additions & 13 deletions redox-core/src/ins/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,13 @@ pub enum Instruction {

/******** [Branching Instructions] ********/
/// Call a subroutine at a specified absolute u32 immediate address.
CallAbsU32Imm(u32),
CallAbsU32Imm(u32, String),
/// Call a subroutine at an absolute address as specified by a u32 register.
CallAbsU32Reg(RegisterId),
/// Call a subroutine at an address as given by an offset from the address pointed to a u32 register.
CallRelU32RegU32Offset(u32, RegisterId),
/// Call a subroutine at an address as given the ECS register and offset by a u32 immediate.
CallRelCSU32Offset(u32),
/// Call a subroutine at an address as given the ECS register and offset by the value of a u32 register.
CallRelCSU32RegOffset(RegisterId),
CallRelCSU32Offset(u32, String),
/// Return from a subroutine that had zero or more u32 arguments supplied.
RetArgsU32,
/// Trigger a specific type of interrupt handler.
Expand Down Expand Up @@ -282,21 +280,25 @@ impl Display for Instruction {
}

/******** [Branching Instructions] ********/
I::CallAbsU32Imm(addr) => {
// TODO - apply labels to these jumps - either dynamically generated or via binary file metadata.
format!("call &0x{addr:08x}")
I::CallAbsU32Imm(addr, label) => {
if label.is_empty() {
format!("call &0x{addr:08x}")
} else {
format!("call {label}")
}
}
I::CallAbsU32Reg(reg) => {
format!("call &{reg}")
}
I::CallRelU32RegU32Offset(offset, reg) => {
format!("callr 0x{offset:08x}, &{reg}")
}
I::CallRelCSU32Offset(offset) => {
format!("callr 0x{offset:08x}")
}
I::CallRelCSU32RegOffset(offset_reg) => {
format!("callr {offset_reg}")
I::CallRelCSU32Offset(offset, label) => {
if label.is_empty() {
format!("callr 0x{offset:08x}")
} else {
format!("callr {label}")
}
}
I::RetArgsU32 => String::from("iret"),
I::Int(int_code) => {
Expand Down Expand Up @@ -528,7 +530,6 @@ impl Instruction {
O::CallAbsU32Reg => ARG_REG_ID_SIZE,
O::CallRelU32RegU32Offset => ARG_U32_IMM_SIZE + ARG_REG_ID_SIZE,
O::CallRelCSU32Offset => ARG_U32_IMM_SIZE,
O::CallRelCSU32RegOffset => ARG_REG_ID_SIZE,
O::RetArgsU32 => 0,
O::Int => ARG_U8_IMM_SIZE,
O::IntRet => 0,
Expand Down
7 changes: 2 additions & 5 deletions redox-core/src/ins/op_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ pub enum OpCode {
CallRelU32RegU32Offset,
/// Call a subroutine at an address as given the ECS register and offset by a u32 immediate.
CallRelCSU32Offset,
/// Call a subroutine at an address as given the ECS register and offset by the value of a u32 register.
CallRelCSU32RegOffset,
/// Return from a subroutine that had zero or more u32 arguments supplied.
RetArgsU32,
/// Trigger a specific type of interrupt handler.
Expand Down Expand Up @@ -225,11 +223,10 @@ impl From<&Instruction> for OpCode {
I::ArithRightShiftU32RegU32Reg(_, _) => O::ArithRightShiftU32RegU32Reg,

/******** [Branching Instructions] ********/
I::CallAbsU32Imm(_) => O::CallAbsU32Imm,
I::CallAbsU32Imm(_, _) => O::CallAbsU32Imm,
I::CallAbsU32Reg(_) => O::CallAbsU32Reg,
I::CallRelU32RegU32Offset(_, _) => O::CallRelU32RegU32Offset,
I::CallRelCSU32Offset(_) => O::CallRelCSU32Offset,
I::CallRelCSU32RegOffset(_) => O::CallRelCSU32RegOffset,
I::CallRelCSU32Offset(_, _) => O::CallRelCSU32Offset,
I::RetArgsU32 => O::RetArgsU32,
I::Int(_) => O::Int,
I::IntRet => O::IntRet,
Expand Down
9 changes: 2 additions & 7 deletions redox-core/src/mem/memory_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ impl MemoryHandler {
O::CallAbsU32Imm => {
let addr = Self::read_u32(arg_bytes, &mut cursor);

I::CallAbsU32Imm(addr)
I::CallAbsU32Imm(addr, String::default())
}
O::CallAbsU32Reg => {
let reg = Self::read_register_id(arg_bytes, &mut cursor);
Expand All @@ -466,12 +466,7 @@ impl MemoryHandler {
O::CallRelCSU32Offset => {
let offset = Self::read_u32(arg_bytes, &mut cursor);

I::CallRelCSU32Offset(offset)
}
O::CallRelCSU32RegOffset => {
let offset_reg = Self::read_register_id(arg_bytes, &mut cursor);

I::CallRelCSU32RegOffset(offset_reg)
I::CallRelCSU32Offset(offset, String::default())
}
O::RetArgsU32 => I::RetArgsU32,
O::Int => {
Expand Down
Loading

0 comments on commit 57dacfe

Please sign in to comment.