1use i8051::{ControlFlow, Instruction, Mnemonic};
2use serde::{Deserialize, Serialize};
3
4pub type AddressValue = u32;
5
6pub const AREA_ORDER: [AddressSpace; 5] = [
8 AddressSpace::Code,
9 AddressSpace::Idata,
10 AddressSpace::Sfr,
11 AddressSpace::Bit,
12 AddressSpace::Xdata,
13];
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
16pub enum AddressSpace {
17 Code,
18 Idata,
19 Sfr,
20 Bit,
21 Xdata,
22}
23
24impl AddressSpace {
25 pub fn area_header(self) -> &'static str {
26 match self {
27 Self::Code => ".area CODE (CODE,ABS)\n",
28 Self::Idata => ".area IDATA (IDATA,ABS)\n",
29 Self::Sfr => ".area SFR (SFR,ABS)\n",
30 Self::Bit => ".area BIT (BIT,ABS)\n",
31 Self::Xdata => ".area XDATA (XDATA,ABS)\n",
32 }
33 }
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
37pub struct PhysicalAddr {
38 pub space: AddressSpace,
39 pub offset: AddressValue,
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
43pub struct Xref {
44 pub from: PhysicalAddr,
45 pub to: PhysicalAddr,
46 pub xref_type: XrefType,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
50pub enum XrefType {
51 Call,
52 Jump,
53 Data,
54}
55
56pub fn branch_target_operand_index(insn: &Instruction) -> Option<usize> {
57 if branch_target(insn).is_none() {
58 return None;
59 }
60 match insn.mnemonic() {
61 Mnemonic::LJMP | Mnemonic::LCALL | Mnemonic::AJMP | Mnemonic::ACALL | Mnemonic::SJMP => {
62 Some(0)
63 }
64 _ => {
65 let decoded = insn.as_string();
66 let operand_count = decoded.split_once(' ').map_or(0, |(_, rest)| {
67 if rest.is_empty() {
68 0
69 } else {
70 rest.split(',').count()
71 }
72 });
73 if operand_count == 0 {
74 None
75 } else {
76 Some(operand_count - 1)
77 }
78 }
79 }
80}
81
82pub fn branch_target(insn: &Instruction) -> Option<u32> {
83 let next = insn.pc().wrapping_add(insn.len() as u32);
84 match insn.control_flow() {
85 ControlFlow::Continue(addr) if u32::from(addr) != next => Some(u32::from(addr)),
86 ControlFlow::Call(_, addr) => Some(u32::from(addr)),
87 ControlFlow::Choice(_, addr) => Some(u32::from(addr)),
88 _ => None,
89 }
90}
91
92pub fn xrefs_from_instruction(instruction: &Instruction, source: PhysicalAddr) -> Vec<Xref> {
93 let next = instruction.pc().wrapping_add(instruction.len() as u32);
94
95 let mut xrefs = Vec::new();
96 let mut push = |to_offset: u32, xref_type: XrefType| {
97 xrefs.push(Xref {
98 from: source,
99 to: PhysicalAddr {
100 space: source.space,
101 offset: to_offset,
102 },
103 xref_type,
104 });
105 };
106
107 match instruction.control_flow() {
108 ControlFlow::Continue(addr) if u32::from(addr) != next => {
109 push(u32::from(addr), xref_type_for(instruction.mnemonic()));
110 }
111 ControlFlow::Call(_, addr) => push(u32::from(addr), XrefType::Call),
112 ControlFlow::Choice(_, addr) => push(u32::from(addr), XrefType::Jump),
113 _ => {}
114 }
115
116 xrefs
117}
118
119pub fn xrefs_to_target(
120 instruction: &Instruction,
121 source: PhysicalAddr,
122 target: &PhysicalAddr,
123) -> Vec<Xref> {
124 xrefs_from_instruction(instruction, source)
125 .into_iter()
126 .filter(|xref| xref.to == *target)
127 .collect()
128}
129
130fn xref_type_for(opcode: Mnemonic) -> XrefType {
131 match opcode {
132 Mnemonic::LCALL | Mnemonic::ACALL => XrefType::Call,
133 _ => XrefType::Jump,
134 }
135}