https://nanochess.org/emulator.html [logo] Main page Intel 8080 emulator Chess programs Contests Store Retrogaming FAQ Links About me Ver en espanol Intel 8080 emulator. 19th IOCCC. Best of Show. Sections: * Source code * How to compile it * A little course on CP/M * What is an 8080? * Porting it * How it works * Other notes * Useful links After winning the IOCCC for the first time, I had the idea of writing an emulator of the 8080 processor in 2000 characters of C, after patterning experimentally the more than 200 instructions and doing measures of byte count, I realized that it was possible and I made it. Then I added CP/M support as a extra feature. I was completely astonished when I won Best of Show of 19th IOCCC :). This program was one of three winning entries I sent for the 19th edition, the other two were a graphical chess program and a knight's tour solver. Source code This program emulates a complete Intel(r) 8080 processor, along with a teletype and a disk controller, just like at the start of the personal computers revolution (circa 1975). Here is the source code, written in C language: #include #define n(o,p,e)=y=(z=a(e)%16 p x%16 p o,a(e)p x p o),h( #define s 6[o] #define p z=l[d(9)]|l[d(9)+1]<<8,1<(9[o]+=2)||++8[o] #define Q a(7) #define w 254>(9[o]-=2)||--8[o],l[d(9)]=z,l[1+d(9)]=z>>8 #define O )):(( #define b (y&1?~s:s)>>"\6\0\2\7"[y/2]&1?0:( #define S )?(z-= #define a(f)*((7&f)-6?&o[f&7]:&l[d(5)]) #define C S 5 S 3 #define D(E)x/8!=16+E&198+E*8!=x? #define B(C)fclose((C)) #define q (c+=2,0[c-2]|1[c-2]<<8) #define m x=64&x?*c++:a(x), #define A(F)=fopen((F),"rb+") unsigned char o[10],l[78114],*c=l,*k=l #define d(e)o[e]+256*o[e-1] #define h(l)s=l>>8&1|128&y|!(y&255)*64|16&z|2,y^=y>>4,y^=y<<2,y^=~y>>1,s|=y&4 +64506; FILE *u, *v, *e, *V; int x,y,z,Z; main(r,U)char**U;{ { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { ; } } { { { } } } { { ; } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } { { { } } } for(v A((u A((e A((r-2?0:(V A(1[U])),"C") ),system("stty raw -echo min 0"),fread(l,78114,1,e),B(e),"B")),"A")); 118-(x =*c++); (y=x/8%8,z=(x&199)-4 S 1 S 1 S 186 S 2 S 2 S 3 S 0,r=(y>5)*2+y,z=(x& 207)-1 S 2 S 6 S 2 S 182 S 4)?D(0)D(1)D(2)D(3)D(4)D(5)D(6)D(7)(z=x-2 C C C C C C C C+129 S 6 S 4 S 6 S 8 S 8 S 6 S 2 S 2 S 12)?x/64-1?((0 O a(y)=a(x) O 9 [o]=a(5),8[o]=a(4) O 237==*c++?((int (*)())(2-*c++?fwrite:fread))(l+*k+1[k]* 256,128,1,(fseek(e=5[k]-1?u:v,((3[k]|4[k]<<8)<<7|2[k])<<7,Q=0),e)):0 O y=a(5 ),z=a(4),a(5)=a(3),a(4)=a(2),a(3)=y,a(2)=z O c=l+d(5) O y=l[x=d(9)],z=l[++x] ,x[l]=a(4),l[--x]=a(5),a(5)=y,a(4)=z O 2-*c?Z||read(0,&Z,1),1&*c++?Q=Z,Z=0:( Q=!!Z):(c++,Q=r=V?fgetc(V):-1,s=s&~1|r<0) O++c,write(1,&7[o],1) O z=c+2-l,w, c=l+q O p,c=l+z O c=l+q O s^=1 O Q=q[l] O s|=1 O q[l]=Q O Q=~Q O a(5)=l[x=q] ,a(4)=l[++x] O s|=s&16|9159?Q+=96,1:0,y=Q,h(s<<8) O l[x=q]=a(5),l[++x]=a(4) O x=Q%2,Q=Q/2+s%2*128,s=s&~1|x O Q=l[d(3)]O x=Q / 128,Q=Q*2+s%2,s=s&~1|x O l[d(3)]=Q O s=s&~1|1&Q,Q=Q/2|Q<<7 O Q=l[d(1)]O s=~1 &s|Q>>7,Q=Q*2|Q>>7 O l[d(1)]=Q O m y n(0,-,7)y) O m z=0,y=Q|=x,h(y) O m z=0, y=Q^=x,h(y) O m z=Q*2|2*x,y=Q&=x,h(y) O m Q n(s%2,-,7)y) O m Q n(0,-,7)y) O m Q n(s%2,+,7)y) O m Q n(0,+,7)y) O z=r-8?d(r+1):s|Q<<8,w O p,r-8?o[r+1]=z,r [o]=z>>8:(s=~40&z|2,Q=z>>8) O r[o]--||--o[r-1]O a(5)=z=a(5)+r[o],a(4)=z=a(4) +o[r-1]+z/256,s=~1&s|z>>8 O ++o[r+1]||r[o]++O o[r+1]=*c++,r[o]=*c++O z=c-l,w ,c=y*8+l O x=q,b z=c-l,w,c=l+x) O x=q,b c=l+x) O b p,c=l+z) O a(y)=*c++O r=y ,x=0,a(r)n(1,-,y)s<<8) O r=y,x=0,a(r)n(1,+,y)s<<8)))); system("stty cooked echo"); B((B((V?B(V):0,u)),v)); } How to compile it First, download the source code from here. It requires an *NIX compatible system (find porting notes below). To compile use: cc toledo2.c -o toledo2 The emulator needs an initial memory image to do something usable, so it will need two files (c_basic.bin and c_bios.bin). Rename c_basic.bin to C and run the emulator, and et voila! you have the public domain Palo Alto Tiny BASIC (by Li-Chen Wang), published on the very first volume of the now extinct Dr. Dobb's Journal magazine. Type using uppercase letters, here are three example programs, press Enter after each line: 10 PRINT "Hello, world!" LIST RUN 10 FOR A=1 TO 10 10 INPUT A 20 PRINT A 20 INPUT B 30 NEXT A 30 PRINT A+B LIST LIST RUN RUN Press Ctrl+Z to quit, by the way, the segmentation fault is normal at this point. All good programmers started learning BASIC, now, what about a CP/M emulator? Download the following file (not included because of possible copyright and blah, blah): http://www.retroarchive.org/cpm/os/KAYPROII.ZIP Extract CPM64.COM from the SOURCE directory, and copy it to files named A and B (these will be the disk drives). Now rename the provided c_bios.bin to C and run the emulator. Now you have a running CP/M operating system!, with two files on A: drive, HALT.COM to stop the emulator (so it closes drives) and IMPORT.COM to introduce new files. To get a complete CP/M system, you will need the following files from the KAYPROII.ZIP, SOURCE directory: ASM.COM DDT.COM DUMP.COM ED.COM LOAD.COM PIP.COM STAT.COM SUBMIT.COM XSUB.COM To import them, you must run the emulator with an argument, by example: prog DDT.COM When the A> prompt appears, do: IMPORT DDT.COM When it ends, do HALT, so the file is saved, and you can start the same process with another file. The WS33-KPR directory of the KAYPROII.ZIP file also contains a Wordstar version that works with this emulator. There is also an interesting game, the classical Adventure by Crowther and Woods in the ADVENTUR directory, at that time was amazing that a microcomputer could contain such big game. At this time I have tested successfully the following software from www.retroarchive.org: Languages http://www.retroarchive.org/cpm/lang/c80v30.zip http://www.retroarchive.org/cpm/lang/Mbasic.com Spreadsheet http://www.retroarchive.org/cpm/business/MULTPLAN.ZIP Games http://www.retroarchive.org/cpm/games/zork123_80.zip Utilities http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/ARC-LBR/UNARC16.ARK http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/ARC-LBR/UNARC16.MSG http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/ARC-LBR/DELBR12.ARK http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/SQUSQ/USQ-20.COM http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/SQUSQ/UNCR8080.LBR http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/DIRUTL/XDIR3-12.LBR http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/DIRUTL/CU.LBR http://www.retroarchive.org/cpm/cdrom/CPM/UTILS/FILCPY/SWEEP40.LBR Some programs require installation to configure the terminal, locate ANSI or VT-100. A little course on CP/M The CP/M user's manuals are available on www.retroarchive.org. But if you remember how to use MS-DOS then you can use CP/M very easily. Here is a little reference of the command line: Internal commands: A: Change current drive to A B: Change current drive to B DIR List files in drive DIR *.TXT List all files with TXT extension TYPE FILE.TXT Shows content of FILE.TXT ERA FILE.TXT Erases file FILE.TXT USER 1 Change to user 1 (0-15 available) It is something as subdirectories. So you can separate your files. External commands: STAT Show used/free space on drive STAT *.* Show file sizes. DDT PROG.COM Debug PROG.COM. To quit use Ctrl+C Dump address 0100 (hex): D0100 Emulator running Wordstar under CP/M Emulator running Wordstar under CP/M. What is an 8080? It is simply the little brother of the Zilog Z80, it has no extended registers (AF', BC', DE', HL', IX or IY), no relative jumps, and every instruction beginning with CB, DD, ED or FD doesn't exist. The flags are only S (Sign, bit 7), Z (Zero, bit 6), P (Parity, bit 2) and C (Carry, bit 0). The 8080 processor was created by Federico Faggin and Masatoshi Shima in 1974, afterwards both would design the Zilog Z80 in 1976, these two processors were pretty important and influential for the rise of microcomputers. Porting it It is easy if your platform has getch/kbhit and ANSI terminal read --> Z=kbhit()?getch():0 write --> putchar(7[o]) system --> nothing Also add the following to trap Ctrl-C: #include signal(SIGINT, SIG_IGN); On PC/DOS you will need to add ANSI.SYS to CONFIG.SYS In *NIX the min 0 for stty is required, circa 2001 it was not required. How it works (SPOILER) The l array contains the 64K memory, it is initialized with a boot image loaded from the 'C' file, the program counter is the c pointer, and registers are on o[]. The main loops reads every op-code and separates it in one of three common forms, a lot of trinary operators selects the instruction. Execution starts at 0000, you can write your own boot or monitor program, or even your own operating system playing with the 'C' file. o[0] = B register o[1] = C register o[2] = D register o[3] = E register o[4] = H register o[5] = L register o[6] = Flags o[7] = A or accumulator The following instructions do peripheral operation: 76 Quits emulator DB 00 Reads key pressed status DB 01 Reads key DB 02 Reads byte from file (Carry=EOF) D3 xx Writes byte from acc. to console ED ED 02 Reads sector (128 bytes) ED ED 03 Writes sector (128 bytes) Memory addresses: FBFA = Low source/target address FBFB - High source/target address FBFC - Sector (0-127) FBFD - Cylinder (low byte) FBFE - Cylinder (high byte) FBFF - Drive (1/2) The BIOS is tailor made for this emulator and helps to simplify it. Though the size of each virtual hard disk drive can reach 1 GB, CP/M only handles up to 8 MB. Other notes: * The 8080 runs at your computer speed divided between a number that I have not calculated. * This obfuscated processor was created using obfuscated code produced by an obfuscated mind, no brains were harmed during its production, except those that tried to read the code. * The original version of this code was eaten by my C++ dog. * I intended to make it simple to understand, it uses only four C keywords. * Also I discovered that braces are very useful for commenting. * Why to bother with prototypes?, every good C programmer can develop its C programs using only one function. And now it is 2024 This emulator was developed eighteen years ago when the computers had 32-bit processors and it used a hole in the C language syntax where you could pass a pointer on an integer. In fact, this is the IOCCC objective: make C compilers to do things these shouldn't be supposed to do. However, the C compilers for 64-bit processors don't allow it anymore as pointers are 64-bit and the int types are 32-bit, so compilers stop with an error (in especial in macOS because clang). The source code in this webpage is already updated to use FILE * instead of int, and this way we brought CP/M to year 2024, hehe. If you are curious about it, the previous version of the emulator can be downloaded here or in the IOCCC website. In 2020, Mark Abene sent me a workaround for x86-64 computers: gcc -static toledo2.c -o toledo2 But this doesn't work in macOS. Useful links: * Palo Alto Tiny BASIC source code, this is a modified version of the original. * CP/M source code, the foundation of an operating system: monotask, no memory manager, only console and file services provided. * Someone received an 8080 computer as a gift, dumped the ROM, and someone else found a way to test them with my 8080 emulator. :) Last modified: Feb/06/2024