Added LDI, LDD, and LDDR instructions for Z80

This commit is contained in:
transistor 2021-12-06 20:44:44 -08:00
parent 427c79b7b4
commit e41970391e
4 changed files with 27 additions and 32 deletions

View File

@ -100,6 +100,13 @@ General Options
By default, the minifb frontend will scale the window by 2. This can be
changed with the `--scale [1,2,4]` option.
The `-t` or `--threaded` options will run the simulated hardware in a separate
thread from the frontend, which will run as fast as possible, faster than
real-time. By default, the simulated hardware is run inline with the frontend's
update cycle, which is limited to 60Hz. The simulation will be run for 16.6ms of
simulated time for each frame the frontend draws. But the simulated time is not
accurate and Sega Genesis games will run slower than they should.
The `-d` or `--debugger` option will make the emulator start the debugger
before running. There is a simple built-in debugger for stepping through
the rom instructions being emulated. The state of the CPU registers will

View File

@ -53,7 +53,6 @@ impl Transmutable for Z80 {
}
impl Z80 {
pub fn step_internal(&mut self, system: &System) -> Result<(), Error> {
match self.state.status {
@ -62,7 +61,6 @@ impl Z80 {
Status::Running => {
match self.cycle_one(system) {
Ok(()) => Ok(()),
//Err(Error { err: ErrorType::Processor, native, .. }) => {
Err(Error { err: ErrorType::Processor, .. }) => {
//self.exception(system, native as u8, false)?;
Ok(())
@ -80,30 +78,15 @@ impl Z80 {
}
pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> {
//self.timer.cycle.start();
self.decode_next()?;
self.execute_current()?;
//self.timer.cycle.end();
//if (self.timer.cycle.events % 500) == 0 {
// println!("{}", self.timer);
//}
//self.check_pending_interrupts(system)?;
self.check_breakpoints(system);
Ok(())
}
pub fn decode_next(&mut self) -> Result<(), Error> {
//self.timer.decode.start();
self.decoder.decode_at(&mut self.port, self.state.pc)?;
//self.timer.decode.end();
//if self.debugger.use_tracing {
//self.decoder.dump_decoded(&mut self.port);
//self.dump_state();
//}
self.state.pc = self.decoder.end;
Ok(())
}
@ -329,24 +312,27 @@ impl Z80 {
Direction::ToAcc => { self.state.reg[Register::A as usize] = *addr; },
}
}
//Instruction::LDD => {
//},
//Instruction::LDDR => {
//},
//Instruction::LDI => {
//},
Instruction::LDIR => {
Instruction::LDD | Instruction::LDDR | Instruction::LDI | Instruction::LDIR => {
let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR {
1
} else {
-1
};
let src_value = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))?;
self.set_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::DE), src_value)?;
self.add_to_regpair(RegisterPair::DE, 1);
self.add_to_regpair(RegisterPair::HL, 1);
self.add_to_regpair(RegisterPair::DE, diff);
self.add_to_regpair(RegisterPair::HL, diff);
let count = self.add_to_regpair(RegisterPair::BC, -1);
if count != 0 {
self.state.pc -= 2;
}
let mask = (Flags::AddSubtract as u8) | (Flags::HalfCarry as u8) | (Flags::Parity as u8);
let parity = if count != 0 { Flags::Parity as u8 } else { 0 };
self.set_flags(mask, parity);
if self.decoder.instruction == Instruction::LDIR || self.decoder.instruction == Instruction::LDDR {
if count != 0 {
self.state.pc -= 2;
}
}
},
Instruction::NEG => {
let acc = self.get_register_value(Register::A);

View File

@ -62,18 +62,19 @@ pub fn build_genesis<H: Host>(host: &mut H, options: SegaGenesisOptions) -> Resu
// Build the Coprocessor's Bus
let bank_register = Signal::new(0);
let coproc_bus = Rc::new(RefCell::new(Bus::new()));
let coproc_ram = wrap_transmutable(MemoryBlock::new(vec![0; 0x00002000]));
let coproc_ym_sound = wrap_transmutable(YM2612::new());
let coproc_sn_sound = wrap_transmutable(SN76489::new());
let coproc_register = wrap_transmutable(CoprocessorBankRegister::new(bank_register.clone()));
let coproc_area = wrap_transmutable(CoprocessorBankArea::new(bank_register, system.bus.clone()));
let coproc_bus = Rc::new(RefCell::new(Bus::new()));
coproc_bus.borrow_mut().insert(0x0000, coproc_ram.clone());
coproc_bus.borrow_mut().insert(0x4000, coproc_ym_sound.clone());
coproc_bus.borrow_mut().insert(0x6000, coproc_register.clone());
coproc_bus.borrow_mut().insert(0x7f11, coproc_sn_sound.clone());
coproc_bus.borrow_mut().insert(0x8000, coproc_area);
let mut coproc = Z80::new(Z80Type::Z80, 3_579_545, BusPort::new(0, 16, 8, coproc_bus.clone()));
let coproc = Z80::new(Z80Type::Z80, 3_579_545, BusPort::new(0, 16, 8, coproc_bus.clone()));
let reset = coproc.reset.clone();
let bus_request = coproc.bus_request.clone();

View File

@ -1,4 +1,5 @@
* add command line arguments to speed up or slow down either the frame rate limiter or the simulated time per frame
* currently you need to implement the 1.5ms reset in the genesis controllers
* should SharedData be HostData, or something else? I don't think the name is very informative
* can you make the connections between things (like memory adapters), be expressed in a way that's more similar to the electrical design?
@ -41,7 +42,7 @@ Genesis/Mega Drive:
* make tests for each instruction
* check all instructions in the docs
* unimplemented: ABCD, ADDX, BFFFO, BFINS, BKPT, CHK, ILLEGAL, MOVEfromCCR,, RTR, RTD, SBCD, SUBX
* unimplemented: ABCD, ADDX, BFFFO, BFINS, BKPT, CHK, ILLEGAL, RTR, RTD, SBCD, SUBX
* >=MC68020 undecoded & unimplemented: CALLM, CAS, CAS2, CHK2, CMP2, RTM, PACK, TRAPcc, UNPK
* add support for MMU