Advertisement
xerpi

DCPU16 emulator (very basic)

Dec 25th, 2012
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.73 KB | None | 0 0
  1. /************************************ dcpu16.h ************************************/
  2.  
  3. #ifndef _DCPU16_H_
  4. #define _DCPU16_H_
  5.  
  6. #include <stdio.h>
  7. #include <stdint.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. #define DCPU16_DEBUG
  12.  
  13. #define DCPU16_WORD          uint16_t
  14. #define DCPU16_RAM_SIZE      0x10000
  15. #define DCPU16_OPCODE(instr) ((instr)     & 0x1F)
  16. #define DCPU16_A(instr)      ((instr>>10) & 0x3F)
  17. #define DCPU16_B(instr)      ((instr>>5)  & 0x1F)
  18.  
  19.  
  20. enum basic_opcodes
  21. {
  22.     SPECIAL_OPCODE = 0x00,
  23.     SET,
  24.     ADD,
  25.     SUB,
  26.     MUL,
  27.     MLI,
  28.     DIV,
  29.     DVI,
  30.     MOD,
  31.     MDI,
  32.     AND,
  33.     BOR,
  34.     XOR,
  35.     SHR,
  36.     ASR,
  37.     SHL,
  38.     IFB,
  39.     IFC,
  40.     IFE,
  41.     IFN,
  42.     IFG,
  43.     IFA,
  44.     IFL,
  45.     IFU,
  46.     ADX = 0x1A,
  47.     SBX,
  48.     STI = 0x1E,
  49.     STD
  50. };
  51.  
  52. enum special_opcodes
  53. {
  54.     JSR = 0x01,
  55.     INT = 0x08,
  56.     IAG,
  57.     IAS,
  58.     RFI,
  59.     IAQ,
  60.     HWN = 0x10,
  61.     HWQ,
  62.     HWI
  63. };
  64.  
  65.  
  66. enum value_position
  67. {
  68.     IN_B,
  69.     IN_A
  70. };
  71.  
  72. typedef struct
  73. {
  74.     DCPU16_WORD ram[DCPU16_RAM_SIZE];
  75.     union
  76.     {
  77.         DCPU16_WORD reg[8];
  78.         struct
  79.         {
  80.             DCPU16_WORD A, B, C, X, Y, Z, I, J;
  81.         };
  82.     };
  83.     DCPU16_WORD PC, SP, EX, IA;
  84.     int32_t literal_value;
  85.     uint64_t clock_cycles;
  86. }dcpu16_t;
  87.  
  88.  
  89. int dcpu16_reset(dcpu16_t *dcpu16);
  90.  
  91. int dcpu16_step(dcpu16_t *dcpu16);
  92.  
  93. void dcpu16_push_stack(dcpu16_t *dcpu16, DCPU16_WORD value);
  94. DCPU16_WORD dcpu16_pop_stack(dcpu16_t *dcpu16);
  95.  
  96. static void *dcpu16_value_pointer(dcpu16_t *dcpu16, uint8_t value, enum value_position pos);
  97.  
  98. int dcpu16_ramdump(dcpu16_t *dcpu16, char *filename);
  99.  
  100. void dcpu16_debug(dcpu16_t *dcpu16);
  101.  
  102.  
  103.  
  104. #endif
  105.  
  106.  
  107.  
  108.  
  109. /************************************ dcpu16.c ************************************/
  110.  
  111. #include "dcpu16.h"
  112.  
  113. static DCPU16_WORD DCPU16_LITERAL_VALUE;
  114.  
  115. int dcpu16_reset(dcpu16_t *dcpu16)
  116. {
  117.     //Clean RAM
  118.         memset(dcpu16->ram, 0x0, DCPU16_RAM_SIZE * sizeof(DCPU16_WORD));
  119.     //Reset clock cycles
  120.         dcpu16->clock_cycles = 0;
  121.     //Reset registers
  122.         memset(dcpu16->reg, 0x0, 8 * sizeof(DCPU16_WORD));
  123.     //Set PC to 0
  124.         dcpu16->PC = 0;
  125.     //Set SP to 0xFFFF
  126.         dcpu16->SP = 0xFFFF;
  127.        
  128.     return 1;
  129. }
  130.  
  131.  
  132. int dcpu16_step(dcpu16_t *dcpu16)
  133. {
  134.     DCPU16_WORD instruction = dcpu16->ram[dcpu16->PC++];
  135.     uint8_t  opcode      = DCPU16_OPCODE(instruction);
  136.     uint8_t  a_value     = DCPU16_A(instruction);
  137.     uint8_t  b_value     = DCPU16_B(instruction);
  138. #ifdef DCPU16_DEBUG
  139.     printf("Instruction 0x%X\n", instruction);
  140.     printf("Opcode 0x%X\n", opcode);
  141.     printf("a_val: 0x%X\n", a_value);
  142.     printf("b_val: 0x%X\n", b_value);
  143.     usleep(100 * 1000);
  144. #endif
  145.     uint32_t tmp_a, tmp_b; //To prevent overflows
  146.     DCPU16_WORD *a_pointer =
  147.                 dcpu16_value_pointer(dcpu16, a_value, IN_A);
  148.     DCPU16_WORD *b_pointer =
  149.                 dcpu16_value_pointer(dcpu16, b_value, IN_B);
  150.     tmp_a = *a_pointer;
  151.     tmp_b = *b_pointer;
  152.     switch(opcode)
  153.     {
  154. /** Special OPCODES **/
  155.     case SPECIAL_OPCODE :
  156.         switch(b_value) //Opcode is B
  157.         {
  158.         case JSR:
  159.             dcpu16_push_stack(dcpu16, dcpu16->PC + 1);
  160.             dcpu16->PC = a_value;
  161.             dcpu16->clock_cycles += 3;
  162.             break;
  163.            
  164.         case INT:
  165.             //triggers a software interrupt with message a
  166.             dcpu16->clock_cycles += 4;
  167.             break;
  168.            
  169.         case IAG:
  170.             dcpu16->IA = tmp_a;
  171.             dcpu16->clock_cycles += 1;
  172.             break;
  173.            
  174.         case IAS:
  175.             *a_pointer = dcpu16->IA;
  176.             dcpu16->clock_cycles += 1;
  177.             break;
  178.        
  179.         case RFI:
  180.             //DISABLE INTERRUPT
  181.             dcpu16->A  = dcpu16_pop_stack(dcpu16);
  182.             dcpu16->PC = dcpu16_pop_stack(dcpu16);
  183.             dcpu16->clock_cycles += 3;
  184.             break;
  185.  
  186.         case IAQ:
  187.             if(tmp_a != 0)
  188.             {
  189.                 //Interrupts queued
  190.             }
  191.             else
  192.             {
  193.                 //Interrupts triggered
  194.             }
  195.             dcpu16->clock_cycles += 2;
  196.             break;
  197.            
  198.         case HWN:
  199.             dcpu16->A = 0;
  200.             dcpu16->clock_cycles += 2;
  201.             break;
  202.            
  203.         case HWQ:
  204.             dcpu16->A = 0;
  205.             dcpu16->B = 0;
  206.             dcpu16->C = 0;
  207.             dcpu16->X = 0;
  208.             dcpu16->Y = 0;
  209.             dcpu16->clock_cycles += 4;
  210.             break;
  211.            
  212.         case HWI:
  213.             //sends an interrupt to hardware a
  214.             dcpu16->clock_cycles += 4;
  215.             break;
  216.        
  217.         default: //Not implemented?
  218.             break;             
  219.         }
  220.         break;
  221. /** Basic OPCODES **/
  222.     case SET:
  223.         *b_pointer = *a_pointer;
  224.         dcpu16->clock_cycles++;
  225.         break;
  226.        
  227.     case ADD:
  228.         tmp_b += tmp_a;
  229.         if(tmp_b > 0xFFFF)
  230.             dcpu16->EX = 0x0001;
  231.         else
  232.             dcpu16->EX = 0x0;
  233.         *b_pointer = tmp_b & 0xFFFF;
  234.         dcpu16->clock_cycles+=2;
  235.         break;
  236.        
  237.     case SUB:
  238.         tmp_b -= tmp_a;
  239.         if(tmp_b < 0)
  240.             dcpu16->EX = 0xFFFF;
  241.         else
  242.             dcpu16->EX = 0x0;
  243.         *b_pointer = tmp_b & 0xFFFF;
  244.         dcpu16->clock_cycles+=2;
  245.         break;
  246.        
  247.     case MUL: case MLI:
  248.         tmp_b *= tmp_a;
  249.         dcpu16->EX = (tmp_b>>16) & 0xFFFF;
  250.         *b_pointer = tmp_b & 0xFFFF;
  251.         dcpu16->clock_cycles+=2;
  252.         break;
  253.    
  254.     case DIV: case DVI:
  255.         if(tmp_a == 0)
  256.         {
  257.             dcpu16->EX = 0;
  258.             tmp_b = 0;
  259.         }
  260.         else
  261.         {
  262.             tmp_b /= tmp_a;
  263.             dcpu16->EX = ((tmp_b<<16)/tmp_a) & 0xFFFF;
  264.         }
  265.         *b_pointer = tmp_b & 0xFFFF;
  266.         dcpu16->clock_cycles+=3;
  267.         break;
  268.        
  269.     case MOD: case MDI:
  270.         if(tmp_a == 0)
  271.         {
  272.             tmp_b = 0;
  273.             dcpu16->EX = 0;
  274.         }
  275.         else
  276.         {
  277.             tmp_b %= tmp_a;        
  278.         }
  279.         *b_pointer = tmp_b & 0xFFFF;
  280.         dcpu16->clock_cycles+=3;
  281.         break;
  282.  
  283.     case AND:
  284.         *b_pointer &= *a_pointer;
  285.         dcpu16->clock_cycles++;
  286.         break;
  287.        
  288.     case BOR:
  289.         *b_pointer |= *a_pointer;
  290.         dcpu16->clock_cycles++;
  291.         break;
  292.  
  293.     case XOR:
  294.         *b_pointer ^= *a_pointer;
  295.         dcpu16->clock_cycles++;
  296.         break;
  297.        
  298.     case SHR: case ASR:
  299.         *b_pointer >>= *a_pointer;
  300.         dcpu16->EX = ((*b_pointer<<16)>>*a_pointer) & 0xFFFF;
  301.         dcpu16->clock_cycles++;
  302.         break;
  303.            
  304.     case SHL:
  305.         *b_pointer <<= *a_pointer;
  306.         dcpu16->EX = ((*b_pointer<<*a_pointer)>>16) & 0xFFFF;
  307.         dcpu16->clock_cycles+=2;
  308.         break;
  309.        
  310.     case IFB:
  311.         if(tmp_b & tmp_a == 0)
  312.         {
  313.             dcpu16->PC++; //Skip next instruction
  314.             dcpu16->clock_cycles++; //Skipping costs 1
  315.         }
  316.         dcpu16->clock_cycles+=2;
  317.         break;
  318.        
  319.     case IFC:
  320.         if(tmp_b & tmp_a != 0)
  321.         {
  322.             dcpu16->PC++; //Skip next instruction
  323.             dcpu16->clock_cycles++; //Skipping costs 1
  324.         }
  325.         dcpu16->clock_cycles+=2;
  326.         break;
  327.  
  328.     case IFE:
  329.         if(tmp_b != tmp_a)
  330.         {
  331.             dcpu16->PC++; //Skip next instruction
  332.             dcpu16->clock_cycles++; //Skipping costs 1
  333.         }
  334.         dcpu16->clock_cycles+=2;
  335.         break;
  336.        
  337.     case IFN:
  338.         if(tmp_b == tmp_a)
  339.         {
  340.             dcpu16->PC++; //Skip next instruction
  341.             dcpu16->clock_cycles++; //Skipping costs 1
  342.         }
  343.         dcpu16->clock_cycles+=2;
  344.         break;
  345.  
  346.     case IFG: case IFA:
  347.         if(tmp_b < tmp_a)
  348.         {
  349.             dcpu16->PC++; //Skip next instruction
  350.             dcpu16->clock_cycles++; //Skipping costs 1
  351.         }
  352.         dcpu16->clock_cycles+=2;
  353.         break;
  354.        
  355.     case IFL: case IFU:
  356.         if(tmp_b > tmp_a)
  357.         {
  358.             dcpu16->PC++; //Skip next instruction
  359.             dcpu16->clock_cycles++; //Skipping costs 1
  360.         }
  361.         dcpu16->clock_cycles+=2;
  362.         break;
  363.    
  364.     case ADX:
  365.         tmp_b += (tmp_a + dcpu16->EX);
  366.         if(tmp_b > 0xFFFF)
  367.             dcpu16->EX = 0x0001;
  368.         else
  369.             dcpu16->EX = 0x0;
  370.         dcpu16->clock_cycles+=3;
  371.         break;
  372.        
  373.     case SBX:
  374.         tmp_b -= (tmp_a + dcpu16->EX);
  375.         if(tmp_b < 0)
  376.             dcpu16->EX = 0xFFFF;
  377.         else
  378.             dcpu16->EX = 0x0;
  379.         dcpu16->clock_cycles+=3;
  380.         break;
  381.        
  382.     case STI:
  383.         *b_pointer = *a_pointer;
  384.         dcpu16->I++;
  385.         dcpu16->J++;
  386.         break;
  387.        
  388.     case STD:
  389.         *b_pointer = *a_pointer;
  390.         dcpu16->I--;
  391.         dcpu16->J--;
  392.         break;
  393.        
  394.     default: //Not implemented?
  395.         printf("lulz: opcode: %i\n", opcode);
  396.         break;
  397.     }
  398.     return 1;
  399. }
  400.  
  401. void dcpu16_push_stack(dcpu16_t *dcpu16, DCPU16_WORD value)
  402. {
  403.     dcpu16->ram[(--dcpu16->SP)] = value;
  404. }
  405.  
  406. DCPU16_WORD dcpu16_pop_stack(dcpu16_t *dcpu16)
  407. {
  408.     return dcpu16->ram[(dcpu16->SP++)];
  409. }
  410.  
  411. static void *dcpu16_value_pointer(dcpu16_t *dcpu16, uint8_t value, enum value_position pos)
  412. {
  413.     switch(value)
  414.     {
  415.     case 0x00: case 0x01: case 0x02:
  416.     case 0x03: case 0x04: case 0x05:
  417.     case 0x06: case 0x07:
  418.         return &dcpu16->reg[value];
  419.        
  420.     case 0x08: case 0x09: case 0x0A:
  421.     case 0x0B: case 0x0C: case 0x0D:
  422.     case 0x0E: case 0x0F:
  423.         return &dcpu16->ram[dcpu16->reg[value - 0x8]];
  424.        
  425.     case 0x10: case 0x11: case 0x12:
  426.     case 0x13: case 0x14: case 0x15:
  427.     case 0x16: case 0x17:
  428.         return &dcpu16->ram[dcpu16->reg[value - 0x8] + dcpu16->ram[dcpu16->PC++]];
  429.        
  430.     case 0x18: //PUSH in B,  POP in A
  431.         if(pos == IN_B)
  432.             return &dcpu16->ram[--dcpu16->SP]; //PUSH
  433.         else
  434.             return &dcpu16->ram[dcpu16->SP++]; //POP
  435.        
  436.     case 0x19: //PEEK
  437.         return &dcpu16->ram[dcpu16->SP];
  438.        
  439.     case 0x1A: //PEEK n (SP + next word)
  440.         return &dcpu16->ram[dcpu16->SP + dcpu16->ram[dcpu16->PC++]];
  441.        
  442.     case 0x1B: //SP
  443.         return &dcpu16->SP;
  444.        
  445.     case 0x1C: //PC
  446.         return &dcpu16->PC;
  447.        
  448.     case 0x1D: //EX
  449.         return &dcpu16->EX;
  450.        
  451.     case 0x1E: //Next word
  452.         return &dcpu16->ram[dcpu16->ram[dcpu16->PC++]];
  453.        
  454.     case 0x1F: //Next word (literal)
  455.         return &dcpu16->ram[dcpu16->PC++];
  456.                
  457.     default:
  458.         DCPU16_LITERAL_VALUE = value - 0x21;
  459.         return &DCPU16_LITERAL_VALUE;
  460.     }
  461. }
  462.  
  463.  
  464. int dcpu16_ramdump(dcpu16_t *dcpu16, char *filename)
  465. {
  466.     FILE *file = fopen(filename, "wb");
  467.     if(file == NULL) return -1;
  468.    
  469.     size_t result = fwrite((void *)dcpu16->ram, sizeof(DCPU16_WORD), DCPU16_RAM_SIZE, file);
  470.     fclose(file);
  471.    
  472.     if(result != DCPU16_RAM_SIZE)
  473.         return 0;
  474.     return 1;
  475. }
  476.  
  477. int dcpu16_load_binary(dcpu16_t *dcpu16, char *filename)
  478. {
  479.     FILE *file = fopen(filename, "rb");
  480.     if(file == NULL)
  481.     {
  482. #ifdef DCPU16_DEBUG
  483.         printf("Could not open '%s'.\n", filename);
  484. #endif     
  485.         return -1;
  486.     }
  487.  
  488.     fseek(file, 0x0, SEEK_END);
  489.     uint64_t file_size = ftell(file);
  490.    
  491.     if(file_size > 0)
  492.     {
  493.         rewind(file);
  494.         size_t result = fread((void *)dcpu16->ram, sizeof(DCPU16_WORD), file_size/2, file);
  495. #ifdef DCPU16_DEBUG
  496.         printf("'%s' opened. Size: %lu byte(s). Result: %lu.\n", filename, file_size, result);
  497. #endif
  498.         fclose(file);
  499.         return 1;
  500.     }
  501.  
  502.     fclose(file);
  503.     return 0;
  504. }
  505.  
  506.  
  507. void dcpu16_debug(dcpu16_t *dcpu16)
  508. {
  509.     printf("PC: 0x%04X   CLOCK: %06lu    A: 0x%04X   B: 0x%04X   C: 0x%04X\n", dcpu16->PC, dcpu16->clock_cycles, dcpu16->A , dcpu16->B , dcpu16->C);
  510.     printf("X: 0x%04X   Y: %04i    Z: 0x%04X   I: 0x%04X   J: 0x%04X\n", dcpu16->X, dcpu16->Y, dcpu16->Z, dcpu16->I, dcpu16->J);
  511.        
  512. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement