Schrijver
| Z80 DAA
|
hap msx addict Berichten: 463 | Geplaatst: 12 Februari 2007, 14:36   |
I'm currently creating a Z80 CPU emulator, using several technical documents, including this: http://wikiti.denglend.net/index.php?title=Z80_Instruction_Set
I noticed blueMSX and openMSX fill a big 4KB lookuptable with an unnecessarily complex calculation, like this (from openMSX):
for (int x = 0; x < 0x800; ++x) {
bool nf = x & 0x400;
bool hf = x & 0x200;
bool cf = x & 0x100;
byte a = x & 0xFF;
byte hi = a / 16;
byte lo = a & 15;
byte diff;
if (cf) {
diff = ((lo <= 9) && !hf) ? 0x60 : 0x66;
} else {
if (lo >= 10) {
diff = (hi <= 8) ? 0x06 : 0x66;
} else {
if (hi >= 10) {
diff = hf ? 0x66 : 0x60;
} else {
diff = hf ? 0x06 : 0x00;
}
}
}
byte res_a = nf ? a - diff : a + diff;
byte res_f = ZSPXYTable[res_a] | (nf ? N_FLAG : 0);
if (cf || ((lo <= 9) ? (hi >= 10) : (hi >= 9))) {
res_f |= C_FLAG;
}
if (nf ? (hf && (lo <= 5)) : (lo >= 10)) {
res_f |= H_FLAG;
}
DAATable[x] = (res_a << 8) + res_f;
}
and then handle DAA like this:
template <class T> void CPUCore<T>::daa()
{
int i = R.getA();
if (R.getF() & C_FLAG) i |= 0x100;
if (R.getF() & H_FLAG) i |= 0x200;
if (R.getF() & N_FLAG) i |= 0x400;
R.AF = DAATable[i];
}
a direct translation from the link above gives exactly the same result, without the need of a DAA table:
u8 r=A;
if NF {
if (HF||(A&0xf)>9) r-=6;
if (CF||A>0x99) r-=0x60;
}
else {
if (HF||(A&0xf)>9) r+=6;
if (CF||A>0x99) r+=0x60;
}
F=(F&3)|lut_flags[r]|(A>0x99)|((A^r)&0x10);
A=r;
I don't know which one's faster, but if you're going to stick with the DAA table, at least get rid of that big, hard-to-understand calculation  |
|
Kwik msx lover Berichten: 105 | Geplaatst: 12 Februari 2007, 15:09   |
I've seen very different implementations on DAA, but none as short as this one. Have you verified it with ZEXALL? Are X-flag and Y flag ("undocumented" ) supported?
|
|
hap msx addict Berichten: 463 | Geplaatst: 12 Februari 2007, 15:25   |
I've verified it by comparing all possible results with that 4KB table, and verified blueMSX DAA opcode by comparing it with my MSX2 (small program: push value, pop af, daa, push af, pop value and write to ram). The X/Y flags are handled by that 256byte lut_flags, which is basically the same as openMSX ZSPXYTable.
My Z80 emulator is far from complete, so it'd be nice if someone double checked this shorter implementation in their own ZEXALL compliant Z80 emulation core.
|
|
Kwik msx lover Berichten: 105 | Geplaatst: 12 Februari 2007, 15:34   |
If the code is correct then it's very cool. I spend several hours on DAA and came up with this (which is a lot bigger):
reg1 = reg_a;
if (reg_f & NFLAG) {
reg2 = reg_f & (CFLAG|NFLAG|HFLAG);
if ((reg_f&CFLAG)||(reg_a>0x99)) reg1 -= 0x160;
if ((reg_f&HFLAG)||((reg_a&0x0F)>9)) {
if ((reg_a&0x0F)>5) reg2 &= ~HFLAG;
reg1 = (reg1&0xFF00)|((reg1-6)&0xFF);
}
} else {
reg2 = (reg_f&CFLAG) | (((reg_a&0x0F)>9)?HFLAG:0);
if ((reg2|reg_f)&HFLAG) reg1 += 6;
if ((reg_f&CFLAG) || ((reg1&0x1F0)>0x90)) reg1 += 0x60;
}
reg_a = reg1&255;
reg_f = flagSZP[reg_a] | reg2 | ((reg1>>8)&CFLAG);
It does pass ZEXALL by the way. |
|
FluBBa msx friend Berichten: 3 | Geplaatst: 22 Mei 2007, 23:16   |
Speaking of which, does anyone know where to find ZEXALL for the MSX?
|
|
Kwik msx lover Berichten: 105 | Geplaatst: 23 Mei 2007, 09:39   |
|
|
FluBBa msx friend Berichten: 3 | Geplaatst: 23 Mei 2007, 12:37   |
So which one should I download for the MSX? The YAZE, CPM or Spectrum?
|
|
NYYRIKKI msx master Berichten: 1500 | Geplaatst: 23 Mei 2007, 14:27   |
CPM
MSX-DOS is CP/M compatible.
|
|
FluBBa msx friend Berichten: 3 | Geplaatst: 23 Mei 2007, 21:40   |
Oh, wow. Thanks a lot.
I guess I have some more coding to do then  |
|
|
|
|