Skip to main content

c6000_disassembler/
lib.rs

1use std::io::{Error, ErrorKind, Result};
2
3use crate::instruction::{
4    C6000Instruction, InstructionInput,
5    branching::BranchInstruction,
6    fphead::CompactInstructionHeader,
7    invalid::InvalidInstruction,
8    memory::MemoryInstruction,
9    moving::{MoveConstantInstruction, MoveRegisterInstruction},
10    nop::NOPInstruction,
11};
12
13pub mod instruction;
14
15/// Reads a compact 16-bit instruction and returns a result containing a
16/// struct with the [C6000Instruction] trait.
17pub fn read_compact_instruction(input: InstructionInput) -> Result<Box<dyn C6000Instruction>> {
18    if let Ok(instruction) = MoveConstantInstruction::new_compact(&input) {
19        return Ok(Box::new(instruction));
20    }
21
22    if let Ok(instruction) = MoveRegisterInstruction::new_compact(&input) {
23        return Ok(Box::new(instruction));
24    }
25
26    if let Ok(instruction) = BranchInstruction::new_compact(&input) {
27        return Ok(Box::new(instruction));
28    }
29
30    if let Ok(instruction) = NOPInstruction::new_compact(&input) {
31        return Ok(Box::new(instruction));
32    }
33
34    Ok(Box::new(InvalidInstruction::new_compact(&input)?))
35}
36
37/// Reads a 32-bit instruction and returns a result containing a
38/// struct with the [C6000Instruction] trait.
39pub fn read_instruction(input: InstructionInput) -> Result<Box<dyn C6000Instruction>> {
40    if let Ok(instruction) = MoveConstantInstruction::new(&input) {
41        return Ok(Box::new(instruction));
42    }
43
44    if let Ok(instruction) = MoveRegisterInstruction::new(&input) {
45        return Ok(Box::new(instruction));
46    }
47
48    if let Ok(instruction) = BranchInstruction::new(&input) {
49        return Ok(Box::new(instruction));
50    }
51
52    if let Ok(instruction) = MemoryInstruction::new(&input) {
53        return Ok(Box::new(instruction));
54    }
55
56    if let Ok(instruction) = NOPInstruction::new(&input) {
57        return Ok(Box::new(instruction));
58    }
59
60    Ok(Box::new(InvalidInstruction::new(&input)?))
61}
62
63/// Size of a regular instruction in bytes
64pub const INSTRUCTION_SIZE: usize = 4;
65/// Size of a compact instruction in bytes
66pub const COMPACT_INSTRUCTION_SIZE: usize = 2;
67/// Size of an FP (Fetch Packet) in bytes
68pub const PACKET_SIZE: usize = 8 * INSTRUCTION_SIZE;
69
70pub fn read_packet(
71    packet: [u8; PACKET_SIZE],
72    address: u32,
73) -> Result<Vec<Box<dyn C6000Instruction>>> {
74    let mut vec: Vec<Box<dyn C6000Instruction>> = vec![];
75    let Ok(fphead) = CompactInstructionHeader::new(&InstructionInput {
76        opcode: u32::from_le_bytes([
77            packet[PACKET_SIZE - 4],
78            packet[PACKET_SIZE - 3],
79            packet[PACKET_SIZE - 2],
80            packet[PACKET_SIZE - 1],
81        ]),
82        fphead: None,
83        pce1_address: address,
84    }) else {
85        return Err(Error::new(
86            ErrorKind::InvalidInput,
87            "Not a fetch packet, use read_instruction instead.",
88        ));
89    };
90
91    let mut index = 0;
92    let mut previous_p_bit = false;
93    while index < 7 * 4 {
94        let instruction = {
95            if fphead.layout[index / 4] {
96                let mut compact_instruction = read_compact_instruction(InstructionInput {
97                    opcode: u16::from_le_bytes([packet[index], packet[index + 1]]) as u32,
98                    fphead: Some(fphead.clone()),
99                    pce1_address: address,
100                })?;
101                compact_instruction.set_parallel(previous_p_bit);
102                previous_p_bit = fphead.compact_p_bits[index / 2];
103                compact_instruction
104            } else {
105                let mut instruction = read_instruction(InstructionInput {
106                    opcode: u32::from_le_bytes([
107                        packet[index],
108                        packet[index + 1],
109                        packet[index + 2],
110                        packet[index + 3],
111                    ]),
112                    fphead: Some(fphead.clone()),
113                    pce1_address: address,
114                })?;
115                instruction.set_parallel(previous_p_bit);
116                previous_p_bit = instruction.get_p_bit();
117                instruction
118            }
119        };
120
121        if instruction.as_any().is::<CompactInstructionHeader>() {
122            return Err(Error::new(
123                ErrorKind::InvalidData,
124                "Compact instruction header found in unusual place",
125            ));
126        }
127
128        if instruction.is_compact() {
129            index += 2;
130        } else {
131            index += 4;
132        }
133        vec.push(instruction);
134    }
135
136    vec.push(Box::new(fphead));
137
138    Ok(vec)
139}