1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404 |
- /* tc-tic54x.c -- Assembly code for the Texas Instruments TMS320C54X
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
- Contributed by Timothy Wall (twall@cygnus.com)
- 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 3, 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, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
- /* Texas Instruments TMS320C54X machine specific gas.
- Written by Timothy Wall (twall@alum.mit.edu).
- Valuable things to do:
- Pipeline conflict warnings
- We encode/decode "ld #_label, dp" differently in relocatable files
- This means we're not compatible with TI output containing those
- expressions. We store the upper nine bits; TI stores the lower nine
- bits. How they recover the original upper nine bits is beyond me.
- Tests to add to expect testsuite:
- '=' and '==' with .if, .elseif, and .break
- Incompatibilities (mostly trivial):
- We don't allow '''
- We fill text section with zeroes instead of "nop"s
- We don't convert '' or "" to a single instance
- We don't convert '' to '\0'
- We don't allow strings with .byte/.half/.short/.long
- Probably details of the subsym stuff are different
- TI sets labels to be data type 4 (T_INT); GAS uses T_NULL.
- COFF1 limits section names to 8 characters.
- Some of the default behavior changed from COFF1 to COFF2. */
- #include "as.h"
- #include <limits.h>
- #include "safe-ctype.h"
- #include "sb.h"
- #include "macro.h"
- #include "subsegs.h"
- #include "struc-symbol.h"
- #include "opcode/tic54x.h"
- #include "obj-coff.h"
- #include <math.h>
- static struct stag
- {
- symbolS *sym; /* Symbol for this stag; value is offset. */
- const char *name; /* Shortcut to symbol name. */
- bfd_vma size; /* Size of struct/union. */
- int current_bitfield_offset; /* Temporary for tracking fields. */
- int is_union;
- struct stag_field /* List of fields. */
- {
- const char *name;
- bfd_vma offset; /* Of start of this field. */
- int bitfield_offset; /* Of start of this field. */
- struct stag *stag; /* If field is struct/union. */
- struct stag_field *next;
- } *field;
- /* For nesting; used only in stag construction. */
- struct stag *inner; /* Enclosed .struct. */
- struct stag *outer; /* Enclosing .struct. */
- } *current_stag = NULL;
- #define MAX_LINE 256 /* Lines longer than this are truncated by TI's asm. */
- typedef struct _tic54x_insn
- {
- const insn_template *tm; /* Opcode template. */
- char mnemonic[MAX_LINE]; /* Opcode name/mnemonic. */
- char parmnemonic[MAX_LINE]; /* 2nd mnemonic of parallel insn. */
- int opcount;
- struct opstruct
- {
- char buf[MAX_LINE];
- enum optype type;
- expressionS exp;
- } operands[MAX_OPERANDS];
- int paropcount;
- struct opstruct paroperands[MAX_OPERANDS];
- int is_lkaddr;
- int lkoperand;
- int words; /* Size of insn in 16-bit words. */
- int using_default_dst; /* Do we need to explicitly set an
- omitted OP_DST operand? */
- struct
- {
- unsigned short word; /* Final encoded opcode data. */
- int unresolved;
- int r_nchars; /* Relocation size. */
- bfd_reloc_code_real_type r_type; /* Relocation type. */
- expressionS addr_expr; /* Storage for unresolved expressions. */
- } opcode[3];
- } tic54x_insn;
- enum cpu_version
- {
- VNONE = 0, V541 = 1, V542 = 2, V543 = 3, V545 = 5, V548 = 8, V549 = 9,
- V545LP = 15, V546LP = 16
- };
- enum address_mode
- {
- c_mode, /* 16-bit addresses. */
- far_mode /* >16-bit addresses. */
- };
- static segT stag_saved_seg;
- static subsegT stag_saved_subseg;
- const char comment_chars[] = ";";
- const char line_comment_chars[] = ";*#"; /* At column zero only. */
- const char line_separator_chars[] = ""; /* Not permitted. */
- int emitting_long = 0;
- /* Characters which indicate that this is a floating point constant. */
- const char FLT_CHARS[] = "fF";
- /* Characters that can be used to separate mantissa from exp in FP
- nums. */
- const char EXP_CHARS[] = "eE";
- const char *md_shortopts = "";
- #define OPTION_ADDRESS_MODE (OPTION_MD_BASE)
- #define OPTION_CPU_VERSION (OPTION_ADDRESS_MODE + 1)
- #define OPTION_COFF_VERSION (OPTION_CPU_VERSION + 1)
- #define OPTION_STDERR_TO_FILE (OPTION_COFF_VERSION + 1)
- struct option md_longopts[] =
- {
- { "mfar-mode", no_argument, NULL, OPTION_ADDRESS_MODE },
- { "mf", no_argument, NULL, OPTION_ADDRESS_MODE },
- { "mcpu", required_argument, NULL, OPTION_CPU_VERSION },
- { "merrors-to-file", required_argument, NULL, OPTION_STDERR_TO_FILE },
- { "me", required_argument, NULL, OPTION_STDERR_TO_FILE },
- { NULL, no_argument, NULL, 0},
- };
- size_t md_longopts_size = sizeof (md_longopts);
- static int assembly_begun = 0;
- /* Addressing mode is not entirely implemented; the latest rev of the Other
- assembler doesn't seem to make any distinction whatsoever; all relocations
- are stored as extended relocatiosn. Older versions used REL16 vs RELEXT16,
- but now it seems all relocations are RELEXT16. We use all RELEXT16.
- The cpu version is kind of a waste of time as well. There is one
- instruction (RND) for LP devices only, and several for devices with
- extended addressing only. We include it for compatibility. */
- static enum address_mode amode = c_mode;
- static enum cpu_version cpu = VNONE;
- /* Include string substitutions in listing? */
- static int listing_sslist = 0;
- /* Did we do subsym substitutions on the line? */
- static int substitution_line = 0;
- /* Last label seen. */
- static symbolS *last_label_seen = NULL;
- /* This ensures that all new labels are unique. */
- static int local_label_id;
- static struct hash_control *subsym_recurse_hash; /* Prevent infinite recurse. */
- static struct hash_control *math_hash; /* Built-in math functions. */
- /* Allow maximum levels of macro nesting; level 0 is the main substitution
- symbol table. The other assembler only does 32 levels, so there! */
- static struct hash_control *subsym_hash[100];
- /* Keep track of local labels so we can substitute them before GAS sees them
- since macros use their own 'namespace' for local labels, use a separate hash
- We do our own local label handling 'cuz it's subtly different from the
- stock GAS handling.
- We use our own macro nesting counter, since GAS overloads it when expanding
- other things (like conditionals and repeat loops). */
- static int macro_level = 0;
- static struct hash_control *local_label_hash[100];
- /* Keep track of struct/union tags. */
- static struct hash_control *stag_hash;
- static struct hash_control *op_hash;
- static struct hash_control *parop_hash;
- static struct hash_control *reg_hash;
- static struct hash_control *mmreg_hash;
- static struct hash_control *cc_hash;
- static struct hash_control *cc2_hash;
- static struct hash_control *cc3_hash;
- static struct hash_control *sbit_hash;
- static struct hash_control *misc_symbol_hash;
- /* Only word (et al.), align, or conditionals are allowed within
- .struct/.union. */
- #define ILLEGAL_WITHIN_STRUCT() \
- do \
- if (current_stag != NULL) \
- { \
- as_bad (_("pseudo-op illegal within .struct/.union")); \
- return; \
- } \
- while (0)
- static void subsym_create_or_replace (char *, char *);
- static char *subsym_lookup (char *, int);
- static char *subsym_substitute (char *, int);
- void
- md_show_usage (FILE *stream)
- {
- fprintf (stream, _("C54x-specific command line options:\n"));
- fprintf (stream, _("-mfar-mode | -mf Use extended addressing\n"));
- fprintf (stream, _("-mcpu=<CPU version> Specify the CPU version\n"));
- fprintf (stream, _("-merrors-to-file <filename>\n"));
- fprintf (stream, _("-me <filename> Redirect errors to a file\n"));
- }
- /* Output a single character (upper octect is zero). */
- static void
- tic54x_emit_char (char c)
- {
- expressionS expn;
- expn.X_op = O_constant;
- expn.X_add_number = c;
- emit_expr (&expn, 2);
- }
- /* Walk backwards in the frag chain. */
- static fragS *
- frag_prev (fragS *frag, segT seg)
- {
- segment_info_type *seginfo = seg_info (seg);
- fragS *fragp;
- for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next)
- if (fragp->fr_next == frag)
- return fragp;
- return NULL;
- }
- static fragS *
- bit_offset_frag (fragS *frag, segT seg)
- {
- while (frag != NULL)
- {
- if (frag->fr_fix == 0
- && frag->fr_opcode == NULL
- && frag->tc_frag_data == 0)
- frag = frag_prev (frag, seg);
- else
- return frag;
- }
- return NULL;
- }
- /* Return the number of bits allocated in the most recent word, or zero if
- none. .field/.space/.bes may leave words partially allocated. */
- static int
- frag_bit_offset (fragS *frag, segT seg)
- {
- frag = bit_offset_frag (frag, seg);
- if (frag)
- return frag->fr_opcode != NULL ? -1 : frag->tc_frag_data;
- return 0;
- }
- /* Read an expression from a C string; returns a pointer past the end of the
- expression. */
- static char *
- parse_expression (char *str, expressionS *expn)
- {
- char *s;
- char *tmp;
- tmp = input_line_pointer; /* Save line pointer. */
- input_line_pointer = str;
- expression (expn);
- s = input_line_pointer;
- input_line_pointer = tmp; /* Restore line pointer. */
- return s; /* Return pointer to where parsing stopped. */
- }
- /* .asg "character-string"|character-string, symbol
- .eval is the only pseudo-op allowed to perform arithmetic on substitution
- symbols. all other use of symbols defined with .asg are currently
- unsupported. */
- static void
- tic54x_asg (int x ATTRIBUTE_UNUSED)
- {
- int c;
- char *name;
- char *str;
- char *tmp;
- int quoted = *input_line_pointer == '"';
- ILLEGAL_WITHIN_STRUCT ();
- if (quoted)
- {
- int len;
- str = demand_copy_C_string (&len);
- c = *input_line_pointer;
- }
- else
- {
- str = input_line_pointer;
- while ((c = *input_line_pointer) != ',')
- {
- if (is_end_of_line[(int) *input_line_pointer])
- break;
- ++input_line_pointer;
- }
- *input_line_pointer = 0;
- }
- if (c != ',')
- {
- as_bad (_("Comma and symbol expected for '.asg STRING, SYMBOL'"));
- ignore_rest_of_line ();
- return;
- }
- ++input_line_pointer;
- c = get_symbol_name (&name); /* Get terminator. */
- if (!ISALPHA (*name))
- {
- as_bad (_("symbols assigned with .asg must begin with a letter"));
- ignore_rest_of_line ();
- return;
- }
- tmp = xmalloc (strlen (str) + 1);
- strcpy (tmp, str);
- str = tmp;
- tmp = xmalloc (strlen (name) + 1);
- strcpy (tmp, name);
- name = tmp;
- subsym_create_or_replace (name, str);
- (void) restore_line_pointer (c);
- demand_empty_rest_of_line ();
- }
- /* .eval expression, symbol
- There's something screwy about this. The other assembler sometimes does and
- sometimes doesn't substitute symbols defined with .eval.
- We'll put the symbols into the subsym table as well as the normal symbol
- table, since that's what works best. */
- static void
- tic54x_eval (int x ATTRIBUTE_UNUSED)
- {
- char c;
- int value;
- char *name;
- symbolS *symbolP;
- char valuestr[32], *tmp;
- int quoted;
- ILLEGAL_WITHIN_STRUCT ();
- SKIP_WHITESPACE ();
- quoted = *input_line_pointer == '"';
- if (quoted)
- ++input_line_pointer;
- value = get_absolute_expression ();
- if (quoted)
- {
- if (*input_line_pointer != '"')
- {
- as_bad (_("Unterminated string after absolute expression"));
- ignore_rest_of_line ();
- return;
- }
- ++input_line_pointer;
- }
- if (*input_line_pointer++ != ',')
- {
- as_bad (_("Comma and symbol expected for '.eval EXPR, SYMBOL'"));
- ignore_rest_of_line ();
- return;
- }
- c = get_symbol_name (&name); /* Get terminator. */
- tmp = xmalloc (strlen (name) + 1);
- name = strcpy (tmp, name);
- (void) restore_line_pointer (c);
- if (!ISALPHA (*name))
- {
- as_bad (_("symbols assigned with .eval must begin with a letter"));
- ignore_rest_of_line ();
- return;
- }
- symbolP = symbol_new (name, absolute_section,
- (valueT) value, &zero_address_frag);
- SF_SET_LOCAL (symbolP);
- symbol_table_insert (symbolP);
- /* The "other" assembler sometimes doesn't put .eval's in the subsym table
- But since there's not written rule as to when, don't even bother trying
- to match their behavior. */
- sprintf (valuestr, "%d", value);
- tmp = xmalloc (strlen (valuestr) + 1);
- strcpy (tmp, valuestr);
- subsym_create_or_replace (name, tmp);
- demand_empty_rest_of_line ();
- }
- /* .bss symbol, size [, [blocking flag] [, alignment flag]
- alignment is to a longword boundary; blocking is to 128-word boundary.
- 1) if there is a hole in memory, this directive should attempt to fill it
- (not yet implemented).
- 2) if the blocking flag is not set, allocate at the current SPC
- otherwise, check to see if the current SPC plus the space to be
- allocated crosses the page boundary (128 words).
- if there's not enough space, create a hole and align with the next page
- boundary.
- (not yet implemented). */
- static void
- tic54x_bss (int x ATTRIBUTE_UNUSED)
- {
- char c;
- char *name;
- char *p;
- int words;
- segT current_seg;
- subsegT current_subseg;
- symbolS *symbolP;
- int block = 0;
- int align = 0;
- ILLEGAL_WITHIN_STRUCT ();
- current_seg = now_seg; /* Save current seg. */
- current_subseg = now_subseg; /* Save current subseg. */
- c = get_symbol_name (&name); /* Get terminator. */
- if (c == '"')
- c = * ++ input_line_pointer;
- if (c != ',')
- {
- as_bad (_(".bss size argument missing\n"));
- ignore_rest_of_line ();
- return;
- }
- ++input_line_pointer;
- words = get_absolute_expression ();
- if (words < 0)
- {
- as_bad (_(".bss size %d < 0!"), words);
- ignore_rest_of_line ();
- return;
- }
- if (*input_line_pointer == ',')
- {
- /* The blocking flag may be missing. */
- ++input_line_pointer;
- if (*input_line_pointer != ',')
- block = get_absolute_expression ();
- else
- block = 0;
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- align = get_absolute_expression ();
- }
- else
- align = 0;
- }
- else
- block = align = 0;
- subseg_set (bss_section, 0);
- symbolP = symbol_find_or_make (name);
- if (S_GET_SEGMENT (symbolP) == bss_section)
- symbolP->sy_frag->fr_symbol = (symbolS *) NULL;
- symbol_set_frag (symbolP, frag_now);
- p = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP,
- (offsetT) (words * OCTETS_PER_BYTE), (char *) 0);
- *p = 0; /* Fill char. */
- S_SET_SEGMENT (symbolP, bss_section);
- /* The symbol may already have been created with a preceding
- ".globl" directive -- be careful not to step on storage class
- in that case. Otherwise, set it to static. */
- if (S_GET_STORAGE_CLASS (symbolP) != C_EXT)
- S_SET_STORAGE_CLASS (symbolP, C_STAT);
- if (align)
- {
- /* s_align eats end of line; restore it */
- s_align_bytes (4);
- --input_line_pointer;
- }
- if (block)
- bss_section->flags |= SEC_TIC54X_BLOCK;
- subseg_set (current_seg, current_subseg); /* Restore current seg. */
- demand_empty_rest_of_line ();
- }
- static void
- stag_add_field_symbols (struct stag *stag,
- const char *path,
- bfd_vma base_offset,
- symbolS *rootsym,
- const char *root_stag_name)
- {
- char prefix[strlen (path) + 2];
- struct stag_field *field = stag->field;
- /* Construct a symbol for every field contained within this structure
- including fields within structure fields. */
- strcpy (prefix, path);
- if (*path)
- strcat (prefix, ".");
- while (field != NULL)
- {
- int len = strlen (prefix) + strlen (field->name) + 2;
- char *name = xmalloc (len);
- strcpy (name, prefix);
- strcat (name, field->name);
- if (rootsym == NULL)
- {
- symbolS *sym;
- sym = symbol_new (name, absolute_section,
- (field->stag ? field->offset :
- (valueT) (base_offset + field->offset)),
- &zero_address_frag);
- SF_SET_LOCAL (sym);
- symbol_table_insert (sym);
- }
- else
- {
- char *replacement = xmalloc (strlen (name)
- + strlen (stag->name) + 2);
- strcpy (replacement, S_GET_NAME (rootsym));
- strcat (replacement, "+");
- strcat (replacement, root_stag_name);
- strcat (replacement, name + strlen (S_GET_NAME (rootsym)));
- hash_insert (subsym_hash[0], name, replacement);
- }
- /* Recurse if the field is a structure.
- Note the field offset is relative to the outermost struct. */
- if (field->stag != NULL)
- stag_add_field_symbols (field->stag, name,
- field->offset,
- rootsym, root_stag_name);
- field = field->next;
- }
- }
- /* Keep track of stag fields so that when structures are nested we can add the
- complete dereferencing symbols to the symbol table. */
- static void
- stag_add_field (struct stag *parent,
- const char *name,
- bfd_vma offset,
- struct stag *stag)
- {
- struct stag_field *sfield = xmalloc (sizeof (struct stag_field));
- memset (sfield, 0, sizeof (*sfield));
- sfield->name = strcpy (xmalloc (strlen (name) + 1), name);
- sfield->offset = offset;
- sfield->bitfield_offset = parent->current_bitfield_offset;
- sfield->stag = stag;
- if (parent->field == NULL)
- parent->field = sfield;
- else
- {
- struct stag_field *sf = parent->field;
- while (sf->next != NULL)
- sf = sf->next;
- sf->next = sfield;
- }
- /* Only create a symbol for this field if the parent has no name. */
- if (!strncmp (".fake", parent->name, 5))
- {
- symbolS *sym = symbol_new (name, absolute_section,
- (valueT) offset, &zero_address_frag);
- SF_SET_LOCAL (sym);
- symbol_table_insert (sym);
- }
- }
- /* [STAG] .struct [OFFSET]
- Start defining structure offsets (symbols in absolute section). */
- static void
- tic54x_struct (int arg)
- {
- int start_offset = 0;
- int is_union = arg;
- if (!current_stag)
- {
- /* Starting a new struct, switch to absolute section. */
- stag_saved_seg = now_seg;
- stag_saved_subseg = now_subseg;
- subseg_set (absolute_section, 0);
- }
- /* Align the current pointer. */
- else if (current_stag->current_bitfield_offset != 0)
- {
- ++abs_section_offset;
- current_stag->current_bitfield_offset = 0;
- }
- /* Offset expression is only meaningful for global .structs. */
- if (!is_union)
- {
- /* Offset is ignored in inner structs. */
- SKIP_WHITESPACE ();
- if (!is_end_of_line[(int) *input_line_pointer])
- start_offset = get_absolute_expression ();
- else
- start_offset = 0;
- }
- if (current_stag)
- {
- /* Nesting, link to outer one. */
- current_stag->inner = (struct stag *) xmalloc (sizeof (struct stag));
- memset (current_stag->inner, 0, sizeof (struct stag));
- current_stag->inner->outer = current_stag;
- current_stag = current_stag->inner;
- if (start_offset)
- as_warn (_("Offset on nested structures is ignored"));
- start_offset = abs_section_offset;
- }
- else
- {
- current_stag = (struct stag *) xmalloc (sizeof (struct stag));
- memset (current_stag, 0, sizeof (struct stag));
- abs_section_offset = start_offset;
- }
- current_stag->is_union = is_union;
- if (line_label == NULL)
- {
- static int struct_count = 0;
- char fake[] = ".fake_stagNNNNNNN";
- sprintf (fake, ".fake_stag%d", struct_count++);
- current_stag->sym = symbol_new (fake, absolute_section,
- (valueT) abs_section_offset,
- &zero_address_frag);
- }
- else
- {
- char label[strlen (S_GET_NAME (line_label)) + 1];
- strcpy (label, S_GET_NAME (line_label));
- current_stag->sym = symbol_new (label, absolute_section,
- (valueT) abs_section_offset,
- &zero_address_frag);
- }
- current_stag->name = S_GET_NAME (current_stag->sym);
- SF_SET_LOCAL (current_stag->sym);
- /* Nested .structs don't go into the symbol table. */
- if (current_stag->outer == NULL)
- symbol_table_insert (current_stag->sym);
- line_label = NULL;
- }
- /* [LABEL] .endstruct
- finish defining structure offsets; optional LABEL's value will be the size
- of the structure. */
- static void
- tic54x_endstruct (int is_union)
- {
- int size;
- const char *path =
- !strncmp (current_stag->name, ".fake", 5) ? "" : current_stag->name;
- if (!current_stag || current_stag->is_union != is_union)
- {
- as_bad (_(".end%s without preceding .%s"),
- is_union ? "union" : "struct",
- is_union ? "union" : "struct");
- ignore_rest_of_line ();
- return;
- }
- /* Align end of structures. */
- if (current_stag->current_bitfield_offset)
- {
- ++abs_section_offset;
- current_stag->current_bitfield_offset = 0;
- }
- if (current_stag->is_union)
- size = current_stag->size;
- else
- size = abs_section_offset - S_GET_VALUE (current_stag->sym);
- if (line_label != NULL)
- {
- S_SET_VALUE (line_label, size);
- symbol_table_insert (line_label);
- line_label = NULL;
- }
- /* Union size has already been calculated. */
- if (!current_stag->is_union)
- current_stag->size = size;
- /* Nested .structs don't get put in the stag table. */
- if (current_stag->outer == NULL)
- {
- hash_insert (stag_hash, current_stag->name, current_stag);
- stag_add_field_symbols (current_stag, path,
- S_GET_VALUE (current_stag->sym),
- NULL, NULL);
- }
- current_stag = current_stag->outer;
- /* If this is a nested .struct/.union, add it as a field to the enclosing
- one. otherwise, restore the section we were in. */
- if (current_stag != NULL)
- {
- stag_add_field (current_stag, current_stag->inner->name,
- S_GET_VALUE (current_stag->inner->sym),
- current_stag->inner);
- }
- else
- subseg_set (stag_saved_seg, stag_saved_subseg);
- }
- /* [LABEL] .tag STAG
- Reference a structure within a structure, as a sized field with an optional
- label.
- If used outside of a .struct/.endstruct, overlays the given structure
- format on the existing allocated space. */
- static void
- tic54x_tag (int ignore ATTRIBUTE_UNUSED)
- {
- char *name;
- int c = get_symbol_name (&name);
- struct stag *stag = (struct stag *) hash_find (stag_hash, name);
- if (!stag)
- {
- if (*name)
- as_bad (_("Unrecognized struct/union tag '%s'"), name);
- else
- as_bad (_(".tag requires a structure tag"));
- ignore_rest_of_line ();
- return;
- }
- if (line_label == NULL)
- {
- as_bad (_("Label required for .tag"));
- ignore_rest_of_line ();
- return;
- }
- else
- {
- char label[strlen (S_GET_NAME (line_label)) + 1];
- strcpy (label, S_GET_NAME (line_label));
- if (current_stag != NULL)
- stag_add_field (current_stag, label,
- abs_section_offset - S_GET_VALUE (current_stag->sym),
- stag);
- else
- {
- symbolS *sym = symbol_find (label);
- if (!sym)
- {
- as_bad (_(".tag target '%s' undefined"), label);
- ignore_rest_of_line ();
- return;
- }
- stag_add_field_symbols (stag, S_GET_NAME (sym),
- S_GET_VALUE (stag->sym), sym, stag->name);
- }
- }
- /* Bump by the struct size, but only if we're within a .struct section. */
- if (current_stag != NULL && !current_stag->is_union)
- abs_section_offset += stag->size;
- (void) restore_line_pointer (c);
- demand_empty_rest_of_line ();
- line_label = NULL;
- }
- /* Handle all .byte, .char, .double, .field, .float, .half, .int, .long,
- .short, .string, .ubyte, .uchar, .uhalf, .uint, .ulong, .ushort, .uword,
- and .word. */
- static void
- tic54x_struct_field (int type)
- {
- int size;
- int count = 1;
- int new_bitfield_offset = 0;
- int field_align = current_stag->current_bitfield_offset != 0;
- int longword_align = 0;
- SKIP_WHITESPACE ();
- if (!is_end_of_line[(int) *input_line_pointer])
- count = get_absolute_expression ();
- switch (type)
- {
- case 'b':
- case 'B':
- case 'c':
- case 'C':
- case 'h':
- case 'H':
- case 'i':
- case 'I':
- case 's':
- case 'S':
- case 'w':
- case 'W':
- case '*': /* String. */
- size = 1;
- break;
- case 'f':
- case 'l':
- case 'L':
- longword_align = 1;
- size = 2;
- break;
- case '.': /* Bitfield. */
- size = 0;
- if (count < 1 || count > 32)
- {
- as_bad (_(".field count '%d' out of range (1 <= X <= 32)"), count);
- ignore_rest_of_line ();
- return;
- }
- if (current_stag->current_bitfield_offset + count > 16)
- {
- /* Set the appropriate size and new field offset. */
- if (count == 32)
- {
- size = 2;
- count = 1;
- }
- else if (count > 16)
- {
- size = 1;
- count = 1;
- new_bitfield_offset = count - 16;
- }
- else
- new_bitfield_offset = count;
- }
- else
- {
- field_align = 0;
- new_bitfield_offset = current_stag->current_bitfield_offset + count;
- }
- break;
- default:
- as_bad (_("Unrecognized field type '%c'"), type);
- ignore_rest_of_line ();
- return;
- }
- if (field_align)
- {
- /* Align to the actual starting position of the field. */
- current_stag->current_bitfield_offset = 0;
- ++abs_section_offset;
- }
- /* Align to longword boundary. */
- if (longword_align && (abs_section_offset & 0x1))
- ++abs_section_offset;
- if (line_label == NULL)
- {
- static int fieldno = 0;
- char fake[] = ".fake_fieldNNNNN";
- sprintf (fake, ".fake_field%d", fieldno++);
- stag_add_field (current_stag, fake,
- abs_section_offset - S_GET_VALUE (current_stag->sym),
- NULL);
- }
- else
- {
- char label[strlen (S_GET_NAME (line_label) + 1)];
- strcpy (label, S_GET_NAME (line_label));
- stag_add_field (current_stag, label,
- abs_section_offset - S_GET_VALUE (current_stag->sym),
- NULL);
- }
- if (current_stag->is_union)
- {
- /* Note we treat the element as if it were an array of COUNT. */
- if (current_stag->size < (unsigned) size * count)
- current_stag->size = size * count;
- }
- else
- {
- abs_section_offset += (unsigned) size * count;
- current_stag->current_bitfield_offset = new_bitfield_offset;
- }
- line_label = NULL;
- }
- /* Handle .byte, .word. .int, .long and all variants. */
- static void
- tic54x_cons (int type)
- {
- unsigned int c;
- int octets;
- /* If we're within a .struct construct, don't actually allocate space. */
- if (current_stag != NULL)
- {
- tic54x_struct_field (type);
- return;
- }
- #ifdef md_flush_pending_output
- md_flush_pending_output ();
- #endif
- generate_lineno_debug ();
- /* Align long words to long word boundaries (4 octets). */
- if (type == 'l' || type == 'L')
- {
- frag_align (2, 0, 2);
- /* If there's a label, assign it to the first allocated word. */
- if (line_label != NULL)
- {
- symbol_set_frag (line_label, frag_now);
- S_SET_VALUE (line_label, frag_now_fix ());
- }
- }
- switch (type)
- {
- case 'l':
- case 'L':
- case 'x':
- octets = 4;
- break;
- case 'b':
- case 'B':
- case 'c':
- case 'C':
- octets = 1;
- break;
- default:
- octets = 2;
- break;
- }
- do
- {
- if (*input_line_pointer == '"')
- {
- input_line_pointer++;
- while (is_a_char (c = next_char_of_string ()))
- tic54x_emit_char (c);
- know (input_line_pointer[-1] == '\"');
- }
- else
- {
- expressionS expn;
- input_line_pointer = parse_expression (input_line_pointer, &expn);
- if (expn.X_op == O_constant)
- {
- offsetT value = expn.X_add_number;
- /* Truncate overflows. */
- switch (octets)
- {
- case 1:
- if ((value > 0 && value > 0xFF)
- || (value < 0 && value < - 0x100))
- as_warn (_("Overflow in expression, truncated to 8 bits"));
- break;
- case 2:
- if ((value > 0 && value > 0xFFFF)
- || (value < 0 && value < - 0x10000))
- as_warn (_("Overflow in expression, truncated to 16 bits"));
- break;
- }
- }
- if (expn.X_op != O_constant && octets < 2)
- {
- /* Disallow .byte with a non constant expression that will
- require relocation. */
- as_bad (_("Relocatable values require at least WORD storage"));
- ignore_rest_of_line ();
- return;
- }
- if (expn.X_op != O_constant
- && amode == c_mode
- && octets == 4)
- {
- /* FIXME -- at one point TI tools used to output REL16
- relocations, but I don't think the latest tools do at all
- The current tools output extended relocations regardless of
- the addressing mode (I actually think that ".c_mode" is
- totally ignored in the latest tools). */
- amode = far_mode;
- emitting_long = 1;
- emit_expr (&expn, 4);
- emitting_long = 0;
- amode = c_mode;
- }
- else
- {
- emitting_long = octets == 4;
- emit_expr (&expn, (octets == 1) ? 2 : octets);
- emitting_long = 0;
- }
- }
- }
- while (*input_line_pointer++ == ',');
- input_line_pointer--; /* Put terminator back into stream. */
- demand_empty_rest_of_line ();
- }
- /* .global <symbol>[,...,<symbolN>]
- .def <symbol>[,...,<symbolN>]
- .ref <symbol>[,...,<symbolN>]
- These all identify global symbols.
- .def means the symbol is defined in the current module and can be accessed
- by other files. The symbol should be placed in the symbol table.
- .ref means the symbol is used in the current module but defined in another
- module. The linker is to resolve this symbol's definition at link time.
- .global should act as a .ref or .def, as needed.
- global, def and ref all have symbol storage classes of C_EXT.
- I can't identify any difference in how the "other" c54x assembler treats
- these, so we ignore the type here. */
- void
- tic54x_global (int type)
- {
- char *name;
- int c;
- symbolS *symbolP;
- if (type == 'r')
- as_warn (_("Use of .def/.ref is deprecated. Use .global instead"));
- ILLEGAL_WITHIN_STRUCT ();
- do
- {
- c = get_symbol_name (&name);
- symbolP = symbol_find_or_make (name);
- c = restore_line_pointer (c);
- S_SET_STORAGE_CLASS (symbolP, C_EXT);
- if (c == ',')
- {
- input_line_pointer++;
- if (is_end_of_line[(int) *input_line_pointer])
- c = *input_line_pointer;
- }
- }
- while (c == ',');
- demand_empty_rest_of_line ();
- }
- /* Remove the symbol from the local label hash lookup. */
- static void
- tic54x_remove_local_label (const char *key, void *value ATTRIBUTE_UNUSED)
- {
- void *elem = hash_delete (local_label_hash[macro_level], key, FALSE);
- free (elem);
- }
- /* Reset all local labels. */
- static void
- tic54x_clear_local_labels (int ignored ATTRIBUTE_UNUSED)
- {
- hash_traverse (local_label_hash[macro_level], tic54x_remove_local_label);
- }
- /* .text
- .data
- .sect "section name"
- Initialized section
- make sure local labels get cleared when changing sections
- ARG is 't' for text, 'd' for data, or '*' for a named section
- For compatibility, '*' sections are SEC_CODE if instructions are
- encountered, or SEC_DATA if not.
- */
- static void
- tic54x_sect (int arg)
- {
- ILLEGAL_WITHIN_STRUCT ();
- /* Local labels are cleared when changing sections. */
- tic54x_clear_local_labels (0);
- if (arg == 't')
- s_text (0);
- else if (arg == 'd')
- s_data (0);
- else
- {
- char *name = NULL;
- int len;
- /* If there are quotes, remove them. */
- if (*input_line_pointer == '"')
- {
- name = demand_copy_C_string (&len);
- demand_empty_rest_of_line ();
- name = strcpy (xmalloc (len + 10), name);
- }
- else
- {
- int c;
- c = get_symbol_name (&name);
- len = strlen(name);
- name = strcpy (xmalloc (len + 10), name);
- (void) restore_line_pointer (c);
- demand_empty_rest_of_line ();
- }
- /* Make sure all named initialized sections flagged properly. If we
- encounter instructions, we'll flag it with SEC_CODE as well. */
- strcat (name, ",\"w\"\n");
- input_scrub_insert_line (name);
- obj_coff_section (0);
- /* If there was a line label, make sure that it gets assigned the proper
- section. This is for compatibility, even though the actual behavior
- is not explicitly defined. For consistency, we make .sect behave
- like .usect, since that is probably what people expect. */
- if (line_label != NULL)
- {
- S_SET_SEGMENT (line_label, now_seg);
- symbol_set_frag (line_label, frag_now);
- S_SET_VALUE (line_label, frag_now_fix ());
- if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
- S_SET_STORAGE_CLASS (line_label, C_LABEL);
- }
- }
- }
- /* [symbol] .space space_in_bits
- [symbol] .bes space_in_bits
- BES puts the symbol at the *last* word allocated
- cribbed from s_space. */
- static void
- tic54x_space (int arg)
- {
- expressionS expn;
- char *p = 0;
- int octets = 0;
- long words;
- int bits_per_byte = (OCTETS_PER_BYTE * 8);
- int bit_offset = 0;
- symbolS *label = line_label;
- int bes = arg;
- ILLEGAL_WITHIN_STRUCT ();
- #ifdef md_flush_pending_output
- md_flush_pending_output ();
- #endif
- /* Read the bit count. */
- expression (&expn);
- /* Some expressions are unresolvable until later in the assembly pass;
- postpone until relaxation/fixup. we also have to postpone if a previous
- partial allocation has not been completed yet. */
- if (expn.X_op != O_constant || frag_bit_offset (frag_now, now_seg) == -1)
- {
- struct bit_info *bi = xmalloc (sizeof (struct bit_info));
- bi->seg = now_seg;
- bi->type = bes;
- bi->sym = label;
- p = frag_var (rs_machine_dependent,
- 65536 * 2, 1, (relax_substateT) 0,
- make_expr_symbol (&expn), (offsetT) 0,
- (char *) bi);
- if (p)
- *p = 0;
- return;
- }
- /* Reduce the required size by any bit offsets currently left over
- from a previous .space/.bes/.field directive. */
- bit_offset = frag_now->tc_frag_data;
- if (bit_offset != 0 && bit_offset < 16)
- {
- int spare_bits = bits_per_byte - bit_offset;
- if (spare_bits >= expn.X_add_number)
- {
- /* Don't have to do anything; sufficient bits have already been
- allocated; just point the label to the right place. */
- if (label != NULL)
- {
- symbol_set_frag (label, frag_now);
- S_SET_VALUE (label, frag_now_fix () - 1);
- label = NULL;
- }
- frag_now->tc_frag_data += expn.X_add_number;
- goto getout;
- }
- expn.X_add_number -= spare_bits;
- /* Set the label to point to the first word allocated, which in this
- case is the previous word, which was only partially filled. */
- if (!bes && label != NULL)
- {
- symbol_set_frag (label, frag_now);
- S_SET_VALUE (label, frag_now_fix () - 1);
- label = NULL;
- }
- }
- /* Convert bits to bytes/words and octets, rounding up. */
- words = ((expn.X_add_number + bits_per_byte - 1) / bits_per_byte);
- /* How many do we have left over? */
- bit_offset = expn.X_add_number % bits_per_byte;
- octets = words * OCTETS_PER_BYTE;
- if (octets < 0)
- {
- as_warn (_(".space/.bes repeat count is negative, ignored"));
- goto getout;
- }
- else if (octets == 0)
- {
- as_warn (_(".space/.bes repeat count is zero, ignored"));
- goto getout;
- }
- /* If we are in the absolute section, just bump the offset. */
- if (now_seg == absolute_section)
- {
- abs_section_offset += words;
- if (bes && label != NULL)
- S_SET_VALUE (label, abs_section_offset - 1);
- frag_now->tc_frag_data = bit_offset;
- goto getout;
- }
- if (!need_pass_2)
- p = frag_var (rs_fill, 1, 1,
- (relax_substateT) 0, (symbolS *) 0,
- (offsetT) octets, (char *) 0);
- /* Make note of how many bits of this word we've allocated so far. */
- frag_now->tc_frag_data = bit_offset;
- /* .bes puts label at *last* word allocated. */
- if (bes && label != NULL)
- {
- symbol_set_frag (label, frag_now);
- S_SET_VALUE (label, frag_now_fix () - 1);
- }
- if (p)
- *p = 0;
- getout:
- demand_empty_rest_of_line ();
- }
- /* [symbol] .usect "section-name", size-in-words
- [, [blocking-flag] [, alignment-flag]]
- Uninitialized section.
- Non-zero blocking means that if the section would cross a page (128-word)
- boundary, it will be page-aligned.
- Non-zero alignment aligns on a longword boundary.
- Has no effect on the current section. */
- static void
- tic54x_usect (int x ATTRIBUTE_UNUSED)
- {
- char c;
- char *name;
- char *section_name;
- char *p;
- segT seg;
- int size, blocking_flag, alignment_flag;
- segT current_seg;
- subsegT current_subseg;
- flagword flags;
- ILLEGAL_WITHIN_STRUCT ();
- current_seg = now_seg; /* Save current seg. */
- current_subseg = now_subseg; /* Save current subseg. */
- c = get_symbol_name (§ion_name); /* Get terminator. */
- name = xmalloc (input_line_pointer - section_name + 1);
- strcpy (name, section_name);
- c = restore_line_pointer (c);
-
- if (c == ',')
- ++input_line_pointer;
- else
- {
- as_bad (_("Missing size argument"));
- ignore_rest_of_line ();
- return;
- }
- size = get_absolute_expression ();
- /* Read a possibly present third argument (blocking flag). */
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- if (*input_line_pointer != ',')
- blocking_flag = get_absolute_expression ();
- else
- blocking_flag = 0;
- /* Read a possibly present fourth argument (alignment flag). */
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- alignment_flag = get_absolute_expression ();
- }
- else
- alignment_flag = 0;
- }
- else
- blocking_flag = alignment_flag = 0;
- seg = subseg_new (name, 0);
- flags = bfd_get_section_flags (stdoutput, seg) | SEC_ALLOC;
- if (alignment_flag)
- {
- /* s_align eats end of line; restore it. */
- s_align_bytes (4);
- --input_line_pointer;
- }
- if (line_label != NULL)
- {
- S_SET_SEGMENT (line_label, seg);
- symbol_set_frag (line_label, frag_now);
- S_SET_VALUE (line_label, frag_now_fix ());
- /* Set scl to label, since that's what TI does. */
- if (S_GET_STORAGE_CLASS (line_label) != C_EXT)
- S_SET_STORAGE_CLASS (line_label, C_LABEL);
- }
- seg_info (seg)->bss = 1; /* Uninitialized data. */
- p = frag_var (rs_fill, 1, 1,
- (relax_substateT) 0, (symbolS *) line_label,
- size * OCTETS_PER_BYTE, (char *) 0);
- *p = 0;
- if (blocking_flag)
- flags |= SEC_TIC54X_BLOCK;
- if (!bfd_set_section_flags (stdoutput, seg, flags))
- as_warn (_("Error setting flags for \"%s\": %s"), name,
- bfd_errmsg (bfd_get_error ()));
- subseg_set (current_seg, current_subseg); /* Restore current seg. */
- demand_empty_rest_of_line ();
- }
- static enum cpu_version
- lookup_version (const char *ver)
- {
- enum cpu_version version = VNONE;
- if (ver[0] == '5' && ver[1] == '4')
- {
- if (strlen (ver) == 3
- && (ver[2] == '1' || ver[2] == '2' || ver[2] == '3'
- || ver[2] == '5' || ver[2] == '8' || ver[2] == '9'))
- version = ver[2] - '0';
- else if (strlen (ver) == 5
- && TOUPPER (ver[3]) == 'L'
- && TOUPPER (ver[4]) == 'P'
- && (ver[2] == '5' || ver[2] == '6'))
- version = ver[2] - '0' + 10;
- }
- return version;
- }
- static void
- set_cpu (enum cpu_version version)
- {
- cpu = version;
- if (version == V545LP || version == V546LP)
- {
- symbolS *symbolP = symbol_new ("__allow_lp", absolute_section,
- (valueT) 1, &zero_address_frag);
- SF_SET_LOCAL (symbolP);
- symbol_table_insert (symbolP);
- }
- }
- /* .version cpu-version
- cpu-version may be one of the following:
- 541
- 542
- 543
- 545
- 545LP
- 546LP
- 548
- 549
- This is for compatibility only. It currently has no affect on assembly. */
- static int cpu_needs_set = 1;
- static void
- tic54x_version (int x ATTRIBUTE_UNUSED)
- {
- enum cpu_version version = VNONE;
- enum cpu_version old_version = cpu;
- int c;
- char *ver;
- ILLEGAL_WITHIN_STRUCT ();
- SKIP_WHITESPACE ();
- ver = input_line_pointer;
- while (!is_end_of_line[(int) *input_line_pointer])
- ++input_line_pointer;
- c = *input_line_pointer;
- *input_line_pointer = 0;
- version = lookup_version (ver);
- if (cpu != VNONE && cpu != version)
- as_warn (_("CPU version has already been set"));
- if (version == VNONE)
- {
- as_bad (_("Unrecognized version '%s'"), ver);
- ignore_rest_of_line ();
- return;
- }
- else if (assembly_begun && version != old_version)
- {
- as_bad (_("Changing of CPU version on the fly not supported"));
- ignore_rest_of_line ();
- return;
- }
- set_cpu (version);
- *input_line_pointer = c;
- demand_empty_rest_of_line ();
- }
- /* 'f' = float, 'x' = xfloat, 'd' = double, 'l' = ldouble. */
- static void
- tic54x_float_cons (int type)
- {
- if (current_stag != 0)
- tic54x_struct_field ('f');
- #ifdef md_flush_pending_output
- md_flush_pending_output ();
- #endif
- /* Align to long word boundary (4 octets) unless it's ".xfloat". */
- if (type != 'x')
- {
- frag_align (2, 0, 2);
- /* If there's a label, assign it to the first allocated word. */
- if (line_label != NULL)
- {
- symbol_set_frag (line_label, frag_now);
- S_SET_VALUE (line_label, frag_now_fix ());
- }
- }
- float_cons ('f');
- }
- /* The argument is capitalized if it should be zero-terminated
- 's' is normal string with upper 8-bits zero-filled, 'p' is packed.
- Code copied from stringer, and slightly modified so that strings are packed
- and encoded into the correct octets. */
- static void
- tic54x_stringer (int type)
- {
- unsigned int c;
- int append_zero = type == 'S' || type == 'P';
- int packed = type == 'p' || type == 'P';
- int last_char = -1; /* Packed strings need two bytes at a time to encode. */
- if (current_stag != NULL)
- {
- tic54x_struct_field ('*');
- return;
- }
- #ifdef md_flush_pending_output
- md_flush_pending_output ();
- #endif
- c = ','; /* Do loop. */
- while (c == ',')
- {
- SKIP_WHITESPACE ();
- switch (*input_line_pointer)
- {
- default:
- {
- unsigned short value = get_absolute_expression ();
- FRAG_APPEND_1_CHAR ( value & 0xFF);
- FRAG_APPEND_1_CHAR ((value >> 8) & 0xFF);
- break;
- }
- case '\"':
- ++input_line_pointer; /* -> 1st char of string. */
- while (is_a_char (c = next_char_of_string ()))
- {
- if (!packed)
- {
- FRAG_APPEND_1_CHAR (c);
- FRAG_APPEND_1_CHAR (0);
- }
- else
- {
- /* Packed strings are filled MS octet first. */
- if (last_char == -1)
- last_char = c;
- else
- {
- FRAG_APPEND_1_CHAR (c);
- FRAG_APPEND_1_CHAR (last_char);
- last_char = -1;
- }
- }
- }
- if (append_zero)
- {
- if (packed && last_char != -1)
- {
- FRAG_APPEND_1_CHAR (0);
- FRAG_APPEND_1_CHAR (last_char);
- last_char = -1;
- }
- else
- {
- FRAG_APPEND_1_CHAR (0);
- FRAG_APPEND_1_CHAR (0);
- }
- }
- know (input_line_pointer[-1] == '\"');
- break;
- }
- SKIP_WHITESPACE ();
- c = *input_line_pointer;
- if (!is_end_of_line[c])
- ++input_line_pointer;
- }
- /* Finish up any leftover packed string. */
- if (packed && last_char != -1)
- {
- FRAG_APPEND_1_CHAR (0);
- FRAG_APPEND_1_CHAR (last_char);
- }
- demand_empty_rest_of_line ();
- }
- static void
- tic54x_p2align (int arg ATTRIBUTE_UNUSED)
- {
- as_bad (_("p2align not supported on this target"));
- }
- static void
- tic54x_align_words (int arg)
- {
- /* Only ".align" with no argument is allowed within .struct/.union. */
- int count = arg;
- if (!is_end_of_line[(int) *input_line_pointer])
- {
- if (arg == 2)
- as_warn (_("Argument to .even ignored"));
- else
- count = get_absolute_expression ();
- }
- if (current_stag != NULL && arg == 128)
- {
- if (current_stag->current_bitfield_offset != 0)
- {
- current_stag->current_bitfield_offset = 0;
- ++abs_section_offset;
- }
- demand_empty_rest_of_line ();
- return;
- }
- ILLEGAL_WITHIN_STRUCT ();
- s_align_bytes (count << 1);
- }
- /* Initialize multiple-bit fields withing a single word of memory. */
- static void
- tic54x_field (int ignore ATTRIBUTE_UNUSED)
- {
- expressionS expn;
- int size = 16;
- char *p;
- valueT value;
- symbolS *label = line_label;
- if (current_stag != NULL)
- {
- tic54x_struct_field ('.');
- return;
- }
- input_line_pointer = parse_expression (input_line_pointer, &expn);
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- size = get_absolute_expression ();
- if (size < 1 || size > 32)
- {
- as_bad (_("Invalid field size, must be from 1 to 32"));
- ignore_rest_of_line ();
- return;
- }
- }
- /* Truncate values to the field width. */
- if (expn.X_op != O_constant)
- {
- /* If the expression value is relocatable, the field size *must*
- be 16. */
- if (size != 16)
- {
- as_bad (_("field size must be 16 when value is relocatable"));
- ignore_rest_of_line ();
- return;
- }
- frag_now->tc_frag_data = 0;
- emit_expr (&expn, 2);
- }
- else
- {
- unsigned long fmask = (size == 32) ? 0xFFFFFFFF : (1ul << size) - 1;
- value = expn.X_add_number;
- expn.X_add_number &= fmask;
- if (value != (valueT) expn.X_add_number)
- as_warn (_("field value truncated"));
- value = expn.X_add_number;
- /* Bits are stored MS first. */
- while (size >= 16)
- {
- frag_now->tc_frag_data = 0;
- p = frag_more (2);
- md_number_to_chars (p, (value >> (size - 16)) & 0xFFFF, 2);
- size -= 16;
- }
- if (size > 0)
- {
- int bit_offset = frag_bit_offset (frag_now, now_seg);
- fragS *alloc_frag = bit_offset_frag (frag_now, now_seg);
- if (bit_offset == -1)
- {
- struct bit_info *bi = xmalloc (sizeof (struct bit_info));
- /* We don't know the previous offset at this time, so store the
- info we need and figure it out later. */
- expressionS size_exp;
- size_exp.X_op = O_constant;
- size_exp.X_add_number = size;
- bi->seg = now_seg;
- bi->type = TYPE_FIELD;
- bi->value = value;
- p = frag_var (rs_machine_dependent,
- 4, 1, (relax_substateT) 0,
- make_expr_symbol (&size_exp), (offsetT) 0,
- (char *) bi);
- goto getout;
- }
- else if (bit_offset == 0 || bit_offset + size > 16)
- {
- /* Align a new field. */
- p = frag_more (2);
- frag_now->tc_frag_data = 0;
- alloc_frag = frag_now;
- }
- else
- {
- /* Put the new value entirely within the existing one. */
- p = alloc_frag == frag_now ?
- frag_now->fr_literal + frag_now_fix_octets () - 2 :
- alloc_frag->fr_literal;
- if (label != NULL)
- {
- symbol_set_frag (label, alloc_frag);
- if (alloc_frag == frag_now)
- S_SET_VALUE (label, frag_now_fix () - 1);
- label = NULL;
- }
- }
- value <<= 16 - alloc_frag->tc_frag_data - size;
- /* OR in existing value. */
- if (alloc_frag->tc_frag_data)
- value |= ((unsigned short) p[1] << 8) | p[0];
- md_number_to_chars (p, value, 2);
- alloc_frag->tc_frag_data += size;
- if (alloc_frag->tc_frag_data == 16)
- alloc_frag->tc_frag_data = 0;
- }
- }
- getout:
- demand_empty_rest_of_line ();
- }
- /* Ideally, we want to check SEC_LOAD and SEC_HAS_CONTENTS, but those aren't
- available yet. seg_info ()->bss is the next best thing. */
- static int
- tic54x_initialized_section (segT seg)
- {
- return !seg_info (seg)->bss;
- }
- /* .clink ["section name"]
- Marks the section as conditionally linked (link only if contents are
- referenced elsewhere.
- Without a name, refers to the current initialized section.
- Name is required for uninitialized sections. */
- static void
- tic54x_clink (int ignored ATTRIBUTE_UNUSED)
- {
- segT seg = now_seg;
- ILLEGAL_WITHIN_STRUCT ();
- if (*input_line_pointer == '\"')
- {
- char *section_name = ++input_line_pointer;
- char *name;
- while (is_a_char (next_char_of_string ()))
- ;
- know (input_line_pointer[-1] == '\"');
- input_line_pointer[-1] = 0;
- name = xmalloc (input_line_pointer - section_name + 1);
- strcpy (name, section_name);
- seg = bfd_get_section_by_name (stdoutput, name);
- if (seg == NULL)
- {
- as_bad (_("Unrecognized section '%s'"), section_name);
- ignore_rest_of_line ();
- return;
- }
- }
- else
- {
- if (!tic54x_initialized_section (seg))
- {
- as_bad (_("Current section is unitialized, "
- "section name required for .clink"));
- ignore_rest_of_line ();
- return;
- }
- }
- seg->flags |= SEC_TIC54X_CLINK;
- demand_empty_rest_of_line ();
- }
- /* Change the default include directory to be the current source file's
- directory, instead of the current working directory. If DOT is non-zero,
- set to "." instead. */
- static void
- tic54x_set_default_include (int dot)
- {
- char *dir = ".";
- char *tmp = NULL;
- if (!dot)
- {
- char *curfile;
- unsigned lineno;
- as_where (&curfile, &lineno);
- dir = strcpy (xmalloc (strlen (curfile) + 1), curfile);
- tmp = strrchr (dir, '/');
- }
- if (tmp != NULL)
- {
- int len;
- *tmp = '\0';
- len = strlen (dir);
- if (include_dir_count == 0)
- {
- include_dirs = (char **) xmalloc (sizeof (*include_dirs));
- include_dir_count = 1;
- }
- include_dirs[0] = dir;
- if (len > include_dir_maxlen)
- include_dir_maxlen = len;
- }
- else if (include_dirs != NULL)
- include_dirs[0] = ".";
- }
- /* .include "filename" | filename
- .copy "filename" | filename
- FIXME 'include' file should be omitted from any output listing,
- 'copy' should be included in any output listing
- FIXME -- prevent any included files from changing listing (compat only)
- FIXME -- need to include source file directory in search path; what's a
- good way to do this?
- Entering/exiting included/copied file clears all local labels. */
- static void
- tic54x_include (int ignored ATTRIBUTE_UNUSED)
- {
- char newblock[] = " .newblock\n";
- char *filename;
- char *input;
- int len, c = -1;
- ILLEGAL_WITHIN_STRUCT ();
- SKIP_WHITESPACE ();
- if (*input_line_pointer == '"')
- {
- filename = demand_copy_C_string (&len);
- demand_empty_rest_of_line ();
- }
- else
- {
- filename = input_line_pointer;
- while (!is_end_of_line[(int) *input_line_pointer])
- ++input_line_pointer;
- c = *input_line_pointer;
- *input_line_pointer = '\0';
- filename = strcpy (xmalloc (strlen (filename) + 1), filename);
- *input_line_pointer = c;
- demand_empty_rest_of_line ();
- }
- /* Insert a partial line with the filename (for the sake of s_include)
- and a .newblock.
- The included file will be inserted before the newblock, so that the
- newblock is executed after the included file is processed. */
- input = xmalloc (sizeof (newblock) + strlen (filename) + 4);
- sprintf (input, "\"%s\"\n%s", filename, newblock);
- input_scrub_insert_line (input);
- tic54x_clear_local_labels (0);
- tic54x_set_default_include (0);
- s_include (0);
- }
- static void
- tic54x_message (int type)
- {
- char *msg;
- char c;
- int len;
- ILLEGAL_WITHIN_STRUCT ();
- if (*input_line_pointer == '"')
- msg = demand_copy_C_string (&len);
- else
- {
- msg = input_line_pointer;
- while (!is_end_of_line[(int) *input_line_pointer])
- ++input_line_pointer;
- c = *input_line_pointer;
- *input_line_pointer = 0;
- msg = strcpy (xmalloc (strlen (msg) + 1), msg);
- *input_line_pointer = c;
- }
- switch (type)
- {
- case 'm':
- as_tsktsk ("%s", msg);
- break;
- case 'w':
- as_warn ("%s", msg);
- break;
- case 'e':
- as_bad ("%s", msg);
- break;
- }
- demand_empty_rest_of_line ();
- }
- /* .label <symbol>
- Define a special symbol that refers to the loadtime address rather than the
- runtime address within the current section.
- This symbol gets a special storage class so that when it is resolved, it is
- resolved relative to the load address (lma) of the section rather than the
- run address (vma). */
- static void
- tic54x_label (int ignored ATTRIBUTE_UNUSED)
- {
- char *name;
- symbolS *symbolP;
- int c;
- ILLEGAL_WITHIN_STRUCT ();
- c = get_symbol_name (&name);
- symbolP = colon (name);
- S_SET_STORAGE_CLASS (symbolP, C_STATLAB);
- (void) restore_line_pointer (c);
- demand_empty_rest_of_line ();
- }
- /* .mmregs
- Install all memory-mapped register names into the symbol table as
- absolute local symbols. */
- static void
- tic54x_mmregs (int ignored ATTRIBUTE_UNUSED)
- {
- symbol *sym;
- ILLEGAL_WITHIN_STRUCT ();
- for (sym = (symbol *) mmregs; sym->name; sym++)
- {
- symbolS *symbolP = symbol_new (sym->name, absolute_section,
- (valueT) sym->value, &zero_address_frag);
- SF_SET_LOCAL (symbolP);
- symbol_table_insert (symbolP);
- }
- }
- /* .loop [count]
- Count defaults to 1024. */
- static void
- tic54x_loop (int count)
- {
- ILLEGAL_WITHIN_STRUCT ();
- SKIP_WHITESPACE ();
- if (!is_end_of_line[(int) *input_line_pointer])
- count = get_absolute_expression ();
- do_repeat (count, "LOOP", "ENDLOOP");
- }
- /* Normally, endloop gets eaten by the preceding loop. */
- static void
- tic54x_endloop (int ignore ATTRIBUTE_UNUSED)
- {
- as_bad (_("ENDLOOP without corresponding LOOP"));
- ignore_rest_of_line ();
- }
- /* .break [condition]. */
- static void
- tic54x_break (int ignore ATTRIBUTE_UNUSED)
- {
- int cond = 1;
- ILLEGAL_WITHIN_STRUCT ();
- SKIP_WHITESPACE ();
- if (!is_end_of_line[(int) *input_line_pointer])
- cond = get_absolute_expression ();
- if (cond)
- end_repeat (substitution_line ? 1 : 0);
- }
- static void
- set_address_mode (int mode)
- {
- amode = mode;
- if (mode == far_mode)
- {
- symbolS *symbolP = symbol_new ("__allow_far", absolute_section,
- (valueT) 1, &zero_address_frag);
- SF_SET_LOCAL (symbolP);
- symbol_table_insert (symbolP);
- }
- }
- static int address_mode_needs_set = 1;
- static void
- tic54x_address_mode (int mode)
- {
- if (assembly_begun && amode != (unsigned) mode)
- {
- as_bad (_("Mixing of normal and extended addressing not supported"));
- ignore_rest_of_line ();
- return;
- }
- if (mode == far_mode && cpu != VNONE && cpu != V548 && cpu != V549)
- {
- as_bad (_("Extended addressing not supported on the specified CPU"));
- ignore_rest_of_line ();
- return;
- }
- set_address_mode (mode);
- demand_empty_rest_of_line ();
- }
- /* .sblock "section"|section [,...,"section"|section]
- Designate initialized sections for blocking. */
- static void
- tic54x_sblock (int ignore ATTRIBUTE_UNUSED)
- {
- int c = ',';
- ILLEGAL_WITHIN_STRUCT ();
- while (c == ',')
- {
- segT seg;
- char *name;
- if (*input_line_pointer == '"')
- {
- int len;
- name = demand_copy_C_string (&len);
- }
- else
- {
- char *section_name;
- c = get_symbol_name (§ion_name);
- name = xmalloc (strlen (section_name) + 1);
- strcpy (name, section_name);
- (void) restore_line_pointer (c);
- }
- seg = bfd_get_section_by_name (stdoutput, name);
- if (seg == NULL)
- {
- as_bad (_("Unrecognized section '%s'"), name);
- ignore_rest_of_line ();
- return;
- }
- else if (!tic54x_initialized_section (seg))
- {
- as_bad (_(".sblock may be used for initialized sections only"));
- ignore_rest_of_line ();
- return;
- }
- seg->flags |= SEC_TIC54X_BLOCK;
- c = *input_line_pointer;
- if (!is_end_of_line[(int) c])
- ++input_line_pointer;
- }
- demand_empty_rest_of_line ();
- }
- /* symbol .set value
- symbol .equ value
- value must be defined externals; no forward-referencing allowed
- symbols assigned with .set/.equ may not be redefined. */
- static void
- tic54x_set (int ignore ATTRIBUTE_UNUSED)
- {
- symbolS *symbolP;
- char *name;
- ILLEGAL_WITHIN_STRUCT ();
- if (!line_label)
- {
- as_bad (_("Symbol missing for .set/.equ"));
- ignore_rest_of_line ();
- return;
- }
- name = xstrdup (S_GET_NAME (line_label));
- line_label = NULL;
- if ((symbolP = symbol_find (name)) == NULL
- && (symbolP = md_undefined_symbol (name)) == NULL)
- {
- symbolP = symbol_new (name, absolute_section, 0, &zero_address_frag);
- S_SET_STORAGE_CLASS (symbolP, C_STAT);
- }
- free (name);
- S_SET_DATA_TYPE (symbolP, T_INT);
- S_SET_SEGMENT (symbolP, absolute_section);
- symbol_table_insert (symbolP);
- pseudo_set (symbolP);
- demand_empty_rest_of_line ();
- }
- /* .fclist
- .fcnolist
- List false conditional blocks. */
- static void
- tic54x_fclist (int show)
- {
- if (show)
- listing &= ~LISTING_NOCOND;
- else
- listing |= LISTING_NOCOND;
- demand_empty_rest_of_line ();
- }
- static void
- tic54x_sslist (int show)
- {
- ILLEGAL_WITHIN_STRUCT ();
- listing_sslist = show;
- }
- /* .var SYM[,...,SYMN]
- Define a substitution string to be local to a macro. */
- static void
- tic54x_var (int ignore ATTRIBUTE_UNUSED)
- {
- static char empty[] = "";
- char *name;
- int c;
- ILLEGAL_WITHIN_STRUCT ();
- if (macro_level == 0)
- {
- as_bad (_(".var may only be used within a macro definition"));
- ignore_rest_of_line ();
- return;
- }
- do
- {
- if (!ISALPHA (*input_line_pointer))
- {
- as_bad (_("Substitution symbols must begin with a letter"));
- ignore_rest_of_line ();
- return;
- }
- c = get_symbol_name (&name);
- /* .var symbols start out with a null string. */
- name = strcpy (xmalloc (strlen (name) + 1), name);
- hash_insert (subsym_hash[macro_level], name, empty);
- c = restore_line_pointer (c);
- if (c == ',')
- {
- ++input_line_pointer;
- if (is_end_of_line[(int) *input_line_pointer])
- c = *input_line_pointer;
- }
- }
- while (c == ',');
- demand_empty_rest_of_line ();
- }
- /* .mlib <macro library filename>
- Macro libraries are archived (standard AR-format) text macro definitions
- Expand the file and include it.
- FIXME need to try the source file directory as well. */
- static void
- tic54x_mlib (int ignore ATTRIBUTE_UNUSED)
- {
- char *filename;
- char *path;
- int len, i;
- bfd *abfd, *mbfd;
- ILLEGAL_WITHIN_STRUCT ();
- /* Parse the filename. */
- if (*input_line_pointer == '"')
- {
- if ((filename = demand_copy_C_string (&len)) == NULL)
- return;
- }
- else
- {
- SKIP_WHITESPACE ();
- len = 0;
- while (!is_end_of_line[(int) *input_line_pointer]
- && !ISSPACE (*input_line_pointer))
- {
- obstack_1grow (¬es, *input_line_pointer);
- ++input_line_pointer;
- ++len;
- }
- obstack_1grow (¬es, '\0');
- filename = obstack_finish (¬es);
- }
- demand_empty_rest_of_line ();
- tic54x_set_default_include (0);
- path = xmalloc ((unsigned long) len + include_dir_maxlen + 5);
- for (i = 0; i < include_dir_count; i++)
- {
- FILE *try;
- strcpy (path, include_dirs[i]);
- strcat (path, "/");
- strcat (path, filename);
- if ((try = fopen (path, "r")) != NULL)
- {
- fclose (try);
- break;
- }
- }
- if (i >= include_dir_count)
- {
- free (path);
- path = filename;
- }
- /* FIXME: if path is found, malloc'd storage is not freed. Of course, this
- happens all over the place, and since the assembler doesn't usually keep
- running for a very long time, it really doesn't matter. */
- register_dependency (path);
- /* Expand all archive entries to temporary files and include them. */
- abfd = bfd_openr (path, NULL);
- if (!abfd)
- {
- as_bad (_("can't open macro library file '%s' for reading: %s"),
- path, bfd_errmsg (bfd_get_error ()));
- ignore_rest_of_line ();
- return;
- }
- if (!bfd_check_format (abfd, bfd_archive))
- {
- as_bad (_("File '%s' not in macro archive format"), path);
- ignore_rest_of_line ();
- return;
- }
- /* Open each BFD as binary (it should be straight ASCII text). */
- for (mbfd = bfd_openr_next_archived_file (abfd, NULL);
- mbfd != NULL; mbfd = bfd_openr_next_archived_file (abfd, mbfd))
- {
- /* Get a size at least as big as the archive member. */
- bfd_size_type size = bfd_get_size (mbfd);
- char *buf = xmalloc (size);
- char *fname = tmpnam (NULL);
- FILE *ftmp;
- /* We're not sure how big it is, but it will be smaller than "size". */
- size = bfd_bread (buf, size, mbfd);
- /* Write to a temporary file, then use s_include to include it
- a bit of a hack. */
- ftmp = fopen (fname, "w+b");
- fwrite ((void *) buf, size, 1, ftmp);
- if (size == 0 || buf[size - 1] != '\n')
- fwrite ("\n", 1, 1, ftmp);
- fclose (ftmp);
- free (buf);
- input_scrub_insert_file (fname);
- unlink (fname);
- }
- }
- const pseudo_typeS md_pseudo_table[] =
- {
- { "algebraic", s_ignore , 0 },
- { "align" , tic54x_align_words , 128 },
- { "ascii" , tic54x_stringer , 'p' },
- { "asciz" , tic54x_stringer , 'P' },
- { "even" , tic54x_align_words , 2 },
- { "asg" , tic54x_asg , 0 },
- { "eval" , tic54x_eval , 0 },
- { "bss" , tic54x_bss , 0 },
- { "byte" , tic54x_cons , 'b' },
- { "ubyte" , tic54x_cons , 'B' },
- { "char" , tic54x_cons , 'c' },
- { "uchar" , tic54x_cons , 'C' },
- { "clink" , tic54x_clink , 0 },
- { "c_mode" , tic54x_address_mode , c_mode },
- { "copy" , tic54x_include , 'c' },
- { "include" , tic54x_include , 'i' },
- { "data" , tic54x_sect , 'd' },
- { "double" , tic54x_float_cons , 'd' },
- { "ldouble" , tic54x_float_cons , 'l' },
- { "drlist" , s_ignore , 0 },
- { "drnolist" , s_ignore , 0 },
- { "emsg" , tic54x_message , 'e' },
- { "mmsg" , tic54x_message , 'm' },
- { "wmsg" , tic54x_message , 'w' },
- { "far_mode" , tic54x_address_mode , far_mode },
- { "fclist" , tic54x_fclist , 1 },
- { "fcnolist" , tic54x_fclist , 0 },
- { "field" , tic54x_field , -1 },
- { "float" , tic54x_float_cons , 'f' },
- { "xfloat" , tic54x_float_cons , 'x' },
- { "global" , tic54x_global , 'g' },
- { "def" , tic54x_global , 'd' },
- { "ref" , tic54x_global , 'r' },
- { "half" , tic54x_cons , 'h' },
- { "uhalf" , tic54x_cons , 'H' },
- { "short" , tic54x_cons , 's' },
- { "ushort" , tic54x_cons , 'S' },
- { "if" , s_if , (int) O_ne },
- { "elseif" , s_elseif , (int) O_ne },
- { "else" , s_else , 0 },
- { "endif" , s_endif , 0 },
- { "int" , tic54x_cons , 'i' },
- { "uint" , tic54x_cons , 'I' },
- { "word" , tic54x_cons , 'w' },
- { "uword" , tic54x_cons , 'W' },
- { "label" , tic54x_label , 0 }, /* Loadtime
- address. */
- { "length" , s_ignore , 0 },
- { "width" , s_ignore , 0 },
- { "long" , tic54x_cons , 'l' },
- { "ulong" , tic54x_cons , 'L' },
- { "xlong" , tic54x_cons , 'x' },
- { "loop" , tic54x_loop , 1024 },
- { "break" , tic54x_break , 0 },
- { "endloop" , tic54x_endloop , 0 },
- { "mlib" , tic54x_mlib , 0 },
- { "mlist" , s_ignore , 0 },
- { "mnolist" , s_ignore , 0 },
- { "mmregs" , tic54x_mmregs , 0 },
- { "newblock" , tic54x_clear_local_labels, 0 },
- { "option" , s_ignore , 0 },
- { "p2align" , tic54x_p2align , 0 },
- { "sblock" , tic54x_sblock , 0 },
- { "sect" , tic54x_sect , '*' },
- { "set" , tic54x_set , 0 },
- { "equ" , tic54x_set , 0 },
- { "space" , tic54x_space , 0 },
- { "bes" , tic54x_space , 1 },
- { "sslist" , tic54x_sslist , 1 },
- { "ssnolist" , tic54x_sslist , 0 },
- { "string" , tic54x_stringer , 's' },
- { "pstring" , tic54x_stringer , 'p' },
- { "struct" , tic54x_struct , 0 },
- { "tag" , tic54x_tag , 0 },
- { "endstruct", tic54x_endstruct , 0 },
- { "tab" , s_ignore , 0 },
- { "text" , tic54x_sect , 't' },
- { "union" , tic54x_struct , 1 },
- { "endunion" , tic54x_endstruct , 1 },
- { "usect" , tic54x_usect , 0 },
- { "var" , tic54x_var , 0 },
- { "version" , tic54x_version , 0 },
- {0 , 0 , 0 }
- };
- int
- md_parse_option (int c, char *arg)
- {
- switch (c)
- {
- default:
- return 0;
- case OPTION_COFF_VERSION:
- {
- int version = atoi (arg);
- if (version != 0 && version != 1 && version != 2)
- as_fatal (_("Bad COFF version '%s'"), arg);
- /* FIXME -- not yet implemented. */
- break;
- }
- case OPTION_CPU_VERSION:
- {
- cpu = lookup_version (arg);
- cpu_needs_set = 1;
- if (cpu == VNONE)
- as_fatal (_("Bad CPU version '%s'"), arg);
- break;
- }
- case OPTION_ADDRESS_MODE:
- amode = far_mode;
- address_mode_needs_set = 1;
- break;
- case OPTION_STDERR_TO_FILE:
- {
- char *filename = arg;
- FILE *fp = fopen (filename, "w+");
- if (fp == NULL)
- as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
- fclose (fp);
- if ((fp = freopen (filename, "w+", stderr)) == NULL)
- as_fatal (_("Can't redirect stderr to the file '%s'"), filename);
- break;
- }
- }
- return 1;
- }
- /* Create a "local" substitution string hash table for a new macro level
- Some docs imply that macros have to use .newblock in order to be able
- to re-use a local label. We effectively do an automatic .newblock by
- deleting the local label hash between macro invocations. */
- void
- tic54x_macro_start (void)
- {
- ++macro_level;
- subsym_hash[macro_level] = hash_new ();
- local_label_hash[macro_level] = hash_new ();
- }
- void
- tic54x_macro_info (const macro_entry *macro)
- {
- const formal_entry *entry;
- /* Put the formal args into the substitution symbol table. */
- for (entry = macro->formals; entry; entry = entry->next)
- {
- char *name = strncpy (xmalloc (entry->name.len + 1),
- entry->name.ptr, entry->name.len);
- char *value = strncpy (xmalloc (entry->actual.len + 1),
- entry->actual.ptr, entry->actual.len);
- name[entry->name.len] = '\0';
- value[entry->actual.len] = '\0';
- hash_insert (subsym_hash[macro_level], name, value);
- }
- }
- /* Get rid of this macro's .var's, arguments, and local labels. */
- void
- tic54x_macro_end (void)
- {
- hash_die (subsym_hash[macro_level]);
- subsym_hash[macro_level] = NULL;
- hash_die (local_label_hash[macro_level]);
- local_label_hash[macro_level] = NULL;
- --macro_level;
- }
- static int
- subsym_symlen (char *a, char *ignore ATTRIBUTE_UNUSED)
- {
- return strlen (a);
- }
- /* Compare symbol A to string B. */
- static int
- subsym_symcmp (char *a, char *b)
- {
- return strcmp (a, b);
- }
- /* Return the index of the first occurrence of B in A, or zero if none
- assumes b is an integer char value as a string. Index is one-based. */
- static int
- subsym_firstch (char *a, char *b)
- {
- int val = atoi (b);
- char *tmp = strchr (a, val);
- return tmp ? tmp - a + 1 : 0;
- }
- /* Similar to firstch, but returns index of last occurrence of B in A. */
- static int
- subsym_lastch (char *a, char *b)
- {
- int val = atoi (b);
- char *tmp = strrchr (a, val);
- return tmp ? tmp - a + 1 : 0;
- }
- /* Returns 1 if string A is defined in the symbol table (NOT the substitution
- symbol table). */
- static int
- subsym_isdefed (char *a, char *ignore ATTRIBUTE_UNUSED)
- {
- symbolS *symbolP = symbol_find (a);
- return symbolP != NULL;
- }
- /* Assign first member of comma-separated list B (e.g. "1,2,3") to the symbol
- A, or zero if B is a null string. Both arguments *must* be substitution
- symbols, unsubstituted. */
- static int
- subsym_ismember (char *sym, char *list)
- {
- char *elem, *ptr, *listv;
- if (!list)
- return 0;
- listv = subsym_lookup (list, macro_level);
- if (!listv)
- {
- as_bad (_("Undefined substitution symbol '%s'"), list);
- ignore_rest_of_line ();
- return 0;
- }
- ptr = elem = xmalloc (strlen (listv) + 1);
- strcpy (elem, listv);
- while (*ptr && *ptr != ',')
- ++ptr;
- *ptr++ = 0;
- subsym_create_or_replace (sym, elem);
- /* Reassign the list. */
- subsym_create_or_replace (list, ptr);
- /* Assume this value, docs aren't clear. */
- return *list != 0;
- }
- /* Return zero if not a constant; otherwise:
- 1 if binary
- 2 if octal
- 3 if hexadecimal
- 4 if character
- 5 if decimal. */
- static int
- subsym_iscons (char *a, char *ignore ATTRIBUTE_UNUSED)
- {
- expressionS expn;
- parse_expression (a, &expn);
- if (expn.X_op == O_constant)
- {
- int len = strlen (a);
- switch (TOUPPER (a[len - 1]))
- {
- case 'B':
- return 1;
- case 'Q':
- return 2;
- case 'H':
- return 3;
- case '\'':
- return 4;
- default:
- break;
- }
- /* No suffix; either octal, hex, or decimal. */
- if (*a == '0' && len > 1)
- {
- if (TOUPPER (a[1]) == 'X')
- return 3;
- return 2;
- }
- return 5;
- }
- return 0;
- }
- /* Return 1 if A is a valid symbol name. Expects string input. */
- static int
- subsym_isname (char *a, char *ignore ATTRIBUTE_UNUSED)
- {
- if (!is_name_beginner (*a))
- return 0;
- while (*a)
- {
- if (!is_part_of_name (*a))
- return 0;
- ++a;
- }
- return 1;
- }
- /* Return whether the string is a register; accepts ar0-7, unless .mmregs has
- been seen; if so, recognize any memory-mapped register.
- Note this does not recognize "A" or "B" accumulators. */
- static int
- subsym_isreg (char *a, char *ignore ATTRIBUTE_UNUSED)
- {
- if (hash_find (reg_hash, a))
- return 1;
- if (hash_find (mmreg_hash, a))
- return 1;
- return 0;
- }
- /* Return the structure size, given the stag. */
- static int
- subsym_structsz (char *name, char *ignore ATTRIBUTE_UNUSED)
- {
- struct stag *stag = (struct stag *) hash_find (stag_hash, name);
- if (stag)
- return stag->size;
- return 0;
- }
- /* If anybody actually uses this, they can fix it :)
- FIXME I'm not sure what the "reference point" of a structure is. It might
- be either the initial offset given .struct, or it may be the offset of the
- structure within another structure, or it might be something else
- altogether. since the TI assembler doesn't seem to ever do anything but
- return zero, we punt and return zero. */
- static int
- subsym_structacc (char *stag_name ATTRIBUTE_UNUSED,
- char *ignore ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- static float
- math_ceil (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) ceil (arg1);
- }
- static float
- math_cvi (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (int) arg1;
- }
- static float
- math_floor (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) floor (arg1);
- }
- static float
- math_fmod (float arg1, float arg2)
- {
- return (int) arg1 % (int) arg2;
- }
- static float
- math_int (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return ((float) ((int) arg1)) == arg1;
- }
- static float
- math_round (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return arg1 > 0 ? (int) (arg1 + 0.5) : (int) (arg1 - 0.5);
- }
- static float
- math_sgn (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (arg1 < 0) ? -1 : (arg1 ? 1 : 0);
- }
- static float
- math_trunc (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (int) arg1;
- }
- static float
- math_acos (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) acos (arg1);
- }
- static float
- math_asin (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) asin (arg1);
- }
- static float
- math_atan (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) atan (arg1);
- }
- static float
- math_atan2 (float arg1, float arg2)
- {
- return (float) atan2 (arg1, arg2);
- }
- static float
- math_cosh (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) cosh (arg1);
- }
- static float
- math_cos (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) cos (arg1);
- }
- static float
- math_cvf (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) arg1;
- }
- static float
- math_exp (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) exp (arg1);
- }
- static float
- math_fabs (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) fabs (arg1);
- }
- /* expr1 * 2^expr2. */
- static float
- math_ldexp (float arg1, float arg2)
- {
- return arg1 * (float) pow (2.0, arg2);
- }
- static float
- math_log10 (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) log10 (arg1);
- }
- static float
- math_log (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) log (arg1);
- }
- static float
- math_max (float arg1, float arg2)
- {
- return (arg1 > arg2) ? arg1 : arg2;
- }
- static float
- math_min (float arg1, float arg2)
- {
- return (arg1 < arg2) ? arg1 : arg2;
- }
- static float
- math_pow (float arg1, float arg2)
- {
- return (float) pow (arg1, arg2);
- }
- static float
- math_sin (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) sin (arg1);
- }
- static float
- math_sinh (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) sinh (arg1);
- }
- static float
- math_sqrt (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) sqrt (arg1);
- }
- static float
- math_tan (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) tan (arg1);
- }
- static float
- math_tanh (float arg1, float ignore ATTRIBUTE_UNUSED)
- {
- return (float) tanh (arg1);
- }
- /* Built-in substitution symbol functions and math functions. */
- typedef struct
- {
- char *name;
- int (*proc) (char *, char *);
- int nargs;
- } subsym_proc_entry;
- static const subsym_proc_entry subsym_procs[] =
- {
- /* Assembler built-in string substitution functions. */
- { "$symlen", subsym_symlen, 1, },
- { "$symcmp", subsym_symcmp, 2, },
- { "$firstch", subsym_firstch, 2, },
- { "$lastch", subsym_lastch, 2, },
- { "$isdefed", subsym_isdefed, 1, },
- { "$ismember", subsym_ismember, 2, },
- { "$iscons", subsym_iscons, 1, },
- { "$isname", subsym_isname, 1, },
- { "$isreg", subsym_isreg, 1, },
- { "$structsz", subsym_structsz, 1, },
- { "$structacc", subsym_structacc, 1, },
- { NULL, NULL, 0 },
- };
- typedef struct
- {
- char *name;
- float (*proc) (float, float);
- int nargs;
- int int_return;
- } math_proc_entry;
- static const math_proc_entry math_procs[] =
- {
- /* Integer-returning built-in math functions. */
- { "$cvi", math_cvi, 1, 1 },
- { "$int", math_int, 1, 1 },
- { "$sgn", math_sgn, 1, 1 },
- /* Float-returning built-in math functions. */
- { "$acos", math_acos, 1, 0 },
- { "$asin", math_asin, 1, 0 },
- { "$atan", math_atan, 1, 0 },
- { "$atan2", math_atan2, 2, 0 },
- { "$ceil", math_ceil, 1, 0 },
- { "$cosh", math_cosh, 1, 0 },
- { "$cos", math_cos, 1, 0 },
- { "$cvf", math_cvf, 1, 0 },
- { "$exp", math_exp, 1, 0 },
- { "$fabs", math_fabs, 1, 0 },
- { "$floor", math_floor, 1, 0 },
- { "$fmod", math_fmod, 2, 0 },
- { "$ldexp", math_ldexp, 2, 0 },
- { "$log10", math_log10, 1, 0 },
- { "$log", math_log, 1, 0 },
- { "$max", math_max, 2, 0 },
- { "$min", math_min, 2, 0 },
- { "$pow", math_pow, 2, 0 },
- { "$round", math_round, 1, 0 },
- { "$sin", math_sin, 1, 0 },
- { "$sinh", math_sinh, 1, 0 },
- { "$sqrt", math_sqrt, 1, 0 },
- { "$tan", math_tan, 1, 0 },
- { "$tanh", math_tanh, 1, 0 },
- { "$trunc", math_trunc, 1, 0 },
- { NULL, NULL, 0, 0 },
- };
- void
- md_begin (void)
- {
- insn_template *tm;
- symbol *sym;
- const subsym_proc_entry *subsym_proc;
- const math_proc_entry *math_proc;
- const char *hash_err;
- char **symname;
- char *TIC54X_DIR = getenv ("TIC54X_DIR");
- char *A_DIR = TIC54X_DIR ? TIC54X_DIR : getenv ("A_DIR");
- local_label_id = 0;
- /* Look for A_DIR and add it to the include list. */
- if (A_DIR != NULL)
- {
- char *tmp = xstrdup (A_DIR);
- do
- {
- char *next = strchr (tmp, ';');
- if (next)
- *next++ = '\0';
- add_include_dir (tmp);
- tmp = next;
- }
- while (tmp != NULL);
- }
- op_hash = hash_new ();
- for (tm = (insn_template *) tic54x_optab; tm->name; tm++)
- {
- if (hash_find (op_hash, tm->name))
- continue;
- hash_err = hash_insert (op_hash, tm->name, (char *) tm);
- if (hash_err)
- as_fatal ("Internal Error: Can't hash %s: %s",
- tm->name, hash_err);
- }
- parop_hash = hash_new ();
- for (tm = (insn_template *) tic54x_paroptab; tm->name; tm++)
- {
- if (hash_find (parop_hash, tm->name))
- continue;
- hash_err = hash_insert (parop_hash, tm->name, (char *) tm);
- if (hash_err)
- as_fatal ("Internal Error: Can't hash %s: %s",
- tm->name, hash_err);
- }
- reg_hash = hash_new ();
- for (sym = (symbol *) regs; sym->name; sym++)
- {
- /* Add basic registers to the symbol table. */
- symbolS *symbolP = symbol_new (sym->name, absolute_section,
- (valueT) sym->value, &zero_address_frag);
- SF_SET_LOCAL (symbolP);
- symbol_table_insert (symbolP);
- hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
- }
- for (sym = (symbol *) mmregs; sym->name; sym++)
- hash_err = hash_insert (reg_hash, sym->name, (char *) sym);
- mmreg_hash = hash_new ();
- for (sym = (symbol *) mmregs; sym->name; sym++)
- hash_err = hash_insert (mmreg_hash, sym->name, (char *) sym);
- cc_hash = hash_new ();
- for (sym = (symbol *) condition_codes; sym->name; sym++)
- hash_err = hash_insert (cc_hash, sym->name, (char *) sym);
- cc2_hash = hash_new ();
- for (sym = (symbol *) cc2_codes; sym->name; sym++)
- hash_err = hash_insert (cc2_hash, sym->name, (char *) sym);
- cc3_hash = hash_new ();
- for (sym = (symbol *) cc3_codes; sym->name; sym++)
- hash_err = hash_insert (cc3_hash, sym->name, (char *) sym);
- sbit_hash = hash_new ();
- for (sym = (symbol *) status_bits; sym->name; sym++)
- hash_err = hash_insert (sbit_hash, sym->name, (char *) sym);
- misc_symbol_hash = hash_new ();
- for (symname = (char **) misc_symbols; *symname; symname++)
- hash_err = hash_insert (misc_symbol_hash, *symname, *symname);
- /* Only the base substitution table and local label table are initialized;
- the others (for local macro substitution) get instantiated as needed. */
- local_label_hash[0] = hash_new ();
- subsym_hash[0] = hash_new ();
- for (subsym_proc = subsym_procs; subsym_proc->name; subsym_proc++)
- hash_err = hash_insert (subsym_hash[0], subsym_proc->name,
- (char *) subsym_proc);
- math_hash = hash_new ();
- for (math_proc = math_procs; math_proc->name; math_proc++)
- {
- /* Insert into the main subsym hash for recognition; insert into
- the math hash to actually store information. */
- hash_err = hash_insert (subsym_hash[0], math_proc->name,
- (char *) math_proc);
- hash_err = hash_insert (math_hash, math_proc->name,
- (char *) math_proc);
- }
- subsym_recurse_hash = hash_new ();
- stag_hash = hash_new ();
- }
- static int
- is_accumulator (struct opstruct *operand)
- {
- return strcasecmp (operand->buf, "a") == 0
- || strcasecmp (operand->buf, "b") == 0;
- }
- /* Return the number of operands found, or -1 on error, copying the
- operands into the given array and the accompanying expressions into
- the next array. */
- static int
- get_operands (struct opstruct operands[], char *line)
- {
- char *lptr = line;
- int numexp = 0;
- int expecting_operand = 0;
- int i;
- while (numexp < MAX_OPERANDS && !is_end_of_line[(int) *lptr])
- {
- int paren_not_balanced = 0;
- char *op_start, *op_end;
- while (*lptr && ISSPACE (*lptr))
- ++lptr;
- op_start = lptr;
- while (paren_not_balanced || *lptr != ',')
- {
- if (*lptr == '\0')
- {
- if (paren_not_balanced)
- {
- as_bad (_("Unbalanced parenthesis in operand %d"), numexp);
- return -1;
- }
- else
- break;
- }
- if (*lptr == '(')
- ++paren_not_balanced;
- else if (*lptr == ')')
- --paren_not_balanced;
- ++lptr;
- }
- op_end = lptr;
- if (op_end != op_start)
- {
- int len = op_end - op_start;
- strncpy (operands[numexp].buf, op_start, len);
- operands[numexp].buf[len] = 0;
- /* Trim trailing spaces; while the preprocessor gets rid of most,
- there are weird usage patterns that can introduce them
- (i.e. using strings for macro args). */
- while (len > 0 && ISSPACE (operands[numexp].buf[len - 1]))
- operands[numexp].buf[--len] = 0;
- lptr = op_end;
- ++numexp;
- }
- else
- {
- if (expecting_operand || *lptr == ',')
- {
- as_bad (_("Expecting operand after ','"));
- return -1;
- }
- }
- if (*lptr == ',')
- {
- if (*++lptr == '\0')
- {
- as_bad (_("Expecting operand after ','"));
- return -1;
- }
- expecting_operand = 1;
- }
- }
- while (*lptr && ISSPACE (*lptr++))
- ;
- if (!is_end_of_line[(int) *lptr])
- {
- as_bad (_("Extra junk on line"));
- return -1;
- }
- /* OK, now parse them into expressions. */
- for (i = 0; i < numexp; i++)
- {
- memset (&operands[i].exp, 0, sizeof (operands[i].exp));
- if (operands[i].buf[0] == '#')
- {
- /* Immediate. */
- parse_expression (operands[i].buf + 1, &operands[i].exp);
- }
- else if (operands[i].buf[0] == '@')
- {
- /* Direct notation. */
- parse_expression (operands[i].buf + 1, &operands[i].exp);
- }
- else if (operands[i].buf[0] == '*')
- {
- /* Indirect. */
- char *paren = strchr (operands[i].buf, '(');
- /* Allow immediate syntax in the inner expression. */
- if (paren && paren[1] == '#')
- *++paren = '(';
- /* Pull out the lk expression or SP offset, if present. */
- if (paren != NULL)
- {
- int len = strlen (paren);
- char *end = paren + len;
- int c;
- while (end[-1] != ')')
- if (--end <= paren)
- {
- as_bad (_("Badly formed address expression"));
- return -1;
- }
- c = *end;
- *end = '\0';
- parse_expression (paren, &operands[i].exp);
- *end = c;
- }
- else
- operands[i].exp.X_op = O_absent;
- }
- else
- parse_expression (operands[i].buf, &operands[i].exp);
- }
- return numexp;
- }
- /* Predicates for different operand types. */
- static int
- is_immediate (struct opstruct *operand)
- {
- return *operand->buf == '#';
- }
- /* This is distinguished from immediate because some numbers must be constants
- and must *not* have the '#' prefix. */
- static int
- is_absolute (struct opstruct *operand)
- {
- return operand->exp.X_op == O_constant && !is_immediate (operand);
- }
- /* Is this an indirect operand? */
- static int
- is_indirect (struct opstruct *operand)
- {
- return operand->buf[0] == '*';
- }
- /* Is this a valid dual-memory operand? */
- static int
- is_dual (struct opstruct *operand)
- {
- if (is_indirect (operand) && strncasecmp (operand->buf, "*ar", 3) == 0)
- {
- char *tmp = operand->buf + 3;
- int arf;
- int valid_mod;
- arf = *tmp++ - '0';
- /* Only allow *ARx, *ARx-, *ARx+, or *ARx+0%. */
- valid_mod = *tmp == '\0' ||
- strcasecmp (tmp, "-") == 0 ||
- strcasecmp (tmp, "+") == 0 ||
- strcasecmp (tmp, "+0%") == 0;
- return arf >= 2 && arf <= 5 && valid_mod;
- }
- return 0;
- }
- static int
- is_mmreg (struct opstruct *operand)
- {
- return (is_absolute (operand)
- || is_immediate (operand)
- || hash_find (mmreg_hash, operand->buf) != 0);
- }
- static int
- is_type (struct opstruct *operand, enum optype type)
- {
- switch (type)
- {
- case OP_None:
- return operand->buf[0] == 0;
- case OP_Xmem:
- case OP_Ymem:
- return is_dual (operand);
- case OP_Sind:
- return is_indirect (operand);
- case OP_xpmad_ms7:
- /* This one *must* be immediate. */
- return is_immediate (operand);
- case OP_xpmad:
- case OP_pmad:
- case OP_PA:
- case OP_dmad:
- case OP_Lmem:
- case OP_MMR:
- return 1;
- case OP_Smem:
- /* Address may be a numeric, indirect, or an expression. */
- return !is_immediate (operand);
- case OP_MMRY:
- case OP_MMRX:
- return is_mmreg (operand);
- case OP_SRC:
- case OP_SRC1:
- case OP_RND:
- case OP_DST:
- return is_accumulator (operand);
- case OP_B:
- return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'B';
- case OP_A:
- return is_accumulator (operand) && TOUPPER (operand->buf[0]) == 'A';
- case OP_ARX:
- return strncasecmp ("ar", operand->buf, 2) == 0
- && ISDIGIT (operand->buf[2]);
- case OP_SBIT:
- return hash_find (sbit_hash, operand->buf) != 0 || is_absolute (operand);
- case OP_CC:
- return hash_find (cc_hash, operand->buf) != 0;
- case OP_CC2:
- return hash_find (cc2_hash, operand->buf) != 0;
- case OP_CC3:
- return hash_find (cc3_hash, operand->buf) != 0
- || is_immediate (operand) || is_absolute (operand);
- case OP_16:
- return (is_immediate (operand) || is_absolute (operand))
- && operand->exp.X_add_number == 16;
- case OP_N:
- /* Allow st0 or st1 instead of a numeric. */
- return is_absolute (operand) || is_immediate (operand) ||
- strcasecmp ("st0", operand->buf) == 0 ||
- strcasecmp ("st1", operand->buf) == 0;
- case OP_12:
- case OP_123:
- return is_absolute (operand) || is_immediate (operand);
- case OP_SHFT:
- return (is_immediate (operand) || is_absolute (operand))
- && operand->exp.X_add_number >= 0 && operand->exp.X_add_number < 16;
- case OP_SHIFT:
- /* Let this one catch out-of-range values. */
- return (is_immediate (operand) || is_absolute (operand))
- && operand->exp.X_add_number != 16;
- case OP_BITC:
- case OP_031:
- case OP_k8:
- return is_absolute (operand) || is_immediate (operand);
- case OP_k8u:
- return is_immediate (operand)
- && operand->exp.X_op == O_constant
- && operand->exp.X_add_number >= 0
- && operand->exp.X_add_number < 256;
- case OP_lk:
- case OP_lku:
- /* Allow anything; assumes opcodes are ordered with Smem operands
- versions first. */
- return 1;
- case OP_k5:
- case OP_k3:
- case OP_k9:
- /* Just make sure it's an integer; check range later. */
- return is_immediate (operand);
- case OP_T:
- return strcasecmp ("t", operand->buf) == 0 ||
- strcasecmp ("treg", operand->buf) == 0;
- case OP_TS:
- return strcasecmp ("ts", operand->buf) == 0;
- case OP_ASM:
- return strcasecmp ("asm", operand->buf) == 0;
- case OP_TRN:
- return strcasecmp ("trn", operand->buf) == 0;
- case OP_DP:
- return strcasecmp ("dp", operand->buf) == 0;
- case OP_ARP:
- return strcasecmp ("arp", operand->buf) == 0;
- default:
- return 0;
- }
- }
- static int
- operands_match (tic54x_insn *insn,
- struct opstruct *operands,
- int opcount,
- const enum optype *refoptype,
- int minops,
- int maxops)
- {
- int op = 0, refop = 0;
- if (opcount == 0 && minops == 0)
- return 1;
- while (op <= maxops && refop <= maxops)
- {
- while (!is_type (&operands[op], OPTYPE (refoptype[refop])))
- {
- /* Skip an optional template operand if it doesn't agree
- with the current operand. */
- if (refoptype[refop] & OPT)
- {
- ++refop;
- --maxops;
- if (refop > maxops)
- return 0;
- }
- else
- return 0;
- }
- /* Save the actual operand type for later use. */
- operands[op].type = OPTYPE (refoptype[refop]);
- ++refop;
- ++op;
- /* Have we matched them all yet? */
- if (op == opcount)
- {
- while (op < maxops)
- {
- /* If a later operand is *not* optional, no match. */
- if ((refoptype[refop] & OPT) == 0)
- return 0;
- /* Flag any implicit default OP_DST operands so we know to add
- them explicitly when encoding the operand later. */
- if (OPTYPE (refoptype[refop]) == OP_DST)
- insn->using_default_dst = 1;
- ++refop;
- ++op;
- }
- return 1;
- }
- }
- return 0;
- }
- /* 16-bit direct memory address
- Explicit dmad operands are always in last word of insn (usually second
- word, but bumped to third if lk addressing is used)
- We allow *(dmad) notation because the TI assembler allows it.
- XPC_CODE:
- 0 for 16-bit addresses
- 1 for full 23-bit addresses
- 2 for the upper 7 bits of a 23-bit address (LDX). */
- static int
- encode_dmad (tic54x_insn *insn, struct opstruct *operand, int xpc_code)
- {
- int op = 1 + insn->is_lkaddr;
- /* Only allow *(dmad) expressions; all others are invalid. */
- if (is_indirect (operand) && operand->buf[strlen (operand->buf) - 1] != ')')
- {
- as_bad (_("Invalid dmad syntax '%s'"), operand->buf);
- return 0;
- }
- insn->opcode[op].addr_expr = operand->exp;
- if (insn->opcode[op].addr_expr.X_op == O_constant)
- {
- valueT value = insn->opcode[op].addr_expr.X_add_number;
- if (xpc_code == 1)
- {
- insn->opcode[0].word &= 0xFF80;
- insn->opcode[0].word |= (value >> 16) & 0x7F;
- insn->opcode[1].word = value & 0xFFFF;
- }
- else if (xpc_code == 2)
- insn->opcode[op].word = (value >> 16) & 0xFFFF;
- else
- insn->opcode[op].word = value;
- }
- else
- {
- /* Do the fixup later; just store the expression. */
- insn->opcode[op].word = 0;
- insn->opcode[op].r_nchars = 2;
- if (amode == c_mode)
- insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
- else if (xpc_code == 1)
- {
- /* This relocation spans two words, so adjust accordingly. */
- insn->opcode[0].addr_expr = operand->exp;
- insn->opcode[0].r_type = BFD_RELOC_TIC54X_23;
- insn->opcode[0].r_nchars = 4;
- insn->opcode[0].unresolved = 1;
- /* It's really 2 words, but we want to stop encoding after the
- first, since we must encode both words at once. */
- insn->words = 1;
- }
- else if (xpc_code == 2)
- insn->opcode[op].r_type = BFD_RELOC_TIC54X_MS7_OF_23;
- else
- insn->opcode[op].r_type = BFD_RELOC_TIC54X_16_OF_23;
- insn->opcode[op].unresolved = 1;
- }
- return 1;
- }
- /* 7-bit direct address encoding. */
- static int
- encode_address (tic54x_insn *insn, struct opstruct *operand)
- {
- /* Assumes that dma addresses are *always* in word 0 of the opcode. */
- insn->opcode[0].addr_expr = operand->exp;
- if (operand->exp.X_op == O_constant)
- insn->opcode[0].word |= (operand->exp.X_add_number & 0x7F);
- else
- {
- if (operand->exp.X_op == O_register)
- as_bad (_("Use the .mmregs directive to use memory-mapped register names such as '%s'"), operand->buf);
- /* Do the fixup later; just store the expression. */
- insn->opcode[0].r_nchars = 1;
- insn->opcode[0].r_type = BFD_RELOC_TIC54X_PARTLS7;
- insn->opcode[0].unresolved = 1;
- }
- return 1;
- }
- static int
- encode_indirect (tic54x_insn *insn, struct opstruct *operand)
- {
- int arf;
- int mod;
- if (insn->is_lkaddr)
- {
- /* lk addresses always go in the second insn word. */
- mod = ((TOUPPER (operand->buf[1]) == 'A') ? 12 :
- (operand->buf[1] == '(') ? 15 :
- (strchr (operand->buf, '%') != NULL) ? 14 : 13);
- arf = ((mod == 12) ? operand->buf[3] - '0' :
- (mod == 15) ? 0 : operand->buf[4] - '0');
- insn->opcode[1].addr_expr = operand->exp;
- if (operand->exp.X_op == O_constant)
- insn->opcode[1].word = operand->exp.X_add_number;
- else
- {
- insn->opcode[1].word = 0;
- insn->opcode[1].r_nchars = 2;
- insn->opcode[1].r_type = BFD_RELOC_TIC54X_16_OF_23;
- insn->opcode[1].unresolved = 1;
- }
- }
- else if (strncasecmp (operand->buf, "*sp (", 4) == 0)
- {
- /* Stack offsets look the same as 7-bit direct addressing. */
- return encode_address (insn, operand);
- }
- else
- {
- arf = (TOUPPER (operand->buf[1]) == 'A' ?
- operand->buf[3] : operand->buf[4]) - '0';
- if (operand->buf[1] == '+')
- {
- mod = 3; /* *+ARx */
- if (insn->tm->flags & FL_SMR)
- as_warn (_("Address mode *+ARx is write-only. "
- "Results of reading are undefined."));
- }
- else if (operand->buf[4] == '\0')
- mod = 0; /* *ARx */
- else if (operand->buf[5] == '\0')
- mod = (operand->buf[4] == '-' ? 1 : 2); /* *ARx+ / *ARx- */
- else if (operand->buf[6] == '\0')
- {
- if (operand->buf[5] == '0')
- mod = (operand->buf[4] == '-' ? 5 : 6); /* *ARx+0 / *ARx-0 */
- else
- mod = (operand->buf[4] == '-' ? 8 : 10);/* *ARx+% / *ARx-% */
- }
- else if (TOUPPER (operand->buf[6]) == 'B')
- mod = (operand->buf[4] == '-' ? 4 : 7); /* ARx+0B / *ARx-0B */
- else if (TOUPPER (operand->buf[6]) == '%')
- mod = (operand->buf[4] == '-' ? 9 : 11); /* ARx+0% / *ARx - 0% */
- else
- {
- as_bad (_("Unrecognized indirect address format \"%s\""),
- operand->buf);
- return 0;
- }
- }
- insn->opcode[0].word |= 0x80 | (mod << 3) | arf;
- return 1;
- }
- static int
- encode_integer (tic54x_insn *insn,
- struct opstruct *operand,
- int which,
- int min,
- int max,
- unsigned short mask)
- {
- long parse, integer;
- insn->opcode[which].addr_expr = operand->exp;
- if (operand->exp.X_op == O_constant)
- {
- parse = operand->exp.X_add_number;
- /* Hack -- fixup for 16-bit hex quantities that get converted positive
- instead of negative. */
- if ((parse & 0x8000) && min == -32768 && max == 32767)
- integer = (short) parse;
- else
- integer = parse;
- if (integer >= min && integer <= max)
- {
- insn->opcode[which].word |= (integer & mask);
- return 1;
- }
- as_bad (_("Operand '%s' out of range (%d <= x <= %d)"),
- operand->buf, min, max);
- }
- else
- {
- if (insn->opcode[which].addr_expr.X_op == O_constant)
- {
- insn->opcode[which].word |=
- insn->opcode[which].addr_expr.X_add_number & mask;
- }
- else
- {
- /* Do the fixup later; just store the expression. */
- bfd_reloc_code_real_type rtype =
- (mask == 0x1FF ? BFD_RELOC_TIC54X_PARTMS9 :
- mask == 0xFFFF ? BFD_RELOC_TIC54X_16_OF_23 :
- mask == 0x7F ? BFD_RELOC_TIC54X_PARTLS7 : BFD_RELOC_8);
- int size = (mask == 0x1FF || mask == 0xFFFF) ? 2 : 1;
- if (rtype == BFD_RELOC_8)
- as_bad (_("Error in relocation handling"));
- insn->opcode[which].r_nchars = size;
- insn->opcode[which].r_type = rtype;
- insn->opcode[which].unresolved = 1;
- }
- return 1;
- }
- return 0;
- }
- static int
- encode_condition (tic54x_insn *insn, struct opstruct *operand)
- {
- symbol *cc = (symbol *) hash_find (cc_hash, operand->buf);
- if (!cc)
- {
- as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
- return 0;
- }
- #define CC_GROUP 0x40
- #define CC_ACC 0x08
- #define CATG_A1 0x07
- #define CATG_B1 0x30
- #define CATG_A2 0x30
- #define CATG_B2 0x0C
- #define CATG_C2 0x03
- /* Disallow group 1 conditions mixed with group 2 conditions
- if group 1, allow only one category A and one category B
- if group 2, allow only one each of category A, B, and C. */
- if (((insn->opcode[0].word & 0xFF) != 0))
- {
- if ((insn->opcode[0].word & CC_GROUP) != (cc->value & CC_GROUP))
- {
- as_bad (_("Condition \"%s\" does not match preceding group"),
- operand->buf);
- return 0;
- }
- if (insn->opcode[0].word & CC_GROUP)
- {
- if ((insn->opcode[0].word & CC_ACC) != (cc->value & CC_ACC))
- {
- as_bad (_("Condition \"%s\" uses a different accumulator from "
- "a preceding condition"),
- operand->buf);
- return 0;
- }
- if ((insn->opcode[0].word & CATG_A1) && (cc->value & CATG_A1))
- {
- as_bad (_("Only one comparison conditional allowed"));
- return 0;
- }
- if ((insn->opcode[0].word & CATG_B1) && (cc->value & CATG_B1))
- {
- as_bad (_("Only one overflow conditional allowed"));
- return 0;
- }
- }
- else if ( ((insn->opcode[0].word & CATG_A2) && (cc->value & CATG_A2))
- || ((insn->opcode[0].word & CATG_B2) && (cc->value & CATG_B2))
- || ((insn->opcode[0].word & CATG_C2) && (cc->value & CATG_C2)))
- {
- as_bad (_("Duplicate %s conditional"), operand->buf);
- return 0;
- }
- }
- insn->opcode[0].word |= cc->value;
- return 1;
- }
- static int
- encode_cc3 (tic54x_insn *insn, struct opstruct *operand)
- {
- symbol *cc3 = (symbol *) hash_find (cc3_hash, operand->buf);
- int value = cc3 ? cc3->value : operand->exp.X_add_number << 8;
- if ((value & 0x0300) != value)
- {
- as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
- return 0;
- }
- insn->opcode[0].word |= value;
- return 1;
- }
- static int
- encode_arx (tic54x_insn *insn, struct opstruct *operand)
- {
- int arf = strlen (operand->buf) >= 3 ? operand->buf[2] - '0' : -1;
- if (strncasecmp ("ar", operand->buf, 2) || arf < 0 || arf > 7)
- {
- as_bad (_("Invalid auxiliary register (use AR0-AR7)"));
- return 0;
- }
- insn->opcode[0].word |= arf;
- return 1;
- }
- static int
- encode_cc2 (tic54x_insn *insn, struct opstruct *operand)
- {
- symbol *cc2 = (symbol *) hash_find (cc2_hash, operand->buf);
- if (!cc2)
- {
- as_bad (_("Unrecognized condition code \"%s\""), operand->buf);
- return 0;
- }
- insn->opcode[0].word |= cc2->value;
- return 1;
- }
- static int
- encode_operand (tic54x_insn *insn, enum optype type, struct opstruct *operand)
- {
- int ext = (insn->tm->flags & FL_EXT) != 0;
- if (type == OP_MMR && operand->exp.X_op != O_constant)
- {
- /* Disallow long-constant addressing for memory-mapped addressing. */
- if (insn->is_lkaddr)
- {
- as_bad (_("lk addressing modes are invalid for memory-mapped "
- "register addressing"));
- return 0;
- }
- type = OP_Smem;
- /* Warn about *+ARx when used with MMR operands. */
- if (strncasecmp (operand->buf, "*+ar", 4) == 0)
- {
- as_warn (_("Address mode *+ARx is not allowed in memory-mapped "
- "register addressing. Resulting behavior is "
- "undefined."));
- }
- }
- switch (type)
- {
- case OP_None:
- return 1;
- case OP_dmad:
- /* 16-bit immediate value. */
- return encode_dmad (insn, operand, 0);
- case OP_SRC:
- if (TOUPPER (*operand->buf) == 'B')
- {
- insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 9);
- if (insn->using_default_dst)
- insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
- }
- return 1;
- case OP_RND:
- /* Make sure this agrees with the OP_DST operand. */
- if (!((TOUPPER (operand->buf[0]) == 'B') ^
- ((insn->opcode[0].word & (1 << 8)) != 0)))
- {
- as_bad (_("Destination accumulator for each part of this parallel "
- "instruction must be different"));
- return 0;
- }
- return 1;
- case OP_SRC1:
- case OP_DST:
- if (TOUPPER (operand->buf[0]) == 'B')
- insn->opcode[ext ? (1 + insn->is_lkaddr) : 0].word |= (1 << 8);
- return 1;
- case OP_Xmem:
- case OP_Ymem:
- {
- int mod = (operand->buf[4] == '\0' ? 0 : /* *arx */
- operand->buf[4] == '-' ? 1 : /* *arx- */
- operand->buf[5] == '\0' ? 2 : 3); /* *arx+, *arx+0% */
- int arf = operand->buf[3] - '0' - 2;
- int code = (mod << 2) | arf;
- insn->opcode[0].word |= (code << (type == OP_Xmem ? 4 : 0));
- return 1;
- }
- case OP_Lmem:
- case OP_Smem:
- if (!is_indirect (operand))
- return encode_address (insn, operand);
- /* Fall through. */
- case OP_Sind:
- return encode_indirect (insn, operand);
- case OP_xpmad_ms7:
- return encode_dmad (insn, operand, 2);
- case OP_xpmad:
- return encode_dmad (insn, operand, 1);
- case OP_PA:
- case OP_pmad:
- return encode_dmad (insn, operand, 0);
- case OP_ARX:
- return encode_arx (insn, operand);
- case OP_MMRX:
- case OP_MMRY:
- case OP_MMR:
- {
- int value = operand->exp.X_add_number;
- if (type == OP_MMR)
- insn->opcode[0].word |= value;
- else
- {
- if (value < 16 || value > 24)
- {
- as_bad (_("Memory mapped register \"%s\" out of range"),
- operand->buf);
- return 0;
- }
- if (type == OP_MMRX)
- insn->opcode[0].word |= (value - 16) << 4;
- else
- insn->opcode[0].word |= (value - 16);
- }
- return 1;
- }
- case OP_B:
- case OP_A:
- return 1;
- case OP_SHFT:
- return encode_integer (insn, operand, ext + insn->is_lkaddr,
- 0, 15, 0xF);
- case OP_SHIFT:
- return encode_integer (insn, operand, ext + insn->is_lkaddr,
- -16, 15, 0x1F);
- case OP_lk:
- return encode_integer (insn, operand, 1 + insn->is_lkaddr,
- -32768, 32767, 0xFFFF);
- case OP_CC:
- return encode_condition (insn, operand);
- case OP_CC2:
- return encode_cc2 (insn, operand);
- case OP_CC3:
- return encode_cc3 (insn, operand);
- case OP_BITC:
- return encode_integer (insn, operand, 0, 0, 15, 0xF);
- case OP_k8:
- return encode_integer (insn, operand, 0, -128, 127, 0xFF);
- case OP_123:
- {
- int value = operand->exp.X_add_number;
- int code;
- if (value < 1 || value > 3)
- {
- as_bad (_("Invalid operand (use 1, 2, or 3)"));
- return 0;
- }
- code = value == 1 ? 0 : value == 2 ? 0x2 : 0x1;
- insn->opcode[0].word |= (code << 8);
- return 1;
- }
- case OP_031:
- return encode_integer (insn, operand, 0, 0, 31, 0x1F);
- case OP_k8u:
- return encode_integer (insn, operand, 0, 0, 255, 0xFF);
- case OP_lku:
- return encode_integer (insn, operand, 1 + insn->is_lkaddr,
- 0, 65535, 0xFFFF);
- case OP_SBIT:
- {
- symbol *sbit = (symbol *) hash_find (sbit_hash, operand->buf);
- int value = is_absolute (operand) ?
- operand->exp.X_add_number : (sbit ? sbit->value : -1);
- int reg = 0;
- if (insn->opcount == 1)
- {
- if (!sbit)
- {
- as_bad (_("A status register or status bit name is required"));
- return 0;
- }
- /* Guess the register based on the status bit; "ovb" is the last
- status bit defined for st0. */
- if (sbit > (symbol *) hash_find (sbit_hash, "ovb"))
- reg = 1;
- }
- if (value == -1)
- {
- as_bad (_("Unrecognized status bit \"%s\""), operand->buf);
- return 0;
- }
- insn->opcode[0].word |= value;
- insn->opcode[0].word |= (reg << 9);
- return 1;
- }
- case OP_N:
- if (strcasecmp (operand->buf, "st0") == 0
- || strcasecmp (operand->buf, "st1") == 0)
- {
- insn->opcode[0].word |=
- ((unsigned short) (operand->buf[2] - '0')) << 9;
- return 1;
- }
- else if (operand->exp.X_op == O_constant
- && (operand->exp.X_add_number == 0
- || operand->exp.X_add_number == 1))
- {
- insn->opcode[0].word |=
- ((unsigned short) (operand->exp.X_add_number)) << 9;
- return 1;
- }
- as_bad (_("Invalid status register \"%s\""), operand->buf);
- return 0;
- case OP_k5:
- return encode_integer (insn, operand, 0, -16, 15, 0x1F);
- case OP_k3:
- return encode_integer (insn, operand, 0, 0, 7, 0x7);
- case OP_k9:
- return encode_integer (insn, operand, 0, 0, 0x1FF, 0x1FF);
- case OP_12:
- if (operand->exp.X_add_number != 1
- && operand->exp.X_add_number != 2)
- {
- as_bad (_("Operand \"%s\" out of range (use 1 or 2)"), operand->buf);
- return 0;
- }
- insn->opcode[0].word |= (operand->exp.X_add_number - 1) << 9;
- return 1;
- case OP_16:
- case OP_T:
- case OP_TS:
- case OP_ASM:
- case OP_TRN:
- case OP_DP:
- case OP_ARP:
- /* No encoding necessary. */
- return 1;
- default:
- return 0;
- }
- return 1;
- }
- static void
- emit_insn (tic54x_insn *insn)
- {
- int i;
- flagword oldflags = bfd_get_section_flags (stdoutput, now_seg);
- flagword flags = oldflags | SEC_CODE;
- if (! bfd_set_section_flags (stdoutput, now_seg, flags))
- as_warn (_("error setting flags for \"%s\": %s"),
- bfd_section_name (stdoutput, now_seg),
- bfd_errmsg (bfd_get_error ()));
- for (i = 0; i < insn->words; i++)
- {
- int size = (insn->opcode[i].unresolved
- && insn->opcode[i].r_type == BFD_RELOC_TIC54X_23) ? 4 : 2;
- char *p = frag_more (size);
- if (size == 2)
- md_number_to_chars (p, (valueT) insn->opcode[i].word, 2);
- else
- md_number_to_chars (p, (valueT) insn->opcode[i].word << 16, 4);
- if (insn->opcode[i].unresolved)
- fix_new_exp (frag_now, p - frag_now->fr_literal,
- insn->opcode[i].r_nchars, &insn->opcode[i].addr_expr,
- FALSE, insn->opcode[i].r_type);
- }
- }
- /* Convert the operand strings into appropriate opcode values
- return the total number of words used by the instruction. */
- static int
- build_insn (tic54x_insn *insn)
- {
- int i;
- /* Only non-parallel instructions support lk addressing. */
- if (!(insn->tm->flags & FL_PAR))
- {
- for (i = 0; i < insn->opcount; i++)
- {
- if ((OPTYPE (insn->operands[i].type) == OP_Smem
- || OPTYPE (insn->operands[i].type) == OP_Lmem
- || OPTYPE (insn->operands[i].type) == OP_Sind)
- && strchr (insn->operands[i].buf, '(')
- /* Don't mistake stack-relative addressing for lk addressing. */
- && strncasecmp (insn->operands[i].buf, "*sp (", 4) != 0)
- {
- insn->is_lkaddr = 1;
- insn->lkoperand = i;
- break;
- }
- }
- }
- insn->words = insn->tm->words + insn->is_lkaddr;
- insn->opcode[0].word = insn->tm->opcode;
- if (insn->tm->flags & FL_EXT)
- insn->opcode[1 + insn->is_lkaddr].word = insn->tm->opcode2;
- for (i = 0; i < insn->opcount; i++)
- {
- enum optype type = insn->operands[i].type;
- if (!encode_operand (insn, type, &insn->operands[i]))
- return 0;
- }
- if (insn->tm->flags & FL_PAR)
- for (i = 0; i < insn->paropcount; i++)
- {
- enum optype partype = insn->paroperands[i].type;
- if (!encode_operand (insn, partype, &insn->paroperands[i]))
- return 0;
- }
- emit_insn (insn);
- return insn->words;
- }
- static int
- optimize_insn (tic54x_insn *insn)
- {
- /* Optimize some instructions, helping out the brain-dead programmer. */
- #define is_zero(op) ((op).exp.X_op == O_constant && (op).exp.X_add_number == 0)
- if (strcasecmp (insn->tm->name, "add") == 0)
- {
- if (insn->opcount > 1
- && is_accumulator (&insn->operands[insn->opcount - 2])
- && is_accumulator (&insn->operands[insn->opcount - 1])
- && strcasecmp (insn->operands[insn->opcount - 2].buf,
- insn->operands[insn->opcount - 1].buf) == 0)
- {
- --insn->opcount;
- insn->using_default_dst = 1;
- return 1;
- }
- /* Try to collapse if Xmem and shift count is zero. */
- if ((OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
- && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT
- && is_zero (insn->operands[1]))
- /* Or if Smem, shift is zero or absent, and SRC == DST. */
- || (OPTYPE (insn->tm->operand_types[0]) == OP_Smem
- && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
- && is_type (&insn->operands[1], OP_SHIFT)
- && is_zero (insn->operands[1]) && insn->opcount == 3))
- {
- insn->operands[1] = insn->operands[2];
- insn->opcount = 2;
- return 1;
- }
- }
- else if (strcasecmp (insn->tm->name, "ld") == 0)
- {
- if (insn->opcount == 3 && insn->operands[0].type != OP_SRC)
- {
- if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
- || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
- && is_zero (insn->operands[1])
- && (OPTYPE (insn->tm->operand_types[0]) != OP_lk
- || (insn->operands[0].exp.X_op == O_constant
- && insn->operands[0].exp.X_add_number <= 255
- && insn->operands[0].exp.X_add_number >= 0)))
- {
- insn->operands[1] = insn->operands[2];
- insn->opcount = 2;
- return 1;
- }
- }
- }
- else if (strcasecmp (insn->tm->name, "sth") == 0
- || strcasecmp (insn->tm->name, "stl") == 0)
- {
- if ((OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT
- || OPTYPE (insn->tm->operand_types[1]) == OP_SHFT)
- && is_zero (insn->operands[1]))
- {
- insn->operands[1] = insn->operands[2];
- insn->opcount = 2;
- return 1;
- }
- }
- else if (strcasecmp (insn->tm->name, "sub") == 0)
- {
- if (insn->opcount > 1
- && is_accumulator (&insn->operands[insn->opcount - 2])
- && is_accumulator (&insn->operands[insn->opcount - 1])
- && strcasecmp (insn->operands[insn->opcount - 2].buf,
- insn->operands[insn->opcount - 1].buf) == 0)
- {
- --insn->opcount;
- insn->using_default_dst = 1;
- return 1;
- }
- if ( ((OPTYPE (insn->tm->operand_types[0]) == OP_Smem
- && OPTYPE (insn->tm->operand_types[1]) == OP_SHIFT)
- || (OPTYPE (insn->tm->operand_types[0]) == OP_Xmem
- && OPTYPE (insn->tm->operand_types[1]) == OP_SHFT))
- && is_zero (insn->operands[1])
- && insn->opcount == 3)
- {
- insn->operands[1] = insn->operands[2];
- insn->opcount = 2;
- return 1;
- }
- }
- return 0;
- }
- /* Find a matching template if possible, and get the operand strings. */
- static int
- tic54x_parse_insn (tic54x_insn *insn, char *line)
- {
- insn->tm = (insn_template *) hash_find (op_hash, insn->mnemonic);
- if (!insn->tm)
- {
- as_bad (_("Unrecognized instruction \"%s\""), insn->mnemonic);
- return 0;
- }
- insn->opcount = get_operands (insn->operands, line);
- if (insn->opcount < 0)
- return 0;
- /* Check each variation of operands for this mnemonic. */
- while (insn->tm->name && strcasecmp (insn->tm->name, insn->mnemonic) == 0)
- {
- if (insn->opcount >= insn->tm->minops
- && insn->opcount <= insn->tm->maxops
- && operands_match (insn, &insn->operands[0], insn->opcount,
- insn->tm->operand_types,
- insn->tm->minops, insn->tm->maxops))
- {
- /* SUCCESS! now try some optimizations. */
- if (optimize_insn (insn))
- {
- insn->tm = (insn_template *) hash_find (op_hash,
- insn->mnemonic);
- continue;
- }
- return 1;
- }
- ++(insn->tm);
- }
- as_bad (_("Unrecognized operand list '%s' for instruction '%s'"),
- line, insn->mnemonic);
- return 0;
- }
- /* We set this in start_line_hook, 'cause if we do a line replacement, we
- won't be able to see the next line. */
- static int parallel_on_next_line_hint = 0;
- /* See if this is part of a parallel instruction
- Look for a subsequent line starting with "||". */
- static int
- next_line_shows_parallel (char *next_line)
- {
- /* Look for the second half. */
- while (ISSPACE (*next_line))
- ++next_line;
- return (next_line[0] == PARALLEL_SEPARATOR
- && next_line[1] == PARALLEL_SEPARATOR);
- }
- static int
- tic54x_parse_parallel_insn_firstline (tic54x_insn *insn, char *line)
- {
- insn->tm = (insn_template *) hash_find (parop_hash, insn->mnemonic);
- if (!insn->tm)
- {
- as_bad (_("Unrecognized parallel instruction \"%s\""),
- insn->mnemonic);
- return 0;
- }
- while (insn->tm->name && strcasecmp (insn->tm->name,
- insn->mnemonic) == 0)
- {
- insn->opcount = get_operands (insn->operands, line);
- if (insn->opcount < 0)
- return 0;
- if (insn->opcount == 2
- && operands_match (insn, &insn->operands[0], insn->opcount,
- insn->tm->operand_types, 2, 2))
- {
- return 1;
- }
- ++(insn->tm);
- }
- /* Didn't find a matching parallel; try for a normal insn. */
- return 0;
- }
- /* Parse the second line of a two-line parallel instruction. */
- static int
- tic54x_parse_parallel_insn_lastline (tic54x_insn *insn, char *line)
- {
- int valid_mnemonic = 0;
- insn->paropcount = get_operands (insn->paroperands, line);
- while (insn->tm->name && strcasecmp (insn->tm->name,
- insn->mnemonic) == 0)
- {
- if (strcasecmp (insn->tm->parname, insn->parmnemonic) == 0)
- {
- valid_mnemonic = 1;
- if (insn->paropcount >= insn->tm->minops
- && insn->paropcount <= insn->tm->maxops
- && operands_match (insn, insn->paroperands,
- insn->paropcount,
- insn->tm->paroperand_types,
- insn->tm->minops, insn->tm->maxops))
- return 1;
- }
- ++(insn->tm);
- }
- if (valid_mnemonic)
- as_bad (_("Invalid operand (s) for parallel instruction \"%s\""),
- insn->parmnemonic);
- else
- as_bad (_("Unrecognized parallel instruction combination \"%s || %s\""),
- insn->mnemonic, insn->parmnemonic);
- return 0;
- }
- /* If quotes found, return copy of line up to closing quote;
- otherwise up until terminator.
- If it's a string, pass as-is; otherwise attempt substitution symbol
- replacement on the value. */
- static char *
- subsym_get_arg (char *line, char *terminators, char **str, int nosub)
- {
- char *ptr = line;
- char *endp;
- int is_string = *line == '"';
- int is_char = ISDIGIT (*line);
- if (is_char)
- {
- while (ISDIGIT (*ptr))
- ++ptr;
- endp = ptr;
- *str = xmalloc (ptr - line + 1);
- strncpy (*str, line, ptr - line);
- (*str)[ptr - line] = 0;
- }
- else if (is_string)
- {
- char *savedp = input_line_pointer;
- int len;
- input_line_pointer = ptr;
- *str = demand_copy_C_string (&len);
- endp = input_line_pointer;
- input_line_pointer = savedp;
- /* Do forced substitutions if requested. */
- if (!nosub && **str == ':')
- *str = subsym_substitute (*str, 1);
- }
- else
- {
- char *term = terminators;
- char *value = NULL;
- while (*ptr && *ptr != *term)
- {
- if (!*term)
- {
- term = terminators;
- ++ptr;
- }
- else
- ++term;
- }
- endp = ptr;
- *str = xmalloc (ptr - line + 1);
- strncpy (*str, line, ptr - line);
- (*str)[ptr - line] = 0;
- /* Do simple substitution, if available. */
- if (!nosub && (value = subsym_lookup (*str, macro_level)) != NULL)
- *str = value;
- }
- return endp;
- }
- /* Replace the given substitution string.
- We start at the innermost macro level, so that existing locals remain local
- Note: we're treating macro args identically to .var's; I don't know if
- that's compatible w/TI's assembler. */
- static void
- subsym_create_or_replace (char *name, char *value)
- {
- int i;
- for (i = macro_level; i > 0; i--)
- {
- if (hash_find (subsym_hash[i], name))
- {
- hash_replace (subsym_hash[i], name, value);
- return;
- }
- }
- if (hash_find (subsym_hash[0], name))
- hash_replace (subsym_hash[0], name, value);
- else
- hash_insert (subsym_hash[0], name, value);
- }
- /* Look up the substitution string replacement for the given symbol.
- Start with the innermost macro substitution table given and work
- outwards. */
- static char *
- subsym_lookup (char *name, int nest_level)
- {
- char *value = hash_find (subsym_hash[nest_level], name);
- if (value || nest_level == 0)
- return value;
- return subsym_lookup (name, nest_level - 1);
- }
- /* Do substitution-symbol replacement on the given line (recursively).
- return the argument if no substitution was done
- Also look for built-in functions ($func (arg)) and local labels.
- If FORCED is set, look for forced substitutions of the form ':SYMBOL:'. */
- static char *
- subsym_substitute (char *line, int forced)
- {
- /* For each apparent symbol, see if it's a substitution symbol, and if so,
- replace it in the input. */
- char *replacement; /* current replacement for LINE. */
- char *head; /* Start of line. */
- char *ptr; /* Current examination point. */
- int changed = 0; /* Did we make a substitution? */
- int eval_line = 0; /* Is this line a .eval/.asg statement? */
- int eval_symbol = 0; /* Are we in the middle of the symbol for
- .eval/.asg? */
- char *eval_end = NULL;
- int recurse = 1;
- int line_conditional = 0;
- char *tmp;
- /* Work with a copy of the input line. */
- replacement = xmalloc (strlen (line) + 1);
- strcpy (replacement, line);
- ptr = head = replacement;
- /* Flag lines where we might need to replace a single '=' with two;
- GAS uses single '=' to assign macro args values, and possibly other
- places, so limit what we replace. */
- if (strstr (line, ".if")
- || strstr (line, ".elseif")
- || strstr (line, ".break"))
- line_conditional = 1;
- /* Watch out for .eval, so that we avoid doing substitution on the
- symbol being assigned a value. */
- if (strstr (line, ".eval") || strstr (line, ".asg"))
- eval_line = 1;
- /* If it's a macro definition, don't do substitution on the argument
- names. */
- if (strstr (line, ".macro"))
- return line;
- while (!is_end_of_line[(int) *ptr])
- {
- int current_char = *ptr;
- /* Need to update this since LINE may have been modified. */
- if (eval_line)
- eval_end = strrchr (ptr, ',');
- /* Replace triple double quotes with bounding quote/escapes. */
- if (current_char == '"' && ptr[1] == '"' && ptr[2] == '"')
- {
- ptr[1] = '\\';
- tmp = strstr (ptr + 2, "\"\"\"");
- if (tmp)
- tmp[0] = '\\';
- changed = 1;
- }
- /* Replace a single '=' with a '==';
- for compatibility with older code only. */
- if (line_conditional && current_char == '=')
- {
- if (ptr[1] == '=')
- {
- ptr += 2;
- continue;
- }
- *ptr++ = '\0';
- tmp = xmalloc (strlen (head) + 2 + strlen (ptr) + 1);
- sprintf (tmp, "%s==%s", head, ptr);
- /* Continue examining after the '=='. */
- ptr = tmp + strlen (head) + 2;
- free (replacement);
- head = replacement = tmp;
- changed = 1;
- }
- /* Flag when we've reached the symbol part of .eval/.asg. */
- if (eval_line && ptr >= eval_end)
- eval_symbol = 1;
- /* For each apparent symbol, see if it's a substitution symbol, and if
- so, replace it in the input. */
- if ((forced && current_char == ':')
- || (!forced && is_name_beginner (current_char)))
- {
- char *name; /* Symbol to be replaced. */
- char *savedp = input_line_pointer;
- int c;
- char *value = NULL;
- char *tail; /* Rest of line after symbol. */
- /* Skip the colon. */
- if (forced)
- ++ptr;
- input_line_pointer = ptr;
- c = get_symbol_name (&name);
- /* '?' is not normally part of a symbol, but it IS part of a local
- label. */
- if (c == '?')
- {
- *input_line_pointer++ = c;
- c = *input_line_pointer;
- *input_line_pointer = '\0';
- }
- /* Avoid infinite recursion; if a symbol shows up a second time for
- substitution, leave it as is. */
- if (hash_find (subsym_recurse_hash, name) == NULL)
- value = subsym_lookup (name, macro_level);
- else
- as_warn (_("%s symbol recursion stopped at "
- "second appearance of '%s'"),
- forced ? "Forced substitution" : "Substitution", name);
- ptr = tail = input_line_pointer;
- input_line_pointer = savedp;
- /* Check for local labels; replace them with the appropriate
- substitution. */
- if ((*name == '$' && ISDIGIT (name[1]) && name[2] == '\0')
- || name[strlen (name) - 1] == '?')
- {
- /* Use an existing identifier for that label if, available, or
- create a new, unique identifier. */
- value = hash_find (local_label_hash[macro_level], name);
- if (value == NULL)
- {
- char digit[11];
- char *namecopy = strcpy (xmalloc (strlen (name) + 1), name);
- value = strcpy (xmalloc (strlen (name) + sizeof (digit) + 1),
- name);
- if (*value != '$')
- value[strlen (value) - 1] = '\0';
- sprintf (digit, ".%d", local_label_id++);
- strcat (value, digit);
- hash_insert (local_label_hash[macro_level], namecopy, value);
- }
- /* Indicate where to continue looking for substitutions. */
- ptr = tail;
- }
- /* Check for built-in subsym and math functions. */
- else if (value != NULL && *name == '$')
- {
- subsym_proc_entry *entry = (subsym_proc_entry *) value;
- math_proc_entry *math_entry = hash_find (math_hash, name);
- char *arg1, *arg2 = NULL;
- *ptr = c;
- if (entry == NULL)
- {
- as_bad (_("Unrecognized substitution symbol function"));
- break;
- }
- else if (*ptr != '(')
- {
- as_bad (_("Missing '(' after substitution symbol function"));
- break;
- }
- ++ptr;
- if (math_entry != NULL)
- {
- float farg1, farg2 = 0;
- volatile float fresult;
- farg1 = (float) strtod (ptr, &ptr);
- if (math_entry->nargs == 2)
- {
- if (*ptr++ != ',')
- {
- as_bad (_("Expecting second argument"));
- break;
- }
- farg2 = (float) strtod (ptr, &ptr);
- }
- fresult = (*math_entry->proc) (farg1, farg2);
- value = xmalloc (128);
- if (math_entry->int_return)
- sprintf (value, "%d", (int) fresult);
- else
- sprintf (value, "%f", fresult);
- if (*ptr++ != ')')
- {
- as_bad (_("Extra junk in function call, expecting ')'"));
- break;
- }
- /* Don't bother recursing; the replacement isn't a
- symbol. */
- recurse = 0;
- }
- else
- {
- int val;
- int arg_type[2] = { *ptr == '"' , 0 };
- int ismember = !strcmp (entry->name, "$ismember");
- /* Parse one or two args, which must be a substitution
- symbol, string or a character-string constant. */
- /* For all functions, a string or substitution symbol may be
- used, with the following exceptions:
- firstch/lastch: 2nd arg must be character constant
- ismember: both args must be substitution symbols. */
- ptr = subsym_get_arg (ptr, ",)", &arg1, ismember);
- if (!arg1)
- break;
- if (entry->nargs == 2)
- {
- if (*ptr++ != ',')
- {
- as_bad (_("Function expects two arguments"));
- break;
- }
- /* Character constants are converted to numerics
- by the preprocessor. */
- arg_type[1] = (ISDIGIT (*ptr)) ? 2 : (*ptr == '"');
- ptr = subsym_get_arg (ptr, ")", &arg2, ismember);
- }
- /* Args checking. */
- if ((!strcmp (entry->name, "$firstch")
- || !strcmp (entry->name, "$lastch"))
- && arg_type[1] != 2)
- {
- as_bad (_("Expecting character constant argument"));
- break;
- }
- if (ismember
- && (arg_type[0] != 0 || arg_type[1] != 0))
- {
- as_bad (_("Both arguments must be substitution symbols"));
- break;
- }
- if (*ptr++ != ')')
- {
- as_bad (_("Extra junk in function call, expecting ')'"));
- break;
- }
- val = (*entry->proc) (arg1, arg2);
- value = xmalloc (64);
- sprintf (value, "%d", val);
- }
- /* Fix things up to replace the entire expression, not just the
- function name. */
- tail = ptr;
- c = *tail;
- }
- if (value != NULL && !eval_symbol)
- {
- /* Replace the symbol with its string replacement and
- continue. Recursively replace VALUE until either no
- substitutions are performed, or a substitution that has been
- previously made is encountered again.
- put the symbol into the recursion hash table so we only
- try to replace a symbol once. */
- if (recurse)
- {
- hash_insert (subsym_recurse_hash, name, name);
- value = subsym_substitute (value, macro_level > 0);
- hash_delete (subsym_recurse_hash, name, FALSE);
- }
- /* Temporarily zero-terminate where the symbol started. */
- *name = 0;
- if (forced)
- {
- if (c == '(')
- {
- /* Subscripted substitution symbol -- use just the
- indicated portion of the string; the description
- kinda indicates that forced substitution is not
- supposed to be recursive, but I'm not sure. */
- unsigned beg, len = 1; /* default to a single char */
- char *newval = strcpy (xmalloc (strlen (value) + 1),
- value);
- savedp = input_line_pointer;
- input_line_pointer = tail + 1;
- beg = get_absolute_expression ();
- if (beg < 1)
- {
- as_bad (_("Invalid subscript (use 1 to %d)"),
- (int) strlen (value));
- break;
- }
- if (*input_line_pointer == ',')
- {
- ++input_line_pointer;
- len = get_absolute_expression ();
- if (beg + len > strlen (value))
- {
- as_bad (_("Invalid length (use 0 to %d"),
- (int) strlen (value) - beg);
- break;
- }
- }
- newval += beg - 1;
- newval[len] = 0;
- tail = input_line_pointer;
- if (*tail++ != ')')
- {
- as_bad (_("Missing ')' in subscripted substitution "
- "symbol expression"));
- break;
- }
- c = *tail;
- input_line_pointer = savedp;
- value = newval;
- }
- name[-1] = 0;
- }
- tmp = xmalloc (strlen (head) + strlen (value) +
- strlen (tail + 1) + 2);
- strcpy (tmp, head);
- strcat (tmp, value);
- /* Make sure forced substitutions are properly terminated. */
- if (forced)
- {
- if (c != ':')
- {
- as_bad (_("Missing forced substitution terminator ':'"));
- break;
- }
- ++tail;
- }
- else
- /* Restore the character after the symbol end. */
- *tail = c;
- strcat (tmp, tail);
- /* Continue examining after the replacement value. */
- ptr = tmp + strlen (head) + strlen (value);
- free (replacement);
- head = replacement = tmp;
- changed = 1;
- }
- else
- *ptr = c;
- }
- else
- {
- ++ptr;
- }
- }
- if (changed)
- return replacement;
- else
- return line;
- }
- /* We use this to handle substitution symbols
- hijack input_line_pointer, replacing it with our substituted string.
- .sslist should enable listing the line after replacements are made...
- returns the new buffer limit. */
- void
- tic54x_start_line_hook (void)
- {
- char *line, *endp;
- char *replacement = NULL;
- /* Work with a copy of the input line, including EOL char. */
- endp = input_line_pointer;
- while (!is_end_of_line[(int) *endp++])
- ;
- line = xmalloc (endp - input_line_pointer + 1);
- strncpy (line, input_line_pointer, endp - input_line_pointer + 1);
- line[endp - input_line_pointer] = 0;
- /* Scan ahead for parallel insns. */
- parallel_on_next_line_hint = next_line_shows_parallel (endp);
- /* If within a macro, first process forced replacements. */
- if (macro_level > 0)
- replacement = subsym_substitute (line, 1);
- else
- replacement = line;
- replacement = subsym_substitute (replacement, 0);
- if (replacement != line)
- {
- char *tmp = replacement;
- char *comment = strchr (replacement, ';');
- char endc = replacement[strlen (replacement) - 1];
- /* Clean up the replacement; we'd prefer to have this done by the
- standard preprocessing equipment (maybe do_scrub_chars?)
- but for now, do a quick-and-dirty. */
- if (comment != NULL)
- {
- comment[0] = endc;
- comment[1] = 0;
- --comment;
- }
- else
- comment = replacement + strlen (replacement) - 1;
- /* Trim trailing whitespace. */
- while (ISSPACE (*comment))
- {
- comment[0] = endc;
- comment[1] = 0;
- --comment;
- }
- /* Compact leading whitespace. */
- while (ISSPACE (tmp[0]) && ISSPACE (tmp[1]))
- ++tmp;
- input_line_pointer = endp;
- input_scrub_insert_line (tmp);
- free (replacement);
- free (line);
- /* Keep track of whether we've done a substitution. */
- substitution_line = 1;
- }
- else
- {
- /* No change. */
- free (line);
- substitution_line = 0;
- }
- }
- /* This is the guts of the machine-dependent assembler. STR points to a
- machine dependent instruction. This function is supposed to emit
- the frags/bytes it assembles to. */
- void
- md_assemble (char *line)
- {
- static int repeat_slot = 0;
- static int delay_slots = 0; /* How many delay slots left to fill? */
- static int is_parallel = 0;
- static tic54x_insn insn;
- char *lptr;
- char *savedp = input_line_pointer;
- int c;
- input_line_pointer = line;
- c = get_symbol_name (&line);
- if (cpu == VNONE)
- cpu = V542;
- if (address_mode_needs_set)
- {
- set_address_mode (amode);
- address_mode_needs_set = 0;
- }
- if (cpu_needs_set)
- {
- set_cpu (cpu);
- cpu_needs_set = 0;
- }
- assembly_begun = 1;
- if (is_parallel)
- {
- is_parallel = 0;
- strcpy (insn.parmnemonic, line);
- lptr = input_line_pointer;
- *lptr = c;
- input_line_pointer = savedp;
- if (tic54x_parse_parallel_insn_lastline (&insn, lptr))
- {
- int words = build_insn (&insn);
- if (delay_slots != 0)
- {
- if (words > delay_slots)
- {
- as_bad (_("Instruction does not fit in available delay "
- "slots (%d-word insn, %d slots left)"),
- words, delay_slots);
- delay_slots = 0;
- return;
- }
- delay_slots -= words;
- }
- }
- return;
- }
- memset (&insn, 0, sizeof (insn));
- strcpy (insn.mnemonic, line);
- lptr = input_line_pointer;
- *lptr = c;
- input_line_pointer = savedp;
- /* See if this line is part of a parallel instruction; if so, either this
- line or the next line will have the "||" specifier preceding the
- mnemonic, and we look for it in the parallel insn hash table. */
- if (strstr (line, "||") != NULL || parallel_on_next_line_hint)
- {
- char *tmp = strstr (line, "||");
- if (tmp != NULL)
- *tmp = '\0';
- if (tic54x_parse_parallel_insn_firstline (&insn, lptr))
- {
- is_parallel = 1;
- /* If the parallel part is on the same line, process it now,
- otherwise let the assembler pick up the next line for us. */
- if (tmp != NULL)
- {
- while (ISSPACE (tmp[2]))
- ++tmp;
- md_assemble (tmp + 2);
- }
- }
- else
- {
- as_bad (_("Unrecognized parallel instruction '%s'"), line);
- }
- return;
- }
- if (tic54x_parse_insn (&insn, lptr))
- {
- int words;
- if ((insn.tm->flags & FL_LP)
- && cpu != V545LP && cpu != V546LP)
- {
- as_bad (_("Instruction '%s' requires an LP cpu version"),
- insn.tm->name);
- return;
- }
- if ((insn.tm->flags & FL_FAR)
- && amode != far_mode)
- {
- as_bad (_("Instruction '%s' requires far mode addressing"),
- insn.tm->name);
- return;
- }
- words = build_insn (&insn);
- /* Is this instruction in a delay slot? */
- if (delay_slots)
- {
- if (words > delay_slots)
- {
- as_warn (_("Instruction does not fit in available delay "
- "slots (%d-word insn, %d slots left). "
- "Resulting behavior is undefined."),
- words, delay_slots);
- delay_slots = 0;
- return;
- }
- /* Branches in delay slots are not allowed. */
- if (insn.tm->flags & FL_BMASK)
- {
- as_warn (_("Instructions which cause PC discontinuity are not "
- "allowed in a delay slot. "
- "Resulting behavior is undefined."));
- }
- delay_slots -= words;
- }
- /* Is this instruction the target of a repeat? */
- if (repeat_slot)
- {
- if (insn.tm->flags & FL_NR)
- as_warn (_("'%s' is not repeatable. "
- "Resulting behavior is undefined."),
- insn.tm->name);
- else if (insn.is_lkaddr)
- as_warn (_("Instructions using long offset modifiers or absolute "
- "addresses are not repeatable. "
- "Resulting behavior is undefined."));
- repeat_slot = 0;
- }
- /* Make sure we check the target of a repeat instruction. */
- if (insn.tm->flags & B_REPEAT)
- {
- repeat_slot = 1;
- /* FIXME -- warn if repeat_slot == 1 at EOF. */
- }
- /* Make sure we check our delay slots for validity. */
- if (insn.tm->flags & FL_DELAY)
- {
- delay_slots = 2;
- /* FIXME -- warn if delay_slots != 0 at EOF. */
- }
- }
- }
- /* Do a final adjustment on the symbol table; in this case, make sure we have
- a ".file" symbol. */
- void
- tic54x_adjust_symtab (void)
- {
- if (symbol_rootP == NULL
- || S_GET_STORAGE_CLASS (symbol_rootP) != C_FILE)
- {
- char *filename;
- unsigned lineno;
- as_where (&filename, &lineno);
- c_dot_file_symbol (filename, 0);
- }
- }
- /* In order to get gas to ignore any | chars at the start of a line,
- this function returns true if a | is found in a line.
- This lets us process parallel instructions, which span two lines. */
- int
- tic54x_unrecognized_line (int c)
- {
- return c == PARALLEL_SEPARATOR;
- }
- /* Watch for local labels of the form $[0-9] and [_a-zA-Z][_a-zA-Z0-9]*?
- Encode their names so that only we see them and can map them to the
- appropriate places.
- FIXME -- obviously this isn't done yet. These locals still show up in the
- symbol table. */
- void
- tic54x_define_label (symbolS *sym)
- {
- /* Just in case we need this later; note that this is not necessarily the
- same thing as line_label...
- When aligning or assigning labels to fields, sometimes the label is
- assigned other than the address at which the label appears.
- FIXME -- is this really needed? I think all the proper label assignment
- is done in tic54x_cons. */
- last_label_seen = sym;
- }
- /* Try to parse something that normal parsing failed at. */
- symbolS *
- tic54x_undefined_symbol (char *name)
- {
- symbol *sym;
- /* Not sure how to handle predefined symbols. */
- if ((sym = (symbol *) hash_find (cc_hash, name)) != NULL ||
- (sym = (symbol *) hash_find (cc2_hash, name)) != NULL ||
- (sym = (symbol *) hash_find (cc3_hash, name)) != NULL ||
- (sym = (symbol *) hash_find (misc_symbol_hash, name)) != NULL ||
- (sym = (symbol *) hash_find (sbit_hash, name)) != NULL)
- {
- return symbol_new (name, reg_section,
- (valueT) sym->value,
- &zero_address_frag);
- }
- if ((sym = (symbol *) hash_find (reg_hash, name)) != NULL ||
- (sym = (symbol *) hash_find (mmreg_hash, name)) != NULL ||
- !strcasecmp (name, "a") || !strcasecmp (name, "b"))
- {
- return symbol_new (name, reg_section,
- (valueT) sym ? sym->value : 0,
- &zero_address_frag);
- }
- return NULL;
- }
- /* Parse a name in an expression before the expression parser takes a stab at
- it. */
- int
- tic54x_parse_name (char *name ATTRIBUTE_UNUSED,
- expressionS *expn ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- char *
- md_atof (int type, char *literalP, int *sizeP)
- {
- /* Target data is little-endian, but floats are stored
- big-"word"ian. ugh. */
- return ieee_md_atof (type, literalP, sizeP, TRUE);
- }
- arelent *
- tc_gen_reloc (asection *section, fixS *fixP)
- {
- arelent *rel;
- bfd_reloc_code_real_type code = fixP->fx_r_type;
- asymbol *sym = symbol_get_bfdsym (fixP->fx_addsy);
- rel = (arelent *) xmalloc (sizeof (arelent));
- rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *rel->sym_ptr_ptr = sym;
- /* We assume that all rel->address are host byte offsets. */
- rel->address = fixP->fx_frag->fr_address + fixP->fx_where;
- rel->address /= OCTETS_PER_BYTE;
- rel->howto = bfd_reloc_type_lookup (stdoutput, code);
- if (!strcmp (sym->name, section->name))
- rel->howto += HOWTO_BANK;
- if (!rel->howto)
- {
- const char *name = S_GET_NAME (fixP->fx_addsy);
- if (name == NULL)
- name = "<unknown>";
- as_fatal ("Cannot generate relocation type for symbol %s, code %s",
- name, bfd_get_reloc_code_name (code));
- return NULL;
- }
- return rel;
- }
- /* Handle cons expressions. */
- void
- tic54x_cons_fix_new (fragS *frag, int where, int octets, expressionS *expn,
- bfd_reloc_code_real_type r)
- {
- switch (octets)
- {
- default:
- as_bad (_("Unsupported relocation size %d"), octets);
- r = BFD_RELOC_TIC54X_16_OF_23;
- break;
- case 2:
- r = BFD_RELOC_TIC54X_16_OF_23;
- break;
- case 4:
- /* TI assembler always uses this, regardless of addressing mode. */
- if (emitting_long)
- r = BFD_RELOC_TIC54X_23;
- else
- /* We never want to directly generate this; this is provided for
- stabs support only. */
- r = BFD_RELOC_32;
- break;
- }
- fix_new_exp (frag, where, octets, expn, 0, r);
- }
- /* Attempt to simplify or even eliminate a fixup.
- To indicate that a fixup has been eliminated, set fixP->fx_done.
- If fixp->fx_addsy is non-NULL, we'll have to generate a reloc entry. */
- void
- md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
- {
- char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
- valueT val = * valP;
- switch (fixP->fx_r_type)
- {
- default:
- as_fatal ("Bad relocation type: 0x%02x", fixP->fx_r_type);
- return;
- case BFD_RELOC_TIC54X_MS7_OF_23:
- val = (val >> 16) & 0x7F;
- /* Fall through. */
- case BFD_RELOC_TIC54X_16_OF_23:
- case BFD_RELOC_16:
- bfd_put_16 (stdoutput, val, buf);
- /* Indicate what we're actually writing, so that we don't get warnings
- about exceeding available space. */
- *valP = val & 0xFFFF;
- break;
- case BFD_RELOC_TIC54X_PARTLS7:
- bfd_put_16 (stdoutput,
- (bfd_get_16 (stdoutput, buf) & 0xFF80) | (val & 0x7F),
- buf);
- /* Indicate what we're actually writing, so that we don't get warnings
- about exceeding available space. */
- *valP = val & 0x7F;
- break;
- case BFD_RELOC_TIC54X_PARTMS9:
- /* TI assembler doesn't shift its encoding for relocatable files, and is
- thus incompatible with this implementation's relocatable files. */
- bfd_put_16 (stdoutput,
- (bfd_get_16 (stdoutput, buf) & 0xFE00) | (val >> 7),
- buf);
- break;
- case BFD_RELOC_32:
- case BFD_RELOC_TIC54X_23:
- bfd_put_32 (stdoutput,
- (bfd_get_32 (stdoutput, buf) & 0xFF800000) | val,
- buf);
- break;
- }
- if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
- fixP->fx_done = 1;
- }
- /* This is our chance to record section alignment
- don't need to do anything here, since BFD does the proper encoding. */
- valueT
- md_section_align (segT segment ATTRIBUTE_UNUSED, valueT section_size)
- {
- return section_size;
- }
- long
- md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- /* Mostly little-endian, but longwords (4 octets) get MS word stored
- first. */
- void
- tic54x_number_to_chars (char *buf, valueT val, int n)
- {
- if (n != 4)
- number_to_chars_littleendian (buf, val, n);
- else
- {
- number_to_chars_littleendian (buf , val >> 16 , 2);
- number_to_chars_littleendian (buf + 2, val & 0xFFFF, 2);
- }
- }
- int
- tic54x_estimate_size_before_relax (fragS *frag ATTRIBUTE_UNUSED,
- segT seg ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- /* We use this to handle bit allocations which we couldn't handle before due
- to symbols being in different frags. return number of octets added. */
- int
- tic54x_relax_frag (fragS *frag, long stretch ATTRIBUTE_UNUSED)
- {
- symbolS *sym = frag->fr_symbol;
- int growth = 0;
- int i;
- if (sym != NULL)
- {
- struct bit_info *bi = (struct bit_info *) frag->fr_opcode;
- int bit_offset = frag_bit_offset (frag_prev (frag, bi->seg), bi->seg);
- int size = S_GET_VALUE (sym);
- fragS *prev_frag = bit_offset_frag (frag_prev (frag, bi->seg), bi->seg);
- int available = 16 - bit_offset;
- if (symbol_get_frag (sym) != &zero_address_frag
- || S_IS_COMMON (sym)
- || !S_IS_DEFINED (sym))
- as_bad_where (frag->fr_file, frag->fr_line,
- _("non-absolute value used with .space/.bes"));
- if (size < 0)
- {
- as_warn (_("negative value ignored in %s"),
- bi->type == TYPE_SPACE ? ".space" :
- bi->type == TYPE_BES ? ".bes" : ".field");
- growth = 0;
- frag->tc_frag_data = frag->fr_fix = 0;
- return 0;
- }
- if (bi->type == TYPE_FIELD)
- {
- /* Bit fields of 16 or larger will have already been handled. */
- if (bit_offset != 0 && available >= size)
- {
- char *p = prev_frag->fr_literal;
- valueT value = bi->value;
- value <<= available - size;
- value |= ((unsigned short) p[1] << 8) | p[0];
- md_number_to_chars (p, value, 2);
- if ((prev_frag->tc_frag_data += size) == 16)
- prev_frag->tc_frag_data = 0;
- if (bi->sym)
- symbol_set_frag (bi->sym, prev_frag);
- /* This frag is no longer used. */
- growth = -frag->fr_fix;
- frag->fr_fix = 0;
- frag->tc_frag_data = 0;
- }
- else
- {
- char *p = frag->fr_literal;
- valueT value = bi->value << (16 - size);
- md_number_to_chars (p, value, 2);
- if ((frag->tc_frag_data = size) == 16)
- frag->tc_frag_data = 0;
- growth = 0;
- }
- }
- else
- {
- if (bit_offset != 0 && bit_offset < 16)
- {
- if (available >= size)
- {
- if ((prev_frag->tc_frag_data += size) == 16)
- prev_frag->tc_frag_data = 0;
- if (bi->sym)
- symbol_set_frag (bi->sym, prev_frag);
- /* This frag is no longer used. */
- growth = -frag->fr_fix;
- frag->fr_fix = 0;
- frag->tc_frag_data = 0;
- goto getout;
- }
- if (bi->type == TYPE_SPACE && bi->sym)
- symbol_set_frag (bi->sym, prev_frag);
- size -= available;
- }
- growth = (size + 15) / 16 * OCTETS_PER_BYTE - frag->fr_fix;
- for (i = 0; i < growth; i++)
- frag->fr_literal[i] = 0;
- frag->fr_fix = growth;
- frag->tc_frag_data = size % 16;
- /* Make sure any BES label points to the LAST word allocated. */
- if (bi->type == TYPE_BES && bi->sym)
- S_SET_VALUE (bi->sym, frag->fr_fix / OCTETS_PER_BYTE - 1);
- }
- getout:
- frag->fr_symbol = 0;
- frag->fr_opcode = 0;
- free ((void *) bi);
- }
- return growth;
- }
- void
- tic54x_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
- segT seg ATTRIBUTE_UNUSED,
- fragS *frag)
- {
- /* Offset is in bytes. */
- frag->fr_offset = (frag->fr_next->fr_address
- - frag->fr_address
- - frag->fr_fix) / frag->fr_var;
- if (frag->fr_offset < 0)
- {
- as_bad_where (frag->fr_file, frag->fr_line,
- _("attempt to .space/.bes backwards? (%ld)"),
- (long) frag->fr_offset);
- }
- frag->fr_type = rs_space;
- }
- /* We need to avoid having labels defined for certain directives/pseudo-ops
- since once the label is defined, it's in the symbol table for good. TI
- syntax puts the symbol *before* the pseudo (which is kinda like MRI syntax,
- I guess, except I've never seen a definition of MRI syntax).
- Don't allow labels to start with '.' */
- int
- tic54x_start_label (int nul_char, int next_char)
- {
- char *rest;
- /* If within .struct/.union, no auto line labels, please. */
- if (current_stag != NULL)
- return 0;
- /* Disallow labels starting with "." */
- if (next_char != ':')
- {
- char *label = input_line_pointer;
- while (!is_end_of_line[(int) label[-1]])
- --label;
- if (*label == '.')
- {
- as_bad (_("Invalid label '%s'"), label);
- return 0;
- }
- }
- if (is_end_of_line[(int) next_char])
- return 1;
- rest = input_line_pointer;
- if (nul_char == '"')
- ++rest;
- while (ISSPACE (next_char))
- next_char = *++rest;
- if (next_char != '.')
- return 1;
- /* Don't let colon () define a label for any of these... */
- return ((strncasecmp (rest, ".tag", 4) != 0 || !ISSPACE (rest[4]))
- && (strncasecmp (rest, ".struct", 7) != 0 || !ISSPACE (rest[7]))
- && (strncasecmp (rest, ".union", 6) != 0 || !ISSPACE (rest[6]))
- && (strncasecmp (rest, ".macro", 6) != 0 || !ISSPACE (rest[6]))
- && (strncasecmp (rest, ".set", 4) != 0 || !ISSPACE (rest[4]))
- && (strncasecmp (rest, ".equ", 4) != 0 || !ISSPACE (rest[4])));
- }
|