IMD 1.17: 25/11/2014 12:45:06 82VKXBVERDOS D* BT18:0 68K VERSADOS/RMS68K OBJECT 4.5 (DS,DD 96 tpi 5.1/4" DISK) REVISED: 04/22/86 DISK 18 OF 24  BT18 82VKXBVERDOS 0420±k-|�CMR‡|-------->|�User…|-------->|‚Input�Buffer�1‚|/*‰|�Parameter�|‰|�Task'sƒ|‰+------------------+*‰|�Block…|‰|�I/O†|„.Ž.*‰+-----------+‰|�Command‚|„.Ž.*Ÿ|�Block„|„.Ž.*Ÿ|Š|*Ÿ|Š|‰+------------------+ *Ÿ|Š|-------->|‚Input�Buffer�n‚|#*Ÿ+----------+‰+------------------+**´Note:‚Input�buffers.*‰+-----------+‰+----------+‰are‚used‚only‚for:*‚A5�--->|�CCB‡|-------->|�MVME-600�|‰the�MEASURE�command./*‰|�(Channel‚|‰|�Memory-‚|‰They�are�not�present,*‰|�Controlƒ|‰|�Mappedƒ|‰for�other�commands.*‰|�Block)„|‰|�I/O�Area�|*‰+-----------+‰+----------+***‰+-----------+*‚A6�--->|�TCB‡| *‰|�(Task…| *‰|�Controlƒ| *‰|�Block)„|*‰+-----------+**E*‡Upon�return�from�subroutine�COMMANDS�register�A6‚must‚be‚preserved.K*‚In‚fact,‚as�a�standard�practice�throughout�the�entire�operating�system�we*‰PAGEJ*‚always�maintain�A6�as�a�pointer�to�the�TCB�for�the�task‚that‚called‚uponI*‚the‚operating‚system‚to�perform�an�operation.‚If�a�system�crash�somehowJ*‚occurs,�register�A6�can�provide�a�clue�to�the�environment�at‚the‚time‚of *‚the�crash.*G*‡Besides‚preserving�register�A6,�subroutine�COMMANDS�must�put�a�statusG*‚code�into�D0.B�(i.e.,�the‚least-significant‚byte‚of‚register‚D0)‚uponI*‚return‚to‚the‚calling�routine.‚If�subroutine�COMMANDS�processes�the�I/OK*‚request�without�finding�any�errors,�the�subroutine�returns�control‚to‚theK*‚calling‚routine�with�D0.B�=�0�to�indicate�that�all�is�well.‚If�subroutineM*‚COMMANDS�discovers�an�error,�however,�the�subroutine�returns�control�to�theF*‚calling‚routine‚with‚a‚nonzero‚error‚code‚in�D0.B�to�indicate�that�aI*‚problem�has�been�encountered.‚Subroutine�COMMANDS�uses‚a‚unique‚nonzeroM*‚error�code�for�each�particular�error�that�the�subroutine�can�detect,�so�theI*‚user�can�determine�the�exact�nature�of�a�problem‚by‚examining‚the‚errorJ*‚code‚that‚subroutine�COMMANDS�returns�in�D0.B.‚A�complete�list�of�all�ofM*‚the�error�codes�and�their�meanings�is�available�elsewhere�in�the�listing�of*‚the�A/D�driver.*H*‡A�zero�status�code�in�D0.B�indicates�only�that�subroutine�COMMANDS�hasK*‚processed�the�user�task's�I/O�request�without�detecting�any�errors,‚and‚aL*‚zero‚status�code�does�not�necessarily�indicate�that�the�I/O�activities�forK*‚the�I/O�request�have�been�completed�without�any�errors.‚Some�I/O‚requestsM*‚cause�subroutine�COMMANDS�to�set�up�sequences�of�I/O�operations�that�are�toK*‚be�performed�over�an�extended�period�of�time.‚In�cases�like�these,�a‚zeroL*‚status‚code�that�is�returned�in�D0.B�by�subroutine�COMMANDS�indicates�onlyF*‚that�the�subroutine�has�processed�the‚I/O‚request‚and‚has‚set‚up‚theI*‚sequences‚of‚I/O‚operations�without�detecting�any�errors.‚A�zero�statusK*‚code�in�such�a�case�does�not�indicate�that�any�of�the�I/O‚operations‚haveH*‚been‚completed‚successfully,‚and‚the‚I/O�operations�could�cause�errors *‚later�when�they�are�performed.*C*‡Besides�returning�a�status�code‚in‚D0.B,‚subroutine‚COMMANDS‚alsoI*‚returns‚the‚same‚status‚code�in�the�status�field�of�the�user�task's�I/OH*‚command�block.‚The�I/O�command�block�is�the‚parameter‚block‚that‚tellsL*‚subroutine‚COMMANDS�exactly�what�the�user�task�wants�the�driver�to�do,�andL*‚the�layout�of�the�I/O�command�block�is�defined�elsewhere�in�the�listing‚of*‚the�A/D�driver.*C*‡In‚addition‚to‚preserving‚A6‚and�returning�a�status�code�in�D0.B,M*‚subroutine�COMMANDS�must,�of�course,�preserve�the�SP�and�the�system�byte�ofH*‚the‚SR.ƒAll‚other‚registers�may�be�modified�upon�return�to�the�calling *‚routine.*F*‡Subroutine�COMMANDS�performs�the�common�tasks�that�are‚necessary‚for H*‚all‚command‚routines,‚and‚then‚the�subroutine�uses�a�command�switchingL*‚table�to�direct�control�to�the�individual�routine�that�processes�the‚givenE*‚command.ƒIf‚the‚command-code‚value‚in‚the‚I/O�command�block�doesn'tI*‚designate�a�valid�command,�subroutine�COMMANDS�returns‚an‚error‚code‚inM*‚D0.B�(and�in�the�status�field�of�the�user�task's�I/O�command�block)�to�tell,*‚the�user�task�that�the�command�is�invalid.*‰PAGEG*‡The�table�below�summarizes�the�general�usage�of�registers�in�the‚partC*‚of‚subroutine‚COMMANDS‚that‚is‚common‚to‚all‚command‚routines.‚InM*‚particular,�the�final�values�that�are�shown�below�are�in�the�registers�whenE*‚control‚branches‚from‚the‚common‚part‚of‚subroutine‚COMMANDS�to�the4*‚individual�routine�that�handles�the�given�command.*F*‚#�&�A6�=�LOC(TCB�of�the�task�that�invoked�CMR).„#�=�Entry�condition.-*‚#�&�A5�=�LOC(CCB).¡&�=�Preserved�on�return.#*†A4�=�LOC(CMD_CODE�field�in�IOCB).*†A3�=�LOC(DUPETBL).?*‚#ƒA2�=�LOC(CMR�Parameter�Block)�initially.‚Then�LOC(MSBDATA).6*†A1�=�LOC(CNFIELD�in�IOCB)�if�the�IOCB�has�a�CNFIELD.*†A0�=�Scratch.* *†D6.L�=�0.D*†D5.L�=�Number�of�words�in�IOCB�after�CMD_CODE�field.‚Also�in�D4.L.D*†D4.L�=�Number�of�words�in�IOCB�after�CMD_CODE�field.‚Copy�of�D5.L. *†D3.L�=�0.*†D2.L�=�Scratch.C*†D1.L�=�Scratch.‚Control�offset�for�the�channel�being�initialized.+*†D0.B�=�STATNSNG�(for�the�MEAS_S�command).**B*‡The�individual�command-processing‚routines‚all‚use‚a‚common‚exitG*‚routine‚to‚ensure‚a‚uniform‚return‚condition�for�subroutine�COMMANDS.J*‚Subroutine�COMMANDS�preserves�A6,�A5,�the�SP,�and�the�system‚byte‚of‚theJ*‚SR,‚and‚the‚subroutine�returns�its�status�code�in�D0.B�and�in�the�statusE*‚field�of�the�user�task's‚I/O‚command‚block.ƒAll‚other‚registers‚areK*‚subject‚to‚modification�and�may�contain�meaningless�values�upon�return�to*‚the�calling�routine.*C*‡Note�with�care�that�the�processor�is‚at‚interrupt‚level‚zero‚whenM*‚subroutine�COMMANDS�receives�control,�so�subroutine�COMMANDS�and�all�of�itsG*‚subordinate�routines�are‚subject‚to‚interrupts‚from‚the‚periodically-L*‚activated‚measurement�routine�and/or�from�the�completion�of�an�externally-K*‚triggered�measurement.‚The�periodically-activated�measurement�routine‚andK*‚the‚A/D‚interrupt�handler�may�access�and/or�change�values�in�the�CCB,�andE*‚subroutine�COMMANDS�must�be�carefully�coded�with�this�fact�in�mind.  ?COMMANDS�MOVE.LƒSP,SAVE_SP(A5)‰Save�the‚stack‚pointer‚so‚we‚can$*¦later‚abort‚at‚any‚level‚of�nested$*¦subroutines‚and‚easily‚restoreƒthe%*¦stack‚environment‚that‚existed‚when*¦this�routine�began�execution.-‰PAGEš#######################################2‰MOVE.LƒA5,A4’Set‚A4�<--�LOC(CCB)�to�indicate�that%*¦A4�doesn't‚yet‚contain‚the‚physical)*¦memory�address�of�the�CMD_CODE�field�of'*¦the�user's�IOCB.‚Since�the�IOCB‚can't)*¦possibly�be�at�the�same�physical�memory(*¦location�where�the�CCB�resides,�we‚can'*¦later‚compare‚A4�to�A5�to�find�out�if)*¦A4�has�been�set�to�contain�the�physical)*¦memory�address�of�the�CMD_CODE�field�of&*¦the�user's�IOCB.‚As�long�as�A4‚=‚A5,)*¦we�know�that�A4�doesn't�yet�contain�the&*¦address�of�the�CMD_CODE‚field‚of‚the'*¦IOCB.ƒAfter�A4�=�LOC(CMD_CODE[IOCB]),(*¦we'll�be�able�to�use�A4�to�address‚the&*¦user's‚IOCB.ƒIn�particular,�we'll�be$*¦able�to�access‚the‚IOCB‚to‚store‚a&*¦status‚code‚into‚the�STATUS�field�of *¦the�IOCB. "*¨This�step‚and‚the‚next‚two‚steps%*¦should‚be‚done‚in‚order�with�no�new%*¦intervening�steps.ƒThe‚code‚remains(*¦sensitive‚until�A4�has�been�set�to�its#*¦final�value,�LOC(CMD_CODE[IOCB]). 8‰MOVE.LƒXIOCPK(A2),D6ŠGet�the�physical‚memory‚address‚of0‰MOVEQ.L‚#0,D5�the‚IOCB‚for‚the‚command‚into‚A4.<‰MOVE.WƒXIOPLN(A2),D5ˆSubroutine�LOGPHY�converts�the‚logical2‰BSR†LOGPHY�IOCB‚address�(in�D6.L)�into�a�physical2‰MOVE.LƒD6,A4�address�for�us.‚We�must‚call‚subrou-$*¦tine‚LOGPHY‚with‚A6‚containing‚the )*¦physical�address�of�the�TCB�of�the�task(*¦that‚owns�the�IOCB,�and�we�must�set�up'*¦D5.L�to�specify�the�length‚(in‚bytes)(*¦of�the�IOCB.‚If�all�goes�well,�subrou-)*¦tine�LOGPHY�returns�the�physical�memory*¦address�of�the�IOCB�in�D6.L. %*¨Subroutine‚LOGPHY‚aborts�processing$*¦if�the�IOCB‚that‚we‚specify‚is‚not'*¦entirely‚within‚a�memory�segment�that)*¦belongs�to�the�task�that�owns�the�IOCB.(*¦If‚this�error�occurs,�the�fact�that�we(*¦set�A4�=�A5�above�will�prevent�us‚from'*¦trying‚to‚store�a�status�code�into�an#*¦IOCB�that�doesn't�properly�exist. #*¨We�must‚execute‚one‚more‚critical(*¦step‚to�set�A4�to�its�final�value,�and&*¦then�this�sequence‚of‚critical‚steps*¦will�be�complete.-‰PAGEš#######################################3‰MOVEQ.L‚#0,D6’Clear�D6.L�for�general�use,�and‚then8‰MOVE.WƒD6,(A4)+�initialize�the�STATUS�field�of�the�IOCB3LˆSET†STATUS�to�zero.‚We'll�later�update�the�least-)*¦significant�byte�of�the�STATUS�field�to(*¦reflect�the�actual�status�code�that‚we*¦want�to�return�to�the�user. %*¨As‚we‚clear�the�STATUS�field�of�the(*¦IOCB�here,�we�simultaneously�set�A4‚to(*¦contain‚the�physical�memory�address�of(*¦the�CMD_CODE�field�of�the�IOCB.‚Now�we&*¦can‚safely‚use‚A4�with�autodecrement%*¦addressing�to�update‚the‚LSB‚of‚the*¦STATUS�field�in�the�IOCB. "*¨Thisƒstep‚completes‚the‚critical&*¦sequence�of�three�steps‚that‚must‚be'*¦done‚in‚order�with�no�intervening�new"*¦steps.ƒNow‚we‚can‚safely‚use‚the)*¦common�exit�routine�whenever�we�want�to *¦exit�from�subroutine�COMMANDS. 7‰MOVEQBƒSTATCBLN,D0ŒIf�the�specified�length�of‚the‚IOCB:‰SUBQ.Lƒ#IOCB_MIN,D5‰is‚shorter‚than�the�minimum�allowable4‰BLO.S„CMDEXIT2�length�for�an‚IOCB,‚abort‚processing-‰LSR.L„#1,D5�andƒreturnƒan‚error‚status‚code.5‰MOVE.LƒD5,D4�Otherwise,�set�both�D5.L�and�D4.L�equal$*¦to‚the‚number‚of‚words‚(not�bytes)(*¦remaining�in�the�IOCB�after�the�end‚of(*¦the�CMD_CODE�field.‚We'll�later�use�D5(*¦and�D4�as�counters�when�we�process‚the(*¦remaining�fields�(if�any)�of�the�IOCB. 8‰MOVEQBƒISTACDN,D0�If�the�A/D�channel�is�down,�go�return7‰TST.B„AD_DOWN(A5)Šan�error�status�to‚indicate‚that‚the5‰BNE.S„CMDEX2AŽA/D‚channel�is�out�of�service�for�now.$*¦Although‚we‚could‚process‚OPEN‚and(*¦CLOSE‚commands�for�a�dead�A/D�channel,&*¦we�choose�to�reject‚all‚A/D‚commands*¦for�the�sake�of�consistency.-‰PAGEš#######################################1‰TST.B„BAD_INT(A5)ŒIf‚we‚have‚receivedƒaƒspurious0‰BEQ.S„L9“interrupt‚from�the�A/D�converter�board(*¦and�haven't�yet�reported�it,�clear‚the8‰CLR.B„BAD_INT(A5)Šbad-interrupt‚flag,‚abort�the�current4‰MOVEQBƒSTATBINT,D0Šcommand,‚andƒreportƒtheƒspurious‚32,767‚(i.e.,‚$7FFF)&*¦because‚the‚processor‚interprets�the(*¦value�in�D2.W�as�a�signed�number‚here.&*¦We‚could‚easily‚avoid�this�potential'*¦error�by�adding�just‚one‚instruction,(*¦but‚the�offset�value�in�D2.W�is�not�at'*¦all�likely�to�exceed�32,767.‚The‚size&*¦of‚the‚entire‚driver�(in�its�initial)*¦release)�is�smaller�than�$500�bytes,�so&*¦an‚offset‚in‚excess�of�32,767�is�not'*¦possible�unless�the�driver‚changes‚by"*¦more�than�an�order�of�magnitude.+‰TTL†5.2.1.‚OPEN_CMD�Routine�(OPEN�Command)-‰PAGEš#######################################N*******************************************************************************Ì*@*ˆThe�remaining�part�of�this�program�is�not�commented�yet.‚Any‡*A*ˆcomments�that�exist�beyond�this�point�are�scratch�comments�or‡**ˆpreliminary�comments.¯**Ì*N****************************************************************************** 4*ˆOPEN�Command.‚Control�enters�at�location�OPEN_CMD. %*†#�A6�=�LOC(TCB�of�requesting�task).*†#�A5�=�LOC(CCB).%*†#�A4�=�LOC(CMD_CODE�field�in�IOCB).*†#�A3�=�LOC(DUPETBL).*†#�A2�=�LOC(MSBDATA).*†#�A1�=�LOC(CNFIELD�in�IOCB)./*ˆA0�=�LOC(Channel�block�for�selected�channel). *ˆD7.L�= *†#�D6.L�=�0.2*†#�D5.L�=�Number�of�words�after�CMD_CODE�in�IOCB.2*†#�D4.L�=�Number�of�words�after�CMD_CODE�in�IOCB. *†#�D3.L�=�0.*ˆD2.L�=�Scratch.*ˆD1.L�=�Scratch.*ˆD0.L�=�Scratch.  8L12†BSR†VALID_CN�Validate�next�channel�number,�and�point'*¦A0�to�its�channel�block.‚Also�advance'*¦A1�to�point�to�following�channel�num. ‰MOVEQBƒSTATOPEN,D0'‰TST.L„TCB_ADDR(A0)‰Is�it�already�open?,‰BNE.S„CMDEXIT2�Error:‚Channel�already�open. 7OPEN_CMD�DBRA…D5,L12�Loop�until�all�channels�processed. ,‰BRA.S„L14’No�errors�in�any�channel�numbers.     ,L13†MOVE.Wƒ-(A1),D1�Get�next�channel�number. LˆSET†CNFIELD(‰BSR†CNLBLKAD�Point�A0�to�channel�block.9‰MOVE.LƒA6,TCB_ADDR(A0)†Open�channel�for�requesting�task./L14†DBRA…D4,L13�Loop�until�all�channels�opened.‰TTL†5.2.2.‚Common�Exit�Routine-‰PAGEš#######################################?*ˆCommon�exit�routine.‚Control�falls�in�from�above�in�one�case. %*†#�A6�=�LOC(TCB�of�requesting�task).*†#�A5�=�LOC(CCB).1*†#�A4�=�LOC(CMD_CODE�field�in�IOCB)�or�LOC(CCB). &*ˆSTATUS�word�in�IOCB�is�zero�already. /CMDEXIT1�MOVEQBƒISTAOK,D0ŒD0.B�<--�Status�code.    ,*ˆSecond�entry�point�to�common�exit�routine. *†#�D0.B�=�Status�code. 8CMDEXIT2�CMP.L„A4,A5’If�A4�=�A5,�then�A4�hasn't�yet�been2‰BEQ.S„CMDEXIT3�set�to�contain�the�physical�memory&*¦address�of�the�CMD_CODE�field�of�the&*¦IOCB.‚In�this�case,�we�have�probably)*¦aborted�processing�because�the�IOCB�was(*¦improperly�specified,�and�we�obviously$*¦can't�store�a�status�code�into�the"*¦STATUS�field�of�the�erroneously-#*¦specified�IOCB.‚The�check�that�we(*¦perform�here�prevents�us�from�making�a&*¦wild�store�into�a�random�location�of *¦memory. 3‰MOVE.BƒD0,-(A4)�Put�the�8-bit�status�code�into�the1LˆSET†STATUS�least-significant�byte�of�the�STATUS(*¦word�in�the�IOCB.‚The�most-significant)*¦byte�of�the�STATUS�word�is�zero�because'*¦we�cleared�it�at�the�beginning�of�the *¦command-processing�subroutine. DCMDEXIT3�MOVE.LƒSAVE_SP(A5),SP‰Restore�the�stack�pointer,�and�return'‰RTS›control�to�the�routine�that�called&*¦subroutine�COMMANDS.‚The�status�code(*¦is�in�D0.B�as�required.‚Notice�that�we&*¦can�use�this�return�routine�to�abort&*¦processing�from�any�level�within�the$*¦command�service�routine�because�we(*¦restore�the�stack�pointer�to�the�value&*¦that�it�had�when�subroutine�COMMANDS$*¦began�execution�at�its�main�level. #*¨Our�handling�of�the�stack�pointer'*¦appears�to�eliminate�re-entrancy,�but'*¦the�A/D�driver�is�still�re-entrant�in'*¦the�necessary�context�because�subrou-%*¦tine�COMMANDS�can�never�be�called�a(*¦second�time�from�a�user�task�executing)*¦at�interrupt�level�zero�until�we�return*¦control�from�the�first�call. $*¨Subroutine�COMMANDS�can�accept�re-'*¦entrant�calls�for�another�A/D�channel'*¦because�each�channel�has�its�own�CCB.+‰TTL†5.2.3.‚STOP_CMD�Routine�(STOP�Command)-‰PAGEš#######################################?*ˆCLOSE�Command�and�STOP�Command.‚First�part�is�common�to�both. %*†#�A6�=�LOC(TCB�of�requesting�task).*†#�A5�=�LOC(CCB).*†#�A4�=�LOC(CMD_CODE�in�IOCB).*†#�A3�=�LOC(DUPETBL).*†#�A2�=�LOC(MSBDATA).*†#�A1�=�LOC(CNFIELD�in�IOCB)./*ˆA0�=�LOC(Channel�block�for�selected�channel). *ˆD7.L�=4*†#�D6.L�=�0.‚We�set�D6.L�<--�-1�for�a�STOP�command.2*†#�D5.L�=�Number�of�words�after�CMD_CODE�in�IOCB.2*†#�D4.L�=�Number�of�words�after�CMD_CODE�in�IOCB. *†#�D3.L�=�0.*ˆD2.L�=�Scratch.*ˆD1.L�=�Scratch.*ˆD0.L�=�Scratch. :STOP_CMD�MOVEQ.L‚#-1,D6�Set�flag�to�indicate�STOP�command. ,‰TTL†5.2.4.‚CLOSECMD�Routine�(CLOSE�Command)5CLOSECMD�TST.L„D5“D5�=�0�if�no�channels�specified.‚In/‰BNE.S„L19’this�case�we�close�all�open�channels'*¦for�this�task.‚Fall�through�to�make�a)*¦list�of�all�channels�open�to�this�task.  L15†EQU†(MAXCNLS-1)*CNLBLKSZ6‰LEA†CNLBLK+L15(A5),A0„Point�A0�to�last�channel�block.7‰MOVEQWƒMAXCNLS-1,D0‰Channel�number�of�last�channel�and *¦channel�count�to�control�loop.  *ˆFirst�pass�through�the�channel�block(s)�of�the�IOCB�for�both1*ˆsingle-ended�and�differential�MEASURE�commands. %*†#�A6�=�LOC(TCB�of�requesting�task).*†#�A5�=�LOC(CCB).*†#�A4�=�LOC(CMD_CODE�in�IOCB).*†#�A3�=�LOC(DUPETBL).@*ˆA2�=�LOC(Current�field�in�channel�block�for�selected�channel).**†#�A1�=�LOC(First�channel�block�in�IOCB)./*ˆA0�=�LOC(Channel�block�for�selected�channel). *ˆD7.L�=%*ˆD6.L�=�Scratch.‚Address�for�LOGPHY.'*ˆD5.L�=�ScratchƒByte�count�for�LOGPHY.I*†#�D4.L�=�Number�of�words�after�beginning�of�first�channel�block�in�IOCB*�>�0.+*†#�D3.L�=�+0�for�single-ended�measurement."*�-1�for�differential�measurement.I*†#�D2.L�=�Number�of�words�after�beginning�of�first�channel�block�in�IOCB*�>�0.B*ˆD1.L�=�Scratch.‚We�use�it�for�channel�number�of�current�channel.*ˆD0.L�=�Scratch.  @MEAS_LP1�SUBQ.Wƒ#CHNBLKSZ/2,D2‰If�the�remaining�part�of�the�IOCB1‰BHS.S„L23’contains�enough�words�to�accommodate�a)*¦full�channel�block,�go�process�the�next*¦channel�block. :‰ADDQ.Wƒ#CHNBLKSZ/2,D2‰If�we've�finished�processing�all�of3‰BEQ.S„MEAS_PS2�the�words�of�the�IOCB,�go�start�the!*¦second�pass�through�the�channel*¦block(s)�of�the�IOCB. '*¨Otherwise,�we�have�an�IOCB�that�isn't)*¦formatted�correctly�since�it�contains�a&*¦partial�channel�block�at�its�end.‚In(*¦this�case,�control�falls�into�the�next'*¦routine,�which�reports�an�IOCB�error. AIOCB_ERR�MOVEQBƒSTATIOCB,D0ŒGet�the�status�code�that�indicates�an&*¦IOCB�that�isn't�correctly�formatted.)*¦We've�found�that�the�length�of�the�IOCB&*¦doesn't�match�up�with�the�predefined&*¦IOCB�template�for�a�MEASURE�command. 6MEAS_ERR�BRA†CMDEXIT2�Abort�processing�for�the�MEASURE'*¦command,�and�report�the�error�that�is'*¦indicated�by�the�status�code�in�D0.B.%*¦Control�branches�to�this�error�exit)*¦from�several�different�places�to�report*¦various�types�of�errors. 6L23†MOVEQ.L‚#0,D6’Clear�D6.L�to�indicate�that�we�don't5‰BSR†VALIDATE�allow�the�specified�measurement�channel(*¦to�be�previously�active,�and�then�call%*¦subroutine�VALIDATE�to�validate�the)*¦channel�number�that�is�addressed�in�the'*¦IOCB�by�A1.‚Subroutine�VALIDATE�makes(*¦several�validity�checks�on�the�channel'*¦number,�and�it�aborts�processing�with'*¦an�error�report�if�it�finds�an�error.(*¦If�subroutine�VALIDATE�doesn't�find�an)*¦error,�it�returns�the�specified�channel&*¦number�in�D1.W.‚Also,�the�subroutine(*¦advances�A1�to�point�to�the�next�field'*¦of�the�channel�block�in�the�IOCB,�and'*¦it�points�A0�to�the�CCB�channel�block(*¦for�the�specified�measurement�channel. 7‰LEA†CNL_CMPL(A0),A2ˆPoint�A2�to�the�channel-completion(*¦field�of�the�CCB�channel�block�for�the&*¦specified�measurement�channel.‚We'll)*¦use�A2�with�autoincrement�addressing�to)*¦access�several�of�the�fields�in�the�CCB*¦channel�block. %*¨We'll�save�the�pointer�to�the�first&*¦byte�of�the�CCB�channel�block�in�A0.&*¦At�the�end�of�the�first�pass�through&*¦the�channel�block(s)�of�the�IOCB,�A0)*¦will�point�to�the�CCB�channel�block�for(*¦the�last�measurement�channel�selected,)*¦and�we'll�use�that�pointer�value�during)*¦the�first�iteration�of�the�second�pass. ‰MOVE.Wƒ(A1)+,D0 LˆSET†CHN_CMP‰MOVE.WƒD0,(A2)+LˆSET†CNL_CMPL ‰ROL.B„#7-SUBR_B,D0 ‰BPL.S„L24 1‰SUBQ.Wƒ#2,D2�2�words�for�the�subroutine�address.‰BLO.S„IOCB_ERR ‰MOVE.Lƒ(A1)+,D6 LˆSET†SUBRTNE6‰MOVEQ.L‚#2,D5�Minimum�possible�length�for�subroutine. ‰BSR†LOGPHY 0L24†MOVE.LƒD6,(A2)+�Physical�subroutine�address. LˆSET†SUBRTN ‰MOVE.Lƒ(A1)+,D6 LˆSET†BUFFER‰MOVE.Wƒ(A1)+,D5 LˆSET†BUFSZ ‰BSR†LOGPHY‰MOVE.LƒD6,(A2)+LˆSET†BUF_ADDR ‰CLR.W„(A2)+LˆSET†BUF_PNTR ‰MOVEQBƒEXTTRG+PGA,D0.‰AND.W„(A1)+,D0�Ignore�all�but�those�two�bits.LˆSET†TRIGGAIN ‰AND.B„#MUX+CNLSEL,D1‰ADDQ.Bƒ#MUX07,D1 ‰OR.B…D1,D0 ‰MOVEQBƒMUX815+MUX07,D14‰AND.B„D3,D1�D3�=�$FF�IF�DIFFERENTIAL,�$00�if�single ‰OR.B…D1,D0 ‰MOV E.BƒD0,(A2)+LˆSET†CTRL_VAL ‰ROL.B„#7-EXTTRG_B,D0‰BPL.S„MEAS_LP1 ‰ST.B…ET_FLG_S(SP) ‰TST.B„MEAS_CNT(A5)‰BEQ.S„MEAS_LP1 ‰MOVEQBƒSTATBUSY,D0‰BRA.S„MEAS_ERR4‰TTL†5.2.5.3.‚Second�Pass�through�the�Channel�Blocks-‰PAGEš#######################################?*ˆSecond�pass�through�the�channel�block(s)�of�the�IOCB�for�both1*ˆsingle-ended�and�differential�MEASURE�commands. %*†#�A6�=�LOC(TCB�of�requesting�task).*†#�A5�=�LOC(CCB).*†#�A4�=�LOC(CMD_CODE�in�IOCB).5*†#�A3�=�LOC(DUPETBL).‚Available�for�scratch�use�now.*ˆA2�=;*ˆA1�=�LOC(Current�field�of�current�channel�block�in�IOCB).E*†#�A0�=�LOC(Channel�block�for�selected�channel).‚Initially�points�to>*�CCB�channel�block�for�last�selected�measurement�channel�from *�first�pass. *ˆD7.L�=*ˆD6.L�=�Scratch.*ˆD5.L�=�ScratchI*†#�D4.L�=�Number�of�words�after�beginning�of�first�channel�block�in�IOCB*�>�0.+*†#�D3.L�=�+0�for�single-ended�measurement."*�-1�for�differential�measurement.*ˆD2.L�=�Scratch.B*ˆD1.L�=�Scratch.‚We�use�it�for�channel�number�of�current�channel.*ˆD0.L�=�Scratch.  "MEAS_PS2�MOVE.Bƒ(SP)+,EXT_TRIG(A5)LˆSET†ET_FLG_S‰ADDQ.Bƒ#1,MEAS_CNT(A5)8‰MOVE.Lƒ(SP)+,A1�Point�A1�to�first�channel�block�in�IOCBLˆSET†CBADDR_S MEAS_LP2�MOVE.Wƒ(A1)+,D1 LˆSET†CHN_NUM>‰MOVE.BƒD1,CNL_PTR(A0)‡Point�previous�channel�block�to�current‰BSR†CNLBLKAD�one. ‰MOVE.Wƒ(A1)+,D0 LˆSET†CHN_CMP‰ROL.B„#7-SUBR_B,D0 ‰BPL.S„L25 +‰SUBQ.Wƒ#2,D4�2�WORDS�FOR�SUBROUTINE�FIELD.+‰ADDQ.Lƒ#4,A1�4�BYTES�FOR�SUBROUTINE�FIELD. L25†EQU†*L26†EQU†BUFSZ-BUFFERC‰MOVE.WƒL26(A1),BUF_SIZE(A0)�The�measurement�channel�is�now�active. ‰ADDQ.Lƒ#CHNBLKSZ-BUFFER,A1 ‰SUBQ.Wƒ#CHNBLKSZ/2,D4‰BHI.S„MEAS_LP2"‰TTL†5.2.5.4.‚Final�Command�Set-Up-‰PAGEš#######################################F*ˆNow�set�up�the�command�variables�in�the�channel�block�for�the�master*‚measurement�channel.  4‰MOVE.BƒCNL_PTR(A0),D1‡Top�half�of�D1.W�=�0�already.'‰BSR†CNLBLKAD�Point�A0�to�top�of�chain.‰LEA†CNL_PTR(A0),A2 3‰TAS.B„(A2)+�Mark�top�of�chain�by�setting�sign�bit. LˆSET†CNL_PTR ‰MOVE.Wƒ(SP)+,(A2)+ LˆSET†COMPL_SLˆSET†CMD_CMPL ,‰MOVE.Lƒ(SP)+,A1�Delta-T�-->�A1.‚(For�RQPA).LˆSET†DELTAT_S ‰MOVE.Wƒ(SP)+,D1 LˆSET†R_CNT_S‰MOVE.WƒD1,(A2)+ LˆSET†RPT_CNT ‰MOVE.LƒA4,(A2)+LˆSET†IOCB_ADR 1‰ST.B…(A2)+’Set�the�flag�that�says�we�haven't�yet3LˆSET†NORQPA�requested�a�periodic�activation�of�the$*¦periodically-activated�measurement'*¦routine�for�this�command.‚We'll�later&*¦clear�the�NORQPA�flag�if�we�success-(*¦fully�request�a�periodic�activation�of(*¦the�periodically-activated�measurement*¦routine�for�this�command. 2‰MOVE.WƒSR,D0’Get�the�SR�value�into�D0.W,�and�save6‰MOVE.WƒD0,-(SP)�a�copy�of�it�on�the�stack�so�we'll�be&*¦able�to�restore�the�present�SR�value*¦later. =‰AND.W„#$FFFF-INT_MASK,D0…Clear�the�interrupt-level�bits�from8‰OR.W…CCBISR(A5),D0ˆthe�SR�value,�and�set�the�interrupt-2‰MOVE.WƒD0,SR�level�bits�to�the�interrupt�level�of'*¦the�A/D�converter�board.‚Then�put�the&*¦updated�SR�value�into�the�SR�to�mask&*¦interrupts�at�the�level�of�the�board&*¦without�changing�any�of�the�other�SR$*¦bits.‚We�take�extra�steps�to�avoid&*¦changing�any�of�the�SR�bits�that�are&*¦presently�undefined�because�those�SR$*¦bits�might�have�meanings�in�future!*¦processors�in�the�68000�family. #*¨We�must�mask�interrupts�before�we'*¦issue�the�RQPA�executive�request�(see%*¦below)�so�we�can�guarantee�that�the$*¦periodically-activated�measurement&*¦routine�won't�be�activated�before�we$*¦perform�the�first�exectuion�of�the&*¦measurement�routine�ourselves.‚Also,#*¦interrupts�must�be�masked�when�we)*¦execute�the�measurement�routine�because'*¦the�measurement�routine�has�no�way�to*¦mask�interrupts�at�the�board. ‰SUBQ.Wƒ#1,D1+‰BEQ.S„L28’Repeat�count�=�1.ƒThe�IMMED�flag *¦doesn't�matter�if�RPT_CNT�=�1. #‰MOVE.LƒA1,D0�Test�Delta-T�(in�A1).%‰SEQ.B„(A2)‘A2�remains�at�LOC(IM MED). LˆSET†IMMED‰BEQ.S„L28’Delta�T�=�0. 1‰MOVE.LƒA0,D2�D2�<--�LOC(CNLBLK�in�CCB)�for�RQPA.!‰LEA†MEAS_PA(PC),A0‡LOC(ROUTINE). ACTIVATE�EQU†0<<15REPEATƒEQU†1<<14‰MOVEQWƒACTIVATE+REPEAT,D1‰MOVE.BƒCCBPPRIO(A5),D1‰MOVE.Lƒ#T0RQPA,D0‰TRAP…#EXEC�Destroys�D0,�D1.‰BRA.S„L27’OK. )‰MOVE.LƒD2,A0�Not�OK.‚LOC(CNLBLK)�-->�A0.*‰BSR†STOP1�Stop�measurements�just�started. ‰MOVEQBƒSTATRQPA,D0‰BRA.S„L29’Go�to�CMDEXIT2. 5L27†CLR.B„-(A2)’We've�successfully�requested�periodic,LˆSET†NORQPA�activation�of�the�periodically-(*¦activated�measurement�routine�for�this'*¦command,�so�clear�the�NORQPA�flag.‚By&*¦clearing�the�NORQPA�flag�we�indicate%*¦that�there�is�a�periodic�activation)*¦active�for�this�command,�and�we'll�know'*¦to�stop�that�periodic�activation�when(*¦we�complete�(or�stop)�the�measurements*¦for�the�command. !‰MOVE.LƒD2,A0�LOC(CNLBLK�in�CCB). =L28†MOVEQ.L‚#T0QEVNTT,D6‹Get�the�code�that�we�use�for�queuing$*¦an�event�from�a�routine�that�isn't)*¦being�executed�as�an�interrupt�handler. 1‰BSR.S„MEAS_RTN�Call�the�measurement�routine.‚The&*¦measurement�routine�returns�a�status*¦value�in�D0.W. #L29†MOVE.Wƒ(SP)+,SR�Restore�the�SR. ‰BRA†CMDEXIT2,‰TTL†5.2.5.5.‚MEAS_RTN�(Measurement�Routine)-‰PAGEš#######################################D*ˆInterrupts�must�be�masked�throughout�this�routine.‚This�routine�is*ˆnot�re-entrant. *†#�A5�=�LOC(CCB).*ˆA3�=�LOC(BUFFER).*ˆA2�=�LOC(MSBDATA).*ˆA1�=�Scratch.#*†#�A0�=�LOC(Channel�block�in�CCB). *†#�D6.L�=�T0QEVNTI�or�T0QEVNTT.*ˆD5.W�=�Status�code.*ˆD4.L�=�Scratch�in�STOP1.*ˆD3.B�=�Scratch�in�STOP1. *ˆD2.B�=�CTRL_VAL(A0)�initially.1*ˆD2.L�=�Buffer�offset�later.‚(Top�half�is�zero.)3*ˆD1.W�=�Measurement�result;�later,�channel�number.**ˆD0.L�=�Scratch.‚D0.W�=�Status�on�return.  MEAS_RTN�MOVE.LƒCCBCHB(A5),A2 >MEAS_NXT�MOVEQ.L‚#0,D1�We'll�depend�on�byte�1�of�D1�being�zero5‰MOVE.BƒCTLOFFST(A0),D1†both�here�and�later�(at�L52).9‰MOVE.BƒCTRL_VAL(A0),D2†Get�CTRL_VAL�and�keep�it�in�D2.B.2‰MOVE.BƒD2,CONTROL(A2,D1.W)‚Start�the�measurement. L43†EQU†8+10‘Cycles�per�loop.�D1.W.‰MOVE.LƒBUF_ADDR(A0),A3‰MOVEQ.L‚#0,D2‰MOVE.WƒBUF_PNTR(A0),D27‰MOVE.WƒD1,0(A3,D2.L)ˆResult�-->�buffer.‚We�use�D2.L�to*¦avoid�sign�extension�of�D2.W. ‰MOVE.WƒCNL_CMPL(A0),D0‰BTST.Lƒ#SUBR_B,D0‰BEQ.S„L48’No�subroutine. ‰MOVE.LƒSUBRTN(A0),A1‰JSR†(A1)‘Call�the�subroutine. L48†ADDQ.Wƒ#2,D2‰CMP.W„BUF_SIZE(A0),D2 ‰BLO.S„L49‰MOVEQ.L‚#0,D21L49†MOVE.WƒD2,BUF_PNTR(A0)†Update�buffer�pointer. *‰BSR.S„WAKEUP�Issue�wakeup�if�appropriate. ‰MOVEQ.L‚#MEAS_TYP,D2 ‰BSR.S„QEVENT ‰MOVEQ.L‚#CP_MASK,D1‰AND.B„CNL_PTR(A0),D1-‰BSR†CNLBLKAD�Point�A0�to�next�channel�block. ‰TST.B„CNL_PTR(A0)!‰BPL†MEAS_NXT�Not�master�channel.  ‰MOVEQ.L‚#0,D5�Good�status. ‰TST.W„RPT_CNT(A0)‰BEQ.S„L50’0�=�infinity. ‰SUBQ.Wƒ#1,RPT_CNT(A0) ‰BEQ.S„L53 L50†TST.B„IMMED(A0)!‰BNE†MEAS_NXT�Repeat�immediately.-‰BRA.S„L55’Return�with�good�status.‚We'll�get&*¦activated�again�by�the�next�periodic *¦activation.  L51†BSR†CNLBLKAD@L52†MOVE.BƒCNL_PTR(A0),D1‡Byte�1�of�D1�=�0�already�from�earlier. ‰BPL.S„L51 L53†MOVE.WƒCMD_CMPL(A0),D0,‰BSR.S„WAKEUP�Issue�a�wakeup�if�appropriate. ‰MOVEQ.L‚#CMPL_TYP,D2 ‰MOVE.WƒD5,D1 ‰BSR.S„QEVENT ‰LSR.W„#EVENT_B+1,D0 ‰BCS.S „L54 ‰MOVE.LƒIOCB_ADR(A0),A1‰MOVE.WƒD5,-(A1) LˆSET†STATUS L54†BSR.S„STOP1 L55†MOVE.WƒD5,D0‰RTS‰TTL†5.2.5.6.‚Subroutine�WAKEUP-‰PAGEš#######################################*ˆSubroutine�WAKEUP ;*†#�A0�=�LOC(Channel�block�for�current�measurement�channel) *†#�D0.W�=�completion�code. +*ˆWe�preserve�all�registers�except�the�CCR.  WAKEUPƒEQU†*WU_REGS‚REG†A0/D0‰MOVEM.L‚WU_REGS,-(SP) ‰LSR.W„#WAKEUP_B+1,D0 ‰BCC.S„L56 ‰MOVEQ.L‚#T0WAKEUP,D0‰MOVE.LƒTCB_ADDR(A0),A0 ‰TRAP…#EXEC L56†MOVEM.L‚(SP)+,WU_REGS‰RTS‰TTL†5.2.5.7.‚Subroutine�QEVENT-‰PAGEš#######################################*ˆSubroutine�QEVENT *†#�A5�=�LOC(CCB).*†#�A0�=�LOC(Channel�Block). "*†#�D6.L�=�Executive�Request�Code.*†#�D2.L�=�Event�type.-*†#�D1.W�=�Status�code�or�measurement�result.*†#�D0.W�=�Completion�option.  QEVENTƒEQU†* !QREGS„REG†D0-D3/D5-D7/A0-A1/A3-A5‰MOVEM.L‚QREGS,-(SP) ‰MOVE.WƒD0,D3�Completion�option.‰LSR.W„#EVENT_B+1,D0‰BCC.S„L59’No�event�requested. ‰SWAP…D30‰MOVE.WƒD1,D3�Status�code�or�measurement�result. ‰ROL.W„#8,D2 L57†EQU†ELENGTH<<24L58†EQU†ECODE<<16 ‰OR.L…#L57+L58+EDRVCD,D2 ‰MOVE.LƒD6,D0‰MOVE.LƒTCB_ADDR(A0),A0 ‰TRAP…#EXEC#‰NOP›Good.‚BRA.S�L59�in�the�future.)*ˆ—Bad.‚For�now,�just�ignore�that. L59†MOVEM.L‚(SP)+,QREGS‰RTS‰TTL†5.2.6.‚Common�Subroutines‰TTL†5.2.6.1.‚Subroutine�STOP-‰PAGEš#######################################6*ˆStop�the�measurements�specified�by�the�STOP�command.-*ˆControl�enters�at�STOP2�for�a�STOP�command.0*ˆControl�enters�at�STOP1�for�a�MEASURE�command.@*ˆInterrupts�are�masked�at�the�level�of�the�A/D�converter�board. *†#�A5�=�LOC(CCB).*ˆA3�=-*†#�A2�=�LOC(MSBDATA).‚We�set�this�for�STOP1.*†#�A1�=�LOC(last�CNFIELD)�+�2./*ˆA0�=�LOC(Channel�block�for�selected�channel). *ˆD7.L�=*ˆD6.L�=*ˆD5.L�=C*†#�D4.L�=�Number�of�words�after�CMD_CODE�in�IOCB.‚Set�0�for�STOP1.H*†#�D3.B�=�+0�initially�to�indicate�that�no�active�MEASURE�commands�have*’been�stopped.:*�Nonzero�later�if�we�actually�stop�an�active�measurement.;*�Initially�random�for�STOP1.‚We�know�we'll�stop�something.*ˆD2.L�=�Scratch.*ˆD1.L�=�Scratch.*ˆD0.L�=�Scratch.  6STOP1„MOVE.LƒSP,A1�To�prevent�bus�error�on�access�with*¦-(A1). ‰MOVE.LƒCCBCHB(A5),A2*‰MOVEQ.L‚#0,D4�Clear�count�for�no�repeats. 0L30†CLR.W„ACTIVE(A0)‹Mark�this�channel�inactive. )‰MOVEQ.L‚#0,D1�To�clear�top�half�of�D1.W.<‰MOVE.BƒCNL_PTR(A0),D1‡Get�channel�number�of�next�channel�in0‰BPL.S„L32’this�group.‚Branch�unless�the�current&*¦channel�is�the�master�channel�of�the*¦group. 1‰MOVE.BƒD1,D3�Save�pointer�to�next�channel�in�D3.%*¦Notice�that�D3.B�<>�0�now�since�the*¦sign�bit�is�set. 6‰TST.B„NORQPA(A0)�Skip�if�the�measurement�sequence�for+‰BNE.S„L31’this�command�wasn't�periodically *¦activated. 3‰MOVEQ.L‚#-1,D1�Bit�15�says�deactivate�routine;�all*¦other�bits�ignored./‰MOVE.LƒA0,D2�Pointer�to�current�channel�block.9‰MOVEQ.L‚#T0RQPA,D0‹Code�for�Request�Periodic�Activation.,‰TRAP…#EXEC�Request�deactivation�of�routine.(‰NOP›Good�return.‚No�such�thing�as�a�bad#*¦return,�so�we�merge�good�and�bad.*¦Destroys�D0�and�D1.-‰PAGEš#######################################*†#�D6.L�=�+0�if�selected�channel�is�not�allowed�to�be�active.*�-1�otherwise.*ˆD5.L�=*ˆD4.L�=*ˆD3.L�=*ˆD2.L�="*ˆD1.W�=�Channel�Number�on�return.*ˆD0.L�=�Scratch.  >VALIDATE�BSR.S„VALID_CN�Validate�next�channel�number�and�point'*¦A0�to�its�channel�block.‚Also�advance*¦A1�to�point�to�next�word. ‰MOVEQBƒSTATNOPN,D08‰CMP.L„TCB_ADDR(A0),A6†Is�the�channel�open�to�this�task?#‰BNE.S„CMDEX2BŽNo.‚Report�an�error. )‰TST.L„D6“Skip�the�active�test�for�a�STOP‰BNE.S„L38’command. ‰MOVEQBƒSTATACTV,D04‰TST.W„ACTIVE(A0)‹Is�the�channel�active�(measuring)?4‰BNE.S„CMDEX2BŽYes.‚Report�an�error.‚Can't�close�it. L38†RTS!‰TTL†5.2.6.3.‚Subroutine�VALID_CN-‰PAGEš#######################################*ˆSubroutine�VALID_CN *†#�A5�=�LOC(CCB).%*†#�A4�=�LOC(CMD_CODE�field�in�IOCB).*†#�A3�=�LOC(DUPETBL).9*†#�A1�=�LOC(Channel-number�word).‚Incremented�on�return.-*ˆA0�=�LOC(Selected�Channel�Block)�on�return. 9*ˆD1.W�=�Channel�Number�on�return.‚On�entry�for�CNLBLKAD.*ˆD0.L�=�Scratch.  >VALID_CN�MOVE.Wƒ(A1)+,D1�Get�next�channel�number�into�D1.W�andLˆSET†CNFIELDŽadvance�A1. LˆSET†CHN_NUM ‰MOVEQBƒSTAT0_95,D0‰CMP.W„#MAXCNLS-1,D1*‰BHI.S„CMDEX2BŽError:‚Channel�Number�>�95. ‰MOVEQBƒSTATDUPE,D0‰TAS.B„0(A3,D1.W) LˆSET†DUPETBL6CMDEX2B‚BNE.S„CMDEX2CŽError:‚Duplicate�channel�number. ‰TST.B„DIFF_F(A5)"‰BEQ.S„CNLBLKAD�Single-ended�mode. ‰MOVEQBƒSTATDIFF,D0‰BTST.Lƒ#MUX_BIT,D13‰BNE.S„CMDEX2CŽInvalid�differential�channel�number. CNLBLKAD�LEA†CNLBLK(A5),A0‰MOVEQWƒCNLBLKSZ,D0 ‰MULU…D1,D00‰ADD.L„D0,A0�Point�A0�to�selected�channel�block. ‰RTSH‚TTL„5.2.6.4.‚Subroutine�LOGPHY�(Logical-to-Physical�Address�Conversion)-‰PAGEš#######################################*ˆSubroutine�LOGPHY %*†#�A6�=�LOC(TCB�of�requesting�task). B*†#�D6.L�=�LOC(Buffer)�to�be�converted.‚Logical�address�coming�in;*­physical�address�going�out.%*†#�D5.L�=�Number�of�bytes�in�buffer. LOGPHYƒEQU†*LOG_REGS�REG†D0-D5/D7/A0‰MOVEM.L‚LOG_REGS,-(SP) ‰MOVE.WƒD6,CCR"‰BCS.S„L39’Starts�at�odd�location. ‰MOVE.WƒD5,CCR(‰BCS.S„L39’Contains�odd�number�of�bytes. ‰TST.L„D5‰BEQ.S„L39’Length�=�0. ‰MOVE.LƒTCBTST(A6),A0‰MOVE.Lƒ#T0LOGPHY,D0 ‰TRAP…#EXEC.‰BRA.S„L40’Valid�physical�address�now�in�D6.L.‰NOP7L39†MOVEQBƒISTAADD,D0‹Bad�buffer�address�and/or�length. 8CMDEX2C‚BRA†CMDEXIT2�Notic e�that�A4�and�A5�have�not�been"*¦changed.‚The�values�of�these�two)*¦registers�are�important�in�the�command-(*¦exit�routine,�and�we�must�never�branch)*¦to�the�command-exit�routine�while�A4�or*¦A5�is�modified. '*¨Some�code�uses�the�branch�instruction(*¦here�as�a�stepping�stone�to�get�to�the*¦command-exit�routine. L40†MOVEM.L‚(SP)+,LOG_REGS‰RTS2‰TTL†6.‚Periodically-Activated�Measurement�Routine-‰PAGEš#######################################-*ˆPeriodically-activated�measurement�routine. $*†#�D0.L�=�Number�of�time�intervals.*†#�D1.L�=�LOC(Channel�block).*ˆD2.L�=�Used�by�MEAS_RTN.*ˆD3.L�=�Used�by�MEAS_RTN.*ˆD4.L�=�Used�by�MEAS_RTN.*ˆD5.L�=�Used�by�MEAS_RTN.*ˆD6.L�=�T0QEVNTI. "*ˆA0�=�saved�and�restored�by�exec."*ˆA1�=�saved�and�restored�by�exec.*ˆA2�=�Used�by�MEAS_RTN.*ˆA3�=�Used�by�MEAS_RTN.*ˆA5�=�LOC(CCB). 8*†#�SR�=�Masked�at�the�level�of�the�A/D�converter�board.  MEAS_PA‚EQU†*PA_REGS‚REG†D2-D6/A2-A3/A5‰MOVEM.L‚PA_REGS,-(SP)/‰MOVE.LƒD1,A0�A0�<--�LOC(Master�channel�block). /‰MOVEQ.L‚#0,D0�A0�-�CNLBLK-CNL_NUM(A0)*CNLBLKSZ‰MOVE.BƒCNL_NUM(A0),D0‰MULU.Wƒ#CNLBLKSZ,D0‰LEA†-CNLBLK(A0),A5‰SUB.L„D0,A5�A5�<--�LOC(CCB). ‰TST.B„ET_WAIT(A5))‰BNE.S„L60’Waiting�on�ET.‚Skip�this�time. ‰MOVEQ.L‚#T0QEVNTI,D6 ‰BSR†MEAS_RTN L60†MOVEM.L‚(SP)+,PA_REGS‰RTE‰TTL†7.‚Interrupt�Handler-‰PAGEš#######################################*ˆInterrupt�handler !*ˆD0�=�Saved�and�restored�by�CMR.*ˆD1�=�Used�by�MEAS_RD.*ˆD2�=�Used�by�MEAS_RD.*ˆD3�=�Used�by�MEAS_RD.*ˆD4�=�Used�by�MEAS_RD.*ˆD5�=�Used�by�MEAS_RD. !*ˆA0�=�Saved�and�restored�by�CMR.!*ˆA1�=�Saved�and�restored�by�CMR.*ˆA2�=�Used�by�MEAS_RD.*ˆA3�=�Used�by�MEAS_RD.*†#�A5�=�LOC(CCB). B*†#�SR�=�Masked�at�the�interrupt�level�of�the�A/D�converter�board.  INTERUPT�MOVE.LƒCCBCHB(A5),A1‰TST.B„MSBDATA(A1)ŠClears�SR.C. LˆSET†INTFF_B%‰BPL.S„L63’Not�our�interrupt.‚Return. ‰TST.B„ET_WAIT(A5))‰BNE.S„L61’Waiting�on�ET.‚Good�interrupt. ‰ST.B…BAD_INT(A5)'‰TST.B„LSBDATA(A1)ŠClear�bad�interrupt. ‰BRA.S„L62 L61†EQU†*INT_REGS�REG†D1-D6/A2-A3‰MOVEM.L‚INT_REGS,-(SP)‰CLR.B„ET_WAIT(A5) 5‰MOVE.LƒCBPTR(A5),A0‰Pointer�to�active�channel�block.&‰MOVE.LƒA1,A2�Pointer�to�LOC(MSBDATA).‰MOVEQ.L‚#T0QEVNTI,D6 ‰BSR†MEAS_RD ‰MOVEM.L‚(SP)+,INT_REGS L62†EQU†*CARRY„EQU†1<<0‰OR.B…#CARRY,CCRL63†RTS NNNœ ?‰TTL†MVME-600�and�MVME-601�Analog-to-Digital�I/O�Driver�ProgramN  NNNNNN?'-/(7*?(G#O.W3_3g6o:w::‡9� —$Ÿ$§7¯6·)¿3Ç8Ï6×;ß5ç<ï:÷9ÿ6  /*ƒVV‡VVƒMM‡MMƒEEEEEEEEE„6666666…0000000…00000007*ƒVV‡VVƒMMM…MMMƒEEEEEEEEEƒ666666666ƒ000000000ƒ000000000(*„VV…VV„MMMMƒMMMMƒEEŠ66…66ƒ00„/00ƒ00„/00)*„VV…VV„MM�MM�MM�MMƒEEŠ66Š00ƒ//00ƒ00ƒ//005*…VVƒVV…MM‚MMM‚MMƒEEEEEEEE„66666666„00‚//�00ƒ00‚//�004*…VVƒVV…MMƒMƒMMƒEEEEEEEE„666666666ƒ00�//‚00ƒ00�//‚00&*†VV�VV†MM‡MMƒEEŠ66…66ƒ00//ƒ00ƒ00//ƒ00$*†VV�VV†MM‡MMƒEEŠ66…66ƒ00/„00ƒ00/„003*‡VVV‡MM‡MMƒEEEEEEEEEƒ666666666ƒ000000000ƒ000000000+*ˆVˆMM‡MMƒEEEEEEEEE„6666666…0000000…0000000   *—AAAAAŽ//ƒDDDDDDDDD*–AAAAAAAŒ//„DDDDDDDDDD*•AA…AAŠ//†DD…DD*•AA…AA‰//‡DD…DD*•AAAAAAAAAˆ//ˆDD…DD*•AAAAAAAAA‡//‰DD…DD*•AA…AA†//ŠDD…DD*•AA…AA…//‹DD…DD*•AA…AA„//‹DDDDDDDDDD*•AA…AAƒ//ŒDDDDDDDDD   4*…DDDDDDDDD„RRRRRRRR„IIIIIIƒVV‡VVƒEEEEEEEEEƒRRRRRRRR7*…DDDDDDDDDDƒRRRRRRRRRƒIIIIIIƒVV‡VVƒEEEEEEEEEƒRRRRRRRRR*†DD…DDƒRR…RR…II†VV…VV„EEŠRR…RR*†DD…DDƒRR…RR…II†VV…VV„EEŠRR…RR-*†DD…DDƒRRRRRRRRR…II‡VVƒVV…EEEEEEEE„RRRRRRRRR+*†DD…DDƒRRRRRRRR†II‡VVƒVV…EEEEEEEE„RRRRRRRR*†DD…DDƒRR‚RRˆIIˆVV�VV†EEŠRR‚RR*†DD…DDƒRRƒRR‡IIˆVV�VV†EEŠRRƒRR-*…DDDDDDDDDDƒRR„RR„IIIIII‡VVV‡EEEEEEEEEƒRR„RR**…DDDDDDDDD„RR…RRƒIIIIIIˆVˆEEEEEEEEEƒRR…RR        E*ˆThis�program�is�re-entrant�and�position�independent,‚and�it�can�runF*ƒin�a�ROM�that‚appears‚at‚any�convenient‚location‚in�the�68000�memoryB*ƒspace.„A�single‚copy�of�the‚A/D‚driver�can‚control�any‚number‚of@*ƒMVME-600�and�MVME-601�A/D�measurement�channels�simultaneously.‰TTL‡Table�of�Contents‰PAGE*ŸTable�of�Contents*I*‚1.‚Introduction�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.„4*I*‚2.‚Options,�Macros,�Equates,�and�Data�Structures‚.�.�.�.�.�.�.�.�.�.ƒ10*E*†2.1.‚Miscellaneous�Options�and�Equates‚.�.�.�.�.�.�.�.�.�.�.�.�.ƒ11E*†2.2.‚Macro�Definitions‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ15E*†2.3.‚CMR�Parameter�Block‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ22F*†2.4.‚IOCB�(I/O�Command�Block)�Structure�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ27*?*Œ2.4.1.‚IOCB�OFFSET�Block‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ28?*Œ2.4.2.‚CMD_CODE�(Command-Code)�Equates‚.�.�.�.�.�.�.�.�.�.ƒ38@*Œ2.4.3.‚STATUS�Equates�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ39*E*†2.5.‚CCB�(Channel�Control�Block)�Structure‚.�.�.�.  �.�.�.�.�.�.�.ƒ46*@*Œ2.5.1.‚Universally-Defined�CCB�Fields�.�.�.�.�.�.�.�.�.�.�.ƒ47?*Œ2.5.2.‚CCB�Fields�for�the�A/D�Driver‚.�.�.�.�.�.�.�.�.�.�.ƒ53*0*”2.5.2.1.‚A/D�CCB�Fields�Relating�to�a�Complete/*žMVME-600�A/D�Converter�Board�.�.�.�.�.�.�.ƒ543*”2.5.2.2.‚CCB�Channel�Block�for�an�A/D�Measurement.*žChannel‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ60*F*†2.6.‚TCB�(Task�Control�Block)�Structure�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ74E*†2.7.‚I/O�Event�Structure‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ75E*†2.8.‚MVME-600�and�MVME-601�Memory�Layout‚.�.�.�.�.�.�.�.�.�.�.�.ƒ79*?*Œ2.8.1.‚Memory-Mapped�I/O�Space‚.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ79@*Œ2.8.2.‚Control�Register�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ82?*Œ2.8.3.‚Output�Data�Registers‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ85@*Œ2.8.4.‚Channel-Number�Equates�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ87*J*‚3.‚Required�Driver�Tables�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ90*F*†3.1.‚A/D�Service�Vector�Table�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ91F*†3.2.‚Parameter�Table�for�CMR�Parameters�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ93F*†3.3.‚Revision�Table�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.ƒ94*I*‚4.‚Initialization�Section�(Subroutine�INITIAL)‚.�.�.�.�.�.�.�.�.�.�.ƒ95* *Â(Continued)*‰PAGE*™Table�of�Contents,�Continued*J*‚5.‚Command�Service�Section‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚101*F*†5.1.‚Command�Switching�Table‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚102F*†5.2.‚Subroutine�COMMANDS�(Command�Processor)‚.�.�.�.�.�.�.�.�.�.‚104*@*Œ5.2.1.‚OPEN_CMD�Routine�(OPEN�Command)‚.�.�.�.�.�.�.�.�.�.‚111@*Œ5.2.2.‚Common�Exit�Routine‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚xxx@*Œ5.2.3.‚STOP_CMD�Routine�(STOP�Command)‚.�.�.�.�.�.�.�.�.�.‚xxxA*Œ5.2.4.‚CLOSECMD�Routine�(CLOSE�Command)�.�.�.�.�.�.�.�.�.�.‚xxx@*Œ5.2.5.‚MEAS_D�and�MEAS_S�Routines�(MEASURE�Commands)‚.�.�.‚xxx*9*”5.2.5.1.‚Initial�Decoding�of�Header�Section�.�.�.�.‚xxx8*”5.2.5.2.‚First�Pass�through�the�Channel�Blocks‚.�.‚xxx9*”5.2.5.3.‚Second�Pass�through�the�Channel�Blocks�.�.‚xxx9*”5.2.5.4.‚Final�Command�Set-Up�.�.�.�.�.�.�.�.�.�.�.‚xxx9*”5.2.5.5.‚MEAS_RTN�(Measurement�Routine)�.�.�.�.�.�.‚xxx8*”5.2.5.6.‚Subroutine�WAKEUP‚.�.�.�.�.�.�.�.�.�.�.�.‚xxx8*”5.2.5.7.‚Subroutine�QEVENT‚.�.�.�.�.�.�.�.�.�.�.�.‚xxx*A*Œ5.2.6.‚Common�Subroutines�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚xxx*8*”5.2.6.1.‚Subroutine�STOP‚.�.�.�.�.�.�.�.�.�.�.�.�.‚xxx8*”5.2.6.2.‚Subroutine�VALIDATE‚.�.�.�.�.�.�.�.�.�.�.‚xxx8*”5.2.6.3.‚Subroutine�VALID_CN‚.�.�.�.�.�.�.�.�.�.�.‚xxx1*”5.2.6.4.‚Subroutine�LOGPHY�(Logical-to-Physical/*žAddress�Conversion)‚.�.�.�.�.�.�.�.�.�.�.‚xxx*K*‚6.‚Periodically-Activated�Measurement�Routine�.�.�.�.�.�.�.�.�.�.�.�.‚xxx*J*‚7.‚Interrupt�Handler‚.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚xxx*K*‚8.‚Symbol-Table�Concordance�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.�.‚xxx‰TTL‡1.‚Introduction‰PAGE*Ÿ1.‚Introduction*H*‡This�program,�which�is�commonly�known�as�the�A/D�driver,�is�the�RMS68KG*‚I/O‚driver‚for‚the‚MVME-600‚analog-to-digital‚converter�board�and�theK*‚MVME-601�analog-to-digital�expander�board.‚RMS68K�is�the�popular�name‚forI*‚the‚Real-Time‚Multitasking‚Software‚that�forms�the�kernel�of�Motorola'sL*‚real-time�operating�system�for�processors�in�the�68000�family,�and�the‚A/DI*‚driver‚runs‚in‚supervisor‚mode�as�an�extension�of�the�RMS68K�executive.F*‚The�A/D�driver‚provides‚the‚device-dependent‚portion‚of‚the‚softwareG*‚interface‚for‚any‚desired‚number‚of‚MVME-600�A/D�converter�boards�and*‚MVME-601�A/D�expander�boards.*G*‡The�A/D�driver�is�written�as�a�re-entrant�program,�and�the�program‚isL*‚also�written�to�be�position�independent.‚Therefore,�the�object�program�forJ*‚the�A/D�driver�can�be�executed�from�a�ROM�that�appears‚at‚any‚convenientF*‚location‚in‚the‚68000‚address‚space,‚and‚the�program�can�be�executedM*‚re-entrantly�so�that�a�single�copy�of�the�A/D�driver�can�control�any�numberC*‚of�MVME-600�and�MVME-601�A/D�measurement�channels�simultaneously.*E*‡Besides‚reading�any‚furthe  r,‚the�reader�should�carefully�review�the)*‚hardware�user's�manual�for‚the‚MVME-600F*‚A/D‚converter‚board‚and‚the‚MVME-601‚A/D�expander�board.‚That�manualG*‚describes�both�boards�in‚detail,‚and‚it‚provides‚complete‚informationJ*‚regarding‚the‚jumpers‚and�other�hardware�options�that�are�available�withF*‚the�boards.‚The�hardware�manual�for‚the‚MVME-600‚and‚the‚MVME-601‚is*‚available�as�follows:*‰PAGEG*‚MVME600�Analog�Input�Module�MVME601�A/D�Expander�Module�User's�Manual(*‚Manual�Number:‚MICROSYSTEMS�MVME600/D1*'*‚Motorola�Semiconductor�Products,�Inc.*‚Literature�Distribution*‚P.�O.�Box�20912*‚Phoenix,�Arizona‚85036*‚(602)�994-6561**‰PAGEG*‡The�driver�is�largely�table�driven,�and�many�future�modifications‚canF*‚be‚made‚by‚simply‚changing‚table‚entries‚or�by�adding�new�entries�to*‚existing�tables.*B*‡The�subroutines�in�the‚A/D‚driver‚are‚general-purpose‚in‚nature.J*‚Instead‚of‚being‚used�to�the�limits�of�their�capabilities�in�the�presentG*‚version�of�the�driver,�they‚are‚flexible‚enough‚to‚perform‚additionalL*‚functions�that�may�be�needed�in�the�future.‚Some�subroutines�may�be�calledI*‚from�only�one�place,�but�they�are�still�coded‚as‚subroutines‚to‚provideL*‚modularity‚of�organization�and�to�make�their�functions�easily�available�to!*‚future�maintenance�programmers.*A*‡Instead�of�using‚a‚complicated‚and‚error-prone‚method‚of‚makingJ*‚measurements‚under‚interrupt‚control,�the�A/D�driver�uses�a�simple�senseD*‚loop�to�make‚normal‚measurements.ƒA‚measurement‚that‚is‚made‚underJ*‚sense-loop‚control‚requires‚only�38�microseconds�of�sense-loop�overhead,H*‚and�the�overhead�that�is�required�to‚service‚a‚single‚interrupt‚easilyH*‚exceeds‚38‚microseconds.ƒTherefore,‚the�driver�actually�saves�time�andF*‚improves�throughput�by�using�a‚simple‚sense‚loop‚instead‚of‚using‚anJ*‚interrupt-driven‚scheme‚for�making�measurements.‚The�A/D�driver�does,�ofI*‚course,�use�an�interrupt-driven�scheme�when�the�driver‚wants‚to‚make‚an#*‚externally-triggered�measurement.*E*‡To‚promote‚readability‚and�maintainability,�the�following�standards3*‚are�carefully�observed�throughout�the�A/D�driver.*=*ŒAll�instructions�in�the�A/D�driver�are�typed�in�upper‚case,>*‡and‚comments‚are‚always‚typed‚in�a�mixture�of�upper�case�and%*‡lower�case�to�maximize�readability.*<*ŒTab�stops�in�the�A/D�driver�are�in�columns�10,�19,‚40,‚and=*‡42,‚and‚the‚right-hand‚margin‚is�in�column�78.‚The�same�tab;*‡stops‚and‚the‚same‚right-hand‚margin‚are‚used‚religiously<*‡throughout‚the‚driver‚to‚ensure‚consistent‚formatting.‚The?*‡opcode�field�starts�at�the�tab�stop�in‚column‚10,‚the‚operand*‰PAGEB*‡field‚starts�at�the�tab�stop�in�column�19,�and�the�comment�field=*‡starts�at�the�tab�stop�in�column�40.‚We‚use‚the‚tab‚stop‚in:*‡column‚42‚to‚provide‚indentation‚for‚the‚first‚line‚of�aA*‡paragraph�of�code�comments.‚Please�refer�to�any�section�of‚codeA*‡anywhere‚in‚the�entire�program�listing�to�see�how�code�comments*‡are�formatted.*<*ŒInstructions�throughout�the�A/D�driver�are‚carefully‚coded:*‡to‚prevent‚the‚operand‚field‚of‚an‚instruction‚from‚ever>*‡extending�into�the�comment�field,‚which‚begins‚in‚column‚40.A*‡Where‚necessary,‚we�define�labels�of�a�local�nature�to�allow�usA*‡to�shorten�a�long�operand�field�and�thereby�prevent‚the‚operandA*‡field‚from�extending�into�the�comment�field.‚By�maintaining�the?*‡strict�columnization�of‚non-overlapping‚fields‚throughout‚theA*‡entire‚program,‚we�significantly�improve�the�readability�of�the *‡listing.*;*ŒThe�current�version�of�Motorola's‚68000‚assembler‚doesn'tC*‡support�local�labels,�so�we�use�labels�of�the�form�Lj,�Ljj,�Ljjj,;*‡or�Ljjjj�where‚local‚labels‚would‚ordinarily‚be‚used.ƒFor=*‡example,‚a‚label‚such‚as‚L1,‚L12,�L123,�or�L1234�in�the�A/D=*‡driver�is�always�a�local�label�with�no�global�significance.*6*ŒWe�use�the�label�"L"‚in‚a‚rather‚special‚way.ƒWhen‚aC*‡segment�of�code�uses�an�addressing�mode�such�as�register-indirect>*‡addressing�to�access�a‚variable‚without‚explicitly‚using‚t  heB*‡variable's‚label,�we�place�a�SET�assembler�directive�immediately:*‡after�the‚code‚segment‚to‚set‚L‚temporarily‚equal‚to‚the?*‡variable's‚label.ƒWe‚don't�really�care�about�the�value�of�the?*‡label�L,�but�we�do�care�about�the�fact‚that‚the‚SET‚assemblerC*‡directive�generates�a�concordance�entry�for�the�variable's�label.A*‡Future�maintenance�programmers�will�conveniently�be�able‚to‚useC*‡the�concordance�listing�to�find�references�to�variables�even�when6*‡the�variable�names�aren't�used�directly�in�the�code.*E*‡Some�of�the�labels�that�are�used�in�the�various‚I/O‚data‚structuresK*‚are‚non-mnemonic,‚and�a�few�of�the�labels�in�the�data�structures�are�evenL*‚anti-mnemonic.‚These�labels�have�been�created�by�a�number�of�people�as�theH*‚operating‚system‚has‚grown‚over‚the�years,�and�these�labels�are�now�soG*‚firmly�entrenched�that�they�can't‚reasonably‚be‚changed.ƒAlthough‚theK*‚labels‚in‚the�I/O�data�structures�can't�easily�be�changed,�the�A/D�driverL*‚does�at�least�provide�comments�to�explain�the�true�meanings�of�the‚variousG*‚fields�of�the�I/O�data�structures�as�they�are�used�by�the�A/D�driver.*5‰TTL‡2.‚Options,�Macros,�Equates,�and�Data�Structures‰PAGE2*�2.‚Options,�Macros,�Equates,�and�Data�Structures*B*‡Before‚we‚get‚into‚the‚actual‚code�of�the�A/D�driver,�we�need�toI*‚define�a�few�miscellaneous�macros�and�some�equates�that‚are‚used‚by‚the *‚driver.*F*‡We‚also‚need�to�define�the�data�structures�with�which�the�A/D�driverL*‚works.‚These�data�structures�include�the�IOCB�(I/O�Control�Block),�the�CMRI*‚parameter‚block,‚the‚CCB‚(Channel�Control�Block),�the�TCB�(Task�ControlI*‚Block),�the�I/O�measurement�event�message,�and‚the‚I/O‚completion‚eventJ*‚message.ƒThe‚A/D�driver�shares�these�data�structures�with�other�parts�ofI*‚the�system�software,�and�the�A/D�driver�doesn't�use‚every‚part‚of‚everyJ*‚data‚structure.ƒThe�documentation�in�this�section�explains�primarily�theF*‚parts�of�the�data�structures�that�are�significant�to�the�A/D�driver.*E*‡Besides�using�the�data�structures�that�are�mentioned‚above,‚the‚A/DH*‚driver‚also‚deals‚with‚the‚memory-mapped�I/O�area�for�the�MVME-600�A/DH*‚converter�board�and�its�subordinate�MVME-601‚A/D‚expander‚boards.ƒThisH*‚section‚of‚the‚listing‚includes‚a�definition�of�that�memory-mapped�I/O*‚area.+‰TTL‡2.1.‚Miscellaneous�Options�and�Equates*‰PAGE(*”2.1.‚Miscellaneous�Options�and�Equates*D*‡This‚section‚contains‚some‚options�that�tell�the�assembler�what�weM*‚want�it�to�do,�and�this�section�also�contains�some�miscellaneous�equates�toK*‚define‚labels�that�are�useful�for�the�code�in�the�A/D�driver.‚The�equatesL*‚in�this�section�are�presented�in�alphabetical�order�for�ease�of‚reference.E*‚The‚options‚must‚occur‚before‚any‚code-affecting‚or‚code-generatingL*‚statements�because�the�options�tell�the�assembler�how�to�assemble�the‚rest*‚of�the�program.  1‰NOFORMAT–####################################### ‰OPT†CRE,PCS /CODE…EQU†8–This�label�defines�the�number�of‚the(*¦program‚section�that�contains�code�and&*¦constants.‚Section�8�is‚a‚relatively"*¦arbitraryƒsection,ƒbut‚it‚is‚the&*¦section�where�the‚system‚expects‚(by%*¦default)�to�see�code�for�a�program. ?DELAY„EQU†38�microsecondsˆThis�label�defines�the�amount�of�time$*¦(in‚terms‚of‚microseconds)‚that‚is(*¦required‚for�an�MVME-600�A/D�converter)*¦board�to�complete�a�single�A/D�measure-&*¦ment.ƒThe‚A/D�driver�uses�this�label(*¦when�the�driver�delays�to�wait�for‚the"*¦boardƒto‚make‚a‚measurement.ƒThe'*¦driver�times�each�A/D‚measurement‚and'*¦aborts‚with‚an�error�if�the�A/D�board)*¦doesn't�complete�a�measurement�within�a*¦reasonable�amount�of�time.-‰PAGEš#######################################)EXEC…EQU†0–This‚label‚is‚used‚with‚aƒTRAP%*¦instruction‚to‚generate‚a‚trap�that *¦requests�an�executive�service. 8INT_MASK�EQU†$0700’This�label�defines�a�bit�mask�for�the#*¦interrupt-levelƒbitsƒin‚the‚68000&*¦status�register.‚The�A/D‚driver‚us  es'*¦this‚label‚when�the�driver�deals�with*¦the�interrupt-level�bits. :MAXCNLS‚EQU†(1+5)*16�This�label�defines�the�maximum�number(*¦of‚measurement�channels�that�can�exist%*¦in�a�single�CMR�A/D‚channel.ƒAn‚A/D'*¦channel‚must‚contain�one�MVME-600�A/D(*¦converter�board,�and�it�can‚optionally%*¦contain‚as‚many‚as‚five�subordinate(*¦MVME-601�A/D�expander�boards.‚The�main)*¦A/D�converter�board�contains�16�single-&*¦ended�measurement‚channels,‚and‚each$*¦expanderƒboard‚contributes‚16‚more$*¦single-ended�measurement�channels. ;‰IFNE…MAXCNLS/4*4-MAXCNLS„The�A/D‚driver‚contains‚code‚that-‰FAILš[****�ERROR�****�ERROR�****�ERROR�****]-‰ENDCšworks�under�the�assumption�that�MAXCNLS&*¦is‚evenly‚divisible�by�4.‚If�someone$*¦ever‚changes‚something‚thatƒcauses'*¦MAXCNLS‚not‚to�be�evenly�divisible�by(*¦4,�the�statement�that�is‚conditionally(*¦skipped‚here�will�generate�an�assembly&*¦error�to�alert�the‚programmer‚to‚the$*¦failure.ƒBy‚using‚the‚assembler�to'*¦perform�this�check,�we�can�be‚sure‚of$*¦finding‚the‚error‚at‚assembly‚time)*¦instead�of�finding�it�later�as�a�result#*¦of�a�difficult�debugging�session.-‰PAGEš#######################################0MHZ†EQU†100”This�label�defines�the�maximum‚clock&*¦rate‚(in‚terms‚of�megahertz)�that�is(*¦expected�for�a�68000�microprocessor‚in&*¦the‚near‚future.‚The�A/D�driver�uses)*¦this�label�when�it�times�a�measurement,&*¦and‚we‚want‚MHZ�to�be�high�enough�to(*¦insure�an�adequate�time�delay�with‚the'*¦fastest‚foreseeable�68000.‚If�we�ever&*¦start�getting�68000‚systems‚that‚can(*¦run‚with�clock�speeds�in�excess�of�100(*¦megahertz,�we�must�adjust�the�value‚of'*¦this‚label�upward.‚On�the�other�hand,)*¦a�value�for�MHZ�that�is�larger�than�the"*¦actualƒspeedƒof‚the‚system‚clock(*¦doesn't�present�any�problems.‚A�larger%*¦MHZ‚value‚simply‚means‚that�the�A/D(*¦driver�delays�longer�in�a�STOP‚command'*¦and‚before‚it�aborts�a�measurement�in)*¦the�case�of�an�A/D�converter�board�that%*¦has‚gone‚bad.ƒSince�the�extra�delay&*¦occurs�only�in‚conjunction‚with‚STOP)*¦commands�and�with�board�failures,�it�is)*¦not�likely�to�be�a�noticeable�factor�in*¦actual�practice. /SAFETYƒEQU†2–This‚label‚defines‚a�safety�factor(*¦that�the�A/D�driver�uses�when�it‚times&*¦out‚a‚measurement.‚By�delaying�twice%*¦as�long�as‚should‚be‚necessary,‚the(*¦A/D‚driver�provides�an�extra�margin�of'*¦safety�that�will�forestall‚the‚advent'*¦of‚timing‚errors�until�timing�changes(*¦exceed�the�limit�of�the�safety�factor.-‰PAGEš#######################################4T0LOGPHY�EQU†8–These�labels�define�executive-request7T0QEVNTI�EQU†24“codes�that�are�used�when�the�A/D�driver7T0QEVNTT�EQU†23“makes�executive�requests�via�TRAP�#EXEC3T0RQPAƒEQU†34“calls�to�the�executive.‚The‚executive6T0WAKEUP�EQU†22“requests‚and�their�functions�are�fully#*¦documented‚in‚theƒstandardƒRMS68K%*¦documentation‚package.ƒBriefly,‚the)*¦functions�of�these�particular�executive*¦requests�are�as�follows: $*¨T0LOGPHY‚converts‚a‚logical�memory)*¦address�into�a�physical�memory�address.)*¦Address�conversion�is�necessary�because(*¦tasks�use�logical�memory-mapped‚memory(*¦addresses‚whereas�the�A/D�driver,�like(*¦the�rest�of�the�operating�system,‚uses#*¦actual�physical�memory�addresses. '*¨T0QEVNTI�queues�an�event�message�from(*¦an�interrupt�handler�to�a�task.‚Please$*¦noteƒthatƒa‚periodically-activated#*¦routine‚such‚asƒtheƒperiodically-&*¦activated‚A/D‚measurement‚routine�is(*¦considered�to�be�an�interrupt�handler. '*¨T0QEVNTT�queues�an�event�message�from'*¦a‚task-level‚process�(such�as�the�A/D)*¦driver's�command-processing�subroutine)"*¦toƒa‚task.ƒThe‚driver's‚command-(*¦processing�subroutine�is�considered‚to'*¦be‚a‚task-level�process�because�it�is$*¦invoked�directly‚as‚a‚result‚of‚an'*¦executive‚request‚from�a�task�instead#*¦of�being�invoked�by�an�interrupt. '*¨T0RQPA�requests�a�periodic�activation'*¦of‚a‚specified�routine�at�a�specified'*¦interrupt�level.‚The�T0RQPA‚executive(*¦requ  est‚can�also�be�used�to�deactivate$*¦a‚routine‚that‚has‚previously‚been$*¦activated.ƒThe‚A/D‚driver‚uses�the&*¦T0RQPA�executive‚request‚to‚activate"*¦and„deactivateƒtheƒperiodically-$*¦activated�A/D�measurement�routine. %*¨T0WAKEUP�wakes�up�a‚specified‚task."*¦TheƒA/Dƒdriver‚uses‚the‚T0WAKEUP%*¦executive�request�to‚wake‚up‚a‚user'*¦task‚when‚the�user�task�has�asked�the(*¦driver�to�wake�it�up�at�the‚completion)*¦of�some�measurement�or�some�sequence�of*¦measurements.‰TTL‡2.2.‚Macro�Definitions‰PAGE*œ2.2.‚Macro�Definitions*G*‡This‚section�contains�the�definitions�of�several�macros�that�might�beL*‚useful�in�the�A/D�driver.‚For�ease�of�reference�the�macros�in�this�section&*‚are�presented�in�alphabetical�order.*C*‡Macros‚are‚occasionally‚useful‚for‚modifying�some�of�the�built-in#*‚characteristics�of�the�assembler.-‰PAGEš#######################################0ADDIA„MACRO›This‚macro�is�useful�when�we�want�to#*¦add‚an‚immediate‚value‚to‚an‚"*¦register.„Ifƒthe‚immediate‚value#*¦happens�to‚be‚in‚the‚range‚from‚1(*¦through‚8,�this�macro�generates�a�one-!*¦word‚ADDQ.Lƒinstruction.„Ifƒthe(*¦immediate‚value�is�out�of�range�for�an(*¦ADDQ.L�instruction�but�is�small‚enough)*¦to�be�represented�correctly�in�a�16-bit&*¦two's-complement‚number‚system,‚this"*¦macroƒgeneratesƒaƒtwo-word‚ADD.W)*¦instruction�knowing�that�sign�extension)*¦will�occur�at�execution�time�to�add�the)*¦correct�32-bit�value�to�the�entire�(*¦register.‚Otherwise,�this�macro�gener-&*¦ates�a�three-word�ADD.L�instruction. '*¨By�using�this�macro�we�can�be�assured$*¦ofƒgenerating‚the‚shortest‚correct'*¦instruction,�and�the�macro‚will‚still%*¦function‚correctly‚if‚the‚immediate(*¦value�happens�to�change�as�a�result‚of#*¦futureƒprogramƒmodifications.ƒThe$*¦ADDIA�macro�is�invoked�as�follows. !*¦[