Emulador Intel 8080. 19º IOCCC. Best of Show.
Este programa emula un procesador completo Intel(r) 8080,
junto con un teletipo y un controlador de discos, tal como al inicio de la
revolución de las computadoras personales (alrededor de 1975).
Aquí está el código fuente, escrito en lenguaje C:
#include <stdio.h>
#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; e,V,v,u,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(y=5[k]-1?u:v,((3[k]|4[k]<<8)<<7|2[k])<<7,Q=0),y)):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|9<Q%16?Q+=6,16:0,z=s|=1&s|Q>159?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)); }
Como compilarlo
Primero descargue el código fuente desde
aquí. Se requiere un sistema compatible con *NIX.
Para compilarlo utilice:
cc toledo2.c -o toledo2
Se requiere una imagen inicial de memoria para hacer algo
útil, así que anexo encontrará dos archivos
(
c_basic.bin y
c_bios.bin).
Renombre
c_basic.bin a C y ejecute el
emulador, y ¡et voila! tiene usted el Palo Alto Tiny BASIC de dominio público
(por Li-Chen Wang), publicado en el antiquísimo primer volumen
de la ahora desaparecida revista Dr. Dobb's Journal.
Teclee usando mayúsculas, aquí hay tres programas de
ejemplo, oprima Enter después de cada línea:
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
Oprima Ctrl+Z para salir, por cierto, el error de
segmentación en este punto es normal.
Todos los buenos programadores comenzaron aprendiendo
BASIC, ahora, ¿qué tal un emulador CP/M?
Descargue el siguiente archivo (no incluído debido a
posible copyright y bla, bla):
http://www.retroarchive.org/cpm/os/KAYPROII.ZIP
Extraiga CPM64.COM del directorio SOURCE, y
copielo a archivos nombrados A y B (estos serán los discos duros).
Ahora renombre el archivo c_bios.bin a C y ejecute el emulador.
¡Ahora tiene un sistema CP/M funcional!, con dos
archivos en el disco A:, HALT.COM para detener el emulador (y asegurarse
de que cierre los discos) e IMPORT.COM para introducir nuevos archivos.
Para obtener un sistema CP/M completo, necesitará los
siguientes archivos del directorio SOURCE de KAYPROII.ZIP:
ASM.COM DDT.COM DUMP.COM ED.COM LOAD.COM
PIP.COM STAT.COM SUBMIT.COM XSUB.COM
Para importarlos, debe ejecutar el emulador con un
argumento, por ejemplo:
prog DDT.COM
Cuando aparezca la petición A>, escriba:
IMPORT DDT.COM
Cuando termine, haga HALT, así el archivo es salvado, y
puede continuar el proceso con otro archivo.
Hasta este momento he probado exitosamente el siguiente
software de
www.retroarchive.org:
http://www.retroarchive.org/cpm/lang/c80v30.zip
http://www.retroarchive.org/cpm/lang/Mbasic.com
http://www.retroarchive.org/cpm/business/MULTPLAN.ZIP
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
Algunos programas requieren instalación para configurar la
terminal, busque ANSI o VT-100.

El emulador ejecutando
Wordstar bajo CP/M.
¿Qué es un 8080?
Sencillamente el hermano menor del Zilog Z80,
no tiene registros extendidos (AF', BC', DE', HL',
IX or IY), no tiene saltos relativos, y cada instrucción
que comienza con CB, DD, ED o FD no existe.
Las banderas son únicamente S (Signo, bit 7), Z (Cero, bit
6), P (Paridad, bit 2) y C (Acarreo, bit 0).
Transportándolo
Es fácil si su plataforma tiene getch/kbhit y terminal
ANSI
read --> Z=kbhit()?getch():0
write --> putchar(7[o])
system --> nada
También añada lo siguiente para bloquear Ctrl-C:
#include <signal.h>
signal(SIGINT, SIG_IGN);
En PC/DOS puede requerir añadir ANSI.SYS a CONFIG.SYS
En *NIX el min 0 en stty es requerido, alrededor del año
2001 no era requerido.
Como trabaja (aguafiestas)
El arreglo l contiene la memoria de 64K, y es
inicializado con una imagen de arranque cargada del archivo 'C',
el contador de programa es el apuntador c, y los registros están
en o[]. El bucle principal lee cada código de operación y lo
separa en una de tres formas comunes, muchos operados trinarios
seleccionan la instrucción.
o[0] = Registro B o[1] = Registro C
o[2] = Registro D o[3] = Registro E
o[4] = Registro H o[5] = Registro L
o[6] = Banderas o[7] = A o acumulador
Las siguientes instrucciones realizan operación de
periféricos:
76 Termina el emulador
DB 00 Lee estatus de tecla oprimida
DB 01 Lee tecla
DB 02 Lee byte de archivo (Carry=Fin de archivo)
D3 xx Escribe byte de acumulador a consola
ED ED 02 Lee un sector
ED ED 03 Escribe un sector
Direcciones de memoria:
FBFA . Dirección baja fuente/destino
FBFB - Dirección alta fuente/destino
FBFC - Sector
FBFD - Cilindro (byte bajo)
FBFE - Cilindro (byte alto)
FBFF - Unidad.
El BIOS está especialmente diseñado para este emulador,
y ayuda a simplificarlo.
Otras notas:
- El 8080 corre a la velocidad de su computadora
dividida entre un número que no he calculado.
- Este procesador confuso fue creado usando
código confuso producido por una mente confusa,
no se dañó a ningún cerebro durante su producción,
excepto aquellos que trataron de leer el código.
- La versión original de este código fue comida
por mi perro C++.
- Trate de hacerlo sencillo de entender, utiliza
solamente cuatro palabras clave del C.
- También descubrí que las llaves son muy útiles
para comentar.
- ¿Porqué molestarse con prototipos?, todos los
buenos programadores de C pueden desarrollar sus
programas usando una sola función.
Última modificación: 11-ago-2009