The "Java Life"

@Karlos:
I don't understand most of that but it looks like it was quite an undertaking.
 
@Karlos:
I don't understand most of that but it looks like it was quite an undertaking.

As a task, it's not a million miles removed from one of the suggestions in your other thread here: http://www.whyzzat.com/threads/advice-from-coders.8506/), namely the 6800 emulator. In my case, I created what amounts to an interpretive emulator for a CPU that doesn't actually exist. A simplified CPU that works well in software but might be a pain in the ass to implement in hardware.

For example, it has a very "orthogonal" instruction set, where almost all instructions are 16-bit words comprising of an 8-bit operation and a pair of 4-bit operands (usually a source and destination register pair). This allows a pretty simple instruction decode routine to be written. Other features that simplify implementing it efficiently in software are separate stacks for saving and restoring the registers verus the general purpose stack (the latter being the only stack that a real CPU would have). The reason for this is that the registers are 64-bit and thus register stack is always 64-bit aligned. The data stack might not be and handling misaligned data access can be expensive on some systems (PPC for example). A final major difference from almost all real CPU's is that it doesn't have a status register. Actually, it does, but it doesn't track the usual negative/overflow/extend type conditions that a real CPU might do. Instead it tracks things like illegal operations that happen infrequently. This is again to allow for improved interpretation performance. Instead of checking every operation (that can do so) overflowed, or resulted in a negative value and recording the fact in case you want to make a decision on it later, it simply provides instructions for comparing two operands and conditionally branching on those. In other words, it implements the C-like if() {} construct as a set of instructions. It also has the ability to jump out of emulation into native functions (which the mandelbrot demo uses for allocating the bitmap and saving it).

All of this makes interpretation of it's instruction set simple enough that a totally naive interpreter model manages a couple of MIPS on my old BlizzardPPC and over 120 on a single core of my current PC. Even my 68040 can interpret it at a speed quick enough to be useful for undemanding operations.

In order to be able to test the thing without having to first write a full assembler, runtime linker and so on, I devised a set of nasty C macros that are used in the previous post to generate 16-bit words that represent the machine instructions from what looks like pseudo assembler.

If you were to tackle it, your 6800 emulation would have to care about some things that my VM does not, especially status register updates and so on. However, the 6800 is also a lot simpler than my VM in terms of what it supports (the VM supports 8/16/32/64-bit signed/unsigned aritthmetic/logic, 32/64-bit floating point, interaction with the native host etc), the 6800 does basic 8/16 bit integer stuff only and can be emulated along with the entire range of memory it can address in a very simple sandbox. Not even sure it implements multiplication operations and most of it's instructions are going to be encoded as bytes without having to worry about extracting fields. Consequently, you could implement a very simple and effective interpretive emulator for that.
 
Really interesting post Karlos, thanks.

If you were to tackle it, your 6800 emulation would have to care about some things that my VM does not, especially status register updates and so on. However, the 6800 is also a lot simpler than my VM in terms of what it supports (the VM supports 8/16/32/64-bit signed/unsigned aritthmetic/logic, 32/64-bit floating point, interaction with the native host etc), the 6800 does basic 8/16 bit integer stuff only and can be emulated along with the entire range of memory it can address in a very simple sandbox. Not even sure it implements multiplication operations and most of it's instructions are going to be encoded as bytes without having to worry about extracting fields. Consequently, you could implement a very simple and effective interpretive emulator for that.

If that does transpire, I shall no doubt be pestering you for further details. :D
 
Really interesting post Karlos, thanks.
If that does transpire, I shall no doubt be pestering you for further details. :D

Feel free :)

Just be careful how you implement the HCF operation ;)

http://en.wikipedia.org/wiki/File:MC6800_Processor_Diagram.png

Just from the above diagram alone, you can start to get an idea of the minimal strucutural requirements of such an emulator. You'd will need some data structure to represent your virtual 6800 containing:

8-bit integer variable for Accumulator A
8-bit integer variable for Accumulator B
16-bit unsigned integer variable for the Index Register
16-bit unsigned integer variable for the Stack Pointer
16-bit unsigned integer variable for the Program Counter
8-bit integer variable (or 6 separate booleans) for the status register (H I N Z V C)

You will also need an array of 65536 bytes to represent the external memory. The index register, stack pointer and program counter will always be interpreted as offsets into this array.
If you are doing this in Java, I don't think it actually has "unsigned" as a qualifier for integers. So, you will probably have to use a regular "int" and make sure it never overflows 65535 for your emulation of the 16-bit registers.
The basic implementation of an interpretive emulator would be as follows:
Look up the value of the byte in the "memory" array at the position indicated by the program counter.
Perform the operation the byte represents, fetching any additional bytes that might represent immediate values.
Check for any special outcomes and handle accordingly.
Update all the register values accordingly (generally, the status register, accumulators and program counter) and external memory (if affected).
Rinse and repeat until some limit on the number of interpreted instructions, virtual clock ticks or whatever is reached.
Do whatever other housework is needed (if you are emulating a complete system), handle any pending virtual interrupts, etc.
Rinse and repeat until the emulation is stopped.
 
@Karlos:

More interesting stuff. Cheers squire.
 
Back
Top