[NTLK] Einstein Simulator Status Update

Matthias Melcher mm at matthiasm.com
Tue Sep 18 17:34:10 EDT 2012

Short version: Simulation will make Einstein much faster - eventually.

Hi guys,

I had a little bit of time and I updated the Einstein Simulator code a bit. So for those who are interested, here is a little description of the inner workings, in the tiny hope that someone might like to write a bit of code.

OK, so the ROM is 8 MBytes, organized in 4 Byte Words. About half of the ROM is written in NewtonScript (NS), and the other half (roughly 1 million commands) in C++. The NS code is easily understood, recreated and relocated. The C++ code however - after compilation - is a spaghetti mess of ARM machine code interleaved with data. Some of that data need to be byte-flipped, some relocated, some not. 

Einstein interprets the words of code as they come into the emulated CPU, And even though there is tons of optimization, one original command corresponds to roughly 100 commands in the emulator. A simulator is different: all code is original, in C++, and after compilation native. So one NewtonOS word corresponds roughly to one native word. To the user that means "full speed ahead".

Sounds great? Yes, and it would be, but we would have to rewrite 1 million lines of code. Something that Apple engineers did in eight years, paid full time. There is a lot of code out there written by various Newton fans, but not complete system yet by far.

The Einstein Simulator will hopefully tie things together. It's a hybrid using the already fully working emulation, combining it with native code wherever we can. So anyone can add code snippets anywhere in the system, replacing the Newton ROM piece by piece.

It's implemented using fibres, a technology that allows multiple contexts (stacks) in a single thread. Switching between JIT emulation and native simulation is "simply" a context switch away. It also uses an abstraction for memory access to give full support for MMU exceptions and interrupts.

To put an end to all the text, here is an example. Further stuff is in the "Simulator" directory of Einstein (which you can find on Google Code).

Let's write a native version of "CArrayIterator::NextIndex". The name and location of the function can be found in the debugger ROM that comes with the Driver Developer Kit. So let's look at this function:

NextIndex__14CArrayIteratorFv:                  @ 0x00038674: t_unknown CArrayIterator::NextIndex(...)
        @ label = 'NextIndex__14CArrayIteratorFv'
        @ ARM R0 = type: 'CArrayIterator'*
        @ name = 'NextIndex'
        @ class = 'CArrayIterator'
        mov     r12, sp                         @ 0x00038674 0xE1A0C00D - ....
        stmdb   sp!, {r4, r11, r12, lr-pc}      @ 0x00038678 0xE92DD810 - .-.. 
        sub     r11, r12, #4                    @ 0x0003867C 0xE24CB004 - .L.. 
        mov     r4, r0                          @ 0x00038680 0xE1A04000 - .. at .
        bl      VEC_Advance__14CArrayIteratorFv  @ 0x00038684 0xEB6EB312 - .n..
        mov     r0, r4                          @ 0x00038688 0xE1A00004 - ....
        bl      VEC_More__14CArrayIteratorFv    @ 0x0003868C 0xEB6EC7B9 - .n..
        teq     r0, #0                          @ 0x00038690 0xE3300000 - .0.. 
        mvneq   r0, #0                          @ 0x00038694 0x03E00000 - .... 
        ldrne   r0, [r4, #4]!                   @ 0x00038698 0x15B40004 - .... 
        ldmdb   r11, {r4, r11, sp, pc}          @ 0x0003869C 0xE91BA810 - ....

Of course, we can only look at the interface! Do not translate the ARM code! Instead, you must "observe" what the function does and recreate that writing your own code. AH well, that said, let's say we write this:

ArrayIndex CArrayIterator::NextIndex()
	if (More()) {
		return GetCurrentIndex();
	} else {
		return kEmptyIndex;

Ah, that is so much more readable. As you can see, CArrayIterator::Advance() and CArrayIterator::More() must already be implemented before writing this function. CArrayIterator::GetCurrentIndex() is an accessor to the member mCurrentIndex that is created using macros (and takes care of the MMU code).

Now we still need to link this code into the ROM. There is a big bunch of macros for that. The code looks like this:

T_SIM_INJECTION(0x00038674, "CArrayIterator::NextIndex") {
	SIM_RETVAL SIM_CLASS(CArrayIterator)->NextIndex();

The hexadecimal number is the address of the function in ROM. SIM_RETVA: makes sure that the return value goes into register r0. SIM_CLASS is used to call class methods. There are also macros for arguments.

Phew, that's a bunch of information. If there is interest in more details, I'll be happy to explain... .

 - Matthias

More information about the NewtonTalk mailing list