📄 picasm.c
字号:
/* * picasm.c * * Freely distributable for non-commercial use (basically, * don't sell this program without my permission. You can * use it for developing commercial PIC applications, but * of course I am not responsible for any damages caused by * this assembler generating bad code or anything like that) * * Copyright 1995-1998 by Timo Rossi * See the file picasm.doc for more information * * email: trossi@iki.fi * www: http://www.iki.fi/trossi/pic/ * */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <ctype.h>#include <time.h>#include "picasm.h"int warnlevel;static int total_line_count;static int errors, warnings; /* error & warning counts */unsigned short list_flags;/* imported from devices.c */extern struct pic_type pic_types[];static FILE *list_fp;static int listing_on;static int list_loc;static pic_instr_t *list_ptr;static long list_val, list_len;int cond_nest_count;int unique_id_count;/* the current source file/macro */struct inc_file *current_file;/* Line buffer & pointer to it */char *line_buf_ptr;char line_buffer[256];static struct patch *global_patch_list;struct patch **local_patch_list_ptr;struct pic_type *pic_type;int prog_mem_size;static int reg_file_limit;short code_generated;static pic_instr_t prog_mem[PROGMEM_MAX];static pic_instr_t data_eeprom[EEPROM_MAX];static pic_instr_t pic_id[4];pic_instr_t config_fuses;org_mode_t O_Mode;int prog_location; /* current address for program code */int reg_location; /* current address for register file */int edata_location; /* current address for data EEPROM */int org_val;int local_level;/* Error handling *//* * Show line number/line with error message */static voiderr_line_ref(void){ struct inc_file *inc; if(current_file != NULL) { inc = current_file; if(inc->type != INC_FILE) { fprintf(stderr, "(Macro %s line %d) ", inc->v.m.sym->name, inc->linenum); while(inc != NULL && inc->type != INC_FILE) inc = inc->next; } fprintf(stderr, "File '%s' at line %d:\n", inc->v.f.fname, inc->linenum); fputs(line_buffer, stderr); if(line_buffer[0] != '\0' && line_buffer[strlen(line_buffer)-1] != '\n') fputc('\n', stderr); }}/* * Warning message */voidwarning(char *fmt, ...){ va_list args; err_line_ref(); fputs("Warning: ", stderr); va_start(args, fmt); vfprintf(stderr, fmt, args); if(list_fp != NULL) { fputs("Warning: ", list_fp); vfprintf(list_fp, fmt, args); fputc('\n', list_fp); } fputc('\n', stderr); va_end(args); warnings++;}/* * skip the end of line, in case of an error */static voiderror_lineskip(void){ write_listing_line(0); skip_eol(); get_token();}/* * Error message * call error_lineskip() if lskip is non-zero * */voiderror(int lskip, char *fmt, ...){ va_list args; err_line_ref(); fputs("Error: ", stderr); va_start(args, fmt); vfprintf(stderr, fmt, args); if(list_fp != NULL) { fputs("Error: ", list_fp); vfprintf(list_fp, fmt, args); fputc('\n', list_fp); } fputc('\n', stderr); va_end(args); if(++errors >= MAX_ERRORS) fatal_error("too many errors, aborting"); if(lskip) error_lineskip();}/* * Fatal error message */voidfatal_error(char *fmt, ...){ va_list args; err_line_ref(); fputs("Fatal error: ", stderr); va_start(args, fmt); vfprintf(stderr, fmt, args); fputc('\n', stderr); va_end(args); exit(EXIT_FAILURE);}/* memory allocation */void *mem_alloc(int size){ void *p; if((p = malloc(size)) == NULL) fatal_error("Out of memory"); return p;}/* * initialize the assembler */static voidinit_assembler(void){ pic_instr_t *cp; int n; init_symtab(); /* initialize symbol table */ /* initialize program memory to invalid values */ for(n = PROGMEM_MAX, cp = prog_mem; n-- > 0; *cp++ = INVALID_INSTR); /* initialize data memory to invalid values */ for(n = EEPROM_MAX, cp = data_eeprom; n-- > 0; *cp++ = INVALID_DATA); /* initialize jump patch list */ global_patch_list = NULL; prog_location = -1; reg_location = -1; edata_location = -1; org_val = -1; current_file = NULL; config_fuses = INVALID_CONFIG; pic_id[0] = INVALID_ID; errors = warnings = 0; list_flags = 0; list_len = 0; listing_on = 1; cond_nest_count = 0; unique_id_count = 1; total_line_count = 0; code_generated = 0; local_level = 0; ifskip_mode = 0;}/* * generate program code */void gen_code(int val){ if(pic_type == NULL) fatal_error("PIC device type not set"); if(O_Mode == O_NONE) { O_Mode = O_PROGRAM; if(org_val < 0) { error(0, "ORG value not set"); prog_location = 0; return; } prog_location = org_val; } else if(O_Mode != O_PROGRAM) { error(0, "ORG mode conflict"); O_Mode = O_PROGRAM; return; } if(prog_location >= prog_mem_size) fatal_error("Code address out of range"); if(prog_mem[prog_location] != INVALID_INSTR) warning("Overlapping code at 0x%x\n", prog_location); if((list_flags & LIST_PROG) == 0) { list_loc = prog_location; list_flags = LIST_LOC | LIST_PROG; } list_len++; prog_mem[prog_location++] = val; code_generated = 1;}/* * Generate data for data EEPROM */voidgen_edata(int val){ if(O_Mode == O_NONE) { O_Mode = O_EDATA; if(org_val < 0) { error(0, "ORG value not set"); edata_location = 0; return; } edata_location = org_val; } else if(O_Mode != O_EDATA) { error(0, "ORG mode conflict"); O_Mode = O_EDATA; return; } if(edata_location >= pic_type->eeprom_size) fatal_error("Data EEPROM address out of range"); if(data_eeprom[edata_location] < 0x100) warning("Overlapping EEPROM data at 0x%x\n", edata_location); if((list_flags & LIST_LOC) == 0) { list_loc = edata_location; list_flags = LIST_LOC | LIST_EDATA; } list_len++; data_eeprom[edata_location++] = val; code_generated = 1;}/* * Write one line of Intel-hex file */static voidwrite_hex_record(FILE *fp, int reclen, /* length (in words) */ int loc, /* address */ pic_instr_t *data, /* pointer to word data */ int format) /* IHX8M or IHX16 */{ int check = 0; switch(format) { case IHX8M: fprintf(fp, ":%02X%04X00", 2*reclen, 2*loc); check += ((2*loc) & 0xff) + (((2*loc) >> 8) & 0xff) + 2*reclen; break; case IHX16: fprintf(fp, ":%02X%04X00", reclen, loc); check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen; break; } while(reclen--) { switch(format) { case IHX8M: fprintf(fp, "%02X%02X", (int)(*data & 0xff), (int)((*data >> 8) & 0xff)); break; case IHX16: fprintf(fp, "%02X%02X", (int)((*data >> 8) & 0xff), (int)(*data & 0xff)); break; } check += (*data & 0xff) + ((*data >> 8) & 0xff); data++; } /* write checksum, assumes 2-complement */ fprintf(fp, "%02X" HEX_EOL, (-check) & 0xff);}/* * Write output file in ihx8m or ihx16-format * */static voidwrite_output(char *fname, int format){ int loc, reclen; FILE *fp; if((fp = fopen(fname, "w")) == NULL) fatal_error("Can't create file '%s'", fname); /* program */ for(loc = 0;;) { while(loc < prog_mem_size && prog_mem[loc] == INVALID_INSTR) loc++; if(loc >= prog_mem_size) break; reclen = 0; while(reclen < 8 && loc < prog_mem_size && prog_mem[loc] != INVALID_INSTR) { loc++; reclen++; } write_hex_record(fp, reclen, loc-reclen, &prog_mem[loc-reclen], format); } /* PIC ID */ if(pic_id[0] != INVALID_ID) { switch(pic_type->instr_set) { case PIC12BIT: write_hex_record(fp, 4, prog_mem_size, pic_id, format); break; case PIC14BIT: write_hex_record(fp, 4, 0x2000, pic_id, format); break; } } /* config fuses */ if(config_fuses != INVALID_CONFIG) { write_hex_record(fp, 1, pic_type->fuse_addr, &config_fuses, format); } if(pic_type->eeprom_size > 0) { /* data EEPROM */ for(loc = 0;;) { while(loc < pic_type->eeprom_size && data_eeprom[loc] >= 0x100) loc++; if(loc >= pic_type->eeprom_size) break; reclen = 0; while(reclen < 8 && loc < pic_type->eeprom_size && data_eeprom[loc] < 0x100) { loc++; reclen++; } write_hex_record(fp, reclen, 0x2100+loc-reclen, &data_eeprom[loc-reclen], format); } } fputs(":00000001FF" HEX_EOL , fp); /* end record */ fclose(fp);}/* * Write one line to listing file (if listing is enabled) */voidwrite_listing_line(int cond_flag){ int i; if(list_fp != NULL && listing_on) { fprintf(list_fp, "%04d%c%c", ++total_line_count, (current_file != NULL && current_file->type == INC_MACRO ? '+' : ' '), (cond_flag ? '!' : ' ')); if(line_buffer[0] != '\0') { if(list_flags & LIST_VAL) { fprintf(list_fp, "%08lX ", list_val); } else { if(list_flags & LIST_LOC) fprintf(list_fp, "%04X", list_loc); else fputs(" ", list_fp); if((list_flags & (LIST_PROG|LIST_EDATA|LIST_PTR)) != 0) { fputc(((list_flags & LIST_FORWARD) ? '?' : ' '), list_fp); if(list_flags & LIST_PROG) { fprintf(list_fp, "%04X ", prog_mem[list_loc]); } else if(list_flags & LIST_EDATA) { fprintf(list_fp, "%04X ", data_eeprom[list_loc]); } else if(list_flags & LIST_PTR) { fprintf(list_fp, "%04X ", *list_ptr++); } } else { fputs(" ", list_fp); } } fputs(line_buffer, list_fp); if(line_buffer[0] != '\0' && line_buffer[strlen(line_buffer)-1] != '\n') fputc('\n', list_fp); list_len--; for(i = 0; i < list_len; i++) { list_loc++; fprintf(list_fp, "%04d%c ", total_line_count, (current_file != NULL && current_file->type == INC_MACRO ? '+' : ' ')); if(list_flags & LIST_LOC) fprintf(list_fp, "%04X", list_loc); else fputs(" ", list_fp); if(list_flags & LIST_PROG) { fprintf(list_fp, " %04X\n", prog_mem[list_loc]); } else if(list_flags & LIST_EDATA) { fprintf(list_fp, " %04X\n", data_eeprom[list_loc]); } else if(list_flags & LIST_PTR) { fprintf(list_fp, " %04X\n", *list_ptr++); } } } if(listing_on < 0) listing_on = 0; } list_flags = 0; list_len = 0;}/* * parse and handle OPT-directive * (this is special as it must be done as macro definition time * if inside a macro) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -