Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /************************************ dcpu16.h ************************************/
- #ifndef _DCPU16_H_
- #define _DCPU16_H_
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #define DCPU16_DEBUG
- #define DCPU16_WORD uint16_t
- #define DCPU16_RAM_SIZE 0x10000
- #define DCPU16_OPCODE(instr) ((instr) & 0x1F)
- #define DCPU16_A(instr) ((instr>>10) & 0x3F)
- #define DCPU16_B(instr) ((instr>>5) & 0x1F)
- enum basic_opcodes
- {
- SPECIAL_OPCODE = 0x00,
- SET,
- ADD,
- SUB,
- MUL,
- MLI,
- DIV,
- DVI,
- MOD,
- MDI,
- AND,
- BOR,
- XOR,
- SHR,
- ASR,
- SHL,
- IFB,
- IFC,
- IFE,
- IFN,
- IFG,
- IFA,
- IFL,
- IFU,
- ADX = 0x1A,
- SBX,
- STI = 0x1E,
- STD
- };
- enum special_opcodes
- {
- JSR = 0x01,
- INT = 0x08,
- IAG,
- IAS,
- RFI,
- IAQ,
- HWN = 0x10,
- HWQ,
- HWI
- };
- enum value_position
- {
- IN_B,
- IN_A
- };
- typedef struct
- {
- DCPU16_WORD ram[DCPU16_RAM_SIZE];
- union
- {
- DCPU16_WORD reg[8];
- struct
- {
- DCPU16_WORD A, B, C, X, Y, Z, I, J;
- };
- };
- DCPU16_WORD PC, SP, EX, IA;
- int32_t literal_value;
- uint64_t clock_cycles;
- }dcpu16_t;
- int dcpu16_reset(dcpu16_t *dcpu16);
- int dcpu16_step(dcpu16_t *dcpu16);
- void dcpu16_push_stack(dcpu16_t *dcpu16, DCPU16_WORD value);
- DCPU16_WORD dcpu16_pop_stack(dcpu16_t *dcpu16);
- static void *dcpu16_value_pointer(dcpu16_t *dcpu16, uint8_t value, enum value_position pos);
- int dcpu16_ramdump(dcpu16_t *dcpu16, char *filename);
- void dcpu16_debug(dcpu16_t *dcpu16);
- #endif
- /************************************ dcpu16.c ************************************/
- #include "dcpu16.h"
- static DCPU16_WORD DCPU16_LITERAL_VALUE;
- int dcpu16_reset(dcpu16_t *dcpu16)
- {
- //Clean RAM
- memset(dcpu16->ram, 0x0, DCPU16_RAM_SIZE * sizeof(DCPU16_WORD));
- //Reset clock cycles
- dcpu16->clock_cycles = 0;
- //Reset registers
- memset(dcpu16->reg, 0x0, 8 * sizeof(DCPU16_WORD));
- //Set PC to 0
- dcpu16->PC = 0;
- //Set SP to 0xFFFF
- dcpu16->SP = 0xFFFF;
- return 1;
- }
- int dcpu16_step(dcpu16_t *dcpu16)
- {
- DCPU16_WORD instruction = dcpu16->ram[dcpu16->PC++];
- uint8_t opcode = DCPU16_OPCODE(instruction);
- uint8_t a_value = DCPU16_A(instruction);
- uint8_t b_value = DCPU16_B(instruction);
- #ifdef DCPU16_DEBUG
- printf("Instruction 0x%X\n", instruction);
- printf("Opcode 0x%X\n", opcode);
- printf("a_val: 0x%X\n", a_value);
- printf("b_val: 0x%X\n", b_value);
- usleep(100 * 1000);
- #endif
- uint32_t tmp_a, tmp_b; //To prevent overflows
- DCPU16_WORD *a_pointer =
- dcpu16_value_pointer(dcpu16, a_value, IN_A);
- DCPU16_WORD *b_pointer =
- dcpu16_value_pointer(dcpu16, b_value, IN_B);
- tmp_a = *a_pointer;
- tmp_b = *b_pointer;
- switch(opcode)
- {
- /** Special OPCODES **/
- case SPECIAL_OPCODE :
- switch(b_value) //Opcode is B
- {
- case JSR:
- dcpu16_push_stack(dcpu16, dcpu16->PC + 1);
- dcpu16->PC = a_value;
- dcpu16->clock_cycles += 3;
- break;
- case INT:
- //triggers a software interrupt with message a
- dcpu16->clock_cycles += 4;
- break;
- case IAG:
- dcpu16->IA = tmp_a;
- dcpu16->clock_cycles += 1;
- break;
- case IAS:
- *a_pointer = dcpu16->IA;
- dcpu16->clock_cycles += 1;
- break;
- case RFI:
- //DISABLE INTERRUPT
- dcpu16->A = dcpu16_pop_stack(dcpu16);
- dcpu16->PC = dcpu16_pop_stack(dcpu16);
- dcpu16->clock_cycles += 3;
- break;
- case IAQ:
- if(tmp_a != 0)
- {
- //Interrupts queued
- }
- else
- {
- //Interrupts triggered
- }
- dcpu16->clock_cycles += 2;
- break;
- case HWN:
- dcpu16->A = 0;
- dcpu16->clock_cycles += 2;
- break;
- case HWQ:
- dcpu16->A = 0;
- dcpu16->B = 0;
- dcpu16->C = 0;
- dcpu16->X = 0;
- dcpu16->Y = 0;
- dcpu16->clock_cycles += 4;
- break;
- case HWI:
- //sends an interrupt to hardware a
- dcpu16->clock_cycles += 4;
- break;
- default: //Not implemented?
- break;
- }
- break;
- /** Basic OPCODES **/
- case SET:
- *b_pointer = *a_pointer;
- dcpu16->clock_cycles++;
- break;
- case ADD:
- tmp_b += tmp_a;
- if(tmp_b > 0xFFFF)
- dcpu16->EX = 0x0001;
- else
- dcpu16->EX = 0x0;
- *b_pointer = tmp_b & 0xFFFF;
- dcpu16->clock_cycles+=2;
- break;
- case SUB:
- tmp_b -= tmp_a;
- if(tmp_b < 0)
- dcpu16->EX = 0xFFFF;
- else
- dcpu16->EX = 0x0;
- *b_pointer = tmp_b & 0xFFFF;
- dcpu16->clock_cycles+=2;
- break;
- case MUL: case MLI:
- tmp_b *= tmp_a;
- dcpu16->EX = (tmp_b>>16) & 0xFFFF;
- *b_pointer = tmp_b & 0xFFFF;
- dcpu16->clock_cycles+=2;
- break;
- case DIV: case DVI:
- if(tmp_a == 0)
- {
- dcpu16->EX = 0;
- tmp_b = 0;
- }
- else
- {
- tmp_b /= tmp_a;
- dcpu16->EX = ((tmp_b<<16)/tmp_a) & 0xFFFF;
- }
- *b_pointer = tmp_b & 0xFFFF;
- dcpu16->clock_cycles+=3;
- break;
- case MOD: case MDI:
- if(tmp_a == 0)
- {
- tmp_b = 0;
- dcpu16->EX = 0;
- }
- else
- {
- tmp_b %= tmp_a;
- }
- *b_pointer = tmp_b & 0xFFFF;
- dcpu16->clock_cycles+=3;
- break;
- case AND:
- *b_pointer &= *a_pointer;
- dcpu16->clock_cycles++;
- break;
- case BOR:
- *b_pointer |= *a_pointer;
- dcpu16->clock_cycles++;
- break;
- case XOR:
- *b_pointer ^= *a_pointer;
- dcpu16->clock_cycles++;
- break;
- case SHR: case ASR:
- *b_pointer >>= *a_pointer;
- dcpu16->EX = ((*b_pointer<<16)>>*a_pointer) & 0xFFFF;
- dcpu16->clock_cycles++;
- break;
- case SHL:
- *b_pointer <<= *a_pointer;
- dcpu16->EX = ((*b_pointer<<*a_pointer)>>16) & 0xFFFF;
- dcpu16->clock_cycles+=2;
- break;
- case IFB:
- if(tmp_b & tmp_a == 0)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case IFC:
- if(tmp_b & tmp_a != 0)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case IFE:
- if(tmp_b != tmp_a)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case IFN:
- if(tmp_b == tmp_a)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case IFG: case IFA:
- if(tmp_b < tmp_a)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case IFL: case IFU:
- if(tmp_b > tmp_a)
- {
- dcpu16->PC++; //Skip next instruction
- dcpu16->clock_cycles++; //Skipping costs 1
- }
- dcpu16->clock_cycles+=2;
- break;
- case ADX:
- tmp_b += (tmp_a + dcpu16->EX);
- if(tmp_b > 0xFFFF)
- dcpu16->EX = 0x0001;
- else
- dcpu16->EX = 0x0;
- dcpu16->clock_cycles+=3;
- break;
- case SBX:
- tmp_b -= (tmp_a + dcpu16->EX);
- if(tmp_b < 0)
- dcpu16->EX = 0xFFFF;
- else
- dcpu16->EX = 0x0;
- dcpu16->clock_cycles+=3;
- break;
- case STI:
- *b_pointer = *a_pointer;
- dcpu16->I++;
- dcpu16->J++;
- break;
- case STD:
- *b_pointer = *a_pointer;
- dcpu16->I--;
- dcpu16->J--;
- break;
- default: //Not implemented?
- printf("lulz: opcode: %i\n", opcode);
- break;
- }
- return 1;
- }
- void dcpu16_push_stack(dcpu16_t *dcpu16, DCPU16_WORD value)
- {
- dcpu16->ram[(--dcpu16->SP)] = value;
- }
- DCPU16_WORD dcpu16_pop_stack(dcpu16_t *dcpu16)
- {
- return dcpu16->ram[(dcpu16->SP++)];
- }
- static void *dcpu16_value_pointer(dcpu16_t *dcpu16, uint8_t value, enum value_position pos)
- {
- switch(value)
- {
- case 0x00: case 0x01: case 0x02:
- case 0x03: case 0x04: case 0x05:
- case 0x06: case 0x07:
- return &dcpu16->reg[value];
- case 0x08: case 0x09: case 0x0A:
- case 0x0B: case 0x0C: case 0x0D:
- case 0x0E: case 0x0F:
- return &dcpu16->ram[dcpu16->reg[value - 0x8]];
- case 0x10: case 0x11: case 0x12:
- case 0x13: case 0x14: case 0x15:
- case 0x16: case 0x17:
- return &dcpu16->ram[dcpu16->reg[value - 0x8] + dcpu16->ram[dcpu16->PC++]];
- case 0x18: //PUSH in B, POP in A
- if(pos == IN_B)
- return &dcpu16->ram[--dcpu16->SP]; //PUSH
- else
- return &dcpu16->ram[dcpu16->SP++]; //POP
- case 0x19: //PEEK
- return &dcpu16->ram[dcpu16->SP];
- case 0x1A: //PEEK n (SP + next word)
- return &dcpu16->ram[dcpu16->SP + dcpu16->ram[dcpu16->PC++]];
- case 0x1B: //SP
- return &dcpu16->SP;
- case 0x1C: //PC
- return &dcpu16->PC;
- case 0x1D: //EX
- return &dcpu16->EX;
- case 0x1E: //Next word
- return &dcpu16->ram[dcpu16->ram[dcpu16->PC++]];
- case 0x1F: //Next word (literal)
- return &dcpu16->ram[dcpu16->PC++];
- default:
- DCPU16_LITERAL_VALUE = value - 0x21;
- return &DCPU16_LITERAL_VALUE;
- }
- }
- int dcpu16_ramdump(dcpu16_t *dcpu16, char *filename)
- {
- FILE *file = fopen(filename, "wb");
- if(file == NULL) return -1;
- size_t result = fwrite((void *)dcpu16->ram, sizeof(DCPU16_WORD), DCPU16_RAM_SIZE, file);
- fclose(file);
- if(result != DCPU16_RAM_SIZE)
- return 0;
- return 1;
- }
- int dcpu16_load_binary(dcpu16_t *dcpu16, char *filename)
- {
- FILE *file = fopen(filename, "rb");
- if(file == NULL)
- {
- #ifdef DCPU16_DEBUG
- printf("Could not open '%s'.\n", filename);
- #endif
- return -1;
- }
- fseek(file, 0x0, SEEK_END);
- uint64_t file_size = ftell(file);
- if(file_size > 0)
- {
- rewind(file);
- size_t result = fread((void *)dcpu16->ram, sizeof(DCPU16_WORD), file_size/2, file);
- #ifdef DCPU16_DEBUG
- printf("'%s' opened. Size: %lu byte(s). Result: %lu.\n", filename, file_size, result);
- #endif
- fclose(file);
- return 1;
- }
- fclose(file);
- return 0;
- }
- void dcpu16_debug(dcpu16_t *dcpu16)
- {
- 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);
- 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);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement