home *** CD-ROM | disk | FTP | other *** search
-
- #include "CodeTable.c"
- #include "TextTable.c"
-
- #define FULL 0xffffffff
-
- FILE *error_file, *out_file, *in_file;
-
- void status(char*);
-
- // contains line of sourcetext
- char textline[256] = "";
- int line_nr,
- error_counter,
- transfer_enabled = 1,
- last_error_file;
-
- // structure for symbols and their addresses
- struct symbolstruct
- {
- char name[40];
- int address;
- int number_of_reads;
- };
-
- // number of defined symbols and room for 1000 symbol structures
- int nr_of_symbols=0;
- struct symbolstruct symbol[1000];
-
- // program counter (points to next free byte)
- int pc, base, base_defined;
-
- //-------------------------------------------------------------
- void put_error(int number, int mode)
- {
- if (mode)
- {
- error_counter++;
- if ( last_error_file != *(line_list + (line_nr << 1) + 1) )
- {
- last_error_file = *(line_list + (line_nr << 1) + 1);
- fprintf(error_file, "\nFile %s\n",
- file_list[ *(line_list + (line_nr << 1) + 1) ] );
- }
- fprintf(error_file, " Line %04d - ",
- *(line_list + (line_nr << 1)) );
- switch (number)
- {
- case 0:
- fprintf(error_file, "Error: Illegal address mode\n"); break;
- case 1:
- fprintf(error_file, "Error: Unknown mnemonic\n"); break;
- case 2:
- fprintf(error_file, "Error: Higher than &ff\n"); break;
- case 3:
- fprintf(error_file, "Error: Branch out of range\n"); break;
- case 4:
- fprintf(error_file, "Error: Overflow in expression\n"); break;
- case 5:
- fprintf(error_file, "Error: Missing \')\'\n"); break;
- case 6:
- fprintf(error_file, "Error: Cannot calculate expression\n"); break;
- case 7:
- fprintf(error_file, "Error: Undefined Symbol found\n"); break;
- case 8:
- fprintf(error_file, "Error: Illegal use of '.\' or \'!\'\n"); break;
- case 9:
- fprintf(error_file, "Error: Too many symbols\n"); break;
- case 10:
- fprintf(error_file, "Error: Illegal chars found in symbol\n"); break;
- case 11:
- fprintf(error_file, "Error: Symbol defined twice\n"); break;
- case 12:
- fprintf(error_file, "Error: Extern symbols must be defined\n"); break;
- case 13:
- fprintf(error_file, "Error: No base defined\n"); break;
- case 14:
- fprintf(error_file, "Error: Labels must not be defined\n"); break;
- case 15:
- fprintf(error_file, "Warning: Overflow\n"); break;
- case 16:
- fprintf(error_file, "Error: Illegal mnemonic\n"); break;
- case 17:
- fprintf(error_file, "Warning: Program counter overflow\n"); break;
- case 18:
- fprintf(error_file, "Error: Missing parameters\n"); break;
- case 19:
- fprintf(error_file, "Error: Missing \'\"\'"); break;
- default:
- fprintf(error_file, "Unexpected error\n"); break;
-
- }
- }
- }
-
- //-------------------------------------------------------------
- int getline(FILE *infile)
- {
- // == NULL if EOF
- char *textpos;
- int length, pos;
-
- // don't return empty lines
- do
- {
- // read line from file
- textpos = fgets(textline, 256, infile);
-
- // end if EOF
- if (textpos == NULL)
- return 0;
-
- line_nr++;
-
- // remove silly things like tabs
- length = strlen(textline);
- for (pos = 0; pos < length; pos++)
- if ( textline[pos] < 32 )
- textline[pos] = 32;
-
- // remove spaces from left side
- pos = 0;
- length = strlen(textline) + 1;
- while (textline[pos] == 32)
- pos++;
- memcpy(textline, textline+pos, length);
-
- length = strlen(textline);
-
- // look for comments
- for (pos = 0; pos < length; pos++)
- {
- if ( textline[pos] == ';' )
- {
- textline[pos] = 0;
- length = strlen(textline);
- }
- }
-
- // remove spaces from right side
- length = strlen(textline);
- while ( ((textline[length-1] == ' ') || (textline[length-1] == '\n'))
- && (length > 0) )
- {
- textline[strlen(textline) - 1] = 0;
- length -= 1;
- }
- }
- while (textline[0] == 0);
-
- return 1;
- }
-
- //-------------------------------------------------------------
- int symbol_value(char *name, int mode)
- // gets the value of an label, 0xffff if not defined
- // if mode == 0 no "Undefind symbol" error
- {
- int loop, ret = FULL;
- char cut_name[40];
-
- memcpy(cut_name, name, 40); // copy name in my workspace
- cut_name[39] = 0; // and cut it
- if ( (cut_name[0] == '.') || (cut_name[0] == '!') )
- { // mustn't start with '.' or '!'
- put_error(8, mode);
- ret = FULL;
- }
- else
- {
- for (loop = 0; loop < nr_of_symbols; loop++)
- if ( !strcmp(cut_name, symbol[loop].name) )
- {
- ret = symbol[loop].address;
- symbol[loop].number_of_reads++;
- loop = nr_of_symbols + 1;
- }
- }
- if (ret == FULL)
- put_error(7, mode);
- return ret;
- }
-
- //-------------------------------------------------------------
- int calc(char *source, int mode)
- // calculates an expression
- // mode == 0 no Unefined symbol error
- {
- os_regset r;
- os_error *err;
- int pos, source_len, dest_len=0, name_len, found, part = 0;
- char c1, dest[200]="", name[40];
-
- source_len = strlen(source) + 1;
- while (*source == 32) // I dislike spaces
- memcpy(source, source + 1, source_len--);
- source_len--;
-
- for (pos = 0; pos < source_len; pos+= 0)
- {
- c1 = *(source + pos);
- found = 0;
-
- if (pos == 0 && c1 == '<')
- {
- part = 1; // return lowbyte
- found = 1;
- pos++;
- }
- if (pos == 0 && c1 == '>')
- {
- part = 2; // return highbyte
- found = 1;
- pos++;
- }
-
- if ( (isalpha(c1)) || (c1 == '.') || (c1 == '!') || (c1 == '_') )
- { // found symbol
- name_len = 0;
- *name = 0;
- name[name_len++] = *(source+pos++);
- while ( (isalnum(*(source + pos)) || *(source + pos) == '_') )
- {
- if (name_len < 39)
- name[name_len++] = *(source + pos);
- pos++;
- }
- name[name_len] = 0;
- r.r[0] = symbol_value(name, mode);
- r.r[1] = name;
- r.r[2] = 5;
- os_swi(OS_ConvertHex4,&r);
- dest[dest_len++] = '&';
- memcpy(dest + dest_len,name,4);
- dest_len += 4;
- found = 1;
- }
-
- if ( (c1 == '$') || (c1 == '&') ) // found hex number
- {
- dest[dest_len++]='&';
- pos++;
- while (isxdigit(*(source+pos)))
- dest[dest_len++]=*(source+pos++);
- found = 1;
- }
- if ( isdigit(c1) ) // found decimal number
- {
- while (isdigit(*(source+pos)))
- dest[dest_len++]=*(source+pos++);
- found = 1;
- }
- if ( !found ) // found another char
- {
- dest[dest_len++] = *(source+pos++);
- }
- }
- r.r[0]=dest;
- r.r[1]=0;
- err = os_swix(OS_EvaluateExpression, &r);
- if (err)
- {
- put_error(6, mode);
- r.r[2] = pc;
- }
- if ( r.r[2] > 0xffff )
- {
- put_error(15, mode);
- r.r[2] = r.r[2] & 0xffff;
- }
-
- if (part) // low or highbyte
- {
- if (part == 1)
- r.r[2] = r.r[2] & 0xff;
- else
- r.r[2] = r.r[2] / 0x100;
- }
- return r.r[2];
- }
-
- //-------------------------------------------------------------
- int good_name(char *name)
- // tests if an name is good enough to become a symbol
- {
- int pos, length, ret = 1;
- length = strlen(name);
- for (pos = 0; pos < length; pos++)
- if ( !isalnum(*(name + pos)) && *(name+pos) != '_' ) ret = 0;
- if (isdigit(*name)) ret = 0;
- *(name + 39) = 0;
- if (ret == 0)
- put_error(10, 1);
- return ret;
- }
-
-
- //-------------------------------------------------------------
- void set_symbol_value(char *symbol_name, int value)
- {
- if (good_name(symbol_name))
- {
- if (nr_of_symbols > 998)
- put_error(9, 1);
- else
- {
- if ( symbol_value(symbol_name,0) == FULL )
- {
- memcpy(symbol[nr_of_symbols].name, symbol_name, 40);
-
- symbol[nr_of_symbols++].address = value;
-
- if ( !strcmp(symbol_name,"base") )
- {
- base_defined=1;
- pc = base = value;
- }
- }
- else
- put_error(11, 1); //defined twice error
- }
- }
- }
-
- //-------------------------------------------------------------
- void def_symbol(int loc)
- // analyses a symbol definition
- // else extern
- {
- char *right_side,*left_side;
- int right_val;
-
- left_side = textline + 1;
-
- // .symbol=expression ?
- right_side = strchr(textline,'=');
-
- if (right_side == NULL)
- {
- if (loc)
- put_error(12, 1);
- else
- // a normal label like ".fred"
- set_symbol_value(left_side, pc);
- }
- else
- {
- if (!loc)
- put_error(14, 1);
- else
- {
- *right_side=0; // mark end of left side
- right_side++; // to start of right side
-
- while ( left_side[strlen(left_side)-1] == ' ' ) // remove spaces from the
- left_side[strlen(left_side)-1] = 0; // end of symbol name
-
- // now we'll try to interpret the right side
- right_val=calc(right_side,1);
- set_symbol_value(left_side, right_val);
- }
- }
- }
-
- //-------------------------------------------------------------
- int search_mnemonic(char *mnemonic,int mode)
- // search for an instruction and returns array index
- // or 0xff if not found
- // if mode == 0 no "Illegal mode" error
- {
- int mnemo_int,
- array_index = 0,
- ret = 0xff;
- mnemo_int = ((mnemonic[0] << 16) + (mnemonic[1] << 8) + mnemonic[2])
- & 0xffdfdfdf;
- while ( (array_index < 80) && (ret == 0xff) )
- {
- if (mnemo_int == instruction[array_index].mnemonic)
- ret = array_index;
- else
- array_index++;
- }
- if (ret == 0xff)
- put_error(16, mode);
- return ret;
- }
-
- //-------------------------------------------------------------
- void translate(char *out_pointer, char *line, int mode)
- // translates a single instruction
- // if mode == 0 => no errors
- {
- int length,
- x_outside = 0,
- y_outside = 0,
- y_inside = 0,
- zeropage = 0,
- number,
- instruct_nr;
- signed int
- branch;
-
- *out_pointer = 0;
-
- instruct_nr = search_mnemonic(line, mode);
- memcpy(line, line + 3, strlen(line) - 2);
-
- if (instruct_nr != 0xff)
- {
- // remove spaces from the left side
- branch = strlen(line);
- while (*line == ' ')
- memcpy(line, line + 1, branch--);
-
- length = strlen(line) + 1;
- // no parameter ?
- if (1 == length--) // akku or single
- if (instruction[instruct_nr].code[0] != 0xff)
- {
- *out_pointer = 1;
- *(out_pointer+1) = instruction[instruct_nr].code[0];
- }
- else
- put_error(0, mode); // illegal address mode error
- else
- {
- // analyse parameters
-
- // starts with '#' ?
- if (*line == '#')
- { // direct
- memcpy(line, line+1, length--); // remove '#'
-
- // the rest must be a number
- number = calc(line, mode);
- if (number > 0xff)
- {
- put_error(2, mode); // higher than 0xff error
- number &= 0xff;
- }
-
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[1];
- *(out_pointer+2) = number;
-
- if (*(out_pointer+1) == 0xff)
- put_error(0, mode); // illegal address mode error
-
- length = 0; // done
- }
-
- if (length > 1)
- { // "Z," is mark for zeropage mode
- if ( toupper(*line) == 'Z'
- && *(line + 1) == ',' )
- {
- zeropage = 1;
- memcpy(line, line + 2, length); // remove "Z,"
- length -= 2;
- }
- }
-
- if (instruction[instruct_nr].code[8] != 0xff)
- {
- // branch...
- if (length && !zeropage)
- {
- branch = calc(line, mode);
- branch = branch - pc - 2;
- if (branch > 0x7d || branch < -0x80)
- {
- put_error(3, mode); // out of range error
- branch = 0;
- }
- length = 0; // done
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[8];
- *(out_pointer+2) = branch;
- }
- else
- put_error(0, mode); // illegal address mode error
- }
-
- if (length > 1)
- {
- // end == ",x" ?
- if ( toupper(*(line + length - 1)) == 'X'
- && *(line + length - 2) == ',' )
- {
- x_outside = 1; // something,X
- *(line + (length -= 2)) = 0; // remove ",X"
- }
- }
-
- if (length > 1)
- {
- // end == ",y" ?
- if ( toupper(*(line + length - 1)) == 'Y'
- && *(line + length - 2) == ',' )
- {
- y_outside = 1; // something,Y
- *(line + (length -= 2)) = 0; // remove ",Y"
- }
- }
-
- // line could contain:
- // case 1: "(expression)" for <absolute indirect> or <(indirect),y>
- // case 2: "expression" for <zeropage [,x|,y]> or <absolute [,x|,y]>
- // case 3: "(expression,x)" for <(indirect,x)>
- if (length > 0)
- {
- if (*line == '(')
- {
- if (line[length-1] == ')')
- {
- // remove brackets
- line[--length] = 0;
- memcpy(line, line + 1, length--);
-
- if ( toupper(*(line + length - 1)) == 'X'
- && *(line + length - 2) == ',' )
- {
- // case 3: e.g. ADC ($02,X)
- *(line + (length -= 2)) = 0; // remove ",X"
- number = calc(line, mode);
-
- if (number < 0x100
- && instruction[instruct_nr].code[9] != 0xff)
- {
- length = 0;
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[9];
- *(out_pointer+2) = number;
- }
- }
- else
- {
- // case 1
- number = calc(line, mode);
- if (y_outside && number < 0x100
- && instruction[instruct_nr].code[10] != 0xff)
- {
- // e.g. ADC ($02),Y
- length = 0;
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[10];
- *(out_pointer+2) = number;
- }
- else
- if (!y_outside && !zeropage
- && instruction[instruct_nr].code[11] != 0xff)
- {
- // e.g. JMP ($1000)
- length = 0;
- *out_pointer = 3;
- *(out_pointer+1) = instruction[instruct_nr].code[11];
- *(out_pointer+2) = number & 0xff;
- *(out_pointer+3) = number >> 8;
- }
- }
-
- if (*out_pointer == 0)
- {
- length = 0;
- put_error(0, mode); // illegal address mode error
- }
- }
- else
- {
- put_error(5, mode); // missing ')' error
- length = 0;
- *out_pointer = 0;
- }
- }
- else
- // case 2...
- {
- number = calc(line, mode);
-
- if (number > 0xffff)
- {
- put_error(4, mode); // overflow error
- number &= 0xffff;
- }
- if (number > 0xff && zeropage)
- {
- put_error(2, mode);
- number &= 0xff;
- }
-
- // all possibilities of case 2 are tested...
- if (zeropage && !y_outside && !x_outside
- && instruction[instruct_nr].code[2] != 0xff)
- {
- // e.g. "LDA $02"
- length = 0; // done
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[2];
- *(out_pointer+2) = number;
- }
- else
- if (zeropage && !y_outside && x_outside
- && instruction[instruct_nr].code[3] != 0xff)
- {
- // e.g. "LDA $02,X"
- length = 0; // done
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[3];
- *(out_pointer+2) = number;
- }
- else
- if (zeropage && y_outside && !x_outside
- && instruction[instruct_nr].code[4] != 0xff)
- {
- // e.g. "LDX $02,Y"
- length = 0;
- *out_pointer = 2;
- *(out_pointer+1) = instruction[instruct_nr].code[4];
- *(out_pointer+2) = number;
- };
-
- // if length > 0 => no zeropage mode is possible
- if (length > 0)
- {
- if (!y_outside && !x_outside
- && instruction[instruct_nr].code[5] != 0xff)
- {
- // e.g. "LDA $1000"
- length = 0;
- *out_pointer = 3;
- *(out_pointer+1) = instruction[instruct_nr].code[5];
- *(out_pointer+2) = number & 0xff;
- *(out_pointer+3) = number >> 8;
- }
- else
- if (!y_outside && x_outside
- && instruction[instruct_nr].code[6] != 0xff)
- {
- // e.g. "LDA $1000,X"
- length = 0;
- *out_pointer = 3;
- *(out_pointer+1) = instruction[instruct_nr].code[6];
- *(out_pointer+2) = number & 0xff;
- *(out_pointer+3) = number >> 8;
- }
- else
- if (y_outside && !x_outside
- && instruction[instruct_nr].code[7] != 0xff)
- {
- // e.g. "LDA $1000,Y"
- length = 0;
- *out_pointer = 3;
- *(out_pointer+1) = instruction[instruct_nr].code[7];
- *(out_pointer+2) = number & 0xff;
- *(out_pointer+3) = number >> 8;
- }
- }
-
- // Something left?
- if (length > 0)
- {
- *out_pointer = 0;
- put_error(0, mode); // illegal address mode error
- }
- }
- }
- }
- }
- } // brackets rule :-)
-
- //-------------------------------------------------------------
- void assemble(FILE *in_file, char* in_filename)
- {
- int found,
- type,
- len,
- count;
- char mem_dump[4]; // [0] contains length of translated instruction
- // [1]..[3] instruction
- nr_of_symbols = 0;
- pc = 0;
- base_defined = 0;
- base = 0;
- last_error_file = -1;
-
- /****************************************/
- /* pass 1 */
- /****************************************/
- fprintf(error_file, "\nSource file: %s\n\n", in_filename);
-
- error_counter = 0;
- status("Assembling: Pass 1");
-
- line_nr = 0;
- while (getline(in_file))
- {
- pc &= 0xffff;
-
- found = 0;
- if (textline[0] == '.')
- {
- def_symbol(0); // intern symbols
- found = 1;
- }
- if (textline[0] == '!')
- {
- def_symbol(1); // extern symbols
- found = 1;
- }
-
- if (*textline == '/') // assembler commands
- {
- if (!strcmp(textline+1,"align"))
- {
- if (pc & 0xff)
- pc = (pc & FULL-0xff) + 0x100; // calculate aligned address
- found = 1;
- }
- else
- {
- if (textline[1] == 'b' && textline[2] == 'y'
- && textline[3] == 32)
- {
- found = strtok(textline+3, ",");
- do
- {
- pc++;
- found = strtok(NULL, ",");
- }
- while (found != NULL);
- found = 1;
- }
- else
- {
- if ( (textline[1] == 's' && textline[2] == 'c')
- || (textline[1] == 't' && textline[2] == 'x') )
- { // found "/tx" or "/sc"
- len = strlen(textline);
- if (textline[len - 1] == '\"')
- {
- for (count = 3; count < len; count++)
- if (textline[count] == '\"')
- {
- found = count;
- count = 256;
- }
- if (len != found + 1)
- pc += (len - found - 2);
- }
- found = 1;
- }
- }
- }
- }
-
- // anything else must be an mnemonic
- if (!found)
- {
- translate(mem_dump, textline, 0);
- pc += mem_dump[0];
- }
- }
-
- /****************************************/
- /* pass 2 */
- /****************************************/
- fseek (in_file, 0, SEEK_SET); // back to start
-
- status("Assembling: Pass 2");
-
- if (base_defined)
- {
- if (transfer_enabled)
- {
- fputc(0, out_file);
- fputc(255, out_file);
- }
-
- fputc(base & 0xff, out_file);
- fputc(base >> 8, out_file);
-
- if (transfer_enabled)
- {
- fputc(pc & 0xff, out_file);
- fputc(pc >> 8, out_file);
- fputc(base & 0xff, out_file);
- fputc(base >> 8, out_file);
- fputc(pc & 0xff, out_file);
- fputc(pc >> 8, out_file);
- }
-
- line_nr = 0;
- pc = base;
- while (getline(in_file))
- {
- found = 0;
- if (textline[0] == '.' || textline[0] == '!')
- found = 1;
-
- if (*textline == '/') // assembler commands
- {
- if (!strcmp(textline+1,"align"))
- {
- while (pc & 0xff)
- {
- fputc(0xEA, out_file);
- pc++;
- }
- found = 1;
- }
- else
- { // "/by ..." found
- if (textline[1] == 'b' && textline[2] == 'y'
- && textline[3] == 32)
- {
- found = strtok(textline+3, ",");
- do
- {
- count = calc( (char *)found, 1);
- if (count < 0x100)
- {
- pc++;
- fputc(count, out_file);
- }
- else
- put_error(2, 1);
- found = strtok(NULL, ",");
- }
- while (found != NULL);
- found = 1;
- }
- else
- { // "/by" without parameters
- if (textline[1] == 'b' && textline[2] == 'y')
- {
- put_error(18, 1);
- found = 1;
- }
- else
- { // "/sc" or "/tx" found
- if ( (textline[1] == 's' && textline[2] == 'c')
- || (textline[1] == 't' && textline[2] == 'x') )
- {
- len = strlen(textline);
- if (textline[len - 1] == '\"')
- {
- for (count = 3; count < len; count++)
- if (textline[count] == '\"')
- {
- found = count;
- count = 256;
- }
- if (len != found + 1)
- pc += (strlen(textline) - found - 2);
- else
- put_error (19, 1); // case: »/tx "«
-
- if (textline[1] == 't')
- type = 0; // "/tx" => type = 1;
- else
- type = 1;
- // send text
- len -= 1;
- for (count = found + 1; count < len; count++)
- fputc ( chr [textline[count]] [type], out_file);
- }
- else
- put_error(19, 1);
- found = 1;
- }
- }
- }
- }
- }
-
- if (!found)
- {
- // it's a mnemonic line :-)
- translate(mem_dump, textline, 1);
- pc += mem_dump[0];
- for (count = 0; count < mem_dump[0]; count++)
- fputc(mem_dump[count+1], out_file);
- if (pc > 0xffff)
- {
- put_error(17, 1); // pc overflow error
- pc &= 0xffff;
- }
- }
- }
- fprintf(error_file, "\nEntries: %d\n", error_counter);
- fprintf(error_file, "\n%d lines assembled.\n", line_nr);
- }
- else
- put_error(13, 1);
- status("Assembling: Pass 2");
- }
-
- //-------------------------------------------------------------
- void transfer_file(void)
- {
- int count, obj_length;
- char *buffer;
- os_filestr p;
-
- p.action = 17;
- p.objname = "<6502-XAss$Dir>.Scrap.Object";
- os_file(&p);
-
- if (p.action == 1 && p.startaddr > 0)
- {
- obj_length = p.startaddr;
- buffer = (char *) malloc(obj_length);
- if (buffer)
- {
- p.action = 16;
- p.loadaddr = buffer;
- p.execaddr = 0;
- os_file(&p);
-
- os_vdu(2);
- for (count = 0; count < obj_length; count++)
- {
- os_vdu(1);
- os_vdu( *(buffer + count) );
- }
- os_vdu(3);
- }
- else
- status("Out of memory");
- free(buffer);
- }
- else
- status("Transfer file error");
- }
-
-