📄 ns32k.c
字号:
/* in: instruction line out: internal structure of instruction that has been prepared for direct conversion to fragment(s) and fixes in a systematical fashion Return-value = recursive_level*//* build iif of one assembly text line */int parse(line,recursive_level) char *line; int recursive_level;{ register char *lineptr,c,suffix_separator; register int i; int argc,arg_type; char sqr,sep; char suffix[MAX_ARGS],*argv[MAX_ARGS];/* no more than 4 operands */ if (recursive_level<=0) { /* called from md_assemble */ for (lineptr=line;(*lineptr)!='\0' && (*lineptr)!=' ';lineptr++); c = *lineptr; *lineptr='\0'; if (!(desc=(struct ns32k_opcode*)hash_find(inst_hash_handle,line))) { as_fatal("No such opcode"); } *lineptr=c; } else { lineptr=line; } argc=0; if (*desc->operands) { if (*lineptr++!='\0') { sqr='['; sep=','; while (*lineptr!='\0') { if (desc->operands[argc<<1]) { suffix[argc]=0; arg_type=desc->operands[(argc<<1)+1]; switch (arg_type) { case 'd': case 'b': case 'p': case 'H': /* the operand is supposed to be a displacement */ /* Hackwarning: do not forget to update the 4 cases above when editing ns32k-opcode.h */ suffix_separator=':'; break; default: suffix_separator='\255'; /* if this char occurs we loose */ } suffix[argc]=0; /* 0 when no ':' is encountered */ argv[argc]=freeptr; *freeptr='\0'; while ((c = *lineptr)!='\0' && c!=sep) { if (c==sqr) { if (sqr=='[') { sqr=']';sep='\0'; } else { sqr='[';sep=','; } } if (c==suffix_separator) { /* ':' - label/suffix separator */ switch (lineptr[1]) { case 'b':suffix[argc]=1;break; case 'w':suffix[argc]=2;break; case 'd':suffix[argc]=4;break; default: as_warn("Bad suffix, defaulting to d"); suffix[argc]=4; if (lineptr[1]=='\0' || lineptr[1]==sep) { lineptr+=1; continue; } } lineptr+=2; continue; } *freeptr++=c; lineptr++; } *freeptr++='\0'; argc+=1; if (*lineptr=='\0') continue; lineptr+=1; } else { as_fatal("Too many operands passed to instruction"); } } } } if (argc!=strlen(desc->operands)/2) { if (strlen(desc->default_args)) { /* we can apply default, dont goof */ if (parse(desc->default_args,1)!=1) { /* check error in default */ as_fatal("Wrong numbers of operands in default, check ns32k-opcodes.h"); } } else { as_fatal("Wrong number of operands"); } } for (i=0;i<IIF_ENTRIES;i++) { iif.iifP[i].type=0; /* mark all entries as void*/ } /* build opcode iif-entry */ iif.instr_size=desc->opcode_size/8; IIF(1,1,iif.instr_size,desc->opcode_seed,0,0,0,0,0,0,-1,0); /* this call encodes operands to iif format */ if (argc) { encode_operand(argc, argv, &desc->operands[0], &suffix[0], desc->im_size, desc->opcode_size); } return recursive_level;} /* Convert iif to fragments. From this point we start to dribble with functions in other files than this one.(Except hash.c) So, if it's possible to make an iif for an other CPU, you don't need to know what frags, relax, obstacks, etc is in order to port this assembler. You only need to know if it's possible to reduce your cpu-instruction to iif-format (takes some work) and adopt the other md_? parts according to given instructions Note that iif was invented for the clean ns32k`s architecure. */convert_iif(){ register int i,j; fragS *inst_frag; char *inst_offset,*inst_opcode; char *memP; segT segment; int l,k; register int rem_size; /* count the remaining bytes of instruction */ register char type; register char size = 0; int size_so_far=0; /* used to calculate pcrel_adjust */ rem_size=iif.instr_size; memP=frag_more(iif.instr_size); /* make sure we have enough bytes for instruction */ inst_opcode=memP; inst_offset=(char*)(memP-frag_now->fr_literal); inst_frag=frag_now; for (i=0;i<IIF_ENTRIES;i++) { if (type=iif.iifP[i].type) { /* the object exist, so handle it */ switch (size=iif.iifP[i].size) { case 42: size=0; /* it's a bitfix that operates on an existing object*/ if (iif.iifP[i].bit_fixP->fx_bit_base) { /* expand fx_bit_base to point at opcode */ iif.iifP[i].bit_fixP->fx_bit_base=(long)inst_opcode; } case 8: /* bignum or doublefloat */ bzero (memP,8); case 1:case 2:case 3:case 4:/* the final size in objectmemory is known */ j=(unsigned long)iif.iifP[i].bit_fixP; switch (type) { case 1: /* the object is pure binary */ if (j || iif.iifP[i].pcrel) { fix_new_ns32k(frag_now, (long)(memP-frag_now->fr_literal), size, 0, 0, iif.iifP[i].object, iif.iifP[i].pcrel, (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ iif.iifP[i].im_disp, j, iif.iifP[i].bsr); /* sequent hack */ } else { /* good, just put them bytes out */ switch (iif.iifP[i].im_disp) { case 0: md_number_to_chars(memP,iif.iifP[i].object,size);break; case 1: md_number_to_disp(memP,iif.iifP[i].object,size);break; default: as_fatal("iif convert internal pcrel/binary"); } } memP+=size; rem_size-=size; break; case 2: /* the object is a pointer at an expression, so unpack it, note that bignums may result from the expression */ if ((segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object))==SEG_BIG || size==8) { if ((k=exprP.X_add_number)>0) { /* we have a bignum ie a quad */ /* this can only happens in a long suffixed instruction */ bzero(memP,size); /* size normally is 8 */ if (k*2>size) as_warn("Bignum too big for long"); if (k==3) memP+=2; for (l=0;k>0;k--,l+=2) { md_number_to_chars(memP+l,generic_bignum[l>>1],sizeof(LITTLENUM_TYPE)); } } else { /* flonum */ LITTLENUM_TYPE words[4]; switch(size) { case 4: gen_to_words(words,2,8); md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); md_number_to_imm(memP+sizeof(LITTLENUM_TYPE),(long)words[1],sizeof(LITTLENUM_TYPE)); break; case 8: gen_to_words(words,4,11); md_number_to_imm(memP ,(long)words[0],sizeof(LITTLENUM_TYPE)); md_number_to_imm(memP+sizeof(LITTLENUM_TYPE) ,(long)words[1],sizeof(LITTLENUM_TYPE)); md_number_to_imm(memP+2*sizeof(LITTLENUM_TYPE),(long)words[2],sizeof(LITTLENUM_TYPE)); md_number_to_imm(memP+3*sizeof(LITTLENUM_TYPE),(long)words[3],sizeof(LITTLENUM_TYPE)); break; } } memP+=size; rem_size-=size; break; } if (j || exprP.X_add_symbol || exprP.X_subtract_symbol || iif.iifP[i].pcrel) { /* fixit */ /* the expression was undefined due to an undefined label */ /* create a fix so we can fix the object later */ exprP.X_add_number+=iif.iifP[i].object_adjust; fix_new_ns32k(frag_now, (long)(memP-frag_now->fr_literal), size, exprP.X_add_symbol, exprP.X_subtract_symbol, exprP.X_add_number, iif.iifP[i].pcrel, (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ iif.iifP[i].im_disp, j, iif.iifP[i].bsr); /* sequent hack */ } else { /* good, just put them bytes out */ switch (iif.iifP[i].im_disp) { case 0: md_number_to_imm(memP,exprP.X_add_number,size);break; case 1: md_number_to_disp(memP,exprP.X_add_number,size);break; default: as_fatal("iif convert internal pcrel/pointer"); } } memP+=size; rem_size-=size; break; default: as_fatal("Internal logic error in iif.iifP[n].type"); } break; case 0: /* To bad, the object may be undefined as far as its final nsize in object memory is concerned. The size of the object in objectmemory is not explicitly given. If the object is defined its length can be determined and a fix can replace the frag. */ { int temp; segment=evaluate_expr(&exprP,(char*)iif.iifP[i].object); if ((exprP.X_add_symbol || exprP.X_subtract_symbol) && !iif.iifP[i].pcrel) { /* OVE: hack, clamp to 4 bytes */ size=4; /* we dont wan't to frag this, use 4 so it reaches */ fix_new_ns32k(frag_now, (long)(memP-frag_now->fr_literal), size, exprP.X_add_symbol, exprP.X_subtract_symbol, exprP.X_add_number, 0, /* never iif.iifP[i].pcrel, */ (char)size_so_far, /*iif.iifP[i].pcrel_adjust,*/ 1, /* always iif.iifP[i].im_disp, */ 0,0); memP+=size; rem_size-=4; break; /* exit this absolute hack */ } if (exprP.X_add_symbol || exprP.X_subtract_symbol) { /* frag it */ if (exprP.X_subtract_symbol) { /* We cant relax this case */ as_fatal("Can't relax difference"); } else { /* at this stage we must undo some of the effect caused by frag_more, ie we must make sure that frag_var causes frag_new to creat a valid fix-size in the frag it`s closing */ temp = -(rem_size-4); obstack_blank_fast(&frags,temp); /* we rewind none, some or all of the requested size we requested by the first frag_more for this iif chunk. Note: that we allocate 4 bytes to an object we NOT YET know the size of, thus rem_size-4. */ (void)frag_variant(rs_machine_dependent, 4, 0, IND(BRANCH,UNDEF), /* expecting the worst */ exprP.X_add_symbol, exprP.X_add_number, (char*)inst_opcode, (char)size_so_far, /*iif.iifP[i].pcrel_adjust);*/ iif.iifP[i].bsr); /* sequent linker hack */ rem_size-=4; if (rem_size>0) { memP=frag_more(rem_size); } } } else {/* Double work, this is done in md_number_to_disp */ exprP.X_add_number; if (-64<=exprP.X_add_number && exprP.X_add_number<=63) { size=1; } else { if (-8192<=exprP.X_add_number && exprP.X_add_number<=8191) { size=2; } else { if (-0x1f000000<=exprP.X_add_number && exprP.X_add_number<=0x1fffffff) /* if (-0x40000000<=exprP.X_add_number && exprP.X_add_number<=0x3fffffff) */ { size=4; } else { as_warn("Displacement to large for :d"); size=4; } } } /* rewind the bytes not used */ temp = -(4-size); md_number_to_disp(memP,exprP.X_add_number,size); obstack_blank_fast(&frags,temp); memP+=size; rem_size-=4; /* we allocated this amount */ } } break; default: as_fatal("Internal logic error in iif.iifP[].type"); } size_so_far+=size; size=0; } }}void md_assemble(line)char *line;{ freeptr=freeptr_static; parse(line,0); /* explode line to more fix form in iif */ convert_iif(); /* convert iif to frags, fix's etc */#ifdef SHOW_NUM printf(" \t\t\t%s\n",line);#endif}void md_begin(){ /* build a hashtable of the instructions */ register struct ns32k_opcode *ptr; register char *stat; inst_hash_handle=hash_new(); for (ptr=ns32k_opcodes;ptr<endop;ptr++) { if (*(stat=hash_insert(inst_hash_handle,ptr->name,(char*)ptr))) { as_fatal("Can't hash %s: %s",ptr->name,stat); /*fatal*/ exit(0); } } freeptr_static=(char*)malloc(PRIVATE_SIZE); /* some private space please! */}voidmd_end(){ free(freeptr_static);}/* Must be equal to MAX_PRECISON in atof-ieee.c */#define MAX_LITTLENUMS 6/* Turn the string pointed to by litP into a floating point constant of type type, and emit the appropriate bytes. The number of LITTLENUMS emitted is stored in *sizeP . An error message is returned, or NULL on OK. */char *md_atof(type,litP,sizeP)char type;char *litP;int *sizeP;{ int prec; LITTLENUM_TYPE words[MAX_LITTLENUMS]; LITTLENUM_TYPE *wordP; char *t; char *atof_ieee(); switch(type) { case 'f': prec = 2; break; case 'd': prec = 4; break; default: *sizeP=0; return "Bad call to MD_ATOF()"; } t=atof_ieee(input_line_pointer,type,words); if(t) input_line_pointer=t; *sizeP=prec * sizeof(LITTLENUM_TYPE); for(wordP=words+prec;prec--;) { md_number_to_chars(litP,(long)(*--wordP),sizeof(LITTLENUM_TYPE)); litP+=sizeof(LITTLENUM_TYPE); } return ""; /* Someone should teach Dean about null pointers */}/* Convert number to chars in correct order */voidmd_number_to_chars (buf, value, nbytes) char *buf; long int value; int nbytes;{ while (nbytes--) {#ifdef SHOW_NUM printf("%x ",value & 0xff);#endif *buf++ = value; /* Lint wants & MASK_CHAR. */ value >>= BITS_PER_CHAR; }}/* Convert number to chars in correct order *//* This is a variant of md_numbers_to_chars. The reason for its' existence is the fact that ns32k uses Huffman coded displacements. This implies that the bit order is reversed in displacements and that they are prefixed
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -