mirror of
https://github.com/mre/mos6502.git
synced 2024-11-25 02:33:26 +00:00
Merge pull request #9 from typelist/big-old-table
Orthogonal AddressingMode handling; implement all addressing modes for ADC, LDA, LDX, LDY
This commit is contained in:
commit
48b0c90c43
@ -25,30 +25,13 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
pub enum AddressingMode {
|
|
||||||
Accumulator, // LSR A work directly on accumulator
|
|
||||||
Immediate, // LDA #10 8-bit constant in instruction
|
|
||||||
ZeroPage, // LDA $00 zero-page address
|
|
||||||
ZeroPageX, // LDA $80,X address is X register + 8-bit constant
|
|
||||||
ZeroPageY, // LDX $10,Y address is Y register + 8-bit constant
|
|
||||||
Relative, // BNE LABEL branch target as signed relative offset
|
|
||||||
Absolute, // JMP $1000 full 16-bit address
|
|
||||||
AbsoluteX, // STA $1000,X full 16-bit address plus X register
|
|
||||||
AbsoluteY, // STA $1000,Y full 16-bit address plus Y register
|
|
||||||
Indirect, // JMP ($1000) jump to address stored at address
|
|
||||||
IndexedIndirectX, // LDA ($10,X) load from address stored at (constant
|
|
||||||
// zero page address plus X register)
|
|
||||||
IndirectIndexedY, // LDA ($10),Y load from (address stored at constant
|
|
||||||
// zero page address) plus Y register
|
|
||||||
}
|
|
||||||
|
|
||||||
// The idea here is that it doesn't make sense to add two addresses, but it
|
// The idea here is that it doesn't make sense to add two addresses, but it
|
||||||
// does make sense to add an address and an "address-difference". (If this
|
// does make sense to add an address and an "address-difference". (If this
|
||||||
// is too annoying to work with we should let it go.)
|
// is too annoying to work with we should let it go.)
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
|
#[deriving(PartialEq, Eq, PartialOrd, Ord, Show)]
|
||||||
pub struct AddressDiff(pub u16);
|
pub struct AddressDiff(pub u16);
|
||||||
|
|
||||||
#[deriving(PartialEq, Eq, PartialOrd, Ord)]
|
#[deriving(PartialEq, Eq, PartialOrd, Ord, Show)]
|
||||||
pub struct Address(pub u16);
|
pub struct Address(pub u16);
|
||||||
|
|
||||||
impl Add<AddressDiff, Address> for Address {
|
impl Add<AddressDiff, Address> for Address {
|
||||||
@ -58,6 +41,13 @@ impl Add<AddressDiff, Address> for Address {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Add<AddressDiff, AddressDiff> for AddressDiff {
|
||||||
|
fn add(&self, &AddressDiff(rhs): &AddressDiff) -> AddressDiff {
|
||||||
|
let &AddressDiff(lhs) = self;
|
||||||
|
AddressDiff(lhs + rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// rustc doesn't seem to like having multiple implementations of Add for
|
// rustc doesn't seem to like having multiple implementations of Add for
|
||||||
// Address. I believe this is a Rust bug (possibly resolved by "associated
|
// Address. I believe this is a Rust bug (possibly resolved by "associated
|
||||||
// types" RFC?). Or I wrote it wrong. Anyway, here's some living dead code:
|
// types" RFC?). Or I wrote it wrong. Anyway, here's some living dead code:
|
||||||
|
126
src/bin/main.rs
126
src/bin/main.rs
@ -34,21 +34,119 @@ fn main() {
|
|||||||
let mut machine = machine::Machine::new();
|
let mut machine = machine::Machine::new();
|
||||||
|
|
||||||
// "Load" a program
|
// "Load" a program
|
||||||
machine.memory.set_byte(&Address(0), 0x69); // ADC immediate opcode
|
|
||||||
machine.memory.set_byte(&Address(1), 0x07); // Immediate operand
|
|
||||||
machine.memory.set_byte(&Address(2), 0x69); // ADC immediate opcode
|
|
||||||
machine.memory.set_byte(&Address(3), 0x08); // ADC immediate opcode
|
|
||||||
|
|
||||||
// Obviously this will run the full program, just
|
// JAM: FIXME: What's the syntax for specifying the array element type,
|
||||||
// executing a finite num of instructions for simplicity
|
// but not the length? (For a fixed-size array)
|
||||||
// right now.
|
|
||||||
for _ in range(0u, 2u) {
|
let zero_page_data: [u8, ..17] = [
|
||||||
let raw_instruction = machine.fetch_instruction();
|
// ZeroPage data start
|
||||||
let instruction = machine.decode_instruction(raw_instruction);
|
0x00,
|
||||||
machine.execute_instruction(instruction);
|
0x02, // ADC ZeroPage target
|
||||||
}
|
0x00,
|
||||||
|
0x04, // ADC ZeroPageX target
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x10, // ADC IndexedIndirectX address
|
||||||
|
0x80, // ADC IndexedIndirectX address
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x08, // ADC IndirectIndexedY address
|
||||||
|
0x80, // ADC IndirectIndexedY address
|
||||||
|
];
|
||||||
|
|
||||||
|
let program: [u8, ..33] = [
|
||||||
|
// Code start
|
||||||
|
0xA9, // LDA Immediate
|
||||||
|
0x01, // Immediate operand
|
||||||
|
|
||||||
|
0x69, // ADC Immediate
|
||||||
|
0x07, // Immediate operand
|
||||||
|
|
||||||
|
0x65, // ADC ZeroPage
|
||||||
|
0x01, // ZeroPage operand
|
||||||
|
|
||||||
|
0xA2, // LDX Immediate
|
||||||
|
0x01, // Immediate operand
|
||||||
|
|
||||||
|
0x75, // ADC ZeroPageX
|
||||||
|
0x02, // ZeroPageX operand
|
||||||
|
|
||||||
|
0x6D, // ADC Absolute
|
||||||
|
0x01, // Absolute operand
|
||||||
|
0x80, // Absolute operand
|
||||||
|
|
||||||
|
0xA2, // LDX immediate
|
||||||
|
0x08, // Immediate operand
|
||||||
|
|
||||||
|
0x7D, // ADC AbsoluteX
|
||||||
|
0x00, // AbsoluteX operand
|
||||||
|
0x80, // AbsoluteX operand
|
||||||
|
|
||||||
|
0xA0, // LDY immediate
|
||||||
|
0x04, // Immediate operand
|
||||||
|
|
||||||
|
0x79, // ADC AbsoluteY
|
||||||
|
0x00, // AbsoluteY operand
|
||||||
|
0x80, // AbsoluteY operand
|
||||||
|
|
||||||
|
0xA2, // LDX immediate
|
||||||
|
0x05, // Immediate operand
|
||||||
|
|
||||||
|
0x61, // ADC IndexedIndirectX
|
||||||
|
0x03, // IndexedIndirectX operand
|
||||||
|
|
||||||
|
0xA0, // LDY immediate
|
||||||
|
0x10, // Immediate operand
|
||||||
|
|
||||||
|
0x71, // ADC IndirectIndexedY
|
||||||
|
0x0F, // IndirectIndexedY operand
|
||||||
|
|
||||||
|
0xEA, // NOP :)
|
||||||
|
|
||||||
|
0xFF, // Something invalid -- the end!
|
||||||
|
];
|
||||||
|
|
||||||
|
let data: [u8, ..25] = [
|
||||||
|
0x00,
|
||||||
|
0x09, // ADC Absolute target
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x40, // ADC AbsoluteY target
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x11, // ADC AbsoluteX target
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x12, // ADC IndexedIndirectX target
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x00,
|
||||||
|
0x06, // ADC IndirectIndexedY target
|
||||||
|
];
|
||||||
|
|
||||||
|
machine.memory.set_bytes(Address(0x0000), &zero_page_data);
|
||||||
|
machine.memory.set_bytes(Address(0x4000), &program);
|
||||||
|
machine.memory.set_bytes(Address(0x8000), &data);
|
||||||
|
|
||||||
|
machine.registers.program_counter = Address(0x4000);
|
||||||
|
|
||||||
|
machine.run();
|
||||||
|
|
||||||
println!("{}", machine);
|
println!("{}", machine);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,10 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
use address::Address;
|
||||||
|
use address::AddressDiff;
|
||||||
|
use machine::Machine;
|
||||||
|
|
||||||
// Abbreviations
|
// Abbreviations
|
||||||
//
|
//
|
||||||
// General
|
// General
|
||||||
@ -48,9 +52,7 @@ pub enum Instruction
|
|||||||
// NV BDIZC A X Y S PC M
|
// NV BDIZC A X Y S PC M
|
||||||
//
|
//
|
||||||
// | outputs | inputs
|
// | outputs | inputs
|
||||||
{
|
{ ADC // ADd with Carry................ | NV ...ZC A = A + M + C
|
||||||
ADC(i8) // ADd with Carry............ | NV ...ZC A = A + M + C
|
|
||||||
|
|
||||||
, AND // logical AND (bitwise)......... | N. ...Z. A = A && M
|
, AND // logical AND (bitwise)......... | N. ...Z. A = A && M
|
||||||
, ASL // Arithmetic Shift Left......... | N. ...ZC A = M << 1
|
, ASL // Arithmetic Shift Left......... | N. ...ZC A = M << 1
|
||||||
, BCC // Branch if Carry Clear......... | .. ..... PC = !C
|
, BCC // Branch if Carry Clear......... | .. ..... PC = !C
|
||||||
@ -111,3 +113,405 @@ pub enum Instruction
|
|||||||
, TYA // Transfer Y to Accumulator..... | N. ...Z. A = Y
|
, TYA // Transfer Y to Accumulator..... | N. ...Z. A = Y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum AMOut {
|
||||||
|
UseImplied,
|
||||||
|
UseImmediate(u8),
|
||||||
|
UseRelative(i8),
|
||||||
|
UseAddress(Address),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AddressingMode
|
||||||
|
// length
|
||||||
|
{ Accumulator // 1 LSR A work directly on accumulator
|
||||||
|
, Implied // 1 BRK
|
||||||
|
, Immediate // 2 LDA #10 8-bit constant in instruction
|
||||||
|
, ZeroPage // 2 LDA $00 zero-page address
|
||||||
|
, ZeroPageX // 2 LDA $80,X address is X register + 8-bit constant
|
||||||
|
, ZeroPageY // 2 LDX $10,Y address is Y register + 8-bit constant
|
||||||
|
, Relative // 2 BNE LABEL branch target as signed relative offset
|
||||||
|
, Absolute // 3 JMP $1000 full 16-bit address
|
||||||
|
, AbsoluteX // 3 STA $1000,X full 16-bit address plus X register
|
||||||
|
, AbsoluteY // 3 STA $1000,Y full 16-bit address plus Y register
|
||||||
|
, Indirect // 3 JMP ($1000) jump to address stored at address
|
||||||
|
, IndexedIndirectX // 2 LDA ($10,X) load from address stored at (constant
|
||||||
|
// zero page address plus X register)
|
||||||
|
, IndirectIndexedY // 2 LDA ($10),Y load from (address stored at constant
|
||||||
|
// zero page address) plus Y register
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arr_to_addr(arr: &[u8]) -> Address {
|
||||||
|
debug_assert!(arr.len() == 2);
|
||||||
|
|
||||||
|
let x = (arr[0] as u16) + (arr[1] as u16 << 8u);
|
||||||
|
Address(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressingMode {
|
||||||
|
pub fn extra_bytes(self) -> AddressDiff {
|
||||||
|
let x = match self {
|
||||||
|
Accumulator => 0,
|
||||||
|
Implied => 0,
|
||||||
|
Immediate => 1,
|
||||||
|
ZeroPage => 1,
|
||||||
|
ZeroPageX => 1,
|
||||||
|
ZeroPageY => 1,
|
||||||
|
Relative => 1,
|
||||||
|
Absolute => 2,
|
||||||
|
AbsoluteX => 2,
|
||||||
|
AbsoluteY => 2,
|
||||||
|
Indirect => 2,
|
||||||
|
IndexedIndirectX => 1,
|
||||||
|
IndirectIndexedY => 1,
|
||||||
|
};
|
||||||
|
AddressDiff(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(self, machine: &Machine, arr: &[u8]) -> AMOut {
|
||||||
|
|
||||||
|
debug_assert!({let AddressDiff(x) = self.extra_bytes();
|
||||||
|
arr.len() == x as uint});
|
||||||
|
|
||||||
|
let x = machine.registers.index_x as u8;
|
||||||
|
let y = machine.registers.index_y as u8;
|
||||||
|
|
||||||
|
let memory = &machine.memory;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Accumulator | Implied => {
|
||||||
|
// Always the same -- no input
|
||||||
|
UseImplied
|
||||||
|
},
|
||||||
|
Immediate => {
|
||||||
|
// Use [u8, ..1] specified in instruction as input
|
||||||
|
UseImmediate(arr[0])
|
||||||
|
},
|
||||||
|
ZeroPage => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// Interpret as zero page address
|
||||||
|
// (Output: an 8-bit zero-page address)
|
||||||
|
UseAddress(Address(arr[0] as u16))
|
||||||
|
},
|
||||||
|
ZeroPageX => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// Add to X register (as u8 -- the final address is in 0-page)
|
||||||
|
// (Output: an 8-bit zero-page address)
|
||||||
|
UseAddress(Address((arr[0] + x) as u16))
|
||||||
|
},
|
||||||
|
ZeroPageY => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// Add to Y register (as u8 -- the final address is in 0-page)
|
||||||
|
// (Output: an 8-bit zero-page address)
|
||||||
|
UseAddress(Address((arr[0] + y) as u16))
|
||||||
|
},
|
||||||
|
Relative => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// (interpret as relative...)
|
||||||
|
UseRelative(arr[0] as i8)
|
||||||
|
},
|
||||||
|
Absolute => {
|
||||||
|
// Use [u8, ..2] from instruction as address
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
UseAddress(arr_to_addr(arr))
|
||||||
|
},
|
||||||
|
AbsoluteX => {
|
||||||
|
// Use [u8, ..2] from instruction as address, add X
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
UseAddress(arr_to_addr(arr) + AddressDiff(x as u16))
|
||||||
|
},
|
||||||
|
AbsoluteY => {
|
||||||
|
// Use [u8, ..2] from instruction as address, add Y
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
UseAddress(arr_to_addr(arr) + AddressDiff(y as u16))
|
||||||
|
},
|
||||||
|
Indirect => {
|
||||||
|
// Use [u8, ..2] from instruction as an address. Interpret the
|
||||||
|
// two bytes starting at that address as an address.
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
let slice = memory.get_slice(arr_to_addr(arr), AddressDiff(2));
|
||||||
|
UseAddress(arr_to_addr(slice))
|
||||||
|
},
|
||||||
|
IndexedIndirectX => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// Add to X register with 0-page wraparound, like ZeroPageX.
|
||||||
|
// This is where the absolute (16-bit) target address is stored.
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
let start = arr[0] + x;
|
||||||
|
let slice = memory.get_slice(Address(start as u16),
|
||||||
|
AddressDiff(2));
|
||||||
|
UseAddress(arr_to_addr(slice))
|
||||||
|
},
|
||||||
|
IndirectIndexedY => {
|
||||||
|
// Use [u8, ..1] from instruction
|
||||||
|
// This is where the absolute (16-bit) target address is stored.
|
||||||
|
// Add Y register to this address to get the final address
|
||||||
|
// (Output: a 16-bit address)
|
||||||
|
let start = arr[0];
|
||||||
|
let slice = memory.get_slice(Address(start as u16),
|
||||||
|
AddressDiff(2));
|
||||||
|
UseAddress(arr_to_addr(slice) + AddressDiff(y as u16))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DecodedInstr = (Instruction, AMOut);
|
||||||
|
|
||||||
|
pub static g_opcodes: [Option<(Instruction, AddressingMode)>, ..256] = [
|
||||||
|
/*0x00*/ Some((BRK, Implied)),
|
||||||
|
/*0x01*/ Some((ORA, IndexedIndirectX)),
|
||||||
|
/*0x02*/ None,
|
||||||
|
/*0x03*/ None,
|
||||||
|
/*0x04*/ None,
|
||||||
|
/*0x05*/ Some((ORA, ZeroPage)),
|
||||||
|
/*0x06*/ Some((ASL, ZeroPage)),
|
||||||
|
/*0x07*/ None,
|
||||||
|
/*0x08*/ Some((PHP, Implied)),
|
||||||
|
/*0x09*/ Some((ORA, Immediate)),
|
||||||
|
/*0x0A*/ Some((ASL, Accumulator)),
|
||||||
|
/*0x0B*/ None,
|
||||||
|
/*0x0C*/ None,
|
||||||
|
/*0x0D*/ Some((ORA, Absolute)),
|
||||||
|
/*0x0E*/ Some((ASL, Absolute)),
|
||||||
|
/*0x0F*/ None,
|
||||||
|
/*0x10*/ Some((BPL, Relative)),
|
||||||
|
/*0x11*/ Some((ORA, IndirectIndexedY)),
|
||||||
|
/*0x12*/ None,
|
||||||
|
/*0x13*/ None,
|
||||||
|
/*0x14*/ None,
|
||||||
|
/*0x15*/ Some((ORA, ZeroPageX)),
|
||||||
|
/*0x16*/ Some((ASL, ZeroPageX)),
|
||||||
|
/*0x17*/ None,
|
||||||
|
/*0x18*/ Some((CLC, Implied)),
|
||||||
|
/*0x19*/ Some((ORA, AbsoluteY)),
|
||||||
|
/*0x1A*/ None,
|
||||||
|
/*0x1B*/ None,
|
||||||
|
/*0x1C*/ None,
|
||||||
|
/*0x1D*/ Some((ORA, AbsoluteX)),
|
||||||
|
/*0x1E*/ Some((ASL, AbsoluteX)),
|
||||||
|
/*0x1F*/ None,
|
||||||
|
/*0x20*/ Some((JSR, Absolute)),
|
||||||
|
/*0x21*/ Some((AND, IndexedIndirectX)),
|
||||||
|
/*0x22*/ None,
|
||||||
|
/*0x23*/ None,
|
||||||
|
/*0x24*/ Some((BIT, ZeroPage)),
|
||||||
|
/*0x25*/ Some((AND, ZeroPage)),
|
||||||
|
/*0x26*/ Some((ROL, ZeroPage)),
|
||||||
|
/*0x27*/ None,
|
||||||
|
/*0x28*/ Some((PLP, Implied)),
|
||||||
|
/*0x29*/ Some((AND, Immediate)),
|
||||||
|
/*0x2A*/ Some((ROL, Accumulator)),
|
||||||
|
/*0x2B*/ None,
|
||||||
|
/*0x2C*/ Some((BIT, Absolute)),
|
||||||
|
/*0x2D*/ Some((AND, Absolute)),
|
||||||
|
/*0x2E*/ Some((ROL, Absolute)),
|
||||||
|
/*0x2F*/ None,
|
||||||
|
/*0x30*/ Some((BMI, Relative)),
|
||||||
|
/*0x31*/ Some((AND, IndirectIndexedY)),
|
||||||
|
/*0x32*/ None,
|
||||||
|
/*0x33*/ None,
|
||||||
|
/*0x34*/ None,
|
||||||
|
/*0x35*/ Some((AND, ZeroPageX)),
|
||||||
|
/*0x36*/ Some((ROL, ZeroPageX)),
|
||||||
|
/*0x37*/ None,
|
||||||
|
/*0x38*/ Some((SEC, Implied)),
|
||||||
|
/*0x39*/ Some((AND, AbsoluteY)),
|
||||||
|
/*0x3A*/ None,
|
||||||
|
/*0x3B*/ None,
|
||||||
|
/*0x3C*/ None,
|
||||||
|
/*0x3D*/ Some((AND, AbsoluteX)),
|
||||||
|
/*0x3E*/ Some((ROL, AbsoluteX)),
|
||||||
|
/*0x3F*/ None,
|
||||||
|
/*0x40*/ Some((RTI, Implied)),
|
||||||
|
/*0x41*/ Some((EOR, IndexedIndirectX)),
|
||||||
|
/*0x42*/ None,
|
||||||
|
/*0x43*/ None,
|
||||||
|
/*0x44*/ None,
|
||||||
|
/*0x45*/ Some((EOR, ZeroPage)),
|
||||||
|
/*0x46*/ Some((LSR, ZeroPage)),
|
||||||
|
/*0x47*/ None,
|
||||||
|
/*0x48*/ Some((PHA, Implied)),
|
||||||
|
/*0x49*/ Some((EOR, Immediate)),
|
||||||
|
/*0x4A*/ Some((LSR, Accumulator)),
|
||||||
|
/*0x4B*/ None,
|
||||||
|
/*0x4C*/ Some((JMP, Absolute)),
|
||||||
|
/*0x4D*/ Some((EOR, Absolute)),
|
||||||
|
/*0x4E*/ Some((LSR, Absolute)),
|
||||||
|
/*0x4F*/ None,
|
||||||
|
/*0x50*/ Some((BVC, Relative)),
|
||||||
|
/*0x51*/ Some((EOR, IndirectIndexedY)),
|
||||||
|
/*0x52*/ None,
|
||||||
|
/*0x53*/ None,
|
||||||
|
/*0x54*/ None,
|
||||||
|
/*0x55*/ Some((EOR, ZeroPageX)),
|
||||||
|
/*0x56*/ Some((LSR, ZeroPageX)),
|
||||||
|
/*0x57*/ None,
|
||||||
|
/*0x58*/ None,
|
||||||
|
/*0x59*/ Some((EOR, AbsoluteY)),
|
||||||
|
/*0x5A*/ None,
|
||||||
|
/*0x5B*/ None,
|
||||||
|
/*0x5C*/ None,
|
||||||
|
/*0x5D*/ Some((EOR, AbsoluteX)),
|
||||||
|
/*0x5E*/ Some((LSR, AbsoluteX)),
|
||||||
|
/*0x5F*/ None,
|
||||||
|
/*0x60*/ Some((RTS, Implied)),
|
||||||
|
/*0x61*/ Some((ADC, IndexedIndirectX)),
|
||||||
|
/*0x62*/ None,
|
||||||
|
/*0x63*/ None,
|
||||||
|
/*0x64*/ None,
|
||||||
|
/*0x65*/ Some((ADC, ZeroPage)),
|
||||||
|
/*0x66*/ Some((ROR, ZeroPage)),
|
||||||
|
/*0x67*/ None,
|
||||||
|
/*0x68*/ Some((PLA, Implied)),
|
||||||
|
/*0x69*/ Some((ADC, Immediate)),
|
||||||
|
/*0x6A*/ Some((ROR, Accumulator)),
|
||||||
|
/*0x6B*/ None,
|
||||||
|
/*0x6C*/ Some((JMP, Indirect)),
|
||||||
|
/*0x6D*/ Some((ADC, Absolute)),
|
||||||
|
/*0x6E*/ Some((ROR, Absolute)),
|
||||||
|
/*0x6F*/ None,
|
||||||
|
/*0x70*/ Some((BVS, Relative)),
|
||||||
|
/*0x71*/ Some((ADC, IndirectIndexedY)),
|
||||||
|
/*0x72*/ None,
|
||||||
|
/*0x73*/ None,
|
||||||
|
/*0x74*/ None,
|
||||||
|
/*0x75*/ Some((ADC, ZeroPageX)),
|
||||||
|
/*0x76*/ Some((ROR, ZeroPageX)),
|
||||||
|
/*0x77*/ None,
|
||||||
|
/*0x78*/ Some((SEI, Implied)),
|
||||||
|
/*0x79*/ Some((ADC, AbsoluteY)),
|
||||||
|
/*0x7A*/ None,
|
||||||
|
/*0x7B*/ None,
|
||||||
|
/*0x7C*/ None,
|
||||||
|
/*0x7D*/ Some((ADC, AbsoluteX)),
|
||||||
|
/*0x7E*/ Some((ROR, AbsoluteX)),
|
||||||
|
/*0x7F*/ None,
|
||||||
|
/*0x80*/ None,
|
||||||
|
/*0x81*/ Some((STA, IndexedIndirectX)),
|
||||||
|
/*0x82*/ None,
|
||||||
|
/*0x83*/ None,
|
||||||
|
/*0x84*/ Some((STY, ZeroPage)),
|
||||||
|
/*0x85*/ Some((STA, ZeroPage)),
|
||||||
|
/*0x86*/ Some((STX, ZeroPage)),
|
||||||
|
/*0x87*/ None,
|
||||||
|
/*0x88*/ Some((DEY, Implied)),
|
||||||
|
/*0x89*/ None,
|
||||||
|
/*0x8A*/ Some((TXA, Implied)),
|
||||||
|
/*0x8B*/ None,
|
||||||
|
/*0x8C*/ Some((STY, Absolute)),
|
||||||
|
/*0x8D*/ Some((STA, Absolute)),
|
||||||
|
/*0x8E*/ Some((STX, Absolute)),
|
||||||
|
/*0x8F*/ None,
|
||||||
|
/*0x90*/ Some((BCC, Relative)),
|
||||||
|
/*0x91*/ Some((STA, IndirectIndexedY)),
|
||||||
|
/*0x92*/ None,
|
||||||
|
/*0x93*/ None,
|
||||||
|
/*0x94*/ Some((STY, ZeroPageX)),
|
||||||
|
/*0x95*/ Some((STA, ZeroPageX)),
|
||||||
|
/*0x96*/ Some((STX, ZeroPageY)),
|
||||||
|
/*0x97*/ None,
|
||||||
|
/*0x98*/ Some((TYA, Implied)),
|
||||||
|
/*0x99*/ Some((STA, AbsoluteY)),
|
||||||
|
/*0x9A*/ Some((TXS, Implied)),
|
||||||
|
/*0x9B*/ None,
|
||||||
|
/*0x9C*/ None,
|
||||||
|
/*0x9D*/ Some((STA, AbsoluteX)),
|
||||||
|
/*0x9E*/ None,
|
||||||
|
/*0x9F*/ None,
|
||||||
|
/*0xA0*/ Some((LDY, Immediate)),
|
||||||
|
/*0xA1*/ Some((LDA, IndexedIndirectX)),
|
||||||
|
/*0xA2*/ Some((LDX, Immediate)),
|
||||||
|
/*0xA3*/ None,
|
||||||
|
/*0xA4*/ Some((LDY, ZeroPage)),
|
||||||
|
/*0xA5*/ Some((LDA, ZeroPage)),
|
||||||
|
/*0xA6*/ Some((LDX, ZeroPage)),
|
||||||
|
/*0xA7*/ None,
|
||||||
|
/*0xA8*/ Some((TAY, Implied)),
|
||||||
|
/*0xA9*/ Some((LDA, Immediate)),
|
||||||
|
/*0xAA*/ Some((TAX, Implied)),
|
||||||
|
/*0xAB*/ None,
|
||||||
|
/*0xAC*/ Some((LDY, Absolute)),
|
||||||
|
/*0xAD*/ Some((LDA, Absolute)),
|
||||||
|
/*0xAE*/ Some((LDX, Absolute)),
|
||||||
|
/*0xAF*/ None,
|
||||||
|
/*0xB0*/ Some((BCS, Relative)),
|
||||||
|
/*0xB1*/ Some((LDA, IndirectIndexedY)),
|
||||||
|
/*0xB2*/ None,
|
||||||
|
/*0xB3*/ None,
|
||||||
|
/*0xB4*/ Some((LDY, ZeroPageX)),
|
||||||
|
/*0xB5*/ Some((LDA, ZeroPageX)),
|
||||||
|
/*0xB6*/ Some((LDX, ZeroPageY)),
|
||||||
|
/*0xB7*/ None,
|
||||||
|
/*0xB8*/ Some((CLV, Implied)),
|
||||||
|
/*0xB9*/ Some((LDA, AbsoluteY)),
|
||||||
|
/*0xBA*/ Some((TSX, Implied)),
|
||||||
|
/*0xBB*/ None,
|
||||||
|
/*0xBC*/ Some((LDY, AbsoluteX)),
|
||||||
|
/*0xBD*/ Some((LDA, AbsoluteX)),
|
||||||
|
/*0xBE*/ Some((LDX, AbsoluteY)),
|
||||||
|
/*0xBF*/ None,
|
||||||
|
/*0xC0*/ Some((CPY, Immediate)),
|
||||||
|
/*0xC1*/ Some((CMP, IndexedIndirectX)),
|
||||||
|
/*0xC2*/ None,
|
||||||
|
/*0xC3*/ None,
|
||||||
|
/*0xC4*/ Some((CPY, ZeroPage)),
|
||||||
|
/*0xC5*/ Some((CMP, ZeroPage)),
|
||||||
|
/*0xC6*/ Some((DEC, ZeroPage)),
|
||||||
|
/*0xC7*/ None,
|
||||||
|
/*0xC8*/ Some((INY, Implied)),
|
||||||
|
/*0xC9*/ Some((CMP, Immediate)),
|
||||||
|
/*0xCA*/ Some((DEX, Implied)),
|
||||||
|
/*0xCB*/ None,
|
||||||
|
/*0xCC*/ Some((CPY, Absolute)),
|
||||||
|
/*0xCD*/ Some((CMP, Absolute)),
|
||||||
|
/*0xCE*/ Some((DEC, Absolute)),
|
||||||
|
/*0xCF*/ None,
|
||||||
|
/*0xD0*/ Some((BNE, Relative)),
|
||||||
|
/*0xD1*/ Some((CMP, IndirectIndexedY)),
|
||||||
|
/*0xD2*/ None,
|
||||||
|
/*0xD3*/ None,
|
||||||
|
/*0xD4*/ None,
|
||||||
|
/*0xD5*/ Some((CMP, ZeroPageX)),
|
||||||
|
/*0xD6*/ Some((DEC, ZeroPageX)),
|
||||||
|
/*0xD7*/ None,
|
||||||
|
/*0xD8*/ Some((CLD, Implied)),
|
||||||
|
/*0xD9*/ Some((CMP, AbsoluteY)),
|
||||||
|
/*0xDA*/ None,
|
||||||
|
/*0xDB*/ None,
|
||||||
|
/*0xDC*/ None,
|
||||||
|
/*0xDD*/ Some((CMP, AbsoluteX)),
|
||||||
|
/*0xDE*/ Some((DEC, AbsoluteX)),
|
||||||
|
/*0xDF*/ None,
|
||||||
|
/*0xE0*/ Some((CPX, Immediate)),
|
||||||
|
/*0xE1*/ Some((SBC, IndexedIndirectX)),
|
||||||
|
/*0xE2*/ None,
|
||||||
|
/*0xE3*/ None,
|
||||||
|
/*0xE4*/ Some((CPX, ZeroPage)),
|
||||||
|
/*0xE5*/ Some((SBC, ZeroPage)),
|
||||||
|
/*0xE6*/ Some((INC, ZeroPage)),
|
||||||
|
/*0xE7*/ None,
|
||||||
|
/*0xE8*/ Some((INX, Implied)),
|
||||||
|
/*0xE9*/ Some((SBC, Immediate)),
|
||||||
|
/*0xEA*/ Some((NOP, Implied)),
|
||||||
|
/*0xEB*/ None,
|
||||||
|
/*0xEC*/ Some((CPX, Absolute)),
|
||||||
|
/*0xED*/ Some((SBC, Absolute)),
|
||||||
|
/*0xEE*/ Some((INC, Absolute)),
|
||||||
|
/*0xEF*/ None,
|
||||||
|
/*0xF0*/ Some((BEQ, Relative)),
|
||||||
|
/*0xF1*/ Some((SBC, IndirectIndexedY)),
|
||||||
|
/*0xF2*/ None,
|
||||||
|
/*0xF3*/ None,
|
||||||
|
/*0xF4*/ None,
|
||||||
|
/*0xF5*/ Some((SBC, ZeroPageX)),
|
||||||
|
/*0xF6*/ Some((INC, ZeroPageX)),
|
||||||
|
/*0xF7*/ None,
|
||||||
|
/*0xF8*/ Some((SED, Implied)),
|
||||||
|
/*0xF9*/ Some((SBC, AbsoluteY)),
|
||||||
|
/*0xFA*/ None,
|
||||||
|
/*0xFB*/ None,
|
||||||
|
/*0xFC*/ None,
|
||||||
|
/*0xFD*/ Some((SBC, AbsoluteX)),
|
||||||
|
/*0xFE*/ Some((INC, AbsoluteX)),
|
||||||
|
/*0xFF*/ None,
|
||||||
|
];
|
||||||
|
|
||||||
|
13
src/lib.rs
13
src/lib.rs
@ -25,6 +25,19 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
// JAM: 'if let' syntax is great for situations where want to match only a
|
||||||
|
// single pattern and ignore all others.
|
||||||
|
//
|
||||||
|
// if let Some(x) = foo() { ... }
|
||||||
|
//
|
||||||
|
#![feature(if_let)]
|
||||||
|
|
||||||
|
// Needed for log! macro
|
||||||
|
#![feature(phase)]
|
||||||
|
|
||||||
|
#[phase(plugin, link)]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
pub mod machine;
|
pub mod machine;
|
||||||
|
167
src/machine.rs
167
src/machine.rs
@ -25,10 +25,13 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
use address::AddressDiff;
|
use log;
|
||||||
use std::fmt;
|
|
||||||
use instruction::Instruction;
|
use std;
|
||||||
use instruction::{ADC, NOP};
|
|
||||||
|
use address::{AddressDiff};
|
||||||
|
use instruction;
|
||||||
|
use instruction::{DecodedInstr};
|
||||||
use memory::Memory;
|
use memory::Memory;
|
||||||
use registers::{ Registers, Status, StatusArgs };
|
use registers::{ Registers, Status, StatusArgs };
|
||||||
use registers::{ ps_negative, ps_overflow, ps_zero, ps_carry };
|
use registers::{ ps_negative, ps_overflow, ps_zero, ps_carry };
|
||||||
@ -50,35 +53,126 @@ impl Machine {
|
|||||||
*self = Machine::new();
|
*self = Machine::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_instruction(&mut self) -> i8 {
|
pub fn fetch_next_and_decode(&mut self) -> Option<DecodedInstr> {
|
||||||
let instr = self.memory.get_byte(&self.registers.program_counter);
|
let x: u8 = self.memory.get_byte(self.registers.program_counter);
|
||||||
|
|
||||||
// Will need smarter logic to fetch the correct number of bytes
|
match instruction::g_opcodes[x as uint] {
|
||||||
// for instruction
|
Some((instr, am)) => {
|
||||||
self.registers.program_counter = self.registers.program_counter + AddressDiff(1);
|
let extra_bytes = am.extra_bytes();
|
||||||
instr as i8
|
let num_bytes = AddressDiff(1) + extra_bytes;
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_instruction(&mut self, raw_instruction: i8) -> Instruction {
|
let data_start = self.registers.program_counter
|
||||||
match raw_instruction {
|
+ AddressDiff(1);
|
||||||
0x69 => ADC(self.fetch_instruction()),
|
|
||||||
_ => NOP
|
let slice = self.memory.get_slice(data_start, extra_bytes);
|
||||||
}
|
let am_out = am.process(self, slice);
|
||||||
}
|
|
||||||
|
// Increment program counter
|
||||||
pub fn execute_instruction(&mut self, instruction: Instruction) {
|
self.registers.program_counter =
|
||||||
match instruction {
|
self.registers.program_counter + num_bytes;
|
||||||
ADC(immediate) => {
|
|
||||||
println!("executing add with carry");
|
Some((instr, am_out))
|
||||||
self.add_with_carry(immediate);
|
|
||||||
},
|
|
||||||
NOP => {
|
|
||||||
println!("nop instr");
|
|
||||||
}
|
}
|
||||||
_ => println!("attempting to execute unimplemented instruction")
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_instruction(&mut self, decoded_instr: DecodedInstr) {
|
||||||
|
match decoded_instr {
|
||||||
|
(instruction::ADC, instruction::UseImmediate(val)) => {
|
||||||
|
log!(log::DEBUG, "add with carry immediate: {}", val);
|
||||||
|
self.add_with_carry(val as i8);
|
||||||
|
},
|
||||||
|
(instruction::ADC, instruction::UseAddress(addr)) => {
|
||||||
|
let val = self.memory.get_byte(addr) as i8;
|
||||||
|
log!(log::DEBUG, "add with carry. address: {}. value: {}",
|
||||||
|
addr, val);
|
||||||
|
self.add_with_carry(val);
|
||||||
|
},
|
||||||
|
|
||||||
|
(instruction::LDA, instruction::UseImmediate(val)) => {
|
||||||
|
log!(log::DEBUG, "load A immediate: {}", val);
|
||||||
|
self.load_accumulator(val as i8);
|
||||||
|
},
|
||||||
|
(instruction::LDA, instruction::UseAddress(addr)) => {
|
||||||
|
let val = self.memory.get_byte(addr);
|
||||||
|
log!(log::DEBUG, "load A. address: {}. value: {}", addr, val);
|
||||||
|
self.load_accumulator(val as i8);
|
||||||
|
},
|
||||||
|
|
||||||
|
(instruction::LDX, instruction::UseImmediate(val)) => {
|
||||||
|
log!(log::DEBUG, "load X immediate: {}", val);
|
||||||
|
self.load_x_register(val as i8);
|
||||||
|
},
|
||||||
|
(instruction::LDX, instruction::UseAddress(addr)) => {
|
||||||
|
let val = self.memory.get_byte(addr);
|
||||||
|
log!(log::DEBUG, "load X. address: {}. value: {}", addr, val);
|
||||||
|
self.load_x_register(val as i8);
|
||||||
|
},
|
||||||
|
|
||||||
|
(instruction::LDY, instruction::UseImmediate(val)) => {
|
||||||
|
log!(log::DEBUG, "load Y immediate: {}", val);
|
||||||
|
self.load_y_register(val as i8);
|
||||||
|
},
|
||||||
|
(instruction::LDY, instruction::UseAddress(addr)) => {
|
||||||
|
let val = self.memory.get_byte(addr);
|
||||||
|
log!(log::DEBUG, "load Y. address: {}. value: {}", addr, val);
|
||||||
|
self.load_y_register(val as i8);
|
||||||
|
},
|
||||||
|
|
||||||
|
(instruction::NOP, _) => {
|
||||||
|
log!(log::DEBUG, "nop instr");
|
||||||
|
},
|
||||||
|
(_, _) => {
|
||||||
|
log!(log::DEBUG, "attempting to execute unimplemented \
|
||||||
|
instruction");
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
loop {
|
||||||
|
if let Some(decoded_instr) = self.fetch_next_and_decode() {
|
||||||
|
self.execute_instruction(decoded_instr);
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_register_with_flags(register: &mut i8,
|
||||||
|
status: &mut Status,
|
||||||
|
value: i8) {
|
||||||
|
*register = value;
|
||||||
|
|
||||||
|
let is_zero = value == 0;
|
||||||
|
let is_negative = value < 0;
|
||||||
|
|
||||||
|
status.set_with_mask(
|
||||||
|
ps_zero | ps_negative,
|
||||||
|
Status::new(StatusArgs { zero: is_zero,
|
||||||
|
negative: is_negative,
|
||||||
|
..StatusArgs::none() } ));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_x_register(&mut self, value: i8) {
|
||||||
|
Machine::load_register_with_flags(&mut self.registers.index_x,
|
||||||
|
&mut self.registers.status,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_y_register(&mut self, value: i8) {
|
||||||
|
Machine::load_register_with_flags(&mut self.registers.index_y,
|
||||||
|
&mut self.registers.status,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_accumulator(&mut self, value: i8) {
|
||||||
|
Machine::load_register_with_flags(&mut self.registers.accumulator,
|
||||||
|
&mut self.registers.status,
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO akeeton: Implement binary-coded decimal.
|
// TODO akeeton: Implement binary-coded decimal.
|
||||||
pub fn add_with_carry(&mut self, value: i8) {
|
pub fn add_with_carry(&mut self, value: i8) {
|
||||||
let a_before: i8 = self.registers.accumulator;
|
let a_before: i8 = self.registers.accumulator;
|
||||||
@ -90,28 +184,27 @@ impl Machine {
|
|||||||
|
|
||||||
let did_carry = (a_after as u8) < (a_before as u8);
|
let did_carry = (a_after as u8) < (a_before as u8);
|
||||||
|
|
||||||
let is_zero = a_after == 0;
|
|
||||||
let is_negative = a_after < 0;
|
|
||||||
let did_overflow =
|
let did_overflow =
|
||||||
(a_before < 0 && value < 0 && a_after >= 0)
|
(a_before < 0 && value < 0 && a_after >= 0)
|
||||||
|| (a_before > 0 && value > 0 && a_after <= 0);
|
|| (a_before > 0 && value > 0 && a_after <= 0);
|
||||||
|
|
||||||
let mask = ps_carry | ps_zero | ps_negative | ps_overflow;
|
let mask = ps_carry | ps_overflow;
|
||||||
|
|
||||||
self.registers.status.set_with_mask(mask,
|
self.registers.status.set_with_mask(mask,
|
||||||
Status::new(StatusArgs { carry: did_carry,
|
Status::new(StatusArgs { carry: did_carry,
|
||||||
zero: is_zero,
|
|
||||||
negative: is_negative,
|
|
||||||
overflow: did_overflow,
|
overflow: did_overflow,
|
||||||
..StatusArgs::none() } ));
|
..StatusArgs::none() } ));
|
||||||
|
|
||||||
self.registers.accumulator = a_after;
|
self.load_accumulator(a_after);
|
||||||
|
|
||||||
|
log!(log::DEBUG, "accumulator: {}", self.registers.accumulator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Show for Machine {
|
impl std::fmt::Show for Machine {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
write!(f, "Machine Dump:\n\nAccumulator: {}", self.registers.accumulator)
|
write!(f, "Machine Dump:\n\nAccumulator: {}",
|
||||||
|
self.registers.accumulator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
// POSSIBILITY OF SUCH DAMAGE.
|
// POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
use address::Address;
|
use address::{Address, AddressDiff};
|
||||||
|
|
||||||
// JAM: We can probably come up with a better way to represent address ranges.
|
// JAM: We can probably come up with a better way to represent address ranges.
|
||||||
// Address range type?
|
// Address range type?
|
||||||
@ -56,21 +56,41 @@ impl Memory {
|
|||||||
pub fn new() -> Memory {
|
pub fn new() -> Memory {
|
||||||
Memory { bytes: [0, ..MEMORY_SIZE] }
|
Memory { bytes: [0, ..MEMORY_SIZE] }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_byte(&self, address: &Address) -> u8 {
|
pub fn get_byte(&self, address: Address) -> u8 {
|
||||||
self.bytes[address.to_uint()]
|
self.bytes[address.to_uint()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_slice(&self, Address(start): Address,
|
||||||
|
AddressDiff(diff): AddressDiff) -> &[u8] {
|
||||||
|
let start = start as uint;
|
||||||
|
let diff = diff as uint;
|
||||||
|
let end = start + diff;
|
||||||
|
self.bytes.slice(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
// Sets the byte at the given address to the given value and returns the
|
// Sets the byte at the given address to the given value and returns the
|
||||||
// previous value at the address.
|
// previous value at the address.
|
||||||
pub fn set_byte(&mut self, address: &Address, value: u8) -> u8 {
|
pub fn set_byte(&mut self, address: Address, value: u8) -> u8 {
|
||||||
let old_value = self.get_byte(address);
|
let old_value = self.get_byte(address);
|
||||||
self.bytes[address.to_uint()] = value;
|
self.bytes[address.to_uint()] = value;
|
||||||
|
old_value
|
||||||
return old_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_bytes(&mut self, Address(start): Address, values: &[u8]) {
|
||||||
|
let start = start as uint;
|
||||||
|
|
||||||
|
// This panics if the range is invalid
|
||||||
|
let slice = self.bytes.slice_mut(start, start + values.len());
|
||||||
|
|
||||||
|
// JAM: Is this the best way to do this copy?
|
||||||
|
for (dest, src) in slice.iter_mut().zip(values.iter()) {
|
||||||
|
*dest = *src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_stack_address(address: &Address) -> bool {
|
pub fn is_stack_address(address: &Address) -> bool {
|
||||||
STACK_ADDRESS_LO <= *address && *address <= STACK_ADDRESS_HI
|
STACK_ADDRESS_LO <= *address && *address <= STACK_ADDRESS_HI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user