Emulator i8080 on bash

  • Tutorial
Today they write xonix, and tomorrow they will write a separate operating system with a framework and a DBMS on the bash.

Finally, tomorrow has arrived. In bash (after some dopilivaniya) can run major operating systems, for example, the CP / M . And for CP / M there are definitely DBMSs, compilers, and more.

Why it is not necessary and why it is necessary to make emulators on bash, a working emulator i8080 on bash and some tips on speeding up the work of bash scripts -

Why you do not need to make emulators in bash

Bash works slowly. Even for such a simple processor as the i8080, it is unlikely that the emulation speed will be at least 1% of the real one. On my Celeron with a frequency of 2.2 GHz, the emulator runs at a speed of about 100 operations per second, while the real i8080 processor at 2.5 MHz processes 600 thousand operations per second.

Another important issue: in bash it is not possible to work with binary data. If you want to output to the port or read from the file a character with the code 0x01, then bash is clearly not the language you need.

The third problem. Emulator development is not an hour or two task. You should not write an emulator without an editor with syntax highlighting and without a debugger. When I started to “compose” my emulator, I thought: “Ah, you only need to do 84 teams! What nonsense! ” When I reached the 51st operation code, I finally realized that the command! = Operation code, and that another 200 codes had to be implemented. If I immediately took into account that the operation codes were two hundred, I would not write an emulator. And since I started writing, I had to finish it.

Why do bash emulators

Then that is super-duper-mega cool. Then that gives a huge bash programming experience. Then, that the programs in the emulator will run very, very slowly, and it will be possible to keep track of changing flags and registers.

Tips for speeding up bash code

The speed of code execution for the emulator is critical. If you want your bash script to run as fast as possible, then:
  • do not use expr and bc if possible;
  • read files with readarray, and not line by line with read;
  • replace all A = $ ((A + 1)) with ((++ A));
  • do not invent bicycles similar to existing bash commands;
  • try not to use the $ sign.

Calling expr or bc in a loop can slow down your program several times.
$ time ( for ((i = 0; i < 100000; ++i)); do echo `expr 1 + 2` ; done ) 
real	0m17.000s
user	0m13.261s
sys	0m8.061s
$ time ( for ((i = 0; i < 100000; ++i)); do echo "$(( 1 + 2 ))" ; done ) 
real	0m3.980s
user	0m2.371s
sys	0m0.237s

Reading files into an array with the readarray command sometimes gives a huge gain compared to the read command in a loop (depending on the length of the file), and certainly looks much prettier.
$ time ( for ((i = 0; i < 10; ++i)); do while read line ; do  rom[${tmpcnt}]=$line ; (( ++tmpcnt )) ; done < bas.e80  ; done )
real	0m6.888s
user	0m5.516s
sys	0m0.336s
$ time ( for ((i = 0; i < 10; ++i)); do readarray -t rom < bas.e80 ; done ) 
real	0m0.146s
user	0m0.048s
sys	0m0.004s

The increment command is faster than the addition command.
$ time ( for ((i = 0; i < 100000; ++i)); do a=$(( a + 1 )) ; done ) 
real	0m4.489s
user	0m3.692s
sys	0m0.108s
$ time ( for ((i = 0; i < 100000; ++i)); do (( ++a )) ; done ) 
real	0m4.053s
user	0m3.296s
sys	0m0.140s

To translate numbers from the hexadecimal number system to decimal, I used my function:
hex2dec () {
uw=`expr index "0123456789ABCDEF" "${1:0:1}"`  
lw=`expr index "0123456789ABCDEF" "${1:1:1}"`  
res=$(( ( ${uw} - 1 ) * 16 + ${lw} - 1 ))

Given what I said about expr, you can guess: this function did not work very quickly. Good mkot suggested a simple way for me to convert numbers from one number system to another:
hex2dec () {
define -i res

Thanks to just this one replacement, the emulation speed has tripled. Therefore, read the Advanced Bash-Scripting Guide carefully, and do not invent brake bikes.

The final tip. Try not to use the $ signs where possible, because US dollars negatively affect the free shell:
$ time ( for ((i = 0; i < 100000; ++i)); do a=$(( $a + 1 )) ; done ) 
real	0m5.155s
user	0m4.828s
sys	0m0.088s
$ time ( for ((i = 0; i < 100000; ++i)); do a=$(( a + 1 )) ; done ) 
real	0m4.489s
user	0m3.692s
sys	0m0.108s

Emulator i8080

It took about 8 hours to develop the emulator. It was probably not without bugs (I'm especially worried about logical functions), but overall it works, and quite successfully. I applied some optimization tips in the emulator, and some did not, with the hope that additional edits will speed up the execution of programs in the emulator slightly. Unfortunately, the emulator does not support working with ports and interrupts, but it does have the function “Display a character on the screen” from the Monitor program for Radio 86РК .

Unfortunately, the source code of the emulator for today (June 1, 2017) is lost.

Run as follows:
$ ./emu.sh program.e80

The contents of the registers and flags will be displayed.

Programs should be written in hexadecimal, one byte per line.
An example of a program that executes an empty loop 256 times:

Fans of programming in machine codes will surely be helped by a brief guide from the virtual computer museum.

Oh yes, about CP / M. Run it, of course, you can. But loading the OS and printing an invitation to the screen may take several minutes.

That's all for today. Happy everyone hacking.

Also popular now: