123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366 |
- /* m68k.c All the m68020 specific stuff in one convenient, huge,
- slow to compile, easy to find file.
- Copyright (C) 1987 Free Software Foundation, Inc.
- This file is part of GAS, the GNU Assembler.
- GAS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
- GAS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GAS; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
- #include <stdio.h>
- #include <ctype.h>
- #include "m68k-opcode.h"
- #include "as.h"
- #include "obstack.h"
- #include "frags.h"
- #include "struc-symbol.h"
- #include "flonum.h"
- #include "expr.h"
- #include "hash.h"
- #include "md.h"
- #include "m68k.h"
- #ifdef M_SUN
- /* This variable contains the value to write out at the beginning of
- the a.out file. The 2<<16 means that this is a 68020 file instead
- of an old-style 68000 file */
- long omagic = 2<<16|OMAGIC; /* Magic byte for header file */
- #else
- long omagic = OMAGIC;
- #endif
- /* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful */
- char comment_chars[] = "|";
- /* This array holds the chars that only start a comment at the beginning of
- a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output */
- /* Note that input_file.c hand checks for '#' at the beginning of the
- first line of the input file. This is because the compiler outputs
- #NO_APP at the beginning of its output. */
- /* Also note that '/*' will always start a comment */
- char line_comment_chars[] = "#";
- /* Chars that can be used to separate mant from exp in floating point nums */
- char EXP_CHARS[] = "eE";
- /* Chars that mean this number is a floating point constant */
- /* As in 0f12.456 */
- /* or 0d1.2345e12 */
- char FLT_CHARS[] = "rRsSfFdDxXeEpP";
- /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
- changed in read.c . Ideally it shouldn't have to know about it at all,
- but nothing is ideal around here.
- */
- void fix_new();
- void install_operand();
- void install_gen_operand();
- /* Its an arbitrary name: This means I don't approve of it */
- /* See flames below */
- struct obstack robyn;
- #define TAB(x,y) (((x)<<2)+(y))
- #define TABTYPE(xy) ((xy) >> 2)
- #define BYTE 0
- #define SHORT 1
- #define LONG 2
- #define SZ_UNDEF 3
- #define BRANCH 1
- #define FBRANCH 2
- #define PCREL 3
- #define BCC68000 4
- #define DBCC 5
- /* BCC68000 is for patching in an extra jmp instruction for long offsets
- on the 68000. The 68000 doesn't support long branches with branchs */
- /* This table desribes how you change sizes for the various types of variable
- size expressions. This version only supports two kinds. */
- /* Note that calls to frag_var need to specify the maximum expansion needed */
- /* This is currently 10 bytes for DBCC */
- /* The fields are:
- How far Forward this mode will reach:
- How far Backward this mode will reach:
- How many bytes this mode will add to the size of the frag
- Which mode to go to if the offset won't fit in this one
- */
- relax_typeS
- md_relax_table[] = {
- { 1, 1, 0, 0 }, /* First entries aren't used */
- { 1, 1, 0, 0 }, /* For no good reason except */
- { 1, 1, 0, 0 }, /* that the VAX doesn't either */
- { 1, 1, 0, 0 },
- { (127), (-128), 0, TAB(BRANCH,SHORT)},
- { (2+32767), (2+-32768), 2, TAB(BRANCH,LONG) },
- { 0, 0, 4, 0 },
- { 1, 1, 0, 0 },
- { 1, 1, 0, 0 }, /* FBRANCH doesn't come BYTE */
- { (2+32767), (2+-32768), 2, TAB(FBRANCH,LONG)},
- { 0, 0, 4, 0 },
- { 1, 1, 0, 0 },
- { 1, 1, 0, 0 }, /* PCREL doesn't come BYTE */
- { (2+32767), (2+-32768), 2, TAB(PCREL,LONG)},
- { 0, 0, 4, 0 },
- { 1, 1, 0, 0 },
- { (127), (-128), 0, TAB(BCC68000,SHORT)},
- { (2+32767), (2+-32768), 2, TAB(BCC68000,LONG) },
- { 0, 0, 6, 0 }, /* jmp long space */
- { 1, 1, 0, 0 },
- { 1, 1, 0, 0 }, /* DBCC doesn't come BYTE */
- { (2+32767), (2+-32768), 2, TAB(DBCC,LONG) },
- { 0, 0, 10, 0 }, /* bra/jmp long space */
- { 1, 1, 0, 0 },
- };
- void s_data1(), s_data2(), s_even(), s_space();
- void float_cons();
- /* These are the machine dependent pseudo-ops. These are included so
- the assembler can work on the output from the SUN C compiler, which
- generates these.
- */
- /* This table describes all the machine specific pseudo-ops the assembler
- has to support. The fields are:
- pseudo-op name without dot
- function to call to execute this pseudo-op
- Integer arg to pass to the function
- */
- pseudo_typeS md_pseudo_table[] = {
- { "data1", s_data1, 0 },
- { "data2", s_data2, 0 },
- { "even", s_even, 0 },
- { "skip", s_space, 0 },
- { 0, 0, 0 }
- };
- /* #define isbyte(x) ((x)>=-128 && (x)<=127) */
- /* #define isword(x) ((x)>=-32768 && (x)<=32767) */
- #define issbyte(x) ((x)>=-128 && (x)<=127)
- #define isubyte(x) ((x)>=0 && (x)<=255)
- #define issword(x) ((x)>=-32768 && (x)<=32767)
- #define isuword(x) ((x)>=0 && (x)<=65535)
- #define isbyte(x) ((x)>=-128 && (x)<=255)
- #define isword(x) ((x)>=-32768 && (x)<=65535)
- #define islong(x) (1)
- char *input_line_pointer;
- /* Operands we can parse: (And associated modes)
- numb: 8 bit num
- numw: 16 bit num
- numl: 32 bit num
- dreg: data reg 0-7
- reg: address or data register
- areg: address register
- apc: address register, PC, ZPC or empty string
- num: 16 or 32 bit num
- num2: like num
- sz: w or l if omitted, l assumed
- scale: 1 2 4 or 8 if omitted, 1 assumed
- 7.4 IMMED #num --> NUM
- 0.? DREG dreg --> dreg
- 1.? AREG areg --> areg
- 2.? AINDR areg@ --> *(areg)
- 3.? AINC areg@+ --> *(areg++)
- 4.? ADEC areg@- --> *(--areg)
- 5.? AOFF apc@(numw) --> *(apc+numw) -- empty string and ZPC not allowed here
- 6.? AINDX apc@(num,reg:sz:scale) --> *(apc+num+reg*scale)
- 6.? AINDX apc@(reg:sz:scale) --> same, with num=0
- 6.? APODX apc@(num)@(num2,reg:sz:scale) --> *(*(apc+num)+num2+reg*scale)
- 6.? APODX apc@(num)@(reg:sz:scale) --> same, with num2=0
- 6.? AMIND apc@(num)@(num2) --> *(*(apc+num)+num2) (previous mode without an index reg)
- 6.? APRDX apc@(num,reg:sz:scale)@(num2) --> *(*(apc+num+reg*scale)+num2)
- 6.? APRDX apc@(reg:sz:scale)@(num2) --> same, with num=0
- 7.0 ABSL num:sz --> *(num)
- num --> *(num) (sz L assumed)
- *** MSCR otherreg --> Magic
- With -l option
- 5.? AOFF apc@(num) --> *(apc+num) -- empty string and ZPC not allowed here still
- examples:
- #foo #0x35 #12
- d2
- a4
- a3@
- a5@+
- a6@-
- a2@(12) pc@(14)
- a1@(5,d2:w:1) @(45,d6:l:4)
- pc@(a2) @(d4)
- etc . . .
- #name@(numw) -->turn into PC rel mode
- apc@(num8,reg:sz:scale) --> *(apc+num8+reg*scale)
- */
- #define IMMED 1
- #define DREG 2
- #define AREG 3
- #define AINDR 4
- #define ADEC 5
- #define AINC 6
- #define AOFF 7
- #define AINDX 8
- #define APODX 9
- #define AMIND 10
- #define APRDX 11
- #define ABSL 12
- #define MSCR 13
- #define REGLST 14
- #define FAIL 0
- #define OK 1
- /* DATA and ADDR have to be contiguous, so that reg-DATA gives 0-7==data reg,
- 8-15==addr reg for operands that take both types */
- #define DATA 1 /* 1- 8 == data registers 0-7 */
- #define ADDR (DATA+8) /* 9-16 == address regs 0-7 */
- #define FPREG (ADDR+8) /* 17-24 Eight FP registers */
- #define COPNUM (FPREG+8) /* 25-32 Co-processor #1-#8 */
- #define PC (COPNUM+8) /* 33 Program counter */
- #define ZPC (PC+1) /* 34 Hack for Program space, but 0 addressing */
- #define SR (ZPC+1) /* 35 Status Reg */
- #define CCR (SR+1) /* 36 Condition code Reg */
- /* These have to be in order for the movec instruction to work. */
- #define USP (CCR+1) /* 37 User Stack Pointer */
- #define ISP (USP+1) /* 38 Interrupt stack pointer */
- #define SFC (ISP+1) /* 39 */
- #define DFC (SFC+1) /* 40 */
- #define CACR (DFC+1) /* 41 */
- #define VBR (CACR+1) /* 42 */
- #define CAAR (VBR+1) /* 43 */
- #define MSP (CAAR+1) /* 44 */
- #define FPI (MSP+1) /* 45 */
- #define FPS (FPI+1) /* 46 */
- #define FPC (FPS+1) /* 47 */
- /*
- * these defines should be in m68k.c but
- * i put them here to keep all the m68851 stuff
- * together -rab
- * JF--Make sure these #s don't clash with the ones in m68k.c
- * That would be BAD.
- */
- #define TC (FPC+1) /* 48 */
- #define DRP (TC+1) /* 49 */
- #define SRP (DRP+1) /* 50 */
- #define CRP (SRP+1) /* 51 */
- #define CAL (CRP+1) /* 52 */
- #define VAL (CAL+1) /* 53 */
- #define SCC (VAL+1) /* 54 */
- #define AC (SCC+1) /* 55 */
- #define BAD (AC+1) /* 56,57,58,59, 60,61,62,63 */
- #define BAC (BAD+8) /* 64,65,66,67, 68,69,70,71 */
- #define PSR (BAC+8) /* 72 */
- #define PCSR (PSR+1) /* 73 */
- /* Note that COPNUM==processor #1 -- COPNUM+7==#8, which stores as 000 */
- /* I think. . . */
- #define SP ADDR+7
- /* JF these tables here are for speed at the expense of size */
- /* You can replace them with the #if 0 versions if you really
- need space and don't mind it running a bit slower */
- static char mklower_table[256];
- #define mklower(c) (mklower_table[(unsigned char)(c)])
- static char notend_table[256];
- static char alt_notend_table[256];
- #define notend(s) ( !(notend_table[(unsigned char)(*s)] || (*s==':' &&\
- alt_notend_table[(unsigned char)(s[1])])))
- #if 0
- #define mklower(c) (isupper(c) ? tolower(c) : c)
- #endif
- struct m68k_exp {
- char *e_beg;
- char *e_end;
- expressionS e_exp;
- short e_siz; /* 0== default 1==short/byte 2==word 3==long */
- };
- /* Internal form of an operand. */
- struct m68k_op {
- char *error; /* Couldn't parse it */
- int mode; /* What mode this instruction is in. */
- unsigned long int reg; /* Base register */
- struct m68k_exp *con1;
- int ireg; /* Index register */
- int isiz; /* 0==unspec 1==byte(?) 2==short 3==long */
- int imul; /* Multipy ireg by this (1,2,4,or 8) */
- struct m68k_exp *con2;
- };
- /* internal form of a 68020 instruction */
- struct m68_it {
- char *error;
- char *args; /* list of opcode info */
- int numargs;
- int numo; /* Number of shorts in opcode */
- short opcode[11];
- struct m68k_op operands[6];
- int nexp; /* number of exprs in use */
- struct m68k_exp exprs[4];
- int nfrag; /* Number of frags we have to produce */
- struct {
- int fragoff; /* Where in the current opcode[] the frag ends */
- symbolS *fadd;
- long int foff;
- int fragty;
- } fragb[4];
- int nrel; /* Num of reloc strucs in use */
- struct {
- int n;
- symbolS *add,
- *sub;
- long int off;
- char wid;
- char pcrel;
- } reloc[5]; /* Five is enough??? */
- };
- struct m68_it the_ins; /* the instruction being assembled */
- /* Macros for adding things to the m68_it struct */
- #define addword(w) the_ins.opcode[the_ins.numo++]=(w)
- /* Like addword, but goes BEFORE general operands */
- #define insop(w) {int z;\
- for(z=the_ins.numo;z>opcode->m_codenum;--z)\
- the_ins.opcode[z]=the_ins.opcode[z-1];\
- for(z=0;z<the_ins.nrel;z++)\
- the_ins.reloc[z].n+=2;\
- the_ins.opcode[opcode->m_codenum]=w;\
- the_ins.numo++;\
- }
- #define add_exp(beg,end) (\
- the_ins.exprs[the_ins.nexp].e_beg=beg,\
- the_ins.exprs[the_ins.nexp].e_end=end,\
- &the_ins.exprs[the_ins.nexp++]\
- )
- /* The numo+1 kludge is so we can hit the low order byte of the prev word. Blecch*/
- #define add_fix(width,exp,pc_rel) {\
- the_ins.reloc[the_ins.nrel].n= ((width)=='B') ? (the_ins.numo*2-1) : \
- (((width)=='b') ? ((the_ins.numo-1)*2) : (the_ins.numo*2));\
- the_ins.reloc[the_ins.nrel].add=adds((exp));\
- the_ins.reloc[the_ins.nrel].sub=subs((exp));\
- the_ins.reloc[the_ins.nrel].off=offs((exp));\
- the_ins.reloc[the_ins.nrel].wid=width;\
- the_ins.reloc[the_ins.nrel++].pcrel=pc_rel;\
- }
- #define add_frag(add,off,type) {\
- the_ins.fragb[the_ins.nfrag].fragoff=the_ins.numo;\
- the_ins.fragb[the_ins.nfrag].fadd=add;\
- the_ins.fragb[the_ins.nfrag].foff=off;\
- the_ins.fragb[the_ins.nfrag++].fragty=type;\
- }
- #define isvar(exp) ((exp) && (adds(exp) || subs(exp)))
- #define seg(exp) ((exp)->e_exp.X_seg)
- #define adds(exp) ((exp)->e_exp.X_add_symbol)
- #define subs(exp) ((exp)->e_exp.X_subtract_symbol)
- #define offs(exp) ((exp)->e_exp.X_add_number)
- struct m68_incant {
- char *m_operands;
- unsigned long m_opcode;
- short m_opnum;
- short m_codenum;
- struct m68_incant *m_next;
- };
- #define getone(x) ((((x)->m_opcode)>>16)&0xffff)
- #define gettwo(x) (((x)->m_opcode)&0xffff)
- /* JF modified this to handle cases where the first part of a symbol name
- looks like a register */
- int
- m68k_reg_parse(ccp)
- register char **ccp;
- {
- register char c1,
- c2,
- c3,
- c4;
- register int n = 0,
- ret;
- c1=mklower(ccp[0][0]);
- c2=mklower(ccp[0][1]);
- c3=mklower(ccp[0][2]);
- c4=mklower(ccp[0][3]);
- switch(c1) {
- case 'a':
- if(c2>='0' && c2<='7') {
- n=2;
- ret=ADDR+c2-'0';
- }
- #ifdef m68851
- else if (c2 == 'c') {
- n = 2;
- ret = AC;
- }
- #endif
- break;
- #ifdef m68851
- case 'b':
- if (c2 == 'a') {
- if (c3 == 'd') {
- if (c4 >= '0' && c4 <= '7') {
- n = 4;
- ret = BAD + c4 - '0';
- }
- }
- if (c3 == 'c') {
- if (c4 >= '0' && c4 <= '7') {
- n = 4;
- ret = BAC + c4 - '0';
- }
- }
- }
- break;
- #endif
- case 'c':
- #ifdef m68851
- if (c2 == 'a' && c3 == 'l') {
- n = 3;
- ret = CAL;
- } else
- #endif
- /* This supports both CCR and CC as the ccr reg. */
- if(c2=='c' && c3=='r') {
- n=3;
- ret = CCR;
- } else if(c2=='c') {
- n=2;
- ret = CCR;
- } else if(c2=='a' && (c3=='a' || c3=='c') && c4=='r') {
- n=4;
- ret = c3=='a' ? CAAR : CACR;
- }
- #ifdef m68851
- else if (c2 == 'r' && c3 == 'p') {
- n = 3;
- ret = (CRP);
- }
- #endif
- break;
- case 'd':
- if(c2>='0' && c2<='7') {
- n=2;
- ret = DATA+c2-'0';
- } else if(c2=='f' && c3=='c') {
- n=3;
- ret = DFC;
- }
- #ifdef m68851
- else if (c2 == 'r' && c3 == 'p') {
- n = 3;
- ret = (DRP);
- }
- #endif
- break;
- case 'f':
- if(c2=='p') {
- if(c3>='0' && c3<='7') {
- n=3;
- ret = FPREG+c3-'0';
- } else if(c3=='i') {
- n=3;
- ret = FPI;
- } else if(c3=='s') {
- n= (c4 == 'r' ? 4 : 3);
- ret = FPS;
- } else if(c3=='c') {
- n= (c4 == 'r' ? 4 : 3);
- ret = FPC;
- }
- }
- break;
- case 'i':
- if(c2=='s' && c3=='p') {
- n=3;
- ret = ISP;
- }
- break;
- case 'm':
- if(c2=='s' && c3=='p') {
- n=3;
- ret = MSP;
- }
- break;
- case 'p':
- if(c2=='c') {
- #ifdef m68851
- if(c3 == 's' && c4=='r') {
- n=4;
- ret = (PCSR);
- } else
- #endif
- {
- n=2;
- ret = PC;
- }
- }
- #ifdef m68851
- else if (c2 == 's' && c3 == 'r') {
- n = 3;
- ret = (PSR);
- }
- #endif
- break;
- case 's':
- #ifdef m68851
- if (c2 == 'c' && c3 == 'c') {
- n = 3;
- ret = (SCC);
- } else if (c2 == 'r' && c3 == 'p') {
- n = 3;
- ret = (SRP);
- } else
- #endif
- if(c2=='r') {
- n=2;
- ret = SR;
- } else if(c2=='p') {
- n=2;
- ret = ADDR+7;
- } else if(c2=='f' && c3=='c') {
- n=3;
- ret = SFC;
- }
- break;
- #ifdef m68851
- case 't':
- if(c2 == 'c') {
- n=2;
- ret=TC;
- }
- break;
- #endif
- case 'u':
- if(c2=='s' && c3=='p') {
- n=3;
- ret = USP;
- }
- break;
- case 'v':
- #ifdef m68851
- if (c2 == 'a' && c3 == 'l') {
- n = 3;
- ret = (VAL);
- } else
- #endif
- if(c2=='b' && c3=='r') {
- n=3;
- ret = VBR;
- }
- break;
- case 'z':
- if(c2=='p' && c3=='c') {
- n=3;
- ret = ZPC;
- }
- break;
- default:
- break;
- }
- if(n) {
- if(isalnum(ccp[0][n]) || ccp[0][n]=='_')
- ret=FAIL;
- else
- ccp[0]+=n;
- } else
- ret = FAIL;
- return ret;
- }
- #define SKIP_WHITE() { str++; if(*str==' ') str++;}
- int
- m68k_ip_op(str,opP)
- char *str;
- register struct m68k_op *opP;
- {
- char *strend;
- long i;
- char *parse_index();
- if(*str==' ')
- str++;
- /* Find the end of the string */
- if(!*str) {
- /* Out of gas */
- opP->error="Missing operand";
- return FAIL;
- }
- for(strend=str;*strend;strend++)
- ;
- --strend;
- /* Guess what: A constant. Shar and enjoy */
- if(*str=='#') {
- str++;
- opP->con1=add_exp(str,strend);
- opP->mode=IMMED;
- return OK;
- }
- i=m68k_reg_parse(&str);
- if((i==FAIL || *str!='\0') && *str!='@') {
- char *stmp;
- char *index();
- if(i!=FAIL && (*str=='/' || *str=='-')) {
- opP->mode=REGLST;
- return get_regs(i,str,opP);
- }
- if(stmp=index(str,'@')) {
- opP->con1=add_exp(str,stmp-1);
- if(stmp==strend) {
- opP->mode=AINDX;
- return OK;
- }
- stmp++;
- if(*stmp++!='(' || *strend--!=')') {
- opP->error="Malformed operand";
- return FAIL;
- }
- i=try_index(&stmp,opP);
- opP->con2=add_exp(stmp,strend);
- if(i==FAIL) opP->mode=AMIND;
- else opP->mode=APODX;
- return OK;
- }
- opP->mode=ABSL;
- if(strend[-1]==':') { /* mode ==foo:[wl] */
- switch(*strend) {
- case 'w':
- case 'W':
- opP->isiz=2;
- break;
- case 'l':
- case 'L':
- opP->isiz=3;
- break;
- default:
- opP->error="size spec not :w or :l";
- return FAIL;
- }
- strend-=2;
- } else {
- opP->isiz=0;
- }
- opP->con1=add_exp(str,strend);
- return OK;
- }
- opP->reg=i;
- if(*str=='\0') {
- if(i>=DATA+0 && i<=DATA+7)
- opP->mode=DREG;
- else if(i>=ADDR+0 && i<=ADDR+7)
- opP->mode=AREG;
- else
- opP->mode=MSCR;
- return OK;
- }
- if((i<ADDR+0 || i>ADDR+7) && i!=PC && i!=ZPC && i!=FAIL) { /* Can't indirect off non address regs */
- opP->error="Invalid indirect register";
- return FAIL;
- }
- if(*str!='@')
- abort();
- str++;
- switch(*str) {
- case '\0':
- opP->mode=AINDR;
- return OK;
- case '-':
- opP->mode=ADEC;
- return OK;
- case '+':
- opP->mode=AINC;
- return OK;
- case '(':
- str++;
- break;
- default:
- opP->error="Junk after indirect";
- return FAIL;
- }
- /* Some kind of indexing involved. Lets find out how bad it is */
- i=try_index(&str,opP);
- /* Didn't start with an index reg, maybe its offset or offset,reg */
- if(i==FAIL) {
- char *beg_str;
- beg_str=str;
- for(i=1;i;) {
- switch(*str++) {
- case '\0':
- opP->error="Missing )";
- return FAIL;
- case ',': i=0; break;
- case '(': i++; break;
- case ')': --i; break;
- }
- }
- opP->con1=add_exp(beg_str,str-2);
- /* Should be offset,reg */
- if(str[-1]==',') {
- i=try_index(&str,opP);
- if(i==FAIL) {
- opP->error="Malformed index reg";
- return FAIL;
- }
- }
- }
- /* We've now got offset) offset,reg) or reg) */
- if(*str=='\0') {
- /* Th-the-thats all folks */
- if(opP->reg==FAIL) opP->mode=AINDX; /* Other form of indirect */
- else if(opP->ireg==FAIL) opP->mode=AOFF;
- else opP->mode=AINDX;
- return OK;
- }
- /* Next thing had better be another @ */
- if(*str!='@' || str[1]!='(') {
- opP->error="junk after indirect";
- return FAIL;
- }
- str+=2;
- if(opP->ireg!=FAIL) {
- opP->mode=APRDX;
- i=try_index(&str,opP);
- if(i!=FAIL) {
- opP->error="Two index registers! not allowed!";
- return FAIL;
- }
- } else
- i=try_index(&str,opP);
- if(i==FAIL) {
- char *beg_str;
- beg_str=str;
- for(i=1;i;) {
- switch(*str++) {
- case '\0':
- opP->error="Missing )";
- return FAIL;
- case ',': i=0; break;
- case '(': i++; break;
- case ')': --i; break;
- }
- }
- opP->con2=add_exp(beg_str,str-2);
- if(str[-1]==',') {
- if(opP->ireg!=FAIL) {
- opP->error="Can't have two index regs";
- return FAIL;
- }
- i=try_index(&str,opP);
- if(i==FAIL) {
- opP->error="malformed index reg";
- return FAIL;
- }
- opP->mode=APODX;
- } else if(opP->ireg!=FAIL)
- opP->mode=APRDX;
- else
- opP->mode=AMIND;
- } else
- opP->mode=APODX;
- if(*str!='\0') {
- opP->error="Junk after indirect";
- return FAIL;
- }
- return OK;
- }
- int
- try_index(s,opP)
- char **s;
- struct m68k_op *opP;
- {
- register int i;
- char *ss;
- #define SKIP_W() { ss++; if(*ss==' ') ss++;}
- ss= *s;
- /* SKIP_W(); */
- i=m68k_reg_parse(&ss);
- if(!(i>=DATA+0 && i<=ADDR+7)) { /* if i is not DATA or ADDR reg */
- *s=ss;
- return FAIL;
- }
- opP->ireg=i;
- /* SKIP_W(); */
- if(*ss==')') {
- opP->isiz=0;
- opP->imul=1;
- SKIP_W();
- *s=ss;
- return OK;
- }
- if(*ss!=':') {
- opP->error="Missing : in index register";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- if(mklower(*ss)=='w') opP->isiz=2;
- else if(mklower(*ss)=='l') opP->isiz=3;
- else {
- opP->error="Size spec not :w or :l";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- if(*ss==':') {
- SKIP_W();
- switch(*ss) {
- case '1':
- case '2':
- case '4':
- case '8':
- opP->imul= *ss-'0';
- break;
- default:
- opP->error="index multiplier not 1, 2, 4 or 8";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- } else opP->imul=1;
- if(*ss!=')') {
- opP->error="Missing )";
- *s=ss;
- return FAIL;
- }
- SKIP_W();
- *s=ss;
- return OK;
- }
- #ifdef TEST1 /* TEST1 tests m68k_ip_op(), which parses operands */
- main()
- {
- char buf[128];
- struct m68k_op thark;
- for(;;) {
- if(!gets(buf))
- break;
- bzero(&thark,sizeof(thark));
- if(!m68k_ip_op(buf,&thark)) printf("FAIL:");
- if(thark.error)
- printf("op1 error %s in %s\n",thark.error,buf);
- printf("mode %d, reg %d, ",thark.mode,thark.reg);
- if(thark.b_const)
- printf("Constant: '%.*s',",1+thark.e_const-thark.b_const,thark.b_const);
- printf("ireg %d, isiz %d, imul %d ",thark.ireg,thark.isiz,thark.imul);
- if(thark.b_iadd)
- printf("Iadd: '%.*s'",1+thark.e_iadd-thark.b_iadd,thark.b_iadd);
- printf("\n");
- }
- exit(0);
- }
- #endif
- static struct hash_control* op_hash = NULL; /* handle of the OPCODE hash table
- NULL means any use before m68_ip_begin()
- will crash */
- /*
- * m 6 8 _ i p ( )
- *
- * This converts a string into a 68k instruction.
- * The string must be a bare single instruction in sun format
- * with RMS-style 68020 indirects
- * (example: )
- *
- * It provides some error messages: at most one fatal error message (which
- * stops the scan) and at most one warning message for each operand.
- * The 68k instruction is returned in exploded form, since we have no
- * knowledge of how you parse (or evaluate) your expressions.
- * We do however strip off and decode addressing modes and operation
- * mnemonic.
- *
- * This function's value is a string. If it is not "" then an internal
- * logic error was found: read this code to assign meaning to the string.
- * No argument string should generate such an error string:
- * it means a bug in our code, not in the user's text.
- *
- * You MUST have called m86_ip_begin() once and m86_ip_end() never before using
- * this function.
- */
- /* JF this function no longer returns a useful value. Sorry */
- void
- m68_ip (instring)
- char *instring;
- {
- register char *p;
- register struct m68k_op *opP;
- register struct m68_incant *opcode;
- register char *s;
- register int tmpreg,
- baseo,
- outro,
- nextword;
- int siz1,
- siz2;
- char c;
- int losing;
- int opsfound;
- char *crack_operand();
- char *atof_m68k();
- LITTLENUM_TYPE words[6];
- LITTLENUM_TYPE *wordp;
- if (*instring == ' ')
- instring++; /* skip leading whitespace */
- /* Scan up to end of operation-code, which MUST end in end-of-string
- or exactly 1 space. */
- for (p = instring; *p != '\0'; p++)
- if (*p == ' ')
- break;
- if (p == instring) {
- the_ins.error = "No operator";
- the_ins.opcode[0] = NULL;
- /* the_ins.numo=1; */
- return;
- }
- /* p now points to the end of the opcode name, probably whitespace.
- make sure the name is null terminated by clobbering the whitespace,
- look it up in the hash table, then fix it back. */
- c = *p;
- *p = '\0';
- opcode = (struct m68_incant *)hash_find (op_hash, instring);
- *p = c;
- if (opcode == NULL) {
- the_ins.error = "Unknown operator";
- the_ins.opcode[0] = NULL;
- /* the_ins.numo=1; */
- return;
- }
- /* found a legitimate opcode, start matching operands */
- for(opP= &the_ins.operands[0];*p;opP++) {
- p = crack_operand (p, opP);
- if(opP->error) {
- the_ins.error=opP->error;
- return;
- }
- }
- opsfound=opP- &the_ins.operands[0];
- /* This ugly hack is to support the floating pt opcodes in their standard form */
- /* Essentially, we fake a first enty of type COP#1 */
- if(opcode->m_operands[0]=='I') {
- int n;
- for(n=opsfound;n>0;--n)
- the_ins.operands[n]=the_ins.operands[n-1];
- /* bcopy((char *)(&the_ins.operands[0]),(char *)(&the_ins.operands[1]),opsfound*sizeof(the_ins.operands[0])); */
- bzero((char *)(&the_ins.operands[0]),sizeof(the_ins.operands[0]));
- the_ins.operands[0].mode=MSCR;
- the_ins.operands[0].reg=COPNUM; /* COP #1 */
- opsfound++;
- }
- /* We've got the operands. Find an opcode that'll
- accept them */
- for(losing=0;;) {
- if(opsfound!=opcode->m_opnum)
- losing++;
- else for(s=opcode->m_operands,opP= &the_ins.operands[0];*s && !losing;s+=2,opP++) {
- /* Warning: this switch is huge! */
- /* I've tried to organize the cases into this order:
- non-alpha first, then alpha by letter. lower-case goes directly
- before uppercase counterpart. */
- /* Code with multiple case ...: gets sorted by the lowest case ...
- it belongs to. I hope this makes sense. */
- switch(*s) {
- case '!':
- if(opP->mode==MSCR || opP->mode==IMMED ||
- opP->mode==DREG || opP->mode==AREG || opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
- losing++;
- break;
- case '#':
- if(opP->mode!=IMMED)
- losing++;
- else {
- long t;
- t=get_num(opP->con1,80);
- if(s[1]=='b' && !isbyte(t))
- losing++;
- else if(s[1]=='w' && !isword(t))
- losing++;
- }
- break;
- case '^':
- case 'T':
- if(opP->mode!=IMMED)
- losing++;
- break;
- case '$':
- if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
- losing++;
- break;
- case '%':
- if(opP->mode==MSCR || opP->reg==PC ||
- opP->reg==ZPC || opP->mode==REGLST)
- losing++;
- break;
- case '&':
- if(opP->mode==MSCR || opP->mode==DREG ||
- opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC ||
- opP->mode==AINC || opP->mode==ADEC || opP->mode==REGLST)
- losing++;
- break;
- case '*':
- if(opP->mode==MSCR || opP->mode==REGLST)
- losing++;
- break;
- case '+':
- if(opP->mode!=AINC)
- losing++;
- break;
- case '-':
- if(opP->mode!=ADEC)
- losing++;
- break;
- case '/':
- if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->mode==REGLST)
- losing++;
- break;
- case ';':
- if(opP->mode==MSCR || opP->mode==AREG || opP->mode==REGLST)
- losing++;
- break;
- case '?':
- if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==AINC || opP->mode==ADEC || opP->mode==IMMED || opP->reg==PC ||
- opP->reg==ZPC || opP->mode==REGLST)
- losing++;
- break;
- case '@':
- if(opP->mode==MSCR || opP->mode==AREG ||
- opP->mode==IMMED || opP->mode==REGLST)
- losing++;
- break;
- case '~': /* For now! (JF FOO is this right?) */
- if(opP->mode==MSCR || opP->mode==DREG ||
- opP->mode==AREG || opP->mode==IMMED || opP->reg==PC || opP->reg==ZPC || opP->mode==REGLST)
- losing++;
- break;
- case 'A':
- if(opP->mode!=AREG)
- losing++;
- break;
- case 'B': /* FOO */
- if(opP->mode!=ABSL)
- losing++;
- break;
- case 'C':
- if(opP->mode!=MSCR || opP->reg!=CCR)
- losing++;
- break;
- case 'd': /* FOO This mode is a KLUDGE!! */
- if(opP->mode!=AOFF && (opP->mode!=ABSL ||
- opP->con1->e_beg[0]!='(' || opP->con1->e_end[0]!=')'))
- losing++;
- break;
- case 'D':
- if(opP->mode!=DREG)
- losing++;
- break;
- case 'F':
- if(opP->mode!=MSCR || opP->reg<(FPREG+0) || opP->reg>(FPREG+7))
- losing++;
- break;
- case 'I':
- if(opP->mode!=MSCR || opP->reg<COPNUM ||
- opP->reg>=COPNUM+7)
- losing++;
- break;
- case 'J':
- if(opP->mode!=MSCR || opP->reg<USP || opP->reg>MSP)
- losing++;
- break;
- case 'k':
- if(opP->mode!=IMMED)
- losing++;
- break;
- case 'l':
- case 'L':
- if(opP->mode==DREG || opP->mode==AREG || opP->mode==FPREG) {
- if(s[1]=='8')
- losing++;
- else {
- opP->mode=REGLST;
- opP->reg=1<<(opP->reg-DATA);
- }
- } else if(opP->mode!=REGLST) {
- losing++;
- } else if(s[1]=='8' && opP->reg&0x0FFffFF)
- losing++;
- else if(s[1]=='3' && opP->reg&0x7000000)
- losing++;
- break;
- case 'M':
- if(opP->mode!=IMMED)
- losing++;
- else {
- long t;
- t=get_num(opP->con1,80);
- if(!issbyte(t) || isvar(opP->con1))
- losing++;
- }
- break;
- case 'O':
- if(opP->mode!=DREG && opP->mode!=IMMED)
- losing++;
- break;
- case 'Q':
- if(opP->mode!=IMMED)
- losing++;
- else {
- long t;
- t=get_num(opP->con1,80);
- if(t<1 || t>8 || isvar(opP->con1))
- losing++;
- }
- break;
- case 'R':
- if(opP->mode!=DREG && opP->mode!=AREG)
- losing++;
- break;
- case 's':
- if(opP->mode!=MSCR || !(opP->reg==FPI || opP->reg==FPS || opP->reg==FPC))
- losing++;
- break;
- case 'S':
- if(opP->mode!=MSCR || opP->reg!=SR)
- losing++;
- break;
- case 'U':
- if(opP->mode!=MSCR || opP->reg!=USP)
- losing++;
- break;
- /* JF these are out of order. We could put them
- in order if we were willing to put up with
- bunches of #ifdef m68851s in the code */
- #ifdef m68851
- /* Memory addressing mode used by pflushr */
- case '|':
- if(opP->mode==MSCR || opP->mode==DREG ||
- opP->mode==AREG || opP->mode==REGLST)
- losing++;
- break;
- case 'f':
- if (opP->mode != MSCR || (opP->reg != SFC && opP->reg != DFC))
- losing++;
- break;
- case 'P':
- if (opP->mode != MSCR || (opP->reg != TC && opP->reg != CAL &&
- opP->reg != VAL && opP->reg != SCC && opP->reg != AC))
- losing++;
- break;
- case 'V':
- if (opP->reg != VAL)
- losing++;
- break;
- case 'W':
- if (opP->mode != MSCR || (opP->reg != DRP && opP->reg != SRP &&
- opP->reg != CRP))
- losing++;
- break;
- case 'X':
- if (opP->mode != MSCR ||
- (!(opP->reg >= BAD && opP->reg <= BAD+7) &&
- !(opP->reg >= BAC && opP->reg <= BAC+7)))
- losing++;
- break;
- case 'Y':
- if (opP->reg != PSR)
- losing++;
- break;
- case 'Z':
- if (opP->reg != PCSR)
- losing++;
- break;
- #endif
- default:
- as_fatal("Internal error: Operand mode %c unknown",*s);
- }
- }
- if(!losing)
- break;
- opcode=opcode->m_next;
- if(!opcode) { /* Fell off the end */
- the_ins.error="instruction/operands mismatch";
- return;
- }
- losing=0;
- }
- the_ins.args=opcode->m_operands;
- the_ins.numargs=opcode->m_opnum;
- the_ins.numo=opcode->m_codenum;
- the_ins.opcode[0]=getone(opcode);
- the_ins.opcode[1]=gettwo(opcode);
- for(s=the_ins.args,opP= &the_ins.operands[0];*s;s+=2,opP++) {
- /* This switch is a doozy.
- What the first step; its a big one! */
- switch(s[0]) {
- case '*':
- case '~':
- case '%':
- case ';':
- case '@':
- case '!':
- case '&':
- case '$':
- case '?':
- case '/':
- #ifdef m68851
- case '|':
- #endif
- switch(opP->mode) {
- case IMMED:
- tmpreg=0x3c; /* 7.4 */
- if(index("bwl",s[1])) nextword=get_num(opP->con1,80);
- else nextword=nextword=get_num(opP->con1,0);
- if(isvar(opP->con1))
- add_fix(s[1],opP->con1,0);
- switch(s[1]) {
- case 'b':
- if(!isbyte(nextword))
- opP->error="operand out of range";
- addword(nextword);
- baseo=0;
- break;
- case 'w':
- if(!isword(nextword))
- opP->error="operand out of range";
- addword(nextword);
- baseo=0;
- break;
- case 'l':
- addword(nextword>>16);
- addword(nextword);
- baseo=0;
- break;
- case 'f':
- baseo=2;
- outro=8;
- break;
- case 'F':
- baseo=4;
- outro=11;
- break;
- case 'x':
- baseo=6;
- outro=15;
- break;
- case 'p':
- baseo=6;
- outro= -1;
- break;
- default:
- as_fatal("Internal error: Can't decode %c%c",*s,s[1]);
- }
- if(!baseo)
- break;
- /* We gotta put out some float */
- if(seg(opP->con1)!=SEG_BIG) {
- int_to_gen(nextword);
- gen_to_words(words,baseo,(long int)outro);
- for(wordp=words;baseo--;wordp++)
- addword(*wordp);
- break;
- } /* Its BIG */
- if(offs(opP->con1)>0) {
- as_warn("Bignum assumed to be binary bit-pattern");
- if(offs(opP->con1)>baseo) {
- as_warn("Bignum too big for %c format; truncated",s[1]);
- offs(opP->con1)=baseo;
- }
- baseo-=offs(opP->con1);
- for(wordp=generic_bignum+offs(opP->con1)-1;offs(opP->con1)--;--wordp)
- addword(*wordp);
- while(baseo--)
- addword(0);
- break;
- }
- gen_to_words(words,baseo,(long int)outro);
- for(wordp=words;baseo--;wordp++)
- addword(*wordp);
- break;
- case DREG:
- tmpreg=opP->reg-DATA; /* 0.dreg */
- break;
- case AREG:
- tmpreg=0x08+opP->reg-ADDR; /* 1.areg */
- break;
- case AINDR:
- tmpreg=0x10+opP->reg-ADDR; /* 2.areg */
- break;
- case ADEC:
- tmpreg=0x20+opP->reg-ADDR; /* 4.areg */
- break;
- case AINC:
- tmpreg=0x18+opP->reg-ADDR; /* 3.areg */
- break;
- case AOFF:
- if(opP->reg==PC)
- tmpreg=0x3A; /* 7.2 */
- else
- tmpreg=0x28+opP->reg-ADDR; /* 5.areg */
- nextword=get_num(opP->con1,80);
- /* Force into index mode. Hope this works */
- if(!issword(nextword)) {
- if(opP->reg==PC)
- tmpreg=0x3B; /* 7.3 */
- else
- tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
- /* addword(0x0171); */
- /* 171 seems to be wrong, and I can't find the 68020 manual, so we'll try 170
- (which is what the Sun asm seems to generate */
- addword(0x0170);
- if(isvar(opP->con1))
- add_fix('l',opP->con1,0);
- addword(nextword>>16);
- /* addword(nextword); */
- } else if(isvar(opP->con1)) {
- if(!flagseen['l']) {
- add_fix('w',opP->con1,0);
- } else {
- tmpreg=0x30+opP->reg-ADDR;
- addword(0x0170);
- add_fix('l',opP->con1,0);
- addword(nextword>>16);
- }
- }
- addword(nextword);
- break;
- case AINDX:
- case APODX:
- case AMIND:
- case APRDX:
- nextword=0;
- baseo=get_num(opP->con1,80);
- outro=get_num(opP->con2,80);
- /* Figure out the 'addressing mode' */
- /* Also turn on the BASE_DISABLE bit, if needed */
- if(opP->reg==PC || opP->reg==ZPC) {
- tmpreg=0x3b; /* 7.3 */
- if(opP->reg==ZPC)
- nextword|=0x80;
- } else if(opP->reg==FAIL) {
- nextword|=0x80;
- tmpreg=0x30; /* 6.garbage */
- } else tmpreg=0x30+opP->reg-ADDR; /* 6.areg */
- siz1= (opP->con1) ? opP->con1->e_siz : 0;
- siz2= (opP->con2) ? opP->con2->e_siz : 0;
- /* Index register stuff */
- if(opP->ireg>=DATA+0 && opP->ireg<=ADDR+7) {
- nextword|=(opP->ireg-DATA)<<12;
- if(opP->isiz==0 || opP->isiz==3)
- nextword|=0x800;
- switch(opP->imul) {
- case 1: break;
- case 2: nextword|=0x200; break;
- case 4: nextword|=0x400; break;
- case 8: nextword|=0x600; break;
- default: abort();
- }
- /* IF its simple, GET US OUT OF HERE! */
- /* Must be INDEX, with an index register. Address register
- cannot be ZERO-PC, and either :b was forced, or we know it'll fit */
- if(opP->mode==AINDX &&
- opP->reg!=FAIL && opP->reg!=ZPC && (siz1==1 || (issbyte(baseo) &&
- !isvar(opP->con1)))) {
- nextword +=baseo&0xff;
- addword(nextword);
- if(isvar(opP->con1))
- add_fix('B',opP->con1,0);
- break;
- }
- } else
- nextword|=0x40; /* No index reg */
-
- /* It aint simple */
- nextword|=0x100;
- /* If the guy specified a width, we assume that
- it is wide enough. Maybe it isn't. Ifso, we lose
- */
- switch(siz1) {
- case 0:
- if(isvar(opP->con1) || !issword(baseo)) {
- siz1=3;
- nextword|=0x30;
- } else if(baseo==0)
- nextword|=0x10;
- else {
- nextword|=0x20;
- siz1=2;
- }
- break;
- case 1:
- as_warn("Byte dispacement won't work. Defaulting to :w");
- case 2:
- nextword|=0x20;
- break;
- case 3:
- nextword|=0x30;
- break;
- }
- /* Figure out innner displacement stuff */
- if(opP->mode!=AINDX) {
- switch(siz2) {
- case 0:
- if(isvar(opP->con2) || !issword(outro)) {
- siz2=3;
- nextword|=0x3;
- } else if(outro==0)
- nextword|=0x1;
- else {
- nextword|=0x2;
- siz2=2;
- }
- break;
- case 1:
- as_warn("Byte dispacement won't work. Defaulting to :w");
- case 2:
- nextword|=0x2;
- break;
- case 3:
- nextword|=0x3;
- break;
- }
- if(opP->mode==APODX) nextword|=0x04;
- else if(opP->mode==AMIND) nextword|=0x40;
- }
- addword(nextword);
- if(isvar(opP->con1))
- add_fix(siz1==3 ? 'l' : 'w',opP->con1,0);
- if(siz1==3)
- addword(baseo>>16);
- if(siz1)
- addword(baseo);
- if(isvar(opP->con2))
- add_fix(siz2==3 ? 'l' : 'w',opP->con2,0);
- if(siz2==3)
- addword(outro>>16);
- if(siz2)
- addword(outro);
- break;
- case ABSL:
- nextword=get_num(opP->con1,80);
- switch(opP->isiz) {
- case 0:
- if(!isvar(opP->con1) && issword(offs(opP->con1))) {
- tmpreg=0x38; /* 7.0 */
- addword(nextword);
- break;
- }
- /* Don't generate pc relative code
- on 68010 and 68000 */
- if(isvar(opP->con1) &&
- !subs(opP->con1) &&
- seg(opP->con1)==SEG_TEXT &&
- now_seg==SEG_TEXT &&
- flagseen['m']==0 &&
- !index("~%&$?", s[0])) {
- tmpreg=0x3A; /* 7.2 */
- add_frag(adds(opP->con1),
- offs(opP->con1),
- TAB(PCREL,SZ_UNDEF));
- break;
- }
- case 3: /* Fall through into long */
- if(isvar(opP->con1))
- add_fix('l',opP->con1,0);
- tmpreg=0x39; /* 7.1 mode */
- addword(nextword>>16);
- addword(nextword);
- break;
- case 2: /* Word */
- if(isvar(opP->con1))
- add_fix('w',opP->con1,0);
- tmpreg=0x38; /* 7.0 mode */
- addword(nextword);
- break;
- }
- break;
- case MSCR:
- default:
- as_warn("unknown/incorrect operand");
- /* abort(); */
- }
- install_gen_operand(s[1],tmpreg);
- break;
- case '#':
- case '^':
- switch(s[1]) { /* JF: I hate floating point! */
- case 'j':
- tmpreg=70;
- break;
- case '8':
- tmpreg=20;
- break;
- case 'C':
- tmpreg=50;
- break;
- case '3':
- default:
- tmpreg=80;
- break;
- }
- tmpreg=get_num(opP->con1,tmpreg);
- if(isvar(opP->con1))
- add_fix(s[1],opP->con1,0);
- switch(s[1]) {
- case 'b': /* Danger: These do no check for
- certain types of overflow.
- user beware! */
- if(!isbyte(tmpreg))
- opP->error="out of range";
- insop(tmpreg);
- if(isvar(opP->con1))
- the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
- break;
- case 'w':
- if(!isword(tmpreg))
- opP->error="out of range";
- insop(tmpreg);
- if(isvar(opP->con1))
- the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
- break;
- case 'l':
- insop(tmpreg); /* Because of the way insop works, we put these two out backwards */
- insop(tmpreg>>16);
- if(isvar(opP->con1))
- the_ins.reloc[the_ins.nrel-1].n=(opcode->m_codenum)*2;
- break;
- case '3':
- tmpreg&=0xFF;
- case '8':
- case 'C':
- install_operand(s[1],tmpreg);
- break;
- default:
- as_fatal("Internal error: Unknown mode #%c",s[1]);
- }
- break;
- case '+':
- case '-':
- case 'A':
- install_operand(s[1],opP->reg-ADDR);
- break;
- case 'B':
- tmpreg=get_num(opP->con1,80);
- switch(s[1]) {
- case 'g':
- if(opP->con1->e_siz) { /* Deal with fixed size stuff by hand */
- switch(opP->con1->e_siz) {
- case 1:
- add_fix('b',opP->con1,1);
- break;
- case 2:
- add_fix('w',opP->con1,1);
- addword(0);
- break;
- case 3:
- add_fix('l',opP->con1,1);
- addword(0);
- addword(0);
- break;
- default:
- as_fatal("Bad size for expression %d",opP->con1->e_siz);
- }
- } else if(subs(opP->con1)) {
- /* We can't relax it */
- the_ins.opcode[the_ins.numo-1]|=0xff;
- add_fix('l',opP->con1,1);
- addword(0);
- addword(0);
- } else if(adds(opP->con1)) {
- if (flagseen['m'] &&
- (the_ins.opcode[0] >= 0x6200) &&
- (the_ins.opcode[0] <= 0x6f00)) {
- add_frag(adds(opP->con1),offs(opP->con1),TAB(BCC68000,SZ_UNDEF));
- } else {
- add_frag(adds(opP->con1),offs(opP->con1),TAB(BRANCH,SZ_UNDEF));
- }
- } else {
- /* JF: This is the WRONG thing to do
- add_frag((symbolS *)0,offs(opP->con1),TAB(BRANCH,BYTE)); */
- the_ins.opcode[the_ins.numo-1]|=0xff;
- add_fix('l',opP->con1,1);
- addword(0);
- addword(4);
- }
- break;
- case 'w':
- if(isvar(opP->con1)) {
- /* check for DBcc instruction */
- if ((the_ins.opcode[0] & 0xf0f8) ==0x50c8){
- /* size varies if patch */
- /* needed for long form */
- add_frag(adds(opP->con1),offs(opP->con1),TAB(DBCC,SZ_UNDEF));
- break;
- }
-
- /* Don't ask! */
- opP->con1->e_exp.X_add_number+=2;
- add_fix('w',opP->con1,1);
- }
- addword(0);
- break;
- case 'c':
- if(opP->con1->e_siz) {
- switch(opP->con1->e_siz) {
- case 2:
- add_fix('w',opP->con1,1)
- addword(0);
- break;
- case 3:
- the_ins.opcode[the_ins.numo-1]|=0x40;
- add_fix('l',opP->con1,1);
- addword(0);
- addword(0);
- break;
- default:
- as_warn("Bad size for offset, must be word or long");
- break;
- }
- } else if(subs(opP->con1)) {
- add_fix('l',opP->con1,1);
- add_frag((symbolS *)0,(long)0,TAB(FBRANCH,LONG));
- } else if(adds(opP->con1)) {
- add_frag(adds(opP->con1),offs(opP->con1),TAB(FBRANCH,SZ_UNDEF));
- } else {
- /* add_frag((symbolS *)0,offs(opP->con1),TAB(FBRANCH,SHORT)); */
- the_ins.opcode[the_ins.numo-1]|=0x40;
- add_fix('l',opP->con1,1);
- addword(0);
- addword(4);
- }
- break;
- default:
- as_fatal("Internal error: operand type B%c unknown",s[1]);
- }
- break;
- case 'C': /* Ignore it */
- break;
- case 'd': /* JF this is a kludge */
- if(opP->mode==AOFF) {
- install_operand('s',opP->reg-ADDR);
- } else {
- char *tmpP;
- tmpP=opP->con1->e_end-2;
- opP->con1->e_beg++;
- opP->con1->e_end-=4; /* point to the , */
- baseo=m68k_reg_parse(&tmpP);
- if(baseo<ADDR+0 || baseo>ADDR+7) {
- as_warn("Unknown address reg, using A0");
- baseo=0;
- } else baseo-=ADDR;
- install_operand('s',baseo);
- }
- tmpreg=get_num(opP->con1,80);
- if(!issword(tmpreg)) {
- as_warn("Expression out of range, using 0");
- tmpreg=0;
- }
- addword(tmpreg);
- break;
- case 'D':
- install_operand(s[1],opP->reg-DATA);
- break;
- case 'F':
- install_operand(s[1],opP->reg-FPREG);
- break;
- case 'I':
- tmpreg=1+opP->reg-COPNUM;
- if(tmpreg==8)
- tmpreg=0;
- install_operand(s[1],tmpreg);
- break;
- case 'J': /* JF foo */
- switch(opP->reg) {
- case SFC:
- tmpreg=0;
- break;
- case DFC:
- tmpreg=0x001;
- break;
- case CACR:
- tmpreg=0x002;
- break;
- case USP:
- tmpreg=0x800;
- break;
- case VBR:
- tmpreg=0x801;
- break;
- case CAAR:
- tmpreg=0x802;
- break;
- case MSP:
- tmpreg=0x803;
- break;
- case ISP:
- tmpreg=0x804;
- break;
- default:
- abort();
- }
- install_operand(s[1],tmpreg);
- break;
- case 'k':
- tmpreg=get_num(opP->con1,55);
- install_operand(s[1],tmpreg&0x7f);
- break;
- case 'l':
- tmpreg=opP->reg;
- if(s[1]=='w') {
- if(tmpreg&0x7FF0000)
- as_warn("Floating point register in register list");
- insop(reverse_16_bits(tmpreg));
- } else {
- if(tmpreg&0x700FFFF)
- as_warn("Wrong register in floating-point reglist");
- install_operand(s[1],reverse_8_bits(tmpreg>>16));
- }
- break;
- case 'L':
- tmpreg=opP->reg;
- if(s[1]=='w') {
- if(tmpreg&0x7FF0000)
- as_warn("Floating point register in register list");
- insop(tmpreg);
- } else if(s[1]=='8') {
- if(tmpreg&0x0FFFFFF)
- as_warn("incorrect register in reglist");
- install_operand(s[1],tmpreg>>24);
- } else {
- if(tmpreg&0x700FFFF)
- as_warn("wrong register in floating-point reglist");
- else
- install_operand(s[1],tmpreg>>16);
- }
- break;
- case 'M':
- install_operand(s[1],get_num(opP->con1,60));
- break;
- case 'O':
- tmpreg= (opP->mode==DREG)
- ? 0x20+opP->reg-DATA
- : (get_num(opP->con1,40)&0x1F);
- install_operand(s[1],tmpreg);
- break;
- case 'Q':
- tmpreg=get_num(opP->con1,10);
- if(tmpreg==8)
- tmpreg=0;
- install_operand(s[1],tmpreg);
- break;
- case 'R':
- /* This depends on the fact that ADDR registers are
- eight more than their corresponding DATA regs, so
- the result will have the ADDR_REG bit set */
- install_operand(s[1],opP->reg-DATA);
- break;
- case 's':
- if(opP->reg==FPI) tmpreg=0x1;
- else if(opP->reg==FPS) tmpreg=0x2;
- else if(opP->reg==FPC) tmpreg=0x4;
- else abort();
- install_operand(s[1],tmpreg);
- break;
- case 'S': /* Ignore it */
- break;
- case 'T':
- install_operand(s[1],get_num(opP->con1,30));
- break;
- case 'U': /* Ignore it */
- break;
- #ifdef m68851
- /* JF: These are out of order, I fear. */
- case 'f':
- switch (opP->reg) {
- case SFC:
- tmpreg=0;
- break;
- case DFC:
- tmpreg=1;
- break;
- default:
- abort();
- }
- install_operand(s[1],tmpreg);
- break;
- case 'P':
- switch(opP->reg) {
- case TC:
- tmpreg=0;
- break;
- case CAL:
- tmpreg=4;
- break;
- case VAL:
- tmpreg=5;
- break;
- case SCC:
- tmpreg=6;
- break;
- case AC:
- tmpreg=7;
- break;
- default:
- abort();
- }
- install_operand(s[1],tmpreg);
- break;
- case 'V':
- if (opP->reg == VAL)
- break;
- abort();
- case 'W':
- switch(opP->reg) {
- case DRP:
- tmpreg=1;
- break;
- case SRP:
- tmpreg=2;
- break;
- case CRP:
- tmpreg=3;
- break;
- default:
- abort();
- }
- install_operand(s[1],tmpreg);
- break;
- case 'X':
- switch (opP->reg) {
- case BAD: case BAD+1: case BAD+2: case BAD+3:
- case BAD+4: case BAD+5: case BAD+6: case BAD+7:
- tmpreg = (4 << 10) | ((opP->reg - BAD) << 2);
- break;
- case BAC: case BAC+1: case BAC+2: case BAC+3:
- case BAC+4: case BAC+5: case BAC+6: case BAC+7:
- tmpreg = (5 << 10) | ((opP->reg - BAC) << 2);
- break;
- default:
- abort();
- }
- install_operand(s[1], tmpreg);
- break;
- case 'Y':
- if (opP->reg == PSR)
- break;
- abort();
- case 'Z':
- if (opP->reg == PCSR)
- break;
- abort;
- #endif /* m68851 */
- default:
- as_fatal("Internal error: Operand type %c unknown",s[0]);
- }
- }
- /* By the time whe get here (FINALLY) the_ins contains the complete
- instruction, ready to be emitted. . . */
- }
- int
- get_regs(i,str,opP)
- struct m68k_op *opP;
- char *str;
- {
- /* 26, 25, 24, 23-16, 15-8, 0-7 */
- /* Low order 24 bits encoded fpc,fps,fpi,fp7-fp0,a7-a0,d7-d0 */
- unsigned long int cur_regs = 0;
- int reg1,
- reg2;
- #define ADD_REG(x) { if(x==FPI) cur_regs|=(1<<24);\
- else if(x==FPS) cur_regs|=(1<<25);\
- else if(x==FPC) cur_regs|=(1<<26);\
- else cur_regs|=(1<<(x-1)); }
- reg1=i;
- for(;;) {
- if(*str=='/') {
- ADD_REG(reg1);
- str++;
- } else if(*str=='-') {
- str++;
- reg2=m68k_reg_parse(&str);
- if(reg2<DATA || reg2>=FPREG+8 || reg1==FPI || reg1==FPS || reg1==FPC) {
- opP->error="unknown register in register list";
- return FAIL;
- }
- while(reg1<=reg2) {
- ADD_REG(reg1);
- reg1++;
- }
- if(*str=='\0')
- break;
- } else if(*str=='\0') {
- ADD_REG(reg1);
- break;
- } else {
- opP->error="unknow character in register list";
- return FAIL;
- }
- /* DJA -- Bug Fix. Did't handle d1-d2/a1 until the following instruction was added */
- if (*str=='/')
- str ++;
- reg1=m68k_reg_parse(&str);
- if((reg1<DATA || reg1>=FPREG+8) && !(reg1==FPI || reg1==FPS || reg1==FPC)) {
- opP->error="unknown register in register list";
- return FAIL;
- }
- }
- opP->reg=cur_regs;
- return OK;
- }
- int
- reverse_16_bits(in)
- int in;
- {
- int out=0;
- int n;
- static int mask[16] = {
- 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
- 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
- };
- for(n=0;n<16;n++) {
- if(in&mask[n])
- out|=mask[15-n];
- }
- return out;
- }
- int
- reverse_8_bits(in)
- int in;
- {
- int out=0;
- int n;
- static int mask[8] = {
- 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
- };
- for(n=0;n<8;n++) {
- if(in&mask[n])
- out|=mask[7-n];
- }
- return out;
- }
-
- void
- install_operand(mode,val)
- int mode;
- int val;
- {
- switch(mode) {
- case 's':
- the_ins.opcode[0]|=val & 0xFF; /* JF FF is for M kludge */
- break;
- case 'd':
- the_ins.opcode[0]|=val<<9;
- break;
- case '1':
- the_ins.opcode[1]|=val<<12;
- break;
- case '2':
- the_ins.opcode[1]|=val<<6;
- break;
- case '3':
- the_ins.opcode[1]|=val;
- break;
- case '4':
- the_ins.opcode[2]|=val<<12;
- break;
- case '5':
- the_ins.opcode[2]|=val<<6;
- break;
- case '6':
- /* DANGER! This is a hack to force cas2l and cas2w cmds
- to be three words long! */
- the_ins.numo++;
- the_ins.opcode[2]|=val;
- break;
- case '7':
- the_ins.opcode[1]|=val<<7;
- break;
- case '8':
- the_ins.opcode[1]|=val<<10;
- break;
- #ifdef m68851
- case '9':
- the_ins.opcode[1]|=val<<5;
- break;
- #endif
-
- case 't':
- the_ins.opcode[1]|=(val<<10)|(val<<7);
- break;
- case 'D':
- the_ins.opcode[1]|=(val<<12)|val;
- break;
- case 'g':
- the_ins.opcode[0]|=val=0xff;
- break;
- case 'i':
- the_ins.opcode[0]|=val<<9;
- break;
- case 'C':
- the_ins.opcode[1]|=val;
- break;
- case 'j':
- the_ins.opcode[1]|=val;
- the_ins.numo++; /* What a hack */
- break;
- case 'k':
- the_ins.opcode[1]|=val<<4;
- break;
- case 'b':
- case 'w':
- case 'l':
- break;
- case 'c':
- default:
- abort();
- }
- }
- void
- install_gen_operand(mode,val)
- int mode;
- int val;
- {
- switch(mode) {
- case 's':
- the_ins.opcode[0]|=val;
- break;
- case 'd':
- /* This is a kludge!!! */
- the_ins.opcode[0]|=(val&0x07)<<9|(val&0x38)<<3;
- break;
- case 'b':
- case 'w':
- case 'l':
- case 'f':
- case 'F':
- case 'x':
- case 'p':
- the_ins.opcode[0]|=val;
- break;
- /* more stuff goes here */
- default:
- abort();
- }
- }
- char *
- crack_operand(str,opP)
- register char *str;
- register struct m68k_op *opP;
- {
- register int parens;
- register int c;
- register char *beg_str;
- if(!str) {
- return str;
- }
- beg_str=str;
- for(parens=0;*str && (parens>0 || notend(str));str++) {
- if(*str=='(') parens++;
- else if(*str==')') {
- if(!parens) { /* ERROR */
- opP->error="Extra )";
- return str;
- }
- --parens;
- }
- }
- if(!*str && parens) { /* ERROR */
- opP->error="Missing )";
- return str;
- }
- c= *str;
- *str='\0';
- if(m68k_ip_op(beg_str,opP)==FAIL) {
- *str=c;
- return str;
- }
- *str=c;
- if(c=='}')
- c= *++str; /* JF bitfield hack */
- if(c) {
- c= *++str;
- if(!c)
- as_warn("Missing operand");
- }
- return str;
- }
- /* See the comment up above where the #define notend(... is */
- #if 0
- notend(s)
- char *s;
- {
- if(*s==',') return 0;
- if(*s=='{' || *s=='}')
- return 0;
- if(*s!=':') return 1;
- /* This kludge here is for the division cmd, which is a kludge */
- if(index("aAdD#",s[1])) return 0;
- return 1;
- }
- #endif
- /* This is the guts of the machine-dependent assembler. STR points to a
- machine dependent instruction. This funciton is supposed to emit
- the frags/bytes it assembles to.
- */
- void
- md_assemble(str)
- char *str;
- {
- char *er;
- short *fromP;
- char *toP;
- int m,n;
- char *to_beg_P;
- int shorts_this_frag;
- bzero((char *)(&the_ins),sizeof(the_ins)); /* JF for paranoia sake */
- m68_ip(str);
- er=the_ins.error;
- if(!er) {
- for(n=the_ins.numargs;n;--n)
- if(the_ins.operands[n].error) {
- er=the_ins.operands[n].error;
- break;
- }
- }
- if(er) {
- as_warn("\"%s\" -- Statement '%s' ignored",er,str);
- return;
- }
- if(the_ins.nfrag==0) { /* No frag hacking involved; just put it out */
- toP=frag_more(2*the_ins.numo);
- fromP= &the_ins.opcode[0];
- for(m=the_ins.numo;m;--m) {
- md_number_to_chars(toP,(long)(*fromP),2);
- toP+=2;
- fromP++;
- }
- /* put out symbol-dependent info */
- for(m=0;m<the_ins.nrel;m++) {
- switch(the_ins.reloc[m].wid) {
- case 'B':
- n=1;
- break;
- case 'b':
- n=1;
- break;
- case 'w':
- n=2;
- break;
- case 'l':
- n=4;
- break;
- default:
- as_fatal("confusing width %c",the_ins.reloc[m].wid);
- }
- fix_new(frag_now,
- (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
- n,
- the_ins.reloc[m].add,
- the_ins.reloc[m].sub,
- the_ins.reloc[m].off,
- the_ins.reloc[m].pcrel);
- }
- return;
- }
- /* There's some frag hacking */
- for(n=0,fromP= &the_ins.opcode[0];n<the_ins.nfrag;n++) {
- int wid;
- if(n==0) wid=2*the_ins.fragb[n].fragoff;
- else wid=2*(the_ins.numo-the_ins.fragb[n-1].fragoff);
- toP=frag_more(wid);
- to_beg_P=toP;
- shorts_this_frag=0;
- for(m=wid/2;m;--m) {
- md_number_to_chars(toP,(long)(*fromP),2);
- toP+=2;
- fromP++;
- shorts_this_frag++;
- }
- for(m=0;m<the_ins.nrel;m++) {
- if((the_ins.reloc[m].n)>= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */) {
- the_ins.reloc[m].n-= 2*shorts_this_frag /* 2*the_ins.fragb[n].fragoff */;
- break;
- }
- wid=the_ins.reloc[m].wid;
- if(wid==0)
- continue;
- the_ins.reloc[m].wid=0;
- wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
- fix_new(frag_now,
- (toP-frag_now->fr_literal)-the_ins.numo*2+the_ins.reloc[m].n,
- wid,
- the_ins.reloc[m].add,
- the_ins.reloc[m].sub,
- the_ins.reloc[m].off,
- the_ins.reloc[m].pcrel);
- }
- know(the_ins.fragb[n].fadd);
- (void)frag_var(rs_machine_dependent,10,0,(relax_substateT)(the_ins.fragb[n].fragty),
- the_ins.fragb[n].fadd,the_ins.fragb[n].foff,to_beg_P);
- }
- n=(the_ins.numo-the_ins.fragb[n-1].fragoff);
- shorts_this_frag=0;
- if(n) {
- toP=frag_more(n*sizeof(short));
- while(n--) {
- md_number_to_chars(toP,(long)(*fromP),2);
- toP+=2;
- fromP++;
- shorts_this_frag++;
- }
- }
- for(m=0;m<the_ins.nrel;m++) {
- int wid;
- wid=the_ins.reloc[m].wid;
- if(wid==0)
- continue;
- the_ins.reloc[m].wid=0;
- wid = (wid=='b') ? 1 : (wid=='w') ? 2 : (wid=='l') ? 4 : 4000;
- fix_new(frag_now,
- (the_ins.reloc[m].n + toP-frag_now->fr_literal)-/* the_ins.numo */ shorts_this_frag*2,
- wid,
- the_ins.reloc[m].add,
- the_ins.reloc[m].sub,
- the_ins.reloc[m].off,
- the_ins.reloc[m].pcrel);
- }
- }
- /* This function is called once, at assembler startup time. This should
- set up all the tables, etc that the MD part of the assembler needs
- */
- void
- md_begin()
- {
- /*
- * md_begin -- set up hash tables with 68000 instructions.
- * similar to what the vax assembler does. ---phr
- */
- /* RMS claims the thing to do is take the m68k-opcode.h table, and make
- a copy of it at runtime, adding in the information we want but isn't
- there. I think it'd be better to have an awk script hack the table
- at compile time. Or even just xstr the table and use it as-is. But
- my lord ghod hath spoken, so we do it this way. Excuse the ugly var
- names. */
- register struct m68k_opcode *ins;
- register struct m68_incant *hack,
- *slak;
- register char *retval = 0; /* empty string, or error msg text */
- register int i;
- register char c;
- if ((op_hash = hash_new()) == NULL)
- as_fatal("Virtual memory exhausted");
- obstack_begin(&robyn,4000);
- for (ins = m68k_opcodes; ins < endop; ins++) {
- hack=slak=(struct m68_incant *)obstack_alloc(&robyn,sizeof(struct m68_incant));
- do {
- slak->m_operands=ins->args;
- slak->m_opnum=strlen(slak->m_operands)/2;
- slak->m_opcode=ins->opcode;
- /* This is kludgey */
- slak->m_codenum=((ins->match)&0xffffL) ? 2 : 1;
- if((ins+1)!=endop && !strcmp(ins->name,(ins+1)->name)) {
- slak->m_next=(struct m68_incant *)
- obstack_alloc(&robyn,sizeof(struct m68_incant));
- ins++;
- } else
- slak->m_next=0;
- slak=slak->m_next;
- } while(slak);
-
- retval = hash_insert (op_hash, ins->name,(char *)hack);
- /* Didn't his mommy tell him about null pointers? */
- if(retval && *retval)
- as_fatal("Internal Error: Can't hash %s: %s",ins->name,retval);
- }
- for (i = 0; i < sizeof(mklower_table) ; i++)
- mklower_table[i] = (isupper(c = (char) i)) ? tolower(c) : c;
- for (i = 0 ; i < sizeof(notend_table) ; i++) {
- notend_table[i] = 0;
- alt_notend_table[i] = 0;
- }
- notend_table[','] = 1;
- notend_table['{'] = 1;
- notend_table['}'] = 1;
- alt_notend_table['a'] = 1;
- alt_notend_table['A'] = 1;
- alt_notend_table['d'] = 1;
- alt_notend_table['D'] = 1;
- alt_notend_table['#'] = 1;
- }
- #if 0
- #define notend(s) ((*s == ',' || *s == '}' || *s == '{' \
- || (*s == ':' && index("aAdD#", s[1]))) \
- ? 0 : 1)
- #endif
- /* This funciton is called once, before the assembler exits. It is
- supposed to do any final cleanup for this part of the assembler.
- */
- void
- md_end()
- {
- }
- #define MAX_LITTLENUMS 6
- /* Turn a string in input_line_pointer into a floating point constant of type
- type, and store the appropriate bytes in *litP. 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_m68k();
- switch(type) {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
- case 'x':
- case 'X':
- prec = 6;
- break;
- case 'p':
- case 'P':
- prec = 6;
- break;
- default:
- *sizeP=0;
- return "Bad call to MD_ATOF()";
- }
- t=atof_m68k(input_line_pointer,type,words);
- if(t)
- input_line_pointer=t;
- *sizeP=prec * sizeof(LITTLENUM_TYPE);
- for(wordP=words;prec--;) {
- md_number_to_chars(litP,(long)(*wordP++),sizeof(LITTLENUM_TYPE));
- litP+=sizeof(LITTLENUM_TYPE);
- }
- return ""; /* Someone should teach Dean about null pointers */
- }
- /* Turn an integer of n bytes (in val) into a stream of bytes appropriate
- for use in the a.out file, and stores them in the array pointed to by buf.
- This knows about the endian-ness of the target machine and does
- THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
- 2 (short) and 4 (long) Floating numbers are put out as a series of
- LITTLENUMS (shorts, here at least)
- */
- void
- md_number_to_chars(buf,val,n)
- char *buf;
- long val;
- int n;
- {
- switch(n) {
- case 1:
- *buf++=val;
- break;
- case 2:
- *buf++=(val>>8);
- *buf++=val;
- break;
- case 4:
- *buf++=(val>>24);
- *buf++=(val>>16);
- *buf++=(val>>8);
- *buf++=val;
- break;
- default:
- abort();
- }
- }
- void
- md_number_to_imm(buf,val,n)
- char *buf;
- long val;
- int n;
- {
- switch(n) {
- case 1:
- *buf++=val;
- break;
- case 2:
- *buf++=(val>>8);
- *buf++=val;
- break;
- case 4:
- *buf++=(val>>24);
- *buf++=(val>>16);
- *buf++=(val>>8);
- *buf++=val;
- break;
- default:
- abort();
- }
- }
- void
- md_number_to_disp(buf,val,n)
- char *buf;
- long val;
- int n;
- {
- abort();
- }
- void
- md_number_to_field(buf,val,fix)
- char *buf;
- long val;
- void *fix;
- {
- abort();
- }
- /* *fragP has been relaxed to its final size, and now needs to have
- the bytes inside it modified to conform to the new size There is UGLY
- MAGIC here. ..
- */
- void
- md_convert_frag(fragP)
- register fragS *fragP;
- {
- long disp;
- long ext;
- /* Address in gas core of the place to store the displacement. */
- register char *buffer_address = fragP -> fr_fix + fragP -> fr_literal;
- /* Address in object code of the displacement. */
- register int object_address = fragP -> fr_fix + fragP -> fr_address;
- know(fragP->fr_symbol);
- /* The displacement of the address, from current location. */
- disp = (fragP->fr_symbol->sy_value + fragP->fr_offset) - object_address;
- switch(fragP->fr_subtype) {
- case TAB(BCC68000,BYTE):
- case TAB(BRANCH,BYTE):
- know(issbyte(disp));
- if(disp==0)
- as_warn("short branch with zero offset: use :w");
- fragP->fr_opcode[1]=disp;
- ext=0;
- break;
- case TAB(DBCC,SHORT):
- know(issword(disp));
- ext=2;
- break;
- case TAB(BCC68000,SHORT):
- case TAB(BRANCH,SHORT):
- know(issword(disp));
- fragP->fr_opcode[1]=0x00;
- ext=2;
- break;
- case TAB(BRANCH,LONG):
- if(flagseen['m']) {
- if(fragP->fr_opcode[0]==0x61) {
- fragP->fr_opcode[0]= 0x4E;
- fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
- subseg_change(SEG_TEXT, 0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0);
- fragP->fr_fix+=4;
- ext=0;
- } else if(fragP->fr_opcode[0]==0x60) {
- fragP->fr_opcode[0]= 0x4E;
- fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
- subseg_change(SEG_TEXT, 0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset,0);
- fragP->fr_fix+=4;
- ext=0;
- }else {
- as_warn("Long branch offset not supported.");
- }
- } else {
- fragP->fr_opcode[1]=0xff;
- ext=4;
- }
- break;
- case TAB(BCC68000,LONG):
- {
- /* only Bcc 68000 instructions can come here */
- /* change bcc into b!cc/jmp absl long */
- fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
- fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */
- fragP->fr_opcode[2] = 0x4e; /* put in jmp long (0x4ef9) */
- fragP->fr_opcode[3] = 0xf9;
- fragP->fr_fix += 2; /* account for jmp instruction */
- subseg_change(SEG_TEXT,0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
- fragP->fr_offset,0);
- fragP->fr_fix += 4;
- ext=0;
- }
- break;
- case TAB(DBCC,LONG):
- {
- /* only DBcc 68000 instructions can come here */
- /* change dbcc into dbcc/jmp absl long */
- fragP->fr_opcode[2] = 0x00; /* branch offset = 4 */
- fragP->fr_opcode[3] = 0x04;
- fragP->fr_opcode[4] = 0x60; /* put in bra pc+6 */
- fragP->fr_opcode[5] = 0x06;
- fragP->fr_opcode[6] = 0x4e; /* put in jmp long (0x4ef9) */
- fragP->fr_opcode[7] = 0xf9;
- fragP->fr_fix += 6; /* account for bra/jmp instructions */
- subseg_change(SEG_TEXT,0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
- fragP->fr_offset,0);
- fragP->fr_fix += 4;
- ext=0;
- }
- break;
- case TAB(FBRANCH,SHORT):
- know((fragP->fr_opcode[1]&0x40)==0);
- ext=2;
- break;
- case TAB(FBRANCH,LONG):
- fragP->fr_opcode[1]|=0x40; /* Turn on LONG bit */
- ext=4;
- break;
- case TAB(PCREL,SHORT):
- ext=2;
- break;
- case TAB(PCREL,LONG):
- /* The thing to do here is force it to ABSOLUTE LONG, since
- PCREL is really trying to shorten an ABSOLUTE address anyway */
- /* JF FOO This code has not been tested */
- subseg_change(SEG_TEXT,0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0, fragP->fr_offset, 0);
- if((fragP->fr_opcode[1] & 0x3F) != 0x3A)
- as_warn("Internal error (long PC-relative operand) for insn 0x%04lx at 0x%lx",
- fragP->fr_opcode[0],fragP->fr_address);
- fragP->fr_opcode[1]&= ~0x3F;
- fragP->fr_opcode[1]|=0x39; /* Mode 7.1 */
- fragP->fr_fix+=4;
- /* md_number_to_chars(buffer_address,
- (long)(fragP->fr_symbol->sy_value + fragP->fr_offset),
- 4); */
- ext=0;
- }
- if(ext) {
- md_number_to_chars(buffer_address,(long)disp,(int)ext);
- fragP->fr_fix+=ext;
- }
- }
- /* Force truly undefined symbols to their maximum size, and generally set up
- the frag list to be relaxed
- */
- int
- md_estimate_size_before_relax(fragP,segtype)
- register fragS *fragP;
- int segtype;
- {
- int old_fix;
- old_fix=fragP->fr_fix;
- /* handle SZ_UNDEF first, it can be changed to BYTE or SHORT */
- switch(fragP->fr_subtype) {
- case TAB(DBCC,SZ_UNDEF):
- if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
- fragP->fr_subtype=TAB(DBCC,SHORT);
- fragP->fr_var+=2;
- break;
- }
- /* only DBcc 68000 instructions can come here */
- /* change dbcc into dbcc/jmp absl long */
- fragP->fr_opcode[2] = 0x00; /* branch offset = 4 */
- fragP->fr_opcode[3] = 0x04;
- fragP->fr_opcode[4] = 0x60; /* put in bra pc+6 */
- fragP->fr_opcode[5] = 0x06;
- fragP->fr_opcode[6] = 0x4e; /* put in jmp long (0x4ef9) */
- fragP->fr_opcode[7] = 0xf9;
- fragP->fr_fix += 6; /* account for bra/jmp instruction */
- subseg_change(SEG_TEXT,0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
- fragP->fr_offset,0);
- fragP->fr_fix += 4;
- frag_wane(fragP);
- break;
-
- case TAB(BCC68000,SZ_UNDEF):
- if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
- fragP->fr_subtype=TAB(BCC68000,BYTE);
- break;
- }
- /* only Bcc 68000 instructions can come here */
- /* change bcc into b!cc/jmp absl long */
- fragP->fr_opcode[0] ^= 0x01; /* invert bcc */
- fragP->fr_opcode[1] = 0x6; /* branch offset = 6 */
- fragP->fr_opcode[2] = 0x4e; /* put in jmp long (0x4ef9) */
- fragP->fr_opcode[3] = 0xf9;
- fragP->fr_fix += 2; /* account for jmp instruction */
- subseg_change(SEG_TEXT,0);
- fix_new(fragP, fragP->fr_fix, 4, fragP->fr_symbol, 0,
- fragP->fr_offset,0);
- fragP->fr_fix += 4;
- frag_wane(fragP);
- break;
-
- case TAB(BRANCH,SZ_UNDEF):
- if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
- fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),BYTE);
- break;
- } else if(flagseen['m']) {
- if(fragP->fr_opcode[0]==0x61) {
- fragP->fr_opcode[0]= 0x4E;
- fragP->fr_opcode[1]= 0xB9; /* JBSR with ABSL LONG offset */
- subseg_change(SEG_TEXT, 0);
- fix_new(fragP, fragP->fr_fix, 4,
- fragP->fr_symbol, 0, fragP->fr_offset, 0);
- fragP->fr_fix+=4;
- frag_wane(fragP);
- } else if(fragP->fr_opcode[0]==0x60) {
- fragP->fr_opcode[0]= 0x4E;
- fragP->fr_opcode[1]= 0xF9; /* JMP with ABSL LONG offset */
- subseg_change(SEG_TEXT, 0);
- fix_new(fragP, fragP->fr_fix, 4,
- fragP->fr_symbol, 0, fragP->fr_offset, 0);
- fragP->fr_fix+=4;
- frag_wane(fragP);
- } else {
- as_warn("Long branch offset to extern symbol not supported.");
- }
- } else { /* Symbol is still undefined. Make it simple */
- fix_new(fragP,(int)(fragP->fr_fix),4,fragP->fr_symbol,
- (symbolS *)0,fragP->fr_offset+4,1);
- fragP->fr_fix+=4;
- fragP->fr_opcode[1]=0xff;
- frag_wane(fragP);
- break;
- }
- default:
- break;
- }
- /* now that SZ_UNDEF are taken care of, check others */
- switch(fragP->fr_subtype) {
- case TAB(BCC68000,BYTE):
- case TAB(BRANCH,BYTE):
- /* We can't do a short jump to the next instruction,
- so we force word mode. */
- if(fragP->fr_symbol && fragP->fr_symbol->sy_value==0 &&
- fragP->fr_symbol->sy_frag==fragP->fr_next) {
- fragP->fr_subtype=TAB(TABTYPE(fragP->fr_subtype),SHORT);
- fragP->fr_var+=2;
- }
- break;
- case TAB(FBRANCH,SZ_UNDEF):
- if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
- fragP->fr_subtype=TAB(FBRANCH,SHORT);
- fragP->fr_var+=2;
- } else {
- fragP->fr_subtype=TAB(FBRANCH,LONG);
- fragP->fr_var+=4;
- }
- break;
- case TAB(PCREL,SZ_UNDEF):
- if((fragP->fr_symbol->sy_type&N_TYPE)==segtype) {
- fragP->fr_subtype=TAB(PCREL,SHORT);
- fragP->fr_var+=2;
- } else {
- fragP->fr_subtype=TAB(PCREL,LONG);
- fragP->fr_var+=4;
- }
- break;
- default:
- break;
- }
- return fragP->fr_var + fragP->fr_fix - old_fix;
- }
- /* the bit-field entries in the relocation_info struct plays hell
- with the byte-order problems of cross-assembly. So as a hack,
- I added this mach. dependent ri twiddler. Ugly, but it gets
- you there. -KWK */
- /* on m68k: first 4 bytes are normal unsigned long, next three bytes
- are symbolnum, most sig. byte first. Last byte is broken up with
- bit 7 as pcrel, bits 6 & 5 as length, bit 4 as pcrel, and the lower
- nibble as nuthin. (on Sun 3 at least) */
- void
- md_ri_to_chars(ri_p, ri)
- struct relocation_info *ri_p, ri;
- {
- unsigned char the_bytes[8];
-
- /* this is easy */
- md_number_to_chars(the_bytes, ri.r_address, sizeof(ri.r_address));
- /* now the fun stuff */
- the_bytes[4] = (ri.r_symbolnum >> 16) & 0x0ff;
- the_bytes[5] = (ri.r_symbolnum >> 8) & 0x0ff;
- the_bytes[6] = ri.r_symbolnum & 0x0ff;
- the_bytes[7] = (((ri.r_pcrel << 7) & 0x80) | ((ri.r_length << 5) & 0x60) |
- ((ri.r_extern << 4) & 0x10));
- /* now put it back where you found it */
- bcopy (the_bytes, (char *)ri_p, sizeof(struct relocation_info));
- }
- #ifndef WORKING_DOT_WORD
- int md_short_jump_size = 4;
- int md_long_jump_size = 6;
- void
- md_create_short_jump(ptr,from_addr,to_addr,frag,to_symbol)
- char *ptr;
- long from_addr,
- to_addr;
- fragS *frag;
- symbolS *to_symbol;
- {
- long offset;
- offset = to_addr - (from_addr+2);
- md_number_to_chars(ptr ,(long)0x6000,2);
- md_number_to_chars(ptr+2,(long)offset,2);
- }
- void
- md_create_long_jump(ptr,from_addr,to_addr,frag,to_symbol)
- char *ptr;
- long from_addr,
- to_addr;
- fragS *frag;
- symbolS *to_symbol;
- {
- long offset;
- if(flagseen['m']) {
- offset=to_addr-to_symbol->sy_value;
- md_number_to_chars(ptr ,(long)0x4EF9,2);
- md_number_to_chars(ptr+2,(long)offset,4);
- fix_new(frag,(ptr+2)-frag->fr_literal,4,to_symbol,(symbolS *)0,(long int)0,0);
- } else {
- offset=to_addr - (from_addr+2);
- md_number_to_chars(ptr ,(long)0x60ff,2);
- md_number_to_chars(ptr+2,(long)offset,4);
- }
- }
- #endif
- /* Different values of OK tell what its OK to return. Things that aren't OK are an error (what a shock, no?)
- 0: Everything is OK
- 10: Absolute 1:8 only
- 20: Absolute 0:7 only
- 30: absolute 0:15 only
- 40: Absolute 0:31 only
- 50: absolute 0:127 only
- 55: absolute -64:63 only
- 60: absolute -128:127 only
- 70: absolute 0:4095 only
- 80: No bignums
- */
- int
- get_num(exp,ok)
- struct m68k_exp *exp;
- int ok;
- {
- #ifdef TEST2
- long l = 0;
- if(!exp->e_beg)
- return 0;
- if(*exp->e_beg=='0') {
- if(exp->e_beg[1]=='x')
- sscanf(exp->e_beg+2,"%x",&l);
- else
- sscanf(exp->e_beg+1,"%O",&l);
- return l;
- }
- return atol(exp->e_beg);
- #else
- char *save_in;
- char c_save;
- if(!exp) {
- /* Can't do anything */
- return 0;
- }
- if(!exp->e_beg || !exp->e_end) {
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)= (ok==10) ? 1 : 0;
- as_warn("Null expression defaults to %ld",offs(exp));
- return 0;
- }
- exp->e_siz=0;
- if(/* ok!=80 && */exp->e_end[-1]==':' && (exp->e_end-exp->e_beg)>2) {
- switch(exp->e_end[0]) {
- case 's':
- case 'b':
- exp->e_siz=1;
- break;
- case 'w':
- exp->e_siz=2;
- break;
- case 'l':
- exp->e_siz=3;
- break;
- default:
- as_warn("Unknown size for expression \"%c\"",exp->e_end[0]);
- }
- exp->e_end-=2;
- }
- c_save=exp->e_end[1];
- exp->e_end[1]='\0';
- save_in=input_line_pointer;
- input_line_pointer=exp->e_beg;
- switch(expression(&(exp->e_exp))) {
- case SEG_NONE:
- /* Do the same thing the VAX asm does */
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)=0;
- if(ok==10) {
- as_warn("expression out of range: defaulting to 1");
- offs(exp)=1;
- }
- break;
- case SEG_ABSOLUTE:
- switch(ok) {
- case 10:
- if(offs(exp)<1 || offs(exp)>8) {
- as_warn("expression out of range: defaulting to 1");
- offs(exp)=1;
- }
- break;
- case 20:
- if(offs(exp)<0 || offs(exp)>7)
- goto outrange;
- break;
- case 30:
- if(offs(exp)<0 || offs(exp)>15)
- goto outrange;
- break;
- case 40:
- if(offs(exp)<0 || offs(exp)>32)
- goto outrange;
- break;
- case 50:
- if(offs(exp)<0 || offs(exp)>127)
- goto outrange;
- break;
- case 55:
- if(offs(exp)<-64 || offs(exp)>63)
- goto outrange;
- break;
- case 60:
- if(offs(exp)<-128 || offs(exp)>127)
- goto outrange;
- break;
- case 70:
- if(offs(exp)<0 || offs(exp)>4095) {
- outrange:
- as_warn("expression out of range: defaulting to 0");
- offs(exp)=0;
- }
- break;
- default:
- break;
- }
- break;
- case SEG_TEXT:
- case SEG_DATA:
- case SEG_BSS:
- case SEG_UNKNOWN:
- case SEG_DIFFERENCE:
- if(ok>=10 && ok<=70) {
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)= (ok==10) ? 1 : 0;
- as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
- }
- break;
- case SEG_BIG:
- if(ok==80 && offs(exp)<0) { /* HACK! Turn it into a long */
- LITTLENUM_TYPE words[6];
- gen_to_words(words,2,8L);/* These numbers are magic! */
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)=words[1]|(words[0]<<16);
- } else if(ok!=0) {
- seg(exp)=SEG_ABSOLUTE;
- adds(exp)=0;
- subs(exp)=0;
- offs(exp)= (ok==10) ? 1 : 0;
- as_warn("Can't deal with expression \"%s\": defaulting to %ld",exp->e_beg,offs(exp));
- }
- break;
- default:
- abort();
- }
- if(input_line_pointer!=exp->e_end+1)
- as_warn("Ignoring junk after expression");
- exp->e_end[1]=c_save;
- input_line_pointer=save_in;
- if(exp->e_siz) {
- switch(exp->e_siz) {
- case 1:
- if(!isbyte(offs(exp)))
- as_warn("expression doesn't fit in BYTE");
- break;
- case 2:
- if(!isword(offs(exp)))
- as_warn("expression doesn't fit in WORD");
- break;
- }
- }
- return offs(exp);
- #endif
- }
- /* These are the back-ends for the various machine dependent pseudo-ops. */
- void demand_empty_rest_of_line(); /* Hate those extra verbose names */
- void
- s_data1()
- {
- subseg_new(SEG_DATA,1);
- demand_empty_rest_of_line();
- }
- void
- s_data2()
- {
- subseg_new(SEG_DATA,2);
- demand_empty_rest_of_line();
- }
- void
- s_even()
- {
- register int temp;
- register long int temp_fill;
- temp = 1; /* JF should be 2? */
- temp_fill = get_absolute_expression ();
- if ( ! need_pass_2 ) /* Never make frag if expect extra pass. */
- frag_align (temp, (int)temp_fill);
- demand_empty_rest_of_line();
- }
- /* s_space is defined in read.c .skip is simply an alias to it. */
- int
- md_parse_option(argP,cntP,vecP)
- char **argP;
- int *cntP;
- char ***vecP;
- {
- switch(**argP) {
- case 'l': /* -l means keep external to 2 bit offset
- rather than 16 bit one */
- break;
- case 'm':
- /* Gas simply ignores this option! */
- (*argP)++;
- if(**argP=='c')
- (*argP)++;
- if(!strcmp(*argP,"68000"))
- flagseen['m']=2;
- else if(!strcmp(*argP,"68010")) {
- #ifdef M_SUN
- omagic= 1<<16|OMAGIC;
- #endif
- flagseen['m']=1;
- } else if(!strcmp(*argP,"68020"))
- flagseen['m']=0;
- else
- as_warn("Unknown -m option ignored");
- while(**argP)
- (*argP)++;
- break;
- default:
- return 0;
- }
- return 1;
- }
- #ifdef TEST2
- /* TEST2: Test md_assemble() */
- /* Warning, this routine probably doesn't work anymore */
- main()
- {
- struct m68_it the_ins;
- char buf[120];
- char *cp;
- int n;
- m68_ip_begin();
- for(;;) {
- if(!gets(buf) || !*buf)
- break;
- if(buf[0]=='|' || buf[1]=='.')
- continue;
- for(cp=buf;*cp;cp++)
- if(*cp=='\t')
- *cp=' ';
- if(is_label(buf))
- continue;
- bzero(&the_ins,sizeof(the_ins));
- m68_ip(&the_ins,buf);
- if(the_ins.error) {
- printf("Error %s in %s\n",the_ins.error,buf);
- } else {
- printf("Opcode(%d.%s): ",the_ins.numo,the_ins.args);
- for(n=0;n<the_ins.numo;n++)
- printf(" 0x%x",the_ins.opcode[n]&0xffff);
- printf(" ");
- print_the_insn(&the_ins.opcode[0],stdout);
- (void)putchar('\n');
- }
- for(n=0;n<strlen(the_ins.args)/2;n++) {
- if(the_ins.operands[n].error) {
- printf("op%d Error %s in %s\n",n,the_ins.operands[n].error,buf);
- continue;
- }
- printf("mode %d, reg %d, ",the_ins.operands[n].mode,the_ins.operands[n].reg);
- if(the_ins.operands[n].b_const)
- printf("Constant: '%.*s', ",1+the_ins.operands[n].e_const-the_ins.operands[n].b_const,the_ins.operands[n].b_const);
- printf("ireg %d, isiz %d, imul %d, ",the_ins.operands[n].ireg,the_ins.operands[n].isiz,the_ins.operands[n].imul);
- if(the_ins.operands[n].b_iadd)
- printf("Iadd: '%.*s',",1+the_ins.operands[n].e_iadd-the_ins.operands[n].b_iadd,the_ins.operands[n].b_iadd);
- (void)putchar('\n');
- }
- }
- m68_ip_end();
- return 0;
- }
- is_label(str)
- char *str;
- {
- while(*str==' ')
- str++;
- while(*str && *str!=' ')
- str++;
- if(str[-1]==':' || str[1]=='=')
- return 1;
- return 0;
- }
- print_address(add,fp)
- FILE *fp;
- {
- fprintf(fp,"%#X",add);
- }
- #endif
- /* Possible states for relaxation:
- 0 0 branch offset byte (bra, etc)
- 0 1 word
- 0 2 long
- 1 0 indexed offsets byte a0@(32,d4:w:1) etc
- 1 1 word
- 1 2 long
- 2 0 two-offset index word-word a0@(32,d4)@(45) etc
- 2 1 word-long
- 2 2 long-word
- 2 3 long-long
- */
- #ifdef DONTDEF
- abort()
- {
- printf("ABORT!\n");
- exit(12);
- }
- char *index(s,c)
- char *s;
- {
- while(*s!=c) {
- if(!*s) return 0;
- s++;
- }
- return s;
- }
- bzero(s,n)
- char *s;
- {
- while(n--)
- *s++=0;
- }
- print_frags()
- {
- fragS *fragP;
- extern fragS *text_frag_root;
- for(fragP=text_frag_root;fragP;fragP=fragP->fr_next) {
- printf("addr %lu next 0x%x fix %ld var %ld symbol 0x%x offset %ld\n",
- fragP->fr_address,fragP->fr_next,fragP->fr_fix,fragP->fr_var,fragP->fr_symbol,fragP->fr_offset);
- printf("opcode 0x%x type %d subtype %d\n\n",fragP->fr_opcode,fragP->fr_type,fragP->fr_subtype);
- }
- fflush(stdout);
- return 0;
- }
- #endif
- #ifdef DONTDEF
- /*VARARGS1*/
- panic(format,args)
- char *format;
- {
- fputs("Internal error:",stderr);
- _doprnt(format,&args,stderr);
- (void)putc('\n',stderr);
- as_where();
- abort();
- }
- #endif
|