diff --git a/Makefile b/Makefile index 357c875..ee0749e 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,6 @@ TARGET = TARGETEXTENSION = -CC = gcc CCOUT = -o COPTS = -c -O2 diff --git a/Makefile.Haiku b/Makefile.Haiku new file mode 100644 index 0000000..c15ccef --- /dev/null +++ b/Makefile.Haiku @@ -0,0 +1,16 @@ +# Unix + +TARGET = +TARGETEXTENSION = + +CC = gcc +CCOUT = -o +COPTS = -c -O2 + +LD = $(CC) +LDOUT = $(CCOUT) +LDFLAGS = + +RM = rm -f + +include make.rules diff --git a/Makefile.MiNT b/Makefile.MiNT new file mode 100644 index 0000000..4ec3aa8 --- /dev/null +++ b/Makefile.MiNT @@ -0,0 +1,16 @@ +# Atari TOS/MiNT + +TARGET = _MiNT +TARGETEXTENSION = + +CC = vc +mint +CCOUT = -o +COPTS = -c -c99 -cpu=68020 -O1 + +LD = $(CC) +LDOUT = $(CCOUT) +LDFLAGS = -lm + +RM = rm -f + +include make.rules diff --git a/Makefile.TOS b/Makefile.TOS new file mode 100644 index 0000000..73a102a --- /dev/null +++ b/Makefile.TOS @@ -0,0 +1,16 @@ +# Atari TOS + +TARGET = _TOS +TARGETEXTENSION = .ttp + +CC = vc +tos +CCOUT = -o +COPTS = -c -c99 -O1 -DATARI + +LD = $(CC) +LDOUT = $(CCOUT) +LDFLAGS = -lm + +RM = rm -f + +include make.rules diff --git a/Makefile.Win32FromLinux b/Makefile.Win32FromLinux new file mode 100644 index 0000000..444b6ce --- /dev/null +++ b/Makefile.Win32FromLinux @@ -0,0 +1,20 @@ +# Windows compiled on a Linux machine with mingw + +TARGET = _win32 +TARGETEXTENSION = .exe + + + +CC = /usr/bin/i586-mingw32msvc-gcc +CCOUT = -o +COPTS = -c -O2 + +LD = $(CC) +LDOUT = $(CCOUT) +LDFLAGS = -lm + +RM = rm -f + + + +include make.rules diff --git a/atom.c b/atom.c index 8e28624..d159417 100644 --- a/atom.c +++ b/atom.c @@ -1,10 +1,9 @@ /* atom.c - atomic objects from source */ -/* (c) in 2010-2011 by Volker Barthelmann and Frank Wille */ +/* (c) in 2010-2014 by Volker Barthelmann and Frank Wille */ #include "vasm.h" -/* test implementation, not good */ /* searches mnemonic list and tries to parse (via the cpu module) the operands according to the mnemonic requirements; returns an instruction or 0 */ @@ -12,85 +11,117 @@ instruction *new_inst(char *inst,int len,int op_cnt,char **op,int *op_len) { #if MAX_OPERANDS!=0 operand ops[MAX_OPERANDS]; - int omitted[MAX_OPERANDS]={0}; + int j,k,mnemo_opcnt,omitted,skipped; #endif - int i,j,inst_found=0,rc; + int i,inst_found=0; hashdata data; - instruction *new=mymalloc(sizeof(*new)); + instruction *new; -#ifdef HAVE_INSTRUCTION_EXTENSION + new = mymalloc(sizeof(*new)); +#if HAVE_INSTRUCTION_EXTENSION init_instruction_ext(&new->ext); #endif -#ifdef NEED_CLEARED_OPERANDS +#if MAX_OPERANDS!=0 && NEED_CLEARED_OPERANDS!=0 /* reset operands to allow the cpu-backend to parse them only once */ memset(ops,0,sizeof(ops)); #endif if (find_namelen_nc(mnemohash,inst,len,&data)) { - /* instruction name fits - are operands ok? */ i = data.idx; - inst_found = 1; - /* search all mnemonics with the same name */ + /* try all mnemonics with the same name until operands match */ do { - for (j=0; j= op_cnt) /* missing mandatory operands */ break; + + rc = parse_operand(op[k],op_len[k],&ops[j], + mnemonics[i].operand_type[j]); + + if (rc == PO_CORRUPT) { + myfree(new); + restore_symbols(); + return 0; + } + if (rc == PO_NOMATCH) + break; + + /* MATCH, move to next parsed operand */ + k++; + if (rc == PO_SKIP) { /* but skip next operand type from table */ + j++; + skipped++; + } } } -#if CPU_CHECKS_OPCNT - if (j 0) #endif + if (jcode = i; - for (j=0; jop[j] = 0; - } - else { - new->op[j] = mymalloc(sizeof(operand)); - *new->op[j] = ops[j]; - } + + /* Matched! Copy operands. */ + mnemo_opcnt -= skipped; + for (j=0; jop[j] = mymalloc(sizeof(operand)); + *new->op[j] = ops[j]; } for(; jop[j] = 0; + +#endif /* MAX_OPERANDS!=0 */ + + new->code = i; return new; - i++; } - while(ispace_exp = space; sb->size = size; if (!(sb->fill_exp = fill)) - memset(sb->fill,0,SB_MAXSIZE); + memset(sb->fill,0,MAXPADBYTES); sb->relocs = 0; + sb->maxalignbytes = 0; return sb; } -static taddr space_size(sblock *sb,section *sec,taddr pc) +static size_t space_size(sblock *sb,section *sec,taddr pc) { - taddr space=0; + utaddr space=0; if (eval_expr(sb->space_exp,&space,sec,pc) || !final_pass) sb->space = space; @@ -133,34 +165,34 @@ static taddr space_size(sblock *sb,section *sec,taddr pc) if (sb->size <= sizeof(taddr)) { /* space is filled with an expression which may also need relocations */ symbol *base=NULL; - taddr fill,i; + taddr fill; + utaddr i; if (!eval_expr(sb->fill_exp,&fill,sec,pc)) { - base = find_base(sb->fill_exp,sec,pc); - if (!base) + if (find_base(sb->fill_exp,&base,sec,pc)==BASE_ILLEGAL) general_error(38); /* illegal relocation */ } copy_cpu_taddr(sb->fill,fill,sb->size); if (base && !sb->relocs) { /* generate relocations */ for (i=0; irelocs,base,fill,REL_ABS, - sb->size<<3,(i*sb->size)<<3); + add_nreloc(&sb->relocs,base,fill,REL_ABS, + sb->size<<3,(sb->size*i)<<3); } } else general_error(30); /* expression must be constant */ } - return space * (taddr)sb->size; + return sb->size * space; } -static taddr rorg_size(expr *rorg,section *sec,taddr pc) +static size_t roffs_size(expr *offsexp,section *sec,taddr pc) { taddr offs; - eval_expr(rorg,&offs,sec,pc); + eval_expr(offsexp,&offs,sec,pc); offs = sec->org + offs - pc; return offs>0 ? offs : 0; } @@ -170,8 +202,6 @@ static taddr rorg_size(expr *rorg,section *sec,taddr pc) section is used */ void add_atom(section *sec,atom *a) { - taddr size; - if (!sec) { sec = default_section(); if (!sec) { @@ -180,8 +210,9 @@ void add_atom(section *sec,atom *a) } } + a->changes = 0; a->src = cur_src; - a->line = cur_src->line; + a->line = cur_src!=NULL ? cur_src->line : 0; if (sec->last) { atom *pa = sec->last; @@ -197,16 +228,13 @@ void add_atom(section *sec,atom *a) a->next = 0; sec->last = a; - sec->pc = (sec->pc + a->align - 1) / a->align * a->align; - size = atom_size(a,sec,sec->pc); -#ifdef CHECK_ATOMSIZE - a->lastsize = size; -#endif - sec->pc += size; + sec->pc = pcalign(a,sec->pc); + a->lastsize = atom_size(a,sec,sec->pc); + sec->pc += a->lastsize; if (a->align > sec->align) sec->align = a->align; - if (produce_listing) { + if (listena) { a->list = last_listing; if (last_listing) { if (!last_listing->atom) @@ -218,7 +246,7 @@ void add_atom(section *sec,atom *a) } -taddr atom_size(atom *p,section *sec,taddr pc) +size_t atom_size(atom *p,section *sec,taddr pc) { switch(p->type) { case LABEL: @@ -226,17 +254,21 @@ taddr atom_size(atom *p,section *sec,taddr pc) case OPTS: case PRINTTEXT: case PRINTEXPR: + case RORG: + case RORGEND: + case ASSERT: return 0; case DATA: return p->content.db->size; case INSTRUCTION: - return instruction_size(p->content.inst,sec,pc); + return p->content.inst->code>=0? + instruction_size(p->content.inst,sec,pc):0; case SPACE: return space_size(p->content.sb,sec,pc); case DATADEF: return (p->content.defb->bitsize+7)/8; - case RORG: - return rorg_size(p->content.roffs,sec,pc); + case ROFFS: + return roffs_size(p->content.roffs,sec,pc); default: ierror(0); break; @@ -249,7 +281,7 @@ static void print_instruction(FILE *f,instruction *p) { int i; - printf("inst %d(%s) ",p->code,mnemonics[p->code].name); + printf("inst %d(%s) ",p->code,p->code>=0?mnemonics[p->code].name:"deleted"); #if MAX_OPERANDS!=0 for (i=0; iop[i]); @@ -292,7 +324,7 @@ void print_atom(FILE *f,atom *p) case LINE: fprintf(f,"line: %d of %s",p->content.srcline,getdebugname()); break; -#ifdef HAVE_CPU_OPTS +#if HAVE_CPU_OPTS case OPTS: print_cpu_opts(f,p->content.opts); break; @@ -302,75 +334,158 @@ void print_atom(FILE *f,atom *p) break; case PRINTEXPR: fprintf(f,"expr: "); - print_expr(f,p->content.pexpr); + print_expr(f,p->content.pexpr->print_exp); break; - case RORG: - fprintf(f,"rorg: offset "); + case ROFFS: + fprintf(f,"roffs: offset "); print_expr(f,p->content.roffs); break; + case RORG: + fprintf(f,"rorg: relocate to 0x%llx",ULLTADDR(*p->content.rorg)); + break; + case RORGEND: + fprintf(f,"rorg end"); + break; + case ASSERT: + fprintf(f,"assert: %s (message: %s)\n",p->content.assert->expstr, + p->content.assert->msgstr?p->content.assert->msgstr:emptystr); + break; default: ierror(0); } } -atom *new_inst_atom(instruction *p) +/* prints and formats an expression from a PRINTEXPR atom */ +void atom_printexpr(printexpr *pexp,section *sec,taddr pc) { - atom *new = mymalloc(sizeof(*new)); + taddr t; + long long v; + int i; + + eval_expr(pexp->print_exp,&t,sec,pc); + if (pexp->type==PEXP_SDEC && (t&(1LL<<(pexp->size-1)))!=0) { + /* signed decimal */ + v = -1; + v &= ~(long long)MAKEMASK(pexp->size); + } + else + v = 0; + v |= t & MAKEMASK(pexp->size); + + switch (pexp->type) { + case PEXP_HEX: + printf("%llX",(unsigned long long)v); + break; + case PEXP_SDEC: + printf("%lld",v); + break; + case PEXP_UDEC: + printf("%llu",(unsigned long long)v); + break; + case PEXP_BIN: + for (i=pexp->size-1; i>=0; i--) + putchar((v & (1LL<size+7)>>3)-1; i>=0; i--) { + unsigned char c = (v>>(i*8))&0xff; + putchar(isprint(c) ? c : '.'); + } + break; + default: + ierror(0); + break; + } +} + + +atom *clone_atom(atom *a) +{ + atom *new = mymalloc(sizeof(atom)); + void *p; + + memcpy(new,a,sizeof(atom)); + + switch (a->type) { + /* INSTRUCTION and DATADEF have to be cloned as well, because they will + be deallocated and transformed into DATA during assemble() */ + case INSTRUCTION: + p = mymalloc(sizeof(instruction)); + memcpy(p,a->content.inst,sizeof(instruction)); + new->content.inst = p; + break; + case DATADEF: + p = mymalloc(sizeof(defblock)); + memcpy(p,a->content.defb,sizeof(defblock)); + new->content.defb = p; + break; + default: + break; + } new->next = 0; - new->type = INSTRUCTION; - new->align = INST_ALIGN; - new->content.inst = p; + new->src = NULL; + new->line = 0; + new->list = NULL; return new; } -atom *new_data_atom(dblock *p,int align) +static atom *new_atom(int type,taddr align) { atom *new = mymalloc(sizeof(*new)); - new->next = 0; - new->type = DATA; + new->next = NULL; + new->type = type; new->align = align; - new->content.db=p; + return new; +} + + +atom *new_inst_atom(instruction *p) +{ + atom *new = new_atom(INSTRUCTION,INST_ALIGN); + + new->content.inst = p; + return new; +} + + +atom *new_data_atom(dblock *p,taddr align) +{ + atom *new = new_atom(DATA,align); + + new->content.db = p; return new; } atom *new_label_atom(symbol *p) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(LABEL,1); - new->next = 0; - new->type = LABEL; - new->align = 1; new->content.label = p; return new; } -atom *new_space_atom(expr *space,int size,expr *fill) +atom *new_space_atom(expr *space,size_t size,expr *fill) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(SPACE,1); int i; if (size<1) ierror(0); /* usually an error in syntax-module */ - new->next = 0; - new->type = SPACE; - new->align = 1; new->content.sb = new_sblock(space,size,fill); return new; } -atom *new_datadef_atom(taddr bitsize,operand *op) +atom *new_datadef_atom(size_t bitsize,operand *op) { - atom *new = mymalloc(sizeof(*new)); - new->next = 0; - new->type = DATADEF; - new->align = DATA_ALIGN(bitsize); + atom *new = new_atom(DATADEF,DATA_ALIGN(bitsize)); + new->content.defb = mymalloc(sizeof(*new->content.defb)); new->content.defb->bitsize = bitsize; new->content.defb->op = op; @@ -380,11 +495,8 @@ atom *new_datadef_atom(taddr bitsize,operand *op) atom *new_srcline_atom(int line) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(LINE,1); - new->next = 0; - new->type = LINE; - new->align = 1; new->content.srcline = line; return new; } @@ -392,11 +504,8 @@ atom *new_srcline_atom(int line) atom *new_opts_atom(void *o) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(OPTS,1); - new->next = 0; - new->type = OPTS; - new->align = 1; new->content.opts = o; return new; } @@ -404,35 +513,61 @@ atom *new_opts_atom(void *o) atom *new_text_atom(char *txt) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(PRINTTEXT,1); - new->next = 0; - new->type = PRINTTEXT; - new->align = 1; - new->content.ptext = txt ? txt : ""; + new->content.ptext = txt ? txt : "\n"; return new; } -atom *new_expr_atom(expr *x) +atom *new_expr_atom(expr *exp,int type,int size) { - atom *new = mymalloc(sizeof(*new)); - - new->next = 0; - new->type = PRINTEXPR; - new->align = 1; - new->content.pexpr = x; + atom *new = new_atom(PRINTEXPR,1); + + new->content.pexpr = mymalloc(sizeof(*new->content.pexpr)); + if (exp==NULL || typePEXP_ASC || size<1 + || size>sizeof(long long)*8) + ierror(0); + new->content.pexpr->print_exp = exp; + new->content.pexpr->type = type; + new->content.pexpr->size = size; return new; } -atom *new_rorg_atom(expr *offs) +atom *new_roffs_atom(expr *offs) { - atom *new = mymalloc(sizeof(*new)); + atom *new = new_atom(ROFFS,1); - new->next = 0; - new->type = RORG; - new->align = 1; new->content.roffs = offs; return new; } + + +atom *new_rorg_atom(taddr raddr) +{ + atom *new = new_atom(RORG,1); + taddr *newrorg = mymalloc(sizeof(taddr)); + + *newrorg = raddr; + new->content.rorg = newrorg; + return new; +} + + +atom *new_rorgend_atom(void) +{ + return new_atom(RORGEND,1); +} + + +atom *new_assert_atom(expr *aexp,char *exp,char *msg) +{ + atom *new = new_atom(ASSERT,1); + + new->content.assert = mymalloc(sizeof(*new->content.assert)); + new->content.assert->assert_exp = aexp; + new->content.assert->expstr = exp; + new->content.assert->msgstr = msg; + return new; +} diff --git a/atom.h b/atom.h index 9ac32d6..f558c30 100644 --- a/atom.h +++ b/atom.h @@ -1,5 +1,5 @@ /* atom.h - atomic objects from source */ -/* (c) in 2010 by Volker Barthelmann and Frank Wille */ +/* (c) in 2010-2014 by Volker Barthelmann and Frank Wille */ #ifndef ATOM_H #define ATOM_H @@ -14,7 +14,10 @@ #define OPTS 7 #define PRINTTEXT 8 #define PRINTEXPR 9 -#define RORG 10 +#define ROFFS 10 +#define RORG 11 +#define RORGEND 12 +#define ASSERT 13 /* a machine instruction */ typedef struct instruction { @@ -25,43 +28,59 @@ typedef struct instruction { #if MAX_OPERANDS!=0 operand *op[MAX_OPERANDS]; #endif -#ifdef HAVE_INSTRUCTION_EXTENSION +#if HAVE_INSTRUCTION_EXTENSION instruction_ext ext; #endif } instruction; typedef struct defblock { - taddr bitsize; + size_t bitsize; operand *op; } defblock; struct dblock { - taddr size; + size_t size; char *data; rlist *relocs; }; -#define SB_MAXSIZE 8 struct sblock { - taddr space; + size_t space; expr *space_exp; /* copied to space, when evaluated as constant */ - int size; - unsigned char fill[SB_MAXSIZE]; + size_t size; + uint8_t fill[MAXPADBYTES]; expr *fill_exp; /* copied to fill, when evaluated - may be NULL */ rlist *relocs; + taddr maxalignbytes; }; +typedef struct printexpr { + expr *print_exp; + short type; /* hex, signed, unsigned */ + short size; /* precision in bits */ +} printexpr; +#define PEXP_HEX 0 +#define PEXP_SDEC 1 +#define PEXP_UDEC 2 +#define PEXP_BIN 3 +#define PEXP_ASC 4 + +typedef struct assertion { + expr *assert_exp; + char *expstr; + char *msgstr; +} assertion; + /* an atomic element of data */ typedef struct atom { struct atom *next; int type; - int align; + taddr align; + size_t lastsize; + unsigned changes; source *src; int line; listing *list; -#ifdef CHECK_ATOMSIZE - taddr lastsize; -#endif union { instruction *inst; dblock *db; @@ -71,29 +90,37 @@ typedef struct atom { void *opts; int srcline; char *ptext; - expr *pexpr; + printexpr *pexpr; expr *roffs; + taddr *rorg; + assertion *assert; } content; } atom; +#define MAXSIZECHANGES 5 /* warning, when atom changed size so many times */ instruction *new_inst(char *inst,int len,int op_cnt,char **op,int *op_len); dblock *new_dblock(); -sblock *new_sblock(expr *,int,expr *); +sblock *new_sblock(expr *,size_t,expr *); void add_atom(section *,atom *); -taddr atom_size(atom *,section *,taddr); +size_t atom_size(atom *,section *,taddr); void print_atom(FILE *,atom *); +void atom_printexpr(printexpr *,section *,taddr); +atom *clone_atom(atom *); atom *new_inst_atom(instruction *); -atom *new_data_atom(dblock *,int); +atom *new_data_atom(dblock *,taddr); atom *new_label_atom(symbol *); -atom *new_space_atom(expr *,int,expr *); -atom *new_datadef_atom(taddr,operand *); +atom *new_space_atom(expr *,size_t,expr *); +atom *new_datadef_atom(size_t,operand *); atom *new_srcline_atom(int); atom *new_opts_atom(void *); atom *new_text_atom(char *); -atom *new_expr_atom(expr *); -atom *new_rorg_atom(expr *); +atom *new_expr_atom(expr *,int,int); +atom *new_roffs_atom(expr *); +atom *new_rorg_atom(taddr); +atom *new_rorgend_atom(void); +atom *new_assert_atom(expr *,char *,char *); #endif diff --git a/cond.c b/cond.c new file mode 100644 index 0000000..8d1a12c --- /dev/null +++ b/cond.c @@ -0,0 +1,85 @@ +/* cond.c - conditional assembly support routines */ +/* (c) in 2015 by Frank Wille */ + +#include "vasm.h" + +int clev; /* conditional level */ + +static char cond[MAXCONDLEV+1]; +static char *condsrc[MAXCONDLEV+1]; +static int condline[MAXCONDLEV+1]; +static ifnesting; + + +/* initialize conditional assembly */ +void cond_init(void) +{ + cond[0] = 1; + clev = ifnesting = 0; +} + + +/* return true, when current level allows assembling */ +int cond_state(void) +{ + return cond[clev]; +} + + +/* ensures that all conditional block are closed at the end of the source */ +void cond_check(void) +{ + if (clev > 0) + general_error(66,condsrc[clev],condline[clev]); /* "endc/endif missing */ +} + + +/* establish a new level of condititional assembly */ +void cond_if(char flag) +{ + if (++clev >= MAXCONDLEV) + general_error(65,clev); /* nesting depth exceeded */ + + cond[clev] = flag; + condsrc[clev] = cur_src->name; + condline[clev] = cur_src->line; +} + + +/* handle skipped if statement */ +void cond_skipif(void) +{ + ifnesting++; +} + + +/* handle else statement after skipped if-branch */ +void cond_else(void) +{ + if (ifnesting == 0) + cond[clev] = 1; +} + + +/* handle else statement after assembled if-branch */ +void cond_skipelse(void) +{ + if (clev > 0) + cond[clev] = 0; + else + general_error(63); /* else without if */ +} + + +/* handle end-if statement */ +void cond_endif(void) +{ + if (ifnesting == 0) { + if (clev > 0) + clev--; + else + general_error(64); /* unexpected endif without if */ + } + else /* the whole conditional block was ignored */ + ifnesting--; +} diff --git a/cond.h b/cond.h new file mode 100644 index 0000000..90a155c --- /dev/null +++ b/cond.h @@ -0,0 +1,25 @@ +/* cond.h - conditional assembly support routines */ +/* (c) in 2015 by Frank Wille */ + +#ifndef COND_H +#define COND_H + +/* defines */ +#ifndef MAXCONDLEV +#define MAXCONDLEV 63 +#endif + +/* global variables */ +extern int clev; + +/* functions */ +void cond_init(void); +int cond_state(void); +void cond_check(void); +void cond_if(char); +void cond_skipif(void); +void cond_else(void); +void cond_skipelse(void); +void cond_endif(void); + +#endif /* COND_H */ diff --git a/cpus/6502/cpu.c b/cpus/6502/cpu.c index 1c63b2b..a08bee8 100644 --- a/cpus/6502/cpu.c +++ b/cpus/6502/cpu.c @@ -1,6 +1,6 @@ /* ** cpu.c 650x/651x cpu-description file -** (c) in 2002,2006,2008-2010 by Frank Wille +** (c) in 2002,2006,2008-2012,2014-2015 by Frank Wille */ #include "vasm.h" @@ -11,12 +11,12 @@ mnemonic mnemonics[] = { int mnemonic_cnt=sizeof(mnemonics)/sizeof(mnemonics[0]); -char *cpu_copyright="vasm 6502 cpu backend 0.5a (c) 2002,2006,2008-2010 Frank Wille"; +char *cpu_copyright="vasm 6502 cpu backend 0.7a (c) 2002,2006,2008-2012,2014-2015 Frank Wille"; char *cpuname = "6502"; int bitsperbyte = 8; int bytespertaddr = 2; -static unsigned short cpu_type = M6502; +static uint16_t cpu_type = M6502; static int branchopt = 0; static int modifier; /* set by find_base() */ @@ -37,14 +37,21 @@ int ext_unary_eval(int type,taddr val,taddr *result,int cnst) } -symbol *ext_find_base(expr *p,section *sec,taddr pc) +int ext_find_base(symbol **base,expr *p,section *sec,taddr pc) { + /* addr/256 equals >addr, addr%256 and addr&255 equal type==DIV || p->type==MOD) { + if (p->right->type==NUM && p->right->c.val==256) + p->type = p->type == DIV ? HIBYTE : LOBYTE; + } + else if (p->type==BAND && p->right->type==NUM && p->right->c.val==255) + p->type = LOBYTE; + if (p->type==LOBYTE || p->type==HIBYTE) { modifier = p->type; - return find_base(p->left,sec,pc); + return find_base(p->left,base,sec,pc); } - modifier = 0; - return 0; + return BASE_ILLEGAL; } @@ -54,7 +61,7 @@ int parse_operand(char *p,int len,operand *op,int required) int indir = 0; p = skip(p); - if (len>0 && *p=='(' && required!=DATAOP) { + if (len>0 && required!=DATAOP && check_indir(p,start+len)) { indir = 1; p = skip(p+1); } @@ -66,8 +73,10 @@ int parse_operand(char *p,int len,operand *op,int required) p = skip(p); break; case INDIR: + case INDIRX: case INDX: case INDY: + case DPINDIR: if (!indir) return PO_NOMATCH; break; @@ -84,6 +93,7 @@ int parse_operand(char *p,int len,operand *op,int required) switch (required) { case INDX: + case INDIRX: if (*p++ == ',') { p = skip(p); if (toupper((unsigned char)*p++) != 'X') @@ -108,7 +118,8 @@ int parse_operand(char *p,int len,operand *op,int required) break; } - if (required==INDIR || required==INDX || required==INDY) { + if (required==INDIR || required==INDX || required==INDY + || required==DPINDIR || required==INDIRX) { p = skip(p); if (*p++ != ')') { cpu_error(2); /* missing closing parenthesis */ @@ -167,8 +178,8 @@ static void optimize_instruction(instruction *ip,section *sec, else { symbol *base; - if (base = find_base(op->value,sec,pc)) { - if (op->type==REL && base->type==LABSYM && base->sec==sec) { + if (find_base(op->value,&base,sec,pc) == BASE_OK) { + if (op->type==REL && LOCREF(base) && base->sec==sec) { taddr bd = val - (pc + 2); if ((bd<-0x80 || bd>0x7f) && branchopt) { @@ -183,7 +194,7 @@ static void optimize_instruction(instruction *ip,section *sec, } -static taddr get_inst_size(instruction *ip) +static size_t get_inst_size(instruction *ip) { if (ip->op[0] != NULL) { switch (ip->op[0]->type) { @@ -193,6 +204,7 @@ static taddr get_inst_size(instruction *ip) case REL: case INDX: case INDY: + case DPINDIR: case IMMED: case ZPAGE: case ZPAGEX: @@ -202,6 +214,7 @@ static taddr get_inst_size(instruction *ip) case ABSX: case ABSY: case INDIR: + case INDIRX: return 3; case RELJMP: return 5; @@ -214,7 +227,7 @@ static taddr get_inst_size(instruction *ip) } -taddr instruction_size(instruction *ip,section *sec,taddr pc) +size_t instruction_size(instruction *ip,section *sec,taddr pc) { instruction *ipcopy; @@ -251,6 +264,7 @@ static void rangecheck(taddr val,int type) switch (type) { case INDX: case INDY: + case DPINDIR: case ZPAGE: case ZPAGEX: case ZPAGEY: @@ -285,8 +299,8 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) if (op->value != NULL) { if (!eval_expr(op->value,&val,sec,pc)) { modifier = 0; - if (base = find_base(op->value,sec,pc)) { - if (optype==REL && base->type==LABSYM && base->sec==sec) { + if (find_base(op->value,&base,sec,pc) == BASE_OK) { + if (optype==REL && !is_pc_reloc(base,sec)) { /* relative branch requires no relocation */ val = val - (pc + 2); } @@ -299,10 +313,12 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) case ABSX: case ABSY: case INDIR: + case INDIRX: size = 16; break; case INDX: case INDY: + case DPINDIR: case ZPAGE: case ZPAGEX: case ZPAGEY: @@ -321,29 +337,29 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) ierror(0); break; } - rl = add_reloc(&db->relocs,base,val,type,size,offs); + rl = add_nreloc(&db->relocs,base,val,type,size,offs); switch (modifier) { case LOBYTE: - ((nreloc *)rl->reloc)->mask = 0xff; + if (rl) + ((nreloc *)rl->reloc)->mask = 0xff; val = val & 0xff; break; case HIBYTE: - ((nreloc *)rl->reloc)->mask = 0xff00; + if (rl) + ((nreloc *)rl->reloc)->mask = 0xff00; val = (val >> 8) & 0xff; break; } } } else - cpu_error(7); /* illegal relocation */ + general_error(38); /* illegal relocation */ } rangecheck(val,op->type); } } /* write code */ - if (!(mnemonics[ip->code].ext.available & cpu_type)) - cpu_error(0); /* instruction not supported */ if (optype==ZPAGE || optype==ZPAGEX || optype==ZPAGEY) *d++ = mnemonics[ip->code].ext.zp_opcode; else if (optype==RELJMP) @@ -358,6 +374,8 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) cpu_error(5); /* operand doesn't fit into 8-bits */ case ABS: case INDIR: + case INDIRX: + case DPINDIR: *d++ = val & 0xff; *d = (val>>8) & 0xff; break; @@ -382,7 +400,7 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) } -dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) +dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc) { dblock *db = new_dblock(); taddr val; @@ -394,24 +412,29 @@ dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) db->data = mymalloc(db->size); if (!eval_expr(op->value,&val,sec,pc)) { symbol *base; + int btype; rlist *rl; modifier = 0; - if (base = find_base(op->value,sec,pc)) { - rl = add_reloc(&db->relocs,base,val,REL_ABS,bitsize,0); + btype = find_base(op->value,&base,sec,pc); + if (btype==BASE_OK || (btype==BASE_PCREL && modifier==0)) { + rl = add_nreloc(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS,bitsize,0); switch (modifier) { case LOBYTE: - ((nreloc *)rl->reloc)->mask = 0xff; + if (rl) + ((nreloc *)rl->reloc)->mask = 0xff; val = val & 0xff; break; case HIBYTE: - ((nreloc *)rl->reloc)->mask = 0xff00; + if (rl) + ((nreloc *)rl->reloc)->mask = 0xff00; val = (val >> 8) & 0xff; break; } } - else - cpu_error(7); /* illegal relocation */ + else if (btype != BASE_NONE) + general_error(38); /* illegal relocation */ } if (bitsize < 16) { if (val<-0x80 || val>0xff) @@ -441,6 +464,12 @@ operand *new_operand() } +int cpu_available(int idx) +{ + return (mnemonics[idx].ext.available & cpu_type) != 0; +} + + int init_cpu() { return 1; @@ -455,6 +484,8 @@ int cpu_args(char *p) cpu_type |= ILL; else if (!strcmp(p,"-dtv")) cpu_type |= DTV; + else if (!strcmp(p,"-c02")) + cpu_type = M6502 | M65C02; else return 0; diff --git a/cpus/6502/cpu.h b/cpus/6502/cpu.h index 8a8ca33..c459ef4 100644 --- a/cpus/6502/cpu.h +++ b/cpus/6502/cpu.h @@ -1,6 +1,6 @@ /* ** cpu.h 650x/651x cpu-description header-file -** (c) in 2002,2008,2009 by Frank Wille +** (c) in 2002,2008,2009,2014 by Frank Wille */ #define BIGENDIAN 0 @@ -10,16 +10,12 @@ /* maximum number of operands for one mnemonic */ #define MAX_OPERANDS 2 -/* allowed to call parse_operand() with an arbitrary number of operands */ -#define CPU_CHECKS_OPCNT 0 - /* maximum number of mnemonic-qualifiers per mnemonic */ #define MAX_QUALIFIERS 0 -/* maximum number of additional command-line-flags for this cpu */ - /* data type to represent a target-address */ -typedef short taddr; +typedef int16_t taddr; +typedef uint16_t utaddr; /* minimum instruction alignment */ #define INST_ALIGN 1 @@ -30,15 +26,18 @@ typedef short taddr; /* operand class for n-bit data definitions */ #define DATA_OPERAND(n) DATAOP +/* returns true when instruction is valid for selected cpu */ +#define MNEMONIC_VALID(i) cpu_available(i) + /* we define two additional unary operations, '<' and '>' */ int ext_unary_eval(int,taddr,taddr *,int); -symbol *ext_find_base(expr *,section *,taddr); +int ext_find_base(symbol **,expr *,section *,taddr); #define LOBYTE (LAST_EXP_TYPE+1) #define HIBYTE (LAST_EXP_TYPE+2) #define EXT_UNARY_NAME(s) (*s=='<'||*s=='>') #define EXT_UNARY_TYPE(s) (*s=='<'?LOBYTE:HIBYTE) #define EXT_UNARY_EVAL(t,v,r,c) ext_unary_eval(t,v,r,c) -#define EXT_FIND_BASE(e,s,p) ext_find_base(e,s,p) +#define EXT_FIND_BASE(b,e,s,p) ext_find_base(b,e,s,p) /* type to store each operand */ typedef struct { @@ -51,13 +50,14 @@ typedef struct { typedef struct { unsigned char opcode; unsigned char zp_opcode; /* !=0 means optimization to zero page allowed */ - unsigned short available; + uint16_t available; } mnemonic_extension; /* available */ #define M6502 1 /* standard 6502 instruction set */ #define ILL 2 /* illegal 6502 instructions */ #define DTV 4 /* C64 DTV instruction set extension */ +#define M65C02 8 /* 65C02 instruction set */ /* adressing modes */ @@ -68,13 +68,19 @@ typedef struct { #define INDIR 4 /* ($1234) - JMP only */ #define INDX 5 /* ($12,X) */ #define INDY 6 /* ($12),Y */ -#define ZPAGE 7 /* add ZPAGE-ABS to optimize ABS/ABSX/ABSY */ -#define ZPAGEX 8 -#define ZPAGEY 9 -#define RELJMP 10 /* B!cc/JMP construction */ -#define REL 11 /* $1234 - relative branch */ -#define IMMED 12 /* #$12 */ -#define DATAOP 13 /* data operand */ -#define ACCU 14 /* A */ -#define DUMX 15 /* dummy X as 'second' operand */ -#define DUMY 16 /* dummy Y as 'second' operand */ +#define DPINDIR 7 /* ($12) */ +#define INDIRX 8 /* ($1234,X) */ +#define ZPAGE 9 /* add ZPAGE-ABS to optimize ABS/ABSX/ABSY */ +#define ZPAGEX 10 +#define ZPAGEY 11 +#define RELJMP 12 /* B!cc/JMP construction */ +#define REL 13 /* $1234 - relative branch */ +#define IMMED 14 /* #$12 */ +#define DATAOP 15 /* data operand */ +#define ACCU 16 /* A */ +#define DUMX 17 /* dummy X as 'second' operand */ +#define DUMY 18 /* dummy Y as 'second' operand */ + + +/* exported by cpu.c */ +int cpu_available(int); diff --git a/cpus/6502/cpu_errors.h b/cpus/6502/cpu_errors.h index 5a1967b..99abb52 100644 --- a/cpus/6502/cpu_errors.h +++ b/cpus/6502/cpu_errors.h @@ -5,4 +5,3 @@ "relocation does not allow hi/lo modifier",ERROR, "operand doesn't fit into 8-bits",ERROR, /* 05 */ "branch destination out of range",ERROR, - "illegal relocation",ERROR, diff --git a/cpus/6502/opcodes.h b/cpus/6502/opcodes.h index ffe68fb..6a3f482 100644 --- a/cpus/6502/opcodes.h +++ b/cpus/6502/opcodes.h @@ -1,6 +1,7 @@ "adc", {IMMED , }, {0x69,0x00,M6502}, "adc", {ABS , }, {0x6d,0x65,M6502}, "adc", {INDX , }, {0x61,0x00,M6502}, + "adc", {DPINDIR, }, {0x72,0x00,M65C02}, "adc", {INDIR ,DUMY}, {0x71,0x00,M6502}, "adc", {ABS ,DUMX}, {0x7d,0x75,M6502}, "adc", {ABS ,DUMY}, {0x79,0x00,M6502}, @@ -12,6 +13,7 @@ "and", {IMMED , }, {0x29,0x00,M6502}, "and", {ABS , }, {0x2d,0x25,M6502}, "and", {INDX , }, {0x21,0x00,M6502}, + "and", {DPINDIR, }, {0x32,0x00,M65C02}, "and", {INDIR ,DUMY}, {0x31,0x00,M6502}, "and", {ABS ,DUMX}, {0x3d,0x35,M6502}, "and", {ABS ,DUMY}, {0x39,0x00,M6502}, @@ -19,7 +21,7 @@ "asl", {ACCU , }, {0x0a,0x00,M6502}, "asl", {ABS , }, {0x0e,0x06,M6502}, "asl", {IMPLIED, }, {0x0a,0x00,M6502}, - "asl", {ABS , }, {0x1e,0x16,M6502}, + "asl", {ABS ,DUMX}, {0x1e,0x16,M6502}, "aso", {ABS , }, {0x0f,0x07,ILL}, "aso", {INDX , }, {0x03,0x00,ILL}, "aso", {INDIR ,DUMY}, {0x13,0x00,ILL}, @@ -34,11 +36,14 @@ "bcc", {REL , }, {0x90,0x00,M6502}, "bcs", {REL , }, {0xb0,0x00,M6502}, "beq", {REL , }, {0xf0,0x00,M6502}, + "bit", {IMMED , }, {0x89,0x00,M65C02}, "bit", {ABS , }, {0x2c,0x24,M6502}, + "bit", {ABS ,DUMX}, {0x3c,0x34,M65C02}, "bmi", {REL , }, {0x30,0x00,M6502}, "bne", {REL , }, {0xd0,0x00,M6502}, "bpl", {REL , }, {0x10,0x00,M6502}, "bra", {REL , }, {0x12,0x00,DTV}, + "bra", {REL , }, {0x80,0x00,M65C02}, "brk", {IMPLIED, }, {0x00,0x00,M6502}, "bvc", {REL , }, {0x50,0x00,M6502}, "bvs", {REL , }, {0x70,0x00,M6502}, @@ -49,6 +54,7 @@ "cmp", {IMMED , }, {0xc9,0x00,M6502}, "cmp", {ABS , }, {0xcd,0xc5,M6502}, "cmp", {INDX , }, {0xc1,0x00,M6502}, + "cmp", {DPINDIR, }, {0xd2,0x00,M65C02}, "cmp", {INDIR ,DUMY}, {0xd1,0x00,M6502}, "cmp", {ABS ,DUMX}, {0xdd,0xd5,M6502}, "cmp", {ABS ,DUMY}, {0xd9,0x00,M6502}, @@ -66,6 +72,9 @@ "dcp", {INDIR ,DUMY}, {0xd3,0x00,ILL}, "dcp", {ABS ,DUMX}, {0xdf,0xd7,ILL}, "dcp", {ABS ,DUMY}, {0xdb,0x00,ILL}, + "dea", {IMPLIED, }, {0x3a,0x00,M65C02}, + "dec", {ACCU , }, {0x3a,0x00,M65C02}, + "dec", {IMPLIED, }, {0x3a,0x00,M65C02}, "dec", {ABS , }, {0xce,0xc6,M6502}, "dec", {ABS ,DUMX}, {0xde,0xd6,M6502}, "dex", {IMPLIED, }, {0xca,0x00,M6502}, @@ -73,9 +82,13 @@ "eor", {IMMED , }, {0x49,0x00,M6502}, "eor", {ABS , }, {0x4d,0x45,M6502}, "eor", {INDX , }, {0x41,0x00,M6502}, + "eor", {DPINDIR, }, {0x52,0x00,M65C02}, "eor", {INDIR ,DUMY}, {0x51,0x00,M6502}, "eor", {ABS ,DUMX}, {0x5d,0x55,M6502}, "eor", {ABS ,DUMY}, {0x59,0x00,M6502}, + "ina", {IMPLIED, }, {0x1a,0x00,M65C02}, + "inc", {ACCU , }, {0x1a,0x00,M65C02}, + "inc", {IMPLIED, }, {0x1a,0x00,M65C02}, "inc", {ABS , }, {0xee,0xe6,M6502}, "inc", {ABS ,DUMX}, {0xfe,0xf6,M6502}, "ins", {ABS , }, {0xef,0xe7,ILL}, @@ -91,6 +104,7 @@ "isc", {ABS ,DUMX}, {0xff,0xf7,ILL}, "isc", {ABS ,DUMY}, {0xfb,0x00,ILL}, "jmp", {ABS , }, {0x4c,0x00,M6502}, + "jmp", {INDIRX , }, {0x7c,0x00,M65C02}, "jmp", {INDIR , }, {0x6c,0x00,M6502}, "jsr", {ABS , }, {0x20,0x00,M6502}, "las", {ABS ,DUMY}, {0xbb,0x00,ILL}, @@ -101,6 +115,7 @@ "lax", {INDIR ,DUMY}, {0xb3,0x00,ILL}, "lda", {IMMED , }, {0xa9,0x00,M6502}, "lda", {ABS , }, {0xad,0xa5,M6502}, + "lda", {DPINDIR, }, {0xb2,0x00,M65C02}, "lda", {INDX , }, {0xa1,0x00,M6502}, "lda", {INDIR ,DUMY}, {0xb1,0x00,M6502}, "lda", {ABS ,DUMX}, {0xbd,0xb5,M6502}, @@ -125,13 +140,18 @@ "ora", {IMMED , }, {0x09,0x00,M6502}, "ora", {ABS , }, {0x0d,0x05,M6502}, "ora", {INDX , }, {0x01,0x00,M6502}, + "ora", {DPINDIR, }, {0x12,0x00,M65C02}, "ora", {INDIR ,DUMY}, {0x11,0x00,M6502}, "ora", {ABS ,DUMX}, {0x1d,0x15,M6502}, "ora", {ABS ,DUMY}, {0x19,0x00,M6502}, "pha", {IMPLIED, }, {0x48,0x00,M6502}, "php", {IMPLIED, }, {0x08,0x00,M6502}, + "phx", {IMPLIED, }, {0xda,0x00,M65C02}, + "phy", {IMPLIED, }, {0x5a,0x00,M65C02}, "pla", {IMPLIED, }, {0x68,0x00,M6502}, "plp", {IMPLIED, }, {0x28,0x00,M6502}, + "plx", {IMPLIED, }, {0xfa,0x00,M65C02}, + "ply", {IMPLIED, }, {0x7a,0x00,M65C02}, "rla", {ABS , }, {0x2f,0x27,ILL}, "rla", {INDX , }, {0x23,0x00,ILL}, "rla", {INDIR ,DUMY}, {0x33,0x00,ILL}, @@ -140,11 +160,11 @@ "rol", {ACCU , }, {0x2a,0x00,M6502}, "rol", {ABS , }, {0x2e,0x26,M6502}, "rol", {IMPLIED, }, {0x2a,0x00,M6502}, - "rol", {ABS , }, {0x3e,0x36,M6502}, + "rol", {ABS ,DUMX}, {0x3e,0x36,M6502}, "ror", {ACCU , }, {0x6a,0x00,M6502}, "ror", {ABS , }, {0x6e,0x66,M6502}, "ror", {IMPLIED, }, {0x6a,0x00,M6502}, - "ror", {ABS , }, {0x7e,0x76,M6502}, + "ror", {ABS ,DUMX}, {0x7e,0x76,M6502}, "rra", {ABS , }, {0x6f,0x67,ILL}, "rra", {INDX , }, {0x63,0x00,ILL}, "rra", {INDIR ,DUMY}, {0x73,0x00,ILL}, @@ -161,6 +181,7 @@ "sbc", {IMMED , }, {0xe9,0x00,M6502}, "sbc", {ABS , }, {0xed,0xe5,M6502}, "sbc", {INDX , }, {0xe1,0x00,M6502}, + "sbc", {DPINDIR, }, {0xf2,0x00,M65C02}, "sbc", {INDIR ,DUMY}, {0xf1,0x00,M6502}, "sbc", {ABS ,DUMX}, {0xfd,0xf5,M6502}, "sbc", {ABS ,DUMY}, {0xf9,0x00,M6502}, @@ -183,6 +204,7 @@ "sre", {ABS ,DUMY}, {0x5b,0x00,ILL}, "sta", {ABS , }, {0x8d,0x85,M6502}, "sta", {INDX , }, {0x81,0x00,M6502}, + "sta", {DPINDIR, }, {0x92,0x00,M65C02}, "sta", {INDIR ,DUMY}, {0x91,0x00,M6502}, "sta", {ABS ,DUMX}, {0x9d,0x95,M6502}, "sta", {ABS ,DUMY}, {0x99,0x00,M6502}, @@ -190,9 +212,13 @@ "stx", {ABS ,DUMY}, {0x00,0x96,M6502}, "sty", {ABS , }, {0x8c,0x84,M6502}, "sty", {ABS ,DUMX}, {0x00,0x94,M6502}, + "stz", {ABS , }, {0x9c,0x64,M65C02}, + "stz", {ABS ,DUMX}, {0x9e,0x74,M65C02}, "tas", {ABS ,DUMY}, {0x9b,0x00,ILL}, "tax", {IMPLIED, }, {0xaa,0x00,M6502}, "tay", {IMPLIED, }, {0xa8,0x00,M6502}, + "trb", {ABS , }, {0x1c,0x14,M65C02}, + "tsb", {ABS , }, {0x0c,0x04,M65C02}, "tsx", {IMPLIED, }, {0xba,0x00,M6502}, "txa", {IMPLIED, }, {0x8a,0x00,M6502}, "txs", {IMPLIED, }, {0x9a,0x00,M6502}, diff --git a/cpus/6800/cpu.c b/cpus/6800/cpu.c new file mode 100644 index 0000000..f688008 --- /dev/null +++ b/cpus/6800/cpu.c @@ -0,0 +1,373 @@ +/* + * cpu.c 6800, 68hc11 cpu description file + * (c) in 2013-2015 by Esben Norby and Frank Wille + */ + +#include "vasm.h" + +mnemonic mnemonics[] = { +#include "opcodes.h" +}; + +int mnemonic_cnt = sizeof(mnemonics) / sizeof(mnemonics[0]); + +int bitsperbyte = 8; +int bytespertaddr = 2; +char * cpu_copyright = "vasm 6800/68hc11 cpu backend 0.2a (c) 2013-2015 Esben Norby"; +char * cpuname = "6800"; + +static uint8_t cpu_type = M6800; +static int modifier; /* set by find_base() */ + + +int +init_cpu() +{ + return 1; +} + + +int +cpu_args(char *p) +{ + if (!strncmp(p, "-m68", 4)) { + p += 4; + if (!strcmp(p, "00")) + cpu_type = M6800; + else if (!stricmp(p, "hc11")) + cpu_type = M68HC11; + else + return 0; + } + return 1; +} + + +char * +parse_cpu_special(char *start) +{ + return start; +} + + +operand * +new_operand() +{ + operand *new = mymalloc(sizeof(*new)); + new->type = -1; + return new; +} + + +int +parse_operand(char *p, int len, operand *op, int required) +{ + char *start = p; + + op->value = NULL; + + switch (required) { + case IMM: + case IMM16: + if (*p++ != '#') + return PO_NOMATCH; + p = skip(p); + /* fall through */ + case REL: + case DATAOP: + op->value = parse_expr(&p); + break; + + case ADDR: + if (*p == '<') { + required = DIR; + p++; + } + else if (*p == '>') { + required = EXT; + p++; + } + op->value = parse_expr(&p); + break; + + case DIR: + if (*p == '>') + return PO_NOMATCH; + else if (*p == '<') + p++; + op->value = parse_expr(&p); + break; + + case EXT: + if (*p == '<') + return PO_NOMATCH; + else if (*p == '>') + p++; + op->value = parse_expr(&p); + break; + + case REGX: + if (toupper((unsigned char)*p++) != 'X') + return PO_NOMATCH; + break; + case REGY: + if (toupper((unsigned char)*p++) != 'Y') + return PO_NOMATCH; + break; + + default: + return PO_NOMATCH; + } + + op->type = required; + return PO_MATCH; +} + + +static size_t +eval_oper(operand *op, section *sec, taddr pc, taddr offs, dblock *db) +{ + size_t size = 0; + symbol *base = NULL; + int btype; + taddr val; + + if (op->value != NULL && !eval_expr(op->value, &val, sec, pc)) { + modifier = 0; + btype = find_base(op->value, &base, sec, pc); + } + + switch (op->type) { + case ADDR: + if (base != NULL || val < 0 || val > 0xff) { + op->type = EXT; + size = 2; + } + else { + op->type = DIR; + size = 1; + } + break; + case DIR: + size = 1; + if (db != NULL && (val < 0 || val > 0xff)) + cpu_error(1); /* operand doesn't fit into 8-bits */ + break; + case IMM: + size = 1; + if (db != NULL && !modifier && (val < -0x80 || val > 0xff)) + cpu_error(1); /* operand doesn't fit into 8-bits */ + break; + case EXT: + case IMM16: + size = 2; + break; + case REL: + size = 1; + break; + } + + if (size > 0 && db != NULL) { + /* create relocation entry and code for this operand */ + if (base != NULL && btype == BASE_OK && op->type == REL) { + /* relative branches */ + if (!is_pc_reloc(base, sec)) { + val = val - (pc + offs + 1); + if (val < -0x80 || val > 0x7f) + cpu_error(2); /* branch out of range */ + } + else + add_nreloc(&db->relocs, base, val, REL_PC, + 8, offs << 3); + } + else if (base != NULL && btype != BASE_ILLEGAL) { + rlist *rl; + + rl = add_nreloc(&db->relocs, base, val, + btype==BASE_PCREL? REL_PC : REL_ABS, + size << 3, offs << 3); + switch (modifier) { + case LOBYTE: + if (rl) ((nreloc *)rl->reloc)->mask = 0xff; + val &= 0xff; + break; + case HIBYTE: + if (rl) ((nreloc *)rl->reloc)->mask = 0xff00; + val = (val >> 8) & 0xff; + break; + } + } + else if (base != NULL) + general_error(38); /* illegal relocation */ + + if (size == 1) { + op->code[0] = val & 0xff; + } + else if (size == 2) { + op->code[0] = (val >> 8) & 0xff; + op->code[1] = val & 0xff; + } + else + ierror(0); + } + return (size); +} + + +size_t +instruction_size(instruction *ip, section *sec, taddr pc) +{ + operand op; + int i; + size_t size; + + size = (mnemonics[ip->code].ext.prebyte != 0) ? 2 : 1; + + for (i = 0; i < MAX_OPERANDS && ip->op[i] != NULL; i++) { + op = *(ip->op[i]); + size += eval_oper(&op, sec, pc, size, NULL); + } + + return (size); +} + + +dblock * +eval_instruction(instruction *ip, section *sec, taddr pc) +{ + dblock *db = new_dblock(); + uint8_t opcode; + uint8_t *d; + int i; + size_t size; + + /* evaluate operands and determine instruction size */ + opcode = mnemonics[ip->code].ext.opcode; + size = (mnemonics[ip->code].ext.prebyte != 0) ? 2 : 1; + for (i = 0; i < MAX_OPERANDS && ip->op[i] != NULL; i++) { + size += eval_oper(ip->op[i], sec, pc, size, db); + if (ip->op[i]->type == DIR) + opcode = mnemonics[ip->code].ext.dir_opcode; + } + + /* allocate and fill data block */ + db->size = size; + d = db->data = mymalloc(size); + + if (mnemonics[ip->code].ext.prebyte != 0) + *d++ = mnemonics[ip->code].ext.prebyte; + *d++ = opcode; + + /* write operands */ + for (i = 0; i < MAX_OPERANDS && ip->op[i] != NULL; i++) { + switch (ip->op[i]->type) { + case IMM: + case DIR: + case REL: + *d++ = ip->op[i]->code[0]; + break; + case IMM16: + case EXT: + *d++ = ip->op[i]->code[0]; + *d++ = ip->op[i]->code[1]; + break; + } + } + + return (db); +} + +dblock * +eval_data(operand *op, size_t bitsize, section *sec, taddr pc) +{ + dblock *db = new_dblock(); + uint8_t *d; + taddr val; + + if (bitsize != 8 && bitsize != 16) + cpu_error(0,bitsize); /* data size not supported */ + + db->size = bitsize >> 3; + d = db->data = mymalloc(db->size); + + if (!eval_expr(op->value, &val, sec, pc)) { + symbol *base; + int btype; + rlist *rl; + + modifier = 0; + btype = find_base(op->value, &base, sec, pc); + if (btype==BASE_OK || (btype==BASE_PCREL && modifier==0)) { + rl = add_nreloc(&db->relocs, base, val, + btype==BASE_PCREL ? REL_PC : REL_ABS, + bitsize, 0); + switch (modifier) { + case LOBYTE: + if (rl) ((nreloc *)rl->reloc)->mask = 0xff; + val &= 0xff; + break; + case HIBYTE: + if (rl) ((nreloc *)rl->reloc)->mask = 0xff00; + val = (val >> 8) & 0xff; + break; + } + } + else if (btype != BASE_NONE) + general_error(38); /* illegal relocation */ + } + + if (bitsize == 8) { + if (val < -0x80 || val > 0xff) + cpu_error(1); /* operand doesn't fit into 8-bits */ + } + else /* 16 bits */ + *d++ = (val >> 8) & 0xff; + *d = val & 0xff; + + return (db); +} + + +int +ext_unary_eval(int type, taddr val, taddr *result, int cnst) +{ + switch (type) { + case LOBYTE: + *result = cnst ? (val & 0xff) : val; + return 1; + case HIBYTE: + *result = cnst ? ((val >> 8) & 0xff) : val; + return 1; + default: + break; + } + + return 0; /* unknown type */ +} + + +int +ext_find_base(symbol **base, expr *p, section *sec, taddr pc) +{ + /* addr/256 equals >addr, addr%256 and addr&255 equal type==DIV || p->type==MOD) { + if (p->right->type==NUM && p->right->c.val==256) + p->type = p->type == DIV ? HIBYTE : LOBYTE; + } + else if (p->type==BAND && p->right->type==NUM && p->right->c.val==255) + p->type = LOBYTE; + + if (p->type==LOBYTE || p->type==HIBYTE) { + modifier = p->type; + return find_base(p->left,base,sec,pc); + } + + return BASE_ILLEGAL; +} + + +int +cpu_available(int idx) +{ + return (mnemonics[idx].ext.available & cpu_type) != 0; +} diff --git a/cpus/6800/cpu.h b/cpus/6800/cpu.h new file mode 100644 index 0000000..7407fee --- /dev/null +++ b/cpus/6800/cpu.h @@ -0,0 +1,79 @@ +/* + * cpu.c 6800, 68hc11 cpu description file + * (c) in 2013-2014 by Esben Norby and Frank Wille +*/ + +#define BIGENDIAN 1 +#define LITTLEENDIAN 0 +#define VASM_CPU_6800 1 + +/* maximum number of operands for one mnemonic */ +#define MAX_OPERANDS 4 + +/* maximum number of mnemonic-qualifiers per mnemonic */ +#define MAX_QUALIFIERS 0 + +/* data type to represent a target-address */ +typedef int16_t taddr; +typedef uint16_t utaddr; + +/* minimum instruction alignment */ +#define INST_ALIGN 1 + +/* default alignment for n-bit data */ +#define DATA_ALIGN(n) 1 + +/* operand class for n-bit data definitions */ +#define DATA_OPERAND(n) DATAOP + +/* returns true when instruction is valid for selected cpu */ +#define MNEMONIC_VALID(i) cpu_available(i) + +/* allow commas and blanks at the same time to separate instruction operands */ +#define OPERSEP_COMMA 1 +#define OPERSEP_BLANK 1 + +/* we define two additional unary operations, '<' and '>' */ +int ext_unary_eval(int,taddr,taddr *,int); +int ext_find_base(symbol **,expr *,section *,taddr); +#define LOBYTE (LAST_EXP_TYPE+1) +#define HIBYTE (LAST_EXP_TYPE+2) +#define EXT_UNARY_NAME(s) (*s=='<'||*s=='>') +#define EXT_UNARY_TYPE(s) (*s=='<'?LOBYTE:HIBYTE) +#define EXT_UNARY_EVAL(t,v,r,c) ext_unary_eval(t,v,r,c) +#define EXT_FIND_BASE(b,e,s,p) ext_find_base(b,e,s,p) + +/* type to store each operand */ +typedef struct { + uint16_t type; + uint8_t code[2]; + expr *value; +} operand; + + +/* additional mnemonic data */ +typedef struct { + unsigned char prebyte; + unsigned char opcode; + unsigned char dir_opcode; /* !=0 means optimization to DIR allowed */ + uint8_t available; +} mnemonic_extension; + +/* available */ +#define M6800 1 +#define M68HC11 2 /* standard 68HC11 instruction set */ + +/* adressing modes */ +#define INH 0 +#define IMM 1 /* #$12 */ /* IMM ii */ +#define IMM16 2 /* #$1234 */ /* IMM jj kk */ +#define ADDR 3 +#define EXT 4 /* EXT hh */ +#define DIR 5 /* DIR dd */ +#define REL 6 /* REL rr */ +#define REGX 7 +#define REGY 8 +#define DATAOP 9 /* data operand */ + +/* exported by cpu.c */ +int cpu_available(int); diff --git a/cpus/6800/cpu_errors.h b/cpus/6800/cpu_errors.h new file mode 100644 index 0000000..f752cc0 --- /dev/null +++ b/cpus/6800/cpu_errors.h @@ -0,0 +1,3 @@ + "data size %d not supported",ERROR, + "operand doesn't fit into 8-bits",ERROR, + "branch destination out of range",ERROR, diff --git a/cpus/6800/opcodes.h b/cpus/6800/opcodes.h new file mode 100644 index 0000000..a3d0283 --- /dev/null +++ b/cpus/6800/opcodes.h @@ -0,0 +1,339 @@ + "aba", {INH }, {0x00, 0x1B, 0x00, M6800|M68HC11}, + "abx", {INH }, {0x00, 0x3A, 0x00, M68HC11}, + "aby", {INH }, {0x18, 0x3A, 0x00, M68HC11}, + "adca", {IMM }, {0x00, 0x89, 0x00, M6800|M68HC11}, + "adca", {ADDR }, {0x00, 0xB9, 0x99, M6800|M68HC11}, + "adca", {DIR, REGX }, {0x00, 0x00, 0xA9, M6800|M68HC11}, + "adca", {DIR, REGY }, {0x18, 0x00, 0xA9, M68HC11}, + "adcb", {IMM }, {0x00, 0xC9, 0x00, M6800|M68HC11}, + "adcb", {ADDR }, {0x00, 0xF9, 0xD9, M6800|M68HC11}, + "adcb", {DIR, REGX }, {0x00, 0x00, 0xE9, M6800|M68HC11}, + "adcb", {DIR, REGY }, {0x18, 0x00, 0xE9, M68HC11}, + "adda", {IMM }, {0x00, 0x8B, 0x00, M6800|M68HC11}, + "adda", {ADDR }, {0x00, 0xBB, 0x9B, M6800|M68HC11}, + "adda", {DIR, REGX }, {0x00, 0x00, 0xAB, M6800|M68HC11}, + "adda", {DIR, REGY }, {0x18, 0x00, 0xAB, M68HC11}, + "addb", {IMM }, {0x00, 0xCB, 0x00, M6800|M68HC11}, + "addb", {ADDR }, {0x00, 0xFB, 0xDB, M6800|M68HC11}, + "addb", {DIR, REGX }, {0x00, 0x00, 0xEB, M6800|M68HC11}, + "addb", {DIR, REGY }, {0x18, 0x00, 0xEB, M68HC11}, + "addd", {IMM16 }, {0x00, 0xC3, 0x00, M68HC11}, + "addd", {ADDR }, {0x00, 0xF3, 0xD3, M68HC11}, + "addd", {DIR, REGX }, {0x00, 0x00, 0xE3, M68HC11}, + "addd", {DIR, REGY }, {0x18, 0x00, 0xE3, M68HC11}, + "anda", {IMM }, {0x00, 0x84, 0x00, M6800|M68HC11}, + "anda", {ADDR }, {0x00, 0xB4, 0x94, M6800|M68HC11}, + "anda", {DIR, REGX }, {0x00, 0x00, 0xA4, M6800|M68HC11}, + "anda", {DIR, REGY }, {0x18, 0x00, 0xA4, M68HC11}, + "andb", {IMM }, {0x00, 0xC4, 0x00, M6800|M68HC11}, + "andb", {ADDR }, {0x00, 0xF4, 0xD4, M6800|M68HC11}, + "andb", {DIR, REGX }, {0x00, 0x00, 0xE4, M6800|M68HC11}, + "andb", {DIR, REGY }, {0x18, 0x00, 0xE4, M68HC11}, + "asl", {EXT }, {0x00, 0x78, 0x00, M6800|M68HC11}, + "asl", {DIR, REGX }, {0x00, 0x00, 0x68, M6800|M68HC11}, + "asl", {DIR, REGY }, {0x18, 0x00, 0x68, M68HC11}, + "asla", {INH }, {0x00, 0x48, 0x00, M6800|M68HC11}, + "aslb", {INH }, {0x00, 0x58, 0x00, M6800|M68HC11}, + "asld", {INH }, {0x00, 0x05, 0x00, M6800|M68HC11}, + "asr", {EXT }, {0x00, 0x77, 0x00, M6800|M68HC11}, + "asr", {DIR, REGX }, {0x00, 0x00, 0x67, M6800|M68HC11}, + "asr", {DIR, REGY }, {0x18, 0x00, 0x67, M68HC11}, + "asra", {INH, }, {0x00, 0x47, 0x00, M6800|M68HC11}, + "asrb", {INH, }, {0x00, 0x57, 0x00, M6800|M68HC11}, + + "bclr", {DIR, IMM }, {0x00, 0x00, 0x15, M68HC11}, + "bclr", {DIR, REGX, IMM }, {0x00, 0x00, 0x1D, M68HC11}, + "bclr", {DIR, REGY, IMM }, {0x18, 0x00, 0x1D, M68HC11}, + + "bcc", {REL, }, {0x00, 0x24, 0x00, M6800|M68HC11}, + "bcs", {REL, }, {0x00, 0x25, 0x00, M6800|M68HC11}, + "beq", {REL, }, {0x00, 0x27, 0x00, M6800|M68HC11}, + "bge", {REL, }, {0x00, 0x2C, 0x00, M6800|M68HC11}, + "bgt", {REL, }, {0x00, 0x2E, 0x00, M6800|M68HC11}, + "bhi", {REL, }, {0x00, 0x22, 0x00, M6800|M68HC11}, + "bhs", {REL, }, {0x00, 0x24, 0x00, M6800|M68HC11}, + "bita", {IMM }, {0x00, 0x85, 0x00, M6800|M68HC11}, + "bita", {ADDR, }, {0x00, 0xB5, 0x95, M6800|M68HC11}, + "bita", {DIR, REGX }, {0x00, 0x00, 0xA5, M6800|M68HC11}, + "bita", {DIR, REGY }, {0x18, 0x00, 0xA5, M68HC11}, + "bitb", {IMM }, {0x00, 0xC5, 0x00, M6800|M68HC11}, + "bitb", {ADDR, }, {0x00, 0xF5, 0xD5, M6800|M68HC11}, + "bitb", {DIR, REGX }, {0x00, 0x00, 0xE5, M6800|M68HC11}, + "bitb", {DIR, REGY }, {0x18, 0x00, 0xE5, M68HC11}, + + "ble", {REL, }, {0x00, 0x2F, 0x00, M6800|M68HC11}, + "blo", {REL, }, {0x00, 0x25, 0x00, M6800|M68HC11}, + "bls", {REL, }, {0x00, 0x23, 0x00, M6800|M68HC11}, + "blt", {REL, }, {0x00, 0x2D, 0x00, M6800|M68HC11}, + "bmi", {REL, }, {0x00, 0x2B, 0x00, M6800|M68HC11}, + "bne", {REL, }, {0x00, 0x26, 0x00, M6800|M68HC11}, + "bpl", {REL, }, {0x00, 0x2A, 0x00, M6800|M68HC11}, + "bra", {REL, }, {0x00, 0x20, 0x00, M6800|M68HC11}, + "jr", {REL, }, {0x00, 0x20, 0x00, M6800|M68HC11}, /* bra */ + + "brclr",{DIR, IMM, REL }, {0x00, 0x00, 0x13, M68HC11}, + "brclr",{DIR, REGX, IMM, REL}, {0x00, 0x00, 0x1F, M68HC11}, + "brclr",{DIR, REGY, IMM, REL}, {0x18, 0x00, 0x1F, M68HC11}, + + "brn", {REL, }, {0x00, 0x21, 0x00, M68HC11}, + + "brset",{DIR, IMM, REL }, {0x00, 0x00, 0x12, M68HC11}, + "brset",{DIR, REGX, IMM, REL}, {0x00, 0x00, 0x1E, M68HC11}, + "brset",{DIR, REGY, IMM, REL}, {0x18, 0x00, 0x1E, M68HC11}, + + "bset", {DIR, IMM }, {0x00, 0x00, 0x14, M68HC11}, + "bset", {DIR, REGX, IMM }, {0x00, 0x00 ,0x1C, M68HC11}, + "bset", {DIR, REGY, IMM }, {0x18, 0x00 ,0x1C, M68HC11}, + + "bsr", {REL, }, {0x00, 0x8D, 0x00, M6800|M68HC11}, + "callr",{REL, }, {0x00, 0x8D, 0x00, M6800|M68HC11}, /* bsr */ + "bvc", {REL, }, {0x00, 0x28, 0x00, M6800|M68HC11}, + "bvs", {REL, }, {0x00, 0x29, 0x00, M6800|M68HC11}, + "cba", {INH, }, {0x00, 0x11, 0x00, M6800|M68HC11}, + "clc", {INH, }, {0x00, 0x0C, 0x00, M6800|M68HC11}, + "cli", {INH, }, {0x00, 0x0E, 0x00, M6800|M68HC11}, + "ei", {INH, }, {0x00, 0x0E, 0x00, M6800|M68HC11}, /* cli */ + "clr", {EXT, }, {0x00, 0x7F, 0x00, M6800|M68HC11}, + "clr", {DIR, REGX }, {0x00, 0x00, 0x6F, M6800|M68HC11}, + "clr", {DIR, REGY }, {0x18, 0x00, 0x6F, M68HC11}, + "clra", {INH, }, {0x00, 0x4F, 0x00, M6800|M68HC11}, + "clrb", {INH, }, {0x00, 0x5F, 0x00, M6800|M68HC11}, + "clv", {INH, }, {0x00, 0x0A, 0x00, M6800|M68HC11}, + "cmpa", {IMM }, {0x00, 0x81, 0x00, M6800|M68HC11}, + "cmpa", {ADDR, }, {0x00, 0xB1, 0x91, M6800|M68HC11}, + "cmpa", {DIR, REGX }, {0x00, 0x00, 0xA1, M6800|M68HC11}, + "cmpa", {DIR, REGY }, {0x18, 0x00, 0xA1, M68HC11}, + "cmpb", {IMM }, {0x00, 0xC1, 0x00, M6800|M68HC11}, + "cmpb", {ADDR, }, {0x00, 0xF1, 0xD1, M6800|M68HC11}, + "cmpb", {DIR, REGX }, {0x00, 0x00, 0xE1, M6800|M68HC11}, + "cmpb", {DIR, REGY }, {0x18, 0x00, 0xE1, M68HC11}, + "com", {EXT, }, {0x00, 0x73, 0x00, M6800|M68HC11}, + "com", {DIR, REGX }, {0x00, 0x00, 0x63, M6800|M68HC11}, + "com", {DIR, REGY }, {0x18, 0x00, 0x63, M68HC11}, + "coma", {INH, }, {0x00, 0x43, 0x00, M6800|M68HC11}, + "comb", {INH, }, {0x00, 0x53, 0x00, M6800|M68HC11}, + "cpd", {IMM16 }, {0x1A, 0x83, 0x00, M68HC11}, + "cpd", {ADDR, }, {0x1A, 0xB3, 0x93, M68HC11}, + "cpd", {DIR, REGX }, {0x1A, 0x00, 0xA3, M68HC11}, + "cpd", {DIR, REGY }, {0xCD, 0x00, 0xA3, M68HC11}, + "cmpd", {IMM16 }, {0x1A, 0x83, 0x00, M68HC11}, /* cpd */ + "cmpd", {ADDR, }, {0x1A, 0xB3, 0x93, M68HC11}, /* cpd */ + "cmpd", {DIR, REGX }, {0x1A, 0x00, 0xA3, M68HC11}, /* cpd */ + "cmpd", {DIR, REGY }, {0xCD, 0x00, 0xA3, M68HC11}, /* cpd */ + "cpx", {IMM16 }, {0x00, 0x8C, 0x00, M6800|M68HC11}, + "cpx", {ADDR, }, {0x00, 0xBC, 0x9C, M6800|M68HC11}, + "cpx", {DIR, REGX }, {0x00, 0x00, 0xAC, M6800|M68HC11}, + "cpx", {DIR, REGY }, {0xCD, 0x00, 0xAC, M68HC11}, + "cmpx", {IMM16 }, {0x00, 0x8C, 0x00, M6800|M68HC11}, /* cpx */ + "cmpx", {ADDR, }, {0x00, 0xBC, 0x9C, M6800|M68HC11}, /* cpx */ + "cmpx", {DIR, REGX }, {0x00, 0x00, 0xAC, M6800|M68HC11}, /* cpx */ + "cmpx", {DIR, REGY }, {0xCD, 0x00, 0xAC, M68HC11}, /* cpx */ + "cpy", {IMM16 }, {0x18, 0x8C, 0x00, M68HC11}, + "cpy", {ADDR, }, {0x18, 0xBC, 0x9C, M68HC11}, + "cpy", {DIR, REGX }, {0x1A, 0x00, 0xAC, M68HC11}, + "cpy", {DIR, REGY }, {0x18, 0x00, 0xAC, M68HC11}, + "cmpy", {IMM16 }, {0x18, 0x8C, 0x00, M68HC11}, /* cpy */ + "cmpy", {ADDR, }, {0x18, 0xBC, 0x9C, M68HC11}, /* cpy */ + "cmpy", {DIR, REGX }, {0x1A, 0x00, 0xAC, M68HC11}, /* cpy */ + "cmpy", {DIR, REGY }, {0x18, 0x00, 0xAC, M68HC11}, /* cpy */ + "daa", {INH, }, {0x00, 0x19, 0x00, M6800|M68HC11}, + "dec", {EXT, }, {0x00, 0x7A, 0x00, M6800|M68HC11}, + "dec", {DIR, REGX }, {0x00, 0x00, 0x6A, M6800|M68HC11}, + "dec", {DIR, REGY }, {0x18, 0x00, 0x6A, M68HC11}, + "deca", {INH, }, {0x00, 0x4A, 0x00, M6800|M68HC11}, + "decb", {INH, }, {0x00, 0x5A, 0x00, M6800|M68HC11}, + "des", {INH, }, {0x00, 0x34, 0x00, M6800|M68HC11}, + "decs", {INH, }, {0x00, 0x34, 0x00, M6800|M68HC11}, /* des */ + "dex", {INH, }, {0x00, 0x09, 0x00, M6800|M68HC11}, + "decx", {INH, }, {0x00, 0x09, 0x00, M6800|M68HC11}, /* dex */ + "dey", {INH, }, {0x18, 0x09, 0x00, M68HC11}, + "decy", {INH, }, {0x18, 0x09, 0x00, M68HC11}, /* dey */ + "eora", {IMM, }, {0x00, 0x88, 0x00, M6800|M68HC11}, + "eora", {ADDR, }, {0x00, 0xB8, 0x98, M6800|M68HC11}, + "eora", {DIR, REGX }, {0x00, 0x00, 0xA8, M6800|M68HC11}, + "eora", {DIR, REGY }, {0x18, 0x00, 0xA8, M68HC11}, + "xora", {IMM, }, {0x00, 0x88, 0x00, M6800|M68HC11}, /* eora */ + "xora", {ADDR, }, {0x00, 0xB8, 0x98, M6800|M68HC11}, /* eora */ + "xora", {DIR, REGX }, {0x00, 0x00, 0xA8, M6800|M68HC11}, /* eora */ + "xora", {DIR, REGY }, {0x18, 0x00, 0xA8, M68HC11}, /* eora */ + "eorb", {IMM, }, {0x00, 0xC8, 0x00, M6800|M68HC11}, + "eorb", {ADDR, }, {0x00, 0xF8, 0xD8, M6800|M68HC11}, + "eorb", {DIR, REGX }, {0x00, 0x00, 0xE8, M6800|M68HC11}, + "eorb", {DIR, REGY }, {0x18, 0x00, 0xE8, M68HC11}, + "xorb", {IMM, }, {0x00, 0xC8, 0x00, M6800|M68HC11}, /* eorb */ + "xorb", {ADDR, }, {0x00, 0xF8, 0xD8, M6800|M68HC11}, /* eorb */ + "xorb", {DIR, REGX }, {0x00, 0x00, 0xE8, M6800|M68HC11}, /* eorb */ + "xorb", {DIR, REGY }, {0x18, 0x00, 0xE8, M68HC11}, /* eorb */ + "fdiv", {INH, }, {0x00, 0x03, 0x00, M68HC11}, + "idiv", {INH, }, {0x00, 0x02, 0x00, M68HC11}, + "inc", {EXT, }, {0x00, 0x7C, 0x00, M6800|M68HC11}, + "inc", {DIR, REGX }, {0x00, 0x00, 0x6C, M6800|M68HC11}, + "inc", {DIR, REGY }, {0x18, 0x00, 0x6C, M68HC11}, + "inca", {INH, }, {0x00, 0x4C, 0x00, M6800|M68HC11}, + "incb", {INH, }, {0x00, 0x5C, 0x00, M6800|M68HC11}, + "ins", {INH, }, {0x00, 0x31, 0x00, M6800|M68HC11}, + "incs", {INH, }, {0x00, 0x31, 0x00, M6800|M68HC11}, /* ins */ + "inx", {INH, }, {0x00, 0x08, 0x00, M6800|M68HC11}, + "incx", {INH, }, {0x00, 0x08, 0x00, M6800|M68HC11}, /* inx */ + "iny", {INH, }, {0x18, 0x08, 0x00, M68HC11}, + "incy", {INH, }, {0x18, 0x08, 0x00, M68HC11}, /* iny */ + "jmp", {EXT, }, {0x00, 0x7E, 0x00, M6800|M68HC11}, + "jmp", {DIR, REGX }, {0x00, 0x00, 0x6E, M6800|M68HC11}, + "jmp", {DIR, REGY }, {0x18, 0x00, 0x6E, M68HC11}, + "jsr", {ADDR, }, {0x00, 0xBD, 0x9D, M6800|M68HC11}, + "jsr", {DIR, REGX }, {0x00, 0x00, 0xAD, M6800|M68HC11}, + "jsr", {DIR, REGY }, {0x18, 0x00, 0xAD, M68HC11}, + "call", {ADDR, }, {0x00, 0xBD, 0x9D, M6800|M68HC11}, /* jsr */ + "call", {DIR, REGX }, {0x00, 0x00, 0xAD, M6800|M68HC11}, /* jsr */ + "call", {DIR, REGY }, {0x18, 0x00, 0xAD, M68HC11}, /* jsr */ + "lda", {IMM, }, {0x00, 0x86, 0x00, M6800|M68HC11}, + "lda", {ADDR, }, {0x00, 0xB6, 0x96, M6800|M68HC11}, + "lda", {DIR, REGX }, {0x00, 0x00, 0xA6, M6800|M68HC11}, + "lda", {DIR, REGY }, {0x18, 0x00, 0xA6, M68HC11}, + "ldaa", {IMM, }, {0x00, 0x86, 0x00, M6800|M68HC11}, + "ldaa", {ADDR, }, {0x00, 0xB6, 0x96, M6800|M68HC11}, + "ldaa", {DIR, REGX }, {0x00, 0x00, 0xA6, M6800|M68HC11}, + "ldaa", {DIR, REGY }, {0x18, 0x00, 0xA6, M68HC11}, + "ldb", {IMM, }, {0x00, 0xC6, 0x00, M6800|M68HC11}, + "ldb", {ADDR, }, {0x00, 0xF6, 0xD6, M6800|M68HC11}, + "ldb", {DIR, REGX }, {0x00, 0x00, 0xE6, M6800|M68HC11}, + "ldb", {DIR, REGY }, {0x18, 0x00, 0xE6, M68HC11}, + "ldab", {IMM, }, {0x00, 0xC6, 0x00, M6800|M68HC11}, + "ldab", {ADDR, }, {0x00, 0xF6, 0xD6, M6800|M68HC11}, + "ldab", {DIR, REGX }, {0x00, 0x00, 0xE6, M6800|M68HC11}, + "ldab", {DIR, REGY }, {0x18, 0x00, 0xE6, M68HC11}, + "ldd", {IMM16, }, {0x00, 0xCC, 0x00, M68HC11}, + "ldd", {ADDR, }, {0x00, 0xFC, 0xDC, M68HC11}, + "ldd", {DIR, REGX }, {0x00, 0x00, 0xEC, M68HC11}, + "ldd", {DIR, REGY }, {0x18, 0x00, 0xEC, M68HC11}, + "lds", {IMM16, }, {0x00, 0x8E, 0x00, M6800|M68HC11}, + "lds", {ADDR, }, {0x00, 0xBE, 0x9E, M6800|M68HC11}, + "lds", {DIR, REGX }, {0x00, 0x00, 0xAE, M6800|M68HC11}, + "lds", {DIR, REGY }, {0x18, 0x00, 0xAE, M68HC11}, + "ldx", {IMM16, }, {0x00, 0xCE, 0x00, M6800|M68HC11}, + "ldx", {ADDR, }, {0x00, 0xFE, 0xDE, M6800|M68HC11}, + "ldx", {DIR, REGX }, {0x00, 0x00, 0xEE, M6800|M68HC11}, + "ldx", {DIR, REGY }, {0xCD, 0x00, 0xEE, M68HC11}, + "ldy", {IMM16, }, {0x18, 0xCE, 0x00, M68HC11}, + "ldy", {ADDR, }, {0x18, 0xFE, 0xDE, M68HC11}, + "ldy", {DIR, REGX }, {0x1A, 0x00, 0xEE, M68HC11}, + "ldy", {DIR, REGY }, {0x18, 0x00, 0xEE, M68HC11}, + "lsl", {EXT, }, {0x00, 0x78, 0x00, M6800|M68HC11}, + "lsl", {DIR, REGX }, {0x00, 0x00, 0x68, M6800|M68HC11}, + "lsl", {DIR, REGY }, {0x18, 0x00, 0x68, M68HC11}, + "lsla", {INH, }, {0x00, 0x48, 0x00, M6800|M68HC11}, + "lslb", {INH, }, {0x00, 0x58, 0x00, M6800|M68HC11}, + "lsld", {INH, }, {0x00, 0x05, 0x00, M68HC11}, + "lsr", {EXT, }, {0x00, 0x74, 0x00, M6800|M68HC11}, + "lsr", {DIR, REGX }, {0x00, 0x00, 0x64, M6800|M68HC11}, + "lsr", {DIR, REGY }, {0x18, 0x00, 0x64, M68HC11}, + "lsra", {INH, }, {0x00, 0x44, 0x00, M6800|M68HC11}, + "lsrb", {INH, }, {0x00, 0x54, 0x00, M6800|M68HC11}, + "lsrd", {INH, }, {0x00, 0x04, 0x00, M68HC11}, + "mul", {INH, }, {0x00, 0x3D, 0x00, M68HC11}, + "neg", {EXT, }, {0x00, 0x70, 0x00, M6800|M68HC11}, + "neg", {DIR, REGX }, {0x00, 0x00, 0x60, M6800|M68HC11}, + "neg", {DIR, REGY }, {0x18, 0x00, 0x60, M68HC11}, + "nega", {INH, }, {0x00, 0x40, 0x00, M6800|M68HC11}, + "negb", {INH, }, {0x00, 0x50, 0x00, M6800|M68HC11}, + "nop", {INH, }, {0x00, 0x01, 0x00, M6800|M68HC11}, + "oraa", {IMM, }, {0x00, 0x8A, 0x00, M6800|M68HC11}, + "oraa", {ADDR, }, {0x00, 0xBA, 0x9A, M6800|M68HC11}, + "oraa", {DIR, REGX }, {0x00, 0x00, 0xAA, M6800|M68HC11}, + "oraa", {DIR, REGY }, {0x18, 0x00, 0xAA, M68HC11}, + "orab", {IMM, }, {0x00, 0xCA, 0x00, M6800|M68HC11}, + "orab", {ADDR, }, {0x00, 0xFA, 0xDA, M6800|M68HC11}, + "orab", {DIR, REGX }, {0x00, 0x00, 0xEA, M6800|M68HC11}, + "orab", {DIR, REGY }, {0x18, 0x00, 0xEA, M68HC11}, + "psha", {INH, }, {0x00, 0x36, 0x00, M6800|M68HC11}, + "pusha",{INH, }, {0x00, 0x36, 0x00, M6800|M68HC11}, /* psha */ + "pshb", {INH, }, {0x00, 0x37, 0x00, M6800|M68HC11}, + "pushb",{INH, }, {0x00, 0x37, 0x00, M6800|M68HC11}, /* pshb */ + "pshx", {INH, }, {0x00, 0x3C, 0x00, M68HC11}, + "pushx",{INH, }, {0x00, 0x3C, 0x00, M68HC11}, /* pshx */ + "pshy", {INH, }, {0x18, 0x3C, 0x00, M68HC11}, + "pushy", {INH, }, {0x18, 0x3C, 0x00, M68HC11}, /* pshy */ + "pula", {INH, }, {0x00, 0x32, 0x00, M6800|M68HC11}, + "popa", {INH, }, {0x00, 0x32, 0x00, M6800|M68HC11}, /* pula */ + "pulb", {INH, }, {0x00, 0x33, 0x00, M6800|M68HC11}, + "popb", {INH, }, {0x00, 0x33, 0x00, M6800|M68HC11}, /* pulb */ + "pulx", {INH, }, {0x00, 0x38, 0x00, M68HC11}, + "popx", {INH, }, {0x00, 0x38, 0x00, M68HC11}, /* pulx */ + "puly", {INH, }, {0x18, 0x38, 0x00, M68HC11}, + "popy", {INH, }, {0x18, 0x38, 0x00, M68HC11}, /* puly */ + "rol", {EXT, }, {0x00, 0x79, 0x00, M6800|M68HC11}, + "rol", {DIR, REGX }, {0x00, 0x00, 0x69, M6800|M68HC11}, + "rol", {DIR, REGY }, {0x18, 0x00, 0x69, M68HC11}, + "rola", {INH, }, {0x00, 0x49, 0x00, M6800|M68HC11}, + "rolb", {INH, }, {0x00, 0x59, 0x00, M6800|M68HC11}, + "ror", {EXT, }, {0x00, 0x76, 0x00, M6800|M68HC11}, + "ror", {DIR, REGX }, {0x00, 0x00, 0x66, M6800|M68HC11}, + "ror", {DIR, REGY }, {0x18, 0x00, 0x66, M68HC11}, + "rora", {INH, }, {0x00, 0x46, 0x00, M6800|M68HC11}, + "rorb", {INH, }, {0x00, 0x56, 0x00, M6800|M68HC11}, + "rti", {INH, }, {0x00, 0x3B, 0x00, M6800|M68HC11}, + "reti", {INH, }, {0x00, 0x3B, 0x00, M6800|M68HC11}, /* rti */ + "rts", {INH, }, {0x00, 0x39, 0x00, M6800|M68HC11}, + "ret", {INH, }, {0x00, 0x39, 0x00, M6800|M68HC11}, /* rts */ + "sba", {INH, }, {0x00, 0x10, 0x00, M6800|M68HC11}, + "sbca", {IMM, }, {0x00, 0x82, 0x00, M6800|M68HC11}, + "sbca", {ADDR, }, {0x00, 0xB2, 0x92, M6800|M68HC11}, + "sbca", {DIR, REGX }, {0x00, 0x00, 0xA2, M6800|M68HC11}, + "sbca", {DIR, REGY }, {0x18, 0x00, 0xA2, M68HC11}, + "sbcb", {IMM, }, {0x00, 0xC2, 0x00, M6800|M68HC11}, + "sbcb", {ADDR, }, {0x00, 0xF2, 0xD2, M6800|M68HC11}, + "sbcb", {DIR, REGX }, {0x00, 0x00, 0xE2, M6800|M68HC11}, + "sbcb", {DIR, REGY }, {0x18, 0x00, 0xE2, M68HC11}, + "sec", {INH, }, {0x00, 0x0D, 0x00, M6800|M68HC11}, + "sei", {INH, }, {0x00, 0x0F, 0x00, M6800|M68HC11}, + "di", {INH, }, {0x00, 0x0F, 0x00, M6800|M68HC11}, /* sei */ + "sev", {INH, }, {0x00, 0x0B, 0x00, M6800|M68HC11}, + "staa", {ADDR, }, {0x00, 0xB7, 0x97, M6800|M68HC11}, + "staa", {DIR, REGX }, {0x00, 0x00, 0xA7, M6800|M68HC11}, + "staa", {DIR, REGY }, {0x18, 0x00, 0xA7, M68HC11}, + "stab", {ADDR, }, {0x00, 0xF7, 0xD7, M6800|M68HC11}, + "stab", {DIR, REGX }, {0x00, 0x00, 0xE7, M6800|M68HC11}, + "stab", {DIR, REGY }, {0x18, 0x00, 0xE7, M68HC11}, + "std", {ADDR, }, {0x00, 0xFD, 0xDD, M68HC11}, + "std", {DIR, REGX }, {0x00, 0x00, 0xED, M68HC11}, + "std", {DIR, REGY }, {0x18, 0x00, 0xED, M68HC11}, + "stop", {INH, }, {0x00, 0xCF, 0x00, M68HC11}, + "sts", {ADDR, }, {0x00, 0xBF, 0x9F, M6800|M68HC11}, + "sts", {DIR, REGX }, {0x00, 0x00, 0xAF, M6800|M68HC11}, + "sts", {DIR, REGY }, {0x18, 0x00, 0xAF, M68HC11}, + "stx", {ADDR, }, {0x00, 0xFF, 0xDF, M6800|M68HC11}, + "stx", {DIR, REGX }, {0x00, 0x00, 0xEF, M6800|M68HC11}, + "stx", {DIR, REGY }, {0xCD, 0x00, 0xEF, M68HC11}, + "sty", {ADDR, }, {0x18, 0xFF, 0xDF, M68HC11}, + "sty", {DIR, REGX }, {0x1A, 0x00, 0xEF, M68HC11}, + "sty", {DIR, REGY }, {0x18, 0x00, 0xEF, M68HC11}, + "suba", {IMM, }, {0x00, 0x80, 0x00, M6800|M68HC11}, + "suba", {ADDR, }, {0x00, 0xB0, 0x90, M6800|M68HC11}, + "suba", {DIR, REGX }, {0x00, 0x00, 0xA0, M6800|M68HC11}, + "suba", {DIR, REGY }, {0x18, 0x00, 0xA0, M68HC11}, + "subb", {IMM, }, {0x00, 0xC0, 0x00, M6800|M68HC11}, + "subb", {ADDR, }, {0x00, 0xF0, 0xD0, M6800|M68HC11}, + "subb", {DIR, REGX }, {0x00, 0x00, 0xE0, M6800|M68HC11}, + "subb", {DIR, REGY }, {0x18, 0x00, 0xE0, M68HC11}, + "subd", {IMM16, }, {0x00, 0x83, 0x00, M68HC11}, + "subd", {ADDR, }, {0x00, 0xB3, 0x93, M68HC11}, + "subd", {DIR, REGX }, {0x00, 0x00, 0xA3, M68HC11}, + "subd", {DIR, REGY }, {0x18, 0x00, 0xA3, M68HC11}, + "swi", {INH, }, {0x00, 0x3F, 0x00, M6800|M68HC11}, + "tab", {INH, }, {0x00, 0x16, 0x00, M6800|M68HC11}, + "tap", {INH, }, {0x00, 0x06, 0x00, M6800|M68HC11}, + "tba", {INH, }, {0x00, 0x17, 0x00, M6800|M68HC11}, + "test", {INH, }, {0x00, 0x00, 0x00, M68HC11}, + "tpa", {INH, }, {0x00, 0x07, 0x00, M6800|M68HC11}, + "tst", {EXT, }, {0x00, 0x7D, 0x00, M6800|M68HC11}, + "tst", {DIR, REGX }, {0x00, 0x00, 0x6D, M6800|M68HC11}, + "tst", {DIR, REGY }, {0x18, 0x00, 0x6D, M68HC11}, + "tsta", {INH, }, {0x00, 0x4D, 0x00, M6800|M68HC11}, + "tstb", {INH, }, {0x00, 0x5D, 0x00, M6800|M68HC11}, + "tsx", {INH, }, {0x00, 0x30, 0x00, M6800|M68HC11}, + "tsy", {INH, }, {0x18, 0x30, 0x00, M68HC11}, + "txs", {INH, }, {0x00, 0x35, 0x00, M6800|M68HC11}, + "tys", {INH, }, {0x18, 0x35, 0x00, M68HC11}, + "wai", {INH, }, {0x00, 0x3E, 0x00, M6800|M68HC11}, + "xgdx", {INH, }, {0x00, 0x8F, 0x00, M68HC11}, + "xgdy", {INH, }, {0x18, 0x8F, 0x00, M68HC11}, diff --git a/cpus/arm/cpu.c b/cpus/arm/cpu.c index cfc0472..514b165 100644 --- a/cpus/arm/cpu.c +++ b/cpus/arm/cpu.c @@ -1,6 +1,6 @@ /* ** cpu.c ARM cpu-description file -** (c) in 2004,2006,2010 by Frank Wille +** (c) in 2004,2006,2010,2011,2014-2015 by Frank Wille */ #include "vasm.h" @@ -10,12 +10,12 @@ mnemonic mnemonics[] = { }; int mnemonic_cnt = sizeof(mnemonics)/sizeof(mnemonics[0]); -char *cpu_copyright = "vasm ARM cpu backend 0.2d (c) 2004,2006,2010 Frank Wille"; +char *cpu_copyright = "vasm ARM cpu backend 0.4a (c) 2004,2006,2010,2011,2014-2015 Frank Wille"; char *cpuname = "ARM"; int bitsperbyte = 8; int bytespertaddr = 4; -unsigned long cpu_type = AAANY; +uint32_t cpu_type = AAANY; int arm_be_mode = 0; /* Little-endian is default */ int thumb_mode = 0; /* 1: Thumb instruction set (16 bit) is active */ @@ -29,11 +29,13 @@ static const char *condition_codes = "eqnecsccmiplvsvchilsgeltgtlealnvhsloul"; static const char *addrmode_strings[] = { "da","ia","db","ib", "fa","fd","ea","ed", - "bt","tb","sb","sh","t","b","h","s","l",NULL,"" + "bt","tb","sb","sh","t","b","h","s","l", + "p",NULL,"" }; enum { AM_DA=0,AM_IA,AM_DB,AM_IB,AM_FA,AM_FD,AM_EA,AM_ED, - AM_BT,AM_TB,AM_SB,AM_SH,AM_T,AM_B,AM_H,AM_S,AM_L,AM_NULL,AM_NONE + AM_BT,AM_TB,AM_SB,AM_SH,AM_T,AM_B,AM_H,AM_S,AM_L, + AM_P,AM_NULL,AM_NONE }; #define NUM_SHIFTTYPES 6 @@ -43,7 +45,6 @@ static const char *shift_strings[NUM_SHIFTTYPES] = { static int OC_SWP,OC_NOP; static int elfoutput = 0; /* output will be an ELF object file */ -static hashtable *regsymhash; /* hash-table for ARM register symbols */ static section *last_section = 0; static int last_data_type = -1; /* for mapping symbol generation */ @@ -62,21 +63,9 @@ operand *new_operand(void) } -static int addregsym(char *sym,int val) -/* add a new register symbol, return 0 if already exists */ +int cpu_available(int idx) { - hashdata data; - regsym *new; - - if (find_name_nc(regsymhash,sym,&data)) - return 0; - - data.ptr = new = mymalloc(sizeof(regsym)); - new->name = mymalloc(strlen(sym)+1); - strcpy(new->name,sym); - new->value = val; - add_hashentry(regsymhash,new->name,data); - return 1; + return (mnemonics[idx].ext.available & cpu_type) != 0; } @@ -119,12 +108,14 @@ char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len, else { /* ARM mode - we might have up to 2 different qualifiers */ int len = s - inst; + char c = tolower((unsigned char)*inst); if (len > 2) { - if (*inst=='b' && strncmp(inst,"bic",3) && (len==3 || len==4)) { + if (c=='b' && strnicmp(inst,"bic",3) && (len==3 || len==4)) { *inst_len = len - 2; } - else if ((*inst=='u' || *inst=='s') && *(inst+1)=='m' && len>=5) { + else if ((c=='u' || c=='s') && + tolower((unsigned char)*(inst+1))=='m' && len>=5) { *inst_len = 5; } else @@ -138,7 +129,7 @@ char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len, const char *cc = condition_codes; while (*cc) { - if (*p==*cc && *(p+1)==*(cc+1)) + if (!strnicmp(p,cc,2)) break; cc += 2; } @@ -153,12 +144,12 @@ char *parse_instruction(char *s,int *inst_len,char **ext,int *ext_len, const char **am = addrmode_strings; do { - if (len==strlen(*am) && !strncmp(*am,p,len)) + if (len==strlen(*am) && !strnicmp(*am,p,len)) break; am++; } while (*am); - if (*am!=NULL || (len==1 && *p=='s')) { + if (*am!=NULL || (len==1 && tolower((unsigned char)*p)=='s')) { ext[cnt] = p; ext_len[cnt++] = len; } @@ -187,19 +178,17 @@ int set_default_qualifiers(char **q,int *q_len) static int parse_reg(char **pp) /* parse register, return -1 on error */ { - hashdata data; char *p = *pp; char *name = p; + regsym *sym; if (ISIDSTART(*p)) { p++; while (ISIDCHAR(*p)) p++; - if (find_namelen_nc(regsymhash,name,p-name,&data)) { - regsym *sym = data.ptr; - + if (sym = find_regsym_nc(name,p-name)) { *pp = p; - return sym->value; + return sym->reg_num; } } return -1; /* no valid register found */ @@ -209,7 +198,6 @@ static int parse_reg(char **pp) static int parse_reglist(char **pp) /* parse register-list, return -1 on error */ { - hashdata data; int r=0,list=0,lastreg=-1; char *p = *pp; char *name; @@ -223,13 +211,12 @@ static int parse_reglist(char **pp) name = p++; while (ISIDCHAR(*p)) p++; - if (find_namelen_nc(regsymhash,name,p-name,&data)) { - sym = data.ptr; - r = sym->value; + if (sym = find_regsym_nc(name,p-name)) { + r = sym->reg_num; if (lastreg >= 0) { /* range-mode? */ if (lastreg < r) { r = lastreg; - lastreg = sym->value; + lastreg = sym->reg_num; } for (; r<=lastreg; list |= 1<value = NULL; p = skip(p); - if (thumb_mode) { + if (optype == DATA64_OP) { + op->value = parse_expr_huge(&p); + } + + else if (thumb_mode) { if (ARMOPER(optype)) { /* standard ARM instruction */ return PO_NOMATCH; } @@ -540,18 +531,6 @@ int parse_operand(char *p,int len,operand *op,int optype) } -static void addmaskedreloc(rlist **relocs,symbol *sym,taddr addend, - int type,int offs,int size,taddr mask) -{ - rlist *rl; - nreloc *r; - - rl = add_reloc(relocs,sym,addend,type,size,offs); - r = rl->reloc; - r->mask = mask; -} - - static void create_mapping_symbol(int type,section *sec,taddr pc) /* create mapping symbol ($a, $t, $d) as required by ARM ELF ABI */ { @@ -577,19 +556,17 @@ static void create_mapping_symbol(int type,section *sec,taddr pc) } -taddr eval_thumb_operands(instruction *ip,section *sec,taddr pc, - unsigned short *insn,dblock *db) +size_t eval_thumb_operands(instruction *ip,section *sec,taddr pc, + uint16_t *insn,dblock *db) /* evaluate expressions and try to optimize THUMB instruction, return size of instruction */ { operand op; mnemonic *mnemo = &mnemonics[ip->code]; int opcnt = 0; - taddr isize = 2; + size_t isize = 2; if (insn) { - if (!(mnemo->ext.available & cpu_type)) - cpu_error(0); /* instruction not supported on selected architecture */ if (pc & 1) cpu_error(27); /* instruction at unaligned address */ @@ -601,23 +578,24 @@ taddr eval_thumb_operands(instruction *ip,section *sec,taddr pc, return 2; } else - *insn = (unsigned short)mnemo->ext.opcode; + *insn = (uint16_t)mnemo->ext.opcode; } - for (opcnt=0; ip->op[opcnt]!=NULL && opcntop[opcnt]!=NULL; opcnt++) { taddr val; symbol *base = NULL; + int btype; op = *(ip->op[opcnt]); if (!eval_expr(op.value,&val,sec,pc)) - base = find_base(op.value,sec,pc); + btype = find_base(op.value,&base,sec,pc); /* do optimizations first */ if (op.type==TPCLW || THBRANCH(op.type)) { /* PC-relative offsets (take prefetch into account: PC+4) */ - if (base) { - if (base->type==LABSYM && base->sec==sec) { + if (base!=NULL && btype==BASE_OK) { + if (!is_pc_reloc(base,sec)) { /* no relocation required, can be resolved immediately */ if (op.type == TPCLW) { /* bit 1 of PC is forced to 0 */ @@ -654,15 +632,15 @@ taddr eval_thumb_operands(instruction *ip,section *sec,taddr pc, if (op.type == TBRHL) { val -= THB_PREFETCH; if (db) { - addmaskedreloc(&db->relocs,base,val,REL_PC,16+5,11,0xffe); - addmaskedreloc(&db->relocs,base,val,REL_PC,5,11,0x7ff000); + add_nreloc_masked(&db->relocs,base,val,REL_PC,11,16+5,0xffe); + add_nreloc_masked(&db->relocs,base,val,REL_PC,11,5,0x7ff000); } } else if (op.type == TPCLW) { /* val -= THB_PREFETCH; @@@ only positive offsets allowed! */ op.type = TUIMA; if (db) - addmaskedreloc(&db->relocs,base,val,REL_PC,8,8,0x3fc); + add_nreloc_masked(&db->relocs,base,val,REL_PC,8,8,0x3fc); base = NULL; /* no more checks */ } else if (insn) @@ -784,12 +762,16 @@ taddr eval_thumb_operands(instruction *ip,section *sec,taddr pc, } if (base!=NULL && db!=NULL) { - if (op.type==TUIM5 || op.type==TUI5I) - addmaskedreloc(&db->relocs,base,val,REL_ABS,5,5,0x1f); - else if (op.type == TSWI8) - addmaskedreloc(&db->relocs,base,val,REL_ABS,8,8,0xff); + if (btype == BASE_OK) { + if (op.type==TUIM5 || op.type==TUI5I) + add_nreloc_masked(&db->relocs,base,val,REL_ABS,5,5,0x1f); + else if (op.type == TSWI8) + add_nreloc_masked(&db->relocs,base,val,REL_ABS,8,8,0xff); + else + cpu_error(6); /* constant integer expression required */ + } else - cpu_error(6); /* constant integer expression required */ + general_error(38); /* illegal relocation */ } } @@ -830,11 +812,11 @@ taddr eval_thumb_operands(instruction *ip,section *sec,taddr pc, #define ROTFAIL (0xffffff) -static unsigned long rotated_immediate(unsigned long val) +static uint32_t rotated_immediate(uint32_t val) /* check if a 32-bit value can be represented as 8-bit-rotated, return ROTFAIL when impossible */ { - unsigned long i,a; + uint32_t i,a; for (i=0; i<32; i+=2) { if ((a = val<>(32-i)) <= 0xff) @@ -844,14 +826,14 @@ static unsigned long rotated_immediate(unsigned long val) } -static int negated_rot_immediate(unsigned long val,mnemonic *mnemo, - unsigned long *insn) +static int negated_rot_immediate(uint32_t val,mnemonic *mnemo, + uint32_t *insn) /* check if negating the ALU-operation makes a valid 8-bit-rotated value, insert it into the current instruction, when successful */ { - unsigned long neg = rotated_immediate(-val); - unsigned long inv = rotated_immediate(~val); - unsigned long op = (mnemo->ext.opcode & 0x01e00000) >> 21; + uint32_t neg = rotated_immediate(-val); + uint32_t inv = rotated_immediate(~val); + uint32_t op = (mnemo->ext.opcode & 0x01e00000) >> 21; switch (op) { /* AND <-> BIC */ @@ -884,11 +866,11 @@ static int negated_rot_immediate(unsigned long val,mnemonic *mnemo, } -static unsigned long double_rot_immediate(unsigned long val,unsigned long *hi) +static uint32_t double_rot_immediate(uint32_t val,uint32_t *hi) /* check if a 32-bit value can be represented by combining two 8-bit rotated values, return ROTFAIL otherwise */ { - unsigned long i,a; + uint32_t i,a; for (i=0; i<32; i+=2) { if (((a = val<>(32-i)) & 0xff) != 0) { @@ -915,7 +897,7 @@ static unsigned long double_rot_immediate(unsigned long val,unsigned long *hi) } -static unsigned long calc_2nd_rot_opcode(unsigned long op) +static uint32_t calc_2nd_rot_opcode(uint32_t op) /* calculates ALU operation for second instruction */ { if (op == 13) @@ -928,16 +910,16 @@ static unsigned long calc_2nd_rot_opcode(unsigned long op) } -static int negated_double_rot_immediate(unsigned long val,unsigned long *insn) +static int negated_double_rot_immediate(uint32_t val,uint32_t *insn) /* check if negating the ALU-operation and/or a second ADD/SUB operation makes a valid 8-bit-rotated value, insert it into the current instruction, when successful */ { - unsigned long op = (*insn & 0x01e00000) >> 21; + uint32_t op = (*insn & 0x01e00000) >> 21; if ((op==2 || op==4 || op==13 || op==15) && insn!=NULL) { /* combined instructions only possible for ADD/SUB/MOV/MVN */ - unsigned long lo,hi; + uint32_t lo,hi; *(insn+1) = *insn & ~0x01ef0000; *(insn+1) |= (*insn&0xf000) << 4; /* Rn = Rd of first instruction */ @@ -955,17 +937,17 @@ static int negated_double_rot_immediate(unsigned long val,unsigned long *insn) } -static unsigned long get_condcode(instruction *ip) +static uint32_t get_condcode(instruction *ip) /* returns condition (bit 31-28) from instruction's qualifiers */ { const char *cc = condition_codes; char *q; if (q = ip->qualifiers[0]) { - unsigned long code = 0; + uint32_t code = 0; while (*cc) { - if (*q==*cc && *(q+1)==*(cc+1) && *(q+2)=='\0') + if (!strnicmp(q,cc,2) && *(q+2)=='\0') break; cc += 2; code++; @@ -997,7 +979,7 @@ static int get_addrmode(instruction *ip) int mode = AM_DA; do { - if (!strcmp(*am,q)) + if (!stricmp(*am,q)) break; am++; mode++; @@ -1012,8 +994,8 @@ static int get_addrmode(instruction *ip) } -taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, - unsigned long *insn,dblock *db) +size_t eval_arm_operands(instruction *ip,section *sec,taddr pc, + uint32_t *insn,dblock *db) /* evaluate expressions and try to optimize ARM instruction, return size of instruction */ { @@ -1022,20 +1004,23 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, int am = get_addrmode(ip); int aa4ldst = 0; int opcnt = 0; - taddr isize = 4; + size_t isize = 4; taddr chkreg = -1; if (insn) { - if (!(mnemo->ext.available & cpu_type)) - cpu_error(0); /* instruction not supported on selected architecture */ if (pc & 3) cpu_error(27); /* instruction at unaligned address */ *insn = mnemo->ext.opcode | get_condcode(ip); - if (mnemo->ext.flags & SETCC) { - if (am == AM_S) - *insn |= 0x00100000; /* set-condition-codes flag */ + if ((mnemo->ext.flags & SETCC)!=0 && am==AM_S) + *insn |= 0x00100000; /* set-condition-codes flag */ + + if ((mnemo->ext.flags & SETPSR)!=0 && am==AM_P) { + /* Rd = R15 for changing the PSR. Recommended for ARM2/250/3 only. */ + *insn |= 0x0000f000; + if (cpu_type & ~AA2) + cpu_error(28); /* deprecated on 32-bit architectures */ } if (!strcmp(mnemo->name,"ldr") || !strcmp(mnemo->name,"str")) { @@ -1050,7 +1035,9 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, else if (am==AM_SB || am==AM_H || am==AM_SH) { /* arch.4 ldr/str */ if (cpu_type & AA4UP) { /* take P-, I- and L-bit from previous standard instruction */ - *insn = (*insn&0xf1100000) | ((*insn&0x02000000)>>3) | 0x90; + *insn = (*insn&0xf1100000) + | (((*insn&0x02000000)^0x02000000)>>3) /* I-bit is flipped */ + | 0x90; if (am != AM_H) { if (*insn & 0x00100000) /* load */ *insn |= 0x40; /* signed transfer */ @@ -1079,21 +1066,22 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, aa4ldst = 1; } - for (opcnt=0; ip->op[opcnt]!=NULL && opcntop[opcnt]!=NULL; opcnt++) { taddr val; symbol *base = NULL; + int btype; op = *(ip->op[opcnt]); if (!eval_expr(op.value,&val,sec,pc)) - base = find_base(op.value,sec,pc); + btype = find_base(op.value,&base,sec,pc); /* do optimizations first */ if (op.type==PCL12 || op.type==PCLRT || op.type==PCLCP || op.type==BRA24) { /* PC-relative offsets (take prefetch into account: PC+8) */ - if (base) { - if (base->type==LABSYM && base->sec==sec) { + if (base!=NULL && btype==BASE_OK) { + if (!is_pc_reloc(base,sec)) { /* no relocation required, can be resolved immediately */ val -= pc + 8; @@ -1110,6 +1098,10 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, if ((!aa4ldst && val<0x1000 && val>-0x1000) || (aa4ldst && val<0x100 && val>-0x100)) { op.type = IMUD2; /* handle as normal #+/-Imm12 */ + if (val < 0) + val = -val; + else + op.flags |= OFL_UP; base = NULL; /* no more checks */ } else { @@ -1141,10 +1133,11 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, *(insn+1) |= (*insn & 0xf000) << 4; insn++; } - if (aa4ldst) - val = (val<0) ? -((-val)&0xff) : (val&0xff); + if (val < 0) + val = -val; else - val = (val<0) ? -((-val)&0xfff) : (val&0xfff); + op.flags |= OFL_UP; + val = aa4ldst ? (val & 0xff) : (val & 0xfff); isize += 4; op.type = IMUD2; base = NULL; /* no more checks */ @@ -1160,6 +1153,10 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, case PCLCP: if (val<0x400 && val>-0x400) { op.type = IMCP2; /* handle as normal #+/-Imm10>>2 */ + if (val < 0) + val = -val; + else + op.flags |= OFL_UP; base = NULL; /* no more checks */ } else { @@ -1184,7 +1181,7 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, } else if (opt_adr || am==AM_L) { /* ADRL or optimize ADR automatically to ADRL */ - unsigned long hi,lo; + uint32_t hi,lo; isize += 4; if ((lo = double_rot_immediate(val,&hi)) != ROTFAIL) { @@ -1198,10 +1195,10 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, } } else if (insn) - cpu_error(5,(unsigned long)val); /* Cannot make rot.immed.*/ + cpu_error(5,(uint32_t)val); /* Cannot make rot.immed.*/ } else if (insn) - cpu_error(5,(unsigned long)val); /* Cannot make rot.immed.*/ + cpu_error(5,(uint32_t)val); /* Cannot make rot.immed.*/ break; default: @@ -1214,13 +1211,13 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, case BRA24: val -= ARM_PREFETCH; if (db) - addmaskedreloc(&db->relocs,base,val,REL_PC,8,24,0x3fffffc); + add_nreloc_masked(&db->relocs,base,val,REL_PC,24,8,0x3fffffc); break; case PCL12: op.type = IMUD2; if (db) { if (val<0x1000 && val>-0x1000) { - addmaskedreloc(&db->relocs,base,val,REL_PC,20,12,0x1fff); + add_nreloc_masked(&db->relocs,base,val,REL_PC,12,20,0x1fff); base = NULL; /* don't add another REL_ABS below */ } else @@ -1238,13 +1235,13 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, if (insn!=NULL && db!=NULL) { *(insn+1) = *insn & ~0xf0000; *(insn+1) |= (*insn&0xf000) << 4; - addmaskedreloc(&db->relocs,base,val,REL_PC,24,8,0xff00); - addmaskedreloc(&db->relocs,base,val,REL_PC,32+24,8,0xff); + add_nreloc_masked(&db->relocs,base,val,REL_PC,8,24,0xff00); + add_nreloc_masked(&db->relocs,base,val,REL_PC,8,32+24,0xff); } } else if (val == 0) { /* ADR */ if (db) - addmaskedreloc(&db->relocs,base,val,REL_PC,24,8,0xff); + add_nreloc_masked(&db->relocs,base,val,REL_PC,8,24,0xff); } else if (db) cpu_error(22); /* operation not allowed on external symbols */ @@ -1261,10 +1258,11 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, } else if (op.type == IMROT) { + op.type = NOOP; /* is handled here */ + if (base == NULL) { - unsigned long rotval; + uint32_t rotval; - op.type = NOOP; /* is handled here */ if ((rotval = rotated_immediate(val)) != ROTFAIL) { if (insn) *insn |= rotval; @@ -1274,7 +1272,7 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, isize += 4; if (insn) { if (!negated_double_rot_immediate(val,insn)) - cpu_error(7,(unsigned long)val); /* const not suitable */ + cpu_error(7,(uint32_t)val); /* const not suitable */ } } } @@ -1363,17 +1361,21 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, *insn |= 0x00800000; /* set UP-flag */ if (base) { - if (base->type == IMPORT) { - if (!aa4ldst) { - /* @@@ does this make any sense? */ - *insn |= 0x00800000; /* only UP */ - addmaskedreloc(&db->relocs,base,val,REL_ABS,20,12,0xfff); + if (btype == BASE_OK) { + if (EXTREF(base)) { + if (!aa4ldst) { + /* @@@ does this make any sense? */ + *insn |= 0x00800000; /* only UP */ + add_nreloc_masked(&db->relocs,base,val,REL_ABS,12,20,0xfff); + } + else + cpu_error(22); /* operation not allowed on external symbols */ } else - cpu_error(22); /* operation not allowed on external symbols */ + cpu_error(6); /* constant integer expression required */ } else - cpu_error(6); /* constant integer expression required */ + general_error(38); /* illegal relocation */ } } @@ -1402,7 +1404,7 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, if (val>=0 && val<0x1000000) { *insn |= val; if (base!=NULL && db!=NULL) - addmaskedreloc(&db->relocs,base,val,REL_ABS,8,24,0xffffff); + add_nreloc_masked(&db->relocs,base,val,REL_ABS,24,8,0xffffff); } else cpu_error(16); /* 24-bit unsigned immediate expected */ @@ -1498,7 +1500,7 @@ taddr eval_arm_operands(instruction *ip,section *sec,taddr pc, } -taddr instruction_size(instruction *ip,section *sec,taddr pc) +size_t instruction_size(instruction *ip,section *sec,taddr pc) /* Calculate the size of the current instruction; must be identical to the data created by eval_instruction. */ { @@ -1524,7 +1526,7 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) inst_type = (mnemonics[ip->code].ext.flags & THUMB) ? TYPE_THUMB : TYPE_ARM; if (inst_type == TYPE_THUMB) { - unsigned short insn[2]; + uint16_t insn[2]; if (db->size = eval_thumb_operands(ip,sec,pc,insn,db)) { unsigned char *d = db->data = mymalloc(db->size); @@ -1536,7 +1538,7 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) } else { /* ARM mode */ - unsigned long insn[2]; + uint32_t insn[2]; if (db->size = eval_arm_operands(ip,sec,pc,insn,db)) { unsigned char *d = db->data = mymalloc(db->size); @@ -1554,7 +1556,7 @@ dblock *eval_instruction(instruction *ip,section *sec,taddr pc) } -dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) +dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc) /* Create a dblock (with relocs, if necessary) for size bits of data. */ { dblock *db = new_dblock(); @@ -1565,35 +1567,46 @@ dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) last_data_type = -1; } - if ((bitsize & 7) || bitsize > 32) + if ((bitsize & 7) || bitsize > 64) cpu_error(17,bitsize); /* data size not supported */ - if (op->type != DATA_OP) + if (op->type!=DATA_OP && op->type!=DATA64_OP) ierror(0); db->size = bitsize >> 3; db->data = mymalloc(db->size); - if (!eval_expr(op->value,&val,sec,pc)) { - symbol *base = find_base(op->value,sec,pc); + if (op->type == DATA64_OP) { + thuge hval; - if (base) - add_reloc(&db->relocs,base,val,REL_ABS,bitsize,0); - else - cpu_error(28); /* illegal relocation */ + if (!eval_expr_huge(op->value,&hval)) + general_error(59); /* cannot evaluate huge integer */ + huge_to_mem(arm_be_mode,db->data,db->size,hval); } - - switch (db->size) { - case 1: - db->data[0] = val & 0xff; - break; - case 2: - case 4: - setval(arm_be_mode,db->data,db->size,val); - break; - default: - ierror(0); - break; + else { + if (!eval_expr(op->value,&val,sec,pc)) { + symbol *base; + int btype; + + btype = find_base(op->value,&base,sec,pc); + if (base) + add_nreloc(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS,bitsize,0); + else if (btype != BASE_NONE) + general_error(38); /* illegal relocation */ + } + switch (db->size) { + case 1: + db->data[0] = val & 0xff; + break; + case 2: + case 4: + setval(arm_be_mode,db->data,db->size,val); + break; + default: + ierror(0); + break; + } } if (last_data_type != TYPE_DATA) @@ -1619,33 +1632,32 @@ int init_cpu() elfoutput = 1; /* define register symbols */ - regsymhash = new_hashtable(REGSYMHTSIZE); for (i=0; i<16; i++) { sprintf(r,"r%d",i); - addregsym(r,i); + new_regsym(0,1,r,0,0,i); sprintf(r,"c%d",i); - addregsym(r,i); + new_regsym(0,1,r,0,0,i); sprintf(r,"p%d",i); - addregsym(r,i); + new_regsym(0,1,r,0,0,i); } /* ATPCS synonyms */ for (i=0; i<8; i++) { if (i < 4) { sprintf(r,"a%d",i+1); - addregsym(r,i); + new_regsym(0,1,r,0,0,i); } sprintf(r,"v%d",i+1); - addregsym(r,i+4); + new_regsym(0,1,r,0,0,i+4); } /* well known aliases */ - addregsym("wr",7); - addregsym("sb",9); - addregsym("sl",10); - addregsym("fp",11); - addregsym("ip",12); - addregsym("sp",13); - addregsym("lr",14); - addregsym("pc",15); + new_regsym(0,1,"wr",0,0,7); + new_regsym(0,1,"sb",0,0,9); + new_regsym(0,1,"sl",0,0,10); + new_regsym(0,1,"fp",0,0,11); + new_regsym(0,1,"ip",0,0,12); + new_regsym(0,1,"sp",0,0,13); + new_regsym(0,1,"lr",0,0,14); + new_regsym(0,1,"pc",0,0,15); return 1; } diff --git a/cpus/arm/cpu.h b/cpus/arm/cpu.h index fde1fd0..d9eab20 100644 --- a/cpus/arm/cpu.h +++ b/cpus/arm/cpu.h @@ -1,5 +1,5 @@ /* cpu.h ARM cpu-description header-file */ -/* (c) in 2004 by Frank Wille */ +/* (c) in 2004,2014 by Frank Wille */ #define LITTLEENDIAN (!arm_be_mode) #define BIGENDIAN (arm_be_mode) @@ -16,7 +16,8 @@ #define END_PARENTH(x) ((x)==')' || (x)=='}') /* data type to represent a target-address */ -typedef long taddr; +typedef int32_t taddr; +typedef uint32_t utaddr; /* minimum instruction alignment */ #define INST_ALIGN (thumb_mode ? 2 : 4) @@ -25,13 +26,16 @@ typedef long taddr; #define DATA_ALIGN(n) ((n)<=8 ? 1 : ((n)<=16 ? 2 : 4)) /* operand class for n-bit data definitions */ -#define DATA_OPERAND(n) DATA_OP +#define DATA_OPERAND(n) (n==64 ? DATA64_OP : DATA_OP) + +/* returns true when instruction is valid for selected cpu */ +#define MNEMONIC_VALID(i) cpu_available(i) /* type to store each operand */ typedef struct { - unsigned short type; /* type of operand from mnemonic.operand_type */ - unsigned short flags; /* see below */ + uint16_t type; /* type of operand from mnemonic.operand_type */ + uint16_t flags; /* see below */ expr *value; /* single register, immed. val. or branch loc.*/ } operand; @@ -49,6 +53,7 @@ enum { /* ARM operands */ NOOP=0, DATA_OP, /* data operand */ + DATA64_OP, /* 64-bit data operand (greater than taddr) */ BRA24, /* 24-bit branch offset to label */ PCL12, /* 12-bit PC-relative offset with up/down-flag to label */ PCLCP, /* 8-bit * 4 PC-relative offset with up/down-flag to label */ @@ -134,9 +139,9 @@ enum { /* additional mnemonic data */ typedef struct { - unsigned long opcode; - unsigned long available; - unsigned long flags; + uint32_t opcode; + uint32_t available; + uint32_t flags; } mnemonic_extension; /* flags: */ @@ -148,15 +153,13 @@ typedef struct { #define NOPCR03 (0x00000020) /* R15 is not allowed for Rm (3..0) */ #define NOPCWB (0x00000040) /* R15 is not allowed in Write-Back mode */ #define SETCC (0x00000100) /* instruction supports S-bit */ +#define SETPSR (0x00000200) /* instruction supports P-bit */ #define THUMB (0x10000000) /* THUMB instruction */ /* register symbols */ +#define HAVE_REGSYMS #define REGSYMHTSIZE 256 -typedef struct regsym { - char *name; - int value; /* usually 0-15 for r0-r15 */ -} regsym; /* cpu types for availability check */ @@ -204,3 +207,5 @@ typedef struct regsym { /* exported by cpu.c */ extern int arm_be_mode; extern int thumb_mode; + +int cpu_available(int); diff --git a/cpus/arm/cpu_errors.h b/cpus/arm/cpu_errors.h index e99f1c4..9679029 100644 --- a/cpus/arm/cpu_errors.h +++ b/cpus/arm/cpu_errors.h @@ -26,4 +26,4 @@ "%d-bit unsigned immediate offset out of range (%ld)",ERROR, /*25*/ "offset has to be a multiple of %d",ERROR, "instruction at unaligned address",ERROR, - "illegal relocation",ERROR, + "TSTP/TEQP/CMNP/CMPP deprecated on 32-bit architectures",WARNING, diff --git a/cpus/arm/opcodes.h b/cpus/arm/opcodes.h index aa26ad0..e7798e5 100644 --- a/cpus/arm/opcodes.h +++ b/cpus/arm/opcodes.h @@ -52,13 +52,13 @@ "bx", {THR05}, {0x4740,AA4TUP,THUMB}, "cdp", {REG11,CPOP4,REG15,REG19,REG03}, {0x0e000000,AA2UP,0}, "cdp", {REG11,CPOP4,REG15,REG19,REG03,CPTYP},{0x0e000000,AA2UP,0}, - "cmn", {REG19,IMROT}, {0x03700000,AAANY,0}, - "cmn", {REG19,REG03}, {0x01700000,AAANY,0}, - "cmn", {REG19,REG03,SHIFT}, {0x01700000,AAANY,0}, + "cmn", {REG19,IMROT}, {0x03700000,AAANY,SETPSR}, + "cmn", {REG19,REG03}, {0x01700000,AAANY,SETPSR}, + "cmn", {REG19,REG03,SHIFT}, {0x01700000,AAANY,SETPSR}, "cmn", {TRG02,TRG05}, {0x42c0,AA4TUP,THUMB}, - "cmp", {REG19,IMROT}, {0x03500000,AAANY,0}, - "cmp", {REG19,REG03}, {0x01500000,AAANY,0}, - "cmp", {REG19,REG03,SHIFT}, {0x01500000,AAANY,0}, + "cmp", {REG19,IMROT}, {0x03500000,AAANY,SETPSR}, + "cmp", {REG19,REG03}, {0x01500000,AAANY,SETPSR}, + "cmp", {REG19,REG03,SHIFT}, {0x01500000,AAANY,SETPSR}, "cmp", {TRG10,TUIM8}, {0x2800,AA4TUP,THUMB}, "cmp", {TRG02,TRG05}, {0x4280,AA4TUP,THUMB}, "cmp", {TRG02,THR05}, {0x4540,AA4TUP,THUMB}, @@ -170,12 +170,12 @@ "swi", {SWI24}, {0x0f000000,AAANY,0}, "swi", {TSWI8}, {0xdf00,AA4TUP,THUMB}, "swp", {REG15,REG03,R19PO}, {0x01000090,AA3UP,NOPC}, - "teq", {REG19,IMROT}, {0x03300000,AAANY,0}, - "teq", {REG19,REG03}, {0x01300000,AAANY,0}, - "teq", {REG19,REG03,SHIFT}, {0x01300000,AAANY,0}, - "tst", {REG19,IMROT}, {0x03100000,AAANY,0}, - "tst", {REG19,REG03}, {0x01100000,AAANY,0}, - "tst", {REG19,REG03,SHIFT}, {0x01100000,AAANY,0}, + "teq", {REG19,IMROT}, {0x03300000,AAANY,SETPSR}, + "teq", {REG19,REG03}, {0x01300000,AAANY,SETPSR}, + "teq", {REG19,REG03,SHIFT}, {0x01300000,AAANY,SETPSR}, + "tst", {REG19,IMROT}, {0x03100000,AAANY,SETPSR}, + "tst", {REG19,REG03}, {0x01100000,AAANY,SETPSR}, + "tst", {REG19,REG03,SHIFT}, {0x01100000,AAANY,SETPSR}, "tst", {TRG02,TRG05}, {0x4200,AA4TUP,THUMB}, "umlal", {REG15,REG19,REG03,REG11}, {0x00a00090,AA3MUP,SETCC|NOPC|DIFR19|DIFR15|DIFR03}, "umull", {REG15,REG19,REG03,REG11}, {0x00800090,AA3MUP,SETCC|NOPC|DIFR19|DIFR15|DIFR03}, diff --git a/cpus/c16x/cpu.c b/cpus/c16x/cpu.c index 64ad7e6..da65530 100644 --- a/cpus/c16x/cpu.c +++ b/cpus/c16x/cpu.c @@ -295,15 +295,16 @@ int parse_operand(char *p,int len,operand *op,int requires) static taddr reloffset(expr *tree,section *sec,taddr pc) { symbol *sym; + int btype; taddr val; simplify_expr(tree); if(tree->type==NUM){ /* should we do it like this?? */ val=tree->c.val; }else{ - sym=find_base(tree,sec,pc); - if(!sym||sym->type!=LABSYM||sym->sec!=sec) - return 0xffff; + btype=find_base(tree,&sym,sec,pc); + if(btype!=BASE_OK||!LOCREF(sym)||sym->sec!=sec) + val=0xffff; else{ eval_expr(tree,&val,sec,pc); val=val-pc; @@ -328,30 +329,21 @@ static taddr absoffset2(expr *tree,int mod,section *sec,taddr pc,rlist **relocs, mask=0x3fff; } if(!eval_expr(tree,&val,sec,pc)){ - nreloc *reloc=new_nreloc(); - rlist *rl=mymalloc(sizeof(*rl)); - rl->type=REL_ABS; - reloc->offset=roffset; - reloc->size=size; - reloc->sym=find_base(tree,sec,pc); - reloc->mask=mask; - if(!reloc->sym){ - cpu_error(2); - }else{ - rl->reloc=reloc; - rl->next=*relocs; - *relocs=rl; + taddr addend=val; + symbol *base; + if(find_base(tree,&base,sec,pc)!=BASE_OK){ + general_error(38); + return val; } - reloc->addend=val; if(mod==MOD_DPP1) val|=0x4000; if(mod==MOD_DPP2) val|=0x8000; if(mod==MOD_DPP3) val|=0xc000; if(mod==MOD_DPPX){ static int dpplen; static char *dppname; - char *id=reloc->sym->name; + char *id=base->name; symbol *dppsym; - reloc->size-=2; + size-=2; if(strlen(id)+9>dpplen){ myfree(dppname); dppname=mymalloc(dpplen=strlen(id)+9); @@ -364,19 +356,10 @@ static taddr absoffset2(expr *tree,int mod,section *sec,taddr pc,rlist **relocs, ierror(0); val<<=14; }else{ - reloc=new_nreloc(); - reloc->offset=roffset+14; - reloc->size=2; - reloc->sym=dppsym; - reloc->mask=0x3; - reloc->addend=0; - rl->next=mymalloc(sizeof(*rl)); - rl=rl->next; - rl->type=REL_ABS; - rl->reloc=reloc; - rl->next=0; + add_nreloc_masked(relocs,dppsym,0,REL_ABS,2,roffset+14,0x3); } } + add_nreloc_masked(relocs,base,addend,REL_ABS,size,roffset,mask); return val; } val&=mask; @@ -643,7 +626,7 @@ dblock *eval_instruction(instruction *p,section *sec,taddr pc) } /* Create a dblock (with relocs, if necessary) for size bits of data. */ -dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) +dblock *eval_data(operand *op,size_t bitsize,section *sec,taddr pc) { dblock *new=new_dblock(); taddr val; @@ -670,7 +653,7 @@ dblock *eval_data(operand *op,taddr bitsize,section *sec,taddr pc) /* Calculate the size of the current instruction; must be identical to the data created by eval_instruction. */ -taddr instruction_size(instruction *p,section *sec,taddr pc) +size_t instruction_size(instruction *p,section *sec,taddr pc) { int c=translate(p,sec,pc),add=0; if(c&JMPCONV){ add=4;c&=~JMPCONV;} diff --git a/cpus/c16x/cpu.h b/cpus/c16x/cpu.h index fed9ff0..9b282dd 100644 --- a/cpus/c16x/cpu.h +++ b/cpus/c16x/cpu.h @@ -11,7 +11,8 @@ /* maximum number of additional command-line-flags for this cpu */ /* data type to represent a target-address */ -typedef long taddr; +typedef int32_t taddr; +typedef uint32_t utaddr; #define LITTLEENDIAN 1 #define BIGENDIAN 0 @@ -85,5 +86,3 @@ typedef struct { unsigned int encoding; unsigned int available; } mnemonic_extension; - - diff --git a/cpus/c16x/cpu_errors.h b/cpus/c16x/cpu_errors.h index 4ac3c6d..cffdaad 100644 --- a/cpus/c16x/cpu_errors.h +++ b/cpus/c16x/cpu_errors.h @@ -1,6 +1,6 @@ -"illegal operand",ERROR, + "illegal operand",ERROR, "word register expected",ERROR, - "illegal relocation",ERROR, + "",ERROR, "value does not find in %d bits",WARNING, "data size not supported",ERROR, "illegal use of SOF",WARNING, diff --git a/cpus/jagrisc/cpu.c b/cpus/jagrisc/cpu.c new file mode 100644 index 0000000..63c4eae --- /dev/null +++ b/cpus/jagrisc/cpu.c @@ -0,0 +1,603 @@ +/* + * cpu.c Jaguar RISC cpu description file + * (c) in 2014-2015 by Frank Wille + */ + +#include "vasm.h" + +mnemonic mnemonics[] = { +#include "opcodes.h" +}; +int mnemonic_cnt = sizeof(mnemonics) / sizeof(mnemonics[0]); + +char *cpu_copyright = "vasm Jaguar RISC cpu backend 0.4 (c) 2014-2015 Frank Wille"; +char *cpuname = "jagrisc"; +int bitsperbyte = 8; +int bytespertaddr = 4; + +int jag_big_endian = 1; /* defaults to big-endian (Atari Jaguar 68000) */ + +static uint8_t cpu_type = GPU|DSP; +static int OC_MOVEI,OC_UNPACK; + +/* condition codes */ +static regsym cc_regsyms[] = { + {"T", RTYPE_CC, 0, 0x00}, + {"NE", RTYPE_CC, 0, 0x01}, + {"EQ", RTYPE_CC, 0, 0x02}, + {"CC", RTYPE_CC, 0, 0x04}, + {"HI", RTYPE_CC, 0, 0x05}, + {"CS", RTYPE_CC, 0, 0x08}, + {"PL", RTYPE_CC, 0, 0x14}, + {"MI", RTYPE_CC, 0, 0x18}, + {"t", RTYPE_CC, 0, 0x00}, + {"ne", RTYPE_CC, 0, 0x01}, + {"eq", RTYPE_CC, 0, 0x02}, + {"cc", RTYPE_CC, 0, 0x04}, + {"hi", RTYPE_CC, 0, 0x05}, + {"cs", RTYPE_CC, 0, 0x08}, + {"pl", RTYPE_CC, 0, 0x14}, + {"mi", RTYPE_CC, 0, 0x18}, + {NULL, 0, 0, 0} +}; + + +int init_cpu(void) +{ + int i; + regsym *r; + + for (i=0; ireg_name!=NULL; r++) + add_regsym(r); + + return 1; +} + + +int cpu_args(char *p) +{ + if (!strncmp(p,"-m",2)) { + p += 2; + if (!stricmp(p,"gpu") || !stricmp(p,"tom")) + cpu_type = GPU; + else if (!stricmp(p,"dsp") || !stricmp(p,"jerry")) + cpu_type = DSP; + else if (!strcmp(p,"any")) + cpu_type = GPU|DSP; + else + return 0; + } + else if (!strcmp(p,"-big")) + jag_big_endian = 1; + else if (!strcmp(p,"-little")) + jag_big_endian = 0; + else + return 0; + + return 1; +} + + +static int parse_reg(char **p) +{ + int reg = -1; + char *rp = skip(*p); + char *s; + + if (s = skip_identifier(rp)) { + regsym *sym = find_regsym(rp,s-rp); + + if (sym!=NULL && sym->reg_type==RTYPE_R) { + reg = sym->reg_num; + } + else if (toupper((unsigned char)*rp++) == 'R') { + if (sscanf(rp,"%d",®)!=1 || reg<0 || reg>31) + reg = -1; + } + + if (reg >= 0) + *p = s; + } + + return reg; +} + + +static expr *parse_cc(char **p) +{ + char *end; + + *p = skip(*p); + + if (end = skip_identifier(*p)) { + regsym *sym = find_regsym(*p,end-*p); + + if (sym!=NULL && sym->reg_type==RTYPE_CC) { + *p = end; + return number_expr((taddr)sym->reg_num); + } + } + + /* otherwise the condition code is any expression */ + return parse_expr(p); +} + + +static void jagswap32(char *d,int32_t w) +/* write a 32-bit word with swapped halfs (Jaguar MOVEI) */ +{ + if (jag_big_endian) { + *d++ = (w >> 8) & 0xff; + *d++ = w & 0xff; + *d++ = (w >> 24) & 0xff; + *d = (w >> 16) & 0xff; + } + else { + /* @@@ Need to verify this! */ + *d++ = w & 0xff; + *d++ = (w >> 8) & 0xff; + *d++ = (w >> 16) & 0xff; + *d = (w >> 24) & 0xff; + } +} + + +char *parse_cpu_special(char *start) +/* parse cpu-specific directives; return pointer to end of cpu-specific text */ +{ + char *name=start; + char *s; + + if (s = skip_identifier(name)) { + /* Atari MadMac compatibility directives */ + if (*name == '.') /* ignore leading dot */ + name++; + + if (s-name==3 && !strnicmp(name,"dsp",3)) { + cpu_type = DSP; + eol(s); + return skip_line(s); + } + + else if (s-name==3 && !strnicmp(name,"gpu",3)) { + cpu_type = GPU; + eol(s); + return skip_line(s); + } + + else if (s-name==8 && !strnicmp(name,"regundef",8) || + s-name==9 && !strnicmp(name,"equrundef",9)) { + /* undefine a register symbol */ + s = skip(s); + if (name = parse_identifier(&s)) { + undef_regsym(name,0,RTYPE_R); + myfree(name); + eol(s); + return skip_line(s); + } + } + + else if (s-name==7 && !strnicmp(name,"ccundef",7)) { + /* undefine a condition code symbol */ + s = skip(s); + if (name = parse_identifier(&s)) { + undef_regsym(name,0,RTYPE_CC); + myfree(name); + eol(s); + return skip_line(s); + } + } + } + + return start; +} + + +int parse_cpu_label(char *labname,char **start) +/* parse cpu-specific directives following a label field, + return zero when no valid directive was recognized */ +{ + char *dir=*start; + char *s,*name; + hashdata data; + + if (*dir == '.') /* ignore leading dot */ + dir++; + + if (s = skip_identifier(dir)) { + + if (s-dir==6 && !strnicmp(dir,"regequ",6) || + s-dir==4 && !strnicmp(dir,"equr",4)) { + /* label REGEQU Rn || label EQUR Rn */ + int r; + + if ((r = parse_reg(&s)) >= 0) + new_regsym(0,0,labname,RTYPE_R,0,r); + else + cpu_error(3); /* register expected */ + eol(s); + *start = skip_line(s); + return 1; + } + + else if (s-dir==5 && !strnicmp(dir,"ccdef",5)) { + /* label CCDEF expr */ + expr *ccexp; + taddr val; + + if ((ccexp = parse_cc(&s)) != NULL) { + if (eval_expr(ccexp,&val,NULL,0)) + new_regsym(0,0,labname,RTYPE_CC,0,(int)val); + else + general_error(30); /* expression must be a constant */ + } + else + general_error(9); /* @@@ */ + eol(s); + *start = skip_line(s); + return 1; + } + } + + return 0; +} + + +operand *new_operand(void) +{ + operand *new = mymalloc(sizeof(*new)); + + new->type = NO_OP; + return new; +} + + +int jag_data_operand(int bits) +/* return data operand type for these number of bits */ +{ + if (bits & OPSZ_SWAP) + return DATAI_OP; + return bits==64 ? DATA64_OP : DATA_OP; +} + + +int parse_operand(char *p, int len, operand *op, int required) +{ + int reg; + + switch (required) { + case IMM0: + case IMM1: + case SIMM: + case IMMLW: + if (*p == '#') + p = skip(p+1); /* skip optional '#' */ + case REL: + case DATA_OP: + case DATAI_OP: + op->val = parse_expr(&p); + break; + + case DATA64_OP: + op->val = parse_expr_huge(&p); + break; + + case REG: /* Rn */ + op->reg = parse_reg(&p); + if (op->reg < 0) + return PO_NOMATCH; + break; + + case IREG: /* (Rn) */ + if (*p++ != '(') + return PO_NOMATCH; + op->reg = parse_reg(&p); + if (op->reg < 0) + return PO_NOMATCH; + if (*p != ')') + return PO_NOMATCH; + break; + + case IR14D: /* (R14+d) */ + case IR15D: /* (R15+d) */ + if (*p++ != '(') + return PO_NOMATCH; + reg = parse_reg(&p); + if ((required==IR14D && reg!=14) || (required==IR15D && reg!=15)) + return PO_NOMATCH; + if (*p++ != '+') + return PO_NOMATCH; + p = skip(p); + op->val = parse_expr(&p); + p = skip(p); + if (*p != ')') + return PO_NOMATCH; + break; + + case IR14R: /* (R14+Rn) */ + case IR15R: /* (R15+Rn) */ + if (*p++ != '(') + return PO_NOMATCH; + reg = parse_reg(&p); + if ((required==IR14R && reg!=14) || (required==IR15R && reg!=15)) + return PO_NOMATCH; + if (*p++ != '+') + return PO_NOMATCH; + op->reg = parse_reg(&p); + if (op->reg < 0) + return PO_NOMATCH; + if (*p != ')') + return PO_NOMATCH; + break; + + case CC: /* condition code: t, eq, ne, mi, pl, cc, cs, ... */ + op->val = parse_cc(&p); + break; + + case PC: /* PC register */ + if (toupper((unsigned char)*p) != 'P' || + toupper((unsigned char)*(p+1)) != 'C' || + ISIDCHAR(*(p+2))) + return PO_NOMATCH; + break; + + default: + return PO_NOMATCH; + } + + op->type = required; + return PO_MATCH; +} + + +static int32_t eval_oper(instruction *ip,operand *op,section *sec, + taddr pc,dblock *db) +{ + symbol *base = NULL; + int optype = op->type; + int btype; + taddr val,loval,hival,mask; + + switch (optype) { + case REG: + case IREG: + case IR14R: + case IR15R: + return op->reg; + + case IMM0: + case IMM1: + case SIMM: + case IMMLW: + case IR14D: + case IR15D: + case REL: + case CC: + mask = 0x1f; + if (!eval_expr(op->val,&val,sec,pc)) + btype = find_base(op->val,&base,sec,pc); + + if (optype==IMM0 || optype==CC || optype==IMM1 || optype==SIMM) { + if (base != NULL) { + loval = -32; + hival = 32; + if (btype != BASE_ILLEGAL) { + if (db) { + add_nreloc_masked(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS, + 5,6,0x1f); + base = NULL; + } + } + } + else if (optype==IMM1) { + loval = 1; + hival = 32; + } + else if (optype==SIMM) { + loval = -16; + hival = 15; + } + else { + loval = 0; + hival = 31; + } + } + else if (optype==IR14D || optype==IR15D) { + if (base==NULL && val==0) { + /* Optimize (Rn+0) to (Rn). Assume that the "load/store (Rn+d)" + instructions follow directly after "load/store (Rn)". */ + ip->code -= optype==IR14D ? 1 : 2; + op->type = IREG; + op->reg = optype==IR14D ? 14 : 15; + return op->reg; + } + loval = 1; + hival = 32; + } + else if (optype==IMMLW) { + mask = ~0; + if (base != NULL) { + if (btype != BASE_ILLEGAL) { + if (db) { + /* two relocations for LSW first, then MSW */ + add_nreloc_masked(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS, + 16,16,0xffff); + add_nreloc_masked(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS, + 16,32,0xffff0000); + base = NULL; + } + } + } + } + else if (optype==REL) { + loval = -16; + hival = 15; + if (base!=NULL && btype==BASE_OK) { + if (is_pc_reloc(base,sec)) { + /* external label or from a different section (distance / 2) */ + add_nreloc_masked(&db->relocs,base,val-2,REL_PC,5,6,0x3e); + } + else if (LOCREF(base)) { + /* known label from the same section doesn't need a reloc */ + val = (val - (pc + 2)) / 2; + } + base = NULL; + } + } + else ierror(0); + + if (base != NULL) + general_error(38); /* bad or unhandled reloc: illegal relocation */ + + /* range check for this addressing mode */ + if (mask!=~0 && (valhival)) + cpu_error(1,(long)loval,(long)hival); + return val & mask; + } + + return 0; /* default */ +} + + +size_t instruction_size(instruction *ip, section *sec, taddr pc) +{ + return ip->code==OC_MOVEI ? 6 : 2; +} + + +dblock *eval_instruction(instruction *ip, section *sec, taddr pc) +{ + dblock *db = new_dblock(); + int32_t src=0,dst=0,extra; + int size = 2; + uint16_t inst; + + /* get source and destination argument, when present */ + if (ip->op[0]) + dst = eval_oper(ip,ip->op[0],sec,pc,db); + if (ip->op[1]) { + if (ip->code == OC_MOVEI) { + extra = dst; + size = 6; + } + else + src = dst; + dst = eval_oper(ip,ip->op[1],sec,pc,db); + } + else if (ip->code == OC_UNPACK) + src = 1; /* pack(src=0)/unpack(src=1) use the same opcode */ + + /* store and jump instructions need the second operand in the source field */ + if (mnemonics[ip->code].ext.flags & OPSWAP) { + extra = src; + src = dst; + dst = extra; + } + + /* allocate dblock data for instruction */ + db->size = size; + db->data = mymalloc(size); + + /* construct the instruction word out of opcode and source/dest. value */ + inst = (mnemonics[ip->code].ext.opcode & 63) << 10; + inst |= ((src&31) << 5) | (dst & 31); + + /* write instruction */ + if (jag_big_endian) { + db->data[0] = (inst >> 8) & 0xff; + db->data[1] = inst & 0xff; + } + else { + db->data[0] = inst & 0xff; + db->data[1] = (inst >> 8) & 0xff; + } + + /* extra words for MOVEI are always written in the order lo-word, hi-word */ + if (size == 6) + jagswap32(&db->data[2],extra); + + return db; +} + + +dblock *eval_data(operand *op, size_t bitsize, section *sec, taddr pc) +{ + dblock *db = new_dblock(); + taddr val; + + if (bitsize!=8 && bitsize!=16 && bitsize!=32 && bitsize!=64) + cpu_error(0,bitsize); /* data size not supported */ + + if (op->type!=DATA_OP && op->type!=DATA64_OP && op->type!=DATAI_OP) + ierror(0); + + db->size = bitsize >> 3; + db->data = mymalloc(db->size); + + if (op->type == DATA64_OP) { + thuge hval; + + if (!eval_expr_huge(op->val,&hval)) + general_error(59); /* cannot evaluate huge integer */ + huge_to_mem(jag_big_endian,db->data,db->size,hval); + } + else { + if (!eval_expr(op->val,&val,sec,pc)) { + symbol *base; + int btype; + + btype = find_base(op->val,&base,sec,pc); + if (base!=NULL && btype!=BASE_ILLEGAL) { + if (op->type == DATAI_OP) { + /* swapped: two relocations for LSW first, then MSW */ + add_nreloc_masked(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS, + 16,0,0xffff); + add_nreloc_masked(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS, + 16,0,0xffff0000); + } + else /* normal 8, 16, 32 bit relocation */ + add_nreloc(&db->relocs,base,val, + btype==BASE_PCREL?REL_PC:REL_ABS,bitsize,0); + } + else if (btype != BASE_NONE) + general_error(38); /* illegal relocation */ + } + + switch (db->size) { + case 1: + db->data[0] = val & 0xff; + break; + case 2: + case 4: + if (op->type == DATAI_OP) + jagswap32(db->data,(int32_t)val); + else + setval(jag_big_endian,db->data,db->size,val); + break; + default: + ierror(0); + break; + } + } + + return db; +} + + +int cpu_available(int idx) +{ + return (mnemonics[idx].ext.flags & cpu_type) != 0; +} diff --git a/cpus/jagrisc/cpu.h b/cpus/jagrisc/cpu.h new file mode 100644 index 0000000..4a22273 --- /dev/null +++ b/cpus/jagrisc/cpu.h @@ -0,0 +1,85 @@ +/* +** cpu.h Jaguar RISC cpu-description header-file +** (c) in 2014-2015 by Frank Wille +*/ + +extern int jag_big_endian; +#define BIGENDIAN (jag_big_endian) +#define LITTLEENDIAN (!jag_big_endian) +#define VASM_CPU_JAGRISC 1 + +/* maximum number of operands for one mnemonic */ +#define MAX_OPERANDS 2 + +/* maximum number of mnemonic-qualifiers per mnemonic */ +#define MAX_QUALIFIERS 0 + +/* data type to represent a target-address */ +typedef int32_t taddr; +typedef uint32_t utaddr; + +/* minimum instruction alignment */ +#define INST_ALIGN 2 + +/* default alignment for n-bit data */ +#define DATA_ALIGN(n) ((n<=8)?1:2) + +/* operand class for n-bit data definitions */ +int jag_data_operand(int); +#define DATA_OPERAND(n) jag_data_operand(n) + +/* returns true when instruction is valid for selected cpu */ +#define MNEMONIC_VALID(i) cpu_available(i) + +/* type to store each operand */ +typedef struct { + uint8_t type; + int8_t reg; + expr *val; +} operand; + +/* operand types */ +enum { + NO_OP=0, + DATA_OP, + DATA64_OP, + DATAI_OP, /* 32-bit with swapped halfwords */ + REG, /* register Rn */ + IMM0, /* 5-bit immediate expression (0-31) */ + IMM1, /* 5-bit immediate expression (1-32) */ + SIMM, /* 5-bit signed immediate expression (-16 - 15) */ + IMMLW, /* 32-bit immediate expression in extra longword */ + IREG, /* register indirect (Rn) */ + IR14D, /* register R14 plus displacement indirect (R14+n) */ + IR15D, /* register R15 plus displacement indirect (R15+n) */ + IR14R, /* register R14 plus register Rn indirect (R14+Rn) */ + IR15R, /* register R15 plus register Rn indirect (R15+Rn) */ + CC, /* condition code, t, cc, cs, eq, ne, mi, pl, hi */ + REL, /* relative branch, PC + 2 + (-16..15) words */ + PC /* PC register */ +}; + +/* additional mnemonic data */ +typedef struct { + uint8_t opcode; + uint8_t flags; +} mnemonic_extension; + +/* Values defined for the 'flags' field of mnemonic_extension. */ +#define GPU 1 +#define DSP 2 +#define ANY GPU|DSP + +#define OPSWAP 128 /* swapped operands in instruction word encoding */ + +/* Register symbols */ +#define HAVE_REGSYMS +#define REGSYMHTSIZE 64 +#define RTYPE_R 0 /* R0-R31 */ +#define RTYPE_CC 1 /* condition codes (0-31) */ + +/* Prototypes */ +int cpu_available(int); + +int parse_cpu_label(char *,char **); +#define PARSE_CPU_LABEL(l,s) parse_cpu_label(l,s) diff --git a/cpus/jagrisc/cpu_errors.h b/cpus/jagrisc/cpu_errors.h new file mode 100644 index 0000000..68db758 --- /dev/null +++ b/cpus/jagrisc/cpu_errors.h @@ -0,0 +1,3 @@ + "data size %d not supported",ERROR, + "value from %ld to %ld required",ERROR, + "register expected",ERROR, diff --git a/cpus/jagrisc/opcodes.h b/cpus/jagrisc/opcodes.h new file mode 100644 index 0000000..281202a --- /dev/null +++ b/cpus/jagrisc/opcodes.h @@ -0,0 +1,72 @@ + "abs", { REG }, { 22, ANY }, + "add", { REG, REG }, { 0, ANY }, + "addc", { REG, REG }, { 1, ANY }, + "addq", { IMM1, REG }, { 2, ANY }, + "addqmod", { IMM1, REG }, { 63, DSP }, + "addqt", { IMM1, REG }, { 3, ANY }, + "and", { REG, REG }, { 9, ANY }, + "bclr", { IMM0, REG }, { 15, ANY }, + "bset", { IMM0, REG }, { 14, ANY }, + "btst", { IMM0, REG }, { 13, ANY }, + "cmp", { REG, REG }, { 30, ANY }, + "cmpq", { SIMM, REG }, { 31, ANY }, + "div", { REG, REG }, { 21, ANY }, + "imacn", { REG, REG }, { 20, ANY }, + "imult", { REG, REG }, { 17, ANY }, + "imultn", { REG, REG }, { 18, ANY }, + "jr", { REL }, { 53, ANY|OPSWAP }, + "jr", { CC, REL }, { 53, ANY|OPSWAP }, + "jump", { IREG }, { 52, ANY|OPSWAP }, + "jump", { CC, IREG }, { 52, ANY|OPSWAP }, + "load", { IREG, REG }, { 41, ANY }, + "load", { IR14R, REG }, { 58, ANY }, + "load", { IR15R, REG }, { 59, ANY }, + "load", { IR14D, REG }, { 43, ANY }, + "load", { IR15D, REG }, { 44, ANY }, + "loadb", { IREG, REG }, { 39, ANY }, + "loadp", { IREG, REG }, { 42, GPU }, + "loadw", { IREG, REG }, { 40, ANY }, + "mirror", { REG, IREG }, { 48, DSP|OPSWAP }, + "mmult", { REG, REG }, { 54, ANY }, + "move", { REG, REG }, { 34, ANY }, + "move", { PC, REG }, { 51, ANY }, + "movefa", { REG, REG }, { 37, ANY }, + "movei", { IMMLW, REG }, { 38, ANY }, + "moveq", { IMM0, REG }, { 35, ANY }, + "moveta", { REG, REG }, { 36, ANY }, + "mtoi", { REG, REG }, { 55, ANY }, + "mult", { REG, REG }, { 16, ANY }, + "neg", { REG }, { 8, ANY }, + "nop", { NO_OP }, { 57, ANY }, + "normi", { REG, REG }, { 56, ANY }, + "not", { REG }, { 12, ANY }, + "or", { REG, REG }, { 10, ANY }, + "pack", { REG }, { 63, GPU }, + "resmac", { REG }, { 19, ANY }, + "ror", { REG, REG }, { 28, ANY }, + "rorq", { IMM1, REG }, { 29, ANY }, + "sat8", { REG }, { 32, GPU }, + "sat16", { REG }, { 33, GPU }, + "sat16s", { REG }, { 33, DSP }, + "sat24", { REG }, { 62, GPU }, + "sat32s", { REG }, { 42, DSP }, + "sh", { REG, REG }, { 23, ANY }, + "sha", { REG, REG }, { 26, ANY }, + "sharq", { IMM1, REG }, { 27, ANY }, + "shlq", { IMM1, REG }, { 24, ANY }, + "shrq", { IMM1, REG }, { 25, ANY }, + "store", { REG, IREG }, { 47, ANY|OPSWAP }, + "store", { REG, IR14R }, { 60, ANY|OPSWAP }, + "store", { REG, IR15R }, { 61, ANY|OPSWAP }, + "store", { REG, IR14D }, { 49, ANY|OPSWAP }, + "store", { REG, IR15D }, { 50, ANY|OPSWAP }, + "storeb", { REG, IREG }, { 45, ANY|OPSWAP }, + "storep", { REG, IREG }, { 48, GPU|OPSWAP }, + "storew", { REG, IREG }, { 46, ANY|OPSWAP }, + "sub", { REG, REG }, { 4, ANY }, + "subc", { REG, REG }, { 5, ANY }, + "subq", { IMM1, REG }, { 6, ANY }, + "subqmod", { IMM1, REG }, { 32, DSP }, + "subqt", { IMM1, REG }, { 7, ANY }, + "unpack", { REG }, { 63, GPU }, + "xor", { REG, REG }, { 11, ANY }, diff --git a/cpus/m68k/cpu.c b/cpus/m68k/cpu.c index d19d4a2..16602a0 100644 --- a/cpus/m68k/cpu.c +++ b/cpus/m68k/cpu.c @@ -1,6 +1,6 @@ /* ** cpu.c Motorola M68k, CPU32 and ColdFire cpu-description file -** (c) in 2002-2011 by Frank Wille +** (c) in 2002-2015 by Frank Wille */ #include @@ -24,12 +24,14 @@ struct cpu_models models[] = { int model_cnt = sizeof(models)/sizeof(models[0]); -char *cpu_copyright="vasm M68k/CPU32/ColdFire cpu backend 1.2a (c) 2002-2011 Frank Wille"; +char *cpu_copyright="vasm M68k/CPU32/ColdFire cpu backend 2.0f (c) 2002-2015 Frank Wille"; char *cpuname = "M68k"; int bitsperbyte = 8; int bytespertaddr = 4; -static unsigned long cpu_type = m68000; +int m68k_mid = 1; /* default a.out MID: 68000/68010 */ + +static uint32_t cpu_type = m68000; static expr *baseexp[7]; /* basereg: expression loaded to reg. */ static signed char sdreg = -1; /* current small-data base register */ static signed char last_sdreg = -1; @@ -42,7 +44,8 @@ static unsigned char opt_clr = 0; /* MOVE #0, -> CLR */ static unsigned char opt_st = 0; /* MOVE.B #-1, -> ST */ static unsigned char opt_lsl = 0; /* LSL #1,Dn -> ADD Dn,Dn */ static unsigned char opt_mul = 0; /* MULU/MULS #n,Dn -> LSL/ASL #n,Dn */ -static unsigned char opt_fconst = 0; /* Fxxx.D #m,FPn -> Fxxx.S #m,FPn */ +static unsigned char opt_div = 0; /* DIVU/DIVS.L #n,Dn -> LSR/ASR #n,Dn */ +static unsigned char opt_fconst = 1; /* Fxxx.D #m,FPn -> Fxxx.S #m,FPn */ static unsigned char opt_brajmp = 0; /* branch to different sect. into jump */ static unsigned char opt_pc = 1; /*