├── examples ├── andlw.bin ├── comf.bin ├── rlf.bin ├── rrf.bin ├── xorlw.bin ├── blink.bin ├── iorwf.bin ├── movf.bin ├── bit_test.bin ├── call.bin ├── dec.bin ├── inc.bin ├── addwf.bin ├── hello.bin ├── iorlw.bin ├── pattern.bin ├── reg_w.bin ├── subwf.bin ├── swapf.bin ├── xorwf.bin ├── hello_call.bin └── hello_retlw.bin ├── assets ├── clip.gif └── amethyst.png ├── src ├── strfy.h ├── term.h ├── types.h ├── utils.h ├── components │ ├── ram.h │ ├── rom.h │ ├── mem.h │ ├── decode.h │ ├── exec.h │ ├── reg.h │ ├── ram.c │ ├── reg.c │ ├── rom.c │ ├── mem.c │ ├── decode.c │ └── exec.c ├── display.h ├── emulator.h ├── rules.h ├── strfy.c ├── types.c ├── term.c ├── emulator.c ├── display.c └── utils.c ├── .gitignore ├── Makefile ├── test.c ├── main.c └── README.md /examples/andlw.bin: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /examples/comf.bin: -------------------------------------------------------------------------------- 1 | f 2 | -------------------------------------------------------------------------------- /examples/rlf.bin: -------------------------------------------------------------------------------- 1 | f 2 |  -------------------------------------------------------------------------------- /examples/rrf.bin: -------------------------------------------------------------------------------- 1 | & 2 |  -------------------------------------------------------------------------------- /examples/xorlw.bin: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /examples/blink.bin: -------------------------------------------------------------------------------- 1 |  2 | -------------------------------------------------------------------------------- /examples/iorwf.bin: -------------------------------------------------------------------------------- 1 | & & 2 | -------------------------------------------------------------------------------- /examples/movf.bin: -------------------------------------------------------------------------------- 1 | &@ 2 | -------------------------------------------------------------------------------- /examples/bit_test.bin: -------------------------------------------------------------------------------- 1 | ffffffF -------------------------------------------------------------------------------- /assets/clip.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/assets/clip.gif -------------------------------------------------------------------------------- /examples/call.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/call.bin -------------------------------------------------------------------------------- /examples/dec.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/dec.bin -------------------------------------------------------------------------------- /examples/inc.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/inc.bin -------------------------------------------------------------------------------- /assets/amethyst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/assets/amethyst.png -------------------------------------------------------------------------------- /examples/addwf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/addwf.bin -------------------------------------------------------------------------------- /examples/hello.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/hello.bin -------------------------------------------------------------------------------- /examples/iorlw.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/iorlw.bin -------------------------------------------------------------------------------- /examples/pattern.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/pattern.bin -------------------------------------------------------------------------------- /examples/reg_w.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/reg_w.bin -------------------------------------------------------------------------------- /examples/subwf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/subwf.bin -------------------------------------------------------------------------------- /examples/swapf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/swapf.bin -------------------------------------------------------------------------------- /examples/xorwf.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/xorwf.bin -------------------------------------------------------------------------------- /examples/hello_call.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/hello_call.bin -------------------------------------------------------------------------------- /examples/hello_retlw.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Empitrix/amethyst/HEAD/examples/hello_retlw.bin -------------------------------------------------------------------------------- /src/strfy.h: -------------------------------------------------------------------------------- 1 | #ifndef __STRFY_HEADER__ 2 | #define __STRFY_HEADER__ 3 | #include "strfy.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/term.h: -------------------------------------------------------------------------------- 1 | #ifndef __TERM_HEADER__ 2 | #define __TERM_HEADER__ 3 | #include "term.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_HEADER__ 2 | #define __TYPES_HEADER__ 3 | #include "types.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_HEADER__ 2 | #define __UTILS_HEADER__ 3 | #include "utils.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/ram.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_RAM_HEADER__ 2 | #define __C_RAM_HEADER__ 3 | #include "ram.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/rom.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_ROM_HEADER__ 2 | #define __C_ROM_HEADER__ 3 | #include "rom.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/display.h: -------------------------------------------------------------------------------- 1 | #ifndef __DISPLAY_HEADER__ 2 | #define __DISPLAY_HEADER__ 3 | #include "display.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_MEMORY_HEADER__ 2 | #define __C_MEMORY_HEADER__ 3 | #include "mem.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/emulator.h: -------------------------------------------------------------------------------- 1 | #ifndef __EMULATOR_HEADER__ 2 | #define __EMULATOR_HEADER__ 3 | #include "emulator.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/decode.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_DECODE_HEADER__ 2 | #define __C_DECODE_HEADER__ 3 | #include "decode.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/exec.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_EXECUTE_HEADER__ 2 | #define __C_EXECUTE_HEADER__ 3 | #include "exec.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef __C_REGISTER_HEADER__ 2 | #define __C_REGISTER_HEADER__ 3 | #include "reg.c" 4 | #endif 5 | -------------------------------------------------------------------------------- /src/components/ram.c: -------------------------------------------------------------------------------- 1 | #include "../types.h" 2 | 3 | 4 | void ram_init(void){ 5 | for(int i = 0; i < RAMSIZ; ++i){ 6 | RAM[i] = 0x00; 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /cpu 3 | /assembler 4 | /examples/test.bin 5 | *.out 6 | *.exe 7 | *.txt 8 | /cpu_state.txt 9 | 10 | # zig compile 11 | /cpu.pdb 12 | *.pdb 13 | /.clangd 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # To compile for 'linux/windows' using "gcc" compiler 2 | all: 3 | @ gcc ./main.c -lm -o ./cpu 4 | 5 | # To compile for 'windows' using "mingw" compiler 6 | windows: 7 | @ x86_64-w64-mingw32-gcc ./main.c -lm -o ./cpu.exe 8 | 9 | llvm: 10 | @ clang ./main.c -o ./cpu.exe 11 | 12 | zig: 13 | @ zig cc ./main.c -lm -o ./cpu.exe 14 | 15 | # To compile for 'linux' using "cc" compiler 16 | linux: 17 | @ cc ./main.c -lm -o ./cpu 18 | 19 | # Debug (show diagnostics) 20 | debug: 21 | @ gcc -g -fanalyzer -Wall -Wextra -pedantic -fsanitize=undefined,address,leak ./main.c -lm -o ./cpu 22 | 23 | # Run cppcheck 24 | check: 25 | @ cppcheck . --check-level=exhaustive 26 | -------------------------------------------------------------------------------- /src/rules.h: -------------------------------------------------------------------------------- 1 | #ifndef __RULES_HEADER__ 2 | #define __RULES_HEADER__ 3 | 4 | #define ROMSIZ 256 // 256 bytes of ROM (Addresses 0x00..0xFF) 5 | #define RAMSIZ 16 // 16 bytes of RAM (Addresses 0x10..0x1F) 6 | #define REGSIZ 10 // 10 Special Registers (Addresses 0x00..0x09) 7 | 8 | #define MALL 1000 // Max Assembly Line Length 9 | 10 | #define MAXSIZ 1024 // String size 11 | 12 | #define MAX_STACK 2 // Max Stack (CALL & RETLW) 13 | 14 | #define KB_P1 "[1388d4]" 15 | #define KB_P2 "[e63c07]" 16 | #define KB_P3 "[14c45b]" 17 | 18 | #define K_HEX "[2979FF]" 19 | #define K_INFO "[98C379]" 20 | 21 | #define K_OP1 "[ed400e]" 22 | #define K_OP2 "[E98C31]" 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/components/reg.c: -------------------------------------------------------------------------------- 1 | #include "../types.h" 2 | 3 | 4 | void reg_init(void){ 5 | for(int i = 0; i < REGSIZ; ++i){ 6 | REGISTERS[i] = 0; 7 | } 8 | } 9 | 10 | 11 | const char *get_reg_name(int reg_addr){ 12 | switch (reg_addr) { 13 | case 0: 14 | return "[FFFFFF]INDF"; 15 | case 1: 16 | return "[FFFFFF]TMR0"; 17 | case 2: 18 | return "[FFFFFF]PCL"; 19 | case 3: 20 | return "[FFFFFF]STATUS"; 21 | case 4: 22 | return "[FFFFFF]FSR"; 23 | case 5: 24 | return "[FFFFFF]OSCCAL"; 25 | case 6: 26 | return "[FFFFFF]GPIO"; 27 | case 7: 28 | return "[FFFFFF]CMCON0"; 29 | case 8: 30 | return "[FFFFFF]TRISGPIO"; 31 | case 9: 32 | return "[FFFFFF]OPTION"; 33 | default: 34 | return "[ABB2BF]N/A"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include "src/components/decode.h" 2 | #include 3 | 4 | int main(void){ 5 | DECODE dcd; 6 | dcd = decode_inst(0b010100000000); // BSF 7 | printf("%s\n", dcd.info); 8 | 9 | dcd = decode_inst(0b010000000000); // BCF 10 | printf("%s\n", dcd.info); 11 | 12 | dcd = decode_inst(0b101000000000); // GOTO 13 | printf("%s\n", dcd.info); 14 | 15 | dcd = decode_inst(0b000000000000); // NOP 16 | printf("%s\n", dcd.info); 17 | 18 | dcd = decode_inst(0b110000000000); // MOVLW 19 | printf("%s\n", dcd.info); 20 | 21 | dcd = decode_inst(0b000000100000); // MOVWF 22 | printf("%s\n", dcd.info); 23 | 24 | dcd = decode_inst(0b000001100000); // CLRF 25 | printf("%s\n", dcd.info); 26 | 27 | dcd = decode_inst(0b000001000000); // CLRW 28 | printf("%s\n", dcd.info); 29 | 30 | dcd = decode_inst(0b000000000011); // SLEEP 31 | printf("%s\n", dcd.info); 32 | 33 | printf("Finished...\n"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /src/strfy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* str_insert: insert 'm' into 'src' that starts at given 'idx' */ 8 | void str_insert(char *src, char *m, int idx) { 9 | int len1 = strlen(src); 10 | int len2 = strlen(m); 11 | memmove(src + idx + len2, src + idx, len1 - idx + 1); 12 | memcpy(src + idx, m, len2); 13 | } 14 | 15 | 16 | /* str_replace: replaces all of the 'a' with 'b' in the given 'src' */ 17 | void str_replace(char src[], char *a, char *b) { 18 | int len_a = strlen(a); 19 | int len_b = strlen(b); 20 | 21 | char *p = src; 22 | 23 | while ((p = strstr(p, a)) != NULL) { 24 | memmove(p + len_b, p + len_a, strlen(p + len_a) + 1); 25 | memcpy(p, b, len_b); 26 | p += len_b; 27 | } 28 | } 29 | 30 | 31 | void shift_over(char *src, int shift, int size){ 32 | for(int j = 0; j < size; ++j){ 33 | src[j] = src[shift + j]; 34 | } 35 | } 36 | 37 | 38 | void str_lower(char *src){ 39 | int len, i; len = (int)strlen(src); 40 | for(i = 0; i < len; ++i){ 41 | src[i] = tolower(src[i]); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/components/rom.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../types.h" 3 | #include "mem.h" 4 | #include "../display.h" 5 | 6 | 7 | /* rom_init: setup EEPROM */ 8 | void rom_init(char *rom_path){ 9 | memset(ROM, 0, sizeof(ROM)); 10 | 11 | FILE *fp; 12 | fp = fopen(rom_path, "rb"); 13 | if(fp == NULL){ 14 | lprt(1, "File \"%s\" does not exist!", rom_path); 15 | } 16 | 17 | 18 | unsigned char buffer[2]; 19 | int value, idx; 20 | idx = 0; 21 | 22 | while (fread(buffer, sizeof(buffer), 1, fp) == 1) { 23 | value = (buffer[0] << 8) | buffer[1]; 24 | ROM[idx++] = value; 25 | } 26 | 27 | fclose(fp); 28 | } 29 | 30 | FETCH rom_fetch(){ 31 | FETCH f; 32 | f.pc = get_sfr(PCL_REGISTER); 33 | f.data = ROM[f.pc]; 34 | return f; 35 | } 36 | 37 | void set_pc(int new_pc){ 38 | set_sfr(PCL_REGISTER, new_pc); 39 | } 40 | 41 | void increment_pc(void){ 42 | int pcl = get_sfr(PCL_REGISTER); 43 | set_sfr(PCL_REGISTER, pcl + 1); 44 | } 45 | 46 | /* Get program counter */ 47 | int get_pc(void){ 48 | return get_sfr(PCL_REGISTER); 49 | } 50 | 51 | /* Reset CPU (clear everything) */ 52 | void reset_cpu(int clear){ 53 | set_pc(0); 54 | int i; 55 | for(i = 0; i < REGSIZ; ++i){ 56 | REGISTERS[i] = 0; 57 | } 58 | 59 | for(i = 0; i < RAMSIZ; ++i){ 60 | RAM[i] = 0; 61 | } 62 | clear_sfr_bit(STATUS_REGISTER, 7); 63 | if(clear){ plat_cls(); } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/types.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "rules.h" 3 | 4 | 5 | short int ROM[ROMSIZ]; 6 | uint8_t RAM[RAMSIZ]; 7 | uint8_t REGISTERS[REGSIZ]; 8 | 9 | 10 | typedef struct FETCH { 11 | int pc; // Program Counter 12 | int data; // Binary data 13 | } FETCH; 14 | 15 | 16 | typedef enum EXEC_TYPE { 17 | SIX_ONE_FIVE, 18 | FOUR_THREE_FIVE, 19 | FOUR_EIGHT, 20 | THREE_NINE, 21 | SEVEN_FIVE, 22 | FULL, 23 | } exec_t; 24 | 25 | 26 | typedef struct EXEC { 27 | int upc; // Updated PC (Program Counter) 28 | int sleep; 29 | } EXEC; 30 | 31 | 32 | typedef enum CPU_LOAD { 33 | PROGRAM_LOAD, 34 | STATE_LOAD 35 | } CPU_LOAD; 36 | 37 | 38 | typedef struct GFLAGS { 39 | int stepping; 40 | int frequency; 41 | CPU_LOAD pload; 42 | char program[MALL]; 43 | char load[MALL]; 44 | int is_pause; 45 | int is_sleep; 46 | int console_en; 47 | int ci_mode; 48 | } GFLAGS; 49 | 50 | 51 | typedef enum OPCODES { 52 | NOP_OP, // NO Operation 53 | BCF_OP, // Bit Clear File 54 | BSF_OP, // Bit Set Forward 55 | GOTO_OP, // Goto 56 | MOVLW_OP, 57 | MOVWF_OP, 58 | CLRF_OP, 59 | CLRW_OP, 60 | DECF_OP, // Decrement F 61 | DECFSZ_OP, 62 | INCF_OP, // Increment F 63 | INCFSZ_OP, 64 | BTFSS_OP, // Test bit F 65 | BTFSC_OP, 66 | SLEEP_OP, // Sleep 67 | ADDWF_OP, 68 | ANDWF_OP, 69 | COMF_OP, 70 | IORWF_OP, 71 | MOVF_OP, 72 | RLF_OP, 73 | RRF_OP, 74 | SUBWF_OP, 75 | SWAPF_OP, 76 | XORWF_OP, 77 | ANDLW_OP, 78 | CALL_OP, 79 | CLRWDT_OP, 80 | IORLW_OP, 81 | OPTION_OP, 82 | RETLW_OP, 83 | TRIS_OP, 84 | XORLW_OP, 85 | } OPCODES; 86 | 87 | 88 | typedef struct TERSIZ { 89 | int x; 90 | int y; 91 | } TERSIZ; 92 | 93 | 94 | typedef enum mem_t { 95 | TO_RAM, 96 | TO_REG, 97 | } mem_t; 98 | 99 | /* Address to memory */ 100 | typedef struct MEM_OUT { 101 | mem_t type; 102 | int addr; 103 | int value; 104 | int valid; 105 | } MEM_OUT; 106 | 107 | 108 | /* Decode Instruction */ 109 | typedef struct DECODE { 110 | OPCODES opcode; // OpCode 111 | int operand; // everything except OpCode 112 | int bits; // Part a Operand (bits) 113 | int addr; // Part b Operand (addr) 114 | char info[MAXSIZ]; // instruction info 115 | exec_t type; // Instruction type (multi operand or mono) 116 | } DECODE; 117 | 118 | 119 | /* Special Function Registers */ 120 | typedef enum SFR { 121 | INDF_REGISTER, 122 | TMR0_REGISTER, 123 | PCL_REGISTER, 124 | STATUS_REGISTER, 125 | FSR_REGISTER, 126 | OSCCAL_REGISTER, 127 | GPIO_REGISTER, 128 | CMCON0_REGISTER, 129 | TRISGPIO_REGISTER, 130 | OPTION_REGISTER 131 | } SFR; 132 | 133 | -------------------------------------------------------------------------------- /src/components/mem.c: -------------------------------------------------------------------------------- 1 | #include "../types.h" 2 | #include 3 | 4 | static int WReg = 0; 5 | static int CARRY_VAL = 0; 6 | static int gpio_temp = 0; 7 | 8 | 9 | static uint8_t _stack[MAX_STACK]; 10 | static int INPUT_EN = 0; 11 | 12 | 13 | static int CPU_COUNTER = 0; 14 | int get_cpu_coutner(){ return CPU_COUNTER; } 15 | void increase_cc(void){ CPU_COUNTER++; } 16 | 17 | 18 | MEM_OUT get_mem(int addr){ 19 | MEM_OUT mem; 20 | mem.valid = 1; 21 | 22 | // if(addr <= (REGSIZ - 1)){ 23 | if(addr <= (REGSIZ - 1)){ 24 | mem.type = TO_REG; 25 | mem.addr = addr; 26 | mem.value = REGISTERS[mem.addr]; 27 | 28 | // } else if (addr >= REGSIZ && addr <= (RAMSIZ - 1)){ 29 | } else if (addr <= (RAMSIZ + REGSIZ - 1) && addr > REGSIZ - 1){ 30 | mem.type = TO_RAM; 31 | mem.addr = addr - REGSIZ; 32 | mem.value = RAM[mem.addr]; 33 | } else { 34 | mem.valid = 0; 35 | } 36 | 37 | return mem; 38 | } 39 | 40 | 41 | int set_mem(MEM_OUT mem, int val){ 42 | if(mem.valid == 0){ 43 | return 1; 44 | } 45 | if(mem.type == TO_REG){ 46 | REGISTERS[mem.addr] = val; 47 | return 0; 48 | } else if (mem.type == TO_RAM){ 49 | RAM[mem.addr] = val; 50 | return 0; 51 | } 52 | return 1; 53 | } 54 | 55 | 56 | /* set W register */ 57 | void set_w_reg(int val){ WReg = val; } 58 | 59 | /* get W register */ 60 | int get_w_reg(){ return WReg; } 61 | 62 | 63 | 64 | 65 | /* Rotate with Carry */ 66 | void set_carry(int val){ CARRY_VAL = val; } 67 | int get_carry(){ return CARRY_VAL; } 68 | 69 | 70 | int rotate_left_carry(uint8_t value){ 71 | set_carry((value & 0x80) >> 7); 72 | return (value << 1) | (get_carry() & 0x01); 73 | } 74 | 75 | int rotate_right_carry(uint8_t value) { 76 | set_carry(value & 1); 77 | return (value >> 1) | (get_carry() << 7); 78 | } 79 | 80 | 81 | 82 | /* STACK */ 83 | void push_stack(uint8_t value){ 84 | for(int i = MAX_STACK - 1; i > 0; --i){ 85 | _stack[i] = _stack[i - 1]; 86 | } 87 | _stack[0] = value; 88 | } 89 | 90 | 91 | uint8_t pop_stack(void){ 92 | uint8_t popped = _stack[0]; 93 | for(int i = MAX_STACK - 1; i > 0; --i){ 94 | _stack[i - 1] = _stack[i]; 95 | } 96 | return popped; 97 | } 98 | 99 | 100 | int get_stack_pos(int idx){ return _stack[idx]; } 101 | 102 | 103 | /* SFR (SPECIAL FUNCTION REGISTERS) */ 104 | 105 | /* Set given bit of SRF to 1 */ 106 | void set_sfr_bit(SFR sfr, int bitnum){ 107 | int regv = REGISTERS[sfr]; 108 | bitnum %= 8; 109 | regv |= (1 << bitnum); 110 | REGISTERS[sfr] = regv; 111 | } 112 | 113 | /* Set given bit of SRF to 0 */ 114 | void clear_sfr_bit(SFR sfr, int bitnum){ 115 | int regv = REGISTERS[sfr]; 116 | bitnum %= 8; 117 | regv &= ~(1 << bitnum); 118 | REGISTERS[sfr] = regv; 119 | } 120 | 121 | /* set srf value */ 122 | void set_sfr(SFR sfr, int literal){ 123 | if(literal > 255){ literal = 0; } 124 | REGISTERS[sfr] = literal; 125 | } 126 | 127 | /* get srf value */ 128 | int get_sfr(SFR sfr){ return REGISTERS[sfr]; } 129 | 130 | -------------------------------------------------------------------------------- /src/term.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include 3 | #include 4 | 5 | #ifdef linux 6 | #include 7 | #include 8 | #include 9 | #else 10 | #include 11 | #include 12 | #endif 13 | 14 | 15 | void plat_cls(void){ 16 | #ifdef linux 17 | system("clear"); 18 | #elif _WIN32 19 | system("cls"); 20 | #endif 21 | } 22 | 23 | 24 | // show cursor 25 | void enable_cursor(void){ 26 | printf("\033[?25h"); 27 | fflush(NULL); 28 | } 29 | 30 | // hide cursor 31 | void disable_cursor(void){ 32 | // setvbuf(stdout, NULL, _IONBF, 0); // Disable buffering for stdout 33 | printf("\033[?25l"); 34 | fflush(NULL); 35 | } 36 | 37 | 38 | #ifdef linux 39 | static struct termios old, current; 40 | #endif 41 | 42 | // Disable Echo 43 | void init_term(){ // terminal i/o settings 44 | #ifdef linux 45 | tcgetattr(0, &old); // grab old terminal i/o settings 46 | current = old; // make new settings same as old settings 47 | current.c_lflag &= ~ICANON; // disable buffered i/o 48 | current.c_lflag &= ~ECHO; // set no echo mode 49 | tcsetattr(0, TCSANOW, ¤t); // use these new terminal i/o settings now 50 | #endif 51 | } 52 | 53 | // Enable Echo 54 | void nrm_term(){ 55 | #ifdef linux 56 | tcgetattr(0, &old); 57 | current = old; 58 | current.c_lflag |= ICANON; 59 | current.c_lflag |= ECHO; 60 | tcsetattr(0, TCSANOW, ¤t); 61 | #endif 62 | } 63 | 64 | // Get a char without echo 65 | char getl(void){ 66 | char ch; 67 | #ifdef linux 68 | init_term(); 69 | ch = getchar(); 70 | nrm_term(); 71 | #elif _WIN32 72 | ch = _getch(); 73 | #endif 74 | 75 | return ch; 76 | } 77 | 78 | 79 | /* clear terminal */ 80 | void cls_term(void){ 81 | printf("\033[H"); // set position of cursor to [0, 0] 82 | // #ifdef linux 83 | // printf("\033[H"); 84 | // #else 85 | // printf("\033[H"); 86 | // // printf("\033[1;1H\033[2J"); 87 | // #endif 88 | } 89 | 90 | 91 | static int tmp_y_siz = 0; 92 | static int tmp_x_siz = 0; 93 | 94 | /* ter_size: get terminal size [x, y] */ 95 | TERSIZ term_size(void){ 96 | TERSIZ siz = {0, 0}; 97 | #ifdef linux 98 | struct winsize w; 99 | ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); 100 | siz.x = w.ws_col; 101 | siz.y = w.ws_row; 102 | #elif _WIN32 103 | CONSOLE_SCREEN_BUFFER_INFO csbi; 104 | int columns, rows; 105 | GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); 106 | siz.x = csbi.srWindow.Right - csbi.srWindow.Left + 1; 107 | siz.y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; 108 | #endif 109 | 110 | // Clear terminal if user changes the window 111 | if(siz.x != tmp_x_siz || siz.y != tmp_y_siz){ plat_cls(); } 112 | tmp_y_siz = siz.y; 113 | tmp_x_siz = siz.x; 114 | 115 | return siz; 116 | } 117 | 118 | /* turn the echo on and make cursor visible */ 119 | void normal_terminal(void){ 120 | plat_cls(); 121 | enable_cursor(); 122 | nrm_term(); 123 | setvbuf(stdout, NULL, _IONBF, 0); // Disable buffering for stdout 124 | fflush(NULL); 125 | } 126 | 127 | 128 | /* Hide terminal cursor and no echo */ 129 | void hidden_terminal(void){ 130 | disable_cursor(); // Hide cursor block/line from the terminal 131 | init_term(); // No ouput from cursor 132 | fflush(NULL); 133 | } 134 | 135 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "src/components/mem.h" 2 | #include "src/components/rom.h" 3 | #include "src/components/ram.h" 4 | #include "src/components/reg.h" 5 | #include "src/components/decode.h" 6 | #include "src/components/exec.h" 7 | #include "src/emulator.h" 8 | #include "src/utils.h" 9 | #include "src/display.h" 10 | #include "src/types.h" 11 | #include "src/term.h" 12 | #include 13 | #include 14 | 15 | 16 | int main(int argc, char *argv[]){ 17 | // hide cursor and no echo for terminal 18 | hidden_terminal(); 19 | // Listen to (END OF THE PROGRAM) & take action & clear screen (one time only) 20 | init_end_sig(); 21 | 22 | int c = ' '; 23 | int ppc = 0; 24 | int bypass = 0; 25 | 26 | int key_input = 0; 27 | int input_value = 0; 28 | 29 | GFLAGS gflags; 30 | FETCH fetch; 31 | DECODE dcd; 32 | EXEC exec; 33 | 34 | 35 | update_gflags(&gflags, argc, argv); // Update flags 36 | 37 | if(gflags.pload == STATE_LOAD){ 38 | int tmp; 39 | tmp = load_cpu_state(&gflags); 40 | if(tmp < 0){ 41 | lprt(1, "Invalid cpu state file!"); 42 | } else { 43 | set_pc(tmp); 44 | } 45 | } 46 | 47 | rom_init(gflags.program); 48 | 49 | if(gflags.pload == PROGRAM_LOAD){ 50 | reg_init(); 51 | ram_init(); 52 | } 53 | 54 | int steps = 0; 55 | 56 | do { 57 | 58 | if(c == 's'){ 59 | dprt(term_size().x - 10, 2, " [00FF00][bl]Saved!"); 60 | save_cpu_state(gflags, ppc); 61 | } 62 | 63 | if(c == 'r' && gflags.is_sleep){ 64 | reset_cpu(0); 65 | // emulate_cpu(&gflags, input_value); // ? 66 | } else if(c != ' '){ 67 | continue; 68 | } 69 | 70 | 71 | if(gflags.stepping == 0){ 72 | 73 | if(getc_keep() == ' '){ 74 | gflags.is_pause = ~gflags.is_pause; 75 | 76 | // clear while paused (*) 77 | // if(gflags.is_pause == 0){ system("clear"); } 78 | } 79 | 80 | if(getc_keep() == 'r' && gflags.is_sleep){ 81 | reset_cpu(1); 82 | } 83 | 84 | 85 | if(getc_keep() == 's'){ 86 | dprt(term_size().x - 10, 2, " [00FF00]Saved!"); 87 | save_cpu_state(gflags, ppc); 88 | } 89 | 90 | if(gflags.is_pause != 0){ 91 | cpu_sleep(gflags.frequency); 92 | dprt(term_size().x - 10, 2, "[26aF9a][bl]❚❚ Paused"); 93 | fflush(NULL); 94 | continue; 95 | } else { 96 | // clear "paused" 97 | // dprt(term_size().x - 10, 2, "[26aF9a][bl] "); 98 | printfxy(" ", term_size().x - 10, 2); 99 | } 100 | } 101 | 102 | // Capture data for each round 103 | fetch = rom_fetch(); 104 | dcd = decode_inst(fetch.data); 105 | exec = soft_execute(dcd); 106 | 107 | // Display CPU 108 | emulate_cpu(&gflags, input_value); 109 | 110 | if((gflags.is_sleep = exec.sleep) == 0){ 111 | ppc = get_pc(); 112 | 113 | // Update PC 114 | if(exec.upc == get_pc()){ 115 | increment_pc(); 116 | } else { 117 | set_pc(exec.upc); 118 | } 119 | 120 | bypass = execute(dcd); // Update Reg & Ram 121 | 122 | if(INPUT_EN){ 123 | if((key_input = get_key()) >= 0){ 124 | // set_sfr(®, GPIO_REGISTER, ~(key_input | get_w_reg())); 125 | set_sfr(GPIO_REGISTER, (key_input & ~get_w_reg())); 126 | input_value = (key_input & ~get_w_reg()); 127 | // (i & ~w) 128 | // c = ~(a & b); 129 | } 130 | } 131 | 132 | // Update Register 133 | clear_sfr_bit(STATUS_REGISTER, 4); 134 | set_sfr_bit(STATUS_REGISTER, 6); 135 | if(gpio_temp != get_sfr(GPIO_REGISTER)){ 136 | gpio_temp = get_sfr(GPIO_REGISTER); 137 | set_sfr_bit(STATUS_REGISTER, 7); 138 | } 139 | 140 | // dprt(term_size().x - 6, 2, " "); // clear sleep text 141 | printfxy(" ", term_size().x - 6, 2); 142 | } else { 143 | dprt(term_size().x - 6, 2, "[26aF9a][bl]Sleep"); 144 | set_sfr_bit(STATUS_REGISTER, 4); 145 | } 146 | 147 | 148 | if(steps == gflags.ci_mode && gflags.ci_mode != 0){ 149 | dprt(term_size().x - 8, 2, "[00FF00][i]Reached!"); 150 | save_cpu_state(gflags, ppc); 151 | } else { 152 | dprt(term_size().x - 8, 2, " "); 153 | } 154 | 155 | // Interruption 156 | if(gflags.stepping == 0){ 157 | cpu_sleep(gflags.frequency); 158 | } 159 | 160 | 161 | if(bypass){ 162 | bypass = 0; 163 | set_pc(get_pc() + 1); 164 | continue; 165 | } 166 | 167 | steps++; 168 | } while(gflags.stepping ? (c = getl()) != 'q' : 1); 169 | 170 | 171 | // turn the echo on and make cursor visible 172 | normal_terminal(); 173 | return 0; 174 | } 175 | 176 | -------------------------------------------------------------------------------- /src/emulator.c: -------------------------------------------------------------------------------- 1 | #include "components/mem.h" 2 | #include "components/rom.h" 3 | #include "components/exec.h" 4 | #include "components/reg.h" 5 | #include "rules.h" 6 | #include "term.h" 7 | #include "types.h" 8 | #include "utils.h" 9 | #include "display.h" 10 | #include 11 | #include 12 | 13 | 14 | #define MAX_TERM_SIZE 1024 15 | 16 | static int cw = 0; 17 | static int ch = 0; 18 | static int cflush = 0; 19 | static char cbuff[MAX_TERM_SIZE][MALL]; 20 | 21 | 22 | /* Make size for console */ 23 | void make_size(int l_len){ 24 | char tbuff[MAX_TERM_SIZE][MALL]; 25 | for(int i = 1; i < l_len; ++i){ 26 | strcpy(tbuff[i - 1], cbuff[i]); 27 | } 28 | 29 | memset(cbuff, 0, sizeof(cbuff)); 30 | 31 | for(int i = 0; i < l_len - 1; ++i){ 32 | strcpy(cbuff[i], tbuff[i]); 33 | } 34 | } 35 | 36 | 37 | void update_console(int x, int y, int max){ 38 | 39 | int flush = edfb(REGISTERS[6], 8, 8); 40 | int cval = edfb(REGISTERS[6], 1, 7); 41 | 42 | if(flush && cflush == 0){ 43 | if(cval == '\n'){ 44 | ch++; 45 | cw = 0; 46 | if(ch == max){ 47 | make_size(max); 48 | ch = max - 1; 49 | } 50 | } else{ 51 | if(cval != '\0'){ 52 | cbuff[ch][cw++] = cval; 53 | } 54 | } 55 | cflush = 1; 56 | } else { 57 | cflush = 0; 58 | } 59 | 60 | // Display 61 | for(int i = 0; i < max; ++i){ 62 | char goto_buff[100]; 63 | sgotoxy(x, y + i, goto_buff); 64 | printf("%s%-*s", goto_buff, max, cbuff[i]); 65 | } 66 | } 67 | 68 | 69 | /* emulate_cpu: display CPU's data as a TUI */ 70 | void emulate_cpu(GFLAGS *flags, int ukey){ 71 | if(flags->is_sleep == 1){ 72 | return; 73 | } 74 | TERSIZ ts = term_size(); ts.y += 1; 75 | cls_term(); 76 | 77 | // Main frame && header 78 | draw_box(1, 1, ts.x - 1, ts.y, "8-BIT CPU"); 79 | int hx = (ts.x / 2); // Half of x 80 | 81 | // ROM Pannel 82 | draw_box(2, 3, hx, ts.y - 3, "ROM"); 83 | // Registers Pannel 84 | draw_box(hx + 3, 3, 27, 13, "Registers"); 85 | // Info Pannel 86 | draw_box(hx + 31, 3, ts.x - (hx + 32), 13, "INFO"); 87 | // RAM Pannel 88 | draw_box(hx + 3, 15, 23, ts.y - 15, "RAM"); 89 | // Console Pannel 90 | draw_box(hx + 27, 15, ts.x - (hx + 28), ts.y - 15, "Console"); 91 | 92 | 93 | // get binary led 94 | char bin_led[100]; 95 | binary_led(REGISTERS[6], ukey, bin_led, 100); 96 | 97 | char gpio_buff[MAXSIZ]; 98 | dtoh(REGISTERS[6], 2, gpio_buff); 99 | 100 | 101 | char stack_0[100]; 102 | char stack_1[100]; 103 | 104 | dtoh(get_stack_pos(0), 2, stack_0); 105 | dtoh(get_stack_pos(1), 2, stack_1); 106 | 107 | // Wreg binary 108 | char wreg[9]; 109 | i2b(get_w_reg(), wreg, 8); 110 | 111 | // Status Line 112 | dprt(2, 2, 113 | " [55B6C2]PC[]: [ed400e]%-4d[] [55B6C2]GPIO[]: [ed400e]%s[] %s[{}] [55B6C2]W-Reg[]: [ed400e]0b%s [55B6C2]S-1[]: [ed400e]%s [55B6C2]S-2[]: [ed400e]%s [55B6C2]Carry[]: %s", 114 | get_pc(), 115 | gpio_buff, 116 | bin_led, 117 | wreg, 118 | stack_0, 119 | stack_1, 120 | get_carry() ? "[00FF00]⬤" : "[909090]⬤" 121 | ); 122 | 123 | 124 | // ROM 125 | int max_h = (ts.y) - 6; 126 | int linen = 0; 127 | 128 | if(get_pc() > (max_h / 2)){ 129 | linen = (get_pc() % ROMSIZ) - (max_h / 2); 130 | if(linen + (max_h / 2) + (max_h / 2) + 2 > ROMSIZ){ 131 | linen = ROMSIZ - max_h; 132 | } 133 | } 134 | 135 | // ROM list view 136 | for(int i = 0; i < max_h; ++i){ 137 | 138 | char einfo[MAXSIZ]; 139 | exec_info(einfo, ROM[linen + i]); 140 | 141 | char hex_buff[MAXSIZ]; 142 | dtoh(linen + i, 4, hex_buff); 143 | 144 | if((linen + i) == get_pc()){ 145 | fixed_dprt(4, 4 + i, 13, "%s%-4s [{}][u]%s", (linen + i) == 0 ? "[F44336]" : "[fcd200]", hex_buff, einfo); 146 | } else { 147 | fixed_dprt(4, 4 + i, 13, "%s%-4s [{}]%s", (linen + i) == 0 ? "[D32F2F]" : "[808080]", hex_buff, einfo); 148 | } 149 | } 150 | 151 | 152 | char addr_buff[MAXSIZ]; 153 | char ram_buff[MAXSIZ]; 154 | char bin_buff[MAXSIZ]; 155 | 156 | // REG 157 | for(int i = 0; i < REGSIZ; ++i){ 158 | dtoh(REGISTERS[i], 2, addr_buff); 159 | dtob(REGISTERS[i], 8, bin_buff), 160 | 161 | dprt(hx + 5, 4 + i, 162 | "%-16s [E06B74]%s [98C379]%s", 163 | get_reg_name(i), 164 | bin_buff, 165 | addr_buff); 166 | } 167 | 168 | 169 | int ram_ps = ts.y - 18; // ram pannel size 170 | 171 | // RAM 172 | for(int i = 0; i < (ram_ps >= 16 ? 16 : ram_ps); ++i){ 173 | dtoh(i + REGSIZ, 2, addr_buff); 174 | dtoh(RAM[i], 2, ram_buff); 175 | dtob(RAM[i], 8, bin_buff), 176 | 177 | dprt(hx + 5, 16 + i, 178 | "[ABB2BF]%-4s [E06B74]%s [98C379]%s", 179 | addr_buff, 180 | bin_buff, 181 | ram_buff); 182 | } 183 | 184 | // Info 185 | dprt(hx + 33, 4, "[2196F3]Mode[FFFFFF]: [8bc34a]%s", flags->stepping ? "Stepping" : "Auto"); 186 | if(flags->stepping){ 187 | dprt(hx + 33, 5, "[2196F3]Frequency[FFFFFF]: [FFDFAF]Keyboard Key"); 188 | } else { 189 | char frq_buff[30]; 190 | frequency_str(1000000 / flags->frequency, frq_buff); 191 | dprt(hx + 33, 5, "[2196F3]Frequency[FFFFFF]: [FFDFAF]%s", frq_buff); 192 | // dprt(hx + 33, 5, "[2196F3]Frequency[FFFFFF]: [FFDFAF]%d", 1000000 / flags->frequency); 193 | } 194 | 195 | // Show program path 196 | dprt(hx + 33, 7, "[2196F3]Program[FFFFFF]:"); 197 | dprt(hx + 33, 8, "[98C379]\"%s\"", flags->program); 198 | 199 | // Update console (from register 6 (GPIO)) 200 | if(flags->console_en){ 201 | update_console(hx + 29, 16, ts.y - 18); 202 | } else { 203 | dprt(hx + 29, 16, "[B0B0B0]Use [D84315]'-c'[B0B0B0] to enable console"); 204 | } 205 | 206 | fflush(NULL); // Flush the output (ALL) 207 | } 208 | 209 | -------------------------------------------------------------------------------- /src/display.c: -------------------------------------------------------------------------------- 1 | #include "strfy.h" 2 | #include "rules.h" 3 | #include "term.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | void update_color(char format[], int clean, char src[]) { 11 | strcpy(src, format); 12 | 13 | char tmp[MAXSIZ]; // Allocate temporary buffer 14 | int dst_idx = 0; // Index for tmp (destination buffer) 15 | int src_idx = 0; // Index for src (source buffer) 16 | 17 | while (src[src_idx] != '\0') { 18 | if (src[src_idx] == '[' || src[src_idx] == '{') { 19 | // Check if it's a color code 20 | char color_code[7]; 21 | for (int i = 0; i < 6; i++) { 22 | color_code[i] = src[src_idx + 1 + i]; // Extract hex code 23 | } 24 | color_code[6] = '\0'; 25 | 26 | // Convert hex color to RGB 27 | int r, g, b; 28 | if (sscanf(color_code, "%2x%2x%2x", &r, &g, &b) == 3) { 29 | if (src[src_idx] == '[') { 30 | dst_idx += sprintf(&tmp[dst_idx], "\033[38;2;%d;%d;%dm", r, g, b); // fg 31 | } else if (src[src_idx] == '{') { 32 | dst_idx += sprintf(&tmp[dst_idx], "\033[48;2;%d;%d;%dm", r, g, b); // bg 33 | } 34 | src_idx += 8; // Don't copy the color code (skip "[FFFFFF]" or "{FFFFFF}") 35 | } else { 36 | tmp[dst_idx++] = src[src_idx++]; // Just copy if color code is invalid 37 | } 38 | } else { 39 | tmp[dst_idx++] = src[src_idx++]; // Copy other characters 40 | } 41 | } 42 | 43 | tmp[dst_idx] = '\0'; // Null-terminate the result 44 | 45 | // Copy the modified string back to the original buffer 46 | strncpy(src, tmp, dst_idx); 47 | src[dst_idx] = '\0'; 48 | 49 | // Insert reset codes at the end 50 | if(clean == 1) { 51 | strcat(src, "\033[0m\033[49m"); 52 | } 53 | 54 | // Perform additional replacements 55 | str_replace(src, "[{}]", "\033[0m\033[49m"); 56 | str_replace(src, "[]", "\033[0m"); 57 | str_replace(src, "{}", "\033[49m"); 58 | str_replace(src, "[u]", "\033[4m"); 59 | str_replace(src, "[bl]", "\x1b[5m"); 60 | str_replace(src, "[b]", "\x1b[1m"); 61 | str_replace(src, "[i]", "\x1b[3m"); 62 | } 63 | 64 | /* Update colors and return in (char *) for foreground: [FFFFFF] & for background: {FFFFFF} */ 65 | /* 66 | void update_color(char *format, int clean, char src[]){ 67 | strcpy(src, format); 68 | 69 | char tmp[MAXSIZ]; // Allocate temporary buffer 70 | char *dst = tmp; 71 | char *ptr = src; 72 | 73 | 74 | while (*ptr) { 75 | if (*ptr == '[' || *ptr == '{') { 76 | // Check if it's a color code 77 | char color_code[7]; 78 | strncpy(color_code, ptr + 1, 6); 79 | color_code[6] = '\0'; 80 | 81 | // Convert hex color to RGB 82 | int r, g, b; 83 | if (sscanf(color_code, "%2x%2x%2x", (unsigned int *)&r, (unsigned int *)&g, (unsigned int *)&b) == 3) { 84 | if (*ptr == '[') { 85 | dst += sprintf(dst, "\033[38;2;%d;%d;%dm", r, g, b); // fg 86 | } else if (*ptr == '{') { 87 | dst += sprintf(dst, "\033[48;2;%d;%d;%dm", r, g, b); // bg 88 | } 89 | ptr += 8; // Don't copy the color code 90 | } else { 91 | *dst++ = *ptr++; // Just copy if color code is invalid 92 | } 93 | } else { 94 | *dst++ = *ptr++; // Copy other characters 95 | } 96 | } 97 | 98 | *dst = '\0'; 99 | 100 | // Copy the modified string back to the original buffer 101 | strncpy(src, tmp, dst - tmp); 102 | src[dst - tmp] = '\0'; 103 | // free(tmp); 104 | 105 | // Insert reset codes at the end 106 | if(clean == 1){ 107 | strcat(src, "\033[0m\033[49m"); 108 | } 109 | 110 | str_replace(src, "[{}]", "\033[0m\033[49m"); 111 | str_replace(src, "[]", "\033[0m"); 112 | str_replace(src, "{}", "\033[49m"); 113 | str_replace(src, "[u]", "\033[4m"); 114 | str_replace(src, "[bl]", "\x1b[5m"); 115 | str_replace(src, "[b]", "\x1b[1m"); 116 | str_replace(src, "[i]", "\x1b[3m"); 117 | } 118 | */ 119 | 120 | 121 | /* goto given x, y coord (set cursor to [x, y])*/ 122 | void gotoxy(int x, int y){ 123 | printf("\033[%d;%df", y, x); 124 | } 125 | 126 | void sgotoxy(int x, int y, char src[]){ 127 | sprintf(src, "\033[%d;%df", y, x); 128 | } 129 | 130 | /* print given char * in given x, y coord */ 131 | void printfxy(char *s, int x, int y){ 132 | gotoxy(x, y); 133 | printf("%s", s); 134 | } 135 | 136 | 137 | // Decorative printf (pring & exit the program) 138 | void lprt(int ecode, char *frmt, ...){ 139 | normal_terminal(); 140 | char buff[MALL]; 141 | va_list args; 142 | va_start(args, frmt); 143 | vsprintf(buff, frmt, args); 144 | char colored[MAXSIZ]; 145 | update_color(buff, 1, colored); 146 | printf("%s\n", colored); 147 | va_end(args); 148 | exit(ecode); 149 | } 150 | 151 | 152 | /* dprt: Decorative Print */ 153 | void dprt(int x, int y, char *frmt, ...) { 154 | char buff[MALL]; 155 | va_list args; 156 | va_start(args, frmt); 157 | vsprintf(buff, frmt, args); 158 | gotoxy(x, y); 159 | char colored[MAXSIZ]; 160 | update_color(buff, 1, colored); 161 | printf("%s", colored); 162 | fflush(NULL); 163 | va_end(args); 164 | } 165 | 166 | 167 | /* fixed_dprt: Decorative Print with right margin (width) */ 168 | void fixed_dprt(int x, int y, int width, char *frmt, ...) { 169 | char buff[MALL]; 170 | va_list args; 171 | va_start(args, frmt); 172 | vsprintf(buff, frmt, args); 173 | gotoxy(x, y); 174 | va_end(args); 175 | 176 | char output[MAXSIZ]; 177 | char colored[MAXSIZ]; 178 | update_color(buff, 1, colored); 179 | sprintf(output, "%s", colored); 180 | int len = (int)strlen(output); 181 | printf("%-*s\n", len + width, output); 182 | } 183 | 184 | 185 | // Line type 186 | typedef enum LINE_TYPE { 187 | HORIZONTAL, 188 | VERTICAL, 189 | HORIZONTAL_LIGHT, 190 | VERTICAL_LIGHT, 191 | } LINE_TYPE; 192 | 193 | 194 | /* Draw a line */ 195 | void draw_line(int x, int y, int size, LINE_TYPE lt, char *a, char *b){ 196 | int i; 197 | for(i = 0 ; i < size; ++i){ 198 | if(i == 0){ 199 | printfxy(a, x, y); 200 | } else if (i == size - 1){ 201 | printfxy(b, x, y); 202 | } else { 203 | if(lt == HORIZONTAL || lt == HORIZONTAL_LIGHT){ 204 | x++; 205 | printfxy(lt == HORIZONTAL_LIGHT ? "┄": "─", x, y); 206 | } else { 207 | y++; 208 | printfxy(lt == VERTICAL_LIGHT ? "┆": "│", x, y); 209 | } 210 | } 211 | } 212 | } 213 | 214 | 215 | /* draw_box: draw a box && use given title if it's not */ 216 | void draw_box(int x, int y, int widht, int height, char *title){ 217 | char colored[MAXSIZ]; 218 | update_color("[808080]", 0, colored); 219 | int empty_title = strcmp(title, ""); 220 | printf("%s", colored); 221 | draw_line(x, y, height, VERTICAL, "╭", "╰"); // Left 222 | draw_line(x + widht, y, height, VERTICAL, "╮", "╯"); // Right 223 | 224 | if(empty_title == 0){ 225 | draw_line(x + 1, y, widht, HORIZONTAL, "─", "─"); // Top 226 | } else { 227 | draw_line(x + 1, y, 1, HORIZONTAL, "─", "─"); // Top 228 | draw_line(x + (int)strlen(title) + 4, y, widht - (int)strlen(title) - 3, HORIZONTAL, "─", "─"); // Top 229 | } 230 | 231 | draw_line(x + 1, y + height - 2, widht, HORIZONTAL, "─", "─"); // Bottom 232 | if(empty_title != 0){ 233 | 234 | if(strcmp(title, "8-BIT CPU") == 0){ 235 | update_color("[98C379]", 0, colored); 236 | } else { 237 | update_color("[F0F0F0]", 0, colored); 238 | } 239 | printf("%s", colored); 240 | dprt(x + 2, y, " %s ", title); 241 | } 242 | } 243 | 244 | -------------------------------------------------------------------------------- /src/components/decode.c: -------------------------------------------------------------------------------- 1 | #include "../utils.h" 2 | #include "../types.h" 3 | 4 | #ifdef _MSC_VER 5 | #pragma warning(push) 6 | #pragma warning(disable : 4996) 7 | #endif 8 | 9 | /* Return a struct that contains the given instruction's information */ 10 | DECODE decode_inst(int inst){ 11 | DECODE dcd; 12 | 13 | dcd.operand = 0; 14 | dcd.bits = 0; 15 | dcd.addr = 0; 16 | 17 | // NOP 18 | if(inst == 0x00){ // 0b000000000000 19 | dcd.opcode = NOP_OP; 20 | dcd.type = FULL; 21 | strcpy(dcd.info, "NOP"); 22 | 23 | // CLRW 24 | } else if(inst == 0x40){ // 0b000001000000 25 | dcd.opcode = CLRW_OP; 26 | dcd.type = FULL; 27 | strcpy(dcd.info, "CLRW"); 28 | 29 | // SLEEP 30 | } else if(inst == 0x03){ // 0b000000000011 31 | dcd.opcode = SLEEP_OP; 32 | dcd.type = FULL; 33 | strcpy(dcd.info, "SLEEP"); 34 | 35 | // BSF 36 | } else if(edfb(inst, 9, 12) == 0x05){ // 0b0101 37 | dcd.opcode = BSF_OP; 38 | dcd.operand = edfb(inst, 1, 8); 39 | dcd.type = FOUR_THREE_FIVE; 40 | strcpy(dcd.info, "BSF"); 41 | dcd.bits = edfb(inst, 6, 8); 42 | dcd.addr = edfb(inst, 1, 5); 43 | 44 | // BCF 45 | } else if(edfb(inst, 9, 12) == 0x04){ // 0b0100 46 | dcd.opcode = BCF_OP; 47 | dcd.operand = edfb(inst, 1, 8); 48 | dcd.type = FOUR_THREE_FIVE; 49 | strcpy(dcd.info, "BCF"); 50 | dcd.bits = edfb(inst, 6, 8); 51 | dcd.addr = edfb(inst, 1, 5); 52 | 53 | // MOVLW 54 | } else if(edfb(inst, 9, 12) == 0x0C){ // 0b1100 55 | dcd.opcode = MOVLW_OP; 56 | dcd.operand = edfb(inst, 1, 8); 57 | dcd.type = FOUR_EIGHT; 58 | strcpy(dcd.info, "MOVLW"); 59 | dcd.bits = edfb(inst, 1, 8); 60 | 61 | // MOVWF 62 | } else if(edfb(inst, 6, 12) == 0x01){ // 0b0000001 63 | dcd.opcode = MOVWF_OP; 64 | dcd.operand = edfb(inst, 1, 5); 65 | dcd.type = SEVEN_FIVE; 66 | strcpy(dcd.info, "MOVWF"); 67 | dcd.addr = edfb(inst, 1, 5); 68 | 69 | // CLRF 70 | } else if(edfb(inst, 6, 12) == 0x03){ // 0b0000011 71 | dcd.opcode = CLRF_OP; 72 | dcd.operand = edfb(inst, 1, 5); 73 | dcd.type = SEVEN_FIVE; 74 | strcpy(dcd.info, "CLRF"); 75 | dcd.addr = edfb(inst, 1, 5); 76 | 77 | // DECF 78 | } else if(edfb(inst, 7, 12) == 0x03){ // 0b000011 79 | dcd.opcode = DECF_OP; 80 | dcd.operand = edfb(inst, 1, 6); 81 | dcd.type = SIX_ONE_FIVE; 82 | strcpy(dcd.info, "DECF"); 83 | dcd.addr = edfb(inst, 1, 5); 84 | dcd.bits = edfb(inst, 6, 6); 85 | 86 | // DECFSZ 87 | } else if(edfb(inst, 7, 12) == 0x0B){ // 0b001011 88 | dcd.opcode = DECFSZ_OP; 89 | dcd.operand = edfb(inst, 1, 6); 90 | dcd.type = SIX_ONE_FIVE; 91 | strcpy(dcd.info, "DECFSZ"); 92 | dcd.addr = edfb(inst, 1, 5); 93 | dcd.bits = edfb(inst, 6, 6); 94 | 95 | // INCF 96 | } else if(edfb(inst, 7, 12) == 0x0A){ // 0b001010 97 | dcd.opcode = INCF_OP; 98 | dcd.operand = edfb(inst, 1, 6); 99 | dcd.type = SIX_ONE_FIVE; 100 | strcpy(dcd.info, "INCF"); 101 | dcd.addr = edfb(inst, 1, 5); 102 | dcd.bits = edfb(inst, 6, 6); 103 | 104 | // INCFSZ 105 | } else if(edfb(inst, 7, 12) == 0x0F){ // 0b001111 106 | dcd.opcode = INCFSZ_OP; 107 | dcd.operand = edfb(inst, 1, 6); 108 | dcd.type = SIX_ONE_FIVE; 109 | strcpy(dcd.info, "INCFSZ"); 110 | dcd.addr = edfb(inst, 1, 5); 111 | dcd.bits = edfb(inst, 6, 6); 112 | 113 | // BTFSS 114 | } else if(edfb(inst, 9, 12) == 0x07){ // 0b0111 115 | dcd.opcode = BTFSS_OP; 116 | dcd.operand = edfb(inst, 1, 8); 117 | dcd.type = FOUR_THREE_FIVE; 118 | strcpy(dcd.info, "BTFSS"); 119 | dcd.addr = edfb(inst, 1, 5); 120 | dcd.bits = edfb(inst, 6, 8); 121 | 122 | // BTFSC 123 | } else if(edfb(inst, 9, 12) == 0x06){ // 0b0110 124 | dcd.opcode = BTFSC_OP; 125 | dcd.operand = edfb(inst, 1, 8); 126 | dcd.type = FOUR_THREE_FIVE; 127 | strcpy(dcd.info, "BTFSC"); 128 | dcd.addr = edfb(inst, 1, 5); 129 | dcd.bits = edfb(inst, 6, 8); 130 | 131 | // GOTO 132 | } else if(edfb(inst, 10, 12) == 5){ // 0b101 133 | dcd.opcode = GOTO_OP; 134 | dcd.operand = edfb(inst, 1, 9); 135 | dcd.type = THREE_NINE; 136 | strcpy(dcd.info, "GOTO"); 137 | dcd.addr = edfb(inst, 1, 9); 138 | 139 | // ADDWF 140 | } else if(edfb(inst, 7, 12) == 0x07){ // 0b000111 141 | dcd.opcode = ADDWF_OP; 142 | dcd.operand = edfb(inst, 1, 6); 143 | dcd.type = SIX_ONE_FIVE; 144 | strcpy(dcd.info, "ADDWF"); 145 | dcd.addr = edfb(inst, 1, 5); 146 | dcd.bits = edfb(inst, 6, 6); 147 | 148 | // ANDWF 149 | } else if(edfb(inst, 7, 12) == 0x05){ // 0b000101 150 | dcd.opcode = ANDWF_OP; 151 | dcd.operand = edfb(inst, 1, 6); 152 | dcd.type = SIX_ONE_FIVE; 153 | strcpy(dcd.info, "ANDWF"); 154 | dcd.addr = edfb(inst, 1, 5); 155 | dcd.bits = edfb(inst, 6, 6); 156 | 157 | // COMF 158 | } else if(edfb(inst, 7, 12) == 0x09){ // 0b001001 159 | dcd.opcode = COMF_OP; 160 | dcd.operand = edfb(inst, 1, 6); 161 | dcd.type = SIX_ONE_FIVE; 162 | strcpy(dcd.info, "COMF"); 163 | dcd.addr = edfb(inst, 1, 5); 164 | dcd.bits = edfb(inst, 6, 6); 165 | 166 | // IORWF 167 | } else if(edfb(inst, 7, 12) == 0x04){ // 0b000100 168 | dcd.opcode = IORWF_OP; 169 | dcd.operand = edfb(inst, 1, 6); 170 | dcd.type = SIX_ONE_FIVE; 171 | strcpy(dcd.info, "IORWF"); 172 | dcd.addr = edfb(inst, 1, 5); 173 | dcd.bits = edfb(inst, 6, 6); 174 | 175 | // MOVF 176 | } else if(edfb(inst, 7, 12) == 0x08){ // 0b001000 177 | dcd.opcode = MOVF_OP; 178 | dcd.operand = edfb(inst, 1, 6); 179 | dcd.type = SIX_ONE_FIVE; 180 | strcpy(dcd.info, "MOVF"); 181 | dcd.addr = edfb(inst, 1, 5); 182 | dcd.bits = edfb(inst, 6, 6); 183 | 184 | // RLF 185 | } else if(edfb(inst, 7, 12) == 0x0D){ // 0b001101 186 | dcd.opcode = RLF_OP; 187 | dcd.operand = edfb(inst, 1, 6); 188 | dcd.type = SIX_ONE_FIVE; 189 | strcpy(dcd.info, "RLF"); 190 | dcd.addr = edfb(inst, 1, 5); 191 | dcd.bits = edfb(inst, 6, 6); 192 | 193 | // RRF 194 | } else if(edfb(inst, 7, 12) == 0x0C){ // 0b001100 195 | dcd.opcode = RRF_OP; 196 | dcd.operand = edfb(inst, 1, 6); 197 | dcd.type = SIX_ONE_FIVE; 198 | strcpy(dcd.info, "RRF"); 199 | dcd.addr = edfb(inst, 1, 5); 200 | dcd.bits = edfb(inst, 6, 6); 201 | 202 | // SUBWF 203 | } else if(edfb(inst, 7, 12) == 0x02){ // 0b000010 204 | dcd.opcode = SUBWF_OP; 205 | dcd.operand = edfb(inst, 1, 6); 206 | dcd.type = SIX_ONE_FIVE; 207 | strcpy(dcd.info, "SUBWF"); 208 | dcd.addr = edfb(inst, 1, 5); 209 | dcd.bits = edfb(inst, 6, 6); 210 | 211 | // SWAPF 212 | } else if(edfb(inst, 7, 12) == 0x0E){ // 0b001110 213 | dcd.opcode = SWAPF_OP; 214 | dcd.operand = edfb(inst, 1, 6); 215 | dcd.type = SIX_ONE_FIVE; 216 | strcpy(dcd.info, "SWAPF"); 217 | dcd.addr = edfb(inst, 1, 5); 218 | dcd.bits = edfb(inst, 6, 6); 219 | 220 | // XORWF 221 | } else if(edfb(inst, 7, 12) == 0x06){ // 0b000110 222 | dcd.opcode = XORWF_OP; 223 | dcd.operand = edfb(inst, 1, 6); 224 | dcd.type = SIX_ONE_FIVE; 225 | strcpy(dcd.info, "XORWF"); 226 | dcd.addr = edfb(inst, 1, 5); 227 | dcd.bits = edfb(inst, 6, 6); 228 | 229 | // ANDLW 230 | } else if(edfb(inst, 9, 12) == 0x0E){ // 0b1110 231 | dcd.opcode = ANDLW_OP; 232 | dcd.operand = edfb(inst, 1, 8); 233 | dcd.type = FOUR_EIGHT; 234 | strcpy(dcd.info, "ANDLW"); 235 | dcd.bits = edfb(inst, 1, 8); 236 | 237 | // CALL 238 | } else if(edfb(inst, 9, 12) == 0x09){ // 0b1001 239 | dcd.opcode = CALL_OP; 240 | dcd.operand = edfb(inst, 1, 8); 241 | dcd.type = FOUR_EIGHT; 242 | strcpy(dcd.info, "CALL"); 243 | dcd.addr = edfb(inst, 1, 8); 244 | 245 | // CLRWDT 246 | } else if(edfb(inst, 1, 12) == 0x04){ // 0b000000000100 247 | dcd.opcode = CLRWDT_OP; 248 | dcd.operand = edfb(inst, 1, 12); 249 | dcd.type = FULL; 250 | strcpy(dcd.info, "CLRWDT"); 251 | 252 | // IORLW 253 | } else if(edfb(inst, 9, 12) == 0x0D){ // 0b1101 254 | dcd.opcode = IORLW_OP; 255 | dcd.operand = edfb(inst, 1, 8); 256 | dcd.type = FOUR_EIGHT; 257 | strcpy(dcd.info, "IORLW"); 258 | dcd.bits = edfb(inst, 1, 8); 259 | 260 | // OPTION 261 | } else if(edfb(inst, 1, 12) == 0x02){ // 0b000000000010 262 | dcd.opcode = OPTION_OP; 263 | dcd.operand = edfb(inst, 1, 12); 264 | dcd.type = FULL; 265 | strcpy(dcd.info, "OPTION"); 266 | 267 | // RETLW 268 | } else if(edfb(inst, 9, 12) == 0x08){ // 0b1000 269 | dcd.opcode = RETLW_OP; 270 | dcd.operand = edfb(inst, 1, 8); 271 | dcd.type = FOUR_EIGHT; 272 | strcpy(dcd.info, "RETLW"); 273 | dcd.bits = edfb(inst, 1, 8); 274 | 275 | // XORLW 276 | } else if(edfb(inst, 9, 12) == 0x0F){ // 0b1111 277 | dcd.opcode = XORLW_OP; 278 | dcd.operand = edfb(inst, 1, 8); 279 | dcd.type = FOUR_EIGHT; 280 | strcpy(dcd.info, "XORLW"); 281 | dcd.bits = edfb(inst, 1, 8); 282 | 283 | // TRIS 284 | } else if(edfb(inst, 1, 12) == 0x06 || edfb(inst, 1, 12) == 0x07){ // 0b000000000110, 0b000000000111 285 | dcd.opcode = TRIS_OP; 286 | dcd.operand = edfb(inst, 1, 3); 287 | dcd.type = FULL; 288 | strcpy(dcd.info, "TRIS"); 289 | dcd.addr = edfb(inst, 1, 3); 290 | 291 | // Undefined 292 | } else { 293 | dcd.opcode = NOP_OP; 294 | } 295 | 296 | return dcd; 297 | } 298 | 299 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "components/mem.h" 7 | #include "rules.h" 8 | #include "types.h" 9 | #include "term.h" 10 | #include "display.h" 11 | 12 | #ifdef linux 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #elif _WIN32 19 | #include 20 | #include 21 | #include 22 | #endif 23 | 24 | /* Decimal TO Binary: convert given decimal to binary (char *) */ 25 | void dtob(int decimal_num, int len, char binary_str[]) { 26 | len = len + 2; 27 | 28 | // Fill with '0' 29 | memset(binary_str, '0', len); 30 | binary_str[len] = '\0'; 31 | 32 | // Add '0b' prefix 33 | binary_str[0] = '0'; 34 | binary_str[1] = 'b'; 35 | 36 | // Convert decimal to binary and fill from the end 37 | int index = len - 1; 38 | while (decimal_num > 0 && index > 1) { 39 | binary_str[index] = (decimal_num % 2) + '0'; 40 | decimal_num /= 2; 41 | index--; 42 | } 43 | } 44 | 45 | 46 | /* dtoh: (Decimal TO Hex) converts given decimal into hex string with size of 'siz' */ 47 | void dtoh(int decimal, int size, char hex[]){ 48 | hex[0] = '0'; 49 | hex[1] = 'x'; 50 | hex[size + 2] = '\0'; // Add null terminator 51 | 52 | // Handle padding 53 | for (int i = size + 1; i >= 2; i--) { 54 | if (decimal == 0 && i > 2) { 55 | hex[i] = '0'; 56 | } else { 57 | int digit = decimal % 16; 58 | if (digit < 10) { 59 | hex[i] = '0' + digit; 60 | } else { 61 | hex[i] = 'A' + digit - 10; 62 | } 63 | decimal /= 16; 64 | } 65 | } 66 | } 67 | 68 | 69 | 70 | /* Function to convert an integer to a binary string */ 71 | void i2b(unsigned int num, char* output, int bit_length) { 72 | for (int i = bit_length - 1; i >= 0; i--) { 73 | output[bit_length - i - 1] = (num & (1 << i)) ? '1' : '0'; 74 | } 75 | output[bit_length] = '\0'; // Null-terminate the string 76 | } 77 | 78 | 79 | /* update_gflags: Update Global Flags */ 80 | void update_gflags(GFLAGS *gflags, int argc, char *argv[]){ 81 | gflags->stepping = 0; 82 | gflags->is_pause = 0; 83 | gflags->frequency = 500000; 84 | gflags->pload = PROGRAM_LOAD; 85 | gflags->is_sleep = 0; 86 | gflags->console_en = 0; 87 | gflags->ci_mode = 0; 88 | 89 | memset(gflags->program, '\0', MALL); 90 | memset(gflags->load, '\0', MALL); 91 | // int ps, fs, ls = 0; // program save 92 | int ps = 0; // program save 93 | int fs = 0; // File save 94 | int ls = 0; // load save 95 | int cc = 0; // capture ci flag 96 | 97 | int i; 98 | for(i = 0; i < argc; ++i){ 99 | 100 | if(ps == 1){ 101 | strcpy(gflags->program, argv[i]); 102 | ps = 0; 103 | continue; 104 | } 105 | 106 | if(ls == 1){ 107 | strcpy(gflags->load, argv[i]); 108 | ls = 0; 109 | gflags->pload = STATE_LOAD; 110 | continue; 111 | } 112 | 113 | if(cc == 1){ 114 | gflags->ci_mode = atoi(argv[i]); 115 | cc = 0; 116 | continue; 117 | } 118 | 119 | if(fs == 1){ 120 | gflags->frequency = atoi(argv[i]); 121 | 122 | if(gflags->frequency == 0){ 123 | gflags->frequency = 500000; 124 | } else if (gflags->frequency > 1000000){ 125 | gflags->frequency = 1; 126 | } else{ 127 | gflags->frequency = 1000000 / gflags->frequency; 128 | } 129 | 130 | fs = 0; 131 | continue; 132 | } 133 | 134 | for(int j = 0; j < (int)strlen(argv[i]); ++j){ 135 | if(argv[i][0] == '-'){ 136 | switch(argv[i][j]){ 137 | case 's': 138 | gflags->stepping = 1; 139 | break; 140 | case 'c': 141 | gflags->console_en = 1; 142 | break; 143 | case 'p': 144 | ps = 1; 145 | break; 146 | case 'f': 147 | fs = 1; 148 | break; 149 | case 'l': 150 | ls = 1; 151 | break; 152 | case 'i': 153 | cc = 1; 154 | default: 155 | break; 156 | } 157 | } 158 | } 159 | 160 | } 161 | 162 | if(ps == 1){ 163 | lprt(1, "After [afaf00]'-p'[ffffff] you should put the path to the supported [f44336].bin[ffffff] file!"); 164 | } 165 | 166 | if(fs == 1){ 167 | lprt(1, "After [afaf00]'-f'[ffffff] you should put clock frequency!"); 168 | } 169 | 170 | if(ls == 1){ 171 | lprt(1, "After [afaf00]'-l'[ffffff] you should put save state file!"); 172 | } 173 | 174 | if(cc == 1){ 175 | lprt(1, "After [afaf00]'-i'[ffffff] you should set CI/CD parameter which is a "); 176 | } 177 | 178 | if(strcmp(gflags->program, "") == 0 && strcmp(gflags->load, "") == 0){ 179 | lprt(1, "By using [afaf00]'-p '[ffffff] specify the path to the program file!"); 180 | } 181 | } 182 | 183 | 184 | 185 | /************************** Signals **************************/ 186 | #ifdef linux 187 | struct sigaction old_action; 188 | #endif 189 | 190 | // Action for end of the program signal 191 | void end_sig_func(int _){ 192 | normal_terminal(); 193 | #ifdef linux 194 | sigaction(SIGINT, &old_action, NULL); 195 | kill(0, SIGINT); 196 | #elif _WIN32 197 | plat_cls(); 198 | exit(0); 199 | #endif 200 | } 201 | 202 | // capture end of program signal 203 | void init_end_sig(){ 204 | #ifdef linux 205 | struct sigaction action; 206 | memset(&action, 0, sizeof(action)); 207 | action.sa_handler = &end_sig_func; 208 | sigaction(SIGINT, &action, &old_action); 209 | system("clear"); // clear screen when start the program 210 | #elif _WIN32 211 | signal(SIGINT, end_sig_func); 212 | // save as utf-8 213 | #pragma execution_character_set_push("utf-8") 214 | SetConsoleOutputCP(65001); 215 | plat_cls(); 216 | #endif 217 | } 218 | 219 | 220 | /* get a char from user with no interruption (no stepping mode)*/ 221 | int getc_keep(void){ 222 | fd_set readfds; 223 | struct timeval tv; 224 | char ch; 225 | 226 | #ifdef linux 227 | // Set stdin to non-blocking mode 228 | int flags = fcntl(STDIN_FILENO, F_GETFL); 229 | fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); 230 | 231 | FD_ZERO(&readfds); 232 | FD_SET(STDIN_FILENO, &readfds); 233 | tv.tv_sec = 0; 234 | tv.tv_usec = 0; // Check immediately 235 | 236 | int ready = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); 237 | if (ready == 1){ 238 | read(STDIN_FILENO, &ch, 1); 239 | return ch; 240 | } 241 | #elif _WIN32 242 | if (_kbhit()) { // Check if a key is pressed 243 | char ch = _getch(); // Read the character (non-blocking) 244 | return ch; 245 | } else { 246 | return -1; 247 | } 248 | #endif 249 | return -1; 250 | } 251 | 252 | 253 | /* save_cpu_state: save current state of CPU to a file */ 254 | void save_cpu_state(GFLAGS gf, int pc){ 255 | FILE *fp; 256 | fp = fopen("./cpu_state.txt", "w+"); 257 | if(fp == NULL) 258 | return; 259 | fprintf(fp, "%s\n", gf.program); 260 | fprintf(fp, "%d\n", gf.frequency); 261 | fprintf(fp, "%d\n", pc); 262 | int i; 263 | for(i = 0; i < REGSIZ; ++i){ 264 | fprintf(fp, "%d\n", REGISTERS[i]); 265 | } 266 | for(i = 0; i < RAMSIZ; ++i){ 267 | fprintf(fp, "%d\n", RAM[i]); 268 | } 269 | fclose(fp); 270 | } 271 | 272 | 273 | /* load_cpu_state: Load state of CPU from a file and return the PC */ 274 | int load_cpu_state(GFLAGS *gf) { 275 | FILE *fp; 276 | 277 | int pc = 0; 278 | 279 | fp = fopen(gf->load, "r"); 280 | if(fp == NULL){ return -1; } 281 | 282 | if (fscanf(fp, "%s\n%d\n%d\n", gf->program, &gf->frequency, &pc) != 3) { 283 | fprintf(stderr, "Error reading file: Invalid format\n"); 284 | fclose(fp); 285 | return -1; 286 | } 287 | 288 | for (int i = 0; i < REGSIZ; ++i) { 289 | if (fscanf(fp, "%d\n", (int *)®ISTERS[i]) != 1){ 290 | fclose(fp); 291 | return -1; 292 | } 293 | } 294 | 295 | for (int i = 0; i < RAMSIZ; ++i) { 296 | if (fscanf(fp, "%d\n", (int *)&RAM[i]) != 1) { 297 | fclose(fp); 298 | return -1; 299 | } 300 | } 301 | 302 | fclose(fp); 303 | return pc; 304 | } 305 | 306 | 307 | /* Extract Decimal From Binary (start and end are included)*/ 308 | int edfb(int decimal, int start, int end) { 309 | start--; 310 | end--; 311 | 312 | // Create a mask to extract the desired bits 313 | int mask = (1 << (end - start + 1)) - 1; 314 | 315 | // Shift the mask to the correct position 316 | mask <<= start; 317 | 318 | // Extract the desired bits 319 | int ebits = (decimal & mask) >> start; 320 | return ebits; 321 | } 322 | 323 | 324 | /* Get keyboard key with no interruption & no echo */ 325 | int get_key(void){ 326 | fd_set readfds; 327 | struct timeval tv; 328 | char ch; 329 | 330 | #ifdef linux 331 | // Set stdin to non-blocking mode 332 | int flags = fcntl(STDIN_FILENO, F_GETFL); 333 | fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); 334 | 335 | FD_ZERO(&readfds); 336 | FD_SET(STDIN_FILENO, &readfds); 337 | tv.tv_sec = 0; 338 | tv.tv_usec = 0; // Check immediately 339 | 340 | int ready = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv); 341 | if (ready == 1) { 342 | read(STDIN_FILENO, &ch, 1); 343 | // return ch; // if you want to return char 344 | 345 | ch = ch - '1'; 346 | if(ch >= 0 && ch <= 7){ 347 | return 0x00 | 1 << (ch); // 0b00000000 | 1 << (c) 348 | } else { 349 | return -1; 350 | } 351 | } 352 | #elif _WIN32 353 | ch = _getch(); 354 | 355 | ch = ch - '1'; 356 | if(ch >= 0 && ch <= 7){ 357 | return 0x00 | 1 << (ch); // 0b00000000 | 1 << (c) 358 | } else { 359 | return -1; 360 | } 361 | 362 | #endif 363 | return -1; 364 | } 365 | 366 | 367 | /* is_input_on: Check that if bit is 1 (GPIO)*/ 368 | int is_input_on(int inpt, int idx){ 369 | idx = idx % 8; 370 | int binary = (inpt & ~get_w_reg()); 371 | return edfb(binary, idx + 1, idx + 1) == 1; 372 | } 373 | 374 | /* is_bit_input: check that given bit is for input (GPIO)*/ 375 | int is_bit_input(int idx){ 376 | idx = idx % 8; 377 | return edfb(get_w_reg(), idx + 1, idx + 1) == 0; 378 | } 379 | 380 | 381 | /* Binary LED (input: red, output: green) for GPIO (0x06) */ 382 | void binary_led(int num, uint8_t keynum, char binary[], int len){ 383 | memset(binary, 0, len); 384 | 385 | for (int i = 7; i >= 0; i--) { 386 | if(INPUT_EN && is_bit_input(i)){ 387 | if(is_input_on(keynum, i)){ 388 | strcat(binary, "[FF0000]❚"); 389 | } else { 390 | strcat(binary, "[909090]❚"); 391 | } 392 | } else { 393 | if (num & (1 << i)) { 394 | strcat(binary, "[00FF00]❚"); 395 | } else { 396 | strcat(binary, "[909090]❚"); 397 | } 398 | } 399 | } 400 | } 401 | 402 | 403 | void cpu_sleep(unsigned int microseconds) { 404 | #ifdef __linux__ 405 | #include 406 | usleep(microseconds); 407 | #elif _WIN32 408 | #include 409 | unsigned int milliseconds = microseconds / 1000; 410 | if (microseconds % 1000 > 0) { 411 | milliseconds += 1; 412 | } 413 | Sleep(milliseconds); 414 | #endif 415 | } 416 | 417 | 418 | 419 | void frequency_str(int frq, char buff[]){ 420 | if (frq >= 1000000) { // Convert to MHz 421 | sprintf(buff, "%.1f MHz", frq / 1000000.0); 422 | } else if (frq >= 1000) { // Convert to kHz 423 | sprintf(buff, "%.1f KHz", frq / 1000.0); 424 | } else { // Frequency in Hz 425 | sprintf(buff, "%d Hz", frq); 426 | } 427 | } 428 | 429 | -------------------------------------------------------------------------------- /src/components/exec.c: -------------------------------------------------------------------------------- 1 | #include "../types.h" 2 | #include "./decode.h" 3 | #include "./mem.h" 4 | #include "rom.h" 5 | #include 6 | 7 | 8 | 9 | int set_z_bit(int value){ 10 | if(value == 0){ 11 | // The result of an arithmetic or logic operation is zero 12 | set_sfr_bit(STATUS_REGISTER, 2); // set Z 13 | return 1; 14 | } else { 15 | // The result of an arithmetic or logic operation is not zero 16 | clear_sfr_bit(STATUS_REGISTER, 2); // clear Z 17 | } 18 | return 0; 19 | } 20 | 21 | /* return EXEC that contains execute information for given instruction */ 22 | /* Soft in soft_execute means it's not memory (register, ram ...) related */ 23 | EXEC soft_execute(DECODE dcd){ 24 | EXEC exec; 25 | 26 | exec.sleep = 0; 27 | exec.upc = get_pc(); // Default PC 28 | 29 | switch(dcd.opcode) { 30 | case GOTO_OP: 31 | exec.upc = dcd.operand; 32 | break; 33 | 34 | case SLEEP_OP: 35 | clear_sfr_bit(STATUS_REGISTER, 3); 36 | set_sfr_bit(STATUS_REGISTER, 4); 37 | exec.sleep = 1; 38 | break; 39 | 40 | case CALL_OP: 41 | push_stack(get_pc() + 1); // (PC + 1) to Stack-1 42 | exec.upc = dcd.addr; 43 | break; 44 | 45 | case RETLW_OP: 46 | exec.upc = pop_stack(); // Stack-1 to PC 47 | set_w_reg(dcd.bits); // Load Register W 48 | break; 49 | 50 | default: 51 | break; 52 | } 53 | 54 | return exec; 55 | } 56 | 57 | 58 | void exec_info(char info[], int inst){ 59 | DECODE dcd = decode_inst(inst); 60 | char dth[MAXSIZ]; // decimal (hex) 61 | char dta[MAXSIZ]; // decimal (addr) 62 | char dtb[MAXSIZ]; // decimal (bits) 63 | 64 | char one[2]; 65 | char three[4]; 66 | char four[5]; 67 | char five[6]; 68 | char six[7]; 69 | char seven[8]; 70 | char eight[9]; 71 | char nine[10]; 72 | 73 | switch(dcd.type) { 74 | case FULL: 75 | dtoh(inst, 3, dth); 76 | char ib[13]; 77 | i2b(inst, ib, 12); 78 | sprintf(info, "%s0b%s %s%s %s%s", KB_P1, ib, K_HEX, dth, K_INFO, dcd.info); 79 | break; 80 | 81 | // KB_P1, edfb(inst, 7, 12), KB_P2, edfb(inst, 6, 6), KB_P3, edfb(inst, 1, 5), 82 | case SIX_ONE_FIVE: 83 | dtoh(dcd.bits, 2, dtb); 84 | dtoh(dcd.addr, 2, dta); 85 | dtoh(inst, 3, dth); 86 | 87 | i2b(edfb(inst, 7, 12), six, 6); 88 | i2b(edfb(inst, 6, 6), one, 1); 89 | i2b(edfb(inst, 1, 5), five, 5); 90 | 91 | sprintf(info, "%s0b%s%s%s%s%s %s%s %s%s %s%s[FFFFFF], %s%s", KB_P1, six, KB_P2, one, KB_P3, five, K_HEX, dth, K_INFO, dcd.info, K_OP1, dta, K_OP2, dtb); 92 | break; 93 | 94 | // KB_P1, edfb(inst, 9, 12), KB_P2, edfb(inst, 6, 8), KB_P3, edfb(inst, 1, 5), 95 | case FOUR_THREE_FIVE: 96 | dtoh(dcd.bits, 2, dtb); 97 | dtoh(dcd.addr, 2, dta); 98 | dtoh(inst, 3, dth); 99 | 100 | i2b(edfb(inst, 9, 12), four, 4); 101 | i2b(edfb(inst, 6, 8), three, 3); 102 | i2b(edfb(inst, 1, 5), five, 5); 103 | 104 | sprintf(info, "%s0b%s%s%s%s%s %s%s %s%s %s%s[FFFFFF], %s%s", KB_P1, four, KB_P2, three, KB_P3, five, K_HEX, dth, K_INFO, dcd.info, K_OP1, dta, K_OP2, dtb); 105 | break; 106 | 107 | // %s0b%04b%s%08b 108 | case FOUR_EIGHT: 109 | dtoh(dcd.bits, 2, dtb); 110 | dtoh(dcd.addr, 2, dta); 111 | dtoh(inst, 3, dth); 112 | 113 | i2b(edfb(inst, 9, 12), four, 4); 114 | i2b(edfb(inst, 1, 8), eight, 8); 115 | 116 | sprintf(info, "%s0b%s%s%s %s%s %s%s %s%s", KB_P1, four, KB_P2, eight, K_HEX, dth, K_INFO, dcd.info, K_OP1, dcd.opcode == CALL_OP ? dta : dtb); 117 | break; 118 | 119 | case THREE_NINE: 120 | dtoh(dcd.addr, 2, dta); 121 | dtoh(inst, 3, dth); 122 | 123 | i2b(edfb(inst, 10, 12), three, 3); 124 | i2b(edfb(inst, 1, 9), nine, 9); 125 | 126 | sprintf(info, "%s0b%s%s%s %s%s %s%s %s%s", KB_P1, three, KB_P2, nine, K_HEX, dth, K_INFO, dcd.info, K_OP1, dta); 127 | break; 128 | 129 | case SEVEN_FIVE: 130 | dtoh(dcd.addr, 2, dta); 131 | dtoh(inst, 3, dth); 132 | 133 | i2b(edfb(inst, 6, 12), seven, 7); 134 | i2b(edfb(inst, 1, 5), five, 5); 135 | 136 | sprintf(info, "%s0b%s%s%s %s%s %s%s %s%s", KB_P1, seven, KB_P2, five, K_HEX, dth, K_INFO, dcd.info, K_OP1, dta); 137 | break; 138 | 139 | default: 140 | dtoh(inst, 3, dth); 141 | sprintf(info, "[62AEEF]%s [2979FF]%s [98C379]%s", "--------------", dth, "NOP"); 142 | break; 143 | } 144 | 145 | char colored[MAXSIZ]; 146 | update_color(info, 1, colored); 147 | strcpy(info, colored); 148 | } 149 | 150 | 151 | 152 | 153 | // put value into register 'W' if 'dcd.bits == 0' otherwise put if 'f' register 154 | void update_by_dist(MEM_OUT mem, DECODE dcd){ 155 | if(dcd.bits == 1){ 156 | set_mem(mem, mem.value); 157 | } else { 158 | set_w_reg(mem.value); 159 | } 160 | } 161 | 162 | 163 | /* Execute & Update Memory etc... */ 164 | int execute(DECODE dcd){ 165 | MEM_OUT m; 166 | int bypass = 0; 167 | 168 | int fsr = get_sfr(FSR_REGISTER); 169 | set_sfr(INDF_REGISTER, fsr); 170 | set_sfr(TMR0_REGISTER, get_cpu_coutner()); 171 | 172 | // // Update Carry bit in STATUS 173 | // if(get_carry()){ 174 | // set_sfr_bit(STATUS_REGISTER, 0); 175 | // } else { 176 | // clear_sfr_bit(STATUS_REGISTER, 0); 177 | // } 178 | 179 | int tmp = 0; 180 | 181 | switch(dcd.opcode) { 182 | // BSF 183 | case BSF_OP: 184 | m = get_mem(dcd.addr); 185 | set_mem(m, m.value | (1 << dcd.bits)); 186 | break; 187 | 188 | // BCF 189 | case BCF_OP: 190 | m = get_mem(dcd.addr); 191 | set_mem(m, m.value & ~(1 << dcd.bits)); 192 | break; 193 | 194 | // MOVLW 195 | case MOVLW_OP: 196 | set_w_reg(dcd.bits); 197 | break; 198 | 199 | // MOVWF 200 | case MOVWF_OP: 201 | m = get_mem(dcd.addr); 202 | set_mem(m, get_w_reg()); 203 | break; 204 | 205 | // CLRF 206 | case CLRF_OP: 207 | m = get_mem(dcd.addr); 208 | set_mem(m, 0); 209 | set_z_bit(0); 210 | break; 211 | 212 | // CLRW 213 | case CLRW_OP: 214 | set_w_reg(0); 215 | set_z_bit(0); 216 | break; 217 | 218 | // DECF 219 | case DECF_OP: 220 | m = get_mem(dcd.addr); 221 | if(m.value != 0){ m.value--; } 222 | update_by_dist(m, dcd); 223 | set_z_bit(m.value); 224 | break; 225 | 226 | // DECFSZ 227 | case DECFSZ_OP: 228 | m = get_mem(dcd.addr); 229 | if(m.value != 0){ 230 | m.value--; 231 | clear_sfr_bit(STATUS_REGISTER, 2); 232 | } else { 233 | set_sfr_bit(STATUS_REGISTER, 2); 234 | } 235 | update_by_dist(m, dcd); 236 | if(m.value == 0){ bypass = 1; } 237 | break; 238 | 239 | // INCF 240 | case INCF_OP: 241 | m = get_mem(dcd.addr); 242 | if(m.value != 255){ 243 | m.value++; 244 | } else { 245 | m.value = 0; 246 | } 247 | update_by_dist(m, dcd); 248 | set_z_bit(m.value); 249 | break; 250 | 251 | // INCFSZ 252 | case INCFSZ_OP: 253 | m = get_mem(dcd.addr); 254 | if(m.value != 255){ 255 | m.value++; 256 | clear_sfr_bit(STATUS_REGISTER, 2); 257 | } else { 258 | m.value = 0; 259 | set_sfr_bit(STATUS_REGISTER, 2); 260 | } 261 | update_by_dist(m, dcd); 262 | if(m.value == 0){ bypass = 1; } 263 | break; 264 | 265 | // BTFSS 266 | case BTFSS_OP: 267 | m = get_mem(dcd.addr); 268 | if(edfb(m.value, dcd.bits + 1, dcd.bits + 1) == 1){ 269 | bypass = 1; 270 | } 271 | break; 272 | 273 | 274 | // BTFSC 275 | case BTFSC_OP: 276 | m = get_mem(dcd.addr); 277 | if(edfb(m.value, dcd.bits + 1, dcd.bits + 1) == 0){ 278 | bypass = 1; 279 | } 280 | break; 281 | 282 | // ADDWF 283 | case ADDWF_OP: 284 | m = get_mem(dcd.addr); 285 | tmp = m.value; 286 | m.value = m.value + get_w_reg(); 287 | 288 | if(m.value > 255){ 289 | clear_sfr_bit(STATUS_REGISTER, 0); 290 | } else { 291 | set_sfr_bit(STATUS_REGISTER, 0); 292 | } 293 | 294 | if((edfb(get_w_reg(), 0, 3) + edfb(tmp, 0, 3)) > 0x0F){ 295 | clear_sfr_bit(STATUS_REGISTER, 1); 296 | } else { 297 | set_sfr_bit(STATUS_REGISTER, 1); 298 | } 299 | 300 | 301 | if(m.value > 255){ m.value = 0; } 302 | set_z_bit(m.value); 303 | update_by_dist(m, dcd); 304 | break; 305 | 306 | // ANDWF 307 | case ANDWF_OP: 308 | m = get_mem(dcd.addr); 309 | m.value &= get_w_reg(); 310 | update_by_dist(m, dcd); 311 | set_z_bit(m.value); 312 | break; 313 | 314 | // COMF 315 | case COMF_OP: 316 | m = get_mem(dcd.addr); 317 | m.value = ~m.value; 318 | update_by_dist(m, dcd); 319 | set_z_bit(m.value); 320 | break; 321 | 322 | // IORWF 323 | case IORWF_OP: 324 | m = get_mem(dcd.addr); 325 | m.value |= get_w_reg(); 326 | update_by_dist(m, dcd); 327 | set_z_bit(m.value); 328 | break; 329 | 330 | // MOVF 331 | case MOVF_OP: 332 | m = get_mem(dcd.addr); 333 | update_by_dist(m, dcd); 334 | set_z_bit(m.value); 335 | break; 336 | 337 | // RLF 338 | case RLF_OP: 339 | m = get_mem(dcd.addr); 340 | m.value = rotate_left_carry(m.value); 341 | update_by_dist(m, dcd); 342 | break; 343 | 344 | // RRF 345 | case RRF_OP: 346 | m = get_mem(dcd.addr); 347 | m.value = rotate_right_carry(m.value); 348 | update_by_dist(m, dcd); 349 | break; 350 | 351 | // SUBWF (W - f) 352 | case SUBWF_OP: 353 | m = get_mem(dcd.addr); 354 | int tmpval = m.value; 355 | m.value = m.value - get_w_reg(); 356 | 357 | if(m.value < 0){ 358 | // A borrow did occurred 359 | clear_sfr_bit(STATUS_REGISTER, 0); 360 | m.value = 0; 361 | } else { 362 | // A borrow did not occurred 363 | set_sfr_bit(STATUS_REGISTER, 0); 364 | } 365 | 366 | if((edfb(get_w_reg(), 0, 3) - edfb(tmpval, 0, 3)) < 0){ 367 | // A borrow from the 4th low-order bit of the result did not occur 368 | clear_sfr_bit(STATUS_REGISTER, 1); 369 | } else { 370 | // A borrow from the 4th low-order bit of the result occur 371 | set_sfr_bit(STATUS_REGISTER, 1); 372 | } 373 | 374 | // if(m.value <= 0){ 375 | // // The result of an arithmetic or logic operation is zero 376 | // m.value = 0; 377 | // set_sfr_bit(STATUS_REGISTER, 2); // set Z 378 | // } else { 379 | // // The result of an arithmetic or logic operation is not zero 380 | // clear_sfr_bit(STATUS_REGISTER, 2); // clear Z 381 | // } 382 | 383 | // if(set_z_bit(m.value)){ m.value = 0; } 384 | set_z_bit(m.value); 385 | update_by_dist(m, dcd); 386 | break; 387 | 388 | // SWAPF 389 | case SWAPF_OP: 390 | m = get_mem(dcd.addr); 391 | m.value = (m.value >> 4) | (m.value << 4); 392 | update_by_dist(m, dcd); 393 | break; 394 | 395 | // XORWF 396 | case XORWF_OP: 397 | m = get_mem(dcd.addr); 398 | m.value = m.value ^ get_w_reg(); 399 | set_z_bit(m.value); 400 | update_by_dist(m, dcd); 401 | break; 402 | 403 | // ANDLW 404 | case ANDLW_OP: 405 | tmp = get_w_reg() & dcd.bits; 406 | set_z_bit(tmp); 407 | set_w_reg(tmp); 408 | break; 409 | 410 | // CLRWDT 411 | case CLRWDT_OP: 412 | set_sfr_bit(STATUS_REGISTER, 3); 413 | set_sfr_bit(STATUS_REGISTER, 4); 414 | set_sfr(TMR0_REGISTER, 0); // clear TIMER 415 | break; 416 | 417 | // IORLW 418 | case IORLW_OP: 419 | tmp = get_w_reg() | dcd.bits; 420 | set_z_bit(tmp); 421 | set_w_reg(tmp); 422 | break; 423 | 424 | // OPTION 425 | case OPTION_OP: 426 | set_sfr(OPTION_REGISTER, get_w_reg()); 427 | break; 428 | 429 | // CLRWDT 430 | case TRIS_OP: 431 | set_sfr(TRISGPIO_REGISTER, dcd.addr); 432 | if(dcd.addr == 6){ 433 | INPUT_EN = 1; 434 | } else { 435 | INPUT_EN = 0; 436 | } 437 | break; 438 | 439 | // XORLW 440 | case XORLW_OP: 441 | tmp = get_w_reg() ^ dcd.bits; 442 | set_w_reg(tmp); 443 | set_z_bit(tmp); 444 | break; 445 | 446 | default: 447 | break; 448 | } 449 | 450 | increase_cc(); // increase cpu timer (counter) 451 | return bypass; 452 | } 453 | 454 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | Amethyst 4 | 5 |

Amethyst

6 |

This project implements a simplified 8-bit CPU architecture in C, along with an assembler, emulator, and a TUI-based visualization tool. It serves as an educational tool for understanding computer architecture, instruction sets, and low-level programming.

7 |
8 | 9 | 10 | ## Preview 11 | ![Amethyst](./assets/clip.gif) 12 | 13 | 14 | ## Build 15 | Clone the project by: 16 | ```bash 17 | git clone https://github.com/empitrix/amethyst 18 | cd ./amethyst 19 | ``` 20 | 21 | To build the project using `gnu make` run: 22 | ```bash 23 | make 24 | ``` 25 | After that you will have `./cpu`. 26 | 27 | > [!NOTE] 28 | > currently this project is for unix-like operating systems only. 29 | 30 | 31 | ## Usage 32 | For example to use the project run: 33 | ```bash 34 | ./cpu -p ./examples/pattern.bin 35 | ``` 36 | 37 | Which executes the file [`pattern.asm`](https://github.com/Empitrix/assembler/blob/master/examples/pattern.asm) that generated by [**Assembler**](https://github.com/Empitrix/assembler). 38 | 39 | Or if you wish to see the instructions step by step use `-s` flag: 40 | ```bash 41 | ./cpu -p ./examples/pattern.bin -s 42 | ``` 43 | In stepping mode if you press `q` the program will end. 44 | 45 | And to see how console works use `-c` flag and `hello.bin` program in `examples/` which is running [`hello.asm`](https://github.com/Empitrix/assembler/blob/master/examples/hello.asm): 46 | ```bash 47 | ./cpu -p ./examples/hello.bin -c 48 | ``` 49 | 50 | 51 | 52 | ## CPU Specifications: 53 | ### Memory 54 | - 16 bytes of RAM (Addresses `0x10` to `0x1F`) 55 | - 256 words of ROM (Addresses `0x00` to `0xFF`) 56 | 57 | ### Registers 58 | - 10 special-purpose registers (Addresses `0x00` to `0x09`) 59 | - Register `0x06`: GPIO (General Purpose Input/Output) 60 | 61 | ### Opcodes 62 | 63 |
64 | BSF f, b 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
DescriptionSet bit (b) at address (f) to 1
Encoding0101 bbbf ffff
ExampleBSF GPIO, 0
79 |
80 | 81 | 82 |
83 | BCF f, b 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
DescriptionSet bit (b) at address (f) to 0
Encoding0100 bbbf ffff
ExampleBCF GPIO, 0
98 |
99 | 100 | 101 |
102 | GOTO k 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 |
DescriptionGoto given lable
Encoding101k kkkk kkkk
ExampleGOTO start
117 |
118 | 119 | 120 | 121 |
122 | NOP 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 |
DescriptionNo operation
Encoding0000 0000 0000
ExampleNOP
137 |
138 | 139 | 140 |
141 | MOVLW K 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
DescriptionLoads a literal (immediate) value into the W register.
Encoding1100 KKKK KKKK (where KKKKKKKK is the 8-bit literal value)
ExampleMOVLW 03H
156 |
157 | 158 | 159 |
160 | MOVWF f 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
DescriptionMoves the contents of the W register to a specified register or memory location.
Encoding0000 001F FFFF (where FFFFF is the 5-bit address)
ExampleMOVWF 06H
175 |
176 | 177 | 178 |
179 | CLRF f 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 |
DescriptionClears (sets to 0) a specified register or memory location.
Encoding0000 011F FFFF
ExampleCLRF 06H
194 |
195 | 196 | 197 |
198 | CLRW 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 |
DescriptionClears the W register.
Encoding0000 0100 0000
ExampleCLRW
213 |
214 | 215 | 216 |
217 | SLEEP 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
DescriptionPuts the CPU into a standby mode.
Encoding0000 0000 0011
ExampleSLEEP
232 |
233 | 234 | 235 |
236 | DECF f, d 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 |
DescriptionDecrement register f and store the result back in f only if (d) destination is 1 otherwise store the resutl into register W.
Encoding0000 11dF FFFF
ExampleDECF 0x01, 1
251 |
252 | 253 | 254 |
255 | DECFSZ f, d 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 |
DescriptionDecrement the contents of register f. If d is 0, place the result in the W register. If d is 1, place the result back in register f. If the result is 0, skip the next instruction (which is already fetched) and execute a NOP instead.
Encoding0010 11dF FFFF
ExampleDECFSZ 0x02, 1
270 |
271 | 272 | 273 |
274 | INCF f, d 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 |
DescriptionIncrement the contents of register f. If d is 0, store the result in the W register. If d is 1, store the result back in register f.
Encoding0010 10dF FFFF
ExampleINCF 0x03, 1
289 |
290 | 291 | 292 |
293 | INCFSZ f, d 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 |
DescriptionIncrement the contents of register f. If d is 0, place the result in the W register. If d is 1, place the result back in register f. If the result is 0, skip the next instruction and execute a NOP instead.
Encoding0011 11dF FFFF
ExampleINCFSZ 0x04, 1
308 |
309 | 310 | 311 |
312 | BTFSS f, b 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 |
DescriptionTest the bit b in register f. If bit b is 1, skip the next instruction (which is already fetched) and execute a NOP instead.
Encoding0110 bbbF FFFF
ExampleBTFSC 0x06, 2
327 |
328 | 329 | 330 |
331 | BTFSC f, b 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 |
DescriptionTest the bit b in register f. If bit b is 0, skip the next instruction (which is already fetched) and execute a NOP instead.
Encoding0111 bbbF FFFF
ExampleBTFSC 0x06, 2
346 |
347 | 348 | 349 | 350 |
351 | ADDWF f, d 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 |
DescriptionAdd the value in W register to the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0001 11df ffff
ExampleADDWF 0x06, 1
366 |
367 | 368 | 369 |
370 | ANDWF f, d 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 |
DescriptionAND the value in W register with the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0001 01df ffff
ExampleANDWF 0x06, 1
385 |
386 | 387 | 388 | 389 |
390 | COMF f, d 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |
DescriptionComplement the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0010 01df ffff
ExampleCOMF 0x06, 1
405 |
406 | 407 | 408 |
409 | IORWF f, d 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 |
DescriptionInclusive OR the value in W register with the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0001 00df ffff
ExampleIORWF 0x06, 1
424 |
425 | 426 | 427 |
428 | MOVF f, d 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 |
DescriptionMove content of the specified register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0010 00df ffff
ExampleMOVF 0x06, 0
443 |
444 | 445 | 446 | 447 |
448 | RLF f, d 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 |
DescriptionRotate the specified file register left through the Carry flag. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0011 01df ffff
ExampleRLF 0x06, 0
463 |
464 | 465 | 466 |
467 | RRF f, d 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 |
DescriptionRotate the specified file register right through the Carry flag. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0011 00df ffff
ExampleRRF 0x06, 0
482 |
483 | 484 | 485 |
486 | SUBWF f, d 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 |
DescriptionSubtract the value in W register from the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0000 10df ffff
ExampleSUBWF 0x06, 0
501 |
502 | 503 | 504 | 505 |
506 | SWAPF f, d 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 |
DescriptionSwap the upper and lower nibbles of the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0011 10df ffff
ExampleSWAPF 0x06, 0
521 |
522 | 523 | 524 |
525 | XORWF f, d 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 |
DescriptionExclusive OR the value in W register with the specified file register. If d is 0, place the result in the W register. If d is 1, place the result back in register f.
Encoding0001 10df ffff
ExampleXORWF 0x06, 0
540 |
541 | 542 | 543 |
544 | ANDLW k 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 |
DescriptionAND a literal value with the W register
Encoding1110 kkkk kkkk
ExampleANDLW 0b00000110
559 |
560 | 561 | 562 |
563 | CALL k 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 |
DescriptionCall a subroutine.
Encoding1001 kkkk kkkk
ExampleCALL start
578 |
579 | 580 | 581 |
582 | CLRWDT 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 |
DescriptionClear the Watchdog Timer.
Encoding0000 0000 0100
ExampleCLRWDT
597 |
598 | 599 | 600 |
601 | IORLW k 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 |
DescriptionInclusive OR a literal value with the W register.
Encoding1101 kkkk kkkk
ExampleIORLW 05H
616 |
617 | 618 | 619 | 620 |
621 | OPTION 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 |
DescriptionLoad the OPTION register.
Encoding0000 0000 0010
ExampleOPTION
636 |
637 | 638 | 639 |
640 | RETLW k 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 |
DescriptionReturn from a subroutine and place a literal value in the W register.
Encoding1000 kkkk kkkk
ExampleRETLW 07H
655 |
656 | 657 | 658 |
659 | TRIS f 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 |
DescriptionLoad the TRIS register.
Encoding0000 0000 0fff (0000 0000 0110 or 0000 0000 0111)
ExampleTRIS 07H or TRIS 06H
674 |
675 | 676 | 677 |
678 | XORLW k 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 |
DescriptionExclusive OR a literal value with the W register.
Encoding1111 kkkk kkkk
ExampleXORLW 12H
693 |
694 | 695 | 696 | 697 | 698 | ## Flags 699 | | Flag | Name | Description | 700 | |-------------|----------------|-------------------------------------------------------------------------------| 701 | | `-s` | Stepping Mode | Clock pulse with keyboard keys | 702 | | `-f ` | Frequency | Clock frequency from 1 to 1000000 | 703 | | `-p ` | Program | Path to `.bin` file from [`assembler`](https://github.com/empitrix/assembler) | 704 | | `-l ` | Load CPU state | Path to a `.txt` file that contains CPU's state | 705 | | `-c` | Console | Enables the `console` and allows loggin for register `0x06` (GPIO) | 706 | | `-i ` | CI Mode | Save CPU state at given position | 707 | 708 | - If CPU state is loaded with `-l` don't need to use `-p` to load a program to CPU, but make sure that the program is exists for CPU to load it. 709 | 710 | ### Console 711 | This section displays ASCII characters directly from the CPU's GPIO port. To print a character, write its 7-bit ASCII code to the port and set the eighth bit (bit 7) to 1. The corresponding ASCII character will appear on the console. 712 | 713 | ```asm 714 | MOVLW 'A' ; Load the ASCII code for 'A' into register W 715 | MOVWF GPIO ; Write the value from register W to the GPIO port 716 | BSF GPIO, 7 ; Set the eighth bit (bit 7) of the GPIO port to 1 717 | ``` 718 | 719 | 720 | ## Actions 721 | - Press `s` to save the cpu's state to a `cpu_state.txt` file! 722 | - Press `` to move to the next step in `stepping mode`. 723 | - Press `` to pause/unpause CPU in `auto mode`. 724 | - Press `r` to reset the cpu while CPU is in `SLEEP`. 725 | 726 | 733 | ## Todo 734 | - [ ] Possible `seg fult` for `update_console` in `./src/emulator.c` when changing terminal size with high frequency so fast... 735 | --------------------------------------------------------------------------------