How to create an 8051 emulator

For training purposes, I'm going to start creating an 8051 microcontroller emulator. I find it convenient to program in C / C ++ / C #. This is not a cool project, etc., but a learning initiative on my part.

I found quite a few questions discussing this. However, I wanted to break it down more at a granular level so that I could know which areas I needed to focus on before I started writing code.

My initial requirements:

  • text editor (can use the editbox control), where the user can write assembly code

  • Check syntax

  • It has a small window that shows register values ​​at runtime.

  • when the user starts the program, the instructions should update the register windows step by step.

More than a GUI element, I'm more interested in learning how to emulate a microcontroller.

As I understand it, I can still break it:

  • I need to have a lookup table for instructions, or some other way of storing available instructions and checking syntax. Any pointers on how to implement this, please let me know.

  • How to emulate each command for 8051?

  • For registers, I can use un / signed integers based on type and update the table.

  • Since the microcontroller has limited RAM, how can I check the length of the code, or rather, the code that runs in memory, to avoid buffer overflows or other problems.

If there are several open source projects that describe in detail how the emulator will be created, evaluate it.

+6
emulation 8051
source share
2 answers

I think you are a little unclear as to the scope of this project, at least with regard to the name.

the emulator executes binary code and nothing more. The emulator does not include an editor (this is a development tool), as well as assembler (the same). The assembler has a duty to perform syntax checking and translation, so the emulator only has a relatively simple job of executing pre-validated legal code.

It looks like you want to create a complete IDE. This will wrap a lot of GUI around the editor, assembler and emulator. I would leave this step last.


As for your questions regarding the emulator itself:

As the working memory of the emulator, you can use an array of up to (for example) 64 KB. You use variables in your program to emulate registers. I would use unsigned char * to emulate the program counter and int for most other things ...

The operation is quite simple: start the program counter at 0 (or a predefined download location) and run a cycle that retrieves instructions through this pointer and applies any operation related to the instruction to the register and memory. A simple implementation will focus around the huge switch , which includes all possible command codes.

As I said, your emulator does not need to worry about illegal instructions, because the assembler should not do anything. You may have your program (i.e. the main loop) if it gets into an illegal operation.

Similarly, your emulator does not need to worry about overflowing a range, index or size ... which is also an assembler problem or maybe a linker, if you have one.


Update: A few pointers right here in SO:

Emulator infrastructure

+7
source share

I recently put together an emulator for an AVR chip, which is also a small 8-bit microcontroller. The source is on github as ghewgill / emulino . The most interesting cpu.c file that contains implementations for each CPU instruction. Key strings are in cpu_run() (omitting some details):

 while (state == CPU_RUN) { u16 instr = Program[PC++]; Instr[instr](instr); } 

This loads a 16-bit word from the program memory that the PC register points to, and then uses it as an index in the instruction jump table (which is an array of 64 KB function pointers - the actual table is generated using script at compile time). This function will be one of the do_XXX() functions in this source file and can further decode the instructions before executing the actual instruction. For example, do_ADD() function:

 static void do_ADD(u16 instr) { trace(__FUNCTION__); // ------rdddddrrrr u16 r = (instr & 0xf) | ((instr >> 5) & 0x10); u16 d = ((instr >> 4) & 0x1f); u8 x = Data.Reg[d] + Data.Reg[r]; Data.SREG.H = (((Data.Reg[d] & Data.Reg[r]) | (Data.Reg[r] & ~x) | (~x & Data.Reg[d])) & 0x08) != 0; Data.SREG.V = (((Data.Reg[d] & Data.Reg[r] & ~x) | (~Data.Reg[d] & ~Data.Reg[r] & x)) & 0x80) != 0; Data.SREG.N = (x & 0x80) != 0; Data.SREG.S = Data.SREG.N ^ Data.SREG.V; Data.SREG.Z = x == 0; Data.SREG.C = (((Data.Reg[d] & Data.Reg[r]) | (Data.Reg[r] & ~x) | (~x & Data.Reg[d])) & 0x80) != 0; Data.Reg[d] = x; Cycle++; } 

This does the add operation ( Data.Reg[d] + Data.Reg[r] ), then sets all condition flags based on the result.

+6
source share

All Articles