Código
/* * Miky Gonzalez Virtual Machine - Segunda revisión * Compilar con: gcc -o vm vm.c -O2 * Para más información y futuras versiones visita: * http://mikygonzalez.16mb.com/ */ #include <stdio.h> #include <stdlib.h> #define MAXIMOS_NODOS 100 typedef struct _nodo { int reg_pila; struct _nodo *siguiente_nodo; } nodo; typedef nodo *__nodo; typedef nodo *__pila; typedef struct _cpu { int reg[16]; unsigned short int reg_temp[5]; unsigned short int estado; unsigned int instruction_pointer; __pila pila_cpu; } cpu; /*! FUNCIONES DE LA PILA */ void push(__pila *pila, int num) { __nodo nodo_push; if(nodo_push != NULL) { nodo_push->reg_pila = num; nodo_push->siguiente_nodo = *pila; *pila = nodo_push; } } int pop(__pila *pila) { __nodo nodo_pop; int valor_nodo_pop = 0; nodo_pop = *pila; valor_nodo_pop = (*pila)->reg_pila; *pila = (*pila)->siguiente_nodo; return valor_nodo_pop; } unsigned int contar_nodos(__nodo nodo_pila) { unsigned int valor_temporal = 0; if(nodo_pila == NULL) return valor_temporal; while(nodo_pila != NULL) { nodo_pila = nodo_pila->siguiente_nodo; valor_temporal++; } return valor_temporal; } /*! FUNCIONES DEL CPU */ void iniciar_datos(cpu* CPU) { unsigned short int bucle_i; for(bucle_i = 0; bucle_i < 16; bucle_i++) CPU->reg[bucle_i] = 0; CPU->estado = 1; CPU->instruction_pointer = 0; CPU->pila_cpu = NULL; } void mostrar_datos(cpu* CPU) { unsigned short int bucle_i; for(bucle_i = 0; bucle_i < 16; bucle_i++) } void preparar_cpu(cpu* CPU, unsigned short int instruccion) { CPU->reg_temp[0] = (instruccion & 0xF000) >> 12; CPU->reg_temp[1] = (instruccion & 0xF00) >> 8; CPU->reg_temp[2] = (instruccion & 0xF0) >> 4; CPU->reg_temp[3] = (instruccion & 0xF); CPU->reg_temp[4] = (instruccion & 0xFF); } void ejecutar_cpu(unsigned int programa[], cpu* CPU) { int valor_temporal = 0; while(CPU->estado) { preparar_cpu(CPU, programa[CPU->instruction_pointer]); switch(CPU->reg_temp[0]) { case 0: /*! halt */ CPU->estado = 0; break; case 1: /*! setr */ // Comprobar si los datos estan dentro de los registros accesibles if(0x0 > CPU->reg_temp[1] > 0xF) { CPU->estado = 0; break; } CPU->reg[CPU->reg_temp[1]] = CPU->reg_temp[4]; break; case 2: /*! push */ // Comprobar si los datos estan dentro de los registros accesibles if(0x0 > CPU->reg_temp[1] > 0xF) { CPU->estado = 0; break; } // Comprobar elementos maximos de la pila if(contar_nodos(CPU->pila_cpu) == MAXIMOS_NODOS) { CPU->estado = 0; break; } push(&CPU->pila_cpu, CPU->reg[CPU->reg_temp[1]]); break; case 3: /*! pop */ // Comprobar existe almenos un elemento en pila_cpu if(CPU->pila_cpu == NULL) { CPU->estado = 0; break; } pop(&CPU->pila_cpu); break; case 4: /*! move */ // Comprobar existe almenos un elemento en pila_cpu if(CPU->pila_cpu == NULL) { CPU->estado = 0; break; } // Comprobar si los datos estan dentro de los registros accesibles if(0x0 > CPU->reg_temp[1] > 0xF) { CPU->estado = 0; break; } valor_temporal = CPU->reg[CPU->reg_temp[1]]; CPU->reg[CPU->reg_temp[1]] = CPU->pila_cpu->reg_pila; CPU->pila_cpu->reg_pila = valor_temporal; break; default: break; } valor_temporal = 0; CPU->instruction_pointer++; } } /*! INICIO DE MG-VM */ int main(int argc, char *argv[]) { cpu CPU; unsigned int programa[] = { 0x1010, // setr 0 10 0x2000, // push 0 0x4100, // move 1 0x2100, // push 1 0x3000, // pop 0x3000, // pop 0x0000 // halt }; iniciar_datos(&CPU); mostrar_datos(&CPU); ejecutar_cpu(programa, &CPU); mostrar_datos(&CPU); return 0; }
Si encuentran una manera mejor de hacer las cosas, o más optimizada, porfavor, puedes comentar que propones. Cualquier sugerencia o queja son bienvenidas.
La máquina virtual sólo cuenta con funciones de manejo de la pila y registros. No tiene funciones artiméticas, en la próxima versión entrarán las demás funciones aritméticas. En total tengo un máximo de 16 funciones.
Un saludo, espero que les agrade el código. Intenté escribirlo para que pudiera entenderlo bien, aún siendo principiante en programación.
Para obtener más información del tutorial ó próximas revisiones del código: http://mikygonzalez.16mb.com/