I want to take an interest in writing my own simple emulator for the Z80 processor. I have no experience with this type of programming. I am mostly fine with using C-based languages as they are the ones I know best.
What do I need to accomplish this and what are some good tutorials/references that could aid me in this project?
I would also like a tutorial for coding a ROM-dumping application for my TI-84 Plus calculator so I can use its ROM with this emulator.
It's a bit of a side trip, but since you say you have no experience with this type of programming, you might want to start by building an emulator for the Universal Virtual Machine from the 2006 ICFP programming contest. This is a task that takes an experienced programmer 90 minutes, but many teams with no experience were able to complete it in a few days. When you finish the emulator it unlocks a bunch of fun stuff, and it might be a good warmup before you tackle the Z80.
Some things to add (especially for Z80):
Do not trust the documentation is 100% bug free
I have not see any without bugs including those mentioned here.
Test your CPU core for bugs properly
It will save you from many headaches and confusion later.
For testing I am using three approaches:
Stepping/tracing against known code (usually commented ROM disassembly)
It's the first step when nothing works yet. You will see badly (de)coded instructions.
Include different Z80 cores in your emulator and process everything as double emulation
Make two 'separated' emulators with the same stepping, tracing, and running system. Both CPUs should have its own memory hardware, etc.
[hl],[sp],[sp-1]
...When you are more run-able use core tester
Use ZEXALL Exerciser. It is the best on Z80 (at least from my experience). It helped me with very many things (my core is now 100% ZEXALL compatible). It's done against real hardware so there are no bugs in it. It's from CP/M so some versions need 64K RAM mode to run. Different OS/ROM or whatever can cause some instructions with memory access to fail, so for those you need to find corrected CRCs or compare against real hardware.
For example, raw ZEXALL fails many things on ZX Spectrum (as it is done for MSX and 64K RAM without ROM), but there are versions done for real ZX Spectrum and they are 100% OK on ZX Spectrum (and on my emulator too :))
Z80all instruction exerciser
<adc,sbc> hl,<bc,de,hl,sp>...OK
add hl,<bc,de,hl,sp>.........OK
add ix,<bc,de,ix,sp>.........OK
add iy,<bc,de,iy,sp>.........OK
aluop a,nn...................OK
aluop a,<b,c,d,e,h,l,(hl),a>.OK
aluop a,<ixh,ixl,iyh,iyl>....OK
aluop a,(<ix,iy>+1)..........OK
bit n,(<ix,iy>+1)............OK
bit n,<b,c,d,e,h,l,(hl),a>...OK
cpd<r>.......................OK
cpi<r>.......................OK
<daa,cpl,scf,ccf>............OK
<inc,dec> a..................OK
<inc,dec> b..................OK
<inc,dec> bc.................OK
<inc,dec> c..................OK
<inc,dec> d..................OK
<inc,dec> de.................OK
<inc,dec> e..................OK
<inc,dec> h..................OK
<inc,dec> hl.................OK
<inc,dec> ix.................OK
<inc,dec> iy.................OK
<inc,dec> l..................OK
<inc,dec> (hl)...............OK
<inc,dec> sp.................OK
<inc,dec> (<ix,iy>+1)........OK
<inc,dec> ixh................OK
<inc,dec> ixl................OK
<inc,dec> iyh...............OK
<inc,dec> iyl................OK
ld <bc,de>,(nnnn)............OK
ld hl,(nnnn).................OK
ld sp,(nnnn).................OK
ld <ix,iy>,(nnnn)............OK
ld (nnnn),<bc,de>............OK
ld (nnnn),hl.................OK
ld (nnnn),sp.................OK
ld (nnnn),<ix,iy>............OK
ld <bc,de,hl,sp>,nnnn........OK
ld <ix,iy>,nnnn..............OK
ld a,<(bc),(de)>.............OK
ld <b,c,d,e,h,l,(hl),a>,nn...OK
ld (<ix,iy>+1),nn............OK
ld <b,c,d,e>,(<ix,iy>+1).....OK
ld <h,l>,(<ix,iy>+1).........OK
ld a,(<ix,iy>+1).............OK
ld <ixh,ixl,iyh,iyl>,nn......OK
ld <bcdehla>,<bcdehla>.......OK
ld <bcdexya>,<bcdexya>.......OK
ld a,(nnnn) / ld (nnnn),a....OK
ldd<r> (1)...................OK
ldd<r> (2)...................OK
ldi<r> (1)...................OK
ldi<r> (2)...................OK
neg..........................OK
<rrd,rld>....................OK
<rlca,rrca,rla,rra>..........OK
shf/rot (<ix,iy>+1)..........OK
shf/rot <b,c,d,e,h,l,(hl),a>.OK
<set,res> n,<bcdehl(hl)a>....OK
<set,res> n,(<ix,iy>+1)......OK
ld (<ix,iy>+1),<b,c,d,e>.....OK
ld (<ix,iy>+1),<h,l>.........OK
ld (<ix,iy>+1),a.............OK
ld (<bc,de>),a...............OK
Tests complete
In case you are about to use ZEXALL beware it is really exhaustive test and IIRC on ~50MHz emulation it took around 30-60
min to complete. And it needs to press a key for scrolling few times ...
If you need a contention model, add proper tests. Then find one. For ZX Spectrum there are many floating bus, interrupt and screen testers. For TI I have no idea... (I am not a TI calculator user)
BTW: How did it go with your emulator? (Have you done it?)
Instruction set
I would copy my instruction set here but it has 1792 lines and 121 KB so it will not fit into a 30 KB limit. Instead you can find it in a download link in this answer of mine
It contains 'all' ZX instructions with correct OP codes, coding timing and machine cycles. It took me few years to put together all documentation, so I am passing ZEXALL 100% correctly. My emulator loads this (1792 instruction) text file to the core on init
and configures the instruction decoder and processor at runtime, so I was able to change things really fast and simple enough (if a bug was detected)... It saved me a lot of time.
Perhaps start by looking at these:
A good tutorial can be found here: Independent Z80 Assembly Guide
Z80 DOCUMENTATION
The Undocumented Z80 Documented v0.91 (pdf)
The Complete Z80 Instruction Reference
Z80 Microprocessor Instruction Set Summary
Mitch is completely correct. Start by understanding the processor. Then play around a bit by writing code to implement particular instructions. Use C++ for this, BTW, not C, or the concepts of the processor will not map to classes in your code.
In the process of implementing instructions, you'll find you need to define things like the flags, and the instruction pointer. That should eventually get you to where you need to implement the memory model, and even the I/O model.
You'll eventually have to figure out how to load code and data into memory, and maybe how to dump it back out to disk.
Only then do you need to get to the point of emulating the execution of code, loaded into memory, at a given instruction pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With