mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-03 16:16:33 +00:00
parent
3fc494759e
commit
6b3528507f
@ -18,6 +18,9 @@ pub struct Line {
|
||||
/// Labels
|
||||
pub labels: Vec<LineLabel>,
|
||||
|
||||
/// Branch delay
|
||||
pub branch_delay: bool,
|
||||
|
||||
/// Instruction
|
||||
pub inst: Option<LineInst>,
|
||||
}
|
||||
@ -28,11 +31,22 @@ impl Line {
|
||||
let mut line = line.trim();
|
||||
|
||||
// Parse all labels and then the mnemonic
|
||||
let mut branch_delay = false;
|
||||
let mut labels = vec![];
|
||||
let mnemonic = loop {
|
||||
// If the line starts with a comment or is empty, return all labels
|
||||
if line.starts_with('#') || line.is_empty() {
|
||||
return Ok(Self { labels, inst: None });
|
||||
return Ok(Self {
|
||||
labels,
|
||||
branch_delay,
|
||||
inst: None,
|
||||
});
|
||||
}
|
||||
|
||||
// If we get a `+`, it's a branch delay
|
||||
if let Some(rest) = line.strip_prefix('+') {
|
||||
branch_delay = true;
|
||||
line = rest.trim_start();
|
||||
}
|
||||
|
||||
// Parse a name
|
||||
@ -41,7 +55,12 @@ impl Line {
|
||||
// Check the character after the name
|
||||
let mut rest = rest.chars();
|
||||
match rest.next() {
|
||||
// If we got ':', add a label and continue
|
||||
// If we get a label after the branch delay, return Err
|
||||
Some(':') if branch_delay => {
|
||||
return Err(ParseLineError::LabelAfterBranchDelay);
|
||||
},
|
||||
|
||||
// Else add the label
|
||||
Some(':') => {
|
||||
line = rest.as_str().trim_start();
|
||||
let label = LineLabel { name: name.to_owned() };
|
||||
@ -53,6 +72,7 @@ impl Line {
|
||||
Some('#') | None => {
|
||||
return Ok(Self {
|
||||
labels,
|
||||
branch_delay,
|
||||
inst: Some(LineInst {
|
||||
mnemonic: name.to_owned(),
|
||||
args: vec![],
|
||||
@ -60,12 +80,12 @@ impl Line {
|
||||
});
|
||||
},
|
||||
|
||||
// If we got a space or eof, we found the mnemonic.
|
||||
// On a space, break and parse arguments
|
||||
// If we got a space, we found the mnemonic.
|
||||
Some(' ') => {
|
||||
line = rest.as_str().trim_start();
|
||||
break name.to_owned();
|
||||
},
|
||||
|
||||
_ => return Err(ParseLineError::InvalidNameSuffix),
|
||||
}
|
||||
};
|
||||
@ -90,7 +110,11 @@ impl Line {
|
||||
// If we got eof or a comment, return
|
||||
Some('#') | None => {
|
||||
let inst = Some(LineInst { mnemonic, args });
|
||||
return Ok(Self { labels, inst });
|
||||
return Ok(Self {
|
||||
labels,
|
||||
branch_delay,
|
||||
inst,
|
||||
});
|
||||
},
|
||||
|
||||
_ => return Err(ParseLineError::InvalidArgSuffix),
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
//! Errors
|
||||
|
||||
// Imports
|
||||
use snailquote::UnescapeError;
|
||||
|
||||
|
||||
/// Error for [`Line::parse`](super::Line::parse)
|
||||
#[derive(PartialEq, Debug, thiserror::Error)]
|
||||
pub enum ParseLineError {
|
||||
@ -21,6 +21,10 @@ pub enum ParseLineError {
|
||||
/// Invalid argument suffix
|
||||
#[error("Invalid argument suffix")]
|
||||
InvalidArgSuffix,
|
||||
|
||||
/// Found label after branch delay token
|
||||
#[error("Labels must come before the branch delay token")]
|
||||
LabelAfterBranchDelay,
|
||||
}
|
||||
|
||||
/// Name parsing error
|
||||
|
||||
@ -131,7 +131,7 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
.map_err(|err| (n, err))?
|
||||
.size();
|
||||
|
||||
assert!(insts.insert(cur_pos, (n, inst)).is_none());
|
||||
assert!(insts.insert(cur_pos, (n, line.branch_delay, inst)).is_none());
|
||||
|
||||
cur_pos += inst_size;
|
||||
}
|
||||
@ -160,17 +160,46 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
.context("Unable to seek stream to beginning of instructions")?;
|
||||
|
||||
// For each instruction, pack it and output it to the file
|
||||
for (&pos, (n, inst)) in &insts {
|
||||
let mut last_inst = None;
|
||||
for (&pos, &(n, branch_delay, ref inst)) in &insts {
|
||||
// Create the context
|
||||
let ctx = Ctx {
|
||||
pos,
|
||||
labels_by_name: &labels_by_name,
|
||||
};
|
||||
|
||||
// If this instruction has a branch delay marker, if the previous instruction wasn't
|
||||
// a jump, return Err
|
||||
if branch_delay && !last_inst.as_ref().map_or(false, Inst::may_jump) {
|
||||
anyhow::bail!(
|
||||
"Unable to parse line {}: Branch delay markers can only be used when the previous instruction is a \
|
||||
jump",
|
||||
n
|
||||
);
|
||||
}
|
||||
|
||||
// If this instruction doesn't have a branch delay marker, but the previous instruction
|
||||
// was a jump, return Err
|
||||
if !branch_delay && last_inst.as_ref().map_or(false, Inst::may_jump) {
|
||||
anyhow::bail!(
|
||||
"Unable to parse line {}: Must use a branch delay after a jump instruction",
|
||||
n
|
||||
);
|
||||
}
|
||||
|
||||
let inst = Inst::parse(&inst.mnemonic, &inst.args, &ctx)
|
||||
.with_context(|| format!("Unable to compile instruction at {} in line {}", pos, n + 1))?;
|
||||
|
||||
// If we got a pseudo instruction larger than 1 basic instruction after a jump, return Err
|
||||
if branch_delay && inst.size() > 4 {
|
||||
anyhow::bail!(
|
||||
"Unable to parse line {}: Cannot use a pseudo instruction larger than 4 bytes as a branch delay",
|
||||
n
|
||||
);
|
||||
}
|
||||
|
||||
inst.write(&mut output_file).context("Unable to write to file")?;
|
||||
last_inst = Some(inst);
|
||||
}
|
||||
|
||||
let size = output_file.stream_position().context("Unable to get stream position")? - 0x800;
|
||||
|
||||
@ -227,12 +227,18 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
|
||||
// If it's standalone, print it by it's own
|
||||
ExeItem::Unknown { insts } => {
|
||||
let mut prev_inst = None;
|
||||
for (pos, inst) in insts {
|
||||
// Write the position
|
||||
if cli.print_inst_pos {
|
||||
print!("{pos}: ");
|
||||
}
|
||||
|
||||
// If we had a branch / jump instruction before this one, add a "+ "
|
||||
if prev_inst.as_ref().map_or(false, Inst::may_jump) {
|
||||
print!("+ ");
|
||||
}
|
||||
|
||||
// Write the instruction
|
||||
print!(
|
||||
"{}",
|
||||
@ -240,6 +246,8 @@ fn main() -> Result<(), anyhow::Error> {
|
||||
);
|
||||
|
||||
println!();
|
||||
|
||||
prev_inst = Some(inst);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@ -230,7 +230,7 @@
|
||||
inline_comments:
|
||||
0x80061910: "args: ($s1, $s0, c & 0xffff, d & 0xffff)"
|
||||
start_pos: 0x800618e4
|
||||
end_pos: 0x80061954
|
||||
end_pos: 0x80061958
|
||||
kind: Known
|
||||
|
||||
- name: modify_spu_delay1
|
||||
@ -847,6 +847,42 @@
|
||||
end_pos: 0x8004b394
|
||||
kind: Known
|
||||
|
||||
- name: something43
|
||||
labels:
|
||||
0x8002d0f4: "0"
|
||||
0x8002d104: "1"
|
||||
0x8002d110: "2"
|
||||
0x8002d120: "3"
|
||||
0x8002d130: "4"
|
||||
start_pos: 0x8002d0e4
|
||||
end_pos: 0x8002d140
|
||||
kind: Known
|
||||
|
||||
- name: something44
|
||||
start_pos: 0x800316a8
|
||||
end_pos: 0x800316b4
|
||||
kind: Known
|
||||
|
||||
- name: something45
|
||||
start_pos: 0x80063cb0
|
||||
end_pos: 0x80063cbc
|
||||
kind: Known
|
||||
|
||||
- name: something46
|
||||
start_pos: 0x80063cc4
|
||||
end_pos: 0x80063cd0
|
||||
kind: Known
|
||||
|
||||
- name: something47
|
||||
start_pos: 0x80063cd8
|
||||
end_pos: 0x80063ce4
|
||||
kind: Known
|
||||
|
||||
- name: something48
|
||||
start_pos: 0x80063d04
|
||||
end_pos: 0x80063d10
|
||||
kind: Known
|
||||
|
||||
# A functions
|
||||
- name: InitHeap
|
||||
signature: "fn(addr: *u32, size: u32)"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user