Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
//legend:
|
2016-09-06 13:53:14 +00:00
|
|
|
// a = register A
|
2016-09-06 00:09:33 +00:00
|
|
|
// c = condition
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
// e = relative operand
|
|
|
|
// in = (operand)
|
2016-09-04 13:51:27 +00:00
|
|
|
// inn = (operand-word)
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
// irr = (register-word)
|
|
|
|
// o = opcode bits
|
|
|
|
// n = operand
|
|
|
|
// nn = operand-word
|
|
|
|
// r = register
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::ADD(uint8 x, uint8 y, bool c) -> uint8 {
|
|
|
|
uint9 z = x + y + c;
|
2016-08-27 04:48:21 +00:00
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
CF = z.bit(8);
|
|
|
|
NF = 0;
|
2016-11-15 07:20:42 +00:00
|
|
|
VF = uint8(~(x ^ y) & (x ^ z)).bit(7);
|
2016-09-06 13:53:14 +00:00
|
|
|
XF = z.bit(3);
|
2016-11-15 07:20:42 +00:00
|
|
|
HF = uint8(x ^ y ^ z).bit(4);
|
2016-09-06 13:53:14 +00:00
|
|
|
YF = z.bit(5);
|
2016-11-15 07:20:42 +00:00
|
|
|
ZF = uint8(z) == 0;
|
2016-09-06 13:53:14 +00:00
|
|
|
SF = z.bit(7);
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::AND(uint8 x, uint8 y) -> uint8 {
|
|
|
|
uint8 z = x & y;
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
CF = 0;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(z);
|
|
|
|
XF = z.bit(3);
|
|
|
|
HF = 1;
|
|
|
|
YF = z.bit(5);
|
|
|
|
ZF = z == 0;
|
|
|
|
SF = z.bit(7);
|
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::BIT(uint3 bit, uint8 x) -> void {
|
|
|
|
NF = 0;
|
|
|
|
HF = 1;
|
|
|
|
ZF = (x & 1 << bit) == 0;
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::DEC(uint8 x) -> uint8 {
|
|
|
|
uint8 z = x - 1;
|
|
|
|
|
|
|
|
NF = 1;
|
|
|
|
VF = z == 0x7f;
|
|
|
|
XF = z.bit(3);
|
|
|
|
HF = z.bits(0,3) == 0x0f;
|
|
|
|
YF = z.bit(5);
|
|
|
|
ZF = z == 0;
|
|
|
|
SF = z.bit(7);
|
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::INC(uint8 x) -> uint8 {
|
|
|
|
uint8 z = x + 1;
|
|
|
|
|
|
|
|
NF = 0;
|
|
|
|
VF = z == 0x80;
|
|
|
|
XF = z.bit(3);
|
|
|
|
HF = z.bits(0,3) == 0x00;
|
|
|
|
YF = z.bit(5);
|
|
|
|
ZF = z == 0;
|
|
|
|
SF = z.bit(7);
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::OR(uint8 x, uint8 y) -> uint8 {
|
|
|
|
uint8 z = x | y;
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
CF = 0;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(z);
|
|
|
|
XF = z.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = z.bit(5);
|
|
|
|
ZF = z == 0;
|
|
|
|
SF = z.bit(7);
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::RES(uint3 bit, uint8 x) -> uint8 {
|
|
|
|
x &= ~(1 << bit);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::RL(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(7);
|
|
|
|
x = x << 1 | CF;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::RLC(uint8 x) -> uint8 {
|
|
|
|
x = x << 1 | x >> 7;
|
|
|
|
|
|
|
|
CF = x.bit(0);
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::RR(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(0);
|
|
|
|
x = x >> 1 | CF << 7;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::RRC(uint8 x) -> uint8 {
|
|
|
|
x = x >> 1 | x << 7;
|
|
|
|
|
|
|
|
CF = x.bit(7);
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::SET(uint3 bit, uint8 x) -> uint8 {
|
|
|
|
x |= (1 << bit);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::SLA(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(7);
|
|
|
|
x = x << 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::SLL(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(7);
|
|
|
|
x = x << 1 | 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::SRA(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(0);
|
|
|
|
x = (int8)x >> 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::SRL(uint8 x) -> uint8 {
|
|
|
|
bool c = x.bit(0);
|
|
|
|
x = x >> 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(x);
|
|
|
|
XF = x.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = x.bit(5);
|
|
|
|
ZF = x == 0;
|
|
|
|
SF = x.bit(7);
|
|
|
|
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::SUB(uint8 x, uint8 y, bool c) -> uint8 {
|
|
|
|
uint9 z = x - y - c;
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
CF = z.bit(8);
|
|
|
|
NF = 1;
|
2016-11-15 07:20:42 +00:00
|
|
|
VF = uint8((x ^ y) & (x ^ z)).bit(7);
|
2016-09-06 13:53:14 +00:00
|
|
|
XF = z.bit(3);
|
2016-11-15 07:20:42 +00:00
|
|
|
HF = uint8(x ^ y ^ z).bit(4);
|
2016-09-06 13:53:14 +00:00
|
|
|
YF = z.bit(5);
|
2016-11-15 07:20:42 +00:00
|
|
|
ZF = uint8(z) == 0;
|
2016-09-06 13:53:14 +00:00
|
|
|
SF = z.bit(7);
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
return z;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::XOR(uint8 x, uint8 y) -> uint8 {
|
|
|
|
uint8 z = x ^ y;
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
CF = 0;
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(z);
|
|
|
|
XF = z.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = z.bit(5);
|
|
|
|
ZF = z == 0;
|
|
|
|
SF = z.bit(7);
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
return z;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
auto Z80::instructionADC_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = ADD(A, read(displace(x)), CF);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionADC_a_n() -> void {
|
|
|
|
A = ADD(A, operand(), CF);
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionADC_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = ADD(A, x, CF);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
auto Z80::instructionADC_hl_rr(uint16& x) -> void {
|
|
|
|
wait(4);
|
|
|
|
auto lo = ADD(HL >> 0, x >> 0, CF);
|
|
|
|
wait(3);
|
|
|
|
auto hi = ADD(HL >> 8, x >> 8, CF);
|
|
|
|
HL = hi << 8 | lo << 0;
|
|
|
|
ZF = HL == 0;
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionADD_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = ADD(A, read(displace(x)));
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionADD_a_n() -> void {
|
|
|
|
A = ADD(A, operand());
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionADD_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = ADD(A, x);
|
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
auto Z80::instructionADD_hl_rr(uint16& x) -> void {
|
2016-11-15 07:20:42 +00:00
|
|
|
auto vf = VF, zf = ZF, sf = SF;
|
2016-09-06 13:53:14 +00:00
|
|
|
wait(4);
|
2016-11-01 11:42:25 +00:00
|
|
|
auto lo = ADD(HL >> 0, x >> 0);
|
2016-09-06 13:53:14 +00:00
|
|
|
wait(3);
|
2016-11-01 11:42:25 +00:00
|
|
|
auto hi = ADD(HL >> 8, x >> 8, CF);
|
|
|
|
HL = hi << 8 | lo << 0;
|
2016-11-15 07:20:42 +00:00
|
|
|
VF = vf, ZF = zf, SF = sf; //restore unaffected flags
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionAND_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = AND(A, read(displace(x)));
|
2016-09-04 13:51:27 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionAND_a_n() -> void {
|
|
|
|
A = AND(A, operand());
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionAND_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = AND(A, x);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionBIT_o_irr(uint3 bit, uint16& x) -> void {
|
|
|
|
BIT(bit, read(displace(x)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionBIT_o_r(uint3 bit, uint8& x) -> void {
|
|
|
|
BIT(bit, x);
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionCALL_c_nn(bool c) -> void {
|
|
|
|
auto addr = operands();
|
|
|
|
if(!c) return;
|
|
|
|
wait(1);
|
|
|
|
push(PC);
|
|
|
|
PC = addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCALL_nn() -> void {
|
|
|
|
auto addr = operands();
|
|
|
|
wait(1);
|
|
|
|
push(PC);
|
|
|
|
PC = addr;
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionCCF() -> void {
|
|
|
|
CF = !CF;
|
|
|
|
NF = 0;
|
|
|
|
HF = !CF;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionCP_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
SUB(A, read(displace(x)));
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCP_a_n() -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
SUB(A, operand());
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCP_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
SUB(A, x);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionCPD() -> void {
|
|
|
|
auto data = read(_HL--);
|
|
|
|
SUB(A, data);
|
|
|
|
VF = --BC > 0;
|
|
|
|
wait(5);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCPDR() -> void {
|
|
|
|
instructionCPD();
|
|
|
|
if(!VF || ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCPI() -> void {
|
|
|
|
auto data = read(_HL++);
|
2016-10-31 21:10:33 +00:00
|
|
|
wait(5);
|
2016-10-29 00:33:30 +00:00
|
|
|
SUB(A, data);
|
|
|
|
VF = --BC > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionCPIR() -> void {
|
|
|
|
instructionCPI();
|
|
|
|
if(!VF || ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionCPL() -> void {
|
|
|
|
A = ~A;
|
|
|
|
|
|
|
|
NF = 1;
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 1;
|
|
|
|
YF = A.bit(5);
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionDAA() -> void {
|
2016-11-15 07:20:42 +00:00
|
|
|
auto a = A;
|
|
|
|
if(CF || (A.bits(0,7) > 0x99)) { A += NF ? -0x60 : 0x60; CF = 1; }
|
|
|
|
if(HF || (A.bits(0,3) > 0x09)) { A += NF ? -0x06 : 0x06; }
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
PF = parity(A);
|
|
|
|
XF = A.bit(3);
|
2016-11-15 07:20:42 +00:00
|
|
|
HF = uint8(A ^ a).bit(4);
|
2016-11-01 11:42:25 +00:00
|
|
|
YF = A.bit(5);
|
|
|
|
ZF = A == 0;
|
|
|
|
SF = A.bit(7);
|
2016-10-31 21:10:33 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionDEC_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
auto data = read(addr);
|
|
|
|
wait(1);
|
|
|
|
write(addr, DEC(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionDEC_r(uint8& x) -> void {
|
|
|
|
x = DEC(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionDEC_rr(uint16& x) -> void {
|
|
|
|
wait(2);
|
|
|
|
x--;
|
2016-09-04 13:51:27 +00:00
|
|
|
}
|
|
|
|
|
2016-08-19 14:11:26 +00:00
|
|
|
auto Z80::instructionDI() -> void {
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
r.iff1 = 0;
|
|
|
|
r.iff2 = 0;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionDJNZ_e() -> void {
|
|
|
|
wait(1);
|
|
|
|
auto e = operand();
|
|
|
|
if(!--B) return;
|
|
|
|
wait(5);
|
|
|
|
PC += (int8)e;
|
|
|
|
}
|
|
|
|
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
auto Z80::instructionEI() -> void {
|
|
|
|
r.iff1 = 1;
|
|
|
|
r.iff2 = 1;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionEX_rr_rr(uint16& x, uint16& y) -> void {
|
|
|
|
auto z = x;
|
|
|
|
x = y;
|
|
|
|
y = z;
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionEXX() -> void {
|
|
|
|
swap(BC, BC_);
|
|
|
|
swap(DE, DE_);
|
|
|
|
swap(_HL, HL_);
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionHALT() -> void {
|
|
|
|
r.halt = 1;
|
|
|
|
}
|
|
|
|
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
auto Z80::instructionIM_o(uint2 code) -> void {
|
|
|
|
wait(4);
|
|
|
|
r.im = code;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
auto Z80::instructionIN_a_in() -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = in(operand());
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionIN_r_ic(uint8& x) -> void {
|
|
|
|
x = in(C);
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionINC_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
auto data = read(addr);
|
|
|
|
wait(1);
|
|
|
|
write(addr, INC(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionINC_r(uint8& x) -> void {
|
|
|
|
x = INC(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionINC_rr(uint16& x) -> void {
|
|
|
|
wait(2);
|
|
|
|
x++;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionIND() -> void {
|
2016-10-31 21:10:33 +00:00
|
|
|
wait(1);
|
2016-10-29 00:33:30 +00:00
|
|
|
auto data = in(C);
|
|
|
|
write(_HL--, data);
|
|
|
|
NF = 0;
|
2016-10-31 21:10:33 +00:00
|
|
|
ZF = --B > 0;
|
2016-10-29 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionINDR() -> void {
|
|
|
|
instructionIND();
|
|
|
|
if(!ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionINI() -> void {
|
2016-10-31 21:10:33 +00:00
|
|
|
wait(1);
|
2016-10-29 00:33:30 +00:00
|
|
|
auto data = in(C);
|
|
|
|
write(_HL++, data);
|
|
|
|
NF = 0;
|
2016-10-31 21:10:33 +00:00
|
|
|
ZF = --B > 0;
|
2016-10-29 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionINIR() -> void {
|
|
|
|
instructionINI();
|
|
|
|
if(!ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
2016-08-27 04:48:21 +00:00
|
|
|
auto Z80::instructionJP_c_nn(bool c) -> void {
|
2016-09-06 00:09:33 +00:00
|
|
|
auto pc = operands();
|
|
|
|
if(c) r.pc = pc;
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionJP_rr(uint16& x) -> void {
|
|
|
|
PC = x;
|
|
|
|
}
|
|
|
|
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
auto Z80::instructionJR_c_e(bool c) -> void {
|
|
|
|
auto e = operand();
|
2016-09-06 00:09:33 +00:00
|
|
|
if(c) wait(5), r.pc += (int8)e;
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionLD_a_inn() -> void {
|
|
|
|
A = read(operands());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_a_irr(uint16& x) -> void {
|
|
|
|
A = read(displace(x));
|
|
|
|
}
|
|
|
|
|
2016-09-04 13:51:27 +00:00
|
|
|
auto Z80::instructionLD_inn_a() -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
write(operands(), A);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_inn_rr(uint16& x) -> void {
|
|
|
|
auto addr = operands();
|
|
|
|
write(addr + 0, x >> 0);
|
|
|
|
write(addr + 1, x >> 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_irr_a(uint16& x) -> void {
|
|
|
|
write(displace(x), A);
|
2016-09-04 13:51:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_irr_n(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, operand());
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_irr_r(uint16& x, uint8& y) -> void {
|
2016-09-06 00:09:33 +00:00
|
|
|
write(displace(x), y);
|
2016-08-27 04:48:21 +00:00
|
|
|
}
|
|
|
|
|
2016-09-04 13:51:27 +00:00
|
|
|
auto Z80::instructionLD_r_n(uint8& x) -> void {
|
Update to v101r14 release.
byuu says:
Changelog:
- rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY)
prefixes
- added Processor::Z80::Bus as a new type of abstraction
- all of the instructions implemented have their proper T-cycle counts
now
- added nall/certificates for my public keys
The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being
2-read + 2-wait states; operand+regular reads/writes being 3-read. For
now, this puts the cycle counts inside the CPU core. At the moment, I
can't think of any CPU core where this wouldn't be appropriate. But it's
certainly possible that such a case exists. So this may not be the
perfect solution.
The reason for having it be a subclass of Processor::Z80 instead of
virtual functions for the MasterSystem::CPU core to define is due to
naming conflicts. I wanted the core to say `in(addr)` and have it take
the four clocks. But I also wanted a version of the function that didn't
consume time when called. One way to do that would be for the core to
call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to
`MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::`
prefix on all of the opcodes. Very easy to forget it, and then end up not
consuming any time. Another is to use uglier names in the
`MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But,
yuck.
So ... yeah, this is an experiment. We'll see how it goes.
2016-09-03 11:26:04 +00:00
|
|
|
x = operand();
|
2016-08-19 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionLD_r_irr(uint8& x, uint16& y) -> void {
|
|
|
|
x = read(displace(y));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLD_r_r(uint8& x, uint8& y) -> void {
|
|
|
|
x = y;
|
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
//LD to/from I/R requires an extra T-cycle
|
|
|
|
auto Z80::instructionLD_r_r1(uint8& x, uint8& y) -> void {
|
|
|
|
wait(1);
|
|
|
|
x = y;
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionLD_rr_inn(uint16& x) -> void {
|
|
|
|
auto addr = operands();
|
|
|
|
x.byte(0) = read(addr + 0);
|
|
|
|
x.byte(1) = read(addr + 1);
|
|
|
|
}
|
|
|
|
|
2016-09-04 13:51:27 +00:00
|
|
|
auto Z80::instructionLD_rr_nn(uint16& x) -> void {
|
2016-09-06 00:09:33 +00:00
|
|
|
x = operands();
|
2016-09-04 13:51:27 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionLD_sp_rr(uint16& x) -> void {
|
|
|
|
wait(2);
|
|
|
|
SP = x;
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionLDD() -> void {
|
|
|
|
auto data = read(_HL--);
|
|
|
|
write(DE--, data);
|
|
|
|
wait(2);
|
|
|
|
NF = 0;
|
|
|
|
VF = --BC > 0;
|
|
|
|
HF = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLDDR() -> void {
|
|
|
|
instructionLDD();
|
|
|
|
if(!VF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLDI() -> void {
|
|
|
|
auto data = read(_HL++);
|
|
|
|
write(DE++, data);
|
|
|
|
wait(2);
|
|
|
|
NF = 0;
|
|
|
|
VF = --BC > 0;
|
|
|
|
HF = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionLDIR() -> void {
|
|
|
|
instructionLDI();
|
|
|
|
if(!VF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionNEG() -> void {
|
|
|
|
A = SUB(0, A);
|
|
|
|
}
|
|
|
|
|
2016-08-19 14:11:26 +00:00
|
|
|
auto Z80::instructionNOP() -> void {
|
|
|
|
}
|
2016-09-06 00:09:33 +00:00
|
|
|
|
|
|
|
auto Z80::instructionOR_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = OR(A, read(displace(x)));
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionOR_a_n() -> void {
|
|
|
|
A = OR(A, operand());
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionOR_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = OR(A, x);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionOTDR() -> void {
|
|
|
|
instructionOUTD();
|
|
|
|
if(!ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionOTIR() -> void {
|
|
|
|
instructionOUTI();
|
|
|
|
if(!ZF) return;
|
|
|
|
wait(5);
|
|
|
|
PC -= 2;
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionOUT_ic_r(uint8& x) -> void {
|
|
|
|
out(C, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionOUT_n_a() -> void {
|
|
|
|
auto addr = operand();
|
|
|
|
out(addr, A);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionOUTD() -> void {
|
2016-10-31 21:10:33 +00:00
|
|
|
wait(1);
|
2016-10-29 00:33:30 +00:00
|
|
|
auto data = read(_HL--);
|
|
|
|
out(C, data);
|
|
|
|
NF = 1;
|
2016-10-31 21:10:33 +00:00
|
|
|
ZF = --B > 0;
|
2016-10-29 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionOUTI() -> void {
|
2016-10-31 21:10:33 +00:00
|
|
|
wait(1);
|
2016-10-29 00:33:30 +00:00
|
|
|
auto data = read(_HL++);
|
|
|
|
out(C, data);
|
|
|
|
NF = 1;
|
2016-10-31 21:10:33 +00:00
|
|
|
ZF = --B > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionPOP_rr(uint16& x) -> void {
|
|
|
|
x = pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionPUSH_rr(uint16& x) -> void {
|
|
|
|
wait(1);
|
|
|
|
push(x);
|
2016-10-29 00:33:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRES_o_irr(uint3 bit, uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, RES(bit, read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRES_o_r(uint3 bit, uint8& x) -> void {
|
|
|
|
x = RES(bit, x);
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionRET() -> void {
|
|
|
|
wait(1);
|
|
|
|
PC = pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRET_c(bool c) -> void {
|
|
|
|
wait(1);
|
|
|
|
if(!c) return;
|
|
|
|
PC = pop();
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRETI() -> void {
|
|
|
|
PC = pop();
|
2016-11-15 07:20:42 +00:00
|
|
|
r.iff1 = r.iff2;
|
2016-10-31 21:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRETN() -> void {
|
|
|
|
PC = pop();
|
|
|
|
r.iff1 = r.iff2;
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionRL_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, RL(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRL_r(uint8& x) -> void {
|
|
|
|
x = RL(x);
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionRLA() -> void {
|
|
|
|
bool c = A.bit(7);
|
|
|
|
A = A << 1 | CF;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionRLC_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, RLC(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRLC_r(uint8& x) -> void {
|
|
|
|
x = RLC(x);
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionRLCA() -> void {
|
|
|
|
bool c = A.bit(7);
|
|
|
|
A = A << 1 | c;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
auto Z80::instructionRLD() -> void {
|
|
|
|
auto data = read(HL);
|
|
|
|
wait(1);
|
|
|
|
write(HL, (data << 4) | (A & 0x0f));
|
|
|
|
wait(3);
|
|
|
|
A = (A & 0xf0) | (data >> 4);
|
|
|
|
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(A);
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
|
|
|
ZF = A == 0;
|
|
|
|
SF = A.bit(7);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionRR_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, RR(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRR_r(uint8& x) -> void {
|
|
|
|
x = RR(x);
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionRRA() -> void {
|
|
|
|
bool c = A.bit(0);
|
|
|
|
A = CF << 7 | A >> 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionRRC_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, RRC(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionRRC_r(uint8& x) -> void {
|
|
|
|
x = RRC(x);
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionRRCA() -> void {
|
|
|
|
bool c = A.bit(0);
|
|
|
|
A = c << 7 | A >> 1;
|
|
|
|
|
|
|
|
CF = c;
|
|
|
|
NF = 0;
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
auto Z80::instructionRRD() -> void {
|
|
|
|
auto data = read(HL);
|
|
|
|
wait(1);
|
|
|
|
write(HL, (data >> 4) | (A << 4));
|
|
|
|
wait(3);
|
|
|
|
A = (A & 0xf0) | (data & 0x0f);
|
|
|
|
|
|
|
|
NF = 0;
|
|
|
|
PF = parity(A);
|
|
|
|
XF = A.bit(3);
|
|
|
|
HF = 0;
|
|
|
|
YF = A.bit(5);
|
|
|
|
ZF = A == 0;
|
|
|
|
SF = A.bit(7);
|
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionRST_o(uint3 vector) -> void {
|
|
|
|
wait(1);
|
|
|
|
push(PC);
|
|
|
|
PC = vector << 3;
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionSBC_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = SUB(A, read(displace(x)), CF);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionSBC_a_n() -> void {
|
|
|
|
A = SUB(A, operand(), CF);
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionSBC_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = SUB(A, x, CF);
|
|
|
|
}
|
|
|
|
|
2016-11-01 11:42:25 +00:00
|
|
|
auto Z80::instructionSBC_hl_rr(uint16& x) -> void {
|
|
|
|
wait(4);
|
|
|
|
auto lo = SUB(HL >> 0, x >> 0, CF);
|
|
|
|
wait(3);
|
|
|
|
auto hi = SUB(HL >> 8, x >> 8, CF);
|
|
|
|
HL = hi << 8 | lo << 0;
|
|
|
|
ZF = HL == 0;
|
|
|
|
}
|
|
|
|
|
2016-09-06 13:53:14 +00:00
|
|
|
auto Z80::instructionSCF() -> void {
|
|
|
|
CF = 1;
|
|
|
|
NF = 0;
|
|
|
|
HF = 0;
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-29 00:33:30 +00:00
|
|
|
auto Z80::instructionSET_o_irr(uint3 bit, uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, SET(bit, read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSET_o_r(uint3 bit, uint8& x) -> void {
|
|
|
|
x = SET(bit, x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSLA_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, SLA(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSLA_r(uint8& x) -> void {
|
|
|
|
x = SLA(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSLL_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, SLL(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSLL_r(uint8& x) -> void {
|
|
|
|
x = SLL(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSRA_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, SRA(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSRA_r(uint8& x) -> void {
|
|
|
|
x = SRA(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSRL_irr(uint16& x) -> void {
|
|
|
|
auto addr = displace(x);
|
|
|
|
write(addr, SRL(read(addr)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionSRL_r(uint8& x) -> void {
|
|
|
|
x = SRL(x);
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionSUB_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = SUB(A, read(displace(x)));
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionSUB_a_n() -> void {
|
|
|
|
A = SUB(A, operand());
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionSUB_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = SUB(A, x);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto Z80::instructionXOR_a_irr(uint16& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = XOR(A, read(displace(x)));
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|
|
|
|
|
2016-10-31 21:10:33 +00:00
|
|
|
auto Z80::instructionXOR_a_n() -> void {
|
|
|
|
A = XOR(A, operand());
|
|
|
|
}
|
|
|
|
|
2016-09-06 00:09:33 +00:00
|
|
|
auto Z80::instructionXOR_a_r(uint8& x) -> void {
|
2016-09-06 13:53:14 +00:00
|
|
|
A = XOR(A, x);
|
2016-09-06 00:09:33 +00:00
|
|
|
}
|