N:ram.1/emulator.txtF%OP%BON %OP%HE/@d@/page @p@/Mark W. Eichin/ %CO:A,12,72%%H1%Z80 emulator design%H1% Opposing goals: high speed for *using* programs good hooks to enhance debugging %H4%1989 Dec 15 (notes MWE)%H4% Z80 emulator (for testing %H1%any%H1% compiler) (or for running real code elsewhere) Register Bank Almost everything is a "special case" but there are certainly patterns. Bitmasks - useful subfields of an instruction can be used in switch statements; obvious breakdown is 2+2+3. Efficiency - early design decisions may contribute %H1%too much%H1% to design efficiency. On the other hand, we've got the MIPS, maybe we should just aim for something with a good debugging environment! %H1%%H2%Logic%H1%%H2%: break down "an instruction" into 'opcode' and 'arguments' then call a routine for that opcode. Provide a 'global' state indicator for debug-on, for which code can be included in each opcode handler. Use 8080 or Z80 opcode breakdown? Provide an option? - 8080 is finer, so it could be done, w/z80 printouts as a toggle, ie. Z80: "ld %PC%s,(0%PC%xH)",wordreg(bitfieldn),following_wordarg() 8080: "l%PC%sd 0%PC%xH", ... except 8080 normally only has lhld, others are z80 only... Provide an "attribute table" which lists useful properties of each value (look at zdis for this???) such as byte-follows, word-follows, bitfield-split-style, groks DD/FD prefix (or should these just jump to another table, like ED and CB must?) and of course, pointer to handler routine... (or token for switch table) split styles: aa bbb ccc aa bbb aaa (these can sometimes be used to split ALU instruction opcodes out of the instruction) aa bba aaa (push, pop, inx, dcx) Should all register changes occur as functions? This would provide control for the debugging routines (stop on change in BC) as well as providing a way for the simulator to catch overflow (maybe this should have a saber-like method of noting "overflow should be ignored at this insn" except that we are doing binary debugging; on the other hand, a real C compiler could provide real symbol table information.) %H4%1989 Dec 15 (notes MWE)%H4% %H1%Z80 emulator OS support%H1% Most operating systems (particular examples: CP/M, OZ) are referenced by the user's program through a small "bottleneck" or two of routines. These can be "trarped" to subroutines builtin to the emulator, which examine the processor's "state" and stack &c. and determine what 'result' occurs. Thus for CP/M (with its well specified interface) or TurboDOS (likewise) we merely write a C emulation of the BDOS or CBIOS calls. For OZ we can either emulate the calls documented in the Book or snarf the entire ROM workspace and emulate it down to IN/OUT instructions (or at least to the point of %H1%figuring out%H1% what the OZ kernel is doing and reworking it in C. For CP/M, we can actually use a %H1%real%H1% BDOS and write an emulation of the CBIOS, allowing us to precisely match some behaviour, such as using real 'CP/M' disk blocks. Alternatively, we can emulate the entire BDOS, permitting (for example) WordStar to be run on UNIX files... (we could compromise and provide some 'magic traps' to permit a program written for CP/M to sneak out to UNIX, for a file transfer or some such, but that might be more work than simply writing a UNIX program to look at a CP/M disk and copy it - in fact, such code already exists in BSD! under /usr/new, I think...) %H1%Memory Management%H1% CP/M does little or none already, but by keeping a vector of uninitialized bytes (vector of flags probably) or at least some sort of bounds check assuming heap grows up and stack down, might help catching some classes of bugs. OZ does some amazing things - should all RAM references go through Page management code (this might be useful for banked TurboDOS too) or do we just blit alot? Then again, a RAM access manager would be useful in detecting mistyped access (running from one data area into another) particularly since most data in CP/M programs is pre-allocated(?) well, alot of it is... and is thus in the symbol table. %H4%1990 Feb 17 - MWE%H4% Additional thoughts on implemenation: it would be better to write some sort of compiler, so that the Z80 can be defined in a register language and then compiled, cutting down the implementation time at the expense of performance. (Once it works, we can come up with a speed hacked version, or just run it on the IBM RISC/6000 :-) The core of the system is the register bank (even control flow, since the PC is a register); then we add all the operations on those, and finally we map opcodes to them. Debugging can be inserted at the opcode-emulation level or at the register manipulation level as needed. This also facilitates writing other emulators (6502, 8088, Vax :-) %CO:B,12,60%%CO:C,12,48%%CO:D,12,36%%CO:E,12,24%%CO:F,12,12%E