
Update: Two weeks after posting this blog post, I got a friendly message from Adrien Bertrand. Turns out, there are various projects that use the CEmu core directly. They’re only a bit hard to discover. Two examples are:
So, more places to get inspiration from on how to use the CEmu core in your own eZ80 projects.
Goals
Although the Zilog ZDS II tools do contain a emulator for the eZ80, it only runs on Windows. And I don’t like Windows… Hence my desire to see if I could get an emulator running on a non Windows OS.
Although there are many open source Z80 emulators I could only find one emulator for the eZ80. And it’s part of a much bigger package: TI84 Cemu project).
When searching for an emulator, I found that someone else was looking for the same thing and I found this question on the Cemetech forum : ez80 emulator that isn’t the TI-84+CE?
I am interested in a standalone ez80 emulator or VM. This forum seems
to know most about the ez80 (apart from TI and Zilog themselves) so I
wanted to ask if there is any emulator out there?
AFAIK Cemu doesn't count as standalone as it's designed to emulate the
CE and it's API isn't general-purpose mostly, though I admit I haven't
checked.
EDIT: I started implementing my own one but I underestimated how long
it would take, which is why I'm asking this.
Which got this, not so friendly IMHO, reaction:
Quote: API isn't general-purpose mostly
hahahahahaha.... yes it is. You'll just need the cpu.c, mem.c, registers.c,
and port.c and the associated header files. Then you can make a few small
modifications to mem.c and port.c to make it work with the design you want.
Anyway, I decided to try it out myself and see if it really was that easy. Hint, it wasn’t.
First attempt
I started by copying the mentioned cpu.c, mem.c, registers.c, and port.c files and discovered I had to add really a lot of include files. It compiled easy enough but when linking there were missing symbols that seem to relate to the GUI (e.g. gui_console_printf()
) and others. I simply commented those out to see how far I would get.
The next problem is that the code (emu_load()
) is really expecting a TI ROM image and the memory layout (RAM and FLASH) is that of a TI calculator. The Zilog ZDS II Tools produce a Intel HEX file. I added the ihex library to read such a Intel HEX file in a 16 MByte size array of uint8_t
and simply referenced it to mem.ram.block
.
Next was figuring out how to execute code step by step. There is the cpu_execute()
function but to get that to work properly I had to do some initialisations first. In the end I came up with this sequence that seemed to work:
void eZ80_init(void)
{
/* First, initilize memory and CPU */
mem_init();
cpu_init();
sched_init();
/* Seed the numbers */
srand(time(NULL));
bus_init_rand(rand(), rand(), rand());
sched_reset();
sched_set_clock(CLOCK_RUN, 1000);
mem_install_memory(memory);
cpu_reset();
set_cpu_clock(1);
reset_proc_count = 0;
add_reset_proc(sched_reset);
printf("[eZ80-emu] Initialized ASIC...\n");
} /* end eZ80_init */
With the following, adapted code from emu_run()
, I was then able to execute instructions step by step:
void emu_run(uint64_t ticks) {
sched.run_event_triggered = false;
sched_repeat(SCHED_RUN, ticks);
while (cpu.abort != CPU_ABORT_EXIT) {
sched_process_pending_events();
if (cpu.abort == CPU_ABORT_RESET) {
cpu_transition_abort(CPU_ABORT_RESET, CPU_ABORT_NONE);
printf("[CEmu] Reset triggered.\n");
}
if (sched.run_event_triggered) {
break;
}
cpu_execute();
printf("LOOP %p\n", &cpu);
}
}
Second attempt
After this initial success, I decided to take the opposite approach and simply build the whole emulator library. Which is pretty easy with the provided Makefile in the core
directory. Just like in my first attempt, there are some missing symbols during the linking step and I solved this, for now, by simply out commenting the code that uses those.
I also included the zdis
git sub-module this time which provides the code for eZ80 disassembly and the code for loading an Intel HEX file of course.
Setting the emulator was now a bit easier and looks more like how it was done in the emu_load()
function:
void eZ80_init(void)
{
asic_free();
asic_init();
asic_reset();
sched_set_clock(CLOCK_RUN, 1000);
set_cpu_clock(1);
ctx.zdis_end_addr = 0xFFFFFF;
ctx.zdis_implicit = false;
ctx.zdis_adl = true;
ctx.zdis_user_size &= ~SUFFIXED_IMM;
ctx.zdis_user_size &= ~DECIMAL_IMM;
ctx.zdis_user_size &= ~MNE_SPACE;
ctx.zdis_user_size |= ARG_SPACE;
} /* end eZ80_init */
The emu_run()
code remains practically the same as in my first attempt.
When everything seemed to work, I started adding some code to dump disassembled code and the content of the registers after each step. The result looks like this:
What’s next
So, it looks like this approach might work. Quite a lot of code of the original emulator can be removed (specific to the TI 84 like LCD code). I need to better understand how the scheduler code works as well as it seems quite complex while little documentation is available.
The biggest task would be to build something really useful with it. I.e. some kind of a TUI or GUI.
For those interested to try it out yourself, this is the link to the repo. Be warned, the code is ugly and really needs cleaning up before doing anything serious with it. But it should be sufficient to get you started.
I don’t know yet what to do with it myself. I’m toying with the idea to build a GUI or TUI on top of it using Rust (a programming language I want to learn).