/* ** VM2GS2.C ** ** by Toshiyasu Morita ** ** Started: 5/14/93 @ 7:51 pm */ /* ** Notes: ** ** I've realized that VM2GS has a few problems, so this is a new ** attempt. Specifically, VM2GS had a few problems with: ** ** 1) Optimization cases where one optimization would lead to another ** possible optimization, such as: ** ** sta foo ** lda bar ** sta bar ** lda foo ** ** The original VM2GS would easily remove "lda bar, sta bar", but ** it was painful to recognize any other optimiztions the current ** optimization would expose since it was single-pass, and each ** possible optimization would have to be hard-coded. ** ** 2) Supporting multiple assembler formats. ** ** VM2GS2 attempts to rectify these problems. VM2GS2 reads in an entire ** function, then performs multiple passes over the function: ** ** 1) Stage1 performs VM-code optimization, such as removing redundant ** loads, etc. Stage1 may be performed multiple times, since performing ** an optimization may create oppportunities for more optimization. ** ** 2) Stage2 will convert the VM-code to 65816 assembly. ** ** 3) Stage3 will perform 65816 assembly optimization. ** ** 4) Stage4 will output 65816 assembly code or an OMF file. */ #include #include #include #include #include #include /* ** Defines */ #define BLOCK_SIZE 32768 #define LOOKAHEAD_LINES 5 #define LAST_LINE (LOOKAHEAD_LINES - 1) /* ** Typedefs */ typedef signed char SBYTE; typedef unsigned char UBYTE; typedef signed short SWORD; typedef unsigned short UWORD; typedef signed long SLONG; typedef unsigned long ULONG; typedef struct MEMORY_BLOCK_TAG { struct MEMORY_BLOCK_TAG *prev, *next; UWORD size, used; void *data; } MEMORY_BLOCK_STRUCT; typedef struct LINE_STRUCT_TAG { struct LINE_STRUCT_TAG *prev, *next; char *label, *operator, *operand; } LINE_STRUCT; /* ** Globals */ MEMORY_BLOCK_STRUCT mem_block_head, mem_block_tail; LINE_STRUCT input_head, input_tail; LINE_STRUCT output_head, output_tail; char current_line[256]; char label[256], operator[256], operand[256], comment[256]; char null = 0; int debug_flag = 0, info_flag = 0; /************************************** * Start memory management functions **************************************/ /* ** Initialize memory manager */ void Init_Memory_Manager(void) { mem_block_head.next = &mem_block_tail; mem_block_tail.prev = &mem_block_head; mem_block_head.prev = mem_block_tail.next = 0; } /* ** Uninitialize memory manager */ void Uninit_Memory_Manager(void) { MEMORY_BLOCK_STRUCT *current, *next; for (current = mem_block_head.next; current != &mem_block_tail;) { next = current->next; free(current); current = next; } } /* ** Clear memory manager */ void Clear_Memory_Manager(void) { MEMORY_BLOCK_STRUCT *current; if (debug_flag) { printf("Clear_Memory_Manager() start\n"); fflush(stdout); } for (current = mem_block_head.next; current != &mem_block_tail; current = current->next) { current->used = 0; memset(current->data, 0, current->size); } mem_block_head.next = &mem_block_tail; mem_block_tail.prev = &mem_block_head; mem_block_head.prev = mem_block_tail.next = 0; if (debug_flag) { printf("Clear_Memory_Manager() end\n"); fflush(stdout); } } /* ** Allocate memory */ void *fast_malloc(int size) { int temp; MEMORY_BLOCK_STRUCT *current; if (size > BLOCK_SIZE) return 0; for (current = mem_block_head.next; current != &mem_block_tail; current = current->next) { if ((current->size - current->used) >= size) { temp = current->used; current->used += size; return (char *)current->data + temp; } } current = calloc((size_t)sizeof(MEMORY_BLOCK_STRUCT) + BLOCK_SIZE, 1); assert(current != 0); current->size = BLOCK_SIZE; current->used = 0; current->data = ¤t[1]; current->prev = &mem_block_head; current->next = mem_block_head.next; mem_block_head.next = current; current->next->prev = current; return fast_malloc(size); } /* ** Dump memory */ void Dump_Memory(void) { MEMORY_BLOCK_STRUCT *current; for (current = mem_block_head.next; current != &mem_block_tail; current = current->next) { if (!current) { printf("Null block!!!\n"); fflush(stdout); return; } printf("block: %p, prev: %p, next: %p, size: %d\n", current, current->prev, current->next, current->size); } } /* ** Check memory */ int Check_Memory(void) { volatile char junk; MEMORY_BLOCK_STRUCT *prev, *prev2, *current; for (current = mem_block_head.next; current != &mem_block_tail; current = current->next) { junk = *(char *)current; /* Dereference it to make sure */ if (!current) { printf("Null block!!!\n"); fflush(stdout); Dump_Memory(); return 1; } prev2 = prev; prev = current; } return 0; } /************************************** * End memory management functions **************************************/ /************************************* * Start input file functions *************************************/ /* ** Clear input lines */ void Clear_Input_Lines(void) { input_head.label = input_head.operator = input_head.operand = &null; input_tail.label = input_tail.operator = input_tail.operand = &null; input_head.next = &input_tail; input_tail.prev = &input_head; input_head.prev = input_tail.next = 0; } /* ** Add line */ void Add_Input_Line(char *label, char *operator, char *operand) { LINE_STRUCT *line; line = fast_malloc(sizeof(LINE_STRUCT)); assert(line != 0); line->label = strcpy(fast_malloc(strlen(label) + 1), label); line->operator = strcpy(fast_malloc(strlen(operator) + 1), operator); line->operand = strcpy(fast_malloc(strlen(operand) + 1), operand); line->prev = input_tail.prev; line->next = &input_tail; input_tail.prev = line; line->prev->next = line; } /* ** Parse line */ void Parse_Line(FILE *infile) { char *source, *dest; *label = *operator = *operand = 0; fgets(current_line, 255, infile); if (*current_line == '\n') /* Early exit for null line */ return; source = current_line; dest = label; /* Extract label */ while (!isspace(*source) && (*source != '*') && (*source != ';') && (*source != '\n')) *dest++ = *source++; *dest = 0; /* Skip whitespace before operator */ while (isspace(*source) && (*source != '*') && (*source != ';') && (*source != '\n')) source++; dest = operator; /* Extract operator */ while (!isspace(*source) && (*source != '*') && (*source != ';') && (*source != '\n')) *dest++ = *source++; *dest = 0; /* Skip whitespace before operand */ while (isspace(*source) && (*source != '*') && (*source != ';') && (*source != '\n')) source++; dest = operand; /* Extract operand */ while (!isspace(*source) && (*source != '*') && (*source != ';') && (*source != '\n')) *dest++ = *source++; *dest = 0; /* Extract comment */ dest = comment; if (*source == '*') while (*source && (*source != '\n')) *dest++ = *source++; *dest = 0; } /************************************* * End input file functions *************************************/ /************************************** * Start Stage1 functions **************************************/ LINE_STRUCT *line[5], *next_line; /* ** Get new line */ void Get_New_Line(void) { line[LAST_LINE] = next_line; if (next_line != &input_tail) next_line = next_line->next; } /* ** Insert line */ void Insert_Input_Line(int line_num, char *operator, char *operand) { int i; LINE_STRUCT *new_line; new_line = fast_malloc(sizeof(LINE_STRUCT)); new_line->label = &null; new_line->operator = strcpy(fast_malloc(strlen(operator) + 1), operator); new_line->operand = strcpy(fast_malloc(strlen(operand) + 1), operand); new_line->next = line[line_num + 1]; new_line->prev = line[line_num]; line[line_num]->next = new_line; line[line_num + 1]->prev = new_line; line_num++; for (i=line_num; i<5; i++) { line[i] = new_line; new_line = new_line->next; } next_line = new_line; } /* ** Delete line */ void Delete_Input_Line(int num, int id) { int i; #ifdef DEBUG printf("opt %d: deleting line %d: %s %s\n", id, num, line[num]->operator, line[num]->operand); #endif line[num]->prev->next = line[num]->next; /* Frosty pointers delicately dancing */ line[num]->next->prev = line[num]->prev; /* in the pale moonlight... */ if (num < LAST_LINE) { for (i=num; ioperator, "ld.l")) { if (!strcmp(line[1]->operator, "st.l") && !strcmp(line[0]->operand, line[1]->operand)) { Delete_Input_Line(1, 1); return 1; } if (Check_Invalidate(line[1]->operator)) { Delete_Input_Line(0, 2); return 1; } if (((*line[0]->operand == '#') || (*line[0]->operand == '<')) && !strcmp(line[1]->operator, "push.l") && !*line[1]->operand && Check_Invalidate(line[2]->operator)) { line[1]->operand = line[0]->operand; Delete_Input_Line(0, 3); return 1; } } if (!strcmp(line[0]->operator, "st.l")) { if (!strcmp(line[1]->operator, "add.l") && !strcmp(line[2]->operator, "st.l") && !strcmp(line[0]->operand, line[2]->operand)) { Delete_Input_Line(0, 4); return 1; } if (!strcmp(line[1]->operator, "ld.l") && !strcmp(line[2]->operator, "add.l") && !strcmp(line[0]->operand, line[2]->operand)) { line[2]->operand = line[1]->operand; Delete_Input_Line(1, 5); return 1; } if (!strcmp(line[1]->operator, "ld.l") && !strcmp(line[0]->operand, line[1]->operand)) { Delete_Input_Line(1, 6); return 1; } } #if 0 if (!strcmp(line[0]->operator, "lea")) { if (!strcmp(line[1]->operator, "push.l") && !*line[1]->operand && Check_Invalidate(line[2]->operator)) { strcpy(line[1]->operator, "pusha"); line[1]->operand = line[0]->operand; Delete_Input_Line(0, 7); return 1; } } #endif return 0; } /* ** Stage1 - optimize VM code */ int Stage1(void) { int i, j; int opts_num, pass_opts_num, total_opts_num, pass_num; int changed; if (debug_flag) { printf("Stage1 start\n"); fflush(stdout); } pass_num = 1; total_opts_num = 0; do { next_line = input_head.next; for (i=0; inext; } if (info_flag) printf("Stage1 Pass %d: removed %d instructions\n", pass_num++, pass_opts_num); total_opts_num += pass_opts_num; if (debug_flag && Check_Memory()) { printf("Stage1(): Memory check failed!\n"); exit(-1); } } while (changed); if (info_flag) printf("Stage1 total: removed %d instructions\n", total_opts_num); return total_opts_num; } /************************************** * End Stage1 functions **************************************/ /************************************** * Start 65816 linked list functions **************************************/ /* ** Clear output lines */ void Clear_Output_Lines(void) { output_head.next = &output_tail; output_tail.prev = &output_head; output_head.prev = output_tail.next = 0; } /* ** Add output line */ void Add_Output_Line(char *label, char *operator, char *operand) { char *dest; int size; LINE_STRUCT *line; size = sizeof(LINE_STRUCT) + strlen(label) + strlen(operator) + strlen(operand) + 3; line = fast_malloc(size); dest = (char *)&line[1]; strcpy(line->label = dest, label); dest += strlen(label) + 1; strcpy(line->operator = dest, operator); dest += strlen(operator) + 1; strcpy(line->operand = dest, operand); line->prev = output_tail.prev; line->next = &output_tail; line->prev->next = line; output_tail.prev = line; } /* ** Add operator line */ void Add_Operator_Line(char *operator, char *operand) { char *dest; int size; LINE_STRUCT *line; size = sizeof(LINE_STRUCT) + strlen(operator) + strlen(operand) + 2; line = fast_malloc(size); dest = (char *)&line[1]; line->label = &null; strcpy(line->operator = dest, operator); dest += strlen(operator) + 1; strcpy(line->operand = dest, operand); line->prev = output_tail.prev; line->next = &output_tail; line->prev->next = line; output_tail.prev = line; } /************************************** * End 65816 linked list functions **************************************/ /************************************** * Start Stage2 functions **************************************/ char temp[80], temp2[80], temp3[80], temp4[80]; /* ** Create doubleword operands */ void Create_Doubleword_Operands(char *operand, char *operand_low, char *operand_high) { if (*operand == '#') { sprintf(operand_low, "#<%s", operand + 1); sprintf(operand_high, "#^%s", operand + 1); } else if ((*operand == '<') || (*operand == '>')) { sprintf(operand_low, "%s", operand); sprintf(operand_high, "%s+2", operand); } } /* ** Create quadword operands */ void Create_Quadword_Operands(char *operand, char *operand1, char *operand2, char *operand3, char *operand4) { if (*operand == '#') { sprintf(operand1, "#%s", operand+1); sprintf(operand2, "#(%s)|-16", operand+1); sprintf(operand3, "#(%s)|-32", operand+1); sprintf(operand4, "#(%s)|-48", operand+1); } else if ((*operand == '<') || (*operand == '>')) { sprintf(operand1, "%s", operand); sprintf(operand2, "%s+2", operand); sprintf(operand3, "%s+4", operand); sprintf(operand4, "%s+6", operand); } } /* ** Push two doubleword operands */ void Push_Doubleword_Operands(char *operand) { Add_Operator_Line("phx", &null); Add_Operator_Line("pha", &null); if (*operand == '#') { sprintf(temp, "+(%s)|-16", operand+1); Add_Operator_Line("pea", temp); Add_Operator_Line("pea", operand+1); } else if (*operand == '<') { sprintf(temp, "%s+2", operand); Add_Operator_Line("pei", temp); Add_Operator_Line("pei", operand); } else if (*operand == '>') { sprintf(temp, "%s+2", operand); Add_Operator_Line("lda", temp); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", operand); Add_Operator_Line("pha", &null); } } /* ** Push two quadword operands */ void Push_Quadword_Operands(char *operand) { Add_Operator_Line("lda", ">dfp_reg"); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", ">dfp_reg+2"); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", ">dfp_reg+4"); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", ">dfp_reg+6"); Add_Operator_Line("pha", &null); Create_Quadword_Operands(operand, temp, temp2, temp3, temp4); if (*operand == '#') { Add_Operator_Line("pea", temp4); Add_Operator_Line("pea", temp3); Add_Operator_Line("pea", temp2); Add_Operator_Line("pea", temp); } else if (*operand == '<') { Add_Operator_Line("pei", temp4); Add_Operator_Line("pei", temp3); Add_Operator_Line("pei", temp2); Add_Operator_Line("pei", temp); } else if (*operand == '>') { Add_Operator_Line("lda", temp4); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", temp3); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", temp2); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", temp); Add_Operator_Line("pha", &null); } } /* ** Output TAY TXA */ void Swap_Register_In(void) { Add_Operator_Line("tay", &null); Add_Operator_Line("txa", &null); } /* ** Output TAX TYA */ void Swap_Register_Out(void) { Add_Operator_Line("tax", &null); Add_Operator_Line("tya", &null); } /* ** Store XA registers */ void Store_XA_Registers(char *label) { sprintf(temp, "%s+2", label); if (*label == '<') { Add_Operator_Line("sta", label); Add_Operator_Line("stx", temp); } else if (*label == '>') { Add_Operator_Line("sta", label); Add_Operator_Line("tay", &null); Add_Operator_Line("txa", &null); Add_Operator_Line("sta", temp); Add_Operator_Line("tya", &null); } } /* ** Load XA registers */ void Load_XA_Registers(char *label) { Create_Doubleword_Operands(label, temp, temp2); if (*label == '>') { Add_Operator_Line("lda", temp2); Add_Operator_Line("tax", &null); Add_Operator_Line("lda", temp); } else { Add_Operator_Line("lda", temp); Add_Operator_Line("ldx", temp2); } } /* ** Convert VM32 loads to 65816 */ int Convert_VM32_Loads(void) { char *operator = line[0]->operator; char *operand = line[0]->operand; if (!strcmp(operator, "ld.b") || !strcmp(operator, "ld.w")) { Add_Operator_Line("lda", operand); return 1; } if (!strcmp(operator, "ld.l") || !strcmp(operator, "ld.f")) { Load_XA_Registers(operand); return 1; } if (!strcmp(operator, "ld.d")) { if (*operand == '#') { Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "dfp_reg"); sprintf(temp, "+(%s)|-16", operand+1); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+2"); sprintf(temp, "+(%s)|-32", operand+1); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+4"); sprintf(temp, "+(%s)|-48", operand+1); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+6"); return 1; } else if ((*operand == '<') || (*operand == '>')) { Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "dfp_reg"); sprintf(temp, "%s+2", operand); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+2"); sprintf(temp, "%s+4", operand); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+4"); sprintf(temp, "%s+6", operand); Add_Operator_Line("lda", temp); Add_Operator_Line("sta", "dfp_reg+6"); return 1; } } if (!strcmp(operator, "ldi.b") || !strcmp(operator, "ldi.w")) { if (!*operand) { Add_Operator_Line("sta", "') { sprintf(temp, "%s+2", operand); Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "') { sprintf(temp, "%s+2", operand); Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "') { sprintf(temp, "#<%s", operand + 1); sprintf(temp2, "#^%s", operand + 1); Add_Operator_Line("lda", temp); Add_Operator_Line("ldx", temp2); return 1; } } return 0; } /* ** Convert VM32 stores to 65816 */ int Convert_VM32_Stores(void) { char *operator = line[0]->operator; char *operand = line[0]->operand; if (!strcmp(operator, "st.b")) { if ((*operand == '<') || (*operand == '>') || (*operand == '#')) { Add_Operator_Line("sep", "#$20"); Add_Operator_Line("sta", operand); Add_Operator_Line("rep", "#$20"); return 1; } } else if (!strcmp(operator, "st.w")) { if ((*operand == '<') || (*operand == '>') || (*operand == '#')) { Add_Operator_Line("sta", operand); return 1; } } else if (!strcmp(operator, "st.l") || !strcmp(operator, "st.f")) { if ((*operand == '<') || (*operand == '>')) { Store_XA_Registers(operand); return 1; } } else if (!strcmp(operator, "st.d")) { Create_Quadword_Operands(operand, temp, temp2, temp3, temp4); Add_Operator_Line("lda", "dfp_reg"); Add_Operator_Line("sta", temp); Add_Operator_Line("lda", "dfp_reg+2"); Add_Operator_Line("sta", temp2); Add_Operator_Line("lda", "dfp_reg+4"); Add_Operator_Line("sta", temp3); Add_Operator_Line("lda", "dfp_reg+6"); Add_Operator_Line("sta", temp4); return 1; } else if (!strcmp(operator, "sti.b")) { if (*operand == '<') { sprintf(temp, "[%s]", operand); Add_Operator_Line("sep", "#$20"); Add_Operator_Line("sta", temp); Add_Operator_Line("rep", "#$20"); return 1; } else if (*operand == '>') { sprintf(temp, "%s+2", operand); Add_Operator_Line("tay", &null); Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "') { sprintf(temp, "%s+2", operand); Add_Operator_Line("tay", &null); Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "') { sprintf(temp, "%s+2", operand); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", operand); Add_Operator_Line("sta", "operator; char *operand = line[0]->operand; int i, shifts_num; if (!strcmp(operator, "lsh.l")) { if (*operand == '#') { Add_Operator_Line("stx", "operator; char *operand = line[0]->operand; if (!strcmp(operator, "pop.w")) { Add_Operator_Line("pla", &null); return 1; } else if (!strcmp(operator, "pop.l")) { Add_Operator_Line("pla", &null); Add_Operator_Line("plx", &null); return 1; } else if (!strcmp(operator, "pusha")) { if (*operand == '<') { sprintf(temp, "#%s", operand+1); Add_Operator_Line("pea", "0"); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", temp); Add_Operator_Line("pha", &null); return 1; } else if (*operand == '>') { sprintf(temp, "+(%s)|-16", operand+1); Add_Operator_Line("pea", temp); Add_Operator_Line("pea", operand+1); return 1; } } else if (!strcmp(operator, "push.w")) { Add_Operator_Line("pha", &null); return 1; } else if (!strcmp(operator, "push.l")) { if (!*operand) { Add_Operator_Line("phx", &null); Add_Operator_Line("pha", &null); return 1; } else if (*operand == '#') { sprintf(temp, "+(%s)|-16", operand+1); Add_Operator_Line("pea", temp); Add_Operator_Line("pea", operand+1); return 1; } else if (*operand == '<') { sprintf(temp, "%s+2", operand); Add_Operator_Line("pei", temp); Add_Operator_Line("pei", operand); return 1; } } else if (!strcmp(operator, "pop")) { if (*operand == '#') { Add_Operator_Line("tay", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", operand); Add_Operator_Line("tcs", &null); Add_Operator_Line("tya", &null); return 1; } } return 0; } /* ** Convert VM32 compares */ int Convert_VM32_Compares(void) { char *operator = line[0]->operator; char *operand = line[0]->operand; if (!strcmp(operator, "cmp.l")) { if (*operand == '#') { sprintf(temp, "scratch,%s", operand); Add_Operator_Line("sta", "')) { sprintf(temp, "scratch,%s", operand+1); Add_Operator_Line("sta", "operator; char *operand = line[0]->operand; if (!strcmp(operator, "blt")) { Add_Operator_Line("bcs", "*+5"); Add_Operator_Line("jmp", operand); return 1; } if (!strcmp(operator, "ble")) { Add_Operator_Line("beq", "*+7"); Add_Operator_Line("bcs", "*+5"); Add_Operator_Line("jmp", operand); return 1; } if (!strcmp(operator, "beq")) { Add_Operator_Line("bne", "*+5"); Add_Operator_Line("jmp", operand); return 1; } if (!strcmp(operator, "bge")) { Add_Operator_Line("bcc", "*+5"); Add_Operator_Line("jmp", operand); return 1; } if (!strcmp(operator, "bgt")) { Add_Operator_Line("bcc", "*+7"); Add_Operator_Line("beq", "*+5"); Add_Operator_Line("jmp", operand); return 1; } if (!strcmp(operator, "bne")) { Add_Operator_Line("beq", "*+5"); Add_Operator_Line("jmp", operand); return 1; } return 0; } /* ** Convert VM32 jumps */ int Convert_VM32_Jumps(void) { char *operator = line[0]->operator; char *operand = line[0]->operand; if (!strcmp(operator, "jmp")) { Add_Operator_Line("jmp", operand); return 1; } else if (!strcmp(operator, "jmpi")) { Add_Operator_Line("sep", "#$10"); Add_Operator_Line("phx", &null); Add_Operator_Line("rep", "#$10"); Add_Operator_Line("dec", "a"); Add_Operator_Line("pha", &null); Add_Operator_Line("rtl", &null); return 1; } else if (!strcmp(operator, "jsr")) { Add_Operator_Line("jsl", operand); return 1; } else if (!strcmp(operator, "jsri")) { if (!*operator) { Add_Operator_Line("sta", "') { Add_Output_Line("; this needs to be worked on...", &null, &null); Add_Operator_Line("phk", &null); Add_Operator_Line("pea", "*+5"); Add_Operator_Line("lda", operand); sprintf(temp, "%s+2", operand); Add_Operator_Line("ldx", temp); Add_Operator_Line("sta", "label; char *operator = line[0]->operator; char *operand = line[0]->operand; switch(*line[0]->operator) { case 'a': if (!strcmp(operator, "add.l")) { if (!strcmp(operand, "#1")) { Add_Operator_Line("inc", "a"); Add_Operator_Line("bne", "*+3"); Add_Operator_Line("inx", &null); return 1; } else { Create_Doubleword_Operands(operand, temp, temp2); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", temp); Swap_Register_In(); Add_Operator_Line("adc", temp2); Swap_Register_Out(); return 1; } } if (!strcmp(operator, "add.f")) { Push_Doubleword_Operands(operand); Add_Operator_Line("jsl", "fp_adds"); return 1; } if (!strcmp(operator, "add.d")) { Push_Quadword_Operands(operand); Add_Operator_Line("jsl", "dfp_adds"); return 1; } if (!strcmp(operator, "and.w")) { if ((*operand == '#') || (*operand == '<') || (*operand == '>')) { Add_Operator_Line("and", operand); return 1; } } if (!strcmp(operator, "and.l")) { Create_Doubleword_Operands(operand, temp, temp2); Add_Operator_Line("and", temp); Swap_Register_In(); Add_Operator_Line("and", temp2); Swap_Register_Out(); return 1; } return 0; case 'b': return Convert_VM32_Branches(); case 'c': if (!strcmp(operator, "cvdf")) { Add_Operator_Line("jsl", "cvdf"); return 1; } return Convert_VM32_Compares(); case 'd': if (!strcmp(operator, "divi.l")) { Add_Operator_Line("sta", "') { sprintf(temp, "%s+2", operand); Add_Operator_Line("lda", operand); Add_Operator_Line("pha", &null); Add_Operator_Line("lda", temp); Add_Operator_Line("pha", &null); } Add_Operator_Line("jsl", "mulu"); Add_Operator_Line("tay", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", "#8"); Add_Operator_Line("tcs", &null); Add_Operator_Line("tya", &null); return 1; } if (!strcmp(operator, "mul.f")) { Push_Doubleword_Operands(operand); Add_Operator_Line("jsl", "fp_muls"); return 1; } if (!strcmp(operator, "mul.d")) { Push_Quadword_Operands(operand); Add_Operator_Line("jsl", "dfp_muls"); return 1; } return 0; case 'n': if (!strcmp(operator, "neg.l")) { if (!*operand) { Add_Operator_Line("eor", "#$ffff"); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", "#1"); Swap_Register_In(); Add_Operator_Line("eor", "#$ffff"); Add_Operator_Line("adc", "#0"); Swap_Register_Out(); return 1; } } return 0; case 'o': if (!strcmp(operator, "or.l")) { Create_Doubleword_Operands(operand, temp, temp2); Add_Operator_Line("ora", temp); Swap_Register_In(); Add_Operator_Line("ora", temp2); Swap_Register_Out(); return 1; } return 0; case 'p': return Convert_VM32_Stack_Ops(); case 'r': if (!strcmp(operator, "ret")) { if (!*operand) { Add_Operator_Line("rtl", &null); return 1; } } return 0; case 's': if (!strcmp(operator, "sub.l")) { Create_Doubleword_Operands(operand, temp, temp2); Add_Operator_Line("sec", &null); Add_Operator_Line("sbc", temp); Swap_Register_In(); Add_Operator_Line("sbc", temp2); Swap_Register_Out(); return 1; } if (!strcmp(operator, "sub.f")) { Push_Doubleword_Operands(operand); Add_Operator_Line("jsl", "fp_subs"); return 1; } if (!strcmp(operator, "sub.d")) { Push_Quadword_Operands(operand); Add_Operator_Line("jsl", "dfp_subs"); return 1; } if (!strcmp(operator, "start")) { Add_Output_Line(label, operator, operand); Add_Operator_Line("longa", "on"); Add_Operator_Line("longi", "on"); return 1; } return Convert_VM32_Stores(); case 'u': if (!strcmp(operator, "unlk")) { Add_Operator_Line("tay", &null); Add_Operator_Line("pld", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", operand); Add_Operator_Line("tcs", &null); Add_Operator_Line("tya", &null); return 1; } return 0; case '!': Add_Output_Line(label, operator+1, operand); return 1; } return 0; } /* ** Convert VM32 (4 instruction optimizations) */ int Convert_VM32_Opt4(void) { /* Check for incrementing short */ if (!strcmp(line[0]->operator, "ld.w") && (*line[0]->operand == '<') && !strcmp(line[1]->operator, "ext.wl") && !strcmp(line[2]->operator, "add.l") && !strcmp(line[2]->operand, "#1") && !strcmp(line[3]->operator, "st.w") && !strcmp(line[0]->operand, line[3]->operand) && Check_Invalidate(line[4]->operator)) { Add_Operator_Line("inc", line[0]->operand); return 4; } /* Check for increment long with save original value */ if (!strcmp(line[0]->operator, "ld.l") && (*line[0]->operand == '<') && !strcmp(line[1]->operator, "st.l") && !strcmp(line[2]->operator, "add.l") && !strcmp(line[2]->operand, "#1") && !strcmp(line[3]->operator, "st.l") && !strcmp(line[0]->operand, line[3]->operand)) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); Add_Operator_Line("lda", temp); Add_Operator_Line("ldx", temp2); Add_Operator_Line("sta", temp3); Add_Operator_Line("stx", temp4); Add_Operator_Line("inc", "a"); Add_Operator_Line("sta", temp); Add_Operator_Line("bne", "*+5"); Add_Operator_Line("inx", &null); Add_Operator_Line("stx", temp2); return 4; } return 0; } /* ** Convert VM32 (3 instruction optimizations) */ int Convert_VM32_Opt3(void) { int value, value2; /* Check for incrementing long */ if (!strcmp(line[0]->operator, "ld.l") && (*line[0]->operand == '<') && !strcmp(line[1]->operator, "add.l") && !strcmp(line[1]->operand, "#1") && !strcmp(line[2]->operator, "st.l") && !strcmp(line[0]->operand, line[2]->operand) && Check_Invalidate(line[3]->operator)) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Add_Operator_Line("inc", temp); Add_Operator_Line("bne", "*+4"); Add_Operator_Line("inc", temp2); return 3; } if (!strcmp(line[0]->operator, "ld.l") && (*line[0]->operand == '#') && !strcmp(line[1]->operator, "unlk") && !strcmp(line[2]->operator, "ret")) { Add_Operator_Line("pld", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", line[1]->operand); Add_Operator_Line("tcs", &null); Load_XA_Registers(line[0]->operand); Add_Operator_Line("rtl", &null); return 3; } if (!strcmp(line[0]->operator, "label") && !strcmp(line[1]->operator, "pop") && !strcmp(line[2]->operator, "unlk")) { value = atol(line[0]->operand + 1); value2 = atol(line[1]->operand + 1); sprintf(temp, "%d,s", value + 1); sprintf(temp2, "#%d", value + value2 + 2); Add_Output_Line(label, "anop", &null); Add_Operator_Line("lda", temp); Add_Operator_Line("tcd", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", temp2); Add_Operator_Line("tcs", &null); return 3; } return 0; } /* ** Convert VM32 (2 instruction optimizations) */ int Convert_VM32_Opt2(void) { int value, value2; if (!strcmp(line[1]->operator, "st.l") && Check_Invalidate(line[2]->operator)) { if (!strcmp(line[0]->operator, "add.l")) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); if (!strcmp(line[0]->operand, "#1") && (*line[1]->operand == '<')) { Add_Operator_Line("inc", "a"); Add_Operator_Line("sta", temp3); Add_Operator_Line("bne", "*+3"); Add_Operator_Line("inx", &null); Add_Operator_Line("stx", temp4); } else { Add_Operator_Line("clc", &null); Add_Operator_Line("adc", temp); Add_Operator_Line("sta", temp3); Add_Operator_Line("txa", &null); Add_Operator_Line("adc", temp2); Add_Operator_Line("sta", temp4); } return 2; } if (!strcmp(line[0]->operator, "sub.l")) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); Add_Operator_Line("sec", &null); Add_Operator_Line("sbc", temp); Add_Operator_Line("sta", temp3); Add_Operator_Line("txa", &null); Add_Operator_Line("sbc", temp2); Add_Operator_Line("sta", temp4); return 2; } if (!strcmp(line[0]->operator, "and.l")) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); Add_Operator_Line("and", temp); Add_Operator_Line("sta", temp3); Add_Operator_Line("txa", &null); Add_Operator_Line("and", temp2); Add_Operator_Line("sta", temp4); return 2; } if (!strcmp(line[0]->operator, "or.l")) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); Add_Operator_Line("ora", temp); Add_Operator_Line("sta", temp3); Add_Operator_Line("txa", &null); Add_Operator_Line("ora", temp2); Add_Operator_Line("sta", temp4); return 2; } if (!strcmp(line[0]->operator, "eor.l")) { Create_Doubleword_Operands(line[0]->operand, temp, temp2); Create_Doubleword_Operands(line[1]->operand, temp3, temp4); Add_Operator_Line("eor", temp); Add_Operator_Line("sta", temp3); Add_Operator_Line("txa", &null); Add_Operator_Line("eor", temp2); Add_Operator_Line("sta", temp4); return 2; } } if (!strcmp(line[0]->operator, "ld.w")) { if (!strcmp(line[0]->operand, "#0") && !strcmp(line[1]->operator, "st.w") && Check_Invalidate(line[2]->operator)) { Add_Operator_Line("stz", line[1]->operand); return 2; } if (!strcmp(line[1]->operator, "ext.wl")) { Add_Operator_Line("ldx", "#0"); Add_Operator_Line("lda", line[0]->operand); Add_Operator_Line("bpl", "*+3"); Add_Operator_Line("dex", &null); return 2; } } if (!strcmp(line[0]->operator, "ld.l")) { if (!strcmp(line[0]->operand, "#0") && !strcmp(line[1]->operator, "st.l") && Check_Invalidate(line[2]->operator)) { Create_Doubleword_Operands(line[1]->operand, temp, temp2); Add_Operator_Line("stz", temp); Add_Operator_Line("stz", temp2); return 2; } if (*line[0]->operand == '<') { if (!strcmp(line[1]->operator, "ldi.b") || !strcmp(line[1]->operator, "ldi.w")) { sprintf(temp, "[%s]", line[0]->operand+1); Add_Operator_Line("lda", temp); return 2; } if (!strcmp(line[1]->operator, "ldi.l")) { sprintf(temp, "[%s],y", line[0]->operand+1); sprintf(temp2, "[%s]", line[0]->operand+1); Add_Operator_Line("ldy", "#2"); Add_Operator_Line("lda", temp); Add_Operator_Line("tax", &null); Add_Operator_Line("lda", temp2); return 2; } } if (!strcmp(line[1]->operator, "unlk")) { Load_XA_Registers(line[0]->operand); Add_Operator_Line("pld", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", line[1]->operand); Add_Operator_Line("tcs", &null); Add_Operator_Line("tya", &null); return 2; } } if (!strcmp(line[0]->operator, "pop") && !strcmp(line[1]->operator, "unlk")) { value = atol(line[0]->operand + 1); value2 = atol(line[1]->operand + 1); sprintf(temp, "%d,s", value + 1); sprintf(temp2, "#%d", value + value2 + 2); Add_Operator_Line("tay", &null); Add_Operator_Line("lda", temp); Add_Operator_Line("tcd", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", temp2); Add_Operator_Line("tcs", &null); Add_Operator_Line("tya", &null); return 2; } if (!strcmp(line[0]->operator, "cmp.l") && !strcmp(line[0]->operand, "#0")) { if (!strcmp(line[1]->operator, "bne")) { Add_Operator_Line("stx", "operand); return 2; } else if (!strcmp(line[1]->operator, "beq")) { Add_Operator_Line("stx", "operand); return 2; } } if (!strcmp(line[0]->operator, "label") && !strcmp(line[1]->operator, "unlk")) { Add_Output_Line(line[0]->label, "anop", &null); Add_Operator_Line("pld", &null); Add_Operator_Line("tsc", &null); Add_Operator_Line("clc", &null); Add_Operator_Line("adc", line[1]->operand); Add_Operator_Line("tcs", &null); return 2; } return 0; } /* ** Convert VM32 (1 instruction optimizations) */ int Convert_VM32_Opt1(void) { if (!strcmp(line[0]->operator, "add.l") && !strcmp(line[0]->operand, "#1")) { Add_Operator_Line("inc", "a"); Add_Operator_Line("bne", "*+3"); Add_Operator_Line("inx", &null); return 1; } return 0; } /* ** Stage2 - convert to 65816 code */ void Stage2(void) { int i, j, lines_num; if (debug_flag) { printf("Stage2 start\n"); fflush(stdout); } next_line = input_head.next; for (i=0; ilabel, line[0]->operator, line[0]->operand); Add_Output_Line(temp, &null, &null); #endif lines_num = Convert_VM32_Opt4(); if (!lines_num) lines_num = Convert_VM32_Opt3(); if (lines_num > LOOKAHEAD_LINES) { printf("Opt3: returned %d on %s, %s\n", lines_num, line[0]->operator, line[0]->operand); exit(-1); } if (!lines_num) lines_num = Convert_VM32_Opt2(); if (lines_num > LOOKAHEAD_LINES) { printf("Opt2: returned %d on %s, %s\n", lines_num, line[0]->operator, line[0]->operand); exit(-1); } if (!lines_num) lines_num = Convert_VM32_Opt1(); if (lines_num > LOOKAHEAD_LINES) { printf("Opt1: returned %d on %s, %s\n", lines_num, line[0]->operator, line[0]->operand); exit(-1); } if (!lines_num) lines_num = Convert_VM32(); if (lines_num > LOOKAHEAD_LINES) { printf("Opt0: returned %d on %s, %s\n", lines_num, line[0]->operator, line[0]->operand); exit(-1); } if (!lines_num) { sprintf(temp, "; Unknown operation: %s %s %s", line[0]->label, line[0]->operator, line[0]->operand); fprintf(stderr, "%s\n", temp); Add_Output_Line(temp, &null, &null); lines_num = 1; } for (i=0; inext; } } if (debug_flag) { printf("Stage2 end\n"); fflush(stdout); } if (debug_flag && Check_Memory()) { printf("Stage2(): Memory check failed!\n"); exit(-1); } } /************************************** * End Stage2 functions **************************************/ /************************************** * Start Stage3 functions **************************************/ /************************************** * End Stage3 functions **************************************/ /************************************** * Start Stage4 functions **************************************/ /* ** Stage 4 - write output file */ void Stage4(FILE *outfile) { LINE_STRUCT *line; if (debug_flag) { printf("Stage4 start\n"); fflush(stdout); } for (line = output_head.next; line != &output_tail; line = line->next) { fprintf(outfile, "%s\t%s\t%s\n", line->label, line->operator, line->operand); } if (debug_flag) { printf("Stage4 end\n"); fflush(stdout); } if (debug_flag && Check_Memory()) { printf("Stage4(): Memory check failed!\n"); exit(-1); } } /************************************** * End Stage4 functions **************************************/ /* ** Dump linked list */ void Dump_Linked_List(void) { LINE_STRUCT *current; printf("linked list dump:\n"); for (current = input_head.next; current != &input_tail; current = current->next) printf("%s\t%s\t%s\n", current->label, current->operator, current->operand); } /* ** Main */ void main(int argc, char **argv) { int i; FILE *infile, *outfile; printf("vm2gs v2.0 by Toshiyasu Morita\n"); if (argc < 2) { printf("usage: vm2gs2 [output file]\n"); exit(0); } for (i=1; (i < argc) && (argv[i][0] == '-'); i++) { if (!strcmp(argv[i], "-debug")) debug_flag = 1; else if (!strcmp(argv[i], "-info")) info_flag = 1; else printf("vm2gs2: Unknown option \"%s\"", argv[i]); } Init_Memory_Manager(); Clear_Input_Lines(); Clear_Output_Lines(); if (!(infile = fopen(argv[i], "rt"))) { fprintf(stderr, "Error: couldn't open %s for input\n", argv[1]); exit(0); } if (!(outfile = fopen(argv[i+1], "wt"))) outfile = stdout; fprintf(outfile, "\tmcopy\t13/orcainclude/m16.orca\n"); while (!feof(infile)) { do { Parse_Line(infile); } while ((!*operator) && !feof(infile)); Add_Input_Line(label, operator, operand); if (!strcmp(operator, "end")) { if (strlen(label)) printf("converting function %s()...\n", label + 1); else printf("converting data...\n"); Stage1(); Stage2(); Stage4(outfile); Clear_Memory_Manager(); Clear_Input_Lines(); Clear_Output_Lines(); } } fclose(infile); fclose(outfile); Uninit_Memory_Manager(); exit(0); }