diagnosed compiler bugs, fixed stuff
This commit is contained in:
parent
c6ef3b4ddb
commit
92ba23e8b3
4
Makefile
4
Makefile
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
|
RUSTC=rustc
|
||||||
|
|
||||||
test:
|
test:
|
||||||
rustc -Z debug-info -o appletest --test apple.rs
|
$(RUSTC) -Z debug-info -o appletest --test apple.rs
|
||||||
./appletest
|
./appletest
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
Rust version of an Apple II emulator.
|
||||||
|
|
||||||
|
CPU simulation heavily borrowed from https://github.com/pcwalton/sprocketnes
|
12
a2.rs
12
a2.rs
|
@ -68,7 +68,6 @@ impl Mem for AppleII
|
||||||
{
|
{
|
||||||
fn loadb(&mut self, addr: u16) -> u8
|
fn loadb(&mut self, addr: u16) -> u8
|
||||||
{
|
{
|
||||||
debug!("Read {:x}", addr);
|
|
||||||
self.nreads += 1;
|
self.nreads += 1;
|
||||||
let val =
|
let val =
|
||||||
// see if it's from main memory (0x0000-0xbfff)
|
// see if it's from main memory (0x0000-0xbfff)
|
||||||
|
@ -84,7 +83,8 @@ impl Mem for AppleII
|
||||||
}
|
}
|
||||||
// it must be an I/O location (0xc000-0xcfff)
|
// it must be an I/O location (0xc000-0xcfff)
|
||||||
else if (addr < HW_LO + 0x100) {
|
else if (addr < HW_LO + 0x100) {
|
||||||
self.doIO(addr, 0)
|
let noise = self.noise(); // when reading, pass noise as value (we might get it back)
|
||||||
|
self.doIO(addr, noise)
|
||||||
} else {
|
} else {
|
||||||
match self.slots[(addr >> 8) & 7] {
|
match self.slots[(addr >> 8) & 7] {
|
||||||
None => self.noise(),
|
None => self.noise(),
|
||||||
|
@ -97,7 +97,7 @@ impl Mem for AppleII
|
||||||
|
|
||||||
fn storeb(&mut self, addr: u16, val: u8)
|
fn storeb(&mut self, addr: u16, val: u8)
|
||||||
{
|
{
|
||||||
debug!("write {:x} = {:x}", addr, val);
|
debug!("Write {:x} = {:x}", addr, val);
|
||||||
// see if it's from main memory (0x0000-0xbfff)
|
// see if it's from main memory (0x0000-0xbfff)
|
||||||
if (addr < HW_LO)
|
if (addr < HW_LO)
|
||||||
{
|
{
|
||||||
|
@ -140,9 +140,11 @@ impl AppleII
|
||||||
nreads: 0
|
nreads: 0
|
||||||
} }
|
} }
|
||||||
|
|
||||||
pub fn set_slot(&mut self, slot: uint, p: ~Peripheral)
|
pub fn set_slot(&mut self, slot: uint, mut p: ~Peripheral)
|
||||||
{
|
{
|
||||||
|
//p.doIO(0,0);
|
||||||
self.slots[slot] = Some(p);
|
self.slots[slot] = Some(p);
|
||||||
|
//self.slots[slot].get_mut_ref().doIO(0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn noise(&mut self) -> u8 { self.mem[self.nreads & 0xffff] }
|
fn noise(&mut self) -> u8 { self.mem[self.nreads & 0xffff] }
|
||||||
|
@ -237,6 +239,6 @@ impl AppleII
|
||||||
use std::vec::bytes::copy_memory;
|
use std::vec::bytes::copy_memory;
|
||||||
let ap2rom = File::open(&Path::new("apple2.rom")).read_bytes(0x3000);
|
let ap2rom = File::open(&Path::new("apple2.rom")).read_bytes(0x3000);
|
||||||
copy_memory(self.mem.mut_slice(0xd000, 0xd000+0x3000), ap2rom);
|
copy_memory(self.mem.mut_slice(0xd000, 0xd000+0x3000), ap2rom);
|
||||||
debug!("loaded apple2.rom");
|
info!("loaded apple2.rom");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
48
diskii.rs
48
diskii.rs
|
@ -19,15 +19,13 @@ struct Drive
|
||||||
{
|
{
|
||||||
disk_data: RawDiskData, // disk data
|
disk_data: RawDiskData, // disk data
|
||||||
track_data: RawTrackData, // array of track data
|
track_data: RawTrackData, // array of track data
|
||||||
track: uint, // current track #
|
half_track: uint, // current track #
|
||||||
track_index: uint, // position of read head along track
|
track_index: uint, // position of read head along track
|
||||||
}
|
}
|
||||||
|
|
||||||
static NoDisk: Option<Drive> = None;
|
|
||||||
|
|
||||||
pub struct DiskController
|
pub struct DiskController
|
||||||
{
|
{
|
||||||
drives: [Option<Drive>, ..NUM_DRIVES],
|
drives: [Option<~Drive>, ..NUM_DRIVES],
|
||||||
selected: u8, // selected drive (0 or 1)
|
selected: u8, // selected drive (0 or 1)
|
||||||
motor: bool, // is motor on?
|
motor: bool, // is motor on?
|
||||||
read_mode: bool,
|
read_mode: bool,
|
||||||
|
@ -37,7 +35,7 @@ pub struct DiskController
|
||||||
impl DiskController
|
impl DiskController
|
||||||
{
|
{
|
||||||
pub fn new() -> DiskController { DiskController {
|
pub fn new() -> DiskController { DiskController {
|
||||||
drives: [NoDisk, NoDisk],
|
drives: [None, None],
|
||||||
selected: 0,
|
selected: 0,
|
||||||
motor: false,
|
motor: false,
|
||||||
read_mode: false,
|
read_mode: false,
|
||||||
|
@ -55,14 +53,19 @@ impl DiskController
|
||||||
f.read(disk_image[track]);
|
f.read(disk_image[track]);
|
||||||
disk_data[track] = nibblizeTrack(254, track as u8, disk_image);
|
disk_data[track] = nibblizeTrack(254, track as u8, disk_image);
|
||||||
}
|
}
|
||||||
self.drives[disknum] = Some(Drive {
|
self.drives[disknum] = Some(~Drive {
|
||||||
disk_data: disk_data,
|
disk_data: disk_data,
|
||||||
track_data: [0, ..RAW_TRACK_SIZE],
|
track_data: [0, ..RAW_TRACK_SIZE],
|
||||||
track: 0,
|
half_track: NUM_TRACKS+1,
|
||||||
track_index: 0,
|
track_index: 0,
|
||||||
});
|
});
|
||||||
debug!("loaded disk image {}", imagefilename);
|
assert!(self.has_disk(disknum));
|
||||||
|
info!("loaded disk image {} into drive {}", imagefilename, disknum);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_disk(&self, disknum: int) -> bool
|
||||||
|
{
|
||||||
|
return self.drives[disknum].is_some();
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn drive<'r>(&'r self) -> &'r Option<~Drive> { &self.drives[self.selected] }
|
// fn drive<'r>(&'r self) -> &'r Option<~Drive> { &self.drives[self.selected] }
|
||||||
|
@ -72,21 +75,21 @@ impl Drive
|
||||||
{
|
{
|
||||||
fn read_latch(&mut self) -> u8
|
fn read_latch(&mut self) -> u8
|
||||||
{
|
{
|
||||||
debug!("read latch @ {:x} track {}", self.track_index, self.track)
|
debug!("read latch @ {:x} track*2 {}", self.track_index, self.half_track)
|
||||||
self.track_index = (self.track_index + 1) % RAW_TRACK_SIZE;
|
self.track_index = (self.track_index + 1) % RAW_TRACK_SIZE;
|
||||||
return self.track_data[self.track_index];
|
return self.track_data[self.track_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_latch(&mut self, value: u8)
|
fn write_latch(&mut self, value: u8)
|
||||||
{
|
{
|
||||||
debug!("write latch @ {:x} track {}", self.track_index, self.track)
|
debug!("write latch @ {:x} track*2 {}", self.track_index, self.half_track)
|
||||||
self.track_index = (self.track_index + 1) % RAW_TRACK_SIZE;
|
self.track_index = (self.track_index + 1) % RAW_TRACK_SIZE;
|
||||||
self.track_data[self.track_index] = value;
|
self.track_data[self.track_index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn servo_phase(&mut self, phase: uint)
|
fn servo_phase(&mut self, phase: uint)
|
||||||
{
|
{
|
||||||
let mut new_track = self.track;
|
let mut new_track = self.half_track;
|
||||||
|
|
||||||
// if new phase is even and current phase is odd
|
// if new phase is even and current phase is odd
|
||||||
if (phase == ((new_track - 1) & 3))
|
if (phase == ((new_track - 1) & 3))
|
||||||
|
@ -108,8 +111,8 @@ impl Drive
|
||||||
} else {
|
} else {
|
||||||
// TODO: self.track_data = None;
|
// TODO: self.track_data = None;
|
||||||
}
|
}
|
||||||
self.track = new_track;
|
self.half_track = new_track;
|
||||||
debug!("phase {:x} track = {}", phase, self.track as f32*0.5);
|
info!("phase {:x} track = {}", phase, self.half_track as f32*0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +130,8 @@ impl Peripheral for DiskController
|
||||||
|
|
||||||
fn doIO(&mut self, addr: u16, val: u8) -> u8
|
fn doIO(&mut self, addr: u16, val: u8) -> u8
|
||||||
{
|
{
|
||||||
//debug!("disk IO {:x} -> {:x}", addr, val);
|
let ref mut drive = self.drives[self.selected];
|
||||||
let &mut drive = &self.drives[self.selected];
|
debug!("disk {} IO {:x} -> {:x} {}", self.selected, addr, val, drive.is_some());
|
||||||
match addr & 0xf
|
match addr & 0xf
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -138,7 +141,7 @@ impl Peripheral for DiskController
|
||||||
* considered to be adjacent. The previous phase number can be
|
* considered to be adjacent. The previous phase number can be
|
||||||
* computed as the track number % 4.
|
* computed as the track number % 4.
|
||||||
*/
|
*/
|
||||||
1|3|5|7 if drive.is_some() => { drive.unwrap().servo_phase(((addr>>1) & 3) as uint); }
|
1|3|5|7 if drive.is_some() => { drive.get_mut_ref().servo_phase(((addr>>1) & 3) as uint); }
|
||||||
/*
|
/*
|
||||||
* Turn drive motor off.
|
* Turn drive motor off.
|
||||||
*/
|
*/
|
||||||
|
@ -162,7 +165,7 @@ impl Peripheral for DiskController
|
||||||
/*
|
/*
|
||||||
* Read a disk byte if read mode is active.
|
* Read a disk byte if read mode is active.
|
||||||
*/
|
*/
|
||||||
0xc if self.read_mode && drive.is_some() => { return drive.unwrap().read_latch(); }
|
0xc if self.read_mode && drive.is_some() => { return drive.get_mut_ref().read_latch(); }
|
||||||
/*
|
/*
|
||||||
* Select read mode and read the write protect status.
|
* Select read mode and read the write protect status.
|
||||||
*/
|
*/
|
||||||
|
@ -171,15 +174,14 @@ impl Peripheral for DiskController
|
||||||
* Write a disk byte if write mode is active and the disk is not
|
* Write a disk byte if write mode is active and the disk is not
|
||||||
* write protected.
|
* write protected.
|
||||||
*/
|
*/
|
||||||
0xd if !self.read_mode && !self.write_protect && drive.is_some() => { drive.unwrap().write_latch(val); }
|
0xd if !self.read_mode && !self.write_protect && drive.is_some() => { drive.get_mut_ref().write_latch(val); }
|
||||||
/*
|
/*
|
||||||
* Read the write protect status only.
|
* Read the write protect status only.
|
||||||
*/
|
*/
|
||||||
0xd if self.write_protect => { return 0x80; }
|
0xd if self.write_protect => { return 0x80; }
|
||||||
0xd => { return 0; }
|
_ => { }
|
||||||
_ => { return 0; }
|
|
||||||
}
|
}
|
||||||
return 0; //emu.noise();
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -327,7 +329,7 @@ impl Peripheral for DiskController
|
||||||
let startindex = skewing_table[sector] as uint << 8;
|
let startindex = skewing_table[sector] as uint << 8;
|
||||||
return nibblizeSector(vol, trk, sector as u8, disk[trk].slice(startindex, startindex+256));
|
return nibblizeSector(vol, trk, sector as u8, disk[trk].slice(startindex, startindex+256));
|
||||||
}).concat_vec();
|
}).concat_vec();
|
||||||
debug!("track {} converted to {:x} raw bytes", trk, arr.len());
|
info!("track {} converted to {:x} raw bytes", trk, arr.len());
|
||||||
assert!(arr.len() == RAW_SECTOR_SIZE*16);
|
assert!(arr.len() == RAW_SECTOR_SIZE*16);
|
||||||
let mut fixarr: RawTrackData = [0xff_u8, ..RAW_TRACK_SIZE];
|
let mut fixarr: RawTrackData = [0xff_u8, ..RAW_TRACK_SIZE];
|
||||||
for i in range(0, arr.len())
|
for i in range(0, arr.len())
|
||||||
|
|
4
tests.rs
4
tests.rs
|
@ -2,6 +2,7 @@
|
||||||
use cpu::Cpu;
|
use cpu::Cpu;
|
||||||
use mem::Mem;
|
use mem::Mem;
|
||||||
use a2::AppleII;
|
use a2::AppleII;
|
||||||
|
use a2::Peripheral;
|
||||||
use diskii::DiskController;
|
use diskii::DiskController;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -40,10 +41,11 @@ fn test_a2()
|
||||||
a2.read_roms();
|
a2.read_roms();
|
||||||
let mut dc: DiskController = DiskController::new();
|
let mut dc: DiskController = DiskController::new();
|
||||||
dc.load_disk(0, "JUNK4.DSK");
|
dc.load_disk(0, "JUNK4.DSK");
|
||||||
|
assert!(dc.has_disk(0));
|
||||||
a2.set_slot(6, ~dc);
|
a2.set_slot(6, ~dc);
|
||||||
let mut cpu = Cpu::new(a2);
|
let mut cpu = Cpu::new(a2);
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
for i in range(0,100000) {
|
for i in range(0,10*1000000) {
|
||||||
cpu.step();
|
cpu.step();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue