├── 20141500.c ├── Makefile ├── README.md ├── asm ├── 2_5.asm ├── correct_2_5.obj ├── error.asm └── error2.asm ├── assemble.c ├── assemble.h ├── command.c ├── command.h ├── command_def.h ├── debug.c ├── debug.h ├── doc ├── Document_proj_1.doc ├── Document_proj_2.doc └── Document_proj_3.doc ├── history.c ├── history.h ├── list.c ├── list.h ├── loader.c ├── loader.h ├── memory.c ├── memory.h ├── obj ├── copy.obj ├── proga.obj ├── progb.obj └── progc.obj ├── opcode.c ├── opcode.h ├── opcode.txt ├── run.c ├── run.h ├── symbol.c └── symbol.h /20141500.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "command.h" 5 | 6 | #define MEMORY_SIZE (1 * 1024 * 1024) /* 1MB */ 7 | #define OPCODE_FILE "opcode.txt" 8 | 9 | static void insert_fake_opcodes (struct opcode_manager *manager) 10 | { 11 | static const struct opcode fake_list[] = 12 | { 13 | { 0, "START", OPCODE_START, OPCODE_FAKE }, 14 | { 0, "END", OPCODE_END, OPCODE_FAKE }, 15 | { 0, "BYTE", OPCODE_BYTE, OPCODE_FAKE }, 16 | { 0, "WORD", OPCODE_WORD, OPCODE_FAKE }, 17 | { 0, "RESB", OPCODE_RESB, OPCODE_FAKE }, 18 | { 0, "RESW", OPCODE_RESW, OPCODE_FAKE }, 19 | { 0, "BASE", OPCODE_BASE, OPCODE_FAKE }, 20 | { 0, "NOBASE", OPCODE_NOBASE, OPCODE_FAKE } 21 | }; 22 | 23 | for (size_t i = 0; i < sizeof(fake_list) / sizeof(*fake_list); ++i) 24 | { 25 | opcode_insert (manager, &fake_list[i]); 26 | } 27 | } 28 | 29 | /* Opcode File을 읽어들여서, opcode manager를 구축해주는 함수. */ 30 | static struct opcode_manager *read_opcode_file () 31 | { 32 | FILE *fp = fopen (OPCODE_FILE, "rt"); 33 | struct opcode_manager *manager = NULL; 34 | 35 | if (!fp) 36 | goto ERROR; 37 | 38 | struct opcode opcode; 39 | char format_buf[16]; 40 | unsigned int val; 41 | 42 | manager = opcode_manager_construct (); 43 | 44 | /* 파일에서 opcode 정보를 읽어들이면서 opcode manager에 그 정보를 추가한다. */ 45 | while (fscanf (fp, "%X %6s %5s", /* TODO */ 46 | &val, opcode.name, format_buf) != EOF) 47 | { 48 | #define COMPARE_WITH(STR) \ 49 | (strcmp (opcode.name, (STR)) == 0) 50 | 51 | if (strcmp (format_buf, "1") == 0) 52 | { 53 | opcode.op_format = OPCODE_FORMAT_1; 54 | opcode.detail_format = OPCODE_FORMAT_1_GENERAL; 55 | } 56 | else if (strcmp (format_buf, "2") == 0) 57 | { 58 | opcode.op_format = OPCODE_FORMAT_2; 59 | 60 | if (COMPARE_WITH ("CLEAR") || COMPARE_WITH ("TIXR")) 61 | opcode.detail_format = OPCODE_FORMAT_2_ONE_REGISTER; 62 | else if (COMPARE_WITH ("SHIFTL") || COMPARE_WITH ("SHIFTR")) 63 | opcode.detail_format = OPCODE_FORMAT_2_REGISTER_N; 64 | else if (COMPARE_WITH ("SVC")) 65 | opcode.detail_format = OPCODE_FORMAT_2_ONE_N; 66 | else 67 | opcode.detail_format = OPCODE_FORMAT_2_GENERAL; 68 | } 69 | else if (strcmp (format_buf, "3/4") == 0) 70 | { 71 | opcode.op_format = OPCODE_FORMAT_3_4; 72 | 73 | if (COMPARE_WITH ("RSUB")) 74 | opcode.detail_format = OPCODE_FORMAT_3_4_NO_OPERAND; 75 | else 76 | opcode.detail_format = OPCODE_FORMAT_3_4_GENERAL; 77 | } 78 | else 79 | goto ERROR; 80 | 81 | opcode.val = val; 82 | opcode_insert (manager, &opcode); 83 | 84 | #undef COMPARE_WITH 85 | } 86 | 87 | goto END; 88 | 89 | ERROR: 90 | if (manager) 91 | { 92 | opcode_manager_destroy (manager); 93 | manager = NULL; 94 | } 95 | 96 | END: 97 | if (fp) 98 | fclose (fp); 99 | 100 | return manager; 101 | } 102 | 103 | int main() 104 | { 105 | struct command_state state; 106 | 107 | /* Command Loop의 State를 초기화한다. */ 108 | 109 | state.history_manager = history_manager_construct (); 110 | state.memory_manager = memory_manager_construct (MEMORY_SIZE); 111 | if (!(state.opcode_manager = read_opcode_file ())) 112 | { 113 | fprintf (stderr, "[ERROR] Can't read opcode file \"%s\"\n", OPCODE_FILE); 114 | return 1; 115 | } 116 | insert_fake_opcodes (state.opcode_manager); 117 | state.symbol_manager = NULL; 118 | state.debug_manager = debug_manager_construct (); 119 | state.is_running = false; 120 | state.saved_dump_start = 0; 121 | state.progaddr = 0; 122 | 123 | /* Command Loop로 진입하여, 사용자의 입력을 처리한다. */ 124 | command_loop(&state); 125 | 126 | return 0; 127 | } 128 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCES=$(shell find . -type f -iname '*.c') 2 | TARGET=20141500.out 3 | 4 | all: $(TARGET) 5 | 6 | $(TARGET): $(SOURCES) 7 | gcc -std=gnu99 $(SOURCES) -o $(TARGET) -W -Wall -Wno-unused-parameter 8 | 9 | clean: 10 | rm -f $(TARGET) 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | System-Programming-SICXE-Project 2 | ======================================== 3 | Sogang Univ. System Programming (CSE4100) - SIC/XE Machine Project 4 | 5 | [Project 1 - Shell Prompt & Opcode Table & Memory Manager](https://github.com/taeguk/System-Programming-SICXE-Project/tree/project-1) 6 | ----------------- 7 | - Shell Prompt 8 | - Command History Management 9 | - Command 'dir' (similar to Unix's 'ls') 10 | - SIC/XE Instruction Opcode Table 11 | - SIC/XE Memory Manager (edit, fill, dump) 12 | - Generic Linked List 13 | 14 | [Project 2 - Assembler](https://github.com/taeguk/System-Programming-SICXE-Project/tree/project-2) 15 | ---------------- 16 | - Assemble SIC/XE assembly code (.asm). 17 | - As a result, generate listing file (.lst) and object file (.obj). 18 | - Not all assembly features are supported. 19 | 20 | [Project 3 - Linking Loader & Runner & Debugger](https://github.com/taeguk/System-Programming-SICXE-Project/tree/project-3) 21 | --------------------- 22 | - Linking Loader 23 | - Link several object files and load the program into specific memory address. 24 | - Runner 25 | - Emulate SIC/XE machine. 26 | - Run SIC/XE program loaded in memory. 27 | - Not all instructions are implemented. 28 | - Debugger 29 | - Break point 30 | 31 | Limitation 32 | ---------------- 33 | This project is just for an assignment of System Programming (CSE4100) course.
34 | I didn't spend much time. So, exception handling is lacking. And some codes and design are inefficient and bad. 35 | -------------------------------------------------------------------------------- /asm/2_5.asm: -------------------------------------------------------------------------------- 1 | COPY START 0 2 | FIRST STL RETADR 3 | LDB #LENGTH 4 | BASE LENGTH 5 | CLOOP +JSUB RDREC 6 | LDA LENGTH 7 | COMP #0 8 | JEQ ENDFIL 9 | +JSUB WRREC 10 | J CLOOP 11 | ENDFIL LDA EOF 12 | STA BUFFER 13 | LDA #3 14 | STA LENGTH 15 | +JSUB WRREC 16 | J @RETADR 17 | EOF BYTE C'EOF' 18 | RETADR RESW 1 19 | LENGTH RESW 1 20 | BUFFER RESB 4096 21 | . 22 | . SUBROUTINE TO READ RECORD INTO BUFFER 23 | . 24 | RDREC CLEAR X 25 | CLEAR A 26 | CLEAR S 27 | +LDT #4096 28 | RLOOP TD INPUT 29 | JEQ RLOOP 30 | RD INPUT 31 | COMPR A, S 32 | JEQ EXIT 33 | STCH BUFFER, X 34 | TIXR T 35 | JLT RLOOP 36 | EXIT STX LENGTH 37 | RSUB 38 | INPUT BYTE X'F1' 39 | . 40 | . SUBROUTINE TO WRITE RECORD FROM BUFFER 41 | . 42 | WRREC CLEAR X 43 | LDT LENGTH 44 | WLOOP TD OUTPUT 45 | JEQ WLOOP 46 | LDCH BUFFER, X 47 | WD OUTPUT 48 | TIXR T 49 | JLT WLOOP 50 | RSUB 51 | OUTPUT BYTE X'05' 52 | END FIRST 53 | 54 | -------------------------------------------------------------------------------- /asm/correct_2_5.obj: -------------------------------------------------------------------------------- 1 | HCOPY 000000001077 2 | T0000001D17202D69202D4B1010360320262900003320074B10105D3F2FEC032010 3 | T00001D130F20160100030F200D4B10105D3E2003454F46 4 | T0010361DB410B400B44075101000E32019332FFADB2013A00433200857C003B850 5 | T0010531D3B2FEA1340004F0000F1B410774000E32011332FFA53C003DF2008B850 6 | T001070073B2FEF4F000005 7 | M00000705 8 | M00001405 9 | M00002705 10 | E000000 11 | -------------------------------------------------------------------------------- /asm/error.asm: -------------------------------------------------------------------------------- 1 | COPY START 0 2 | FIRST STL RETADR 3 | LDB #LENGTH 4 | BASE LENGTH 5 | CLOOP +JSUB RDREC 6 | LDA LENGTH 7 | COMP #0 8 | JEQ ENDFIL 9 | +JSUB WRREC 10 | J CLOOP 11 | ENDFIL LDA EOF 12 | STA BUFFER 13 | LDA #3 14 | STA LENGTH 15 | +JSUB WRREC 16 | J @RETADR 17 | EOF BYTE C'EOF' 18 | RETADR RESW 1 19 | LENGTH RESW 1 20 | BUFFER RESB 4096 21 | . 22 | . SUBROUTINE TO READ RECORD INTO BUFFER 23 | . 24 | RDREC CLEAR X 25 | CLEAR A 26 | CLEAR S 27 | +LDT #4096 28 | RLOOP TD INPUT 29 | JEQ RLOOP 30 | RD INPUT 31 | COMPR A, S 32 | JEQ EXIT 33 | STCH BUFFER, X 34 | TIXR T 35 | JLT RLOOP 36 | EXIT STX LENGTH 37 | RSUB 38 | INPUT BYTE X'F1' 39 | . 40 | . SUBROUTINE TO WRITE RECORD FROM BUFFER 41 | . 42 | WRREC CLEAR X 43 | LDT LENGTH 44 | WLOOP TD OUTPUT 45 | JEQ WLOO 46 | LDCH BUFFER, X 47 | WD OUTPUT 48 | TIXR T 49 | JLT WLOOP 50 | RSUB 51 | OUTPUT BYTE X'05' 52 | END FIRST 53 | 54 | -------------------------------------------------------------------------------- /asm/error2.asm: -------------------------------------------------------------------------------- 1 | COPY START 0 2 | FIRST STL RETADR 3 | LDB #LENGTH 4 | BASE LENGTH 5 | CLOOP +JSUB RDREC 6 | LDA LENGTH 7 | COMP #0 8 | JEQ ENDFIL 9 | +JSUB WRREC 10 | J CLOOP 11 | ENDFIL LDA EOF 12 | STA BUFFER 13 | LDA #3 14 | STA LENGTH 15 | +JSUB WRREC 16 | J @RETADR 17 | EOF BYTE C'EOF' 18 | RETADR RESW 1 19 | LENGTH RESW 1 20 | BUFFER RESB 4096 21 | . 22 | . SUBROUTINE TO READ RECORD INTO BUFFER 23 | . 24 | RDREC CLEAR X 25 | CLEAR A 26 | CLEAR S 27 | +LDT #4096 28 | RLOOP TD INPUT 29 | JEQ RLOOP 30 | RD INPUT 31 | COMPR A, S 32 | JEQ EXIT 33 | STCH BUFFER, X 34 | TIXR T 35 | JLT RLOOP 36 | LENGTH STX LENGTH 37 | RSUB 38 | INPUT BYTE X'F1' 39 | . 40 | . SUBROUTINE TO WRITE RECORD FROM BUFFER 41 | . 42 | WRREC CLEAR X 43 | LDT LENGTH 44 | WLOOP TD OUTPUT 45 | JEQ WLOOP 46 | LDCH BUFFER, X 47 | WD OUTPUT 48 | TIXR T 49 | JLT WLOOP 50 | RSUB 51 | OUTPUT BYTE X'05' 52 | END FIRST 53 | 54 | -------------------------------------------------------------------------------- /assemble.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "assemble.h" 10 | 11 | #define ASSEMBLE_STATEMENT_TOKEN_MAX_NUM 8 12 | #define ASSEMBLE_STATEMENT_MAX_LEN 100 13 | 14 | #define SYMBOL_PART_MAX_LEN 7 15 | #define MNEMONIC_PART_MAX_LEN 7 16 | 17 | #define TEXT_RECORD_MAX_BYTES_PER_ROW 30 18 | 19 | #define MAX_ASM_FILENAME_LEN 280 20 | 21 | #define MAX_MOD_REC_NUM 1000 22 | #define MAX_PROGRAM_NAME_LEN 10 23 | #define MAX_REC_HEAD_LEN 30 24 | #define MAX_OBJ_BUF_LEN 1000 25 | #define MAX_BYTE_BUF_LEN 1000 26 | 27 | /* ASM 파일에서 한 줄 (statement)의 정보를 저장하는 구조체 */ 28 | struct statement 29 | { 30 | bool is_comment; 31 | const char *symbol; 32 | const struct opcode *opcode; 33 | bool extend; 34 | char *input; // statement 문자열을 그대로 간직하고 있는 pointer. 35 | 36 | /* tokens for operand */ 37 | size_t token_cnt; 38 | char *token_list[ASSEMBLE_STATEMENT_TOKEN_MAX_NUM+1]; 39 | }; 40 | 41 | union instruction_format_1 42 | { 43 | struct 44 | { 45 | uint8_t opcode : 8; 46 | } bit_field; 47 | uint8_t val; 48 | }; 49 | 50 | union instruction_format_2 51 | { 52 | struct 53 | { 54 | uint16_t r2 : 4; 55 | uint16_t r1 : 4; 56 | uint16_t opcode : 8; 57 | } bit_field; 58 | uint16_t val; 59 | }; 60 | 61 | union instruction_format_3 62 | { 63 | struct 64 | { 65 | uint32_t disp : 12; 66 | uint32_t e : 1; // must be 0 67 | uint32_t p : 1; 68 | uint32_t b : 1; 69 | uint32_t x : 1; 70 | uint32_t i : 1; 71 | uint32_t n : 1; 72 | uint32_t opcode : 6; 73 | } bit_field; 74 | uint32_t val; 75 | }; 76 | 77 | union instruction_format_4 78 | { 79 | struct 80 | { 81 | uint32_t address: 20; 82 | uint32_t e : 1; // must be 1 83 | uint32_t p : 1; 84 | uint32_t b : 1; 85 | uint32_t x : 1; 86 | uint32_t i : 1; 87 | uint32_t n : 1; 88 | uint32_t opcode : 6; 89 | } bit_field; 90 | uint32_t val; 91 | }; 92 | 93 | static int assemble_pass_1 (const char *asm_file, const char *mid_file, 94 | const struct opcode_manager *opcode_manager, 95 | struct symbol_manager *symbol_manager); 96 | 97 | static int assemble_pass_2 (const char *mid_file, const char *lst_file, const char *obj_file, 98 | const struct opcode_manager *opcode_manager, 99 | const struct symbol_manager *symbol_manager); 100 | 101 | int assemble (const char *filename, const struct opcode_manager *opcode_manager, 102 | struct symbol_manager *symbol_manager) 103 | { 104 | /* 105 | * 1. filename의 확장자가 .asm 인지 체크 106 | * 2. listing file과 outputfile 열기. 107 | */ 108 | char name[MAX_ASM_FILENAME_LEN+1], mid_file[MAX_ASM_FILENAME_LEN+1], 109 | lst_file[MAX_ASM_FILENAME_LEN+1], obj_file[MAX_ASM_FILENAME_LEN+1]; 110 | 111 | strncpy (name, filename, MAX_ASM_FILENAME_LEN); 112 | 113 | char *dot = strrchr (name, '.'); 114 | if (dot == NULL) 115 | { 116 | fprintf (stderr, "[ERROR] Invalid file: %s\n", filename); 117 | return -1; 118 | } 119 | 120 | *dot = '\0'; 121 | snprintf (mid_file, MAX_ASM_FILENAME_LEN, "%s.mid", name); 122 | snprintf (lst_file, MAX_ASM_FILENAME_LEN, "%s.lst", name); 123 | snprintf (obj_file, MAX_ASM_FILENAME_LEN, "%s.obj", name); 124 | 125 | fprintf (stdout, "[Progress] Now, start pass 1.\n"); 126 | if (assemble_pass_1 (filename, mid_file, opcode_manager, symbol_manager) != 0) 127 | { 128 | unlink (mid_file); 129 | return -1; 130 | } 131 | fprintf (stdout, "[Progress] Now, start pass 2.\n"); 132 | if (assemble_pass_2 (mid_file, lst_file, obj_file, opcode_manager, symbol_manager) != 0) 133 | { 134 | unlink (mid_file); 135 | unlink (lst_file); 136 | unlink (obj_file); 137 | return -1; 138 | } 139 | unlink (mid_file); 140 | fprintf (stdout, "[Progress] Successfully finish to assemble.\n"); 141 | return 0; 142 | } 143 | 144 | static int fetch_statement (FILE *fp, const struct opcode_manager *opcode_manager, 145 | struct statement *statement, 146 | bool is_mid_file, uint32_t *LOCCTR, uint32_t *statement_size) 147 | { 148 | static char input[ASSEMBLE_STATEMENT_MAX_LEN]; 149 | static char input_token[ASSEMBLE_STATEMENT_MAX_LEN]; 150 | 151 | if (fgets (input, ASSEMBLE_STATEMENT_MAX_LEN, fp) == NULL) 152 | return 0; 153 | 154 | int len = strlen (input); 155 | if (input[len-1] != '\n') 156 | return -1; 157 | 158 | input[len-1] = '\0'; 159 | 160 | if (is_mid_file) 161 | { 162 | int offset, i; 163 | sscanf (input, "%X\t%X%n", LOCCTR, statement_size, &offset); 164 | for (i = 0; input[i + offset]; ++i) 165 | input[i] = input[i + offset]; 166 | input[i] = 0; 167 | } 168 | strncpy (input_token, input, ASSEMBLE_STATEMENT_MAX_LEN); 169 | 170 | statement->input = input; 171 | statement->token_cnt = 0; 172 | statement->token_list[statement->token_cnt] = strtok (input_token, " ,\t\n"); 173 | 174 | while (statement->token_cnt <= ASSEMBLE_STATEMENT_TOKEN_MAX_NUM && 175 | statement->token_list[statement->token_cnt]) 176 | statement->token_list[++statement->token_cnt] = strtok (NULL, " ,\t\n"); 177 | 178 | if (statement->token_cnt <= 0) 179 | return -1; 180 | 181 | if (statement->token_cnt > ASSEMBLE_STATEMENT_TOKEN_MAX_NUM) 182 | return -1; 183 | 184 | // need to be refactored. 185 | // 주석일 경우, 186 | if (statement->token_list[0][0] == '.') 187 | { 188 | statement->is_comment = true; 189 | statement->opcode = NULL; 190 | } 191 | // 주석이 아닌 경우, 192 | else 193 | { 194 | statement->is_comment = false; 195 | const char *opcode_token; 196 | int operand_token_offset; 197 | 198 | if (statement->token_list[0][0] == '+') 199 | { 200 | statement->extend = true; 201 | opcode_token = &statement->token_list[0][1]; 202 | } 203 | else 204 | { 205 | statement->extend = false; 206 | opcode_token = statement->token_list[0]; 207 | } 208 | 209 | const struct opcode *opcode = opcode_find (opcode_manager, opcode_token); 210 | 211 | /* 첫 번째 token을 symbol로 인식할 것이냐 opcode로 인식할 것이냐의 문제가 있다. 212 | * 나는 이를 해결하기 위해서 opcode table를 검색하여 valid할 경우, opcode로 아닐 경우 213 | * symbol로 인식하는 방법을 사용하였다. 214 | */ 215 | 216 | // Symbol이 없는 경우, 217 | if (opcode) 218 | { 219 | operand_token_offset = 1; 220 | statement->symbol = NULL; 221 | statement->opcode = opcode; 222 | } 223 | // Symbol이 있는 경우, 224 | else 225 | { 226 | if (statement->token_cnt < 2) 227 | return -1;/*error*/ 228 | 229 | if (statement->token_list[1][0] == '+') 230 | { 231 | statement->extend = true; 232 | opcode_token = &statement->token_list[1][1]; 233 | } 234 | else 235 | { 236 | statement->extend = false; 237 | opcode_token = statement->token_list[1]; 238 | } 239 | 240 | opcode = opcode_find (opcode_manager, opcode_token); 241 | if (opcode == NULL) 242 | return -1;/*error*/ 243 | 244 | operand_token_offset = 2; 245 | statement->symbol = statement->token_list[0]; 246 | statement->opcode = opcode; 247 | } 248 | 249 | // token list에 있는 symbol과 opcode의 token을 지움. 250 | for (size_t i = operand_token_offset; i < statement->token_cnt; ++i) 251 | statement->token_list[i - operand_token_offset] = statement->token_list[i]; 252 | statement->token_cnt -= operand_token_offset; 253 | } 254 | 255 | return 0; 256 | } 257 | 258 | static int assemble_pass_1 (const char *asm_file, const char *mid_file, 259 | const struct opcode_manager *opcode_manager, 260 | struct symbol_manager *symbol_manager) 261 | { 262 | FILE *asm_fp = fopen (asm_file, "rt"); 263 | FILE *mid_fp = fopen (mid_file, "wt"); 264 | int ret; 265 | 266 | if (!asm_fp || !mid_fp) 267 | { 268 | // result에 에러정보 할당 269 | ret = -1; 270 | goto ERROR; 271 | } 272 | 273 | struct statement statement; 274 | uint32_t LOCCTR = 0; 275 | int line_no = 5; 276 | 277 | if (fetch_statement (asm_fp, opcode_manager, &statement, false, NULL, NULL) != 0) 278 | { 279 | /* handling error */ 280 | ret = -1; 281 | goto ERROR; 282 | } 283 | 284 | if (!statement.is_comment && statement.opcode->op_format == OPCODE_START) 285 | { 286 | LOCCTR = strtol (statement.token_list[0], NULL, 16); 287 | fprintf (mid_fp, "%04X\t0\t%s\n", LOCCTR, statement.input); 288 | 289 | if (fetch_statement (asm_fp, opcode_manager, &statement, false, NULL, NULL) != 0) 290 | { 291 | /* handling error */ 292 | ret = -1; 293 | goto ERROR; 294 | } 295 | 296 | line_no += 5; 297 | } 298 | 299 | while (true) 300 | { 301 | /* process */ 302 | 303 | if (statement.is_comment) 304 | { 305 | fprintf (mid_fp, "%04X\t0\t%s\n", LOCCTR, statement.input); 306 | } 307 | else 308 | { 309 | size_t old_LOCCTR = LOCCTR; 310 | 311 | // symbol을 symbol table에 넣음. 312 | if (statement.symbol) 313 | { 314 | // 이미 존재하는 symbol일 경우,,, error. 315 | if (symbol_find (symbol_manager, statement.symbol)) 316 | { 317 | ret = -1; 318 | goto ERROR; 319 | } 320 | 321 | struct symbol symbol; 322 | strncpy (symbol.label, statement.symbol, SYMBOL_NAME_MAX_LEN); 323 | symbol.LOCCTR = LOCCTR; 324 | symbol_insert (symbol_manager, &symbol); 325 | } 326 | 327 | if (statement.opcode->op_format == OPCODE_FORMAT_1) 328 | { 329 | LOCCTR += 1; 330 | } 331 | else if (statement.opcode->op_format == OPCODE_FORMAT_2) 332 | { 333 | LOCCTR += 2; 334 | } 335 | else if (statement.opcode->op_format == OPCODE_FORMAT_3_4) 336 | { 337 | LOCCTR += 3; 338 | } 339 | else if (statement.opcode->op_format == OPCODE_BYTE) 340 | { 341 | if (statement.token_cnt != 1) 342 | { 343 | ret = -1; 344 | goto ERROR; 345 | } 346 | 347 | const char *operand = statement.token_list[0]; 348 | int len, bytes; 349 | 350 | if (operand[1] != '\'') 351 | { 352 | ret = -1; 353 | goto ERROR; 354 | } 355 | 356 | len = strlen (operand); 357 | 358 | if (operand[0] == 'C') 359 | { 360 | bytes = len - 3; 361 | } 362 | else if (operand[0] == 'X') 363 | { 364 | bytes = (len - 3) / 2; 365 | } 366 | else 367 | { 368 | ret = -1; 369 | goto ERROR; 370 | } 371 | 372 | if (operand[len-1] != '\'') 373 | { 374 | ret = -1; 375 | goto ERROR; 376 | } 377 | 378 | LOCCTR += bytes; 379 | } 380 | else if (statement.opcode->op_format == OPCODE_WORD) 381 | { 382 | if (statement.token_cnt != 1) 383 | { 384 | ret = -1; 385 | goto ERROR; 386 | } 387 | LOCCTR += 3; 388 | } 389 | else if (statement.opcode->op_format == OPCODE_RESB) 390 | { 391 | if (statement.token_cnt != 1) 392 | { 393 | ret = -1; 394 | goto ERROR; 395 | } 396 | int cnt = strtol (statement.token_list[0], NULL, 10); 397 | LOCCTR += cnt; 398 | } 399 | else if (statement.opcode->op_format == OPCODE_RESW) 400 | { 401 | if (statement.token_cnt != 1) 402 | { 403 | ret = -1; 404 | goto ERROR; 405 | } 406 | int cnt = strtol (statement.token_list[0], NULL, 10); 407 | LOCCTR += cnt * 3; 408 | } 409 | else 410 | { 411 | // no variation of LOCCTR. 412 | } 413 | 414 | if (statement.extend) 415 | { 416 | if (statement.opcode->op_format == OPCODE_FORMAT_3_4) 417 | ++LOCCTR; 418 | else 419 | { 420 | ret = -1; 421 | goto ERROR; 422 | } 423 | } 424 | 425 | fprintf (mid_fp, "%04X\t%X\t%s\n", (unsigned int) old_LOCCTR, 426 | (unsigned int )(LOCCTR-old_LOCCTR), statement.input); 427 | } 428 | 429 | if (feof (asm_fp) != 0) 430 | break; 431 | else if (!statement.is_comment && statement.opcode->op_format == OPCODE_END) 432 | break; 433 | 434 | if (fetch_statement (asm_fp, opcode_manager, &statement, false, NULL, NULL) != 0) 435 | { 436 | /* handling error */ 437 | ret = -1; 438 | goto ERROR; 439 | } 440 | 441 | line_no += 5; 442 | } 443 | 444 | ret = 0; 445 | goto END; 446 | 447 | ERROR: 448 | fprintf (stderr, "[ERROR] Line no %d: an error occurs in pass 1.\n", line_no); 449 | END: 450 | if (asm_fp) 451 | fclose (asm_fp); 452 | if (mid_fp) 453 | fclose (mid_fp); 454 | 455 | return ret; 456 | } 457 | 458 | static int convert_register_mnemonic_to_no (const char *register_mnemonic) 459 | { 460 | #define COMPARE_WITH(STR) \ 461 | (strcmp (register_mnemonic, (STR)) == 0) 462 | 463 | if (COMPARE_WITH("A")) return 0; 464 | else if (COMPARE_WITH("X")) return 1; 465 | else if (COMPARE_WITH("L")) return 2; 466 | else if (COMPARE_WITH("PC")) return 8; 467 | else if (COMPARE_WITH("SW")) return 9; 468 | else if (COMPARE_WITH("B")) return 3; 469 | else if (COMPARE_WITH("S")) return 4; 470 | else if (COMPARE_WITH("T")) return 5; 471 | else if (COMPARE_WITH("F")) return 6; 472 | else return -1; 473 | 474 | #undef COMPARE_WITH 475 | } 476 | 477 | static int assemble_pass_2 (const char *mid_file, const char *lst_file, const char *obj_file, 478 | const struct opcode_manager *opcode_manager, 479 | const struct symbol_manager *symbol_manager) 480 | { 481 | FILE *mid_fp = fopen (mid_file, "rt"); 482 | FILE *lst_fp = fopen (lst_file, "wt"); 483 | FILE *obj_fp = fopen (obj_file, "wt"); 484 | int ret; 485 | 486 | if (!mid_fp || !lst_fp || !obj_fp) 487 | { 488 | // result에 에러정보 할당 489 | ret = -1; 490 | goto ERROR; 491 | } 492 | 493 | int line_no = 5; 494 | struct statement statement; 495 | uint32_t start_LOCCTR, row_LOCCTR, LOCCTR; 496 | uint32_t statement_size; 497 | uint32_t object_code; 498 | bool exist_base = false; 499 | uint32_t base; 500 | uint32_t mod_LOCCTR_list[MAX_MOD_REC_NUM]; 501 | int mod_LOCCTR_cnt = 0; 502 | char program_name[MAX_PROGRAM_NAME_LEN+1] = {0,}; 503 | char byte_buf[MAX_BYTE_BUF_LEN+1]; 504 | char obj_buf[MAX_OBJ_BUF_LEN+1], rec_head[MAX_REC_HEAD_LEN+1]; 505 | 506 | obj_buf[0] = '\0'; 507 | 508 | #define VERIFY_TEXT_RECORD_MAX_BYTES(bytes) \ 509 | if (LOCCTR + bytes > row_LOCCTR + TEXT_RECORD_MAX_BYTES_PER_ROW) \ 510 | { \ 511 | snprintf (rec_head, MAX_REC_HEAD_LEN, "T%06X%02X", row_LOCCTR, (uint8_t) strlen (obj_buf) / 2); \ 512 | fprintf (obj_fp, "%s%s\n", rec_head, obj_buf); \ 513 | row_LOCCTR = LOCCTR; \ 514 | obj_buf[0] = '\0'; \ 515 | } 516 | 517 | if (fetch_statement (mid_fp, opcode_manager, &statement, true, &LOCCTR, &statement_size) != 0) 518 | { 519 | /* handling error */ 520 | ret = -1; 521 | goto ERROR; 522 | } 523 | 524 | start_LOCCTR = row_LOCCTR = LOCCTR; 525 | 526 | if (!statement.is_comment && statement.opcode->op_format == OPCODE_START) 527 | { 528 | if (statement.symbol) 529 | strncpy (program_name, statement.symbol, MAX_PROGRAM_NAME_LEN); 530 | 531 | fprintf (lst_fp, "%d\t%04X%s\n", line_no, LOCCTR, statement.input); 532 | fprintf (obj_fp, "%19s\n", ""); 533 | 534 | if (fetch_statement (mid_fp, opcode_manager, &statement, true, &LOCCTR, &statement_size) != 0) 535 | { 536 | /* handling error */ 537 | ret = -1; 538 | goto ERROR; 539 | } 540 | 541 | line_no += 5; 542 | } 543 | while (true) 544 | { 545 | /* process */ 546 | 547 | if (statement.is_comment) 548 | { 549 | fprintf (lst_fp, "%d\t%s\n", line_no, statement.input); 550 | } 551 | else 552 | { 553 | /***************** Format 1의 Instruction의 경우 ****************/ 554 | if (statement.opcode->op_format == OPCODE_FORMAT_1) 555 | { 556 | if (statement.token_cnt != 0) 557 | { 558 | ret = -1; 559 | goto ERROR; 560 | } 561 | object_code = statement.opcode->val; 562 | } 563 | /***************** Format 2의 Instruction의 경우 ****************/ 564 | else if (statement.opcode->op_format == OPCODE_FORMAT_2) 565 | { 566 | union instruction_format_2 instruction; 567 | 568 | switch (statement.opcode->detail_format) 569 | { 570 | case OPCODE_FORMAT_2_GENERAL: 571 | { 572 | if (statement.token_cnt != 2) 573 | { 574 | ret = -1; 575 | goto ERROR; 576 | } 577 | int reg_no_1, reg_no_2; 578 | reg_no_1 = convert_register_mnemonic_to_no (statement.token_list[0]); 579 | reg_no_2 = convert_register_mnemonic_to_no (statement.token_list[1]); 580 | if (reg_no_1 == -1 || reg_no_2 == -1) 581 | { 582 | ret = -1; 583 | goto ERROR; 584 | } 585 | instruction.bit_field.opcode = statement.opcode->val; 586 | instruction.bit_field.r1 = reg_no_1; 587 | instruction.bit_field.r2 = reg_no_2; 588 | } 589 | break; 590 | case OPCODE_FORMAT_2_ONE_REGISTER: 591 | { 592 | if (statement.token_cnt != 1) 593 | { 594 | ret = -1; 595 | goto ERROR; 596 | } 597 | int reg_no = convert_register_mnemonic_to_no (statement.token_list[0]); 598 | if (reg_no == -1) 599 | { 600 | ret = -1; 601 | goto ERROR; 602 | } 603 | instruction.bit_field.opcode = statement.opcode->val; 604 | instruction.bit_field.r1 = reg_no; 605 | instruction.bit_field.r2 = 0; 606 | } 607 | break; 608 | case OPCODE_FORMAT_2_REGISTER_N: 609 | { 610 | if (statement.token_cnt != 2) 611 | { 612 | ret = -1; 613 | goto ERROR; 614 | } 615 | int reg_no = convert_register_mnemonic_to_no (statement.token_list[0]); 616 | char *endptr; 617 | long int n = strtol (statement.token_list[1], &endptr, 16); 618 | if (reg_no == -1 || *endptr != '\0' || n > 0xF || n < 0) 619 | { 620 | ret = -1; 621 | goto ERROR; 622 | } 623 | instruction.bit_field.opcode = statement.opcode->val; 624 | instruction.bit_field.r1 = reg_no; 625 | instruction.bit_field.r2 = n; 626 | } 627 | break; 628 | case OPCODE_FORMAT_2_ONE_N: 629 | { 630 | if (statement.token_cnt != 1) 631 | { 632 | ret = -1; 633 | goto ERROR; 634 | } 635 | char *endptr; 636 | long int n = strtol (statement.token_list[0], &endptr, 16); 637 | if (*endptr != '\0' || n > 0xF || n < 0) 638 | { 639 | ret = -1; 640 | goto ERROR; 641 | } 642 | instruction.bit_field.opcode = statement.opcode->val; 643 | instruction.bit_field.r1 = n; 644 | instruction.bit_field.r2 = 0; 645 | } 646 | break; 647 | default: 648 | /* Can't reach here */ 649 | assert (false); 650 | } 651 | object_code = instruction.val; 652 | } 653 | /***************** Format 3의 Instruction의 경우 ****************/ 654 | else if (statement.opcode->op_format == OPCODE_FORMAT_3_4) 655 | { 656 | union instruction_format_3 instruction_for_3; instruction_for_3.val = 0; 657 | union instruction_format_4 instruction_for_4; 658 | 659 | #define CONTROL_INST(S) \ 660 | if (statement.extend) instruction_for_4.S; \ 661 | else instruction_for_3.S; 662 | 663 | CONTROL_INST (bit_field.opcode = (statement.opcode->val >> 2)); 664 | CONTROL_INST (bit_field.e = statement.extend); 665 | 666 | if (statement.opcode->detail_format == OPCODE_FORMAT_3_4_NO_OPERAND) 667 | { 668 | if (statement.token_cnt != 0) 669 | { 670 | ret = -1; 671 | goto ERROR; 672 | } 673 | 674 | CONTROL_INST (bit_field.n = 1); 675 | CONTROL_INST (bit_field.i = 1); 676 | CONTROL_INST (bit_field.x = 0); 677 | CONTROL_INST (bit_field.b = 0); 678 | CONTROL_INST (bit_field.p = 0); 679 | if (statement.extend) 680 | instruction_for_4.bit_field.address = 0; 681 | else 682 | instruction_for_3.bit_field.disp = 0; 683 | } 684 | else // OPCODE_FORMAT_3_4_GENERAL 685 | { 686 | if (statement.token_cnt > 2 || statement.token_cnt < 1) 687 | { 688 | ret = -1; 689 | goto ERROR; 690 | } 691 | 692 | /* Index 모드 처리. */ 693 | if (statement.token_cnt == 2) 694 | { 695 | if (strcmp (statement.token_list[1], "X") != 0) 696 | { 697 | ret = -1; 698 | goto ERROR; 699 | } 700 | CONTROL_INST (bit_field.x = 1); 701 | } 702 | else 703 | { 704 | CONTROL_INST (bit_field.x = 0); 705 | } 706 | 707 | const char *operand = statement.token_list[0]; 708 | 709 | /* Addressing 모드 처리 */ 710 | 711 | bool operand_is_constant = false; 712 | 713 | // Immediate addressing 714 | if (operand[0] == '#') 715 | { 716 | CONTROL_INST(bit_field.n = 0); 717 | CONTROL_INST(bit_field.i = 1); 718 | if ('0' <= operand[1] && operand[1] <= '9') 719 | operand_is_constant = true; 720 | ++operand; 721 | } 722 | // Indirect addressing 723 | else if (operand[0] == '@') 724 | { 725 | CONTROL_INST(bit_field.n = 1); 726 | CONTROL_INST(bit_field.i = 0); 727 | ++operand; 728 | } 729 | // simple addressing 730 | else 731 | { 732 | CONTROL_INST(bit_field.n = 1); 733 | CONTROL_INST(bit_field.i = 1); 734 | } 735 | 736 | uint32_t operand_value; 737 | 738 | if (operand_is_constant) 739 | { 740 | operand_value = strtol (operand, NULL, 10); 741 | } 742 | else 743 | { 744 | const struct symbol *symbol = symbol_find (symbol_manager, operand); 745 | if (!symbol) 746 | { 747 | ret = -1; 748 | goto ERROR; 749 | } 750 | operand_value = symbol->LOCCTR; 751 | } 752 | 753 | if (statement.extend) 754 | { 755 | instruction_for_4.bit_field.b = 0; 756 | instruction_for_4.bit_field.p = 0; 757 | instruction_for_4.bit_field.address = operand_value; 758 | if (!operand_is_constant) 759 | mod_LOCCTR_list[mod_LOCCTR_cnt++] = LOCCTR+1; 760 | } 761 | else if (operand_is_constant) 762 | { 763 | instruction_for_3.bit_field.b = 0; 764 | instruction_for_3.bit_field.p = 0; 765 | instruction_for_3.bit_field.disp = operand_value; 766 | } 767 | else 768 | { 769 | /* Displacement 계산 */ 770 | int32_t disp; 771 | 772 | /* 먼저 PC relative가 가능한 지 확인 */ 773 | const size_t PC = LOCCTR + statement_size; 774 | 775 | disp = operand_value - PC; 776 | 777 | // PC relative가 가능한 경우 778 | if (-(1 << 11) <= disp && disp < (1 << 11)) 779 | { 780 | instruction_for_3.bit_field.b = 0; 781 | instruction_for_3.bit_field.p = 1; 782 | instruction_for_3.bit_field.disp = disp; 783 | } 784 | // PC relative가 불가능한 경우 785 | else 786 | { 787 | /* Base relative가 가능한 지 확인 */ 788 | 789 | // Base가 없을 경우, 에러.. 790 | if (!exist_base) 791 | { 792 | ret = -1; 793 | goto ERROR; 794 | } 795 | 796 | disp = operand_value - base; 797 | 798 | // Base relative가 가능한 경우 799 | if (0 <= disp && disp < (1 << 12)) 800 | { 801 | instruction_for_3.bit_field.b = 1; 802 | instruction_for_3.bit_field.p = 0; 803 | instruction_for_3.bit_field.disp = disp; 804 | } 805 | // Base relative가 불가능한 경우 806 | else 807 | { 808 | ret = -1; 809 | goto ERROR; 810 | } 811 | } /* PC Relative 가 불가능한 경우의 scope */ 812 | } /* Displacement를 계산해야하는 경우의 scope */ 813 | } /* OPCODE_FORMAT_3_4_GENERAL인 경우의 scope */ 814 | 815 | if (statement.extend) 816 | object_code = instruction_for_4.val; 817 | else 818 | object_code = instruction_for_3.val; 819 | 820 | #undef CONTROL_INST 821 | } /* OPCODE_FORMAT_3_4인 경우의 scope */ 822 | else if (statement.opcode->op_format == OPCODE_BASE) 823 | { 824 | if (statement.token_cnt != 1) 825 | { 826 | ret = -1; 827 | goto ERROR; 828 | } 829 | const struct symbol *symbol = symbol_find (symbol_manager, statement.token_list[0]); 830 | if (!symbol) 831 | { 832 | ret = -1; 833 | goto ERROR; 834 | } 835 | exist_base = true; 836 | base = symbol->LOCCTR; 837 | } 838 | else if (statement.opcode->op_format == OPCODE_NOBASE) 839 | { 840 | exist_base = false; 841 | } 842 | else if (statement.opcode->op_format == OPCODE_BYTE) 843 | { 844 | if (statement.token_cnt != 1) 845 | { 846 | ret = -1; 847 | goto ERROR; 848 | } 849 | 850 | const char *operand = statement.token_list[0]; 851 | int len = strlen (operand); 852 | 853 | if (len > 500) 854 | { 855 | ret = -1; 856 | goto ERROR; 857 | } 858 | 859 | if (operand[0] == 'C') 860 | { 861 | int idx = 0; 862 | for (int i = 2; i < len-1; ++i) 863 | { 864 | unsigned char ch = operand[i]; 865 | uint8_t val[2] = { ch / 16 , ch % 16 }; 866 | for (int j = 0; j < 2; ++j, ++idx) 867 | { 868 | if (/*0 <= val[j] && */val[j] <= 9) 869 | byte_buf[idx] = val[j] + '0'; 870 | else 871 | byte_buf[idx] = val[j] - 10 + 'A'; 872 | } 873 | } 874 | byte_buf[idx] = '\0'; 875 | } 876 | else if (operand[0] == 'X') 877 | { 878 | int i; 879 | for (i = 2; i < len-1; ++i) 880 | byte_buf[i-2] = operand[i]; 881 | byte_buf[i-2] = '\0'; 882 | } 883 | else 884 | { 885 | ret = -1; 886 | goto ERROR; 887 | } 888 | } /* OPCODE_BYTE인 경우의 scope */ 889 | else if (statement.opcode->op_format == OPCODE_WORD) 890 | { 891 | if (statement.token_cnt != 1) 892 | { 893 | ret = -1; 894 | goto ERROR; 895 | } 896 | int32_t val = strtol (statement.token_list[0], NULL, 10); 897 | object_code = val; 898 | } 899 | else 900 | { 901 | // nothing to do 902 | } 903 | 904 | const char *format; 905 | if (statement.opcode->op_format == OPCODE_FORMAT_1) 906 | { 907 | format = "%d\t%04X%-30s%02X\n"; 908 | VERIFY_TEXT_RECORD_MAX_BYTES (1); 909 | sprintf (obj_buf + strlen (obj_buf), "%02X", object_code); 910 | } 911 | else if (statement.opcode->op_format == OPCODE_FORMAT_2) 912 | { 913 | format = "%d\t%04X%-30s%04X\n"; 914 | VERIFY_TEXT_RECORD_MAX_BYTES (2); 915 | sprintf (obj_buf + strlen (obj_buf), "%04X", object_code); 916 | } 917 | else if (statement.opcode->op_format == OPCODE_FORMAT_3_4) 918 | { 919 | if (statement.extend) 920 | { 921 | format = "%d\t%04X%-30s%08X\n"; 922 | VERIFY_TEXT_RECORD_MAX_BYTES (4); 923 | sprintf (obj_buf + strlen (obj_buf), "%08X", object_code); 924 | } 925 | else 926 | { 927 | format = "%d\t%04X%-30s%06X\n"; 928 | VERIFY_TEXT_RECORD_MAX_BYTES (3); 929 | sprintf (obj_buf + strlen (obj_buf), "%06X", object_code); 930 | } 931 | } 932 | else if (statement.opcode->op_format == OPCODE_BYTE) 933 | { 934 | fprintf (lst_fp, "%d\t%04X%-30s%s\n", line_no, LOCCTR, statement.input, byte_buf); 935 | format = NULL; 936 | VERIFY_TEXT_RECORD_MAX_BYTES (strlen (byte_buf)); 937 | sprintf (obj_buf + strlen (obj_buf), "%s", byte_buf); 938 | } 939 | else if (statement.opcode->op_format == OPCODE_WORD) 940 | { 941 | format = "%d\t%04X%-30s%06X\n"; 942 | VERIFY_TEXT_RECORD_MAX_BYTES (3); 943 | sprintf (obj_buf + strlen (obj_buf), "%06X", object_code); 944 | } 945 | else 946 | { 947 | fprintf (lst_fp, "%d\t%s\n", line_no, statement.input); 948 | format = NULL; 949 | } 950 | 951 | if (format) 952 | fprintf (lst_fp, format, line_no, LOCCTR, statement.input, object_code); 953 | } /* 주석이 아닌 경우의 scope */ 954 | 955 | if (feof (mid_fp) != 0) 956 | break; 957 | if (!statement.is_comment && statement.opcode->op_format == OPCODE_END) 958 | break; 959 | 960 | if (fetch_statement (mid_fp, opcode_manager, &statement, true, &LOCCTR, &statement_size) != 0) 961 | { 962 | /* handling error */ 963 | ret = -1; 964 | goto ERROR; 965 | } 966 | 967 | line_no += 5; 968 | } /* Outer while문의 scope */ 969 | 970 | LOCCTR += statement_size; 971 | 972 | VERIFY_TEXT_RECORD_MAX_BYTES (TEXT_RECORD_MAX_BYTES_PER_ROW); 973 | for (int i = 0; i < mod_LOCCTR_cnt; ++i) 974 | { 975 | snprintf (rec_head, MAX_REC_HEAD_LEN, "M%06X05", mod_LOCCTR_list[i]); 976 | fprintf (obj_fp, "%s\n", rec_head); 977 | } 978 | snprintf (rec_head, MAX_REC_HEAD_LEN, "E%06X", start_LOCCTR); 979 | fprintf (obj_fp, "%s\n", rec_head); 980 | snprintf (rec_head, MAX_REC_HEAD_LEN, "H%-6s%06X%06X", program_name, start_LOCCTR, LOCCTR - start_LOCCTR); 981 | fseek (obj_fp, 0, SEEK_SET); 982 | fprintf (obj_fp, "%s\n", rec_head); 983 | 984 | ret = 0; 985 | goto END; 986 | 987 | #undef VERIFY_TEXT_RECORD_MAX_BYTES 988 | 989 | ERROR: 990 | fprintf (stderr, "[ERROR] Line no %d: an error occurs in pass 2.\n", line_no); 991 | END: 992 | if (mid_fp) 993 | fclose (mid_fp); 994 | if (lst_fp) 995 | fclose (lst_fp); 996 | if (obj_fp) 997 | fclose (obj_fp); 998 | 999 | return ret; 1000 | } 1001 | -------------------------------------------------------------------------------- /assemble.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASSEMBLE_H__ 2 | #define __ASSEMBLE_H__ 3 | 4 | #include "opcode.h" 5 | #include "symbol.h" 6 | 7 | /* 8 | // Not used now.. But it can be used later. 9 | struct assemble_result 10 | { 11 | int error_code; 12 | char *error_msg; 13 | }; 14 | */ 15 | 16 | /* 성공 시 0, 그렇지 않을 경우 그외의 값을 반환. */ 17 | int assemble (const char *filename, const struct opcode_manager *opcode_manager, 18 | struct symbol_manager *symbol_manager /*, struct assemble_result *result */); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /command.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "command.h" 11 | #include "assemble.h" 12 | #include "loader.h" 13 | #include "run.h" 14 | 15 | #define COMMAND_TOKEN_MAX_NUM 8 16 | 17 | /* 사용자가 입력한 명령에 대한 parsing / processing 결과에 대한 코드 */ 18 | #define COMMAND_STATUS_SUCCESS 0 19 | #define COMMAND_STATUS_INVALID_INPUT 1 20 | #define COMMAND_STATUS_TOO_MANY_TOKENS 2 21 | #define COMMAND_STATUS_FAIL_TO_PROCESS 3 22 | 23 | enum command_type 24 | { 25 | COMMAND_HELP, COMMAND_DIR, COMMAND_QUIT, COMMAND_HISTORY, 26 | COMMAND_DUMP, COMMAND_EDIT, COMMAND_FILL, COMMAND_RESET, 27 | COMMAND_OPCODE, COMMAND_OPCODELIST, 28 | COMMAND_ASSEMBLE, COMMAND_TYPE, COMMAND_SYMBOL, 29 | COMMAND_PROGADDR, COMMAND_LOADER, 30 | COMMAND_RUN, COMMAND_BP 31 | }; 32 | 33 | /* 사용자가 입력한 명령을 의미하는 구조체 */ 34 | struct command 35 | { 36 | enum command_type type; 37 | size_t token_cnt; 38 | char *token_list[COMMAND_TOKEN_MAX_NUM+1]; // 사용자가 입력한 명령어가 token별로 쪼개서 여기에 들어간다. 39 | char *input; // 사용자 입력한 명령어 라인 전부가 이 곳에 들어간다. 40 | }; 41 | 42 | static int command_fetch (struct command *command); 43 | static int command_process (struct command_state *state, struct command *command, bool *quit); 44 | 45 | static int command_h_help (struct command_state *state, struct command *command); 46 | static int command_h_dir (struct command_state *state, struct command *command); 47 | static int command_h_history (struct command_state *state, struct command *command); 48 | static int command_h_dump (struct command_state *state, struct command *command); 49 | static int command_h_edit (struct command_state *state, struct command *command); 50 | static int command_h_fill (struct command_state *state, struct command *command); 51 | static int command_h_reset (struct command_state *state, struct command *command); 52 | static int command_h_opcode (struct command_state *state, struct command *command); 53 | static int command_h_opcodelist (struct command_state *state, struct command *command); 54 | static int command_h_assemble (struct command_state *state, struct command *command); 55 | static int command_h_type (struct command_state *state, struct command *command); 56 | static int command_h_symbol (struct command_state *state, struct command *command); 57 | static int command_h_progaddr (struct command_state *state, struct command *command); 58 | static int command_h_loader (struct command_state *state, struct command *command); 59 | static int command_h_run(struct command_state *state, struct command *command); 60 | static int command_h_bp (struct command_state *state, struct command *command); 61 | 62 | bool command_loop (struct command_state *state) 63 | { 64 | struct command command; 65 | bool quit = false; 66 | 67 | while (!quit) 68 | { 69 | int error_code; 70 | 71 | printf("sicsim> "); 72 | error_code = command_fetch (&command); 73 | 74 | switch (error_code) 75 | { 76 | case COMMAND_STATUS_SUCCESS: 77 | break; 78 | 79 | case COMMAND_STATUS_INVALID_INPUT: 80 | fprintf (stderr, "[ERROR] Invalid command!\n"); 81 | continue; 82 | 83 | case COMMAND_STATUS_TOO_MANY_TOKENS: 84 | fprintf (stderr, "[ERROR] Too many tokens.\n"); 85 | continue; 86 | 87 | default: 88 | assert (false); 89 | } 90 | 91 | error_code = command_process (state, &command, &quit); 92 | 93 | switch (error_code) 94 | { 95 | case COMMAND_STATUS_SUCCESS: 96 | break; 97 | 98 | case COMMAND_STATUS_INVALID_INPUT: 99 | fprintf (stderr, "[ERROR] Invalid command parameters!!!\n"); 100 | continue; 101 | 102 | case COMMAND_STATUS_FAIL_TO_PROCESS: 103 | fprintf (stderr, "[ERROR] Fail to process your command.\n"); 104 | continue; 105 | 106 | default: 107 | assert (false); 108 | } 109 | 110 | history_insert (state->history_manager, command.input); 111 | } 112 | 113 | return true; 114 | } 115 | 116 | /* Command를 fetch하는 함수. 117 | * 사용자로 부터 명령어를 입력받고, 그 것을 바탕으로 command 구조체를 구축한다. 118 | */ 119 | static int command_fetch (struct command *command) 120 | { 121 | static char input[COMMAND_INPUT_MAX_LEN]; 122 | static char input_token[COMMAND_INPUT_MAX_LEN]; 123 | 124 | fgets (input, COMMAND_INPUT_MAX_LEN, stdin); 125 | strncpy (input_token, input, COMMAND_INPUT_MAX_LEN); 126 | 127 | command->input = input; 128 | command->token_cnt = 0; 129 | command->token_list[command->token_cnt] = strtok (input_token, " ,\t\n"); 130 | while (command->token_cnt <= COMMAND_TOKEN_MAX_NUM && command->token_list[command->token_cnt]) 131 | command->token_list[++command->token_cnt] = strtok (NULL, " ,\t\n"); 132 | 133 | if (command->token_cnt <= 0) 134 | return COMMAND_STATUS_INVALID_INPUT; 135 | 136 | if (command->token_cnt > COMMAND_TOKEN_MAX_NUM) 137 | return COMMAND_STATUS_TOO_MANY_TOKENS; 138 | 139 | #define COMPARE_WITH(STR) \ 140 | (strcmp (command->token_list[0], (STR)) == 0) 141 | 142 | if (COMPARE_WITH ("h") || COMPARE_WITH ("help")) 143 | command->type = COMMAND_HELP 144 | ; 145 | else if (COMPARE_WITH ("d") || COMPARE_WITH ("dir")) 146 | command->type = COMMAND_DIR 147 | ; 148 | else if (COMPARE_WITH ("q") || COMPARE_WITH ("quit")) 149 | command->type = COMMAND_QUIT 150 | ; 151 | else if (COMPARE_WITH ("hi") || COMPARE_WITH ("history")) 152 | command->type = COMMAND_HISTORY 153 | ; 154 | else if (COMPARE_WITH ("du") || COMPARE_WITH ("dump")) 155 | command->type = COMMAND_DUMP 156 | ; 157 | else if (COMPARE_WITH ("e") || COMPARE_WITH ("edit")) 158 | command->type = COMMAND_EDIT 159 | ; 160 | else if (COMPARE_WITH ("f") || COMPARE_WITH ("fill")) 161 | command->type = COMMAND_FILL 162 | ; 163 | else if (COMPARE_WITH ("reset")) 164 | command->type = COMMAND_RESET 165 | ; 166 | else if (COMPARE_WITH ("opcode")) 167 | command->type = COMMAND_OPCODE 168 | ; 169 | else if (COMPARE_WITH ("opcodelist")) 170 | command->type = COMMAND_OPCODELIST 171 | ; 172 | else if (COMPARE_WITH ("assemble")) 173 | command->type = COMMAND_ASSEMBLE 174 | ; 175 | else if (COMPARE_WITH ("type")) 176 | command->type = COMMAND_TYPE 177 | ; 178 | else if (COMPARE_WITH ("symbol")) 179 | command->type = COMMAND_SYMBOL 180 | ; 181 | else if (COMPARE_WITH ("progaddr")) 182 | command->type = COMMAND_PROGADDR 183 | ; 184 | else if (COMPARE_WITH ("loader")) 185 | command->type = COMMAND_LOADER 186 | ; 187 | else if (COMPARE_WITH ("run")) 188 | command->type = COMMAND_RUN 189 | ; 190 | else if (COMPARE_WITH ("bp")) 191 | command->type = COMMAND_BP 192 | ; 193 | else 194 | return COMMAND_STATUS_INVALID_INPUT; 195 | 196 | #undef COMPARE_WITH 197 | 198 | return COMMAND_STATUS_SUCCESS; 199 | } 200 | 201 | /* Command를 처리하는 함수. 202 | * command type에 따라 서로 다른 handler를 호출해 준다. 203 | */ 204 | static int command_process (struct command_state *state, struct command *command, bool *quit) 205 | { 206 | *quit = false; 207 | 208 | switch (command->type) 209 | { 210 | case COMMAND_HELP: 211 | return command_h_help (state, command); 212 | ; 213 | case COMMAND_DIR: 214 | return command_h_dir (state, command); 215 | ; 216 | case COMMAND_QUIT: 217 | *quit = true; 218 | return COMMAND_STATUS_SUCCESS; 219 | ; 220 | case COMMAND_HISTORY: 221 | return command_h_history (state, command); 222 | ; 223 | case COMMAND_DUMP: 224 | return command_h_dump (state, command); 225 | ; 226 | case COMMAND_EDIT: 227 | return command_h_edit (state, command); 228 | ; 229 | case COMMAND_FILL: 230 | return command_h_fill (state, command); 231 | ; 232 | case COMMAND_RESET: 233 | return command_h_reset (state, command); 234 | ; 235 | case COMMAND_OPCODE: 236 | return command_h_opcode (state, command); 237 | ; 238 | case COMMAND_OPCODELIST: 239 | return command_h_opcodelist (state, command); 240 | ; 241 | case COMMAND_ASSEMBLE: 242 | return command_h_assemble (state, command); 243 | ; 244 | case COMMAND_TYPE: 245 | return command_h_type (state, command); 246 | ; 247 | case COMMAND_SYMBOL: 248 | return command_h_symbol (state, command); 249 | ; 250 | case COMMAND_PROGADDR: 251 | return command_h_progaddr (state, command); 252 | ; 253 | case COMMAND_LOADER: 254 | return command_h_loader (state, command); 255 | ; 256 | case COMMAND_RUN: 257 | return command_h_run (state, command); 258 | ; 259 | case COMMAND_BP: 260 | return command_h_bp (state, command); 261 | ; 262 | default: 263 | return COMMAND_STATUS_INVALID_INPUT; 264 | } 265 | } 266 | 267 | /* help 명령어에 대한 handler. */ 268 | static int command_h_help (__attribute__((unused)) struct command_state *state, __attribute__((unused)) struct command *command) 269 | { 270 | if (command->token_cnt != 1) 271 | return COMMAND_STATUS_INVALID_INPUT; 272 | 273 | printf ("h[elp]\n" 274 | "d[ir]\n" 275 | "q[uit]\n" 276 | "hi[story]\n" 277 | "du[mp] [start, end]\n" 278 | "e[dit] address, value\n" 279 | "f[ill] start, end, value\n" 280 | "reset\n" 281 | "opcode mnemonic\n" 282 | "opcodelist\n" 283 | "assemble filename\n" 284 | "type filename\n" 285 | "symbol\n" 286 | "progaddr address\n" 287 | "loader object_filename_1 [object file names...]\n" 288 | "run\n" 289 | "bp [address]\n" 290 | "bp clear\n" 291 | ); 292 | return COMMAND_STATUS_SUCCESS; 293 | } 294 | 295 | /* dir 명령어에 대한 handler */ 296 | static int command_h_dir (__attribute__((unused)) struct command_state *state, __attribute__((unused)) struct command *command) 297 | { 298 | if (command->token_cnt != 1) 299 | return COMMAND_STATUS_INVALID_INPUT; 300 | 301 | DIR *dir; 302 | struct dirent *entry; 303 | struct stat stat; 304 | 305 | if (!(dir = opendir ("."))) 306 | { 307 | fprintf (stderr, "[ERROR] Cannot open directory '.'\n"); 308 | return COMMAND_STATUS_FAIL_TO_PROCESS; 309 | } 310 | 311 | char buf[1024]; // need to be refactored. 312 | int cnt = 0; 313 | printf ("\t"); 314 | while ((entry = readdir (dir))) 315 | { 316 | lstat (entry->d_name, &stat); 317 | 318 | if (S_ISDIR (stat.st_mode)) 319 | sprintf (buf, "%s/", entry->d_name); 320 | else if (S_IXUSR & stat.st_mode) 321 | sprintf (buf, "%s*", entry->d_name); 322 | else 323 | sprintf (buf, "%s ", entry->d_name); 324 | 325 | printf ("%-20s", buf); 326 | 327 | if (++cnt % 4 == 0) 328 | printf("\n\t"); 329 | } 330 | if (cnt % 4 != 0) 331 | printf ("\n"); 332 | 333 | closedir (dir); 334 | 335 | return COMMAND_STATUS_SUCCESS; 336 | } 337 | 338 | /* history 명령어에 대한 handler */ 339 | static int command_h_history (struct command_state *state, struct command *command) 340 | { 341 | if (command->token_cnt != 1) 342 | return COMMAND_STATUS_INVALID_INPUT; 343 | 344 | history_print (state->history_manager, command->input); 345 | return COMMAND_STATUS_SUCCESS; 346 | } 347 | 348 | /* dump 명령어에 대한 handler */ 349 | static int command_h_dump (struct command_state *state, struct command *command) 350 | { 351 | uint32_t start, end; 352 | bool enable_max_end; 353 | uint32_t memory_size = memory_get_memory_size (state->memory_manager); 354 | 355 | // 명령어의 형태가 매개변수없는 dump 일 때, 356 | if (command->token_cnt == 1) 357 | { 358 | start = state->saved_dump_start; 359 | end = start + 159; 360 | // memory size를 넘어가는 경우, 다음 dump때 출력할 위치를 0으로 초기화한다. 361 | if (end > memory_size) 362 | state->saved_dump_start = 0; 363 | else 364 | state->saved_dump_start += 160; 365 | enable_max_end = true; 366 | } 367 | // 명령어의 형태가 dump start 일 때, 368 | else if (command->token_cnt == 2) 369 | { 370 | start = strtol (command->token_list[1], NULL, 16); 371 | end = start + 159; 372 | enable_max_end = true; 373 | } 374 | // 명령어의 형태가 dump start, end 일 때, 375 | else if (command->token_cnt == 3) 376 | { 377 | start = strtol (command->token_list[1], NULL, 16); 378 | end = strtol (command->token_list[2], NULL, 16); 379 | enable_max_end = false; 380 | } 381 | else 382 | return COMMAND_STATUS_INVALID_INPUT; 383 | 384 | if (!memory_dump (state->memory_manager, start, end, enable_max_end)) 385 | { 386 | return COMMAND_STATUS_INVALID_INPUT; 387 | } 388 | 389 | return COMMAND_STATUS_SUCCESS; 390 | } 391 | 392 | /* edit 명령어에 대한 handler */ 393 | static int command_h_edit (struct command_state *state, struct command *command) 394 | { 395 | if (command->token_cnt != 3) 396 | return COMMAND_STATUS_INVALID_INPUT; 397 | 398 | uint32_t offset; 399 | uint32_t val; 400 | 401 | offset = strtol (command->token_list[1], NULL, 16); 402 | val = strtol (command->token_list[2], NULL, 16); 403 | if (val > 0xFF) 404 | return COMMAND_STATUS_INVALID_INPUT; 405 | 406 | if (!memory_edit (state->memory_manager, offset, (uint8_t) val)) 407 | { 408 | return COMMAND_STATUS_INVALID_INPUT; 409 | } 410 | 411 | return COMMAND_STATUS_SUCCESS; 412 | } 413 | 414 | /* fill 명령어에 대한 handler */ 415 | static int command_h_fill (struct command_state *state, struct command *command) 416 | { 417 | if (command->token_cnt != 4) 418 | return COMMAND_STATUS_INVALID_INPUT; 419 | 420 | uint32_t start, end; 421 | uint32_t val; 422 | 423 | start = strtol (command->token_list[1], NULL, 16); 424 | end = strtol (command->token_list[2], NULL, 16); 425 | val = strtol (command->token_list[3], NULL, 16); 426 | if (val > 0xFF) 427 | return COMMAND_STATUS_INVALID_INPUT; 428 | 429 | if (!memory_fill (state->memory_manager, start, end, (uint8_t) val)) 430 | { 431 | return COMMAND_STATUS_INVALID_INPUT; 432 | } 433 | 434 | return COMMAND_STATUS_SUCCESS; 435 | } 436 | 437 | /* reset 명령어에 대한 handler */ 438 | static int command_h_reset (struct command_state *state, struct command *command) 439 | { 440 | if (command->token_cnt != 1) 441 | return COMMAND_STATUS_INVALID_INPUT; 442 | 443 | memory_reset (state->memory_manager); 444 | return COMMAND_STATUS_SUCCESS; 445 | } 446 | 447 | /* opcode 명령어에 대한 handler */ 448 | static int command_h_opcode (struct command_state *state, struct command *command) 449 | { 450 | if (command->token_cnt != 2) 451 | return COMMAND_STATUS_INVALID_INPUT; 452 | 453 | const struct opcode *opcode = opcode_find (state->opcode_manager, command->token_list[1]); 454 | 455 | if (opcode) 456 | { 457 | printf ("opcode is %02X\n", opcode->val); 458 | return COMMAND_STATUS_SUCCESS; 459 | } 460 | else 461 | { 462 | fprintf (stderr, "[ERROR] Cannot find opcode.\n"); 463 | return COMMAND_STATUS_FAIL_TO_PROCESS; 464 | } 465 | } 466 | 467 | /* opcodelist 명령어에 대한 handler */ 468 | static int command_h_opcodelist (struct command_state *state, struct command *command) 469 | { 470 | if (command->token_cnt != 1) 471 | return COMMAND_STATUS_INVALID_INPUT; 472 | 473 | opcode_print_list (state->opcode_manager); 474 | return COMMAND_STATUS_SUCCESS; 475 | } 476 | 477 | static int command_h_assemble (struct command_state *state, struct command *command) 478 | { 479 | if (command->token_cnt != 2) 480 | return COMMAND_STATUS_INVALID_INPUT; 481 | 482 | struct symbol_manager *symbol_manager = symbol_manager_construct (); 483 | int error_code = assemble (command->token_list[1], state->opcode_manager, symbol_manager); 484 | if (error_code != 0) 485 | { 486 | fprintf (stderr, "[ERROR] Assemble Fail.\n"); 487 | symbol_manager_destroy (symbol_manager); 488 | return COMMAND_STATUS_FAIL_TO_PROCESS; 489 | } 490 | 491 | if (state->symbol_manager) 492 | symbol_manager_destroy (state->symbol_manager); 493 | 494 | state->symbol_manager = symbol_manager; 495 | 496 | return COMMAND_STATUS_SUCCESS; 497 | } 498 | 499 | static int command_h_type (__attribute__((unused)) struct command_state *state, struct command *command) 500 | { 501 | if (command->token_cnt != 2) 502 | return COMMAND_STATUS_INVALID_INPUT; 503 | 504 | FILE *fp = fopen (command->token_list[1], "rt"); 505 | 506 | if (!fp) 507 | { 508 | fprintf (stderr, "[ERROR] Invalid file name: %s\n", command->token_list[1]); 509 | return COMMAND_STATUS_INVALID_INPUT; 510 | } 511 | 512 | char buf[512]; 513 | 514 | // TODO: 마지막 개행 처리?? 515 | while (fgets (buf, sizeof(buf), fp)) 516 | fputs (buf, stdout); 517 | 518 | fclose (fp); 519 | 520 | return COMMAND_STATUS_SUCCESS; 521 | } 522 | 523 | static int command_h_symbol (struct command_state *state, struct command *command) 524 | { 525 | if (command->token_cnt != 1) 526 | return COMMAND_STATUS_INVALID_INPUT; 527 | 528 | if (!state->symbol_manager) 529 | { 530 | fprintf (stderr, "[ERROR] There is no symbol table.\n"); 531 | return COMMAND_STATUS_FAIL_TO_PROCESS; 532 | } 533 | 534 | symbol_print_list (state->symbol_manager); 535 | 536 | return COMMAND_STATUS_SUCCESS; 537 | } 538 | 539 | static int command_h_progaddr (struct command_state *state, struct command *command) 540 | { 541 | if (command->token_cnt != 2) 542 | return COMMAND_STATUS_INVALID_INPUT; 543 | 544 | uint32_t progaddr; 545 | progaddr = strtol (command->token_list[1], NULL, 16); 546 | 547 | if (progaddr > 0xFFFF) 548 | { 549 | fprintf (stderr, "[ERROR] Invalid progaddr : %s\n", command->token_list[1]); 550 | return COMMAND_STATUS_INVALID_INPUT; 551 | } 552 | 553 | state->progaddr = progaddr; 554 | 555 | return COMMAND_STATUS_SUCCESS; 556 | } 557 | 558 | static int command_h_loader (struct command_state *state, struct command *command) 559 | { 560 | if (command->token_cnt == 1) 561 | { 562 | fprintf (stderr, "[ERROR] No object file names.\n"); 563 | return COMMAND_STATUS_INVALID_INPUT; 564 | } 565 | else if (command->token_cnt > 4) 566 | { 567 | fprintf (stderr, "[ERROR] Maximum of the number of object files is 4.\n"); 568 | return COMMAND_STATUS_INVALID_INPUT; 569 | } 570 | 571 | static char *object_filename_list[3]; 572 | 573 | for (size_t i = 1; i < command->token_cnt; ++i) 574 | object_filename_list[i-1] = command->token_list[i]; 575 | 576 | // TODO: memory manager의 예외 안정성 고려하기. 577 | int error_code = loader(state->memory_manager, state->progaddr, 578 | (const char **)object_filename_list, command->token_cnt-1); 579 | if (error_code != 0) 580 | { 581 | fprintf (stderr, "[ERROR] Loader Fail.\n"); 582 | return COMMAND_STATUS_FAIL_TO_PROCESS; 583 | } 584 | 585 | return COMMAND_STATUS_SUCCESS; 586 | } 587 | 588 | static int command_h_run(struct command_state *state, struct command *command) 589 | { 590 | if (!state->is_running) 591 | state->reg_set.PC = state->progaddr; 592 | int error_code = run (state->memory_manager, state->debug_manager, &state->reg_set, &state->is_running); 593 | if (error_code != 0) 594 | { 595 | fprintf (stderr, "[ERROR] Run Fail.\n"); 596 | return COMMAND_STATUS_FAIL_TO_PROCESS; 597 | } 598 | 599 | printf ( 600 | "A : %08X X : %08X \n" 601 | "L : %08X PC: %08X \n" 602 | "B : %08X S : %08X \n" 603 | "T : %08X \n", 604 | state->reg_set.A, state->reg_set.X, 605 | state->reg_set.L, state->reg_set.PC, 606 | state->reg_set.B, state->reg_set.S, 607 | state->reg_set.T 608 | ); 609 | 610 | return COMMAND_STATUS_SUCCESS; 611 | } 612 | 613 | static int command_h_bp (struct command_state *state, struct command *command) 614 | { 615 | if (command->token_cnt > 2) 616 | return COMMAND_STATUS_INVALID_INPUT; 617 | 618 | if (command->token_cnt == 1) 619 | { 620 | debug_bp_print_list (state->debug_manager); 621 | } 622 | else 623 | { 624 | if (strcmp (command->token_list[1], "clear") == 0) 625 | { 626 | debug_bp_clear (state->debug_manager); 627 | } 628 | else 629 | { 630 | uint32_t address = strtol (command->token_list[1], NULL, 16); 631 | debug_bp_add (state->debug_manager, address); 632 | } 633 | } 634 | 635 | return COMMAND_STATUS_SUCCESS; 636 | } 637 | -------------------------------------------------------------------------------- /command.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMAND_H__ 2 | #define __COMMAND_H__ 3 | 4 | #include 5 | 6 | #include "history.h" 7 | #include "memory.h" 8 | #include "opcode.h" 9 | #include "symbol.h" 10 | #include "debug.h" 11 | #include "command_def.h" 12 | #include "run.h" 13 | 14 | /* Command Loop의 state를 의미하는 구조체 15 | * command loop 내에서 이 state 구조체 정보를 바탕으로 사용자 명령들을 처리하게 된다. 16 | * 만약, memory manager를 바꾼다던지 등등, state를 변경하고 싶다면, command loop내에서 17 | * 이 구조체 내의 값들을 변경하면 된다. 18 | */ 19 | struct command_state 20 | { 21 | struct history_manager *history_manager; 22 | struct memory_manager *memory_manager; 23 | struct opcode_manager *opcode_manager; 24 | struct symbol_manager *symbol_manager; 25 | struct debug_manager *debug_manager; 26 | struct run_register_set reg_set; 27 | bool is_running; 28 | uint32_t saved_dump_start; /* parameter가 없는 dump 명령어에서 위치를 저장하기 위해 쓰인다. */ 29 | uint32_t progaddr; /* loader 또는 run 명령어를 수행할 때 시작하는 주소. */ 30 | }; 31 | 32 | /* 사용자의 입력을 받아서 처리하는 Command Loop로 진입하는 함수. */ 33 | bool command_loop (struct command_state *state); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /command_def.h: -------------------------------------------------------------------------------- 1 | #ifndef __COMMAND_DEF_H__ 2 | #define __COMMAND_DEF_H__ 3 | 4 | #define COMMAND_INPUT_MAX_LEN 100 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "debug.h" 5 | 6 | #define INITIAL_BP_LIST_MAX_SIZE 10 7 | 8 | struct debug_manager 9 | { 10 | uint32_t *bp_list; 11 | uint32_t cnt; 12 | uint32_t max_size; 13 | }; 14 | 15 | struct debug_manager *debug_manager_construct () 16 | { 17 | struct debug_manager *manager = malloc (sizeof (*manager)); 18 | manager->max_size = INITIAL_BP_LIST_MAX_SIZE; 19 | manager->cnt = 0; 20 | manager->bp_list = malloc (sizeof (*manager->bp_list) * manager->max_size); 21 | return manager; 22 | } 23 | 24 | void debug_manager_destroy (struct debug_manager *manager) 25 | { 26 | free (manager->bp_list); 27 | free (manager); 28 | } 29 | 30 | bool debug_bp_add (struct debug_manager *manager, uint32_t address) 31 | { 32 | if (debug_bp_check (manager, address, address + 1, NULL)) 33 | return false; 34 | 35 | if (manager->cnt >= manager->max_size) 36 | { 37 | manager->max_size *= 2; 38 | manager->bp_list = realloc (manager->bp_list, sizeof (*manager->bp_list) * manager->max_size); 39 | } 40 | manager->bp_list[manager->cnt++] = address; 41 | return true; 42 | } 43 | 44 | void debug_bp_clear (struct debug_manager *manager) 45 | { 46 | manager->cnt = 0; 47 | manager->max_size = INITIAL_BP_LIST_MAX_SIZE; 48 | free (manager->bp_list); 49 | manager->bp_list = malloc (sizeof (*manager->bp_list) * manager->max_size); 50 | } 51 | 52 | bool debug_bp_check (const struct debug_manager *manager, uint32_t start, uint32_t end, uint32_t *bp) // [start, end) 53 | { 54 | for (size_t i = 0; i < manager->cnt; ++i) 55 | { 56 | if (start <= manager->bp_list[i] && manager->bp_list[i] < end) 57 | { 58 | if (bp) 59 | *bp = manager->bp_list[i]; 60 | return true; 61 | } 62 | } 63 | return false; 64 | } 65 | 66 | void debug_bp_print_list (const struct debug_manager *manager) 67 | { 68 | if (manager->cnt == 0) 69 | { 70 | printf ("There is no breakpoint.\n"); 71 | } 72 | else 73 | { 74 | printf ("breakpoint\n" 75 | "----------\n"); 76 | for (size_t i = 0; i < manager->cnt; ++i) 77 | printf ("%04X\n", manager->bp_list[i]); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEBUG_H__ 2 | #define __DEBUG_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* debug manager 오직 factory 함수를 통해서만 생성될 수 있다. */ 8 | struct debug_manager; 9 | 10 | /* debug manager를 생성하고 소멸시키는 함수들 */ 11 | struct debug_manager *debug_manager_construct (); 12 | void debug_manager_destroy (struct debug_manager *manager); 13 | 14 | /* break points를 조작하는 함수들 */ 15 | bool debug_bp_add (struct debug_manager *manager, uint32_t address); 16 | void debug_bp_clear (struct debug_manager *manager); 17 | bool debug_bp_check (const struct debug_manager *manager, uint32_t start, uint32_t end, uint32_t *bp); // [start, end) 18 | void debug_bp_print_list (const struct debug_manager *manager); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /doc/Document_proj_1.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taeguk/System-Programming-SICXE-Project/53d3280235a09330510efc8d6b9674e4a90b0fc6/doc/Document_proj_1.doc -------------------------------------------------------------------------------- /doc/Document_proj_2.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taeguk/System-Programming-SICXE-Project/53d3280235a09330510efc8d6b9674e4a90b0fc6/doc/Document_proj_2.doc -------------------------------------------------------------------------------- /doc/Document_proj_3.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taeguk/System-Programming-SICXE-Project/53d3280235a09330510efc8d6b9674e4a90b0fc6/doc/Document_proj_3.doc -------------------------------------------------------------------------------- /history.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "history.h" 7 | #include "command_def.h" 8 | #include "list.h" 9 | 10 | struct history_manager 11 | { 12 | struct list *history_list; // history들을 관리하는 링크드 리스트 13 | }; 14 | 15 | struct history 16 | { 17 | char command_str[COMMAND_INPUT_MAX_LEN+1]; 18 | }; 19 | 20 | /* history manager 내의 history_list에 사용될 node 구조체 */ 21 | struct history_node 22 | { 23 | struct history history; 24 | struct list_node list_node; 25 | }; 26 | 27 | /* history manager를 생성하는 factory 함수 */ 28 | struct history_manager *history_manager_construct () 29 | { 30 | struct history_manager *manager = malloc (sizeof(*manager)); 31 | 32 | manager->history_list = list_construct (); 33 | 34 | return manager; 35 | } 36 | 37 | /* history manager를 소멸시키는 함수 */ 38 | void history_manager_destroy (struct history_manager *manager) 39 | { 40 | struct list_node *node; 41 | while ((node = list_pop_front (manager->history_list))) 42 | { 43 | free (list_entry (node, struct history_node, list_node)); 44 | } 45 | list_destroy (manager->history_list); 46 | free (manager); 47 | } 48 | 49 | /* history manager에 history를 추가하는 함수 */ 50 | void history_insert (struct history_manager *manager, const char *command_str) 51 | { 52 | struct history_node *node = malloc (sizeof(*node)); 53 | 54 | strncpy (node->history.command_str, command_str, COMMAND_INPUT_MAX_LEN); 55 | 56 | list_push_back (manager->history_list, &node->list_node); 57 | } 58 | 59 | /* history manager내에 있는 history 들을 출력하는 함수 */ 60 | void history_print (struct history_manager *manager, const char *cur_command_str) 61 | { 62 | struct list_node *node; 63 | int no = 0; 64 | 65 | for (node = list_begin (manager->history_list); 66 | node != list_end (manager->history_list); 67 | node = list_next (node)) 68 | { 69 | struct history_node *history_node = list_entry (node, struct history_node, list_node); 70 | printf ("%-4d %s", ++no, history_node->history.command_str); 71 | } 72 | printf ("%-4d %s", ++no, cur_command_str); 73 | } 74 | -------------------------------------------------------------------------------- /history.h: -------------------------------------------------------------------------------- 1 | #ifndef __HISTORY_H__ 2 | #define __HISTORY_H__ 3 | 4 | /* history manager는 오직 factory 함수를 통해서만 얻을 수 있다. */ 5 | struct history_manager; 6 | 7 | /* history manager를 생성하고 소멸시키는 함수들 */ 8 | struct history_manager *history_manager_construct (); 9 | void history_manager_destroy (struct history_manager *manager); 10 | 11 | /* history manager에 history를 추가하는 함수 */ 12 | void history_insert (struct history_manager *manager, const char *command_str); 13 | 14 | /* history manager내에 있는 history 들을 출력하는 함수 */ 15 | void history_print (struct history_manager *manager, const char *cur_command_str); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "list.h" 5 | 6 | struct list 7 | { 8 | struct list_node head_node; // 링크드 리스트의 맨 앞에 위치하는 dummy node 9 | struct list_node tail_node; // 링크드 리스트의 맨 뒤에 위치하는 dummy node 10 | }; 11 | 12 | /* list를 생성하는 factory 함수 */ 13 | struct list *list_construct () 14 | { 15 | struct list *list = malloc (sizeof(*list)); 16 | 17 | list->head_node.prev = NULL; 18 | list->head_node.next = &list->tail_node; 19 | list->tail_node.prev = &list->head_node; 20 | list->tail_node.next = NULL; 21 | 22 | return list; 23 | } 24 | 25 | /* list를 소멸시키는 함수 */ 26 | void list_destroy (struct list *list) 27 | { 28 | assert (list_empty (list)); 29 | free (list); 30 | } 31 | 32 | /* list의 시작 node를 반환하는 함수 */ 33 | struct list_node *list_begin (struct list *list) 34 | { 35 | assert (list); 36 | return list->head_node.next; 37 | } 38 | 39 | /* 다음 node를 반환하는 함수 */ 40 | struct list_node *list_next (struct list_node *cur_node) 41 | { 42 | assert (cur_node); 43 | return cur_node->next; 44 | } 45 | 46 | /* list의 끝을 의미하는 node (즉, tail dummy node)를 반환하는 함수 */ 47 | struct list_node *list_end (struct list *list) 48 | { 49 | assert (list); 50 | return &list->tail_node; 51 | } 52 | 53 | /* list가 비었는 지 확인해주는 함수. */ 54 | bool list_empty (struct list *list) 55 | { 56 | assert (list); 57 | return list->head_node.next == &list->tail_node; 58 | } 59 | 60 | /* list의 맨 앞에 node를 추가하는 함수 */ 61 | void list_push_front (struct list *list, struct list_node *node) 62 | { 63 | assert (list && node); 64 | 65 | node->prev = &list->head_node; 66 | node->next = list->head_node.next; 67 | list->head_node.next->prev = node; 68 | list->head_node.next = node; 69 | } 70 | 71 | /* list의 맨 뒤에 node를 추가하는 함수 */ 72 | void list_push_back (struct list *list, struct list_node *node) 73 | { 74 | assert (list && node); 75 | 76 | node->prev = list->tail_node.prev; 77 | node->next = &list->tail_node; 78 | list->tail_node.prev->next = node; 79 | list->tail_node.prev = node; 80 | } 81 | 82 | /* list의 맨 앞에서 node를 삭제하고 반환하는 함수 */ 83 | struct list_node *list_pop_front (struct list *list) 84 | { 85 | assert (list && list->head_node.next); 86 | 87 | struct list_node *node = list->head_node.next; 88 | list->head_node.next = node->next; 89 | node->next->prev = &list->head_node; 90 | return node; 91 | } 92 | 93 | /* list의 맨 뒤에서 node를 삭제하고 반환하는 함수 */ 94 | struct list_node *list_pop_back (struct list *list) 95 | { 96 | assert (list && list->tail_node.prev); 97 | 98 | struct list_node *node = list->tail_node.prev; 99 | list->tail_node.prev = node->prev; 100 | node->prev->next = &list->tail_node; 101 | return node; 102 | } 103 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H__ 2 | #define __LIST_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* list 자료구조의 논리구조를 위한 node 구조체 */ 9 | struct list_node 10 | { 11 | struct list_node *prev; 12 | struct list_node *next; 13 | }; 14 | 15 | /* list는 오직 factory 함수를 통해서만 생성될 수 있다. */ 16 | struct list; 17 | 18 | /* list_node로 부터 실제 node (entry) 를 얻어오는 매크로 함수 */ 19 | #define list_entry(LIST_NODE, ENTRY_STRUCT, NODE_MEMBER) \ 20 | ((ENTRY_STRUCT *) ((uint8_t *) &((LIST_NODE)->prev) - offsetof(ENTRY_STRUCT, NODE_MEMBER.prev))) 21 | 22 | /* List를 생성하고 소멸시키는 함수들 */ 23 | struct list *list_construct (); 24 | void list_destroy (struct list *list); // Must be called when list is empty. 25 | 26 | /* List를 순회하는 함수들 */ 27 | struct list_node *list_begin (struct list *list); 28 | struct list_node *list_next (struct list_node *cur_node); 29 | struct list_node *list_end (struct list *list); 30 | 31 | /* List의 property에 대한 함수들 */ 32 | bool list_empty (struct list *list); 33 | 34 | /* List에 node를 추가하는 함수들 */ 35 | void list_push_front (struct list *list, struct list_node *node); 36 | void list_push_back (struct list *list, struct list_node *node); 37 | 38 | /* List에서 node를 삭제하는 함수들 */ 39 | struct list_node *list_pop_front (struct list *list); 40 | struct list_node *list_pop_back (struct list *list); 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "loader.h" 6 | #include "symbol.h" 7 | #include "list.h" 8 | 9 | /* 10 | * ESTAB -> symbol table 활용 11 | * load map -> 자체 구조체의 linked list로서 구현. 12 | * Reference Number -> array table 13 | */ 14 | 15 | enum load_map_node_type 16 | { 17 | LOAD_MAP_NODE_TYPE_CONTROL_SECTION, 18 | LOAD_MAP_NODE_TYPE_SYMBOL 19 | }; 20 | 21 | #define LOAD_MAP_NODE_NAME_MAX_LEN 10 22 | 23 | struct load_map_node 24 | { 25 | enum load_map_node_type type; 26 | char name[LOAD_MAP_NODE_NAME_MAX_LEN + 1]; 27 | uint32_t address; 28 | uint32_t length; /* only used when type == LOAD_MAP_NODE_TYPE_CONTROL_SECTION */ 29 | struct list_node list_node; 30 | }; 31 | 32 | static int loader_pass_1_to_one_obj (uint32_t *CSADDR, struct symbol_manager *ESTAB, struct list *load_map, 33 | const char *obj_file); 34 | static int loader_pass_1 (uint32_t progaddr, struct symbol_manager *ESTAB, struct list *load_map, 35 | const char *obj_file_list[], int count); 36 | 37 | static int loader_pass_2_to_one_obj (uint32_t *CSADDR, const struct symbol_manager *ESTAB, 38 | struct memory_manager *memory_manager, const char *obj_file); 39 | static int loader_pass_2 (uint32_t progaddr, const struct symbol_manager *ESTAB, 40 | struct memory_manager *memory_manager, 41 | const char *obj_file_list[], int count); 42 | 43 | static void print_load_map (struct list *load_map); 44 | 45 | // TODO: 실패했을 때, memory 원상복구 관련해서 고려하기. 46 | int loader (struct memory_manager *memory_manager, uint32_t progaddr, 47 | const char *obj_file_list[], int count) 48 | { 49 | int ret; 50 | struct symbol_manager *ESTAB = symbol_manager_construct (); 51 | struct list *load_map = list_construct (); 52 | 53 | if (loader_pass_1 (progaddr, ESTAB, load_map, obj_file_list, count) != 0) 54 | { 55 | fprintf (stderr, "[ERROR] An error occurs in pass 1 of loader.\n"); 56 | ret = -1; 57 | goto ERROR; 58 | } 59 | 60 | if (loader_pass_2 (progaddr, ESTAB, memory_manager, obj_file_list, count) != 0) 61 | { 62 | fprintf (stderr, "[ERROR] An error occurs in pass 2 of loader.\n"); 63 | ret = -1; 64 | goto ERROR; 65 | } 66 | 67 | print_load_map (load_map); 68 | 69 | ret = 0; 70 | goto END; 71 | 72 | ERROR: 73 | END: 74 | if (ESTAB) 75 | symbol_manager_destroy (ESTAB); 76 | if (load_map) 77 | { 78 | while (!list_empty (load_map)) 79 | { 80 | struct list_node *node = list_pop_front (load_map); 81 | free (list_entry (node, struct load_map_node, list_node)); 82 | } 83 | list_destroy (load_map); 84 | } 85 | 86 | return ret; 87 | } 88 | 89 | static void print_load_map (struct list *load_map) 90 | { 91 | struct list_node *node; 92 | uint32_t total_length = 0; 93 | 94 | printf ("%-15s %-15s %-15s %-15s\n", "Control", "Symbol", "Address", "Length"); 95 | printf ("%-15s %-15s %-15s %-15s\n", "Section", "Name", "", ""); 96 | printf ("------------------------------------------------------------\n"); // 60 * '-' 97 | for (node = list_begin (load_map); 98 | node != list_end (load_map); 99 | node = list_next (node)) 100 | { 101 | struct load_map_node *load_map_node = list_entry (node, struct load_map_node, list_node); 102 | 103 | if (load_map_node->type == LOAD_MAP_NODE_TYPE_CONTROL_SECTION) 104 | { 105 | printf ("%-15s %-15c %04X%11c %04X%11c\n", load_map_node->name, ' ', load_map_node->address, ' ', load_map_node->length, ' '); 106 | total_length += load_map_node->length; 107 | } 108 | else if (load_map_node->type == LOAD_MAP_NODE_TYPE_SYMBOL) 109 | { 110 | printf ("%-15c %-15s %04X%11c %-15c\n", ' ', load_map_node->name, load_map_node->address, ' ', ' '); 111 | } 112 | } 113 | printf ("------------------------------------------------------------\n"); // 60 * '-' 114 | printf ("%-15c %-15c %-15s %04X%11c\n", ' ', ' ', "Total Length", total_length, ' '); 115 | } 116 | 117 | #define MAX_OBJECT_BUF_LEN 1000 118 | 119 | static int loader_pass_1_to_one_obj (uint32_t *CSADDR, struct symbol_manager *ESTAB, struct list *load_map, 120 | const char *obj_file) 121 | { 122 | int ret; 123 | FILE *obj_fp; 124 | char obj_buf[MAX_OBJECT_BUF_LEN+1]; 125 | bool header_appear = false; 126 | uint32_t base_address = *CSADDR; 127 | 128 | obj_fp = fopen (obj_file, "rt"); 129 | if (!obj_fp) 130 | { 131 | ret = -1; 132 | goto ERROR; 133 | } 134 | 135 | // fprintf (stderr, "[DEBUG] PASS 1 to %s\n", obj_file); 136 | 137 | while (fgets (obj_buf, MAX_OBJECT_BUF_LEN, obj_fp) != NULL) 138 | { 139 | if (obj_buf[0] == 'H') 140 | { 141 | if (header_appear) 142 | { 143 | ret = -1; 144 | goto ERROR; 145 | } 146 | else 147 | { 148 | header_appear = true; 149 | } 150 | 151 | uint32_t dummy; 152 | struct load_map_node *node = malloc (sizeof(*node)); 153 | 154 | node->type = LOAD_MAP_NODE_TYPE_CONTROL_SECTION; 155 | sscanf (obj_buf, "H%6s%06X%06X", node->name, &dummy, &node->length); 156 | node->address = base_address; 157 | 158 | list_push_back (load_map, &node->list_node); 159 | // fprintf (stderr, "[DEBUG] Control Section = %s, %06X %06X\n", node->name, node->address, node->length); 160 | 161 | *CSADDR += node->length; 162 | } 163 | else if (obj_buf[0] == 'D') 164 | { 165 | int rec_len = strlen(obj_buf); 166 | rec_len -= 2; /* Exclude 'D' and '\n' */ 167 | if (rec_len % 12 != 0) 168 | { 169 | ret = -1; 170 | goto ERROR; 171 | } 172 | 173 | for (int i = 0; i < rec_len / 12; ++i) 174 | { 175 | uint32_t offset; 176 | struct symbol symbol; 177 | struct load_map_node *node = malloc (sizeof(*node)); 178 | 179 | node->type = LOAD_MAP_NODE_TYPE_SYMBOL; 180 | sscanf (obj_buf + 1 + i * 12, "%6s%06X", node->name, &offset); 181 | node->address = base_address + offset; 182 | 183 | list_push_back (load_map, &node->list_node); 184 | 185 | strncpy (symbol.label, node->name, SYMBOL_NAME_MAX_LEN); 186 | symbol.LOCCTR = node->address; 187 | symbol_insert (ESTAB, &symbol); 188 | 189 | // fprintf (stderr, "[DEBUG] Symbol = %s, %06X\n", node->name, node->address); 190 | } 191 | } 192 | else 193 | continue; 194 | } 195 | 196 | if (!header_appear) 197 | { 198 | fprintf (stderr, "[ERRPR] Header is not appeared in object file."); 199 | ret = -1; 200 | goto ERROR; 201 | } 202 | 203 | ret = 0; 204 | goto END; 205 | 206 | ERROR: 207 | END: 208 | if (obj_fp) 209 | fclose (obj_fp); 210 | 211 | return ret; 212 | } 213 | 214 | static int loader_pass_1 (uint32_t progaddr, struct symbol_manager *ESTAB, struct list *load_map, 215 | const char *obj_file_list[], int count) 216 | { 217 | uint32_t CSADDR = progaddr; 218 | 219 | for (int i = 0; i < count; ++i) 220 | { 221 | if (loader_pass_1_to_one_obj (&CSADDR, ESTAB, load_map, obj_file_list[i]) != 0) 222 | { 223 | fprintf (stderr, "[ERROR] An object file (%s) is invalid.\n", obj_file_list[i]); 224 | return -1; 225 | } 226 | } 227 | 228 | return 0; 229 | } 230 | 231 | static int loader_pass_2_to_one_obj (uint32_t *CSADDR, const struct symbol_manager *ESTAB, 232 | struct memory_manager *memory_manager, const char *obj_file) 233 | { 234 | // * Must be ascending order. * 235 | #define STATE_HEADER_PART 0 // 'H', 'R' 236 | #define STATE_TEXT_PART 1 // 'T' 237 | #define STATE_MODIFICATION_PART 2 // 'M' 238 | 239 | const char ch_to_state[128] = { 240 | ['H'] = STATE_HEADER_PART, 241 | ['R'] = STATE_HEADER_PART, 242 | ['T'] = STATE_TEXT_PART, 243 | ['M'] = STATE_MODIFICATION_PART 244 | }; 245 | 246 | int ret; 247 | FILE *obj_fp; 248 | char obj_buf[MAX_OBJECT_BUF_LEN+1]; 249 | int state = STATE_HEADER_PART; 250 | uint32_t ref_no_to_address[256]; 251 | bool ref_no_validation[256] = { false, }; 252 | uint32_t base_address = *CSADDR; 253 | 254 | ref_no_validation[1] = true; 255 | ref_no_to_address[1] = base_address; 256 | 257 | obj_fp = fopen (obj_file, "rt"); 258 | if (!obj_fp) 259 | { 260 | ret = -1; 261 | goto ERROR; 262 | } 263 | 264 | // fprintf (stderr, "[DEBUG] PASS 2 to %s\n", obj_file); 265 | 266 | #define CHECK_AND_UPDATE_STATE(ch) \ 267 | if (state > ch_to_state[(uint8_t)ch]) \ 268 | { \ 269 | ret = -1; \ 270 | goto ERROR; \ 271 | } \ 272 | state = ch_to_state[(uint8_t)ch]; 273 | 274 | while (fgets (obj_buf, MAX_OBJECT_BUF_LEN, obj_fp) != NULL) 275 | { 276 | // fprintf (stderr, "[DEBUG] %s", obj_buf); 277 | if (obj_buf[0] == 'H') 278 | { 279 | CHECK_AND_UPDATE_STATE (obj_buf[0]); 280 | char dummy_name[8]; 281 | uint32_t dummy_hex, length; 282 | sscanf (obj_buf, "H%6s%06X%06X", dummy_name, &dummy_hex, &length); 283 | *CSADDR += length; 284 | } 285 | else if (obj_buf[0] == 'R') 286 | { 287 | CHECK_AND_UPDATE_STATE (obj_buf[0]); 288 | 289 | uint32_t ref_no; 290 | char label[8]; 291 | int read_cnt; 292 | char *ptr = obj_buf + 1; 293 | // fprintf (stderr, "[DEBUG] Rest = %s", ptr); 294 | 295 | while (sscanf (ptr, "%02X%6s%n", &ref_no, label, &read_cnt) > 0) 296 | { 297 | ptr += read_cnt; 298 | // fprintf (stderr, "[DEBUG] read_cnt = %d, ref_no = %02X, label = %s, Rest = %s", read_cnt, ref_no, label, ptr); 299 | 300 | const struct symbol *symbol = symbol_find (ESTAB, label); 301 | if (!symbol) 302 | { 303 | ret = -1; 304 | goto ERROR; 305 | } 306 | 307 | ref_no_to_address[ref_no] = symbol->LOCCTR; 308 | ref_no_validation[ref_no] = true; 309 | } 310 | } 311 | else if (obj_buf[0] == 'T') 312 | { 313 | CHECK_AND_UPDATE_STATE (obj_buf[0]); 314 | 315 | uint32_t start_offset; 316 | uint32_t length; 317 | sscanf (obj_buf, "T%06X%02X", &start_offset, &length); 318 | for (size_t i = 0; i < length; ++i) 319 | { 320 | uint32_t val; 321 | sscanf (obj_buf + 9 + i * 2, "%02X", &val); 322 | memory_edit (memory_manager, base_address + start_offset + i, val); 323 | } 324 | } 325 | else if (obj_buf[0] == 'M') 326 | { 327 | CHECK_AND_UPDATE_STATE (obj_buf[0]); 328 | 329 | uint32_t offset; 330 | uint32_t length, ref_no = 0xFFFFFFFF; 331 | char op = 0; 332 | 333 | sscanf (obj_buf, "M%06X%02X%c%02X", &offset, &length, &op, &ref_no); 334 | 335 | if (ref_no == 0xFFFFFFFF) 336 | { 337 | op = '+'; 338 | ref_no = 0x01; 339 | } 340 | 341 | if (!ref_no_validation[ref_no]) 342 | { 343 | ret = -1; 344 | goto ERROR; 345 | } 346 | 347 | // fprintf (stderr, "[DEBUG] offset = %06X, length = %02X, op = %c, ref_no = %02X\n", offset, length, op, ref_no); 348 | 349 | uint32_t value = ref_no_to_address[ref_no]; 350 | uint32_t new_value = 0; 351 | 352 | for (int i = 0; i < 3; ++i) 353 | { 354 | uint8_t val; 355 | memory_get (memory_manager, base_address + offset + i, &val); 356 | new_value <<= 8; 357 | new_value += val; 358 | } 359 | 360 | if (length == 5) 361 | { 362 | if (op == '+') 363 | new_value = ((new_value + value) & 0xFFFFF) + ((new_value >> 20) << 20); 364 | else if (op == '-') 365 | new_value = ((new_value - value) & 0xFFFFF) + ((new_value >> 20) << 20); 366 | else 367 | {ret = -1; goto ERROR;} 368 | } 369 | else if (length == 6) 370 | { 371 | if (op == '+') 372 | new_value += value; 373 | else if (op == '-') 374 | new_value -= value; 375 | else 376 | {ret = -1; goto ERROR;} 377 | } 378 | 379 | memory_edit (memory_manager, base_address + offset, (uint8_t) (new_value >> 16)); 380 | memory_edit (memory_manager, base_address + offset + 1, (uint8_t) (new_value >> 8)); 381 | memory_edit (memory_manager, base_address + offset + 2, (uint8_t) new_value); 382 | } 383 | else 384 | continue; 385 | } 386 | #undef CHECK_AND_UPDATE_STATE 387 | #undef STATE_HEADER_PART 388 | #undef STATE_TEXT_PART 389 | #undef STATE_MODIFICATION_PART 390 | 391 | ret = 0; 392 | goto END; 393 | 394 | ERROR: 395 | END: 396 | if (obj_fp) 397 | fclose (obj_fp); 398 | 399 | return ret; 400 | } 401 | 402 | static int loader_pass_2 (uint32_t progaddr, const struct symbol_manager *ESTAB, 403 | struct memory_manager *memory_manager, 404 | const char *obj_file_list[], int count) 405 | { 406 | uint32_t CSADDR = progaddr; 407 | 408 | for (int i = 0; i < count; ++i) 409 | { 410 | if (loader_pass_2_to_one_obj (&CSADDR, ESTAB, memory_manager, obj_file_list[i]) != 0) 411 | { 412 | fprintf (stderr, "[ERROR] An object file (%s) is invalid.\n", obj_file_list[i]); 413 | return -1; 414 | } 415 | } 416 | 417 | return 0; 418 | } 419 | -------------------------------------------------------------------------------- /loader.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOADER_H__ 2 | #define __LOADER_H__ 3 | 4 | #include 5 | 6 | #include "memory.h" 7 | 8 | /* 성공 시 0, 그렇지 않을 경우 그외의 값을 반환. */ 9 | int loader (struct memory_manager *memory_manager, uint32_t progaddr, 10 | const char *obj_file_list[], int count); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "memory.h" 6 | 7 | struct memory_manager 8 | { 9 | void *memory; 10 | uint32_t memory_size; 11 | }; 12 | 13 | /* memory manager를 생성하는 factory 함수 */ 14 | struct memory_manager *memory_manager_construct (uint32_t memory_size) 15 | { 16 | struct memory_manager *manager = malloc (sizeof(*manager)); 17 | 18 | manager->memory = malloc (memory_size); 19 | manager->memory_size = memory_size; 20 | 21 | return manager; 22 | } 23 | 24 | /* memory manager를 소멸시키는 함수 */ 25 | void memory_manager_destroy (struct memory_manager *manager) 26 | { 27 | free (manager->memory); 28 | free (manager); 29 | } 30 | 31 | /* 특정 offset의 memory의 값을 val로 바꿔주는 함수 */ 32 | bool memory_edit (struct memory_manager *manager, uint32_t offset, uint8_t val) 33 | { 34 | if (offset >= manager->memory_size) 35 | return false; 36 | 37 | ((uint8_t*) manager->memory)[offset] = val; 38 | return true; 39 | } 40 | 41 | /* [start, end] offset 범위의 memory에 대하여 val 값으로 채워주는 함수 */ 42 | bool memory_fill (struct memory_manager *manager, uint32_t start, uint32_t end, uint8_t val) 43 | { 44 | if (start > end) 45 | return false; 46 | 47 | memset (manager->memory + start, val, end-start+1); 48 | 49 | return true; 50 | } 51 | 52 | /* memory를 0으로 초기화하는 함수 */ 53 | void memory_reset (struct memory_manager *manager) 54 | { 55 | memset (manager->memory, 0, manager->memory_size); 56 | } 57 | 58 | bool memory_get (struct memory_manager *manager, uint32_t offset, uint8_t *val) 59 | { 60 | if (offset >= manager->memory_size) 61 | return false; 62 | 63 | *val = ((uint8_t*) manager->memory)[offset]; 64 | return true; 65 | } 66 | 67 | /* [start, end] offset 범위의 memory를 dump해서 출력해주는 함수 68 | * 만약 enable_max_end가 true라면, end가 memory 범위를 초과하는 offset일 경우 69 | * end를 가능한 최대 memory offset으로 세팅해준다. 70 | */ 71 | bool memory_dump (struct memory_manager *manager, uint32_t start, uint32_t end, bool enable_max_end) 72 | { 73 | if (enable_max_end && end >= manager->memory_size) 74 | end = manager->memory_size - 1; 75 | 76 | if (start > end) 77 | return false; 78 | 79 | uint32_t aligned_start = start / 16 * 16, 80 | aligned_end = (end + 15 + 1) / 16 * 16; 81 | 82 | for (uint32_t base = aligned_start; 83 | base < aligned_end; 84 | base += 16) 85 | { 86 | printf ("%05X ", base); 87 | 88 | for (int i = 0; i < 16; ++i) 89 | { 90 | uint32_t offset = base + i; 91 | 92 | if (offset < start || offset > end) 93 | printf (" "); 94 | else 95 | printf ("%02X ", ((uint8_t*) manager->memory)[offset]); 96 | } 97 | printf ("; "); 98 | 99 | for (int i = 0; i < 16; ++i) 100 | { 101 | uint32_t offset = base + i; 102 | 103 | if (offset < start || offset > end) 104 | printf ("."); 105 | else 106 | { 107 | uint8_t val = ((uint8_t*) manager->memory)[offset]; 108 | if (0x20 <= val && val <= 0x7E) 109 | printf ("%c", (char) val); 110 | else 111 | printf ("."); 112 | } 113 | } 114 | printf("\n"); 115 | } 116 | 117 | return true; 118 | } 119 | 120 | /* memory 크기를 반환하는 함수 */ 121 | uint32_t memory_get_memory_size (struct memory_manager *manager) 122 | { 123 | return manager->memory_size; 124 | } 125 | -------------------------------------------------------------------------------- /memory.h: -------------------------------------------------------------------------------- 1 | #ifndef __MEMORY_H__ 2 | #define __MEMORY_H__ 3 | 4 | #include 5 | #include 6 | 7 | /* memory manager는 오직 factory 함수를 통해서만 생성될 수 있다. */ 8 | struct memory_manager; 9 | 10 | /* memory manager를 생성하고 소멸시키는 함수들 */ 11 | struct memory_manager *memory_manager_construct (uint32_t memory_size); 12 | void memory_manager_destroy (struct memory_manager *manager); 13 | 14 | /* memory를 조작하는 함수들 */ 15 | bool memory_edit (struct memory_manager *manager, uint32_t offset, uint8_t val); 16 | bool memory_fill (struct memory_manager *manager, uint32_t start, uint32_t end, uint8_t val); // [start, end] 17 | void memory_reset (struct memory_manager *manager); 18 | 19 | bool memory_get (struct memory_manager *manager, uint32_t offset, uint8_t *val); 20 | 21 | /* memory를 dump하여 출력해주는 함수 */ 22 | bool memory_dump (struct memory_manager *manager, uint32_t start, uint32_t end, bool enable_max_end); // [start, end]. 23 | 24 | /* memory 크기를 반환하는 함수 */ 25 | uint32_t memory_get_memory_size (struct memory_manager *manager); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /obj/copy.obj: -------------------------------------------------------------------------------- 1 | HCOPY 000000001077 2 | T0000001D17202D69202D4B1010360320262900003320074B10105D3F2FEC032010 3 | T00001D130F20160100030F200D4B10105D3E2003454F46 4 | T0010361DB410B400B44075101000E32019332FFADB2013A00433200857C003B850 5 | T0010531D3B2FEA1340004F0000F1B410774000E32011332FFA53C003DF2008B850 6 | T001070073B2FEF4F000005 7 | E000000 -------------------------------------------------------------------------------- /obj/proga.obj: -------------------------------------------------------------------------------- 1 | HPROGA 000000000063 2 | DLISTA 000040ENDA 000054 3 | R02LISTB 03ENDB 04LISTC 05ENDC 4 | . 5 | . 6 | T0000200A03201D77100004050014 7 | . 8 | . 9 | T0000540F000014FFFFF600003F000014FFFFC0 10 | M00002405+02 11 | M00005406+04 12 | M00005706+05 13 | M00005706-04 14 | M00005A06+05 15 | M00005A06-04 16 | M00005A06+01 17 | M00005D06-03 18 | M00005D06+02 19 | M00006006+02 20 | M00006006-01 21 | E000020 -------------------------------------------------------------------------------- /obj/progb.obj: -------------------------------------------------------------------------------- 1 | HPROGB 00000000007F 2 | DLISTB 000060ENDB 000070 3 | R02LISTA 03ENDA 04LISTC 05ENDC 4 | . 5 | . 6 | T0000360B0310000077202705100000 7 | . 8 | . 9 | T0000700F000000FFFFF6FFFFFFFFFFF0000060 10 | M00003705+02 11 | M00003E05+03 12 | M00003E05-02 13 | M00007006+03 14 | M00007006-02 15 | M00007006+04 16 | M00007306+05 17 | M00007306-04 18 | M00007606+05 19 | M00007606-04 20 | M00007606+02 21 | M00007906+03 22 | M00007906-02 23 | M00007C06+01 24 | M00007C06-02 25 | E -------------------------------------------------------------------------------- /obj/progc.obj: -------------------------------------------------------------------------------- 1 | HPROGC 000000000051 2 | DLISTC 000030ENDC 000042 3 | R02LISTA 03ENDA 04LISTB 05ENDB 4 | . 5 | . 6 | T0000180C031000007710000405100000 7 | . 8 | . 9 | T0000420F000030000008000011000000000000 10 | M00001905+02 11 | M00001D05+04 12 | M00002105+03 13 | M00002105-02 14 | M00004206+03 15 | M00004206-02 16 | M00004206+01 17 | M00004806+02 18 | M00004B06+03 19 | M00004B06-02 20 | M00004B06-05 21 | M00004B06+04 22 | M00004E06+04 23 | M00004E06-02 24 | E -------------------------------------------------------------------------------- /opcode.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "opcode.h" 6 | #include "list.h" 7 | 8 | #define OPCODE_HASH_TABLE_SIZE 20 9 | 10 | struct opcode_manager 11 | { 12 | struct list *buckets[OPCODE_HASH_TABLE_SIZE]; // opcode들을 저장하는 linked list 기반의 hash table. 13 | }; 14 | 15 | /* opcode manager에서 bucket으로서 사용되는 list를 위한 node */ 16 | struct opcode_node 17 | { 18 | struct opcode opcode; 19 | struct list_node list_node; 20 | }; 21 | 22 | static size_t hash_string (const char *str, size_t hash_size); 23 | 24 | /* opcode manager를 생성하는 factory 함수. */ 25 | struct opcode_manager *opcode_manager_construct () 26 | { 27 | struct opcode_manager *manager = malloc (sizeof(*manager)); 28 | 29 | for (int i = 0; i < OPCODE_HASH_TABLE_SIZE; ++i) 30 | manager->buckets[i] = list_construct (); 31 | 32 | return manager; 33 | } 34 | 35 | /* opcode manager를 소멸시키는 함수 */ 36 | void opcode_manager_destroy (struct opcode_manager *manager) 37 | { 38 | for (int i = 0; i < OPCODE_HASH_TABLE_SIZE; ++i) 39 | { 40 | while (!list_empty (manager->buckets[i])) 41 | { 42 | struct list_node *node = list_pop_front (manager->buckets[i]); 43 | free (list_entry (node, struct opcode_node, list_node)); 44 | } 45 | list_destroy (manager->buckets[i]); 46 | } 47 | free (manager); 48 | } 49 | 50 | /* opcode manager에 opcode를 추가하는 함수 */ 51 | void opcode_insert (struct opcode_manager *manager, const struct opcode *opcode) 52 | { 53 | size_t hash = hash_string (opcode->name, OPCODE_HASH_TABLE_SIZE); 54 | struct opcode_node *node = malloc (sizeof(*node)); 55 | 56 | node->opcode = *opcode; 57 | 58 | list_push_front (manager->buckets[hash], &node->list_node); 59 | } 60 | 61 | /* opcode manager에서 이름 (mnemonic) 을 통해 opcode를 찾는 함수 */ 62 | const struct opcode *opcode_find (const struct opcode_manager *manager, const char *name) 63 | { 64 | size_t hash = hash_string (name, OPCODE_HASH_TABLE_SIZE); 65 | struct list_node *node; 66 | 67 | for (node = list_begin (manager->buckets[hash]); 68 | node != list_end (manager->buckets[hash]); 69 | node = list_next (node)) 70 | { 71 | struct opcode_node *opcode_node = list_entry (node, struct opcode_node, list_node); 72 | if (strncmp (opcode_node->opcode.name, name, OPCODE_NAME_MAX_LEN) == 0) 73 | return &opcode_node->opcode; 74 | } 75 | 76 | return NULL; 77 | } 78 | 79 | /* opcode manager 내의 opcode들을 모두 출력하는 함수 */ 80 | void opcode_print_list (const struct opcode_manager *manager) 81 | { 82 | for (int i = 0; i < OPCODE_HASH_TABLE_SIZE; ++i) 83 | { 84 | bool first = true; 85 | 86 | printf ("%d : ", i); 87 | 88 | for (struct list_node *node = list_begin (manager->buckets[i]); 89 | node != list_end (manager->buckets[i]); 90 | node = list_next (node)) 91 | { 92 | struct opcode_node *opcode_node = list_entry (node, struct opcode_node, list_node); 93 | enum opcode_format op_format = opcode_node->opcode.op_format; 94 | 95 | if (op_format != OPCODE_FORMAT_1 && op_format != OPCODE_FORMAT_2 && 96 | op_format != OPCODE_FORMAT_3_4) 97 | continue; /* skip fake opcodes */ 98 | 99 | if (first) 100 | first = false; 101 | else 102 | printf (" -> "); 103 | 104 | printf ("[%s,%02X]", opcode_node->opcode.name, opcode_node->opcode.val); 105 | } 106 | printf ("\n"); 107 | } 108 | } 109 | 110 | /* 문자열을 정수형태로 변환해주는 hash function */ 111 | static size_t hash_string (const char *str, size_t hash_size) 112 | { 113 | int32_t hash = 2729; 114 | int c; 115 | while((c = *str++)) 116 | hash = (hash * 585) + c; 117 | return hash % hash_size; 118 | } 119 | -------------------------------------------------------------------------------- /opcode.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPCODE_H__ 2 | #define __OPCODE_H__ 3 | 4 | #include 5 | 6 | #define OPCODE_NAME_MAX_LEN 8 7 | 8 | /* opcode의 포멧을 의미하는 enum */ 9 | enum opcode_format 10 | { 11 | /* FAKE OPCODES */ 12 | OPCODE_START, OPCODE_END, 13 | OPCODE_BYTE, OPCODE_WORD, 14 | OPCODE_RESB, OPCODE_RESW, 15 | OPCODE_BASE, OPCODE_NOBASE, 16 | 17 | /* REAL OPCODES */ 18 | OPCODE_FORMAT_1, OPCODE_FORMAT_2, OPCODE_FORMAT_3_4 19 | }; 20 | 21 | enum opcode_detail_format 22 | { 23 | /* For fake opcodes */ 24 | OPCODE_FAKE, 25 | 26 | /* For format 1 */ 27 | OPCODE_FORMAT_1_GENERAL, 28 | 29 | /* For format 2 */ 30 | OPCODE_FORMAT_2_GENERAL, // r1, r2 31 | OPCODE_FORMAT_2_ONE_REGISTER, // r1 32 | OPCODE_FORMAT_2_REGISTER_N, // r1, n 33 | OPCODE_FORMAT_2_ONE_N, // n 34 | 35 | /* For format 3, 4 */ 36 | OPCODE_FORMAT_3_4_GENERAL, // m 37 | OPCODE_FORMAT_3_4_NO_OPERAND, // 38 | }; 39 | 40 | /* opcode를 의미하는 구조체 */ 41 | struct opcode 42 | { 43 | uint8_t val; // opcode의 값. 두자리 수 hex 값. 44 | char name[OPCODE_NAME_MAX_LEN + 1]; // opcode의 이름 (mnemonic) 45 | enum opcode_format op_format; 46 | enum opcode_detail_format detail_format; 47 | }; 48 | 49 | /* opcode manager는 무조건 factory 함수를 통해서만 생성될 수 있다. */ 50 | struct opcode_manager; 51 | 52 | /* opcode manager를 생성하고 소멸시키는 함수들 */ 53 | struct opcode_manager *opcode_manager_construct (); 54 | void opcode_manager_destroy (struct opcode_manager *manager); 55 | 56 | /* opcode manager에 opcode를 추가하는 함수 */ 57 | void opcode_insert (struct opcode_manager *manager, const struct opcode *opcode); 58 | 59 | /* opcode manager에서 이름 (mnemonic) 을 통해 opcode를 찾는 함수 */ 60 | const struct opcode *opcode_find (const struct opcode_manager *manager, const char *name); // Be cautious to dangling pointer problem. 61 | 62 | /* opcode manager 내의 opcode들을 모두 출력하는 함수 */ 63 | void opcode_print_list (const struct opcode_manager *manager); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /opcode.txt: -------------------------------------------------------------------------------- 1 | 18 ADD 3/4 2 | 58 ADDF 3/4 3 | 90 ADDR 2 4 | 40 AND 3/4 5 | B4 CLEAR 2 6 | 28 COMP 3/4 7 | 88 COMPF 3/4 8 | A0 COMPR 2 9 | 24 DIV 3/4 10 | 64 DIVF 3/4 11 | 9C DIVR 2 12 | C4 FIX 1 13 | C0 FLOAT 1 14 | F4 HIO 1 15 | 3C J 3/4 16 | 30 JEQ 3/4 17 | 34 JGT 3/4 18 | 38 JLT 3/4 19 | 48 JSUB 3/4 20 | 00 LDA 3/4 21 | 68 LDB 3/4 22 | 50 LDCH 3/4 23 | 70 LDF 3/4 24 | 08 LDL 3/4 25 | 6C LDS 3/4 26 | 74 LDT 3/4 27 | 04 LDX 3/4 28 | D0 LPS 3/4 29 | 20 MUL 3/4 30 | 60 MULF 3/4 31 | 98 MULR 2 32 | C8 NORM 1 33 | 44 OR 3/4 34 | D8 RD 3/4 35 | AC RMO 2 36 | 4C RSUB 3/4 37 | A4 SHIFTL 2 38 | F0 SIO 1 39 | EC SSK 3/4 40 | 0C STA 3/4 41 | 78 STB 3/4 42 | 54 STCH 3/4 43 | 80 STF 3/4 44 | D4 STI 3/4 45 | 14 STL 3/4 46 | 7C STS 3/4 47 | E8 STSW 3/4 48 | 84 STT 3/4 49 | 10 STX 3/4 50 | 1C SUB 3/4 51 | 5C SUBF 3/4 52 | 94 SUBR 2 53 | B0 SVC 2 54 | E0 TD 3/4 55 | F8 TIO 1 56 | 2C TIX 3/4 57 | B8 TIXR 2 58 | DC WD 3/4 59 | -------------------------------------------------------------------------------- /run.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "run.h" 6 | #include "opcode.h" 7 | 8 | struct inst_param 9 | { 10 | union 11 | { 12 | struct 13 | { 14 | uint16_t r2 : 4; 15 | uint16_t r1 : 4; 16 | uint16_t opcode : 8; 17 | } f2_param; 18 | 19 | struct 20 | { 21 | uint32_t address: 12; 22 | uint32_t e : 1; // must be 0 23 | uint32_t p : 1; 24 | uint32_t b : 1; 25 | uint32_t x : 1; 26 | uint32_t i : 1; 27 | uint32_t n : 1; 28 | uint32_t opcode : 6; 29 | } f3_param; 30 | 31 | struct 32 | { 33 | uint32_t address: 20; 34 | uint32_t e : 1; // must be 1 35 | uint32_t p : 1; 36 | uint32_t b : 1; 37 | uint32_t x : 1; 38 | uint32_t i : 1; 39 | uint32_t n : 1; 40 | uint32_t opcode : 6; 41 | } f4_param; 42 | 43 | uint32_t val; 44 | } param; 45 | bool extend; 46 | }; 47 | 48 | typedef void (*inst_handler_t) (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 49 | 50 | static void _h_STA (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 51 | static void _h_STL (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 52 | static void _h_STCH (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 53 | static void _h_STX (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 54 | static void _h_LDA (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 55 | static void _h_LDB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 56 | static void _h_LDT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 57 | static void _h_LDX (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 58 | static void _h_LDCH (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 59 | static void _h_JSUB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 60 | static void _h_JEQ (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 61 | static void _h_J (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 62 | static void _h_JGT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 63 | static void _h_JLT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 64 | static void _h_RSUB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 65 | static void _h_COMP (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 66 | static void _h_COMPR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 67 | static void _h_TD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 68 | static void _h_RD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 69 | static void _h_WD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 70 | static void _h_CLEAR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 71 | static void _h_TIXR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set); 72 | 73 | static bool load_mem (struct memory_manager *memory_manager, const struct run_register_set *reg_set, 74 | struct inst_param inst_param, uint32_t *value, size_t bytes, bool jump_op); 75 | static bool store_mem (struct memory_manager *memory_manager, const struct run_register_set *reg_set, 76 | struct inst_param inst_param, uint32_t value, size_t bytes); 77 | 78 | static bool load_reg (struct run_register_set *reg_set, int reg_no, uint32_t *reg_val); 79 | static bool store_reg (struct run_register_set *reg_set, int reg_no, uint32_t reg_val); 80 | 81 | int run (struct memory_manager *memory_manager, const struct debug_manager *debug_manager, 82 | struct run_register_set *reg_set, bool *is_running) 83 | { 84 | // 1. PC로 부터 opcode를 읽는다. 85 | // 2. opcode마다 추가적으로 0~3바이트를 더 읽고, 86 | // - opcode -> instruction format number table 작성 87 | // 3. debug_manager에게 bp check를 요청한다. 88 | // 3-1. bp에 걸릴 경우, run을 멈춤.(반환) 89 | // 3-2. bp에 안걸릴 경우 계속 진행. 90 | // 4. instruction을 수행한다. 91 | // - opcode -> instruction handler table 작성. 92 | // 5. 다시 1부터 반복. 93 | 94 | enum opcode_format opcode_format_table[256] = 95 | { 96 | [0x00] = OPCODE_FORMAT_3_4, 97 | [0x68] = OPCODE_FORMAT_3_4, 98 | [0x74] = OPCODE_FORMAT_3_4, 99 | [0x04] = OPCODE_FORMAT_3_4, 100 | [0x50] = OPCODE_FORMAT_3_4, 101 | [0x0C] = OPCODE_FORMAT_3_4, 102 | [0x14] = OPCODE_FORMAT_3_4, 103 | [0x10] = OPCODE_FORMAT_3_4, 104 | [0x54] = OPCODE_FORMAT_3_4, 105 | [0x48] = OPCODE_FORMAT_3_4, 106 | [0x30] = OPCODE_FORMAT_3_4, 107 | [0x34] = OPCODE_FORMAT_3_4, 108 | [0x38] = OPCODE_FORMAT_3_4, 109 | [0x3C] = OPCODE_FORMAT_3_4, 110 | [0x28] = OPCODE_FORMAT_3_4, 111 | [0xE0] = OPCODE_FORMAT_3_4, 112 | [0xD8] = OPCODE_FORMAT_3_4, 113 | [0x4C] = OPCODE_FORMAT_3_4, 114 | [0xDC] = OPCODE_FORMAT_3_4, 115 | [0xB4] = OPCODE_FORMAT_2, 116 | [0xA0] = OPCODE_FORMAT_2, 117 | [0xB8] = OPCODE_FORMAT_2 118 | }; 119 | inst_handler_t inst_handler_table[256] = 120 | { 121 | [0x00] = _h_LDA, 122 | [0x68] = _h_LDB, 123 | [0x74] = _h_LDT, 124 | [0x04] = _h_LDX, 125 | [0x50] = _h_LDCH, 126 | [0x0C] = _h_STA, 127 | [0x14] = _h_STL, 128 | [0x10] = _h_STX, 129 | [0x54] = _h_STCH, 130 | [0x48] = _h_JSUB, 131 | [0x30] = _h_JEQ, 132 | [0x34] = _h_JGT, 133 | [0x38] = _h_JLT, 134 | [0x3C] = _h_J, 135 | [0x28] = _h_COMP, 136 | [0xE0] = _h_TD, 137 | [0xD8] = _h_RD, 138 | [0x4C] = _h_RSUB, 139 | [0xDC] = _h_WD, 140 | [0xB4] = _h_CLEAR, 141 | [0xA0] = _h_COMPR, 142 | [0xB8] = _h_TIXR 143 | }; 144 | 145 | int ret; 146 | bool is_continue = *is_running; 147 | 148 | if (*is_running) 149 | { 150 | printf ("[Info] Continuous Running.\n"); 151 | } 152 | else 153 | { 154 | uint32_t PC = reg_set->PC; 155 | memset (reg_set, 0, sizeof (*reg_set)); 156 | reg_set->PC = PC; 157 | reg_set->L = 0x00FFFFFF; 158 | } 159 | 160 | *is_running = true; 161 | 162 | while (reg_set->PC != 0x00FFFFFF) 163 | { 164 | uint8_t opcode; 165 | uint32_t inst_val = 0; 166 | uint8_t mem_val; 167 | int inst_size; 168 | 169 | memory_get (memory_manager, reg_set->PC, &mem_val); 170 | inst_val = mem_val; 171 | opcode = mem_val & 0xFC; 172 | 173 | //fprintf (stderr, "[DEBUG] running opcode %02X, PC = %08X, SW = %08X\n", mem_val, reg_set->PC, reg_set->SW); 174 | 175 | switch (opcode_format_table[opcode]) 176 | { 177 | case OPCODE_FORMAT_1: 178 | inst_size = 1; 179 | break; 180 | case OPCODE_FORMAT_2: 181 | memory_get (memory_manager, reg_set->PC + 1, &mem_val); 182 | inst_size = 2; 183 | inst_val = (inst_val << 8) + mem_val; 184 | break; 185 | case OPCODE_FORMAT_3_4: 186 | memory_get (memory_manager, reg_set->PC + 1, &mem_val); 187 | inst_val = (inst_val << 8) + mem_val; 188 | memory_get (memory_manager, reg_set->PC + 2, &mem_val); 189 | inst_val = (inst_val << 8) + mem_val; 190 | inst_size = 3; 191 | if (inst_val & (1 << 12)) 192 | { 193 | memory_get (memory_manager, reg_set->PC + 3, &mem_val); 194 | inst_val = (inst_val << 8) + mem_val; 195 | ++inst_size; 196 | } 197 | break; 198 | default: 199 | return -1; 200 | } 201 | 202 | uint32_t bp; 203 | if (!is_continue && debug_bp_check (debug_manager, reg_set->PC, reg_set->PC + inst_size, &bp)) 204 | { 205 | // bp에 걸림. 206 | printf ("Stop at checkpoint[%04X]\n", bp); 207 | return 0; 208 | } 209 | 210 | struct inst_param inst_param = { 211 | .extend = (inst_size == 4), 212 | .param.val = inst_val 213 | }; 214 | 215 | inst_handler_t inst_handler = inst_handler_table[opcode]; 216 | if (!inst_handler) 217 | { 218 | fprintf (stderr, "[ERROR] Not supported opcode : %02X\n", opcode); 219 | ret = -1; 220 | goto ERROR; 221 | } 222 | 223 | reg_set->PC += inst_size; 224 | inst_handler (memory_manager, inst_param, reg_set); 225 | 226 | is_continue = false; 227 | 228 | /* 229 | fprintf (stderr, 230 | "A : %08X X : %08X \n" 231 | "L : %08X PC: %08X \n" 232 | "B : %08X S : %08X \n" 233 | "T : %08X \n", 234 | reg_set->A, reg_set->X, 235 | reg_set->L, reg_set->PC, 236 | reg_set->B, reg_set->S, 237 | reg_set->T 238 | ); 239 | */ 240 | 241 | //getchar(); 242 | } 243 | 244 | *is_running = false; 245 | 246 | ret = 0; 247 | goto END; 248 | 249 | ERROR: 250 | *is_running = false; 251 | END: 252 | printf ("[Info] Program Terminated.\n"); 253 | 254 | return ret; 255 | } 256 | 257 | // TODO: range check. 258 | static bool load_mem (struct memory_manager *memory_manager, const struct run_register_set *reg_set, 259 | struct inst_param inst_param, uint32_t *value, size_t bytes, bool jump_op) 260 | { 261 | uint32_t target_address; 262 | 263 | #define INST_PARAM(S) \ 264 | (inst_param.extend ? inst_param.param.f4_param.S : inst_param.param.f3_param.S) 265 | 266 | if (INST_PARAM (b) == 1 && INST_PARAM (p) == 0) // Base relative 267 | target_address = INST_PARAM (address) + reg_set->B; 268 | else if (INST_PARAM (b) == 0 && INST_PARAM (p) == 1) // PC relative 269 | { 270 | int32_t value; 271 | uint32_t boundary; 272 | 273 | if (inst_param.extend) 274 | boundary = (1 << 19); 275 | else 276 | boundary = (1 << 11); 277 | 278 | if (INST_PARAM (address) >= boundary) 279 | value = INST_PARAM (address) - (boundary << 1); 280 | else 281 | value = INST_PARAM (address); 282 | 283 | target_address = reg_set->PC + value; 284 | } 285 | else 286 | target_address = INST_PARAM (address); 287 | 288 | if (INST_PARAM (x) == 1) 289 | { 290 | target_address += reg_set->X; 291 | } 292 | 293 | // fprintf (stderr, "[DEBUG - load_mem] address = %08X, target_address = %08X\n", INST_PARAM (address), target_address); 294 | 295 | bool is_immediate, is_simple, is_indirect; 296 | if (jump_op) 297 | { 298 | is_immediate = INST_PARAM (n) == 1 && INST_PARAM (i) == 1; 299 | is_simple = INST_PARAM (n) == 1 && INST_PARAM (i) == 0; 300 | is_indirect = false; 301 | } 302 | else 303 | { 304 | is_immediate = INST_PARAM (n) == 0 && INST_PARAM (i) == 1; 305 | is_simple = INST_PARAM (n) == 1 && INST_PARAM (i) == 1; 306 | is_indirect = INST_PARAM (n) == 1 && INST_PARAM (i) == 0; 307 | } 308 | 309 | if (is_immediate) // immediate 310 | { 311 | //fprintf (stderr, "[DEBUG - load_mem - immediate]\n"); 312 | *value = target_address; 313 | } 314 | else if (is_simple) // simple 315 | { 316 | //fprintf (stderr, "[DEBUG - load_mem - simple]\n"); 317 | uint8_t mem_val; 318 | *value = 0; 319 | for (size_t i = 0; i < bytes; ++i) 320 | { 321 | memory_get (memory_manager, target_address + i, &mem_val); 322 | *value = (*value << 8) + mem_val; 323 | } 324 | } 325 | else if (is_indirect) // indirect 326 | { 327 | //fprintf (stderr, "[DEBUG - load_mem - indirect]\n"); 328 | uint32_t address = 0; 329 | uint8_t mem_val; 330 | 331 | for (int i = 0; i < 3; ++i) 332 | { 333 | memory_get (memory_manager, target_address + i, &mem_val); 334 | address = (address << 8) + mem_val; 335 | } 336 | 337 | //fprintf (stderr, "[DEBUG - load_mem - indirect] final address = %08X\n", address); 338 | 339 | *value = 0; 340 | for (size_t i = 0; i < bytes; ++i) 341 | { 342 | memory_get (memory_manager, address + i, &mem_val); 343 | *value = (*value << 8) + mem_val; 344 | } 345 | } 346 | else 347 | { 348 | return false; 349 | } 350 | 351 | #undef CONTROL_INST 352 | 353 | return true; 354 | } 355 | 356 | // TODO: range check. 357 | static bool store_mem (struct memory_manager *memory_manager, const struct run_register_set *reg_set, 358 | struct inst_param inst_param, uint32_t value, size_t bytes) 359 | { 360 | uint32_t target_address; 361 | 362 | #define INST_PARAM(S) \ 363 | (inst_param.extend ? inst_param.param.f4_param.S : inst_param.param.f3_param.S) 364 | 365 | if (INST_PARAM (b) == 1 && INST_PARAM (p) == 0) // Base relative 366 | target_address = INST_PARAM (address) + reg_set->B; 367 | else if (INST_PARAM (b) == 0 && INST_PARAM (p) == 1) // PC relative 368 | { 369 | int32_t value; 370 | uint32_t boundary; 371 | 372 | if (inst_param.extend) 373 | boundary = (1 << 19); 374 | else 375 | boundary = (1 << 11); 376 | 377 | if (INST_PARAM (address) >= boundary) 378 | value = INST_PARAM (address) - (boundary << 1); 379 | else 380 | value = INST_PARAM (address); 381 | 382 | target_address = reg_set->PC + value; 383 | } 384 | else 385 | target_address = INST_PARAM (address); 386 | 387 | if (INST_PARAM (x) == 1) 388 | { 389 | target_address += reg_set->X; 390 | } 391 | 392 | // fprintf (stderr, "[DEBUG - store_mem] address = %08X, target_address = %08X\n", INST_PARAM (address), target_address); 393 | 394 | if (INST_PARAM (n) == 0 && INST_PARAM (i) == 1) // immediate 395 | { 396 | // WTF? 397 | return false; 398 | } 399 | else if (INST_PARAM (n) == 1 && INST_PARAM (i) == 1) // simple 400 | { 401 | for (int i = bytes-1; i >= 0; --i) 402 | { 403 | memory_edit (memory_manager, target_address + i, value); 404 | value >>= 8; 405 | } 406 | } 407 | else if (INST_PARAM (n) == 1 && INST_PARAM (i) == 0) // indirect 408 | { 409 | uint8_t mem_val; 410 | uint32_t address = 0; 411 | for (int i = 0; i < 3; ++i) 412 | { 413 | memory_get (memory_manager, target_address + i, &mem_val); 414 | address = (address << 8) + mem_val; 415 | } 416 | for (int i = 2; i >= 0; --i) 417 | { 418 | memory_edit (memory_manager, address + i, value); 419 | value >>= 8; 420 | } 421 | } 422 | else 423 | { 424 | return false; 425 | } 426 | 427 | #undef CONTROL_INST 428 | 429 | return true; 430 | } 431 | 432 | static bool load_reg (struct run_register_set *reg_set, int reg_no, uint32_t *reg_val) 433 | { 434 | switch (reg_no) 435 | { 436 | case 0: 437 | *reg_val = reg_set->A; 438 | break; 439 | case 1: 440 | *reg_val = reg_set->X; 441 | break; 442 | case 2: 443 | *reg_val = reg_set->L; 444 | break; 445 | case 3: 446 | *reg_val = reg_set->B; 447 | break; 448 | case 4: 449 | *reg_val = reg_set->S; 450 | break; 451 | case 5: 452 | *reg_val = reg_set->T; 453 | break; 454 | case 6: 455 | // *reg_val = reg_set->F; 456 | return false; // Not supported. 457 | case 8: 458 | *reg_val = reg_set->PC; 459 | break; 460 | case 9: 461 | *reg_val = reg_set->SW; 462 | break; 463 | default: 464 | return false; // invalid 465 | } 466 | return true; 467 | } 468 | 469 | static bool store_reg (struct run_register_set *reg_set, int reg_no, uint32_t reg_val) 470 | { 471 | switch (reg_no) 472 | { 473 | case 0: 474 | reg_set->A = reg_val; 475 | break; 476 | case 1: 477 | reg_set->X = reg_val; 478 | break; 479 | case 2: 480 | reg_set->L = reg_val; 481 | break; 482 | case 3: 483 | reg_set->B = reg_val; 484 | break; 485 | case 4: 486 | reg_set->S = reg_val; 487 | break; 488 | case 5: 489 | reg_set->T = reg_val; 490 | break; 491 | case 6: 492 | // reg_set->F = reg_val; 493 | return false; // Not supported. 494 | case 8: 495 | reg_set->PC = reg_val; 496 | break; 497 | case 9: 498 | reg_set->SW = reg_val; 499 | break; 500 | default: 501 | return false; 502 | } 503 | return true; 504 | } 505 | 506 | static void _h_STA (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 507 | { 508 | store_mem (memory_manager, reg_set, inst_param, reg_set->A, 3); 509 | } 510 | static void _h_STL (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 511 | { 512 | store_mem (memory_manager, reg_set, inst_param, reg_set->L, 3); 513 | } 514 | static void _h_STCH (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 515 | { 516 | store_mem (memory_manager, reg_set, inst_param, reg_set->A & 0xFF, 1); 517 | } 518 | static void _h_STX (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 519 | { 520 | store_mem (memory_manager, reg_set, inst_param, reg_set->X, 3); 521 | } 522 | static void _h_LDA (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 523 | { 524 | load_mem (memory_manager, reg_set, inst_param, ®_set->A, 3, false); 525 | } 526 | static void _h_LDB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 527 | { 528 | load_mem (memory_manager, reg_set, inst_param, ®_set->B, 3, false); 529 | } 530 | static void _h_LDT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 531 | { 532 | load_mem (memory_manager, reg_set, inst_param, ®_set->T, 3, false); 533 | } 534 | static void _h_LDX (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 535 | { 536 | load_mem (memory_manager, reg_set, inst_param, ®_set->X, 3, false); 537 | } 538 | static void _h_LDCH (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 539 | { 540 | uint32_t value; 541 | load_mem (memory_manager, reg_set, inst_param, &value, 1, false); 542 | reg_set->A = (reg_set->A & 0xFFFFFF00) + (value & 0xFF); 543 | } 544 | static void _h_JSUB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 545 | { 546 | uint32_t jump_address; 547 | load_mem (memory_manager, reg_set, inst_param, &jump_address, 3, true); 548 | // fprintf (stderr, "[DEBUG - JSUB] jump_address = %08X\n", jump_address); 549 | 550 | reg_set->L = reg_set->PC; 551 | reg_set->PC = jump_address; 552 | } 553 | static void _h_JEQ (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 554 | { 555 | if (reg_set->SW == 0) 556 | { 557 | load_mem (memory_manager, reg_set, inst_param, ®_set->PC, 3, true); 558 | // fprintf (stderr, "[DEBUG - JEQ] jump_address = %08X\n", reg_set->PC); 559 | } 560 | } 561 | static void _h_J (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 562 | { 563 | load_mem (memory_manager, reg_set, inst_param, ®_set->PC, 3, true); 564 | } 565 | static void _h_JLT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 566 | { 567 | if ((int32_t) reg_set->SW < 0) 568 | { 569 | load_mem (memory_manager, reg_set, inst_param, ®_set->PC, 3, true); 570 | // fprintf (stderr, "[DEBUG - JLT] jump_address = %08X\n", reg_set->PC); 571 | } 572 | } 573 | static void _h_JGT (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 574 | { 575 | if ((int32_t) reg_set->SW > 0) 576 | load_mem (memory_manager, reg_set, inst_param, ®_set->PC, 3, true); 577 | } 578 | static void _h_RSUB (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 579 | { 580 | reg_set->PC = reg_set->L; 581 | } 582 | static void _h_COMP (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 583 | { 584 | uint32_t value; 585 | load_mem (memory_manager, reg_set, inst_param, &value, 3, false); 586 | if (reg_set->A > value) 587 | reg_set->SW = 1; 588 | else if (reg_set->A < value) 589 | reg_set->SW = -1; 590 | else 591 | reg_set->SW = 0; 592 | } 593 | static void _h_COMPR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 594 | { 595 | uint32_t reg_val_1, reg_val_2; 596 | load_reg (reg_set, inst_param.param.f2_param.r1, ®_val_1); 597 | load_reg (reg_set, inst_param.param.f2_param.r2, ®_val_2); 598 | if (reg_val_1 > reg_val_2) 599 | reg_set->SW = 1; 600 | else if (reg_val_1 < reg_val_2) 601 | reg_set->SW = -1; 602 | else 603 | reg_set->SW = 0; 604 | } 605 | static void _h_TD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 606 | { 607 | /* I/O instructions are not supported. 608 | * This behavior is just for test */ 609 | // fprintf (stderr, "[DEBUG] TD\n"); 610 | reg_set->SW = 1; 611 | } 612 | static void _h_RD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 613 | { 614 | /* I/O instructions are not supported. 615 | * This behavior is just for test */ 616 | static char device_input_mock[] = "HELLO WORLD\0I'M TAEGUK\0"; 617 | static size_t device_input_idx = 0; 618 | 619 | reg_set->A = (reg_set->A & 0xFFFFFF00) + (uint8_t) device_input_mock[device_input_idx++]; 620 | 621 | fprintf (stdout, "--- [Input Device] input = '%c'\n", (char)(reg_set->A & 0xFF)); 622 | 623 | if (device_input_idx >= sizeof(device_input_mock) / sizeof(char)) 624 | device_input_idx = 0; 625 | } 626 | static void _h_WD (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 627 | { 628 | /* I/O instructions are not supported. 629 | * This behavior is just for test */ 630 | fprintf (stdout, "+++ [Output Device] output = '%c'\n", (char)(reg_set->A & 0xFF)); 631 | } 632 | static void _h_CLEAR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 633 | { 634 | store_reg (reg_set, inst_param.param.f2_param.r1, 0); 635 | } 636 | static void _h_TIXR (struct memory_manager *memory_manager, struct inst_param inst_param, struct run_register_set *reg_set) 637 | { 638 | uint32_t reg_val; 639 | load_reg (reg_set, inst_param.param.f2_param.r1, ®_val); 640 | ++reg_set->X; 641 | 642 | if (reg_set->X > reg_val) 643 | reg_set->SW = 1; 644 | else if (reg_set->X < reg_val) 645 | reg_set->SW = -1; 646 | else 647 | reg_set->SW = 0; 648 | } 649 | -------------------------------------------------------------------------------- /run.h: -------------------------------------------------------------------------------- 1 | #ifndef __RUN_H__ 2 | #define __RUN_H__ 3 | 4 | #include 5 | 6 | #include "memory.h" 7 | #include "debug.h" 8 | 9 | struct run_register_set 10 | { 11 | uint32_t A, X, L, PC, B, S, T, SW; 12 | }; 13 | 14 | /* 성공 시 0, 그렇지 않을 경우 그외의 값을 반환. */ 15 | int run (struct memory_manager *memory_manager, const struct debug_manager *debug_manager, 16 | struct run_register_set *reg_set, bool *is_running); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /symbol.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "symbol.h" 6 | #include "list.h" 7 | 8 | #define SYMBOL_HASH_TABLE_SIZE 40 9 | 10 | struct symbol_manager 11 | { 12 | struct list *buckets[SYMBOL_HASH_TABLE_SIZE]; // symbol들을 저장하는 linked list 기반의 hash table. 13 | }; 14 | 15 | /* symbol manager에서 bucket으로서 사용되는 list를 위한 node */ 16 | struct symbol_node 17 | { 18 | struct symbol symbol; 19 | struct list_node list_node; 20 | }; 21 | 22 | static size_t hash_string (const char *str, size_t hash_size); 23 | 24 | /* symbol manager를 생성하는 factory 함수. */ 25 | struct symbol_manager *symbol_manager_construct () 26 | { 27 | struct symbol_manager *manager = malloc (sizeof(*manager)); 28 | 29 | for (int i = 0; i < SYMBOL_HASH_TABLE_SIZE; ++i) 30 | manager->buckets[i] = list_construct (); 31 | 32 | return manager; 33 | } 34 | 35 | /* symbol manager를 소멸시키는 함수 */ 36 | void symbol_manager_destroy (struct symbol_manager *manager) 37 | { 38 | for (int i = 0; i < SYMBOL_HASH_TABLE_SIZE; ++i) 39 | { 40 | while (!list_empty (manager->buckets[i])) 41 | { 42 | struct list_node *node = list_pop_front (manager->buckets[i]); 43 | free (list_entry (node, struct symbol_node, list_node)); 44 | } 45 | list_destroy (manager->buckets[i]); 46 | } 47 | free (manager); 48 | } 49 | 50 | /* symbol manager에 symbol를 추가하는 함수 */ 51 | void symbol_insert (struct symbol_manager *manager, const struct symbol *symbol) 52 | { 53 | size_t hash = hash_string (symbol->label, SYMBOL_HASH_TABLE_SIZE); 54 | struct symbol_node *node = malloc (sizeof(*node)); 55 | 56 | node->symbol = *symbol; 57 | 58 | list_push_front (manager->buckets[hash], &node->list_node); 59 | } 60 | 61 | /* symbol manager에서 이름 (mnemonic) 을 통해 symbol를 찾는 함수 */ 62 | const struct symbol *symbol_find (const struct symbol_manager *manager, const char *label) 63 | { 64 | size_t hash = hash_string (label, SYMBOL_HASH_TABLE_SIZE); 65 | struct list_node *node; 66 | 67 | for (node = list_begin (manager->buckets[hash]); 68 | node != list_end (manager->buckets[hash]); 69 | node = list_next (node)) 70 | { 71 | struct symbol_node *symbol_node = list_entry (node, struct symbol_node, list_node); 72 | if (strncmp (symbol_node->symbol.label, label, SYMBOL_NAME_MAX_LEN) == 0) 73 | return &symbol_node->symbol; 74 | } 75 | 76 | return NULL; 77 | } 78 | 79 | static int symbol_compare_func (const void *A, const void *B) 80 | { 81 | struct symbol_node *nodeA = *(struct symbol_node **) A; 82 | struct symbol_node *nodeB = *(struct symbol_node **) B; 83 | return strcmp (nodeA->symbol.label, nodeB->symbol.label); 84 | } 85 | 86 | /* symbol manager 내의 symbol들을 모두 출력하는 함수 */ 87 | void symbol_print_list (struct symbol_manager *manager) 88 | { 89 | struct symbol_node *all_node_list[1111]={0}; 90 | int cnt = 0; 91 | 92 | for (int i = 0; i < SYMBOL_HASH_TABLE_SIZE; ++i) 93 | { 94 | struct list_node *node; 95 | 96 | for (node = list_begin (manager->buckets[i]); 97 | node != list_end (manager->buckets[i]); 98 | node = list_next (node)) 99 | { 100 | struct symbol_node *symbol_node = list_entry (node, struct symbol_node, list_node); 101 | all_node_list[cnt++] = symbol_node; 102 | } 103 | } 104 | 105 | qsort (all_node_list, cnt, sizeof(struct symbol_node*), symbol_compare_func); 106 | 107 | for (int i = 0; i < cnt; ++i) 108 | { 109 | struct symbol_node *symbol_node = all_node_list[i]; 110 | printf ("\t%s\t%04X\n", symbol_node->symbol.label, symbol_node->symbol.LOCCTR); 111 | } 112 | } 113 | 114 | /* 문자열을 정수형태로 변환해주는 hash function */ 115 | static size_t hash_string (const char *str, size_t hash_size) 116 | { 117 | int32_t hash = 2729; 118 | int c; 119 | while((c = *str++)) 120 | hash = (hash * 585) + c; 121 | return hash % hash_size; 122 | } 123 | -------------------------------------------------------------------------------- /symbol.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYMBOL_H__ 2 | #define __SYMBOL_H__ 3 | 4 | #include 5 | 6 | #define SYMBOL_NAME_MAX_LEN 8 7 | 8 | /* symbol을 의미하는 구조체 */ 9 | struct symbol 10 | { 11 | char label[SYMBOL_NAME_MAX_LEN + 1]; 12 | uint32_t LOCCTR; 13 | }; 14 | 15 | /* symbol manager는 무조건 factory 함수를 통해서만 생성될 수 있다. */ 16 | struct symbol_manager; 17 | 18 | /* symbol manager를 생성하고 소멸시키는 함수들 */ 19 | struct symbol_manager *symbol_manager_construct (); 20 | void symbol_manager_destroy (struct symbol_manager *manager); 21 | 22 | /* symbol manager에 symbol를 추가하는 함수 */ 23 | void symbol_insert (struct symbol_manager *manager, const struct symbol *symbol); 24 | 25 | /* symbol manager에서 이름 (mnemonic) 을 통해 symbol를 찾는 함수 */ 26 | const struct symbol *symbol_find (const struct symbol_manager *manager, const char *label); // Be cautious to dangling pointer problem. 27 | 28 | /* symbol manager 내의 symbol들을 모두 출력하는 함수 */ 29 | void symbol_print_list (struct symbol_manager *manager); 30 | 31 | #endif 32 | --------------------------------------------------------------------------------