Implemented RLD and RRD instructions for Z80

This commit is contained in:
transistor 2023-05-13 21:06:00 -07:00
parent f3d1fd0ae2
commit 5ec2fe4157
2 changed files with 96 additions and 39 deletions

View File

@ -94,6 +94,7 @@ impl Z80 {
pub fn decode_next(&mut self) -> Result<(), Error> {
self.decoder.decode_at(&mut self.port, self.current_clock, self.state.pc)?;
self.increment_refresh(self.decoder.end.saturating_sub(self.decoder.start) as u8);
self.state.pc = self.decoder.end;
Ok(())
}
@ -249,9 +250,9 @@ impl Z80 {
Instruction::EXsp(regpair) => {
let reg_value = self.get_register_pair_value(regpair);
let sp = self.get_register_pair_value(RegisterPair::SP);
let sp_value = self.port.read_leu16(self.current_clock, sp as Address)?;
let sp_value = self.read_port_u16(sp)?;
self.set_register_pair_value(regpair, sp_value);
self.port.write_leu16(self.current_clock, sp as Address, reg_value)?;
self.write_port_u16(sp, reg_value)?;
},
Instruction::HALT => {
self.state.status = Status::Halted;
@ -307,7 +308,6 @@ impl Z80 {
},
Instruction::JPIndirect(regpair) => {
let value = self.get_register_pair_value(regpair);
//let addr = self.port.read_leu16(value as Address)?;
self.state.pc = value;
},
Instruction::JPcc(cond, addr) => {
@ -334,14 +334,19 @@ impl Z80 {
};
match dir {
Direction::FromAcc => { *addr = self.state.reg[Register::A as usize]; },
Direction::ToAcc => { self.state.reg[Register::A as usize] = *addr; },
Direction::FromAcc => {
*addr = self.state.reg[Register::A as usize];
},
Direction::ToAcc => {
self.state.reg[Register::A as usize] = *addr;
let value = self.state.reg[Register::A as usize];
self.set_numeric_flags(value as u16, Size::Byte);
self.set_flag(Flags::Parity, self.state.iff2);
self.set_flag(Flags::AddSubtract, false);
self.set_flag(Flags::HalfCarry, false);
},
}
let value = self.state.reg[Register::A as usize];
self.set_numeric_flags(value as u16, Size::Byte);
self.set_flag(Flags::Parity, self.state.iff2);
self.set_flag(Flags::AddSubtract, false);
self.set_flag(Flags::HalfCarry, false);
}
Instruction::LDD | Instruction::LDDR | Instruction::LDI | Instruction::LDIR => {
let diff = if self.decoder.instruction == Instruction::LDI || self.decoder.instruction == Instruction::LDIR {
@ -468,8 +473,22 @@ impl Z80 {
self.set_flag(Flags::Carry, out_bit);
self.set_register_value(Register::A, result);
},
//Instruction::RLD => {
//},
Instruction::RLD => {
let a = self.get_register_value(Register::A);
let mem = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))? as u8;
let lower_a = a & 0x0F;
let a = (a & 0xF0) | (mem >> 4);
let mem = (mem << 4) | lower_a;
self.set_register_value(Register::A, a);
self.set_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL), mem as u16)?;
self.set_numeric_flags(a as u16, Size::Byte);
self.set_parity_flags(a);
self.set_flag(Flags::HalfCarry, false);
self.set_flag(Flags::AddSubtract, false);
},
Instruction::RR(target, opt_copy) => {
let value = self.get_target_value(target)?;
let (result, out_bit) = self.rotate_right(value, RotateType::Bit9);
@ -504,8 +523,22 @@ impl Z80 {
self.set_flag(Flags::Carry, out_bit);
self.set_register_value(Register::A, result);
},
//Instruction::RRD => {
//},
Instruction::RRD => {
let a = self.get_register_value(Register::A);
let mem = self.get_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL))? as u8;
let lower_mem = mem & 0x0F;
let mem = (a << 4) | (mem >> 4);
let a = (a & 0xF0) | lower_mem;
self.set_register_value(Register::A, a);
self.set_load_target_value(LoadTarget::IndirectRegByte(RegisterPair::HL), mem as u16)?;
self.set_numeric_flags(a as u16, Size::Byte);
self.set_parity_flags(a);
self.set_flag(Flags::HalfCarry, false);
self.set_flag(Flags::AddSubtract, false);
},
Instruction::RST(addr) => {
self.push_word(self.decoder.end)?;
self.state.pc = addr as u16;
@ -652,17 +685,17 @@ impl Z80 {
fn push_word(&mut self, value: u16) -> Result<(), Error> {
self.state.sp = self.state.sp.wrapping_sub(1);
self.port.write_u8(self.current_clock, self.state.sp as Address, (value >> 8) as u8)?;
self.write_port_u8(self.state.sp, (value >> 8) as u8)?;
self.state.sp = self.state.sp.wrapping_sub(1);
self.port.write_u8(self.current_clock, self.state.sp as Address, (value & 0x00FF) as u8)?;
self.write_port_u8(self.state.sp, (value & 0x00FF) as u8)?;
Ok(())
}
fn pop_word(&mut self) -> Result<u16, Error> {
let mut value;
value = self.port.read_u8(self.current_clock, self.state.sp as Address)? as u16;
value = self.read_port_u8(self.state.sp)? as u16;
self.state.sp = self.state.sp.wrapping_add(1);
value |= (self.port.read_u8(self.current_clock, self.state.sp as Address)? as u16) << 8;
value |= (self.read_port_u8(self.state.sp)? as u16) << 8;
self.state.sp = self.state.sp.wrapping_add(1);
Ok(value)
}
@ -674,21 +707,21 @@ impl Z80 {
LoadTarget::DirectRegWord(regpair) => self.get_register_pair_value(regpair),
LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.read_u8(self.current_clock, addr as Address)? as u16
self.read_port_u8(addr)? as u16
},
LoadTarget::IndirectOffsetByte(index_reg, offset) => {
let addr = self.get_index_register_value(index_reg);
self.port.read_u8(self.current_clock, ((addr as i16).wrapping_add(offset as i16)) as Address)? as u16
self.read_port_u8((addr as i16).wrapping_add(offset as i16) as u16)? as u16
},
LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.read_leu16(self.current_clock, addr as Address)?
self.read_port_u16(addr)?
},
LoadTarget::IndirectByte(addr) => {
self.port.read_u8(self.current_clock, addr as Address)? as u16
self.read_port_u8(addr)? as u16
},
LoadTarget::IndirectWord(addr) => {
self.port.read_leu16(self.current_clock, addr as Address)?
self.read_port_u16(addr)?
},
LoadTarget::ImmediateByte(data) => data as u16,
LoadTarget::ImmediateWord(data) => data,
@ -704,21 +737,21 @@ impl Z80 {
LoadTarget::DirectRegWord(regpair) => self.set_register_pair_value(regpair, value),
LoadTarget::IndirectRegByte(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_u8(self.current_clock, addr as Address, value as u8)?;
self.write_port_u8(addr, value as u8)?;
},
LoadTarget::IndirectOffsetByte(index_reg, offset) => {
let addr = self.get_index_register_value(index_reg);
self.port.write_u8(self.current_clock, ((addr as i16).wrapping_add(offset as i16)) as Address, value as u8)?;
self.write_port_u8((addr as i16).wrapping_add(offset as i16) as u16, value as u8)?;
},
LoadTarget::IndirectRegWord(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_leu16(self.current_clock, addr as Address, value)?;
self.write_port_u16(addr, value)?;
},
LoadTarget::IndirectByte(addr) => {
self.port.write_u8(self.current_clock, addr as Address, value as u8)?;
self.write_port_u8(addr, value as u8)?;
},
LoadTarget::IndirectWord(addr) => {
self.port.write_leu16(self.current_clock, addr as Address, value)?;
self.write_port_u16(addr, value)?;
},
_ => panic!("Unsupported LoadTarget for set: {:?}", target),
}
@ -731,11 +764,11 @@ impl Z80 {
Target::DirectRegHalf(reg) => Ok(self.get_index_register_half_value(reg)),
Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(regpair);
Ok(self.port.read_u8(self.current_clock, addr as Address)?)
Ok(self.read_port_u8(addr)?)
},
Target::IndirectOffset(reg, offset) => {
let addr = self.get_index_register_value(reg).wrapping_add_signed(offset as i16);
Ok(self.port.read_u8(self.current_clock, addr as Address)?)
Ok(self.read_port_u8(addr)?)
},
Target::Immediate(data) => Ok(data),
}
@ -747,17 +780,41 @@ impl Z80 {
Target::DirectRegHalf(reg) => self.set_index_register_half_value(reg, value),
Target::IndirectReg(regpair) => {
let addr = self.get_register_pair_value(regpair);
self.port.write_u8(self.current_clock, addr as Address, value)?;
self.write_port_u8(addr, value)?;
},
Target::IndirectOffset(reg, offset) => {
let addr = self.get_index_register_value(reg).wrapping_add_signed(offset as i16);
self.port.write_u8(self.current_clock, addr as Address, value)?;
self.write_port_u8(addr, value)?;
},
_ => panic!("Unsupported LoadTarget for set"),
}
Ok(())
}
fn increment_refresh(&mut self, count: u8) {
self.state.r = (self.state.r & 0x80) | ((self.state.r + count) & 0x7F);
}
fn read_port_u8(&mut self, addr: u16) -> Result<u8, Error> {
self.increment_refresh(1);
self.port.read_u8(self.current_clock, addr as Address)
}
fn write_port_u8(&mut self, addr: u16, value: u8) -> Result<(), Error> {
self.increment_refresh(1);
self.port.write_u8(self.current_clock, addr as Address, value)
}
fn read_port_u16(&mut self, addr: u16) -> Result<u16, Error> {
self.increment_refresh(2);
self.port.read_leu16(self.current_clock, addr as Address)
}
fn write_port_u16(&mut self, addr: u16, value: u16) -> Result<(), Error> {
self.increment_refresh(2);
self.port.write_leu16(self.current_clock, addr as Address, value)
}
fn get_ioport_value(&mut self, upper: u8, lower: u8) -> Result<u8, Error> {
let addr = ((upper as Address) << 8) | (lower as Address);
if let Some(io) = self.ioport.as_mut() {

View File

@ -1,4 +1,4 @@
Last run on 2023-05-13 at commit e61e0cfe8f79c42b3ec232ddb3c97e63dbb40864
Last run on 2023-05-13 at commit f3d1fd0ae2410a164c92150cc3caa0f525cbb4b7
00.json completed, all passed!
01.json completed, all passed!
@ -524,7 +524,7 @@ ed 43.json completed, all passed!
ed 44.json completed, all passed!
ed 45.json completed, all passed!
ed 46.json completed, all passed!
ed 47.json completed: 34 passed, 966 FAILED
ed 47.json completed, all passed!
ed 48.json completed, all passed!
ed 49.json completed, all passed!
ed 4a.json completed, all passed!
@ -532,7 +532,7 @@ ed 4b.json completed, all passed!
ed 4c.json completed, all passed!
ed 4d.json completed, all passed!
ed 4e.json completed, all passed!
ed 4f.json completed: 36 passed, 964 FAILED
ed 4f.json completed, all passed!
ed 50.json completed, all passed!
ed 51.json completed, all passed!
ed 52.json completed, all passed!
@ -548,21 +548,21 @@ ed 5b.json completed, all passed!
ed 5c.json completed, all passed!
ed 5d.json completed, all passed!
ed 5e.json completed, all passed!
ed 5f.json completed: 0 passed, 1000 FAILED
ed 5f.json completed, all passed!
ed 60.json completed, all passed!
ed 61.json completed, all passed!
ed 62.json completed, all passed!
ed 64.json completed, all passed!
ed 65.json completed, all passed!
ed 66.json completed, all passed!
ed 67.json completed: 0 passed, 1000 FAILED
ed 67.json completed, all passed!
ed 68.json completed, all passed!
ed 69.json completed, all passed!
ed 6a.json completed, all passed!
ed 6c.json completed, all passed!
ed 6d.json completed, all passed!
ed 6e.json completed, all passed!
ed 6f.json completed: 0 passed, 1000 FAILED
ed 6f.json completed, all passed!
ed 72.json completed, all passed!
ed 73.json completed, all passed!
ed 74.json completed, all passed!
@ -643,5 +643,5 @@ fd f9.json completed, all passed!
fe.json completed, all passed!
ff.json completed, all passed!
passed: 624068, failed: 17932, total 97%
passed: 628998, failed: 13002, total 98%
completed in 0m 31s