udo-munk / z80pack

A Zilog Z80 and Intel 8080 systems emulation
MIT License
160 stars 37 forks source link

Rest of ED and [DF]D CB opcodes and bit 5 and 3 of status flags #132

Closed sneakywumpus closed 2 years ago

sneakywumpus commented 2 years ago

Just a question: Is the implementation of the complete opcode space and status flags bit 5 and 3 of interest for this project? When yes, I have this nearly ready.

udo-munk commented 2 years ago

My point of view always was that the flag bits have no use for anything. All one can do is PUSH AF and then look at the bits in memory, what some CPU test programs do, but that's it. Also handling of these flags will increase the code size, which is not an issue with our modern 64bit PC's, but might be an issue on the low end hardware like ESP32, Pi, etc. However, if you add another ifdef like Z80_UNDOC_FLAGS or something, so that the code for this can be compiled conditionaly or disabled by the user I will accept it.

The undocumented opcodes used by existing software all are implemented. So same here, adding all opcodes will increase the code significantely, while the code never ever is used (yet). I assume you implement them with the existing ifdef for the undocumened opcodes, and then I will accept it.

sneakywumpus commented 2 years ago

Ok. Two more questions:

  1. Is this kind of coding style acceptable?
#define C_U() do {      \
    if (u_flag) {       \
        trap_ddcb();    \
        return(0);  \
    }           \
} while (0)

#define OPU_SLLIXDR(REG) do {               \
    WORD addr;                  \
                            \
    C_U();                      \
                            \
    addr = IX + d;                  \
    REG = memrdr(addr);             \
    (REG & 128) ? (F |= C_FLAG) : (F &= ~C_FLAG);   \
    REG = (REG << 1) | 1;               \
    memwrt(addr, REG);              \
    F_SZP_HN0(P);                   \
    return(23);                 \
} while (0)

static int opu_sllixda(int d) { OPU_SLLIXDR(A); } /* SLL (IX+d),A */
static int opu_sllixdb(int d) { OPU_SLLIXDR(B); } /* SLL (IX+d),B */
static int opu_sllixdc(int d) { OPU_SLLIXDR(C); } /* SLL (IX+d),C */
static int opu_sllixdd(int d) { OPU_SLLIXDR(D); } /* SLL (IX+d),D */
static int opu_sllixde(int d) { OPU_SLLIXDR(E); } /* SLL (IX+d),E */
static int opu_sllixdh(int d) { OPU_SLLIXDR(H); } /* SLL (IX+d),H */
static int opu_sllixdl(int d) { OPU_SLLIXDR(L); } /* SLL (IX+d),L */
static int opu_sllixd(int d) { BYTE P; OPU_SLLIXDR(P); } /* SLL (IX+d) */
  1. Why is there a cpu_bus assignment in sim1.c:op_calc? It's the only conditional CALL instruction that has this.
udo-munk commented 2 years ago

No macros in the implementation of instructions. Reason is that you can just look at any instruction source and immediatly see what it does, without the need to understand layers of macros before. Yes it will be more work, but the code is written only once, while it is read over and over again. Sorry no exceptions, because then I'll get requests for even more macros again.

Good find, looks like I forgot to implement updating the status bus in the other call instructions. Should be there of course because the CPU needs to read the destination address from memory.

EtchedPixels commented 2 years ago

Its also extremely hard to get the bit 3 and 5 stuff correct and some of it even depends if you have an NEC or Zilog part. Almost no emulator actually gets the scf nop test right.

sneakywumpus commented 2 years ago

@EtchedPixels can you direct to CPU test suites? I currently use ex.mac from the z80tests.dsk in this project and github.com/raxoft/z80test. During my use of ex.mac I've concluded that IMHO the <ini,outi,ind,outd> test only passes on the AltairZ80 emulator because of its curious implementation which uses loops and the value of B from the beginning of the loop for the flags.

EtchedPixels commented 2 years ago

I generally use ZEXALL is the classic for undocumented. ZEXDOC for documented. It's fairly complete (there are some holes on SBC 16bit corner cases and probably other oddments but it's very thorough. z80test is probably more complete as it's also checking the ccf/scf stuff.

At that point you are deep into crazyville anyway

The Fuzix code only relies on CB 37 (which is what the Z280 data book says to use to tell Z280 from Z80). It only uses the 3/5 stuff for cosmetic amusement and the other stuff to log cpu and emulator bugs (U880 OTDR bug, T80 LD A,R bug, Z80 NMOS IFF bug, libz80 SBC bug)

I keep meaning to do the Z280 bugs but it's such a heap of ... that I think a hammer would be the best way to debug it.

sneakywumpus commented 2 years ago

Added support for the rest of the undocumented instructions to the dis-/assembler in #135

udo-munk commented 2 years ago

Good find, looks like I forgot to implement updating the status bus in the other call instructions. Should be there of course because the CPU needs to read the destination address from memory.

This is wrong, status bus is updated in memory.h in the memory read/write functions, removed it from the instruction.

sneakywumpus commented 2 years ago

Added implementation for the rest of the undocumented instructions to the simulator in #138

z80sim now passes z80doc from github.com/raxoft/z80test when not using WANT_FASTB and adding the Spectrum Z80 I/O port 0xfe with return data of 0xbf to iosim.c

sneakywumpus commented 2 years ago

@udo-munk I've completed the implementation of the bit 5 and 3 status flags (some 8000 lines of diffs). It passes the tests, but I've now come to the conclusion that this stuff makes no sense :-). It's probably useful only for emulators of old home computers to run games with some weird copy protection schemes, or something like that. And this is not the intended audience of z80pack, I think.

I'm even contemplating of reverting the I/O block instructions flag code, after looking at, for example, stuff like https://stardot.org.uk/forums/viewtopic.php?f=3&t=15464&start=240 .

What do you say?

udo-munk commented 2 years ago

As I said, bit 3 and 5 are waste of time and code, nothing can be done with this. I don't know if it was used for copy protection, but have some doubts about this. If there would be some existing code (not just the Z80 exercisers) that only works with the bits implemented, then it might make sense to implement this, but conditional compiled.

The block instruction flag code so far was not needed, this is undocumented and questionable, can be reverted.

EtchedPixels commented 2 years ago

Some quite naiive copy protection does it by accident on 8bit game systems. Never seen it anywhere else.

            ld iy,#magicvalue
            bits of loader loop
            push af
            bits of loader loop
           push af
        etc
           pop de
           add iy,de
           pop de
           add iy,de
         etc
           jp (iy)

These kind of systems also do stuff like clock timing video interrupts and switching memory chasing the video beam for colour effects so it's not like a more generic emulation would work with them anyway.

udo-munk commented 2 years ago

Interesting, so if the undocumented flag bits are different from the Z80 used in the system, the jp (iy) runs off, when #magicvalue is not adjusted. Awefull programming IMHO.