COREEMUL.A 152 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844
  1. (* Release 3.10 *)
  2. (*-------------------------------------------------------------------------*
  3. * *
  4. * COREEMUL.A - 8087 emulator *
  5. * *
  6. * COPYRIGHT (C) 1989..1992 Clarion Software Corporation. *
  7. * All Rights Reserved *
  8. * *
  9. *--------------------------------------------------------------------------*)
  10. include "corelib.inc"
  11. module CoreEmul
  12. (********************************************************************)
  13. (* 8087 emulation support - part common to real and protected modes *)
  14. (********************************************************************)
  15. false = 0 (* Beware ! For incoming parameters, non-false = true.*)
  16. true = 1 (* For results, we generate the proper numbers.*)
  17. lesser = -1 (* Incoming, lesser < 0*)
  18. equal = 0
  19. greater = 1 (* Incoming, greater > 0*)
  20. by0 = 0
  21. by1 = 1
  22. w0 = 0
  23. w1 = 2
  24. w2 = 4
  25. w3 = 6
  26. dd0 = 0
  27. dd1 = 4
  28. nearParam = 4
  29. emInt = 34H (* allocated to 8087 by Microsoft Corp.*)
  30. (* The iAPX87 chips usually report exceptions when the next numeric *)
  31. (* instruction is attempted (since processing runs in parallel *)
  32. (* with the CPU). The emulator will normally do the same, but *)
  33. (* if the following symbol is defined some optional assembly is *)
  34. (* enabled which allows exceptions to be emulated in the failing *)
  35. (* instruction. The main benefit is that FWAIT may validly be *)
  36. (* converted to no-op, gaining speed. *)
  37. instantException = true (* report excep immediately *)
  38. (* error types *)
  39. fe_OK = 0
  40. fe_Divide_By_Zero = 04H
  41. fe_Imaginary = 01H
  42. fe_Operand_Too_Small = 02H
  43. fe_Operand_Too_Big = 01H
  44. fe_Overflow = 08H
  45. fe_Underflow = 10H
  46. fe_Bad_Parameter = 01H
  47. fe_Invalid_Operation = 01H
  48. fe_No_Space = 01H
  49. fe_Precision = 20H
  50. (* Using a 15-bit signed exponent is enough to emulate the iNDP-87 *)
  51. (* and simplifies avoids overflow when combining exponents. *)
  52. zero_exponent = 0C001H
  53. infinite_exponent = 4001H
  54. positive_sign = 0
  55. negative_sign = 1
  56. (* 8087/287 status word values after comparisons *)
  57. e287_incomparable = 4500H
  58. e287_lesser = 0100H
  59. e287_equal = 4000H
  60. e287_greater = 0000H
  61. (* 8087/287 status word after XAM *)
  62. e287_plusInfinity = 0500H
  63. e287_plusNormal = 0400H
  64. e287_plusZero = 4000H
  65. e287_minusNormal = 0600H
  66. e287_empty = 4100H
  67. (* control word rounding control field *)
  68. e287_roundingControl = 0CH
  69. e287_round = 00H
  70. e287_floor = 04H
  71. e287_ceiling = 08H
  72. e287_chop = 0CH
  73. (* IEEE exponent bias constants, relative to temporary format *)
  74. iees_exponent_bias = 7EH
  75. ieel_exponent_bias = 3FEH
  76. temp_exponent_bias = 3FFEH
  77. (* The temporary format here is not identical to iNDP-87 format. The *)
  78. (* exponent is not biased and the sign is held in a separate *)
  79. (* byte. This format is faster for emulation software to use. *)
  80. emu_fraction = 0
  81. emu_exponent = 8
  82. emu_sign = 10
  83. emu_spare = 11
  84. emu_temp_size = 12
  85. (*INCLUDE E086ENTR*)
  86. (* The emulation does not extend to some more exotic possibilities for *)
  87. (* using the iNDP registers. When stack overflow occurs, registers do *)
  88. (* not wrap around. When registers below stack bottom are addressed, the *)
  89. (* register actually used is undefined. In both cases, the emulator *)
  90. (* generates an "invalid operation" exception. If the exception is not *)
  91. (* masked and exception interrupts are properly supported, the program *)
  92. (* should behave as if the real chip was present. If exceptions are not *)
  93. (* processed, then the result will be unpredictable. *)
  94. fregs = 200
  95. emws_limitSP = 200 (* org 8*emu_temp_size *)
  96. emws_initialSP = 296 (* org 9*emu_temp_size *)
  97. emws_saveVector = 404 (* org 4 *)
  98. emws_not_used = 408 (* org 6 *)
  99. emws_status = 414 (* org 2, aligned. Result of comparisons *)
  100. emws_control = 416 (* org 2 processing options and exceptions. *)
  101. emws_instrnPtrxx = 418 (* org 4 used with error recovery *)
  102. emws_dataPtrxx = 422 (* org 4 --------- " ------------ *)
  103. emws_instructionxx = 426 (* org 2 bytes swapped, used for error recovery *)
  104. emws_tos = 428 (* org 2 current level of e87 register stack *)
  105. emws_maxStack = 430 (* org 2 *)
  106. invLn2 = 432 (* org emu_temp_size, dw 0F0BBH, 05C17H, 03B29H, 0B8AAH, 1; db positive_sign, 0*)
  107. emws_resume_ip = 444 (* org 2 *)
  108. emws_resume_bp = 446 (* org 2 *)
  109. emuRecSize = 448
  110. (* offsets from bp of saved registers *)
  111. oldFlags = 22
  112. oldCS = 20
  113. oldIP = 18
  114. oldAX = 16
  115. oldBX = 14
  116. oldCX = 12
  117. oldDX = 10
  118. oldSI = 8
  119. oldDI = 6
  120. oldDS = 4
  121. oldES = 2
  122. oldBP = 0
  123. segment EMU_TEXT (EMU_CODE,28H)
  124. (*%T _mthread *)
  125. extrn __FloatSave
  126. extrn __FloatRestore
  127. (*%E *)
  128. public __FloatInitStack :
  129. mov word ss:[InMathLib],0
  130. (*%T RegParam *)
  131. push cx (* initialise fp registers except for stack top *)
  132. mov cx,7
  133. push_zero:
  134. fldz st(0)
  135. loop push_zero
  136. pop cx
  137. (*%E *)
  138. (*%T _mthread *)
  139. push ds
  140. push es
  141. push ss
  142. pop ds
  143. push ss
  144. pop es
  145. call far __FloatSave
  146. call far __FloatRestore
  147. pop es
  148. pop ds
  149. (*%E *)
  150. ret far 0
  151. segment EMU_TEXT(EMU_CODE,28H)
  152. public __EmulInitInstance: (* ax = resume address, bx = stack segment *)
  153. push cx
  154. push di
  155. push ds
  156. push es
  157. mov ds, bx
  158. mov es, bx
  159. mov [emws_resume_ip],ax
  160. mov di, emws_limitSP
  161. mov cx, emws_resume_ip - emws_limitSP
  162. sub ax, ax
  163. rep; stosb
  164. mov word [emws_status],0
  165. mov word [emws_control],33FH + 0C00H
  166. and word [emws_control],~001DH (* enable invalid op/underflow/overflow/divide by zero exception *)
  167. mov word [emws_tos],(*offset*) emws_initialSP
  168. mov word [emws_maxStack],(*offset*) emws_initialSP
  169. mov word [emws_initialSP],0
  170. mov word [emws_initialSP][2],0
  171. mov word [emws_initialSP][4],0
  172. mov word [emws_initialSP][6],0
  173. mov word [emws_initialSP][8],infinite_exponent
  174. mov word [invLn2][0],0F0BBH
  175. mov word [invLn2][2],05C17H
  176. mov word [invLn2][4],03B29H
  177. mov word [invLn2][6],0B8AAH
  178. mov word [invLn2][8],00001H
  179. (*mov word [invLn2][10],00000H*)
  180. pop es
  181. pop ds
  182. pop di
  183. pop cx
  184. ret 0
  185. other_jumps :
  186. dw e287_tos_Function
  187. dw e287_FPU_Control
  188. dw e287_Reserved_1
  189. dw e287_Reserved_2
  190. arith_push : dw iees_Push, emu_Float32, ieel_Push, emu_Float
  191. arith_actCase:
  192. dw arith_Add, arith_Multiply
  193. dw arith_Compare, arith_CompareP
  194. dw arith_Subtract, arith_SubtractR
  195. dw arith_Divide, arith_DivideR
  196. en_regCaseSwitch :
  197. dw en_regCase0
  198. dw en_regCase1
  199. dw en_regCase2
  200. dw en_regCase3
  201. dw en_regCase4
  202. dw en_regCase5
  203. dw en_regCase6
  204. dw en_regCase7
  205. public emulate8087:
  206. (* AL contains 0..7, the op code number, and AH contains mod/r/m
  207. DL indicates if there was a segment override
  208. ES contains the segment of the segment override (if any)
  209. *)
  210. mov ss:[emws_resume_bp], bp
  211. mov sp, ss:[emws_tos]
  212. mov bx, 0C007H
  213. and bl, ah (* bl = regMode *)
  214. and bh, ah (* bh = disp *)
  215. xchg cx, ax (* ch = mod/R/M, cl = op *)
  216. cmp bh, 0C0H
  217. jae en_NotMemoryOperand
  218. en_memoryOperand:
  219. sub ax, ax
  220. shl bl, 1
  221. cmp bh, 40H
  222. mov bh, 0
  223. ja en_dispCase_80
  224. je en_dispCase_40
  225. en_dispCase_00:
  226. cmp bl, 6*2
  227. jne en_dispCaseEnd
  228. lodsw
  229. mov di, [bp][oldDS]
  230. jmp en_checkSegFix
  231. en_dispCase_40:
  232. lodsb
  233. cbw
  234. jmp cs:[en_regCaseSwitch][bx]
  235. en_dispCase_80:
  236. lodsw
  237. en_dispCaseEnd:
  238. jmp cs:[en_regCaseSwitch][bx]
  239. en_regCase0:
  240. add ax, [bp][oldBX]
  241. add ax, [bp][oldSI]
  242. mov di, [bp][oldDS]
  243. jmp en_regCaseEnd
  244. en_regCase1:
  245. add ax, [bp][oldBX]
  246. add ax, [bp][oldDI]
  247. mov di, [bp][oldDS]
  248. jmp en_regCaseEnd
  249. en_regCase2:
  250. add ax, [bp][oldBP]
  251. add ax, [bp][oldSI]
  252. mov di, ss
  253. jmp en_regCaseEnd
  254. en_regCase3:
  255. add ax, [bp][oldBP]
  256. add ax, [bp][oldDI]
  257. mov di, ss
  258. jmp en_regCaseEnd
  259. en_regCase4:
  260. add ax, [bp][oldSI]
  261. mov di, [bp][oldDS]
  262. jmp en_regCaseEnd
  263. en_regCase5:
  264. add ax, [bp][oldDI]
  265. mov di, [bp][oldDS]
  266. jmp en_regCaseEnd
  267. en_regCase6:
  268. add ax, [bp][oldBP]
  269. mov di, ss
  270. jmp en_regCaseEnd
  271. en_regCase7:
  272. add ax, [bp][oldBX]
  273. mov di, [bp][oldDS]
  274. en_regCaseEnd:
  275. en_checkSegFix:
  276. mov [bp][oldIP], si (* CSIP correct for next instruction *)
  277. xchg si, ax (* operandPtr := es:si *)
  278. cmp dl, true (* was segFix present ? *)
  279. je en_wasFixed
  280. mov es, di
  281. en_wasFixed:
  282. push ss
  283. pop ds
  284. (*mov [emws_dataPtr][0], si*)
  285. (*mov [emws_dataPtr][2], es*)
  286. jmp en_gotoLong
  287. en_NotMemoryOperand:
  288. mov [bp][oldIP], si (* CSIP correct for next instruction *)
  289. mov ax, ss
  290. mov ds, ax
  291. mov es, ax (* ss=cs=ds=es *)
  292. en_gotoLong:
  293. test cl, 1
  294. jz e287_Arith
  295. cmp ch, 3 * 40H
  296. jb e287_Load_Store
  297. test ch, 20H
  298. jz e287_Register_Move
  299. other_case:
  300. mov bx, 6
  301. and bl, cl
  302. jmp cs:[other_jumps][bx]
  303. (*public*) e287_Register_Move :
  304. (* which register ?*)
  305. mov al, emu_temp_size
  306. mul bl (* register number*)
  307. add ax, sp
  308. xchg si, ax (* operandPtr := es : si*)
  309. mov bx, 18H
  310. and bl, ch
  311. and cl, 06H
  312. or bl, cl
  313. cld
  314. mov cx, emu_temp_size/2
  315. jmp near cs:[remo_case][bx]
  316. (*public*) e287_Arith :
  317. mov bp, cx (* save a copy of cx in BP*)
  318. cmp ch, 0C0H
  319. jnb arith_reg
  320. sub sp, emu_temp_size
  321. mov di, sp
  322. mov bx, 6
  323. and bl, cl (* switch according to TYP field*)
  324. call cs:[arith_push][bx]
  325. mov bx, sp
  326. lea ax, [bx][emu_temp_size]
  327. mov dx, ax
  328. mov si, emu_temp_size (* si = popAfter*)
  329. jmp arith_action
  330. arith_reg:
  331. mov al, emu_temp_size
  332. mul bl (* register number*)
  333. add ax, sp
  334. xchg bx, ax (* op2 := ^register [bl];*)
  335. mov ax, sp
  336. test cl, 4 (* test .Reverse bit*)
  337. mov dx, ax
  338. jz arith_notReversed
  339. mov dx, bx
  340. arith_notReversed:
  341. arith_testPop:
  342. sub si, si (* si = popAfter*)
  343. test cl, 2 (* isolate the .Pop bit*)
  344. jz arith_action
  345. mov si, emu_temp_size
  346. arith_action:
  347. push ss
  348. pop es (* es = ds = ss*)
  349. and bp, 3800H
  350. mov cl, 6
  351. rol bp, cl (* BP = word index [opb]*)
  352. mov cx, (*offset*) arith_end (* optimise return from cases*)
  353. jmp near cs:[arith_actCase][bp]
  354. (*public*) e287_Load_Store :
  355. (* these two statements are an optimised preparation for the case switches*)
  356. mov bp, 6
  357. and bp, cx (* select CL.typ (same as CL.xtp)*)
  358. (* Note BP is conserved by subroutine calls*)
  359. test ch, 20H
  360. jnz ldst_extended
  361. test ch, 10H
  362. jnz ldst_store
  363. test ch, 08H
  364. jnz ldst_pushThenPop
  365. sub sp, emu_temp_size
  366. mov di, sp
  367. call cs:[ldst_loadCase][bp]
  368. (* jmp ldst_end*)
  369. ldst_pushThenPop: (*{ reserved, logically No-Op's }*)
  370. jmp ldst_end
  371. ldst_store:
  372. mov di, sp
  373. xchg si, di
  374. push cx
  375. call cs:[ldst_storeCase][bp]
  376. pop cx
  377. test ch, 08H (* pop required ?*)
  378. jz ldst_end
  379. add sp, emu_temp_size
  380. jmp ldst_end
  381. ldst_extended:
  382. mov ax, 08H
  383. and al, ch (* select CH.x*)
  384. or bp, ax (* BP = 2 * x|xtp*)
  385. test ch, 10H
  386. jnz ldst_xStore
  387. call cs:[ldst_xPushCase][bp]
  388. jmp ldst_end
  389. ldst_xStore:
  390. xchg si, di
  391. call cs:[ldst_xStoreCase][bp]
  392. ldst_end:
  393. jmp near e287_Exit
  394. (*public*) e287_Exit :
  395. mov ss:[emws_tos], sp (* record the e87 registers' new stack top *)
  396. ExceptionExit:
  397. mov bp, ss:[emws_resume_bp]
  398. jmp ss:[emws_resume_ip]
  399. (*INCLUDE E287ADSU.ASM*)
  400. (* algorithm notes*)
  401. (* subtraction is done as (a - b) = (a + (-b))*)
  402. (* align the lesser operand rightwards to match the greater.*)
  403. (* add them together, realign fraction rounded if overflow.*)
  404. (* The arithmetic is done using 5 bytes (dx:ax:CH), with the least significant*)
  405. (* byte (CH) holding the right-shifted part of the lesser of the two numbers.*)
  406. (* Actually only 2 bits are required, but use of a whole byte is easier.*)
  407. (* This 5th byte comes into play if the numbers are nearly equal. At the end*)
  408. (* of calculation the 5th byte is rounded off and a 4-byte result is*)
  409. (* delivered.*)
  410. x_p = 4+nearParam
  411. y_p = 2+nearParam
  412. z_p = 0+nearParam (* z := x +- y*)
  413. paramsize = 6
  414. align = -1 (* used for shift counts*)
  415. excess = -2 (* bits 64..71 of calculation*)
  416. zExp = -4 (* effective exponent of z*)
  417. zSign = -5 (* effective sign of z*)
  418. op = -6 (* are we to add or to subtract*)
  419. (*public*) emu_Subtract : (*NEAR*)
  420. mov cl, negative_sign
  421. jmp @Shared_Add_Sub
  422. (*public*) emu_Add : (*NEAR*)
  423. mov cl, positive_sign
  424. @Shared_Add_Sub : (*NEAR*)
  425. push bp; mov bp,sp; lea sp,[bp][op]; push si; push di
  426. mov si, [bp][x_p]
  427. mov di, [bp][y_p]
  428. mov al, cl
  429. xor al, [di][emu_sign]
  430. xor al, [si][emu_sign]
  431. mov [bp][op], al (* op := negative if the operands are to*)
  432. (* be subtracted*)
  433. (* op := positive if same sign, addition.*)
  434. mov ax, [si][emu_exponent]
  435. mov bx, [di][emu_exponent]
  436. cmp ax, bx
  437. jge @share_x_ge_y
  438. @share_y_gt_x:
  439. xor cl, [di][emu_sign]
  440. xchg ax, bx
  441. xchg si, di
  442. jmp @share_limits
  443. @share_x_ge_y:
  444. mov cl, [si][emu_sign]
  445. @share_limits:
  446. (* si points to the larger, di to the smaller (or near-equal)*)
  447. (* ax exponent bx exponent*)
  448. mov [bp][zSign], cl (* larger's sign dominates result*)
  449. mov cx, [si][emu_exponent] (* the larger's exponent*)
  450. mov [bp][zExp], cx (* will dominate result*)
  451. cmp ax, infinite_exponent
  452. jge @larger_is_result
  453. cmp bx, zero_exponent
  454. jle @larger_is_result
  455. @share_align: (* now align the smaller number to match the larger.*)
  456. sub ax, bx
  457. cmp ax, 64
  458. jle @share_normal
  459. @larger_is_result:
  460. mov ax, [si][emu_fraction][w0]
  461. mov bx, [si][emu_fraction][w1]
  462. mov cx, [si][emu_fraction][w2]
  463. mov dx, [si][emu_fraction][w3]
  464. jmp near @shared_end
  465. @share_normal:
  466. mov [bp][align], al
  467. mov ax, [di][emu_fraction][w0]
  468. mov bx, [di][emu_fraction][w1]
  469. mov cx, [di][emu_fraction][w2]
  470. mov dx, [di][emu_fraction][w3]
  471. mov byte [bp][excess], 0
  472. sub byte [bp][align], 8
  473. jl @align_bits
  474. @align_bytes:
  475. mov [bp][excess], al
  476. mov al, ah
  477. mov ah, bl
  478. mov bl, bh
  479. mov bh, cl
  480. mov cl, ch
  481. mov ch, dl
  482. mov dl, dh
  483. mov dh, 0
  484. sub byte [bp][align], 8
  485. jge @align_bytes
  486. @align_bits:
  487. and byte [bp][align], 7
  488. jz @align_end
  489. @align_bit_shift:
  490. shr dx, 1
  491. rcr cx, 1
  492. rcr bx, 1
  493. rcr ax, 1
  494. rcr byte [bp][excess], 1
  495. dec byte [bp][align]
  496. jnz @align_bit_shift
  497. @align_end:
  498. sub di, di (* convenient zero*)
  499. cmp byte [bp][op], positive_sign (* add or subtract*)
  500. jne @share_do_subtract
  501. (* start of addition*)
  502. @share_do_add:
  503. add ax, [si][emu_fraction][w0]
  504. adc bx, [si][emu_fraction][w1]
  505. adc cx, [si][emu_fraction][w2]
  506. adc dx, [si][emu_fraction][w3]
  507. jnc @shared_round (* normalise if overflowed*)
  508. rcr dx, 1
  509. rcr cx, 1
  510. rcr bx, 1
  511. rcr ax, 1
  512. rcr byte [bp][excess], 1
  513. inc word [bp][zExp]
  514. jmp @shared_round
  515. (* end of addition*)
  516. (* start of subtraction*)
  517. @share_do_subtract:
  518. xor byte [bp][zSign], negative_sign
  519. sub ax, [si][emu_fraction][w0] (* smaller - larger*)
  520. sbb bx, [si][emu_fraction][w1] (* is the*)
  521. sbb cx, [si][emu_fraction][w2] (* negative of*)
  522. sbb dx, [si][emu_fraction][w3] (* the expected result*)
  523. (* Since we compared only exponents when checking which is "larger", in*)
  524. (* the case where exponents were equal there is a chance the fraction is*)
  525. (* smaller. Since the smaller is supposed to be in registers, the subtraction*)
  526. (* would give a negative result (carry=borrow bit flagged) if they are the*)
  527. (* correct way around.*)
  528. jnb @sub_align (* "smaller" actually larger*)
  529. (* "larger" was larger, so negate to get correct result.*)
  530. xor byte [bp][zSign], negative_sign
  531. not dx
  532. not cx (* use the identity -x = not(x) + 1*)
  533. not bx
  534. not ax
  535. neg byte [bp][excess]
  536. cmc
  537. adc ax, di
  538. adc bx, di
  539. adc cx, di
  540. adc dx, di
  541. @sub_align:
  542. mov si, 64
  543. or dh, dh
  544. js @shared_round
  545. (* Bit shifting appears inefficient. However, note that only when x and y*)
  546. (* are nearly equal will their difference require large realignments, and*)
  547. (* such cases are unlikely. It does not seem worthwhile to provide byte*)
  548. (* or word shifts.*)
  549. @sub_bit_shift:
  550. dec si
  551. jz @sub_result_zero
  552. shl byte [bp][excess], 1
  553. rcl ax, 1
  554. rcl bx, 1
  555. rcl cx, 1
  556. adc dx, dx
  557. jns @sub_bit_shift
  558. sub si, 64
  559. add [bp][zExp], si
  560. jmp @shared_round
  561. @sub_result_zero:
  562. mov word [bp][zExp], zero_exponent
  563. mov byte [bp][zSign], positive_sign
  564. jmp @shared_end
  565. (* end of subtraction*)
  566. (* shared code for both add and subtract*)
  567. @shared_round:
  568. shl byte [bp][excess], 1
  569. adc ax, di
  570. adc bx, di
  571. adc cx, di
  572. adc dx, di
  573. jnc @roundEnd
  574. rcr dx, 1 (* note dx:cx:bx:ax must be 8000:0:0:0*)
  575. inc word [bp][zExp] (* if you get to here*)
  576. @roundEnd:
  577. cmp word [bp][zExp], infinite_exponent
  578. jge @overflow
  579. cmp word [bp][zExp], zero_exponent
  580. jle @underflow
  581. @shared_end:
  582. cld
  583. mov di, [bp][z_p]
  584. stosw
  585. xchg ax, bx
  586. stosw
  587. xchg ax, cx
  588. stosw
  589. xchg ax, dx
  590. stosw
  591. mov ax, [bp][zExp]
  592. stosw
  593. mov al, [bp][zSign]
  594. stosb
  595. pop di; pop si; mov sp,bp; pop bp
  596. ret paramsize
  597. @overflow:
  598. mov ch, fe_Overflow
  599. mov word [bp][zExp], infinite_exponent
  600. jmp @extreme
  601. @underflow:
  602. mov ch, fe_Underflow
  603. mov word [bp][zExp], zero_exponent
  604. @extreme:
  605. call e287_Exception
  606. mov byte [bp][zSign], positive_sign (* extremes always positive*)
  607. sub ax, ax
  608. mov bx, ax
  609. mov cx, ax
  610. mov dx, ax
  611. jmp @shared_end
  612. (*INCLUDE E287ATAN.ASM*)
  613. pi_by_2 : dw 0C235H, 2168H, 0DAA2H, 0C90FH, 1; db positive_sign, 0
  614. (* Polynomial coefficients for Chebyshev approx. to ArcTan (x) / x,*)
  615. (* in terms of every second power.*)
  616. poly_terms : dw 8
  617. poly_coeffs :
  618. dw 0H, 0H, 0H, 0H, 0H; db positive_sign, 0 (* 1.0*)
  619. dw 05557H, 05555H, 05555H, 0155H, 0H; db negative_sign, 0
  620. dw 032BEH, 03333H, 03333H, 03H, 0H; db positive_sign, 0
  621. dw 01E7DH, 09249H, 0924H, 0H, 0H; db negative_sign, 0
  622. dw 0FEBCH, 071C6H, 01CH, 0H, 0H; db positive_sign, 0
  623. dw 0FF5CH, 05D16H, 0H, 0H, 0H; db negative_sign, 0
  624. dw 0BBD8H, 013AH, 0H, 0H, 0H; db positive_sign, 0
  625. dw 00C0AH, 04H, 0H, 0H, 0H; db negative_sign, 0
  626. numOfIntervals = 4
  627. topInterval = 3
  628. topsOf :
  629. dw 00000H, 00000H, 00000H, 0E700H, -3; db positive_sign, 0
  630. dw 0A4BDH, 07BD6H, 064EEH, 0B35CH, -1; db positive_sign, 0
  631. dw 085B5H, 0FC47H, 03074H, 0A111H, 0; db positive_sign, 0
  632. one :
  633. dw 00000H, 00000H, 00000H, 08000H, 1; db positive_sign, 0
  634. arcTans :
  635. dw 0FA9CH, 0B064H, 01DB2H, 0E607H, -2; db positive_sign, 0
  636. dw 0FA9CH, 0B064H, 01DB2H, 0E607H, -1; db positive_sign, 0
  637. dw 0BBF5H, 0044BH, 05646H, 0AC85H, 0; db positive_sign, 0
  638. middles :
  639. dw 06EE6H, 01FD9H, 009BDH, 0E9FAH, -2; db positive_sign, 0
  640. dw 07B8DH, 0BD35H, 0845BH, 0F6DDH, -1; db positive_sign, 0
  641. dw 0D57FH, 00235H, 080DBH, 0CC73H, 0; db positive_sign, 0
  642. (* algorithm notes*)
  643. (* Firstly we take the ratio z = x / y, with x and y the parameters. We only*)
  644. (* need z.*)
  645. (* A Chebyshev polynomial expansion is used for a very narrow domain*)
  646. (* of arguments, -1/N .. +1/N, where N is on the order of 8. The remaining*)
  647. (* range +1/N .. 1.0 is mapped onto the smaller interval.*)
  648. (* Beginning with high-school trigonometry:*)
  649. (* Tan (a + b) = (Tan (a) + Tan (b)) / (1 - Tan(a) * Tan(b))*)
  650. (* We seek to find:*)
  651. (* psi = ArcTan (z)*)
  652. (* let z = (centre + v) / (1 - centre * v)*)
  653. (* where the closest value of centre is chosen by comparing z to a table*)
  654. (* of bounds of intervals from 0 to infinity, and v is a number in the*)
  655. (* range -1/N .. +1/N. The intervals and centres are pre-computed to*)
  656. (* ensure that v will be in this range.*)
  657. (* We can calculate v by re-arranging the algebra:*)
  658. (* v = (z - centre) / (1 + centre * z)*)
  659. (* The importance of this formula is that if*)
  660. (* theta = ArcTan (centre) -- pre-calculated table of theta values*)
  661. (* phi = ArcTan (v) -- calculated by rapid polynomial*)
  662. (* then*)
  663. (* ArcTan (z) = theta + phi*)
  664. (* which is the answer we seek.*)
  665. (* VAR*)
  666. (* sign : (positive_sign, negative_sign);*)
  667. (* theta : 0 .. topInterval;*)
  668. (* result : emu_temp;*)
  669. (* BEGIN*)
  670. (* z := x / y;*)
  671. (* theta := 0;*)
  672. (* WHILE (theta < top_interval) AND (x > topsOf [theta]) DO theta := theta + 1;*)
  673. (* IF theta = 0 THEN result := ArcTan (z)*)
  674. (* ELSE*)
  675. (* theta := theta - 1;*)
  676. (* z := (z - middles [theta]) / (1 + z * middles [theta]);*)
  677. (* result := ArcTan (z) + arcTans [theta];*)
  678. (* emu_PAtan := result;*)
  679. (* END;*)
  680. (*public*) emu_PAtan : (*NEAR*)
  681. _theta = -2
  682. _temp = _theta - emu_temp_size
  683. push bp; mov bp,sp; lea sp,[bp][_temp]; push si; push di
  684. push si
  685. push di
  686. push si
  687. call emu_Divide
  688. mov byte [bp][_theta], 0
  689. mov di, (*offset*) topsOf (* di := ^ topsOf [theta]*)
  690. at@while:
  691. cmp byte [bp][_theta], topInterval
  692. jae at@whileEnd
  693. push di (*1*)
  694. push si
  695. call copy_di_to_temp
  696. push di
  697. call emu_Compare
  698. pop di (*1*)
  699. cmp ax, e287_greater
  700. jne at@whileEnd
  701. inc byte [bp][_theta]
  702. add di, emu_temp_size
  703. jmp at@while
  704. at@whileEnd:
  705. cmp byte [bp][_theta], 0
  706. jne at@notSmall
  707. at@small:
  708. call ArcTan (* _result := ArcTan (si)*)
  709. jmp at@normalEnd
  710. at@notSmall:
  711. dec byte [bp][_theta] (* theta := theta - 1;*)
  712. (* z := (z - middles [theta]) / (1 + z * middles [theta]);*)
  713. mov al, emu_temp_size
  714. mul byte [bp][_theta]
  715. add ax, (*offset*) middles
  716. xchg di, ax
  717. sub sp, emu_temp_size
  718. mov ax, sp
  719. push si
  720. call copy_di_to_temp
  721. push di
  722. push ax
  723. call emu_Subtract
  724. push si
  725. push di
  726. push si
  727. call emu_Multiply
  728. mov di, one
  729. call copy_di_to_temp
  730. push di
  731. push si
  732. push si
  733. call emu_Add
  734. mov ax, sp
  735. push ax
  736. push si
  737. push si
  738. call emu_Divide
  739. add sp, emu_temp_size
  740. call ArcTan
  741. mov al, emu_temp_size
  742. mul byte [bp][_theta]
  743. add ax, (*offset*) arcTans
  744. xchg di, ax
  745. call copy_di_to_temp
  746. push di
  747. push si
  748. push si
  749. call emu_Add
  750. at@normalEnd:
  751. at@end:
  752. pop di; pop si; mov sp,bp; pop bp
  753. ret 0
  754. copy_di_to_temp:
  755. push ax
  756. mov ax, cs:[di]
  757. mov [bp][_temp],ax
  758. mov ax, cs:[di][2]
  759. mov [bp][_temp][2],ax
  760. mov ax, cs:[di][4]
  761. mov [bp][_temp][4],ax
  762. mov ax, cs:[di][6]
  763. mov [bp][_temp][6],ax
  764. mov ax, cs:[di][8]
  765. mov [bp][_temp][8],ax
  766. mov ax, cs:[di][0AH]
  767. mov [bp][_temp][0AH],ax
  768. lea di, [bp][_temp]
  769. pop ax
  770. ret 0
  771. (* FUNCTION ArcTan ( _z : emu_temp ) _result : emu_temp;*)
  772. (* { Polynomial evaluation of ArcTan of a number within a small domain*)
  773. (* centred upon zero.*)
  774. (* BEGIN*)
  775. (* _result := _z * Poly ( _z * _z, poly_terms, poly_coeffs);*)
  776. (* END;*)
  777. ArcTan :
  778. (* parameter and result both at [si]*)
  779. linear_bound = -32
  780. push si
  781. push di
  782. call emup_Push
  783. cmp word [si][emu_exponent], linear_bound
  784. jg art@nonLinear
  785. mov di, si
  786. call emu_Pop (* ArcTan (x) ~= x for very small x*)
  787. jmp art@end
  788. art@nonLinear:
  789. mov di, sp
  790. add word [di][emu_exponent], 3 (* the polynomial is designed*)
  791. (* for a *8 magnified parameter.*)
  792. call emup_Square_Fix
  793. push cs:[poly_terms] (* number of terms to evaluate*)
  794. mov ax, poly_coeffs
  795. push cs
  796. push ax
  797. call emup_Polynomial
  798. push di
  799. push si
  800. push si
  801. call emu_Multiply
  802. add sp, emu_temp_size (* pop Poly value off stack*)
  803. art@end:
  804. pop di
  805. pop si
  806. ret 0
  807. (*INCLUDE E287CNST.ASM*)
  808. (*
  809. one: dw 0, 0, 0, 8000H, 1; db positive_sign, 0
  810. *)
  811. Log2of10: dw 08AFEH, 0CD1BH, 0784BH, 0D49AH, 2; db positive_sign, 0
  812. Log2ofE: dw 0F0BBH, 05C17H, 03B29H, 0B8AAH, 1; db positive_sign, 0
  813. Pi: dw 0C235H, 2168H, 0DAA2H, 0C90FH, 2; db positive_sign, 0
  814. Log10of2: dw 0F799H, 0FBCFH, 09A84H, 09A20H, -1; db positive_sign, 0
  815. LogEof2: dw 079ACH, 0D1CFH, 017F7H, 0B172H, 0; db positive_sign, 0
  816. zero: dw 0, 0, 0, 0, zero_exponent; db positive_sign, 0
  817. (* All constants' procedures are in0-out1 pattern (see e287long.asm) and*)
  818. (* thus take no input and place their output at ss=ds=es:[di]*)
  819. (*public*) emu_1 : (*NEAR*)
  820. mov ax, (*offset*) one
  821. jmp MoveConstant
  822. (*public*) emu_Log2of10 : (*NEAR*)
  823. mov ax, (*offset*) Log2of10
  824. jmp MoveConstant
  825. (*public*) emu_Log2ofE : (*NEAR*)
  826. mov ax, (*offset*) Log2ofE
  827. jmp MoveConstant
  828. (*public*) emu_Pi : (*NEAR*)
  829. mov ax, (*offset*) Pi
  830. jmp MoveConstant
  831. (*public*) emu_Log10of2 : (*NEAR*)
  832. mov ax, (*offset*) Log10of2
  833. jmp MoveConstant
  834. (*public*) emu_LogEof2 : (*NEAR*)
  835. mov ax, (*offset*) LogEof2
  836. jmp MoveConstant
  837. (*public*) emu_0 : (*NEAR*)
  838. mov ax, (*offset*) zero
  839. (* jmp MoveConstant*)
  840. MoveConstant:
  841. push ds
  842. push cs
  843. pop ds
  844. xchg si, ax
  845. cld
  846. mov cx, emu_temp_size / 2
  847. rep; movsw
  848. sub di, emu_temp_size (* restore original di*)
  849. xchg si, ax (* and si values*)
  850. pop ds
  851. ret 0
  852. (*public*) emu_Extreme : (*NEAR*)
  853. push di
  854. mov es:[di][emu_exponent], ax (* infinity or zero, chosen by caller*)
  855. mov byte es:[di][emu_sign], positive_sign
  856. sub ax, ax
  857. cld
  858. stosw (* zero fraction*)
  859. stosw
  860. stosw
  861. stosw
  862. pop di
  863. ret 0
  864. (*INCLUDE E287CNVT.ASM*)
  865. (* procedure to float an integer to yield a long temporary real*)
  866. (* input is an integer at es : [si]*)
  867. (* result is a temporary real at ds : [di]*)
  868. (* no exceptions.*)
  869. (*public*) emu_Float : (*NEAR*)
  870. mov ax, es : [si][w0]
  871. sub cx, cx (* convenient zero*)
  872. mov dx, positive_sign
  873. or ax, ax
  874. jl @fl_negative
  875. jg @fl_signed
  876. @fl_zero:
  877. mov bx, zero_exponent
  878. jmp @fl_end
  879. @fl_negative:
  880. neg ax
  881. mov dl, negative_sign
  882. @fl_signed:
  883. sub bx, bx
  884. xchg cx, ax
  885. @fl_shift:
  886. inc bx
  887. shr cx, 1
  888. rcr ax, 1
  889. jcxz @fl_aligned
  890. jmp @fl_shift
  891. @fl_aligned:
  892. @fl_end:
  893. mov [di][emu_sign][w0], dx
  894. mov [di][emu_exponent], bx
  895. mov [di][emu_fraction][w3], ax
  896. mov [di][emu_fraction][w2], cx (* cx = zero*)
  897. mov [di][emu_fraction][w1], cx
  898. mov [di][emu_fraction][w0], cx
  899. ret 0
  900. (*public*) emu_Round : (*NEAR*)
  901. (* Convert a long temporary floating point number to a 16 bit integer*)
  902. (* with fraction rounded according to current rounding control.*)
  903. (* Input operand at ds:[si]*)
  904. (* Result at es:[di]*)
  905. (* Side effects: may exit via exception*)
  906. mov cx, [si][emu_exponent]
  907. cmp cx, 15
  908. jg @ro_overflow
  909. cmp cx, zero_exponent
  910. jg @ro_standard
  911. @ro_zero:
  912. sub ax, ax
  913. jmp @ro_end
  914. @ro_overflow:
  915. mov ch, fe_Operand_Too_Big
  916. call e287_Exception
  917. mov ax, 8000H
  918. jmp @ro_end
  919. @ro_standard:
  920. mov bx, [si][emu_fraction][w3] (* ax:bx holds the*)
  921. sub ax, ax (* integer:fraction*)
  922. mov dx, ax (* dx collects the sticky bits*)
  923. cmp cx, 0
  924. jge @ro_getSticky
  925. shr bx, 1 (* ensure tiny numbers are*)
  926. rcr dx, 1 (* aligned <= 1/4*)
  927. @ro_getSticky:
  928. or dx, [si][emu_fraction][w0] (* stick the lesser*)
  929. or dx, [si][emu_fraction][w1] (* words all*)
  930. or dx, [si][emu_fraction][w2] (* together*)
  931. cmp cx, 0
  932. jle @ro_bitAligned
  933. @ro_bitLoop:
  934. shl bx, 1
  935. rcl ax, 1
  936. loop @ro_bitLoop
  937. @ro_bitAligned:
  938. or bl, dh (* BL is completely sticky*)
  939. or bl, dl (* bx is fraction byte + sticky byte*)
  940. mov cl, e287_roundingControl
  941. and cl, [emws_control][by1] (* get rounding control*)
  942. cmp cl, e287_chop
  943. je @ro_chop
  944. cmp cl, e287_round
  945. je @ro_roundNear
  946. add cl, [si][emu_sign][by0]
  947. cmp cl, e287_floor + positive_sign
  948. je @ro_chop
  949. cmp cl, e287_ceiling + negative_sign
  950. je @ro_chop
  951. @ro_roundUp: (* this is what sticky bits are for !*)
  952. neg bx (* sets carry if any bit not zero*)
  953. adc ax, 0
  954. js @ro_overflow
  955. jmp @ro_setSign
  956. @ro_roundNear:
  957. mov dl, 1 (* banker's rounding needs test*)
  958. and dl, al (* of ls bit of integer*)
  959. or bl, dl
  960. add bx, 7FFFH
  961. adc ax, 0
  962. js @ro_overflow
  963. @ro_chop:
  964. @ro_setSign:
  965. cmp byte [si][emu_sign], negative_sign
  966. jne @ro_end
  967. neg ax
  968. @ro_end:
  969. mov es : [di][w0], ax
  970. ret 0
  971. (* algorithm notes*)
  972. (* The scaling operation is quite simple, just adding an integer to*)
  973. (* the exponent of the floating point number. The complications are*)
  974. (* that the "integer" is a real in tos(1) which must first be truncated,*)
  975. (* then to check against scaling zeroes and infinities, and to report*)
  976. (* on underflows or overflows created.*)
  977. (*public*) emu_Scale : (*NEAR*)
  978. push bp; mov bp,sp; push si; push di
  979. (* first we truncate sc_n*)
  980. mov cx, [si][emu_exponent]
  981. cmp cx, 15
  982. jg sc@overScale
  983. or cx, cx
  984. jg sc@non_zero
  985. sub ax, ax
  986. jmp sc@truncated
  987. sc@overScale:
  988. mov ch, fe_Operand_Too_Big
  989. call e287_Exception
  990. mov ax, 7FFFH (* largest signable magnitude*)
  991. jmp sc@signScale
  992. sc@non_zero:
  993. mov ax, [si][emu_fraction][w3]
  994. neg cl
  995. add cl, 16
  996. shr ax, cl
  997. sc@signScale:
  998. cmp byte [si][emu_sign], negative_sign
  999. jne sc@truncated
  1000. neg ax
  1001. sc@truncated:
  1002. (* now apply scale to tos' exponent*)
  1003. mov cx, [di][emu_exponent]
  1004. cmp cx, zero_exponent
  1005. jle sc@end (* zero * anything = zero*)
  1006. cmp cx, infinite_exponent
  1007. jge sc@end (* infinity cannot be changed*)
  1008. add cx, ax
  1009. jo sc@under_or_overflow
  1010. cmp cx, zero_exponent
  1011. jle sc@underflow
  1012. cmp cx, infinite_exponent
  1013. jge sc@overflow
  1014. mov [di][emu_exponent], cx
  1015. sc@end:
  1016. pop di; pop si; pop bp
  1017. ret 0
  1018. sc@under_or_overflow:
  1019. test ax,ax
  1020. jl @underflow
  1021. sc@overflow:
  1022. mov ch, fe_Overflow
  1023. call e287_Exception
  1024. mov ax, infinite_exponent
  1025. jmp sc@extreme
  1026. sc@underflow:
  1027. mov ch, fe_Underflow
  1028. call e287_Exception
  1029. mov ax, zero_exponent
  1030. sc@extreme:
  1031. call emu_Extreme
  1032. jmp sc@end
  1033. (*
  1034. (*INCLUDE E287COMP1.ASM*)
  1035. (* second parameter in cs *)
  1036. (*public*) emu_Compare1 : (*NEAR*)
  1037. co_x_p = 2+nearParam (* based on ds*)
  1038. co_y_p = 0+nearParam (* based on cs*)
  1039. co_paramsize = 4
  1040. (* result in [emws_status]*)
  1041. push bp; mov bp,sp; push si; push di
  1042. mov si, [bp][co_x_p]
  1043. mov di, [bp][co_y_p]
  1044. mov ax, [si][emu_exponent]
  1045. cmp ax, cs:[di][emu_exponent]
  1046. jge @1ax_is_greater
  1047. mov ax, cs:[di][emu_exponent]
  1048. @1ax_is_greater:
  1049. cmp ax, zero_exponent
  1050. jle @1both_equal (* both must be zero*)
  1051. cmp ax, infinite_exponent
  1052. jge @1incomparable (* infinities are incomparable*)
  1053. mov cl, [si][emu_sign]
  1054. cmp cl, cs:[di][emu_sign]
  1055. jl @1x_greater (* positive_sign < negative_sign*)
  1056. jg @1x_lesser
  1057. mov ax, [si][emu_exponent]
  1058. cmp ax, cs:[di][emu_exponent]
  1059. jl @1x_smaller
  1060. jg @1x_larger
  1061. mov ax, [si][emu_fraction][w3]
  1062. cmp ax, cs:[di][emu_fraction][w3]
  1063. jne co@1notEqual
  1064. mov ax, [si][emu_fraction][w2]
  1065. cmp ax, cs:[di][emu_fraction][w2]
  1066. jne co@1notEqual
  1067. mov ax, [si][emu_fraction][w1]
  1068. cmp ax, cs:[di][emu_fraction][w1]
  1069. jne co@1notEqual
  1070. mov ax, [si][emu_fraction][w0]
  1071. cmp ax, cs:[di][emu_fraction][w0]
  1072. jne co@1notEqual
  1073. @1both_equal:
  1074. mov ax, e287_equal
  1075. jmp @1co_end
  1076. co@1notEqual:
  1077. ja @1x_larger
  1078. @1x_smaller:
  1079. cmp cl, positive_sign
  1080. jne @1x_greater
  1081. @1x_lesser:
  1082. mov ax, e287_lesser
  1083. jmp @1co_end
  1084. @1x_larger:
  1085. cmp cl, positive_sign
  1086. jne @1x_lesser
  1087. @1x_greater:
  1088. mov ax, e287_greater
  1089. jmp @1co_end
  1090. @1incomparable:
  1091. mov ax, e287_incomparable
  1092. @1co_end:
  1093. mov [emws_status][by1], ah
  1094. pop di; pop si; pop bp
  1095. ret co_paramsize
  1096. *)
  1097. (*INCLUDE E287COMP.ASM*)
  1098. (* algorithm notes:*)
  1099. (* first check for infinities. Infinities are incomparable.*)
  1100. (* Next check for sign. If signs differ, and not both numbers are zero,*)
  1101. (* then the positive number is the greater.*)
  1102. (* Check for the greater absolute value, beginning with the exponent then*)
  1103. (* working down through the fraction. If not both are equal, then if both*)
  1104. (* are positive the greater maginitude is the greater, else if negative*)
  1105. (* the greater magnitude is lesser.*)
  1106. (*public*) emu_Compare : (*NEAR*)
  1107. co_x_p = 2+nearParam (* based on ds*)
  1108. co_y_p = 0+nearParam (* based on ds*)
  1109. co_paramsize = 4
  1110. (* result in [emws_status]*)
  1111. push bp; mov bp,sp; push si; push di
  1112. mov si, [bp][co_x_p]
  1113. mov di, [bp][co_y_p]
  1114. mov ax, [si][emu_exponent]
  1115. cmp ax, [di][emu_exponent]
  1116. jge @ax_is_greater
  1117. mov ax, [di][emu_exponent]
  1118. @ax_is_greater:
  1119. cmp ax, zero_exponent
  1120. jle @both_equal (* both must be zero*)
  1121. cmp ax, infinite_exponent
  1122. jge @incomparable (* infinities are incomparable*)
  1123. mov cl, [si][emu_sign]
  1124. cmp cl, [di][emu_sign]
  1125. jl @x_greater (* positive_sign < negative_sign*)
  1126. jg @x_lesser
  1127. mov ax, [si][emu_exponent]
  1128. cmp ax, [di][emu_exponent]
  1129. jl @x_smaller
  1130. jg @x_larger
  1131. mov ax, [si][emu_fraction][w3]
  1132. cmp ax, [di][emu_fraction][w3]
  1133. jne co@notEqual
  1134. mov ax, [si][emu_fraction][w2]
  1135. cmp ax, [di][emu_fraction][w2]
  1136. jne co@notEqual
  1137. mov ax, [si][emu_fraction][w1]
  1138. cmp ax, [di][emu_fraction][w1]
  1139. jne co@notEqual
  1140. mov ax, [si][emu_fraction][w0]
  1141. cmp ax, [di][emu_fraction][w0]
  1142. jne co@notEqual
  1143. @both_equal:
  1144. mov ax, e287_equal
  1145. jmp @co_end
  1146. co@notEqual:
  1147. ja @x_larger
  1148. @x_smaller:
  1149. cmp cl, positive_sign
  1150. jne @x_greater
  1151. @x_lesser:
  1152. mov ax, e287_lesser
  1153. jmp @co_end
  1154. @x_larger:
  1155. cmp cl, positive_sign
  1156. jne @x_lesser
  1157. @x_greater:
  1158. mov ax, e287_greater
  1159. jmp @co_end
  1160. @incomparable:
  1161. mov ax, e287_incomparable
  1162. @co_end:
  1163. mov [emws_status][by1], ah
  1164. pop di; pop si; pop bp
  1165. ret co_paramsize
  1166. (* A very simple procedure.*)
  1167. (* Compare_Zero :=*)
  1168. (* IF x = 0 THEN equal*)
  1169. (* ELSE x = infinity THEN incomparable*)
  1170. (* ELSE x < 0 THEN lesser*)
  1171. (* ELSE greater;*)
  1172. (* with apologies to Algol-68, Prof. Dijkstra, and P. B. Hansen for the syntax.*)
  1173. (*public*) emu_Compare_Zero : (*NEAR*)
  1174. (* result in ax and [emws_status]*)
  1175. mov ax, e287_equal
  1176. cmp word [si][emu_exponent], zero_exponent
  1177. jle cz@end
  1178. mov ax, e287_incomparable
  1179. cmp word [si][emu_exponent], infinite_exponent
  1180. jge cz@end
  1181. mov ax, e287_lesser
  1182. cmp byte [si][emu_sign], negative_sign
  1183. je cz@end
  1184. mov ax, e287_greater
  1185. cz@end:
  1186. mov [emws_status][by1], ah
  1187. ret 0
  1188. (* Another simple procedure.*)
  1189. (* XAM :=*)
  1190. (* IF x = 0 THEN plusZero*)
  1191. (* ELSE x = infinity THEN plusInfinity*)
  1192. (* ELSE x < 0 THEN minusNormal*)
  1193. (* ELSE plusNormal;*)
  1194. (*public*) emu_XAM : (*NEAR*)
  1195. (* result in ax and [emws_status]*)
  1196. mov ax, e287_plusZero
  1197. cmp word [si][emu_exponent], zero_exponent
  1198. jle xa@end
  1199. mov ax, e287_plusInfinity
  1200. cmp word [si][emu_exponent], infinite_exponent
  1201. jge xa@end
  1202. mov ax, e287_minusNormal
  1203. cmp byte [si][emu_sign], negative_sign
  1204. je xa@end
  1205. mov ax, e287_plusNormal
  1206. xa@end:
  1207. mov [emws_status][by1], ah
  1208. ret 0
  1209. (*INCLUDE E287DCML.ASM*)
  1210. (* Packed Decimal Format*)
  1211. (* The format used by the 8087/287 coprocessors uses 10 bytes to hold a*)
  1212. (* signed 18-digit decimal integer. The sign occupies the 79th (most*)
  1213. (* significant) bit (1 = negative), the bits 72..78 are don't cares (always*)
  1214. (* generated as zeroes by this software), and the 4-bit groups 68..71,*)
  1215. (* 64..67, .., 0..3 are the decimal digits in decreasing significance.*)
  1216. (* The number is an integer, so the least significant digit is always*)
  1217. (* interpreted as the units' digit. The Intel co-processors do not*)
  1218. (* directly handle decimal fractions or floating points.*)
  1219. (*packedDecimal STRUC*)
  1220. pdec_digits = 0 (*db 9 dup (?)*)
  1221. pdec_sign = 9 (*db ?*)
  1222. (*packedDecimal ENDS*)
  1223. (* FUNCTION emu_Push_Decimal ( VAR dec : packedDecimal) : emu_temp;*)
  1224. (* VAR*)
  1225. (* res : emu_temp;*)
  1226. (* FUNCTION WordDecToBin ( posn : cardinal );*)
  1227. (* BEGIN*)
  1228. (* WordDecToBin := ((dec.digit [posn + [3] * 10 +*)
  1229. (* dec.digit [posn + [2]) * 10 +*)
  1230. (* dec.digit [posn + [1]) * 10 + dec.digit [posn];*)
  1231. (* END;*)
  1232. WordDecToBin : (* posn supplied in si*)
  1233. (* result in ax*)
  1234. push bx
  1235. push cx
  1236. push dx
  1237. mov cl, 4
  1238. mov ch, 10
  1239. mov bx, es:[si][w0]
  1240. mov al, bh
  1241. shr al, cl
  1242. mul ch (* ax in range 0..90*)
  1243. mov dl, 0FH
  1244. and dl, bh
  1245. add al, dl
  1246. mul ch (* ax in range 0..990*)
  1247. mov dx, 0F0H
  1248. and dl, bl
  1249. shr dx, cl
  1250. add ax, dx
  1251. mov cx, 10
  1252. mul cx (* ax in range 0..9990*)
  1253. and bx, 0FH
  1254. add ax, bx
  1255. pop dx
  1256. pop cx
  1257. pop bx
  1258. ret 0
  1259. (* BEGIN*)
  1260. (* res.sign := dec.sign;*)
  1261. (* res.fraction := dec.digit [16] + tens [dec.digit [17];*)
  1262. (* res.fraction := res.fraction * 10000 + WordDecToBin (12);*)
  1263. (* res.fraction := res.fraction * 10000 + WordDecToBin (8);*)
  1264. (* res.fraction := res.fraction * 10000 + WordDecToBin (4);*)
  1265. (* res.fraction := res.fraction * 10000 + WordDecToBin (0);*)
  1266. (* res.exponent := 64;*)
  1267. (* Normalise (res);*)
  1268. (* END;*)
  1269. (*public*) emu_Push_Decimal : (*NEAR*)
  1270. (* inputs: packed decimal at es:[si]*)
  1271. (* outputs: emu_temp at ds:[di]*)
  1272. (* side effects: no exceptions reported.*)
  1273. push bp
  1274. mov bp, sp
  1275. push si
  1276. pu?decPtr = -2 (* saved value of si*)
  1277. push di
  1278. pu?resPtr = -4 (* saved value of di*)
  1279. (* res.sign := dec.sign;*)
  1280. mov al, es : [si][pdec_sign]
  1281. and ax, 80H (* separate the sign bit*)
  1282. rol al, 1 (* into bit 0*)
  1283. mov [di][emu_sign][w0], ax
  1284. (* res.fraction := dec.digit [16] + tens [dec.digit [17];*)
  1285. mov cl, 4
  1286. (* mov ah, 0 ; done above*)
  1287. mov al, es:[si][8][by0]
  1288. shl ax, cl
  1289. shr al, cl
  1290. aad (* AL := AL + 10 * AH, AH := 0*)
  1291. (* res.fraction := res.fraction * 10000 + WordDecToBin (12);*)
  1292. mov di, 10000
  1293. mul di
  1294. xchg bx, ax (* dx:bx in range 0..990000*)
  1295. lea si, [si][w3]
  1296. call WordDecToBin
  1297. add ax, bx
  1298. adc dl, dh (* dh=0 dx:ax in range 0..999,999*)
  1299. (* res.fraction := res.fraction * 10000 + WordDecToBin (8);*)
  1300. mov bx, dx
  1301. mul di
  1302. xchg ax, bx
  1303. mov cx, dx
  1304. mul di
  1305. add cx, ax
  1306. adc dl, dh (* dh=0 dx:cx:bx in range 0..9,999,990,000*)
  1307. sub si, 2
  1308. call WordDecToBin
  1309. add ax, bx
  1310. adc cx, 0
  1311. adc dl, dh (* dh=0 dx:cx:ax in range 0..9,999,999,999*)
  1312. (* res.fraction := res.fraction * 10000 + WordDecToBin (4);*)
  1313. push si
  1314. mov bx, dx (* bx:cx:ax*)
  1315. mul di
  1316. xchg ax, cx
  1317. mov si, dx (* si:cx*)
  1318. mul di
  1319. xchg ax, bx
  1320. xchg di, dx (* di:bx*)
  1321. mul dx (* dx:ax*)
  1322. add bx, si
  1323. adc di, ax (* dx = 0 di:bx:cx range 0..10^14 < 2^47*)
  1324. pop si
  1325. sub si, 2
  1326. call WordDecToBin
  1327. add ax, cx
  1328. adc bx, dx (* dx = 0*)
  1329. adc di, dx (* di:bx:ax range 0..10^14*)
  1330. (* res.fraction := res.fraction * 10000 + WordDecToBin (0);*)
  1331. mov si, 10000
  1332. mul si
  1333. xchg ax, bx
  1334. mov cx, dx (* cx:bx*)
  1335. mul si
  1336. xchg ax, si
  1337. xchg di, dx (* di:si*)
  1338. mul dx (* dx:ax*)
  1339. add cx, si
  1340. adc di, ax
  1341. adc dx, 0 (* dx:di:cx:bx range 0..10^18 < 2^60*)
  1342. mov si, [bp][pu?decPtr]
  1343. call WordDecToBin
  1344. add bx, ax
  1345. adc cx, 0
  1346. adc di, 0
  1347. adc dx, 0
  1348. (* res.exponent := 64;*)
  1349. mov ax, 64
  1350. (* Normalise (res);*)
  1351. pu@alignWord:
  1352. or dx, dx
  1353. jnz pu@alignBit
  1354. sub ax, 16
  1355. jz pu@zero
  1356. xchg dx, di
  1357. xchg di, cx
  1358. xchg cx, bx
  1359. jmp pu@alignWord
  1360. pu@alignBit:
  1361. js pu@finish
  1362. pu@anotherBit:
  1363. dec ax
  1364. shl bx, 1
  1365. rcl cx, 1
  1366. rcl di, 1
  1367. adc dx, dx
  1368. jns pu@anotherBit
  1369. pu@finish:
  1370. mov si, [bp][pu?resPtr]
  1371. mov [si][emu_fraction][w0], bx
  1372. mov [si][emu_fraction][w1], cx
  1373. mov [si][emu_fraction][w2], di
  1374. mov [si][emu_fraction][w3], dx
  1375. mov [si][emu_exponent], ax
  1376. pu@end:
  1377. pop di
  1378. pop si
  1379. mov sp, bp
  1380. pop bp
  1381. ret 0
  1382. pu@zero:
  1383. mov ax, zero_exponent
  1384. jmp pu@finish
  1385. public __emul_fbstp :
  1386. TempReal = -10
  1387. locals = 10
  1388. push bp
  1389. mov bp, sp
  1390. sub sp, locals
  1391. push bx
  1392. push cx
  1393. push dx
  1394. push di
  1395. push si
  1396. push ds
  1397. fld st(0), st(0)
  1398. fstp tbyte [bp][TempReal], st(0)
  1399. push ss
  1400. pop ds
  1401. push ss
  1402. pop es
  1403. lea si, [bp][TempReal]
  1404. mov di, ax
  1405. call emu_Pop_Decimal
  1406. pop ds
  1407. pop si
  1408. pop di
  1409. pop dx
  1410. pop cx
  1411. pop bx
  1412. mov sp, bp
  1413. pop bp
  1414. ret far 0
  1415. (* PROCEDURE emu_Pop_Decimal ( z : emu_temp ;*)
  1416. (* VAR dec : packedDecimal );*)
  1417. (* Convert a floating point temporary to a packed decimal integer.*)
  1418. (* VAR*)
  1419. (* exp : integer;*)
  1420. (* frac : cardinal64;*)
  1421. (* res ; packedDecimal;*)
  1422. (* PROCEDURE PutFourDigits ( rem, posn : cardinal );*)
  1423. (* BEGIN*)
  1424. (* res.digits [posn] := rem MOD 10;*)
  1425. (* rem := rem DIV 10;*)
  1426. (* res.digits [posn+[1] := rem MOD 10;*)
  1427. (* rem := rem DIV 10;*)
  1428. (* res.digits [posn+[2] := rem MOD 10;*)
  1429. (* res.digits [posn+[3] := rem DIV 10;*)
  1430. (* END;*)
  1431. PutFourDigits : (* rem in dx, posn in di*)
  1432. push ax
  1433. push cx
  1434. mov al, 100
  1435. mov cl, 4
  1436. xchg ax, dx
  1437. div dl
  1438. mov dl, ah
  1439. aam (* AH, AL := AL DIV 10, AL MOD 10*)
  1440. shl ah, cl
  1441. or ah, al
  1442. xchg ax, dx
  1443. aam
  1444. shl ah, cl
  1445. or al, ah
  1446. mov ah, dh
  1447. stosw
  1448. pop cx
  1449. pop ax
  1450. ret 0
  1451. (* BEGIN*)
  1452. (* exp := z.exp;*)
  1453. (* frac := z.frac;*)
  1454. (* IF exp < 1 THEN res := 0*)
  1455. (* ELSE exp > 60 THEN res := +infinity*)
  1456. (* ELSE*)
  1457. (* WHILE exp < 64 DO*)
  1458. (* frac := frac DIV 2;*)
  1459. (* exp := exp + 1;*)
  1460. (* frac := frac + carry; { rounding }*)
  1461. (* res := 0;*)
  1462. (* PutFourDigits (frac MOD 10000, 0);*)
  1463. (* frac := frac DIV 10000;*)
  1464. (* PutFourDigits (frac MOD 10000, 4);*)
  1465. (* frac := frac DIV 10000;*)
  1466. (* PutFourDigits (frac MOD 10000, 8);*)
  1467. (* frac := frac DIV 10000;*)
  1468. (* PutFourDigits (frac MOD 10000, 12);*)
  1469. (* frac := frac DIV 10000;*)
  1470. (* res.digits [16] := frac MOD 10;*)
  1471. (* res.digits [17] := frac DIV 10;*)
  1472. (* res.sign := z.sign;*)
  1473. (* emu_Pop_Decimal := res;*)
  1474. (* END;*)
  1475. (*public*) emu_Pop_Decimal : (*NEAR*)
  1476. push bp
  1477. mov bp, sp
  1478. push si (* ds:si points to input*)
  1479. push di (* es:di used to point to result*)
  1480. cld (* forward string direction*)
  1481. (* exp := z.exp;*)
  1482. (* frac := z.frac;*)
  1483. mov ax, [si][emu_exponent]
  1484. mov bx, [si][emu_fraction][w0]
  1485. mov cx, [si][emu_fraction][w1]
  1486. mov dx, [si][emu_fraction][w3]
  1487. mov si, [si][emu_fraction][w2]
  1488. (* IF exp < 1 THEN res := 0*)
  1489. (* { will the result exceed 999,999,999,999,999,999 ? }*)
  1490. (* ELSE z > [3C, DE0B 6B3A 763F [FFF0] THEN res := +infinity*)
  1491. cmp ax, 0
  1492. jl po@underflowJmp
  1493. sub ax, 3CH
  1494. jl po@inRange
  1495. jg po@overflowJmp
  1496. cmp dx, 0DE0BH
  1497. jb po@inRange
  1498. ja po@overflowJmp
  1499. cmp si, 06B3AH
  1500. jb po@inRange
  1501. ja po@overflowJmp
  1502. cmp cx, 0763FH
  1503. jb po@inRange
  1504. ja po@overflowJmp
  1505. cmp bx, 0FFF0H
  1506. ja po@overflowJmp
  1507. (* ELSE*)
  1508. (* WHILE exp < 64 DO*)
  1509. (* frac := frac DIV 2;*)
  1510. (* exp := exp + 1;*)
  1511. po@inRange:
  1512. mov ah, 0 (* excess precision for rounding*)
  1513. sub al, 4
  1514. po@wordAlign:
  1515. add al, 16
  1516. jg po@bitAlign
  1517. mov ah, bh
  1518. mov bx, cx
  1519. mov cx, si
  1520. mov si, dx
  1521. sub dx, dx
  1522. jmp po@wordAlign
  1523. (*----*)
  1524. po@underflowJmp: jmp po@underflow
  1525. po@overflowJmp: jmp po@overflow
  1526. (*----*)
  1527. po@bitAlign:
  1528. sub al, 16
  1529. jnl po@aligned
  1530. po@anotherBit:
  1531. shr dx, 1
  1532. rcr si, 1
  1533. rcr cx, 1
  1534. rcr bx, 1
  1535. rcr ah, 1
  1536. inc al
  1537. jl po@anotherBit
  1538. po@aligned:
  1539. (* frac := frac + carry; { rounding }*)
  1540. add ah, ah
  1541. adc bx, 0
  1542. adc cx, 0
  1543. adc si, 0
  1544. adc dx, 0 (* dx:si:cx:bx is now an integer < 2^60*)
  1545. (* PutFourDigits (frac MOD 10000, 0);*)
  1546. (* frac := frac DIV 10000;*)
  1547. (* dx < 4096 since 2^60 = 4096 * 2^48*)
  1548. xchg ax, si
  1549. mov si, 10000
  1550. div si
  1551. xchg ax, cx
  1552. div si
  1553. xchg ax, bx
  1554. div si (* frac = cx:bx:ax < 2^47, dx = mod 10000*)
  1555. call PutFourDigits (* dx is parameter*)
  1556. (* PutFourDigits (frac MOD 10000, 4);*)
  1557. (* frac := frac DIV 10000;*)
  1558. sub dx, dx
  1559. xchg ax, cx
  1560. div si
  1561. xchg ax, bx
  1562. div si
  1563. xchg ax, cx
  1564. div si (* frac = bx:cx:ax < 2^34, dx = mod 10000*)
  1565. call PutFourDigits (* dx is parameter*)
  1566. (* PutFourDigits (frac MOD 10000, 8);*)
  1567. (* frac := frac DIV 10000;*)
  1568. mov dx, bx
  1569. xchg ax, cx
  1570. div si
  1571. xchg ax, cx
  1572. div si (* frac = cx:ax < 2^20, dx = mod 10000*)
  1573. call PutFourDigits (* dx is parameter*)
  1574. (* PutFourDigits (frac MOD 10000, 12);*)
  1575. (* frac := frac DIV 10000;*)
  1576. mov dx, cx
  1577. div si (* frac = ax < 2^7, dx = mod 10000*)
  1578. call PutFourDigits (* dx is parameter*)
  1579. (* res.digits [16] := frac MOD 10;*)
  1580. (* res.digits [17] := frac DIV 10;*)
  1581. aam (* AH, AL := AL DIV 10, AL MOD 10*)
  1582. mov cl, 4
  1583. shl ah, cl
  1584. or al, ah
  1585. stosb
  1586. po@end:
  1587. (* res.sign := z.sign;*)
  1588. mov si, [bp][-2][w0]
  1589. mov al, [si][emu_sign]
  1590. ror al, 1
  1591. stosb
  1592. pop di
  1593. pop si
  1594. pop bp
  1595. ret 0
  1596. (* ----*)
  1597. po@underflow:
  1598. mov al, 0
  1599. po@extreme:
  1600. mov cx, 9
  1601. rep; stosb
  1602. jmp po@end
  1603. po@overflow:
  1604. mov ch, fe_Overflow
  1605. call e287_Exception
  1606. mov al, 99H
  1607. jmp po@extreme
  1608. (* ----*)
  1609. (*INCLUDE E287DIV.ASM*)
  1610. (* algorithm notes.*)
  1611. (* We are looking for the solution to the ratio:*)
  1612. (* aNNN + bNN + cN + d*)
  1613. (* ---------------------- = (vNNN +wNN + xN + y) / K*)
  1614. (* pNNN + qNN + rN + s*)
  1615. (* Where a, p, v are in the range N/2 .. N-1 and the other lower-case*)
  1616. (* symbols range from 0..N-1 , and K is either NNNN or NNNN/2.*)
  1617. (* The machine provides a primitive for NN / N division.*)
  1618. (* Knuth proposed a method for double length divide which uses an*)
  1619. (* approximation:*)
  1620. (* AN + B AN + B PN AN + B*)
  1621. (* ------ = ------ x ------ = ------ x ( 1 - Q/PN + (Q/PN)^2 ...)*)
  1622. (* PN + Q PN PN + Q PN*)
  1623. (* We can use the same algebra, noting that B = bcd, Q = qrs.*)
  1624. (* The algebra is better changed into a finite equation:*)
  1625. (* AN + B = ((PN + Q) * V) - error*)
  1626. (* = (PN*V + QV) - error*)
  1627. (* Now if V = (AN + B) / PN then we have*)
  1628. (* error = QV*)
  1629. (* Unfortunately, calculating QV is not likely to be fast enough, as*)
  1630. (* in our case it involves roughly 12 multiplications plus some additions.*)
  1631. (* A faster method is to be more crude, and accept only a rounded*)
  1632. (* version of V such that*)
  1633. (* V + Ev = (AN + B) / PN*)
  1634. (* This gives the equation*)
  1635. (* error = (PN + Q)*V - (AN + B)*)
  1636. (* It will be convenient for the error to have a predictable sign, so*)
  1637. (* V is always rounded up. The truncation PN also causes an error in*)
  1638. (* the same direction. It saves code to know which direction to correct*)
  1639. (* at each stage, and will not actually change speed.*)
  1640. (* If another stage is applied, so that*)
  1641. (* W = error / P*)
  1642. (* is the next estimate, then a new error will remain*)
  1643. (* error(2) = error(1) - (PN + Q) * W*)
  1644. (* and that can be substituted to give*)
  1645. (* (PN + Q)*W + error(2) = (PN + Q)*V - (AN + B)*)
  1646. (* error(2) = (PN + Q)(V - W) - (AN + B)*)
  1647. (* Generalised to 5 stages the result is*)
  1648. (* error(5) = (PN + Q)(V - W + X - Y + Z) - (AN + B)*)
  1649. (* The crucial question is, how large are the error terms at each stage ?*)
  1650. (* If we look at the first stage, it can be seen that the error term is*)
  1651. (* made up of two parts. Let us introduce the symbol*)
  1652. (* V' = (AN + B) / P accurately*)
  1653. (* V = RoundUp(V')*)
  1654. (* Then the error has two components:*)
  1655. (* error(1) = V'*Q + (V - V') * (PN + Q)*)
  1656. (* For the floating point fractions we have:*)
  1657. (* NNNN/2 <= AN + B < NNNN and N/2 <= P < N*)
  1658. (* (don't forget to normalise by dividing products by NNNN).*)
  1659. (* so the first component of V has bounds*)
  1660. (* NNNN/2 < V < 2NNNN*)
  1661. (* and that leads to a first error term of*)
  1662. (* 0 < V * Q < 2NNN*)
  1663. (* The second component depends on (V - V'), which ranges over*)
  1664. (* 0 <= V' - V < NNN*)
  1665. (* so the second component of the error ranges*)
  1666. (* 0 <= (PN + Q) * (V' - V) < NNN*)
  1667. (* The two terms are almost independent, so the total error range will*)
  1668. (* be*)
  1669. (* 0 < error < 3NNN*)
  1670. (* More succinctly, the error is up to 3 times the least bit.*)
  1671. (* In fact, that will be our error at every stage since the code uses*)
  1672. (* a double length estimate for V, W, X, Y, Z, where the most significant*)
  1673. (* word acts as a guard so that later stages are not complicated by over-*)
  1674. (* flow from early stages. The 4'th stage will thus have an error of*)
  1675. (* up to 3 LSB and biased positive, which is acceptable if intended for*)
  1676. (* use only to support an HLL which does not provide temporary-precision*)
  1677. (* variables accessible to the user.*)
  1678. numP = 4+nearParam (* based on ds*)
  1679. dvrP = 2+nearParam (* based on ds*)
  1680. quoP = 0+nearParam (* based on es*)
  1681. div_paramsize = 6
  1682. quoExp = -2
  1683. quoSign = -3
  1684. excess = -4
  1685. result = -12
  1686. temp = -16
  1687. guard = -18
  1688. (* note that temp and result, both quad-word objects, overlap by two words.*)
  1689. (* This is allowed because the most significant words of temp are discarded*)
  1690. (* as the least significant words of result are generated.*)
  1691. (*public*) emu_Divide : (*NEAR*)
  1692. push bp; mov bp,sp;
  1693. lea sp, [bp][temp][w3][w1]
  1694. mov bx, [bp][numP]
  1695. push [bx][emu_fraction][w3] (* copy fraction to*)
  1696. push [bx][emu_fraction][w2]
  1697. push [bx][emu_fraction][w1] (* temp work area*)
  1698. push [bx][emu_fraction][w0]
  1699. sub ax, ax
  1700. push ax (* zero guard*)
  1701. push si
  1702. push di
  1703. cld
  1704. mov di, [bp][dvrP]
  1705. mov si, [di][emu_exponent]
  1706. mov ax, [bx][emu_exponent]
  1707. (* first check for all the extreme cases*)
  1708. cmp si, zero_exponent
  1709. jle @div_by_zero
  1710. cmp ax, infinite_exponent
  1711. jge @div_infinite_result
  1712. cmp ax, zero_exponent
  1713. jle @div_result_zero
  1714. cmp si, infinite_exponent
  1715. jge @div_underflow
  1716. sub ax, si
  1717. cmp ax, infinite_exponent
  1718. jge @div_overflow
  1719. cmp ax, zero_exponent
  1720. jg @ordinary_division
  1721. @div_underflow:
  1722. mov ch, fe_Underflow
  1723. call e287_Exception
  1724. @div_result_zero:
  1725. mov si, zero_exponent
  1726. jmp @div_extreme_result
  1727. @div_overflow:
  1728. mov ch, fe_Overflow
  1729. jmp @div_infinite_excep
  1730. @div_by_zero:
  1731. mov ch, fe_Divide_By_Zero
  1732. @div_infinite_excep:
  1733. call e287_Exception
  1734. @div_infinite_result:
  1735. mov si, infinite_exponent
  1736. @div_extreme_result:
  1737. sub ax, ax
  1738. mov di, [bp][quoP]
  1739. stosw
  1740. stosw
  1741. stosw
  1742. stosw
  1743. xchg ax, si
  1744. stosw
  1745. mov ax, positive_sign (* zero/infinity always positive*)
  1746. stosw
  1747. jmp near @div_emu_end
  1748. (* here begin the non-extreme cases*)
  1749. @ordinary_division:
  1750. mov [bp][quoExp], ax
  1751. mov al, [bx][emu_sign]
  1752. xor al, [di][emu_sign]
  1753. mov [bp][quoSign], al
  1754. sub cx, cx
  1755. mov dx, [bp][bp][temp][w3]
  1756. mov si, [di][emu_fraction][w3]
  1757. cmp si, dx
  1758. ja div_noExcess
  1759. sub dx, si
  1760. inc cx
  1761. div_noExcess:
  1762. mov ax, [bp][temp][w2]
  1763. div si
  1764. adc ax, 1 (* round up always !*)
  1765. adc cl, ch
  1766. mov [bp][excess], cl
  1767. mov [bp][bp][result][w3], ax
  1768. push ax
  1769. (* Now we have V = excess:[bp][result][w3], up to 18 bits in size. Next*)
  1770. (* calculate V * (pqrs)*)
  1771. mov ax, [di][emu_fraction][w0]
  1772. mov bx, [di][emu_fraction][w1]
  1773. jcxz w3excessSubtracted
  1774. mov dx, [di][emu_fraction][w2]
  1775. w3subExcess:
  1776. sub [bp][temp][w0], ax (* anticipate calculation*)
  1777. sbb [bp][temp][w1], bx (* of (abcd) - V * (pqrs)*)
  1778. sbb [bp][temp][w2], dx (* by subtracting*)
  1779. sbb [bp][temp][w3], si (* excess * (pqrs)*)
  1780. loop w3subExcess (* V <= 2:0000H*)
  1781. (* result may be negative*)
  1782. w3excessSubtracted:
  1783. (* Calculate [bp][result][w3] (= si) * (pqrs)*)
  1784. pop si
  1785. mul si
  1786. mov [bp][guard], ax
  1787. xchg ax, dx
  1788. xchg ax, bx
  1789. mul si
  1790. add bx, ax
  1791. adc cx, dx (* cx = 0 since excessSubtracted*)
  1792. mov ax, [di][emu_fraction][w2]
  1793. mul si
  1794. add cx, ax
  1795. adc dx, 0
  1796. xchg ax, dx
  1797. xchg ax, si
  1798. mul word [di][emu_fraction][w3]
  1799. add ax, si
  1800. adc dx, 0
  1801. (* We know that V * (pqrs>= (abcd) since V = Roundup ( (abcd) / p )*)
  1802. (* Therefore, subtract abcd from (V * (pqrs)) so that we can work*)
  1803. (* with a conveniently positive remainder.*)
  1804. sub bx, [bp][temp][w0]
  1805. sbb cx, [bp][temp][w1]
  1806. sbb ax, [bp][temp][w2]
  1807. sbb dx, [bp][temp][w3]
  1808. mov [bp][temp][w0], bx
  1809. mov [bp][temp][w1], cx
  1810. mov [bp][temp][w2], ax
  1811. (* mov [bp][temp][w3], dx not needed, use only dx copy*)
  1812. (* Now the next stage begins. Calculate W = Roundup (temp / p).*)
  1813. mov si, [di][emu_fraction][w3]
  1814. div si
  1815. xchg cx, ax
  1816. div si
  1817. sub dx, dx
  1818. stc
  1819. adc ax, dx (* rounded up always !*)
  1820. adc cx, dx (* cx:ax = W*)
  1821. sub dx, ax
  1822. mov [bp][result][w2], dx (* result = V - W*)
  1823. sbb [bp][result][w3], cx
  1824. sbb byte [bp][excess], 0
  1825. (* The error from the previous stage was up to 3NNN, so W <= 6:0000H.*)
  1826. (* However, W is typically < 3:0000, so we will get the fastest times*)
  1827. (* by using subtraction loops to do the effect of*)
  1828. (* temp - W[w1] * pqrs*)
  1829. push ax (* save W[w0]*)
  1830. mov ax, [di][emu_fraction][w0]
  1831. mov bx, [di][emu_fraction][w1]
  1832. jcxz w2excessSubtracted
  1833. mov dx, [di][emu_fraction][w2]
  1834. w2subExcess:
  1835. sub [bp][guard], ax
  1836. sbb [bp][temp][w0], bx
  1837. sbb [bp][temp][w1], dx
  1838. sbb [bp][temp][w2], si
  1839. (* sbb [bp][temp][w3], 0 ignore [bp][temp][w3], it will always be 0*)
  1840. loop w2subExcess
  1841. (* Now calculate W[w0] * pqrs.*)
  1842. w2excessSubtracted:
  1843. pop si (* retrieve W[w0]*)
  1844. mul si
  1845. xchg ax, dx (* forget contents of ax, too insignificant*)
  1846. xchg ax, bx
  1847. mul si
  1848. add bx, ax
  1849. adc cx, dx (* ASSERT cx = 0*)
  1850. mov ax, [di][emu_fraction][w2]
  1851. mul si
  1852. add cx, ax
  1853. adc dx, 0
  1854. xchg ax, dx
  1855. xchg si, ax
  1856. mul word [di][emu_fraction][w3]
  1857. add ax, si
  1858. adc dx, 0
  1859. (* Again, we know that temp < W[w0] * pqrs, and we want to continue*)
  1860. (* with a positive remainder, so temp := W[w0] * pqrs - temp*)
  1861. (* The approximation is now accurate enough that [bp][temp][w3] is always 0.*)
  1862. sub bx, [bp][guard]
  1863. sbb cx, [bp][temp][w0]
  1864. sbb ax, [bp][temp][w1]
  1865. sbb dx, [bp][temp][w2]
  1866. mov [bp][guard], bx
  1867. mov [bp][temp][w0], cx
  1868. mov [bp][temp][w1], ax
  1869. (* mov [bp][temp][w2], dx not needed, use only the dx copy*)
  1870. (* Next we calculate X = RoundUp ( temp / p );*)
  1871. mov si, [di][emu_fraction][w3]
  1872. div si
  1873. xchg cx, ax
  1874. div si
  1875. sub dx, dx
  1876. stc
  1877. adc ax, dx (* round up always !*)
  1878. adc cx, dx (* cx:ax = X*)
  1879. mov [bp][result][w1], ax
  1880. add [bp][result][w2], cx (* result = V - W + X*)
  1881. adc [bp][result][w3], dx
  1882. adc [bp][excess], dl
  1883. (* Again, V <= 6:0000H but typically V < 3:0000, so we will*)
  1884. (* use a subtraction loop to do the effect of*)
  1885. (* temp - V[w1] * pqrs*)
  1886. (* A new feature at this stage is that we ignore the least word of*)
  1887. (* pqrs, because it is 16 bits below significance.*)
  1888. xchg si, ax
  1889. mov dx, [di][emu_fraction][w1]
  1890. xchg ax, dx
  1891. mov bx, [di][emu_fraction][w2]
  1892. jcxz w1excessSubtracted
  1893. w1subExcess:
  1894. sub [bp][guard], ax
  1895. sbb [bp][temp][w0], bx
  1896. sbb [bp][temp][w1], dx
  1897. (* sbb [bp][temp][w2], 0 ignore [bp][temp][w2], it will always be 0*)
  1898. loop w1subExcess
  1899. (* Now calculate V[w0] * pqr.*)
  1900. w1excessSubtracted:
  1901. mul si
  1902. xchg ax, dx (* forget contents of ax, too insignificant*)
  1903. xchg ax, bx
  1904. mul si
  1905. add bx, ax
  1906. adc cx, dx (* ASSERT cx = 0 from excessSubtracted*)
  1907. mov ax, [di][emu_fraction][w3]
  1908. mul si
  1909. add ax, cx
  1910. adc dx, 0
  1911. (* As usual, calculate temp := V[w0] * pqr - temp.*)
  1912. (* Temp[w2] is now always zero.*)
  1913. sub bx, [bp][guard]
  1914. sbb ax, [bp][temp][w0]
  1915. sbb dx, [bp][temp][w1]
  1916. mov [bp][guard], bx
  1917. mov [bp][temp][w0], ax
  1918. (* mov [bp][temp][w1], dx not needed, use only the dx copy*)
  1919. (* Lastly we calculate Y = temp / p, rounded to nearest.*)
  1920. mov si, [di][emu_fraction][w2]
  1921. add si, si
  1922. mov si, [di][emu_fraction][w3]
  1923. adc si, 0
  1924. jnc calcY
  1925. (* if carry occured, then P rounded to 1:0000, so Y = temp. Rearrange*)
  1926. (* the registers to look as if division has occured:*)
  1927. xchg bx, dx (* temp = Y = bx:ax:DH*)
  1928. jmp finalCombine
  1929. calcY:
  1930. shl bx, 1
  1931. rcl ax, 1
  1932. rcl dx, 1
  1933. div si
  1934. xchg bx, ax
  1935. div si
  1936. shr bx, 1
  1937. rcr ax, 1
  1938. rcr dh, 1 (* least 7 bits of DH are don't cares*)
  1939. finalCombine:
  1940. mov cx, -1
  1941. mov si, cx
  1942. mov dl, cl
  1943. not bx
  1944. not ax
  1945. neg dh
  1946. cmc (* negate Y*)
  1947. adc ax, 0
  1948. adc bx, [bp][result][w1]
  1949. adc cx, [bp][result][w2] (* result = V - W + X - Y*)
  1950. adc si, [bp][result][w3]
  1951. adc dl, [bp][excess] (* result is now in DL:si:cx:bx:ax:DH*)
  1952. div_align:
  1953. shr dl, 1
  1954. jnc div_round
  1955. rcr si, 1
  1956. rcr cx, 1
  1957. rcr bx, 1
  1958. rcr ax, 1
  1959. rcr dh, 1
  1960. inc word [bp][quoExp]
  1961. div_round:
  1962. sub di, di
  1963. add dh, dh
  1964. adc ax, di
  1965. adc bx, di
  1966. adc cx, di
  1967. adc si, di
  1968. adc dl, 0
  1969. mov dx, [bp][quoExp]
  1970. jz div_checkExp
  1971. mov si, 8000H (* result must be 8000:0:0:0H*)
  1972. inc dx
  1973. div_checkExp:
  1974. cmp dx, infinite_exponent
  1975. jl div_store
  1976. jmp near @div_infinite_result
  1977. div_store:
  1978. mov di, [bp][quoP]
  1979. mov [di][emu_fraction][w0], ax
  1980. mov [di][emu_fraction][w1], bx
  1981. mov [di][emu_fraction][w2], cx
  1982. mov [di][emu_fraction][w3], si
  1983. mov [di][emu_exponent], dx
  1984. mov al, [bp][quoSign]
  1985. mov [di][emu_sign], al
  1986. @div_emu_end:
  1987. pop di; pop si; mov sp,bp; pop bp
  1988. ret div_paramsize
  1989. (*INCLUDE E287EXPS.ASM*)
  1990. (* CONST*)
  1991. (* { coeffs for range -Ln2/2 .. +Ln2/2, magnified twice. }*)
  1992. (* exp_polycount = 13;*)
  1993. (* exp_polycoeffs = ARRAY [0..[14] OF emu_temp;*)
  1994. exp_polycount : dw 13
  1995. exp_polycoeffs :
  1996. dw 0, 0, 0, 0, 0; db positive_sign, 0
  1997. dw 00003H, 00000H, 00000H, 4000H, 0; db positive_sign, 0
  1998. dw 0AAA9H, 0AAAAH, 0AAAAH, 0AAAH, 0; db positive_sign, 0
  1999. dw 05578H, 05555H, 05555H, 0155H, 0; db positive_sign, 0
  2000. dw 02326H, 02222H, 02222H, 0022H, 0; db positive_sign, 0
  2001. dw 02B1CH, 082D8H, 0D82DH, 0002H, 0; db positive_sign, 0
  2002. dw 0F9FCH, 04033H, 03403H, 0000H, 0; db positive_sign, 0
  2003. dw 05214H, 03403H, 00340H, 0000H, 0; db positive_sign, 0
  2004. dw 06C1EH, 03BC7H, 0002EH, 0000H, 0; db positive_sign, 0
  2005. dw 0B04CH, 04FC9H, 00002H, 0000H, 0; db positive_sign, 0
  2006. dw 00E91H, 01AE6H, 00000H, 0000H, 0; db positive_sign, 0
  2007. dw 07651H, 0011FH, 00000H, 0000H, 0; db positive_sign, 0
  2008. dw 02CC5H, 0000BH, 00000H, 0000H, 0; db positive_sign, 0
  2009. (* FUNCTION emu_2XM1 ( x : emu_temp ) : emu_temp;*)
  2010. (* BEGIN*)
  2011. (* x := x * LogEof2;*)
  2012. (* emu_2XM1 := x * Polynomial ( FixedPoint (x), exp_polycount, exp_polycoeffs);*)
  2013. (* END;*)
  2014. (*public*) emu_2XM1 : (*NEAR*)
  2015. push bp; mov bp,sp; push si; push di
  2016. sub sp, emu_temp_size
  2017. mov di, sp
  2018. call emu_LogEof2
  2019. push di
  2020. push si
  2021. push si
  2022. call emu_Multiply
  2023. add sp, emu_temp_size (* discard LogEof2*)
  2024. mov di, [si][emu_exponent]
  2025. cmp di, -32
  2026. jle e@end (* linear domain, answer = x * LogEof2*)
  2027. mov ax, [si][emu_fraction][w0]
  2028. mov bx, [si][emu_fraction][w1]
  2029. mov cx, [si][emu_fraction][w2]
  2030. mov dx, [si][emu_fraction][w3]
  2031. e@notLinear:
  2032. inc di
  2033. jnl e@fixed (* fix point for Poly*)
  2034. e@fix:
  2035. shr dx, 1
  2036. rcr cx, 1
  2037. rcr bx, 1
  2038. rcr ax, 1
  2039. inc di
  2040. jl e@fix
  2041. adc ax, 0 (* round after shift*)
  2042. adc bx, 0
  2043. adc cx, 0
  2044. adc dx, 0
  2045. e@fixed:
  2046. mov di, positive_sign
  2047. push di
  2048. sub di, di (* exponent has been fixed at zero*)
  2049. push di
  2050. push dx
  2051. push cx
  2052. push bx
  2053. push ax (* fixed ?x now tos*)
  2054. push cs:[exp_polycount]
  2055. push cs
  2056. mov ax, (*offset*) exp_polycoeffs
  2057. push ax
  2058. call emup_Polynomial
  2059. mov ax, sp
  2060. push ax
  2061. push si
  2062. push si
  2063. call emu_Multiply
  2064. add sp, emu_temp_size (* discard polynomial result*)
  2065. e@end:
  2066. pop di; pop si; pop bp
  2067. ret 0
  2068. (*INCLUDE E287LOGS.ASM*)
  2069. (* CONST*)
  2070. (* invLn2 = 1 / Ln (2);*)
  2071. (* polycount = 9;*)
  2072. (* log_polycoeffs = ARRAY [0..(log_polycount - [1)] OF emu_temp;*)
  2073. log_polycount : dw 9
  2074. log_polycoeffs :
  2075. dw 0,0,0,0, 0; db positive_sign, 0
  2076. dw 05568H, 05555H, 05555H, 0555H, 0; db positive_sign, 0
  2077. dw 034BAH, 03333H, 03333H, 033H, 0; db positive_sign, 0
  2078. dw 0C3A7H, 09248H, 04924H, 02H, 0; db positive_sign, 0
  2079. dw 05D4DH, 0C722H, 01C71H, 0H, 0; db positive_sign, 0
  2080. dw 05624H, 05CEBH, 0174H, 0H, 0; db positive_sign, 0
  2081. dw 0AD39H, 0B1ECH, 013H, 0H, 0; db positive_sign, 0
  2082. dw 0D6FDH, 00F80H, 01H, 0H, 0; db positive_sign, 0
  2083. dw 07AB5H, 010E4H, 0H, 0H, 0; db positive_sign, 0
  2084. (* FUNCTION emu_YL2X ( y, x : emu_temp ) : emu_temp;*)
  2085. (* VAR*)
  2086. (* frac : emu_temp;*)
  2087. (* BEGIN*)
  2088. (* frac := x.fraction;*)
  2089. (* { We convert frac to a domain symmetric around 0, as required for the domain*)
  2090. (* of LnXP1. }*)
  2091. (* IF frac <= Sqrt (1/2) THEN*)
  2092. (* frac := (2 * frac) - 1;*)
  2093. (* x.exponent := x.exponent - 1;*)
  2094. (* ELSE*)
  2095. (* frac := frac - 1;*)
  2096. (* emu_YL2X := ( LnXP1 (frac) * invLn2 + x.exponent ) * Y;*)
  2097. (* END;*)
  2098. (*public*) emu_YL2X : (*NEAR*)
  2099. _exponent = -2
  2100. _yPtr = -4
  2101. _xPtr = -6
  2102. push bp
  2103. mov bp, sp
  2104. push [di][emu_exponent]
  2105. push si
  2106. push di
  2107. mov ax, [di][emu_fraction][w0]
  2108. mov bx, [di][emu_fraction][w1]
  2109. mov cx, [di][emu_fraction][w2]
  2110. mov dx, [di][emu_fraction][w3]
  2111. cmp dx, 0B505H (* approx. Sqrt (1/2)*)
  2112. ja x@else
  2113. shl ax, 1
  2114. rcl bx, 1
  2115. rcl cx, 1
  2116. rcl dx, 1 (* ignoring carry achieves subtraction of 1*)
  2117. mov si, positive_sign
  2118. dec word [bp][_exponent] (* frac * 2^exp = 2 * frac * 2^(exp-1)*)
  2119. jmp x@endIf
  2120. x@else:
  2121. not dx
  2122. not cx
  2123. not bx
  2124. neg ax
  2125. cmc
  2126. adc bx, 0
  2127. adc cx, 0
  2128. adc dx, 0
  2129. mov si, negative_sign
  2130. x@endIf:
  2131. sub di, di (* di will be exponent for frac, begin = 0*)
  2132. x@wordNorm:
  2133. or dx, dx
  2134. jnz x@bitNorm
  2135. xchg ax, bx
  2136. xchg ax, cx
  2137. xchg ax, dx
  2138. sub di, 16
  2139. cmp di, -64
  2140. jg x@wordNorm
  2141. (* drop through to here if fraction is very tiny*)
  2142. sub sp, emu_temp_size
  2143. mov di, sp
  2144. call emu_0 (* if frac <= 2^-64 then LnXP1 = 0*)
  2145. jmp x@logDone (* so take a -cut*)
  2146. x@bitNorm:
  2147. js x@normalised
  2148. x@bitNormLoop:
  2149. dec di
  2150. shl ax, 1
  2151. rcl bx, 1
  2152. rcl cx, 1
  2153. adc dx, dx
  2154. jns x@bitNormLoop
  2155. x@normalised:
  2156. push si (* sign*)
  2157. push di (* exponent*)
  2158. push dx
  2159. push cx
  2160. push bx
  2161. push ax (* pushed frac*)
  2162. mov si, sp
  2163. call LnXP1 (* result at [si], which is stack*)
  2164. mov ax, (*offset*) invLn2
  2165. push ax
  2166. push si
  2167. push si
  2168. call emu_Multiply (* tos := LnXP1 (frac) * invLn2*)
  2169. x@logDone:
  2170. lea si, [bp][_exponent]
  2171. sub sp, emu_temp_size (* temp on stack*)
  2172. mov di, sp
  2173. call emu_Float
  2174. lea si, [di][emu_temp_size]
  2175. push si
  2176. push di
  2177. push di
  2178. call emu_Add (* (temp) := LnXP1 (frac) * invLn2 + x.exponent*)
  2179. push di
  2180. push [bp][_yPtr]
  2181. push [bp][_yPtr] (* result overwrites _y*)
  2182. call emu_Multiply (* emu_YL2X := temp * Y*)
  2183. add sp, 2 * emu_temp_size (* clear operands from stack*)
  2184. x@end:
  2185. pop di
  2186. pop si
  2187. mov sp, bp
  2188. pop bp
  2189. ret 0
  2190. (* FUNCTION emu_YL2XP1 ( y, x : emu_temp ) : emu_temp;*)
  2191. (* X is limited by 8087/287 rules to 0 <= x < (1 - Sqrt (1/2))*)
  2192. (* which is comfortably within (1 - Sqrt (2)) <= x <= (Sqrt(2) - 1),*)
  2193. (* the domain of LnXP1.*)
  2194. (* BEGIN*)
  2195. (* emu_YL2XP1 := LnXP1 (x) * invLn2 * Y;*)
  2196. (* END;*)
  2197. (*public*) emu_YL2XP1 : (*NEAR*)
  2198. (* parameters arranged same as YLn2X*)
  2199. p1_yPtr = -2
  2200. p1_xPtr = -4
  2201. push bp
  2202. mov bp, sp
  2203. push si
  2204. push di
  2205. mov si, di
  2206. call emup_Push (* Do not overwrite _x -- the 8087 doesn't.*)
  2207. mov si, sp
  2208. call LnXP1 (* parameter at [si], result overwrites param.*)
  2209. mov ax, (*offset*) invLn2
  2210. push ax
  2211. push si
  2212. push si
  2213. call emu_Multiply
  2214. push si
  2215. push [bp][p1_yPtr]
  2216. push [bp][p1_yPtr] (* result overwrites _y*)
  2217. call emu_Multiply
  2218. add sp, emu_temp_size (* pop temporary from stack*)
  2219. xp1@end:
  2220. pop di
  2221. pop si
  2222. mov sp, bp
  2223. pop bp
  2224. ret 0
  2225. (* FUNCTION LnXP1 ( frac : emu_temp ) : emu_temp;*)
  2226. (* Input domain is (1 - Sqrt(2)) <= frac <= (Sqrt(2) - 1)*)
  2227. (* We first transform frac into a more linear domain*)
  2228. (* which is easier to use with polynomials.*)
  2229. (* ln (frac) := 2 * y * (1 + y^2/3 + y^4/5 + ...)*)
  2230. (* The polynomial is prepared for * 4 scaling.*)
  2231. (* VAR*)
  2232. (* interval, step : cardinal;*)
  2233. (* BEGIN*)
  2234. (* y := frac / (2 + frac);*)
  2235. (* LnXP1 := 2 * y * Poly (Square_Fix (4 * y), log_polycount, log_polycoeffs);*)
  2236. (* END;*)
  2237. LnXP1 :
  2238. push bp
  2239. mov bp, sp
  2240. push si
  2241. push di
  2242. cmp word [si][emu_exponent], -32 (* in linear domain of small fracs,*)
  2243. jle LnXP1@end (* LnXP1 (frac) = frac*)
  2244. sub sp, emu_temp_size
  2245. mov di, sp
  2246. call emu_1
  2247. inc word ss : [di][emu_exponent] (* tos now = 2.0*)
  2248. push si
  2249. push di
  2250. push di
  2251. call emu_Add
  2252. push si
  2253. push di
  2254. push di
  2255. call emu_Divide (* [di] = tos = y = frac / (2 + frac)*)
  2256. call emu_Duplicate_tos
  2257. mov bx, sp
  2258. add word ss : [bx][emu_exponent], 2 (* * 4*)
  2259. call emup_Square_Fix (* uses and overwrites tos*)
  2260. push cs:[log_polycount]
  2261. push cs
  2262. mov ax, (*offset*) log_polycoeffs
  2263. push ax
  2264. call emup_Polynomial (* Poly (Sqfx (y * 4), count, coeffs*)
  2265. (* uses and overwrites tos*)
  2266. mov ax, sp (* push sp is incompatible 8086/80286 !!*)
  2267. push ax
  2268. push di (* points to duplicate of y*)
  2269. push si (* result overwrites _x*)
  2270. call emu_Multiply
  2271. inc word ss : [si][emu_exponent] (* * 2*)
  2272. add sp, 2 * emu_temp_size (* clear intermediate values from stack*)
  2273. LnXP1@end:
  2274. pop di
  2275. pop si
  2276. mov sp, bp
  2277. pop bp
  2278. ret 0
  2279. arith_Add:
  2280. push ax
  2281. push bx
  2282. push dx
  2283. push cx (* return address = arith_end*)
  2284. jmp near emu_Add
  2285. arith_Multiply:
  2286. push ax
  2287. push bx
  2288. push dx
  2289. push cx (* return address = arith_end*)
  2290. jmp near emu_Multiply
  2291. arith_CompareP:
  2292. add si, emu_temp_size
  2293. arith_Compare:
  2294. push ax
  2295. push bx
  2296. push cx (* return address = arith_end*)
  2297. jmp near emu_Compare
  2298. arith_SubtractR:
  2299. xchg ax, bx
  2300. arith_Subtract:
  2301. push ax
  2302. push bx
  2303. push dx
  2304. push cx (* return address = arith_end*)
  2305. jmp near emu_Subtract
  2306. arith_DivideR:
  2307. xchg ax, bx
  2308. arith_Divide:
  2309. push ax
  2310. push bx
  2311. push dx
  2312. call emu_Divide
  2313. arith_end:
  2314. add sp, si (* popAfter*)
  2315. jmp near e287_Exit
  2316. (* format name op number modr/m*)
  2317. (* - - - - - - - - - - -*)
  2318. (* load / store typ.1 mod.0.S.P. r/m .*)
  2319. (* IF (CH & 20H) = 0 THEN*)
  2320. (* IF (CH.S) = 0 THEN*)
  2321. (* IF CH.P = 0 THEN*)
  2322. (* CASE CL.typ OF*)
  2323. (* 0 : iees_Push (es:si);*)
  2324. (* 1 : emu_Float32 (es:si);*)
  2325. (* 2 : ieel_Push (es:si);*)
  2326. (* 3 : emu_Float (es:si);*)
  2327. (* ELSE*)
  2328. (* { reserved, logically these are No-Op's }*)
  2329. (* ELSE*)
  2330. (* IF (CH.P) = 0 THEN emu_Duplicate_tos;*)
  2331. (* CASE CL.typ OF*)
  2332. (* 0 : iees_Pop (es:si);*)
  2333. (* 1 : emu_Round32 (es:si);*)
  2334. (* 2 : ieel_Pop (es:si);*)
  2335. (* 3 : emu_Round (es:si);*)
  2336. (* ELSE {*)
  2337. (* - - - - - - - - - - -*)
  2338. (* -- " -- extended xtp.1 mod.1.S.x. r/m .*)
  2339. (* IF CH.S = 0 THEN*)
  2340. (* CASE (x|xtp) OF { load NDP from memory }*)
  2341. (* 0 : FLDENV;*)
  2342. (* 1 : { reserved }*)
  2343. (* 2 : { Restore }*)
  2344. (* 3 : emu_Push_Decimal (es:si);*)
  2345. (* 4 : FLDCW;*)
  2346. (* 5 : emu_Push_Temp87 (es:si);*)
  2347. (* 6 : { reserved, would be "FLDSW" }*)
  2348. (* 7 : emu_Float64 (es:si);*)
  2349. (* ELSE*)
  2350. (* di := si;*)
  2351. (* CASE (x|xtp) OF { store NDP to memory }*)
  2352. (* 0 : FSTENV;*)
  2353. (* 1 : { reserved };*)
  2354. (* 2 : { Save }*)
  2355. (* 3 : emu_Pop_Decimal (es:di);*)
  2356. (* 4 : [es:[di] := [emws_control];*)
  2357. (* 5 : emu_Pop_Temp87 (es:di);*)
  2358. (* 6 : [es:[di] := [emws_status];*)
  2359. (* 7 : emu_Round64 (es:di);*)
  2360. (* END;*)
  2361. ldst_loadCase :
  2362. dw iees_Push, emu_Float32, ieel_Push, emu_Float
  2363. ldst_storeCase :
  2364. dw iees_Pop, emu_Round32, ieel_Pop, emu_Round
  2365. ldst_notEmulated:
  2366. ldst_reserved :
  2367. mov ch, fe_Invalid_Operation
  2368. call e287_Exception
  2369. ret 0
  2370. (*environment STRUC*)
  2371. env_control = 0 (*dw ?*)
  2372. env_status = 2 (*dw ?*)
  2373. env_tag = 4 (*dw ?*)
  2374. env_instrnPtr = 6 (*dd ?*)
  2375. env_dataPtr = 10 (*dd ?*)
  2376. environment_size = 14
  2377. (*environment ENDS*)
  2378. ldst_ldEnv :
  2379. mov cl, 4
  2380. mov ax, es:[si][env_status]
  2381. mov [emws_status], ax
  2382. (* instrnPtr not supported
  2383. mov ax, env_instrnPtr+w0 (*!!!???*) (*george*)
  2384. mov [emws_instrnPtr][w0], ax
  2385. mov ax, env_instrnPtr+w1 (*!!!???*)
  2386. mov bx, 7FFH
  2387. and bx, ax
  2388. xor ax, bx
  2389. xchg bh, bl (* emws_instruction bytes are swapped*)
  2390. mov [emws_instruction], bx (* for speed of normal operations*)
  2391. rol ax, cl
  2392. mov [emws_instrnPtr][w1], ax
  2393. mov ax, env_dataPtr+w0
  2394. mov [emws_dataPtr][w0], ax
  2395. mov ax, env_dataPtr+w1
  2396. rol ax, cl
  2397. mov [emws_dataPtr][w1], ax
  2398. *)
  2399. (* jmp ldst_loadControl*)
  2400. ldst_loadControl :
  2401. (* note keep ldEnv just above here !!!*)
  2402. mov ax, es : [si][env_control]
  2403. mov [emws_control], ax
  2404. mov ch, 0
  2405. jmp near e287_Exception (* any exceptions newly unmasked ?*)
  2406. (* Exception returns to our caller.*)
  2407. ldst_Float64 :
  2408. pop dx (* return address*)
  2409. sub sp, emu_temp_size (* make space on stack*)
  2410. mov di, sp
  2411. push dx
  2412. jmp near emu_Float64 (* will return to this routine's caller*)
  2413. ldst_Push_Decimal :
  2414. pop dx (* return address*)
  2415. sub sp, emu_temp_size (* make space on stack*)
  2416. mov di, sp
  2417. push dx
  2418. jmp near emu_Push_Decimal (* will return to this routine's caller*)
  2419. ldst_Push_Temp87 :
  2420. pop dx (* return address*)
  2421. sub sp, emu_temp_size (* make space on stack*)
  2422. mov di, sp
  2423. push dx
  2424. jmp near emu_Push_Temp87 (* will return to this routine's caller*)
  2425. ldst_xPushCase :
  2426. dw ldst_ldEnv, ldst_reserved
  2427. dw ldst_Restore, ldst_Push_Decimal
  2428. dw ldst_loadControl, ldst_Push_Temp87
  2429. dw ldst_reserved, ldst_Float64
  2430. ldst_stEnv :
  2431. call ldst_storeControl
  2432. call ldst_storeStatus
  2433. mov ax, (*offset*) emws_initialSP
  2434. sub ax, sp
  2435. mov dl, emu_temp_size
  2436. div dl (* AL = count of regs in use*)
  2437. mov cx, -1
  2438. xchg cx, ax
  2439. add cx, cx (* 2 bits per tag*)
  2440. shr ax, cl (* simulate the tag word*)
  2441. stosw
  2442. (*rest not supported
  2443. mov ax, 16
  2444. mul word [emws_instrnPtr][w1]
  2445. add ax, [emws_instrnPtr][w0]
  2446. adc dl, dh
  2447. stosw
  2448. mov cl, 4
  2449. ror dx, cl
  2450. mov ax, [emws_instruction]
  2451. xchg ah, al (* bytes are swapped as Emu287 does decode*)
  2452. or ax, dx
  2453. stosw
  2454. mov ax, 16
  2455. mul word [emws_dataPtr][w1]
  2456. add ax, [emws_dataPtr][w0]
  2457. adc dl, dh
  2458. stosw
  2459. ror dx, cl
  2460. xchg ax, dx
  2461. stosw
  2462. *)
  2463. add di,8 (* Skip *)
  2464. ret 0
  2465. ldst_Save :
  2466. call ldst_stEnv
  2467. mov si, sp
  2468. add si, 2
  2469. mov bp, es:[di][-10][w0] (* retrieve the tags*)
  2470. mov cx, 8
  2471. or bp, bp
  2472. jz ldst_sv_Full
  2473. mov cl, -1
  2474. decLoop:
  2475. inc cl
  2476. shl bp, 1
  2477. shl bp, 1
  2478. jnc decLoop
  2479. ldst_sv_Full:
  2480. mov bp, 8
  2481. sub bp, cx
  2482. jcxz ldst_sv_loop2
  2483. (* The first loop copies non-empty registers.*)
  2484. ldst_sv_loop:
  2485. push cx
  2486. call emu_Pop_Temp87
  2487. pop cx
  2488. add si, emu_temp_size
  2489. add di, 10
  2490. loop ldst_sv_loop
  2491. (* The second loop writes out zeroes in place of unused registers.*)
  2492. or bp, bp
  2493. jz ldst_sv_done
  2494. sub ax, ax
  2495. ldst_sv_loop2:
  2496. mov cx, 5
  2497. rep; stosw
  2498. dec bp
  2499. jnz ldst_sv_loop2
  2500. ldst_sv_done:
  2501. ret 0
  2502. ldst_Restore :
  2503. pop [emws_tos] (* remember return address*)
  2504. (* in a convenient location*)
  2505. mov sp, (*offset*) emws_initialSP (* stack wiped !!*)
  2506. mov bp, es:[si][env_tag]
  2507. add si, (7 * 10) + environment_size (* last stack element*)
  2508. or bp, 5555H
  2509. (* The first loop skips empty registers.*)
  2510. ldst_rs_loop:
  2511. shr bp, 1
  2512. shr bp, 1
  2513. jnc ldst_rs_loop2
  2514. sub si, 10
  2515. or bp, bp
  2516. jnz ldst_rs_loop
  2517. jmp ldst_rs_allPushed
  2518. (* The second loop reads in the defined registers.*)
  2519. ldst_rs_moreRegs:
  2520. shr bp, 1
  2521. ldst_rs_loop2:
  2522. sub sp, emu_temp_size
  2523. mov di, sp
  2524. call emu_Push_Temp87 (* from es:[si] to ds:[di]*)
  2525. sub si, 10
  2526. shr bp, 1
  2527. jc ldst_rs_moreRegs
  2528. (* when reach here si is pointing one temp87 below the register save vector.*)
  2529. ldst_rs_allPushed:
  2530. mov ax, sp
  2531. xchg ax, [emws_tos] (* fix the stack depth*)
  2532. push ax (* and restore return address*)
  2533. add si, (10) - environment_size (* si = & environment*)
  2534. jmp near ldst_ldEnv (* will return to our caller*)
  2535. ldst_storeControl :
  2536. mov ax, [emws_control]
  2537. stosw
  2538. ret 0
  2539. ldst_storeStatus :
  2540. mov ax, (*offset*) emws_initialSP
  2541. sub ax, sp
  2542. mov cl, emu_temp_size
  2543. div cl
  2544. neg al
  2545. and al, 7
  2546. mov cl, 3
  2547. shl al, cl
  2548. mov cx, [emws_status]
  2549. and ch, 0C7H
  2550. or ch, al
  2551. xchg ax, cx
  2552. stosw
  2553. ret 0
  2554. ldst_Round64 :
  2555. mov si, sp
  2556. add si, 2
  2557. call emu_Round64
  2558. ret emu_temp_size
  2559. ldst_Pop_Decimal :
  2560. mov si, sp
  2561. add si, 2
  2562. call emu_Pop_Decimal
  2563. ret emu_temp_size
  2564. ldst_Pop_Temp87 :
  2565. mov si, sp
  2566. add si, 2
  2567. call emu_Pop_Temp87
  2568. ret emu_temp_size
  2569. ldst_xStoreCase :
  2570. dw ldst_stEnv, ldst_reserved
  2571. dw ldst_Save, ldst_Pop_Decimal
  2572. dw ldst_storeControl, ldst_Pop_Temp87
  2573. dw ldst_storeStatus, ldst_Round64
  2574. (* format name op number modr/m*)
  2575. (* - - - - - - - - - - -*)
  2576. (* register moves opa.1 1 1 0.opc. reg .*)
  2577. (* CASE opc|opa OF*)
  2578. (* 0 : emu_Push; { FLD reg }*)
  2579. (* 1, 5, 9, 13 : reserved;*)
  2580. (* 2 : FFREE;*)
  2581. (* 3 : FFREEP;*)
  2582. (* 4, 6, 7 : emu_Push; emu_Swap_tos; emu_Pop; { FXCHG tos, reg }*)
  2583. (* 8 : IF reg = 0 THEN FNOP*)
  2584. (* ELSE reserved;*)
  2585. (* 10 : emu_Duplicate_tos; emu_Pop; { FST reg }*)
  2586. (* 11, 12, 14, 15 : emu_Pop; { FSTP reg }*)
  2587. (* END;*)
  2588. remo_case :
  2589. dw remo_push, remo_res, remo_free, remo_freep
  2590. dw remo_xch, remo_res, remo_xch, remo_xch
  2591. dw remo_nop, remo_res, remo_st, remo_stp
  2592. dw remo_stp, remo_res, remo_stp, remo_stp
  2593. remo_push:
  2594. sub sp, emu_temp_size
  2595. mov di, sp
  2596. rep; movsw
  2597. jmp remo_end
  2598. remo_freep:
  2599. mov di, emu_temp_size
  2600. jmp remo_freeMayPop
  2601. remo_free:
  2602. xchg di, si
  2603. mov ax, infinite_exponent
  2604. call emu_Extreme
  2605. jmp remo_end
  2606. remo_freeMayPop:
  2607. xchg di, si
  2608. mov ax, infinite_exponent
  2609. call emu_Extreme
  2610. add sp, di
  2611. jmp remo_end
  2612. remo_notEm:
  2613. remo_res:
  2614. mov ch, fe_Invalid_Operation
  2615. call e287_Exception
  2616. jmp remo_end
  2617. remo_xch:
  2618. mov di, sp
  2619. remo_xchgLoop:
  2620. mov ax, [di]
  2621. xchg ax, [si]
  2622. stosw
  2623. add si, 2
  2624. loop remo_xchgLoop
  2625. jmp remo_end
  2626. remo_nop:
  2627. test ch, 7
  2628. jnz remo_res
  2629. jmp remo_end
  2630. remo_st:
  2631. mov di, si
  2632. mov si, sp
  2633. rep; movsw
  2634. jmp remo_end
  2635. remo_stp:
  2636. mov di, si
  2637. mov si, sp
  2638. rep; movsw
  2639. mov sp, si
  2640. remo_end:
  2641. jmp near e287_Exit
  2642. (* format name op number modr/m*)
  2643. (* - - - - - - - - - - -*)
  2644. (* tos functions 0 0 1 1 1 1. fun .*)
  2645. (* CASE CH.fun OF*)
  2646. (* 0 : [tos][emu_sign] := -[tos][emu_sign] {=FCHS}*)
  2647. (* 1 : [tos][emu_sign] := positive_sign; {=FABS}*)
  2648. (* 2..3 : reserved;*)
  2649. (* 4 : emu_Compare_Zero; {=FTST}*)
  2650. (* 5 : emu_XAM;*)
  2651. (* 6..7 : reserved;*)
  2652. (* 8 : emu_1;*)
  2653. (* 9 : emu_Log2of10;*)
  2654. (* 10 : emu_Log2ofE;*)
  2655. (* 11 : emu_PI;*)
  2656. (* 12 : emu_Log10of2;*)
  2657. (* 13 : emu_LogEof2;*)
  2658. (* 14 : emu_0;*)
  2659. (* 15 : reserved;*)
  2660. (* 16 : emu_2XM1;*)
  2661. (* 17 : emu_YL2X;*)
  2662. (* 18 : emu_PTan;*)
  2663. (* 19 : emu_PAtan;*)
  2664. (* 20 : tosf_Xtract;*)
  2665. (* 21 : reserved;*)
  2666. (* 22 : emu_DecStP;*)
  2667. (* 23 : emu_IncStP;*)
  2668. (* 24 : emu_PRem;*)
  2669. (* 25 : emu_YL2XP1;*)
  2670. (* 26 : emu_Square_Root;*)
  2671. (* 27 : reserved;*)
  2672. (* 28 : emu_RndInt;*)
  2673. (* 29 : emu_Scale;*)
  2674. (* 30..31 : reserved;*)
  2675. (* END;*)
  2676. tosf_pat01 = 0
  2677. tosf_pat10 = 2
  2678. tosf_pat11 = 4
  2679. tosf_pat12 = 6
  2680. tosf_pat21 = 8
  2681. tosf_pat22 = 10
  2682. tosf_pattern :
  2683. db tosf_pat11,tosf_pat11 (* tosf_Negate, tosf_Absolute*)
  2684. db tosf_pat11,tosf_pat11 (* tosf_Reserved, tosf_Reserved*)
  2685. db tosf_pat11 (* emu_Compare_Zero*)
  2686. db tosf_pat11 (* emu_XAM*)
  2687. db tosf_pat11,tosf_pat11 (* tosf_Reserved, tosf_Reserved*)
  2688. db tosf_pat01,tosf_pat01,tosf_pat01 (* emu_1, emu_Log2of10, emu_Log2ofE*)
  2689. db tosf_pat01,tosf_pat01,tosf_pat01 (* emu_Pi, emu_Log10of2, emu_LogEof2*)
  2690. db tosf_pat01 (* emu_0*)
  2691. db tosf_pat11 (* tosf_Reserved*)
  2692. db tosf_pat11 (* emu_2XM1*)
  2693. db tosf_pat21 (* emu_YL2X*)
  2694. db tosf_pat12 (* emu_PTan*)
  2695. db tosf_pat21 (* emu_PAtan*)
  2696. db tosf_pat12 (* tosf_Xtract*)
  2697. db tosf_pat11 (* tosf_Reserved*)
  2698. db tosf_pat10 (* emu_DecStP*)
  2699. db tosf_pat01 (* emu_IncStP*)
  2700. db tosf_pat22 (* emu_PRem*)
  2701. db tosf_pat21 (* emu_YL2XP1*)
  2702. db tosf_pat11 (* emu_Square_Root*)
  2703. db tosf_pat11 (* tosf_Reserved*)
  2704. db tosf_pat11 (* emu_RndInt*)
  2705. db tosf_pat22 (* emu_Scale*)
  2706. db tosf_pat11 (* tosf_Reserved*)
  2707. db tosf_pat11 (* tosf_Reserved*)
  2708. tosf_case :
  2709. dw tosf_Negate, tosf_Absolute
  2710. dw tosf_Reserved, tosf_Reserved
  2711. dw emu_Compare_Zero
  2712. dw emu_XAM
  2713. dw tosf_Reserved, tosf_Reserved
  2714. dw emu_1, emu_Log2of10, emu_Log2ofE
  2715. dw emu_Pi, emu_Log10of2, emu_LogEof2
  2716. dw emu_0, tosf_Reserved
  2717. dw emu_2XM1
  2718. dw emu_YL2X
  2719. dw emu_PTan
  2720. dw emu_PAtan
  2721. dw tosf_Xtract
  2722. dw tosf_Reserved
  2723. dw tosf_NoOp (* emu_DecStP*)
  2724. dw tosf_NoOp (* emu_IncStP*)
  2725. dw emu_PRem
  2726. dw emu_YL2XP1
  2727. dw emu_Square_Root
  2728. dw tosf_Reserved
  2729. dw emu_RndInt
  2730. dw emu_Scale
  2731. dw tosf_Reserved
  2732. dw tosf_Reserved
  2733. tosf_Negate :
  2734. xor byte [si][emu_sign], negative_sign
  2735. ret 0
  2736. tosf_Absolute :
  2737. mov byte [si][emu_sign], positive_sign
  2738. ret 0
  2739. tosf_Xtract :
  2740. push si
  2741. push di
  2742. push si
  2743. push di
  2744. cld
  2745. mov cx, emu_temp_size/2
  2746. rep; movsw
  2747. pop di
  2748. pop si
  2749. xchg si, di (* swap so [si] = fraction, [di] = exp*)
  2750. lea si, [si][emu_exponent]
  2751. cmp word [si][w0], zero_exponent
  2752. jle toxt_end
  2753. cmp word [si][w0], infinite_exponent
  2754. jge toxt_infinite
  2755. dec word [si][w0] (* e287 binary point aligned*)
  2756. call emu_Float
  2757. mov word [si][w0], 1 (* differently to 80287*)
  2758. toxt_end:
  2759. pop di
  2760. pop si
  2761. ret 0
  2762. toxt_infinite:
  2763. mov word [si][w0], zero_exponent (* infinity.fraction = 0.0*)
  2764. mov word [di][emu_exponent], 0DH
  2765. mov byte [di][emu_fraction][w3][by1], 80H (* infinity.exponent = 4000H*)
  2766. jmp toxt_end
  2767. tosf_Reserved :
  2768. mov ch, fe_Invalid_Operation
  2769. jmp near e287_Exception
  2770. (* ret*)
  2771. tosf_NoOp :
  2772. ret 0
  2773. tosf_patternSwitch :
  2774. dw tosf_in0out1, tosf_in1out0
  2775. dw tosf_in1out1, tosf_in1out2, tosf_in2out1
  2776. dw tosf_in2out2
  2777. (*public*) e287_tos_Function :
  2778. mov bx, 1FH
  2779. and bl, ch
  2780. mov cl, cs:[tosf_pattern][bx]
  2781. mov ch, 0
  2782. shl bx, 1 (* ready for indexing a word table*)
  2783. mov di, cx
  2784. jmp near cs:[tosf_patternSwitch][di]
  2785. tosf_in0out1:
  2786. sub sp, emu_temp_size
  2787. mov di, sp (* no input, output pushed to tos*)
  2788. jmp tosf_viaCase
  2789. tosf_in1out1:
  2790. mov si, sp (* input and output are both tos element*)
  2791. jmp tosf_viaCase
  2792. tosf_in1out2:
  2793. mov si, sp (* tos input*)
  2794. sub sp, emu_temp_size (* push...*)
  2795. mov di, sp (* tos1 and tos output*)
  2796. jmp tosf_viaCase
  2797. tosf_in1out0: (* only used for DecStP*)
  2798. add sp, emu_temp_size
  2799. jmp near e287_Exit
  2800. tosf_in2out1:
  2801. mov di, sp
  2802. lea si, [di][emu_temp_size]
  2803. call cs:[tosf_case][bx]
  2804. add sp, emu_temp_size
  2805. jmp near e287_Exit
  2806. tosf_in2out2:
  2807. mov di, sp
  2808. lea si, [di][emu_temp_size]
  2809. (* jmp tosf_via_case*)
  2810. tosf_viaCase:
  2811. call cs:[tosf_case][bx]
  2812. jmp near e287_Exit
  2813. (* format name op number modr/m*)
  2814. (* - - - - - - - - - - -*)
  2815. (* FPU control 0 1 1 1 1 1. ctl .*)
  2816. (* CASE CH.ctl OF*)
  2817. (* 0 : { FENI -- no-op on 80287 };*)
  2818. (* 1 : { FDISI -- no-op on 80287 };*)
  2819. (* 2 : FCLEX;*)
  2820. (* 3 : FINIT;*)
  2821. (* 4 : { FSETPM };*)
  2822. (* 5..31 : reserved;*)
  2823. (* END;*)
  2824. (*public*) e287_FPU_Control :
  2825. and ch, 31
  2826. cmp ch, 3 (* FINIT ?*)
  2827. jne fpuc_notInit
  2828. (* Set infinite values into 9 registers, corresponding to 1 underflow*)
  2829. (* guard and 8 normal.*)
  2830. mov sp, (*offset*) emws_initialSP
  2831. mov di, sp
  2832. mov ax, infinite_exponent
  2833. call emu_Extreme (* set the underflow guard*)
  2834. lea si, [di][emu_temp_size][-2]
  2835. sub di, 2
  2836. std (* reverse string direction*)
  2837. sub sp, 8 * emu_temp_size
  2838. mov cx, (8 * emu_temp_size) / 2
  2839. rep; movsw (* make 8 infinite (undefined) temps*)
  2840. mov sp, (*offset*) emws_initialSP
  2841. mov word [emws_status], 0
  2842. mov word [emws_control], 033FH (* precision = temp real,*)
  2843. (* all exceptions masked.*)
  2844. jmp fpuc_end
  2845. fpuc_notInit:
  2846. cmp ch, 2 (* FCLEX ?*)
  2847. jne Reserved
  2848. mov byte [emws_status][by0], 0 (* clear exceptions*)
  2849. jmp fpuc_end
  2850. (*------- This label is called from several nearby groups*)
  2851. e287_Reserved_1:
  2852. e287_Reserved_2:
  2853. Reserved:
  2854. mov ch, fe_Invalid_Operation
  2855. call e287_Exception
  2856. (*-------*)
  2857. fpuc_end:
  2858. jmp near e287_Exit
  2859. (* format name op number modr/m*)
  2860. (* - - - - - - - - - - -*)
  2861. (* reserved 1 0 1 1 1 1.- - - - -.*)
  2862. (* reserved;*)
  2863. (* END;*)
  2864. (*
  2865. (*public*) e287_Reserved_1 :
  2866. jmp Reserved
  2867. (* format name op number modr/m*)
  2868. (* - - - - - - - - - - -*)
  2869. (* reserved 1 1 1 1 1 1.- - - - -.*)
  2870. (* IF (CH & 1Fh) = 0 THEN { FSTSW ax }*)
  2871. (* ELSE reserved;*)
  2872. (* END;*)
  2873. (*public*) e287_Reserved_2 :
  2874. test ch, 1FH
  2875. jnz Reserved
  2876. mov ax, (*offset*) emws_initialSP
  2877. sub ax, sp
  2878. mov cl, emu_temp_size
  2879. div cl
  2880. and al, 7
  2881. mov cl, 3
  2882. shl al, cl
  2883. mov cx, [emws_status]
  2884. and ch, 0C7H
  2885. or ch, al
  2886. mov [bp][oldAX], cx
  2887. jmp near e287_Exit
  2888. *)
  2889. (*INCLUDE E287MULT][ASM*)
  2890. (* Multiplication first involves checks for the special cases of zero*)
  2891. (* and infinity][ If these are encountered, an exception may be raised*)
  2892. (* and a special value is returned][ Otherwise, a subroutine is called*)
  2893. (* to perform a fixed point 64-bit multiplication][ This is then*)
  2894. (* normalised and rounded, and the result and flags set][*)
  2895. (*public*) emu_Multiply :
  2896. x_p = 4+nearParam
  2897. y_p = 2+nearParam
  2898. z_p = 0+nearParam
  2899. mul_paramsize = 6
  2900. push bp; mov bp,sp; push si; push di
  2901. cld
  2902. mov si, [bp][x_p]
  2903. mov di, [bp][y_p]
  2904. mov bx, [di][emu_exponent]
  2905. mov ax, [si][emu_exponent]
  2906. cmp ax, bx
  2907. jl @exponents_ordered
  2908. xchg ax, bx
  2909. @exponents_ordered:
  2910. cmp bx, infinite_exponent
  2911. jge @mult_infinite
  2912. cmp ax, zero_exponent
  2913. jle @mult_zero
  2914. add ax, bx
  2915. cmp ax, infinite_exponent
  2916. jge @mult_overflow
  2917. cmp ax, zero_exponent
  2918. jg @mult_ordinary
  2919. @mult_underflow:
  2920. mov ch, fe_Underflow
  2921. call e287_Exception
  2922. @mult_zero:
  2923. mov bx, zero_exponent
  2924. jmp @mult_extreme_result
  2925. @mult_overflow:
  2926. mov ch, fe_Overflow
  2927. call e287_Exception
  2928. @mult_infinite:
  2929. mov bx, infinite_exponent
  2930. @mult_extreme_result:
  2931. sub ax, ax
  2932. mov di, [bp][z_p]
  2933. stosw
  2934. stosw
  2935. stosw
  2936. stosw
  2937. xchg ax, bx
  2938. stosw
  2939. mov al, positive_sign
  2940. stosb
  2941. jmp @mult_end
  2942. @mult_ordinary:
  2943. mov bl, [si][emu_sign]
  2944. xor bl, [di][emu_sign]
  2945. push bx (* save result's sign*)
  2946. push ax (* save result's exponent*)
  2947. call emup_Push
  2948. xchg si, di
  2949. call emup_Push
  2950. mov bx, sp
  2951. push bp
  2952. lea bp, [bx][-nearParam] (* Inner@Mult caller sets BP*)
  2953. call Inner@Multiply (* result in DX:CX:BX:AX:SI*)
  2954. pop bp
  2955. add sp, 2 * emu_temp_size (* Inner routine does not pop parameters*)
  2956. pop di (* retrieve result's exponent*)
  2957. or dx, dx (* result must be normalised*)
  2958. js @round
  2959. dec di
  2960. shl si, 1
  2961. rcl ax, 1
  2962. rcl bx, 1
  2963. rcl cx, 1
  2964. rcl dx, 1 (* 1 bit shift is the most ever needed*)
  2965. @round:
  2966. shl si, 1
  2967. adc ax, 0
  2968. adc bx, 0
  2969. adc cx, 0
  2970. adc dx, 0
  2971. jnc @ready
  2972. rcr dx, 1 (* here, result is 8000:0:0:0H*)
  2973. inc di
  2974. @ready:
  2975. mov si, di
  2976. mov di, [bp][z_p]
  2977. stosw
  2978. xchg ax, bx
  2979. stosw
  2980. xchg ax, cx
  2981. stosw
  2982. xchg ax, dx
  2983. stosw
  2984. xchg ax, si
  2985. stosw
  2986. pop ax
  2987. mov ah, 0
  2988. stosw
  2989. @mult_end:
  2990. pop di; pop si; pop bp
  2991. ret mul_paramsize
  2992. (* Fraction multiplication ignores the exponent and sign and returns the*)
  2993. (* non-aligned 5-word result of fraction multiplication, the 5th word*)
  2994. (* being only significant in the top two bits, used for rounding][*)
  2995. (*public*) emup_Fraction_Multiply :
  2996. ?x = emu_temp_size+nearParam (* emu_temp*)
  2997. ?y = 0+nearParam (* emu_temp*)
  2998. ?paramsize = 2 * emu_temp_size
  2999. ?res = emu_temp_size+nearParam (* result overwrites [bp][?x]*)
  3000. push bp; mov bp,sp; push si; push di
  3001. mov al, [bp][?y][emu_sign]
  3002. xor [bp][bp][?res][emu_sign], al (* multiply the signs together*)
  3003. call Inner@Multiply (* result in DX:CX:BX:AX:SI*)
  3004. mov [bp][?res][emu_fraction][w0], ax
  3005. mov [bp][?res][emu_fraction][w1], bx
  3006. mov [bp][?res][emu_fraction][w2], cx
  3007. mov [bp][?res][emu_fraction][w3], dx
  3008. mov ax, si
  3009. pop di; pop si; pop bp
  3010. ret ?paramsize - emu_temp_size (* result on stack and in AX*)
  3011. Inner@Multiply :
  3012. (* Algorithm:*)
  3013. (* let N = 2^32*)
  3014. (* the problem to multiply abcd * uvwx, where each letter represents 16 bits][*)
  3015. (* use the transforms:*)
  3016. (* abcd = (ab + i)N + (cd - iN), where i = Ord (cd >= N/2)*)
  3017. (* uvwx = (uv + j)N + (wx - jN), j = Ord (wx >= N/2)*)
  3018. (* The useful aspect of this transform is that the trailing terms*)
  3019. (* |(cd - iN)| <= N/2, and |(wx - jN)| <= N/2*)
  3020. (* are limited in magnitude, and the product of those terms <= NN/4*)
  3021. (* On the other hand, both leading terms*)
  3022. (* (ab + i) >= N/2, and (uv + j) >= N/2, since both are left-normalised,*)
  3023. (* and the product of the leading terms is therefore >= NNNN/4][*)
  3024. (* The consequence of ignoring the lesser terms' mutual product is to cause*)
  3025. (* a maximum error of 1/NN, and a probable error of 1/4NN, unbiased][ The*)
  3026. (* gain is to avoid four 16-bit multiplications][*)
  3027. (* It turns out that the "i" and "j" terms can easily be added to the result,*)
  3028. (* given a bit more algebraic juggling:*)
  3029. (* result = (ab+i)N * (uv+j)N + (ab+i)N * (wx-jN) + (uv+j)N * (cd-iN)*)
  3030. (* = (ab)(uv)NN + abjNN + uviNN + ijNN*)
  3031. (* (ab)(wx)N - abjNN - ijNN + wxiN*)
  3032. (* (uv)(cd)N - uviNN - ijNN + cdjN*)
  3033. (* -----------------------------------------------------------*)
  3034. (* = (ab)(uv)NN + (ab)(wx)N + (uv)(cd)N + wxiN + cdjN - ijNN*)
  3035. (* and so, fortunately, the calculation can be done in terms of the*)
  3036. (* unsigned 16-bit integers a,b,c,d,u,v,w,x, with the terms using i or j*)
  3037. (* calculated conditionally if i or j <> 0][*)
  3038. (* A further optimisation relates to the evaluation of polynomials][*)
  3039. (* This procedure is used for the multiplication of fixed point*)
  3040. (* coefficients of polynomials, and many of these have 1,2, or even 3*)
  3041. (* zeroed most significant words][ The method of coefficient evaluation*)
  3042. (* ensures that the first of the two multiplicands will be the coeffs,*)
  3043. (* so checks for leading zeroes can look at ?x and ignore ?y][*)
  3044. (* The accumulation of products begins with the least significant][ As*)
  3045. (* more significant products are introduced, the least significant bits*)
  3046. (* of the accumulation are truncated, so that only the most significant*)
  3047. (* 80 bits are kept][ These are then normalised and rounded to 64 bits][*)
  3048. (* the multiplication terms are aligned as follows:*)
  3049. (* |w x -- * iN*)
  3050. (* + |c d -- * jN*)
  3051. (* - 1| -- * ijNN*)
  3052. (* + |d v*)
  3053. (* + |b x*)
  3054. (* + d|u*)
  3055. (* + c|v*)
  3056. (* + b|w*)
  3057. (* + a|x*)
  3058. (* + c u|*)
  3059. (* + b v|*)
  3060. (* + a w|*)
  3061. (* + b u |*)
  3062. (* + a v |*)
  3063. (* + a u |*)
  3064. (* - - - -*)
  3065. (* (64 bits)*)
  3066. (* The four registers DI:SI:CX:BX act as a 64-bit accumulator][ However,*)
  3067. (* since the terms produce results spanning 96 bits, the alignment of the*)
  3068. (* "accumulator" changes by 16 bits between each group of similarily*)
  3069. (* aligned terms][ The 6th, least significant word is discarded when no*)
  3070. (* longer of use][ The 5th word is kept as it is significant for rounding][*)
  3071. sub di, di
  3072. mov cx, di
  3073. mov si, di
  3074. test byte [bp][?x][emu_fraction][w1][by1], 80H
  3075. jz @i_skip
  3076. mov cx, [bp][?y][emu_fraction][w0] (* + wxiN*)
  3077. mov si, [bp][?y][emu_fraction][w1]
  3078. @i_skip:
  3079. test byte [bp][?y][emu_fraction][w1][by1], 80H
  3080. jz @j_skip
  3081. add cx, [bp][?x][emu_fraction][w0] (* + cdjN*)
  3082. adc si, [bp][?x][emu_fraction][w1]
  3083. adc di, di
  3084. test byte [bp][?x][emu_fraction][w1][by1], 80H
  3085. jz @ij_skip
  3086. dec di (* - ijNN*)
  3087. @ij_skip:
  3088. @j_skip:
  3089. sub bx, bx
  3090. (*mulAdd [w0], [w2], cx, si, di*) (* + d*v N*)
  3091. mov ax, [bp][?x][emu_fraction][w0];
  3092. mul word [bp][?y][emu_fraction][w2]
  3093. add cx, ax; adc si, dx; adc di, 0
  3094. (*mulAdd [w2], [w0], cx, si, di, @skip1*) (* + b*x N*)
  3095. mov ax, [bp][?x][emu_fraction][w2];
  3096. or ax, ax
  3097. jz @skip1
  3098. mul word [bp][?y][emu_fraction][w0]
  3099. add cx, ax; adc si, dx; adc di, 0
  3100. (*mulAdd [w2], [w1], si, di, bx*) (* + b*w N*)
  3101. mov ax, [bp][?x][emu_fraction][w2];
  3102. mul word [bp][?y][emu_fraction][w1]
  3103. add si, ax; adc di, dx; adc bx, 0
  3104. @skip1:
  3105. (*mulAdd [w0], [w3], si, di, bx*) (* + d*u N*)
  3106. mov ax, [bp][?x][emu_fraction][w0];
  3107. mul word [bp][?y][emu_fraction][w3]
  3108. add si, ax; adc di, dx; adc bx, 0
  3109. (*mulAdd [w1], [w2], si, di, bx*) (* + c*v N*)
  3110. mov ax, [bp][?x][emu_fraction][w1];
  3111. mul word [bp][?y][emu_fraction][w2]
  3112. add si, ax; adc di, dx; adc bx, 0
  3113. (*mulAdd [w3], [w0], si, di, bx, @skip2*) (* + a*x N*)
  3114. mov ax, [bp][?x][emu_fraction][w3];
  3115. or ax, ax
  3116. jz @skip2
  3117. mul word [bp][?y][emu_fraction][w0]
  3118. add si, ax; adc di, dx; adc bx, 0
  3119. @skip2:
  3120. sub cx, cx (* discard bits 80 downwards*)
  3121. push si (* save bits 64][][79 for later rounding*)
  3122. mov si, cx
  3123. (*mulAdd [w1], [w3], di, bx, cx*) (* + c*u N*)
  3124. mov ax, [bp][?x][emu_fraction][w1];
  3125. mul word [bp][?y][emu_fraction][w3]
  3126. add di, ax; adc bx, dx; adc cx, 0
  3127. (*mulAdd [w2], [w2], di, bx, cx, @skip3*) (* + b*v NN*)
  3128. mov ax, [bp][?x][emu_fraction][w2];
  3129. or ax, ax
  3130. jz @skip3
  3131. mul word [bp][?y][emu_fraction][w2]
  3132. add di, ax; adc bx, dx; adc cx, 0
  3133. (*mulAdd [w2], [w3], bx, cx, si*) (* + b*u NN*)
  3134. mov ax, [bp][?x][emu_fraction][w2];
  3135. mul word [bp][?y][emu_fraction][w3]
  3136. add bx, ax; adc cx, dx; adc si, 0
  3137. @skip3:
  3138. (*mulAdd [w3], [w1], di, bx, cx, @skip4*) (* + a*w N*)
  3139. mov ax, [bp][?x][emu_fraction][w3];
  3140. or ax, ax
  3141. jz @skip4
  3142. mul word [bp][?y][emu_fraction][w1]
  3143. add di, ax; adc bx, dx; adc cx, 0
  3144. adc si, 0
  3145. (*mulAdd [w3], [w2], bx, cx, si*) (* + a*v NN*)
  3146. mov ax, [bp][?x][emu_fraction][w3];
  3147. mul word [bp][?y][emu_fraction][w2]
  3148. add bx, ax; adc cx, dx; adc si, 0
  3149. (* final product added in as a special case*)
  3150. mov ax, [bp][?x][emu_fraction][w3] (* + a*u NN*)
  3151. mul word [bp][?y][emu_fraction][w3]
  3152. add cx, ax
  3153. adc si, dx (* never a carry-out at the end, maximum*)
  3154. @skip4: (* possible is ][FFFF:FFFF:FFFF:FFFFh*)
  3155. mov dx, si
  3156. xchg ax, di
  3157. pop si (* result now in dx:cx:bx:ax:si*)
  3158. ret 0
  3159. (*INCLUDE E287POLY.ASM*)
  3160. (* algorithm notes:*)
  3161. (* The polynomial is rearranged in the usual way (due to Horner ?):*)
  3162. (* poly := (..(c [N] * x + c [N-[1]) * x + c [N-[2])..) * x + c [0];*)
  3163. (* which minimises the number of calculations needed.*)
  3164. (* The procedure is a loop of the form:*)
  3165. (* poly = coeff [terms-[1];*)
  3166. (* FOR i := terms-2 DOWNTO 0 DO poly := poly * x + coef [i]*)
  3167. (* result := 1.0 + poly;*)
  3168. (* The calculations are fixed point. The largest error is that introduced*)
  3169. (* by the final stage of multiplication and addition, since x is usually*)
  3170. (* small and multiplication by x therefore shrinks the prior error in*)
  3171. (* the calculation.*)
  3172. (*public*) emup_Polynomial : (*NEAR*)
  3173. _x = 6+nearParam (* emu_temp*)
  3174. _terms = 4+nearParam
  3175. _coef_p = 0+nearParam
  3176. _result = 6+nearParam (* overwrites parameter*)
  3177. _paramsize = 18
  3178. push bp; mov bp,sp; push si; push di
  3179. push ds
  3180. push es
  3181. mov al, emu_temp_size
  3182. mul byte [bp][_terms]
  3183. sub ax, emu_temp_size
  3184. lds si, [bp][_coef_p]
  3185. add si, ax
  3186. push ss
  3187. pop es (* es = ss until @end*)
  3188. sub sp, emu_temp_size
  3189. mov di, sp
  3190. cld
  3191. mov cx, emu_temp_size
  3192. rep; movsb (* poly now on Top Of Stack*)
  3193. mov di, si
  3194. dec byte [bp][_terms]
  3195. sub di, emu_temp_size
  3196. @for:
  3197. dec byte [bp][_terms]
  3198. jl @forEnd
  3199. lea si, [bp][_x]
  3200. call emu_Push
  3201. call emup_Fraction_Multiply
  3202. sub di, emu_temp_size (* ds:di points to coeff [terms - [2]*)
  3203. push bp
  3204. mov bp, sp
  3205. _poly = 2 (* access to tos*)
  3206. mov bx, [di][emu_fraction][w0]
  3207. mov cx, [di][emu_fraction][w1]
  3208. mov dx, [di][emu_fraction][w2]
  3209. mov si, [di][emu_fraction][w3] (* coeff now in si:dx:cx:bx*)
  3210. mov al, [di][emu_sign]
  3211. cmp al, [bp][_poly][emu_sign]
  3212. je @add
  3213. @subtract: (* note that the coeff to be subtracted is almost*)
  3214. (* always larger than the accumulated lesser*)
  3215. (* terms of the polynomial. Hence subtract*)
  3216. (* poly from coeff to keep a positive fraction.*)
  3217. sub bx, [bp][_poly][emu_fraction][w0]
  3218. sbb cx, [bp][_poly][emu_fraction][w1]
  3219. sbb dx, [bp][_poly][emu_fraction][w2]
  3220. sbb si, [bp][_poly][emu_fraction][w3]
  3221. jnc @storePoly
  3222. @negate: (* carry flag = borrow when subtracting,*)
  3223. (* so we have now a negative fraction. This*)
  3224. (* must be restored to positive.*)
  3225. not si
  3226. not dx
  3227. not cx
  3228. neg bx (* -x = (not x) + 1*)
  3229. cmc
  3230. adc cx, 0
  3231. adc dx, 0
  3232. adc si, 0
  3233. xor al, negative_sign
  3234. @storePoly:
  3235. mov [bp][_poly][emu_fraction][w0], bx
  3236. mov [bp][_poly][emu_fraction][w1], cx
  3237. mov [bp][_poly][emu_fraction][w2], dx
  3238. mov [bp][_poly][emu_fraction][w3], si
  3239. mov [bp][_poly][emu_sign], al
  3240. pop bp
  3241. jmp @for
  3242. @add:
  3243. add [bp][_poly][emu_fraction][w0], bx
  3244. adc [bp][_poly][emu_fraction][w1], cx
  3245. adc [bp][_poly][emu_fraction][w2], dx
  3246. adc [bp][_poly][emu_fraction][w3], si (* it is a requirement that*)
  3247. (* the polynomial partial sum*)
  3248. (* never exceeds 1, so there*)
  3249. (* is no carry.*)
  3250. pop bp
  3251. jmp @for
  3252. @forEnd: (* pop [bp][_poly] from tos into registers*)
  3253. pop bx (* w0*)
  3254. pop cx (* w1*)
  3255. pop dx (* w2*)
  3256. pop si (* w3*)
  3257. pop ax (* ignore exponent*)
  3258. pop ax (* sign in al*)
  3259. sub di, di (* convenient zero*)
  3260. cmp al, negative_sign (* result above or below 1.0 _*)
  3261. jne @above
  3262. @below:
  3263. not si (* res := 1.0 - poly;*)
  3264. not dx
  3265. not cx
  3266. neg bx
  3267. cmc (* -poly = (not poly) + 1*)
  3268. adc cx, di
  3269. adc dx, di
  3270. adc si, di
  3271. (* di = 0 is the exponent, conveniently*)
  3272. jmp @log_polyend
  3273. @above:
  3274. stc (* res := 1.0 + poly;*)
  3275. rcr si, 1
  3276. rcr dx, 1
  3277. rcr cx, 1
  3278. rcr bx, 1
  3279. adc bx, di (* round off*)
  3280. adc cx, di
  3281. adc dx, di
  3282. adc si, di
  3283. inc di (* di = 1 is the exponent*)
  3284. @log_polyend:
  3285. mov [bp][_result][emu_exponent], di
  3286. mov byte [bp][_result][emu_sign], positive_sign
  3287. mov [bp][_result][emu_fraction][w0], bx
  3288. mov [bp][_result][emu_fraction][w1], cx
  3289. mov [bp][_result][emu_fraction][w2], dx
  3290. mov [bp][_result][emu_fraction][w3], si
  3291. pop es
  3292. pop ds
  3293. pop di; pop si; pop bp
  3294. ret _paramsize - emu_temp_size
  3295. (*INCLUDE E287PTAN.ASM*)
  3296. (* Polynomial coefficients for Chebyshev approx. to Sine (x) / x,*)
  3297. (* in terms of every second power.*)
  3298. sine_terms : dw 8
  3299. sine_coeffs : dw 0H, 0H, 0H, 0H, 0H; db positive_sign, 0
  3300. dw 0AAB6H, 0AAAAH, 0AAAAH, 2AAAH, 0H; db negative_sign, 0
  3301. dw 2403H, 2222H, 2222H, 0222H, 0H; db positive_sign, 0
  3302. dw 0E4B3H, 0D00H, 00D0H, 0DH, 0H; db negative_sign, 0
  3303. dw 086EH, 0C74BH, 2E3BH, 0H, 0H; db positive_sign, 0
  3304. dw 40C6H, 9916H, 6BH, 0H, 0H; db negative_sign, 0
  3305. dw 450CH, 0B092H, 0H, 0H, 0H; db positive_sign, 0
  3306. dw 45D5H, 0D6H, 0H, 0H, 0H; db negative_sign, 0
  3307. (* Coeffs converted into hexadecimals, Cosine (-pi/4 .. pi/4)*)
  3308. cosine_terms : dw 8
  3309. cosine_coeffs : dw 0H, 0H, 0H, 0H, 0H; db positive_sign, 0 (* 1.0*)
  3310. dw 0FF88H, 0FFFFH, 0FFFFH, 07FFFH, 0H; db negative_sign, 0
  3311. dw 9AA6H, 0AAAAH, 0AAAAH, 0AAAH, 0H; db positive_sign, 0
  3312. dw 0E67FH, 5B04H, 05B0H, 05BH, 0H; db negative_sign, 0
  3313. dw 26EFH, 019BH, 0A01AH, 01H, 0H; db positive_sign, 0
  3314. dw 0CE1DH, 93DCH, 49FH, 0H, 0H; db negative_sign, 0
  3315. dw 0B10FH, 0F74BH, 8H, 0H, 0H; db positive_sign, 0
  3316. dw 0D803H, 0C7BH, 0H, 0H, 0H; db negative_sign, 0
  3317. (* algorithm notes*)
  3318. (* Two Chebyshev series expansions are used. The first series calculates*)
  3319. (* y = Sine (x) for 0 <= x < pi/4*)
  3320. (* and the second:*)
  3321. (* y = Cosine (x) for 0 <= x <= pi/4*)
  3322. (* Tangent is represented as a Sine, Cosine pair left on top of the stack.*)
  3323. (* BEGIN*)
  3324. (* fix := Square_Fix (x);*)
  3325. (* cos := Polynomial (fix, cosine_terms, cosine_coeffs);*)
  3326. (* sin := x * Polynomial (fix, sine_terms, sine_coeffs);*)
  3327. (* emu_PTan := (sin, cos);*)
  3328. (* END;*)
  3329. (*public*) emu_PTan : (*NEAR*)
  3330. push bp; mov bp,sp; push si; push di
  3331. call emup_Push
  3332. call emup_Square_Fix (* tos = fix*)
  3333. call emu_Duplicate_tos (* save a copy for sine*)
  3334. push cs:[cosine_terms] (* number of terms to evaluate*)
  3335. mov ax, (*offset*) cosine_coeffs
  3336. push cs
  3337. push ax
  3338. call emup_Polynomial (* cosine now on tos*)
  3339. call emu_Pop (* put cos in its place in result.*)
  3340. (* "fix" is now tos*)
  3341. push cs:[sine_terms] (* number of terms to evaluate*)
  3342. mov ax, (*offset*) sine_coeffs
  3343. push cs
  3344. push ax
  3345. call emup_Polynomial (* tos = polynomial result*)
  3346. mov ax, sp (* caution : push sp 8086/286 incompatible*)
  3347. push ax (* * poly (fix)*)
  3348. push si (* x*)
  3349. push si (* x := *)
  3350. call emu_Multiply (* sine now in tan?x*)
  3351. add sp, emu_temp_size (* discard Sine poly result*)
  3352. tan@end:
  3353. pop di; pop si; pop bp
  3354. ret 0
  3355. (*INCLUDE E287REM.ASM*)
  3356. (* algorithm notes*)
  3357. (* The method is similar to division, but the process stops when the*)
  3358. (* numerator is or becomes less than the divisor. Only the least significant*)
  3359. (* 16 bits of the quotient are retained.*)
  3360. (* The procedure ignores operand signs and does not guard against 0 divisor,*)
  3361. (* trusting the caller, so is not suitable for carefree use.*)
  3362. (* In detail:*)
  3363. (* We seek to find (Remainder, Quotient) such that*)
  3364. (* Q * Y + R = X exactly*)
  3365. (* X = j.x.2^m 1/2 <= x < 1*)
  3366. (* Y = y.2^n 1/2 <= y < 1*)
  3367. (* R = j.r.2^p 1/2 <= r < 1*)
  3368. (* j is either +1 or -1, and m, n, p and Q are integers.*)
  3369. (* Initially, R = X, Q = 0.*)
  3370. (* The eventual goal is for 0 <= R < Y if 0 < Y,*)
  3371. (* ELSE Y < R <= 0.*)
  3372. (* STAGE 1 :*)
  3373. (* IF p > n THEN GOTO end; { X = R is the answer }*)
  3374. (* ELSE*)
  3375. (* introduce Y' = y.2^p*)
  3376. (* transform Y' -> Y , maintaining invariant Q * Y' + R = X :*)
  3377. (* WHILE*)
  3378. (* (p > n) AND (r < y)*)
  3379. (* r, p, Q := 2r, p-1, 2Q { A }*)
  3380. (* (p >= n) AND (r >= y)*)
  3381. (* r, Q := (r - y), Q + 1 { B }*)
  3382. (* Transform { A } does not change the value of R or of (Q * Y'), it merely*)
  3383. (* re-aligns their representation.*)
  3384. (* Transform { B } increases the magnitude of (Q * Y') and decreases that*)
  3385. (* of R. We can further prove that R will eventually become less than Y:*)
  3386. (* If {A} is used, then p is reduced towards n, while r < 2*y*)
  3387. (* IF {B} is used, then p is constant but since r < 2*y (initial*)
  3388. (* condition invariant under A and B), r is reduced to less than*)
  3389. (* half its present magnitude.*)
  3390. (* Now, either R < Y, or there are a finite number of applications of {A}*)
  3391. (* possible before r >= y (a fundamental property of floating point*)
  3392. (* representation). We can set an upper limit on the number of uses of*)
  3393. (* {A}, N{A} <= (p-n). Therefore no more than (p-n) uses of {A} can*)
  3394. (* occur.*)
  3395. (* Similarily, there are a finite number of applications of {B} possible*)
  3396. (* before R < Y (given R is not infinite), since X < Y * 2^(p+1-n).*)
  3397. (* Each application of {B} at least halves R from its initial value X,*)
  3398. (* so N{B} <= (p+1-n).*)
  3399. (* Since only {A} or {B} is possible at each turn of the WHILE loop, at*)
  3400. (* most N{A} + N{B} loops are possible, and we therefore have proof*)
  3401. (* that R < Y obtains within a strictly bounded time.*)
  3402. (* Implementation note:*)
  3403. (* It is crucial that there be no rounding error in this algorithm. The*)
  3404. (* transform {A} can produce an carry of one bit. The implementation*)
  3405. (* will use the carry flag to give the extra bit of precision. This is*)
  3406. (* possible because if an carry occurs during {A} we know that r > y,*)
  3407. (* and also p >= n, so we know that the guard of {B} will be satisfied and*)
  3408. (* can immediately apply {B}. After {B} we know that r < y, so we are*)
  3409. (* again safely within the bounds of normal precision.*)
  3410. (* STAGE 2 : { normalisation }*)
  3411. (* After stage 1, we have the correct value of R but it is not properly*)
  3412. (* normalised. Therefore normalise in the usual way, shifiting left until*)
  3413. (* the most significant bit is in the MS bit of the MS word.*)
  3414. (* IF r <> 0*)
  3415. (* WHILE |r| < .5*)
  3416. (* r, p := 2r, p-1*)
  3417. (* After normalisation, we are finished.*)
  3418. (* The 8087/287 delivers the least significant three bits of the remainder,*)
  3419. (* and scrambles them into the Condition bits of the status word.*)
  3420. conditions : db 0H, 02H, 40H, 42H, 01H, 03H, 41H, 43H
  3421. (*public*) emu_PRem : (*NEAR*)
  3422. ?sign = -2
  3423. Q_ = -4
  3424. ?incr = -6
  3425. dvrP = -8
  3426. resP = -10
  3427. push bp
  3428. mov bp, sp
  3429. push [di][emu_sign][w0]
  3430. lea sp, [bp][?incr]
  3431. push si
  3432. push di
  3433. mov ax, [di][emu_fraction][w0] (* fetch the numerator*)
  3434. mov bx, [di][emu_fraction][w1]
  3435. mov cx, [di][emu_fraction][w2]
  3436. mov dx, [di][emu_fraction][w3]
  3437. mov word [bp][Q_], 0 (* initial quotient := 0*)
  3438. (* NOTE p_ overwrites numerator pointer, which we no longer need.*)
  3439. mov di, [di][emu_exponent]
  3440. sub di, [si][emu_exponent] (* compare the exponents*)
  3441. jge @while
  3442. jmp @finish
  3443. (* The WHILE statement is re-ordered to minimise the number of (slow) jumps*)
  3444. (* needed. It is optimal to place the WHILE following clause {A}.*)
  3445. @isA: (* assert p >= n, r < y*)
  3446. dec di
  3447. jl @overshootA (* quit if was p = n, maintain p now >= n.*)
  3448. shl word [bp][Q_], 1
  3449. shl ax, 1
  3450. rcl bx, 1
  3451. rcl cx, 1
  3452. adc dx, dx
  3453. jc @isB (* carry implies r >= 1.0 > y*)
  3454. jns @isA (* optimise if r < .5 <= y*)
  3455. @while: (* assert p >= n, 1.0 > r >= .5*)
  3456. cmp dx, [si][emu_fraction][w3]
  3457. ja @isB
  3458. jb @isA
  3459. cmp cx, [si][emu_fraction][w2]
  3460. ja @isB
  3461. jb @isA
  3462. cmp bx, [si][emu_fraction][w1]
  3463. ja @isB
  3464. jb @isA
  3465. cmp ax, [si][emu_fraction][w0]
  3466. ja @isB
  3467. jb @isA
  3468. jmp @isZero
  3469. @overshootA:
  3470. inc di (* assert p=n and r < y, therefore finished*)
  3471. jmp @normalise
  3472. @isB: (* assert y < r < 2y, p >= n*)
  3473. inc word [bp][Q_]
  3474. sub ax, [si][emu_fraction][w0]
  3475. sbb bx, [si][emu_fraction][w1]
  3476. sbb cx, [si][emu_fraction][w2]
  3477. sbb dx, [si][emu_fraction][w3]
  3478. or di, di
  3479. jg @isA (* optimise, since r < y, if p > n*)
  3480. (* ELSE r < y, p = n, so finished.*)
  3481. @normalise:
  3482. or dx, dx
  3483. js @finish
  3484. jz @check_zero
  3485. @align_loop:
  3486. dec di
  3487. shl ax, 1
  3488. rcl bx, 1
  3489. rcl cx, 1
  3490. adc dx, dx
  3491. jns @align_loop
  3492. @finish:
  3493. add di, [si][emu_exponent]
  3494. @end: (* result overwrites ?dvr*)
  3495. push di (* p_*)
  3496. mov di, [bp][resP]
  3497. stosw (* ax*)
  3498. xchg ax, bx
  3499. stosw (* bx*)
  3500. xchg ax, cx
  3501. stosw (* cx*)
  3502. xchg ax, dx
  3503. stosw (* dx*)
  3504. pop ax
  3505. stosw (* di*)
  3506. mov al, [bp][?sign] (* result sign = numerator sign*)
  3507. cbw
  3508. stosw (* sign*)
  3509. and byte [emws_status][by1], ~47H (* ggfb - fixed 31/5/88 *)
  3510. mov di, 7
  3511. mov ax, [bp][Q_]
  3512. cmp byte [bp][?sign], negative_sign
  3513. jne @scramble
  3514. neg ax
  3515. @scramble:
  3516. and di, ax (* iNDP delivers only three quotient*)
  3517. mov dl, cs:[conditions][di] (* bits, scrambled into*)
  3518. or [emws_status][by1], dl (* a condition code*)
  3519. pop di
  3520. pop si
  3521. mov sp, bp
  3522. pop bp
  3523. ret 0
  3524. @check_zero:
  3525. xchg dx, cx
  3526. xchg cx, bx
  3527. xchg bx, ax
  3528. sub di, 16
  3529. or dx, dx
  3530. jnz @normalise
  3531. xchg dx, cx
  3532. xchg cx, bx
  3533. sub di, 16
  3534. xchg dx, cx
  3535. sub di, 16
  3536. or dx, dx
  3537. jnz @normalise
  3538. @isZero:
  3539. inc word [bp][Q_] (* ggfb added 15/2/90 *)
  3540. mov di, zero_exponent
  3541. sub dx, dx
  3542. sub cx, cx
  3543. sub bx, bx
  3544. sub ax, ax
  3545. jmp @end
  3546. (*INCLUDE E287SQFX.ASM*)
  3547. (* Squaring can be almost twice as fast as multiplying two different*)
  3548. (* numbers together, since most terms are duplicated.*)
  3549. (* Fixing the point is done at the start, since the number of bit-shifts*)
  3550. (* necessary will be doubled after the multiplication. It might seem that*)
  3551. (* this causes a loss of accuracy. However, consider that the least bit*)
  3552. (* is to be multiplied by the overall fraction. If the fraction is more*)
  3553. (* than .5 , in other words if there are no shifts anyway, the least bit*)
  3554. (* will account for up to one bit of the result. If the fraction is less*)
  3555. (* than .5, then the least bit will count for less than 1/2 bit of error.*)
  3556. (* If this is combined with rounding after the shift, then the error due*)
  3557. (* to shifting first is at most 1/4 bit, which isworth sacrificing for the*)
  3558. (* speed.*)
  3559. (*public*) emup_Square_Fix : (*NEAR*)
  3560. sf_x = 0+nearParam
  3561. sf_result = 0+nearParam (* result overwrites parameter*)
  3562. push bp; mov bp,sp; push si; push di
  3563. mov ax, [bp][sf_x][emu_fraction][w0]
  3564. mov bx, [bp][sf_x][emu_fraction][w1]
  3565. mov cx, [bp][sf_x][emu_fraction][w2]
  3566. mov dx, [bp][sf_x][emu_fraction][w3]
  3567. sub di, di (* hold the rounding bits*)
  3568. mov si, [bp][sf_x][emu_exponent]
  3569. cmp si, -16
  3570. jg sf@bitShift
  3571. mov di, ax
  3572. mov ax, bx
  3573. mov bx, cx
  3574. mov cx, dx
  3575. sub dx, dx
  3576. add si, 16
  3577. sf@bitShift:
  3578. inc si
  3579. jg sf@aligned
  3580. shr dx, 1
  3581. rcr cx, 1
  3582. rcr bx, 1
  3583. rcr ax, 1
  3584. rcr di, 1
  3585. jmp sf@bitShift
  3586. sf@aligned:
  3587. shl di, 1
  3588. mov di, 0 (* di is ZERO throughout.*)
  3589. adc ax, di
  3590. adc bx, di
  3591. adc cx, di
  3592. adc dx, di
  3593. (* let the factors be (a:b:c:d) ^2*)
  3594. (* We apply the usual cut to rounding (see emu_Multiply), which*)
  3595. (* works even better for squares:*)
  3596. (* Let i = Ord (c > 8000H)*)
  3597. (* then a:b:c:d = (ab + i)N : (cd - iN)*)
  3598. (* square = (ab+i)N ^2 + 2 * (ab+i)N * (cd-iN) + (cd-iN)^2*)
  3599. (* If the final term is ignored, on the grounds that it has a maximum*)
  3600. (* error of 1/4 least bit (biased positive unfortunately, but the average*)
  3601. (* value is 1/12 which can be tolerated)*)
  3602. (* approx = (ab)^2 NN + 2 abiNN + iiNN*)
  3603. (* 2(ab)(cd)N - 2 abiNN + 2 cdiN - 2 iiNN*)
  3604. (* -----------------------------------------------------------*)
  3605. (* = (ab)^2NN + 2(ab)(cd)N + 2 cdiN - iiNN*)
  3606. (* the multiplication terms are aligned as follows:*)
  3607. (* | 2c d -- * iN*)
  3608. (* - 1| -- * iN*)
  3609. (* + 2|b d*)
  3610. (* + 2b |c*)
  3611. (* + 2a |d *)
  3612. (* + b b |*)
  3613. (* + 2a c |*)
  3614. (* + 2a b |*)
  3615. (* + a a |*)
  3616. (* - - - - |- - - -*)
  3617. (* put the shifted value back into the parameter area, clearing the*)
  3618. (* registers for work space:*)
  3619. mov [bp][sf_x][emu_fraction][w0], ax
  3620. mov [bp][sf_x][emu_fraction][w1], bx
  3621. mov [bp][sf_x][emu_fraction][w2], cx
  3622. mov [bp][sf_x][emu_fraction][w3], dx
  3623. (* si:cx:bx will serve as a 48-bit accumulator which scans from right to left*)
  3624. (* building up the product. It accumulates the sum of partial products of*)
  3625. (* the same alignment, then shifts the accumulation right and adds in the sum*)
  3626. (* of the next, more significant group. Since only a small mumber of 32-bit*)
  3627. (* numbers are being added to the accumulator, si will be a small number and*)
  3628. (* carry never overflows si. This greatly simplifies matters. Rounding can*)
  3629. (* be done at an early stage, as soon as all remaining products are to be*)
  3630. (* more significant than the rounding position.*)
  3631. mov bx, di
  3632. mov cx, di
  3633. mov si, di
  3634. test byte [bp][sf_x][emu_fraction][w1][by1], 80H
  3635. jz @sf_i_skip
  3636. mov bx, [bp][sf_x][emu_fraction][w0] (* + c D*)
  3637. mov cx, [bp][sf_x][emu_fraction][w1]
  3638. shl bx, 1 (* * 2*)
  3639. rcl cx, 1 (* ignore the carry, equivalent*)
  3640. (* to -iN*)
  3641. @sf_i_skip:
  3642. mov ax, [bp][sf_x][emu_fraction][w0]
  3643. mul word [bp][sf_x][emu_fraction][w2]
  3644. add bx, ax
  3645. adc cx, dx
  3646. adc si, di (* + b d*)
  3647. add bx, ax
  3648. adc cx, dx
  3649. adc si, di (* * 2*)
  3650. mov bx, cx (* discard bx since below 80 bit level*)
  3651. mov cx, si (* and move the rest "right" one word*)
  3652. sub si, si (* to match next group's alignment*)
  3653. mov ax, [bp][sf_x][emu_fraction][w1]
  3654. mul word [bp][sf_x][emu_fraction][w2]
  3655. add bx, ax
  3656. adc cx, dx
  3657. adc si, di (* + b c*)
  3658. add bx, ax
  3659. adc cx, dx
  3660. adc si, di (* * 2*)
  3661. mov ax, [bp][sf_x][emu_fraction][w0]
  3662. mul word [bp][sf_x][emu_fraction][w3]
  3663. add bx, ax
  3664. adc cx, dx
  3665. adc si, di (* + a d*)
  3666. add bx, ax
  3667. adc cx, dx
  3668. adc si, di (* * 2*)
  3669. shl bx, 1 (* round off at bit 64*)
  3670. adc cx, di
  3671. adc si, di
  3672. mov bx, cx
  3673. mov cx, si (* and move the rest "right" one word*)
  3674. sub si, si (* to match next group's alignment*)
  3675. mov ax, [bp][sf_x][emu_fraction][w2]
  3676. mul word ax
  3677. add bx, ax
  3678. adc cx, dx
  3679. adc si, di (* + b b*)
  3680. mov ax, [bp][sf_x][emu_fraction][w3]
  3681. mul word [bp][sf_x][emu_fraction][w1]
  3682. add bx, ax
  3683. adc cx, dx
  3684. adc si, di (* + a c*)
  3685. add bx, ax
  3686. adc cx, dx
  3687. adc si, di (* * 2*)
  3688. (* henceforth di:si:cx:bx = sum*)
  3689. mov ax, [bp][sf_x][emu_fraction][w3]
  3690. mul word [bp][sf_x][emu_fraction][w2]
  3691. add cx, ax
  3692. adc si, dx
  3693. adc di, di (* + a b*)
  3694. (* zero = di, so "zero" is no longer available.*)
  3695. add cx, ax
  3696. adc si, dx
  3697. adc di, 0 (* * 2*)
  3698. (* final product added in as a special case*)
  3699. mov ax, [bp][sf_x][emu_fraction][w3]
  3700. mul ax (* + a a*)
  3701. add si, ax
  3702. adc di, dx (* never a carry-out at the end.*)
  3703. (* max result is .FFFF:FFFF:..h*)
  3704. (* result now in di:si:cx:bx*)
  3705. mov [bp][sf_result][emu_fraction][w0], bx
  3706. mov [bp][sf_result][emu_fraction][w1], cx
  3707. mov [bp][sf_result][emu_fraction][w2], si
  3708. mov [bp][sf_result][emu_fraction][w3], di
  3709. mov byte [bp][sf_result][emu_sign], positive_sign
  3710. mov word [bp][sf_result][emu_exponent], 0
  3711. @sf_end:
  3712. pop di; pop si; pop bp
  3713. ret 0
  3714. (*INCLUDE E287SQRT.ASM*)
  3715. (* Algorithm notes.*)
  3716. (* 25 May 84 -- Preliminary comments.*)
  3717. (* I was rather partial to the earlier algorithm, but it really didn't*)
  3718. (* suit the iAPX-86. It required rather too much shifting and ideally*)
  3719. (* needed two extended shift registers to hold the intermediate values.*)
  3720. (* Given a machine such as the Z-8000 or AMD-2903 (or, presumably, the*)
  3721. (* i8087) it was an algorithm of about the same speed as division.*)
  3722. (* However, for the iAPX-86 there is a quicker way.*)
  3723. (* It was shown in the algorithm notes for square root that the*)
  3724. (* formula*)
  3725. (* x [n] := (y / x [n-[1] + x [n-[1]) / 2*)
  3726. (* converges rapidly to Sqrt (y), indeed more than doubling the number*)
  3727. (* of significant bits if x [n-[1] is already a fair estimate. Using*)
  3728. (* this method has yielded a very fast precision square root,*)
  3729. (* typically faster than single precision divide.*)
  3730. (* We will use a precision Square root to provide the estimate*)
  3731. (* for the long precision version. Applying the above formula once*)
  3732. (* should double the accuracy. This is about 10% faster than the bit-*)
  3733. (* shift algorithm was, but requires only 1/3 as much code.*)
  3734. (*public*) emu_Square_Root : (*NEAR*)
  3735. push bp; mov bp,sp; push si; push di
  3736. mov ax, [si][emu_exponent]
  3737. (* Square roots of zero or infinity are zero or infinity, respectively.*)
  3738. cmp ax, zero_exponent
  3739. jng @noChange
  3740. cmp ax, infinite_exponent
  3741. jnl @noChange
  3742. (* Square root only valid on positive numbers*)
  3743. cmp byte [si][emu_sign], positive_sign
  3744. je @isPositive
  3745. mov ch, fe_Imaginary
  3746. call e287_Exception
  3747. mov di, si
  3748. call emu_0
  3749. mov word [di][emu_exponent], infinite_exponent (* mark bad result*)
  3750. jmp @sq_end
  3751. @isPositive:
  3752. lea si, [si][by0]
  3753. call emup_Push
  3754. call Inner_Square_Root (* x [n-[1] now on tos*)
  3755. mov di, sp (* [di] := x [n-[1]*)
  3756. push si
  3757. push di
  3758. push si
  3759. call emu_Divide (* (y / x [n-[1]*)
  3760. push di
  3761. push si
  3762. push si
  3763. call emu_Add (* + x [n-[1])*)
  3764. dec word [si][emu_exponent] (* / 2*)
  3765. add sp, emu_temp_size (* discard x [n-[1]*)
  3766. @noChange:
  3767. @sq_end:
  3768. pop di; pop si; pop bp
  3769. ret 0
  3770. (* Algorithm Notes*)
  3771. (* The method is simple first-order successive approximation,*)
  3772. (* based on the refinement:*)
  3773. (* x' = (x + z/x)/2*)
  3774. (* where the aim is to generate x = Sqrt (z).*)
  3775. (* let y = Sqrt (z) exactly, and x = (1 + a) y { approximately }*)
  3776. (* then x' = y (1 + a + 1 - a + a**2 - a**3) / 2*)
  3777. (* = y (1 + a*a/2 - a**3/2...)*)
  3778. (* which, if abs (a) < 1, gives*)
  3779. (* a' < a*a/2*)
  3780. (* Actually, the convergence is excellent even when 1 = a:*)
  3781. (* let z = 1/4, y = 1/2, x = 1, a = 1*)
  3782. (* x' = (1 + 1/4)/2= 5/8, a' = 1/4*)
  3783. (* x'' = (5/8 + 8/20)/2 = 41/80, a'' = 1/40*)
  3784. (* and we can predict a''' < 1/3200, a'''' < 1/(2**24)*)
  3785. (* Incidentally, that was the worst-case, since the range we*)
  3786. (* will cover is 1/4 <= z < 1. It converged to better than*)
  3787. (* 17 bits in 4 iterations. This is important, because we*)
  3788. (* break the 32-bit process into two stages. The first stage*)
  3789. (* finds the most significant 16 bits, then one final iteration*)
  3790. (* extends that to 32 bits.*)
  3791. (* In order to stop the iteration after the optimal number of*)
  3792. (* stages, we simply check the difference between x and z/x.*)
  3793. (* When the difference is one or less, it is time to finish the*)
  3794. (* calculation to 32 bits.*)
  3795. Inner_Square_Root : (*NEAR*)
  3796. s?x = 0+nearParam
  3797. s?res = 0+nearParam (* result overlays [bp][s?x]*)
  3798. push bp; mov bp,sp; push di
  3799. mov bx, [bp][s?x][emu_exponent]
  3800. mov dx, [bp][s?x][emu_fraction][w3]
  3801. mov ax, [bp][s?x][emu_fraction][w2]
  3802. mov cx, [bp][s?x][emu_fraction][w1] (* cx will act as guard bits.*)
  3803. sar bx, 1
  3804. jnc s@aligned
  3805. inc bx
  3806. shr dx, 1
  3807. rcr ax, 1
  3808. rcr cx, 1
  3809. s@aligned:
  3810. cmp dx, 0FFFEH
  3811. jae s@nearly_one
  3812. push bx (* save exponent*)
  3813. push cx (* save guard bits*)
  3814. mov cx, dx
  3815. mov bx, ax (* save fraction in cs:bx*)
  3816. mov di, dx
  3817. stc
  3818. rcr di, 1 (* di = (1 + z) / 2, first approximation.*)
  3819. s@loop:
  3820. div di
  3821. dec di
  3822. cmp di, ax
  3823. jna s@stage_2
  3824. inc di
  3825. add di, ax
  3826. rcr di, 1
  3827. mov dx, cx
  3828. mov ax, bx
  3829. jmp s@loop
  3830. (* When the input aligned fraction is greater than .FFFE0001 it must be*)
  3831. (* a special case, since the square root is greater than .FFFF and thus*)
  3832. (* stage 1 (16 bit precision) would overflow. Fortunately, no 16 bit*)
  3833. (* iterations are necessary since the estimate (1 + z) / 2 is accurate*)
  3834. (* to 32 bits within this range.*)
  3835. s@nearly_one:
  3836. stc
  3837. rcr dx, 1
  3838. rcr ax, 1
  3839. jmp s@end
  3840. s@stage_2:
  3841. inc di
  3842. cmp di, ax
  3843. jae s@balanced
  3844. xchg ax, di (* minimise the difference. The remainder*)
  3845. (* is not alterred by the swap.*)
  3846. s@balanced:
  3847. pop cx (* retrieve guard bits*)
  3848. pop bx (* retrieve exponent*)
  3849. xchg ax, cx
  3850. div di
  3851. sub dx, dx (* dx insignificant, use as convenient zero*)
  3852. add di, cx
  3853. rcr di, 1
  3854. rcr ax, 1
  3855. adc ax, dx (* .. dx is conveniently zero.*)
  3856. adc dx, di
  3857. s@end:
  3858. mov word [bp][s?res][emu_fraction][w0], 0
  3859. mov word [bp][s?res][emu_fraction][w1], 0
  3860. mov [bp][s?res][emu_fraction][w2], ax
  3861. mov [bp][s?res][emu_fraction][w3], dx
  3862. mov [bp][s?res][emu_exponent], bx
  3863. mov byte [bp][s?res][emu_sign], positive_sign
  3864. pop di; pop bp
  3865. ret 0
  3866. (*INCLUDE E287STAK.ASM*)
  3867. (*public*) emu_Push : (*NEAR*) (* push ES:[si].emu_temp*)
  3868. pop ax
  3869. push es : [si][emu_sign][w0]
  3870. push es : [si][emu_exponent]
  3871. push es : [si][emu_fraction][w3]
  3872. push es : [si][emu_fraction][w2]
  3873. push es : [si][emu_fraction][w1]
  3874. push es : [si][emu_fraction][w0]
  3875. jmp near ax
  3876. (*public*) emup_Push : (*NEAR*) (* push ds:[si][emu_temp*)
  3877. pop ax
  3878. push [si][emu_sign][w0]
  3879. push [si][emu_exponent]
  3880. push [si][emu_fraction][w3]
  3881. push [si][emu_fraction][w2]
  3882. push [si][emu_fraction][w1]
  3883. push [si][emu_fraction][w0]
  3884. jmp near ax
  3885. (*public*) emu_Pop : (*NEAR*) (* pop emu_temp to es:[di]*)
  3886. pop dx (* save the return address*)
  3887. cld
  3888. pop ax
  3889. stosw (* fraction[w0]*)
  3890. pop ax
  3891. stosw (* fraction[w1]*)
  3892. pop ax
  3893. stosw (* fraction[w2]*)
  3894. pop ax
  3895. stosw (* fraction[w3]*)
  3896. pop ax
  3897. stosw (* exponent*)
  3898. pop ax
  3899. stosb (* sign*)
  3900. sub di, 11
  3901. jmp near dx (* return*)
  3902. (*public*) emu_Duplicate_tos : (*NEAR*)
  3903. pop ax (* save the return address*)
  3904. mov dx, bp (* save old BP*)
  3905. mov bp, sp
  3906. push [bp][emu_sign][w0]
  3907. push [bp][emu_exponent]
  3908. push [bp][emu_fraction][w3]
  3909. push [bp][emu_fraction][w2]
  3910. push [bp][emu_fraction][w1]
  3911. push [bp][emu_fraction][w0]
  3912. mov bp, dx
  3913. jmp near ax
  3914. (* Swap the two emu_temps currently in tos and tos[1]*)
  3915. (*public*) emu_Swap_tos : (*NEAR*)
  3916. pop cx (* save the return address*)
  3917. mov dx, bp (* save old BP*)
  3918. mov bp, sp
  3919. mov al, [bp][emu_sign]
  3920. xchg al, [bp][emu_temp_size][emu_sign]
  3921. mov [bp][emu_sign], al
  3922. mov ax, [bp][emu_exponent]
  3923. xchg ax, [bp][emu_temp_size][emu_exponent]
  3924. mov [bp][emu_exponent], ax
  3925. mov ax, [bp][emu_fraction][w3]
  3926. xchg ax, [bp][emu_temp_size][emu_fraction][w3]
  3927. mov [bp][emu_fraction][w3], ax
  3928. mov ax, [bp][emu_fraction][w2]
  3929. xchg ax, [bp][emu_temp_size][emu_fraction][w2]
  3930. mov [bp][emu_fraction][w2], ax
  3931. mov ax, [bp][emu_fraction][w1]
  3932. xchg ax, [bp][emu_temp_size][emu_fraction][w1]
  3933. mov [bp][emu_fraction][w1], ax
  3934. mov ax, [bp][emu_fraction][w0]
  3935. xchg ax, [bp][emu_temp_size][emu_fraction][w0]
  3936. mov [bp][emu_fraction][w0], ax
  3937. mov bp, dx
  3938. jmp near cx
  3939. (*INCLUDE E287TEMP.ASM*)
  3940. (* input Intel 8087 temp at es:[si]*)
  3941. (* output emu_temp at ds:[di]*)
  3942. (* no exceptions.*)
  3943. (*public*) emu_Push_Temp87 : (*NEAR*)
  3944. push si
  3945. push di
  3946. push ds
  3947. push es
  3948. mov ax, ds
  3949. mov bx, es
  3950. mov es, ax
  3951. mov ds, bx
  3952. std (* reverse directions*)
  3953. lea si, [si][8][w0]
  3954. lea di, [di][emu_sign]
  3955. lodsw
  3956. xchg bx, ax (* bx = sign bit : exponent*)
  3957. sub ax, ax
  3958. shl bx, 1
  3959. jz put_zeroExponent
  3960. rcl ax, 1
  3961. stosw (* write the sign*)
  3962. shr bx, 1
  3963. sub bx, temp_exponent_bias
  3964. xchg ax, bx
  3965. stosw (* write the exponent*)
  3966. movsw (* copy 4 fraction words*)
  3967. movsw
  3968. movsw
  3969. movsw
  3970. put_end:
  3971. cld (* default is forward strings*)
  3972. pop es
  3973. pop ds
  3974. pop di
  3975. pop si
  3976. ret 0
  3977. put_zeroExponent: (* interpret denormals as zeroes.*)
  3978. stosw (* sign = 0, zero always positive*)
  3979. mov ax, zero_exponent
  3980. stosw
  3981. sub ax, ax
  3982. stosw
  3983. stosw
  3984. stosw
  3985. stosw (* fraction = 0*)
  3986. jmp put_end
  3987. (*public*) emu_Pop_Temp87 : (*NEAR*)
  3988. (* input : Emu temp at ds:[si]*)
  3989. (* output: Intel 8087 Temp format at es:[di]*)
  3990. push si
  3991. push di
  3992. cld
  3993. movsw (* fractions are the same*)
  3994. movsw
  3995. movsw
  3996. movsw
  3997. lodsw
  3998. mov cx, [si]
  3999. cmp ax, infinite_exponent
  4000. jge pot_infinite
  4001. add ax, temp_exponent_bias
  4002. jl pot_zero
  4003. shl ax, 1
  4004. shr cx, 1
  4005. rcr ax, 1
  4006. pot_exit:
  4007. stosw (* exponent and sign together*)
  4008. pop di
  4009. pop si
  4010. ret 0
  4011. pot_infinite:
  4012. mov bx, 7FFFH (* biased infinite exponent*)
  4013. jmp pot_extreme
  4014. pot_zero:
  4015. sub bx, bx (* biased zero exponent*)
  4016. pot_extreme:
  4017. sub ax, ax (* make sure a zero fraction is written*)
  4018. sub di, 8
  4019. stosw
  4020. stosw
  4021. stosw
  4022. stosw
  4023. xchg ax, bx
  4024. jmp pot_exit
  4025. (*INCLUDE E287XCVT.ASM*)
  4026. (* procedure to float an integer to yield a long temporary real*)
  4027. (* input is a 32-bit integer at es:[si]*)
  4028. (* result is an emu_temp real at ds:[di]*)
  4029. (* No exceptions.*)
  4030. (*public*) emu_Float32 : (*NEAR*)
  4031. mov bx, es : [si][w0]
  4032. mov dx, es : [si][w1]
  4033. sub ax, ax
  4034. mov cx, positive_sign
  4035. or dx, dx
  4036. jns @fl32_signed
  4037. @fl32_negative:
  4038. not dx
  4039. neg bx
  4040. sbb dx, -1 (* negate dx:bx*)
  4041. mov cl, negative_sign
  4042. @fl32_signed:
  4043. mov [di][emu_sign][w0], cx
  4044. mov cx, 16
  4045. or dx, dx
  4046. jnz @fl32_shift
  4047. xchg bx, dx
  4048. mov cl, 0
  4049. @fl32_shift:
  4050. or dx, dx
  4051. jz @fl32_aligned
  4052. inc cx
  4053. shr dx, 1
  4054. rcr bx, 1
  4055. rcr ax, 1
  4056. jmp @fl32_shift
  4057. @fl32_zero:
  4058. mov cx, zero_exponent
  4059. (* jmp @fl32_end*)
  4060. @fl32_aligned:
  4061. jcxz @fl32_zero
  4062. @fl32_end:
  4063. mov [di][emu_exponent], cx
  4064. mov [di][emu_fraction][w3], bx
  4065. mov [di][emu_fraction][w2], ax
  4066. mov [di][emu_fraction][w1], dx (* dx is zero*)
  4067. mov [di][emu_fraction][w0], dx
  4068. ret 0
  4069. (*public*) emu_Round32 : (*NEAR*)
  4070. (* Convert a long temporary floating point number to a 32 bit integer*)
  4071. (* with fraction rounded according to current rounding mode.*)
  4072. (* Input operand an emu_temp at ds:[si]*)
  4073. (* Result at es:[di]*)
  4074. (* Side effects may exit via exception*)
  4075. mov cx, [si][emu_exponent]
  4076. cmp cx, 31
  4077. jg @ro32_overflow
  4078. or cx, cx
  4079. jge @ro32_non_zero
  4080. (* -.5..+.5 may round to -1, 0, or 1, according to rounding control*)
  4081. cmp cx, zero_exponent
  4082. jle @ro32_zero
  4083. mov bl, e287_roundingControl
  4084. and bl, [emws_control][by1] (* get rounding control*)
  4085. add bl, [si][emu_sign][by0]
  4086. cmp bl, e287_floor + negative_sign
  4087. je @ro32_one
  4088. cmp bl, e287_ceiling + positive_sign
  4089. je @ro32_one
  4090. @ro32_zero:
  4091. sub dx, dx
  4092. mov ax, dx
  4093. jmp @ro32_endJmp
  4094. @ro32_one:
  4095. sub dx, dx
  4096. mov ax, 1
  4097. cmp bl, e287_floor + negative_sign
  4098. jne @ro32_endJmp
  4099. neg ax
  4100. not dx
  4101. jmp @ro32_endJmp
  4102. @ro32_overflow:
  4103. mov ch, fe_Operand_Too_Big
  4104. call e287_Exception
  4105. mov dx, 8000H
  4106. sub ax, ax
  4107. @ro32_endJmp:
  4108. jmp near @ro32_end
  4109. @ro32_non_zero:
  4110. mov bx, [si][emu_fraction][w1] (* bx will be sticky,*)
  4111. or bl, [si][emu_fraction][w0][by0] (* used for rounding up*)
  4112. or bl, [si][emu_fraction][w0][by1]
  4113. mov ax, [si][emu_fraction][w2]
  4114. mov dx, [si][emu_fraction][w3]
  4115. sub cl, 16
  4116. ja @ro32_wordAligned
  4117. @ro32_below_1:
  4118. or al, bl
  4119. or al, bh
  4120. xchg bx, ax (* sticky bx*)
  4121. xchg ax, dx
  4122. sub dx, dx
  4123. add cl, 16
  4124. jng @ro32_below_1 (* if 0.5 <= x < 1 go round twice*)
  4125. and cl, 0FH
  4126. @ro32_wordAligned:
  4127. jcxz @ro32_noBitShift
  4128. push si
  4129. mov si, 0FFFFH
  4130. rol dx, cl
  4131. rol ax, cl (* align the fraction*)
  4132. shl si, cl
  4133. mov cx, si (* and two copies of a mask*)
  4134. and cx, ax
  4135. xor ax, cx (* mask out the low-end shift-out*)
  4136. and si, dx
  4137. xor dx, si
  4138. or ax, si (* transfer bits from msw to lsw*)
  4139. or bl, bh
  4140. or bl, cl (* bl is a "sticky" byte for rounding up.*)
  4141. mov bh, ch (* bh is sticky + 1/2 ls bit.*)
  4142. pop si
  4143. @ro32_noBitShift:
  4144. mov cl, e287_roundingControl
  4145. and cl, [emws_control][by1] (* get rounding control*)
  4146. cmp cl, e287_chop
  4147. je @ro32_chop
  4148. cmp cl, e287_round
  4149. je @ro32_roundNear
  4150. add cl, [si][emu_sign][by0]
  4151. cmp cl, e287_floor + positive_sign
  4152. je @ro32_chop
  4153. cmp cl, e287_ceiling + negative_sign
  4154. je @ro32_chop
  4155. @ro32_roundUp: (* this is what sticky bits are for !*)
  4156. neg bx (* sets carry if any bit not zero*)
  4157. jc @ro32_addCarry
  4158. jmp @ro32_setSign
  4159. @ro32_roundNear:
  4160. mov cl, 1
  4161. and cl, al
  4162. or bl, cl (* apply banker's rounding if sticky was 8000H*)
  4163. add bx, 7FFFH
  4164. @ro32_addCarry:
  4165. adc ax, 0
  4166. adc dx, 0
  4167. jns @ro32_setSign
  4168. jmp near @ro32_overflow
  4169. @ro32_chop:
  4170. @ro32_setSign:
  4171. cmp byte [si][emu_sign], negative_sign
  4172. jne @ro32_end
  4173. not dx
  4174. neg ax
  4175. sbb dx, -1 (* negate dx:ax*)
  4176. @ro32_end:
  4177. mov es:[di][w0], ax
  4178. mov es:[di][w1], dx
  4179. ret 0
  4180. (* procedure to float an integer to yield a long temporary real*)
  4181. (* input is a 64-bit signed integer at es:[si]*)
  4182. (* result is an emu_temp at ds:[di]*)
  4183. (* No exceptions.*)
  4184. (*public*) emu_Float64 : (*NEAR*)
  4185. push bp
  4186. push si
  4187. mov ax, es : [si][w0]
  4188. mov bx, es : [si][w1]
  4189. mov cx, es : [si][w2]
  4190. mov dx, es : [si][w3]
  4191. mov bp, positive_sign
  4192. or dx, dx
  4193. jl @fl64_negative
  4194. jg @fl64_signed
  4195. or cx, cx
  4196. jnz @fl64_signed
  4197. or bx, bx
  4198. jnz @fl64_signed
  4199. or ax, ax
  4200. jnz @fl64_signed
  4201. @fl64_zero:
  4202. mov si, zero_exponent
  4203. jmp @fl64_end
  4204. @fl64_negative:
  4205. not dx
  4206. not cx
  4207. not bx
  4208. not ax
  4209. add ax, 1
  4210. adc bx, 0
  4211. adc cx, 0
  4212. adc dx, 0 (* negate dx:cx:bx:ax*)
  4213. mov bp, negative_sign
  4214. @fl64_signed:
  4215. mov si, 64
  4216. @fl64_maybeTiny:
  4217. or dx, dx
  4218. jnz @fl64_notTiny
  4219. xchg dx, cx
  4220. xchg cx, bx
  4221. xchg bx, ax
  4222. sub si, 16
  4223. jmp @fl64_maybeTiny
  4224. @fl64_notTiny:
  4225. js @fl64_aligned
  4226. @fl64_shift:
  4227. dec si
  4228. add ax, ax
  4229. adc bx, bx
  4230. adc cx, cx
  4231. adc dx, dx
  4232. jns @fl64_shift
  4233. @fl64_aligned:
  4234. @fl64_end:
  4235. mov [di][emu_sign][w0], bp
  4236. mov [di][emu_exponent], si
  4237. mov [di][emu_fraction][w3], dx
  4238. mov [di][emu_fraction][w2], cx
  4239. mov [di][emu_fraction][w1], bx
  4240. mov [di][emu_fraction][w0], ax
  4241. pop si
  4242. pop bp
  4243. ret 0
  4244. (*public*) emu_Round64 : (*NEAR*)
  4245. (* Convert a long temporary floating point number to a 64 bit integer*)
  4246. (* with fraction rounded as specified in [emws_control].*)
  4247. (* Input operand an emu_temp at ds:[si]*)
  4248. (* Result at es:[di]*)
  4249. (* May generate an exception.*)
  4250. push bp
  4251. push di
  4252. mov cx, [si][emu_exponent]
  4253. cmp cx, 63
  4254. jg @ro64_overflow
  4255. or cx, cx
  4256. jge @ro64_non_zero
  4257. (* small fractions may round to 1 or -1, according to rounding control*)
  4258. cmp cx, zero_exponent
  4259. jle @ro64_zero (* true zero rounds to zero*)
  4260. mov bl, e287_roundingControl
  4261. and bl, [emws_control][by1] (* get rounding control*)
  4262. add bl, [si][emu_sign][by0]
  4263. cmp bl, e287_floor + negative_sign
  4264. je @ro64_one
  4265. cmp bl, e287_ceiling + positive_sign
  4266. je @ro64_one
  4267. @ro64_zero:
  4268. sub bp, bp
  4269. jmp @ro64_extreme
  4270. @ro64_one:
  4271. sub bp, bp
  4272. mov dx, bp
  4273. mov ax, 1
  4274. cmp bl, e287_floor + negative_sign
  4275. mov bx, bp
  4276. jne @ro64_endJmp
  4277. neg ax
  4278. not bx
  4279. not dx
  4280. not bp
  4281. jmp @ro64_endJmp
  4282. @ro64_overflow:
  4283. mov ch, fe_Operand_Too_Big
  4284. call e287_Exception
  4285. mov bp, 8000H
  4286. @ro64_extreme:
  4287. sub dx, dx
  4288. mov bx, dx
  4289. mov ax, bx
  4290. @ro64_endJmp:
  4291. jmp near @ro64_end
  4292. @ro64_non_zero:
  4293. mov bp, [si][emu_fraction][w3]
  4294. mov dx, [si][emu_fraction][w2]
  4295. mov bx, [si][emu_fraction][w1]
  4296. mov di, [si][emu_fraction][w0]
  4297. sub ax, ax (* ax will act as sticky collector*)
  4298. sub cl, 48
  4299. ja @ro64_wordAligned
  4300. @ro64_wordShift:
  4301. or al, ah (* AL is completely sticky*)
  4302. mov ah, 0
  4303. or ax, di (* AH is 1/2 ls bit + sticky*)
  4304. mov di, bx
  4305. mov bx, dx
  4306. mov dx, bp
  4307. sub bp, bp
  4308. add cl, 16
  4309. jng @ro64_wordShift
  4310. and cl, 0FH
  4311. @ro64_wordAligned:
  4312. neg cl
  4313. jz @ro64_bitAligned
  4314. add cl, 16
  4315. @ro64_bitShift:
  4316. or al, ah
  4317. shr bp, 1
  4318. rcr dx, 1
  4319. rcr bx, 1
  4320. rcr di, 1
  4321. rcr ah, 1
  4322. loop @ro64_bitShift
  4323. @ro64_bitAligned:
  4324. mov cl, e287_roundingControl
  4325. and cl, [emws_control][by1]
  4326. cmp cl, e287_chop
  4327. je @ro64_chop
  4328. cmp cl, e287_round
  4329. je @ro64_roundNear
  4330. add cl, [si][emu_sign][by0]
  4331. cmp cl, e287_floor + positive_sign
  4332. je @ro64_chop
  4333. cmp cl, e287_ceiling + negative_sign
  4334. je @ro64_chop
  4335. @ro64_roundUp:
  4336. neg ax (* set carry if any sticky or rounding bit = 1*)
  4337. jc @ro64_addCarry
  4338. jmp @ro64_setsign
  4339. @ro64_overflowJmp:
  4340. jmp @ro64_overflow
  4341. @ro64_roundNear:
  4342. mov cl, 1
  4343. and cx, di (* bankers' rounding, add the odd integer bit*)
  4344. or al, cl (* to sticky, force 8000H to 8001H*)
  4345. add ax, 7FFFH
  4346. @ro64_addCarry:
  4347. mov cx, 0 (* convenient zero*)
  4348. adc di, cx
  4349. adc bx, cx
  4350. adc dx, cx
  4351. adc bp, cx
  4352. js @ro64_overflowJmp
  4353. @ro64_chop:
  4354. @ro64_setsign:
  4355. xchg ax, di (* ax is now more convenient than di*)
  4356. cmp byte [si][emu_sign], negative_sign
  4357. jne @ro64_end
  4358. not bp
  4359. not dx
  4360. not bx
  4361. neg ax
  4362. cmc (* Fixed 12/11/91 *)
  4363. adc bx, 0
  4364. adc dx, 0
  4365. adc bp, 0
  4366. @ro64_end:
  4367. pop di
  4368. mov es:[di][w0], ax
  4369. mov es:[di][w1], bx
  4370. mov es:[di][w2], dx
  4371. mov es:[di][w3], bp
  4372. pop bp
  4373. ret 0
  4374. (*public*) emu_RndInt : (*NEAR*)
  4375. (* Round the tos contents to the nearest integer, although the number remains*)
  4376. (* in emu_temp format on tos.*)
  4377. (* Input operand at [si], but we change to more convenient [bp]*)
  4378. (* Output overwrites input.*)
  4379. (* may report exceptions.*)
  4380. push bp
  4381. push si
  4382. push di
  4383. xchg bp, si
  4384. mov cx, [bp][emu_exponent]
  4385. cmp cx, 64 (* note this is wider range than int64*)
  4386. jg rndi_overflow
  4387. or cx, cx
  4388. jge rndi_normalRange
  4389. cmp cx, zero_exponent
  4390. jle rndi_zero
  4391. mov cl, e287_roundingControl
  4392. and cl, [emws_control][by1]
  4393. add cl, [bp][emu_sign][by0]
  4394. cmp cl, e287_floor + negative_sign
  4395. je rndi_one
  4396. cmp cl, e287_ceiling + positive_sign
  4397. je rndi_one
  4398. rndi_zero:
  4399. sub bx, bx
  4400. mov si, zero_exponent
  4401. jmp rndi_special
  4402. rndi_one:
  4403. mov si, 1
  4404. mov bx, 8000H
  4405. jmp rndi_special
  4406. rndi_overflow:
  4407. mov ch, fe_Precision
  4408. call e287_Exception
  4409. jmp near rndi_end
  4410. rndi_special:
  4411. sub ax, ax
  4412. mov [bp][emu_fraction][w0], ax
  4413. mov [bp][emu_fraction][w1], ax
  4414. mov [bp][emu_fraction][w2], ax
  4415. mov [bp][emu_fraction][w3], bx
  4416. mov [bp][emu_exponent], si
  4417. jmp near rndi_end
  4418. rndi_normalRange:
  4419. (* locate the byte where the most significant fraction bits lie.*)
  4420. mov si, 7
  4421. rndi_nextByte:
  4422. sub cl, 8
  4423. jl rndi_split
  4424. dec si
  4425. jge rndi_nextByte
  4426. (* if you fall through here, then there are no fraction bits. The*)
  4427. (* value in X is effectively an integer.*)
  4428. jmp near rndi_end
  4429. rndi_split:
  4430. (* byte [si] of the fraction has at least one MS bit of the fraction.*)
  4431. (* load registers AH = least sig all integer byte*)
  4432. (* AL = split integer/fraction byte*)
  4433. (* BL = sticky fraction bits*)
  4434. cmp si, 7
  4435. jne rndi_notMSbyte
  4436. mov ah, 0
  4437. mov al, [bp][si][by0]
  4438. jmp rndi_AXloaded
  4439. rndi_notMSbyte:
  4440. mov ax, [bp][si][w0]
  4441. rndi_AXloaded:
  4442. sub bx, bx
  4443. mov di, si
  4444. rndi_nextSticky:
  4445. dec di
  4446. jl rndi_stickyLoaded
  4447. or bl, [bp][di][by0]
  4448. mov [bp][di][by0], bh (* clear x.fraction*)
  4449. jmp rndi_nextSticky
  4450. rndi_stickyLoaded:
  4451. mov dx, 0FFH
  4452. and cl, 07H
  4453. shr dx, cl (* zeroes = integers, ones = fractions*)
  4454. mov di, dx
  4455. inc di (* di = fraction carry / least integer bit*)
  4456. and dx, ax (* dx = fraction MS bits*)
  4457. xor ax, dx (* ax = integer LS bits*)
  4458. or bl, dl
  4459. jz rndi_maskAligned
  4460. push cx
  4461. mov ch, fe_Precision
  4462. call e287_Exception
  4463. pop cx
  4464. rndi_maskAligned:
  4465. mov cl, e287_roundingControl
  4466. and cl, [emws_control][by1]
  4467. cmp cl, e287_chop
  4468. je rndi_chop
  4469. cmp cl, e287_round
  4470. je rndi_roundNear
  4471. add cl, [bp][emu_sign][by0]
  4472. cmp cl, e287_floor + positive_sign
  4473. je rndi_chop
  4474. cmp cl, e287_ceiling + negative_sign
  4475. je rndi_chop
  4476. rndi_roundUp:
  4477. or bl, dl (* were there any fraction bits ?*)
  4478. jnz rndi_oneUp
  4479. jmp rndi_end (* if not, number already is an integer*)
  4480. rndi_chop:
  4481. mov [bp][si][by0], al
  4482. cmp byte [bp][emu_fraction][w3][by1], 0 (* did we chop to zero ?*)
  4483. jne rndi_end
  4484. jmp near rndi_zero
  4485. rndi_roundNear:
  4486. or bl, bl
  4487. jnz rndi_bankersUp
  4488. (* Banker's rounding aims to balance out the rounding of exact halves by*)
  4489. (* rounding always towards the nearest even integer. Thus half the*)
  4490. (* halves round up, and half down, on average cancelling.*)
  4491. rndi_bankersBit:
  4492. test ax, di (* test for even/odd integer*)
  4493. jnz rndi_bankersUp
  4494. rndi_bankersDown:
  4495. add dx, dx
  4496. cmp dx, di
  4497. jna rndi_chop
  4498. jmp rndi_oneUp
  4499. rndi_bankersUp:
  4500. add dx, dx (* was fraction at least half ?*)
  4501. cmp dx, di (* if so, carry will be found*)
  4502. jb rndi_chop
  4503. rndi_oneUp:
  4504. sub si, 7
  4505. jl rndi_severalBytes
  4506. add ax, di
  4507. mov [bp][si][7], al
  4508. neg ah (* set carry if not zero*)
  4509. jmp rndi_oneUpped
  4510. rndi_severalBytes:
  4511. add ax, di
  4512. mov [bp][si][7], ax
  4513. inc si
  4514. rndi_oneUpLoop:
  4515. inc si
  4516. jg rndi_oneUpped
  4517. adc byte [bp][si][7][by0], 0
  4518. jc rndi_oneUpLoop
  4519. rndi_oneUpped:
  4520. jnc rndi_end (* is there an overflowed carry ?*)
  4521. stc (* if carry, then result has form 8000:0:0:0H*)
  4522. rcr word [bp][emu_fraction][w3], 1
  4523. inc word [bp][emu_exponent]
  4524. rndi_end:
  4525. pop di
  4526. pop si
  4527. pop bp
  4528. ret 0
  4529. (*INCLUDE IEELSTAK.ASM*)
  4530. (* An IEEE long real is packed into 64 bits.*)
  4531. (* -------- ---- ---- -------- -------- -------- -------- -------- --------*)
  4532. (* |seeeeeee eeee.ffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff|*)
  4533. (* -------- ----.---- -------- -------- -------- -------- -------- --------*)
  4534. (* 63 . 0*)
  4535. (* 1.*)
  4536. (* The three parts of the number are its sign, exponent, and fraction.*)
  4537. (* If the number is denoted by the triple (sign, exponent, fraction) then*)
  4538. (* its value is:*)
  4539. (* (-1)^sign * 2^(exponent-1023) * 1.fraction*)
  4540. (* with the exception of the special cases with all-zeroes exponents.*)
  4541. (* The sign is in the most significant bit and is "1" if negative.*)
  4542. (* The exponent occupies the next 11 bits. It represents powers of 2, biased*)
  4543. (* so that an exponent of 3FFH is used for numbers in the range 1.0 to 1.999...*)
  4544. (* If the exponent is all ones, then the number is either "infinity" or*)
  4545. (* "Not A Number" (NAN), described below. If the exponent is all zeroes, then*)
  4546. (* the number is either zero or a "denormal", as described below.*)
  4547. (* The fraction is the remaining 52 bits. Excepting "denormal" special cases,*)
  4548. (* numbers are normalised into the triple form shown above. Since the final*)
  4549. (* term is a number in the range 1.0 to 1.999... it is predictable that the*)
  4550. (* first bit of the final term shoul be "1" (the "integer bit"), and this*)
  4551. (* need not be packed into the 64 bits. However, this bit is necessary for*)
  4552. (* calculation, and so whenever the number is unpacked into temporary format*)
  4553. (* the integer bit is restored. The 52 bits of packed IEEE fraction are*)
  4554. (* therefore equivalent to 53 bits of temporary fraction.*)
  4555. (* If the exponent is all ones and the fraction is all zeroes, then the number*)
  4556. (* represented is infinite. IEEE makes allowance for both positive and*)
  4557. (* negative infinities, but both are treated as positive by the Combinatorics*)
  4558. (* algorithms. If the exponent is all ones but the fraction not zeroes, then*)
  4559. (* the value is a "NAN", an illegal combination. A huge range of NAN values*)
  4560. (* is possible, and one suggested use is as distinct space-fill values for use*)
  4561. (* in detecting uninitialised variables in programs. When a NAN is found*)
  4562. (* an overflow status is generated and an infinite temporary used.*)
  4563. (* If the exponent and fraction are all zeroes then the number represented is*)
  4564. (* zero. Zero can have either sign, but Combinatorics treats either as if*)
  4565. (* positive. If the exponent is zeroes but the fraction is not, then the*)
  4566. (* number is a denormal, normally a value with an exponent in the range from*)
  4567. (* -1024 to -1075. Combinatorics algorithms do not use denormals, instead*)
  4568. (* flagging them with underflow status and substituting zero. It is an*)
  4569. (* extremely insignificant range.*)
  4570. (* convert a temporary floating-point number to an IEEE 64-bit real.*)
  4571. (* inputs*)
  4572. (* - a long temporary floating point (emu format) at ds : [si]*)
  4573. (* outputs*)
  4574. (* - a long IEEE real at es:[di]*)
  4575. (* side effects*)
  4576. (* - instruction may quit in case of exception*)
  4577. (*public*) ieel_Pop : (*NEAR*)
  4578. push di
  4579. (* move fraction to DL:cx:di:ax:DH. The strange choice of registers*)
  4580. (* is the result of forward planning to minimise register*)
  4581. (* shuffling and shifting at the pack-and-align stage.*)
  4582. mov ax, [si][emu_fraction][by1][w0]
  4583. mov di, [si][emu_fraction][by1][w1]
  4584. mov cx, [si][emu_fraction][by1][w2]
  4585. mov dl, [si][emu_fraction][w3][by1]
  4586. mov bx, [si][emu_exponent]
  4587. mov dh, 3
  4588. and dh, al
  4589. or dh, [si][emu_fraction][w0][by0] (* sticky rounding..*)
  4590. jnz @lpop_isSticky
  4591. test al, 8 (* bankers' rounding to nearest-even*)
  4592. jz @lpop_rounded (* means alternate round up/down of exact .5*)
  4593. @lpop_isSticky:
  4594. add ax, 4 (* round off at the 53rd bit*)
  4595. adc di, 0
  4596. adc cx, 0
  4597. adc dl, 0
  4598. jnc @lpop_rounded
  4599. rcr dl, 1 (* carry overflow implies 8000:0:0:0 result*)
  4600. inc bx
  4601. @lpop_rounded:
  4602. add bx, ieel_exponent_bias
  4603. jle @lpop_small
  4604. cmp bx, 7FFH
  4605. jl @lpop_normal_range
  4606. (* All numbers too large for IEEE range will be given as positive infinity.*)
  4607. (* If the number was already infinity, then ok, but if it becomes an*)
  4608. (* infinity through limitations in representation, give overflow status.*)
  4609. @lpop_large:
  4610. cmp word [si][emu_exponent], infinite_exponent
  4611. jge @lpop_infinite
  4612. mov ch, fe_Overflow
  4613. call e287_Exception
  4614. @lpop_infinite:
  4615. mov dx, 07FF0H (* note clear sign bit = positive*)
  4616. jmp @lpop_extreme
  4617. (* All number too small for IEEE normal range will be given as zeroes.*)
  4618. (* If the number was already zero, this is no problem. However, if the*)
  4619. (* number is zeroed because it falls outside IEEE range, an underflow*)
  4620. (* status is reported.*)
  4621. @lpop_small:
  4622. cmp word [si][emu_exponent], zero_exponent
  4623. jle @lpop_zero
  4624. mov ch, fe_Underflow
  4625. call e287_Exception
  4626. @lpop_zero:
  4627. sub dx, dx
  4628. @lpop_extreme:
  4629. sub cx, cx (* both zero and infinity have zero fraction*)
  4630. mov bx, cx
  4631. mov ax, bx
  4632. jmp @lpop_end
  4633. (* For normal range numbers, we must do some rotations and pack the three*)
  4634. (* parts into their correct positions.*)
  4635. @lpop_normal_range:
  4636. and al, 0F8H (* Discard least bits of fraction.*)
  4637. shl dl, 1 (* Discard integer bit*)
  4638. shr bx, 1
  4639. rcr dl, 1
  4640. or al, bh (* Replace with upper bits of exponent.*)
  4641. mov dh, bl (* Move lower byte of exponent into place.*)
  4642. mov bx, di (* di will be consumed to prime the carry flag.*)
  4643. (* Number is now in dx:cx:bx:ax, but lacks*)
  4644. (* sign and needs rotation.*)
  4645. shr di, 1
  4646. rcr ax, 1
  4647. rcr dx, 1
  4648. rcr cx, 1
  4649. rcr bx, 1
  4650. shr di, 1
  4651. rcr ax, 1
  4652. rcr dx, 1
  4653. rcr cx, 1
  4654. rcr bx, 1
  4655. or al, [si][emu_sign] (* Put the sign bit into place.*)
  4656. shr di, 1
  4657. rcr ax, 1
  4658. rcr dx, 1
  4659. rcr cx, 1
  4660. rcr bx, 1
  4661. @lpop_end:
  4662. pop di
  4663. cld (* store dx:cx:bx:ax at es:[di]*)
  4664. stosw
  4665. xchg ax, bx
  4666. stosw
  4667. xchg ax, cx
  4668. stosw
  4669. xchg ax, dx
  4670. stosw
  4671. sub di, 8 (* preserve original di value*)
  4672. ret 0
  4673. (* procedure to unpack a long IEEE real yielding a long temporary*)
  4674. (* inputs*)
  4675. (* - a long IEEE real in four words at es : [si]*)
  4676. (* outputs*)
  4677. (* - a long temporary floating point in Emu287 format at ds:[di]*)
  4678. (* side effects*)
  4679. (* - may cause exit via exception for NANs and Denormals*)
  4680. (*public*) ieel_Push : (*NEAR*)
  4681. push di
  4682. (* more convenient to have ds and es the other way around, so swap*)
  4683. mov ax, ds
  4684. mov bx, es
  4685. mov ds, bx
  4686. mov es, ax
  4687. mov dx, [si][w3] (* word 3 contains sign,*)
  4688. sub ax, ax (* exponent, and*)
  4689. shl dx, 1 (* top 4 bits of fraction*)
  4690. rcl ax, 1 (* ax is sign*)
  4691. mov cl, 5
  4692. shr dx, cl (* dx now holds only the exponent*)
  4693. jz @lpush_small
  4694. cmp dx, 7FFH
  4695. je @lpush_large
  4696. @lpush_normal_range:
  4697. std (* reverse string direction*)
  4698. lea di, [di][emu_sign] (* result "pushed" in reverse order*)
  4699. stosw (* push the sign*)
  4700. sub dx, ieel_exponent_bias
  4701. xchg ax, dx
  4702. stosw (* push the exponent*)
  4703. mov dx, [si][1][w2]
  4704. mov cx, [si][1][w1]
  4705. mov bx, [si][1][w0]
  4706. mov ah, [si][by0]
  4707. mov al, 0 (* fraction now in dx:cx:bx:ax*)
  4708. and dh, 0FH (* but needs alignment*)
  4709. shl ax, 1
  4710. rcl bx, 1
  4711. rcl cx, 1
  4712. rcl dx, 1
  4713. shl ax, 1
  4714. rcl bx, 1
  4715. rcl cx, 1
  4716. rcl dx, 1
  4717. shl ax, 1
  4718. rcl bx, 1
  4719. rcl cx, 1
  4720. rcl dx, 1
  4721. or dh, 80H (* set the integer bit*)
  4722. xchg ax, dx
  4723. stosw
  4724. xchg ax, cx
  4725. stosw
  4726. xchg ax, bx
  4727. stosw
  4728. xchg ax, dx
  4729. stosw (* the fraction is now pushed*)
  4730. @lpush_end:
  4731. mov ax, ds (* swap segments back as they were*)
  4732. mov bx, es
  4733. mov ds, bx
  4734. mov es, ax
  4735. pop di
  4736. ret 0
  4737. (* handle extreme values here.*)
  4738. @lpush_small:
  4739. mov dx, zero_exponent
  4740. mov ch, fe_Operand_Too_Small (* anticipate a Denormal*)
  4741. jmp @lpush_extreme
  4742. @lpush_large:
  4743. mov dx, infinite_exponent
  4744. mov ch, fe_Operand_Too_Big (* anticipate a NAN*)
  4745. @lpush_extreme:
  4746. mov al, [si][w3][by0] (* Check for NAN's or Denormals*)
  4747. and ax, 000FH (* which will not have*)
  4748. or ax, [si][w2] (* all-zeroes*)
  4749. or ax, [si][w1] (* fractions.*)
  4750. or ax, [si][w0]
  4751. jz @lpush_extremeCorrect
  4752. call e287_Exception
  4753. @lpush_extremeCorrect:
  4754. xchg ax, dx
  4755. call emu_Extreme
  4756. jmp @lpush_end
  4757. (*INCLUDE IEESSTAK.ASM*)
  4758. (* An IEEE real is packed into 32 bits.*)
  4759. (* byte 3 byte 0*)
  4760. (* - ------- - ------- -------- --------*)
  4761. (* |s eeeeeee|e.fffffff|ffffffff|ffffffff|*)
  4762. (* - ------- -.------- -------- --------*)
  4763. (* bit 32 . 0 bit*)
  4764. (* 1.*)
  4765. (* The most significant bit is the sign bit, one if negative.*)
  4766. (* The next 8 bits are the exponent, "biased" so that a value of 7Fh*)
  4767. (* is used for numbers from 1.0 to 1.999..., and the extreme values*)
  4768. (* 00H and FFH represent zero and infinity respectively. The exponent*)
  4769. (* is in powers of 2.*)
  4770. (* The remaining 23 bits are the normalised fraction. When the fraction*)
  4771. (* is normalised its leftmost bit is always "1", so it can be ignored*)
  4772. (* and only the 23 next, unpredictable, bits are kept. The 24th bit is*)
  4773. (* restored before any calculations. For both infinities and zero the*)
  4774. (* fraction part is all zeroes.*)
  4775. (* If the number is denoted by the triple (sign, exponent, fraction) then*)
  4776. (* its value is*)
  4777. (* (-1)^sign * 2^(exponent-127) * 1.fraction*)
  4778. (* There are in addition some special values. NAN's (Not A Number) are*)
  4779. (* variations on infinity, having an exponent of FFH but fraction parts*)
  4780. (* which are not all zeroes. NAN's have various uses the most likely of*)
  4781. (* which is use as memory-fill values when checking for non-initialisation*)
  4782. (* errors. When a NAN is encountered, an overflow status is generated.*)
  4783. (* The other special values are denormals, which are underflows. These*)
  4784. (* have zero exponent but non-zero fraction, while true zero has an*)
  4785. (* all-zeroes fraction. They represent numbers in the marginal range*)
  4786. (* too small to be represented normally but close enough to the edge*)
  4787. (* of normal to allow partial representation. Here no attempt is made*)
  4788. (* to interpret de-normals, which are of marginal utility, and they*)
  4789. (* give rise to underflow status if they are encountered.*)
  4790. (*public*) iees_Pop : (*NEAR*)
  4791. (* FUNCTION iees_Pop (x : emu_temp) : IEEE_short;*)
  4792. (* convert a temporary floating-point number to an IEEE 32-bit real.*)
  4793. (* input:*)
  4794. (* - a temporary floating point number at ds:[si]*)
  4795. (* output:*)
  4796. (* - an IEEE real at es:[di]*)
  4797. (* side effects*)
  4798. (* - may exit via exception*)
  4799. mov ax, [si][emu_fraction][w2]
  4800. mov dx, [si][emu_fraction][w3]
  4801. mov bx, [si][emu_exponent]
  4802. mov cl, [si][emu_sign]
  4803. cmp word [si][emu_fraction][w0], 0
  4804. jnz @spop_isSticky
  4805. cmp word [si][emu_fraction][w1], 0
  4806. jnz @spop_isSticky
  4807. test al, 7FH
  4808. jnz @spop_isSticky
  4809. test ah, 1 (* bankers' rounding causes alternate*)
  4810. jz @spop_carried (* round up/down of exact .5 fraction.*)
  4811. @spop_isSticky:
  4812. add al, al (* round off least 8 bits*)
  4813. adc ah, 0
  4814. adc dx, 0
  4815. jnc @spop_carried (* rounding can force renormalisation*)
  4816. rcr dx, 1
  4817. rcr ax, 1
  4818. inc bx
  4819. @spop_carried:
  4820. add bx, iees_exponent_bias (* IEEE exponent is biased*)
  4821. jle @spop_underflow
  4822. cmp bx, 255
  4823. jnl @spop_overflow
  4824. (* If the number is not to be zero or infinite, then pack the three*)
  4825. (* parts into 32 bits as per IEEE.*)
  4826. @spop_normal:
  4827. shl dx, 1 (* throw away the integer bit (always = 1)*)
  4828. shr cl, 1 (* get the sign bit*)
  4829. rcr bl, 1 (* which becomes most sig bit of result*)
  4830. rcr dx, 1 (* .. and exponent shuffles up fraction*)
  4831. mov al, ah
  4832. mov ah, dl
  4833. mov dl, dh
  4834. mov dh, bl
  4835. @spop_end:
  4836. stosw (* store result at es:di*)
  4837. xchg ax, dx
  4838. stosw
  4839. sub di, 4 (* restore original value of di*)
  4840. ret 0
  4841. (* Note that status warning need be generated only if the number has*)
  4842. (* just become infinite or zero due to change in representation. If*)
  4843. (* the input was already zero or infinite, the status remains OK.*)
  4844. @spop_overflow: (* all overflows become positive infinity*)
  4845. cmp word [si][emu_exponent], infinite_exponent
  4846. jge @spop_prior_infinity
  4847. mov ch, fe_Overflow
  4848. call e287_Exception
  4849. @spop_prior_infinity:
  4850. mov dx, 7F80H
  4851. sub ax, ax
  4852. jmp @spop_end
  4853. @spop_underflow: (* all underflows become positive zero*)
  4854. cmp word [si][emu_exponent], zero_exponent
  4855. jle @spop_prior_zero
  4856. mov ch, fe_Underflow
  4857. call e287_Exception
  4858. @spop_prior_zero:
  4859. sub dx, dx
  4860. mov ax, dx
  4861. jmp @spop_end
  4862. (*public*) iees_Push : (*NEAR*)
  4863. (* FUNCTION iees_Push (x : IEEE_short) : emu_temp;*)
  4864. (* Procedure to take a IEEE real and push the equivalent*)
  4865. (* temporary format number onto stack.*)
  4866. (* inputs*)
  4867. (* - short IEEE real at es:si*)
  4868. (* outputs*)
  4869. (* - temp floating point at ds:di*)
  4870. (* side effects*)
  4871. (* - can set exception exit*)
  4872. push si
  4873. push di
  4874. push es
  4875. cld (* forward string direction*)
  4876. mov ax, es : [si][w0]
  4877. mov dx, es : [si][w1]
  4878. sub si, si
  4879. shl dx, 1 (* carry := sign, DH := exponent*)
  4880. rcl si, 1 (* si is sign*)
  4881. or dh, dh
  4882. jz @spush_small (* check for extreme exponents*)
  4883. cmp dh, 0FFH
  4884. je @spush_large
  4885. @spush_normal:
  4886. mov bl, dh (* get the exponent byte*)
  4887. mov bh, 0
  4888. sub bx, iees_exponent_bias (* bx is exponent*)
  4889. stc (* set carry = integer bit*)
  4890. rcr dl, 1
  4891. mov dh, dl
  4892. mov dl, ah
  4893. mov ch, al
  4894. mov cl, 0 (* dx:cx is now the fraction*)
  4895. @spush_result:
  4896. push ds
  4897. pop es (* arrange so es:[di] points to result*)
  4898. sub ax, ax
  4899. stosw (* extended to 64 bits with zeroes*)
  4900. stosw
  4901. xchg ax, cx
  4902. stosw
  4903. xchg ax, dx
  4904. stosw
  4905. xchg ax, bx
  4906. stosw
  4907. xchg ax, si
  4908. stosw
  4909. @spush_end:
  4910. pop es
  4911. pop di
  4912. pop si
  4913. ret 0
  4914. (* special treatment for extreme values.*)
  4915. @spush_large:
  4916. inc dh (* convert FFH to 00H*)
  4917. mov bx, infinite_exponent
  4918. mov ch, fe_Operand_Too_Big (* anticipate a NAN*)
  4919. jmp @spush_extreme
  4920. @spush_small:
  4921. mov bx, zero_exponent
  4922. mov ch, fe_Operand_Too_Small (* anticipate a Denormal*)
  4923. @spush_extreme:
  4924. or dx, ax (* check for de-normals*)
  4925. jz @spush_continue
  4926. call e287_Exception
  4927. @spush_continue:
  4928. mov si, positive_sign (* extremes always positive*)
  4929. sub dx, dx
  4930. sub cx, cx (* zero or infinite, fraction = 0*)
  4931. jmp @spush_result
  4932. (*INCLUDE EMUINIT.ASM*)
  4933. (*public*) e287_Exception :
  4934. (* called when exception detected. Exception status in CH. Process *)
  4935. (* CH against mask. If masked, then return to caller to continue with *)
  4936. (* default exception processing, otherwise do exception exit. If *)
  4937. (* allowed, then stop the current instruction and forget all partial *)
  4938. (* calculations, just return. *)
  4939. (* Precision Errors do not stop completion of the current operation, *)
  4940. (* being considered a "mild" error, and often being signalled with the *)
  4941. (* default action of a harsher masked error, though this if unmasked *)
  4942. (* does cause error interrupt when the next instruction is attempted. *)
  4943. (* The routine is designed also to be called with CH=0 after the Control *)
  4944. (* Word (and hence the mask) is changed, and can thus clear Error Summary *)
  4945. (* as well as set it. *)
  4946. (* The error is actually detected when the program tries to execute the *)
  4947. (* next numerics instruction. Presumably the iNDP-87 is designed like *)
  4948. (* that because the iAPX-?86 may have switched into unrelated code by *)
  4949. (* the time the exception occurs, and the iNDP-87 can't be sure the *)
  4950. (* CPU will be in the correct context until the next numeric instruction. *)
  4951. push ax (* must not upset caller's registers *)
  4952. push cx
  4953. push ds
  4954. push ss
  4955. pop ds (* some callers may use other ds values *)
  4956. mov al, [emws_status]
  4957. mov cl, [emws_control]
  4958. and cl, 3FH (* select the exception mask bits *)
  4959. xor cl, 3FH (* invert the mask for convenience *)
  4960. or al, ch (* add in new exceptions *)
  4961. mov ah, al
  4962. and ah, cl
  4963. xor ah, al (* AH shows masked exceptions. *)
  4964. test ah, fe_Overflow (* if Overflow but masked, *)
  4965. jz notMaskedOver
  4966. or al, 20H (* then convert into Precision error *)
  4967. notMaskedOver:
  4968. test al, cl (* any unmasked exceptions ? *)
  4969. jz resumeDefault
  4970. or al, 80H (* set Error Summary *)
  4971. mov [emws_status], al
  4972. and al, cl
  4973. cmp al, 20H (* if only a precision error, resume. *)
  4974. (*ifndef instantException
  4975. jne ExceptionExit (* else abort current instruction. *)
  4976. else*)
  4977. jne QuitException (* emulate exception interrupt now. *)
  4978. (*endif*)
  4979. pop ds
  4980. pop cx
  4981. pop ax
  4982. ret 0 (* resume if precision error. *)
  4983. resumeDefault:
  4984. and al, 7FH (* clear Error Summary *)
  4985. mov [emws_status], al
  4986. pop ds
  4987. pop cx
  4988. pop ax
  4989. ret 0
  4990. public QuitException :
  4991. mov sp, ss:[emws_resume_bp]
  4992. pop bp
  4993. pop es
  4994. pop ds
  4995. pop di
  4996. pop si
  4997. pop dx
  4998. pop cx
  4999. pop bx
  5000. pop ax
  5001. extrn __FloatEmulNMI
  5002. jmp far __FloatEmulNMI
  5003. end
  5004.