Compare commits
2 Commits
8c08555003
...
258e4dc59b
| Author | SHA1 | Date | |
|---|---|---|---|
| 258e4dc59b | |||
| a5042383c9 |
@ -21,24 +21,34 @@ fn main() {
|
|||||||
// Fill with 0xea -> NOP
|
// Fill with 0xea -> NOP
|
||||||
let mut vec: [u8; SIZE_32KB] = [ISA_OP_NOP; SIZE_32KB];
|
let mut vec: [u8; SIZE_32KB] = [ISA_OP_NOP; SIZE_32KB];
|
||||||
|
|
||||||
|
// Load to A
|
||||||
vec[0] = ISA_OP_LDA_I; // LDA #$ab
|
vec[0] = ISA_OP_LDA_I; // LDA #$ab
|
||||||
vec[1] = 0b1010_1011; // 1010 1011
|
vec[1] = 0b1010_1011; // 1010 1011
|
||||||
|
// Jump to rotate cycle
|
||||||
vec[2] = 0x02; // --
|
vec[2] = 0x02; // --
|
||||||
vec[3] = 0x03; // --
|
vec[3] = 0x03; // --
|
||||||
|
|
||||||
|
// Jump to Main
|
||||||
|
vec[0x2210] = ISA_OP_JMP_ABS;
|
||||||
|
vec[0x2211] = 0x00;
|
||||||
|
vec[0x2212] = 0x40;
|
||||||
|
|
||||||
|
// load to a
|
||||||
vec[0x4000] = ISA_OP_LDA_I;
|
vec[0x4000] = ISA_OP_LDA_I;
|
||||||
vec[0x4001] = 0b0101_0100;
|
vec[0x4001] = 0b0101_0100;
|
||||||
|
// jump to top of load to a
|
||||||
vec[0x4002] = ISA_OP_JMP_ABS;
|
vec[0x4002] = ISA_OP_JMP_ABS;
|
||||||
vec[0x4003] = 0x00;
|
vec[0x4003] = 0x00;
|
||||||
vec[0x4004] = 0x40;
|
vec[0x4004] = 0x40;
|
||||||
vec[0x4005] = ISA_OP_NOP;
|
vec[0x4005] = ISA_OP_NOP;
|
||||||
|
|
||||||
|
vec[0x7ffa] = 0x22; // NMI Vector
|
||||||
|
vec[0x7ffb] = 0x11;
|
||||||
vec[0x7ffc] = 0x12; // Reset Vector
|
vec[0x7ffc] = 0x12; // Reset Vector
|
||||||
vec[0x7ffd] = 0x34;
|
vec[0x7ffd] = 0x34;
|
||||||
vec[0x7ffe] = 0x43; // Interrupt Vector
|
vec[0x7ffe] = 0x43; // Interrupt Vector
|
||||||
vec[0x7fff] = 0x21;
|
vec[0x7fff] = 0x21;
|
||||||
|
|
||||||
|
|
||||||
vec = le_swap(&vec);
|
vec = le_swap(&vec);
|
||||||
|
|
||||||
// write the rom to disk
|
// write the rom to disk
|
||||||
|
|||||||
154
cli/src/bin/de6502.rs
Normal file
154
cli/src/bin/de6502.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::thread::current;
|
||||||
|
use core::constants::constants_system::*;
|
||||||
|
use core::constants::constants_isa_op::*;
|
||||||
|
use clap::{Parser, Subcommand};
|
||||||
|
use core::instruction_table::INSTRUCTION_TABLE;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(version, about, long_about = None)]
|
||||||
|
struct CliOptions {
|
||||||
|
/// File to Decompile
|
||||||
|
input: PathBuf,
|
||||||
|
/// File to write
|
||||||
|
output: PathBuf
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DecompiledLine {
|
||||||
|
offset: u16,
|
||||||
|
text: String,
|
||||||
|
label: Option<String>,
|
||||||
|
bytes: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DecompiledLine {
|
||||||
|
/// is_jump
|
||||||
|
///
|
||||||
|
/// Check if the current line is a type of a jump
|
||||||
|
pub fn is_jump(&self) -> bool {
|
||||||
|
self.bytes[0] == ISA_OP_JMP_ABS || self.bytes[0] == ISA_OP_JMP_IND
|
||||||
|
}
|
||||||
|
|
||||||
|
/// is_branch
|
||||||
|
///
|
||||||
|
/// Check if the current line is a branch
|
||||||
|
pub fn is_branch(&self) -> bool {
|
||||||
|
self.bytes[0] == ISA_OP_BCC || self.bytes[0] == ISA_OP_BCS ||
|
||||||
|
self.bytes[0] == ISA_OP_BEQ || self.bytes[0] == ISA_OP_BMI ||
|
||||||
|
self.bytes[0] == ISA_OP_BNE || self.bytes[0] == ISA_OP_BPL ||
|
||||||
|
self.bytes[0] == ISA_OP_BVS || self.bytes[0] == ISA_OP_BVC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// WorkingProgram
|
||||||
|
///
|
||||||
|
/// Where we keep the program being decompiled
|
||||||
|
struct WorkingProgram {
|
||||||
|
data: [u8; SIZE_64KB],
|
||||||
|
lines: Vec<DecompiledLine>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorkingProgram {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decompile(data: &[u8]) -> Vec<(u16, DecompiledLine)> {
|
||||||
|
println!("Preparing to decompile {}b", data.len());
|
||||||
|
let mut current_data_position: u16 = 0;
|
||||||
|
let mut lines: HashMap<u16, DecompiledLine> = HashMap::new();
|
||||||
|
|
||||||
|
while current_data_position < data.len() as u16 {
|
||||||
|
// read the next byte.
|
||||||
|
let next_byte = data[current_data_position as usize];
|
||||||
|
let mut bytes = vec![next_byte];
|
||||||
|
let target_op = INSTRUCTION_TABLE[next_byte as usize].clone();
|
||||||
|
|
||||||
|
if let Some(top) = target_op {
|
||||||
|
// println!("Instruction {:?}/{:?} needs {:?} bytes.", top.operation, top.mode, top.length);
|
||||||
|
|
||||||
|
let num_bytes_to_load = top.length - 1;
|
||||||
|
println!("Need {num_bytes_to_load} more bytes.");
|
||||||
|
let mut formatted_asm = String::from(top.format_prefix);
|
||||||
|
let mut param = None;
|
||||||
|
if num_bytes_to_load == 1 {
|
||||||
|
bytes.push(data[current_data_position as usize + 1]);
|
||||||
|
formatted_asm = format!("{}{:02x}{}", formatted_asm, bytes[1], top.format_postfix);
|
||||||
|
};
|
||||||
|
|
||||||
|
if num_bytes_to_load == 2 {
|
||||||
|
bytes.push(data[current_data_position as usize + 1]);
|
||||||
|
bytes.push(data[current_data_position as usize + 2]);
|
||||||
|
// 16 bit parameter.
|
||||||
|
param = Some(((bytes[2] as u16) << 8) | bytes[1] as u16);
|
||||||
|
formatted_asm = format!("{}{:04x}{}", formatted_asm, param.unwrap(), top.format_postfix);
|
||||||
|
};
|
||||||
|
|
||||||
|
// figure out how long the instruction is and read that much more data
|
||||||
|
lines.insert(current_data_position, DecompiledLine {
|
||||||
|
offset: current_data_position,
|
||||||
|
text: String::from(formatted_asm),
|
||||||
|
label: None,
|
||||||
|
bytes,
|
||||||
|
});
|
||||||
|
|
||||||
|
current_data_position = current_data_position + top.length as u16;
|
||||||
|
} else {
|
||||||
|
// invalid instruction
|
||||||
|
println!("Byte sequence 0x{} invalid.", next_byte);
|
||||||
|
current_data_position += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Found {} instructions in pass 1. Adding labels for jumps.", lines.len());
|
||||||
|
|
||||||
|
//let targets = vec![];
|
||||||
|
|
||||||
|
for (index, line) in &lines {
|
||||||
|
|
||||||
|
if line.bytes[0] == ISA_OP_JMP_ABS {
|
||||||
|
// println!("ABS JUMP FOUND");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut items: Vec<_> = lines.into_iter().collect();
|
||||||
|
items.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
|
|
||||||
|
// loop through the lines for JSR and label the 'target' as SUB<index>
|
||||||
|
|
||||||
|
// check the vectors to label those entrypoints.
|
||||||
|
// -> main
|
||||||
|
// -> NMI
|
||||||
|
// -> IRQ
|
||||||
|
|
||||||
|
items
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let opts = CliOptions::parse();
|
||||||
|
println!("Taxation is theft.");
|
||||||
|
|
||||||
|
// Load program to an array...
|
||||||
|
let data = vec![
|
||||||
|
0xa9, 0xab, 0x4c, 0x00, 0x40, 0xa9, 0x54, 0x4c, 0x00, 0x40,
|
||||||
|
ISA_OP_TYA, ISA_OP_TXA, ISA_OP_TSX
|
||||||
|
];
|
||||||
|
|
||||||
|
let loaded_data = fs::read(opts.input).unwrap();
|
||||||
|
println!("Loaded {}b", loaded_data.len());
|
||||||
|
// ...load the array to the WorkingProgram structure...
|
||||||
|
let result = decompile(&loaded_data);
|
||||||
|
let mut output_file = File::create(opts.output).unwrap();
|
||||||
|
|
||||||
|
// ...reap the decompiled code.
|
||||||
|
for (_, line) in &result {
|
||||||
|
let line =format!("{:width$}; {:?}", line.text,line.bytes, width=30 );
|
||||||
|
println!("{}", line);
|
||||||
|
writeln!(output_file, "{}", line).expect("cant write output file. you picked the red snapper.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
println!("Taxation is theft.");
|
|
||||||
println!("TODO:");
|
|
||||||
println!(" Load specified binary and parse it out to ASM");
|
|
||||||
}
|
|
||||||
@ -19,7 +19,7 @@ impl Instruction {
|
|||||||
pub fn opinfo(bytes: &[u8]) -> Option<OpInfo> {
|
pub fn opinfo(bytes: &[u8]) -> Option<OpInfo> {
|
||||||
trace!("DECODING : {bytes:?}");
|
trace!("DECODING : {bytes:?}");
|
||||||
let opcode = bytes.get(0).copied()?;
|
let opcode = bytes.get(0).copied()?;
|
||||||
Some(INSTRUCTION_TABLE[opcode as usize])?
|
Some(INSTRUCTION_TABLE[opcode as usize].clone())?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
pub fn decode(bytes: &[u8]) -> Option<Instruction> {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -67,7 +67,7 @@ impl Default for Mos6502Cpu {
|
|||||||
mode: AddressMode::Implied,
|
mode: AddressMode::Implied,
|
||||||
operand: Operand::None,
|
operand: Operand::None,
|
||||||
},
|
},
|
||||||
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].unwrap(),
|
oi: INSTRUCTION_TABLE[ISA_OP_NOP as usize].clone().unwrap(),
|
||||||
has_reset: false,
|
has_reset: false,
|
||||||
iv: 0xfffe,
|
iv: 0xfffe,
|
||||||
cycle_carry: 0x0000,
|
cycle_carry: 0x0000,
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::address_mode::AddressMode;
|
use crate::address_mode::AddressMode;
|
||||||
use crate::operation::Operation;
|
use crate::operation::Operation;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct OpInfo {
|
pub struct OpInfo {
|
||||||
/// What is the operation
|
/// What is the operation
|
||||||
pub operation: Operation,
|
pub operation: Operation,
|
||||||
@ -11,4 +11,7 @@ pub struct OpInfo {
|
|||||||
pub length: u8,
|
pub length: u8,
|
||||||
/// CPU Cycles to complete the instruction
|
/// CPU Cycles to complete the instruction
|
||||||
pub cycles: u8,
|
pub cycles: u8,
|
||||||
}
|
/// Format string for disassembly
|
||||||
|
pub format_prefix: &'static str,
|
||||||
|
pub format_postfix: &'static str
|
||||||
|
}
|
||||||
3
resources/beneater/README
Normal file
3
resources/beneater/README
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
To Build
|
||||||
|
|
||||||
|
64tass -a -b -o <your_bin> <your_asm>
|
||||||
26
resources/beneater/asm/lda_loop.asm
Normal file
26
resources/beneater/asm/lda_loop.asm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
* = $A000
|
||||||
|
.fill Reset - *, $ea
|
||||||
|
Reset:
|
||||||
|
SEI
|
||||||
|
CLD
|
||||||
|
LDX #$FF
|
||||||
|
TXS
|
||||||
|
; Drop to the start of our main loop
|
||||||
|
MainLoop:
|
||||||
|
LDA #$AA
|
||||||
|
ROR
|
||||||
|
JMP MainLoop
|
||||||
|
|
||||||
|
; What to do when we get a NMI
|
||||||
|
NMI:
|
||||||
|
RTI
|
||||||
|
|
||||||
|
; What do we get when we get an interrupt
|
||||||
|
IRQ:
|
||||||
|
RTI
|
||||||
|
|
||||||
|
; setup the requirements for the CPU
|
||||||
|
* = $FFF8
|
||||||
|
.word NMI
|
||||||
|
.word Reset
|
||||||
|
.word IRQ
|
||||||
22
resources/beneater/asm/skeleton.asm
Normal file
22
resources/beneater/asm/skeleton.asm
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
* = $0000
|
||||||
|
.fill Reset - *, $ea
|
||||||
|
|
||||||
|
Reset:
|
||||||
|
SEI
|
||||||
|
CLD
|
||||||
|
LDX #$FF
|
||||||
|
TXS
|
||||||
|
|
||||||
|
MainLoop:
|
||||||
|
NOP
|
||||||
|
JMP MainLoop
|
||||||
|
|
||||||
|
NMI:
|
||||||
|
RTI
|
||||||
|
IRQ:
|
||||||
|
RTI
|
||||||
|
|
||||||
|
* = $FFF8
|
||||||
|
.word NMI
|
||||||
|
.word RESET
|
||||||
|
.word IRQ
|
||||||
17
resources/test/instructions.asm
Normal file
17
resources/test/instructions.asm
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
; Test of instructions for the decompiler
|
||||||
|
;
|
||||||
|
; This file is intended to be assembled and then
|
||||||
|
; used as an input to a test that decompiles the
|
||||||
|
; binary back to the text version of the instructions
|
||||||
|
ADC #$ab ; ADC Immediate
|
||||||
|
ADC $ab ; ADC ZeroPage
|
||||||
|
ADC $ab,X ; ADC ZeroPageX
|
||||||
|
ADC $abcd ; ADC Absolute
|
||||||
|
ADC $abcd,X; ADC AbsoluteX
|
||||||
|
ADC $abcd,Y; ADC AbsoluteY
|
||||||
|
ADC ($ab,X); ADC IndirectX
|
||||||
|
ADC ($ab),Y; ADC IndirectY
|
||||||
|
|
||||||
|
AND #$ab ; AND Immediate
|
||||||
|
AND $ab ; AND ZeroPage
|
||||||
|
AND $ab,X ; AND ZeroPageX
|
||||||
Loading…
x
Reference in New Issue
Block a user