123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299 |
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- MOTOROLA MICROPROCESSOR & MEMORY TECHNOLOGY GROUP
- M68000 Hi-Performance Microprocessor Division
- M68060 Software Package
- Production Release P1.00 -- October 10, 1994
- M68060 Software Package Copyright © 1993, 1994 Motorola Inc. All rights reserved.
- THE SOFTWARE is provided on an "AS IS" basis and without warranty.
- To the maximum extent permitted by applicable law,
- MOTOROLA DISCLAIMS ALL WARRANTIES WHETHER EXPRESS OR IMPLIED,
- INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
- and any warranty against infringement with regard to the SOFTWARE
- (INCLUDING ANY MODIFIED VERSIONS THEREOF) and any accompanying written materials.
- To the maximum extent permitted by applicable law,
- IN NO EVENT SHALL MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER
- (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS,
- BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR OTHER PECUNIARY LOSS)
- ARISING OF THE USE OR INABILITY TO USE THE SOFTWARE.
- Motorola assumes no responsibility for the maintenance and support of the SOFTWARE.
- You are hereby granted a copyright license to use, modify, and distribute the SOFTWARE
- so long as this entire notice is retained without alteration in any modified and/or
- redistributed versions, and that such modified versions are clearly identified as such.
- No licenses are granted by implication, estoppel or otherwise under any patents
- or trademarks of Motorola, Inc.
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # ireal.s:
- # This file is appended to the top of the 060ISP package
- # and contains the entry points into the package. The user, in
- # effect, branches to one of the branch table entries located
- # after _060ISP_TABLE.
- # Also, subroutine stubs exist in this file (_isp_done for
- # example) that are referenced by the ISP package itself in order
- # to call a given routine. The stub routine actually performs the
- # callout. The ISP code does a "bsr" to the stub routine. This
- # extra layer of hierarchy adds a slight performance penalty but
- # it makes the ISP code easier to read and more mainatinable.
- #
- set _off_chk, 0x00
- set _off_divbyzero, 0x04
- set _off_trace, 0x08
- set _off_access, 0x0c
- set _off_done, 0x10
- set _off_cas, 0x14
- set _off_cas2, 0x18
- set _off_lock, 0x1c
- set _off_unlock, 0x20
- set _off_imr, 0x40
- set _off_dmr, 0x44
- set _off_dmw, 0x48
- set _off_irw, 0x4c
- set _off_irl, 0x50
- set _off_drb, 0x54
- set _off_drw, 0x58
- set _off_drl, 0x5c
- set _off_dwb, 0x60
- set _off_dww, 0x64
- set _off_dwl, 0x68
- _060ISP_TABLE:
- # Here's the table of ENTRY POINTS for those linking the package.
- bra.l _isp_unimp
- short 0x0000
- bra.l _isp_cas
- short 0x0000
- bra.l _isp_cas2
- short 0x0000
- bra.l _isp_cas_finish
- short 0x0000
- bra.l _isp_cas2_finish
- short 0x0000
- bra.l _isp_cas_inrange
- short 0x0000
- bra.l _isp_cas_terminate
- short 0x0000
- bra.l _isp_cas_restart
- short 0x0000
- space 64
- #############################################################
- global _real_chk
- _real_chk:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_chk,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_divbyzero
- _real_divbyzero:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_divbyzero,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_trace
- _real_trace:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_trace,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_access
- _real_access:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_access,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _isp_done
- _isp_done:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_done,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- #######################################
- global _real_cas
- _real_cas:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_cas,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_cas2
- _real_cas2:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_cas2,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_lock_page
- _real_lock_page:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_lock,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _real_unlock_page
- _real_unlock_page:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_unlock,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- #######################################
- global _imem_read
- _imem_read:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_imr,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_read
- _dmem_read:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_dmr,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_write
- _dmem_write:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_dmw,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _imem_read_word
- _imem_read_word:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_irw,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _imem_read_long
- _imem_read_long:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_irl,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_read_byte
- _dmem_read_byte:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_drb,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_read_word
- _dmem_read_word:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_drw,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_read_long
- _dmem_read_long:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_drl,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_write_byte
- _dmem_write_byte:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_dwb,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_write_word
- _dmem_write_word:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_dww,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- global _dmem_write_long
- _dmem_write_long:
- mov.l %d0,-(%sp)
- mov.l (_060ISP_TABLE-0x80+_off_dwl,%pc),%d0
- pea.l (_060ISP_TABLE-0x80,%pc,%d0)
- mov.l 0x4(%sp),%d0
- rtd &0x4
- #
- # This file contains a set of define statements for constants
- # in oreder to promote readability within the core code itself.
- #
- set LOCAL_SIZE, 96 # stack frame size(bytes)
- set LV, -LOCAL_SIZE # stack offset
- set EXC_ISR, 0x4 # stack status register
- set EXC_IPC, 0x6 # stack pc
- set EXC_IVOFF, 0xa # stacked vector offset
- set EXC_AREGS, LV+64 # offset of all address regs
- set EXC_DREGS, LV+32 # offset of all data regs
- set EXC_A7, EXC_AREGS+(7*4) # offset of a7
- set EXC_A6, EXC_AREGS+(6*4) # offset of a6
- set EXC_A5, EXC_AREGS+(5*4) # offset of a5
- set EXC_A4, EXC_AREGS+(4*4) # offset of a4
- set EXC_A3, EXC_AREGS+(3*4) # offset of a3
- set EXC_A2, EXC_AREGS+(2*4) # offset of a2
- set EXC_A1, EXC_AREGS+(1*4) # offset of a1
- set EXC_A0, EXC_AREGS+(0*4) # offset of a0
- set EXC_D7, EXC_DREGS+(7*4) # offset of d7
- set EXC_D6, EXC_DREGS+(6*4) # offset of d6
- set EXC_D5, EXC_DREGS+(5*4) # offset of d5
- set EXC_D4, EXC_DREGS+(4*4) # offset of d4
- set EXC_D3, EXC_DREGS+(3*4) # offset of d3
- set EXC_D2, EXC_DREGS+(2*4) # offset of d2
- set EXC_D1, EXC_DREGS+(1*4) # offset of d1
- set EXC_D0, EXC_DREGS+(0*4) # offset of d0
- set EXC_TEMP, LV+16 # offset of temp stack space
- set EXC_SAVVAL, LV+12 # offset of old areg value
- set EXC_SAVREG, LV+11 # offset of old areg index
- set SPCOND_FLG, LV+10 # offset of spc condition flg
- set EXC_CC, LV+8 # offset of cc register
- set EXC_EXTWPTR, LV+4 # offset of current PC
- set EXC_EXTWORD, LV+2 # offset of current ext opword
- set EXC_OPWORD, LV+0 # offset of current opword
- ###########################
- # SPecial CONDition FLaGs #
- ###########################
- set mia7_flg, 0x04 # (a7)+ flag
- set mda7_flg, 0x08 # -(a7) flag
- set ichk_flg, 0x10 # chk exception flag
- set idbyz_flg, 0x20 # divbyzero flag
- set restore_flg, 0x40 # restore -(an)+ flag
- set immed_flg, 0x80 # immediate data flag
- set mia7_bit, 0x2 # (a7)+ bit
- set mda7_bit, 0x3 # -(a7) bit
- set ichk_bit, 0x4 # chk exception bit
- set idbyz_bit, 0x5 # divbyzero bit
- set restore_bit, 0x6 # restore -(a7)+ bit
- set immed_bit, 0x7 # immediate data bit
- #########
- # Misc. #
- #########
- set BYTE, 1 # len(byte) == 1 byte
- set WORD, 2 # len(word) == 2 bytes
- set LONG, 4 # len(longword) == 4 bytes
- #########################################################################
- # XDEF **************************************************************** #
- # _isp_unimp(): 060ISP entry point for Unimplemented Instruction #
- # #
- # This handler should be the first code executed upon taking the #
- # "Unimplemented Integer Instruction" exception in an operating #
- # system. #
- # #
- # XREF **************************************************************** #
- # _imem_read_{word,long}() - read instruction word/longword #
- # _mul64() - emulate 64-bit multiply #
- # _div64() - emulate 64-bit divide #
- # _moveperipheral() - emulate "movep" #
- # _compandset() - emulate misaligned "cas" #
- # _compandset2() - emulate "cas2" #
- # _chk2_cmp2() - emulate "cmp2" and "chk2" #
- # _isp_done() - "callout" for normal final exit #
- # _real_trace() - "callout" for Trace exception #
- # _real_chk() - "callout" for Chk exception #
- # _real_divbyzero() - "callout" for DZ exception #
- # _real_access() - "callout" for access error exception #
- # #
- # INPUT *************************************************************** #
- # - The system stack contains the Unimp Int Instr stack frame #
- # #
- # OUTPUT ************************************************************** #
- # If Trace exception: #
- # - The system stack changed to contain Trace exc stack frame #
- # If Chk exception: #
- # - The system stack changed to contain Chk exc stack frame #
- # If DZ exception: #
- # - The system stack changed to contain DZ exc stack frame #
- # If access error exception: #
- # - The system stack changed to contain access err exc stk frame #
- # Else: #
- # - Results saved as appropriate #
- # #
- # ALGORITHM *********************************************************** #
- # This handler fetches the first instruction longword from #
- # memory and decodes it to determine which of the unimplemented #
- # integer instructions caused this exception. This handler then calls #
- # one of _mul64(), _div64(), _moveperipheral(), _compandset(), #
- # _compandset2(), or _chk2_cmp2() as appropriate. #
- # Some of these instructions, by their nature, may produce other #
- # types of exceptions. "div" can produce a divide-by-zero exception, #
- # and "chk2" can cause a "Chk" exception. In both cases, the current #
- # exception stack frame must be converted to an exception stack frame #
- # of the correct exception type and an exit must be made through #
- # _real_divbyzero() or _real_chk() as appropriate. In addition, all #
- # instructions may be executing while Trace is enabled. If so, then #
- # a Trace exception stack frame must be created and an exit made #
- # through _real_trace(). #
- # Meanwhile, if any read or write to memory using the #
- # _mem_{read,write}() "callout"s returns a failing value, then an #
- # access error frame must be created and an exit made through #
- # _real_access(). #
- # If none of these occur, then a normal exit is made through #
- # _isp_done(). #
- # #
- # This handler, upon entry, saves almost all user-visible #
- # address and data registers to the stack. Although this may seem to #
- # cause excess memory traffic, it was found that due to having to #
- # access these register files for things like data retrieval and <ea> #
- # calculations, it was more efficient to have them on the stack where #
- # they could be accessed by indexing rather than to make subroutine #
- # calls to retrieve a register of a particular index. #
- # #
- #########################################################################
- global _isp_unimp
- _isp_unimp:
- link.w %a6,&-LOCAL_SIZE # create room for stack frame
- movm.l &0x3fff,EXC_DREGS(%a6) # store d0-d7/a0-a5
- mov.l (%a6),EXC_A6(%a6) # store a6
- btst &0x5,EXC_ISR(%a6) # from s or u mode?
- bne.b uieh_s # supervisor mode
- uieh_u:
- mov.l %usp,%a0 # fetch user stack pointer
- mov.l %a0,EXC_A7(%a6) # store a7
- bra.b uieh_cont
- uieh_s:
- lea 0xc(%a6),%a0
- mov.l %a0,EXC_A7(%a6) # store corrected sp
- ###############################################################################
- uieh_cont:
- clr.b SPCOND_FLG(%a6) # clear "special case" flag
- mov.w EXC_ISR(%a6),EXC_CC(%a6) # store cc copy on stack
- mov.l EXC_IPC(%a6),EXC_EXTWPTR(%a6) # store extwptr on stack
- #
- # fetch the opword and first extension word pointed to by the stacked pc
- # and store them to the stack for now
- #
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_long # fetch opword & extword
- mov.l %d0,EXC_OPWORD(%a6) # store extword on stack
- #########################################################################
- # muls.l 0100 1100 00 |<ea>| 0*** 1100 0000 0*** #
- # mulu.l 0100 1100 00 |<ea>| 0*** 0100 0000 0*** #
- # #
- # divs.l 0100 1100 01 |<ea>| 0*** 1100 0000 0*** #
- # divu.l 0100 1100 01 |<ea>| 0*** 0100 0000 0*** #
- # #
- # movep.w m2r 0000 ***1 00 001*** | <displacement> | #
- # movep.l m2r 0000 ***1 01 001*** | <displacement> | #
- # movep.w r2m 0000 ***1 10 001*** | <displacement> | #
- # movep.l r2m 0000 ***1 11 001*** | <displacement> | #
- # #
- # cas.w 0000 1100 11 |<ea>| 0000 000* **00 0*** #
- # cas.l 0000 1110 11 |<ea>| 0000 000* **00 0*** #
- # #
- # cas2.w 0000 1100 11 111100 **** 000* **00 0*** #
- # **** 000* **00 0*** #
- # cas2.l 0000 1110 11 111100 **** 000* **00 0*** #
- # **** 000* **00 0*** #
- # #
- # chk2.b 0000 0000 11 |<ea>| **** 1000 0000 0000 #
- # chk2.w 0000 0010 11 |<ea>| **** 1000 0000 0000 #
- # chk2.l 0000 0100 11 |<ea>| **** 1000 0000 0000 #
- # #
- # cmp2.b 0000 0000 11 |<ea>| **** 0000 0000 0000 #
- # cmp2.w 0000 0010 11 |<ea>| **** 0000 0000 0000 #
- # cmp2.l 0000 0100 11 |<ea>| **** 0000 0000 0000 #
- #########################################################################
- #
- # using bit 14 of the operation word, separate into 2 groups:
- # (group1) mul64, div64
- # (group2) movep, chk2, cmp2, cas2, cas
- #
- btst &0x1e,%d0 # group1 or group2
- beq.b uieh_group2 # go handle group2
- #
- # now, w/ group1, make mul64's decode the fastest since it will
- # most likely be used the most.
- #
- uieh_group1:
- btst &0x16,%d0 # test for div64
- bne.b uieh_div64 # go handle div64
- uieh_mul64:
- # mul64() may use ()+ addressing and may, therefore, alter a7
- bsr.l _mul64 # _mul64()
- btst &0x5,EXC_ISR(%a6) # supervisor mode?
- beq.w uieh_done
- btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
- beq.w uieh_done # no
- btst &0x7,EXC_ISR(%a6) # is trace enabled?
- bne.w uieh_trace_a7 # yes
- bra.w uieh_a7 # no
- uieh_div64:
- # div64() may use ()+ addressing and may, therefore, alter a7.
- # div64() may take a divide by zero exception.
- bsr.l _div64 # _div64()
- # here, we sort out all of the special cases that may have happened.
- btst &mia7_bit,SPCOND_FLG(%a6) # was a7 changed?
- bne.b uieh_div64_a7 # yes
- uieh_div64_dbyz:
- btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
- bne.w uieh_divbyzero # yes
- bra.w uieh_done # no
- uieh_div64_a7:
- btst &0x5,EXC_ISR(%a6) # supervisor mode?
- beq.b uieh_div64_dbyz # no
- # here, a7 has been incremented by 4 bytes in supervisor mode. we still
- # may have the following 3 cases:
- # (i) (a7)+
- # (ii) (a7)+; trace
- # (iii) (a7)+; divide-by-zero
- #
- btst &idbyz_bit,SPCOND_FLG(%a6) # did divide-by-zero occur?
- bne.w uieh_divbyzero_a7 # yes
- tst.b EXC_ISR(%a6) # no; is trace enabled?
- bmi.w uieh_trace_a7 # yes
- bra.w uieh_a7 # no
- #
- # now, w/ group2, make movep's decode the fastest since it will
- # most likely be used the most.
- #
- uieh_group2:
- btst &0x18,%d0 # test for not movep
- beq.b uieh_not_movep
- bsr.l _moveperipheral # _movep()
- bra.w uieh_done
- uieh_not_movep:
- btst &0x1b,%d0 # test for chk2,cmp2
- beq.b uieh_chk2cmp2 # go handle chk2,cmp2
- swap %d0 # put opword in lo word
- cmpi.b %d0,&0xfc # test for cas2
- beq.b uieh_cas2 # go handle cas2
- uieh_cas:
- bsr.l _compandset # _cas()
- # the cases of "cas Dc,Du,(a7)+" and "cas Dc,Du,-(a7)" used from supervisor
- # mode are simply not considered valid and therefore are not handled.
- bra.w uieh_done
- uieh_cas2:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word # read extension word
- tst.l %d1 # ifetch error?
- bne.w isp_iacc # yes
- bsr.l _compandset2 # _cas2()
- bra.w uieh_done
- uieh_chk2cmp2:
- # chk2 may take a chk exception
- bsr.l _chk2_cmp2 # _chk2_cmp2()
- # here we check to see if a chk trap should be taken
- cmpi.b SPCOND_FLG(%a6),&ichk_flg
- bne.w uieh_done
- bra.b uieh_chk_trap
- ###########################################################################
- #
- # the required emulation has been completed. now, clean up the necessary stack
- # info and prepare for rte
- #
- uieh_done:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- # if exception occurred in user mode, then we have to restore a7 in case it
- # changed. we don't have to update a7 for supervisor mose because that case
- # doesn't flow through here
- btst &0x5,EXC_ISR(%a6) # user or supervisor?
- bne.b uieh_finish # supervisor
- mov.l EXC_A7(%a6),%a0 # fetch user stack pointer
- mov.l %a0,%usp # restore it
- uieh_finish:
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- btst &0x7,EXC_ISR(%a6) # is trace mode on?
- bne.b uieh_trace # yes;go handle trace mode
- mov.l EXC_EXTWPTR(%a6),EXC_IPC(%a6) # new pc on stack frame
- mov.l EXC_A6(%a6),(%a6) # prepare new a6 for unlink
- unlk %a6 # unlink stack frame
- bra.l _isp_done
- #
- # The instruction that was just emulated was also being traced. The trace
- # trap for this instruction will be lost unless we jump to the trace handler.
- # So, here we create a Trace Exception format number two exception stack
- # frame from the Unimplemented Integer Intruction Exception stack frame
- # format number zero and jump to the user supplied hook "_real_trace()".
- #
- # UIEH FRAME TRACE FRAME
- # ***************** *****************
- # * 0x0 * 0x0f4 * * Current *
- # ***************** * PC *
- # * Current * *****************
- # * PC * * 0x2 * 0x024 *
- # ***************** *****************
- # * SR * * Next *
- # ***************** * PC *
- # ->* Old * *****************
- # from link -->* A6 * * SR *
- # ***************** *****************
- # /* A7 * * New * <-- for final unlink
- # / * * * A6 *
- # link frame < ***************** *****************
- # \ ~ ~ ~ ~
- # \***************** *****************
- #
- uieh_trace:
- mov.l EXC_A6(%a6),-0x4(%a6)
- mov.w EXC_ISR(%a6),0x0(%a6)
- mov.l EXC_IPC(%a6),0x8(%a6)
- mov.l EXC_EXTWPTR(%a6),0x2(%a6)
- mov.w &0x2024,0x6(%a6)
- sub.l &0x4,%a6
- unlk %a6
- bra.l _real_trace
- #
- # UIEH FRAME CHK FRAME
- # ***************** *****************
- # * 0x0 * 0x0f4 * * Current *
- # ***************** * PC *
- # * Current * *****************
- # * PC * * 0x2 * 0x018 *
- # ***************** *****************
- # * SR * * Next *
- # ***************** * PC *
- # (4 words) *****************
- # * SR *
- # *****************
- # (6 words)
- #
- # the chk2 instruction should take a chk trap. so, here we must create a
- # chk stack frame from an unimplemented integer instruction exception frame
- # and jump to the user supplied entry point "_real_chk()".
- #
- uieh_chk_trap:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- mov.w EXC_ISR(%a6),(%a6) # put new SR on stack
- mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack
- mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack
- mov.w &0x2018,0x6(%a6) # put Vector Offset on stack
- mov.l EXC_A6(%a6),%a6 # restore a6
- add.l &LOCAL_SIZE,%sp # clear stack frame
- bra.l _real_chk
- #
- # UIEH FRAME DIVBYZERO FRAME
- # ***************** *****************
- # * 0x0 * 0x0f4 * * Current *
- # ***************** * PC *
- # * Current * *****************
- # * PC * * 0x2 * 0x014 *
- # ***************** *****************
- # * SR * * Next *
- # ***************** * PC *
- # (4 words) *****************
- # * SR *
- # *****************
- # (6 words)
- #
- # the divide instruction should take an integer divide by zero trap. so, here
- # we must create a divbyzero stack frame from an unimplemented integer
- # instruction exception frame and jump to the user supplied entry point
- # "_real_divbyzero()".
- #
- uieh_divbyzero:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- mov.w EXC_ISR(%a6),(%a6) # put new SR on stack
- mov.l EXC_IPC(%a6),0x8(%a6) # put "Current PC" on stack
- mov.l EXC_EXTWPTR(%a6),0x2(%a6) # put "Next PC" on stack
- mov.w &0x2014,0x6(%a6) # put Vector Offset on stack
- mov.l EXC_A6(%a6),%a6 # restore a6
- add.l &LOCAL_SIZE,%sp # clear stack frame
- bra.l _real_divbyzero
- #
- # DIVBYZERO FRAME
- # *****************
- # * Current *
- # UIEH FRAME * PC *
- # ***************** *****************
- # * 0x0 * 0x0f4 * * 0x2 * 0x014 *
- # ***************** *****************
- # * Current * * Next *
- # * PC * * PC *
- # ***************** *****************
- # * SR * * SR *
- # ***************** *****************
- # (4 words) (6 words)
- #
- # the divide instruction should take an integer divide by zero trap. so, here
- # we must create a divbyzero stack frame from an unimplemented integer
- # instruction exception frame and jump to the user supplied entry point
- # "_real_divbyzero()".
- #
- # However, we must also deal with the fact that (a7)+ was used from supervisor
- # mode, thereby shifting the stack frame up 4 bytes.
- #
- uieh_divbyzero_a7:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack
- mov.w &0x2014,0xa(%a6) # put Vector Offset on stack
- mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
- mov.l EXC_A6(%a6),%a6 # restore a6
- add.l &4+LOCAL_SIZE,%sp # clear stack frame
- bra.l _real_divbyzero
- #
- # TRACE FRAME
- # *****************
- # * Current *
- # UIEH FRAME * PC *
- # ***************** *****************
- # * 0x0 * 0x0f4 * * 0x2 * 0x024 *
- # ***************** *****************
- # * Current * * Next *
- # * PC * * PC *
- # ***************** *****************
- # * SR * * SR *
- # ***************** *****************
- # (4 words) (6 words)
- #
- #
- # The instruction that was just emulated was also being traced. The trace
- # trap for this instruction will be lost unless we jump to the trace handler.
- # So, here we create a Trace Exception format number two exception stack
- # frame from the Unimplemented Integer Intruction Exception stack frame
- # format number zero and jump to the user supplied hook "_real_trace()".
- #
- # However, we must also deal with the fact that (a7)+ was used from supervisor
- # mode, thereby shifting the stack frame up 4 bytes.
- #
- uieh_trace_a7:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- mov.l EXC_IPC(%a6),0xc(%a6) # put "Current PC" on stack
- mov.w &0x2024,0xa(%a6) # put Vector Offset on stack
- mov.l EXC_EXTWPTR(%a6),0x6(%a6) # put "Next PC" on stack
- mov.l EXC_A6(%a6),%a6 # restore a6
- add.l &4+LOCAL_SIZE,%sp # clear stack frame
- bra.l _real_trace
- #
- # UIEH FRAME
- # *****************
- # * 0x0 * 0x0f4 *
- # UIEH FRAME *****************
- # ***************** * Next *
- # * 0x0 * 0x0f4 * * PC *
- # ***************** *****************
- # * Current * * SR *
- # * PC * *****************
- # ***************** (4 words)
- # * SR *
- # *****************
- # (4 words)
- uieh_a7:
- mov.b EXC_CC+1(%a6),EXC_ISR+1(%a6) # insert new ccodes
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- mov.w &0x00f4,0xe(%a6) # put Vector Offset on stack
- mov.l EXC_EXTWPTR(%a6),0xa(%a6) # put "Next PC" on stack
- mov.w EXC_ISR(%a6),0x8(%a6) # put SR on stack
- mov.l EXC_A6(%a6),%a6 # restore a6
- add.l &8+LOCAL_SIZE,%sp # clear stack frame
- bra.l _isp_done
- ##########
- # this is the exit point if a data read or write fails.
- # a0 = failing address
- # d0 = fslw
- isp_dacc:
- mov.l %a0,(%a6) # save address
- mov.l %d0,-0x4(%a6) # save partial fslw
- lea -64(%a6),%sp
- movm.l (%sp)+,&0x7fff # restore d0-d7/a0-a6
- mov.l 0xc(%sp),-(%sp) # move voff,hi(pc)
- mov.l 0x4(%sp),0x10(%sp) # store fslw
- mov.l 0xc(%sp),0x4(%sp) # store sr,lo(pc)
- mov.l 0x8(%sp),0xc(%sp) # store address
- mov.l (%sp)+,0x4(%sp) # store voff,hi(pc)
- mov.w &0x4008,0x6(%sp) # store new voff
- bra.b isp_acc_exit
- # this is the exit point if an instruction word read fails.
- # FSLW:
- # misaligned = true
- # read = true
- # size = word
- # instruction = true
- # software emulation error = true
- isp_iacc:
- movm.l EXC_DREGS(%a6),&0x3fff # restore d0-d7/a0-a5
- unlk %a6 # unlink frame
- sub.w &0x8,%sp # make room for acc frame
- mov.l 0x8(%sp),(%sp) # store sr,lo(pc)
- mov.w 0xc(%sp),0x4(%sp) # store hi(pc)
- mov.w &0x4008,0x6(%sp) # store new voff
- mov.l 0x2(%sp),0x8(%sp) # store address (=pc)
- mov.l &0x09428001,0xc(%sp) # store fslw
- isp_acc_exit:
- btst &0x5,(%sp) # user or supervisor?
- beq.b isp_acc_exit2 # user
- bset &0x2,0xd(%sp) # set supervisor TM bit
- isp_acc_exit2:
- bra.l _real_access
- # if the addressing mode was (an)+ or -(an), the address register must
- # be restored to its pre-exception value before entering _real_access.
- isp_restore:
- cmpi.b SPCOND_FLG(%a6),&restore_flg # do we need a restore?
- bne.b isp_restore_done # no
- clr.l %d0
- mov.b EXC_SAVREG(%a6),%d0 # regno to restore
- mov.l EXC_SAVVAL(%a6),(EXC_AREGS,%a6,%d0.l*4) # restore value
- isp_restore_done:
- rts
- #########################################################################
- # XDEF **************************************************************** #
- # _calc_ea(): routine to calculate effective address #
- # #
- # XREF **************************************************************** #
- # _imem_read_word() - read instruction word #
- # _imem_read_long() - read instruction longword #
- # _dmem_read_long() - read data longword (for memory indirect) #
- # isp_iacc() - handle instruction access error exception #
- # isp_dacc() - handle data access error exception #
- # #
- # INPUT *************************************************************** #
- # d0 = number of bytes related to effective address (w,l) #
- # #
- # OUTPUT ************************************************************** #
- # If exiting through isp_dacc... #
- # a0 = failing address #
- # d0 = FSLW #
- # elsif exiting though isp_iacc... #
- # none #
- # else #
- # a0 = effective address #
- # #
- # ALGORITHM *********************************************************** #
- # The effective address type is decoded from the opword residing #
- # on the stack. A jump table is used to vector to a routine for the #
- # appropriate mode. Since none of the emulated integer instructions #
- # uses byte-sized operands, only handle word and long operations. #
- # #
- # Dn,An - shouldn't enter here #
- # (An) - fetch An value from stack #
- # -(An) - fetch An value from stack; return decr value; #
- # place decr value on stack; store old value in case of #
- # future access error; if -(a7), set mda7_flg in #
- # SPCOND_FLG #
- # (An)+ - fetch An value from stack; return value; #
- # place incr value on stack; store old value in case of #
- # future access error; if (a7)+, set mia7_flg in #
- # SPCOND_FLG #
- # (d16,An) - fetch An value from stack; read d16 using #
- # _imem_read_word(); fetch may fail -> branch to #
- # isp_iacc() #
- # (xxx).w,(xxx).l - use _imem_read_{word,long}() to fetch #
- # address; fetch may fail #
- # #<data> - return address of immediate value; set immed_flg #
- # in SPCOND_FLG #
- # (d16,PC) - fetch stacked PC value; read d16 using #
- # _imem_read_word(); fetch may fail -> branch to #
- # isp_iacc() #
- # everything else - read needed displacements as appropriate w/ #
- # _imem_read_{word,long}(); read may fail; if memory #
- # indirect, read indirect address using #
- # _dmem_read_long() which may also fail #
- # #
- #########################################################################
- global _calc_ea
- _calc_ea:
- mov.l %d0,%a0 # move # bytes to a0
- # MODE and REG are taken from the EXC_OPWORD.
- mov.w EXC_OPWORD(%a6),%d0 # fetch opcode word
- mov.w %d0,%d1 # make a copy
- andi.w &0x3f,%d0 # extract mode field
- andi.l &0x7,%d1 # extract reg field
- # jump to the corresponding function for each {MODE,REG} pair.
- mov.w (tbl_ea_mode.b,%pc,%d0.w*2), %d0 # fetch jmp distance
- jmp (tbl_ea_mode.b,%pc,%d0.w*1) # jmp to correct ea mode
- swbeg &64
- tbl_ea_mode:
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short addr_ind_a0 - tbl_ea_mode
- short addr_ind_a1 - tbl_ea_mode
- short addr_ind_a2 - tbl_ea_mode
- short addr_ind_a3 - tbl_ea_mode
- short addr_ind_a4 - tbl_ea_mode
- short addr_ind_a5 - tbl_ea_mode
- short addr_ind_a6 - tbl_ea_mode
- short addr_ind_a7 - tbl_ea_mode
- short addr_ind_p_a0 - tbl_ea_mode
- short addr_ind_p_a1 - tbl_ea_mode
- short addr_ind_p_a2 - tbl_ea_mode
- short addr_ind_p_a3 - tbl_ea_mode
- short addr_ind_p_a4 - tbl_ea_mode
- short addr_ind_p_a5 - tbl_ea_mode
- short addr_ind_p_a6 - tbl_ea_mode
- short addr_ind_p_a7 - tbl_ea_mode
- short addr_ind_m_a0 - tbl_ea_mode
- short addr_ind_m_a1 - tbl_ea_mode
- short addr_ind_m_a2 - tbl_ea_mode
- short addr_ind_m_a3 - tbl_ea_mode
- short addr_ind_m_a4 - tbl_ea_mode
- short addr_ind_m_a5 - tbl_ea_mode
- short addr_ind_m_a6 - tbl_ea_mode
- short addr_ind_m_a7 - tbl_ea_mode
- short addr_ind_disp_a0 - tbl_ea_mode
- short addr_ind_disp_a1 - tbl_ea_mode
- short addr_ind_disp_a2 - tbl_ea_mode
- short addr_ind_disp_a3 - tbl_ea_mode
- short addr_ind_disp_a4 - tbl_ea_mode
- short addr_ind_disp_a5 - tbl_ea_mode
- short addr_ind_disp_a6 - tbl_ea_mode
- short addr_ind_disp_a7 - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short _addr_ind_ext - tbl_ea_mode
- short abs_short - tbl_ea_mode
- short abs_long - tbl_ea_mode
- short pc_ind - tbl_ea_mode
- short pc_ind_ext - tbl_ea_mode
- short immediate - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- short tbl_ea_mode - tbl_ea_mode
- ###################################
- # Address register indirect: (An) #
- ###################################
- addr_ind_a0:
- mov.l EXC_A0(%a6),%a0 # Get current a0
- rts
- addr_ind_a1:
- mov.l EXC_A1(%a6),%a0 # Get current a1
- rts
- addr_ind_a2:
- mov.l EXC_A2(%a6),%a0 # Get current a2
- rts
- addr_ind_a3:
- mov.l EXC_A3(%a6),%a0 # Get current a3
- rts
- addr_ind_a4:
- mov.l EXC_A4(%a6),%a0 # Get current a4
- rts
- addr_ind_a5:
- mov.l EXC_A5(%a6),%a0 # Get current a5
- rts
- addr_ind_a6:
- mov.l EXC_A6(%a6),%a0 # Get current a6
- rts
- addr_ind_a7:
- mov.l EXC_A7(%a6),%a0 # Get current a7
- rts
- #####################################################
- # Address register indirect w/ postincrement: (An)+ #
- #####################################################
- addr_ind_p_a0:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A0(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A0(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x0,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a1:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A1(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A1(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x1,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a2:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A2(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A2(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x2,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a3:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A3(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A3(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x3,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a4:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A4(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A4(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x4,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a5:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A5(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A5(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x5,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a6:
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A6(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A6(%a6) # save incremented value
- mov.l %a0,EXC_SAVVAL(%a6) # save in case of access error
- mov.b &0x6,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_p_a7:
- mov.b &mia7_flg,SPCOND_FLG(%a6) # set "special case" flag
- mov.l %a0,%d0 # copy no. bytes
- mov.l EXC_A7(%a6),%a0 # load current value
- add.l %a0,%d0 # increment
- mov.l %d0,EXC_A7(%a6) # save incremented value
- rts
- ####################################################
- # Address register indirect w/ predecrement: -(An) #
- ####################################################
- addr_ind_m_a0:
- mov.l EXC_A0(%a6),%d0 # Get current a0
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A0(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x0,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a1:
- mov.l EXC_A1(%a6),%d0 # Get current a1
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A1(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x1,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a2:
- mov.l EXC_A2(%a6),%d0 # Get current a2
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A2(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x2,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a3:
- mov.l EXC_A3(%a6),%d0 # Get current a3
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A3(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x3,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a4:
- mov.l EXC_A4(%a6),%d0 # Get current a4
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A4(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x4,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a5:
- mov.l EXC_A5(%a6),%d0 # Get current a5
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A5(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x5,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a6:
- mov.l EXC_A6(%a6),%d0 # Get current a6
- mov.l %d0,EXC_SAVVAL(%a6) # save in case of access error
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A6(%a6) # Save decr value
- mov.l %d0,%a0
- mov.b &0x6,EXC_SAVREG(%a6) # save regno, too
- mov.b &restore_flg,SPCOND_FLG(%a6) # set flag
- rts
- addr_ind_m_a7:
- mov.b &mda7_flg,SPCOND_FLG(%a6) # set "special case" flag
- mov.l EXC_A7(%a6),%d0 # Get current a7
- sub.l %a0,%d0 # Decrement
- mov.l %d0,EXC_A7(%a6) # Save decr value
- mov.l %d0,%a0
- rts
- ########################################################
- # Address register indirect w/ displacement: (d16, An) #
- ########################################################
- addr_ind_disp_a0:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A0(%a6),%a0 # a0 + d16
- rts
- addr_ind_disp_a1:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A1(%a6),%a0 # a1 + d16
- rts
- addr_ind_disp_a2:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A2(%a6),%a0 # a2 + d16
- rts
- addr_ind_disp_a3:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A3(%a6),%a0 # a3 + d16
- rts
- addr_ind_disp_a4:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A4(%a6),%a0 # a4 + d16
- rts
- addr_ind_disp_a5:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A5(%a6),%a0 # a5 + d16
- rts
- addr_ind_disp_a6:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A6(%a6),%a0 # a6 + d16
- rts
- addr_ind_disp_a7:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_A7(%a6),%a0 # a7 + d16
- rts
- ########################################################################
- # Address register indirect w/ index(8-bit displacement): (dn, An, Xn) #
- # " " " w/ " (base displacement): (bd, An, Xn) #
- # Memory indirect postindexed: ([bd, An], Xn, od) #
- # Memory indirect preindexed: ([bd, An, Xn], od) #
- ########################################################################
- _addr_ind_ext:
- mov.l %d1,-(%sp)
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word # fetch extword in d0
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.l (%sp)+,%d1
- mov.l (EXC_AREGS,%a6,%d1.w*4),%a0 # put base in a0
- btst &0x8,%d0
- beq.b addr_ind_index_8bit # for ext word or not?
- movm.l &0x3c00,-(%sp) # save d2-d5
- mov.l %d0,%d5 # put extword in d5
- mov.l %a0,%d3 # put base in d3
- bra.l calc_mem_ind # calc memory indirect
- addr_ind_index_8bit:
- mov.l %d2,-(%sp) # save old d2
- mov.l %d0,%d1
- rol.w &0x4,%d1
- andi.w &0xf,%d1 # extract index regno
- mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
- btst &0xb,%d0 # is it word or long?
- bne.b aii8_long
- ext.l %d1 # sign extend word index
- aii8_long:
- mov.l %d0,%d2
- rol.w &0x7,%d2
- andi.l &0x3,%d2 # extract scale value
- lsl.l %d2,%d1 # shift index by scale
- extb.l %d0 # sign extend displacement
- add.l %d1,%d0 # index + disp
- add.l %d0,%a0 # An + (index + disp)
- mov.l (%sp)+,%d2 # restore old d2
- rts
- ######################
- # Immediate: #<data> #
- #########################################################################
- # word, long: <ea> of the data is the current extension word #
- # pointer value. new extension word pointer is simply the old #
- # plus the number of bytes in the data type(2 or 4). #
- #########################################################################
- immediate:
- mov.b &immed_flg,SPCOND_FLG(%a6) # set immediate flag
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch extension word ptr
- rts
- ###########################
- # Absolute short: (XXX).W #
- ###########################
- abs_short:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word # fetch short address
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # return <ea> in a0
- rts
- ##########################
- # Absolute long: (XXX).L #
- ##########################
- abs_long:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_long # fetch long address
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.l %d0,%a0 # return <ea> in a0
- rts
- #######################################################
- # Program counter indirect w/ displacement: (d16, PC) #
- #######################################################
- pc_ind:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word # fetch word displacement
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.w %d0,%a0 # sign extend displacement
- add.l EXC_EXTWPTR(%a6),%a0 # pc + d16
- # _imem_read_word() increased the extwptr by 2. need to adjust here.
- subq.l &0x2,%a0 # adjust <ea>
- rts
- ##########################################################
- # PC indirect w/ index(8-bit displacement): (d8, PC, An) #
- # " " w/ " (base displacement): (bd, PC, An) #
- # PC memory indirect postindexed: ([bd, PC], Xn, od) #
- # PC memory indirect preindexed: ([bd, PC, Xn], od) #
- ##########################################################
- pc_ind_ext:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word # fetch ext word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.l EXC_EXTWPTR(%a6),%a0 # put base in a0
- subq.l &0x2,%a0 # adjust base
- btst &0x8,%d0 # is disp only 8 bits?
- beq.b pc_ind_index_8bit # yes
- # the indexed addressing mode uses a base displacement of size
- # word or long
- movm.l &0x3c00,-(%sp) # save d2-d5
- mov.l %d0,%d5 # put extword in d5
- mov.l %a0,%d3 # put base in d3
- bra.l calc_mem_ind # calc memory indirect
- pc_ind_index_8bit:
- mov.l %d2,-(%sp) # create a temp register
- mov.l %d0,%d1 # make extword copy
- rol.w &0x4,%d1 # rotate reg num into place
- andi.w &0xf,%d1 # extract register number
- mov.l (EXC_DREGS,%a6,%d1.w*4),%d1 # fetch index reg value
- btst &0xb,%d0 # is index word or long?
- bne.b pii8_long # long
- ext.l %d1 # sign extend word index
- pii8_long:
- mov.l %d0,%d2 # make extword copy
- rol.w &0x7,%d2 # rotate scale value into place
- andi.l &0x3,%d2 # extract scale value
- lsl.l %d2,%d1 # shift index by scale
- extb.l %d0 # sign extend displacement
- add.l %d1,%d0 # index + disp
- add.l %d0,%a0 # An + (index + disp)
- mov.l (%sp)+,%d2 # restore temp register
- rts
- # a5 = exc_extwptr (global to uaeh)
- # a4 = exc_opword (global to uaeh)
- # a3 = exc_dregs (global to uaeh)
- # d2 = index (internal " " )
- # d3 = base (internal " " )
- # d4 = od (internal " " )
- # d5 = extword (internal " " )
- calc_mem_ind:
- btst &0x6,%d5 # is the index suppressed?
- beq.b calc_index
- clr.l %d2 # yes, so index = 0
- bra.b base_supp_ck
- calc_index:
- bfextu %d5{&16:&4},%d2
- mov.l (EXC_DREGS,%a6,%d2.w*4),%d2
- btst &0xb,%d5 # is index word or long?
- bne.b no_ext
- ext.l %d2
- no_ext:
- bfextu %d5{&21:&2},%d0
- lsl.l %d0,%d2
- base_supp_ck:
- btst &0x7,%d5 # is the bd suppressed?
- beq.b no_base_sup
- clr.l %d3
- no_base_sup:
- bfextu %d5{&26:&2},%d0 # get bd size
- # beq.l _error # if (size == 0) it's reserved
- cmpi.b %d0,&2
- blt.b no_bd
- beq.b get_word_bd
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_long
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- bra.b chk_ind
- get_word_bd:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- ext.l %d0 # sign extend bd
- chk_ind:
- add.l %d0,%d3 # base += bd
- no_bd:
- bfextu %d5{&30:&2},%d0 # is od suppressed?
- beq.w aii_bd
- cmpi.b %d0,&0x2
- blt.b null_od
- beq.b word_od
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x4,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_long
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- bra.b add_them
- word_od:
- mov.l EXC_EXTWPTR(%a6),%a0 # fetch instruction addr
- addq.l &0x2,EXC_EXTWPTR(%a6) # incr instruction ptr
- bsr.l _imem_read_word
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- ext.l %d0 # sign extend od
- bra.b add_them
- null_od:
- clr.l %d0
- add_them:
- mov.l %d0,%d4
- btst &0x2,%d5 # pre or post indexing?
- beq.b pre_indexed
- mov.l %d3,%a0
- bsr.l _dmem_read_long
- tst.l %d1 # dfetch error?
- bne.b calc_ea_err # yes
- add.l %d2,%d0 # <ea> += index
- add.l %d4,%d0 # <ea> += od
- bra.b done_ea
- pre_indexed:
- add.l %d2,%d3 # preindexing
- mov.l %d3,%a0
- bsr.l _dmem_read_long
- tst.l %d1 # ifetch error?
- bne.b calc_ea_err # yes
- add.l %d4,%d0 # ea += od
- bra.b done_ea
- aii_bd:
- add.l %d2,%d3 # ea = (base + bd) + index
- mov.l %d3,%d0
- done_ea:
- mov.l %d0,%a0
- movm.l (%sp)+,&0x003c # restore d2-d5
- rts
- # if dmem_read_long() returns a fail message in d1, the package
- # must create an access error frame. here, we pass a skeleton fslw
- # and the failing address to the routine that creates the new frame.
- # FSLW:
- # read = true
- # size = longword
- # TM = data
- # software emulation error = true
- calc_ea_err:
- mov.l %d3,%a0 # pass failing address
- mov.l &0x01010001,%d0 # pass fslw
- bra.l isp_dacc
- #########################################################################
- # XDEF **************************************************************** #
- # _moveperipheral(): routine to emulate movep instruction #
- # #
- # XREF **************************************************************** #
- # _dmem_read_byte() - read byte from memory #
- # _dmem_write_byte() - write byte to memory #
- # isp_dacc() - handle data access error exception #
- # #
- # INPUT *************************************************************** #
- # none #
- # #
- # OUTPUT ************************************************************** #
- # If exiting through isp_dacc... #
- # a0 = failing address #
- # d0 = FSLW #
- # else #
- # none #
- # #
- # ALGORITHM *********************************************************** #
- # Decode the movep instruction words stored at EXC_OPWORD and #
- # either read or write the required bytes from/to memory. Use the #
- # _dmem_{read,write}_byte() routines. If one of the memory routines #
- # returns a failing value, we must pass the failing address and a FSLW #
- # to the _isp_dacc() routine. #
- # Since this instruction is used to access peripherals, make sure #
- # to only access the required bytes. #
- # #
- #########################################################################
- ###########################
- # movep.(w,l) Dx,(d,Ay) #
- # movep.(w,l) (d,Ay),Dx #
- ###########################
- global _moveperipheral
- _moveperipheral:
- mov.w EXC_OPWORD(%a6),%d1 # fetch the opcode word
- mov.b %d1,%d0
- and.w &0x7,%d0 # extract Ay from opcode word
- mov.l (EXC_AREGS,%a6,%d0.w*4),%a0 # fetch ay
- add.w EXC_EXTWORD(%a6),%a0 # add: an + sgn_ext(disp)
- btst &0x7,%d1 # (reg 2 mem) or (mem 2 reg)
- beq.w mem2reg
- # reg2mem: fetch dx, then write it to memory
- reg2mem:
- mov.w %d1,%d0
- rol.w &0x7,%d0
- and.w &0x7,%d0 # extract Dx from opcode word
- mov.l (EXC_DREGS,%a6,%d0.w*4), %d0 # fetch dx
- btst &0x6,%d1 # word or long operation?
- beq.b r2mwtrans
- # a0 = dst addr
- # d0 = Dx
- r2mltrans:
- mov.l %d0,%d2 # store data
- mov.l %a0,%a2 # store addr
- rol.l &0x8,%d2
- mov.l %d2,%d0
- bsr.l _dmem_write_byte # os : write hi
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- add.w &0x2,%a2 # incr addr
- mov.l %a2,%a0
- rol.l &0x8,%d2
- mov.l %d2,%d0
- bsr.l _dmem_write_byte # os : write lo
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- add.w &0x2,%a2 # incr addr
- mov.l %a2,%a0
- rol.l &0x8,%d2
- mov.l %d2,%d0
- bsr.l _dmem_write_byte # os : write lo
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- add.w &0x2,%a2 # incr addr
- mov.l %a2,%a0
- rol.l &0x8,%d2
- mov.l %d2,%d0
- bsr.l _dmem_write_byte # os : write lo
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- rts
- # a0 = dst addr
- # d0 = Dx
- r2mwtrans:
- mov.l %d0,%d2 # store data
- mov.l %a0,%a2 # store addr
- lsr.w &0x8,%d0
- bsr.l _dmem_write_byte # os : write hi
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- add.w &0x2,%a2
- mov.l %a2,%a0
- mov.l %d2,%d0
- bsr.l _dmem_write_byte # os : write lo
- tst.l %d1 # dfetch error?
- bne.w movp_write_err # yes
- rts
- # mem2reg: read bytes from memory.
- # determines the dest register, and then writes the bytes into it.
- mem2reg:
- btst &0x6,%d1 # word or long operation?
- beq.b m2rwtrans
- # a0 = dst addr
- m2rltrans:
- mov.l %a0,%a2 # store addr
- bsr.l _dmem_read_byte # read first byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- mov.l %d0,%d2
- add.w &0x2,%a2 # incr addr by 2 bytes
- mov.l %a2,%a0
- bsr.l _dmem_read_byte # read second byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- lsl.w &0x8,%d2
- mov.b %d0,%d2 # append bytes
- add.w &0x2,%a2 # incr addr by 2 bytes
- mov.l %a2,%a0
- bsr.l _dmem_read_byte # read second byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- lsl.l &0x8,%d2
- mov.b %d0,%d2 # append bytes
- add.w &0x2,%a2 # incr addr by 2 bytes
- mov.l %a2,%a0
- bsr.l _dmem_read_byte # read second byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- lsl.l &0x8,%d2
- mov.b %d0,%d2 # append bytes
- mov.b EXC_OPWORD(%a6),%d1
- lsr.b &0x1,%d1
- and.w &0x7,%d1 # extract Dx from opcode word
- mov.l %d2,(EXC_DREGS,%a6,%d1.w*4) # store dx
- rts
- # a0 = dst addr
- m2rwtrans:
- mov.l %a0,%a2 # store addr
- bsr.l _dmem_read_byte # read first byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- mov.l %d0,%d2
- add.w &0x2,%a2 # incr addr by 2 bytes
- mov.l %a2,%a0
- bsr.l _dmem_read_byte # read second byte
- tst.l %d1 # dfetch error?
- bne.w movp_read_err # yes
- lsl.w &0x8,%d2
- mov.b %d0,%d2 # append bytes
- mov.b EXC_OPWORD(%a6),%d1
- lsr.b &0x1,%d1
- and.w &0x7,%d1 # extract Dx from opcode word
- mov.w %d2,(EXC_DREGS+2,%a6,%d1.w*4) # store dx
- rts
- # if dmem_{read,write}_byte() returns a fail message in d1, the package
- # must create an access error frame. here, we pass a skeleton fslw
- # and the failing address to the routine that creates the new frame.
- # FSLW:
- # write = true
- # size = byte
- # TM = data
- # software emulation error = true
- movp_write_err:
- mov.l %a2,%a0 # pass failing address
- mov.l &0x00a10001,%d0 # pass fslw
- bra.l isp_dacc
- # FSLW:
- # read = true
- # size = byte
- # TM = data
- # software emulation error = true
- movp_read_err:
- mov.l %a2,%a0 # pass failing address
- mov.l &0x01210001,%d0 # pass fslw
- bra.l isp_dacc
- #########################################################################
- # XDEF **************************************************************** #
- # _chk2_cmp2(): routine to emulate chk2/cmp2 instructions #
- # #
- # XREF **************************************************************** #
- # _calc_ea(): calculate effective address #
- # _dmem_read_long(): read operands #
- # _dmem_read_word(): read operands #
- # isp_dacc(): handle data access error exception #
- # #
- # INPUT *************************************************************** #
- # none #
- # #
- # OUTPUT ************************************************************** #
- # If exiting through isp_dacc... #
- # a0 = failing address #
- # d0 = FSLW #
- # else #
- # none #
- # #
- # ALGORITHM *********************************************************** #
- # First, calculate the effective address, then fetch the byte, #
- # word, or longword sized operands. Then, in the interest of #
- # simplicity, all operands are converted to longword size whether the #
- # operation is byte, word, or long. The bounds are sign extended #
- # accordingly. If Rn is a data regsiter, Rn is also sign extended. If #
- # Rn is an address register, it need not be sign extended since the #
- # full register is always used. #
- # The comparisons are made and the condition codes calculated. #
- # If the instruction is chk2 and the Rn value is out-of-bounds, set #
- # the ichk_flg in SPCOND_FLG. #
- # If the memory fetch returns a failing value, pass the failing #
- # address and FSLW to the isp_dacc() routine. #
- # #
- #########################################################################
- global _chk2_cmp2
- _chk2_cmp2:
- # passing size parameter doesn't matter since chk2 & cmp2 can't do
- # either predecrement, postincrement, or immediate.
- bsr.l _calc_ea # calculate <ea>
- mov.b EXC_EXTWORD(%a6), %d0 # fetch hi extension word
- rol.b &0x4, %d0 # rotate reg bits into lo
- and.w &0xf, %d0 # extract reg bits
- mov.l (EXC_DREGS,%a6,%d0.w*4), %d2 # get regval
- cmpi.b EXC_OPWORD(%a6), &0x2 # what size is operation?
- blt.b chk2_cmp2_byte # size == byte
- beq.b chk2_cmp2_word # size == word
- # the bounds are longword size. call routine to read the lower
- # bound into d0 and the higher bound into d1.
- chk2_cmp2_long:
- mov.l %a0,%a2 # save copy of <ea>
- bsr.l _dmem_read_long # fetch long lower bound
- tst.l %d1 # dfetch error?
- bne.w chk2_cmp2_err_l # yes
- mov.l %d0,%d3 # save long lower bound
- addq.l &0x4,%a2
- mov.l %a2,%a0 # pass <ea> of long upper bound
- bsr.l _dmem_read_long # fetch long upper bound
- tst.l %d1 # dfetch error?
- bne.w chk2_cmp2_err_l # yes
- mov.l %d0,%d1 # long upper bound in d1
- mov.l %d3,%d0 # long lower bound in d0
- bra.w chk2_cmp2_compare # go do the compare emulation
- # the bounds are word size. fetch them in one subroutine call by
- # reading a longword. sign extend both. if it's a data operation,
- # sign extend Rn to long, also.
- chk2_cmp2_word:
- mov.l %a0,%a2
- bsr.l _dmem_read_long # fetch 2 word bounds
- tst.l %d1 # dfetch error?
- bne.w chk2_cmp2_err_l # yes
- mov.w %d0, %d1 # place hi in %d1
- swap %d0 # place lo in %d0
- ext.l %d0 # sign extend lo bnd
- ext.l %d1 # sign extend hi bnd
- btst &0x7, EXC_EXTWORD(%a6) # address compare?
- bne.w chk2_cmp2_compare # yes; don't sign extend
- # operation is a data register compare.
- # sign extend word to long so we can do simple longword compares.
- ext.l %d2 # sign extend data word
- bra.w chk2_cmp2_compare # go emulate compare
- # the bounds are byte size. fetch them in one subroutine call by
- # reading a word. sign extend both. if it's a data operation,
- # sign extend Rn to long, also.
- chk2_cmp2_byte:
- mov.l %a0,%a2
- bsr.l _dmem_read_word # fetch 2 byte bounds
- tst.l %d1 # dfetch error?
- bne.w chk2_cmp2_err_w # yes
- mov.b %d0, %d1 # place hi in %d1
- lsr.w &0x8, %d0 # place lo in %d0
- extb.l %d0 # sign extend lo bnd
- extb.l %d1 # sign extend hi bnd
- btst &0x7, EXC_EXTWORD(%a6) # address compare?
- bne.b chk2_cmp2_compare # yes; don't sign extend
- # operation is a data register compare.
- # sign extend byte to long so we can do simple longword compares.
- extb.l %d2 # sign extend data byte
- #
- # To set the ccodes correctly:
- # (1) save 'Z' bit from (Rn - lo)
- # (2) save 'Z' and 'N' bits from ((hi - lo) - (Rn - hi))
- # (3) keep 'X', 'N', and 'V' from before instruction
- # (4) combine ccodes
- #
- chk2_cmp2_compare:
- sub.l %d0, %d2 # (Rn - lo)
- mov.w %cc, %d3 # fetch resulting ccodes
- andi.b &0x4, %d3 # keep 'Z' bit
- sub.l %d0, %d1 # (hi - lo)
- cmp.l %d1,%d2 # ((hi - lo) - (Rn - hi))
- mov.w %cc, %d4 # fetch resulting ccodes
- or.b %d4, %d3 # combine w/ earlier ccodes
- andi.b &0x5, %d3 # keep 'Z' and 'N'
- mov.w EXC_CC(%a6), %d4 # fetch old ccodes
- andi.b &0x1a, %d4 # keep 'X','N','V' bits
- or.b %d3, %d4 # insert new ccodes
- mov.w %d4, EXC_CC(%a6) # save new ccodes
- btst &0x3, EXC_EXTWORD(%a6) # separate chk2,cmp2
- bne.b chk2_finish # it's a chk2
- rts
- # this code handles the only difference between chk2 and cmp2. chk2 would
- # have trapped out if the value was out of bounds. we check this by seeing
- # if the 'N' bit was set by the operation.
- chk2_finish:
- btst &0x0, %d4 # is 'N' bit set?
- bne.b chk2_trap # yes;chk2 should trap
- rts
- chk2_trap:
- mov.b &ichk_flg,SPCOND_FLG(%a6) # set "special case" flag
- rts
- # if dmem_read_{long,word}() returns a fail message in d1, the package
- # must create an access error frame. here, we pass a skeleton fslw
- # and the failing address to the routine that creates the new frame.
- # FSLW:
- # read = true
- # size = longword
- # TM = data
- # software emulation error = true
- chk2_cmp2_err_l:
- mov.l %a2,%a0 # pass failing address
- mov.l &0x01010001,%d0 # pass fslw
- bra.l isp_dacc
- # FSLW:
- # read = true
- # size = word
- # TM = data
- # software emulation error = true
- chk2_cmp2_err_w:
- mov.l %a2,%a0 # pass failing address
- mov.l &0x01410001,%d0 # pass fslw
- bra.l isp_dacc
- #########################################################################
- # XDEF **************************************************************** #
- # _div64(): routine to emulate div{u,s}.l <ea>,Dr:Dq #
- # 64/32->32r:32q #
- # #
- # XREF **************************************************************** #
- # _calc_ea() - calculate effective address #
- # isp_iacc() - handle instruction access error exception #
- # isp_dacc() - handle data access error exception #
- # isp_restore() - restore An on access error w/ -() or ()+ #
- # #
- # INPUT *************************************************************** #
- # none #
- # #
- # OUTPUT ************************************************************** #
- # If exiting through isp_dacc... #
- # a0 = failing address #
- # d0 = FSLW #
- # else #
- # none #
- # #
- # ALGORITHM *********************************************************** #
- # First, decode the operand location. If it's in Dn, fetch from #
- # the stack. If it's in memory, use _calc_ea() to calculate the #
- # effective address. Use _dmem_read_long() to fetch at that address. #
- # Unless the operand is immediate data. Then use _imem_read_long(). #
- # Send failures to isp_dacc() or isp_iacc() as appropriate. #
- # If the operands are signed, make them unsigned and save the #
- # sign info for later. Separate out special cases like divide-by-zero #
- # or 32-bit divides if possible. Else, use a special math algorithm #
- # to calculate the result. #
- # Restore sign info if signed instruction. Set the condition #
- # codes. Set idbyz_flg in SPCOND_FLG if divisor was zero. Store the #
- # quotient and remainder in the appropriate data registers on the stack.#
- # #
- #########################################################################
- set NDIVISOR, EXC_TEMP+0x0
- set NDIVIDEND, EXC_TEMP+0x1
- set NDRSAVE, EXC_TEMP+0x2
- set NDQSAVE, EXC_TEMP+0x4
- set DDSECOND, EXC_TEMP+0x6
- set DDQUOTIENT, EXC_TEMP+0x8
- set DDNORMAL, EXC_TEMP+0xc
- global _div64
- #############
- # div(u,s)l #
- #############
- _div64:
- mov.b EXC_OPWORD+1(%a6), %d0
- andi.b &0x38, %d0 # extract src mode
- bne.w dcontrolmodel_s # %dn dest or control mode?
- mov.b EXC_OPWORD+1(%a6), %d0 # extract Dn from opcode
- andi.w &0x7, %d0
- mov.l (EXC_DREGS,%a6,%d0.w*4), %d7 # fetch divisor from register
- dgotsrcl:
- beq.w div64eq0 # divisor is = 0!!!
- mov.b EXC_EXTWORD+1(%a6), %d0 # extract Dr from extword
- mov.b EXC_EXTWORD(%a6), %d1 # extract Dq from extword
- and.w &0x7, %d0
- lsr.b &0x4, %d1
- and.w &0x7, %d1
- mov.w %d0, NDRSAVE(%a6) # save Dr for later
- mov.w %d1, NDQSAVE(%a6) # save Dq for later
- # fetch %dr and %dq directly off stack since all regs are saved there
- mov.l (EXC_DREGS,%a6,%d0.w*4), %d5 # get dividend hi
- mov.l (EXC_DREGS,%a6,%d1.w*4), %d6 # get dividend lo
- # separate signed and unsigned divide
- btst &0x3, EXC_EXTWORD(%a6) # signed or unsigned?
- beq.b dspecialcases # use positive divide
- # save the sign of the divisor
- # make divisor unsigned if it's negative
- tst.l %d7 # chk sign of divisor
- slt NDIVISOR(%a6) # save sign of divisor
- bpl.b dsgndividend
- neg.l %d7 # complement negative divisor
- # save the sign of the dividend
- # make dividend unsigned if it's negative
- dsgndividend:
- tst.l %d5 # chk sign of hi(dividend)
- slt NDIVIDEND(%a6) # save sign of dividend
- bpl.b dspecialcases
- mov.w &0x0, %cc # clear 'X' cc bit
- negx.l %d6 # complement signed dividend
- negx.l %d5
- # extract some special cases:
- # - is (dividend == 0) ?
- # - is (hi(dividend) == 0 && (divisor <= lo(dividend))) ? (32-bit div)
- dspecialcases:
- tst.l %d5 # is (hi(dividend) == 0)
- bne.b dnormaldivide # no, so try it the long way
- tst.l %d6 # is (lo(dividend) == 0), too
- beq.w ddone # yes, so (dividend == 0)
- cmp.l %d7,%d6 # is (divisor <= lo(dividend))
- bls.b d32bitdivide # yes, so use 32 bit divide
- exg %d5,%d6 # q = 0, r = dividend
- bra.w divfinish # can't divide, we're done.
- d32bitdivide:
- tdivu.l %d7, %d5:%d6 # it's only a 32/32 bit div!
- bra.b divfinish
- dnormaldivide:
- # last special case:
- # - is hi(dividend) >= divisor ? if yes, then overflow
- cmp.l %d7,%d5
- bls.b ddovf # answer won't fit in 32 bits
- # perform the divide algorithm:
- bsr.l dclassical # do int divide
- # separate into signed and unsigned finishes.
- divfinish:
- btst &0x3, EXC_EXTWORD(%a6) # do divs, divu separately
- beq.b ddone # divu has no processing!!!
- # it was a divs.l, so ccode setting is a little more complicated...
- tst.b NDIVIDEND(%a6) # remainder has same sign
- beq.b dcc # as dividend.
- neg.l %d5 # sgn(rem) = sgn(dividend)
- dcc:
- mov.b NDIVISOR(%a6), %d0
- eor.b %d0, NDIVIDEND(%a6) # chk if quotient is negative
- beq.b dqpos # branch to quot positive
- # 0x80000000 is the largest number representable as a 32-bit negative
- # number. the negative of 0x80000000 is 0x80000000.
- cmpi.l %d6, &0x80000000 # will (-quot) fit in 32 bits?
- bhi.b ddovf
- neg.l %d6 # make (-quot) 2's comp
- bra.b ddone
- dqpos:
- btst &0x1f, %d6 # will (+quot) fit in 32 bits?
- bne.b ddovf
- ddone:
- # at this point, result is normal so ccodes are set based on result.
- mov.w EXC_CC(%a6), %cc
- tst.l %d6 # set %ccode bits
- mov.w %cc, EXC_CC(%a6)
- mov.w NDRSAVE(%a6), %d0 # get Dr off stack
- mov.w NDQSAVE(%a6), %d1 # get Dq off stack
- # if the register numbers are the same, only the quotient gets saved.
- # so, if we always save the quotient second, we save ourselves a cmp&beq
- mov.l %d5, (EXC_DREGS,%a6,%d0.w*4) # save remainder
- mov.l %d6, (EXC_DREGS,%a6,%d1.w*4) # save quotient
- rts
- ddovf:
- bset &0x1, EXC_CC+1(%a6) # 'V' set on overflow
- bclr &0x0, EXC_CC+1(%a6) # 'C' cleared on overflow
- rts
- div64eq0:
- andi.b &0x1e, EXC_CC+1(%a6) # clear 'C' bit on divbyzero
- ori.b &idbyz_flg,SPCOND_FLG(%a6) # set "special case" flag
- rts
- ###########################################################################
- #########################################################################
- # This routine uses the 'classical' Algorithm D from Donald Knuth's #
- # Art of Computer Programming, vol II, Seminumerical Algorithms. #
- # For this implementation b=2**16, and the target is U1U2U3U4/V1V2, #
- # where U,V are words of the quadword dividend and longword divisor, #
- # and U1, V1 are the most significant words. #
- # #
- # The most sig. longword of the 64 bit dividend must be in %d5, least #
- # in %d6. The divisor must be in the variable ddivisor, and the #
- # signed/unsigned flag ddusign must be set (0=unsigned,1=signed). #
- # The quotient is returned in %d6, remainder in %d5, unless the #
- # v (overflow) bit is set in the saved %ccr. If overflow, the dividend #
- # is unchanged. #
- #########################################################################
- dclassical:
- # if the divisor msw is 0, use simpler algorithm then the full blown
- # one at ddknuth:
- cmpi.l %d7, &0xffff
- bhi.b ddknuth # go use D. Knuth algorithm
- # Since the divisor is only a word (and larger than the mslw of the dividend),
- # a simpler algorithm may be used :
- # In the general case, four quotient words would be created by
- # dividing the divisor word into each dividend word. In this case,
- # the first two quotient words must be zero, or overflow would occur.
- # Since we already checked this case above, we can treat the most significant
- # longword of the dividend as (0) remainder (see Knuth) and merely complete
- # the last two divisions to get a quotient longword and word remainder:
- clr.l %d1
- swap %d5 # same as r*b if previous step rqd
- swap %d6 # get u3 to lsw position
- mov.w %d6, %d5 # rb + u3
- divu.w %d7, %d5
- mov.w %d5, %d1 # first quotient word
- swap %d6 # get u4
- mov.w %d6, %d5 # rb + u4
- divu.w %d7, %d5
- swap %d1
- mov.w %d5, %d1 # 2nd quotient 'digit'
- clr.w %d5
- swap %d5 # now remainder
- mov.l %d1, %d6 # and quotient
- rts
- ddknuth:
- # In this algorithm, the divisor is treated as a 2 digit (word) number
- # which is divided into a 3 digit (word) dividend to get one quotient
- # digit (word). After subtraction, the dividend is shifted and the
- # process repeated. Before beginning, the divisor and quotient are
- # 'normalized' so that the process of estimating the quotient digit
- # will yield verifiably correct results..
- clr.l DDNORMAL(%a6) # count of shifts for normalization
- clr.b DDSECOND(%a6) # clear flag for quotient digits
- clr.l %d1 # %d1 will hold trial quotient
- ddnchk:
- btst &31, %d7 # must we normalize? first word of
- bne.b ddnormalized # divisor (V1) must be >= 65536/2
- addq.l &0x1, DDNORMAL(%a6) # count normalization shifts
- lsl.l &0x1, %d7 # shift the divisor
- lsl.l &0x1, %d6 # shift u4,u3 with overflow to u2
- roxl.l &0x1, %d5 # shift u1,u2
- bra.w ddnchk
- ddnormalized:
- # Now calculate an estimate of the quotient words (msw first, then lsw).
- # The comments use subscripts for the first quotient digit determination.
- mov.l %d7, %d3 # divisor
- mov.l %d5, %d2 # dividend mslw
- swap %d2
- swap %d3
- cmp.w %d2, %d3 # V1 = U1 ?
- bne.b ddqcalc1
- mov.w &0xffff, %d1 # use max trial quotient word
- bra.b ddadj0
- ddqcalc1:
- mov.l %d5, %d1
- divu.w %d3, %d1 # use quotient of mslw/msw
- andi.l &0x0000ffff, %d1 # zero any remainder
- ddadj0:
- # now test the trial quotient and adjust. This step plus the
- # normalization assures (according to Knuth) that the trial
- # quotient will be at worst 1 too large.
- mov.l %d6, -(%sp)
- clr.w %d6 # word u3 left
- swap %d6 # in lsw position
- ddadj1: mov.l %d7, %d3
- mov.l %d1, %d2
- mulu.w %d7, %d2 # V2q
- swap %d3
- mulu.w %d1, %d3 # V1q
- mov.l %d5, %d4 # U1U2
- sub.l %d3, %d4 # U1U2 - V1q
- swap %d4
- mov.w %d4,%d0
- mov.w %d6,%d4 # insert lower word (U3)
- tst.w %d0 # is upper word set?
- bne.w ddadjd1
- # add.l %d6, %d4 # (U1U2 - V1q) + U3
- cmp.l %d2, %d4
- bls.b ddadjd1 # is V2q > (U1U2-V1q) + U3 ?
- subq.l &0x1, %d1 # yes, decrement and recheck
- bra.b ddadj1
- ddadjd1:
- # now test the word by multiplying it by the divisor (V1V2) and comparing
- # the 3 digit (word) result with the current dividend words
- mov.l %d5, -(%sp) # save %d5 (%d6 already saved)
- mov.l %d1, %d6
- swap %d6 # shift answer to ms 3 words
- mov.l %d7, %d5
- bsr.l dmm2
- mov.l %d5, %d2 # now %d2,%d3 are trial*divisor
- mov.l %d6, %d3
- mov.l (%sp)+, %d5 # restore dividend
- mov.l (%sp)+, %d6
- sub.l %d3, %d6
- subx.l %d2, %d5 # subtract double precision
- bcc dd2nd # no carry, do next quotient digit
- subq.l &0x1, %d1 # q is one too large
- # need to add back divisor longword to current ms 3 digits of dividend
- # - according to Knuth, this is done only 2 out of 65536 times for random
- # divisor, dividend selection.
- clr.l %d2
- mov.l %d7, %d3
- swap %d3
- clr.w %d3 # %d3 now ls word of divisor
- add.l %d3, %d6 # aligned with 3rd word of dividend
- addx.l %d2, %d5
- mov.l %d7, %d3
- clr.w %d3 # %d3 now ms word of divisor
- swap %d3 # aligned with 2nd word of dividend
- add.l %d3, %d5
- dd2nd:
- tst.b DDSECOND(%a6) # both q words done?
- bne.b ddremain
- # first quotient digit now correct. store digit and shift the
- # (subtracted) dividend
- mov.w %d1, DDQUOTIENT(%a6)
- clr.l %d1
- swap %d5
- swap %d6
- mov.w %d6, %d5
- clr.w %d6
- st DDSECOND(%a6) # second digit
- bra.w ddnormalized
- ddremain:
- # add 2nd word to quotient, get the remainder.
- mov.w %d1, DDQUOTIENT+2(%a6)
- # shift down one word/digit to renormalize remainder.
- mov.w %d5, %d6
- swap %d6
- swap %d5
- mov.l DDNORMAL(%a6), %d7 # get norm shift count
- beq.b ddrn
- subq.l &0x1, %d7 # set for loop count
- ddnlp:
- lsr.l &0x1, %d5 # shift into %d6
- roxr.l &0x1, %d6
- dbf %d7, ddnlp
- ddrn:
- mov.l %d6, %d5 # remainder
- mov.l DDQUOTIENT(%a6), %d6 # quotient
- rts
- dmm2:
- # factors for the 32X32->64 multiplication are in %d5 and %d6.
- # returns 64 bit result in %d5 (hi) %d6(lo).
- # destroys %d2,%d3,%d4.
- # multiply hi,lo words of each factor to get 4 intermediate products
- mov.l %d6, %d2
- mov.l %d6, %d3
- mov.l %d5, %d4
- swap %d3
- swap %d4
- mulu.w %d5, %d6 # %d6 <- lsw*lsw
- mulu.w %d3, %d5 # %d5 <- msw-dest*lsw-source
- mulu.w %d4, %d2 # %d2 <- msw-source*lsw-dest
- mulu.w %d4, %d3 # %d3 <- msw*msw
- # now use swap and addx to consolidate to two longwords
- clr.l %d4
- swap %d6
- add.w %d5, %d6 # add msw of l*l to lsw of m*l product
- addx.w %d4, %d3 # add any carry to m*m product
- add.w %d2, %d6 # add in lsw of other m*l product
- addx.w %d4, %d3 # add any carry to m*m product
- swap %d6 # %d6 is low 32 bits of final product
- clr.w %d5
- clr.w %d2 # lsw of two mixed products used,
- swap %d5 # now use msws of longwords
- swap %d2
- add.l %d2, %d5
- add.l %d3, %d5 # %d5 now ms 32 bits of final product
- rts
- ##########
- dcontrolmodel_s:
- movq.l &LONG,%d0
- bsr.l _calc_ea # calc <ea>
- cmpi.b SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?
- beq.b dimmed # yes
- mov.l %a0,%a2
- bsr.l _dmem_read_long # fetch divisor from <ea>
- tst.l %d1 # dfetch error?
- bne.b div64_err # yes
- mov.l %d0, %d7
- bra.w dgotsrcl
- # we have to split out immediate data here because it must be read using
- # imem_read() instead of dmem_read(). this becomes especially important
- # if the fetch runs into some deadly fault.
- dimmed:
- addq.l &0x4,EXC_EXTWPTR(%a6)
- bsr.l _imem_read_long # read immediate value
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.l %d0,%d7
- bra.w dgotsrcl
- ##########
- # if dmem_read_long() returns a fail message in d1, the package
- # must create an access error frame. here, we pass a skeleton fslw
- # and the failing address to the routine that creates the new frame.
- # also, we call isp_restore in case the effective addressing mode was
- # (an)+ or -(an) in which case the previous "an" value must be restored.
- # FSLW:
- # read = true
- # size = longword
- # TM = data
- # software emulation error = true
- div64_err:
- bsr.l isp_restore # restore addr reg
- mov.l %a2,%a0 # pass failing address
- mov.l &0x01010001,%d0 # pass fslw
- bra.l isp_dacc
- #########################################################################
- # XDEF **************************************************************** #
- # _mul64(): routine to emulate mul{u,s}.l <ea>,Dh:Dl 32x32->64 #
- # #
- # XREF **************************************************************** #
- # _calc_ea() - calculate effective address #
- # isp_iacc() - handle instruction access error exception #
- # isp_dacc() - handle data access error exception #
- # isp_restore() - restore An on access error w/ -() or ()+ #
- # #
- # INPUT *************************************************************** #
- # none #
- # #
- # OUTPUT ************************************************************** #
- # If exiting through isp_dacc... #
- # a0 = failing address #
- # d0 = FSLW #
- # else #
- # none #
- # #
- # ALGORITHM *********************************************************** #
- # First, decode the operand location. If it's in Dn, fetch from #
- # the stack. If it's in memory, use _calc_ea() to calculate the #
- # effective address. Use _dmem_read_long() to fetch at that address. #
- # Unless the operand is immediate data. Then use _imem_read_long(). #
- # Send failures to isp_dacc() or isp_iacc() as appropriate. #
- # If the operands are signed, make them unsigned and save the #
- # sign info for later. Perform the multiplication using 16x16->32 #
- # unsigned multiplies and "add" instructions. Store the high and low #
- # portions of the result in the appropriate data registers on the #
- # stack. Calculate the condition codes, also. #
- # #
- #########################################################################
- #############
- # mul(u,s)l #
- #############
- global _mul64
- _mul64:
- mov.b EXC_OPWORD+1(%a6), %d0 # extract src {mode,reg}
- cmpi.b %d0, &0x7 # is src mode Dn or other?
- bgt.w mul64_memop # src is in memory
- # multiplier operand in the data register file.
- # must extract the register number and fetch the operand from the stack.
- mul64_regop:
- andi.w &0x7, %d0 # extract Dn
- mov.l (EXC_DREGS,%a6,%d0.w*4), %d3 # fetch multiplier
- # multiplier is in %d3. now, extract Dl and Dh fields and fetch the
- # multiplicand from the data register specified by Dl.
- mul64_multiplicand:
- mov.w EXC_EXTWORD(%a6), %d2 # fetch ext word
- clr.w %d1 # clear Dh reg
- mov.b %d2, %d1 # grab Dh
- rol.w &0x4, %d2 # align Dl byte
- andi.w &0x7, %d2 # extract Dl
- mov.l (EXC_DREGS,%a6,%d2.w*4), %d4 # get multiplicand
- # check for the case of "zero" result early
- tst.l %d4 # test multiplicand
- beq.w mul64_zero # handle zero separately
- tst.l %d3 # test multiplier
- beq.w mul64_zero # handle zero separately
- # multiplier is in %d3 and multiplicand is in %d4.
- # if the operation is to be signed, then the operands are converted
- # to unsigned and the result sign is saved for the end.
- clr.b EXC_TEMP(%a6) # clear temp space
- btst &0x3, EXC_EXTWORD(%a6) # signed or unsigned?
- beq.b mul64_alg # unsigned; skip sgn calc
- tst.l %d3 # is multiplier negative?
- bge.b mul64_chk_md_sgn # no
- neg.l %d3 # make multiplier positive
- ori.b &0x1, EXC_TEMP(%a6) # save multiplier sgn
- # the result sign is the exclusive or of the operand sign bits.
- mul64_chk_md_sgn:
- tst.l %d4 # is multiplicand negative?
- bge.b mul64_alg # no
- neg.l %d4 # make multiplicand positive
- eori.b &0x1, EXC_TEMP(%a6) # calculate correct sign
- #########################################################################
- # 63 32 0 #
- # ---------------------------- #
- # | hi(mplier) * hi(mplicand)| #
- # ---------------------------- #
- # ----------------------------- #
- # | hi(mplier) * lo(mplicand) | #
- # ----------------------------- #
- # ----------------------------- #
- # | lo(mplier) * hi(mplicand) | #
- # ----------------------------- #
- # | ----------------------------- #
- # --|-- | lo(mplier) * lo(mplicand) | #
- # | ----------------------------- #
- # ======================================================== #
- # -------------------------------------------------------- #
- # | hi(result) | lo(result) | #
- # -------------------------------------------------------- #
- #########################################################################
- mul64_alg:
- # load temp registers with operands
- mov.l %d3, %d5 # mr in %d5
- mov.l %d3, %d6 # mr in %d6
- mov.l %d4, %d7 # md in %d7
- swap %d6 # hi(mr) in lo %d6
- swap %d7 # hi(md) in lo %d7
- # complete necessary multiplies:
- mulu.w %d4, %d3 # [1] lo(mr) * lo(md)
- mulu.w %d6, %d4 # [2] hi(mr) * lo(md)
- mulu.w %d7, %d5 # [3] lo(mr) * hi(md)
- mulu.w %d7, %d6 # [4] hi(mr) * hi(md)
- # add lo portions of [2],[3] to hi portion of [1].
- # add carries produced from these adds to [4].
- # lo([1]) is the final lo 16 bits of the result.
- clr.l %d7 # load %d7 w/ zero value
- swap %d3 # hi([1]) <==> lo([1])
- add.w %d4, %d3 # hi([1]) + lo([2])
- addx.l %d7, %d6 # [4] + carry
- add.w %d5, %d3 # hi([1]) + lo([3])
- addx.l %d7, %d6 # [4] + carry
- swap %d3 # lo([1]) <==> hi([1])
- # lo portions of [2],[3] have been added in to final result.
- # now, clear lo, put hi in lo reg, and add to [4]
- clr.w %d4 # clear lo([2])
- clr.w %d5 # clear hi([3])
- swap %d4 # hi([2]) in lo %d4
- swap %d5 # hi([3]) in lo %d5
- add.l %d5, %d4 # [4] + hi([2])
- add.l %d6, %d4 # [4] + hi([3])
- # unsigned result is now in {%d4,%d3}
- tst.b EXC_TEMP(%a6) # should result be signed?
- beq.b mul64_done # no
- # result should be a signed negative number.
- # compute 2's complement of the unsigned number:
- # -negate all bits and add 1
- mul64_neg:
- not.l %d3 # negate lo(result) bits
- not.l %d4 # negate hi(result) bits
- addq.l &1, %d3 # add 1 to lo(result)
- addx.l %d7, %d4 # add carry to hi(result)
- # the result is saved to the register file.
- # for '040 compatibility, if Dl == Dh then only the hi(result) is
- # saved. so, saving hi after lo accomplishes this without need to
- # check Dl,Dh equality.
- mul64_done:
- mov.l %d3, (EXC_DREGS,%a6,%d2.w*4) # save lo(result)
- mov.w &0x0, %cc
- mov.l %d4, (EXC_DREGS,%a6,%d1.w*4) # save hi(result)
- # now, grab the condition codes. only one that can be set is 'N'.
- # 'N' CAN be set if the operation is unsigned if bit 63 is set.
- mov.w %cc, %d7 # fetch %ccr to see if 'N' set
- andi.b &0x8, %d7 # extract 'N' bit
- mul64_ccode_set:
- mov.b EXC_CC+1(%a6), %d6 # fetch previous %ccr
- andi.b &0x10, %d6 # all but 'X' bit changes
- or.b %d7, %d6 # group 'X' and 'N'
- mov.b %d6, EXC_CC+1(%a6) # save new %ccr
- rts
- # one or both of the operands is zero so the result is also zero.
- # save the zero result to the register file and set the 'Z' ccode bit.
- mul64_zero:
- clr.l (EXC_DREGS,%a6,%d2.w*4) # save lo(result)
- clr.l (EXC_DREGS,%a6,%d1.w*4) # save hi(result)
- movq.l &0x4, %d7 # set 'Z' ccode bit
- bra.b mul64_ccode_set # finish ccode set
- ##########
- # multiplier operand is in memory at the effective address.
- # must calculate the <ea> and go fetch the 32-bit operand.
- mul64_memop:
- movq.l &LONG, %d0 # pass # of bytes
- bsr.l _calc_ea # calculate <ea>
- cmpi.b SPCOND_FLG(%a6),&immed_flg # immediate addressing mode?
- beq.b mul64_immed # yes
- mov.l %a0,%a2
- bsr.l _dmem_read_long # fetch src from addr (%a0)
- tst.l %d1 # dfetch error?
- bne.w mul64_err # yes
- mov.l %d0, %d3 # store multiplier in %d3
- bra.w mul64_multiplicand
- # we have to split out immediate data here because it must be read using
- # imem_read() instead of dmem_read(). this becomes especially important
- # if the fetch runs into some deadly fault.
- mul64_immed:
- addq.l &0x4,EXC_EXTWPTR(%a6)
- bsr.l _imem_read_long # read immediate value
- tst.l %d1 # ifetch error?
- bne.l isp_iacc # yes
- mov.l %d0,%d3
- bra.w mul64_multiplicand
- ##########
- # if dmem_read_long() returns a fail message in d1, the package
- # must create an access error frame. here, we pass a skeleton fslw
- # and the failing address to the routine that creates the new frame.
- # also, we call isp_restore in case the effective addressing mode was
- # (an)+ or -(an) in which case the previous "an" value must be restored.
- # FSLW:
- # read = true
- # size = longword
- # TM = data
- # software emulation error = true
- mul64_err:
- bsr.l isp_restore # restore addr reg
- mov.l %a2,%a0 # pass failing address
- mov.l &0x01010001,%d0 # pass fslw
- bra.l isp_dacc
- #########################################################################
- # XDEF **************************************************************** #
- # _compandset2(): routine to emulate cas2() #
- # (internal to package) #
- # #
- # _isp_cas2_finish(): store ccodes, store compare regs #
- # (external to package) #
- # #
- # XREF **************************************************************** #
- # _real_lock_page() - "callout" to lock op's page from page-outs #
- # _cas_terminate2() - access error exit #
- # _real_cas2() - "callout" to core cas2 emulation code #
- # _real_unlock_page() - "callout" to unlock page #
- # #
- # INPUT *************************************************************** #
- # _compandset2(): #
- # d0 = instruction extension word #
- # #
- # _isp_cas2_finish(): #
- # see cas2 core emulation code #
- # #
- # OUTPUT ************************************************************** #
- # _compandset2(): #
- # see cas2 core emulation code #
- # #
- # _isp_cas_finish(): #
- # None (register file or memroy changed as appropriate) #
- # #
- # ALGORITHM *********************************************************** #
- # compandset2(): #
- # Decode the instruction and fetch the appropriate Update and #
- # Compare operands. Then call the "callout" _real_lock_page() for each #
- # memory operand address so that the operating system can keep these #
- # pages from being paged out. If either _real_lock_page() fails, exit #
- # through _cas_terminate2(). Don't forget to unlock the 1st locked page #
- # using _real_unlock_paged() if the 2nd lock-page fails. #
- # Finally, branch to the core cas2 emulation code by calling the #
- # "callout" _real_cas2(). #
- # #
- # _isp_cas2_finish(): #
- # Re-perform the comparison so we can determine the condition #
- # codes which were too much trouble to keep around during the locked #
- # emulation. Then unlock each operands page by calling the "callout" #
- # _real_unlock_page(). #
- # #
- #########################################################################
- set ADDR1, EXC_TEMP+0xc
- set ADDR2, EXC_TEMP+0x0
- set DC2, EXC_TEMP+0xa
- set DC1, EXC_TEMP+0x8
- global _compandset2
- _compandset2:
- mov.l %d0,EXC_TEMP+0x4(%a6) # store for possible restart
- mov.l %d0,%d1 # extension word in d0
- rol.w &0x4,%d0
- andi.w &0xf,%d0 # extract Rn2
- mov.l (EXC_DREGS,%a6,%d0.w*4),%a1 # fetch ADDR2
- mov.l %a1,ADDR2(%a6)
- mov.l %d1,%d0
- lsr.w &0x6,%d1
- andi.w &0x7,%d1 # extract Du2
- mov.l (EXC_DREGS,%a6,%d1.w*4),%d5 # fetch Update2 Op
- andi.w &0x7,%d0 # extract Dc2
- mov.l (EXC_DREGS,%a6,%d0.w*4),%d3 # fetch Compare2 Op
- mov.w %d0,DC2(%a6)
- mov.w EXC_EXTWORD(%a6),%d0
- mov.l %d0,%d1
- rol.w &0x4,%d0
- andi.w &0xf,%d0 # extract Rn1
- mov.l (EXC_DREGS,%a6,%d0.w*4),%a0 # fetch ADDR1
- mov.l %a0,ADDR1(%a6)
- mov.l %d1,%d0
- lsr.w &0x6,%d1
- andi.w &0x7,%d1 # extract Du1
- mov.l (EXC_DREGS,%a6,%d1.w*4),%d4 # fetch Update1 Op
- andi.w &0x7,%d0 # extract Dc1
- mov.l (EXC_DREGS,%a6,%d0.w*4),%d2 # fetch Compare1 Op
- mov.w %d0,DC1(%a6)
- btst &0x1,EXC_OPWORD(%a6) # word or long?
- sne %d7
- btst &0x5,EXC_ISR(%a6) # user or supervisor?
- sne %d6
- mov.l %a0,%a2
- mov.l %a1,%a3
- mov.l %d7,%d1 # pass size
- mov.l %d6,%d0 # pass mode
- bsr.l _real_lock_page # lock page
- mov.l %a2,%a0
- tst.l %d0 # error?
- bne.l _cas_terminate2 # yes
- mov.l %d7,%d1 # pass size
- mov.l %d6,%d0 # pass mode
- mov.l %a3,%a0 # pass addr
- bsr.l _real_lock_page # lock page
- mov.l %a3,%a0
- tst.l %d0 # error?
- bne.b cas_preterm # yes
- mov.l %a2,%a0
- mov.l %a3,%a1
- bra.l _real_cas2
- # if the 2nd lock attempt fails, then we must still unlock the
- # first page(s).
- cas_preterm:
- mov.l %d0,-(%sp) # save FSLW
- mov.l %d7,%d1 # pass size
- mov.l %d6,%d0 # pass mode
- mov.l %a2,%a0 # pass ADDR1
- bsr.l _real_unlock_page # unlock first page(s)
- mov.l (%sp)+,%d0 # restore FSLW
- mov.l %a3,%a0 # pass failing addr
- bra.l _cas_terminate2
- #############################################################
- global _isp_cas2_finish
- _isp_cas2_finish:
- btst &0x1,EXC_OPWORD(%a6)
- bne.b cas2_finish_l
- mov.w EXC_CC(%a6),%cc # load old ccodes
- cmp.w %d0,%d2
- bne.b cas2_finish_w_save
- cmp.w %d1,%d3
- cas2_finish_w_save:
- mov.w %cc,EXC_CC(%a6) # save new ccodes
- tst.b %d4 # update compare reg?
- bne.b cas2_finish_w_done # no
- mov.w DC2(%a6),%d3 # fetch Dc2
- mov.w %d1,(2+EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op
- mov.w DC1(%a6),%d2 # fetch Dc1
- mov.w %d0,(2+EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op
- cas2_finish_w_done:
- btst &0x5,EXC_ISR(%a6)
- sne %d2
- mov.l %d2,%d0 # pass mode
- sf %d1 # pass size
- mov.l ADDR1(%a6),%a0 # pass ADDR1
- bsr.l _real_unlock_page # unlock page
- mov.l %d2,%d0 # pass mode
- sf %d1 # pass size
- mov.l ADDR2(%a6),%a0 # pass ADDR2
- bsr.l _real_unlock_page # unlock page
- rts
- cas2_finish_l:
- mov.w EXC_CC(%a6),%cc # load old ccodes
- cmp.l %d0,%d2
- bne.b cas2_finish_l_save
- cmp.l %d1,%d3
- cas2_finish_l_save:
- mov.w %cc,EXC_CC(%a6) # save new ccodes
- tst.b %d4 # update compare reg?
- bne.b cas2_finish_l_done # no
- mov.w DC2(%a6),%d3 # fetch Dc2
- mov.l %d1,(EXC_DREGS,%a6,%d3.w*4) # store new Compare2 Op
- mov.w DC1(%a6),%d2 # fetch Dc1
- mov.l %d0,(EXC_DREGS,%a6,%d2.w*4) # store new Compare1 Op
- cas2_finish_l_done:
- btst &0x5,EXC_ISR(%a6)
- sne %d2
- mov.l %d2,%d0 # pass mode
- st %d1 # pass size
- mov.l ADDR1(%a6),%a0 # pass ADDR1
- bsr.l _real_unlock_page # unlock page
- mov.l %d2,%d0 # pass mode
- st %d1 # pass size
- mov.l ADDR2(%a6),%a0 # pass ADDR2
- bsr.l _real_unlock_page # unlock page
- rts
- ########
- global cr_cas2
- cr_cas2:
- mov.l EXC_TEMP+0x4(%a6),%d0
- bra.w _compandset2
- #########################################################################
- # XDEF **************************************************************** #
- # _compandset(): routine to emulate cas w/ misaligned <ea> #
- # (internal to package) #
- # _isp_cas_finish(): routine called when cas emulation completes #
- # (external and internal to package) #
- # _isp_cas_restart(): restart cas emulation after a fault #
- # (external to package) #
- # _isp_cas_terminate(): create access error stack frame on fault #
- # (external and internal to package) #
- # _isp_cas_inrange(): checks whether instr addess is within range #
- # of core cas/cas2emulation code #
- # (external to package) #
- # #
- # XREF **************************************************************** #
- # _calc_ea(): calculate effective address #
- # #
- # INPUT *************************************************************** #
- # compandset(): #
- # none #
- # _isp_cas_restart(): #
- # d6 = previous sfc/dfc #
- # _isp_cas_finish(): #
- # _isp_cas_terminate(): #
- # a0 = failing address #
- # d0 = FSLW #
- # d6 = previous sfc/dfc #
- # _isp_cas_inrange(): #
- # a0 = instruction address to be checked #
- # #
- # OUTPUT ************************************************************** #
- # compandset(): #
- # none #
- # _isp_cas_restart(): #
- # a0 = effective address #
- # d7 = word or longword flag #
- # _isp_cas_finish(): #
- # a0 = effective address #
- # _isp_cas_terminate(): #
- # initial register set before emulation exception #
- # _isp_cas_inrange(): #
- # d0 = 0 => in range; -1 => out of range #
- # #
- # ALGORITHM *********************************************************** #
- # #
- # compandset(): #
- # First, calculate the effective address. Then, decode the #
- # instruction word and fetch the "compare" (DC) and "update" (Du) #
- # operands. #
- # Next, call the external routine _real_lock_page() so that the #
- # operating system can keep this page from being paged out while we're #
- # in this routine. If this call fails, jump to _cas_terminate2(). #
- # The routine then branches to _real_cas(). This external routine #
- # that actually emulates cas can be supplied by the external os or #
- # made to point directly back into the 060ISP which has a routine for #
- # this purpose. #
- # #
- # _isp_cas_finish(): #
- # Either way, after emulation, the package is re-entered at #
- # _isp_cas_finish(). This routine re-compares the operands in order to #
- # set the condition codes. Finally, these routines will call #
- # _real_unlock_page() in order to unlock the pages that were previously #
- # locked. #
- # #
- # _isp_cas_restart(): #
- # This routine can be entered from an access error handler where #
- # the emulation sequence should be re-started from the beginning. #
- # #
- # _isp_cas_terminate(): #
- # This routine can be entered from an access error handler where #
- # an emulation operand access failed and the operating system would #
- # like an access error stack frame created instead of the current #
- # unimplemented integer instruction frame. #
- # Also, the package enters here if a call to _real_lock_page() #
- # fails. #
- # #
- # _isp_cas_inrange(): #
- # Checks to see whether the instruction address passed to it in #
- # a0 is within the software package cas/cas2 emulation routines. This #
- # can be helpful for an operating system to determine whether an access #
- # error during emulation was due to a cas/cas2 emulation access. #
- # #
- #########################################################################
- set DC, EXC_TEMP+0x8
- set ADDR, EXC_TEMP+0x4
- global _compandset
- _compandset:
- btst &0x1,EXC_OPWORD(%a6) # word or long operation?
- bne.b compandsetl # long
- compandsetw:
- movq.l &0x2,%d0 # size = 2 bytes
- bsr.l _calc_ea # a0 = calculated <ea>
- mov.l %a0,ADDR(%a6) # save <ea> for possible restart
- sf %d7 # clear d7 for word size
- bra.b compandsetfetch
- compandsetl:
- movq.l &0x4,%d0 # size = 4 bytes
- bsr.l _calc_ea # a0 = calculated <ea>
- mov.l %a0,ADDR(%a6) # save <ea> for possible restart
- st %d7 # set d7 for longword size
- compandsetfetch:
- mov.w EXC_EXTWORD(%a6),%d0 # fetch cas extension word
- mov.l %d0,%d1 # make a copy
- lsr.w &0x6,%d0
- andi.w &0x7,%d0 # extract Du
- mov.l (EXC_DREGS,%a6,%d0.w*4),%d2 # get update operand
- andi.w &0x7,%d1 # extract Dc
- mov.l (EXC_DREGS,%a6,%d1.w*4),%d4 # get compare operand
- mov.w %d1,DC(%a6) # save Dc
- btst &0x5,EXC_ISR(%a6) # which mode for exception?
- sne %d6 # set on supervisor mode
- mov.l %a0,%a2 # save temporarily
- mov.l %d7,%d1 # pass size
- mov.l %d6,%d0 # pass mode
- bsr.l _real_lock_page # lock page
- tst.l %d0 # did error occur?
- bne.w _cas_terminate2 # yes, clean up the mess
- mov.l %a2,%a0 # pass addr in a0
- bra.l _real_cas
- ########
- global _isp_cas_finish
- _isp_cas_finish:
- btst &0x1,EXC_OPWORD(%a6)
- bne.b cas_finish_l
- # just do the compare again since it's faster than saving the ccodes
- # from the locked routine...
- cas_finish_w:
- mov.w EXC_CC(%a6),%cc # restore cc
- cmp.w %d0,%d4 # do word compare
- mov.w %cc,EXC_CC(%a6) # save cc
- tst.b %d1 # update compare reg?
- bne.b cas_finish_w_done # no
- mov.w DC(%a6),%d3
- mov.w %d0,(EXC_DREGS+2,%a6,%d3.w*4) # Dc = destination
- cas_finish_w_done:
- mov.l ADDR(%a6),%a0 # pass addr
- sf %d1 # pass size
- btst &0x5,EXC_ISR(%a6)
- sne %d0 # pass mode
- bsr.l _real_unlock_page # unlock page
- rts
- # just do the compare again since it's faster than saving the ccodes
- # from the locked routine...
- cas_finish_l:
- mov.w EXC_CC(%a6),%cc # restore cc
- cmp.l %d0,%d4 # do longword compare
- mov.w %cc,EXC_CC(%a6) # save cc
- tst.b %d1 # update compare reg?
- bne.b cas_finish_l_done # no
- mov.w DC(%a6),%d3
- mov.l %d0,(EXC_DREGS,%a6,%d3.w*4) # Dc = destination
- cas_finish_l_done:
- mov.l ADDR(%a6),%a0 # pass addr
- st %d1 # pass size
- btst &0x5,EXC_ISR(%a6)
- sne %d0 # pass mode
- bsr.l _real_unlock_page # unlock page
- rts
- ########
- global _isp_cas_restart
- _isp_cas_restart:
- mov.l %d6,%sfc # restore previous sfc
- mov.l %d6,%dfc # restore previous dfc
- cmpi.b EXC_OPWORD+1(%a6),&0xfc # cas or cas2?
- beq.l cr_cas2 # cas2
- cr_cas:
- mov.l ADDR(%a6),%a0 # load <ea>
- btst &0x1,EXC_OPWORD(%a6) # word or long operation?
- sne %d7 # set d7 accordingly
- bra.w compandsetfetch
- ########
- # At this stage, it would be nice if d0 held the FSLW.
- global _isp_cas_terminate
- _isp_cas_terminate:
- mov.l %d6,%sfc # restore previous sfc
- mov.l %d6,%dfc # restore previous dfc
- global _cas_terminate2
- _cas_terminate2:
- mov.l %a0,%a2 # copy failing addr to a2
- mov.l %d0,-(%sp)
- bsr.l isp_restore # restore An (if ()+ or -())
- mov.l (%sp)+,%d0
- addq.l &0x4,%sp # remove sub return addr
- subq.l &0x8,%sp # make room for bigger stack
- subq.l &0x8,%a6 # shift frame ptr down, too
- mov.l &26,%d1 # want to move 51 longwords
- lea 0x8(%sp),%a0 # get address of old stack
- lea 0x0(%sp),%a1 # get address of new stack
- cas_term_cont:
- mov.l (%a0)+,(%a1)+ # move a longword
- dbra.w %d1,cas_term_cont # keep going
- mov.w &0x4008,EXC_IVOFF(%a6) # put new stk fmt, voff
- mov.l %a2,EXC_IVOFF+0x2(%a6) # put faulting addr on stack
- mov.l %d0,EXC_IVOFF+0x6(%a6) # put FSLW on stack
- movm.l EXC_DREGS(%a6),&0x3fff # restore user regs
- unlk %a6 # unlink stack frame
- bra.l _real_access
- ########
- global _isp_cas_inrange
- _isp_cas_inrange:
- clr.l %d0 # clear return result
- lea _CASHI(%pc),%a1 # load end of CAS core code
- cmp.l %a1,%a0 # is PC in range?
- blt.b cin_no # no
- lea _CASLO(%pc),%a1 # load begin of CAS core code
- cmp.l %a0,%a1 # is PC in range?
- blt.b cin_no # no
- rts # yes; return d0 = 0
- cin_no:
- mov.l &-0x1,%d0 # out of range; return d0 = -1
- rts
- #################################################################
- #################################################################
- #################################################################
- # This is the start of the cas and cas2 "core" emulation code. #
- # This is the section that may need to be replaced by the host #
- # OS if it is too operating system-specific. #
- # Please refer to the package documentation to see how to #
- # "replace" this section, if necessary. #
- #################################################################
- #################################################################
- #################################################################
- # ###### ## ###### ####
- # # # # # # #
- # # ###### ###### #
- # # # # # #
- # ###### # # ###### ######
- #########################################################################
- # XDEF **************************************************************** #
- # _isp_cas2(): "core" emulation code for the cas2 instruction #
- # #
- # XREF **************************************************************** #
- # _isp_cas2_finish() - only exit point for this emulation code; #
- # do clean-up; calculate ccodes; store #
- # Compare Ops if appropriate. #
- # #
- # INPUT *************************************************************** #
- # *see chart below* #
- # #
- # OUTPUT ************************************************************** #
- # *see chart below* #
- # #
- # ALGORITHM *********************************************************** #
- # (1) Make several copies of the effective address. #
- # (2) Save current SR; Then mask off all maskable interrupts. #
- # (3) Save current SFC/DFC (ASSUMED TO BE EQUAL!!!); Then set #
- # according to whether exception occurred in user or #
- # supervisor mode. #
- # (4) Use "plpaw" instruction to pre-load ATC with effective #
- # address pages(s). THIS SHOULD NOT FAULT!!! The relevant #
- # page(s) should have already been made resident prior to #
- # entering this routine. #
- # (5) Push the operand lines from the cache w/ "cpushl". #
- # In the 68040, this was done within the locked region. In #
- # the 68060, it is done outside of the locked region. #
- # (6) Use "plpar" instruction to do a re-load of ATC entries for #
- # ADDR1 since ADDR2 entries may have pushed ADDR1 out of the #
- # ATC. #
- # (7) Pre-fetch the core emulation instructions by executing #
- # one branch within each physical line (16 bytes) of the code #
- # before actually executing the code. #
- # (8) Load the BUSCR w/ the bus lock value. #
- # (9) Fetch the source operands using "moves". #
- # (10)Do the compares. If both equal, go to step (13). #
- # (11)Unequal. No update occurs. But, we do write the DST1 op #
- # back to itself (as w/ the '040) so we can gracefully unlock #
- # the bus (and assert LOCKE*) using BUSCR and the final move. #
- # (12)Exit. #
- # (13)Write update operand to the DST locations. Use BUSCR to #
- # assert LOCKE* for the final write operation. #
- # (14)Exit. #
- # #
- # The algorithm is actually implemented slightly differently #
- # depending on the size of the operation and the misalignment of the #
- # operands. A misaligned operand must be written in aligned chunks or #
- # else the BUSCR register control gets confused. #
- # #
- #########################################################################
- #################################################################
- # THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON #
- # ENTERING _isp_cas2(). #
- # #
- # D0 = xxxxxxxx #
- # D1 = xxxxxxxx #
- # D2 = cmp operand 1 #
- # D3 = cmp operand 2 #
- # D4 = update oper 1 #
- # D5 = update oper 2 #
- # D6 = 'xxxxxxff if supervisor mode; 'xxxxxx00 if user mode #
- # D7 = 'xxxxxxff if longword operation; 'xxxxxx00 if word #
- # A0 = ADDR1 #
- # A1 = ADDR2 #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #################################################################
- # align 0x1000
- # beginning label used by _isp_cas_inrange()
- global _CASLO
- _CASLO:
- global _isp_cas2
- _isp_cas2:
- tst.b %d6 # user or supervisor mode?
- bne.b cas2_supervisor # supervisor
- cas2_user:
- movq.l &0x1,%d0 # load user data fc
- bra.b cas2_cont
- cas2_supervisor:
- movq.l &0x5,%d0 # load supervisor data fc
- cas2_cont:
- tst.b %d7 # word or longword?
- beq.w cas2w # word
- ####
- cas2l:
- mov.l %a0,%a2 # copy ADDR1
- mov.l %a1,%a3 # copy ADDR2
- mov.l %a0,%a4 # copy ADDR1
- mov.l %a1,%a5 # copy ADDR2
- addq.l &0x3,%a4 # ADDR1+3
- addq.l &0x3,%a5 # ADDR2+3
- mov.l %a2,%d1 # ADDR1
- # mask interrupts levels 0-6. save old mask value.
- mov.w %sr,%d7 # save current SR
- ori.w &0x0700,%sr # inhibit interrupts
- # load the SFC and DFC with the appropriate mode.
- movc %sfc,%d6 # save old SFC/DFC
- movc %d0,%sfc # store new SFC
- movc %d0,%dfc # store new DFC
- # pre-load the operand ATC. no page faults should occur here because
- # _real_lock_page() should have taken care of this.
- plpaw (%a2) # load atc for ADDR1
- plpaw (%a4) # load atc for ADDR1+3
- plpaw (%a3) # load atc for ADDR2
- plpaw (%a5) # load atc for ADDR2+3
- # push the operand lines from the cache if they exist.
- cpushl %dc,(%a2) # push line for ADDR1
- cpushl %dc,(%a4) # push line for ADDR1+3
- cpushl %dc,(%a3) # push line for ADDR2
- cpushl %dc,(%a5) # push line for ADDR2+2
- mov.l %d1,%a2 # ADDR1
- addq.l &0x3,%d1
- mov.l %d1,%a4 # ADDR1+3
- # if ADDR1 was ATC resident before the above "plpaw" and was executed
- # and it was the next entry scheduled for replacement and ADDR2
- # shares the same set, then the "plpaw" for ADDR2 can push the ADDR1
- # entries from the ATC. so, we do a second set of "plpa"s.
- plpar (%a2) # load atc for ADDR1
- plpar (%a4) # load atc for ADDR1+3
- # load the BUSCR values.
- mov.l &0x80000000,%a2 # assert LOCK* buscr value
- mov.l &0xa0000000,%a3 # assert LOCKE* buscr value
- mov.l &0x00000000,%a4 # buscr unlock value
- # there are three possible mis-aligned cases for longword cas. they
- # are separated because the final write which asserts LOCKE* must
- # be aligned.
- mov.l %a0,%d0 # is ADDR1 misaligned?
- andi.b &0x3,%d0
- beq.b CAS2L_ENTER # no
- cmpi.b %d0,&0x2
- beq.w CAS2L2_ENTER # yes; word misaligned
- bra.w CAS2L3_ENTER # yes; byte misaligned
- #
- # D0 = dst operand 1 <-
- # D1 = dst operand 2 <-
- # D2 = cmp operand 1
- # D3 = cmp operand 2
- # D4 = update oper 1
- # D5 = update oper 2
- # D6 = old SFC/DFC
- # D7 = old SR
- # A0 = ADDR1
- # A1 = ADDR2
- # A2 = bus LOCK* value
- # A3 = bus LOCKE* value
- # A4 = bus unlock value
- # A5 = xxxxxxxx
- #
- align 0x10
- CAS2L_START:
- movc %a2,%buscr # assert LOCK*
- movs.l (%a1),%d1 # fetch Dest2[31:0]
- movs.l (%a0),%d0 # fetch Dest1[31:0]
- bra.b CAS2L_CONT
- CAS2L_ENTER:
- bra.b ~+16
- CAS2L_CONT:
- cmp.l %d0,%d2 # Dest1 - Compare1
- bne.b CAS2L_NOUPDATE
- cmp.l %d1,%d3 # Dest2 - Compare2
- bne.b CAS2L_NOUPDATE
- movs.l %d5,(%a1) # Update2[31:0] -> DEST2
- bra.b CAS2L_UPDATE
- bra.b ~+16
- CAS2L_UPDATE:
- movc %a3,%buscr # assert LOCKE*
- movs.l %d4,(%a0) # Update1[31:0] -> DEST1
- movc %a4,%buscr # unlock the bus
- bra.b cas2l_update_done
- bra.b ~+16
- CAS2L_NOUPDATE:
- movc %a3,%buscr # assert LOCKE*
- movs.l %d0,(%a0) # Dest1[31:0] -> DEST1
- movc %a4,%buscr # unlock the bus
- bra.b cas2l_noupdate_done
- bra.b ~+16
- CAS2L_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CAS2L_START
- ####
- #################################################################
- # THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #
- # ENTERING _isp_cas2(). #
- # #
- # D0 = destination[31:0] operand 1 #
- # D1 = destination[31:0] operand 2 #
- # D2 = cmp[31:0] operand 1 #
- # D3 = cmp[31:0] operand 2 #
- # D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #
- # D5 = xxxxxxxx #
- # D6 = xxxxxxxx #
- # D7 = xxxxxxxx #
- # A0 = xxxxxxxx #
- # A1 = xxxxxxxx #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #################################################################
- cas2l_noupdate_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- sf %d4 # indicate no update was done
- bra.l _isp_cas2_finish
- cas2l_update_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- st %d4 # indicate update was done
- bra.l _isp_cas2_finish
- ####
- align 0x10
- CAS2L2_START:
- movc %a2,%buscr # assert LOCK*
- movs.l (%a1),%d1 # fetch Dest2[31:0]
- movs.l (%a0),%d0 # fetch Dest1[31:0]
- bra.b CAS2L2_CONT
- CAS2L2_ENTER:
- bra.b ~+16
- CAS2L2_CONT:
- cmp.l %d0,%d2 # Dest1 - Compare1
- bne.b CAS2L2_NOUPDATE
- cmp.l %d1,%d3 # Dest2 - Compare2
- bne.b CAS2L2_NOUPDATE
- movs.l %d5,(%a1) # Update2[31:0] -> Dest2
- bra.b CAS2L2_UPDATE
- bra.b ~+16
- CAS2L2_UPDATE:
- swap %d4 # get Update1[31:16]
- movs.w %d4,(%a0)+ # Update1[31:16] -> DEST1
- movc %a3,%buscr # assert LOCKE*
- swap %d4 # get Update1[15:0]
- bra.b CAS2L2_UPDATE2
- bra.b ~+16
- CAS2L2_UPDATE2:
- movs.w %d4,(%a0) # Update1[15:0] -> DEST1+0x2
- movc %a4,%buscr # unlock the bus
- bra.w cas2l_update_done
- nop
- bra.b ~+16
- CAS2L2_NOUPDATE:
- swap %d0 # get Dest1[31:16]
- movs.w %d0,(%a0)+ # Dest1[31:16] -> DEST1
- movc %a3,%buscr # assert LOCKE*
- swap %d0 # get Dest1[15:0]
- bra.b CAS2L2_NOUPDATE2
- bra.b ~+16
- CAS2L2_NOUPDATE2:
- movs.w %d0,(%a0) # Dest1[15:0] -> DEST1+0x2
- movc %a4,%buscr # unlock the bus
- bra.w cas2l_noupdate_done
- nop
- bra.b ~+16
- CAS2L2_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CAS2L2_START
- #################################
- align 0x10
- CAS2L3_START:
- movc %a2,%buscr # assert LOCK*
- movs.l (%a1),%d1 # fetch Dest2[31:0]
- movs.l (%a0),%d0 # fetch Dest1[31:0]
- bra.b CAS2L3_CONT
- CAS2L3_ENTER:
- bra.b ~+16
- CAS2L3_CONT:
- cmp.l %d0,%d2 # Dest1 - Compare1
- bne.b CAS2L3_NOUPDATE
- cmp.l %d1,%d3 # Dest2 - Compare2
- bne.b CAS2L3_NOUPDATE
- movs.l %d5,(%a1) # Update2[31:0] -> DEST2
- bra.b CAS2L3_UPDATE
- bra.b ~+16
- CAS2L3_UPDATE:
- rol.l &0x8,%d4 # get Update1[31:24]
- movs.b %d4,(%a0)+ # Update1[31:24] -> DEST1
- swap %d4 # get Update1[23:8]
- movs.w %d4,(%a0)+ # Update1[23:8] -> DEST1+0x1
- bra.b CAS2L3_UPDATE2
- bra.b ~+16
- CAS2L3_UPDATE2:
- rol.l &0x8,%d4 # get Update1[7:0]
- movc %a3,%buscr # assert LOCKE*
- movs.b %d4,(%a0) # Update1[7:0] -> DEST1+0x3
- bra.b CAS2L3_UPDATE3
- nop
- bra.b ~+16
- CAS2L3_UPDATE3:
- movc %a4,%buscr # unlock the bus
- bra.w cas2l_update_done
- nop
- nop
- nop
- bra.b ~+16
- CAS2L3_NOUPDATE:
- rol.l &0x8,%d0 # get Dest1[31:24]
- movs.b %d0,(%a0)+ # Dest1[31:24] -> DEST1
- swap %d0 # get Dest1[23:8]
- movs.w %d0,(%a0)+ # Dest1[23:8] -> DEST1+0x1
- bra.b CAS2L3_NOUPDATE2
- bra.b ~+16
- CAS2L3_NOUPDATE2:
- rol.l &0x8,%d0 # get Dest1[7:0]
- movc %a3,%buscr # assert LOCKE*
- movs.b %d0,(%a0) # Update1[7:0] -> DEST1+0x3
- bra.b CAS2L3_NOUPDATE3
- nop
- bra.b ~+16
- CAS2L3_NOUPDATE3:
- movc %a4,%buscr # unlock the bus
- bra.w cas2l_noupdate_done
- nop
- nop
- nop
- bra.b ~+14
- CAS2L3_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- bra.w CAS2L3_START
- #############################################################
- #############################################################
- cas2w:
- mov.l %a0,%a2 # copy ADDR1
- mov.l %a1,%a3 # copy ADDR2
- mov.l %a0,%a4 # copy ADDR1
- mov.l %a1,%a5 # copy ADDR2
- addq.l &0x1,%a4 # ADDR1+1
- addq.l &0x1,%a5 # ADDR2+1
- mov.l %a2,%d1 # ADDR1
- # mask interrupt levels 0-6. save old mask value.
- mov.w %sr,%d7 # save current SR
- ori.w &0x0700,%sr # inhibit interrupts
- # load the SFC and DFC with the appropriate mode.
- movc %sfc,%d6 # save old SFC/DFC
- movc %d0,%sfc # store new SFC
- movc %d0,%dfc # store new DFC
- # pre-load the operand ATC. no page faults should occur because
- # _real_lock_page() should have taken care of this.
- plpaw (%a2) # load atc for ADDR1
- plpaw (%a4) # load atc for ADDR1+1
- plpaw (%a3) # load atc for ADDR2
- plpaw (%a5) # load atc for ADDR2+1
- # push the operand cache lines from the cache if they exist.
- cpushl %dc,(%a2) # push line for ADDR1
- cpushl %dc,(%a4) # push line for ADDR1+1
- cpushl %dc,(%a3) # push line for ADDR2
- cpushl %dc,(%a5) # push line for ADDR2+1
- mov.l %d1,%a2 # ADDR1
- addq.l &0x3,%d1
- mov.l %d1,%a4 # ADDR1+3
- # if ADDR1 was ATC resident before the above "plpaw" and was executed
- # and it was the next entry scheduled for replacement and ADDR2
- # shares the same set, then the "plpaw" for ADDR2 can push the ADDR1
- # entries from the ATC. so, we do a second set of "plpa"s.
- plpar (%a2) # load atc for ADDR1
- plpar (%a4) # load atc for ADDR1+3
- # load the BUSCR values.
- mov.l &0x80000000,%a2 # assert LOCK* buscr value
- mov.l &0xa0000000,%a3 # assert LOCKE* buscr value
- mov.l &0x00000000,%a4 # buscr unlock value
- # there are two possible mis-aligned cases for word cas. they
- # are separated because the final write which asserts LOCKE* must
- # be aligned.
- mov.l %a0,%d0 # is ADDR1 misaligned?
- btst &0x0,%d0
- bne.w CAS2W2_ENTER # yes
- bra.b CAS2W_ENTER # no
- #
- # D0 = dst operand 1 <-
- # D1 = dst operand 2 <-
- # D2 = cmp operand 1
- # D3 = cmp operand 2
- # D4 = update oper 1
- # D5 = update oper 2
- # D6 = old SFC/DFC
- # D7 = old SR
- # A0 = ADDR1
- # A1 = ADDR2
- # A2 = bus LOCK* value
- # A3 = bus LOCKE* value
- # A4 = bus unlock value
- # A5 = xxxxxxxx
- #
- align 0x10
- CAS2W_START:
- movc %a2,%buscr # assert LOCK*
- movs.w (%a1),%d1 # fetch Dest2[15:0]
- movs.w (%a0),%d0 # fetch Dest1[15:0]
- bra.b CAS2W_CONT2
- CAS2W_ENTER:
- bra.b ~+16
- CAS2W_CONT2:
- cmp.w %d0,%d2 # Dest1 - Compare1
- bne.b CAS2W_NOUPDATE
- cmp.w %d1,%d3 # Dest2 - Compare2
- bne.b CAS2W_NOUPDATE
- movs.w %d5,(%a1) # Update2[15:0] -> DEST2
- bra.b CAS2W_UPDATE
- bra.b ~+16
- CAS2W_UPDATE:
- movc %a3,%buscr # assert LOCKE*
- movs.w %d4,(%a0) # Update1[15:0] -> DEST1
- movc %a4,%buscr # unlock the bus
- bra.b cas2w_update_done
- bra.b ~+16
- CAS2W_NOUPDATE:
- movc %a3,%buscr # assert LOCKE*
- movs.w %d0,(%a0) # Dest1[15:0] -> DEST1
- movc %a4,%buscr # unlock the bus
- bra.b cas2w_noupdate_done
- bra.b ~+16
- CAS2W_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CAS2W_START
- ####
- #################################################################
- # THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #
- # ENTERING _isp_cas2(). #
- # #
- # D0 = destination[15:0] operand 1 #
- # D1 = destination[15:0] operand 2 #
- # D2 = cmp[15:0] operand 1 #
- # D3 = cmp[15:0] operand 2 #
- # D4 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #
- # D5 = xxxxxxxx #
- # D6 = xxxxxxxx #
- # D7 = xxxxxxxx #
- # A0 = xxxxxxxx #
- # A1 = xxxxxxxx #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #################################################################
- cas2w_noupdate_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- sf %d4 # indicate no update was done
- bra.l _isp_cas2_finish
- cas2w_update_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- st %d4 # indicate update was done
- bra.l _isp_cas2_finish
- ####
- align 0x10
- CAS2W2_START:
- movc %a2,%buscr # assert LOCK*
- movs.w (%a1),%d1 # fetch Dest2[15:0]
- movs.w (%a0),%d0 # fetch Dest1[15:0]
- bra.b CAS2W2_CONT2
- CAS2W2_ENTER:
- bra.b ~+16
- CAS2W2_CONT2:
- cmp.w %d0,%d2 # Dest1 - Compare1
- bne.b CAS2W2_NOUPDATE
- cmp.w %d1,%d3 # Dest2 - Compare2
- bne.b CAS2W2_NOUPDATE
- movs.w %d5,(%a1) # Update2[15:0] -> DEST2
- bra.b CAS2W2_UPDATE
- bra.b ~+16
- CAS2W2_UPDATE:
- ror.l &0x8,%d4 # get Update1[15:8]
- movs.b %d4,(%a0)+ # Update1[15:8] -> DEST1
- movc %a3,%buscr # assert LOCKE*
- rol.l &0x8,%d4 # get Update1[7:0]
- bra.b CAS2W2_UPDATE2
- bra.b ~+16
- CAS2W2_UPDATE2:
- movs.b %d4,(%a0) # Update1[7:0] -> DEST1+0x1
- movc %a4,%buscr # unlock the bus
- bra.w cas2w_update_done
- nop
- bra.b ~+16
- CAS2W2_NOUPDATE:
- ror.l &0x8,%d0 # get Dest1[15:8]
- movs.b %d0,(%a0)+ # Dest1[15:8] -> DEST1
- movc %a3,%buscr # assert LOCKE*
- rol.l &0x8,%d0 # get Dest1[7:0]
- bra.b CAS2W2_NOUPDATE2
- bra.b ~+16
- CAS2W2_NOUPDATE2:
- movs.b %d0,(%a0) # Dest1[7:0] -> DEST1+0x1
- movc %a4,%buscr # unlock the bus
- bra.w cas2w_noupdate_done
- nop
- bra.b ~+16
- CAS2W2_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CAS2W2_START
- # ###### ## ######
- # # # # #
- # # ###### ######
- # # # # #
- # ###### # # ######
- #########################################################################
- # XDEF **************************************************************** #
- # _isp_cas(): "core" emulation code for the cas instruction #
- # #
- # XREF **************************************************************** #
- # _isp_cas_finish() - only exit point for this emulation code; #
- # do clean-up #
- # #
- # INPUT *************************************************************** #
- # *see entry chart below* #
- # #
- # OUTPUT ************************************************************** #
- # *see exit chart below* #
- # #
- # ALGORITHM *********************************************************** #
- # (1) Make several copies of the effective address. #
- # (2) Save current SR; Then mask off all maskable interrupts. #
- # (3) Save current DFC/SFC (ASSUMED TO BE EQUAL!!!); Then set #
- # SFC/DFC according to whether exception occurred in user or #
- # supervisor mode. #
- # (4) Use "plpaw" instruction to pre-load ATC with efective #
- # address page(s). THIS SHOULD NOT FAULT!!! The relevant #
- # page(s) should have been made resident prior to entering #
- # this routine. #
- # (5) Push the operand lines from the cache w/ "cpushl". #
- # In the 68040, this was done within the locked region. In #
- # the 68060, it is done outside of the locked region. #
- # (6) Pre-fetch the core emulation instructions by executing one #
- # branch within each physical line (16 bytes) of the code #
- # before actually executing the code. #
- # (7) Load the BUSCR with the bus lock value. #
- # (8) Fetch the source operand. #
- # (9) Do the compare. If equal, go to step (12). #
- # (10)Unequal. No update occurs. But, we do write the DST op back #
- # to itself (as w/ the '040) so we can gracefully unlock #
- # the bus (and assert LOCKE*) using BUSCR and the final move. #
- # (11)Exit. #
- # (12)Write update operand to the DST location. Use BUSCR to #
- # assert LOCKE* for the final write operation. #
- # (13)Exit. #
- # #
- # The algorithm is actually implemented slightly differently #
- # depending on the size of the operation and the misalignment of the #
- # operand. A misaligned operand must be written in aligned chunks or #
- # else the BUSCR register control gets confused. #
- # #
- #########################################################################
- #########################################################
- # THIS IS THE STATE OF THE INTEGER REGISTER FILE UPON #
- # ENTERING _isp_cas(). #
- # #
- # D0 = xxxxxxxx #
- # D1 = xxxxxxxx #
- # D2 = update operand #
- # D3 = xxxxxxxx #
- # D4 = compare operand #
- # D5 = xxxxxxxx #
- # D6 = supervisor ('xxxxxxff) or user mode ('xxxxxx00) #
- # D7 = longword ('xxxxxxff) or word size ('xxxxxx00) #
- # A0 = ADDR #
- # A1 = xxxxxxxx #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #########################################################
- global _isp_cas
- _isp_cas:
- tst.b %d6 # user or supervisor mode?
- bne.b cas_super # supervisor
- cas_user:
- movq.l &0x1,%d0 # load user data fc
- bra.b cas_cont
- cas_super:
- movq.l &0x5,%d0 # load supervisor data fc
- cas_cont:
- tst.b %d7 # word or longword?
- bne.w casl # longword
- ####
- casw:
- mov.l %a0,%a1 # make copy for plpaw1
- mov.l %a0,%a2 # make copy for plpaw2
- addq.l &0x1,%a2 # plpaw2 points to end of word
- mov.l %d2,%d3 # d3 = update[7:0]
- lsr.w &0x8,%d2 # d2 = update[15:8]
- # mask interrupt levels 0-6. save old mask value.
- mov.w %sr,%d7 # save current SR
- ori.w &0x0700,%sr # inhibit interrupts
- # load the SFC and DFC with the appropriate mode.
- movc %sfc,%d6 # save old SFC/DFC
- movc %d0,%sfc # load new sfc
- movc %d0,%dfc # load new dfc
- # pre-load the operand ATC. no page faults should occur here because
- # _real_lock_page() should have taken care of this.
- plpaw (%a1) # load atc for ADDR
- plpaw (%a2) # load atc for ADDR+1
- # push the operand lines from the cache if they exist.
- cpushl %dc,(%a1) # push dirty data
- cpushl %dc,(%a2) # push dirty data
- # load the BUSCR values.
- mov.l &0x80000000,%a1 # assert LOCK* buscr value
- mov.l &0xa0000000,%a2 # assert LOCKE* buscr value
- mov.l &0x00000000,%a3 # buscr unlock value
- # pre-load the instruction cache for the following algorithm.
- # this will minimize the number of cycles that LOCK* will be asserted.
- bra.b CASW_ENTER # start pre-loading icache
- #
- # D0 = dst operand <-
- # D1 = update[15:8] operand
- # D2 = update[7:0] operand
- # D3 = xxxxxxxx
- # D4 = compare[15:0] operand
- # D5 = xxxxxxxx
- # D6 = old SFC/DFC
- # D7 = old SR
- # A0 = ADDR
- # A1 = bus LOCK* value
- # A2 = bus LOCKE* value
- # A3 = bus unlock value
- # A4 = xxxxxxxx
- # A5 = xxxxxxxx
- #
- align 0x10
- CASW_START:
- movc %a1,%buscr # assert LOCK*
- movs.w (%a0),%d0 # fetch Dest[15:0]
- cmp.w %d0,%d4 # Dest - Compare
- bne.b CASW_NOUPDATE
- bra.b CASW_UPDATE
- CASW_ENTER:
- bra.b ~+16
- CASW_UPDATE:
- movs.b %d2,(%a0)+ # Update[15:8] -> DEST
- movc %a2,%buscr # assert LOCKE*
- movs.b %d3,(%a0) # Update[7:0] -> DEST+0x1
- bra.b CASW_UPDATE2
- bra.b ~+16
- CASW_UPDATE2:
- movc %a3,%buscr # unlock the bus
- bra.b casw_update_done
- nop
- nop
- nop
- nop
- bra.b ~+16
- CASW_NOUPDATE:
- ror.l &0x8,%d0 # get Dest[15:8]
- movs.b %d0,(%a0)+ # Dest[15:8] -> DEST
- movc %a2,%buscr # assert LOCKE*
- rol.l &0x8,%d0 # get Dest[7:0]
- bra.b CASW_NOUPDATE2
- bra.b ~+16
- CASW_NOUPDATE2:
- movs.b %d0,(%a0) # Dest[7:0] -> DEST+0x1
- movc %a3,%buscr # unlock the bus
- bra.b casw_noupdate_done
- nop
- nop
- bra.b ~+16
- CASW_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CASW_START
- #################################################################
- # THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #
- # CALLING _isp_cas_finish(). #
- # #
- # D0 = destination[15:0] operand #
- # D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #
- # D2 = xxxxxxxx #
- # D3 = xxxxxxxx #
- # D4 = compare[15:0] operand #
- # D5 = xxxxxxxx #
- # D6 = xxxxxxxx #
- # D7 = xxxxxxxx #
- # A0 = xxxxxxxx #
- # A1 = xxxxxxxx #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #################################################################
- casw_noupdate_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- sf %d1 # indicate no update was done
- bra.l _isp_cas_finish
- casw_update_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- st %d1 # indicate update was done
- bra.l _isp_cas_finish
- ################
- # there are two possible mis-aligned cases for longword cas. they
- # are separated because the final write which asserts LOCKE* must
- # be an aligned write.
- casl:
- mov.l %a0,%a1 # make copy for plpaw1
- mov.l %a0,%a2 # make copy for plpaw2
- addq.l &0x3,%a2 # plpaw2 points to end of longword
- mov.l %a0,%d1 # byte or word misaligned?
- btst &0x0,%d1
- bne.w casl2 # byte misaligned
- mov.l %d2,%d3 # d3 = update[15:0]
- swap %d2 # d2 = update[31:16]
- # mask interrupts levels 0-6. save old mask value.
- mov.w %sr,%d7 # save current SR
- ori.w &0x0700,%sr # inhibit interrupts
- # load the SFC and DFC with the appropriate mode.
- movc %sfc,%d6 # save old SFC/DFC
- movc %d0,%sfc # load new sfc
- movc %d0,%dfc # load new dfc
- # pre-load the operand ATC. no page faults should occur here because
- # _real_lock_page() should have taken care of this.
- plpaw (%a1) # load atc for ADDR
- plpaw (%a2) # load atc for ADDR+3
- # push the operand lines from the cache if they exist.
- cpushl %dc,(%a1) # push dirty data
- cpushl %dc,(%a2) # push dirty data
- # load the BUSCR values.
- mov.l &0x80000000,%a1 # assert LOCK* buscr value
- mov.l &0xa0000000,%a2 # assert LOCKE* buscr value
- mov.l &0x00000000,%a3 # buscr unlock value
- bra.b CASL_ENTER # start pre-loading icache
- #
- # D0 = dst operand <-
- # D1 = xxxxxxxx
- # D2 = update[31:16] operand
- # D3 = update[15:0] operand
- # D4 = compare[31:0] operand
- # D5 = xxxxxxxx
- # D6 = old SFC/DFC
- # D7 = old SR
- # A0 = ADDR
- # A1 = bus LOCK* value
- # A2 = bus LOCKE* value
- # A3 = bus unlock value
- # A4 = xxxxxxxx
- # A5 = xxxxxxxx
- #
- align 0x10
- CASL_START:
- movc %a1,%buscr # assert LOCK*
- movs.l (%a0),%d0 # fetch Dest[31:0]
- cmp.l %d0,%d4 # Dest - Compare
- bne.b CASL_NOUPDATE
- bra.b CASL_UPDATE
- CASL_ENTER:
- bra.b ~+16
- CASL_UPDATE:
- movs.w %d2,(%a0)+ # Update[31:16] -> DEST
- movc %a2,%buscr # assert LOCKE*
- movs.w %d3,(%a0) # Update[15:0] -> DEST+0x2
- bra.b CASL_UPDATE2
- bra.b ~+16
- CASL_UPDATE2:
- movc %a3,%buscr # unlock the bus
- bra.b casl_update_done
- nop
- nop
- nop
- nop
- bra.b ~+16
- CASL_NOUPDATE:
- swap %d0 # get Dest[31:16]
- movs.w %d0,(%a0)+ # Dest[31:16] -> DEST
- swap %d0 # get Dest[15:0]
- movc %a2,%buscr # assert LOCKE*
- bra.b CASL_NOUPDATE2
- bra.b ~+16
- CASL_NOUPDATE2:
- movs.w %d0,(%a0) # Dest[15:0] -> DEST+0x2
- movc %a3,%buscr # unlock the bus
- bra.b casl_noupdate_done
- nop
- nop
- bra.b ~+16
- CASL_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CASL_START
- #################################################################
- # THIS MUST BE THE STATE OF THE INTEGER REGISTER FILE UPON #
- # CALLING _isp_cas_finish(). #
- # #
- # D0 = destination[31:0] operand #
- # D1 = 'xxxxxx11 -> no reg update; 'xxxxxx00 -> update required #
- # D2 = xxxxxxxx #
- # D3 = xxxxxxxx #
- # D4 = compare[31:0] operand #
- # D5 = xxxxxxxx #
- # D6 = xxxxxxxx #
- # D7 = xxxxxxxx #
- # A0 = xxxxxxxx #
- # A1 = xxxxxxxx #
- # A2 = xxxxxxxx #
- # A3 = xxxxxxxx #
- # A4 = xxxxxxxx #
- # A5 = xxxxxxxx #
- # A6 = frame pointer #
- # A7 = stack pointer #
- #################################################################
- casl_noupdate_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupt mask level.
- mov.w %d7,%sr # restore old SR
- sf %d1 # indicate no update was done
- bra.l _isp_cas_finish
- casl_update_done:
- # restore previous SFC/DFC value.
- movc %d6,%sfc # restore old SFC
- movc %d6,%dfc # restore old DFC
- # restore previous interrupts mask level.
- mov.w %d7,%sr # restore old SR
- st %d1 # indicate update was done
- bra.l _isp_cas_finish
- #######################################
- casl2:
- mov.l %d2,%d5 # d5 = Update[7:0]
- lsr.l &0x8,%d2
- mov.l %d2,%d3 # d3 = Update[23:8]
- swap %d2 # d2 = Update[31:24]
- # mask interrupts levels 0-6. save old mask value.
- mov.w %sr,%d7 # save current SR
- ori.w &0x0700,%sr # inhibit interrupts
- # load the SFC and DFC with the appropriate mode.
- movc %sfc,%d6 # save old SFC/DFC
- movc %d0,%sfc # load new sfc
- movc %d0,%dfc # load new dfc
- # pre-load the operand ATC. no page faults should occur here because
- # _real_lock_page() should have taken care of this already.
- plpaw (%a1) # load atc for ADDR
- plpaw (%a2) # load atc for ADDR+3
- # puch the operand lines from the cache if they exist.
- cpushl %dc,(%a1) # push dirty data
- cpushl %dc,(%a2) # push dirty data
- # load the BUSCR values.
- mov.l &0x80000000,%a1 # assert LOCK* buscr value
- mov.l &0xa0000000,%a2 # assert LOCKE* buscr value
- mov.l &0x00000000,%a3 # buscr unlock value
- # pre-load the instruction cache for the following algorithm.
- # this will minimize the number of cycles that LOCK* will be asserted.
- bra.b CASL2_ENTER # start pre-loading icache
- #
- # D0 = dst operand <-
- # D1 = xxxxxxxx
- # D2 = update[31:24] operand
- # D3 = update[23:8] operand
- # D4 = compare[31:0] operand
- # D5 = update[7:0] operand
- # D6 = old SFC/DFC
- # D7 = old SR
- # A0 = ADDR
- # A1 = bus LOCK* value
- # A2 = bus LOCKE* value
- # A3 = bus unlock value
- # A4 = xxxxxxxx
- # A5 = xxxxxxxx
- #
- align 0x10
- CASL2_START:
- movc %a1,%buscr # assert LOCK*
- movs.l (%a0),%d0 # fetch Dest[31:0]
- cmp.l %d0,%d4 # Dest - Compare
- bne.b CASL2_NOUPDATE
- bra.b CASL2_UPDATE
- CASL2_ENTER:
- bra.b ~+16
- CASL2_UPDATE:
- movs.b %d2,(%a0)+ # Update[31:24] -> DEST
- movs.w %d3,(%a0)+ # Update[23:8] -> DEST+0x1
- movc %a2,%buscr # assert LOCKE*
- bra.b CASL2_UPDATE2
- bra.b ~+16
- CASL2_UPDATE2:
- movs.b %d5,(%a0) # Update[7:0] -> DEST+0x3
- movc %a3,%buscr # unlock the bus
- bra.w casl_update_done
- nop
- bra.b ~+16
- CASL2_NOUPDATE:
- rol.l &0x8,%d0 # get Dest[31:24]
- movs.b %d0,(%a0)+ # Dest[31:24] -> DEST
- swap %d0 # get Dest[23:8]
- movs.w %d0,(%a0)+ # Dest[23:8] -> DEST+0x1
- bra.b CASL2_NOUPDATE2
- bra.b ~+16
- CASL2_NOUPDATE2:
- rol.l &0x8,%d0 # get Dest[7:0]
- movc %a2,%buscr # assert LOCKE*
- movs.b %d0,(%a0) # Dest[7:0] -> DEST+0x3
- bra.b CASL2_NOUPDATE3
- nop
- bra.b ~+16
- CASL2_NOUPDATE3:
- movc %a3,%buscr # unlock the bus
- bra.w casl_noupdate_done
- nop
- nop
- nop
- bra.b ~+16
- CASL2_FILLER:
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- bra.b CASL2_START
- ####
- ####
- # end label used by _isp_cas_inrange()
- global _CASHI
- _CASHI:
|