Moving Forth Part 3.docx
《Moving Forth Part 3.docx》由会员分享,可在线阅读,更多相关《Moving Forth Part 3.docx(23页珍藏版)》请在冰豆网上搜索。
MovingForthPart3
MOVINGFORTH
Part3:
DemystifyingDOES>
byBradRodriguez
ThisarticlefirstappearedinTheComputerJournal#62(July/August1993).
OOPS!
There'sacolossalmistakeinoneofmy6809designdecisionsinthepreviousinstallment.ItbecameevidentwhenIstartedtocodetheForthwordEXECUTE.
EXECUTEcausestheexecutionofasingleForthword,whoseaddressisgivenontheParameterStack.(Tobeprecise:
thecompilationaddress,a.k.a.CodeFieldAddress,isgivenonthestack.)ThiscanbeanykindofForthword:
CODEdefinition,colondefinition,CONSTANT,VARIABLE,ordefinedword.ThisdiffersfromtheusualForthinterpretationprocessinthattheaddressoftheword-to-executeisgivenonthestack,andnottakenfromthe"thread"(aspointedtobyIP).
Inourdirect-threaded6809codethiscanbeeasilycoded:
EXECUTE:
TFRTOS,WputaddressofwordinW
PULUTOSpopnewTOS
JMP,WjumptoaddressgiveninW
Note:
thisisJMP,WandnotJMP[,W],sincewealreadyhavethecodeaddressoftheword.We'renotfetchingfromthehigh-levelthread.(IfTOSwasn'tinregister,EXECUTEcouldbedonewithsimplyJMP[,PSP++].)NowsupposethatthisEXECUTEdwordisacolondefinition.WwillbepointingtoitsCodeField,whichcontainsJMPENTER.Thisdoesthefollowing(describedinthepreviousarticle):
JMPENTER
...
ENTER:
PSHSIP
LDX-2,IPre-fetchtheCodeFieldaddress
LEAY3,X
NEXT
Thisisthemistake!
Wearenotexecutingthiswordfromwithinathread,soIPwasnotpointingtoacopyofitsCodeFieldaddress!
(Remember,theaddressoftheword-to-EXECUTEcamefromthestack.)ThisformofENTERwillnotworkwithEXECUTE,becausethereisnowaytofindtheaddressofthewordbeingexecuted!
ThissuggestsanewgeneralruleforDTCForths:
ifNEXTdoesNOTleavetheaddressoftheword-being-executedinaregister,youMUSTuseaCallinthecodefield.
So,the6809ForthisbacktousingaJSRintheCodeField.ButtoavoidthespeedpenaltyforENTER--oneofthemost-usedcodefragmentsinForth--I'llcompletethe"exerciseforthestudent"fromthelastarticle.NotewhathappensifyouswaptheregistersassignedtoRSPandPSP:
withRSP=S,withRSP=U,
andPSP=UandPSP=S
(previous)(new)
JSRENTERJSRENTER
......
ENTER:
PULSWPSHUIPpusholdIPontoRstack
PSHSIPPULSIPpopnewIPfromJSRstack
TFRW,IPNEXT
NEXT
Thenewversionexecutesin31cycles,thesameastheJMPversionIhadwantedtouse.TheimprovementisbecausetheJSRversionofENTERmustusebothForth'sReturnStack,andthe6809subroutine-returnstack("JSRstack").Usingtwodifferentstackpointersmeanswedon'thaveto"swap"thetop-of-stackwithIP,eliminatingtheneedforatemporaryregister.
ThisillustratestheusualdevelopmentprocessforanewForthkernel:
makesomedesigndecisions,writesomesamplecode,discoverabugorabetterwaytodothings,throwoutsomecode,changesomedesigndecisions,rewritesomesamplecode,loopuntilsatisfied.(Thisistheprogrammingequivalentofa"ripup"PCboardautorouter.)
Thisteachesanimportantlesson:
makeEXECUTEoneofyourbenchmarkwords!
OOPS,AGAIN
CareyBloodworthofVanBuren,ARhaspointedoutaminorbutembarassingmistakeinmy6809codeinthepreviousinstallment.Forthe"TOS-in-memory"versionof0=,Ishowedthecodefragment
LDD,PSP
CMPD#0
totestfortop-of-stackequallingzero.Inthiscase,theCMPDinstructioniscompletlysuperfluous,sincetheLDDinstructionwillsettheZeroflagifDiszero!
(TheTOS-in-DversionstillrequirestheCMPDinstruction,butremainsfasterthanTOS-in-memory.)
Now,ontoourmaintopic:
WHAT'SACODEFIELD?
TheDOES>conceptseemstobeoneofthemostmisunderstoodandmystifyingaspectsofForth.YetDOES>isalsooneofForth'smostpowerfulfeatures--inmanyways,itanticipatedobject-orientedprogramming.TheactionandpowerofDOES>hingesuponabrilliantinnovationofForth:
theCodeField.
RecallfromPart1thatthe"body"ofaForthdefinitionconsistsoftwoparts:
theCodeField,andtheParameterField.Youcanthinkofthesetwofieldsinseveralways:
*TheCodeFieldisthe"action"takenbythisForthword,andtheParameterFieldisthedataonwhichitacts.
*TheCodeFieldisasubroutinecall,andtheParameterFieldisparametersthatareincluded"in-line"afterthecall.(Theassemblylanguageprogrammer'sview.)
*TheCodeFieldisthesingle"method"forthis"class"ofwords,andtheParameterFieldcontainsthe"instancevariables"forthisparticularword.(Theobject-orientedprogrammer'sview.)
Commonfeaturesappearinalltheseviews:
*TheCodeFieldroutineisalwayscalledwithatleastoneargument,namely,theaddressoftheParameterFieldfortheForthwordbeingexecuted.TheParameterFieldmaycontainanynumberofparameters.
*Therearerelativelyfewdistinctactions,i.e.,relativelyfewdistinctroutinesreferencedbytheCodeField.Eachoftheseroutinesiswidelyshared(exceptforCODEwords,aswewillseelater).Recall,forexample,theENTERroutinefromPart2:
thiscommonroutineisusedbyallForthcolondefinitions.
*TheinterpretationoftheParameterFieldisimplicitlydeterminedbythecontentsoftheCodeField.I.e.,eachCodeFieldroutineexpectstheParameterFieldtocontainacertainkindofdata.
AtypicalForthkernelwillhaveseveralCodeFieldroutinespredefined.
CodeFieldParameterField
routinecontents
ENTERahigh-level"thread"(seriesofaddresses)
DOCONaconstantvalue
DOVARastoragelocationfordata
DOVOCvocabularyinfo(variesbyimplementation)
WhatmakesthisfeaturepowerfulisthataForthprogramisnotlimitedtothissetofCodeFieldroutines(orwhateversetisprovidedinyourkernel).TheprogrammercandefinenewCodeFieldroutines,andnewParameterFieldstomatch.Inobject-orientedlingo,new"classes"and"methods"canbecreated(althougheachclasshasonlyonemethod).And--likeForthwordsthemselves--theCodeFieldactionscanbedefinedineitherassemblylanguageorhigh-levelForth!
TounderstandthemechanismoftheCodeField,andhowparametersarepassed,wewillfirstlookatthecaseofassembly-language(machinecode)actions.We'llstartwithIndirectThreading(ITC),sinceitistheeasiesttounderstand,andthenseehowthelogicismodifiedinDirect-Threaded(DTC)andSubroutine-Threaded(STC)Forths.Then,we'lllookathowtheCodeFieldactioncanbewritteninhigh-levelForth.
Forthwrightsaresomewhatinconsistentintheirterminology,soI'lldefinemyterms,usingtheITCForthwordillustratedinFigure1.TheHeadercontainsthedictionaryinformation,andisn'tinvolvedintheexecutionoftheForthword.TheBodyisthe"working"partoftheword,andconsistsofthefixed-lengthCodeField,andthevariable-lengthParameterField.Foranygivenword,thelocationsofthesetwofieldsinmemoryaretheCodeFieldAddress(CFA)andtheParameterFieldAddress(PFA),respectively.TheCodeFieldAddressofawordistheaddressinmemorywhereitsCodeFieldislocated.ThisisnottobeconfusedwiththecontentsoftheCodeField,which,inITCForths,isanotherdifferentaddress.Tobespecific,thecontentsoftheCodeFieldistheaddressofafragmentofmachinecodesomewhereelseinmemory.IwillrefertothisastheCodeAddress.Later,whenindiscussingDTCandSTCForths,Iwillalsorefertothe"CodeFieldcontents,"whichwillincludemorethanjusttheCodeAddress.
MACHINE-CODEACTIONS
ForthCONSTANTsareprobablythesimplestexampleofamachine-codeaction.Let'sconsidersomegoodFrancophoneconstants
1CONSTANTUN
2CONSTANTDEUX
3CONSTANTTROIS
ExecutingthewordUNwillpushthevalue1ontotheForthParameterStack.ExecutingDEUXwillpusha2ontothestack,andsoon.(Don'tconfuseParameterStackwithParameterField;theyareentirelyseparate.)
IntheForthkernelthereisasinglewordcalledCONSTANT.Thisisnotaconstant-typeworditself;itisahigh-levelForthdefinition.CONSTANTisa"definingword":
itcreatesnewwordsintheForthdictionary.Herewecreatethenew"constant-type"wordsUN,DEUX,andTROIS.(Youmaythinkoftheseas"instances"ofthe"class"CONSTANT.)ThesethreewordswillhavetheirCodeFieldspointingtoamachinecodefragmentthatdoestheactionofCONSTANT.
Whatmustthiscodefragmentdo?
Figure2showsthememoryrepresentationofthethreeconstants.Allthreewordspointtoacommonactionroutine.ThedifferenceinthewordsisentirelycontainedintheirParameterFields,which,inthiscase,simplyholdtheconstantvalues("instancevariables"inobjectlingo).So,theactionofthesethreewordsshouldbefetchthecontentsoftheParameterField,andpushthisontothestack.Thecodeunderstandsimplicitlythattheparameterfieldcontainsasingle-cellvalue.
Towriteamachine-codefragmenttodothis,weneedtoknowhowtofindtheParameterFieldAddress,aftertheForthinterepreterjumpstothemachinecode.Thatis,howisthePFApassedtothemachine-coderoutine?
This,inturn,dependsonhowtheForthinterpreterNEXThasbeencoded,whichvariesfromimplementationtoimplementation.Towritemachine-codeactions,wemustunderstandNEXT.
TheITCNEXTwasdescribedinpseudo-codeinPart1.Here'soneimplementationforthe6809,usingY=IPandX=W:
NEXT:
LDX,Y++;(IP)->W,andIP+2->IP
JMP[,X];(W)->temp,JMP(temp)
Supposethatwe'reinahigh-levelthread
...SWAPDEUX+...
withtheInterpreterPointer(IP)pointingtotheDEUX"instruction,"whenNEXTisexecuted.(ThiswouldbeattheveryendofSWAP.)Figure3illustrateswhathappens.IP(registerY)