use zerodmg_utils::little_endian::{u16_to_u8s, u8s_to_u16};
use std::fmt;
use std::fmt::{Debug, Display};
use crate::instruction::Instruction;
use crate::instruction::Instruction::*;
use crate::instruction::U16Register::*;
use crate::instruction::U8Register::*;
pub mod prelude {
pub use super::AssembledROM;
pub use super::DisassembledROM;
pub use super::ROMBlock;
pub use super::ROMBlockContent::*;
}
use self::prelude::*;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DisassembledROM {
pub blocks: Vec<ROMBlock>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ROMBlock {
pub content: ROMBlockContent,
pub address: Option<u16>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ROMBlockContent {
Code(Vec<Instruction>),
Data(Vec<u8>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AssembledROM {
pub bytes: Vec<ROMByte>,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ROMByte {
pub byte: u8,
pub role: ROMByteRole,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ROMByteRole {
Unknown,
InstructionStart(Instruction, IsJumpDestination),
InstructionRest,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum IsJumpDestination {
Unknown,
Yes,
}
trait FlowsTo {
fn flows_to(&self) -> ControlFlowsTo;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct ControlFlowsTo {
next: bool,
jump: Option<JumpReference>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum JumpReference {
Absolute(u16),
Relative(i8),
}
impl FlowsTo for Instruction {
fn flows_to(&self) -> ControlFlowsTo {
match self {
NOP => ControlFlowsTo::next(),
INC(_) => ControlFlowsTo::next(),
DEC(_) => ControlFlowsTo::next(),
JP_NZ(address) => ControlFlowsTo::next_and_jump(JumpReference::Absolute(*address)),
JP(address) => ControlFlowsTo::jump(JumpReference::Absolute(*address)),
}
}
}
impl ControlFlowsTo {
pub fn none() -> Self {
ControlFlowsTo {
next: false,
jump: None,
}
}
pub fn next() -> Self {
ControlFlowsTo {
next: true,
jump: None,
}
}
pub fn jump(jump: JumpReference) -> Self {
ControlFlowsTo {
next: false,
jump: Some(jump),
}
}
pub fn next_and_jump(jump: JumpReference) -> Self {
ControlFlowsTo {
next: false,
jump: Some(jump),
}
}
}
impl DisassembledROM {
pub fn example() -> DisassembledROM {
DisassembledROM {
blocks: vec![ROMBlock {
address: None,
content: Code(vec![INC(A), INC(A), INC(B), INC(C)]),
}],
}
}
}
impl AssembledROM {
pub fn new(bytes: &Vec<u8>) -> Self {
let mut assembled = Self::from(bytes);
assembled.get_known_instruction(0x0000);
assembled
}
pub fn get_known_instruction(&mut self, _address: u16) -> Instruction {
unimplemented!();
}
pub fn example() -> AssembledROM {
AssembledROM {
bytes: vec![
ROMByte {
role: ROMByteRole::InstructionStart(INC(A), IsJumpDestination::Yes),
byte: 0x3C,
},
ROMByte {
role: ROMByteRole::InstructionStart(INC(A), IsJumpDestination::Unknown),
byte: 0x3C,
},
ROMByte {
role: ROMByteRole::InstructionStart(INC(B), IsJumpDestination::Unknown),
byte: 0x04,
},
ROMByte {
role: ROMByteRole::InstructionStart(INC(C), IsJumpDestination::Unknown),
byte: 0x0C,
},
],
}
}
}
#[test]
fn test_disassembled_from_assembled() {
let assembled = AssembledROM::example();
let _disassembled = DisassembledROM::from(&assembled);
}
impl From<&AssembledROM> for DisassembledROM {
fn from(_assembled: &AssembledROM) -> Self {
unimplemented!()
}
}
#[test]
fn test_assembled_from_disassembled() {
let disassembled = DisassembledROM::example();
let _assembled = AssembledROM::from(&disassembled);
}
impl From<&DisassembledROM> for AssembledROM {
fn from(_assembled: &DisassembledROM) -> Self {
unimplemented!()
}
}
#[test]
fn test_assembled_from_bytes_then_decode_trivial() {
let bytes = vec![0x3Cu8, 0x3C, 0x04, 0x0C];
let mut assembled = AssembledROM::from(&bytes);
assert_eq!(NOP, assembled.get_known_instruction(0x0000));
assert_eq!(INC(A), assembled.get_known_instruction(0x0001));
assert_eq!(INC(B), assembled.get_known_instruction(0x0002));
assert_eq!(INC(C), assembled.get_known_instruction(0x0003));
assert_eq!(NOP, assembled.get_known_instruction(0x0000));
}
impl From<&Vec<u8>> for AssembledROM {
fn from(bytes: &Vec<u8>) -> Self {
Self {
bytes: bytes.iter().map(|byte| byte.clone().into()).collect(),
}
}
}
#[test]
fn test_bytes_from_assembled() {
let assembled = AssembledROM::example();
let _bytes = Vec::<u8>::from(&assembled);
}
impl From<&AssembledROM> for Vec<u8> {
fn from(assembled: &AssembledROM) -> Self {
assembled.bytes.iter().map(|&byte| byte.byte).collect()
}
}
impl From<ROMBlockContent> for ROMBlock {
fn from(content: ROMBlockContent) -> Self {
Self {
content,
address: None,
}
}
}
impl From<u8> for ROMByte {
fn from(byte: u8) -> Self {
Self {
byte,
role: ROMByteRole::Unknown,
}
}
}
impl From<Vec<ROMBlock>> for DisassembledROM {
fn from(blocks: Vec<ROMBlock>) -> Self {
DisassembledROM { blocks }
}
}
impl From<Vec<ROMBlockContent>> for DisassembledROM {
fn from(blocks_contents: Vec<ROMBlockContent>) -> Self {
DisassembledROM {
blocks: blocks_contents
.into_iter()
.map(|content| content.into())
.collect(),
}
}
}
impl From<Vec<Instruction>> for DisassembledROM {
fn from(instructions: Vec<Instruction>) -> Self {
DisassembledROM {
blocks: vec![Code(instructions).into()],
}
}
}
impl From<Vec<u8>> for DisassembledROM {
fn from(bytes: Vec<u8>) -> Self {
(&AssembledROM::from(&bytes)).into()
}
}
impl From<Vec<ROMBlock>> for AssembledROM {
fn from(blocks: Vec<ROMBlock>) -> Self {
(&DisassembledROM::from(blocks)).into()
}
}
impl From<Vec<ROMBlockContent>> for AssembledROM {
fn from(blocks_contents: Vec<ROMBlockContent>) -> Self {
(&DisassembledROM::from(blocks_contents)).into()
}
}
impl From<Vec<Instruction>> for AssembledROM {
fn from(instructions: Vec<Instruction>) -> Self {
(&DisassembledROM::from(instructions)).into()
}
}
impl From<&DisassembledROM> for Vec<u8> {
fn from(disassembled: &DisassembledROM) -> Self {
(&AssembledROM::from(disassembled)).into()
}
}
impl Display for DisassembledROM {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for block in self.blocks.iter() {
Display::fmt(&block, f)?;
write!(f, "\n")?;
}
Ok(())
}
}
impl Display for ROMBlock {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(address) = self.address {
write!(f, "0x{:04X}:\n", address)?;
} else {
write!(f, "0x____:\n")?;
}
match self.content {
Data(ref bytes) => {
let mut n = 0;
for byte in bytes.iter() {
if n == 0 {
write!(f, " DATA 0x")?;
n += 6;
}
write!(f, "{:02X}", byte)?;
n += 2;
if n >= 61 {
write!(f, "\n")?;
n = 0;
}
}
write!(f, "\n")?;
}
Code(ref instructions) => {
for instruction in instructions.iter() {
write!(f, " {}\n", instruction)?;
}
}
}
Ok(())
}
}