IMD 1.17: 11/11/2014 10:43:00 82VKXSVRDOS B* VERSADOS/RMS68K SRC/OBJ 4.4 (NOT BOOTABLE) SN=49367 3 OF 30  SR03q82VKXSVRDOS 0420¥j-DACINIT5‚TST.L‚(A1,D3)Œlook�for�an�entry�slot�to�save�this�guy5ŠBMI.S‚DACINIT6‹branch�if�this�slot�is�empty�-�use�it.ŠADD.W‚#IOLNG,D3‰not�empty,�bump�to�next�entry"ŠSUB.B‚#1,D4Ždecrement�the�counter(ŠBNE.S‚DACINIT5‹branch�if�more�to�search4ŠBRA„DACEXTER‹error�if�got�here-�no�room�for�the�map>DACINIT6‚MOVE.L�D2,(A1,D3)‰save�this�memory�mapped�I/O�address1DACEXIT1‚CLR.B‚CCBFLG(A5)‰set�for�good�allocation'DACINEX1:�POP_POINT‘recall�all�pointersŠRTS*ŠPAGEJ***************************************************************************$*‰DAC�DRIVER�COMMAND�SERVICE�ROUTINE*6*‹PARAMETER�ADDRESS�AND�BOUNDARY�CHECKS�HAVE�BEEN�MADE**ƒEntry:‚JSR�FROM�CMR�HANDLER.*‹A2�-�PHYSICAL�ADDRESS�OF�CMR�PARAMETER�BLOCK*‹A5�-�PHYSICAL�ADDRESS�OF�CCB*5*ƒExit:‚RTS�-�PARAMETER�BLOCK�VALIDATION�STATUS�IN�D0**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A**P**PP*"*”A3�=�DAC�PARAMETER�BLOCK�ADDRESS*”A6�=�REQUESTOR�TCB�ADDRESS**ƒCODE�IS�RE-ENTRANT*J***************************************************************************)*‰Convert�logical�PB�address�to�physical.*DACCMD„CLR.L‚D5;ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�DAC�parameter�block:ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�DAC�parameter�block+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚CMD010�Good�return.ŠNOP—Bad�length�return. ŠCLR.L‚D0;ŠMOVE.W�#RTCDPBLK,D0‡Set�up�invalid�parameter�block�addressŠRTS*!*‰see�if�passed�the�initialize�ok*7CMD010„MOVE.L�D6,A3ŽStage�phys.�addr.�of�DAC�para.�blk. ŠCLR.L‚D04ŠTST.B‚CCBFLG(A5)‰error�code�set�in�CCB�during�INIT?/ŠBEQ.S‚CMD020�branch�if�no�error�code,�continue$ŠMOVE.B�CCBFLG(A5),D0†set�error�codeŠBRA.S‚DACCEX2Œgoto�error�exit CMD020„EQU�**,*‰get�DACTBL�address�into�A4�for�command�use* ŠMOVE.L�DACTBL,A4ŠDACTBL�address)ŠCMP.L‚#'!DAC',(A4)‡really�is�the�DACTBL?,ŠBEQ.S‚CMD030�branch�if�really�is�the�DACTBL4ŠMOVE.W�#DACNTBL,D0ˆset�error�return�code�-�no�tableŠBRA.S‚DACCEX2Œand�return**‰find�DAC-ID�in�DACTBL*‰A1�=�entry�address*0CMD030„MOVE.L�XIOCID(A2),D0†get�specified�DAC-ID(ŠMOVE.B�DACNMAX(A4),D1…max�#�of�DAC-ID's$ŠMOVE.L�#DACNTRY,D2ˆbump�past�header"FNDDCO10‚CMP.L‚(A4,D2),D0‰a�match?!ŠBEQ.S‚FNDDCO20‹branch�if�a�match&ŠADD.W‚#DACIDLNG,D2‡bump�to�next�entry1ŠSUB.B‚#1,D1Ždecrement�number�of�entries�to�check&ŠBNE.S‚FNDDCO10‹branch�if�more�entries.ŠMOVE.W�#DACNID,D0‰error�-�DAC-ID�not�in�table5ŠBRA.S‚DACCEX2Œreturn�to�CMR�with�error�condition�set+FNDDCO20‚MOVE.L�A4,A1Žbass�address�of�tableŠADD.L‚D2,A1Žaddress�of�entry (*‰Find�the�command�in�the�command�table.*-ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table.+ŠMOVE.W�CMDCOD(A3),D6†get�DAC�command�code.8CMDSRCHƒCMP.W‚(A0)+,D6‹Search�the�table�for�the�command.ŠDBEQƒD0,CMDSRCH3ŠBNE.S‚CMDERR�If�we�found�the�command�in�the�table,8ŠADD.L‚#JMPOFF-2,A0‡get�the�corresponding�entry�from�the5ŠMOVE.W�(A0),D0Œjump�table�and�jump�to�the�routine�to"ŠJMP„(A0,D0.W)Šhandle�the�command.DCMDERR„MOVE.W�#DACINVD,D0ˆdidn't�find�command�code�-�exit�with�errorCDACCEX2ƒMOVE.WƒD0,CMDSTA(A3)„write�error�code�to�users�DAC�para�blkŠRTS*ŠPAGEL******************************************************************************‰OPEN�COMMAND*A*‰This�command�assigns�the�logical�connection�between�a�user�task9*‰and�specified�channels�within�an�DAC�module.�4�channels/*‰maximum�may�be�specified�in�one�open�command.*#*‰DAC�OPEN�command‚parameter�block: *�DS.W‚1„returned�command�status*�DS.W‚1„command�code�(01)*�DS.W‚1„#�of�channels�to�open*�DS.W‚1„1st�channel�number$*�DS.W‚1„channel�wake-up�information*’.*’.%*�DS.W‚1„nth�channel�number‚(max�=�4)$*�DS.W‚1„channel�wake-up�information**)*‚Entry:�A1�=�address�of�DAC-ID�in�DACTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DAC�parameter�block *‰A4�=�address�of�DACTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�CLRIOM,SETIO*K*****************************************************************************‰see�if�channel�already�opened*$OPEN†PUSHPOINT‘save�all�address�regsŠALLOCATEƒCHCONFIG4ŠBSR.S‚VALIDACŒMake�sure�the�DAC�has�been�allocated.(ŠBNE.S‚OPNOID�Error�if�Dac�not�allocatedŠCLR.L‚D7‘channel�counter$ŠCLR.L‚D2‘channel�offset�into�DACTBL)ŠCLR.L‚D1‘offset�into�DAC�parameter�block1ŠMOVE.W�CMDCHN(A3),D0†get�#�of�channels�specified/ŠBLE.S‚OPNINC�branch�if�negative�or�zero,�error0ŠCMP.W‚#4,D0�cannot�specify�more�than�4�channels-ŠBGT.S‚OPNINC�branch�if�greater�than�4,�errorGOPEN10„MOVE.W�NUMCHAN(A3,D1),D2‚get�channel�number�from�DAC�param.�blk.!ŠCMP.W�#4,D2�insure�channel�#�<�4 ŠBGT.S�OPNINVŠMOVE.W�D2,D5Žsave�it0ŠMULUƒ#CHANLNG,D2ˆget�channel�offset�into�DACTBLŠADD.L‚#4,D2Žbump�past�DAC-ID+ŠTST.W‚(A1,D2)Œthis�channel�already�opened?-ŠBPL.S‚OPNOPN�branch�if�already�opened,�errorŠADD.L‚#1,D7Žcount�this�channel**…Save�TCB�address*)ŠMOVE.L�A6,DACTCB(A1,D2)ƒsave�TCB�address4ŠADD.W‚#OPNTRY,D1‰bump�to�next�DAC�param.�blk.�entry3ŠSUB.W‚#1,D0Ždecrement�number�of�channels�specified)ŠBGT„OPEN10�branch�if�more�channels�to�doŠBRA.S‚OPNXIT�go�return�to�CMR**‰open�errors�here*5OPNINVƒMOVE.W„#DACICNS,D0‰set�invalid�channel�#�error ‰BRA.S…OPNXIT8OPNINCƒMOVE.W„#DACINC,D0‰set�invalid�#�of�channels�error‰BRA.S…OPNXIT‹exit;OPNOIDƒMOVE.W„#DACNID,D0‰set�DAC�module�not�allocated�error‰BRA.S…OPNXIT�go�return�to�CMR9OPNOPNƒMOVE.W„#DACPND,D0‰set�channel�already�opened�error*)*‰reset�any�opened�channels�to�not�opened*%OPNERR„TST.W‚D7‘any�channels�to�undo?3ŠBEQ.S‚OPNXIT�branch�if�none�to�undo,�return�to�CMR&ŠMOVE.W�#$FFFF,D3Šset�'un-opened'�codeŠCLR.L‚D1‘clear�for�use6OPNERR10‚MOVE.W�NUMCHAN(A3,D1),D2‚get�a�channel�number$ŠMULUƒ#CHANLNG,D2ˆget�channel�offsetŠADD.L‚#4,D2Žbump�past�headers*ŠMOVE.W�D3,(A1,D2)‰set�this�entry�unopened-ŠADD.W‚#OPNTRY,D1‰bump�to�next�channel�numberŠSUB.W‚#1,D7Ždecrement�counter&ŠBGT.S‚OPNERR10‹branch�if�more�to�undo*…Fall�into�exit* OPNXIT EQU *4ŠADD.L„#NUM_RESERVED,A7‚DEALLOCATE�CHCONFIG�on�stackŠPOP_POINT‘restore�all�pointers ŠBRA�NRMEXIT*ŠPAGEL*****************************************************************************2*‰VALIDAC‚Checks�to�insure�DAC�has�been�allocated.*&*‰Entry:�A1�=�DAC-ID�address�in�DACTBL%*�A2�=�address�of�CMR�parameter�block%*�A3�=�address�of�DAC�parameter�block*�A4�=�address�of�DACTBL*�A5�=�address�of�CCB*�A6�=�address�of�users�TCB**‰Uses:‚D4,D6,D7*%*‰Exit:‚D0�=�DACNID�if�an�error�found**�D0�=�contents�on�entry�if�no�error�found*L*****************************************************************************1VALIDAC‚MOVE.W�DACIO(A4),D7†get�offset�to�IO�maps.ŠMOVE.B�DACNAL(A4),D6†get�#�of�DAC'S�allocated3ŠMOVE.L�CCBCHB(A5),D4†get�memory�mapped�I/O�addressCVALIDAC1�CMP.L‚IODDR(A4,D7),D4ƒlook�for�matching�mem.�map.�I/O�addrŠBEQ.S‚VALIDAC2Šbranch�if�found#ŠADD.W‚#IOLNG,D7‰bump�to�next�entryŠSUB.B‚#1,D6Ždecrement�counter0ŠBNE.S‚VALIDAC1Šbranch�if�more�entries�to�search#ŠMOVE.W�#DACNID,D0‰set�error�returnVALIDAC2ŠRTS—return�to�caller*ŠPAGEL******************************************************************************‚CLOSE�COMMAND*A*‚Close�all�connections�with�this�user�task�and�his�open�channelsB*‚for�this�DAC�module.�The�channels�are�put�back�to�the�pre-opened)*‚state.�The�channels�are�set�to�0�volts.*$*‚DAC�CLOSE�COMMAND�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�02*)*‚Entry:�A1�=�address�of�DAC-ID�in�DACTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DAC�parameter�block*‰A4�=�address�of�DACTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�STOPIO*L*****************************************************************************CLOSE:+ŠMOVE.L�#4,D1Žbump�past�DAC-ID�in�the�table !ŠCLR.L‚D2‘use�for�channel�counter5CLOSE10ƒCMP.L‚DACTCB(A1,D1),A6ƒchannel�for�this�user?*ŠBNE.S‚CLOSE20Œbranch�if�not�for�this�user5ŠBSR.S‚STOPIOŒgo�stop�I/O�on�this�channel�D2�=�chan�#?ŠMOVE.W�#$FFFF,DACTCB(A1,D1)�set�this�channel�entry�to�not�used5CLOSE20ƒADD.L‚#CHANLNG,D1ˆpoint�to�next�channel�entryŠADD.L‚#1,D2Žcount�this�channel#ŠCMP.L‚#4,D2�searched�all�channels?&ŠBNE.S‚CLOSE10Œbranch�if�more�channelsŠCLR.L‚D0‘set�for�no�errorsŠBRA„NRMEXITŒand�return�to�CMR*ŠPAGED*********************************************************************3*‚STOPIOƒdeactivate�I/O�on�specified�channel�number*&*‚Entry:�A1�=�DAC-ID�address�in�DACTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DAC�parameter�block*‰A4�=�address�of�DACTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‰D0.W�=�channel�configuration%*‰D2.L�=�channel�number�to�deactivate* *‚Uses:‚D0,A0*L*****************************************************************************9STOPIOƒMOVE.L�CCBCHB(A5),A0†get�memory�mapped�I/O�address+‰MOVEƒIOADR(A1,D1),D0„Get�offset�to�channel5‰MOVE.B�#ZEROL,(A0,D0)…Set�low�byte�of�converter�to�07‰MOVE.B�#ZEROH,2(A0,D0)„Set�high�byte�of�converter�to�0‰RTS—return�to�caller*ŠPAGEF*********************************************************************** *‰CNVRT�-�TURN�ON�OUTPUT�COMMAND<*‰This�command�activates�outputs�for�specified�channels�that9*‰have�previously�been�opened�for�output�by�the�same�task<*‰requesting�this�activation.‚The�parameter�block�is�checked:*‰for�errors�before�any�output�is�activated.‚No�channel�is!*‰activated�if�an�error�is�found.*%*‰DAC�OUTPUT�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�03*‰DS.Wƒ1ƒChannel�#�to�convert**‰DS.Wƒ1ƒ#�of�conversions�for�this�channel(*‰DS.Lƒ1ƒAddress�of�conversion�data�list*‹.2*‹.ˆUp�to�4�channels�in�the�list�and�they�must�all*‹.ˆbe�for�the�same�board=*‰DS.Wƒ1ƒWake�up�information�when�end�of�list�is�encountered.* *‰Data�list*.*‰DS.Wƒ1ƒDelay�information�between�conversions&*‰DS.Wƒ1ƒDigital�value�to�be�converted*)*‚Entry:�A1�=�address�of�DAC-ID�in�DACTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DAC�parameter�block*‰A4�=�address�of�DACTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*L*****************************************************************************CNVRT:6ŠMOVE.L�A3,-(A7)‹Save�the�register--I�need�to�remember"*£where�to�write�the�status�later.:ŠMOVEƒCMDCHN(A3),D7†Get�the�number�of�channels�to�convert.ŠIF.W��OR.B�D7��#4�THEN.SŠMOVE.L�(A7)+,A30ŠMOVEƒ#DACINC,D0‰Set�invalid�#�of�channels�errorŠBRA„EXIT�get�outŠENDI 0ŠSUBQƒ#1,D7ŽAdjust�the�number�for�the�DBRA�loop.5ŠADD.L‚#CMDNXT,A3‰Point�to�the�convert�portion�of�the*£parameter�block.CNVRT19ŠMOVEƒ(A3)+,D1‹D1�<--�channel�number�for�this�conversion.)ŠCMP„#3,D1ŽMake�sure�channel�is�in�range.ŠIF…�THEN.S"ŠMOVE.L�(A7)+,A3‹Restore�the�stack0ŠMOVEƒ#DACICNS,D0ˆSet�the�error�return�conditionŠBRA„EXIT�Now�we�can�get�outŠENDI 7ŠMOVEƒ(A3)+,D2‹D2�<--�#�of�conversions�for�this�channel:ŠMOVE.L�(A3)+,D6‹D6�<--�logical�address�of�conversion�data1ŠMOVEƒD2,D5ŽFind�length�of�conversion�data�buffer#*£for�the�logical�to�physical�call.2ŠMULUƒ#4,D5ŽMulitiply�the�number�of�conversions�by&*£the�number�of�bytes�per�entry�in�the*£table.1ŠSUBQƒ#1,D2ŽDBRA�adjust�the�number�of�conversions6ŠMOVE.L�A1,-(A7)‹Need�this�register�for�the�logical�to*£physical�call.+ŠMOVE.L�A6,A1ŽA1�<--�TCB�address�of�caller.ŠBSR„IOHADRCK‹Do�translation.ŠBRA.S‚CNVRT2�Good�return.ŠNOP—Bad�return�from�call<ŠMOVEM.L�(A7)+,A1/A6‡Clean�up�the�stack�for�the�error�return5ŠMOVEƒ#RTCDPBLK,D0‡Tell�user�address�not�in�his�spaceŠBRA„EXIT�Get�out�of�here.CNVRT28ŠMOVE.L�D6,A0ŽA0�<--�physical�address�of�conversion�data+ŠMOVE.L�CCBCHB(A5),A2†Offset�to�I/O�address'*£A2�<--�Base�I/O�address�of�the�board.*ŠMOVE.L�(A7),A1ŒRestore�pointer�to�DACTBL. 8ŠADDQ.L�#4,A1ŽPoint�to�the�information�about�the�channel *£in�the�DAC.1ŠMULUƒ#CHANLNG,D1ˆOffset�to�the�specific�channel.CŠCMP.L‚DACTCB(A1,D1),A6ƒFind�out�if�the�caller�really�owns�the�chnlŠIF…�THEN.S(ŠMOVEM.L�(A7)+,A1/A3ˆClean�up�the�stack.,ŠMOVEƒ#DACICU,D0‰Set�the�error�return�value.ŠBRA.S‚EXIT�get�outŠENDIAŠMOVEƒIOADR(A1,D1),D3„D3�<--�offset�from�base�I/O�address�of�this,ŠMOVE.L�(A7)+,A1‹Restore�the�saved�register.,ŠMOVE.L�(A1),D5ŒSave�the�ID�for�this�module. *£channelCNVRT36ŠTST„(A0)+ŽIs�there�a�delay�before�converting�the�dataŠIF��THEN.S#ŠMOVE.L�(A7)+,D0‹Clean�up�the�stack<ŠDIVUƒ#CHANLNG,D1ˆGet�the�channel�#�for�this�conversion�backŠMOVEƒD1,D6ŽSave�it@ŠMULUƒ#SAVEREGS*4,D6…This�is�the�offset�to�this�channels�area�in**£the�CCB�where�we�can�save�the�registers.:ŠMOVEM.L�D0-D3/D5/D7/A0-A6,CHNLREGS(A5,D6)�Save�the�world.7ŠMOVE.L�A5,D2ŽUse�the�CCB�address�as�the�identification&ŠOR.BƒD1,D2ŽEncode�the�channel�number.ŠSUB.L‚A1,A1ŽZero�the�register.#ŠMOVEƒ-2(A0),A1ŠGet�delay�interval.,ŠLEA„ACTENTRY(PC),A0„Activation�entry�point.0ŠMOVE„#1,D1�Set�options--New�periodic�activation*°single�activation*°interrupt�level�1ŠTR0$.RQPA‘Do�it.$ŠBRA.S‚EXIT1ŽGet�out�if�good�return.;ŠBRA.S‚*ˆ**********************FOR�NOW*********************CNVRT3A7ŠMOVE.L�D0,-(A7)‹Stack�<--�start�address�of�para.�blockŠENDI#ŠMOVEƒ(A0)+,D4‹Get�data�to�convert.2ŠMOVE.B�D4,0(A2,D3)ˆGive�low�byte�to�the�hardware. ŠROR„#8,D4ŽSet�up�the�high�byte.7ŠMOVE.B�D4,2(A2,D3)ˆGive�the�high�byte�to�the�hardware."ŠDBRAƒD2,CNVRT3ŠDo�the�whole�list.!ŠDBRAƒD7,CNVRT1ŠDo�every�channel.(ŠMOVEƒ(A3),D0ŒD0�<--�wake�up�information7ŠMOVE.L�(A7)+,A3‹Restore�the�stack�pointer�which�we�had)*£saved�the�address�of�the�status�word�in*£the�command�packet.,ŠTST„D0‘Find�out�how�requestor�whats�to�knowŠBMI.S‚CNVRT5�the�job�is�done. ŠBTSTƒ#0,D0 ŠBEQ.S‚CNVRT4*0*‰The�requestor�wants�a�wake-up�so�give�him�one.*-ŠMOVE.L�A6,A0ŽA0�<--�TCB�Address�of�requestor ŠTR0$.WAKEUPŠBRA.S‚CNVRT5�Exit�good**‰Unable�to�wake�up�the�user*0ŠBRA.S‚*’***************FOR�NOW*****************CNVRT4+ŠBSR.S‚QUEVENTŒQueue�the�requestor�an�eventCNVRT5#ŠCLR„D0‘Set�returned�status�to�goodEXIT-ŠMOVEƒD0,(A3)ŒPut�status�in�users�parm�block.EXIT1 ŠCLR.L‚D0ŠRTS‰PAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DAC�parameter�block*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D0�=�DAC�error�code*I**************************************************************************NRMEXIT:>ŠMOVE.W�D0,CMDSTA(A3)†set�return�status�in�DAC�parameter�blockŠRTS—return�to�CMR*ŠPAGE*‚ACTIVATION�ENTRY�POINT*ACTENTRY)ŠMOVEM.L�D2-D7/A2-A6,-(A7)�Save�registersŠAND.W‚#$F8FF,SRŠDrop�the�mask.ŠCLR„D2‘Initialize�registers.#ŠMOVE.B�D1,D2ŽD2�<--�channel�numberŠAND.B‚#0,D1ŽD1�<--�CCB�address-ŠMOVE.L�D1,A0ŽPut�CCB�address�in�useable�reg.5ŠMULUƒ#SAVEREGS*4,D2…Find�registers�for�this�channel.*ŠMOVEM.L�CHNLREGS(A0,D2),D0-D3/D5/D7/A0-A6ŠMULU„#CHANLNG,D1.ŠBSR.S‚CNVRT3AŒGo�work�on�the�conversion�list.-ŠMOVEM.L�(A7)+,D2-D7/A2-A6�Restore�the�stack. ŠRTE—Exit.ŠPAGE*H*‚QUEVENT�-�queue's�event�to�driving�task�using�data�staged�in�registers *‹as�follows:*‹A6�=�user's�TCB�address&*‹D2�=�$0C01�*‹D3�=�DACID‚(module�name)&*‹D4�=�mem�mapped�I/O�address�of�board<*†(dumps�contents�of�registers�D2,�D3,�&�D4�to�users�buffer)* QUEVENT EQU *‹PUSHALL”push�all�regs"‹MOVE.L…A6,A0Žstage�user's�address+ŠMOVE.L�D5,D3ŽPut�DACID�in�the�correct�reg.-ŠMOVE.L�A2,D4ŽPut�I/O�address�in�correct�reg.!ŠCLR.L‚D2‘Initialize�the�register*ŠMOVEƒ#$0C01,D2ŠSet�event�length�and�type.(ŠSWAPƒD2‘Set�up�to�move�in�the�channel�#7ŠDIVUƒ#CHANLNG,D1ˆThe�channel�#�has�to�be�re-calculated ŠMOVEƒD1,D2ŽFinish�up�the�event. ‹TR0$.QEVNTI*)‹BRA.SƒQUEVNTOKŒgood�return�for�que�event '‹BRA.SƒQUEVNTERŒbad�return�from�queventQUEVNTOK EQU *‹POPALL•restore�all�regs‹RTS QUEVNTER:(‹BRA�QUEVNTOK�put�a�break�here�for�debug*ŠPAGEF***********************************************************************B* SUBROUTINE TO CHECK ADDRESS BOUNDARIES TO SEE IF ENTIRELY WITHIN*ƒCALLING�TASKS�ADDRESS�SPACE.*#*�ENTRY:ƒD5‚-�NO.�OF�BYTES�TO�CHECK*ŠD6‚-�68000�ADDRESS�(LOGICAL)*ŠA1‚-�TCB�ADDRESS** EXEC ROUTINE#* REGISTERS USED: D0-D1,D3,D6/A0-A1*7*�EXIT:„D6�-�PHYSICAL�ADDRESS�OF�BUFFER�BASE�(IF�LEGAL)*ŠRETURN�TO�PC„FOR�GOOD�ADDRESS*”PC+2‚FOR�BAD�LENGTH*”PC+4‚FOR�BAD�ADDRESS*F*********************************************************************** IOHADRCK:%ŠBTSTƒ#0,D6‘Must�be�on�work�boundary.)ŠBNE.S‚IOHADR4�Branch�if�bad�buffer�base.ŠTST.L‚D5”Length�can't�be�zero.2ŠBEQ.S‚IOHADR8�Don't�go�to�logphy�with�zero�count.1ŠMOVE.L�TCBTST(A1),A0‰Address�of�task�seg.�table. ŠTR0$.LOGPHY*.ŠBRA.S‚IOHADR8�Branch�for�good�address�return.0ŠBRA.S‚IOHADR6�Branch�for�bad�byte�count�return.(ŠTST.L‚D5”Was�an�entry�pointer�returned.#ŠBEQ.S‚IOHADR4�Branch�if�no�-�ERROR)ŠTST.B‚7(A0,D5)ŽIs�this�an�MMIO�segment�?ŠBNE.S‚IOHADR8�Yes,�OK.3IOHADR4ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.3IOHADR6ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.IOHADR8ƒRTSšReturn.* PAGE**ˆINTERRUPT�SERVICE�ENTRY�POINT*<*ˆThere�are�no�interrupts�for�this�board�so�exit�if�entered.*DACINT‰RTS‰ENDéé=/*=/*†M605LIB.AF=/*D=/* Chain file to assemble FORTRAN-callable subroutines to interface=/* with the MVME605 driver.=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M605LIB.LS=/*=/IFC \1„=ARG�M605LIB.LS=/ENDIF=/*=ASM M605LIB.SA,M605LIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDéééééé €FTDAC…IDNTƒ1,0�DAC�subroutines**‰FORTRAN�callable�subroutines*‰for�DAC�driver�calls*$*‰CALL�DACCMD(dac_id,param_blk_addr)*‰where�DACCMD�may�be:*)*‰CALL�DAOPEN(dac_id,param_blk_addr)…open**‰CALL�DACCLS(dac_id,param_blk_addr)…close.*‰CALL�DACOUT(dac_id,param_blk_addr)…output�on*,*‰All�arguments�for�the�calls�are�identical.7*‰The�contents�of�the�param_blk�for�each�call�is�unique*‰to�the�call.*6*‰All�the�command�subroutines�call�a�common�subroutine3*‰DACSET�to�build�the�initiate�I/O�parameter�block.**‰STACK�FOR�ALL�CALLS:*7*‰deepest�stack:�(stack�address�stays�at�DACSET�return)0*˜command�codeƒ2�bytes�(initiate�I/O�param.�blk) *˜n/aŒ2�bytes*˜dac_id‰4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes,*˜command�addrƒ4�bytes�(dac�command�address)**˜command�lng„2�bytes�(dac�command�length)-*˜DACSET�return‚4�bytes�deepest�stack�address *˜A3�4�bytes *˜A2�4�bytes *˜A1�4�bytes *˜D0�4�bytes*‰entry�stack:ƒreturn‰4�bytes*˜^param_blk_adr�4�bytes*˜^dac-idˆ4�bytes* ŠSECTION�9ŠXDEFƒDAOPEN,DACCLS,DACNVT*$*‰CALL�DAOPEN(dac_id,param_blk_addr)*‰open�and�configure�channels*1DAOPEN„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DACSET�set-up�the�initiate�I/O�parameter�block)ŠMOVE.L�#1,(A2)Œset�the�open�command�codeDACPN00ƒCLR.L‚D0‘clear�for�use'ŠMOVE.W�4(A2),D0‹get�number�of�channelsŠASL.L‚#1,D0Žmultiply�by�4.DACPN05ƒADD.L‚#6,D0Žadd�in�the�6�byte�overhead-DACPN10ƒMOVE.W�D0,(A1)Œset�the�command�length-ŠMOVE.L�A3,A0ŽTRAP�#1�parameter�block�address#ŠMOVE.L�#60,D0�CMR�directive�numberŠTRAPƒ#1‘call�RMS68K'ŠMOVE.W�D0,(A2)Œset�the�returned�status)ŠMOVEM.L�(A7)+,D0/A1-A3„restore�registers!ŠMOVE.L�(A7)+,A0‹put�return�in�A0 ŠLEA„8(A7),A7‹clean�up�the�stackŠJMP„(A0)�return�to�user*$*‰CALL�DACCLS(dac_id,param_blk_addr)"*‰close�all�channels�for�this�user*1DACCLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DACSET�set-up�the�initiate�I/O�parameter�block*ŠMOVE.L�#2,(A2)Œset�the�close�command�code‰D’;&ŠMOVE.W�#4,D0ŽDAC�close�command�lengthŠBRA„DACPN10Œgo�do�the�CMR�call*$*‰CALL�DACNVT(dac_id,param_blk_addr)'*‰activate�output�on�requested�channels*1DACNVT„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DACSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#3,(A2)Œset�the�output�command�code+ŠMOVE.W�4(A2),D0‹get�the�number�of�channels2ŠMULUƒ#8,D0Žfind�the�length�of�the�parameter�block%DACUT10ƒADD.W„#6,D0Œadd�in�the�headerŠBRA„DACPN10Œgo�do�the�CMR�call*ŠPAGE*4*‰DACSET�set�up�the�CMR�initiate�I/O�parameter�block,*‰returns:ƒA1=address�for�DAC�command�length(*”A2=DAC�command�parameter�block�address)*”A3=initiate�I/O�parameter�block�address*(DACSET„CLR.W‚-2(A7)�clear�command�length-ŠLEA„-2(A7),A1Šsave�address�of�command�length$ŠMOVE.L�24(A7),A0Šget�param_blk_addr%ŠMOVE.L�A0,-6(A7)Šsave�param_blk_addr,ŠMOVE.L�A0,A2Žsave�param_blk_addr�for�returnŠCLR.L‚-10(A7)Œnot�usedŠCLR.L‚-14(A7)Œnot�usedŠCLR.L‚-18(A7)Œnot�usedŠMOVE.L�28(A7),A0Šget�^dac_idŠMOVE.L�(A0),-22(A7)‡get�dac_idŠCLR.W‚-24(A7)Œnot�used0ŠMOVE.W�#$0700,-26(A7)…initiate�I/O�command�code4ŠLEA„-26(A7),A3‰initiate�I/O�parameter�block�addressŠRTS—return�to�caller* *ˆGet�the�location�of�a�variable* *ˆI=LOC(VAR)*-*’I‰The�integer*4�variable�which�receives�the*œlocation�of�VAR.**’VAR‡Any�variable�or�constant.* ‰XDEF†LOC**ˆDeepest�stack:*ˆEntry�stack:ˆreturn*œ^var* ‰SECTION�9LOC#‰MOVE.L„(A7)+,A0ŒGet�return�address"‰MOVE.L„(A7)+,D0ŒSupply�the�answ er‰JMP‡(A0)�Return*ŠEND*é=/*=/*†M610DRV.AF=/*-=/* Chain file to assemble the MVME610 driver=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M610DRV.LS=/*=/IFC \1ƒ=ARG�M610DRV.LS=/ENDIF=/*$=ASM M610DRV.SA,M610DRV.RO,\1;RZ=100=/*{ Included files are:=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TR1RTCD.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.BAB.EQ=/*ƒ9995.&.M610CCB.EQ=/*ƒ9995.&.M610INTQ.EQ=/*ƒ9995.&.M610CMD.EQ=/*}=/*=ENDéééééš ŠNOFORMAT ŠOPT„CRE,BRS;ŠTTL�VME�610/620�Input�Module�Driver�Version�1.0�-�11/01/848M610†IDNTƒ1,0�VME�610/620�Input�Module�Driver�-�11/01/84K****************************************************************************<*ŠVME�610-AC/620-DC�Input�Module�Driver�Source�-�Version�1.0<*Š----------------------------------------------------------*K*ƒThis�source�satisfies�all�requirements�set�forth�in�the�VME�610/620�AC/DCC* Input Module Driver Engineering Specification - ES0145 Issue 2.0.***ƒRevision�history:*A*Š11/01/84‚Removed�all�references�to�the�RMS68K�TIMEOD�parameter.4*”They�were�replaced�by�a�call�to�the�RMS68K�RDTIMER,*”routine�to�obtain�the�current�time-of-day.***‰Glossary�of�Abbreviations*‰-------------------------**‰CCBƒ-�Channel�Control�Block#*‰BABƒ-�Background�Activation�Block&*‰IQCT‚-�Interrupt�Queue�Control�Table(*‰ICCT‚-�Interrupt�Channel�Control�Table-*‰NICCT�-�Non-interrupt�Channel�Control�Table*L****************************************************************************ŠFORMATŠPAGE*‰INCLUDE‚9995.&.STR.EQŠINCLUDE‚9995.&.STR.EQŠPAGE*‰INCLUDE‚9995.&.TR1RTCD.EQŠINCLUDE‚9995.&.TR1RTCD.EQŠPAGE*‰INCLUDE‚9995.&.TCB.EQŠINCLUDE‚9995.&.TCB.EQŠPAGE*‰INCLUDE‚9995.&.L V5.EQŠINCLUDE‚9995.&.LV5.EQŠPAGE*‰INCLUDE‚9995.&.CCB.EQŠINCLUDE‚9995.&.CCB.EQ ŠNOFORMAT*‰INCLUDE‚9995.&.BAB.EQŠINCLUDE‚9995.&.BAB.EQŠINCLUDE‚9995.&.M610CCB.EQŠINCLUDE‚9995.&.M610INTQ.EQŠINCLUDE‚9995.&.M610CMD.EQŠPAGE*(*ƒInput�Module�Hardware�Register�Offsets*E*ƒThe�following�equates�define�the�offsets�to�each�VME�610/620�moduleJ* hardware register from the base memory mapped I/O address of the module.D* The base address is assumed to specified on an even byte boundary.*ŠSPC„2 ŠOFFSET�0ŠSPC„20INPCSTAT‚DS.Bƒ1”This�the�offset�to�the�read-only*£Channel�Status�register.ŠSPC„2:INPICNTR‚EQU„INPCSTAT�This�is�the�offset�to�the�write-only(*£Interrupt�Mask/Sense�Control�register.ŠSPC„2œ£E¬<´0¼0Ä9Ì'Ô)Ü2ä2ì6ô3ü$4 5(6$6,44/<1D0L2T4\,d5l2t1|2„.Œ0-ŠDS.Bƒ1”All�even�byte�addresses�are�undefined*£on�the�I/O�Channel.ŠSPC„23INPISTAT‚DS.Bƒ1”This�is�the�offset�to�the�read-only*£Interrupt�Status�register.ŠPAGE ŠSECTION�0 ŠOPT„BRS,CREŠSPC„2(*‚Externally�Defined�Symbol�Declarations 7ŠXREF.S�INPTBL�This�symbol�is�the�address�of�a�location&*£within�SYSPAR�that�contains�the�base**£address�of�the�Global�Variable�Area�that)*£allocated�and�initialized�during�system*£initialization.ŠPAGEN*******************************************************************************0*‰CMR�Parameters�and�Module�Revision�Information0*‰----------------------------------------------*L*ƒThis�section�contains�the�CMR�Service�Vector�Table,�CMR�channel�allcoation.* parameters, and module revision Information.*N****************************************************************************** INPDRV: **‚CMR�Service�Vector�Table*H*ƒThis�table�contains�the�entry�point�offsets�of�the�input�module�driverK* Foreground Interrupt Handler, Command Handler, and Initialization RoutineK* relative to the driver base memory address. When one of these routines isG* to be executed, CMR adds the entry point offset of the routine to theH* driver base memory address defined by SYSgen and performs a JSR to the* resulting address.*ŠSPC„27ŠDC.LƒINTERUPT-INPDRV†This�field�defines�the�Foreground'*£Interrupt�Handler�entry�point�offset.ŠSPC„2;ŠDC.LƒCOMMAND-INPDRV‡This�field�defines�the�Command�Handler*£entry�point�offset.ŠSPC„27ŠDC.LƒINIT-INPDRVŠThis�field�defines�the�Initialization*£Routine�entry�point�offset.ŠSPC„2-ŠDC.Lƒ0”This�field�is�reserved�for�future�use *£by�CMR.ŠSPC„2*H*ƒThis�section�contains�information�used�by�CMR�to�allocate�input�moduleN* CCB's. Currently, the only parameter defined for this field is the number ofH* additional pages to be allocated to each CCB. All other fields in this-* section are reserved for future use by CMR.*ŠSPC„2(ŠDC.Bƒ1”This�field�defines�the�number�of+*£additional�pages�to�be�allocated�for�each+*£CCB�by�CMR.�This�driver�uses�two�pages�in *£each�CCB.ŠSPC„24ŠDCB.B‚15,0‘The�remaining�15�bytes�of�this�parameter+*£field�are�reserved�for�future�use�by�CMR.ŠSPC„2*G*ƒThis�section�contains�module�revision�information.�The�information�isO* stored as part of the driver object code to allow determination of the driverK* revision that was included in a particular application system when SYSgen* listings are not available.*ŠSPC„22ŠDC.Bƒ'110184'�This�is�the�date�of�assembly�of�the**£release�version�of�this�driver�revision.ŠSPC„2,ŠDC.Bƒ'�'’This�field�specifies�the�number�of&*£patches�that�have�been�applied�since'*£release�of�this�driver�revision.�This(*£field�always�contains�a�blank�whenever*£the�driver�is�reassembled.ŠSPC„20ŠDC.Bƒ'4'’This�field�contains�the�minimum�RMS68K&*£major�revision�level�with�which�this'*£revision�of�the�driver�is�compatible.ŠPAGEM****************************************************************** ************4*‰Input�Module�Driver�Channel�Initialization�Routine4*‰--------------------------------------------------*J*ƒThe�channel�initialization�routine�is�called�by�CMR�whenever�an�AllocateH* Channel command is issued to CMR. This normally occurs once, at systemM* initialization time, for each input module specified by SYSgen. On entry toL* this routine, A5 contains the address of the CCB allocated by CMR for thisK* input module. Also, CMR initializes the device independent portion of theM* CCB and clears the device dependent portion to zeros before the calling the* initialization routine.*F*ƒThis�routine�first�initializes�the�input�module�hardware�at�the�baseN* memory mapped I/O address specified in the Allocate call. Several CCB fieldsH* are initialized that contain bit masks used to manipulate the hardwareM* registers of the VME 610/620 module and control operation of the Foreground* Interrupt Handler.*%*‰Entry�Conditions�:�A0�=�CCB�address*6*‰Exit�Conditions‚:�All�registers�are�preserved�by�CMR*-*‰General�Register�Usage�:�D0�=�Work�Register*¢D1�=�Work�Register*¢A0�=�Work�Register**¢A3�=�Interrupt�Queue�Control�Table�Entry *§address#*¢A4�=�Global�Variable�Area�address*¢A5�=�CCB�address*N******************************************************************************ŠPAGEJ*ƒThe�following�table�contains�the�directive�numbers�for�the�RMS68K�Trap�0K* routines that are called by this driver. This table is used by the driverL* initialization routine to obtain the JSR entry point address correspondingK* to each directive number in the table. The order of the table entries mayL* not be changed unless the order of the corresponding JSR address fields in* the CCB is also changed. *TRAP0TBL‚DC.BƒT0GUARDŒCall�Guarded�routine)ŠDC.BƒT0SCHEDŒSchedule�Background�routine4ŠDC.BƒT0LOGPHY‹Logcal�to�physical�address�conversion2ŠDC.BƒT0RQPA�Executive�Periodic�Activation�routine,ŠDC.BƒT0QEVNTI‹Interrupt�Queue�Event�routine"ŠDC.BƒT0WAKEUP‹Task�Wakeup�routine3ŠDC.BƒT0RDTIMŒRead�Timer�routine‚***�added�10/25/84ŠSPC„2>NUMTR0„EQU„*-TRAP0TBL‰Number�of�entries�in�the�directive�tableŠPAGEAINIT†MOVE.L�CCBCHB(A5),A0ˆLoad�the�memory-mapped�I/O�base�address<ŠCLR.B‚INPICNTR(A0)‡of�the�input�module�and�perform�hardware9ŠTST.B‚INPISTAT(A0)‡initialization�by�writing�zero�to�the**£Interrupt�Mask/Sense�Control�register�to(*£disable�all�interrupts�from�the�module'*£followed�by�a�read�from�the�Interrupt&*£Status�register�to�clear�any�pending$*£interrupts.�The�order�of�these�two,*£operations�cannot�be�changed�or�interrupts*£may�be�left�pending.ŠSPC„29ŠMOVE.L�INPTBL,A4ŒLoad�the�address�of�the�Global�Variable*£area�from�SYSPAR.ŠSPC„2=ŠMOVE.B�CCBPPRIO(A5),D1†If�the�hardware�interrupt�priority�of=ŠCMP.B‚QMAXIL(A4),D1†the�new�CCB�is�higher�than�the�interrupt7ŠBLS„INIT010Œpriorities�of�all�previous�CCBs�allocated,?ŠMOVE.B�D1,QMAXIL(A4)†copy�the�new�maximum�interrupt�level�into$*£the�Interrupt�Queue�Control�Table.ŠSPC„2*J*ƒInitialize�the�fields�of�the�CCB�that�apply�to�all�input�channels�on�the* the input module.*ŠSPC„2CINIT010ƒMOVE.L�A4,CCBQCTAD(A5)†Write�the�addresses�of�the�Interrupt!*£Queue�Control�Table�to�the�CCB.ŠSPC„2;ŠLEA.L‚BACKGRND(PC),A0ŠInitialize�the�Activation�Address�in@ŠMOVE.L�A0,QBAB+BABPTR(A4)…the�Interrupt�Queue�Control�entry�BAB#*§to�the�entry�point�address�of�the*§background�interrupt�handler.ŠSPC„2;ŠLEA.L‚DOWNCHAN(PC),A0ˆStore�the�entry�point�address�of�theCŠMOVE.L�A0,CCBBAB+BABPTR(A5)�Background�Channel�Shutdown�Handler�in**¥the�pointer�field�of�the�BAB�in�the�CCB.ŠSPC„2;ŠCLR.B‚CCBIQENA(A5)‰Set�the�Interrupt�Queueing�Mask�so�that%*£queueing�of�interrupts�is�initially,*£disabled�for�all�interrupt�channels�on�the*£input�module.ŠSPC„29ŠCLR.B‚CCBCHTYP(A5)‰Set�the�Channel�Type�mask�to�mark�all$*£channels�initially�as�non-debounce *£channels.ŠPAGEE*‚Obtain�the�JSR�entry�point�addresses�for�the�RMS68K�Trap�0�routines 6ŠMOVE.L�#T0ENTRY,D0ŠCall �the�Entry�Point�routine�via�a2ŠMOVE.L�D0,D1ŽTrap�0�to�obtain�the�JSR�entry�pointŠTRAPƒ#0‘of�the�routine�itself.ŠNOPŠSPC„26ŠMOVE.L�A0,A3�Save�the�Entry�Point�routine�JSR�address*£in�A3.ŠSPC„25ŠMOVE.L�#0,D1�Clear�D1�in�preparation�for�the�loading"*£of�the�Trap�0�directive�numbers.ŠSPC„2<ŠLEA.L‚CCBGUARD(A5),A2†Load�the�base�address�of�block�of�JSR*£address�locations�in�the�CCB.ŠSPC„2:ŠLEA.L‚TRAP0TBL(PC),A1†Load�the�base�address�of�the�Trap�0<ŠMOVE.W�#NUMTR0-1,D0‡Directive�Number�Table�and�initialize�a'*£loop�counter�with�the�number�of�table *£entries.ŠSPC„2AINIT020ƒMOVE.B�(A1)+,D1�Load�the�Trap�0�directive�number�into�D1.ŠSPC„21ŠJSR„(A3)‘Call�the�Entry�Point�routine.�The�entry0ŠNOP—point�of�the�routine�whose�Trap�0�directive-*£number�is�in�D1�will�be�returned�in�A0.�The+*£NOP�is�a�place�filler�for�the�Entry�Point,*£directives�"non-error"�return.�The�"error"'*£return�(following�the�NOP)�is�ignored(*£because�the�Trap�0�routines�must�be�in$*£RMS68K�for�this�driver�to�operate.ŠSPC„26ŠMOVE.L�A0,(A2)+�Store�the�returned�JSR�address�in�the*£corresponding�CCB�location.ŠSPC„25ŠDBRAƒD0,INIT020‹Loop�until�all�entry�necessary�entry*£points�have�been�obtained.ŠSPC„2)ŠRTS™The�initialization�of�the�CCB�is�now*£complete�so�return�to�CMR.ŠPAGEO********************************************************************************7*ŠInput�Module�Driver�Common�Command�Processing�Routine7*Š-----------------------------------------------------*L*ƒThis�command�processing�routine�is�called�by�CMR�whenever�a�task�issues�anG* Initiate I/O command to CMR, via a Trap 1, that specifies the channelN* mnemonic for an input module controlled by this driver. The function of thisL* module is to perform all command independent pre-processing before passing<* control to one of the command specific processing modules.*H*ƒThis�routine�assumes�that�the�Initiate�I/O�command�parameter�block�hasM* already been validated by CMR before entry to the command handler. The onlyH* fields in this parameter block that are processed here are the commandO* sub-code field and the fields that specify the base address and length of theK* Input Driver command parameter block(IPB). Command sub-codes for Reset or!* Halt I/O commands are rejected.*L*ƒAfter�verifying�that�the�user�specified�base�address�and�length�of�the�IPBN* reside within the requesting tasks address space, several checks are made onL* the contents of the IPB for the following commands: Close Channels, EnableM* Interrupts, Disable Interrupts, and Input Status. All IPB validation for anN* Open Channels command is performed by the associated command specific moduleN* because its IPB structure is different from those of the other commands. ForL* the other commands this module validates IPB length and checks the ChannelM* number mask for non-existent channels (channel numbers 8-15) and checks forH* channels that the requesting task has not claimed via an Open Channels * command.*L*ƒAfter�all�IPB�checks�have�been�passed,�the�command�processing�routine�jumpN* table is searched for a match to the specified Input Driver Command Code. IfO* no match is found the request is rejected and an error is returned. OtherwiseJ* a JSR is performed to the entry point of the command specific processing * routine.*J*ƒWhen�control�returns�to�this�module�following�normal�command�completion,M* the command handler returns to CMR with a zero status in D0. If an error isH* detected during command processing, a jump is performed to the commandN* handler error exit where the original value of the stack pointer is restored:* an a return is made to CMR with a non-zero status in D0.*F*‰Entry�Conditions�:�A2�=�Initiate�I/O�Command�parameter�block�address1*œA5�=�Address�of�the�CCB�for�the�Input�Module�on'*¡which�the�command�is�to�be�performed.)*œA6�=�TCB�address�of�the�requesting�task*2*‰Exit�Conditions‚:�D0�=�Command�status/error�code'*œAll�other�registers�preserved�by�CMR.*F *‰General�Register�Usage�:�D1�=�Contains�an�error�code�when�an�exit�is*§made�through�CMDERR&*¢D2�=�Channels�Mask�(CMDCHM)�from�IPB*¢D5�=�Length�of�IPB*¢D0,D3,D6�=�Scratch�registers*¢A0,A1�=�Scratch�registers'*¢A4�=�Physical�base�address�of�the�IPB*O*******************************************************************************ŠPAGEK*ƒThe�following�table�contains�the�IPB�command�codes�that�are�recognized�byM* this driver and the command specific processing routine entry point offsetsM* from the base address of the command table. For each table entry, the entryN* point offset to the command specific routine preceeds the command code. BothN* the offset and command code fields are 16-bit long to force each table entry* to start on a word boundary.ŠSPC„2:CMDTBL„DC.WƒOPEN-CMDTBL,INOPEN„Open�Channels�command�entry6ŠDC.WƒCLOSE-CMDTBL,INCLOSƒClose�Channels�command�entry:ŠDC.WƒSTATUS-CMDTBL,INSTAT‚Read�Input�Status�command�entry:ŠDC.WƒENABIN-CMDTBL,INENAB‚Enable�Interrupts�command�entry;ŠDC.WƒDSABIN-CMDTBL,INDSAB‚Disable�Interrupts�command�entryŠSPC„2;NUMCMD„EQU„(*-CMDTBL)/4‰This�equate�specifies�the�number�of*£entries�in�the�command�table.ŠPAGEHCOMMANDƒMOVE.L�A7,CCBCMDST(A5)†Save�the�entry�value�of�the�stack�pointer(*£in�the�CCB�so�it�can�be�restored�if�an&*£error�exit�is�required�from�a�nested *£subroutine.ŠSPC„22ŠCLR.L‚D1“If�the�command�sub-code�specified�in�the9ŠMOVE.B�#INPISC,D1‰in�the�Initiate�I/O�parameter�block�is6ŠTST.B‚XIOSCD(A2)‰not�zero,�perform�an�error�exit�with(ŠBNE.L‚CMDERR�an�invalid�sub-code�error.ŠSPC„29ŠMOVE.B�#INPBAWB,D1ŠLoad�the�base�address�of�the�IPB�from>ŠMOVE.L�XIOCPK(A2),D6†the�Initiate�I/O�parameter�block.�If�the3ŠBTSTƒ#0,D6Žaddress�is�not�on�a�word�boundary,�exit7ŠBNE.L‚CMDERR�with�an�odd�byte�boundary�parameter�block*£base�address�error.ŠSPC„2<ŠMOVE.B�#INPPBLN,D1ŠLoad�the�length�of�the�IPB�in�bytes�into<ŠMOVE.W�XIOPLN(A2),D5†D5�and�return�a�parameter�block�length4ŠCMP.W‚#4,D5Žerror�if�the�specified�length�is�either6ŠBLO.L‚CMDERR�less�than�four�bytes�or�specifies�an�oddŠBTSTƒ#0,D5Žnumber�of�bytes. ŠBNE.L‚CMDERRŠSPC„2*:*‰New�Register�Assignments�D5�=�Length�of�the�IPB�in�bytes*<ŠMOVE.L�CCBLOGPY(A5),A1†Call�RMS68K�subroutine�LOGPHY,�via�a;ŠMOVE.L�TCBTST(A6),A0†JSR,�to�verify�that�the�specified�IPB0ŠJSR„(A1)�lies�entirely�within�the�address�space3ŠBRA„CMD010�of�the�task�that�issued�the�command.�If**£no�error�is�detected,�control�returns�to)*£the�instruction�following�the�trap�with)*£the�physical�base�address�of�the�IPB�in*£D6.ŠSPC„2)ŠNOP™There�are�two�possible�error�returns:ŠMOVE.B�#INPPBLK,D1ˆfrom�LOGPHY�at�the�trap�return�address8ŠBRA.L‚CMDERR�plus�two�or�four�bytes�respectively.�Since+*£the�errors�are�not�differentiated�here,�a&*£NOP�is�specified�for�the�first�error)*£return.�In�either�case,�an�exit�is�made'*£with�a�parameter�block�address�error.ŠSPC„2=CMD010„MOVE.L�D6,A4�Move�the�physical�base�address�of�the�IPBAŠMOVE.W�XIOPLN(A2),D5†into�A4�and�restore�the�IPB�length�in�D5�as)*£it�was�destroyed�by�the�LOGPHY�routine.ŠPAGE@*‰New�Register�Assignments‚A4�=�Physical�Base�Address�of�the�IPB*CŠCMP.W‚#INOPEN,CMDCOD(A4)ƒIf�the�IPB�command�code�specifies�an�Open9ŠBEQ„CMDFCTCK‹Channels�command,�skip�the�remaining�common*£IPB�validation�steps.ŠSPC„26ŠMOVE.B�#INPPBLN,D1ŠLoad�the�error�code�for�an�invalid(*£parameter�block�length�into�the�return*£status�register.ŠSPC„29ŠCMP.L‚#CMDLEN,D5‹If�the�specified�IPB�length�is�equal�to5ŠBEQ„CMD020�the�standard�length�proceed�with�the�next*£check.ŠSPC„22ŠBHI„CMDERR�If�the�specified�IPB�length�is�greater'*£than�the�standard�length,�exit�with�a*£parameter�block�length�error.ŠSPC„2<ŠCMP.W‚#INCLOS,CMDCOD(A4)‚If�the�IPB�length�is�less�than�the3ŠBNE„CMDERR�standard�length�and�this�is�not�a�Close-*£All�Channels�command,�exit�with�a�parameter*£block�length�error.ŠSPC„29ŠCMP.L‚#CMDLEN-2,D5‰The�only�valid�IPB�length�for�a�Close7ŠBNE„CMDERR�All� Channels�command�is�the�standard�length7ŠBRA„CMDFCTCK‹minus�2�bytes.�For�any�other�length,�exit&*£with�a�parameter�block�length�error.ŠSPCƒ2*G*ƒCheck�the�bit�mask�that�specifies�the�channels�to�be�affected�by�thisN* command for non-existant channel numbers (8-15) and for channel numbers thatN* have not been connected to the requesting task via an Open Channels command.* ACMD020„MOVE.B�#INPUNKWN,D1‰If�the�upper�byte�of�the�channels�mask;ŠTST.B‚CMDCHM(A4)‰word�of�the�IPB�is�non-zero,�exit�with�an)ŠBNE„CMDERR�invalid�channel�number�error.ŠSPC„28ŠMOVE.B�#INPOWNR,D1ŠLoad�the�error�code�for�specifying�a,*£channel�not�owned�by�the�requestor�in�case*£an�error�is�detected.ŠSPC„20ŠCLR.L‚D2“Load�the�least�significant�byte�of�theAŠMOVE.B�CMDCHM+1(A4),D2„channels�mask�word�into�D2.�Move�the�mask2ŠSWAPƒD2‘bits�for�the�non-interrupt�channels�(4-7)8ŠLSR.L‚#4,D2Žinto�the�four�least�significant�bits�of�the-*£upper�word�of�D2�and�move�the�mask�bits�for,*£the�interrupt�channels�(0-3)�into�the�four,*£most�significant�bits�of�the�lower�word�of*£D2.ŠPAGE0ŠTST.W‚D2“If�none�of�the�interrupt�channels�were6ŠBEQ„CMD045�selected�in�the�channels�mask,�skip�to�the(*£checks�for�the�non-interrupt�channels.ŠSPC„2=ŠLEA.L‚CCBICCTE+1(A5),A0„Load�the�end�address�plus�one�of�the**£Interrupt�Channel�Control�Table�into�A0.ŠSPC„2CCMD030„LEA.L‚-ICCENTLN(A0),A0…Update�the�ICCT�index�to�point�to�the-*£entry�for�the�next�lower�numbered�interrupt *£channel.ŠSPC„23ŠLSL.W‚#1,D2�If�the�next�bit�of�the�channel�mask�is5ŠBCC„CMD040�zero,�the�corresponding�interrupt�channel+*£is�not�affected�by�the�current�command�so*£skip�to�the�next�channel.ŠSPC„2=ŠCMP.L‚ICCTCB(A0),A6ˆIf�the�TCB�address�of�the�task�trying�to5ŠBNE„CMDERR�access�the�channel�does�not�match�the�TCB**£address�in�the�Interrupt�Channel�Control**£Entry,�then�the�requested�channel�is�not**£accessible�to�the�requestor�so�exit�with#*£the�previously�loaded�error�code.ŠSPC„27CMD040„TST.W‚D2“Loop�until�all�of�the�mask�bits�for�the1ŠBNE„CMD030�interrupt�channels�have�been�checked.ŠSPC„21CMD045„SWAPƒD2“Move�the�channel�mask�bits�for�the5ŠBEQ„CMDFCTCK‹non-interrupt�channels�into�the�4�least+*£significant�bits�of�the�lower�word�of�D2.+*£If�none�of�the�non-interrupt�channels�are(*£selected,�skip�to�the�command�function *£code�check.ŠSPC„23ŠLEA.L‚CCBNICCT(A5),A0†Load�the�base�address�of�the&*£Non-interrupt�Channel�Control�Table.ŠSPC„27CMD050„LSR.B‚#1,D2�If�the�next�bit�of�the�channels�mask4ŠBCC„CMD060�is�zero,�the�corresponding�non-interrupt+*£channel�is�not�affected�by�the�command�so*£skip�to�the�next�channel.ŠSPC„28ŠCMP.L‚(A0),A6ŽIf�the�TCB�address�of�the�task�attempting4ŠBNE„CMDERR�access�to�the�channel�does�not�match�the**£TCB�address�in�the�Non-interrupt�Channel#*£Control�Entry,�the�channel�is�not+*£accessable�to�the�requesting�task�so�exit(*£with�the�previously�loaded�error�code. ŠPAGE;CMD060„ADD.L‚#4,A0�Update�the�Non-interrupt�Channel�Control4ŠTST.B‚D2‘Table�pointer�to�access�the�next�entry�and2ŠBNE„CMD050�loop�until�all�specified�non-interrupt*£channels�have�been�checked.ŠSPC„2 K*ƒThe�following�code�verifies�that�the�command�code�specified�in�the�IPB�isH*�valid.‚Then�a�JSR�is�made�,�via�the�command�jump�table,�to�the�command* specific handling routine. ACMDFCTCK‚LEA.L‚CMDTBL(PC),A1ˆLoad�the�base�address�of�the�command<ŠMOVE.B�#INPICMD,D1ˆspecific�handling�routine�jump�table�and>ŠMOVE.W�CMDCOD(A4),D2†the�command�code�from�the�IPB.�Also�load&*£the�error�code�to�be�returned�if�the**£specified�command�code�cannot�be�located*£in�the�jump�table.ŠSPC„23ŠMOVE.L�A1,A0�Copy�the�jump�table�base�address�to�a>ŠMOVE.L�#NUMCMD-1,D0‡table�index�register,�load�a�loop�counter4ŠCLR.L‚D3‘to�tell�when�the�end�of�the�jump�table�has+*£been�reached,�and�clear�D3�to�contain�the(*£offset�of�the�command�handling�routine(*£entry�point�relative�to�the�jump�table*£base�address.ŠSPC„2>CMD070„MOVE.W�(A0)+,D3�Load�the�entry�point�offset �of�the�next7ŠCMP.W‚(A0)+,D2‹command�handler�from�the�jump�table�and(*£compare�the�corresponding�command�code*£to�the�code�from�the�IPB.ŠSPC„27ŠDBEQƒD0,CMD070ŒSearch�the�jump�table�until�an�entry�is-*£found�with�a�matching�command�code�or�until"*£the�end�of�the�table�is�reached.ŠSPC„20ŠBNE„CMDERR�If�command�code�from�the�IPB�did�not)*£match�any�entry�in�the�jump�table,�exit(*£with�the�previously�loaded�error�code.ŠSPC„2.ŠCLR.L‚D1“Clear�the�command�status�register�to,*£indicate�that�no�errors�have�been�detected+*£in�the�Common�Command�Processing�Routine.ŠSPC„22ŠJSRƒ0(A1,D3.W)ŒCall�the�appropriate�subroutine�to**£perform�the�specified�command.�The�entry+*£point�offset�obtained�from�the�jump�table'*£is�added�to�the�table�base�address�to$*£determine�the�entry�point�address.ŠPAGEDCMDERR„MOVE.L�CCBCMDST(A5),A7†Restore�the�stack�pointer�to�the�state(*£in�effect�when�the�command�handler�was**£entered.�This�step�is�necessary�only�for**£error�exits�from�nested�subroutines.�For(*£normal�command�exits,�this�instruction**£acts�as�a�NOP�since�the�stack�is�already*£in�the�proper�state.ŠSPC„2=CMDDONEƒMOVE.L�D1,D0�Move�the�command�return�status�to�D0�and@ŠMOVE.W�D0,CMDSTA(A4)†to�the�IPB�status�field�and�return�to�CMR.ŠRTSŠPAGEO*********************************************************************************–Open�Input�Channels�Command*–---------------------------M*ƒThis�subroutine�creates�connections�between�a�task�and�one�or�more�channelsO* on an input module. After a connection is made, the task has exclusive accessN* rights to the associated input channel. The task may then issue any commandsO* to manipulate the channel with the exception of another Open Channels command"* that specifies the same channel.*L*ƒThe�first�function�performed�by�this�routine�is�validation�of�the�contentsJ* of the IPB (command parameter block). After verifying that the number ofN* channels to be opened is in the range 1-8, the minimum acceptable length forK* the specified number of channels is calculated and compared to the actualF* IPB length specified by the user. If the IPB length is less than theN* acceptable minimum, the routine exits with an error. The routine then checksL* the list of channels to be opened for invalid channel numbers (i.e. not inO* the range 0-7) or for channels that are already owned by some task (includingM* the requesting task). If either condition occurs, the routine exits with an* error.*I*ƒAfter�the�IPB�contents�have�been�validated,�the�subroutine�performs�theI* operations necessary to open and initialize the specified channels. ForJ* non-interrupt channels, the only operation necessary is to place the TCBK* address of the requesting task in the Non-interrupt Channel Control TableO* entries for the requested channels. When interrupt channels are being opened,J* the Interrupt Channel Control Table entry for each channel is cleared toL* zeros and initialized using the TCB address of the requesting task and theG* information contained in the Configuration word for each channel. TheI* required initialization of the VME 610/620 module hardware is done in aO* single operation after all channels have been opened rather than by accessing)* the hardware as each channel is opened.*+*‰Entry�Registers�:�D5�=�Command�IPB�length&*›A4�=�Physical�address�of�command�IPB*›A5�=�CCB�address*›A6�=�Requestor's�TCB�address*4*‚General�Register�Usage�:�A0-A2�=�Working�registers4*›A3�=�Base�address�of�list�of�channels�to�be�opened*›D2,D3,D5�=�Working�Registers&*›D4�=�Number�of�channels�to�be�opened/*›D6-D7�=�Used�to�accumulate�miscellaneous�data,*£necessary�to�initialize�interrupt�channels*1*‰Exit�Registers‚:‚D1�=�Command�Completion�Status*œA5�=�CCB�Address*œA6�=�Requestor's�TCB�address**œAll�other�registers�are�preserved�by�CMR*O*******************************************************************************ŠPAGE@OPEN†MOVE.B�#INPMAXCH,D1‰Load�the�error�code�to�be�issued�if�the**£number�of� channels�to�open�is�not�in�the *£range�1-8.ŠSPC„2.ŠCLR.L‚D2“If�the�number�of�channels�to�open�is;ŠMOVE.W�CMDNCO(A4),D2†zero,�exit�with�an�error.�Make�a�copy6ŠMOVE.L�D2,D4Žof�the�number�of�channels�to�open�in�D4. ŠBEQ„CMDERRŠSPC„25ŠCMP.W‚#8,D2�If�the�number�of�channels�to�open�has�an3ŠBHI„CMDERR�unsigned�value�greater�than�eight,�exit*£with�an�error.ŠSPC„22ŠLSL.W‚#2,D2�Multiply�the�number�of�channels�to�be<ŠADD.W‚#CMDLEN,D2‰opened�by�the�length�of�the�data�block�for+*£each�channel�(4�bytes)�and�add�the�length**£of�a�standard�command�parameter�block�to**£determine�the�expected�length�of�the�IPB *£in�process.ŠSPC„2;ŠMOVE.B�#INPPBLN,D1ŠIf�the�actual�length�of�the�IPB�is�less2ŠCMP.L‚D2,D5Žthan�the�expected�length,�exit�with�a5ŠBLO„CMDERR�parameter�block�length�error.�No�error�is'*£returned�if�the�IPB�is�longer�than�is'*£necessary�for�the�specified�number�of *£channels.ŠSPC„29ŠLEA.L‚CMDCHL(A4),A3ˆLoad�the�base�address�of�the�list�of6ŠMOVE.L�A3,A0Žchannels�to�be�opened�into�A3�and�make�a3ŠSUB.W‚#1,D4Žscratch�copy�in�A0.�Load�the�number�of(*£channels�to�open�minus�one�to�use�as�a*£loop�counter.ŠSPC„2/ŠCLR.B‚D6“Clear�the�lower�byte�of�D6�so�that�it)*£can�be�used�to�accumulate�a�mask�of�all*£channels�to�be�opened.ŠSPC„2AOPN010„MOVE.W�OPNCHN(A0),D0ˆLoad�the�next�channel�number�from�the *£list�of�channels�to�be�opened.ŠSPC„2>ŠMOVE.W�#INPUNKWN,D1‰If�the�channel�number�specified�is�not�in2ŠCMP.W‚#7,D0Žthe�range�0-7,�perform�an�error�exit. ŠBHI„CMDERRŠSPC„29ŠMOVE.W�#INPDUPL,D1ŠIf�the�channels�mask�bit�for�the�next6ŠBSETƒD0,D6Žchannel�to�be�opened�is�already�set,�issue6ŠBNE„CMDERR�the�error�for�specifying�duplicate�channel**£numbers.�Otherwise�set�the�channels�mask*£bit�for�the�new�channel.ŠPAGE8ŠMOVE.B�#INPOWNR,D1ŠLoad�the�error�code�for�specifying�a)*£channel�number�that�is�owned�by�another*£task.ŠSPC„2<ŠLEA.L‚CCBICCT(A5),A1‡In�case�the�channel�to�be�opened�is�an=ŠMOVE.W�#ICCENTLN,D3‡interrupt�channel,�load�the�base�address6ŠMULUƒD0,D3Žof�the�Interrupt�Channel�Control�Table�andEŠLEA.L‚ICCTCB(A1,D3.L),A2�load�A2�with�the�address�of�the�TCB�address-*£field�of�the�table�entry�for�the�channel�to *£be�opened.ŠSPC„26ŠCMP.W‚#3,D0�If�the�number�of�the�channel�to�be�opened3ŠBLS„OPN020�is�for�a�interrupt�channel�(range�4-7),)*£we�already�have�the�right�control�table,*£address�and�entry�length�loaded�so�skip�to*£the�table�offset�calculation.ŠSPC„23ŠLEA.L‚CCBNICCT(A5),A1†Load�the�base�address�of�the&*£Non-interrupt�channel�control�table.ŠSPC„26ŠMOVE.W�D0,D3�Subtract�four�from�the�channel�number�to5ŠSUB.W‚#4,D3Žobtain�the�Non-Interrupt�Channel�Control**£Table�entry�number�for�the�channel�being *£opened.ŠSPC„23ŠLSL.L‚#2,D3�Multiply�the�table�entry�number�by�the@ŠLEA.L‚0(A1,D3.L),A2†entry�length�(4�bytes)�and�load�A2�with�the,*£address�of�the�table�entry�for�the�channel*£being�opened.ŠSPC„27OPN020„TST.L‚(A2)‘If�the�owner�TCB�address�field�of�the5ŠBEQ„OPN025�channel�control�entry�is�zero,�proceed�to&*£check�the�next�channel�to�be�opened.ŠSPC„26ŠCMP.L‚(A2),A6ŽIf�the�TCB�address�of�the�channel�owner6ŠBNE„CMDERR�does�not�match�that�of�the�requestor,�exit#*£with�a�requestor�not�owner�error.ŠSPC„2<ŠMOVE.B�#INPAOPN,D1ŠIf�the�task�requesting�the�channel�to�be4ŠBRA„CMDERR�opened�already�owns�the�channel,�issue�a*£channel�already�opened�error.ŠSPC„2ŠMOVE.W�CMDNCO(A4),D4ˆLoad�the�number�of�channels�to�be�opened6ŠSUB.W‚#1,D4Žminus�one�to�serve�as�a�loop�counter.�The)*£base�address�of�the�list�of�channels�to!*£open�is�already�loaded�into�A3.ŠSPC„2BOPN030„MOVE.W�OPNCHN(A3),D0ˆLoad�the�number�of�the�next�channel�to"*£be�opened�from�the�channel�list.ŠSPC„24ŠMOVE.W�D0,D5�Store�the�channel�number�plus�16�in�D58ŠADD.W‚#16,D5�This�value�is�used�to�manipulate�data�bits"*£in�the�upper�words�of�D6�and�D7.ŠSPC„26ŠCMP.W‚#3,D0�If�the�number�of�the�channel�to�be�opened1ŠBLS„OPN040�is�in�the�range�0-3,�branch�to�handle*£opening�an�interrupt�channel.ŠSPC„2G*ƒOpen�a�non-interrupt�channel�and�initialize�the�Non-interrupt�Channel* Control Entry.ŠSPC„25ŠSUB.W‚#4,D0�Subtract�four�from�the�channel�number�to**£obtain�the�Non-interrupt�Channel�Control+*£Table�entry�for�the�channel�being�opened.ŠPAGE?ŠLEA.L‚CCBNICCT(A5),A1†Since�the�channel�to�be�opened�is�a�non-(*£interrupt�channel�(4-7),�load�the�base&*£address�of�the�Non-interrupt�Channel*£Control�Table.ŠSPC„27ŠMOVE.W�D0,D3�Multiply�the�channel�number�by�the�length7ŠLSL.W‚#2,D3Žof�a�Non-interrupt�Control�Entry�(4�bytes)@ŠMOVE.L�A6,0(A1,D3.L)†to�determine�the�offset�for�the�channel�to)*£be�opened.�Store�the�TCB�address�of�the,*£requesting�task�in�the�table�entry�to�open*£the�channel.ŠSPC„23ŠBRA„OPN100�Branch�to�the�end�of�the�loop�to�set-up$*£for�the�next�channel�to�be�opened.ŠSPC„2H*ƒOpen�an�interrupt�channel�and�initialize�the�Interrupt�Channel�Control* Entry.ŠSPC„2EOPN040„LEA.L‚CCBICCT(A5),A1‡Load�the�base�address�and�entry�length�of9ŠMOVE.W�#ICCENTLN,D3‡the�Interrupt�Channel�Control�Table.ŠSPC„2/ŠBSETƒD5,D6�Since�an�interrupt�channel�is�to�be(*£opened,�set�the�appropriate�bit�in�the**£upper�word�of�D6�(mask�of�channels�to�be *£opened).ŠSPC„24ŠMULUƒD0,D3�Multiply�the�number�of�the�channel�to�be=ŠLEA.L‚0(A1,D3.L),A1†opened�by�the�table�entry�length�to�find'*£the�table�entry�offset.�Load�the�base*£address�of�the�entry�into�A1.ŠSPC„2F*ƒInitialize�the�Interrupt�Channel�Control�Entry�for�the�channel�to�be * opened.ŠSPC„26ŠMOVE.L�A1,A0�Initialize�the�Interrupt�Channel�Control(ŠMOVE.W�#ICCENTLN,D1‡Entry�to�all�zeros.OPN050„CLR.B‚(A0)+ŠDBRAƒD1,OPN050ŠSPC„29ŠLEA.L‚DBTOBKG(PC),A0‹Load�the�entry�point�address�of�theAŠMOVE.L�A0,ICCBAB+BABPTR(A1)ƒBackground�Debounce�Time-out�Handler(*§and�store�it�in�the�Activation�Address(*§field�of�the�Interrupt�Channel�Control *§Entry�BAB.ŠPAGE>ŠMOVE.L�CCBBKGST(A5),ICCBKGST(A1)‚Store�the�JSR�address�of�the%*©background�scheduler�routine�in�the%*©ICCT�entry�for�use�by�the�Interrupt*©Debounce�Timeout�Handler.ŠSPC„2=ŠMOVE.L�A6,ICCTCB(A1)ˆStore�the�TCB�address�of�the�requesting-*£task�in�the�entry�to�mark�the�channel�open.ŠSPC„28ŠMOVE.L�A5,ICCB(A1)ŠStore�the�CCB�address�in�the�control&*£entry.�This�is�necessary�because�the)*£Background�Debounce�Timeout�Handler�has+*£only�the�address�of�the�Interrupt�Channel)*£Control�Entry�when  �it�begins�execution.ŠSPC„2;ŠMOVE.B�D0,ICCNUM(A1)ˆStore�the�number�of�the�channel�being**£opened�in�the�entry.�This�information�is(*£also�needed�by�the�Background�Debounce*£Timeout�Handler.ŠSPC„2;ŠMOVE.W�OPNCFG(A3),D1ˆIf�bit�7�of�the�Channel�Configuration2ŠBPL„OPN060�word�clear,�branch�to�process�the�user*£specified�configuration.ŠSPC„2=ŠMOVE.W�#DEFLTCFG,D1‰Since�bit�7�of�the�Channel�Configuration**£word�was�set,�the�user�wishes�to�use�the)*£default�configuration.�Load�the�default)*£configuration�word�for�processing�as�if*£it�had�been�user�specified.ŠSPC„2:OPN060„LSR.W‚#2,D1�Ignore�bit�0�of�the�configuration�word.0ŠBCS„OPN070�If�the�Interrupt�Control�bit�says�to,*£disable�interrupts�(bit�set),�no�action�is'*£necessary�since�interrupts�are�always-*£disabled�prior�to�opening�a�channel�and�the(*£Interrupts�Enabled�flag�in�the�channel!*£control�entry�is�already�clear.ŠSPC„27ŠST…ICCENABL(A1)‰Set�the�Interrupts�Enabled�flag�in�the-ŠBSETƒD0,D7Žchannel�control�entry�and�set�the-*£bit�in�the�Interrupt�Control�register�image-*£in�D7�that�corresponds�to�the�number�of�the*£channel�being�opened.ŠSPC„2:OPN070„LSR.W‚#1,D1�If�interrupts�are�to�occur�on�energized3ŠBCC„OPN080�to�deenergized�transitions,�the�ICCEDGE,*£flag�in�the�control�entry�is�already�clear**£and�the�appropriate�bit�of�the�Interrupt'*£Sense�Control�register�image�in�D6�is*£already�clear.ŠPAGE0ŠST…ICCEDGE(A1)ŠSince�interrupts�are�to�occur�on5ŠBSETƒD0,D6Ždeenergized�to�energized�transitions,�set+*£the�ICCEGDE�flag�in�the�control�entry�and,*£set�the�bit�of�the�Interrupt�Sense�Control**£register�image�in�D6�that�corresponds�to)*£the�number�of�the�channel�being�opened.ŠSPC„2:OPN080„LSR.W‚#1,D1�If�interrupt�notification�is�to�be�made/ŠBCS„OPN090�via�a�WAKEUP�request�to�RMS68K,�the'*£ICCQEVNT�flag�in�the�control�entry�is*£already�clear.ŠSPC„26ŠST…ICCQEVNT(A1)‰Since�interrupt�notifiaction�is�to�be)*£made�via�a�event�sent�to�the�requestors'*£ASQ,�the�ICCQEVNT�flag�in�the�control*£entry�is�set.ŠSPC„2:OPN090„BCLRƒD5,D7�Clear�the�appropriate�bit�of�the�channel+*£type�mask�in�the�upper�word�of�D7�in�case,*£no�software�debounce�is�to�be�performed�on*£the�channel.5ŠLSR.W‚#4,D1�Skip�bits�4-7�of�the�configuration�word.ŠSPC„25ŠLSL.W‚#2,D1�Multiply�the�debounce�interval�length�by2ŠBEQ„OPN100�four�to�determine�the�number�of�milli-)*£seconds�per�debounce�interval�and�store)*£the�result�in�the�control�entry.�If�the&*£interval�length�is�zero,�no�software-*£debounce�is�to�be�performed�on�the�channel.ŠSPC„2?ŠMOVE.W�D1,ICCDBINT(A1)†Store�the�debounce�interval�length�into1ŠBSETƒD5,D7Žthe�channel�control�entry�and�set�the**£appropriate�bit�of�the�channel�type�mask**£in�the�upper�word�of�D7�to�indicate�that!*£the�channel�is�to�be�debounced.ŠSPC„2>OPN100„ADD.L‚#OPNCDB,A3‹Adjust�the�pointer�in�A3�to�select�the:ŠDBRAƒD4,OPN030Šnext�entry�in�the�list�of�channels�to�open+*£and�loop�until�all�list�entries�have�been *£processed.ŠPAGE!*�[**********�WARNING�**********] G*ƒThe�following�section�of�code�performs�hardware�setup,�clears�pendingI* interrupts on all channels being opened and then enables queuing of newO* interrupts by the Foreground Interrupt Handler. This code is HIGHLY interruptI* sensitive. The sequence of operations given below is CRITICAL to assureK* that newly opened interrupt channels are initialized properly and withoutO* side effects. NOTE that interrupts must not be disabled anywhere in this codeJ* since the Foreground Interrupt Handler must execute to clear any pending * interrupts.ŠSPC„2>ŠMOVE.L�CCBCHB(A5),A0ˆLoad�the�base,�memory-mapped�I/O�address'*£of�the�input�module�hardware�into�A0.ŠSPC„24ŠMOVE.B�D6,D0�Copy�the�hardware�interrupt�sense�bits3ŠLSL.B‚#4,D0Žfrom�bits�0-3�of�D6�to�bits�4-7�of�D0.ŠSPC„22ŠSWAPƒD6“Copy�the�mask�of�interrupt�channels�being3ŠOR.BƒD6,D0Žopened�by�the�current�command�from�bits *£16-19�of�D6�to�bits�0-3�of�D0.ŠSPC„2ŠOR.BƒD0,CCBINTCR(A5)!ŠMOV  E.B�CCBINTCR(A5),INPICNTR(A0))*¥OR�the�value�in�bits�0-7�of�D0�with�the+*£hardware�interrupt�control�register�image+*£in�the�CCB�and�move�the�image�to�the�real-*£hardware�register.�Bits�4-7�of�D0�configure&*£the�interrupt�sense�bits�for�the�new-*£channels�as�specified�by�the�user.�Bits�0-3**£of�D0�enable�interrupts�for�the�channels,*£being�opened.�Thus�any�interrupts�that�are,*£pending�(whether�pre-existing�or�caused�by(*£initialization�of�the�sense�bits)�will(*£occur.�Any�such�interrupts�will�not�be**£placed�in�the�Interrupt�Processing�Queue%*£by�the�Foreground�Interrupt�Handler(*£because�interrupt�queueing�for�the�new)*£channels�is�disabled�by�the�bit�mask�in *£CCBIQENA.ŠPAGE?ŠEOR.B‚D6,CCBINTCR(A5)†EOR�the�mask�of�interrupt�channels�being,*£opened�with�the�hardware�interrupt�control**£register�image�to�force�interrupts�to�be**£disabled�for�the�new�channels.�Note�that**£although�the�register�image�is�not�moved**£to�the�hardware�until�after�execution�of+*£the�next�instruction,�no�damage�can�occur*£if�an�interrupt�occurs�here.ŠSPC„27ŠOR.BƒD7,CCBINTCR(A5)�Set�the�state�of�interrupts�(i.e.>ŠMOVE.B�CCBINTCR(A5),INPICNTR(A0)�enabled/disabled)�on�the�new*ªchannels�as�specified�by�the&*ªcommand.�The�bits�are�changed�in�the!*ªcontrol�register�image�and�then*ªmoved�to�the�actual�hardware!*ªregister.�Note�that�queueing�of&*ªinterrupts�is�still�disabled�for�the*ªnew�channels.ŠSPC„2+ŠSWAPƒD7“OR�the�channel�type�bits�from�bits?ŠOR.BƒD7,CCBCHTYP(A5)„16-19�of�D7�into�the�channel�type�mask�in(*£the�CCB.�This�step�must�be�done�before**£the�interrupt�queues�are�enabled�so�that**£no�interrupts�are�discarded�prematurely.ŠSPC„2?ŠOR.BƒD6,CCBIQENA(A5)†OR�the�mask�of�channels�to�be�opened�into-*£the�Interrupt�Queue�Enable�mask�in�the�CCB.+*£The�enabling�of�the�interrupt�queues�must$*£be�the�last�step�to�assure�that�no,*£undesired�interrupts�are�queued.�This�also-*£serves�to�simultaneously�"arm"�all�channels*£opened�in�the�same�command.ŠSPC„29*‰[**********�END�OF�INTERRUPT�SENSITIVE�CODE�**********]ŠSPC„2K*ƒAt�this�point,�Open�Channels�command�processing�has�been�completed�and�noK* errors were detected so a return is made to the Common Command Processing * Routine.ŠSPC„29OPNRTN„CLR.L‚D1“Set�D1�to�zero�to�indicate�that�no�errors+ŠRTS—were�detected�and�return�to�the�Common*£Command�Processing�Routine.ŠPAGEO********************************************************************************(*‘Close�All�or�Selected�Channels�Command(*‘--------------------------------------*L*ƒThis�routine�closes�previously�established�connections�between�a�user�taskJ* and one or more channels of an input module. If the user has specified aJ* non-zero mask of channels to close, only those selected channels will beJ* affected by the command. If the channel mask is zero or the IPB does notK* contain a channel mask, all channels currently attached to the requesting* task are closed.*G*ƒNon-interrupt�channels�are�closed�by�simply�clearing�the�owning�tasksF* TCB address from the Non-Interrupt Channel Control Table entry. WhenF* interrupt channels with software debounce are closed, interrupts areJ* disabled and any debounce operations in progress are canceled before theH* owners TCB address is cleared from the Interrupt Channel Control TableK* entry. Non-debounce interrupt channels are closed by disabling interruptsH* and clearing the owners TCB address from the ICCT entry. Also, when anL* interrupt channel is closed, whether debounce or non-debounce, queueing ofK* interrupts for the channel is disabled and the channel type bit is set toL* zero so that a new channel type may be ORed in if the channel is reopened.*=*�Entry�registers�:�D5�=�Input�Command�Parameter�Block�length,*¢A4�=�Input�Command�Parameter�Block�address*¢A5�=�CCB�address*¢A6�=�Requestors�TCB�address*%*�Register�Usage‚:�D0�=�Work�Register*¢D3�=�Work�Register�(CLSINTCH)*¢D4�=�Work�Register�(CL  SINTCH) *¢D7�=�Mask�of�channels�to�close*¢A0�=�Work�Register*¢A1�=�Work�Register*7*�Exit�Registers‚:�Entry�registers�and�unused�registers+*¢preserved.�All�other�registers�destroyed.*O*******************************************************************************ŠPAGEBCLOSE…MOVE.B�#%11111111,D7ˆLoad�a�channel�mask�of�all�ones�in�case%*£the�user�task�wants�all�of�its�open*£channels�closed.ŠSPC„24ŠCMP.W‚#CMDLEN,D5‹If�the�IPB�length�is�less�than�the0ŠBNE„CLS010�standard�length,�this�is�a�close�all**£channels�command�so�use�the�channel�mask*£already�loaded�in�D7.ŠSPC„2<ŠMOVE.B�CMDCHM+1(A4),D0†If�the�specified�mask�of�channels�to5ŠBEQ„CLS010�close�is�zero,�process�as�for�a�close�all*£channels�command.ŠSPC„26ŠMOVE.B�D0,D7�Move�the�user�specified�mask�of�channels*£to�close�into�D7.ŠSPC„2L*ƒPerform�close�operations�for�non-interrupt�channels�in�order�of�decreasing* channel number.ŠSPC„2FCLS010„LEA.L‚CCBNICCE+1(A5),A1„Load�the�ending�address�plus�one�of�the8ŠMOVE.L�#4-1,D0ŒNon-interrupt�Channel�Control�Table�into)*£an�index�register�and�initialize�a�loop *£counter.ŠSPC„29CLS020„SUB.L‚#4,A1�Adjust�the�table�index�to�the�previous*£table�entry.ŠSPC„24ŠLSL.B‚#1,D7�If�the�channel�mask�bit�for�the�current5ŠBCC„CLS030�channel�number�is�clear,�skip�to�the�next *£channel.ŠSPC„25ŠCMP.L‚(A1),A6ŽIf�the�TCB�address�of�the�requestor�is6ŠBNE„CLS030�not�the�same�as�that�of�the�task�that�owns(*£the�channel,�skip�to�the�next�channel.$*£This�condition�can�only�occur�when**£processing�a�close�all�channels�command.ŠSPC„2/ŠCLR.L‚(A1)‘Clear�the�owners�TCB�address�in�the+*£Non-interrupt�Channel�Control�Table�entry*£to�close�the�channel.ŠSPC„2;CLS030„DBRAƒD0,CLS020ŒLoop�until�all�non-interrupt�channels*£have�been�processed.ŠPAGE9ŠMOVE.L�CCBGUARD(A5),A1†The�necessary�processing�to�close=ŠLEA.L‚CLSINTCH(PC),A0„interrupt�channels�is�performed�from�a.ŠJSR„(A1)�guarded�subroutine.�Since�background&*£activity�will�be�suspended�while�the%*£subroutine�executes,�each�interrupt#*£channel�is�shutdown�in�a�neat�and)*£orderly�fashion.�The�guarded�subroutine"*£is�entered�via�a�call�to�RMS68K.ŠSPC„2+ŠRTS™After�all�requested�channels�have�been&*£closed,�return�to�the�Common�Command*£Processing�RoutineŠPAGEO********************************************************************************-*�Close�Interrupt�Channels�Guarded�Subroutine-*�-------------------------------------------*H*ƒThis�subroutine�is�executed�by�RMS68K�in�Guarded�Mode.�Guarded�Mode�isL* used when operations are to be performed (i.e. modification of shared dataI* structures) that are sensitive to "concurrent" background activity as aD* result of an interrupt. While the guarded subroutine executes, newL* background processes may be scheduled but their execution is held pending.*I*ƒWithin�the�environment�of�this�driver,�Guarded�Mode�blocks�execution�ofL* the Background Interrupt Handler, Background Debounce Timeout Handler, andI* the Background Channel Shutdown Handler. Since Close command processingG* affects several data structures that are accessed by these backgroundF* routines, the guarded subroutine guarantees mutual exclusion without5* requiring interrupts to be masked at the processor.*J*‚This�routine�disables�queueing�of�interrupts,�disables�interrupts�at�theH* VME 160/620 module, and cancels any pending debounce operations on the* channels being closed.*<*�Entry�Registers�:�D7�=�Mask�of�interrupt�channels�to�close*§(bits�4-7�only)*¢A5�=�CCB�address*¢A6�=�Requestors�TCB�address*.*�Register�usage‚:�D3�=�Current�channel�number!*¢D4�=�Current�channel�number�+�4)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�entry�address*=*�Exit�Registers‚:�A5,�A6,�and�all�unused�registers�preserved *¢All�other�registers�destroyed.*N******************************************************************************ŠPAGEFCLSINTCH‚MOVE.L�CCBCHB(A5),A0ˆLoad�the�memory-mapped�input�module�base   *£address.ŠSPC„2=ŠLEA.L‚CCBICCTE+1(A5),A1„Load�the�end�address�plus�one�of�the"*£Interrupt�Channel�Control�Table.ŠSPC„21ŠMOVE.B�#3,D3�Processing�will�be�done�in�order�of5ŠMOVE.B�#3+4,D4Œdecreasing�channel�number�so�load�the)*£starting�channel�number�into�D3�and�the,*£starting�channel�number�plus�four�into�D4.ŠSPC„2FCLI010„LEA.L‚-ICCENTLN(A1),A1…Update�the�table�index�to�the�ICCT�entry&*£for�the�next�lower�numbered�channel.ŠSPC„24ŠLSL.B‚#1,D7�If�the�current�bit�of�the�channels�mask/ŠBCC„CLI030�is�clear,�skip�to�the�next�channel.ŠSPC„2;ŠCMP.L‚ICCTCB(A1),A6ˆIf�the�TCB�address�of�the�requestor�is6ŠBNE„CLI030�not�the�same�as�that�of�the�channel�owner,**£skip�to�the�next�channel.�This�condition,*£can�occur�only�when�processing�a�Close�All*£Channels�command.ŠSPC„2<ŠBCLRƒD3,CCBIQENA(A5)†Disable�queueing�of�interrupts�for�the*£channel�being�closed.ŠSPC„2:ŠBCLRƒD4,CCBINTCR(A5)†Clear�the�sense�bit�in�the�interrupt)*£control�register�image�that�corresponds(*£to�the�channel�being�closed.�This�will**£allow�a�new�sense�bit�setting�to�be�ORed"*£in�when�the�channel�is�reopened.ŠSPC„28ŠBCLRƒD3,CCBCHTYP(A5)†Clear�the�channel�type�bit�for�the)*£channel�being�closed.�This�will�allow�a(*£new�channel�type�setting�to�be�ORed�in*£when�the�channel�is�reopened.ŠSPC„28ŠBSR.L‚DBCANCLŽCall�DBCANCL�to�disable�interrupts�on�the(*£channel�being�closed�and�to�cancel�any,*£pending�software�debounce�processing.�Note**£that�the�called�routine�is�automatically**£guarded�since�it�is�called�from�within�a*£guarded�subroutine.ŠSPC„2;ŠCLR.L‚ICCTCB(A1)‹Clear�the�owners�TCB�address�field�of�the"*£ICCT�entry�to�close�the�channel.ŠSPC„24CLI030„SUB.B‚#1,D3�Prepare�to�process�the�next�lower(ŠSUB.B‚#1,D4Žnumbered�interrupt�channel.ŠSPC„21ŠTST.B‚D7“Loop�until�all�interrupt�channels�to�be'ŠBNE„CLI010�closed�have�been�processed.ŠSPC„2$ŠRTS™Return�to�the�non-guarded�close*£processing�routine.ŠPAGEO********************************************************************************.*�Enable�Interrupts�Command�Processing�Routine.*�--------------------------------------------*E*…This�enables�interrupts�on�one�or�more�channels�as�specified�by�theI* requesting task. If any of the specified channels are already interruptI* enabled a warning code is returned to the user in D0 and in the commandI* parameter block but interrupts are still enabled on the other requestedG* channels. First, queueing of interrupts is disabled for the specifiedL* channels. Next interrupts are enabled on the input module hardware so thatJ* any pending interrupts will occur and be discarded. Finally, queueing ofJ* interrupts on the selected channels is reenabled. Due to restrictions inL* the VME 610/620 module hardware, interrupt conditions occuring on disabledM* channels may or may not still be pending when interrupts are later enabled.M* Since the status of pending interrupts is not predictable prior to enablingH* of interrupts, pending interrupts are cleared to put each channel in a* known state.*>*�Entry�Registers�:�A4�=�Input�Command�Parameter�Block�address*¢A5�=�CCB�address*%*�Register�usage‚:�D0�=�Work�Register+*¢D1�=�Command�status�(warning�code�if�any)!*¢D6�=�Mask�of�channels�to�enable!*¢D7�=�Mask�of�channels�to�enable)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�entry�address*7*�Exit�Registers‚:�Entry�registers�and�unused�registers(*¢are�preserved.�All�other�registers�are *¢destroyed.*O*******************************************************************************ŠPAGE9ENABIN„BSR.L‚EIDICHKŽCall�EIDICHK�to�validate�the�mask�of)*£channels�to�be�enabled�and�to�load�data*£into�various�registers.**£On�return�:�D1�=�Destroyed*¯D6�=�Enable�Channels�Mask*¯D7�=�Enable�Channels�Mask*¯A0�=�Memory-mapped�channel*´base�address*¯A1�=�ICCT�base�addressŠSPC„2F*ƒThe�following�code�looks�for�channels�specified�in�the�mask�that�areK* already interrupt   enabled. If any such channels are found, a warning codeH* is loaded into D1 and the corresponding channel mask bits are cleared.ŠSPC„2:ENA010„LSR.B‚#1,D7�If�the�mask�bit�for�the�current�channel/ŠBCC„ENA030�is�clear,�skip�to�the�next�channel.ŠSPC„29ŠTST.B‚ICCENABL(A1)‰Test�the�interrupt�enable�flag�in�the9ŠST…ICCENABL(A1)‡ICCT�entry�and�then�set�the�flag.�If�the3ŠBEQ„ENA030�flag�was�previously�clear,�proceed�with*£the�next�channel.ŠSPC„2=ŠMOVE.B�ICCNUM(A1),D0ˆSince�interrupts�are�already�enabled�on7ŠBCLRƒD0,D6Žthe�current�channel,�force�the�mask�bit�for<ŠMOVE.B�#INPINTR,D1ˆthe�channel�to�zero�and�load�the�warning*£code�into�D1.ŠSPC„2BENA030„LEA.L‚ICCENTLN(A1),A1†Update�the�index�register�to�the�ICCT4ŠTST.B‚D7‘entry�for�the�next�higher�numbered�channel5ŠBNE„ENA010�and�loop�until�all�the�requested�channels*£have�been�checked.ŠSPC„2J*ƒThe�following�code�clears�pending�interrupts�and�then�enables�interruptsI* on the requested channels that were disabled when the request was made.ŠSPC„2=ŠEOR.B‚D6,CCBIQENA(A5)†Disable�queueing�of�interrupts�for�the*£channels�to�be�enabled.ŠSPC„28ŠOR.BƒD6,CCBINTCR(A5)�Enable�interrupts�on�the�requestedEŠMOVE.B�CCBINTCR(A5),INPICNTR(A0)�channels.�Any�pending�interrupts�on#ŠNOPžthe�channels�will�occur�and�be)ŠNOPždiscarded.�The�NOPs�are�necessary�to%ŠNOPžallow�time�for�this�interrupt�to*ªoccur.ŠSPC„2;ŠOR.BƒD6,CCBIQENA(A5)†Enable�queueing�of�interrupts�for�the"*£channels�that�were�just�enabled.ŠPAGE,ŠRTS™Return�to�the�Common�Command�Processing+*£Routine�with�either�a�no�error�or�warning*£status�in�D1.ŠPAGEO********************************************************************************/*�Disable�Interrupts�Command�Processing�Routine/*�---------------------------------------------*J*ƒThis�routine�disables�interrupts�on�one�or�more�channels�as�specified�byL* the requesting task. The routine verifies that only interrupt channels areN* specified in the channels mask. If any of the channels specified are alreadyI* interrupt disabled, a warning code is returned in D0 and in the commandJ* parameter block but interrupts are still disabled on the other requestedH* channels. The remainder of the processing to disable interrupts on theO* channels is performed from within a guarded subroutine so that all background* activity is suspended.*>*�Entry�Registers�:�A4�=�Input�Command�Parameter�Block�address*¢A5�=�CCB�address*%*�Register�usage‚:�D0�=�Work�Register+*¢D1�=�Command�status�(warning�code�if�any)!*¢D6�=�Mask�of�channels�to�enable!*¢D7�=�Mask�of�channels�to�enable)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�entry�address*7*�Exit�Registers‚:�Entry�registers�and�unused�registers(*¢are�preserved.�All�other�registers�are *¢destroyed.*O*******************************************************************************ŠPAGE7DSABIN„BSR„EIDICHKŽCall�EIDICHK�to�validate�the�mask�of**£channels�to�be�disabled�and�to�load�data*£into�various�registers.**£On�return�:�D1�=�Destroyed*¯D6�=�Disable�Channels�Mask*¯D7�=�Disable�Channels�Mask*¯A0�=�Memory-mapped�channel*´base�address*¯A1�=�ICCT�base�addressŠSPC„2;DSA010„LSR.B‚#1,D7�If�the�disable�channels�mask�bit�for�the6ŠBCC„DSA030�current�channel�is�clear,�skip�to�the�next *£channel.ŠSPC„2:ŠTST.B‚ICCENABL(A1)‰If�interrupts�are�currently�enabled�on2ŠBNE„DSA030�the�channel,�proceed�to�check�the�next *£channel.ŠSPC„29ŠMOVE.B�ICCNUM(A1),D0ˆClear�the�channels�mask�bit�for�the1ŠBCLRƒD0,D6Žalready�disabled�channel�and�load�the)ŠMOVE.B�#INPINTR,D1ˆwarning�code�into�D1.ŠSPC„2CDSA030„LEA.L‚ICCENTLN(A1),A1†Update�the�index�to�the�ICCT�entry�for3ŠTST.B‚D7‘the�next�higher�numbered�channel�and�loop2ŠBNE„DSA010�until�all�requested�channels�have�been *£checked.ŠSPC„2?ŠMOVE.L�CCBGUARD(A5),A1†The�remainder�of�the�disable�interrupts<ŠLEA.L‚GDSABLE(PC),A0…processing�is�performed�from�a�guarded0ŠJSR„(A1)�subrouti  ne�which�is�called�via�RMS68K.ŠSPC„2,ŠRTS™Return�to�the�Common�Command�Processing *£Routine.ŠPAGEO********************************************************************************'*•Guarded�Disable�Interrupts�Subroutine'*•-------------------------------------*H*ƒThis�subroutine�is�executed�by�RMS68K�in�Guarded�Mode.�Guarded�Mode�isL* used when operations are to be performed (i.e. modification of shared dataI* structures) that are sensitive to "concurrent" background activity as aD* result of an interrupt. While the guarded subroutine executes, newL* background processes may be scheduled but their execution is held pending.*I*ƒWithin�the�environment�of�this�driver,�Guarded�Mode�blocks�execution�ofL* the Background Interrupt Handler, Background Debounce Timeout Handler, andH* the Background Channel Shutdown Handler. Since this subroutine affectsI* several data structures that are accessed by these background routines,F* the guarded subroutine guarantees mutual exclusion without requiring+* interrupts to be masked at the processor.*H*ƒThe�function�of�this�routine�is�to�disable�interrupts�on�the�currentlyN* enabled channels that were specified by the requesting task and to terminateB* pending software debounce operations, if any, on these channels.*>*�Entry�registers�:�D6�=�Mask�of�channels�to�interrupt�disable*¢A5�=�CCB�address*¢A6�=�Requestors�TCB�address*.*�Register�usage‚:�D3�=�Current�channel�number)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�entry�address*;*�Exit�registers‚:�All�entry�registers�and�unused�registers&*¢(except�D6)�are�preserved.�All�other*¢registers�are�destroyed.*O*******************************************************************************ŠPAGEDGDSABLEƒMOVE.L�CCBCHB(A5),A0ˆLoad�the�memory-mapped�channel�base�and,ŠLEA.L‚CCBICCT(A5),A1…the�ICCT�base�address.ŠSPC„2:GDS010„LSR.B‚#1,D6�If�the�mask�bit�for�the�current�channel/ŠBCC„GDS020�is�clear,�skip�to�the�next�channel.ŠSPC„29ŠSF…ICCENABL(A1)‰Clear�the�Interrupts�Enabled�flag�in�the-*£ICCT�entry�to�indicate�that�interrupts�were-*£disabled�at�the�request�of�the�owning�task.ŠSPC„2;ŠMOVE.B�ICCNUM(A1),D3ˆLoad�the�channel�number�from�the�ICCT5ŠBSR„DBCANCLŒentry�for�the�channel�to�be�disabled�and(*£call�DBCANCL�to�disable�interrupts�and,*£to�terminate�any�pending�software�debounce)*£activity�on�the�channel.�Note�that�this+*£subroutine�executes�in�Guarded�Mode�since)*£it�is�called�from�a�guarded�subroutine.ŠSPC„2CGDS020„LEA.L‚ICCENTLN(A1),A1†Update�the�index�to�the�ICCT�entry�for3ŠTST.B‚D6‘the�next�higher�numbered�channel�and�loop2ŠBNE„GDS010�until�all�requested�channels�have�been *£processed.ŠSPC„2&ŠRTS™Return�to�the�non-guarded�Disable(*£Interrupts�Command�processing�routine.ŠPAGEO********************************************************************************>*‰Read�Current�Input�Channel�Status�Command�Processing�Routine>*‰------------------------------------------------------------*H*ƒThis�routine�reads�the�current�status�of�all�eight�input�channels�of�aL* VME 610/620 module and returns the results to the user in the Channel MaskI* field of the Input Command Parameter Block. All bits that correspond toG* channels specified in the channels mask are returned as read from the1* hardware and all other bits are forced to zero.*>*‰Entry�registers�:‚A4�=�Input�Command�Parameter�Block�address*œA5�=�CCB�address*D*‰Register�usage‚:‚D0�=�VME�610/620�Channel�Status�register�contents)*œA0�=�Memory-mapped�channel�base�address*?*‰Exit�registers‚:‚D1�=�Command�Status�Code�(zero�for�no�error)-*œAll�entry�registers�or�unused�registers�are *�preserved.*O*******************************************************************************ŠPAGEBSTATUS„MOVE.L�CCBCHB(A5),A0ˆLoad�the�memory-mapped�base�address�of*£the�input�module�hardware.ŠSPC„2=ŠMOVE.B�INPCSTAT(A0),D0†Read�the�current�input�channel�status  ,*£from�the�hardware�Channel�Status�register.ŠSPC„2>ŠAND.B‚D0,CMDCHM+1(A4)†And�the�current�channel�status�into�the(*£channels�mask�in�the�command�parameter)*£block�to�clear�status�bits�for�channels*£that�were�not�requested.ŠSPC„25ŠMOVE.L�#0,D1�Return�to�the�Common�Command�Processing*ŠRTS—routine�with�a�no-error�status�in�D1.ŠPAGEO********************************************************************************>*‰Enable/Disable�Interrupts�Channel�Mask�Validation�Subroutine>*‰------------------------------------------------------------*J*„This�routine�checks�the�channels�mask�specified�for�an�Enable�or�DisableI* Interrupts Command to make sure that none of the non-interrupt channelsN* are specified. If any such channels are specified an error exit is made withL* an error code in D1. The routine then loads the memory-mapped channel baseK* address and the Interrupt Channel Control Table base address and returns.*>*�Entry�registers�:�A4�=�Input�Command�Parameter�Block�address*¢A5�=�CCB�address*!*�Exit�registers‚:�D0�=�destroyed*¢D1�=�Command�Status�Code)*¢D6�=�Mask�of�channels�to�enable/disable)*¢D7�=�Mask�of�channels�to�enable/disable)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�base�address*$*¢All�other�registers�are�preserved.*O*******************************************************************************ŠPAGEDEIDICHKƒMOVE.B�CMDCHM+1(A4),D7†Load�the�channels�mask�from�the�Input6ŠMOVE.B�D7,D6ŽCommand�Parameter�Block�into�D7�and�make*£a�copy�in�D6ŠSPC„26ŠMOVE.L�#INPICHN,D1ŠIf�the�channels�mask�specifies�any>ŠMOVE.B�#%11110000,D0†non-interrupt�channels�(4-7)�exit�to�the6ŠAND.B‚D7,D0Žcommon�command�handler�with�an�error�codeŠBNE.L‚CMDERR�in�D1.ŠSPC„29ŠMOVE.L�CCBCHB(A5),A0ˆLoad�the�memory-mapped�channel�baseAŠLEA.L‚CCBICCT(A5),A1…address�into�A0�and�the�base�address�of�the**£Interrupt�Channel�Control�Table�into�A1.ŠSPC„22ŠMOVE.L�#0,D1�Return�to�the�calling�routine�with�aŠRTS—no�error�status�in�D1.ŠPAGEO********************************************************************************-*�Interrupt�Disable�and�Debounce�Cancellation*œGuarded�Subroutine-*�-------------------------------------------*H*ƒThis�subroutine�is�executed�by�RMS68K�in�Guarded�Mode.�Guarded�Mode�isL* used when operations are to be performed (i.e. modification of shared dataI* structures) that are sensitive to "concurrent" background activity as aD* result of an interrupt. While the guarded subroutine executes, newL* background processes may be scheduled but their execution is held pending.*I*ƒWithin�the�environment�of�this�driver,�Guarded�Mode�blocks�execution�ofL* the Background Interrupt Handler, Background Debounce Timeout Handler, andH* the Background Channel Shutdown Handler. Since this subroutine affectsI* several data structures that are accessed by these background routines,F* the guarded subroutine guarantees mutual exclusion without requiring+* interrupts to be masked at the processor.*H*ƒThe�function�of�this�routine�is�to�disable�interrupts�on�the�interruptD* channel specified in D3 on entry and to terminate pending debounce$* operations on the channel, if any.*:*�Entry�Registers�:�D3�=�Number�of�interrupt�channel�to�be *§processed.)*¢A0�=�Memory-mapped�channel�base�address*¢A1�=�ICCT�entry�address*¢A5�=�CCB�address*)*�Register�Usage‚:�D0-D2�=�Work�registers*3*�Exit�registers‚:�All�registers�preserved�on�exit.*O*******************************************************************************ŠPAGEDDBCANCLƒMOVEM.L�D0-D2/A0,-(A7)†Save�all�registers�used�on�the�stack.ŠSPC„20ŠBCLRƒD3,CCBINTCR(A5)�Disable�interrupts�for�theDŠMOVE.B�CCBINTCR(A5),INPICNTR(A0)�specified�channel�in�the�Interrupt!*ªControl�Register�image�and�move%*ªthe�image�to�the�hardware�register.ŠSPC„2;ŠTST.B‚ICCDBACT(A1)‰If�no�software�debounce�operation�is�in2ŠBEQ„DBC010�process�on�the�specified�channel,�exit*£from�the�subroutine.ŠSPC„29ŠCLR.B‚ICCDBACT(A1)‰Clear�the�Debounce�Act  ive�flag�in�the,*£ICCT�entry�so�that�the�Background�Debounce-*£Timeout�Handler�will�know�that�the�debounce*£operation�was�canceled.ŠSPC„2CANRQPAƒEQU„$8000:ŠMOVE.W�#CANRQPA,D1ŠLoad�the�option�to�cancel�a�previously5ŠMOVE.L�A1,D2Žrequested�executive�periodic�activation+*£and�specify�the�Activation�ID�as�the�ICCT*£entry�address.ŠSPC„26ŠMOVE.L�CCBRQPA(A5),A0‡Attempt�to�cancel�the�requested4ŠJSR„(A0)�activation�of�the�Interrupt�Level�Debounce-ŠNOP—Timeout�Handler.�If�an�error�occurs,�the)*£activation�has�already�occurred�and�the(*£Background�Debounce�Timeout�Handler�is)*£scheduled�to�execute�as�soon�as�command)*£processing�exits�Guarded�Mode.�However,'*£the�background�routine�will�terminate)*£when�it�sees�that�the�Background�Active*£flag�has�been�clearedŠSPC„2DDBC010„MOVEM.L�(A7)+,D0-D2/A0†Restore�the�entry�registers�and�returnŠRTS—to�the�calling�routine.ŠPAGEO********************************************************************************«”6�¥!­5µ/½'Å,Í/Õ2Ý,å7í/õ0ý21 !/1%-&54=,E1M2U*] *šBackground�Interrupt�Handler*š----------------------------*G*ƒThis�routine�is�called�by�the�RMS68K�Background�Process�Dispatcher�atO* processor interrupt mask level zero after it has been scheduled for executionG* by the Foreground Interrupt Handler. The Foreground Interrupt HandlerN* attempts to schedule this routine after each interrupt event has been placedM* in the Interrupt Processing Queue. However, if multiple scheduling requestsF* are made using the same Background Activation Block (BAB) before theN* background process has been dispatched, the process will be scheduled on the* first request only.*L*ƒUpon�entry�to�this�routine,�A1�contains�the�address�of�the�activating�BAB.F* The contents of all other address and data registers, except A7, areJ* considered to be undefined. Since the activating BAB is contained in theO* Interrupt Queue Control Table, the base address of the table is easily found.:* The routine then enters the queue entry processing loop.*H*ƒWe�first�check�for�an�empty�queue�by�testing�for�equality�of�the�queueN* input and output offsets. This check is made with a single instruction so itI* is not vulnerable to an interrupt that would cause the output offset toM* change. This empty queue check must be performed the first time through theG* loop since it is possible for this background routine to be activatedM* when the queue is empty. This condition occurs if the background process isK* in execution and an interrupt occurs that places a new interrupt entry inM* the queue. The new interrupt causes the background routine to scheduled forM* execution even though it is already executing. Since the current invocationO* of the process will empty the queue before terminating, the second invocationO* will start execution with no queue entries to process. This is an unavoidableL* side effect of assuring that whenever at least one interrupt entry exists,N* the Background Interrupt Handler is either already executing or is scheduledL* for execution so that interrupt entry processing is guaranteed before task* level execution can resume.*J*ƒWhen�the�interrupt�queue�is�non-empty,�the�oldest�entry�(as�indicated�byM* the queue output offset) is retrieved and processed. The entry contains theK* CCB address of the VME 610/620 module that interrupted, a bit mask of theI* interrupting input channels, and the contents of the RMS68K Time-of-DayK* clock at the time of the interrupt. The queue output offset is updated to%* access the next oldest queue entry.*L*ƒThe�interrupting�channels�mask,�obtained�from�the�queue�entry,�are�checkedJ* in order of decreasing channel number. For each channel with a interruptO* the corresponding Interrupt Channel Control Table entry in the C  CB is checked5* to determine how the interrupt should be processed.*E*ƒIf�the�interrupting�channel�is�not�software�debounced,�an�immediateM* interrupt notification is made to the owning task via either Queue Event orL* Wakeup as specified in the channel configuration word when the channel was * opened.ŠPAGEJ*ƒFor�a�software�debounce�channel,�interrupts�for�the�channel�have�alreadyM* been disabled on the VME 610/620 board by the Foreground Interrupt Handler.K* A debounce timeout interval is determined from the elapsed time since theL* occurrance of the interrupt and the user specified debounce period. If theJ* specified debounce period has not already passed, the Interrupt DebounceL* Timeout Handler is scheduled for execution at the appropriate time. If theO* specified debounce period has already expired, the routine clears any pendingE* interrupts on the channel, enables interrupts, and issues interrupt"* notification to the owning task.*M*ƒWhen�all�of�the�interrupting�channels�mask�bits�obtained�from�the�interruptL* queue entry have been processed, the next entry is obtained from the queueM* and the process is repeated. When there are no more entries in the queue toJ* process, the Background Interrupt Handler terminates by returning to the'* RMS68K Background Process Dispatcher.*;*�Entry�registers�:‚A1�=�Address�of�Interrupt�Queue�Control *¨Table�BAB*6*�Register�Usage‚:‚D1�=�Channel�Number�Being�Processed$*£D3�=�Input�Module�Channel�Mnemonic!*£D4�=�Interrupt�Queue�Entry�Time$*£D7�=�Mask�of�Interrupting�Channels*£A2�=�CCB�address*£A3�=�ICCT�entry�address,*£A6�=�Interrupt�Queue�Control�Table�Address*:*�Exit�registers‚:‚All�registers�are�saved/restored�by�the&*£RMS68K�Background�Process�Dispatcher*O*******************************************************************************ŠPAGE DBACKGRND‚LEA.L‚-QBAB(A1),A6‰Load�the�Interrupt�Control�Table�Address*£into�an�address�register.ŠSPC„2L*ƒCheck�for�an�empty�interrupt�queue�by�comparing�the�queue�input�and�outputI*�offsets.‚This�check�is�performed�via�a�memory-to-memory�compare�so�that * interrupts need not be masked. EBCK000„LEA.L‚QINOFST(A6),A0‡If�the�queue�input�and�output�offsets�are<ŠCMP.W‚(A0)+,(A0)+ˆnot�equal,�there�is�at�least�one�entry�in7ŠBNE„BCK005�the�queue�so�proceed�to�the�interrupt�queue,ŠRTS—entry�processing�loop.�If�the�input�and(*£output�offsets�are�equal,�the�queue�is+*£empty�so�the�Background�Interrupt�Handler**£returns�control�to�the�RMS68K�Background*£Process�Dispatcher.ŠSPC„21*‚Read�the�oldest�entry�from�the�interrupt�queue. BBCK005„MOVE.W�QOUTOFST(A6),D0†Load�the�queue�output�offset�and�the9ŠMOVE.L�QPTR(A6),A0ˆqueue�base�address�from�the�Interrupt*£Queue�Control�Table.ŠSPC„2?ŠMOVEM.L�0(A0,D0.W),D4/D7/A2‚Pull�the�entry�from�the�queue�into*£working�registers�as�follows:**¦A2�=�CCB�address�of�interrupting�channel(*¦D4�=�Time�of�interrupt�occurrance�(mS)#*«(D4�is�used�so�that�bytes�8-11�of!*¬an�interrupt�notification�event*¬are�pre-staged�in�the�proper$*¬register�when�EXQEVNTI�is�called.)$*¦D7�=�Mask�of�Interrupting�Channels%*«(�Only�bits�0-4�of�D7�contain�valid!*­data.�It�is�placed�in�the�queue *­as�a�long�word�so�that�a�MOVEM*­instruction�can�be�used�to *­minimize�queuing�and�dequeuing*­time.)ŠSPC„2;ŠADD.W‚#IQENTLN,D0ŠUpdate�the�queue�output�offset�to�access>ŠAND.W‚QWAMSK(A6),D0†the�next�oldest�queue�entry�by�adding�the?ŠMOVE.W�D0,QOUTOFST(A6)„queue�entry�length�and�force�wraparound,*£from�the�end�of�the�queue�to�the�beginning+*£if�necessary.�Since�the�length,�in�bytes,+*£of�both�the�interrupt�queue�and�the�queue,*£entry�are�powers�of�two,�wraparound�to�the(*£beginning�of�the�queue�is�performed�by,*£logically�ANDing�the�queue�length�-�1�with*£the�queue�output�offset.ŠPAGE=ŠMOVE.L�CCBMNEM(A2),D3‡Load�the�input�module�channel�mnemonic)*£into�D3�in�case�a�Queue�Event�interrupt**£notification�must�be�sent�to�a�task.�The (*£channel�mnemonic�occupies�bytes�4-7�of)*£the�interrupt�notification�event.�Since**£D3�must�contain�event�bytes�4-7�on�entry)*£to�the�EXQEVNTI�routine,�the�last�eight**£bytes�of�an�interrupt�notification�event*£are�pre-staged�in�D3�and�D4.ŠSPC„2J*‚Start�processing�of�the�interruping�channels�mask�bits�obtained�from�theN* interrupt queue entry. The channels will be processed in order of decreasing)* channel number starting with channel 3. =ŠLEA.L‚CCBICCTE+1(A2),A3„Load�the�end�address�plus�one�of�the9ŠMOVE.L�#3,D1ŽInterrupt�Queue�Control�Table�and�the�first!*£channel�number�to�be�processed.ŠSPC„2FBCK010„LEA.L‚-ICCENTLN(A3),A3…Update�the�ICCT�entry�index�to�reference'*£the�entry�for�the�next�lower�numbered *£channel.ŠSPC„21ŠBCLRƒD1,D7�Test�and�clear�the�status�bit�for�the6ŠBEQ.L‚BCK050�current�channel.�If�the�status�was�zero,)*£no�interrupt�occurred�so�proceed�to�the*£next�channel.ŠSPC„2I*ƒSince�the�interrupt�status�bit�for�the�current�channel�is�set,�there�isK* an interrupt to process. In the event that the interrupt occurred and wasK* queued while a Close Channels or Disable Interrupts command was executingK* in Guarded Mode (i.e. background processing was blocked), the channel forH* which the interrupt was queued may already be closed or interrupts mayM* already be disabled when the Background Interrupt Handler begins execution.L* Therefore, before proceeding with interrupt processing, it is necessary toG* assure that the channel is currently open and interrupts are enabled.K* Otherwise it would be possible for one or more interrupt notifications toO* be sent to a task AFTER a Close or Disable Interrupts command for the channel!* had been sucessfully completed. 9ŠTST.L‚ICCTCB(A3)‹If�the�TCB�address�of�the�channel�owner6ŠBEQ„BCK050�in�the�ICCT�entry�is�zero,�the�channel�has'*£been�closed�so�discard�the�interrupt.ŠSPC„2;ŠTST.B‚ICCENABL(A3)‰If�interrupts�have�been�disabled�on�the+ŠBEQ„BCK050�channel,�discard�the�interrupt.ŠSPC„2 6ŠMOVE.L�#0,D6�If�the�user�specified�debounce�period�is?ŠMOVE.W�ICCDBINT(A3),D6„zero,�the�channel�is�not�to�be�software1ŠBEQ„BCK040�debounced�so�proceed�to�the�interrupt*£notification�step.ŠPAGEM*ƒAn�interrupt�has�been�received�on�a�channel�that�is�configured�for�softwareL* debounce. Since the user specified debounce period is to be timed from theO* occurrance of the interrupt, the time that has elapsed since the occurrance oK* the interrupt is calculated to determine if the debounce period should beJ* shortened or if the required debounce period has already expired. In theO* latter case, the interrupt is processed immediately. Otherwise, processing ofG* the interrupt is deferred until required debounce period has expired. K*ƒThe�line�of�code‚'MOVE.L�TIMEOD,D5'‚had�to�be�replaced�because�the�TIMEODL* parameter has been eliminated in the new Periodic Activation mechanism forN*�VERSAdos�4.4.‚A�call�is�now�made�to�the�RMS68K�RDTIMER�routine�to�obtain�the* current time-of-day. ;ŠMOVEM.L�D0-D1/A0,-(A7)„Save�the�registers�used�by�RDTIMER.;ŠMOVE.L�CCBRDTIM(A2),A0„Get�the�RMS68K�address�for�RDTIMER,0ŠJSR„(A0)�and�go�obtain�the�current�time-of-day.*(*ƒThe�registers�returned�by�RDTIMER�are:%*…D0.L�=�timer�contents�(not�needed).G*…D1.L�=�time-of-day�expressed�in�milliseconds�since�midnight�(TIMEOD).*4ŠMOVE.L�D1,D5ŽSave�time-of-day�as�per�original�code.:ŠMOVEM.L�(A7)+,D0-D1/A0„Restore�registers�used�by�RDTIMER.*>*ƒEnd�of�replacement�code�for‚'MOVE.L�TIMEOD,D5'‚***�10/25/84.*1ŠSUB.L‚D4,D5ŽCalculate�the�elapsed�time�since�the6ŠBPL„BCK030�occurrance�of�the�interrupt�by�reading�the)*£current�value�of�the�RMS68K�time-of-day**£clock�and�subtracting�the�interrupt�time)*£that�was�obtained�from�the�queue�entry.-*£If�the�result�is�positive,�there�is�no�need)*£to�adjust�for�midnight�crossover�of�the*£time-of-day�clock.ŠSPC„2>MSPERDAY‚EQU„24*60*60*1000ˆIf�the�interrupt�occurs�just�before?ŠADD.L‚#MSPERDAY,D5‡midnight�and�pro cessing�of�the�interrupt�is(*£delayed�until�just�after�midnight,�the**£interrupt�time�value�will�be�larger�than,*£the�time-of-day�clock�value�so�the�elapsed(*£time�calculation�will�yield�a�negative%*£result.�The�correct�elapsed�time�is(*£obtained�by�adding�the�total�number�of*£milliseconds�in�a�day.ŠSPC„27BCK030„SUB.W‚D5,D6�Subtract�the�calculated�elapsed�time1ŠBGT„BCK035�from�the�requested�debounce�period�to&*£obtain�the�adjusted�debounce�period.,*£If�the�adjusted�debounce�period�is�greater)*£than�zero,�setup�for�a�debounce�timeout&*£interrupt�at�the�end�of�the�adjusted(*£period.�Note�that�a�16-bit�subtract�is+*£permissable�here�because�it�is�impossible**£for�the�elapsed�time�since�the�interrupt)*£occurred�to�exceed�32,767�milliseconds.ŠPAGEL*ƒControl�reaches�here�when�the�adjusted�debounce�period�is�zero�or�negativeM* meaning that the requested debounce period has expired. Any such interruptsM* are processed in the same way as those that are processed by the BackgroundL* Debounce Timeout Handler. First, any pending interrupts on the channel areO* cleared, channel interrupts are enabled, and the current state of the channelK* (Energized/Deenergized) is checked for consistency with the channel stateN* transition that caused the interrupt. If the current state of the channel isL* inconsistent, the interrupt is assumed to be spurious and is discarded. IfK* the current state is consistent, an interrupt notification is sent to the* task that owns the channel. =ŠMOVE.L�CCBCHB(A2),A0ˆLoad�the�memory-mapped�I/O�base�address!*£of�the�610/620�module�hardware.ŠSPC„2;ŠBCLRƒD1,CCBIQENA(A2)†Disable�queueing�of�new�interrupts�on)*£the�channel�by�the�Foreground�Interrupt *£Handler.ŠSPC„29ŠBSETƒD1,CCBINTCR(A2)ŒEnable�interrupts�on�the�channel�atBŠMOVE.B�CCBINTCR(A2),INPICNTR(A0)�the�610/620�module�hardware.�Any(ŠNOPžpending�interrupt�will�occur�and�be(ŠNOPždiscarded�because�interrupt�queuing&ŠNOPžhas�been�disabled�on�the�channel."*ªThe�NOP's�allow�time�for�the�I/O&*ªchannel�interrupt�hardware�to�act�on*ªthe�interrupt.ŠSPC„2:ŠBSETƒD1,CCBIQENA(A2)†Enable�queueing�of�interrupts�on�the,*£channel�now�that�any�pending�interrupt�has*£been�cleared.ŠSPC„28ŠMOVE.B�INPCSTAT(A0),D0†If�the�current�channel�status�isAŠMOVE.B�ICCEDGE(A3),D2…inconsistent�with�the�interrupt�generating7ŠEOR.B‚D2,D0Žtransition,�discard�the�interrupt�assuming4ŠBTSTƒD1,D0Žit�to�be�spurious�and�proceed�to�process0ŠBNE„BCK050�the�next�lower�numbered�channel.�The-*£interrupt�generating�'edge'�flag�meaning�is**£described�in�the�ICCT�equates.�Since�the(*£current�channel�status�is�a�one�if�the$*£channel�is�energized�and�a�zero�if-*£deenergized,�an�exclusive�OR�of�the�channel-*£status�bit�and�the�corresponding�bit�in�the,*£'edge'�flag�always�yields�either�zero�when**£the�interrupt�is�valid�or�a�one�when�the*£interrupt�is�spurious.ŠSPC„23ŠBRA„BCK040�Since�the�current�status�of�the�channel-*£is�consistent�with�the�interrupt�generating-*£transition,�issue�an�interrupt�notification*£to�the�owning�task.ŠPAGEI*‚When�the�adjusted�debounce�period�is�greater�than�zero,�we�must�issue�aJ* request to RMS68K for a 'timer interrupt' at the end of the period. ThisO* 'timer interrupt' causes execution of the Interrupt Debounce Timeout Handler.E* The RMS68K routine EXRQPA is called to setup the 'timer interrupt'. ?BCK035„ST…ICCDBACT(A3)‰Set�a�flag�in�the�ICCT�entry�to�indicate,*£that�debounce�operations�are�active�on�the *£channel.ŠSPC„2@ŠMOVE.L�D4,ICCDBST(A3)‡Save�the�time�of�interrupt�ocurrance�from-*£the�interrupt�queue�entry�into�the�debounce,*£period�start�time�field�of�the�ICCT�entry.ŠSPC„2M*ƒSetup�the�registers�necessary�for�the�EXRQPA�routine�to�schedule�activationO* of the Interrupt Debounce Timeout Handler at the end of the adjusted debounce* timeout period. 1ŠMOVE.W�D1,-(A7)�Save�D1�on�the�stack�since�it�is"*£destroyed�by�the�call�to�EXRQPA.ŠSPC„2?ŠMOVE.B�CCBPPRIO(A2),D1†Se t�the�timeout�routine�to�execute�at�a-*£processor�interrupt�mask�level�that�matches-*£the�hardware�interrupt�level�of�the�channel*£being�debounced.ŠSPC„25ŠMOVE.L�A3,D2�Set�the�Activation�ID�to�the�ICCT�entry*£address�for�the�channel.ŠSPC„20ŠMOVE.L�D6,A1�Set�the�Activation�Interval�to�the*£adjusted�debounce�period.ŠSPC„2:ŠLEA.L‚DBTIMOUT(PC),A0†Load�the�entry�point�address�of�the?ŠMOVE.L�CCBRQPA(A2),A4…Interrupt�Debounce�Timeout�Handler.�Load/ŠJSR„(A4)�the�entry�point�address�of�the�EXRQPA7ŠBRA.S‚BCK037�routine�from�the�CCB�and�call�the�routine *£via�a�JSR.ŠSPC„25RQPAERRƒNOP™This�error�return�should�never�be�reached**£under�normal�operating�conditions.�If�an'*£error�does�occur�for�some�reason,�the(*£channel�will�'lockup'�until�a�Close�or,*£a�Disable�Interrupts�command�is�issued�for*£the�channel.ŠSPC„2>BCK037„MOVE.W�(A7)+,D1�Restore�D1�and�proceed�to�processing�ofŠBRA„BCK050�the�next�channel.ŠPAGEL*ƒControl�reaches�here�when�an�interrupt�notification�is�to�be�issued�to�theJ* owner of the channel. The Interrupt Notification subroutine is called toH* issue either a Wakeup or a Queue Event to the task as specified in the9* channel configuration word when the channel was opened. :BCK040„MOVE.L�#0,D2�Issue�an�interrupt�notification�to�the7ŠBSR„NOTFYINT‹owning�task.�If�an�event�is�to�be�sent�to+*£the�task,�set�the�event�status�to�zero�to*£indicate�'no�error'.ŠSPC„2J*ƒInterrupt�processing�for�the�current�channel�is�completed,�so�proceed�toL* process the next lower numbered channel. If all interrupting channels fromG* the interrupt queue entry have been processed, return to the start ofH* the interrupt queue entry processing loop to obtain a new queue entry. 7BCK050„TST.B‚D7“Loop�until�all�interrupting�channels�in1ŠDBEQƒD1,BCK010Šthe�current�queue�entry�have�been *£processed.ŠSPC„22ŠBRA.L‚BCK000�Return�to�the�start�of�the�interrupt-*£queue�entry�processing�loop�to�obtain�a�new*£queue�entry.ŠPAGEO********************************************************************************#*“Interrupt�Notification�Subroutine#*“---------------------------------K*ƒThis�subroutine�is�called�when�an�interrupt�notification�is�to�be�sent�toL* the owner of a particular channel. The TCB address of the channel owner isI*�obtained�from�the�ICCT�entry.‚The�notification�mode�is�specified�by�theO* owning task to be either a Wakeup of the task or an event queued to the task.*C*ƒIf�an�event�is�to�be�sent,�the�format�of�the�event�is�as�follows:* *˜Event�length�(12�bytes)�(byte)*˜Event�Code�($01)”(byte)*˜Event�Status˜(byte)**˜Interrupting�Input�Channel�Numberƒ(byte)(*˜Mnemonic�of�610/620�module�that…(long)#*šcontains�the�interrupting�channel$*˜Time�of�Interrupt�Occurance‰(long)*K* The twelve data bytes of the event must be in registers D2, D3, and D4 onI* entry the RMS68K EXQEVNTI routine. D3 and D4 are already setup with theL* proper data on entry to this subroutine, so the only register that must beI*�setup�is�D2.‚All�of�the�entry�registers�to�this�routine,�except�D2,�areG* preserved when the subroutine exits. All other registers are probably-* probably destroyed by the EXQEVNTI routine.*K*ƒIf�a�Wakeup�is�issued�to�the�task,�all�entry�registers�are�preserved�when* the subroutine exits.*?*ƒAlternate�entry�points:�NOTQEVNT�-�Queue�an�event�to�the�task'*›NOTWAKUP�-�Issue�a�Wakeup�to�the�task*9*�Entry�Registers�:�D1.W�=�Number�of�interrupting�channel*¢D2ƒ=�Interrupt�event�status$*¢D3ƒ=�Input�Module�Channel�Mnemonic#*¢D4ƒ=�Time�of�interrupt�occurrance&*¢D7.W�=�Mask�of�interrupting�channels*¢A2ƒ=�CCB�address*¢A3ƒ=�ICCT�entry�address*7*�Exit�registers‚:�D1.W,D3,D4,D7.W,A2,A3,A6,�and�A7�are-*¢preserved.�All�other�registers�are�probably *¢destroyed.*O*******************************************************************************ŠPAGE?NOTFYINT‚TST.B‚ICCQEVNT(A3)‰If�no�event�is�to�be�queued�for�the6ŠBEQ„N OTWAKUP‹interrupt,�branch�to�the�Wakeup�routine.ŠSPC„2"* Interrupt Notification via Event :NOTQEVNT‚MOVE.L�A3,-(A7)�Save�entry�registers�that�will�be8ŠMOVE.W�D1,-(A7)‹destroyed�by�the�call�to�EXQEVNT.�Since8ŠMOVE.W�D7,-(A7)‹vital�data�is�contained�only�in�the�low-*£order�words�of�the�data�registers,�the�high+*£order�word�of�each�register�is�allowed�to*£be�destroyed�by�EXQEVNT.ŠSPC„2?ŠMOVE.L�ICCTCB(A3),A0ˆLoad�the�TCB�address�of�the�channel�owner*£from�the�ICCT�entry.ŠSPC„2:EVNTHDRƒEQU„$0C010000ŒThis�equate�defines�the�event�length&*£(12�bytes)�and�the�event�code�($01).ŠSPC„21ŠLSL.W‚#8,D2�Load�the�event�code�and�event�length6ŠOR.BƒD1,D2Žheader�into�the�upper�word�of�D2.�Load�the;ŠOR.Lƒ#EVNTHDR,D2ˆevent�status�and�the�interrupting�channel#*£number�into�the�lower�word�of�D2.ŠSPC„2;ŠMOVE.L�CCBQEVNT(A2),A4†Load�the�entry�point�address�of�the2ŠJSR„(A4)�RMS68K�EXQEVNTI�routine�from�the�CCB�and'ŠBRA„NOT010�call�the�routine�via�a�JSR.ŠSPC„25NOTQUERƒNOP™This�error�return�should�only�be�executed *£in�one�of�the�following�cases:**¨Task�does�not�exist*¨Task�has�no�ASQ�allocated*¨The�tasks�ASQ�is�disabled*¨The�tasks�ASQ�is�full+*£Since�there�is�no�single�action�that�will)*£adequately�cover�all�of�these�cases�and+*£the�cases�cannot�be�differentiated�with�a)*£single�error�return,�there�is�no�choice-*£other�than�ignoring�the�error.�Note�that�if+*£owning�task�no�longer�exists,�there�is�no-*£way�for�another�task�to�takeover�use�of�the *£channel.ŠSPC„2@NOT010„MOVE.W�(A7)+,D7�Restore�the�values�of�the�entry�registers8ŠMOVE.W�(A7)+,D1‹that�were�destroyed.�Only�the�low�order:ŠMOVE.L�(A7)+,A3‹words�of�the�data�registers�are�restored.ŠSPC„2#ŠRTS™Return�to�the�calling�routine.ŠPAGE#* Interrupt Notification via Wakeup ANOTWAKUP‚MOVE.L�ICCTCB(A3),A0ˆLoad�the�TCB�address�of�the�channel*£owner�from�the�ICCT�entry.ŠSPC„2;ŠMOVE.L�CCBWAKUP(A2),A4†Load�the�entry�point�address�of�the0ŠJSR„(A4)�EXWAKEUP�routine�from�the�CCB�and�call!ŠBRA„NOT020�the�routine�via�a�JSRŠSPC„22NOTWAKER‚NOP™The�only�time�this�error�routine�will&*£ever�be�used�is�when�the�owning�task(*£no�longer�exists.�As�was�mentioned�for-*£queue�event�notification,�if�this�condition**£occurs�the�channel�becomes�inaccessable.ŠSPC„2)NOT020„RTS™Return�to�the�calling�routine.ŠPAGEO********************************************************************************$*”Interrupt�Debounce�Timeout�Handler$*”----------------------------------*K*ƒThis�routine�executes�as�a�result�of�the�EXRQPA�request�made�to�RMS68K�byL* the Background Interrupt Handler for a 'timer interrupt' at the end of theM* adjusted debounce period. On entry to this routine, the processor interruptJ* mask is set to the hardware interrupt level of the input channel that isM* being debounced. Since there is no need to perform the remaining processingN* for the channel with interrupts masked, this routine schedules activation ofM* the Background Debounce Timeout Handler to perform the remaining processingI* at processor interrupt mask level zero. After scheduling the background4* routine this routine returns to RMS68K via an RTE.*<*�Entry�registers�:‚D0�=�Number�of�activation�intervals�that"*¨have�passed�since�activation�was%*¨scheduled.�(This�information�is�not*¨used�in�this�routine.)+*£D1�=�Address�of�Interrupt�Channel�Control'*¨Table�entry�BAB�for�the�channel�being *¨debounced.*>*�Exit�Registers‚:‚All�registers�preserved�by�the�RMS68K�timer*£interrupt�handler.*O*******************************************************************************ŠPAGE?DBTIMOUT‚MOVE.L�D1,A0�Load�the�ICCT�entry�Background�Activation**£Block�address�into�A0.�This�BAB�contains+*£the�entry�point�address�of�the�Background*£Debounce�Timeout�Handler.ŠSPC„2;ŠMOVE.L�ICCBKGST(A0),A1†Load�the�entry�point�address�of�the2ŠJSR„(A1)�RMS68K�Background�Process�Scheduler�from)*£the�ICCT�entry�and�call�the�routine�via*£a�JSR.ŠSPC„2.ŠRTE™Ret urn�to�RMS68K�timer�interrupt�handler.ŠPAGEO********************************************************************************%*”Background�Debounce�Timeout�Handler%*”-----------------------------------*J*ƒThis�routine�performs�post-debounce�processing�of�interrupts�on�softwareJ* debounced input channels. It executes as an RMS68K background process atI* processor interrupt mask level 0 after being scheduled by the Interrupt* Debounce Timeout Handler.*M*‚The�function�of�this�routine�is�to�clear�pending�interrupts�on�the�channel,N* enable interrupts on the channel, and issue an interrupt notification to theN* owning task if the current state of the input channel is consistent with theO* channel state transition that generated the initial interrupt. If the currentG* state is inconsistent, the interrupt is assumed to be spurious and isH* discarded. After processing is completed on the debounced channel, the>* routine returns to the RMS68K Background Process Dispatcher.*=*�Entry�Registers‚:�A1�=�Address�of�the�ICCT�entry�Background(*¨Activation�Block�for�the�channel�being$*¨debounced.�This�is�the�same�as�the*¨ICCT�entry�base�address.*6*�Register�usageƒ:�D1�=�Channel�number�being�processed$*£D3�=�Input�Module�Channel�mnemonic)*£D4�=�Time�of�interrupt�that�started�the*¨debounce�operation.*£A2�=�CCB�address*£A3�=�ICCT�entry�address*=*�Exit�registersƒ:�All�registers�saved/restored�by�the�RMS68K&*£Background�Process�Dispatch�routine.*O*******************************************************************************ŠPAGE8DBTOBKGƒMOVE.L�A1,A3�Save�the�ICCT�entry�base�address�in&*£the�address�register�required�by�the*£NOTFYINT�subroutine.ŠSPC„2M*ƒIn�the�event�that�this�background�routine�was�scheduled�for�execution�whileN* a Close Channels or Disable Interrupts command was executing in Guarded ModeJ* (i.e. background processing was blocked), the channel for which debounceK* processing was to be completed may have already been closed or interruptsJ* may have been disabled prior to execution of this routine. Therefore, itM* is necessary to assure that the channel is currently open and that debounceL* processing on the channel is still active. Otherwise, it would be possibleM* for an interrupt notification to be sent to a task AFTER a Close or DisableE* Interrupts command for the channel had been successfully completed. 7ŠTST.L‚ICCTCB(A3)‹If�the�owners�TCB�address�in�the�ICCT6ŠBEQ„DBTRTN�entry�is�zero,�the�channel�has�been�closed*£so�discard�the�interrupt.ŠSPC„2:ŠTST.B‚ICCDBACT(A3)‰If�the�debounce�cycle�was�canceled�via5ŠBEQ„DBTRTN�a�Disable�Interrupts�command,�discard�the *£interrupt.ŠSPC„29ŠCLR.B‚ICCDBACT(A3)‰Clear�the�debounce�active�flag�in�the *£ICCT�entry.ŠSPC„2=ŠMOVE.L�ICCB(A3),A2ŠLoad�the�CCB�address�for�the�channel�from*£the�ICCT�entry.ŠSPC„2=ŠMOVE.L�CCBCHB(A2),A0ˆLoad�the�input�module�memory-mapped�I/O*£base�address.ŠSPC„2:ŠMOVE.B�ICCNUM(A3),D1ˆLoad�the�number�of�the�channel�being *£processed�from�the�ICCT�entry.ŠSPC„2:ŠBCLRƒD1,CCBIQENA(A2)†Disable�queuing�of�interrupts�on�the%*£channel�by�the�Foreground�Interrupt *£Handler.ŠSPC„26ŠBSETƒD1,CCBINTCR(A2)�Enable�interrupts�on�the�channelEŠMOVE.B�CCBINTCR(A2),INPICNTR(A0)�at�the�610/620�module�hardware.�Any(ŠNOPžpending�interrupt�will�occur�and�be(ŠNOPždiscarded�because�interrupt�queuing&ŠNOPžhas�been�disabled�on�the�channel.!*ªThe�NOPs�allow�time�for�the�I/O#*ªChannel�interrupt�hardware�to�act*ªon�the�interrupt.ŠPAGE9ŠBSETƒD1,CCBIQENA(A2)†Enable�queuing�of�interrupts�on�the,*£channel�now�that�any�pending�interrupt�has*£been�cleared.ŠSPC„28ŠMOVE.B�INPCSTAT(A0),D0†If�the�current�channel�status�isAŠMOVE.B�ICCEDGE(A3),D2…inconsistent�with�the�interrupt�generating7ŠEOR.B‚D2,D0Žtransition,�discard�the�interrupt�assuming4ŠBTSTƒD1,D0Žit�to�be�spurious�and�proceed�to�process0ŠBNE„DBTRTN�the�next�lower�numbered�channel.�The-*£interrupt�generating�'edge'�flag�meaning�is **£described�in�the�ICCT�equates.�Since�the(*£current�channel�status�is�a�one�if�the$*£channel�is�energized�and�a�zero�if-*£deenergized,�an�exclusive�OR�of�the�channel-*£status�bit�and�the�corresponding�bit�in�the,*£'edge'�flag�always�yields�either�zero�when**£the�interrupt�is�valid�or�a�one�when�the*£interrupt�is�spurious.ŠSPC„2=ŠMOVE.L�CCBMNEM(A2),D3‡Load�the�input�module�channel�mnemonic?ŠMOVE.L�ICCDBST(A3),D4…from�the�CCB�and�the�time�of�the�initial(*£interrupt�from�the�debounce�start�time+*£field�of�the�ICCT�entry.�These�values�are)*£loaded�to�prepare�to�issue�an�interrupt"*£notification�event�if�necessary.ŠSPC„24ŠMOVE.L�#0,D2�Issue�an�interrupt�notification�to�the7ŠBSR„NOTFYINT‹owning�task.�If�an�event�is�to�be�sent�to**£the�task�set�the�event�status�to�zero�to*£indicate�'no�error'.ŠSPC„22DBTRTN„RTS™Return�to�the�RMS68K�Background�Process *£Dispatcher.ŠPAGEO********************************************************************************%*�Background�Channel�Shutdown�Handler%*�-----------------------------------*F*ƒThis�background�routine�is�scheduled�for�execution�by�the�ForegroundI* Interrupt Handler when an incoming interrupt could not be placed in theL* Interrupt Processing Queue because the queue was full. When this conditionK* occurs, the Foreground Interrupt Handler disables interrupts on the inputK* channels that could not be processed and sets a mask of shutdown channelsK* in the CCB so that this routine can issue a Channel Shutdown NotificationL* to the owners of the affected channels. A Channel Shutdown Notification isL* an event that is sent to the owning tasks ASQ. The format of this event isL* the same as that for an Interrupt Notification Event except that the eventI* status is $FF and the time of interrupt occurrance is always zero. ThisN* special event informs the owning task that interrupt queue overflow occurredK* resulting in the loss of one or more interrupts on the channel. The eventN* also informs the task that the driver has disabled interrupts on the channel*J*ƒWhen�the�interrupt�notification�method�for�a�channel�is�via�a�Wakeup,�noM* Shutdown Notification is sent since a Wakeup sent as a result of a shutdownO* is indistinguishable from one sent as a result of an interrupt. If a shutdownF* occurs for a Wakeup channel, the task owning the channel will become?* permanently locked-up when it issues the next Wait directive.*H*ƒSince�this�background�routine�is�only�scheduled�for�execution�when�theG* interrupt queue is full, the Background Interrupt Handler will alwaysH* be scheduled or already in execution. Therefore this routine will onlyF* execute after the interrupt queue has been emptied by the BackgroundL* Interrupt Handler. This assures that the owning task will recieve shutdownJ* notification for a channel only after notification has been received forD* all interrupts that were queued for the channel prior to shutdown.*9*�Entry�registers�:‚A1�=�Address�of�the�BAB�in�the�device#*¨dependent�portion�of�the�CCB�that*¨activated�this�routine.*6*�Register�usageƒ:�D1�=�Channel�number�being�processed$*£D3�=�Input�Module�Channel�mnemonic)*£D4�=�Time�of�interrupt�that�started�the*¨debounce�operation. *£D7�=�Mask�of�shutdown�channels*£A2�=�CCB�address*£A3�=�ICCT�entry�address*:*�Exit�registersƒ:�All�registers�are�saved/restored�by�the-*£RMS68K�Background�Process�Dispatch�routine.*O*******************************************************************************ŠPAGE?DOWNCHAN‚LEA.L‚-CCBBAB(A1),A2‡Calculate�the�CCB�address�for�the-*£shutdown�channel(s)�from�the�BAB�address�in*£A1�on�entry�to�this�routine.ŠSPC„2>ŠMOVE.B�CCBSHTDN(A2),D7†Copy�the�mask�of�shutdown�channels�and<ŠEOR.B‚D7,CCBSHTDN(A2)„force�to�zero,�all�bits�that�were�set,*£in�the�original�mask�in�the�CCB.�An�EOR�is&*£used�instead�of�a�CLR�to�produce�the'*£effect�a�single�instruction�"read�and-*£clear"�in�that�any�other�mask�bits�that�are +*£set�as�a�result�of�an�interrupt�after�the+*£MOVE.B�will�not�be�modified�by�the�EOR.B.ŠSPC„2?ŠMOVE.L�CCBMNEM(A2),D3‡Load�the�610/620�module�channel�mnemonic+*£to�be�sent�in�the�Channel�Shutdown�Event.ŠSPC„22ŠMOVE.L�#0,D4�Load�an�interrupt�time�of�zero�to�be*£sent�in�the�shutdown�event.ŠSPC„2<ŠLEA.L‚CCBICCTE+1(A2),A3„Since�the�shutdown�channels�will�be6ŠMOVE.L�#3,D1Žprocessed�in�order�of�decreasing�channel**£number,�load�the�end�address�of�the�ICCT+*£plus�one�and�start�with�channel�number�3.ŠSPC„2BDWN020„LEA.L‚-ICCENTLN(A3),A3…Index�the�ICCT�entry�with�next�lower*£channel�number.ŠSPC„24ŠBCLRƒD1,D7�Test�and�clear�the�shutdown�flag�for�the4ŠBEQ„DWN030�current�channel.�If�the�flag�was�not�set*£proceed�to�the�next�channel.ŠSPC„2M*ƒIn�the�event�that�this�background�routine�was�scheduled�for�execution�whileN* a Close Channels or Disable Interrupts command was executing in Guarded ModeL* (i.e. background processing was blocked), the channel for which a shutdownL* event was to be issued may have already been closed or interrupts may haveN* been disabled prior to execution of this routine. Therefore, it is necessaryM* to assure that the channel is currently open and that interrupts are markedL* as Enabled in the ICCT entry. If the channel was closed or interrupts wereH* disabled by the owning task, all queued interrupts for the channel areJ* automatically discarded making the information contained in the shutdown* event redundant. 7ŠTST.L‚ICCTCB(A3)‹If�the�owners�TCB�address�in�the�ICCT6ŠBEQ„DWN030�entry�is�zero,�the�channel�has�been�closed)*£so�there�is�no�need�to�issue�a�shutdown*£event.ŠSPC„2;ŠTST.B‚ICCENABL(A3)‰If�interrupts�have�been�disabled�on�the0ŠBEQ„DWN030�channel,�there�is�no�need�to�issue�a*£shutdown�event.ŠPAGE8ŠSF…ICCENABL(A3)‰Interrupts�for�the�channel�have�already%*£been�disabled�at�the�610/620�module,*£hardware�so�interrupts�must�also�be�marked *£as�disabled�in�the�ICCT�entry.ŠSPC„2<ŠTST.B‚ICCQEVNT(A3)‰If�interrupt�notification�is�via�Wakeup,3ŠBEQ„DWN030�no�shutdown�notification�is�possible�so&*£proceed�to�process�the�next�shutdown *£channel.ŠSPC„2SHUTDOWN‚EQU„$FF;ŠMOVE.L�#SHUTDOWN,D2‰Load�the�status�for�a�channel�shutdown*£event�into�D2.ŠSPC„24ŠBSR„NOTQEVNT�Issue�the�shutdown�event�to�the�owning*£task.ŠSPC„27DWN030„TST.B‚D7“Loop�until�all�shutdown�flags�have�been;ŠDBEQƒD1,DWN020Šcleared�or�all�interrupt�channels�have�been *£processed.ŠSPC„2)ŠRTS™Return�to�the�background�dispatcher.ŠPAGEO*********************************************************************************•Foreground�Interrupt�Handler*•----------------------------N*�(Note:‚This�routine�always�executes�with�the�processor�interrupt�mask�set�to7*‡at�least�the�level�of�the�interrupt�being�processed.)*I*ƒThis�routine�is�called�by�the�RMS68K�Channel�Management�Routine�when�anJ* I/O Channel interrupt is being processed and a VME 610/620 module CCB isH* encountered in the interrupt polling chain. On entry to this interruptN* handler, the memory mapped I/O base address of the 610/620 board is obtainedO* from the CCB and the Interrupt Status register is read. The latched interruptK* channel status (bits 0-3) is ANDed with the interrupt channel enable maskN* (bits 4-7) to obtain the mask of interrupting input channels for the 610/620L* module being processed. If none of the input channels are interrupting, anN* immediate return is made to CMR with the SR Carry bit clear to indicate thatM* the interrupt has not been claimed and that the polling chain search should * continue.*J*ƒIf�one�or�more�channels�on�the�610/620�module�are�interrupting,�the�maskG* of interrupting channels is ANDed with the mask of channels for whichH* interrupt queuing is enabled. If all of the interrupting channels haveL* interrupt queuing disabled, an immediate return is made to CMR with the SRI* Carry bit set to indicate that the interrupt was  claimed. This allows aI* Command Handler routine to generate a 'programmed interrupt' to clear aK* particular input channel by disabling interrupt queuing and then enablingK* interrupts on the channel. If a command routine simply read the InterruptJ* Status register to clear the channel, it could accidentally 'capture' anF* interrupt that occurred during the read operation. Since the latchedM* interrupt status would be cleared after the read, the command routine wouldN* have the only knowledge that an interrupt had occurred but there would be noH* way to process it. The 'programmed interrupt' approach eliminates thisM* problem since any channel with a pending interrupt that has queuing enabledK* will be processed normally and interrupts on queue disabled channels will* be discarded.*B*ƒThe�Foreground�Interrupt�Handler�then�disables�interrupts�on�allG* interrupting channels that are software debounced to block additionalA* interrupts from occurring until the end of the debounce period.*H*ƒNext,�if�the�Interrupt�Processing�Queue�is�not�full,�a�new�queue�entryL* is created that contains the mask of interrupting channels, the address ofK* the CCB for the interrupting 610/610 module, and the current value of theK* RMS68K Time-of-Day clock (milliseconds past midnight of the current day).N* Then, the Background Interrupt Handler is scheduled for execution by callingN* the RMS68K Background Process Scheduler and a return is made to CMR with the>* SR Carry bit set to indicate that the interrupt was claimed.ŠPAGEK*ƒIf�the�a�new�interrupt�queue�entry�cannot�be�created�because�the�queue�isO* full, the driver performs channel shutdown processing on all of the currentlyO* interrupting channels. First, the shutdown flag is set in the CCB for each ofI* the interrupting channels. This information is needed by the BackgroundM* Channel Shutdown Handler to send a Shutdown Notification Event to the ownerJ* of each shutdown channel. Second, interrupts are disabled at the 610/620K* module hardware for each of the shutdown channels. If frequent interruptsI* from a single channel or a small group of channels are the cause of theJ* interrupt queue overflow, disabling of interrupts on each channel as itsK* interrupts are discarded should shutdown the trouble causing channels andH* reduce interrupt activity to a manageable level without penalizing theN* input channels that have lower interrupt rates. After the channels have beenM* marked as shutdown, the Foreground Interrupt Handler schedules execution ofN* the Background Channel Shutdown Handler and returns to CMR with the SR Carry:* bit set to indicate that the interrupt has been claimed.*&*�Entry�registers‚:�D0�=�Work�register*£A0�=�Work�register*£A1�=�Work�register*£A5�=�CCB�address*&*�Registers�usedƒ:�D0,D1,D2,A0,�and�A1*8*�Exit�registersƒ:�All�registers�except�D0,A0,and�A1�are*£preserved�on�return�to�CMR.*O*******************************************************************************ŠPAGEEINTERUPT‚MOVE.L�CCBCHB(A5),A1ˆLoad�the�memory-mapped�I/O�base�address*£of�VME�610/620�hardware.ŠSPC„2:ŠMOVE.B�INPISTAT(A1),D0†Read�the�hardware�Interrupt�Status'*£register�to�get�the�latched�interrupt+*£status�and�the�interrupt�enabled�channels$*£mask.�The�read�also�clears�pending$*£interrupts�on�all�of�the�channels.ŠSPC„24ŠMOVE.B�D0,-(A7)�Save�a�copy�of�the�Interrupt�Status5ŠLSR.B‚#4,D0Žregister�contents�on�the�stack�and�shift+*£the�mask�of�interrupt�enabled�channels�to*£bits�0-3�of�D0.ŠSPC„25ŠAND.B‚(A7)+,D0�AND�the�mask�of�enabled�channels�with/ŠBNE„INT010�interrupt�status�to�get�the�mask�of)*£interrupting�channels�in�bits�0-3�of�D0'*£and�zeros�in�bits�3-7.‚If�the�mask�is**£non-zero,�one�or�more�input�channels�are&*£interrupting�so�continue�processing.ŠSPC„2,ŠRTS™If�no�channels�of�this�input�module�are)*£interrupting,�return�to�CMR�with�the�SR&*£Carry�bit�clear�to�indicate�that�the+*£interrupt�has�not�been�claimed.�The� Carry**£bit�was�cleared�automatically�by�the�AND*£that�was�just�executed.ŠSPC„2BINT010„AND.B‚CCBIQENA(A5),D0†AND�the�mask�of�interrupting�channels4ŠBNE„INT020�with�the�mask�of�channels�with�interrupt&*£queuing�enabled.�If�this�new�mask�of,*£interrupting�channels�is�non-zero,�proceed*£with�interrupt�processingŠSPC„22ŠSUB.B‚#1,D0�None�of�the�interrupting�channels�are+ŠRTS—interrupt�queue�enabled�so�discard�the)*£interrupt�information�that�was�obtained-*£and�return�to�CMR�with�the�SR�Carry�bit�set)*£to�show�that�the�interrupt�was�claimed.-*£Since�the�low�order�byte�of�D0�is�zero,�the+*£Carry�bit�can�be�set�subtracting�one�from*£D0.ŠSPC„2>INT020„MOVE.W�D1,-(A7)�Save�the�contents�of�the�data�registers8ŠMOVE.W�D2,-(A7)‹that�will�be�destroyed�by�the�interrupt+*£handler�and�not�restored�by�CMR.�Only�the)*£low�order�word�of�each�register�is�used'*£by�the�interrupt�handler�so�only�that**£portion�is�saved�on�the�stack�for�faster*£interrupt�service.ŠSPC„27ŠMOVE.B�D0,D1�Copy�the�mask�of�interrupting�channels�toAŠAND.B‚CCBCHTYP(A5),D0„D1.�AND�the�other�copy�in�D0�with�the�mask(*£of�software�debounce�channels�to�get�a)*£mask�of�interrupting�debounce�channels.ŠSPC„2/ŠEOR.B‚D0,CCBINTCR(A5)�Exclusive�OR�the�mask�of@ŠMOVE.B�CCBINTCR(A5),INPICNTR(A1)�interrupting�software�debounce%*ªchannels�with�the�Interrupt�Control%*ªregister�image�in�the�CCB�and�write *ªthe�image�into�the�hardware�to$*ªdisable�interrupts�on�the�debounce *ªchannels.ŠSPC„2?ŠMOVE.L�CCBQCTAD(A5),A1†Load�the�address�of�the�Interrupt�Queue**£Control�Table�from�the�CCB�into�an�index *£register.ŠSPC„29ŠMOVE.L�QPTR(A1),A0ŠLoad�the�Interrupt�Queue�base�address-*£from�the�Interrupt�Queue�Control�Table�into*£an�address�register.ŠSPC„2G*ƒThe�following�code�stores�a�new�interrupt�entry�into�the�queue�at�theN* location specified by the queue input offset. Since the same interrupt queueH* is used to contain interrupt entries for 610/620 modules that may haveO* different hardware interrupt priorities, the processor interrupt mask must beO* raised to the level of the highest priority 610/620 module interrupt possibleN* while a new entry is being placed in the queue. The hardware interrupt levelI* of the highest priority 610/620 module is stored in the Interrupt QueueN* Control Table and is updated each time a CMR channel for a 610/620 module isL* allocated. After the queue entry has been created and the input offset hasK* been updated, the processor interrupt mask is reduced to the level of the* original interrupt. 6ŠMOVE.W�SR,D0�Copy�the�current�SR�into�a�data�register.ŠMOVE.W�D0,-(A7)‹and�save�a�copy�on�the�stack.ŠSPC„26ŠAND.W‚#$F8FF,D0ŒSet�the�interrupt�mask�bits�in�the�SR8ŠOR.WƒQMAXIL(A1),D0†copy�to�zero�and�OR�in�the�interrupt3ŠMOVE.W�D0,SRŽlevel�of�the�highest�priority�610/620&*£module�from�the�IQCT.�Then�raise�the(*£processor�mask�to�the�desired�level�by+*£moving�the�modified�data�register�back�to%*£the�SR.�This�code�modifies�only�the(*£processor�interrupt�mask�and�condition+*£code�portion�of�the�SR.�All�other�bits�of)*£the�SR�are�unmodified�for�compatibility,*£with�future�M68XXX�family�processors�(i.e. *£68020).ŠPAGE;ŠMOVE.W�QINOFST(A1),D2‡Load�the�queue�input�offset�from�the-*£Interrupt�Queue�Control�Table�into�an�index *£register. K*ƒThe�line�of�code‚'MOVE.L�TIMEOD,D0'‚had�to�be�replaced�because�the�TIMEODL* parameter has been eliminated in the new Periodic Activation mechanism forN*�VERSAdos�4.4.‚A�call�is�now�made�to�the�RMS68K�RDTIMER�routine�to�obtain�the* current time-of-day. 8ŠMOVEM.L�D1/A0,-(A7)‡Save�the�registers�used�by�RDTIMER.;ŠMOVE.L�CCBRDTIM(A5),A0„Get�the�RMS68K�address�for�RDTIMER,0ŠJSR„(A0)�and�go�obtain�the�current�time-of-day.*(*ƒThe�registers�returned�by�RDTIMER�are:%*…D0.L�=�timer�contents�(not�needed).G*…D1.L�=�time-of-day�expressed�in�milliseconds�since�midnight�(TIMEOD).*4ŠMOVE.L�D1,D0ŽSave�time-of-day�as�per�original�code.7ŠMOVEM.L�(A7)+,D1/A0‡Restore�registers�used�by�R DTIMER.(*£Here�we�WANT�the�time-of-day�in�D0,�so'*£we�don't�need�to�save�and�restore�D0.*>*ƒEnd�of�replacement�code�for‚'MOVE.L�TIMEOD,D0'‚***�10/25/84.*ŠSPC„2DŠMOVEM.L�D0/D1/A5,0(A0,D2.W)�Move�a�new�interrupt�entry�to�the�queue)*£at�the�location�referenced�by�the�queue**£input�offset.�The�data�is�moved�in�three$*£long�words�in�the�following�order:*«Time-of-Day�clock�value*«Mask�of�interrupting�channels*«CCB�address�supplied�by�CMR+*£A�MOVEM.L�instruction�is�used�to�minimize+*£the�total�execution�time�of�the�interrupt,*£handler.�All�other�methods�of�storing�data,*£into�the�queue�entry�would�spend�additonal+*£time�in�saving,�loading,�and�restoring�an,*£address�register�and�in�performing�address)*£calculations.�Four�bytes�are�stored�for(*£the�mask�of�interrupting�channels�even)*£though�only�the�low�order�byte�contains,*£useful�data.�The�values�of�the�upper�three'*£bytes�are�considered�to�be�undefined.ŠSPC„2:ŠADD.W‚#IQENTLN,D2ŠUpdate�the�queue�input�offset�to�access<ŠAND.W‚QWAMSK(A1),D2†the�next�free�queue�entry�by�adding�the)*£queue�entry�length�and�force�wraparound,*£from�the�end�of�the�queue�to�the�beginning+*£if�necessary.�Since�the�length,�in�bytes,+*£of�both�the�interrupt�queue�and�the�queue,*£entry�are�powers�of�two,�wraparound�to�the(*£beginning�of�the�queue�is�performed�by,*£logically�ANDing�the�queue�length�-�1�with*£the�queue�input�offset.ŠPAGE;ŠCMP.W‚QOUTOFST(A1),D2†If�the�updated�queue�input�offset�is7ŠBEQ„QOVERFLO‹not�equal�to�the�queue�output�offset,�the-*£interrupt�queue�is�not�full�so�proceed�with-*£normal�processing.�If�the�queue�is�full�and,*£the�updated�input�offset�were�written�back(*£into�the�Interrupt�Queue�Control�Table(*£here,�the�Background�Interrupt�Handler)*£would�erroneously�decide�that�the�queue**£was�empty.�To�prevent�this,�the�queue�is)*£treated�as�full�when�there�is�still�one,*£unused�entry�and�the�test�for�a�full�queue,*£is�made�AFTER�information�has�been�written'*£to�the�unused�entry.�By�allowing�this+*£single�wasted�write�to�a�"full"�queue,�we**£save�time�when�writing�entries�to�a�non-(*£full�queue�via�a�faster�queue�overflow*£check.ŠSPC„2=ŠMOVE.W�D2,QINOFST(A1)‡Save�the�updated�queue�input�offset�in$*£the�Interrupt�Queue�Control�Table.ŠSPC„27ŠMOVE.W�(A7)+,SR�Restore�the�saved�value�of�the�SR�from-*£the�stack�to�reduce�the�processor�interrupt*£mask�to�its�previous�level.ŠSPC„28ŠMOVE.W�(A7)+,D2�Restore�the�low�order�words�of�the�data8ŠMOVE.W�(A7)+,D1‹registers�that�were�saved�on�the�stack.,*£Note�that�a�MOVEM.W�cannot�be�used�because(*£the�word�values�would�be�sign�extended,*£and�the�upper�words�of�the�registers�would*£be�destroyed.ŠSPC„27ŠLEA.L‚QBAB(A1),A0ŠSchedule�execution�of�the�Background?ŠMOVE.L�CCBBKGST(A5),A1„Interrupt�Handler,�using�the�BAB�in�the3ŠJSR„(A1)�Interrupt�Queue�Control�Table,�by�loading'*£the�entry�point�address�of�the�RMS68K+*£Background�Process�Scheduler�from�the�CCB$*£and�calling�the�routine�via�a�JSR.ŠSPC„25ŠMOVE.L�#0,D0�Return�to�CMR�with�the�SR�Carry�bit�set8ŠSUB.L‚#1,D0Žto�indicate�that�the�interrupt�was�claimed./ŠRTS—Since�D0�is�restored�by�CMR,�setting�D0�to,*£zero�and�subtracting�one�sets�Carry�faster *£than�a�OR.W�#1,SR�instruction.ŠPAGEH*‚Control�reaches�here�when�one�or�more�interrupting�input�channels�on�aK* 610/620 module must be processed and there is only one free entry left inK* the Interrupt Processing Queue. Since each new interrupt entry is writtenO* into the queue before a check is made for a full queue, the last entry acts aL* a safety buffer between the last occupied queue entry and the first. UnderL* these circumstances, the updated queue input offset is not written back toK* the Interrupt Queue Control Table so the queue still is shown to have oneM* free entry. The data written to the last entry is discarded. Therefore, anyK* additional interrupts that occur while the queue is full will receive the4* same shutdown processing as the initial interrupt. ?QOVE RFLO‚MOVE.W�(A7)+,SR�Restore�the�saved�value�of�the�SR�from-*£the�stack�to�reduce�the�processor�interrupt*£mask�to�its�previous�level.ŠSPC„24ŠMOVE.B�D1,D0�Save�the�mask�of�interrupting�channels-*£to�be�shutdown�in�a�data�register�that�will*£be�restored�on�return�to�CMR.ŠSPC„28ŠMOVE.W�(A7)+,D2�Restore�the�low�order�words�of�the�data8ŠMOVE.W�(A7)+,D1‹registers�that�were�saved�on�the�stack.,*£Note�that�a�MOVEM.W�cannot�be�used�because(*£the�word�values�would�be�sign�extended,*£and�the�upper�words�of�the�registers�would*£be�destroyed.ŠSPC„2=ŠOR.BƒD0,CCBSHTDN(A5)†OR�the�mask�of�interrupting�channels�to)*£be�shutdown�with�the�mask�of�previously*£shutdown�channels�in�the�CCB.ŠSPC„22ŠMOVE.L�CCBCHB(A5),A0�EOR�the�mask�of�interrupting7ŠEOR.B‚D0,CCBINTCR(A5)‹channels�to�be�shutdown�with�the>ŠMOVE.B�CCBINTCR(A5),INPICNTR(A0)�interrupt�enable�bits�in�the&*ªCCB�interrupt�control�register�image#*ªand�move�the�image�to�the�610/620#*ªhardware�to�disable�interrupts�on*ªthe�shutdown�channels.ŠSPC„2:ŠLEA.L‚CCBBAB(A5),A0ˆSchedule�activation�of�the�BackgroundAŠMOVE.L�CCBBKGST(A5),A1„Channel�Shutdown�Handler�using�the�BAB�at3ŠJSR„(A1)�the�start�of�the�device�dependent�portion'*£of�the�CCB�by�loading�the�entry�point**£address�of�the�RMS68K�Background�Process(*£Scheduler�from�the�CCB�and�calling�the*£routine�via�a�JSR.ŠSPC„25ŠMOVE.L�#0,D0�Return�to�CMR�with�the�SR�Carry�bit�set8ŠSUB.L‚#1,D0Žto�indicate�that�the�interrupt�was�claimed./ŠRTS—Since�D0�is�restored�by�CMR,�setting�D0�to,*£zero�and�subtracting�one�sets�Carry�faster *£than�a�OR.W�#1,SR�instruction.ŠENDéééééé=/*=/*†M610LIB.AF=/*7=/* Chain file to assemble FORTRAN-callable subroutines-=/* to interface with the MVME610/620 driver.=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M610LIB.LS=/*=/IFC \1ƒ=ARG�M610LIB.LS=/ENDIF=/*=ASM M610LIB.SA,M610LIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDé éééééeDFTINP…IDNTƒ1,0�VME�610/620�Driver�FORTRAN�Interface�Routines�9/12/83**‰FORTRAN�callable�subroutines*‰for�VME�610/620�driver�calls*&*‰CALL�INPCMD(input_id,param_blk_addr)*‰where�INPCMD�may�be:*4*ŠCALL�INOPEN(input_id,param_blk_addr)…open�channels>*ŠCALL�INCLOS(input_id,param_blk_addr)…close�selected�channels-*ŠCALL�INSTAT(input_id,param_blk_addr)…status8*ŠCALL�INENAB(input_id,param_blk_addr)…enable�interrupts9*ŠCALL�INDSAB(input_id,param_blk_addr)…disable�interrupts*D*‰and�where�input_id�is�the�CMR�channel�mnemonic�of�a�VME�610�or�620*”boardA*‰and�where�param_blk_addr�is�the�base�address�of�an�Input�Driver*“Command�Parameter�Block*,*‰All�arguments�for�the�calls�are�identical.7*‰The�contents�of�the�param_blk�for�each�call�is�unique*‰to�the�call.*6*‰All�the�command�subroutines�call�a�common�subroutine3*‰INPSET�to�build�the�Initiate�I/O�parameter�block.**‰STACK�FOR�ALL�CALLS:*7*‰deepest�stack:�(stack�address�stays�at�INPSET�return)0*˜command�codeƒ2�bytes�(initiate�I/O�param.�blk) *˜n/aŒ2�bytes*˜input_id‡4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes.*˜command�addrƒ4�bytes�(input�command�address),*˜command�lng„2�bytes�(input�command�length)-*˜INPSET�return‚4�bytes�deepest�stack�address *˜A3�4�bytes *˜A2�4�bytes *˜A1�4�bytes *˜D0�4�bytes*‰entry�stack:ƒreturn‰4�bytes*˜^param_blk_adr�4�bytes*˜^input-idˆ4�bytes* ŠSECTION�9?ŠXDEFƒINOPEN,INCLOS,INSTATƒThe�FORTRAN�subroutine�calls�use�the5ŠXDEFƒINENAB,INDSAB‰the�same�command�mnemonics�as�the(*¦corresponding�assembly�language�calls.&*‰CALL�INOPEN(input_id,param_blk_addr)*‰open�and�configure�channels*1INOPEN„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚INPSET�set-up�the�initiate�I/O�parameter�block)ŠMOVE.L�#1,(A2)Œset�the�open�command�codeINOPN00ƒCLR.L‚D0‘clear�for�use'ŠMOVE.W�4(A2),D0‹get�number�of�channelsŠASL.L‚#2,D0Žmultiply�by�4.INOPN05ƒADD.L‚#6,D0Žadd�in�the�6�byte�overhead-INOPN10ƒMOVE.W�D0,(A1)Œset�the�command�lengthn=w8-ŠMOVE.L�A3,A0ŽTRAP�#1�parameter�block�address#ŠMOVE.L�#60,D0�CMR�directive�numberŠTRAPƒ#1‘call�RMS68K'ŠMOVE.W�D0,(A2)Œset�the�returned�status)ŠMOVEM.L�(A7)+,D0/A1-A3„restore�registers!ŠMOVE.L�(A7)+,A0‹put�return�in�A0 ŠLEA„8(A7),A7‹clean�up�t he�stackŠJMP„(A0)�return�to�user*&*‰CALL�INCLOS(input_id,param_blk_addr)"*‰close�all�channels�for�this�user*1INCLOS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚INPSET�set-up�the�initiate�I/O�parameter�block*ŠMOVE.L�#2,(A2)Œset�the�close�command�code/INCLS10ƒMOVE.W�#6,D0ŽInput�close�command�lengthŠBRA„INOPN10Œgo�do�the�CMR�call*&*‰CALL�INSTAT(input_id,param_blk_addr))*‰read�input�status�on�specified�channels*1INSTAT„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚INPSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#5,(A2)Œset�the�status�command�code4ŠBRA„INCLS10Œgo�set�command�length�&�do�the�CMR�call*&*‰CALL�INENAB(input_id,param_blk_addr).*‰enable�interrpts�on�specified�input�channels*1INENAB„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚INPSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#6,(A2)Œset�the�enable�command�code4ŠBRA„INCLS10Œgo�set�command�length�&�do�the�CMR�call*&*‰CALL�INDSAB(input_id,param_blk_addr)0*‰disable�interrupts�on�specified�input�channels*1INDSAB„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚INPSET�set-up�the�initiate�I/O�parameter�block,ŠMOVE.L�#7,(A2)Œset�the�disable�command�code4ŠBRA„INCLS10Œgo�set�command�length�&�do�the�CMR�call*4*‰INPSET�set�up�the�CMR�initiate�I/O�parameter�block.*‰returns:ƒA1=address�for�Input�command�length**”A2=Input�command�parameter�block�address)*”A3=Initiate�I/O�parameter�block�address*(INPSET„CLR.W‚-2(A7)�clear�command�length-ŠLEA„-2(A7),A1Šsave�address�of�command�length$ŠMOVE.L�24(A7),A0Šget�param_blk_addr%ŠMOVE.L�A0,-6(A7)Šsave�param_blk_addr,ŠMOVE.L�A0,A2Žsave�param_blk_addr�for�returnŠCLR.L‚-10(A7)Œnot�usedŠCLR.L‚-14(A7)Œnot�usedŠCLR.L‚-18(A7)Œnot�usedŠMOVE.L�28(A7),A0Šget�^input_id!ŠMOVE.L�(A0),-22(A7)‡get�input_idŠCLR.W‚-24(A7)Œnot�used0ŠMOVE.W�#$0700,-26(A7)…initiate�I/O�command�code4ŠLEA„-26(A7),A3‰initiate�I/O�parameter�block�addressŠRTS—return�to�callerŠENDééééééé=/*=/*†M615DRV.AF=/*>=/* Chain file to assemble the MVME615 AC OUTPUT device driver=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M615DRV.LS=/*=/IFC \1ƒ=ARG�M615DRV.LS=/ENDIF=/*$=A SM M615DRV.SA,M615DRV.RO,\1;MRZ=75=/*{ Included files are:=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.TR1RTCD.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.M615DRV.EQ=/*}=/*=ENDéééééé‡*!*…MVME�615�AC�OUTPUT�BOARD�DRIVER *…copyrighted�1983�MOTOROLA�INC. *œTOM�KRYKA* ‰LLEN†120 ‰TTL‡STR.EQ‰INCLUDEƒ9995.&.STR.EQ ‰TTL‡TCB.EQ‰PAGE‰INCLUDEƒ9995.&.TCB.EQ‰TTL‡TR1RTCD.EQ‰PAGE‰INCLUDEƒ9995.&.TR1RTCD.EQ ‰TTL‡CCB.EQ‰PAGE‰INCLUDEƒ9995.&.CCB.EQ ‰TTL‡LV5.EQ‰PAGE‰INCLUDEƒ9995.&.LV5.EQ‰TTL‡M615DRV.EQ‰PAGE‰INCLUDEƒ9995.&.M615DRV.EQ‰TTL‡MVME615�DRIVER‰PAGEM615DRV‚IDNT†1,0‡ACO�DRIVERJ****************************************************************************ƒDR615�--�REV.�1.00�8/2/83*+*ƒPurpose:‚MVME�615�AC�OUTPUT�BOARD�HANDLER*/*ƒEntry:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER-*ƒExit:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION**ƒCODE�IS�RE-ENTRANT********************************* CHANNEL CONTROL BLOCK (CCB) *********************************B*ƒContains�channel�device�dependent�description�and�data�areas�for*ƒI/O�handler.*‰OFFSETƒCCBDDP*H* I/O HANDLER DATA AREA *************************************************CCBFLGƒDS.B†2‰Flags(CCBERAD1�DS.B†4‰Error�debug�save�address2CCBQVER1�DS.B†4‰Event�queueing�error�debug�address7CCBCCBƒDS.B†4‰Physical�address�of�command�packet�(IOCB)CCBTASKB�DS.B†4‰Buffer�task�TCB-CCBPKTƒDS.B†18ˆEvent�work�area�(command�tour)0CCBCPKT‚DS.B†18ˆEvent�work�area�(interrupt�tour)(CCBPTRƒDS.B†4‰Physical�address�of�bufferCCBLENƒDS.B†4‰Length�of�buffer0CCBPTR1‚DS.B†4‰Physical�address�of�2ndary�buffer&CCBLEN1‚DS.B†4‰Length�of�2ndary�buffer*CCBCIDƒDS.B†4‰CMR�parameter�block�id�(DCB)CCBCOPT‚DS.B†2‰IOCB�options#CCBCFIG‚DS.B†$26‡Configuration�data**‰56�bytes�remain*9*‰CCBFLG�DEFINITIONS:�if‚CCBFLG.B�if�not�0�the�ACO�module$*�for�the�CCB�cannot�be�used�for�the*�following�reasons:*9*‰CCBFLG.B�=�$FA�=�CCB�allocation�exceeded�#�of�specified/*šdevices�-�no�room�in�ACO�table�for�the�module!*’=�$FC�=�no�ACOTBL�was�allocated/*’=�$F5�=�no�room�in�ACOTBL�for�this�ACO�module*™(incorrect�table�allocation)*‰PAGE  �M™<¡0©?±8¹4Á<ÉGÑ>Ù9á4é;ñ7ù1B 8CH!8) ‰SECTIONƒ8 ‰XREF†ACOTBLH*************************************************************************ƒACO�SERVICE�VECTOR�TABLEH************************************************************************#*ˆDC.L†ACOINTŽinterrupt�svc�address!*ˆDC.L†ACOCMDŽcommand�svc�address)*ˆDC.L†ACOINIT�initialization�svc�address*7*…Below�are�the�offset�form�of�service�pointers�for�CMR*.ACODVRƒDC.L†ACOINT-ACODVR‡interrupt�svc�offset*‰DC.L†ACOCMD-ACODVR‡command�service�offset.‰DC.L†ACOINIT-ACODVR†initialization�svc�offset‰DC.L†0“Reserved‰DC.B†0“number�of�extra�pages‰DC.B†0,0,0�reserved‰DC.L†0,0,0�reserved*3*ƒ---ƒ---…CONFIGURATION�CONTROL�INFORMATION…---ƒ---*$‰DC.B†'080283'‚date�of�last�assembly'‰DC.B†'�'‡space�means�no�patches�in�.LO#‰DC.B†'4'‡major�Versados�revision�#*I**************************************************************************ƒCOMMAND�TABLE�&�JUMP�TABLE:*‰These�are�used�by�the�command�service�routine�to�jump�to.*‰the�appropriate�routine�to�handle�a�command.I************************************************************************** CMDTBLƒDC.W†ACOPEN„OPEN�command.‰DC.W†ACOCLS„CLOSE�command.‰DC.W†ACOUT…OUTPUT�ON�command. ‰DC.W†ACOOFF„OUTPUT�OFF�command.‰DC.W†ACOSTA„STATUS�command.‰DC.W†X1ˆ(not�used)‰DC.W†X2ˆ(not�used)#‰DC.W†ACOPLS„PULSED�OUTPUT�command.=NUMCMDS‚EQU‡(*-CMDTBL)/2‚The�number�of�commands�in�the�table.*8JMPTBLƒDC.W†OPEN-*„Biases�to�the�corresponding�routines. ‰DC.W†CLOSE-* ‰DC.W†OUTON-*‰DC.W†OUTOFF-* ‰DC.W†STAT-*‰DC.W†ENABLER-*‰DC.W†DSABLE-* ‰DC.W†PLSO-*7JMPOFFƒEQU‡JMPTBL-CMDTBL‡Offset�between�the�two�tables.*‰PAGEH*************************************************************************+*ƒACO�DRIVER�INITIALIZATION�SERVICE�ROUTINE*>*ˆThe�driver�is�entered�here�for�each�CCB�allocated.‚More�than:*ˆone�CCB�may�be�allocated�for�each�ACO�module.‚One�CCB�is%*ˆallocated�for�each�interrupt�level.?*ˆThis�routine�checks�to�see�if�there�is�room�in�the�ACOTBL�for=*ˆthe�device�ID.‚It�saves�the�device�ID�and�the�memory�mapped**ˆI/O�address�of�the�device�in�the�ACOTBL.*:*ˆAn�error�code�is�saved�in�the�CCB�if�this�CCB�allocation=*ˆexceeds�the�maximum�number�of�CCB's�specified�during�SYSGEN9*ˆ(SYSGEN�parameter�NACO),�if�no�ACOTBL�exists�or�no�room*ˆin�the�table�for�this�module.*$*ˆEntry:‚all�registers�are�available*�A5�=�CCB�address,*ˆsingle�exit�&�pointer�(A0-A6)�preservationI**************************************************************************ACOINIT‚PUSHPOINT•save�pointers3‰MOVE.L„CCBCHB(A5),A0‡get�memory�mapped�I/O�address$‰MOVE.L„ACOTBL,A1‹get�ACOTBL�address‰CMP.L…#0,A1�is�there�one?&‰BNE.S…ACOINIT1Œbranch�if�have�a�table8‰MOVE.B„#ACONTBL,CCBFLG(A5)�set�no�table�error�condition!‰BRA.S…ACOINEX1Œgoto�error�returnACOINIT5�TST.L…(A1,D3)�look�for�an�entry�slot�to�save�this�guy5‰BMI.S…ACOINIT6Œbranch�if�this�slot�is�empty�-�use�it.‰ADD.W…#IOLNG,D3‹not�empty,�bump�to�next�entry"‰SUB.B…#1,D4�decrement�the�counter(‰BNE.S…ACOINIT5Œbranch�if�more�to�search4‰BRA‡ACOEXTERŒerror�if�got�here-�no�room�for�the�map>ACOINIT6�MOVE.L„D2,(A1,D3)Šsave�this�memory�mapped�I/O�address‰MOVE.L„#0,D0�write�0�to�reg‰MOVE.B„D0,IOADR(A0)1ACOEXIT1�CLR.B…CCBFLG(A5)Šset�for�good�allocation3‰MOVE.L„CCBCHB(A5),A1‡get�memory�mapped�I/O�address&ACOINEX1�POP_POINT•recall�all�pointers‰RTS*‰PAGEG************************************************************************$*ƒACO�DRIVER�COMMAND�SERVICE�ROUTINE*6*‹PARAMETER�ADDRESS�AND�BOUNDARY�CHECKS�HAVE�BEEN�MADE**ƒEntry:‚JSR�FROM�CMR�HANDLER.*‹A2�-�PHYSICAL�ADDRESS�OF�CMR�PARAMETER�BLOCK*‹A5�-�PHYSICAL�ADDRESS�OF�CCB*5*ƒExit:‚RTS�-�PARAMETER�BLOCK�VALIDATION�STATUS�IN�D0**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A**P**PP*"*”A3�=�ACO�PARAMETER�BLOCK�ADDRESS*”A6�=�REQUESTOR�TCB�ADDRESS*J***************************************************************************)*ŒConvert�logical�PB�address�to�physical.*ACOCMDƒCLR.L…D57‰MOVE.L„XIOCPK(A2),D6‡Set�up�address�of�ACO�para.�block:‰MOVE.W„XIOPLN(A2),D5‡Set�up�length�of�ACO�parameter�block+‰MOVE.L„CCBTASKA(A5),A1…Set�up�TCB�pointer.&‰BSR‡IOHADRCKŒCall�conversion�routine.‰BRA.S…CMD010ŽGood�return.‰NOP›Bad�length�return. ‰CLR.L…D0;‰MOVE.W„#RTCDPBLK,D0ˆSet�up�invalid�parameter�block�address‰BRA.S…ACOCEX1�goto�error�exit*!*�see�if�passed�the�initialize�ok*7CMD010ƒMOVE.L„D6,A3�Stage�phys.�addr.�of�ACO�para.�blk. ‰CLR.L…D04‰TST.B…CCBFLG(A5)Šerror�code�set�in�CCB�during�INIT?/‰BEQ.S…CMD020Žbranch�if�no�error�code,�continue$‰MOVE.B„CCBFLG(A5),D0‡set�error�code‰BRA.S…ACOCEX2�goto�error�exit*,*Œget�ACOTBL�address�into�A4�for�command�use* CMD020ƒEQU‡* ‰MOVE.L„ACOTBL,A4‹ACOTBL�address)‰CMP.L…#'!ACO',(A4)ˆreally�is�the�ACOTBL?,‰BEQ.S…CMD030Žbranch�if�really�is�the�ACOTBL4‰MOVE.W„#ACONTBL,D0‰set�error�return�code�-�no�table‰BRA.S…ACOCEX2�and�return**‹find�ACO-ID�in�ACOTBL*‹A1�=�entry�address*0CMD030ƒMOVE.L„XIOCID(A2),D0‡get�specified�ACO-ID(‰MOVE.B„ACONMAX(A4),D1†max�#�of�ACO-ID's$‰MOVE.L„#ACONTRY,D2‰bump�past�header"FNDACO10�CMP.L…(A4,D2),D0Ša�match?!‰BEQ.S…FNDACO20Œbranch�if�a�match&‰ADD.W…#ACOIDLNG,D2ˆbump�to�next�entry1‰SUB.L…#1,D1�decrement�number�of�entries�to�check&‰BNE.S…FNDACO10Œbranch�if�more�entries.‰MOVE.W„#ACONID,D0Šerror�-�ACO-ID�not�in�table3‰BRA.S…ACOCEX2�return�to�CMR�with�err�condition�set+FNDACO20�MOVE.L„A4,A1�bass�address�of�table‰ADD.L…D2,A1�address�of�entry*(*ŒFind�the�command�in�the�command�table.*-‰MOVEQ…#NUMCMDS-1,D0‡Set�up�the�loop�counter./‰LEA‡CMDTBL,A0‹A0�<--�address�of�command�table.+‰MOVE.W„CMDCOD(A3),D6‡get�ACO�command�code.8CMDSRCH‚CMP.W…(A0)+,D6ŒSearch�the�table�for�the�command.‰DBEQ†D0,CMDSRCH3‰BNE.S…CMDERRŽIf�we�found�the�command�in�the�table,8‰ADD.L…#JMPOFF-2,A0ˆget�the�corresponding�entry�from�the5‰MOVE.W„(A0),D0�jump�table�and�jump�to�the�routine�to"‰JMP‡(A0,D0.W)‹handle�the�command.>CMDERRƒMOVE.W„#ACOINVD,D0‰didn't�find�cmd�code�-�exit�with�errAACOCEX2‚MOVE.W„D0,CMDSTA(A3)‡write�err�code�to�users�ACO�para�blk ACOCEX1‚RTS*‰PAGEJ***************************************************************************A*„OPEN�COMMAND‚assigns�the�logical�connection�between�a�user�task9*‰and�specified�channels�within�an�ACO�module.�8�channels/*‰maximum�may�be�specified�in�one�open�command.*#*„ACO�OPEN�command‚parameter�block: *‰DS.W‚1„returned�command�status*‰DS.W‚1„command�code�(01)*‰DS.W‚1„#�of�channels�to�open*‰DS.W‚1„1st�channel�n umber*‰DS.W‚1„channel�configuration*Œ.*‰DS.W‚1„nth�channel�number*‰DS.W‚1„channel�configuration**„configuration�word:+*‰bit�0=1�wake-up�task�on�output�pulse�done-*Ž=0�queue�event�to�task�on�output�pulse�done2*ˆbit�15=1�use�default�configuration(ignore�bit�0)+*Ž=0�use�specified�configuration�from�bit�0B*ƒDefault�configuration:‚no�wakeup�or�queue�event�on�pulse�output.-*‰The�actual�configuation�is�saved�in�ACOTBL.%*‰The�task�TCB�address�is�also�saved.*)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�CLRIOM,�SETIO,�DOIOH**************************************************************************‰see�if�channel�already�opened*$OPEN…PUSHPOINT‹save�all�address�regs‰ALLOCATE‚CHCONFIG*2‰BSR‡CLRIOM„clear�(to�$FF)�the�IO�map�for�this�ACO‰CLR.L…D7ˆchannel�counter:‰CMP.W…#ACONID,D0‚an�error�returned�from�clearing�the�map?)‰BEQ.S…OPNOID‡branch�if�an�error�returned$‰CLR.L…D2‘channel�offset�into�ACOTBL)‰CLR.L…D1‘offset�into�ACO�parameter�block1‰MOVE.W„CMDCHN(A3),D0†get�#�of�channels�specified/‰BLE.S…OPNINC�branch�if�negative�or�zero,�error0‰CMP.W…#8,D0�cannot�specify�more�than�8�channels-‰BGT.S…OPNINC�branch�if�greater�than�8,�errorEOPEN10ƒMOVE.W„NUMCHAN(A3,D1),D2‚get�channel�number�from�ACO�para.blk.!‰CMP.W…#7,D2�insure�channel�#�<�8 ‰BGT.S…OPNINV‰MOVE.W„D2,D5Žsave�it0‰MULU†#CHANLNG,D2ˆget�channel�offset�into�ACOTBL‰ADD.L…#4,D2Žbump�past�ACO-ID+‰TST.W…(A1,D2)Œthis�channel�already�opened?-‰BPL.S…OPNOPN�branch�if�already�opened,�error‰ADD.L…#1,D7Žcount�this�channel>‰MOVE.W„CHNCNFG(A3,D1),D3‚get�configuration�from�ACO�para.blk.-‰STORE…D3,CHCONFIG†save�channel�configuration*0*Œsave�TCB�address�and�configuration�information*.‰LOAD†D3,CHCONFIG‰recall�channel�configuration)‰BSR‡SETIO�go�set�IO�map�for�this�channel5‰CMP.W…#ACONID,D0Šan�error�found�during�the�save�map?*‰BEQ.S…OPNERRŽbranch�if�an�error�was�found6‰MOVE.W„D3,ACOCNIF(A1,D2)ƒsave�configuration�in�ACOTBL)‰MOVE.L„A6,ACOTCB(A1,D2)„save�TCB�address4‰ADD.W…#OPNTRY,D1Šbump�to�next�ACO�param.�blk.�entry3‰SUB.W…#1,D0�decrement�number�of�channels�specified)‰BGT‡OPEN10Žbranch�if�more�channels�to�do*‰BSR‡DOIO�go�set�the�IO�hardware�registers!‰CMP.W…#ACONID,D0Šan�error�found?2‰BEQ.S…OPNERRŽbra�if�an�err�was�found�-�don't�open‰CLR.L…D0’set�for�good�return‰BRA.S…OPNXITŽgo�return�to�CMR**Œopen�errors�here*5OPNINVƒMOVE.W„#ACOICNS,D0‰set�invalid�channel�#�error ‰BRA.S…OPNXIT8OPNINCƒMOVE.W„#ACOINC,D0Šset�invalid�#�of�channels�error‰BRA.S…OPNXITŽexit;OPNOIDƒMOVE.W„#ACONID,D0Šset�ACO�module�not�allocated�error‰BRA.S…OPNXITŽgo�return�to�CMR9OPNOPNƒMOVE.W„#ACOPND,D0Šset�channel�already�opened�error*)*Œreset�any�opened�channels�to�not�opened*%OPNERRƒTST.W…D7’any�channels�to�undo?3‰BEQ.S…OPNXITŽbranch�if�none�to�undo,�return�to�CMR&‰MOVE.W„#$FFFF,D3‹set�'un-opened'�code‰CLR.L…D1’clear�for�use6OPNERR10�MOVE.W„NUMCHAN(A3,D1),D2ƒget�a�channel�number$‰MULU†#CHANLNG,D2‰get�channel�offset‰ADD.L…#4,D2�bump�past�headers*‰MOVE.W„D3,(A1,D2)Šset�this�entry�unopened-‰ADD.W…#OPNTRY,D1Šbump�to�next�channel�number‰SUB.W…#1,D7�decrement�counter&‰BGT.S…OPNERR10Œbranch�if�more�to�undo*ŽFall�into�exit* OPNXITƒEQU‡*)‰ADD.L…#8,A7…DEALLOCATE�CHCONFIG�on�stack‰POP_POINT‹restore�all�pointers ‰BRA‡NRMEXIT*I**************************************************************************A*ƒCLRIOMƒClear�out�the�IO�map�for�this�memory�mapped�I/O�address.*&*‰Entry:�A1�=�ACO-ID�address�in�ACOTBL%*�A2�=�address�of�CMR�parameter�block%*�A3�=�address�of�ACO�parameter�block*�A4�=�address�of�ACOTBL*�A5�=�address�of�CCB*�A6�=�address�of�users�TCB**‰Uses:‚D4,D6,D7*%*‰Exit:‚D0�=�ACONID�if�an�error�found**�D0�=�contents�on�entry�if�no�error�found*I**************************************************************** **********0CLRIOMƒMOVE.W„ACOIO(A4),D7ˆget�offset�to�IO�maps.‰MOVE.B„ACONAL(A4),D6‡get�#�of�ACO'S�allocated3‰MOVE.L„CCBCHB(A5),D4‡get�memory�mapped�I/O�address?CLRIOM1‚CMP.L…IODDR(A4,D7),D4…look�for�match�mem.�map.�I/O�addr‰BEQ.S…CLRIOM2�branch�if�found#‰ADD.W…#IOLNG,D7‹bump�to�next�entry‰SUB.B…#1,D6�decrement�counter/‰BNE.S…CLRIOM1�branch�if�more�entries�to�search#‰MOVE.W„#ACONID,D0Šset�error�return‰RTS›return�to�caller)CLRIOM2‚CLR.B…DODR07(A4,D7)‡clear�the�map‰RTS›return�to�caller*‰PAGEI**************************************************************************<*ƒSETIO…Build�the�IO�map�entries�for�the�specified�channels.*�Builds�1�entry�per�call*�Map�is�in�ACOTBL.**‰Entry:�A4ƒ=�ACOTBL�address*�D3.W�=�channel�configuration*�D5.B�=�channel�number*7*‰Exit:‚D0.W�=�ACONID�if�map�entry�not�found,�otherwise*—D0�unchanged *‰Uses:�D4,D6*‰Entry�point�=�SETIO*‰Exit�point‚=�SETIORT**ˆPrivate�subroutine�for�OPEN*$* Single exit & pointer preservation*I***************************************************************************‰find�map�entry* SETIO„EQU‡*‰PUSHPOINT‘save�all�pointers‰MOVE.L„D7,-(A7)‹save�D73‰MOVE.W„ACOIO(A4),D7†get�offset�to�start�of�IO�maps.‰MOVE.B„ACONAL(A4),D6†get�#�of�ACO'S�allocated3‰MOVE.L„CCBCHB(A5),D4†get�memory�mapped�I/O�address;SETIOFD‚CMP.L…IODDR(A4,D7),D4ƒfind�the�matching�I/O�address‰BEQ.S…SETIO00‹branch�if�found#‰ADD.W…#IOLNG,D7‰bump�to�next�entry‰SUB.B…#1,D6Ždecrement�counter/‰BNE.S…SETIOFD‹branch�if�more�entries�to�search8‰MOVE.W„#ACONID,D0†set�fatal�err�-�this�shouldn't�happen‰BRA.S…SETIORT‰return�to�caller**Œdetermine�channel�number*SETIO00‚CLR.L…D6‘clear�for�use/‰MOVE.B„D5,D6Žcopy�channel�number�to�work�space**ŒCHANNEL�0-7�as�output�channel*0‰BSET†D5,DODR07(A4,D7)ƒset�data�image�for�output"SETIORT‚MOVE.L„(A7)+,D7‹restore�D7‰POP_POINT‘restore�all�pointers‰RTS—return�to�caller*‰PAGED*********************************************************************;*ƒDOIO†Copy�the�data�information�from�the�IO�register�image"*�(in�the�map)�to�the�IO�register.**ˆENTRY�PARAMETERS:*�A4�=�address�of�ACOTBL*�A5�=�address�of�CCB*)*‰Exit:‚D0.W�=�ACONID�if�IO�map�not�found*�D0.W�=�0�if�no�errors�found**‰Uses:�A0,D1,D6,D7*#* Single exit, pointer preservation*D********************************************************************* DOIO…EQU‡*‰PUSHPOINT’save�all�pointers!‰MOVE.L„D7,-(A7)‹save�register�D7*‰MOVE.W„ACOIO(A4),D7†get�offset�to�IO�maps$‰MOVE.B„ACONAL(A4),D6†get�#�of�ACO'S3‰MOVE.L„CCBCHB(A5),D1†get�memory�mapped�I/O�address*‰This�command�deactivates�outputs�for�specified�channels�that9*‰have�previously�been�opened�for�output�by�the�same�task<*‰requesting�this�activation.‚The�parameter�block�is�checked<*‰for�errors�before�any�output�is�deactivated.‚No�channel�is#*‰deactivated�if�an�error�is�found.*)*‰ACO�OUTPUT�OFF�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�044*‰DS.Wƒ1ƒbit�mask�containing�channel�#'s�to�activate*)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�DOOFF*%* Single exit with pointers preserved*H*************************************************************************"OUTOFFƒPUSHPOINT‘save�all�pointers0‰CLR.L‚D3‘flag�-�ck�para.blk.�before�stop�output'‰MOVE.L�#4,D1Žbump�past�ACO-ID�in�table!‰CLR.L‚D2‘use�for�channel�counter‰CLR.L‚D0‘clear�for�use+‰MOVE.W�CMDCHN(A3),D0†get�channels�to�start0‰MOVE.WƒD0,D3Œcopy�chan.�to�turn�off�to�work�reg+OUTOF20‚BTSTƒD2,D0Ždeactivate�this�channel?0‰BEQ.S‚OUTOF30Œbranch�if�no�-�check�next�channel5‰CMP.L‚ACOTCB(A1,D1),A6ƒchannel�belongs�to�this�user? ‰BNE„OUTONERŒbranch�if�no,�error.‰BCLR…D2,D3Œnegate�check�flag�for�this�channel$‰TST„D3‘is�all�of�parameter�checked?(‰BNE.S‚OUTOF30Œbranch�if�not�all�checked2‰BSR.S‚DOOFFŽgood�para.�block�-�deactivate�channel‰BRA.S„OUTOFFXŠnormal�exit/OUTOF30‚ADD.L‚#1,D2Žbump�to�next�channel�number-‰ADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry&‰CMP.L‚#8,D2�checked�all�the�channels?/‰BNE.S‚OUTOF20Œbranch�if�more�channels�to�check ‰BRA†OUTONEROUTOFFX‚EQU‡*‰normal�exit‰POP_POINT‹recall�all�pointers‰CLR.L„D0‰signal�no�errors‰BRA.S…NRMEXITƒnormal�exit*‰PAGEI**************************************************************************"*‚STAT�-�GET�OUTPUT�STATUS�COMMANDA*†This�command�reads�the�status�of�specified�output�channels.�The>*†channels�must�have�previously�been�opened�for�output�by�thisC*†user.�The�parameter�block�is�checked�for�errors�before�any�outputA*†status�is�read.�The�users�parameter�block�is�modified�to�signalB*†active�channels�by�setting�the�corresponding�bit�in�the�bit-maskE*†word.�The�corresponding�bit�number�of�inactive�channels�is�cleared.* *†All�channels�are�read�at�once.*,*„ACO�OUTPUT�STATUS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�05<*‰DS.Wƒ1ƒbit�mask�containing�channels�numbers�to�read�status$*”(�this�is�also�the�returned�field)*)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�GTSTAT*I********************************************************** **************** STAT†PUSHPOINT‘save�all�pointers(ŠCLR.L‚D5‘use�for�returned�status�values/ŠCLR.L‚D3‘flag�-�ck�para.blk.before�read�status(ŠMOVE.L�#4,D1Žbump�past�ACO-ID�in�ACOTBLŠCLR.L‚D2‘channel�counterŠCLR.L‚D0‘clear�for�use;ŠMOVE.W�CMDCHN(A3),D0†get�channel�numbers�to�read�status�on3ŠMOVE.W�D0,D3Žcopy�chan�activation�req.�bit�pattern$ŠAND„#$00FF,D0Šmask�all�but�low�byte/STAT20„BTSTƒD2,D0Žread�status�for�this�channel?ŠBEQ.S‚STAT40�branch�if�no5ŠCMP.L‚ACOTCB(A1,D1),A6ƒchannel�belongs�to�this�user?1ŠBNE„OUTONERŒbranch�if�no�-�return�with�error�set0ŠBCLRƒD2,D3Žclr�activation�flag�for�this�channel*ŠTST„D3‘finished�checking�parameter�block?1ŠBNE.S‚STAT40�branch�if�not�finished�checking�yet0ŠBSR.S‚GTSTAT�go�read�status�and�save�in�REG.�D5!ŠBRA.S‚STAT50�goto�procedure�exit3STAT40„ADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry(ŠADD.L‚#1,D2Žbump�to�next�channel�number,ŠBRA„STAT20�branch�to�channel�check�sequence6STAT50„MOVE.W�D5,CMDCHN(A3)†set�returned�status�values&ŠBRA„OUTONEXŒand�return�with�no�errors*‰PAGEI*************************************************************************<*‚ENABLE�-�ENABLE�INTERRUPTS�COMMAND�---�NOT�USED�THIS�BOARD3*‰IF�CALLED,�EXITS�WITH�INVALID�COMMAND�ERROR�CODE.*0*„ACO�ENABLE�INTERRUPTS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�066*‰DS.Wƒ1ƒbit�mask�of�channels�to�enable�for�interrupts)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCBI**************************************************************************5ENABLER‚MOVE.W„#ACOINVD,D0‡set�code�'invalid�command'(‰BRA.S…NRMEXITŒand�return�with�error�set**I*************************************************************************=*‚DSABLE�-�DISABLE�INTERRUPTS�COMMAND�---�NOT�USED�THIS�BOARD-*‰IF�CALLED,�EXITS�WITH�INVALID�COMMAND�CODE.*1*„ACO�DISABLE�INTERRUPTS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�077*‰DS.Wƒ1ƒbit�mask�of�channels�to�disable�for�interrupts)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCBH*************************************************************************DSABLEƒBRA.S…ENABLER**H************************************************************************* *ƒNORMAL�EXIT,*ˆEntry:�A2�=�address�of�CMR�parameter�block%*�A3�=�address�of�ACO�parameter�block*�A5�=�address�of�CCB*�A6�=�address�of�users�TCB*�D0�=�ACO�error�code*I**************************************************************************ANRMEXITƒMOVE.W�D0,CMDSTA(A3)†set�return�status�in�ACO�para.�blockŠRTS—return�to�CMR*‰PAGEH**************************************************************************ƒPLSO�-�PULSED�OUTPUT�COMMAND*)*‚Entry:�A1�=�address�of�ACO-ID�in�ACOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�ACO�parameter�block*‰A4�=�address�of�ACOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‚Exits�to�NRMEXIT*+*‚Parameter�block�format�for�pulsed�output:1*‚ACO�parameter�block�(pointed�to�by�A3�on�entry)* *ˆDS.W†1‰returned�command�status*ˆDS.W†1‰command�code*ˆDS.W†1‰number�of�channels<*�---ƒ---ƒ---ƒparameters�for�individual�channelsƒ---ƒ---ƒ---*ˆDS.W†1‰first�channel�number,*ˆDS.L†1‰number�of�milliseconds�for�pulse�on*ˆ.*ˆ.*ˆDS.W†1‰nth�channel�number2*ˆDS.L†1‰number�of�milliseconds�for�nth�chan�pulse*7* EACH CHANNEL IS ACTIVATED IN TURN (NON-SYNCHRONOUSLY)H*************************************************************************@*„Pulsed_Out(IN-LIST�OF�channel�activation�request,�pulse�times;*�OUT-error�code)?PLSO…ALLOCATE�CHANID,ACOPARBK†allocate�chan.id�&�ACO�para�block3‰STORE…A3,ACOPARBK‰save�ACO�parameter�block�address ‰CLR.L…D 6’Initiate�pulsed�output ‰CLR.L…D3 ‰CLR.L…D2 ‰CLR.L…D0$*—get�number�of�channels�to�activate9‰MOVE.W„CMDCHN(A3),D0‡get�no.�of�chan's�from�ACO�para�blk)PLSO1„TST.W…D0’loop�on�#�of�chan.'s�to�do ‰BEQ.S…PLSOX‰CLR.L…D5’get�channel�number‰MOVE.W„NUMCHAN(A3,D6),D5-‰STORE…D5,CHANID‹save�channel�number�on�stackC*„Channel�ID�consists�of�user�CCB�address�+�chan�number�in�LS�byte.+‰MOVE.L„A5,D7�copy�user's�CCB�address�to�D75‰ADD.L…D7,CHANID(A7)‡CHANID�now�has�complete�chan.�ID"‰MOVE.L„D5,D7�copy�channel�#�to�D7,‰BSR‡BIN_BIT�convert�binary�to�bit�map�in�D56‰MULU†#CHANLNG,D7‰compute�offset�to�nth�chan�in�ACOTBL%‰ADD‡#4,D7�bump�to�user�TCB�in�ACOTBL-‰CMP.L…ACOTCB(A1,D7),A6„compare�TCB�addresses1‰BNE.S…PLSOER1�branch�on�channel�not�current�user2*„Get�pulse�time�from�ACO�commmand�parameter�block‰MOVE.L„CHNCNFG(A3,D6),D3%*„IF�pulse�time�>�pulse_min_time�THEN'‰BEQ.S…PLSOER3ƒbranch�on�pulse�time�=�0(‰ADD.W…#6,D6…increment�to�next�channel�#-*„request�periodic�activation(this�channel�#)2‰LEA‡PLSOFF(PC),A0‡point�to�pulse�turn�off�routine%‰CLR.L…D1’set�request�for�1�time�only6‰MOVE.B„CCBPPRIO(A5),D1…set�act.�priority�same�as�task/‰LOAD†D2,CHANID‹setup�channel�ID�to�goto�PLSOFF‰PUSHALL'‰MOVE.L„D3,A1�setup�activation�interval$‰TR0$.RQPA�,“pass�request�for�wakeup)*ŒIf�no�err�in�periodic�act.�request�THEN‰BRA.S…RQPAOKŽgood�return(‰BRA.S…PLSOER4�err�in�periodic�act.�req."*›activate_this_channel(channel�#)*RQPAOKƒMOVE.L„D5,D0�pass�bit�mask�to�DOOUT ‰BSR‡DOOUT‰POPALL"‰SUB‡#1,D0�decrement�channel�count ‰BRA‡PLSO1**ŒError�handling)PLSOER1‚CLR.L…D0’Channel�not�current�user‰MOVE.W„#ACOICNS,D0 ‰BRA.S…PLSOX1)PLSOER3‚CLR.L…D0’Requested�pulse�time�=�03‰MOVE.W„#ACOCNFG,D0‰return�'bad�configuration'�code ‰BRA.S…PLSOX1PLSOER4‚POPALL#‰CLR.L…D0’Periodic�activation�error,‰MOVE.W„#ACOBSY,D0‹return�'device�busy'�code ‰BRA.S…PLSOX1*ŒPulsed�output�good�exit�point6PLSOX„LOAD†A3,ACOPARBK‚restore�ACO�para�blk�addr�to�A3‰CLR.L…D0ˆset�for�normal�return4PLSOX1ƒADD.L…#12,A7„DEALLOC‚CHANID,ACOPARBK�on�stack*‰BRA‡NRMEXITƒgoto�normal�common�exit�point*‰PAGE*<*‚PULSED�OUTPUT�DEACTIVATION‚Entered�by�periodic�activation. *„On�entry:?*‡D1�contains�channel�ID�composed�of�user's�CCB�address�in�M.S.7*Š3�bytes,�and�channel�number�(0-7)�in�least�sig.�byte.*PLSOFFƒPUSHALL&‰MOVE.B„D1,D5�save�combined�channel�ID ‰AND.B…#0,D1�recover�CCB�address+‰MOVE.L„D1,A5�stage�CCB�address�for�'DOOFF'+‰AND.L…#$000000FF,D5‡recover�channel�number‰MOVE.L„D5,D4�save�binary�value‰MOVE.L„#$0C010000,D2 ‰MOVE.B„D5,D2.‰BSR.S…BIN_BIT�convert�chan�#�to�bit�map�in�D5"‰MOVE.L„D5,D0�stage�data�for�DOOFF‰BSR‡DOOFF�turn�off�channel0‰MULU†#6,D4�point�to�data�field�assoc.with�chan.5‰ADD‡#ACONTRY,D4‰add�offset�to�1st�channel�data�field‰ADD‡#4,D4�add�in�size�of�ACOID+‰MOVE.L„ACOTBL,A2‹get�addr.�of�ACOTBL�to�A2,‰MOVE.L„CCBTASKA(A5),A6…A6�=�users�TCB�addr. ‰CLR.L…D72‰MOVE.B„ACONMAX(A2),D7†get�max�#�of�ACO-ID's�to�D7#‰MOVE.L„CCBMNEM(A5),D6†get�CCB�name!PLS001ƒEQU‡*“find�matching�ACO-ID!‰MOVE.L„ACOID(A2),D3ˆACO-ID�to�D3(‰CMP.L…D3,D6�does�CCB�name�match�ACO-ID?‰BEQ.S…PLS002Žbranch�on�match*‰ADDA.W„#ACOIDLNG,A2ˆadd�offset�to�next�ID"‰SUB.B…#1,D7�end�of�possible�ID's?$‰BMI.S…PLS003Žbranch�on�ID�not�found‰BRA‡PLS001Žcheck�next�ID PLS002ƒEQU‡*-‰MOVE.W„ACOCNIF(A2,D4),D0ƒconfiguration�to�D0(‰BSR.S…NOTFYUSRŒsee�if�wakeup�or�quevent PLS003ƒEQU‡*‰POPALL‰RTE*‰PAGEF**********************************************************************$*‚BINARY�to�BIT-map�conversion�in�D5@*…Produces�a�1�in�D5�bit�corresponding�to�the�binary�value�in�D5*…(up�to�bit�15).A*…For�input�>�15�binary,�the�resultant�pattern�in�D5�is�undefined*BIN_BIT‚ALLOCATE‚BITMAP‰CLR.L…BITMAP(A7)‰ADD.W…#1,BITMAP(A7) LOOP…EQU‡* ‰TST.W…D5 ‰BEQ.S…BINBITX�exit�on�bit�found‰ROL.W…BITMAP(A7) ‰SUB‡#1,D5 ‰BRA.S…LOOP* BINBITX‚EQU‡*‰MOVE.W„BITMAP(A7),D5'‰ADD.L…#8,A7�DEALLOCATE�BITMAP�on�stack‰RTS*‰PAGEA*‚NOTIFY�USERƒby�means�of�que�event�or�wak eup�as�specified�in�the*”channel�configuration�word.*ƒINPUT�PARAMETERS:'*�A2:�Address�of�channel�name�in�ACOTBL;*�D4:�Offset�from�channel�name�to�channel�data�field�(base) *™in�ACOTBL.*�A5:�Address�of�channel�CCB.*�A6:�User's�TCB�address#*�D2:�$0C01�*GNOTFYUSR�MOVE.WƒACOCNIF(A2,D4),D0�get�configuration�from�channel�ACOTBL#‰BTST†#15,D0‹default�configuration? ‰BNE.S…NOTIFX1‰BTST…#0,D0‰no,�determine:�wake-up=1�or�q-event=0 ‰BNE.S…NOTIFA*ŽQueue�event;�data�staging:$*ŽD2�=�$0C01� *ŽD3�=�ACOID*ŽD4�=�Mem�mapped�I/O�address*ŽA6�=�User's�TCB�address*8‰MOVE.L„CCBCHB(A5),D4ƒget�mem.�mapped�I/O�address�staged‰BSR.S…QUEVENT‰queue�the�event‰BRA.S…NOTIFXŠgo�to�exit*+NOTIFAƒMOVE.LƒA6,A0Žstage�users�TCB�address#‰TR0$.WAKEUP�,�issue�wakeup�to�userNOTIFX:‰RTS*ŠPAGE*H*‚QUEVENT�-�queue's�event�to�driving�task�using�data�staged�in�registers *‹as�follows:*‹A6�=�user's�TCB�address&*‹D2�=�$0C01�*‹D3�=�ACOID‚(module�name)&*‹D4�=�mem�mapped�I/O�address�of�board<*†(dumps�contents�of�registers�D2,�D3,�&�D4�to�users�buffer)* QUEVENT‚EQU‡*‰PUSHALL�push�all�regs"‰MOVE.L„A6,A0…stage�user's�address ‰TR0$.QEVNTI*+‰BRA.S…QUEVNTOK‚good�return�for�queue�event+‰BRA.S…QUEVNTER‚bad�return�from�queue�eventQUEVNTOK�EQU‡*‰POPALLŽrestore�all�regs‰RTS QUEVNTER:(‰BRA‡QUEVNTOK‚put�a�break�here�for�debug*‰PAGEF***********************************************************************B* SUBROUTINE TO CHECK ADDRESS BOUNDARIES TO SEE IF ENTIRELY WITHIN*ƒCALLING�TASKS�ADDRESS�SPACE.*#*�ENTRY:ƒD5‚-�NO.�OF�BYTES�TO�CHECK*ŠD6‚-�68000�ADDRESS�(LOGICAL)*ŠA1‚-�TCB�ADDRESS** EXEC ROUTINE#* REGISTERS USED: D0-D1,D3,D6/A0-A1*7*�EXIT:„D6�-�PHYSICAL�ADDRESS�OF�BUFFER�BASE�(IF�LEGAL)*ŠRETURN�TO�PC„FOR�GOOD�ADDRESS*”PC+2‚FOR�BAD�LENGTH*”PC+4‚FOR�BAD�ADDRESS*F***********************************************************************-IOHADRCK‚BTSTƒ#0,D6‘Must�be�on�word�boundary.)ŠBNE.S‚IOHADR4�Branch�if�bad�buffer�base.ŠTST.L‚D5”Length�can't�be�zero.1ŠBEQ.S‚IOHADR8�Don't�go�to�logphy�with�zero�count1ŠMOVE.L�TCBTST(A1),A0‰Address�of�task�seg.�table. ŠTR0$.LOGPHY*.ŠBRA.S‚IOHADR8�Branch�for�good�address�return.0ŠBRA.S‚IOHADR6�Branch�for�bad�byte�count�return.(ŠTST.L‚D5”Was�an�entry�pointer�returned.#ŠBEQ.S‚IOHADR4�Branch�if�no�-�ERROR)ŠTST.B‚7(A0,D5)ŽIs�this�an�MMIO�segment�?ŠBNE.S‚IOHADR8�Yes,�OK.3IOHADR4ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.3IOHADR6ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.IOHADR8ƒRTSšReturn.*ŠPAGEH*************************************************************************!* INTERRUPT SIDE FOR IOH HANDLING*?*ƒPURPOSE:‚HANDLE�ACKNOWLEDGEMENTS�AND�MESSAGE�COMPLETIONS�FROM2*ˆTHE�IOH.‚OPERATES�AT�HARDWARE�INTERRUPT�PRIORITY=*ˆLEVEL�AS�A�SUBROUTINE�TO�THE�FIRST�LEVEL�INTERRUPT�HANDLER.*+*ƒENTRY:‚JSR‚FROM�INTERRUPT�HANDLER�ROUTINE*‹A0�-�WORK�REGISTER *‹A1�=�SELF*‹A5�=�ADDRESS�OF�CCB*‹D0�=�WORK�REGISTER*/*ƒEXIT:‚RTS�-�BACK�TO�INTERRUPT�HANDLER�ROUTINE*/*ƒNOTE:ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***@*ƒThis�routine�is�called�only�by�the�common�interrupt�handler�in'*ƒRMS68K.ƒThe�common�interrupt�handler:7*ƒDOES‚NOT‚PRESERVEƒVALUES‚IN‚REGISTERS‚BEFORE‚THE‚CALL?*ƒThis�interrupt�handler�MUST�PRESERVE�all�data�&�address�regs.**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P***4*ƒIf�channel�is�off-line�or�not�attached,�just�exit.H*************************************************************************<*‹Find�ACO�TABLE�module�(board)�name�which�matches�CCB�name:*3ACOINTƒMOVEM.LƒA0-A6/D1-D7,-(A7)ƒsave�all�except�D01‰ALLOCATE‚ACOTADR,CHANUM†allocate�local�variables-‰MOVE.L„ACOTBL,A2‹get�address�of�ACOTBL�to�A2 ‰CLR.L…D76‰MOVE.B„ACONMAX(A2),D7†get�max�number�of�ACOID's�to�D7#‰MOVE.L„CCBMNEM(A5),D0†get�ccb�name2IOHI011‚EQU‡*‡find�matching�ACOID�loop�entry�point*‰MOVE.L„ACOID(A2),D3ˆget�ACOID�for�staging'‰CMP.L…D3, D0�does�CCB�name�match�ACOID?#‰BEQ.S…IOHI020�branch�on�name�match.‰ADDA.W„#ACOIDLNG,A2ˆadd�offset�to�next�ACOTBL#‰SUB.B…#1,D7�test�for�end�of�ACOTBL4‰BMI.S…IOHIPX„error,�exit�on�ACO-ID�not�found�in�CCB ‰BRA‡IOHI011D*„Found�matching�names,�now�get�number�of�interrupting�channel�to�D2C*„on�this�board,�use�non-existant�chan.�8�to�indicate�no�interrupt.5IOHI020‚STORE…A2,ACOTADRŠsave�ACOTBL�address�on�stack,‰MOVE.L„#$0C010008,D2‡init�para�fields�in�D2*‰STORE…D2,CHANUM‹save�chan.#�&�return�code>*„Compute�address�of�field�in�ACOTBL�having�user's�TCB�address ‰CLR.L…D4!‰MOVE.B„D2,D4�get�channel‚to�D4.B$IOHIPXƒEQU‡*“'ACOINT'�procedure�exit-‰MOVE.L„#0,D0�get�int.�claim�check(�0�=�none)*„dealocate�ACOTADR,CHANUM#‰ADD‡#12,A7Žrelease�local�variables0‰MOVEM.Lƒ(A7)+,A0-A6/D1-D7ƒrestore�all�except�D0-‰AND‡#$FFFE,SR‹signal�CMR�'int.�not�from�ACO'‰RTS**‰ENDééééé=/*=/*†M615LIB.AF=/*7=/* Chain file to assemble FORTRAN-callable subroutines)=/* to interface with the MVME615 driver.=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M615LIB.LS=/*=/IFC \1ƒ=ARG�M615LIB.LS=/ENDIF=/*=ASM M615LIB.SA,M615LIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDééééé é1FTACO…IDNTƒ1,0�ACO�subroutines**‰FORTRAN�callable�subroutines*‰for�ACO�driver�calls*$*‰CALL�ACOCMD(aco_id,param_blk_addr)*‰where�ACOCMD�may�be:*)*‰CALL�ACOPEN(aco_id,param_blk_addr)…open**‰CALL�ACOCLS(aco_id,param_blk_addr)…close.*‰CALL�ACOOUT(aco_id,param_blk_addr)…output�on/*‰CALL�ACOOFF(aco_id,param_blk_addr)…output�off+*‰CALL�ACOSTA(aco_id,param_blk_addr)…status2*‰CALL�ACOPLS(aco_id,param_blk_addr)„output�pulsed*,*‰All�arguments�for�the�calls�are�identical.7*‰The�contents�of�the�param_blk�for�each�call�is�unique*‰to�the�call.*6*‰All�the�command�subroutines�call�a�common�subroutine3*‰ACOSET�to�build�the�initiate�I/O�parameter�block.**‰STACK�FOR�ALL�CALLS:*7*‰deepest�stack:�(stack�address�stays�at�ACOSET�return)0*˜command�codeƒ2�bytes�(initiate�I/O�param.�blk) *˜n/aŒ2�bytes*˜aco_id‰4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes,*˜command�addrƒ4�bytes�(aco�command�address)**˜command�lng„2�bytes�(aco�command�length)-*˜ACOSET�return‚4�bytes�deepest�stack�address *˜A3�4�bytes *˜A2�4�bytes *˜A1�4�bytes *˜D0�4�bytes*‰entry�stack:ƒreturn‰4�bytes*˜^param_blk_adr�4�bytes*˜^aco-idˆ4�bytes* ŠSECTION�9!ŠXDEFƒACOPEN,ACOCLS,ACOOUT,ACOOFFŠXDEFƒACOSTA,ACOPLS*$*‰CALL�ACOPEN(aco_id,param_blk_addr)*‰open�and�configure�channels*1ACOPEN„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers3ŠBSR„ACOSET�set-up�the�initiate�I/O�parameter�block)ŠMOVE.L�#1,(A2)Œset�the�open�command�codeACOPN00ƒCLR.L‚D0‘clear�for�use'ŠMOVE.W�4(A2),D0‹get�number�of�channelsŠASL.L‚#2,D0Žmultiply�by�4.ACOPN05ƒADD.L‚#6,D0Žadd�in�the�6�byte�overhead-ACOPN10ƒMOVE.W�D0,(A1)Œset�the�command�length-ŠMOVE.L�A3,A0ŽTRAP�#1�parameter�block�address#ŠMOVE.L�#60,D0�CMR�directive�numberŠTRAPƒ#1‘call�RMS68K'ŠMOVE.W�D0,(A2)Œset�the�returned�status)ŠMOVEM.L�(A7)+,D0/A1-A3„restore�registers!ŠMOVE.L�(A7)+,A0‹put�return�in�A0 ŠLEA„8(A7),A7‹clean�up�the�stackŠJMP„(A0)�return�to�user*$*‰CALL�ACOCLS(aco_id,param_blk_addr)"*‰close�all�channels�for�this�user:DC8K *1ACOCLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚ACOSET�set-up�the�initiate�I/O�parameter�block*ŠMOVE.L�#2,(A2)Œset�the�close�command�code&ŠMOVE.W�#4,D0ŽACO�close�command�lengthŠBRA„ACOPN10Œgo�do�the�CMR�call*$*‰CALL�ACOOUT(aco_id,param_blk_addr)'*‰activate�output�on�requested�channels*1ACOOUT„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚ACOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#3,(A2)Œset�the�output�command�code*ACOUT10ƒMOVE.Wƒ#6,D0Œset�up�command�lengthŠBRA„ACOPN10Œgo�do�the�CMR�call*$*‰CALL�ACOOFF(aco_id,param_blk_addr))*‰deactivate�output�on�specified�channels*1ACOOFF„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚ACOSET�set-up�the�initiate�I/O�parameter�block/ŠMOVE.L�#4,(A2)Œset�the�output�off�command�code4ŠBRA„ACOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�ACOSTA(aco_id,param_blk_addr))*‰read�input�status�on�specified�channels*1ACOSTA„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚ACOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#5,(A2)Œset�the�status�command�code4ŠBRA„ACOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�ACOPLS(aco_id,param_blk_addr)>*‰activate�output�for�x#�of�milliseconds�on�specified�channels*1ACOPLS„MOVEM.L�D0/ A1-A3,-(A7)„save�some�registers5ŠBSR.S‚ACOSET�set-up�the�initiate�I/O�parameter�block2ŠMOVE.L�#8,(A2)Œset�the�pulsed�output�command�codeŠCLR.L‚D0‘clear�for�use,ŠMOVE.W�4(A2),D0‹get�specified�#�of�channelsŠASL.L‚#2,D0Žmultiply�by�6ŠADD.W‚4(A2),D04ŠBRA„ACOPN05Œgo�set�command�length�&�do�the�CMR�callŠPAGE*4*‰ACOSET�set�up�the�CMR�initiate�I/O�parameter�block,*‰returns:ƒA1=address�for�ACO�command�length(*”A2=ACO�command�parameter�block�address)*”A3=initiate�I/O�parameter�block�address*(ACOSET„CLR.W‚-2(A7)�clear�command�length-ŠLEA„-2(A7),A1Šsave�address�of�command�length$ŠMOVE.L�24(A7),A0Šget�param_blk_addr%ŠMOVE.L�A0,-6(A7)Šsave�param_blk_addr,ŠMOVE.L�A0,A2Žsave�param_blk_addr�for�returnŠCLR.L‚-10(A7)Œnot�usedŠCLR.L‚-14(A7)Œnot�usedŠCLR.L‚-18(A7)Œnot�usedŠMOVE.L�28(A7),A0Šget�aco_idŠMOVE.L�(A0),-22(A7)‡get�aco_idŠCLR.W‚-24(A7)Œnot�used0ŠMOVE.W�#$0700,-26(A7)…initiate�I/O�command�code4ŠLEA„-26(A7),A3‰initiate�I/O�parameter�block�addressŠRTS—return�to�caller*ŠEND*éééééé=/*=/*†M625DRV.AF=/*>=/* Chain file to assemble the MVME625 DC OUTPUT device driver=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M625DRV.LS=/*=/IFC \1ƒ=ARG�M625DRV.LS=/ENDIF=/*$=ASM M625DRV.SA,M625DRV.RO,\1;MRZ=75=/*{ Included files are:=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.TR1RTCD.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.M625DRV.EQ=/*}=/*=ENDééé éééS*!*…MVME�625�DC�OUTPUT�BOARD�DRIVER *…copyrighted�1983�MOTOROLA�INC. *œTOM�KRYKA* ‰LLEN�120 ŠTTL„STR.EQŠINCLUDE�9995.&.STR.EQ ŠTTL„TCB.EQ‰PAGEŠINCLUDE�9995.&.TCB.EQŠTTL�TR1RTCD.EQ‰PAGEŠINCLUDE�9995.&.TR1RTCD.EQ ŠTTL�CCB.EQ‰PAGEŠINCLUDE�9995.&.CCB.EQ ŠTTL�LV5.EQ‰PAGEŠINCLUDE�9995.&.LV5.EQŠTTL�9995.&.M625DRV.EQ‰PAGEŠINCLUDE�9995.&.M625DRV.EQŠTTL�MVME625�DRIVER‰PAGE#M625DRV‚IDNTƒ1,0‰DCO�DRIVERƒ4/21/83J****************************************************************************ƒDR625�--�REV.�1.00�7/5/83*+*ƒPurpose:‚MVME�625�DC�OUTPUT�BOARD�HANDLER*/*ƒEntry:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER-*ƒExit:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION**ƒCODE�IS�RE-ENTRANT*H*-----------------------------------------------------------------------********************************* CHANNEL CONTROL BLOCK (CCB) *********************************B*ƒContains�channel�device�dependent�description�and�data�areas�for*ƒI/O�handler.*ŠOFFSET‚CCBDDP*H* I/O HANDLER DATA AREA *************************************************CCBFLG„DS.B„2ŒFlags(CCBERAD1‚DS.B„4ŒError�debug�save�address2CCBQVER1‚DS.B„4ŒEvent�queueing�error�debug�address7CCBCCB„DS.B„4ŒPhysical�address�of�command�packet�(IOCB)CCBTASKB‚DS.B„4ŒBuffer�task�TCB-CCBPKT„DS.B„18‹Event�work�area�(command�tour)0CCBCPKTƒDS.B„18‹Event�work�area�(interrupt�tour)(CCBPTR„DS.B„4ŒPhysical�address�of�bufferCCBLEN„DS.B„4ŒLength�of�buffer0CCBPTR1ƒDS.B„4ŒPhysical�address�of�2ndary�buffer&CCBLEN1ƒDS.B„4ŒLength�of�2ndary�buffer*CCBCID„DS.B„4ŒCMR�parameter�block�id�(DCB)CCBCOPTƒDS.B„2ŒIOCB�options#CCBCFIGƒDS.B„$26ŠConfiguration�data**‰56�bytes�remain*9*‰CCBFLG�DEFINITIONS:�if‚CCBFLG.B�if�not�0�the�DCO�module$*�for�the�CCB�cannot�be�used�for�the*�following�reasons:*9*‰CCBFLG.B�=�$FA�=�CCB�allocation�exceeded�#�of�specified/*šdevices�-�no�room�in�DCO�table�for�the�module!*’=�$FC�=�no�DCOTBL�was�allocated \KeGm2u=}9…9�@•D�@¥<­7µ<½5Å=Í?ÕAÝDåJí>õ&/*’=�$F5�=�no�room�in�DCOTBL�for�this�DCO�module*™(incorrect�table�allocation)*‰PAGE ‰SECTION�8 ‰XREF�DCOTBLJ****************************************************************************‚DCO�SERVICE�VECTOR�TABLE*L*****************************************************************************#*ˆDC.L†DCOINTŽinterrupt�svc�address!*ˆDC.L†DCOCMDŽcommand�svc�address)*ˆDC.L†DCOINIT�initialization�svc�address*?*Below are the new offset form of service pointers, for new CMR*DCODVR:(‰DC.L†DCOINT-DCODVR†interrupt�svc�offset*‰DC.L†DCOCMD-DCODVR†command�service�offset.‰DC.L†DCOINIT-DCODVR…initialization�svc�offset‰DC.L†0‰Reserved‰DC.B†0“number�of�extra�pages‰DC.B†0,0,0�reserved‰DC.L†0,0,0�reserved*3*ƒ---ƒ---…CONFIGUR ATION�CONTROL�INFORMATION…---ƒ---*$‰DC.B…'070583'ƒdate�of�last�assembly'‰DC.B†'�'‡space�means�no�patches�in�.LO#‰DC.B†'4'‡major�Versados�revision�#*‰PAGEJ****************************************************************************‰COMMAND�TABLE�&�JUMP�TABLE*:*‰These�are�used�by�the�command�service�routine�to�jump�to.*‰the�appropriate�routine�to�handle�a�command.*J***************************************************************************CMDTBL:ŠDC.WƒDCOPEN�OPEN�command.ŠDC.WƒDCOCLS�CLOSE�command.ŠDC.WƒDCOUTŽOUTPUT�ON�command. ŠDC.WƒDCOOFF�OUTPUT�OFF�command.ŠDC.WƒDCOSTA�STATUS�command.ŠDC.WƒX1‘(not�used)ŠDC.WƒX2‘(not�used)#ŠDC.WƒDCOPLS�PULSED�OUTPUT�command.=NUMCMDSƒEQU„(*-CMDTBL)/2‡The�number�of�commands�in�the�table.*9JMPTBL:ƒDC.WƒOPEN-*�Biases�to�the�corresponding�routines. ŠDC.WƒCLOSE-* ŠDC.WƒOUTON-*ŠDC.WƒOUTOFF-* ŠDC.WƒSTAT-*ŠDC.WƒENABLE-*ŠDC.WƒDSABLE-* ŠDC.WƒPLSO-**7JMPOFF„EQU„JMPTBL-CMDTBL†Offset�between�the�two�tables.*ŠPAGEJ***************************************************************************+*ˆDCO�DRIVER�INITIALIZATION�SERVICE�ROUTINE*>*ˆThe�driver�is�entered�here�for�each�CCB�allocated.‚More�than:*ˆone�CCB�may�be�allocated�for�each�DCO�module.‚One�CCB�is%*ˆallocated�for�each�interrupt�level.?*ˆThis�routine�checks�to�see�if�there�is�room�in�the�DCOTBL�for=*ˆthe�device�ID.‚It�saves�the�device�ID�and�the�memory�mapped**ˆI/O�address�of�the�device�in�the�DCOTBL.*:*ˆAn�error�code�is�saved�in�the�CCB�if�this�CCB�allocation=*ˆexceeds�the�maximum�number�of�CCB's�specified�during�SYSGEN:*ˆ(SYSGEN�parameter�NDCO1),�if�no�DCOTBL�exists�or�no�room*ˆin�the�table�for�this�module.*$*ˆEntry:‚all�registers�are�available*�A5�=�CCB�address*I**************************************************************************,*‚single�exit�&�pointer�(A0-A6)�preservation*DCOINIT:ŠPUSHPOINT‘save�pointers3ŠMOVE.LƒCCBCHB(A5),A0„get�memory�mapped�I/O�address$ŠMOVE.L�DCOTBL,A1Šget�DCOTBL�addressŠCMP.L‚#0,A1Žis�there�one?&ŠBNE.S‚DCOINIT1‹branch�if�have�a�table8ŠMOVE.B�#DCONTBL,CCBFLG(A5)�set�no�table�error�condition!ŠBRA.S�DCOINEX1Œgoto�error�returnDCOINIT5‚TST.L‚(A1,D3)Œlook�for�an�entry�slot�to�save�this�guy5ŠBMI.S‚DCOINIT6‹branch�if�this�slot�is�empty�-�use�it.ŠADD.W‚#IOLNG,D3‰not�empty,�bump�to�next�entry"ŠSUB.B‚#1,D4Ždecrement�the�counter(ŠBNE.S‚DCOINIT5‹branch�if�more�to�search4ŠBRA„DCOEXTER‹error�if�got�here-�no�room�for�the�map>DCOINIT6‚MOVE.L�D2,(A1,D3)‰save�this�memory�mapped�I/O�addressŠMOVE.L‚#0,D0�write�0�to�regŠMOVE.B‚D0,IOADR(A0)1DCOEXIT1‚CLR.B‚CCBFLG(A5)‰set�for�good�allocation3ŠMOVE.L�CCBCHB(A5),A1†get�memory�mapped�I/O�address'DCOINEX1 :�POP_POINT‘recall�all�pointersŠRTS*ŠPAGEJ***************************************************************************$*‰DCO�DRIVER�COMMAND�SERVICE�ROUTINE*6*‹PARAMETER�ADDRESS�AND�BOUNDARY�CHECKS�HAVE�BEEN�MADE**ƒEntry:‚JSR�FROM�CMR�HANDLER.*‹A2�-�PHYSICAL�ADDRESS�OF�CMR�PARAMETER�BLOCK*‹A5�-�PHYSICAL�ADDRESS�OF�CCB*5*ƒExit:‚RTS�-�PARAMETER�BLOCK�VALIDATION�STATUS�IN�D0**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A**P**PP*"*”A3�=�DCO�PARAMETER�BLOCK�ADDRESS*”A6�=�REQUESTOR�TCB�ADDRESS**ƒCODE�IS�RE-ENTRANT*J***************************************************************************)*‰Convert�logical�PB�address�to�physical.*DCOCMD„CLR.L‚D5;ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�DCO�parameter�block:ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�DCO�parameter�block+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚CMD010�Good�return.ŠNOP—Bad�length�return. ŠCLR.L‚D0;ŠMOVE.W�#RTCDPBLK,D0‡Set�up�invalid�parameter�block�addressŠBRA.S�DCOCEX1�goto�error�exit*!*‰see�if�passed�the�initialize�ok*7CMD010„MOVE.LƒD6,A3ŒStage�phys.�addr.�of�DCO�para.�blk. ŠCLR.L‚D04ŠTST.B‚CCBFLG(A5)‰error�code�set�in�CCB�during�INIT?/ŠBEQ.S‚CMD020�branch�if�no�error�code,�continue$ŠMOVE.B�CCBFLG(A5),D0†set�error�codeŠBRA.S‚DCOCEX2Œgoto�error�exit CMD020„EQU�**,*‰get�DCOTBL�address�into�A4�for�command�use* ŠMOVE.L�DCOTBL,A4ŠDCOTBL�address)ŠCMP.L‚#'!DCO',(A4)‡really�is�the�DCOTBL?,ŠBEQ.S‚CMD030�branch�if�really�is�the�DCOTBL4ŠMOVE.W�#DCONTBL,D0ˆset�error�return�code�-�no�tableŠBRA.S‚DCOCEX2Œand�return**‰find�DCO-ID�in�DCOTBL*‰A1�=�entry�address*0CMD030„MOVE.L�XIOCID(A2),D0†get�specified�DCO-ID(ŠMOVE.B�DCONMAX(A4),D1…max�#�of�DCO-ID's$ŠMOVE.L�#DCONTRY,D2ˆbump�past�header"FNDDCO10‚CMP.L‚(A4,D2),D0‰a�match?!ŠBEQ.S‚FNDDCO20‹branch�if�a�match&ŠADD.W‚#DCOIDLNG,D2‡bump�to�next�entry1ŠSUB.L‚#1,D1Ždecrement�number�of�entries�to�check&ŠBNE.S‚FNDDCO10‹branch�if�more�entries.ŠMOVE.W�#DCONID,D0‰error�-�DCO-ID�not�in�table5ŠBRA.S‚DCOCEX2Œreturn�to�CMR�with�error�condition�set+FNDDCO20‚MOVE.L�A4,A1Žbass�address�of�tableŠADD.L‚D2,A1Žaddress�of�entry (*‰Find�the�command�in�the�command�table.*-ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table.+ŠMOVE.W�CMDCOD(A3),D6†get�DCO�command�code.8CMDSRCHƒCMP.W‚(A0)+,D6‹Search�the�table�for�the�command.ŠDBEQƒD0,CMDSRCH3ŠBNE.S‚CMDERR�If�we�found�the�command�in�the�table,8ŠADD.L‚#JMPOFF-2,A0‡get�the�corresponding�entry�from�the5ŠMOVE.W�(A0),D0Œjump�table�and�jump�to�the�routine�to"ŠJMP„(A0,D0.W)Šhandle�the�command.DCMDERR„MOVE.W�#DCOINVD,D0ˆdidn't�find�command�code�-�exit�with�errorCDCOCEX2ƒMOVE.WƒD0,CMDSTA(A3)„write�error�code�to�users�DCO�para�blk DCOCEX1ƒRTS*ŠPAGEL******************************************************************************‰OPEN�COMMAND*A*‰This�command�assigns�the�logical�connection�between�a�user�task9*‰and�specified�channels�within�an�DCO�module.�8�channels/*‰maximum�may�be�specified�in�one�open�command.*#*‰DCO�OPEN�command‚parameter�block: *�DS.W‚1„returned�command�status*�DS.W‚1„command�code�(01)*�DS.W‚1„#�of�channels�to�open*�DS.W‚1„1st�channel�number*�DS.W‚1„channel�configuration*’.*�DS.W‚1„nth�channel�number*�DS.W‚1„channel�configuration**‰configuration�word:+*�bit�0=1�wake-up�task�on�output�pulse�done-*•=0�queue�event�to�task�on�output�pulse�done2*�bit�15=1�use�default�configuration(ignore�bit�0) *•=0�use�specified�configuration**‰Default�configuration:,*�no�wakeup�or�queue�event�on�pulsed�output.B*‰When�default�configuration�is�specified,�the�actual�configuation9*‰is�saved�in�DCOTBL.�The�task�TCB�address�is�also�saved.*)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4�=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�CLR IOM,�SETIO,�DOIO*K*****************************************************************************‰see�if�channel�already�opened*$OPEN†PUSHPOINT‘save�all�address�regsŠALLOCATEƒCHCONFIG2ŠBSR�CLRIOM�clear�(to�$FF)�the�IO�map�for�this�DCOŠCLR.L‚D7‘channel�counter:ŠCMP.W‚#DCONID,D0‰an�error�returned�from�clearing�the�map?)ŠBEQ.S‚OPNOID�branch�if�an�error�returned$ŠCLR.L‚D2‘channel�offset�into�DCOTBL)ŠCLR.L‚D1‘offset�into�DCO�parameter�block1ŠMOVE.W�CMDCHN(A3),D0†get�#�of�channels�specified/ŠBLE.S‚OPNINC�branch�if�negative�or�zero,�error0ŠCMP.W‚#8,D0�cannot�specify�more�than�8�channels-ŠBGT.S‚OPNINC�branch�if�greater�than�8,�errorGOPEN10„MOVE.W�NUMCHAN(A3,D1),D2‚get�channel�number�from�DCO�param.�blk.!ŠCMP.W�#7,D2�insure�channel�#�<�8 ŠBGT.S�OPNINVŠMOVE.W�D2,D5Žsave�it0ŠMULUƒ#CHANLNG,D2ˆget�channel�offset�into�DCOTBLŠADD.L‚#4,D2Žbump�past�DCO-ID+ŠTST.W‚(A1,D2)Œthis�channel�already�opened?-ŠBPL.S‚OPNOPN�branch�if�already�opened,�errorŠADD.L‚#1,D7Žcount�this�channel@ŠMOVE.W�CHNCNFG(A3,D1),D3‚get�configuration�from�DCO�param.�blk.-ŠSTORE„D3,CHCONFIG†save�channel�configuration*0*‰save�TCB�address�and�configuration�information*.ŠLOAD…D3,CHCONFIG†recall�channel�configuration+ŠBSR.S‚SETIO�go�set�IO�map�for�this�channel5ŠCMP.W‚#DCONID,D0‰an�error�found�during�the�save�map?*ŠBEQ.S‚OPNERR�branch�if�an�error�was�found6ŠMOVE.W�D3,DCOCNIF(A1,D2)‚save�configuration�in�DCOTBL)ŠMOVE.L�A6,DCOTCB(A1,D2)ƒsave�TCB�address4ŠADD.W‚#OPNTRY,D1‰bump�to�next�DCO�param.�blk.�entry3ŠSUB.W‚#1,D0Ždecrement�number�of�channels�specified)ŠBGT„OPEN10�branch�if�more�channels�to�do,ŠBSR.S‚DOIOŽgo�set�the�IO�hardware�registers!ŠCMP.W‚#DCONID,D0‰an�error�found?7ŠBEQ.S‚OPNERR�branch�if�an�error�was�found�-�don't�openŠCLR.L‚D0‘set�for�good�returnŠBRA.S‚OPNXIT�go�return�to�CMR**‰open�errors�here*5OPNINVƒMOVE.W„#DCOICNS,D0‰set�invalid�channel�#�error ‰BRA.S…OPNXIT8OPNINCƒMOVE.W„#DCOINC,D0‰set�invalid�#�of�channels�error‰BRA.S…OPNXIT‹exit;OPNOIDƒMOVE.W„#DCONID,D0‰set�DCO�module�not�allocated�error‰BRA.S…OPNXIT�go�return�to�CMR9OPNOPNƒMOVE.W„#DCOPND,D0‰set�channel�already�opened�error*)*‰reset�any�opened�channels�to�not�opened*%OPNERR„TST.W‚D7‘any�channels�to�undo?3ŠBEQ.S‚OPNXIT�branch�if�none�to�undo,�return�to�CMR&ŠMOVE.W�#$FFFF,D3Šset�'un-opened'�codeŠCLR.L‚D1‘clear�for�use6OPNERR10‚MOVE.W�NUMCHAN(A3,D1),D2‚get�a�channel�number$ŠMULUƒ#CHANLNG,D2ˆget�channel�offsetŠADD.L‚#4,D2Žbump�past�headers*ŠMOVE.W�D3,(A1,D2)‰set�this�entry�unopened-ŠADD.W‚#OPNTRY,D1‰bump�to�next�channel�numberŠSUB.W‚#1,D7Ždecrement�counter&ŠBGT.S‚OPNERR10‹branch�if�more�to�undo*…Fall�into�exit* OPNXIT EQU *)ŠADD.L„#8,A7ŒDEALLOCATE�CHCONFIG�on�stackŠPOP_POINT‘restore�all�pointers ŠBRA�NRMEXIT*ŠPAGEK*****************************************************************************‰SETIO*6*‰Build�the�IO�map�entries�for�the�specified�channels.*‰Builds�1�entry�per�call*‰Map�is�in�DCOTBL.**‰Entry:�A4ƒ=�DCOTBL�address*�D3.W�=�channel�configuration*�D5.B�=�channel�number*7*‰Exit:‚D0.W�=�DCONID�if�map�entry�not�found,�otherwise*—D0�unchanged *‰Uses:�D4,D6*‰Entry�point�=�SETIO*‰Exit�point‚=�SETIORT**ˆPrivate�subroutine�for�OPEN*$* Single exit & pointer preservation*L******************************************************************************‰find�map�entry* SETIO EQU *ŠPUSHPOINT‘save�all�pointersŠMOVE.L�D7,-(A7)‹save�D73ŠMOVE.W�DCOIO(A4),D7†get�offset�to�start�of�IO�maps.ŠMOVE.B�DCONAL(A4),D6†get�#�of�DCO'S�allocated3ŠMOVE.L�CCBCHB(A5),D4†get�memory�mapped�I/O�address;SETIOFD‚CMP.L‚IODDR(A4,D7),D4ƒfind�the�matching�I/O�addressŠBEQ.S‚SETIO00‹branch�if�found#ŠADD.W‚#IOLNG,D7‰bump�to�next�entryŠSUB.B‚#1,D6Ždecrement�counter/ŠBNE.S‚SETIOFD‹branch�if�more�entries�to�search>ŠMOVE.W�#DCONID,D0‰set�for�fatal�error�-�this�shouldn't�happenŠBRA.S„SETIORT‰return�to�caller**‰determine�channel�number*SETIO00‚CLR.L‚D6‘clear�for�use/ŠMOVE.B�D5 ,D6Žcopy�channel�number�to�work�space**‰CHANNEL�0-7�as�output�channel*/ŠBSETƒD5,DODR07(A4,D7)ƒset�ddr�image�for�output"SETIORT‚MOVE.L�(A7)+,D7‹restore�D7ŠPOP_POINT‘restore�all�pointersŠRTS—return�to�caller*ŠPAGED**********************************************************************‰DOIO*6*ˆCopy�the�data�information�from�the�IO�register�image"*ˆ(in�the�map)�to�the�IO�register.**ˆENTRY�PARAMETERS:*�A4�=�address�of�DCOTBL*�A5�=�address�of�CCB*)*‰Exit:‚D0.W�=�DCONID�if�IO�map�not�found*�D0.W�=�0�if�no�errors�found**‰Uses:�A0,D1,D6,D7*#* Single exit, pointer preservation*D********************************************************************* DOIO EQU *ŠPUSHPOINT’save�all�pointers!ŠMOVE.L�D7,-(A7)‹save�register�D7*ŠMOVE.W�DCOIO(A4),D7†get�offset�to�IO�maps$ŠMOVE.B�DCONAL(A4),D6†get�#�of�DCO'S3ŠMOVE.L�CCBCHB(A5),D1†get�memory�mapped�I/O�address*‰This�command�deactivates�outputs�for�specified�channels�that9*‰have�previously�been�opened�for�output�by�the�same�task<*‰requesting�this�activation.‚The�parameter�block�is�checked<*‰for�errors�before�any�output�is�deactivated.‚No�channel�is#*‰deactivated�if�an�error�is�found.*)*‰DCO�OUTPUT�OFF�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�044*‰DS.Wƒ1ƒbit�mask�containing�channel�#'s�to�activate*)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4 �=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�DOOFF*%* Single exit with pointers preserved*L*****************************************************************************OUTOFF:ŠPUSHPOINT‘save�all�pointers2ŠCLR.L‚D3‘flag�to�ck�para.�blk.�before�stop�output'ŠMOVE.L�#4,D1Žbump�past�DCO-ID�in�table!ŠCLR.L‚D2‘use�for�channel�counterŠCLR.L‚D0‘clear�for�use+ŠMOVE.W�CMDCHN(A3),D0†get�channels�to�start0ŠMOVE.WƒD0,D3Œcopy�chan.�to�turn�off�to�work�reg+OUTOF20ƒBTSTƒD2,D0Ždeactivate�this�channel?0ŠBEQ.S‚OUTOF30Œbranch�if�no�-�check�next�channel5ŠCMP.L‚DCOTCB(A1,D1),A6ƒchannel�belongs�to�this�user? ŠBNE„OUTONERŒbranch�if�no,�error.ŠBCLR…D2,D3Œnegate�check�flag�for�this�channel$ŠTST„D3‘is�all�of�parameter�checked?(ŠBNE.S‚OUTOF30Œbranch�if�not�all�checked5ŠBSR.S‚DOOFFŽgood�para.�block�-�go�deactivate�channelŠBRA.S„OUTOFFXŠnormal�exit/OUTOF30ƒADD.L‚#1,D2Žbump�to�next�channel�number-ŠADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry&ŠCMP.L‚#8,D2�checked�all�the�channels?/ŠBNE.S‚OUTOF20Œbranch�if�more�channels�to�check ŠBRA†OUTONEROUTOFFX�EQU�*šnormal�exitŠPOP_POINT‘recall�all�pointersŠCLR.L„D0�signal�no�errorsŠBRA�NRMEXIT�normal�exit*‰PAGE*;* DOOFF talks directly to the IO reg and turns off outputs.G* On entry: D0 has bit map of channels to turn off (a 1 means turn off)*‹A5�has�address�of�user�CCB:*ˆDOOFF�is�called�by�OUTOFF�and�PULSED�OUTPUT�deactivation DOOFF…EQU†*/ŠMOVE.LƒA2,-(A7)Œsave�address�of�CMR�para�block3ŠMOVE.LƒCCBCHB(A5),A2‡get�memory�mapped�I/O�address)ŠEOR.B„D0,IOADR(A2)†turn�off�selected�0-72ŠMOVE.Lƒ(A7)+,A2Œrestore�address�of�CMR�para�blockŠRTS*ŠPAGEM******************************************************************************"*ˆSTAT�-�GET�OUTPUT�STATUS�COMMANDA*ˆThis�command�reads�the�status�of�specified�output�channels.�The>*ˆchannels�must�have�previously�been�opened�for�output�by�thisC*ˆuser.�The�parameter�block�is�checked�for�errors�before�any�outputA*ˆstatus�is�read.�The�users�parameter�block�is�modified�to�signalB*ˆactive�channels�by�setting�the�corresponding�bit�in�the�bit-maskE*ˆword.�The�corresponding�bit�number�of�inactive�channels�is�cleared.*-*ˆAll�channels�in�a�IO�side�are�read�at�once.*,*‰DCO�OUTPUT�STATUS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�05<*‰DS.Wƒ1ƒbit�mask�containing�channels�numbers�to�read�status$*”(�this�is�also�the�returned�field)*)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4�=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�GTSTAT*M******************************************************************************STAT:ŠPUSHPOINT‘save�all�pointers(ŠCLR.L‚D5‘use�for�returned�status�values2ŠCLR.L‚D3‘flag�to�ck�para.�blk.�before�read�status(ŠMOVE.L�#4,D1Žbump�past�DCO-ID�in�DCOTBLŠCLR.L‚D2‘channel�counterŠCLR.L‚D0‘clear�for�use;ŠMOVE.W�CMDCHN(A3),D0†get�channel�numbers�to�read�status�on3ŠMOVE.W�D0,D3Žcopy�chan�activation�req.�bit�pattern$ŠAND„#$00FF,D0Šmask�all�but�low�byte/STAT20„BTSTƒD2,D0Žread�status�for�this�channel?ŠBEQ.S‚STAT40�branch�if�no5ŠCMP.L‚DCOTCB(A1,D1),A6ƒchannel�belongs�to�this�user?1ŠBNE„OUTONERŒbranch�if�no�-�return�with�error�set0ŠBCLRƒD2,D3Žclr�activation�flag�for�this�channel*ŠTST„D3‘finished�checking�parameter�block?1ŠBNE.S‚STAT40�branch�if�not�finished�checking�yet0ŠBSR.S‚GTSTAT�go�read�status�and�save�in�REG.�D5!ŠBRA.S‚STAT50�goto�procedure�exit3STAT40„ADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry(ŠADD.L‚#1,D2Žbump�to�next�channel�number,ŠBRA„STAT20�branch�to�channel�check�sequence6STAT50„MOVE.W�D5,CMDCHN(A3)†set�returned�status�values&ŠBRA„OUTONEXŒand�return�with�no�errors*‰PAGE*I* GSTAT reads the channels as required by the channel activation bit map,*‡on�a�byte�basis.**‡Data�is�returned�in�D5.**…Channel�data�mask:/BS07…EQU‡$000000FF ‹select�mask�for�channels�0-7* GTSTAT EQU *‰MOVE.L„A2,-(A7)Œpush�A25‰MOVE.L„CCBCHB(A5),A2‡get�memory�mapped�I/O�base�addr8‰MOVE.W„CMDCHN(A3),D0‡get�new�channel�activation�bit�map)‰AND‡#BS07,D0Œselect�channels�0-7�bit�map)‰BEQ.S…GSTATXŽexit�on�no�channels�to�read%‰MOVE.B„IOADR(A2),D5†get�channels�0-7'‰AND.B…D0,D5�mask�off�non-read�channels GSTATX EQU *‰MOVE.L„(A7)+,A2Œrestore�A2‰RTS*ŠPAGEM******************************************************************************$*‰ENABLE�-�ENABLE�INTERRUPTS�COMMAND**‰NOT�USED�THIS�BOARD3*‰IF�CALLED,�EXITS�WITH�INVALID�COMMAND�ERROR�CODE.*0*‰DCO�ENABLE�INTERRUPTS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�06A*‰DS.Wƒ1ƒbit�mask�containing�channel�numbers�to�enable�interrupts)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4�=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCBM******************************************************************************ENABLE:5ENABLERƒMOVE.Wƒ#DCOINVD,D0‡set�code�'invalid�command'&ŠBRA„NRMEXITŒand�return�with�error�set***M******************************************************************************%*ˆDSABLE�-�DISABLE�INTERRUPTS�COMMAND**‰NOT�USED�THIS�BOARD-*‰IF�CALLED,�EXITS�WITH�INVALID�COMMAND�CODE.*1*‰DCO�DISABLE�INTERRUPTS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�07B*‰DS.Wƒ1ƒbit�mask�containing�channel�numbers�to�disable�interrupts)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4�=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCBM******************************************************************************DSABLE:‰BRA.S…ENABLER*‰PAGEM*******************************************************************************ˆPLSO�-�PULSED�OUTPUT�COMMAND*)*‚Entry:�A1�=�address�of�DCO-ID�in�DCOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A4�=�address�of�DCOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‚Exits�to�NRMEXIT*+* Parameter block format for pulsed output:1* DCO parameter block (pointed to by A3 on entry)* *ˆDS.W†1‰returned�command�status*ˆDS.W†1‰command�code*ˆDS.W†1‰number�of�channels<*ƒ---ƒ---ƒ---ƒparameters�for�individual�channelsƒ---ƒ---ƒ---*ˆDS.W†1‰first�channel�number,*ˆDS.L†1‰number�of�milliseconds�for�pulse�on*ˆ.*ˆ.*ˆDS.W†1‰nth�channel�number5*ˆDS.L†1‰number�of�milliseconds�for�nth�channel�pulse*7* EACH CHANNEL IS ACTIVATED IN TURN (NON-SYNCHRONOUSLY)M******************************************************************************@*„Pulsed_Out(IN-LIST�OF�channel�activation�request,�pulse�times;*�OUT-error�code)BPLSO…ALLOCATE�CHANID,DCOPARBK†allocate�channel�id�&�DCO�para�block3‰STORE…A3,DCOPARBK‰save�DCO�parameter�block�address ‰CLR.L…D6’Initiate�pulsed�output ‰CLR.L…D3 ‰CLR.L…D2 ‰CLR.L…D0$*—get�number�of�channels�to�activate<‰MOVE.W„CMDCHN(A3),D0‡get�number�of�chan's�from�DCO�para�blkPLSO1:$‰TST.W…D0’loop�on�#�of�chan.'s�to�do ‰BEQ.S…PLSOX‰CLR.L…D5’get�channel�number‰MOVE.W„NUMCHAN(A3,D6),D5-‰STORE…D5,CHANID‹save�channel�number�on�stackC*„Channel�ID�consists�of�user�CCB�address�+�chan�number�in�LS�byte.+‰MOVE.L„A5,D7�copy�user's�CCB�address�to�D75‰ADD.L…D7,CHANID(A7)‡CHANID�now�has�complete�chan.�ID"‰MOVE.L„D5,D7�copy�channel�#�to�D7,‰BSR‡BIN_BIT�convert�binary�to�bit�map�in�D56‰MULU†#CHANLNG,D7‰compute�offset�to�nth�chan�in�DCOTBL%‰ADD‡#4,D7�bump�to�user�TCB�in�DCOTBL-‰CMP.L…DCOTCB(A1,D7),A6„compare�TCB�addresses1‰BNE.S…PLSOER1�branch�on�channel�not�current�user2*„Get�pulse�time�from�DCO�commmand�parameter�block‰MOVE.L„CHNCNFG(A3,D6),D3%*„IF�pulse�time�>�pulse_min_time�THEN'‰BEQ.S…PLSOER3ƒbranch�on�pulse�time�=� 0(‰ADD.W…#6,D6…increment�to�next�channel�#-*„request�periodic�activation(this�channel�#)2‰LEA‡PLSOFF(PC),A0‡point�to�pulse�turn�off�routine%‰CLR.L…D1’set�request�for�1�time�only6‰MOVE.B„CCBPPRIO(A5),D1…set�act.�priority�same�as�task/‰LOAD†D2,CHANID‹setup�channel�ID�to�goto�PLSOFF‰PUSHALL'‰MOVE.L„D3,A1�setup�activation�interval$‰TR0$.RQPA�,“pass�request�for�wakeup)*ŒIf�no�err�in�periodic�act.�request�THEN‰BRA.S…RQPAOKŽgood�return(‰BRA.S…PLSOER4�err�in�periodic�act.�req.RQPAOK:"*›activate_this_channel(channel�#)$‰MOVE.L„D5,D0�pass�bit�mask�to�DOOUT ‰BSR‡DOOUT‰POPALL"‰SUB‡#1,D0�decrement�channel�count ‰BRA‡PLSO1**ŒError�handlingPLSOER1:"‰CLR.L…D0’Channel�not�current�user‰MOVE.W„#DCOICNS,D0 ‰BRA.S…PLSOX1*PLSOER3:"‰CLR.L…D0’Requested�pulse�time�=�03‰MOVE.W„#DCOCNFG,D0‰return�'bad�configuration'�code ‰BRA.S…PLSOX1*PLSOER4:‰POPALL#‰CLR.L…D0’Periodic�activation�error,‰MOVE.W„#DCOBSY,D0‹return�'device�busy'�code ‰BRA.S…PLSOX1*PLSOX:*ŒPulsed�output�good�exit�point6‰LOAD†A3,DCOPARBK‰restore�DCO�para�block�address�to�A3‰CLR.L…D0ˆset�for�normal�return*PLSOX1:1‰ADD.L…#12,A7„DEALLOCATE�CHANID,DCOPARBK�on�stack*‰BRA‡NRMEXITƒgoto�normal�common�exit�point*‰PAGE*„PULSED�OUTPUT�DEACTIVATION:!*ŒEntered�by�periodic�activation. *‡On�entry:?*ˆD1�contains�channel�ID�composed�of�user's�CCB�address�in�M.S.7*‹3�bytes,�and�channel�number�(0-7)�in�least�sig.�byte.*PLSOFF:‰PUSHALL&‰MOVE.B„D1,D5�save�combined�channel�ID ‰AND.B…#0,D1�recover�CCB�address+‰MOVE.L„D1,A5�stage�CCB�address�for�'DOOFF'+‰AND.L…#$000000FF,D5‡recover�channel�number‰MOVE.L„D5,D4�save�binary�value‰MOVE.L„#$0C010000,D2 ‰MOVE.B„D5,D2.‰BSR.S…BIN_BIT�convert�chan�#�to�bit�map�in�D5"‰MOVE.L„D5,D0�stage�data�for�DOOFF‰BSR‡DOOFF�turn�off�channel0‰MULU†#6,D4�point�to�data�field�assoc.with�chan.5‰ADD‡#DCONTRY,D4‰add�offset�to�1st�channel�data�field‰ADD‡#4,D4�add�in�size�of�DCOID+‰MOVE.L„DCOTBL,A2‹get�addr.�of�DCOTBL�to�A2,‰MOVE.L„CCBTASKA(A5),A6…A6�=�users�TCB�addr. ‰CLR.L…D72‰MOVE.B„DCONMAX(A2),D7†get�max�#�of�DCO-ID's�to�D7#‰MOVE.L„CCBMNEM(A5),D6†get�CCB�name!PLS001ƒEQU‡*“find�matching�DCO-ID!‰MOVE.L„DCOID(A2),D3ˆDCO-ID�to�D3(‰CMP.L…D3,D6�does�CCB�name�match�DCO-ID?‰BEQ.S…PLS002Žbranch�on�match*‰ADDA.W„#DCOIDLNG,A2ˆadd�offset�to�next�ID"‰SUB.B…#1,D7�end�of�possible�ID's?$‰BMI.S…PLS003Žbranch�on�ID�not�found‰BRA‡PLS001Žcheck�next�ID PLS002ƒEQU‡*-‰MOVE.W„DCOCNIF(A2,D4),D0ƒconfiguration�to�D0(‰BSR.S…NOTFYUSRŒsee�if�wakeup�or�quevent PLS003ƒEQU‡*‰POPALL‰RTE*‰PAGE$*‰Binary�to�bit-map�conversion�in�D5@*‰Produces�a�1�in�D5�bit�corresponding�to�the�binary�value�in�D5*‰up�to�bit�15.@*‹For�input�>�15�binary�the�resultant�pattern�in�D5�is�undefinedBIN_BIT:‰ALLOCATE‚BITMAP‰CLR.L…BITMAP(A7)‰ADD.W…#1,BITMAP(A7) LOOP…EQU‡* ‰TST.W…D5 ‰BEQ.S…BINBITX�exit�on�bit�found‰ROL.W…BITMAP(A7) ‰SUB‡#1,D5 ‰BRA.S…LOOP* BINBITX‚EQU‡*‰MOVE.W„BITMAP(A7),D5'‰ADD.L…#8,A7�DEALLOCATE�BITMAP�on�stack‰RTS*‰PAGE *„NOTIFY�USERA*ˆnotify�user�by�means�of�que�event�or�wakeup�as�specified�in�the*ˆchannel�configuration�word.*„INPUT�PARAMETERS:'*’A2:�Address�of�channel�name�in�DCOTBL;*’D4:�Offset�from�channel�name�to�channel�data�field�(base) *™in�DCOTBL.*’A5:�Address�of�channel�CCB.*’A6:�User's�TCB�address#*’D2:�$0C01�* NOTFYUSR:?‰MOVE.WƒDCOCNIF(A2,D4),D0�get�configuration�from�channel�DCOTBL#‰BTST†#15,D0‹default�configuration? ‰BNE.S…NOTIFX1‰BTST…#0,D0‰no,�determine:�wake-up=1�or�q-event=0 ‰BNE.S…NOTIFA*ŽEnqueue�event;�data�staging:$*ŽD2�=�$0C01� *ŽD3�=�DCOID*ŽD4�=�Mem�mapped�I/O�address*ŽA6�=�User's�TCB�address*8‰MOVE.LƒCCBCHB(A5),D4…get�mem.�mapped�I/O�address�staged ‰BSR.S�QUEVENT�enqueue�the�event‰BRA.S‚NOTIFXŽgoto�exit*+NOTIFAƒMOVE.LƒA6,A0Žstage�users�TCB�address#‰TR0$.WAKEUP�,�issue�wakeup�to�userNOTIFX:‰RTS*ŠPAGEO******** ************************************************************************ *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�DCO�parameter�block*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D0�=�DCO�error�code*I**************************************************************************NRMEXIT:>ŠMOVE.W�D0,CMDSTA(A3)†set�return�status�in�DCO�parameter�blockŠRTS—return�to�CMR*ŠPAGE*H*‚QUEVENT�-�queue's�event�to�driving�task�using�data�staged�in�registers *‹as�follows:*‹A6�=�user's�TCB�address&*‹D2�=�$0C01�*‹D3�=�DCOID‚(module�name)&*‹D4�=�mem�mapped�I/O�address�of�board<*†(dumps�contents�of�registers�D2,�D3,�&�D4�to�users�buffer)* QUEVENT EQU *‹PUSHALL”push�all�regs"‹MOVE.L…A6,A0Žstage�user's�address ‹TR0$.QEVNTI*)‹BRA.SƒQUEVNTOKŒgood�return�for�que�event'‹BRA.SƒQUEVNTERŒbad�return�from�queventQUEVNTOK EQU *‹POPALL•restore�all�regs‹RTS QUEVNTER:(‹BRA�QUEVNTOK�put�a�break�here�for�debug*ŠPAGEF***********************************************************************B* SUBROUTINE TO CHECK ADDRESS BOUNDARIES TO SEE IF ENTIRELY WITHIN*ƒCALLING�TASKS�ADDRESS�SPACE.*#*�ENTRY:ƒD5‚-�NO.�OF�BYTES�TO�CHECK*ŠD6‚-�68000�ADDRESS�(LOGICAL)*ŠA1‚-�TCB�ADDRESS** EXEC ROUTINE#* REGISTERS USED: D0-D1,D3,D6/A0-A1*7*�EXIT:„D6�-�PHYSICAL�ADDRESS�OF�BUFFER�BASE�(IF�LEGAL)*ŠRETURN�TO�PC„FOR�GOOD�ADDRESS*”PC+2‚FOR�BAD�LENGTH*”PC+4‚FOR�BAD�ADDRESS*F*********************************************************************** IOHADRCK:%ŠBTSTƒ#0,D6‘Must�be�on�work�boundary.)ŠBNE.S‚IOHADR4�Branch�if�bad�buffer�base.ŠTST.L‚D5”Length�can't�be�zero.2ŠBEQ.S‚IOHADR8�Don't�go�to�logphy�with�zero�count.1ŠMOVE.L�TCBTST(A1),A0‰Address�of�task�seg.�table. ŠTR0$.LOGPHY*.ŠBRA.S‚IOHADR8�Branch�for�good�address�return.0ŠBRA.S‚IOHADR6�Branch�for�bad�byte�count�return.(ŠTST.L‚D5”Was�an�entry�pointer�returned.#ŠBEQ.S‚IOHADR4�Branch�if�no�-�ERROR)ŠTST.B‚7(A0,D5)ŽIs�this�an�MMIO�segment�?ŠBNE.S‚IOHADR8�Yes,�OK.3IOHADR4ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.3IOHADR6ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.IOHADR8ƒRTSšReturn.*ŠPAGEJ***************************************************************************!* INTERRUPT SIDE FOR IOH HANDLING*?*ƒPURPOSE:‚HANDLE�ACKNOWLEDGEMENTS�AND�MESSAGE�COMPLETIONS�FROM2*�THE�IOH.‚OPERATES�AT�HARDWARE�INTERRUPT�PRIORITY=*�LEVEL�AS�A�SUBROUTINE�TO�THE�FIRST�LEVEL�INTERRUPT�HANDLER.*+*ƒENTRY:‚JSR‚FROM�INTERRUPT�HANDLER�ROUTINE*‹A0�-�WORK�REGISTER *‹A1�=�SELF*‹A5�=�ADDRESS�OF�CCB*‹D0�=�WORK�REGISTER*/*ƒEXIT:‚RTS�-�BACK�TO�INTERRUPT�HANDLER�ROUTINE*/*ƒNOTE:ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***@*ƒThis�routine�is�called�only�by�the�common�interrupt�handler�in'*ƒRMS68K.ƒThe�common�interrupt�handler:;*ƒ!!!ƒDOES‚NOTƒPRESERVEƒVALUESƒINƒREGISTERSƒBEFOREƒTHEƒCALLK*ƒso�this�interrupt�handler�must�pruserve�all�data�reg.'s�&�address�reg.'s.5*ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***ƒ***‚***‚***�***ƒ***ƒ***ƒ*****ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P***4*ƒIf�channel�is�off-line�or�not�attached,�just�exit.K****************************************************************************<*‹Find�DCO�TABLE�module�(board)�name�which�matches�CCB�name:*3DCOINTƒMOVEM.LƒA0-A6/D1-D7,-(A7)ƒsave�all�except�D01‰ALLOCATE‚DCOTADR,CHANUM†allocate�local�variables-‰MOVE.L„DCOTBL,A2‹get�address�of�DCOTBL�to�A2 ‰CLR.L…D76‰MOVE.B„DCONMAX(A2),D7†get�max�number�of�DCOID's�to�D7#‰MOVE.L„CCBMNEM(A5),D0†get�ccb�name2IOHI011‚EQU‡*‡find�matching�DCOID�loop�entry�point*‰MOVE.L„DCOID(A2),D3ˆget�DCOID�for�staging'‰CMP.L…D3,D0�does�CCB�name�match�DCOID?#‰BEQ.S…IOHI020�branch�on�name�match.‰ADDA.W„#DCOIDLNG,A2ˆadd�offset�to�next�DCOTBL#‰SUB.B…#1,D7�test�for�end�of�DCOTBL6‰BMI.S…IOHIEX01Œbranch�to�error�exit�1�on�id�not�found ‰BRA‡IOHI011F*…Found�matching�names,�now�get�number�of�interrupting�channel�(to�D2)$*£in�this�case,�non-existant�chan.�8  5IOHI020‚STORE…A2,DCOTADRŠsave�DCOTBL�address�on�stack,‰MOVE.L„#$0C010008,D2‡init�para�fields�in�D2+‰STORE…D2,CHANUM‹save�chan.�#�&�return�code>*„Compute�address�of�field�in�DCOTBL�having�user's�TCB�address ‰CLR.L…D4!‰MOVE.B„D2,D4�get�channel‚to�D4.B$IOHIPXƒEQU‡*‰'DCOINT'�procedure�exit2‰MOVE.L„#0,D0�get�interrupt�claim�check(=0�-�none)*„dealocate�DCOTADR,CHANUM#‰ADD‡#12,A7Žrelease�local�variables0‰MOVEM.Lƒ(A7)+,A0-A6/D1-D7ƒrestore�all�except�D02‰AND‡#$FFFE,SR‹signal�CMR�'interrupt�not�from�DCO'‰RTS*IOHIEX01�EQU‡*,*‹error�exit�for�DCOID�name�not�found�in�CCB‰BRA‡IOHIPXŽgoto�procedure�exit**‰ENDéé=/*=/*†M625LIB.AF=/*7=/* Chain file to assemble FORTRAN-callable subroutines)=/* to interface with the MVME625 driver.=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to M625LIB.LS=/*=/IFC \1ƒ=ARG�M625LIB.LS=/ENDIF=/*=ASM M625LIB.SA,M625LIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDééééééýFTDCO…IDNTƒ1,0�DCO�subroutines**‰FORTRAN�callable�subroutines*‰for�DCO�driver�calls*$*‰CALL�DCOCMD(dco_id,param_blk_addr)*‰where�DCOCMD�may�be:*)*‰CALL�DCOPEN(dco_id,param_blk_addr)…open**‰CALL�DCOCLS(dco_id,param_blk_addr)…close.*‰CALL�DCOOUT(dco_id,param_blk_addr)…output�on/*‰CALL�DCOOFF(dco_id,param_blk_addr)…output�off+*‰CALL�DCOSTA(dco_id,param_blk_addr)…status2*‰CALL�DCOPLS(dco_id,param_blk_addr)„output�pulsed*,*‰All�arguments�for�the�calls�are�identical.7*‰The�contents  �of�the�param_blk�for�each�call�is�unique*‰to�the�call.*6*‰All�the�command�subroutines�call�a�common�subroutine3*‰DCOSET�to�build�the�initiate�I/O�parameter�block.**‰STACK�FOR�ALL�CALLS:*7*‰deepest�stack:�(stack�address�stays�at�DCOSET�return)0*˜command�codeƒ2�bytes�(initiate�I/O�param.�blk) *˜n/aŒ2�bytes*˜dco_id‰4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes,*˜command�addrƒ4�bytes�(dco�command�address)**˜command�lng„2�bytes�(dco�command�length)-*˜DCOSET�return‚4�bytes�deepest�stack�address *˜A3�4�bytes *˜A2�4�bytes *˜A1�4�bytes *˜D0�4�bytes*‰entry�stack:ƒreturn‰4�bytes*˜^param_blk_adr�4�bytes*˜^dco-idˆ4�bytes* ŠSECTION�9!ŠXDEFƒDCOPEN,DCOCLS,DCOOUT,DCOOFFŠXDEFƒDCOSTA,DCOPLS*$*‰CALL�DCOPEN(dco_id,param_blk_addr)*‰open�and�configure�channels*1DCOPEN„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers3ŠBSR„DCOSET�set-up�the�initiate�I/O�parameter�block)ŠMOVE.L�#1,(A2)Œset�the�open�command�codeDCOPN00ƒCLR.L‚D0‘clear�for�use'ŠMOVE.W�4(A2),D0‹get�number�of�channelsŠASL.L‚#2,D0Žmultiply�by�4.DCOPN05ƒADD.L‚#6,D0Žadd�in�the�6�byte�overhead-DCOPN10ƒMOVE.W�D0,(A1)Œset�the�command�length-ŠMOVE.L�A3,A0ŽTRAP�#1�parameter�block�address#ŠMOVE.L�#60,D0�CMR�directive�numberŠTRAPƒ#1‘call�RMS68K'ŠMOVE.W�D0,(A2)Œset�the�returned�status)ŠMOVEM.L�(A7)+,D0/A1-A3„restore�registers!ŠMOVE.L�(A7)+,A0‹put�return�in�A0 ŠLEA„8(A7),A7‹clean�up�the�stackŠJMP„(A0)�return�to�user*$*‰CALL�DCOCLS(dco_id,param_blk_addr)"*‰close�all�channels�for�this�userD8 *1DCOCLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DCOSET�set-up�the�initiate�I/O�parameter�block*ŠMOVE.L�#2,(A2)Œset�the�close�command�code&ŠMOVE.W�#4,D0ŽDCO�close�command�lengthŠBRA„DCOPN10Œgo�do�the�CMR�call*$*‰CALL�DCOOUT(dco_id,param_blk_addr)'*‰activate�output�on�requested�channels*1DCOOUT„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DCOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#3,(A2)Œset�the�output�command�code*DCOUT10ƒMOVE.Wƒ#6,D0Œset�up�command�lengthŠBRA„DCOPN10Œgo�do�the�CMR�call*$*‰CALL�DCOOFF(dco_id,param_blk_addr))*‰deactivate�output�on�specified�channels*1DCOOFF„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DCOSET�set-up�the�initiate�I/O�parameter�block/ŠMOVE.L�#4,(A2)Œset�the�output�off�command�code4ŠBRA„DCOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�DCOSTA(dco_id,param_blk_addr))*‰read�input�status�on�specified�channels*1DCOSTA„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DCOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#5,(A2)Œset�the�status�command�code4ŠBRA„DCOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�DCOPLS(dco_id,param_blk_addr)>*‰activate�output�for�x#�of�milliseconds�on�specified�channels*1DCOPLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚DCOSET�set-up�the�initiate�I/O�parameter�block2ŠMOVE.L�#8,(A2)Œset�the�pulsed�output�command�codeŠCLR.L‚D0‘clear�for�use,ŠMOVE.W�4(A2),D0‹get�specified�#�of�channelsŠASL.L‚#2,D0Žmultiply�by�6ŠADD.W‚4(A2),D04ŠBRA„DCOPN05Œgo�set�command�length�&�do�the�CMR�callŠPAGE*4*‰DCOSET�set�up�the�CMR�initiate�I/O�parameter�block,*‰returns:ƒA1=address�for�DCO�command�length(*”A2=DCO�command�parameter�block�address)*”A3=initiate�I/O�parameter�block�address*(DCOSET„CLR.W‚-2(A7)�clear�command�length-ŠLEA„-2(A7),A1Šsave�address�of�command�length$ŠMOVE.L�24(A7),A0Šget�param_blk_addr%ŠMOVE.L�A0,-6(A7)Šsave�param_blk_addr,ŠMOVE.L�A0,A2Žsave�param_blk_addr�for�returnŠCLR.L‚-10(A7)Œnot�usedŠCLR.L‚-14(A7)Œnot�usedŠCLR.L‚-18(A7)Œnot�usedŠMOVE.L�28(A7),A0Šget�^dco_idŠMOVE.L�(A0),-22(A7)‡get�dco_idŠCLR.W‚-24(A7)Œnot�used0ŠMOVE.W�#$0700,-26(A7)…initiate�I/O�command�code4ŠLEA„-26(A7),A3‰initiate�I/O�parameter�block�addressŠRTS—r! eturn�to�caller*ŠEND*éééééé=/* =/*†RADDRV.AF=/*&=/* Chain file to assemble RAD1 driver=/*:=/* If no output argument is specified for the listing the(=/* chain file will default to RADDRV.LS=/*=/IFC \1ƒ=ARG�RADDRV.LS=/ENDIF=/*#=ASM RADDRV.SA,RADDRV.RO,\1;MRZ=126=/*{ Included files are:=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.RADDRV.EQ=/*}=/*=ENDéééééé! @‰TTL�RAD1�DRIVER‚===============================================9RADDRVƒIDNT†1,0�RAD1�DRIVER‚COPYRIGHT�1982�MOTOROLA,�INC.‰PAGE8*ˆ6/21/82ƒ<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<H*************************************************************************ˆ======================*ˆ{”}*‡{†RAD�Driver†}*ˆ{”}*ˆ======================I*************************************************************************** ‰TTL�STR.SA‰PAGE‰INCLUDE�9995.&.STR.EQ* ‰TTL�TCB.EQ‰PAGE‰INCLUDE�9995.&.TCB.EQ* ‰TTL�CCB.SA‰PAGE‰INCLUDE�9995.&.CCB.EQ* ‰TTL�LV5.SA‰PAGE‰INCLUDE�9995.&.LV5.EQ*‰TTL�9995.&.RADDRV.EQ‰PAGEŠINCLUDE�9995.&.RADDRV.EQ*@‰TTL�RAD1�DRIVER‚===============================================ŠPAGE;************************************************************ *ˆCONSTANTS*;*************************************************************ˆCommand�Codes*%RASTPCMD�EQU‡00ˆ"Stop"�command�value.%RALODCMD�EQU‡01ˆ"Load"�command�value.%RADMPCMD�EQU‡02ˆ"Dump"�command�value.%RAJMPCMD�EQU‡03ˆ"Jump"�command�value.*RATSTCMD�EQU‡04ˆ"Self-test"�command�value.&RAOPNCMD�EQU‡$10‡"Open"�command�value.'RACLSCMD�EQU‡$20‡"Close"�command�value.'RAABTCMD�EQU‡$7F‡"Abort"�command�value.2RAEXTCMD�EQU‡$81‡"External�trigger"�command�value.*RASETCMD�EQU‡$82‡"Setpoint"�command�value.&RASCNCMD�EQU‡$83‡"Scan"�command�value.1RAATOCMD�EQU‡$84‡"Auto-range�scan"�command�value.+RACALCMD�EQU‡$85‡"Calibrate"�command�value.1RAHISCMD�EQU‡$86‡"High-speed�scan"�command�value.:RAXEQBYT�EQU‡$80‡"Execute�function"�command�(OR-ed�in�with(*¦function�number�to�form�command�byte.)RAXEQCMD�EQU‡RAXEQBYT7RASTOPIT�EQU‡$FF‡Value�to�put�in�stop�byte�to�stop�RAD.**ˆOffsets�in�shared-RAM=*’(68000�addressing--i.e.�values�are�twice�the�6809�offsets.)*RASTPBYT�EQU‡0‰Stop�byte.RACMDBYT�EQU‡2‰Command�byte.#RAINTFLG�EQU‡4‰Interrupt�flag�byte."RACSTAT‚EQU‡6‰Command�status�byte.#RAINTMSK�EQU‡8‰Interrupt�mask�byte.!(F1<98A0IFQ0YCa7i2qEy?�-‰2‘5™0¡@©:±:¹6Á3É=Ñ5Ù3á0é8ñ8ù-6 -6%RAFIFOST�EQU‡10ˆStart-of-FIFO�offset."RAFIFOND�EQU‡12ˆEnd-of-FIFO�offset(RANXT2GT�EQU‡14ˆFIFO-next-to-get�offset.RAPRMPTR�EQU‡18ˆParameter�ptr.'RAPARAM‚EQU‡84ˆStart�of�parameter�list.!RATSTAT‚EQU‡502‡Self-test�status.BRAOK2STO�EQU‡508‡High-speed�scan�"communications"�flag.‚(1�=�ok�to**¦put�data,�2�=�ok�to�take�data,�0�=�stop))RAXSTAT‚EQU‡510‡Hardware�status�register.***ˆTable�offsets**)*‚CCB�(device-dependent�section)�offsets.*;RARDLADR�EQU‡CCBDDP„Addr�of�this�RAD's�entry�in�'RARADLST'.ARACMDCOD�EQU‡RARDLADR+4ˆCommand�code�RAD�is�currently�working�on.8RARDFLAG�EQU‡RACMDCOD+1Š"Interrupt-being-serviced"�flag.3RAUSRTCB�EQU‡RARDFLAG+1ŠAddr�of�current�user's�TCB.:RARTRVAD�EQU‡RAUSRTCB+4ŠAddr�of�data-retrieval�subroutine.=RACHNUSR�EQU‡RARTRVAD+4ŠUser�ptr�for�chan�0‚(start�of�channel*¦user�ptr�list).?RAINSTR‚EQU‡RACHNUSR+64‰Interrupt�"instruction"�flag�(indicates&*¦what�is�to�be�done�when�an�interrupt$*¦occurs�from�the�current�function).9RAJMPRRG�EQU‡RAINSTR+1‹Contains�value�from�harware�jumper%*¦"register"�on�RAD�board�(loc�7000)./RASHRAD‚EQU‡CCBCHBŽStarting�addr�of�shared-RAM.*M*============================================================================B*‚CCB�offsets�for�locations�used�by�standard�driver�skeleton�code.0CCBERAD1�EQU‡RAJMPRRG+1ŠError�debug�save�address9CCBQVER1�EQU‡CCBERAD1+4ŠEvent�queuing�error�debug�address(CCBCIDƒEQU‡CCBQVER1+4ŠCMR�param�block�ID*3******‚Check�for�too�much�stuff�to�fit�in�CCB�.�.�.‰IFGT†CCBCID+4-256%‰FAIL†499‘Abort�assembly�if�too�much.‰ENDC******** CCB flag positionsCCBFGBSY�EQU‡7“Channel�busyN*=============================================================================***‚Command�packet�offsets**RACMDERR�EQU‡0“Error�return�code" �location..RAREQCMD�EQU‡RACMDERR+2ŠRequested�command�code8RACMDPRM�EQU‡RAREQCMD+2ŠStart�of�command�parameter�list.** *ˆFlag�values*:RAWRKFLG�EQU‡1‰Flag�setting�for�RARDFLAG�indicating�we�are(*¦working�on�an�interrupt�from�this�RAD.** *ˆError�codes*RAERR1ƒEQU‡$F0‡RAD�is�"bad".RAERR2ƒEQU‡$F1‡RAD�is�"busy".RANOTUSR�EQU‡$FF‡This�user�is�not�using�this�RAD�now�(tried�to*œdo�a�RADSTP).:RAABORTD�EQU‡$FB‡This�RAD�was�aborted�since�this�user�last#*¦called--user�must�reopen�for�RAD.7RASYSERR�EQU‡$FA‡This�is�an�"extra"�RAD--can't�be�used.'*¦(SYSGEN�was�set�up�for�too�few�RADs.)RAOVRFLO�EQU‡$FC‡FIFO�overflow.***ˆRAD�status�codes*(RAUNINIT�EQU‡$F000…RAD�is�uninitialized.RASTBAD‚EQU‡$FFFF…RAD�is�"bad".6RASTOKƒEQU‡$F0F0…RAD�is�ok�and�ready�to�take�commands.3RASTDOIN�EQU‡$F001…RAD�is�now�doing�initialization.*** *ˆBit�masks*=RAINTBIT�EQU‡$C0‡Bits�to�check�in�status�byte�for�interrupts..*œ(Bit�7�=�level�4�int.,�bit�6�=�level�3�int.)*;RASUBRBT�EQU‡0‰Option�bit�#�for�user-supplied�data-handling+*œsubroutine�for�when�data�for�this�chan�is*œreceived�from�the�RAD.;RAQUEBT‚EQU‡1‰Option�bit�#�to�queue�event�to�user�when�data)*œfor�this�chan�is�received�from�the�RAD.=RAWAKEBT�EQU‡2‰Option�bit�#�to�wake�up�the�user�when�data�for%*œthis�chan�is�received�from�the�RAD.**ˆMisc.�constants*RARDRMND�EQU‡$D7FF…End�addr�of�RAD�RAM�(excluding�shared-RAM).?RALODLNG�EQU‡100‡Max�#�of�words�to�load�or�dump�thru�shared-RAM*¦at�one�time.*ˆset�aside�in�the�SYSGEN�for�use�by�the�driver�(RAD1TBL).‚TheC*ˆdriver�takes�a�command�from�the�user,�passes�it�on�to�the�correct?*ˆRAD1�board�(where�the�firmware�will�interpret�and�execute�theD*ˆcommand),�takes�the�data�back�from�the�RAD1,�and�passes�it�back�to>*ˆthe�user�in�the�manner�specified�by�that�user.‚Communication>*ˆbetween�the�68000�and�the�RAD1�board�takes�place�through�the*ˆ256-byte-long�shared-RAM.*>*ˆCode�in�this�driver�is�relocatable,�re-entrant,�and�ROMable.**/*ƒENTRY:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒEXIT:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION**I*========================================================================*²<<<<<<<<<<<<<<<<<<<<<<<<<<<A*ˆAssemble�using�chain�file�RADASM.CF‡<<<<<<<<<<<<<<<<<<<<<<<<<<<*²<<<<<<<<<<<<<<<<<<<<<<<<<<<H*-----------------------------------------------------------------------*‰PAGEJ*****************************************************************************C*‚THIS�IS�THE�SERVICE�VECTOR�TABLE�WHICH�IS�REQUIRED�FOR�CMR-CALLED*ˆI/O�DRIVERS.***L****************************************************************************** ‰SECTION�8***‚Service�vector�table�for�CMR: RADDRVR‚EQU‡*9‰DC.L†RADISR-RADDRVR†Offset�to�interrupt�service�routine.7‰DC.L†RADCMD-RADDRVR†Offset�to�command�service�routine.6‰DC.L†RAINIT-RADDRVR†Offset�to�initialization�routine.‰DC.L†0“RESERVED***‚Other�CMR�params:!‰DC.B†0“#�of�extra�pages�per�CCB. ‰DC.B†0,0,0 ‰DC.L†0,0,0***‚Revision�info.:-‰DC.B†'021783'ŒRADDRV�revision�date�(MMDDYY).*‰DC.B†'�'‘Patch�flag�(blank�=�no�patches).$‰DC.B†'4'‘Major�VERSAdos�revision�#.*‰PAGEM*******************************************************************************ˆInitialization�Routine*5*’Called�through�CMR�once�for�each�CCB�when�system�is5*’booted.‚This�routine�initializes�the�data�area�used*’by�the�RAD�driver.*!*ˆUpon�entry:‰A5�=�address�of�CCB*8*ˆUpon�exit:ŠThe�following�register�contents�are�changed%*œ(and�not�restored):ƒA0,�A1,�D1,�D2.*M***************************************************************************** RAINITƒEQU‡*7‰MOVEA.LƒRAD1TBL,A0ŠPut�address�of�RAD�table�area�(from*¦SYSPAR)�into�A0.5‰CMPA.L„#0,A0�Has�memory�been�set�up�for�RADs�on�this!‰BEQ.S…RAERRXS�system?‚No--error.>‰CMPI.B„#RALVL4,CCBPPRIO(A5)…Is�this�a�level�4�CCB?‚(Interrupt**¦levels�are�set�internally�as�1�more�than*¦actual�level.)7‰BEQ.S…RAINRET�Yes--ignore�it,�no�initializtion�needed."‰CLR.L…D2’No,�must�be�level�3�CCB.%‰MOVE.L„D2,A1�Clear�A1�for�later�use.>‰MOVE.B„RARADUSD(A0),D2…Set�up�D2�to�contain�number�of�entries*¦in�RARADLST�already�used.6‰CMP.B…RANUMRAD(A0),D2…Are�any�entries�left�available?(‰BGE.S…RAERRXS�No--table�is�full--error.8‰ADDQ.B„#1,RARADUSD(A0)…Yes.‚Bump�count�of�entries�used.9‰MULU†#RARDENTL,D2ˆMultiply�#�entries�used�by�length�of�1$*¦entry�to�get�offset�in�RARADLST�to*¦next�available�entry.=‰MOVEA…RARADLAD(A0),A1…Put�start�addr�of�RARADLST�into�A1,�by4‰ADDA.L„A0,A1�adding�table�area�start�addr�to�offset*¦to�RARADLST..‰ADDA.L„D2,A1�Set�A1�to�addr�of�next�available*¦entry�in�RARADLST.<‰MOVE.L„CCBMNEM(A5),(A1)„Move�RAD-ID�into�RARADLST�entry�for *¦this�RAD.=‰MOVE.L„A1,RARDLADR(A5)…Put�addr�of�this�RAD's�RARADLST�entry *¦into�CCB.2‰CLR.B…RACMDCOD(A5)ˆInitialize�the�rest�of�the�CCB*‰CLR.B…RARDFLAG(A5)ˆdevice-dependent�area.0‰LEA‡RARDFIFO(PC),A1…Set�addr�for�data-retrieval8‰MOVE.L„A1,RARTRVAD(A5)…subroutine�to�read-FIFO�routine.‰CLR.B…RAINSTR(A5)‰CLR.B…RAJMPRRG(A5)0‰MOVE†#16,D2ŽInit�the�channel�user�ptrs‚(2�bytes,‰LEA‡RACHNUSR(A5),A1…each--for�32�channels).ARAINLP4‚MOVE.L„#$F000F000,(A1)+„Set�channel�user�ptrs�to�$F000�to&*¦indicate�channels�can't�be�used�yet.‰SUBQ†#1,D2�Done?‰BGT‡RAINLP4�No--do�next.=‰MOVE.L„RARDLADR(A5),A1…Yes.‚Set�add# ress�of�entry�in�RARADLST*¦for�this�RAD�in�A1..‰MOVE†#RAUNINIT,RARDSTAT(A1)ˆSet�RAD�status�to)*¦"uninitialized".‚(The�RAD�board�will�be'*¦initialized�upon�the�1st�user�request*¦for�this�RAD.)‰CLR.L…D1ˆSet�D1�to�zero.9‰ADDQ.L„#RACHNLST,A1ˆSet�ptr�to�1st�channel�for�this�RAD.?‰MOVE.L„#8*RACHNLLG,D2„Init�D2�to�be�used�as�a�channel�counter.1*œ(Set�D2�to:‚32�*�RACHNLLG�/�4,�since�we�will�be0*�initializing�the�32�channel�entries�4�bytes�at *�a�time.)HRAINLP1‚MOVE.L„D1,(A1)+‚Init�channel�data�for�this�RAD�in�RARADLST�to�0.‰SUBQ†#1,D2…All�done?$‰BHI‡RAINLP1ƒNo--go�do�next�channel.RAINRET‚RTS‘Return.*;RAERRXS‚EQU‡*‰SOMETHING�IS�WRONG!!!‚This�routine�was�called#*¦more�times�than�there�are�RADs�in*¦the�system!!!*;‰MOVE.B„#RASYSERR,RAINSTR(A5)‰Set�a�flag�in�CCB�to�indicate&*¦that�this�RAD�cannot�be�used--due�to%*¦a�SYSGEN�error,�there�is�not�enough'*¦room�in�the�RAD�table�area�to�include *¦this�RAD.‰BRA‡RAINRETƒReturn‰PAGEJ***************************************************************************%*ˆTHIS�IS�THE�COMMAND�SERVICE�ROUTINE**ƒENTRY:‚JSR�FROM�CMR�HANDLER**‹A2�-�PHYSICAL�ADDRESS�OF�PARAMETER�BLOCK*‹A5�-�PHYSICAL�ADDRESS�OF�CCB,*‹A6�-�PHYSICAL�ADDRESS�OF�ATTACHED�TASK�TCB*5*ƒEXIT:‚RTS�-�PARAMETER�BLOCK�VALIDATION�STATUS�IN�D0**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A**P**PP**”A3�=�COMMAND�PACKET�POINTER*”A6�=�REQUESTOR�TCB�ADDRESS***ƒCODE�IS�RE-ENTRANT*J*************************************************************************** RADCMD„EQU„*-‰TST.B…XIOSCD(A2)ŠIs�the�CMR�cmd�subcode�=�0?‰BEQ.S…IOH01110ŒYes.9‰MOVE.B„#RAERR9,D7ŠNo--error--set�"illegal�command"�error,‰BSR‡IOHERCHKŒcode�and�go�make�error�return.*1* CHECK FOR COMMAND PACKET WITHIN TASK BOUNDARIES*CIOH01110‚MOVE.L�XIOUID(A2),CCBCID(A5)�SAVE�CMR�PARAM�BLOCK�ID�(DCB) ŠCLR.L‚D5,ŠMOVE.L�XIOCPK(A2),D6†ADDR�OF�COMMAND�PACKET)ŠMOVEƒXIOPLN(A2),D5†LENGTH�OF�COMMAND�PKT*ŠMOVE.L�CCBTASKA(A5),A1„SET�UP�TCB�POINTER ŠBSR„IOHADRCKŠBRA.S‚IOH01160‹GOOD�RETURNŠNOP—BAD�LENGTH�RETURN%ŠMOVE.B�#XSTBLN,D7‰BAD�ADDRESS�RETURN ŠBSR„IOHERCHK5IOH01160‚MOVE.L�D6,A3ŽCOMMAND�PACKET�PHYSICAL�ADDRESS*0* INSURE THAT COMMAND PACKET IS ON EVEN BOUNDARY* ŠBTSTƒ#0,D6ŠBEQ.S„RACOMAND6ŠMOVE.B�#XSTBLN,D7‰BAD�COMMAND�PACKET�ADDR�(ODD�BNDRY) ŠBSR„IOHERCHK**F************************************************************************ˆCommand�Processor*2*’User's�command�is�processed�here.‚A�check�on�the1*’desired�RAD's�status�is�made,�and�if�the�status0*’is�"good",�the�command�processor�will�call�the/*’appropriate�subroutine�to�handle�the�command.*F***********************************************************************RACOMAND�EQU‡**7‰CLR‡RACMDERR(A3)ˆClear�error�return�location�in�user's)*¦cmd�param�table�(used�later�as�a�flag).4‰CMP.B…#RASYSERR,RAINSTR(A5)‰Is�this�a�non-available*¦RAD�(due�to�SYSGEN�error)?-‰BEQ‡RASKIPITŒYes--make�error�return�to�user.-‰BSR‡RAFNDUSRŒNo.‚Find�this�user�in�RAUSRLST.7‰CMP.L…#RAABORTD,D0ˆWas�this�RAD�aborted�since�the�last*¦time�this�user�called?3‰BEQ‡RACMDRETŒYes--make�error�return�(D0�is�already *¦set�up).*;*’No.‚Data�in�D0�and�D1�will�be�used�later�in�this�routine.*9‰MOVE†RAREQCMD(A3),D2…Store�requested�command�code�in�D2.*‰CLR.L…D3’Init�D3,�which�will�be�offset�in*¦'RAJMPTBL'�for�this�command.5‰LEA‡RACMDTBL(PC),A4…Set�A4�to�addr�of�start�of�table*¦of�"legal"�command�codes.=RACMDLUP�CMP.B…(A4),D2�Does�requested�command�code�match�this*¦table�entry?6‰BEQ.S…RAGOTCMDŒYes--continue�processing�this�command.‰CMP.B…#$FF,(A4)+ŠEnd�of�table?*‰BEQ.S…RANOSUCHŒYes--illegal�command�code.-‰ADDQ†#4,D3�Set�jump�table�ptr�to�next�entry.+‰BRA‡RACMDLUPŒGo�back�and�check�next�entry.?RANOSUCH�MOVE.L„#RAERR9,D0ŠSet�error�return�to�"illegal�command‰BRA‡RACMDRETŒcode"�and�return.ARAGOTCMD�MOVE.L„RARDLADR(A5),A1…Put�addr�of�entry�for�this�RAD�in*¦'RARADLST'�into�A1.4RACMD0ƒCMPI†#RASTBAD,RARDSTAT(A1)‰Is�RAD�marked�bad?‰BNE.S…R# ACMD1ŽNo.-‰MOVE.L„#RAERR1,D0ŠYes--set�D0�to�error�code.‰BRA.S…RACMDRETŒGo�return.=RACMD1ƒCMPI†#RAUNINIT,RARDSTAT(A1)ˆIs�this�RAD�uninitialized?‰BNE.S…RACMD2ŽNo.$‰BSR‡RAINITRDŒYes--go�initialize�it.‰BRA‡RACMD0ŽNow�try�again.BRACMD2ƒCMP‡#RASTDOIN,RARDSTAT(A1)‚Is�RAD�doing�initialization�now?*‰BEQ.S…RACMD3ŽYes--make�"RAD�busy"�return.6‰CMPI.B„#RAOPNCMD,D2ˆAt�this�point,�the�RAD�must�be�in%*¦working�condition.‚Is�the�requested*¦command�an�"open"?+‰BEQ.S…RADOITŽYes--go�do�"open"�processing.8‰CMPI.B„#RACLSCMD,D2ˆIs�the�requested�command�a�"close"?,‰BEQ.S…RADOITŽYes--go�do�"close"�processing..‰CMPI.B„#RASTPCMD,D2ˆIs�this�a�"stop"�command?‰BEQ.S…RADOIT2�Yes--go�do�it.0‰CMPI.B„#RAABTCMD,D2ˆIs�this�an�"abort"�command?‰BEQ.S…RADOIT2�Yes--go�do�it./‰CMP‡#RASTOK,RARDSTAT(A1)‚No.‚Is�RAD�ready�now?'‰BEQ.S…RADOCMD�Yes--go�process�command.6RACMD3ƒMOVE.L„#RAERR2,D0ŠNo--set�error�code�to�"busy".‰BRA.S…RACMDRETŒGo�return.ARACMD4ƒMOVE.L„#RAUSRERR,D0ˆSet�error�flag�to�indicate�user�is�not*¦set�up�to�use�this�RAD.‰BRA.S…RACMDRETŒGo�return.*4RADOCMD‚EQU‡*“At�this�point,�must�be�a�command�which)*¦actually�uses�the�RAD�board,�so�set�the*¦RAD�status�to�busy.*8*’D0�and�D1�still�contain�data�from�RAFNDUSR�call�above.*)‰TST.L…D0’Is�user�set�up�to�use�this�RAD?‰BNE‡RACMD4ŽNo--error.9‰MOVE†D1,RARDSTAT(A1)…Set�RAD�status�to�user�ptr�for�this*¦user�to�indicate�RAD�is�busy.:‰MOVE†#1,RACMDERR(A3)…Set�cmd�error�code�to�1�as�a�flag�to%*¦indicate�that�this�cmd�uses�the�RAD%*¦board�and�set�the�status�to�"busy".3RADOIT2‚MOVE.L„A6,RAUSRTCB(A5)…Store�addr�of�user's*¦TCB�in�CCB�for�future�use. RADOITƒEQU‡*8‰LEA‡RAINSTBL(PC),A4…Put�start�addr�of�interrupt�"instr-*¦uction"�table.1‰MOVE.L„D3,D0�Get�offset�into�this�table�for�this‰ASR.L…#2,D0�command.?‰MOVE.B„(A4,D0),RAINSTR(A5)�Store�"instruction"�flag�in�CCB�for*¦use�when�interrupt�comes�in.:‰LEA‡RAJMPTBL(PC),A4…Load�addr�of�start�of�jump�table�into"*¦A4.‚D3�still�has�offset�for�this#*¦command�code�into�the�jump�table.%*¦A3�contains�addr�of�command�packet.1‰JSR‡(A4,D3)�Go�to�command-processing�routine�for(*¦this�command.‚(NOTE:�D1�still�contains*¦user�ptr�for�this�user.)6‰TST‡RACMDERR(A3)ˆDid�this�cmd�set�the�RAD�status�flag *¦to�"busy"?‰BEQ.S…RACMDRETŒNo--go�return. ‰TST‡D0’Yes.‚Was�there�an�error?‰BEQ.S…RACMDRETŒNo--go�return.,‰BSR‡RACLRSTAŒYes--go�clear�RAD�status�flag.*ARACMDRET�MOVE†D0,RACMDERR(A3)…Put�error�return�code�in�user's�cmd*¦param�table.!‰RTS›Return�from�command�handler.*?RASKIPIT�MOVE.L„#RASYSERR,D0ˆSet�D0�to�indicate�"can't�use�this*¦RAD"�(due�to�SYSGEN�error).‰BRA‡RACMDRETŒReturn�to�user.*D*-------------------------------------------------------------------D*ˆCommand�table,�jump�table,�and�"interrupt�instruction"�flag�table.2*’(Entries�in�these�three�tables�must�correspond.)*9RAJMPTBL�BRA.L…RARADSTPŒJump�table�--�all�entries�must�be6‰BRA.L…RARADLODŒlong�branches�to�appropriate�routines.‰BRA.L…RARADDMP‰BRA.L…RARADJMP‰BRA.L…RARADTSTŒ(5th�entry)‰BRA.L…RARADEXT‰BRA.L…RARADSET‰BRA.L…RARADSCN‰BRA.L…RARADATO‰BRA.L…RARADCALŒ(10th�entry)‰BRA.L…RARADOPN‰BRA.L…RARADCLS‰BRA.L…RARADXEQ‰BRA.L…RARADABT‰BRA.L…RARADHISŒ(15th�entry)**--------------------------*4RACMDTBL�DC.B†RASTPCMDŒTable�of�legal�command�codes.2‰DC.B†RALODCMDŒEach�entry�is�one�byte�long;‚end�of4‰DC.B†RADMPCMDŒtable�is�indicated�by�$FF,�which�must.‰DC.B†RAJMPCMDŒNOT�be�a�valid�code,�of�course.‰DC.B†RATSTCMDŒ(5th�entry)‰DC.B†RAEXTCMD‰DC.B†RASETCMD‰DC.B†RASCNCMD‰DC.B†RAATOCMD‰DC.B†RACALCMDŒ(10th�entry)‰DC.B†RAOPNCMD‰DC.B†RACLSCMD‰DC.B†RAXEQCMD‰DC.B†RAABTCMD‰DC.B†RAHISCMDŒ(15th�entry)‰DC.B†$FF‘End�of�table.**----------------------------*7RAINSTBL�DC.B†1‰Table�of�"instruction"�flags�which�tell-‰DC.B†1‰the�driver�what�is�to�be�done�when�an-‰DC.B†1‰interrupt�comes�in�for�this�function.4‰DC.B†2‰(1�=�Put�"task"�into�READY�state;�i.e.,�turn)‰DC.B†1“cmd�handler�for�this�cmd�back�on.+‰DC.B†2Š$ 2�=�Call�data-retrieval�subroutine.4‰DC.B†2Š0�=�Don't�do�anything�special--just�turn�off,‰DC.B†2“the�interrupt�and�return.‚(Shouldn't#‰DC.B†2“get�an�interrupt�on�these.)‰DC.B†1‰(10th�entry)‰DC.B†0‰DC.B†1‰DC.B†2‰DC.B†1‰DC.B†0‰(15th�entry)*‰DSˆ0‰(Set�PC�to�even�address.)‰PAGE** ERROR ROUTINE*IOHERCHK‚EQU„* ŠCLR.L‚D0ŠMOVE.B�D7,D0ŽVALIDATION�STATUS2ŠMOVE.L�(A7)+,CCBERAD1(A5)�SAVE�DBUG�ERROR�ADDRESSŠBRA†RACMDRET‰GET�OUT�OF�HEREŠPAGE;************************************************************$*ˆSubroutine�to�handle�RADOPN�calls.*3*’This�routine�"opens"�the�desired�channels�for�use*’by�this�user.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P*;***********************************************************RARADOPN�EQU‡*8‰BSR‡RAFNDUSR‚Check�user�list�to�see�if�there�already�is*¦and�entry�for�this�user-RAD*¦combination�in�RAUSRLST.6‰MOVE.L„RAD1TBL,A1ŠSet�A1�to�start�addr�of�table�area.‰TST‡D0ˆIs�there�an�entry?(‰BEQ.S…RAOPGOT1‚Yes--use�the�same�entry.+‰CLR.L…D2ˆNo--put�this�comb.�into�RAUSRLST.7‰MOVE†RAUSRLNX(A1),D2…Put�next-avail�entry�ptr�into�D2.4‰CMP‡#$FFFF,D2‹Is�there�an�available�RAUSRLST�entry?‰BEQ‡RAOPNORMŒNo--error.***¦Yes--calculate�addr�of�next�avail�entry.5‰MOVE.L„D2,D1�Store�next�avail�entry�#�for�later�use.*‰MULU†#RAULNG,D2ŠMultiply�by�entry�length.9‰LEA‡RAUSRLST(A1),A4…Load�start�addr�of�RAUSRLST�into�A4.2‰ADDA.L„D2,A4�Set�A4�to�start�addr�of�avail�entry.:‰MOVE†RAURADID(A4),RAUSRLNX(A1)…Move�ptr�to�the�next�avail(*¦entry�(which�was�stored�in�the�1st�two'*¦bytes�of�the�RAD-ID�field�of�RAUSRLST#*¦entry)�into�header�of�table�area.8‰MOVE.L„TCBNAME(A6),RAUUSRNO(A4)†Store�user�#�and�RAD-ID6‰MOVE.L„TCBSESSN(A6),RAUUSRNO+4(A4)ƒinto�this�entry�in*‰MOVE.L„CCBMNEM(A5),RAURADID(A4)†RAUSRLST.>RAOPGOT1�EQU‡*‰At�this�point,�D1�contains�the�ptr�to�the�entry*¦for�this�user�in�RAUSRLST.‚A3"*¦contains�addr�of�command�packet.:‰MOVE†#RAUNORET,D0ˆInit�D0�to�error�code�for�"user�has�not$*¦specified�error-reporting�option"./‰MOVE.L„D1,D3�Set�D3�to�user�ptr�for�this�user.9‰MULU†#RAULNG,D3ŠMultiply�by�length�of�an�RAUSRLST�entry.6‰MOVE.L„RAD1TBL,A1ŠSet�A1�to�start�addr�of�table�area.8‰LEA‡RAUSRLST(A1),A1…Put�start�addr�of�RAUSRLST�into�A1.4‰ADD.L…D3,A1�A1�now�contains�the�addr�of�this�user's*¦entry�in�RAUSRLST.:‰TST‡RAUEROPT(A1)ˆHas�error-reporting�option�for�this�user‰BEQ.S…RAOP2�been�set?‚No. ‰CLR.L…D0’Yes--clear�error�flag.ARAOP2„MOVE†RACMDPRM(A3),D2…Put�#�chan's�(from�param�table)�in�D2."‰BNE.S…RAOP3�If�not�0,�then�go�on.:‰MOVE.L„#RAERR4,D0ŠSet�D0�to�"parameter-table-error"�code.‰BRA‡RAOPRET�Go�return.@RAOP3„LEA‡RACMDPRM+2(A3),A4ƒSet�A4�to�start�addr�of�chan�data�in*¦command�param�table./RAOPLUP1�CLR.L…D3’Put�requested�chan�#�into�D3.‰MOVE.B„1(A4),D3‰CMPI.B„#$1F,D3�Valid�chan�#?‰BLS.S…RAOP4�Yes.5‰CMP.B…#$FF,D3�No--is�this�the�error-reporting�option*¦specification?6‰BNE‡RAOPERR1ŒNo--invalid�chan�#.�Go�to�error�routine.+‰MOVE†2(A4),D4ŒYes.‚Check�the�options�flag.%‰AND.L…#7,D4�Are�any�option�bits�set?(‰BEQ‡RAOPERR1ŒNo--no�options�set--error. ‰CLR.L…D0’Yes--clear�error�flag.‰BRA.S…RAOPOKX�Do�next�chan.3RAOP4„ASL‡#1,D3�Double�chan�#�to�be�used�as�offset.8‰CMPI†#$FFFF,RACHNUSR(A5,D3)ˆCheck�the�user�ptr�for�this)*¤chan�(in�CCB).‚Is�this�chan�unassigned?‰BEQ.S…RAOPOK1�Yes--it's�ok.?‰CMP‡RACHNUSR(A5,D3),D1‚No.‚Is�it�already�"owned"�by�this�user?3‰BNE.S…RAOPERR2ŒNo--this�chan�belongs�to�some�other*¦user.‚Go�to�error�routine.4‰MOVE.B„#1,(A4)�Yes--set�upper�byte�of�chan�#�in�cmd(*¦param�table�to�1�to�indicate�this�chan#*¦was�already�"owned"�by�this�user.'*¦(This�will�be�used�if�an�error�occurs'*¦so�that�the�user�ptr�won't�be�reset.)HRAOPOK1‚MOVE†D1,RACHNUSR(A5,D3)‚Set�user�ptr�for�this�chan�to�this�user.RAOPERR1�MOVE.L„#RAOPILL,D0‰Set�D0�to�indicate�illegal�chan�#.0‰BRA.S…RAOPERR3ŒGo�reset�user�ptrs.�for�previous*¦channels�in�cmd�param�list.CRAOPERR2�MOVE.L„#RAOPUNAV,D0ˆSet�D0�to�indicate�unavailable�chan�#.*1RAOPERR3�EQU‡*“Clear�any�user�ptrs�which�were�set'*¦while�processing�this�call�before�the*¦error�was�detected.9‰LEA‡RACMDPRM+2(A3),A4ƒSet�A4�to�start�of�chan�#'s�in�cmd *¦param�list.9‰MOVE†RACMDPRM(A3),D4…Store�#�of�chans�in�cmd�param�list.7RAOPERLP�CMP‡D2,D4�Have�we�gone�thru�all�the�entries�we(*¦went�thru�before?‚(Quit�when�we�get�to'*¦the�same�chan�#�we�got�the�error�on.)%‰BEQ‡RAOPRET�Yes--that's�all--return.#‰SUBQ†#1,D4�No--dec�count�of�chans.<‰TST.B…(A4)†Was�this�chan�assigned�to�user�before�this�call?(‰BEQ.S…RAOPERR4‚No--must�clear�user�ptr.;‰CLR.B…(A4)†Yes--leave�assignment�alone.‚Just�clear�"flag"./‰BRA.S…RAOPERR5‚Set�up�to�do�next�chan�in�list./RAOPERR4�CLR.L…D3ˆClear�user�ptr�for�this�chan.$‰MOVE.B„1(A4),D3‚Put�chan�#�into�D3.:‰ASL‡#1,D3…Double�it�to�give�offset�into�chan�list�in�CCB.5‰MOVE†#$FFFF,RACHNUSR(A5,D3)ˆSet�this�chan�to�unused.GRAOPERR5�ADDA.L„#12,A4„Set�A4�to�addr�of�next�chan�#�in�cmd�param�list.'‰BRA‡RAOPERLP‚Go�back�and�do�next�chan.**?RAOPNORM�MOVE.L„#RAOPNOMO,D0ˆSet�D0�to�indicate�no�room�for�any*¦more�user-RAD�combinations.‰BRA‡RAOPRET�Return.*‰PAGEK****************************************************************************)*ˆSubroutine�to�initialize�the�RAD�board.9*’(Sends�a�DUMP�command�to�RAD�and�checks�for�completion.3*’If�RAD�responds�correctly,�sets�chan�user�ptrs�to5*’"available"�status�and�sets�RAD�status�to�"ready".)*,*’Called�from�the�command�processor�routine.*7*ˆUpon�entry:‰A1�=�addr�of�this�RAD's�entry�in�RARADLST*œA5�=�CCB�addr**ˆUpon�return:**œ0�1�2�3�4�5�6�7*˜D:‚P�P�P�P�*�*�*�**˜A:‚*�P�P�P�*�P�P**K***************************************************************************RAINITRD�EQU‡*-‰MOVEM.LƒD0-D3,-(A7)‰Store�register�contents.;‰MOVE†#RASTDOIN,RARDSTAT(A1)‚Set�RAD�status�to�"busy--doing*¦initialization".6‰MOVE†#RAINNTRY,D4ˆSet�D4�to�max�#�of�times�to�try�for$*¦a�successful�response�from�the�RAD"*¦before�declaring�the�RAD�"dead".ARAINRD2‚MOVE.L„RASHRAD(A5),A4†Set�A4�to�start�addr�of�shared-RAM.=‰BTST.B„#7,RAXSTAT(A4)†Is�RAD�done�with�power�up�routine�yet?6‰BNE.S…RAINRDEDŒNo--should�have�been,�something�wrong.=‰MOVE.B„#RAPARAM/2,RAPRMPTR(A4)‡Yes.‚Set�param�ptr�in�shared-&*¦RAM�to�offset�in�shared-RAM�to�param%*¦area�(us% ing�RAD-addressing�offset).8‰CLR.B…RAINTMSK(A4)ˆSet�interrupt�mask�to�no�interrupts.<‰MOVE.B„#RADMPCMD,RACMDBYT(A4)ˆPut�DUMP�command�into�command)*¦byte�in�shared-RAM.‚This�will�start�the*¦"RAD-initialize"�dump.6‰BSR.S…RAWAITŽWait�for�10�millisec�before�checking�for*¦response�from�RAD.2‰CMPI.B„#$81,RACSTAT(A4)„Is�initial�dump�complete?$‰BNE.S…RAINRDEDŒNo--something�wrong.,‰MOVEP.LƒRAPARAM(A4),D3†Yes.‚Check�response.8‰CMP.L…#RABNGRAD,D3ˆIs�dump�ok�(i.e.,�was�first�longword*¦correct--should�be�"!RAD")?$‰BNE.S…RAINRDEDŒNo--something�wrong.:‰MOVE.B„RAPARAM+8(A4),RAJMPRRG(A5)ˆYes--store�RAD�"jumper"*¦data�from�dump�in�CCB�loc.(‰MOVE.L„#16,D3ŽSet�counter�for�channels.@‰BTST.B„#5,RAJMPRRG(A5)…Is�RAD�board�jumpered�for�16�chan�or�32?‰BNE.S…RAINRD3�16�channels.3‰MOVE.L„#32,D3Ž32�channels--set�chan�counter�to�32.CRAINRD3‚LEA‡RACHNUSR(A5),A4…Put�start�addr�of�chan�user�ptrs�in�A4.GRAINRDLP�MOVE.L„#$FFFFFFFF,(A4)+„Set�chan�ptr�to�"unused"�(2�chans�at�a‰SUBQ†#2,D3�time).‚All�done?‰BGT‡RAINRDLPŒNo--go�do�next.B‰MOVE†#RASTOK,RARDSTAT(A1)�Yes--set�RAD�status�to�ok�(and�unused).7RAINRDRT�MOVEM.Lƒ(A7)+,D0-D3‰Restore�register�contents. ‰RTS›Return.**:RAINRDED�SUBQ†#1,D4�RAD�did�not�respond�correctly.‚Have�we*¦tried�enough�times?*‰BLE.S…RAINRBADŒYes--go�mark�this�RAD�bad.(‰BSR.S…RAWAITŽNo--delay�for�10�millisec.‰BRA‡RAINRD2�Go�try�it�again.9RAINRBAD�MOVE†#RASTBAD,RARDSTAT(A1)‰RAD�is�not�responding&*¦correctly--set�RAD�status�to�"dead".‰BRA‡RAINRDRTŒReturn.*G* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*.RAWAITƒEQU‡*‰Routine�to�delay�10�milliseconds.*-‰MOVEM.LƒD2/A1,-(A7)‰Store�register�contents.7‰MOVE.L„#RANREQ,D3ŠSet�D3�to�max�#�of�times�to�"request%*¦periodic�activation"�unsuccessfully&*¦before�giving�up�and�just�returning.ARAWAIT1‚LEA‡RADLAY(PC),A0‡Set�up�for�periodic�activation�routine.%*¦RADLAY�is�the�routine�which�will�be)*¦turned�on�at�the�end�of�10�msec.,�which&*¦will,�in�turn,�reactivate�this�task.%‰MOVE.L„#10,A1ŽSet�delay�for�10�msec.2‰CLR.L…D1’Set�to�request�activation�one�time�only.:‰MOVE.B„CCBPPRIO(A5),D1…Set�priority�of�activation�to�same*¦priority�as�this�task�has.1‰MOVE.L„A6,D2�Put�TCB�addr�into�D2,�to�be�used�as *¦request�ID.2‰TR0$.RQPA‚,’Trap�to�"request�periodic�activation" *¦routine.%‰BRA.S…RAWAITOKŒRequest�was�accepted.0‰SUBQ†#1,D3�Request�was�denied.‚Have�we�tried�it*¦enough�times?#‰BGT‡RAWAIT1�No--try�request�again.,‰BRA.S…RAWAITRTŒYes--forget�it--just�return.9RAWAITOK�TR0$.PAUSE�,’Wait�for�10�msec.�to�be�up.‚(RADLAY(*¦will�then�be�"turned�on"�and�will�then*¦restart�this�task�here.)7RAWAITRT�MOVEM.L„(A7)+,D2/A1ˆRestore�register�contents. ‰RTS›Return.*M*‚=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=�=*2RADLAYƒEQU‡*“Routine�to�re-activate�driver�routine#*¦after�a�delay�made�using�"request*¦periodic�activation"�routine.*3‰MOVE.L„D1,A0�D1�contains�TCB�addr�which�was�passed&*¦as�request�ID�to�periodic�activation%*¦routine.‚Put�it�in�A0�as�task�to�be*¦turned�back�on.*‰TR0$.READY�,’Put�task�into�"ready"�state.%‰RTE›Return�from�periodic�activation.**‰PAGE:***********************************************************$*ˆSubroutine�to�handle�RADSET�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**:**********************************************************3RARADSET�EQU‡*‰Routine�to�set�up�for�setpoint�scan.:‰MOVE†RACMDPRM+2(A3),D4ƒPut�#�of�non-setpoint�chans�in�D4.:‰LEA‡RACMDPRM+4(A3),A4ƒSet�A4�to�addr�of�start�of�chans�in*¦cmd�param�table. ‰CLR.L…D35‰MOVE†RAPARAM(A3),D3†Put�#�of�setpoint�chans�into�D3.0‰MULU†#6,D3�Calculate�#�bytes�for�setpt�chans�in*¦cmd�param�table.1‰ADD.L…D3,A4�S% et�A4�to�start�addr�of�non-setpoint*¦chans�in�cmd�param�table.3‰MOVE.L„#2,D3�Set�D3�to�addr�increment�to�next�chan *¦in�list.6‰BSR‡RACHKCHNŒGo�check�these�chans�to�be�sure�they�are*¦"owned"�by�this�user.‰TST.L…D0’All�ok?3‰BNE.S…RASETRETŒNo,�error--make�error�return�(D0�is#*¦already�set�to�error�flag�value).*‰CLR.L…D4ˆPut�#�of�setpoint�chans�into�D4.‰MOVE†RACMDPRM(A3),D47‰LEA‡RACMDPRM+4(A3),A4ƒSet�A4�to�start�addr�of�setpoint*¦chans�in�cmd�param�list..‰MOVE.L„#6,D3�Set�D3�to�addr�increment�to�next*¦setpoint�chan�#�in�list.1‰BSR‡RACHKCHNŒGo�check�setpoint�chans�to�see�that*¦they�"belong"�to�this�user.‰TST.L…D0’Do�they?4‰BNE.S…RASETRETŒNo,�error--return�(D0�contains�error*¦code�already).8‰MULU†#3,D4…Multiply�by�3�to�give�#�of�words�of�setpoint*¦chan�data�in�param�table.3‰ADD‡RACMDPRM+2(A3),D4„Add�#�of�non-setpoint�chans./‰ADD‡#2,D4�Add�2�for�the�counts�to�give�total�#*¦of�words�in�param�table. ‰MOVE†D4,D3�Store�#�words�in�D3.'‰ADDQ†#1,D4�Add�1�for�#-of-words�count.;‰ASL‡#1,D4…Double�D4�to�give�#�bytes�to�move�to�shared-RAM.:‰LEA‡RACMDPRM-2(A3),A4…Set�A4�to�start�addr�of�params�(1st**¦2�bytes�are�garbage--will�be�set�later.)2‰BSR‡RAMOVPRMŒPut�the�param�table�into�shared-RAM.8‰MOVEP…D3,RAPARAM(A1)†Set�#�of�words�in�shared-RAM�param*¦table.2‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�in�shared-RAM.;‰MOVE.B„#5,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to)*¦interrupt�at�end�of�scan�or�end�of�cmd.8‰MOVE.B„#RASETCMD,RACMDCOD(A5)ˆStore�cmd�code�in�CCB�for *¦later�use.<‰MOVE.B„#RASETCMD,RACMDBYT(A1)ˆStore�cmd�code�in�cmd�byte�of,*£shared-RAM�to�start�execution�of�function./‰CLR.L…D0’Clear�D0�to�indicate�successful�start*¦of�setpoint�cmd.RASETRET�EQU‡**‰RTS›Return�and�wait�for�"done"�interrupt.‰PAGE K****************************************************************************$*ˆSubroutine�to�handle�RADSCN�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**K***************************************************************************RARADSCN�EQU‡****+‰MOVE†RACMDPRM+2(A3),D4ƒMove�#�chans�to�do.7‰LEA‡RACMDPRM+4(A3),A4ƒSet�A4�to�addr�of�chan�#s�in�cmd*¦param�table.0‰MOVE.L„#2,D3�Set�increment�value�to�next�chan�# *¦in�list.1‰BSR‡RACHKCHNŒCheck�requested�chan�#s�to�see�that!*¦they�all�"belong"�to�this�user.‰TST.L…D0’Do�they?2‰BNE.S…RASCNRETŒNo--make�error�return.‚(D0�already*¦contains�error�code.)1‰ADDQ†#2,D4�Add�2�to�give�#�of�words�to�move�into4‰ASL.L…#1,D4�param�area;�then�double�to�get�#�bytes.9‰LEA‡RACMDPRM(A3),A4…Set�A4�to�start�addr�of�params�to�be*¦put�into�shared-RAM./‰BSR‡RAMOVPRMŒMove�param�table�into�shared-RAM.3‰LEA‡RAPARAM(A1),A4†Set�A4�to�addr�in�shared-RAM�of*¦param�table.-‰MOVE†RACMDPRM+2(A3),D4ƒSet�D4�to�#�of�chans.&‰ADDQ†#1,D4�Add�1�to�give�#�of�params.6‰MOVE.B„(A4),4(A4)ŠRearrange�param�table�in�shared-RAM9‰MOVE.B„2(A4),6(A4)‰for�RAD�firmware.‚Put�#�params�first,&*¦followed�by�delay�length.‚(Note�that2‰MOVEP…D4,0(A4)Œ68000�addresses�shared-RAM�on�only*¦every�other�byte.);‰CLR.B…RACSTAT(A1)‰Clear�command�status�byte�in�shared-RAM.=‰MOVE.B„#5,RAINTMSK(A1)…Set�interrupt�mask�byte�in�shared-RAM!*¦for�interrupt�on�end-of-scan�or*¦end-of-command.C‰MOVE.B„#RASCNCMD,RACMDCOD(A5)‚Store�cmd�code�in�CCB�for�later�use.:‰MOVE.B„#RASCNCMD,RACMDBYT(A1)ˆSet�command�byte�in�shared-#*¦RAM�to�execute�scanning�function.8‰CLR.L…D0ˆClear�D0�to�indicate�successful�start�of�scan.RASCNRET�EQU‡**‰RTS‘Return�and�wait�for�"done"�interrupt.‰PAGEL*****************************************************************************$*ˆSubroutine�to�handle�RADEXT�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�ret& urn:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**L****************************************************************************?RARADEXT�EQU‡*‰Routine�to�set�up�for�external�trigger�function.1‰MOVE†RACMDPRM(A3),D4…Set�D4�to�#�of�chans�to�do.5‰LEA‡RACMDPRM+2(A3),A4ƒPut�addr�of�chan�#�list�in�A4.1‰MOVE.L„#2,D3�Set�D2�to�increment�to�next�chan�#.0‰BSR‡RACHKCHNŒCheck�chan�#s�to�see�that�they�all*¦"belong"�to�this�user.‰TST.L…D0’Do�they?3‰BNE.S…RAEXTRETŒNo,�make�error�return.‚(D0�contains*¦correct�error�code.),‰ADDQ†#1,D4�Add�one�to�#�of�chans�for�count..‰ASL.L…#1,D4�Double�to�give�#�bytes�to�be�sent *¦to�the�RAD.7‰LEA‡RACMDPRM(A3),A4…Set�A4�to�addr�of�params�to�be�put!*¦into�param�table�in�shared-RAM.*‰BSR‡RAMOVPRMŒMove�params�into�shared-RAM.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.;‰MOVE.B„#5,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to)*¦interrupt�on�end�of�scan�or�end�of�cmd.C‰MOVE.B„#RAEXTCMD,RACMDCOD(A5)‚Store�cmd�code�in�CCB�for�later�use.<‰MOVE.B„#RAEXTCMD,RACMDBYT(A1)‚Put�cmd�code�into�cmd�byte�in,*¤shared-RAM�to�start�execution�of�function.<‰CLR.L…D0ˆClear�D0�to�indicate�successful�start�of�function.RAEXTRET�EQU‡*#‰RTS›Return�and�wait�for�interrupt.‰PAGEN*******************************************************************************$*ˆSubroutine�to�handle�RADATO�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**N******************************************************************************5RARADATO�EQU‡*‰Routine�to�set�up�for�auto-range�scan.*‰MOVE†RACMDPRM(A3),D4…Move�#�chan�to�scan.5‰LEA‡RACMDPRM+2(A3),A4ƒPut�addr�of�chan�list�into�A4.6‰MOVE.L„#2,D3�Set�D3�to�addr�increment�to�next�chan�#.0‰BSR‡RACHKCHNŒCheck�chan�#s�to�see�that�they�all*¦"belong"�to�this�user.‰TST.L…D0’Do�they?3‰BNE.S…RAATORETŒNo,�make�error�return.‚(D0�contains*¦correct�error�code.)1‰ADDQ†#1,D4…Add�1�to�#�of�chans�to�include�count.;‰ASL‡#1,D4…Double�to�give�#�bytes�of�params�to�send�to�RAD.:‰LEA‡RACMDPRM(A3),A4…Set�A4�to�addr�of�params�to�be�moved.-‰BSR‡RAMOVPRMŒMove�param�table�to�shared-RAM.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.@‰MOVE.B„#5,RAINTMSK(A1)…Set�interrupt�mask�byte�in�shared-RAM�to)*¦interrupt�on�end�of�scan�or�end�of�cmd.C‰MOVE.B„#RAATOCMD,RACMDCOD(A5)‚Store�cmd�code�in�CCB�for�later�use.B‰MOVE.B„#RAATOCMD,RACMDBYT(A1)‚Set�cmd�byte�in�shared-RAM�to�start*¦auto-range�scanning�function.<‰CLR.L…D0ˆClear�D0�to�indicate�successful�start�of�function.RAATORET�EQU‡*#‰RTS›Return�and�wait�for�interrupt.‰PAGEN*******************************************************************************$*ˆSubroutine�to�handle�RADHIS�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**N******************************************************************************5RARADHIS�EQU‡*‰Routine�to�set�up�for�high-speed�scan.,‰CLR.L…D3’Set�up�to�check�chan�#�to�see�that(‰MOVE.L„#1,D4�it�"belongs"�to�this�user.5‰LEA‡RACMDPRM+4(A3),A4ƒSet�A4�to�addr�of�chan�"list".‰BSR‡RACHKCHNŒGo�check�chan�#./‰TST.L…D0’Does�this�chan�"belong"�to�this�user?2‰BNE.S…RAHISRETŒNo--make�error�return.‚(D0�already*¦contains�correct�error�code.);‰TST.L…RACMDPRM(A3)ˆIs�there�a�user-supplied�data-retrieval *¦subroutine?‰BEQ.S…RAHIS2ŽNo--error.?‰MOVE.L„RASHRAD(A5),A1†Yes--set�A1�to�start�addr�of�shared-RAM.:‰CLR.B…RAPARAM(A1)‰Move�$0001�into�1st�word�of�param�table'‰MOVE.B„#1,RAPARAM+2(A1)„in�shared-RAM.B‰MOVE.B„RACMDPRM+4(A3),RAPAR& AM+4(A1)‚Put�chan�#�to�be�scanned�into?‰MOVE.B„RACMDPRM+5(A3),RAPARAM+6(A1)‚param�table�in�shared-RAM.<‰MOVE.B„#RAPARAM/2,RAPRMPTR(A1)‡Put�offset�to�param�table�in)*¦shared-RAM�(6809�addressing)�into�param*¦ptr�in�shared-RAM.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.9‰CLR.B…RAINTMSK(A1)ˆSet�interrupt�mask�in�shared-RAM�to�0*¦to�indicate�no�interrupts.>‰MOVE.B„#1,RAOK2STO(A1)…Set�"ok�to�store�next�conversion"�flag*¦in�shared-RAM.8‰MOVE.B„#RAHISCMD,RACMDCOD(A5)ˆStore�cmd�code�in�CCB�for *¦later�use.<‰MOVE.B„#RAHISCMD,RACMDBYT(A1)ˆSet�cmd�byte�in�shared-RAM�to%*¦begin�execution�of�high-speed�scan.<‰MOVE.L„RACMDPRM(A3),A2…Go�to�user-supplied�data-acquisition=‰MOVEM.LƒD0-D7/A0-A6,-(A7)ƒroutine�after�storing�all�register.‰JSR‡(A2)�contents.‚This�routine�will�take�all(*¦the�desired�data�and�will�return�after(*¦having�stopped�the�high-speed�scanning *¦function.5‰MOVEM.Lƒ(A7)+,D0-D7/A0-A6ƒRestore�register�contents.4‰CLR.L…D0‡Clear�D0�indicate�a�successful�completion.RAHISRET�EQU‡* ‰RTS›Return..RAHIS2ƒMOVE.L„#RAERR4,D0ŠSet�error�code�in�D0.‰BRA‡RAHISRETŒGo�return.‰PAGEN*******************************************************************************$*ˆSubroutine�to�handle�RADJMP�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**N******************************************************************************>RARADJMP�EQU‡*‰Routine�to�set�up�for�jump-to-RAD-addr�command.9‰MOVE.B„#RAJMPCMD,D1ˆSet�D1�to�cmd�code�for�jump�command.=‰LEA‡RACMDPRM(A3),A4…Set�A4�to�start�addr�of�cmd�param�table.4‰BRA.S…RAXEQ2ŽGo�to�2nd�entry�in�RARADXEQ.‚(Jump�and)*¦execute-function�routines�have�the�same*¦set-up�for�running.)‰PAGEL*****************************************************************************$*ˆSubroutine�to�handle�RADXEQ�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**L****************************************************************************>RARADXEQ�EQU‡*‰Routine�to�set�up�for�execute-function�command.>‰MOVE.B„RACMDPRM+1(A3),D1…Set�D1�to�function�#�to�be�executed.5‰OR.B†#RAXEQBYT,D1ˆSet�the�"execute�function"�cmd�bit*¦to�get�the�command�code.<‰LEA‡RACMDPRM+2(A3),A4ƒSet�A4�to�addr�of�rest�of�the�params.*M*============================================================================K*=============‚RAXEQ2�is�a�2nd�entry�point�into�this�routine.‚=============>*=============…(It�is�used�by�RARADJMP�routine.)Œ=============*9RAXEQ2ƒTST.L…(A4)†Is�there�a�user-supplied�data-retrieval*¦subroutine�specified?2‰BEQ.S…RAXEQ3„No--use�read-FIFO�routine�(default).>‰MOVE.L„(A4),RARTRVAD(A5)ƒYes--store�addr�of�subroutine�in�CCB*¦for�later�use.BRAXEQ3ƒADDQ.L„#6,A4…Set�A4�to�start�of�params�to�be�passed�to�RAD.1‰MOVE†(A4),D4ƒSet�D4�to�#�of�params�to�be�passed.(‰ADDQ†#1,D4…Add�1�to�include�word�count.<‰ASL‡#1,D4…Double�to�give�#�bytes�to�be�moved�to�shared-RAM.9‰BSR‡RAMOVPRM‚Move�params�into�param�table�in�shared-RAM.9‰MOVE.B„-1(A4),RAINTMSK(A1)‹Set�interrupt�mask�in�shared-*¦RAM�as�specified�by�the�user.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.<‰MOVE.B„D1,RACMDCOD(A5)…Store�cmd�code�in�CCB�for�later�use.;‰MOVE.B„D1,RACMDBYT(A1)…Set�cmd�byte�in�shared-RAM�to�start*¦execution�of�desired�command.<‰CLR.L…D0ˆClear�D0�to�indicate�successful�start�of�function.‰RTS›Return�and�wait�for�data.‰PAGEM******************************************************************************$*ˆSubroutine�to�handle�RADSTP�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�c' ommand�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**M*****************************************************************************>RARADSTP�EQU‡*‰Routine�to�stop�this�user's�function�running�on*¦the�RAD�board.1‰BSR‡RAFNDUSR‚Find�this�user's�entry�in�RAUSRLST.%‰TST‡D0ˆIs�this�user/RAD�in�RAUSRLST?‰BNE.S…RASTPER1‚No--error.9‰MOVE.L„RARDLADR(A5),A1…Yes.‚Put�addr�of�this�RAD's�entry*¦in�RARADLST�into�A1.4‰CMP‡RARDSTAT(A1),D1…(D1�contains�user�ptr.)‚Is�this*¦user�using�this�RAD�now?‰BNE.S…RASTPER1ŒNo--error.;‰MOVE.L„RASHRAD(A5),A1†Yes.‚Set�A1�to�start�addr�of�shared-*¦RAM.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.;‰MOVE.B„#1,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to#*¦interrupt�when�command�completes.:‰MOVE.B„#RASTOPIT,RASTPBYT(A1)ˆSet�stop�byte�in�shared-RAM*¦to�stop�RAD�processing.&‰TR0$.PAUSEŠ,‰Wait�for�done�interrupt.K*>>>>>>>>>>>>>>>>‚Return�here�from�interrupt.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'‰CMP.B…#$84,RACSTAT(A1)„RAD�stopped�ok?‰BNE.S…RASTPERRŒNo--error.7‰MOVE.L„RARTRVAD(A5),A2…Yes.‚Get�addr�of�data-retrieval>‰MOVEM.LƒD0-D7/A0-A6,-(A7)ƒroutine�and�get�whatever�data�there‰JSR‡(A2)�is�in�shared-RAM.5‰MOVEM.Lƒ(A7)+,D0-D7/A0-A6ƒRestore�register�contents.7‰MOVE.L„RARDLADR(A5),A1…Put�addr�of�this�RAD's�entry�in*¦RARADLST�into�A1.4‰MOVE†#RASTOK,RARDSTAT(A1)ŠSet�RAD�status�to�unused./‰LEA‡RARDFIFO(PC),A1…Set�addr�of�data-retrieval4‰MOVE.L„A1,RARTRVAD(A5)…subroutine�to�RARDFIFO�addr./‰CLR.L…D0ˆClear�D0�to�indicate�successful�stop.RASTPRET�EQU‡*‰RTS‘Return�to�user.7RASTPERR�BSR‡RAEXERR�Set�"execution�error"�value�in�D0.‰BRA‡RASTPRETŒGo�return.>RASTPER1�MOVE.L„#RANOTUSR,D0ˆSet�"this�user�not�using�RAD�now"'‰BRA‡RASTPRETŒerror�flag�and�go�return.‰PAGEM******************************************************************************$*ˆSubroutine�to�handle�RADCLS�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**M*****************************************************************************:RARADCLS�EQU‡*‰Routine�to�close�RAD�from�use�by�this�user.?‰BSR‡RAFNDUSR‚Find�this�user's�entry�(w/�this�RAD)�in�RAUSRLST.,‰TST‡D0ˆWas�this�user/RAD�combination�found?‰BNE.S…RACLSERR‚No--error.<‰MOVE.L„RARDLADR(A5),A2…Yes--D1�contains�user�ptr.‚Set�A2�to'*¦addr�of�this�RAD's�entry�in�RARADLST.5‰CMP‡RARDSTAT(A2),D1…Is�this�user�using�this�RAD�now?‰BNE.S…RACLS2ŽNo.9‰MOVE.L„RASHRAD(A5),A1†Yes--stop�function�running�in�RAD.%*¦Set�A1�to�start�addr�of�shared-RAM.9‰MOVE†#1,RACMDERR(A3)…Set�error�return�location�in�user's&*¦cmd�table�to�indicate�that�this�user'*¦is�stopping�the�RAD�board,�so�the�RAD'*¦status�will�be�set�to�"ok"�when�done.2‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�in�shared-RAM.;‰MOVE.B„#1,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to*¦interrupt�at�end�of�cmd.:‰MOVE.B„#RASTOPIT,RASTPBYT(A1)ˆSet�stop�byte�in�shared-RAM*¦to�stop�RAD�processing.&‰TR0$.PAUSEŠ,‰Wait�fpr�done�interrupt.=*>>>>>>>>>>>> Return here from interrupt. <<<<<<<<<<<<<<<<<<<(‰CMP.B…#$84,RACSTAT(A1)„Did�RAD�stop�ok?0‰BNE.S…RACLSER2ŒNo--some�kind�of�error�occurred.4RACLS2ƒMOVE†#32,D2ŽYes.‚Close�all�this�user's�chans.5‰LEA‡RACHNUSR(A5),A1…Set�A1�to�addr�of�user�pointers.:RACLSLUP�CMP‡(A1),D1�Does�this�chan�"belong"�to�this�user? ‰BNE.S…RACLS3ŽNo--go�check�next.0‰MOVE†#$FFFF,(A1)‰Yes--set�this�chan�user�ptr�to*¦"unassigned"�status.9RACLS3ƒADD.L…#2,A1�Bump�A1�to�pt�to�next�chan's�user�ptr.‰SUBQ†#1,D2�All�done?‰BGT‡RACLSLUPŒNo--go�do�next.2‰MOVE†D1,D2�Yes.‚Store�user�ptr�for�this�user/RAD.:‰MULU†#RAULNG,D1ˆDelete�this�user/RAD�entry�from�RAUSRLST.0‰MOVE.L„RAD1TBL,A1ŠPut�addr�of�RAUSRLST�' into�A2.‰LEA‡RAUSRLST(A1),A2<‰CLR.L…RAUUSRNO(A2,D1)…Clear�user�#,�RAD-ID,�and�user�status+‰CLR.L…RAUUSRNO+4(A2,D1)ƒfor�this�user/RAD.‰CLR.L…RAURADID(A2,D1)‰CLR‡RAUSTAT(A2,D1)A‰MOVE†RAUSRLNX(A1),RAURADID(A2,D1)‚Put�ptr�to�next�avail�entry�in,*¤RAUSRLST�into�1st�2�bytes�of�RAD-ID�field.=‰MOVE†D2,RAUSRLNX(A1)…Set�next-avail-entry�ptr�to�this�entry.0‰CLR.L…D0’Clear�D0�to�indicate�successful�close.RACLSRET�EQU‡*3‰TST‡RACMDERR(A3)ˆDid�this�user�stop�the�RAD�board?‰BEQ.S…RACLSRT2ŒNo--go�return.'‰BSR‡RACLRSTAŒYes--go�clear�RAD�status.RACLSRT2�EQU‡* ‰RTS›Return.BRACLSERR�MOVE.L„#RAUSRERR,D0ˆSet�"this�user�not�open�for�this�RAD"*¦error�flag�in�D0.‰BRA‡RACLSRETŒGo�return.6RACLSER2�BSR‡RAEXERR�Set�"execution�error"�flag�in�D0.‰BRA‡RACLSRET‚Go�return.‰PAGEM******************************************************************************$*ˆSubroutine�to�handle�RADDMP�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**M*****************************************************************************6RARADDMP�EQU‡*‰Routine�to�set�up�to�dump�RAD's�memory.3‰MOVE.L„RACMDPRM(A3),-(A7)‚Save�command�parameters.‰MOVE.L„RACMDPRM+4(A3),-(A7)RADMP1ƒCLR.L…D39‰MOVE†RACMDPRM+4(A3),D3ƒPut�#�words�to�be�dumped�into�D3.6‰CMP‡#RALODLNG,D3ˆIs�#�words�to�be�dumped�small�enough$*¦to�be�done�in�one�transfer�through *¦shared-RAM?‰BLS.S…RADMP2ŽYes--go�do�it.6‰MOVE†#RALODLNG,D3ˆNo--must�break�it�up�and�do�it�part'*¦at�a�time.‚Set�up�to�do�the�1st�part.@RADMP2ƒMOVE.L„RASHRAD(A5),A1†Set�A1�to�start�addr�of�shared-RAM.;‰MOVE.B„#RAPARAM/2,RAPRMPTR(A1)‡Set�up�param�ptr�in�shared-5‰CLR.B…RAPARAM(A1)‰RAM.‚Clear�1st�byte�of�param�table9‰MOVE.B„#2,RAPARAM+2(A1)„and�put�2�(#�of�words�of�params)!*¦into�param�table�in�shared-RAM.<‰MOVEP…D3,RAPARAM+8(A1)„Put�#�words�to�dump�into�param�table*¦in�shared-RAM.>‰MOVE.B„RACMDPRM+6(A3),RAPARAM+4(A1)‚Put�RAD�addr�to�dump�fromA‰MOVE.B„RACMDPRM+7(A3),RAPARAM+6(A1)‚into�shared-RAM�param�table.8‰MOVE.B„#RADMPCMD,RACMDCOD(A5)ˆStore�cmd�code�in�CCB�for *¦later�use.2‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�in�shared-RAM.;‰MOVE.B„#1,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to *¦interrupt�on�command�complete.9‰MOVE.B„#RADMPCMD,RACMDBYT(A1)ˆSet�cmd�code�in�shared-RAM*¦to�execute�dump�function.(‰TR0$.PAUSEŠ,‰Wait�for�"done"�interrupt.F*>>>>>>>>>>>>>‚Return�from�interrupt�here.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<:‰CMPI.B„#$80,RACSTAT(A1)„Check�completion�status�from�RAD.*‰BNE.S…RADMPERRŒStatus�is�not�good--error.'‰MOVE†D3,D4�Put�#�words�dumped�into�D4.$‰ASL‡#1,D4�Double�it�to�get�#�bytes.:‰MOVE.L„RACMDPRM(A3),A4…Put�addr�of�user's�buffer�into�A4.:‰LEA‡RAPARAM+12(A1),A2ƒPut�addr�in�shared-RAM�of�dump�data *¦into�A2.;RADMPLUP�MOVE.B„(A2),(A4)+ŠMove�a�byte�from�shared-RAM�into*¦user's�data�buffer.+‰ADD‡#2,A2�Bump�shared-RAM�ptr�to�next�byte*¦(68000�addressing).1‰SUBQ†#1,D4�Decrement�byte�count--any�more�to�do?‰BHI‡RADMPLUPŒYes--go�do�next.<‰SUB‡D3,RACMDPRM+4(A3)ƒNo.‚Subtract�#�words�dumped�this�time!*¦from�total�#�left�to�be�dumped.6‰BEQ.S…RADMP3ŽIf�zero,�finished�all�of�requested�dump.+‰ASL.L…#1,D3�Double�#�words�to�get�#�bytes.9‰ADD.L…D3,RACMDPRM(A3)…Add�#�bytes�to�user's�buffer�addr.<‰ADD‡D3,RACMDPRM+6(A3)ƒAdd�#�bytes�to�RAD�addr�to�dump�from.(‰BRA‡RADMP1ŽGo�back�and�do�next�piece�of*¦requested�dump./RADMP3ƒCLR.L…D0’Clear�D0�to�indicate�successful*¦completion�of�dump.‰BSR‡RACLRSTAŒClear�RAD�status.RADMPRET�EQU‡*3‰MOVE.L„(A7)+,RACMDPRM+4(A3)ŠRestore�user's�command+‰MOVE.L„(A7)+,RACMDPRM(A3)Œparameter�table. ‰RTS›Return.‰MOVE.B„RACMDPRM+6(A3),RAPARAM+4(A1)‚Put�addr�in�RAD�RAM�to�be;‰MOVE.B„RACMDPRM+7(A3),RAPARAM+6(A1)‚loaded�into�shared-RAM*¦param�table.+‰MOVE†D3,D4�Put�#�words�to�be�loaded�in�D4.&‰ADDQ†#1,D4�Add�1�to�give�#�of�params.2‰MOVEP…D4,RAPARAM(A1)†Put�#�params�into�shared-RAM*¦param�table.C‰MOVE.B„#RALODCMD,RACMDCOD(A5)‚Store�cmd�code�in�CCB�for�later�use.7‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�byte�in�shared-RAM.;‰MOVE.B„#1,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to *¦interrupt�on�command�complete.<‰MOVE.B„#RALODCMD,RACMDBYT(A1)‚Set�cmd�byte�in�shared-RAM�to*¦execute�load�function.(‰TR0$.PAUSEŠ,‰Wait�for�"done"�interrupt.K*>>>>>>>>>>>>>>>>‚Return�here�from�interrupt.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:‰CMPI.B„#$80,RACSTAT(A1)„Check�completion�status�from�RAD.*‰BNE.S…RALODER2ŒStatus�is�not�good--error.=‰SUB‡D3,RACMDPRM+4(A3)ƒSubtract�#�words�loaded�this�time�from*¦#�left�to�be�loaded.,‰BEQ.S…RALOD3ŽIf�no�more�left�to�do,�return./‰ASL.L…#1,D3�Double�to�get�#�bytes�just�loaded.6‰ADD.L…D3,RACMDPRM(A3)…Add�#�bytes�loaded�this�time�to7‰ADD‡D3,RACMDPRM+6(A3)ƒaddresses�in�cmd�param�table�for*¦remaining�loading.'‰BRA‡RALOD1ŽGo�back�and�load�next�part.5RALOD3ƒCLR.L…D0’Clear�D0�to�indicate�successful�load.‰BSR‡RACLRSTAŒClear�RAD�status.RALODRET�EQU‡*3‰MOVE.L„(A7)+,RACMDPRM+4(A3)ŠRestore�user's�command+‰MOVE.L„(A7)+,RACMDPRM(A3)Œparameter�table. ‰RTS›Return.@RALODERR�MOVE.L„#RAERR4,D0ŠSet�D0�to�error�value�for�param�table*¦error.‰BRA‡RALODRETŒGo�return.8RALODER2�BSR‡RAEXERR�Set�D0�to�error�value�for�execution*¦error.‰BRA‡RALODRET‚Go�return.‰PAGEJ***************************************************************************$*ˆSubroutine�to�handle�RADCAL�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**K***************************************************************************>>>>>>>>>>>>>>‚Return�from�interrupt�here.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<-‰CMP.B…#$80,RACSTAT(A1)„Was�cmd�completed�ok?‰BNE.S…RACALERRŒNo--error.@‰MOVE.B„RANXT2GT(A1),D2…Yes--get�calibration�readings�from�FIFO.!*¦Put�next-to-get�offset�into�D2. ‰CLR.L…D5>>>>>>>>>>>>>>‚Return�from�interrupt�here.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<;‰MOVEP.LƒRATSTAT(A1),D0†Put�status�into�cmd�param�table�for)‰MOVE.L„D0,RACMDPRM+2(A3)†return�to�user./‰CMP.B…#$80,RACSTAT(A1)„Self-test�completed�ok?‰BEQ.S…RATST2ŽYes.-‰CMP.B…#$03,RACSTAT(A1)„No.‚Self-test�failed?%‰BNE.S…RATSTERRŒNo--some�other�error.8‰MOVE.L„#RATSTFAL,D0ˆSet�D0�to�"test�failed"�indication.4‰MOVE.L„RARDLADR(A5),A1…Set�the�RAD�status�to�"bad".‰MOVE†#RASTBAD,RARDSTAT(A1)RATSTRET�EQU‡* ‰RTS›Return-RATST2ƒCLR.L…D0’Set�D0�to�indicate�no�errors.‰BSR‡RACLRSTAŒClear�RAD�status.‰BRA‡RATSTRETŒGo�return.:RA) TSTERR�BSR‡RAEXERR�Set�D0�to�indicate�"execution�error".‰BRA‡RATSTRETŒGo�return.‰PAGEN*******************************************************************************$*ˆSubroutine�to�handle�RADABT�calls.*,*’Called�from�the�command�processor�routine.*#*ˆUpon�entry:‰A2�=�param�block�addr*œA3�=�command�packet�addr*œA5�=�CCB�addr*œA6�=�TCB�addr*2*ˆUpon�return:ˆD0�=�error�code�(=0,�if�successful)**œ0�1�2�3�4�5�6�7*˜D:‚*�*�*�*�*�*�*�**˜A:‚*�*�P�P�*�P�P**O*******************************************************************************=RARADABT�EQU‡*‰Routine�to�abort�whatever�the�RAD�is�doing�and$*¦close�all�chans�for�this�RAD.‚(All&*¦users�of�this�RAD�will�be�flagged�in'*¦RAUSRLST�so�they�can�be�"notified"�of"*¦the�abort�on�their�next�request.@‰MOVE.L„RARDLADR(A5),A1…Put�addr�of�this�RAD's�entry�in�RARADLST ‰CLR.L…D3=‰MOVE†RARDSTAT(A1),D3…Store�RAD�status�(which�is�the�user�ptr&*¦if�the�RAD�is�currently�being�used).*‰CMP‡#RASTOK,D3Šin�A1.‚Is�RAD�running�now?(‰BEQ.S…RAABT0ŽNo--don't�have�to�stop�it.#‰CMP‡#RASTBAD,D3‰Is�RAD�marked�bad?)‰BEQ.S…RAABT0ŽYes--don't�have�to�stop�it.#*¦No--RAD�must�be�running--stop�it.<‰MOVE.L„RASHRAD(A5),A1†Put�start�addr�of�shared-RAM�into�A1.2‰CLR.B…RACSTAT(A1)‰Clear�cmd�status�in�shared-RAM.;‰MOVE.B„#1,RAINTMSK(A1)…Set�interrupt�mask�in�shared-RAM�to *¦interrupt�when�RAD�is�stopped.:‰MOVE.B„#RASTOPIT,RASTPBYT(A1)ˆSet�stop�byte�in�shared-RAM*¦to�stop�RAD�processing.&‰TR0$.PAUSEŠ,‰Wait�for�done�interrupt.I*>>>>>>>>>>>>>>>‚Return�from�interrupt�here.‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<6RAABT1ƒMOVE.L„RAD1TBL,A1ŠPut�addr�of�table�area�in�A1.6‰LEA‡RAUSRLST(A1),A2…Set�A2�to�start�addr�of�RAUSRLST.4‰MOVE†#32,D1ŽMust�set�all�chans�to�unused�status�and&*¦flag�all�users�of�this�RAD�to�inform'*¦them�of�the�abort�on�their�next�call.?‰LEA‡RACHNUSR(A5),A1‚Set�A1�to�start�of�user�ptrs�for�this�RAD.1RAABTLUP�CMP‡#$FFFF,(A1)‰Is�this�chan�unassigned?&‰BEQ.S…RAABT2ŽYes--go�on�to�next�chan.*‰CMP‡#$F000,(A1)‰Is�this�chan�unavailable?&‰BEQ.S…RAABT2ŽYes--go�on�to�next�chan.(‰CLR.L…D2’No--must�"unassign"�this�chan.!‰MOVE†(A1),D2�Put�user�ptr�in�D2.0‰MOVE†#$FFFF,(A1)‰Set�chan�to�unassigned�status.02"3*82+:4B4J8R4ZBb/j1r</‰CMP‡D2,D3�Does�this�chan�belong�to�the�current*¦user�of�this�RAD�(if�any)?#‰BEQ.S…RAABT2ŽYes--don't�flag�user.8‰MULU†#RAULNG,D2ŠMultiply�user�ptr�by�length�of�RAUSRLST+*¤entry�to�get�offset�to�this�user's�entry.<‰MOVE.B„#RAABTCOD,RAUSTAT(A2,D2)†Set�user�status�in�RAUSRLST#*¦to�abort�code�so�that�user�can�be%*¦notified�of�abort�on�his�next�call.2RAABT2ƒADD.L…#2,A1�Bump�A1�to�pt�to�next�user�ptr.‰SUBQ†#1,D1�All�chans�done?‰BGT‡RAABTLUPŒNo--go�do�next.=‰MOVE.L„#RAABTCOD,D0ˆYes--notify�current�user�(if�any)�of�the‰BSR‡RANOTIFYŒabort.@‰MOVE.L„RARDLADR(A5),A1…Put�addr�of�this�RAD's�entry�in�RARADLST *¦into�A1.2‰MOVE†#RASTOK,RARDSTAT(A1)ŠSet�RAD�status�to�"ok".5‰MOVE.L„RASHRAD(A5),A1†Set�A1�to�start�of�shared-RAM.8‰CMP.B…#$84,RACSTAT(A1)„Yes.‚Did�the�RAD�stop�correctly?‰BNE.S…RAABTERRŒNo--error.3‰CLR.L…D0�Yes--set�D0�to�indicate�successful�abort.RAABTRET�EQU‡* ‰RTS›Return.@RAABT0ƒMOVE.L„RASHRAD(A5),A1†Set�A1�to�start�addr�of�shared-RAM.8‰MOVE.B„#$84,RACSTAT(A1)„Set�cmd�status�in�shared-RAM�to$*¦"successful�stop"�value�for�later.+‰BRA‡RAABT1ŽContinue�with�abort�processing.6RAABTERR�BSR‡RAEXERR�Execution�error�in�RAD.‚Set�D0�to *¦error�code.‰BRA.S…RAABTRETŒGo�return.‰PAGEK****************************************************************************=*ˆSubroutine�to�set�error�return�value�in�D0�for�unsuccessful*’function�execution.*+*ˆCalled�from�command-handling�subroutines.*2*ˆUpon�entry:ƒA1�=�addr�of�shared-RAM�for�this�RAD*K********************) *******************************************************ARAEXERR‚CMP.B…#$01,RACSTAT(A1)„Did�we�get�an�"illegal�cmd"�return*¦from�the�RAD?‰BNE.S…RAEXERR2ŒNo.-‰MOVE.L„#RAERR9,D0ŠYes--set�D0�to�error�code.‰BRA.S…RAEXERR9ŒGo�return.=RAEXERR2�MOVE.L„#RAEXERRV,D0ˆSet�D0�to�execution�error�value.RAEXERR9�RTS›Return‰PAGEM******************************************************************************>*ˆSubroutine�to�set�the�RAD�status�to�"ok"�and�reset�the�data-:*’retrieval-subroutine�address�to�the�address�of�RARDFIFO.*+*ˆCalled�from�command-handling�subroutines.**ˆUpon�entry:‰A5�=�CCB�address.*=*ˆUpon�exit:‚contents�of�register�A1�are�destroyed--all�other*œregisters�are�"untouched".*N******************************************************************************RACLRSTA�EQU‡**;‰LEA‡RARDFIFO(PC),A1…Put�addr�of�read-FIFO�routine�into�A1.=‰MOVE.L„A1,RARTRVAD(A5)…Store�it�in�data-retrieval-subroutine)*¦addr�loc�in�CCB.‚(This�is�the�"default"*¦data-retrieval�subroutine.)=‰MOVE.L„RARDLADR(A5),A1…Set�A1�to�addr�of�this�RAD's�entry�in *¦RARADLST.2‰MOVE†#RASTOK,RARDSTAT(A1)ŠSet�RAD�status�to�"ok". ‰RTS›Return.‰PAGEN*******************************************************************************,*ˆSubroutine�to�read�the�FIFO�in�shared-RAM.*(*ˆCalled�from�interrupt�service�routine.*3*’Upon�entry,�A1�contains�start�addr�of�shared-RAM.**•0�1�2�3�4�5�6�7*’D:�*ƒ*�*�*�*�* *’A:ƒP�*�**N******************************************************************************RARDFIFO�EQU‡*RAFILUP1�CLR.L…D29‰MOVE.B„RANXT2GT(A1),D2…Get�next-to-get�ptr�for�FIFO�from *°shared-RAM.0‰CLR.L…D6’Set�up�D6�to�contain�command�status�in=‰MOVE.B„RACSTAT(A1),D6†bits�8-15�for�later�use�in�queueing�an‰ASL.L…#8,D6�event.;‰ASL‡#1,D2…Double�next-to-get�ptr�to�get�actual�offset�from'*¦start�of�shared-RAM�(68K-addressing).4‰LEA‡(A1,D2),A2ŠGet�actual�addr�of�next�value�to�get*°and�store�it�in�A2.3‰CMPI.B„#$FF,(A2)‹Any�data�in�next-to-get�location?$‰BEQ‡RAFIFOMTŒNo--FIFO�is�now�empty.4‰MOVE.B„0(A2),D5‚Yes--find�out�what�to�do�with�data.1‰MOVE.B„D5,D3�Store�gain�and�chan�#�in�D5�and�D3.>‰AND.L…#$1F,D5ƒMask�off�gain,�leaving�just�the�channel�number.0‰MOVE.B„D5,D6�Move�chan�#�into�D6�for�later�use.7‰MULU†#RACHNLLG,D5ˆCalculate�offset�into�'RARADLST'�for*¦this�channel.5‰ADD.L…RARDLADR(A5),D5…Add�start-of-entry�address�(in*¦'RARADLST')�for�this�RAD.;‰ADD.L…#RACHNLST,D5ˆD5�now�contains�the�addr�of�the�options4‰MOVE.L„D5,A3�flag�for�this�channel.‚Put�addr�in�A3.*9*’========‚Pack�data�for�this�reading�into�D3.‚==========4‰MOVE.B„2(A2),D4ŒPut�flags�and�hi-data�byte�into�D4.‰ASL.L…#8,D3�Shift�data�in�D3.,‰MOVE.B„D4,D3�Put�flags�and�hi-data�into�D3.6‰ANDI.B„#$F0,D3�Mask�off�low�byte,�leaving�just�flags.&‰ASL.L…#8,D3�Shift�data�over�one�byte.2‰MOVE.B„D4,D3�Put�flags�and�hi-data�into�D3�again.8‰ANDI.B„#$0F,D3�Mask�off�low�byte,�leaving�just�hi-data.&‰ASL.L…#8,D3�Shift�data�over�one�byte.7‰MOVE.B„4(A2),D3ŒPut�lo-data�byte�into�D3.‚Now�all�data(*¦for�this�reading�has�been�put�into�the&*¦4�bytes�of�D3�in�the�correct�format.8‰MOVE.L„RACHNSTO-RACHNOPT(A3),A3†Put�storage-addr�in�A3.4‰MOVE.L„D3,(A3)�Store�data�in�loc�specified�by�user.+‰MOVE.B„#$FF,(A2)‹Set�FIFO�loc�to�"unused".=‰ADDQ.B„#3,RANXT2GT(A1)…Set�FIFO�next-to-get�ptr�to�next�data*°location�in�the�FIFO.3‰MOVE.B„RAFIFOND(A1),D4…Set�D4�to�end-of-FIFO�addr.7‰CMP.B…RANXT2GT(A1),D4…Are�we�past�the�end�of�the�FIFO?‰BHS.S…RAF1�No.?‰MOVE.B„RAFIFOST(A1),RANXT2GT(A1)…Yes--set�FIFO�next-to-get�ptr*°to�start-of-FIFO�ptr�value.6RAF1…MOVE.L„D5,A3�Reset�A3�to�addr�of�options�flag�for *¦this�chan.'‰MOVE†(A3),D0�Put�options�flag�into�D0.<‰BTST.L„#RASUBRBT,D0ˆIs�there�a�subroutine�to�be�called�when*¦there�is�data�for�this�chan?‰BEQ.S…RAF2�No.?‰MOVE.L„RACHNSUB-RACHNOPT(A3),A3†Yes,�put�addr�of�subr�into�A3.3‰MOVEM.LƒD1-D7/A0-A6,-(A7)ƒStore�register�contents.‰JSR‡(A3)�Jump�to�subroutine.5‰MOVEM.Lƒ(A7)+,D1-D7/A0-A6ƒRestore�register�co* ntents.L*======================‚On�return�from�subroutine,�D0�will�be�set�for�either0*œqueue�event�or�wakeup�if�either�of�these�is�to-*œbe�done�after�the�subr.‚Else,�D0�will�be�0.=RAF2…BTST.L„#RAQUEBT,D0‰Are�we�to�queue�an�event�to�the�user?‰BEQ.S…RAF3�No.:‰MOVE.L„#RAEVNTHI,D2ˆYes--set�upper�half�of�D2�to�standard*¦event�data�(length�and�code).2‰MOVE†D6,D2�Put�command�status�and�chan�#�into�D2.=‰MOVE.L„CCBMNEM(A5),D3†Put�RAD-ID�into�2nd�longword�of�event.*‰BSR‡QEVENTŽGo�queue�an�event�to�the�user.$‰BRA.S…RAF9�All�done�with�this�chan.;RAF3…BTST.L„#RAWAKEBT,D0ˆAre�we�to�do�a�wakeup�of�the�user?(‰BEQ.S…RAF9�No--all�done�with�this�chan.#‰MOVE.L„A6,A0�Put�TCB�addr�into�A0.+‰MOVEM.LƒD0-D7/A0-A6,-(A7)ƒStore�registers.*‰TR0$.WAKEUP‰,‰Issue�a�wakeup�to�the�user.-‰MOVEM.Lƒ(A7)+,D0-D7/A0-A6ƒRestore�registers.9RAF9…BRA‡RAFILUP1‚Go�back�and�get�next�reading�from�FIFO.-RAFIFOMT�RTS‘RAD�FIFO�is�now�empty�--�return.‰PAGEK****************************************************************************/*ˆSubroutine�to�find�user's�entry�in�'RAUSRLST'*>*ˆCalled�from�command�processor�and�command-handling�routines.**’Upon�exit:ƒD0�=�error�flag*ŸD1�=�entry�#�for�this�user.**œAll�other�registers�used�will�have�their*œcontents�restored.*L****************************************************************************RAFNDUSR�EQU‡**3‰MOVEM.LƒD2-D4/A0-A1,-(A7)ƒStore�register�contents.4‰MOVE.L„RAD1TBL,A1ŠPut�addr�of�RAD�table�area�in�A1.1‰LEA‡RAUSRLST(A1),A0…Put�addr�of�user�list�in�A0.6‰MOVE.L„A1,D0�Set�D0�to�addr�of�RARADLST,�which�is�the1‰ADD‡RARADLAD(A1),D0…same�as�the�end�of�RAUSRLST.-‰CLR.L…D1’D1�will�be�a�"user�counter".‚(First*¦user�will�be�#�0.)7‰MOVE.L„TCBNAME(A6),D2†Put�user�task�name�and�session�#'‰MOVE.L„TCBSESSN(A6),D3…into�D2�and�D3.(‰MOVE.L„CCBMNEM(A5),D4†Put�RAD-ID�in�D4.4RAFNDLP‚CMP.L…RAUUSRNO(A0),D2…Does�this�entry�match?!‰BNE.S…RAFNXTŽNo--try�next�entry.‰CMP.L…RAUUSRNO+4(A0),D3ƒMaybe.‰BNE.S…RAFNXTŽNo--try�next.‰CMP.L…RAURADID(A0),D4…Maybe.‰BEQ.S…RAFGOTITŒYes.:RAFNXTƒADDA.L„#RAULNG,A0ŠDoesn't�match.‚Set�up�to�try�next0‰CMPA.L„D0,A0�entry.‚Are�there�any�more�entries?2‰BHS.S…RAFNOGOTŒNo--this�user�is�not�set�up�to�use!*¦this�RAD.‚Go�make�error�return.!‰ADDQ†#1,D1�Yes--inc�entry�count.*‰BRA‡RAFNDLP�Go�back�and�check�this�entry.*RAFNOGOT�MOVE.L„#RAERR3,D0ŠSet�error�code.‰BRA.S…RAFRETŽGo�return.)RAFGOTIT�EQU‡*“A0�contains�addr�of�entry;&*¦D1�contains�ptr�to�this�entry�(i.e., *¦entry�#).7‰CMP.B…#RAABTCOD,RAUSTAT(A0)‰Was�this�RAD�aborted�since*¦the�last�call�by�this�user?#‰BNE.S…RAFNDOK�No--everything's�ok.*B************‚Because�of�the�way�the�"abort"�flag�is�set�and�reset,G************‚the�following�code�will�only�be�executed�when�this�routineD************‚is�called�from�the�command�handler�on�the�first�call�by@************‚each�user�after�this�RAD�has�been�aborted�(RADABT).*3‰CLR.B…RAUSTAT(A0)‰Yes.‚Clear�the�"aborted"�flag�in*¦this�user's�status.8‰MOVE.L„#RAABORTD,D0ˆSet�error�code�to�"warning--RAD�was*¦aborted"�code.‰BRA.S…RAFRETŽGo�return. ************ ************/RAFNDOK‚CLR.L…D0’Clear�D0�to�indicate�no�error.;RAFRETƒMOVEM.Lƒ(A7)+,D2-D4/A0-A1ƒRestore�register�contents. ‰RTS›Return.‰PAGEL*****************************************************************************@*ˆSubroutine�to�move�parameters�into�shared-RAM�parameter�table.*+*’Called�from�command-handling�subroutines.*L*****************************************************************************2*’Upon�entry--ˆA4�=�addr�of�parameters�to�be�moved*¦D4�=�#�of�bytes�to�be�moved7*’(A4�and�D4�will�contain�the�same�as�above�upon�exit.)$*’Upon�exit:ŠA1�=�addr�of�shared-RAML*---------------------------------------------------------------------------RAMOVPRM�EQU‡*-‰MOVEM.LƒA4/D4,-(A7)‰Store�register�contents.<‰MOVE.L„RASHRAD(A5),A1†Put�start�addr�of�shared-RAM�into�A1.9‰LEA‡RAPARAM(A1),A0†Put�addr�of�param�table�in�shared-RAM *¦into�A0.RANTF2ƒBTST.L„#RAWAKEBT,D0ˆAre�we�supposed�to�issue�a�wake-up?‰BEQ.S…RANTFRETŒNo--go�return.8‰MOVEM.LƒD0-D7/A0-A6,-(A7)ƒYes--store�register�contents.*‰MOVE.L„A6,A0�Put�user's�TCB�addr�into�A0. ‰TR0$.WAKEUP‰,‰Go�+ issue�wake-up.-‰MOVEM.Lƒ(A7)+,D0-D7/A0-A6ƒRestore�registers.RANTFRET�EQU‡*0‰MOVEM.Lƒ(A7)+,D0-D3/A1-A2/A6ŠRestore�registers. ‰RTS›Return.‰PAGEF***********************************************************************B* SUBROUTINE TO CHECK ADDRESS BOUNDARIES TO SEE IF ENTIRELY WITHIN*ƒCALLING�TASKS�ADDRESS�SPACE.*#*�ENTRY:ƒD5‚-�NO.�OF�BYTES�TO�CHECK*ŠD6‚-�68000�ADDRESS�(LOGICAL)*ŠA1‚-�TCB�ADDRESS**#* REGISTERS USED: D0-D1,D3,D6/A0-A1**7*�EXIT:„D6�-�PHYSICAL�ADDRESS�OF�BUFFER�BASE�(IF�LEGAL)*ŠRETURN�TO�PC„FOR�GOOD�ADDRESS*”PC+2‚FOR�BAD�LENGTH*”PC+4‚FOR�BAD�ADDRESS**C*******************************************************************IOHADRCK‚EQU„*$ŠBTSTƒ#0,D6ŽMUST�BE�ON�WORD�BOUNDARY(ŠBNE.S‚IOHADR4ŒBRANCH�IF�BAD�BUFFER�BASE ŠTST.L‚D5.ŠBEQ.S‚IOHADR8ŒDON'T�GO�TO�LOGPHY�WITH�0�COUNT IOHADR2ƒEQU„*/ŠMOVE.L�TCBTST(A1),A0†ADDRESS�OF�TASK�SEG�TABLE ŠTR0$.LOGPHY&ŠBRA.S‚IOHADR8ŒBRANCH�FOR�GOOD�ADDRESS(ŠBRA.S‚IOHADR6ŒBRANCH�FOR�BAD�BYTE�COUNT'ŠTST.L‚D5‘WAS�AN�ENTRY�POINTER�RETURNED#ŠBEQ.S‚IOHADR4ŒBRANCH�IF�NO�-�ERROR'ŠTST.B‚7(A0,D5)‹IS�THIS�AN�MMIO�SEGMENTŠBNE.S‚IOHADR8ŒYES,�OKIOHADR4ƒADD.L‚#2,(A7)IOHADR6ƒADD.L‚#2,(A7) IOHADR8ƒRTSŠPAGEJ***************************************************************************F*�INTERRUPT�SERVICE�ROUTINE…<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*?*ƒPURPOSE:‚HANDLE�ACKNOWLEDGEMENTS�AND�MESSAGE�COMPLETIONS�FROM3*�THE�RAD1.‚OPERATES�AT�HARDWARE�INTERRUPT�PRIORITY<*�LEVEL�AS�A�SUBROUTINE�TO�THE�FIRST�LEVEL�INTERRUPT�HANDLER *�(IN�CMR).*4*ƒENTRY:‚JSR‚FROM�INTERRUPT�HANDLER�ROUTINE�(IN�CMR)*‹A0�=�WORK�REGISTER *‹A1�=�SELF*‹A5�=�CCB�ADDRESS*‹D0�=�WORK�REGISTER*/*ƒEXIT:‚RTS�-�BACK�TO�INTERRUPT�HANDLER�ROUTINE**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****PP***ƒCODE�IS�RE-ENTRANT*F*---------------------------------------------------------------------**"RADISR„EQU„*’INTERRUPT�ENTRY�POINT.‰MOVEM.LƒD1-D7/A2-A4/A6,-(A7)…STORE�REGISTERS.*=‰MOVE.L„RAUSRTCB(A5),A6…Set�A6�to�addr�of�current�user's�TCB,(*¦which�was�stored�when�command�was�sent*¦to�this�RAD�board.7‰MOVEA.LƒRASHRAD(A5),A1†Put�addr�of�shared-RAM�into�A1.3‰MOVE.B„RAXSTAT(A1),D1†Put�status�from�RAD�into�D1.4‰AND.B…#RAINTBIT,D1ˆDid�this�RAD�send�the�interrupt?)‰BEQ‡RAINO�No.‚Return�and�check�next�RAD.8‰CMP.B…#RALVL4,CCBPPRIO(A5)ŠIs�this�a�level�4�interrupt?‰BNE.S…RAISR1ŽNo--level�3.**¦Yes--RAD�"died".8‰MOVE.L„CCBMNEM(A5),D0†Put�RAD-ID�from�this�CCB�into�D0.7‰SUB.L…#$0400,D0‹Subtract�to�get�RAD-ID�for�level�3�CCB(*¦which�corresponds�to�this�level�4�CCB.*0*�Search�CCB�chain�for�level�3�CCB�for�this�RAD.*+‰MOVE.L„A5,-(A7)ŒStore�addr�of�level�4�CCB.6‰MOVE.L„CCBHD,A5ŒStore�addr�of�1st�CCB�in�chain�in�A5.%RAISRLP‚CMP.L…#0,A5�End�of�CCB�chain?6‰BEQ.S…RAISRFALŒYes.‚Something�wrong--can't�find�level)*¦3�CCB�for�this�RAD.‚Oh�well,�forget�it!<‰CMP.L…CCBMNEM(A5),D0†Is�this�the�CCB�we�have�been�searching#‰BEQ.S…RAISR0Žfor?ƒEUREKA!!!�It�is!0‰MOVE.L„CCBALL(A5),A5‡No--try�next�CCB�in�chain. ‰BRA‡RAISRLPFRAISR0ƒMOVE.L„RARDLADR(A5),A2…Put�addr�of�this�RAD's�entry�in�RARADLST *¦into�A2. ‰CLR.L…D3=‰MOVE†RARDSTAT(A2),D3…Store�RAD�status�(which�is�user�ptr�for*¦current�user,�if�any).4‰MOVE†#RASTBAD,RARDSTAT(A2)‰Set�RAD�status�to�"bad".(‰MOVE.L„#RAERR1,D0ŠSet�D0�to�error�code.3‰BSR‡RANOTIFYŒNotify�current�user,�if�any,�that�RAD *¦just�died.RAISR8ƒCLR.B…RARDFLAG(A5)ˆFinished�processing�this�interrupt--$*¦clear�"working�on�interrupt"�flag.*3RAISR4ƒEQU‡*“Tell�CMR�that�interrupt�has�been�taken *¦care�of.7‰CLR.B…RAINTFLG(A1)ˆClear�interrupt�flag�in�shared-RAM.-‰ORˆ#1,SR�Set�carry�bit�to�indicate�that�this*¦interrupt�has�been�handled. ‰BRA.S…RAISR9*4RAINO„EQU‡*“Tell�CMR�that�this�interrupt�is�not�from *¦this�RAD.2‰AND‡#$FFFE,SR‹(Clear�carry�bit�to�indicate�this.)**RAISR9ƒEQU‡*“Return�to�CMR.***-* RAD INTERRUPT HANDLER EXITS FROM THIS POINT*/ŠMOVEM.L�(A7)+,D1-D7/A2-A4/A6…RESTORE�REGISTERSŠRTSšBACK�TO�INTERRUPT�HANDLERŠPAGEK*****************************************************************************9* ROUTINE TO QUEUE EVENT (ALREADY STAGED IN REGISTERS) TO*ƒ-�DRIVING�TASK. *ƒ-�EVENT�BEGINS�IN�REGISTER�D2.***ˆEXEC�ROUTINE/*ˆREGISTERS�USED:�D0-D1/A0,A3-A6‚WORK�REGISTERS*˜D2-D7‹STAGING�REGISTERS**K**************************************************************************** QEVENTƒEQU‡**ŠMOVEM.L�A0-A6/D0-D7,-(A7)‡Save�registers.#‰MOVE.L„A6,A0�Caller's�TCB�address.6ŠTR0$.QEVNTIˆ,‰(QEVNTI�routine�is�used�since�this�will#*¦be�called�only�while�servicing�an *¦interrupt.)#ŠBRA.S‚IOHQ5ŽBranch�if�queueing�ok.-ŠMOVEM, .L�(A7)+,A0-A6/D0-D7…Restore�registers.9ŠMOVE.L�(A7),CCBQVER1(A5)‚Save�callers�address�for�debug.ŠBRA.S‚IOHQRTN 2IOHQ5…MOVEM.L�(A7)+,A0-A6/D0-D7„Restore�registers..ŠCLR.L‚CCBQVER1(A5)‡Clear�queue�error�address. IOHQRTNƒRTS—RETURN‰ENDé=/* =/*†RADLIB.AF=/*7=/* Chain file to assemble FORTRAN-callable subroutines&=/* to interface with the RAD1 driver.=/*:=/* If no output argument is specified for the listing the(=/* chain file will default to RADLIB.LS=/*=/IFC \1ƒ=ARG�RADLIB.LS=/ENDIF=/*=ASM RADLIB.SA,RADLIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDéééééézK*==========================================================================*=*ˆFORTRAN-callable�subroutines�used�to�invoke�the�RAD�driver.*K*==========================================================================** ‰SECTIONƒ9=‰XDEF†RADOPN,RADTST,RADABT,RADJMP,RADLOD,RADDMP,RADXEQ,RADSTP6‰XDEF†RADATO,RADCLS,RADSCN,RADEXT,RADSET,RADHIS,RADCAL****J*----------------‚CONSTANTS�----------------------------------------------*2ERRCODƒEQU‡$F3‘Error�code�for�"param�table�error".*%RASTPCMD�EQU‡00ˆ"Stop"�command�value.%RALODCMD�EQU‡01ˆ"Load"�command�value.%RADMPCMD�EQU‡02ˆ"Dump"�command�value.%RAJMPCMD�EQU‡03ˆ"Jump"�command�value.*RATSTCMD�EQU‡04ˆ"Self-test"�command�value.&RAOPNCMD�EQU‡$10‡"Open"�command�value.'RACLSCMD�EQU‡$20‡"Close"�command�value.'RAABTCMD�EQU‡$7F‡"Abort"�command�value.2RAEXTCMD�EQU‡$81‡"External�trigger"�command�value.*RASETCMD�EQU‡$82‡"Setpoint"�command�value.&RASCNCMD�EQU‡$83‡"Scan"�command�value.1RAATOCMD�EQU‡$84‡"Auto-range�scan"�command�value.+RACALCMD�EQU‡$85‡"Calibrate"�command�value.1RAHISCMD�EQU‡$86‡"High-speed�scan"�command�value.2RAXEQCMD�EQU‡$80‡"Execute�function"�command�value.‰PAGE*H*-----------------------------------------------------------------------*!*ˆ, General�format�of�FORTRAN�call:&*’CALL�RADXXX(rad-id,param-table-addr)*=*ˆThis�call�will�cause�3�items�to�be�pushed�onto�the�stack�--:*’(1)‚address�where�the�desired�RAD-ID�is�stored‚(4�bytes)9*’(2)‚address�of�parameter�table�in�user's�area‚(4�bytes)*’(3)‚return�address‚(4�bytes)*A*ˆAll�registers�will�be�saved�and�restored�upon�return�except�for+*’register�A0,�whose�contents�will�be�lost.*@*ˆUpon�return,�the�stack�pointer�will�be�the�same�as�it�was�just6*’prior�to�the�RAD�call.‚The�following�illustrates�the4*’data�which�is�put�on�the�stack�(and�removed�before$*’returning�to�the�calling�program).*?*ˆ(Lowest�addr�of�stack)…1)�CMR�command�code,�subcode…(2�bytes)*£2)�**‚(zero-filled)�(2�bytes)*£3)�RAD-ID˜(4�bytes)ƒ8Œ6”7œ9¤*£4)�**‚(zero-filled)�(4�bytes)*£5)�**‚(zero-filled)�(4�bytes)*£6)�**‚(zero-filled)�(4�bytes)%*£7)�cmd�packet�addr�(=addr�of�user's*°param�table)ˆ(4�bytes)#*£8)�length�of�cmd�packetŠ(2�bytes)*£9)�contents�of�A3�(4�bytes)*¢10)�contents�of�D2�(4�bytes)*¢11)�contents�of�D1�(4�bytes)*¢12)�contents�of�D0�(4�bytes)*¢13)�return�addr“(4�bytes) *¢14)�param-table-addrŽ(4�bytes)>*ˆ(high�memory�addr)ˆ15)�addr�where�RAD-ID�is�storedƒ(4�bytes)*5*’#1�through�8�above�form�the�parameter�block�for�the(*œCMR�TRAP1.‚(**�mark�the�unused�fields)6*’#9�through�12�are�storage�locations�for�the�register *œcontents.;*’#14�and�15�are�the�parameters�passed�by�the�FORTRAN�call.*O*********************************************************************************‰PAGECRADOPNƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents�on�the�stack.1‰MOVE†#RAOPNCMD,D1ˆStore�command�code�for�"open".9‰MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D2)‰MOVE†4(A3),D2ŒPut�#�of�channels�into�D2..‰MULU†#12,D2ŽCalculate�#�of�bytes�in�parameter-‰ADD.L…#6,D2�table�(including�first�6�bytes).6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**CRADTSTƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents�on�the�stack.2‰MOVE†#RATSTCMD,D1ˆStore�cmd�code�for�"self-test".@RADTST2‚MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3.2‰MOVE.L„#10,D2ŽPut�#�bytes�in�param�table�into�D2.6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADABTƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents..‰MOVE†#RAABTCMD,D1ˆStore�cmd�code�for�"abort".@RADABT2‚MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3.0‰MOVE.L„#4,D2�Put�length�of�param�table�into�D2.6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADJMPƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.-‰MOVE†#RAJMPCMD,D1ˆStore�cmd�code�for�"jump".9‰MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D2%‰MOVE†10(A3),D2‹Put�#�params�into�D2.&‰ASL.L…#1,D2�Double�to�get�#�of�bytes./‰ADD.L…#12,D2ŽAdd�#�bytes�in�beginning�of�table**¦(including�count)�to�give�total�#�bytes.6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADLODƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.-‰MOVE†#RALODCMD,D1ˆStore�cmd�code�for�"load".>RADLOD2‚MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�in�A3.2‰MOVE.L„#12,D2ŽPut�#�bytes�in�param�table�into�D2.6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADDMPƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.-‰MOVE†#RADMPCMD,D1ˆStore�cmd�code�for�"dump".3‰BRA‡RADLOD2�Go�finish�set�up�(same�as�for�RADLOD).**‰PAGE6RADXEQƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.9‰MOVE†#RAXEQCMD,D1ˆStore�cmd�code�for�"execute�function".9‰MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D2(‰MOVE†12(A3),D2‹Put�#�of�params�into�D2.'‰ASL.L…#1,D2�Double�to�give�#�of�bytes.2‰ADD.L…#14,D2ŽAdd�#�bytes�in�beginning�of�table�to*¦total�#�bytes�in�table.6‰BRA‡CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.- **6RADSTPƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.-‰MOVE†#RASTPCMD,D1ˆStore�cmd�code�for�"stop".3‰BRA‡RADABT2�Go�finish�set�up�(same�as�for�RADABT).**6RADATOƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.8‰MOVE†#RAATOCMD,D1ˆStore�cmd�code�for�"auto-range�scan".@RADATO2‚MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D2#‰MOVE†4(A3),D2ŒPut�#�chans�into�D2.'‰ASL.L…#1,D2�Double�to�give�#�of�bytes.5‰ADD.L…#6,D2�Add�to�give�total�length�of�param�table.8‰BRA.S…CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADCLSƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents..‰MOVE†#RACLSCMD,D1ˆStore�cmd�code�for�"close".3‰BRA‡RADABT2�Go�finish�set�up�(same�as�for�RADABT).**6RADSCNƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.-‰MOVE†#RASCNCMD,D1ˆStore�cmd�code�for�"scan".9‰MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D2#‰MOVE†6(A3),D2ŒPut�#�chans�into�D2.$‰ASL.L…#1,D2�Double�to�give�#�bytes.4‰ADD.L…#8,D2�Add�#�bytes�in�beginning�of�param�table'*¦to�give�total�#�bytes�in�param�table.8‰BRA.S…CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADEXTƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.9‰MOVE†#RAEXTCMD,D1ˆStore�cmd�code�for�"external�trigger".3‰BRA‡RADATO2�Go�finish�set�up�(same�as�for�RADATO).**‰PAGE6RADSETƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.9‰MOVE.L„20(A7),A3‹Put�addr�of�user's�param�table�into�A3. ‰CLR.L…D13‰MOVE†4(A3),D1ŒMultiply�#�of�setpoint�chans�by�6�to$‰MULU†#6,D1�#�bytes�for�setpt�chans. ‰CLR.L…D20‰MOVE†6(A3),D2ŒPut�#�non-setpoint�chans�into�D2.6‰ASL.L…#1,D2ŽDouble�to�get�#�bytes�of�non-setpt�chans.0‰ADD.L…D1,D2�Get�total�#�of�bytes�in�param�table‰ADD.L…#8,D2�into�D2.9‰MOVE†RASETCMD,D1‰Set�D1�to�cmd�code�for�"setpoint�scan".8‰BRA.S…CALLDRVRŒGo�set�up�param�block�and�make�CMR�call.**6RADHISƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.8‰MOVE†#RAHISCMD,D1ˆStore�cmd�code�for�"high-speed�scan"./‰BRA‡RADTST2�Go�finish�set�up�(same�as�RADTST).**6RADCALƒMOVEM.LƒD0-D2/A3,-(A7)†Store�register�contents.4‰MOVE†#RACALCMD,D1ˆStore�cmd�code�for�"calibration"./‰BRA‡RADLOD2�Go�finish�set�up�(same�as�RADLOD).**‰PAGE?CALLDRVR�MOVE†D1,2(A3)ŒPut�cmd�code�intouser's�cmd�param�table.2‰CMP.L…#$7FFF,D2‹Is�length�of�param�table�too�big?‰BHI.S…PRMERRŽYes--error."*---------------------------------*/*ˆSet�up�parameter�block�for�CMR�call�on�stack.**’(This�will�be�built�from�the�bottom�up.)*2‰MOVE†D2,-(A7)ŒPut�packet�length�(i.e.,�#�bytes�in$*¦user's�param�table)�at�"bottom"�of*¦param�block�for�CMR.7‰MOVE.L„A3,-(A7)ŒAddr�of�param�table�(=cmd�packet)�goes*¦next.0‰CLR.L…-(A7)�Clear�unused�fields�of�param�block. ‰CLR.L…-(A7) ‰CLR.L…-(A7)-‰MOVE.L„42(A7),A3‹Put�addr�of�RAD-ID�into�A3.7‰MOVE.L„(A3),-(A7)ŠPut�RAD-ID�into�param�block�for�CMR.<‰MOVE.L„#$07000000,-(A7)„Put�CMR�cmd�code,�subcode,�etc.,�at*¦"top"�of�param�block�for�CMR.0‰MOVE.L„A7,A0�Put�addr�of�param�block�(which�now"*¦starts�at�top�of�stack)�into�A0.#‰MOVE.L„#60,D0ŽSet�D0�for�CMR�call..‰TRAP†#1’Call�CMR,�which�will�in�turn�call�the *¦RAD�driver.=RTRN…MOVE.L„46(A7),A3‹Put�addr�of�user's�param�table�into�A3.5‰MOVE†D0,(A3)�Put�returned�error�flag�into�error�code*¦byte�in�user's�param�table.3‰LEA‡26(A7),A7‹Set�stack�ptr�to�addr�where�register*¦contents�are�stored.2‰MOVEM.Lƒ(A7)+,D0-D2/A3†Restore�register�contents.)‰MOVE.L„(A7)+,A0ŒPut�return�addr�into�A0.0‰LEA‡8(A7),A7Œ"Pop"�passed�parameters�off�stack.‰JMP‡(A0)�Return�to�user.**<*--------------------------‚Error�in�user's�parameter�table.*:PRMERRƒMOVE†#ERRCOD,D0ŠSet�D0�to�error�code�for�"parameter*¦table�error".‰BRA‡RTRN�Go�return�to�user.**‰END  é- éééé=/* =/*†RIODRV.AF=/*%=/* Chain file to assemble RIO driver=/*:=/* If no output argument is specified for the listing the(=/* chain file will default to RIODRV.LS=/*=/IFC \1ƒ=ARG�RIODRV.LS=/ENDIF=/*%=ASM RIODRV.SA,RIODRV.RO,\1;MR-WZ=134=/*{ Included files are:=/*ƒ9995.&.TR1RTCD.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.RIODRV.EQ=/*ƒSTDMACRO.AI=/*}=/*=ENDéééééé¬Î' RIODRV SAÁ²|qqRIOLIB AFÛÛqqRIOLIB SAää–qqSTDMACROAIýý_qqM605MEM AG;qqM610MEM AG~qqM615MEM AG00<qqM625MEM AGAA9qqIOCINT AGRRºqqADMEM AGkkqqRIOMEM AGtt6qqM605MEM CI…… qqRADMEM CIŽŽ qqM610MEM CI—— qqM625DRV CI  qqM6. 15MEM CI©© qqRIOMEM CI²² qqM625MEM CI»» qqM600DRV CIÄÄqqM605DRV CIÍÍqqŠPAGEŠTTL„TR1RTCD.EQŠINCLUDE�9995.&.TR1RTCD.EQ ŠTTL„STR.EQŠINCLUDE�9995.&.STR.EQ ŠTTL„TCB.EQŠINCLUDE�9995.&.TCB.EQ ŠTTL�CCB.EQŠINCLUDE�9995.&.CCB.EQ ŠTTL�LV5.EQŠINCLUDE�9995.&.LV5.EQŠLISTŠTTL�RIODRV.EQŠINCLUDE�9995.&.RIODRV.EQŠTTL�STDMACRO.AIŠINCLUDE�STDMACRO.AI/ŠTTL�RIO�DRIVER�COPYRIGHT�1982�BY�MOTOROLA�INC.*‰INCLUDE�9995.&.STR.EQ*‰INCLUDE�9995.&.TR1RTCD.EQ*‰INCLUDE�9995.&.TCB.EQ*‰INCLUDE�9995.&.CCB.EQ*‰INCLUDE�9995.&.LV5.EQ*‰INCLUDE�9995.&.RIO.EQ*‰INCLUDE�0..STDMACRO.SA@RIODRV„IDNTƒ2,0‰RIO�DRVR�3/28/83�COPYRIGHT�1982�BY�MOTOROLA�INC. ŠLLENƒ120ŠPAGEJ****************************************************************************8*ƒRIODRV�--�REV.�1.00�5/12/82�(C313)�RONI�WOOD�&�JIM�LOE4*�REV.�2.00�3/28/83�(C313)�CHANGED�INTERRUPT�HANDLER***ƒPurpose:‚REMOTE�I/O�HANDLER*/*ƒEntry:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒExit:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION***ƒCODE�IS�RE-ENTRANT*&*ˆASSEMBLY:�USE�CHAIN�FILE�'RIOASM.CF'*H*-----------------------------------------------------------------------*ŠPAGE*************************** MISCELLANEOUS EQUATES ***************************IOEVCD„EQU„1’I/O�event�code*********************** *‡MACROS†************************* Macro for putting the H/W priority level'* to the priority indicated by the CCB.* INHIB„MACRO-‰MOVE.W„CCBISR(A5),SR‡Set�processor�priority.‰ENDM*+* Macro for dropping the H/W priority level* to an interruptable state.* ENABL„MACRO4‰MOVE.W„CCBSR(A5),SRˆDrop�processor�priority�by�one.‰ENDM*+* Macro for dropping the H/W priority level * to zero.* UNMASKƒMACRO1‰MOVE.W„#$2000,SR‹Set�processor�priority�to�zero.‰ENDM‰PAGE********************************* CHANNEL CONTROL BLOCK (CCB) *********************************B*ƒContains�channel�device�dependent�description�and�data�areas�for*ƒI/O�handler.*ŠOFFSET‚CCBDDP*²¹\ÂFÊ9Ò-ÚHâ<ê9ò9ú;F K7>"/*@28:<B5J=R8Z3b<j5r=z>‚OŠ^’QšI¢9H* I/O HANDLER DATA AREA *************************************************CCBFLG„DS.B„2ŒFlags(CCBERAD1‚DS.B„4ŒError�debug�save�address2CCBQVER1‚DS.B„4ŒEvent�queueing�error�debug�address7CCBCCB„DS.B„4ŒPhysical�address�of�command�packet�(IOCB)CCBTASKB‚DS.B„4ŒBuffer�task�TCB-CCBPKT„DS.B„18‹Event�work�area�(command�tour)0CCBCPKTƒDS.B„18‹Event�work�area�(interrupt�tour)(CCBPTR„DS.B„4ŒPhysical�address�of�bufferCCBLEN„DS.B„4ŒLength�of�buffer0CCBPTR1ƒDS.B„4ŒPhysical�address�of�2ndary�buffer&CCBLEN1ƒDS.B„4ŒLength�of�2ndary�buffer*CCBCID„DS.B„4ŒCMR�parameter�block�id�(DCB)CCBCOPTƒDS.B„2ŒIOCB�options#CCBCFIGƒDS.B„$26ŠConfiguration�data**‰56�bytes�remain*9*‰CCBFLG�DEFINITIONS:�if‚CCBFLG.B�if�not�0�the�RIO�module$*�for�the�CCB�cannot�be�used�for�the*�following�reasons:*9*‰CCBFLG.B�=�$FA�=�CCB�allocation�exceeded�#�of�specified/*šdevices�-�no�room�in�RIO�table�for�the�module!*’=�$FC�=�no�RIOTBL�was�allocated/*’=�$F5�=�no�room�in�RIOTBL�for�this�RIO�module*™(incorrect�table�allocation)**‰PAGE ‰SECTION�8 ‰XREF�RIOTBLJ******************************************************************************‚RIO�SERVICE�VECTOR�TABLE***L*****************************************************************************RIODVR:#*ˆDC.L†RIOINTŽinterrupt�svc�address!*ˆDC.L†RIOCMDŽcommand�svc�address)*ˆDC.L†RIOINIT�initialization�svc�address**?*Below are the new offset form of service pointers, for new CMR**(‰DC.L†RIOINT-RIODVR†interrupt�sv. c�offset*‰DC.L†RIOCMD-RIODVR†command�service�offset.‰DC.L†RIOINIT-RIODVR…initialization�svc�offset‰DC.L†0‰Reserved‰DC.B†0“number�of�extra�pages‰DC.B†0,0,0�reserved‰DC.L†0,0,0�reserved 3*ƒ---ƒ---…CONFIGURATION�CONTROL�INFORMATION…---ƒ---ŠSPC�1$‰DC.B…'032983'ƒdate�of�last�assembly'‰DC.B†'�'‡space�means�no�patches�in�.LO#‰DC.B†'4'‡major�Versados�revision�#‰PAGEJ****************************************************************************‰COMMAND�TABLE�&�JUMP�TABLE*:*‰These�are�used�by�the�command�service�routine�to�jump�to.*‰the�appropriate�routine�to�handle�a�command.*J***************************************************************************CMDTBL:ŠDC.WƒROPENŽOPEN�command.ŠDC.WƒRCLOSE�CLOSE�command.ŠDC.WƒROUTON�RELAY�ON�command. ŠDC.WƒROUTOFFŒRELAY�OFF�command.ŠDC.WƒRSTATŽSTATUS�command.'ŠDC.WƒRENABL�ENABLE�INTERRUPTS�command.(ŠDC.WƒRDSABL�DISABLE�INTERRUPTS�command."ŠDC.WƒRPLSOŽPULSED�OUTPUT�command.=NUMCMDSƒEQU„(*-CMDTBL)/2‡The�number�of�commands�in�the�table.*9JMPTBL:ƒDC.WƒOPEN-*�Biases�to�the�corresponding�routines. ŠDC.WƒCLOSE-* ŠDC.WƒOUTON-*ŠDC.WƒOUTOFF-* ŠDC.WƒSTAT-*ŠDC.WƒENABLE-*ŠDC.WƒDSABLE-* ŠDC.WƒPLSO-**7JMPOFF„EQU„JMPTBL-CMDTBL†Offset�between�the�two�tables.ŠPAGEJ****************************************************************************+*ˆRIO�DRIVER�INITIALIZATION�SERVICE�ROUTINE*>*ˆThe�driver�is�entered�here�for�each�CCB�allocated.‚More�than:*ˆone�CCB�may�be�allocated�for�each�RIO�module.‚One�CCB�is>*ˆallocated�for�each�interrupt�level�the�board�is�jumpered�to.?*ˆThis�routine�checks�to�see�if�there�is�room�in�the�RIOTBL�for=*ˆthe�device�ID.‚It�saves�the�device�ID�and�the�memory�mapped>*ˆI/O�address�of�the�device�the�the�RIOTBL.‚It�initializes�the5*ˆinput�PIA�of�the�device�if�not�already�initialized.B*ˆThis�routine�also�checks�to�see�if�the�RIO�LED�is�on,�indicating<*ˆan�I/O�channel�reset�was�issued�or�a�power-up.�If�on,�thisA*ˆroutine�turns�it�off.�The�on/off�indicator�is�bit�#7�of�TSTREG.*:*ˆAn�error�code�is�saved�in�the�CCB�if�this�CCB�allocation=*ˆexceeds�the�maximum�number�of�CCB's�specified�during�SYSGEN9*ˆ(SYSGEN�parameter�NRIO),�if�no�RIOTBL�exists�or�no�room*ˆin�the�table�for�this�module.*$*ˆEntry:‚all�registers�are�available*�A5�=�CCB�address*I**************************************************************************RIOINIT:ŠPUSHPOINT‘save�pointers3ŠMOVE.LƒCCBCHB(A5),A0„get�memory�mapped�I/O�address$ŠMOVE.L�RIOTBL,A1Šget�RIOTBL�addressŠCMP.L‚#0,A1Žis�there�one?&ŠBNE.S‚RIOINIT1‹branch�if�have�a�table8ŠMOVE.B�#RIONTBL,CCBFLG(A5)�set�no�table�error�conditionŠBRA�RIOINEX1�goto�error�returnRIOINIT5‚TST.L‚(A1,D3)Œlook�for�an�entry�slot�to�save�this�guy5ŠBMI.S‚RIOINIT6‹branch�if�this�s/ lot�is�empty�-�use�it/ŠADD.W‚#PIALNG,D3‰not�empty,�bump�to�next�entry"ŠSUB.B‚#1,D4Ždecrement�the�counter(ŠBNE.S‚RIOINIT5‹branch�if�more�to�search4ŠBRA„RIOEXTER‹error�if�got�here-�no�room�for�the�map>RIOINIT6‚MOVE.L�D2,(A1,D3)‰save�this�memory�mapped�I/O�address*E*The input pia ios used exclusively for all input, and is initialized1* to all inputs and muist remain so for all time.*N*The output pia (PIA 2) is used exclusively for all output, and is initializedL*to�all�inputs.‚On�any�channel�which�is�allocted�for�output,�only�the�outputD*�Pia�will�be�set�for�output.‚When�this�channel�is�de-allocated,�theH*�corresponding�output�PIA�bit�must�be�re-initialized�for�input.‚FailureM* to follow this policy will result in impropper operation of input channels.*.ŠMOVE.L‚#0,D0�write�0�to�all�pia�control�reg'sŠBSR.SƒRIO.WCR‹do�itBŠMOVE.B‚#0,PIA1ADR(A0)„clear�all�data�direction�regs�(set�for�inpu!ŠMOVE.B‚#0,PIA1BDR(A0)„clear�next!ŠMOVE.B‚#0,PIA2ADR(A0)„clear�next!ŠMOVE.B‚#0,PIA2BDR(A0)„clear�last2ŠMOVE.B‚#4,D0�set�control�regs�for�data�reg�access ,ŠBSR.SƒRIO.WCR‹writes�are�done�by�subroutine&ŠBSR.SƒRIO.CLR‹go�clear�all�interrupts **‰turn�off�the�LED*1RIOEXIT1‚CLR.B‚CCBFLG(A5)‰set�for�good�allocation3ŠMOVE.L�CCBCHB(A5),A1†get�memory�mapped�I/O�address,ŠMOVE.B�TSTREG(A1),D1†read�the�test�register$ŠBPL.S‚RIOINEX1‹return�if�LED�is�off%ŠBCLRƒ#LEDSTA,D1‰clear�the�LED�on�bit&ŠMOVE.B�D1,TSTREG(A1)†turn�the�LED�off'RIOINEX1:�POP_POINT‘recall�all�pointersŠRTS**‚Subroutines�used�by�RIOINIT:*DRIO.WCR‚EQU�*ƒwrites�data�in�ls�byte�of�D0�to�all�pia�control�reg`s.‰MOVE.B‚D0,PIA1ACR(A0)‰MOVE.B‚D0,PIA1BCR(A0)‰MOVE.B‚D0,PIA2ACR(A0)‰MOVE.B‚D0,PIA2BCR(A0)‰RTS›end�RIOWCR**RIO.CLRƒEQU�*ƒclear�any�pending�interrupts*‰MOVE.B‚PIA1ADR(A0),D0‰MOVE.B‚PIA1BDR(A0),D0‰MOVE.B‚PIA2ADR(A0),D0‰MOVE.B‚PIA2BDR(A0),D0‰RTS›end�RIOCLRŠPAGEJ***************************************************************************$*‰RIO�DRIVER�COMMAND�SERVICE�ROUTINE*6*‹PARAMETER�ADDRESS�AND�BOUNDARY�CHECKS�HAVE�BEEN�MADE**ƒEntry:‚JSR�FROM�CMR�HANDLER.*‹A2�-�PHYSICAL�ADDRESS�OF�CMR�PARAMETER�BLOCK*‹A5�-�PHYSICAL�ADDRESS�OF�CCB*5*ƒExit:‚RTS�-�PARAMETER�BLOCK�VALIDATION�STATUS�IN�D0**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A**P**PP*"*”A3�=�RIO�PARAMETER�BLOCK�ADDRESS*”A6�=�REQUESTOR�TCB�ADDRESS**ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT*****J***************************************************************************RIOCMD:*)*‰Convert�logical�PB�address�to�physical.* ŠCLR.L‚D5;ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�RIO�parameter�block:ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�RIO�parameter�block+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚CMD010�Good�return.ŠNOP—Bad�length�return. ŠCLR.L‚D0;ŠMOVE.B�#RTCDPBLK,D0‡Set�up�invalid�parameter�block�addressŠBRA�RIOCEX2�goto�error�exit*!*‰see�if�passed�the�initialize�ok*CMD010„CLR.L‚D02ŠMOVE.LƒD6,A3ŒStage�phys.�addr.�opf�RIO�para.�blk.4ŠTST.B‚CCBFLG(A5)‰error�code�set�in�CCB�during�INIT?/ŠBEQ.S‚CMD020�branch�if�no�error�code,�continue$ŠMOVE.B�CCBFLG(A5),D0†set�error�code%CMDSRTRƒBRA.S‚RIOCEX2Œgoto�error�exit CMD020„EQU�**,*‰get�RIOTBL�address�into�A4�for�command�use* ŠMOVE.L�RIOTBL,A4ŠRIOTBL�address)ŠCMP.L‚#'!RIO',(A4)‡really�is�the�RIOTBL?,ŠBEQ.S‚CMD030�branch�if�really�is�the�RIOTBL4ŠMOVE.B�#RIONTBL,D0ˆset�error�return�code�-�no�tableŠBRA.S‚CMDSRTRŒand�return**‰find�RIO-ID�in�RIOTBL*‰A1�=�entry�address*0CMD030„MOVE.L�XIOCID(A2),D0†get�specified�RIO-ID(ŠMOVE.B�RIONMAX(A4),D1…max�#�of�RIO-ID's$ŠMOVE.L�#RIONTRY,D2ˆbump�past�header"FNDRIO10‚CMP.L‚(A4,D2),D0‰a�match?!ŠBEQ.S‚FNDRIO20‹branch�if�a�match&ŠADD.W‚#RIOIDLNG,D2‡bump�to�next�entry1ŠSUB.L‚#1,D1Ždecrement�number�of�entries�to�check&ŠBNE.S‚FNDRIO10‹branch�if�more�entries.ŠMOVE.W�#RIONID,D0‰error�-�RIO-ID�not�in�table3ŠBRA„C/ MDSRTRŒreturn�to�CMR�with�error�condition�set+FNDRIO20‚MOVE.L�A4,A1Žbass�address�of�tableŠADD.L‚D2,A1Žaddress�of�entry*(*‰Find�the�command�in�the�command�table.*-ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table.+ŠMOVE.W�CMDCOD(A3),D6†get�RIO�command�code.8CMDSRCHƒCMP.W‚(A0)+,D6‹Search�the�table�for�the�command.ŠDBEQƒD0,CMDSRCH‰*3ŠBNE.S‚CMDERR�If�we�found�the�command�in�the�table,8ŠADD.L‚#JMPOFF-2,A0‡get�the�corresponding�entry�from�the5ŠMOVE.W�(A0),D0Œjump�table�and�jump�to�the�routine�to"ŠJMP„(A0,D0.W)Šhandle�the�command.DCMDERR„MOVE.B�#RIOINVD,D1ˆdidn't�find�command�code�-�exit�with�errorŠSPC�1RIOCEX2:;ŠMOVE.WƒD0,CMDSTA(A3)‡write�error�code�to�users�RIO�para�blRIOCEX1:ŠRTSŠPAGEL*****************************************************************************‰OPEN�COMMANDA*‰This�command�assigns�the�logical�connection�between�a�user�task:*‰and�specified�channels�within�an�RIO�module.�16�channels?*‰maximum�may�be�specified�in�one�open�command.�Interrupt�levelB*‰of�the�channels�are�taken�from�the�CCB.�The�interrupts�levels�of4*‰input�channels�0-7�must�match�the�following�order:-*‰channels�0-1�must�have�same�interrupt�level-*‰channels�2-3�must�have�same�interrupt�level-*‰channels�4-5�must�have�same�interrupt�level-*‰channels�6-7�must�have�same�interrupt�levelD*‰It�is�ok�for�all�these�channels�to�have�the�same�interrupt�levels.*#*‰RIO�OPEN�command‚parameter�block: *�DS.W‚1„returned�command�status*�DS.W‚1„command�code�(01)*�DS.W‚1„#�of�channels�to�open*�DS.W‚1„1st�channel�number*�DS.W‚1„channel�configuration*’.*�DS.W‚1„nth�channel�number*�DS.W‚1„channel�configuration**‰configuration�byte:*�bit�0=1�output�channel*•=0�input�channel*�bit�1=1�disable�interrupt*•=0�enable�interrupt"*�bit�2=1�interrupt�on�rising�edge*•=0�interrupt�on�falling�edge)*�bit�3=1�wake-up�task�on�input�interrupt,*•=0�queue�event�to�task�on�intput�interrupt8*Œbits�8-14=‚debounce�interval.‚0=no�debounce,�otherwise-*˜debounce�time�is�value�times�4�milliseconds$*�bit�15=1�use�default�configuration *•=0�use�specified�configuration**‰Default�configuration:*�channels�0-7’channels�8-15*�------------’-------------*�input�channel‘output�channel*�interrupt�enabled*�interrupt�on�falling�edge*�queue�event�on�interruptB*‰When�default�configuration�is�specified,�the�actual�configuation9*‰is�saved�in�RIOTBL.�The�task�TCB�address�is�also�saved.*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�CLRPIAM,�SETPIA,�DOPIA*L**************************************************************************** PAGE*OPEN:*‰see�if�channel�already�opened* ŠPUSHPOINT‘save�all�address�regsŠALLOCATEƒCHCONFIG4ŠBSR�CLRPIAM�clear�(to�$FF)�the�PIA�map�for�this�RIOŠCLR.L‚D7‘channel�counter:ŠCMP.W‚#RIONID,D0‰an�error�returned�from�clearing�the�map?'ŠBEQ„OPNOID�branch�if�an�error�returned$ŠCLR.L‚D2‘channel�offset�into�RIOTBL)ŠCLR.L‚D1‘offset�into�RIO�parameter�block1ŠMOVE.W�CMDCHN(A3),D0†get�#�of�channels�specified-ŠBLE„OPNINC�branch�if�negative�or�zero,�error2ŠCMP.W‚#16,D0�cannot�specify�more�than�16�channels,ŠBGT„OPNINC�branch�if�greater�than�16,�errorGOPEN10„MOVE.W�NUMCHAN(A3,D1),D2‚get�channel�number�from�RIO�param.�blk.ŠMOVE.W�D2,D5Žsave�it0ŠMULUƒ#CHANLNG,D2ˆget�channel�offset�into�RIOTBLŠADD.L‚#4,D2Žbump�past�RIO-ID+ŠTST.W‚(A1,D2)Œthis�channel�already�opened?+ŠBPL„OPNOPN�branch�if�already�opened,�errorŠADD.L‚#1,D7Žcount�this�channel@ŠMOVE.W�CHNCNFG(A3,D1),D3‚get�configuration�from�RIO�param.�blk.-ŠSTORE„D3,CHCONFIG†save�channel�configuration*ŠBMI.S‚OPEN60�branch�if�defaults�specifiedŠBTSTƒ#0,D3Žoutput�channel?&ŠBNE.S‚OPEN70�branch�if�output�channel**‰set�this�channel�for�input* ŠMOVE.W�D3,D4Žsave�configuration"ŠCMP.B‚#8,D5Žsee�if�channel�#�8-153ŠBGE.S‚OPEN50�branch�if�channel�8-150 ,�no�interrupts3ŠMOVE.B�CCBPPRIO(A5),D4„get�intrrupt�level�from�CCBŠASL.L‚#4,D4Žget�into�bits�4-6$ŠOR.WƒD4,D3Žsave�the�interrupt�level*6*‰check�to�see�that�interrupt�levels�of�channels�match*,OPEN20„MOVE.B�D5,D6Žsave�this�channel�numberŠBTSTƒ#0,D5Žodd�channel?*ŠBNE.S‚OPEN30�branch�if�odd�channel�number*ŠADD.B‚#1,D6Ževen�-�get�channel�number�+�1ŠBRA.S‚OPEN40�and�continue/OPEN30„SUB.B‚#1,D6Žodd�-�get�channel�number�-�15OPEN40„MULUƒ#CHANLNG,D6ˆget�channel�offset�into�tableŠADD.L‚#4,D6Žbump�past�RIO-ID#ŠTST.W‚(A1,D6)Œthis�channel�opened?"ŠBMI.S‚OPEN50�branch�if�not�opened9ŠMOVE.W�RIOCNIF(A1,D6),D6‚get�other�channel�configurationŠSPC�2ŠBTSTƒ#0,D6Žan�input�channel?,ŠBNE.S‚OPEN50�branch�if�not�an�input�channel$ŠASR.L‚#4,D6Žget�into�low�order�bits**‰good�configuration0*‰save�TCB�address�and�configuration�information* OPEN50„EQU†*.ŠLOAD…D3,CHCONFIG†recall�channel�configuration+ŠBSR„SETPIA�go�set�PIA�map�for�this�channel5ŠCMP.W‚#RIONID,D0‰an�error�found�during�the�save�map?*ŠBEQ.S‚OPNERR�branch�if�an�error�was�found6ŠMOVE.W�D3,RIOCNIF(A1,D2)‚save�configuration�in�RIOTBL)ŠMOVE.L�A6,RIOTCB(A1,D2)ƒsave�TCB�address4ŠADD.W‚#OPNTRY,D1‰bump�to�next�RIO�param.�blk.�entry3ŠSUB.W‚#1,D0Ždecrement�number�of�channels�specified)ŠBGT„OPEN10�branch�if�more�channels�to�do,ŠBSR„DOPIAŽgo�set�the�PIA�hardware�registers!ŠCMP.W‚#RIONID,D0‰an�error�found?7ŠBEQ.S‚OPNERR�branch�if�an�error�was�found�-�don't�openŠCLR.L‚D0‘set�for�good�returnŠBRA.S‚OPNXIT�go�return�to�CMR**‰default�configuration�set*%OPEN60„CMP.W‚#7,D5Žsee�if�channel�0-7!ŠBLE.S‚OPEN80�branch�if�maybe�0-7!ŠCMP.W‚#16,D5�see�if�channel�8-16-ŠBGT.S‚OPNCNŽbranch�if�greater�than�16,�error**‰output�channel*,OPEN70„MOVE.W�#1,D3Žset�output�configurationŠBRA.S‚OPEN50�go�save�it**‰input�configuration�specified*-OPEN80„TST.W‚D5‘must�be�channel�#0�or�greater)ŠBLT.S‚OPNCNŽbranch�if�less�than�0,�errorŠCLR.W‚D3‘set�for�defaults/ŠMOVE.B�CCBPPRIO(A5),D3„get�CCB�interrupt�levelŠASL.L‚#4,D3Žput�into�bits�4-6ŠBRA.S‚OPEN20�go�save�it**‰open�errors�here*;OPNINT„MOVE.W�#RIOIINT,D0ˆset�invalid�interrupt�level�error.ŠBRA.S‚OPNERR�go�'de-open'�any�opened�channels>OPNCN…MOVE.W�#RIOICNS,D0ˆset�illegal�channel�#�specified�error.ŠBRA.S‚OPNERR�go�'de-open'�any�opened�channels8OPNINC„MOVE.W�#RIOINC,D0‰set�invalid�#�of�channels�errorŠBRA.S„OPNXIT‹exit;OPNOID„MOVE.W�#RIONID,D0‰set�RIO�module�not�allocated�errorŠBRA.S‚OPNXIT�go�return�to�CMR9OPNOPN„MOVE.W�#RIOPND,D0‰set�channel�already�opened�error*)*‰reset�any�opened�channels�to�not�opened*%OPNERR„TST.W‚D7‘any�channels�to�undo?3ŠBEQ.S‚OPNXIT�branch�if�none�to�undo,�return�to�CMR&ŠMOVE.W�#$FFFF,D3Šset�'un-opened'�codeŠCLR.L‚D1‘clear�for�use6OPNERR10‚MOVE.W�NUMCHAN(A3,D1),D2‚get�a�channel�number$ŠMULUƒ#CHANLNG,D2ˆget�channel�offsetŠADD.L‚#4,D2Žbump�past�headers*ŠMOVE.W�D3,(A1,D2)‰set�this�entry�unopened-ŠADD.W‚#OPNTRY,D1‰bump�to�next�channel�numberŠSUB.W‚#1,D7Ždecrement�counter&ŠBGT.S‚OPNERR10‹branch�if�more�to�undo** Fall into exit* OPNXIT EQU * ŠADD.L„#8,A7Œdeallocate�CHCONFIGŠPOP_POINT‘restore�all�pointers ŠBRA�NRMEXITŠPAGEK*****************************************************************************‰SETPIA*7*‰Build�the�PIA�map�entries�for�the�specified�channels.*‰Builds�1�entry�per�call*‰Map�is�in�RIOTBL.**‰Entry:�A4ƒ=�RIOTBL�address*�D3.W�=�channel�configuration*�D5.B�=�channel�number*7*‰Exit:‚D0.W�=�RIONID�if�map�entry�not�found,�otherwise*—D0�unchanged *‰Uses:�D4,D6*‰Entry�point�=�SETPIA*‰Exit�point‚=�SETPIART**L******************************************************************************‰find�map�entry* SETPIA EQU *ŠPUSHPOINT‘save�all�pointersŠMOVE.L�D7,-(A7)‹save�D75ŠMOVE.W�RIOPIA(A4),D7†get�offset�to�start�of�PIA�maps.ŠMOVE.B�RIONAL(A4),D6†get�#�of�RIO'S�allocated3ŠMOVE.L�CCBCHB(A5),D4†get�memory�mapped�I/O�address=SETPIAFD‚CMP.L‚PIADDR(A4,D7),D4ƒfind�the�matching�I/O�address0 ŠBEQ.S‚SETPIA00‹branch�if�found$ŠADD.W‚#PIALNG,D7‰bump�to�next�entryŠSUB.B‚#1,D6Ždecrement�counter0ŠBNE.S‚SETPIAFD‹branch�if�more�entries�to�search>ŠMOVE.W�#RIONID,D0‰set�for�fatal�error�-�this�shouldn't�happen ŠBRA.S„SETPIART‰return�to�caller**‰determine�channel�number*SETPIA00‚CLR.L‚D6‘clear�for�use/ŠMOVE.B�D5,D6Žcopy�channel�number�to�work�spaceŠCMP.B‚#7,D5Žchannel�0-7?ŠBLE.S‚SETPIA20‹branch�if�0-7**‰channel�8-15*/ŠSUB.B‚#8,D6Žget�bit�#�offset�of�channel�numberŠBTSTƒ#0,D3Žan�output�channel?0ŠBNE.S‚SETPIA10‹branch�if�yes,�an�output�channel**‰channel�8-15�as�input�channel*%ŠBCLRƒD6,DODR815(A4,D7)‚set�for�input ŠBRA.S‚SETPIART‹return�to�caller* *‰channel�8-15�as�output�channel*SETPIA10 EQU *0ŠBSET…D6,DODR815(A4,D7)ƒset�ddr�image�for�output ŠBRA.S‚SETPIART‹return�to�caller* *‰channel�0-7*%SETPIA20‚BTSTƒ#0,D3Žan�input�channel?,ŠBEQ.S‚SETPIA30‹branch�if�yes,�input�channel**‰CHANNEL�0-7�as�output�channel*/ŠBSETƒD5,DODR07(A4,D7)ƒset�ddr�image�for�output#SETPIART‚MOVE.L�(A7)+,D7‹restore�D7ŠPOP_POINT‘restore�all�pointersŠRTS—return�to�caller**‰channel�0-7�as�input�channel*SETPIA30‚EQU�*$ŠBCLRƒD5,DODR07(A4,D7)ƒset�for�input1ŠBSR„NEWSETPŒinit�PIA�control�regs�for�interrupts ŠBRA†SETPIARTŠPAGED********************************************************************&*ˆNEWSETP�is�interrupt�setup�for�PIA's&*ˆNEWSETP�initializes�one�PIA�per�call** Private subroutine for SETPIA** Table driven pia setup::*‚PIAICMSK‚is�a�table�of�PIA�interrupt�control�mask�words.N*‚The�LS�byte�is�AND'ed�with�map�entry,�and�the�MS�byte�is�OR'd�with�map�entry‰SPC�3PIAICMSK EQU *-‰DC.W†$05FD…enable�falling�irq�on�even�port�#‰DC.W†$04FE…disable�even‰DC.W†$07FF…enable�rising‰even‰DC.W†$04FE…disable�evenA*----------------------------------------------------------------‰DC.W†$0CEF…enable�fallingˆodd‰DC.W†$04F7…disable�odd‰DC.W†$1CFF…enable�rising‰odd‰DC.W†$04F7…disable�oddŠSPC�3)PIAMGOFF�EQU�*‚IRQ�control�image�offsets:‰DC.B†2‰DC.B†3‰DC.B†0‰DC.B†1‰SPC�3NEWSETP:ŠSPC�1L*Generate index into table of interrupt control masks based on configuration * and even / odd channel number:(*Configurations are between 00X and 11X.**On entry (data input:)%*ˆD3.W‚contains�channel�configuration*ˆD5.B‚contains�channel�number%*ˆD7„contains�offset�to�PIA�map�start**‰PUSHALL–save�all ‰CLR.L…D0/‰MOVE.B„D3,D0…get�IRQ�config.�to�working�reg�D0+‰AND.B…#$0004,D0‚select�IRQ�config�data�bit‰TST.B…D0ˆsetup�for�branches7‰BMI.S…SETPIA33‚branch�on�default�configuration�request8‰BEQ.S…SETPIA32‚branch�on�falling�edge�irq�configuration‰CMP.B…#4,D0…rising�edge�irq�?7‰BEQ.S…SETPIA32‚branch�on�rising�edge�irq�configuration1‰MOVE.L„#2,D0…on�all�other�config.'s,�disable�irq6SETPIA32ƒEQU‚*ƒnow�determine�even�/�odd�channel�number"‰BTST†#0,D5…even�or�odd�channel�#?(‰BEQ.S…SETPIA31‚branch�on�even�channel�#"‰ADD‡#8,D0…add�8�for�odd�channel�##SETPIA31ŠEQU�*…rejoin�main�sequence ‰CLR.L…D18‰MOVE.W„PIAICMSK(PC,D0),D1‚fetch�control�word�from�table)‰MOVE.L„D3,D0…get�new�copy�of�config�data5‰AND.L…#$00000008,D0‚select�wakeup/que�event�data�bit ‰MOVE.L„#21,D4„setup�shift�count2‰LSL.L…D4,D0„position�wakeup/quevent�bit�in�bit�24‰SPC�1)‰AND.L…#$0000FF00,D3‡select�debounce�data1‰LSL.L…#8,D3…position�debounce�data�in�bits�16-23‰OR.L†D3,D1…add�debounce�data-‰OR.L†D0,D1…add�wakeup/quevent�data�at�bit�248‰BSR‡WRITMAPƒwrite�the�interrupt�control�data�to�PIA�map7SETPIA33‚EQU‚*‚branch�here�for�no�change�in�irq�setting‰POPALL˜restore�register�values‰RTS‰PAGEWRITMAP:#*ˆWrites�interrupt�data�to�PIA�map.*ˆInput�parameters�to�WRITMAP:*ˆD5ƒchannel�# *ˆD7ƒoffset�to�start�of�PIA�maps$*ˆA4ƒRIOTBL�address�for�current�user;*ˆD1.L�PIA�control�mask�word�(bits�16-23�are�debounce�data)!*¤(bit�24�is�wakeup/quevent�bit).*>*ˆTranslates�channel�number�to�PIA�register�image�map�address,4*ˆthen�modifys�the�map�image�based�on�data�in�D1�.L.21 *ˆNow�translate�channel�number�into�PIA�map�offset* ‰CLR.L…D0/‰MOVE.B„D5,D0…put�channel�#�into�working�reg�D0"‰LSR.B…#1,D0…divide�channel�#�by�2*;*‡PIA�channel�index�now�in�D0;�now�add�offset�from�PIAMGOFF*‡(pia�image�offset�table)*;‰ADD.B…PIAMGOFF(PC,D0),D7‚add�offset�to�channel�IRQ�control$‰ADD.B…#8,D7…bump�to�register�images**ˆD7�contains�offset�to�PIA�map*.‰AND.B…D1,(A4,D7)‚modify�PIA�control�reg�image0‰LSR.L…#8,D1…bring�OR�byte�into�working�position-‰OR.B†D1,(A4,D7)‚modify�PIA�control�reg�image.‰LSR.L…#8,D1…bring�debounce�data�into�position/‰OR.B†D1,-1(A4,D7)‚add�debounce�data�to�PIA�map*‰LSR.L…#1,D1‡bring�wakeup/que�bit�to�bit�7(‰AND.B…#$80,D1Šselect�wakeup/quevent�bit.‰OR.B†D1,(A4,D7)„add�wakeup/que�bit�to�PIA�map‰RTS‰PAGED*********************************************************************:*‰DOPIA‚Copy�the�interrupt�control�data�and�data�direction3*�information�from�the�PIA�register�images�(in�map)*�to�the�PIA�registers.*A*‚The�PIA�must�not�be�allowed�to�generate�an�interrupt�during�theE*‚initialization�process�because�the�CMR�and�RIO�tables�have�not�been@*‚set�up.‚To�enforce�this,�all�interupts�are�disabled�during�the@*‚code�section�where�the�PIA�control�reg.'s�are�set,�and�the�PIA*‚interrupt�flags�are�cleared.**ˆENTRY�PARAMETERS:*�A4�=�address�of�RIOTBL*�A5�=�address�of�CCB***‰Exit:‚D0.W�=�RIONID�if�PIA�map�not�found*�D0.W�=�0�if�no�errors�found**‰Uses:�A0,D1,D6,D7**D*********************************************************************;*‚CLRIRQ�is�an�AND�mask�used�to�clear�PIA�IRQ�control�bits.*"CLRIRQƒEQU‡$E4‡clears�bits�0,1,3,4*** DOPIA EQU *ŠPUSHPOINT’save�all�pointers!ŠMOVE.L�D7,-(A7)‹save�register�D7,ŠMOVE.W�RIOPIA(A4),D7†get�offset�to�PIA�maps$ŠMOVE.B�RIONAL(A4),D6†get�#�of�RIO'S3ŠMOVE.L�CCBCHB(A5),D1†get�memory�mapped�I/O�address>DOPIA10ƒCMP.L‚PIADDR(A4,D7),D1ƒlook�for�a�matching‚I/O�address(ŠBEQ.S‚DOPIA20Œbranch�if�found�the�entry(ŠADD.W‚#PIALNG,D7‰bump�to�next�map�entry"ŠSUB.B‚#1,D6Ždecrement�the�counter/ŠBNE.S‚DOPIA10Œbranch�if�more�entries�to�search9ŠMOVE.W�#RIONID,D0‰set�for�fatal�error�(shouldn't�happen) ŠBRA�DOPIAX�branch�to�exit�point**‰D7�contains�offset�to�PIA�map(*‰set�direction�register�of�channels�0-7**ˆMASK�ALL�INTERRUPTS* DOPIA20 EQU *0ŠMOVE.WƒSR,D6Œsave�present�interrupt�mask�status!ŠOR‡#$0700,SRˆmask�all�interrupts***‰Set�direction�register�for�channel�0�-�73*‰Newly�created�OUTPUT�channels�must�be�set�to�OFF.4*‰To�do�this,�OR�new�channels�bit�map�with�data�reg.<*‰(there�is�logical�inversion)�between�PIA�and�final�output.*ŠCLR†D2�for�useŠCLR†D1�for�use6ŠMOVE.L�PIADDR(A4,D7),A0ƒget�memory�mapped�I/O�address,ŠBSET…#2,PIA2ADR(A0)ƒset�for�data�reg�access-ŠMOVE.BƒPIA2ADR(A0),D4ƒget�old�data�reg�value+ŠNOT†D4�convert�data�format�to�conventional'ŠBCLR…#2,PIA2ACR(A0)ƒset�for�DDR�access;ŠMOVE.BƒPIA2ADR(A0),D2ƒget�a�copy�of�old�data�direction�reg-ŠAND†D2,D4Œselect�on�channels�that�are�outputŠNOT†D24ŠMOVE.BƒDODR07(A4,D7),D1„get�the�new�output�channelsŠAND†D2,D1Œfind�new�channels:ŠMOVE.B�PIA2ADR(A0),D0…read�channel�0-7�direction�register9ŠOR.BƒDODR07(A4,D7),D0ƒadd�in�the�new�setting�information8ŠMOVE.B�D0,PIA2ADR(A0)…store�into�the�direction�register,ŠBSETƒ#2,PIA2ACR(A0)…set�for�output�function4ŠOR.B„D1,PIA2ADR(A0)„set�new�OUTPUT�channels�for�OFF'ŠNOT…D4�convert�to�inverted�data�format/ŠAND.B„D4,PIA2ADR(A0)ƒadd�in�old�data�reg�value*-*‰Set�direction�register�for�channels�8�-�16.*>*‰Newly�created�OUTPUT�channels�must�be�set�OFF.‚To�do�this,OR>*‰new�channels�bit�mask�with�data�register�(there�is�a�logical3*‰inversion�between�PIA�outputs�and�final�outputs).*ŠCLR†D2�for�useŠCLR†D1�for�use,ŠBSET…#2,PIA2BDR(A0)ƒset�for�data�reg�access-ŠMOVE.BƒPIA2BDR(A0),D4†get�old�data�reg�value+ŠNOT†D4�convert�data�to�conventional�format'ŠBCLR…#2,PIA2BCR(A0)†set�for�DDR�access7ŠMOVE.BƒPIA2BDR(A0),D2†get�a�copy�of�old�direction�r1 eg.-ŠAND†D2,D4Œselect�on�channels�that�are�outputŠNOT†D20ŠMOVE.BƒDODR815(A4,D7),D1ƒget�new�direction�reg.%ŠAND†D2,D1Œselect�new�output�channels;ŠMOVE.B�PIA2BDR(A0),D0…read�channel�8-15�direction�register:ŠOR.BƒDODR815(A4,D7),D0‚add�in�the�new�setting�information8ŠMOVE.B�D0,PIA2BDR(A0)…store�into�the�direction�register,ŠBSETƒ#2,PIA2BCR(A0)…set�for�output�function0ŠOR.BƒD1,PIA2BDR(A0)…set�new�output�channels�off'ŠNOT†D4�convert�data�to�inverted�format1ŠAND.B„D4,PIA2BDR(A0)ƒreplace�old�data�reg�values **ˆClear�all�PIA�interrupts*‰TST.B…PIA1ADR(A0)‰clear�PIA�1A‰TST.B…PIA1BDR(A0)‰clear�PIA�1B‰TST.B…PIA2ADR(A0)‰clear�PIA�2A‰TST.B…PIA2BDR(A0)‰clear�PIA�2B*#* Set channels 4-5 IRQ control bits*6ŠMOVE.B�PIA2ACR(A0),D0…get�0-7�output�control�register)ŠAND.B„#CLRIRQ,D0‡negate�IRQ�control�bits;ŠOR.BƒOCR07(A4,D7),D0„add�channel�4-5�interrupt�information*ŠMOVE.B�D0,PIA2ACR(A0)…write�the�new�stuff*,*‰set�interrupt�information�for�channels�6-7*<ŠMOVE.B�PIA2BCR(A0),D0…get�chan�8-15�output�control�register(ŠAND.B„#CLRIRQ,D0‡clear�IRQ�control�bits<ŠOR.BƒOCR815(A4,D7),D0ƒset�channel�6-7�interrupt�information*ŠMOVE.B�D0,PIA2BCR(A0)…write�the�new�stuff*,*‰set�interrupt�information�for�channels�0-1*:ŠMOVE.B�PIA1ACR(A0),D0…get�chan�0-7�input�control�register(ŠAND.B„#CLRIRQ,D0‡clear�IRQ�control�bits;ŠOR.BƒICR07(A4,D7),D0„set�channel�0-1�interrupt�information*ŠMOVE.B�D0,PIA1ACR(A0)…write�the�new�stuff*,*‰set�interrupt�information�for�channels�2-3*>ŠMOVE.B�PIA1BCR(A0),D0…get�channel�8-15�input�control�register(ŠAND.B„#CLRIRQ,D0‡clear�IRQ�control�bits<ŠOR.BƒICR815(A4,D7),D0ƒset�channel�2-3�interrupt�information*ŠMOVE.B�D0,PIA1BCR(A0)…write�the�new�stuffŠCLR.L‚D0‘set�for�good�return**ˆrestore�interrupt�level*6ŠMOVE.WƒD6,SRŒreturn�interrupt�masks�to�previous�valueDOPIAX�EQU�*˜exit�sequenceŠMOVE.Lƒ(A7)+,D7‰restore�D7ŠPOP_POINT‘recall�all�pointersŠRTS—return�to�callerŠPAGEL*****************************************************************************6*‰CLRPIAMƒClear�out�the�PIA�map�for�this�memory�mapped*“I/O�address.*&*‰Entry:�A1�=�RIO-ID�address�in�RIOTBL%*�A2�=�address�of�CMR�parameter�block%*�A3�=�address�of�RIO�parameter�block*�A4�=�address�of�RIOTBL*�A5�=�address�of�CCB*�A6�=�address�of�users�TCB**‰Uses:‚D4,D6,D7*%*‰Exit:‚D0�=�RIONID�if�an�error�found**�D0�=�contents�on�entry�if�no�error�found*L*****************************************************************************3CLRPIAMƒMOVE.W�RIOPIA(A4),D7†get�offset�to�PIA�maps.ŠMOVE.B�RIONAL(A4),D6†get�#�of�RIO'S�allocated3ŠMOVE.L�CCBCHB(A5),D4†get�memory�mapped�I/O�addressDCLRPIAM1‚CMP.L‚PIADDR(A4,D7),D4ƒlook�for�matching�mem.�map.�I/O�addrŠBEQ.S‚CLRPIAM2‹branch�if�found$ŠADD.W‚#PIALNG,D7‰bump�to�next�entryŠSUB.B‚#1,D6Ždecrement�counter0ŠBNE.S‚CLRPIAM1‹branch�if�more�entries�to�search#ŠMOVE.W�#RIONID,D0‰set�error�returnŠRTS—return�to�caller*CLRPIAM2‚CLR.L‚DODR07(A4,D7)†clear�the�map ŠCLR.L‚OCR07(A4,D7)‡and�the�restŠRTS—return�to�callerŠPAGEL******************************************************************************‚CLOSE�COMMAND*A*‚Close�all�connections�with�this�user�task�and�his�open�channelsB*‚for�this�RIO�module.�The�channels�are�put�back�to�the�pre-opened4*‚state.�All�I/O�on�this�user's�channels�is�stopped.*$*‚RIO�CLOSE�COMMAND�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�02*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�STOPPIA*L*****************************************************************************CLOSE:+ŠMOVE.L�#4,D1Žbump�past�RIO-ID�in�the�table!ŠCLR.L‚D2‘use�for�channel�counter5CLOSE10ƒCMP.L‚RIOTCB(A1,D1),A6ƒchannel�for�this�user?*ŠBNE.S‚CLOSE20Œbranch�if�not�for�this�user2 3ŠMOVE.W�RIOCNIF(A1,D1),D0‚get�channel�configuration4ŠBSR„STOPPIAŒgo�stop�I/O�on�this�channel�D2�=�chan�#?ŠMOVE.W�#$FFFF,RIOTCB(A1,D1)�set�this�channel�entry�to�not�used5CLOSE20ƒADD.L‚#CHANLNG,D1ˆpoint�to�next�channel�entryŠADD.L‚#1,D2Žcount�this�channel$ŠCMP.L‚#16,D2�searched�all�channels?&ŠBNE.S‚CLOSE10Œbranch�if�more�channelsŠCLR.L‚D0‘set�for�no�errorsŠBRA„NRMEXITŒand�return�to�CMRŠPAGED*********************************************************************4*‚STOPPIAƒdeactivate�I/O�on�specified�channel�number*&*‚Entry:�A1�=�RIO-ID�address�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‰D0.W�=�channel�configuration%*‰D2.L�=�channel�number�to�deactivate* *‚Uses:‚D0,A0*L*****************************************************************************:STOPPIAƒMOVE.L�CCBCHB(A5),A0†get�memory�mapped�I/O�addressŠCMP.B‚#8,D2Žchannel�8-15?&ŠBGE.S‚STOPIA60‹branch�if�channel�8-15* *‰channel�0-7*5ŠBCLRƒ#2,PIA2ACR(A0)…select�output�direction�register/ŠBCLRƒD2,PIA2ADR(A0)…set�this�channel�for�input0ŠBSETƒ#2,PIA2ACR(A0)…select�output�data�register,ŠBCLRƒD2,PIA2ADR(A0)…deactivate�this�channelŠBTSTƒ#0,D0Žinput�channel?,ŠBNE.S‚STOPIART‹branch�if�no,�output�channel*/*‰input�channel�-�determine�if�using�interrupts* ŠBTSTƒ#1,D0Žinterrupts�disabled?"ŠBNE.S‚STOPIART‹branch�if�disabled-ŠBTSTƒ#0,D2Žsee�if�odd�or�even�channel�number,ŠBNE.S‚STOPIA10‹branch�if�odd�channel�number7ŠMOVE.B�#1,D0Ževen�chan�-�disable�interrupts�bit�#�is�0ŠBRA.S‚STOPIA20‹and�continue>STOPIA10�MOVE.B�#4,D0�odd�chan�-�disable�interrupts�bit�#�is�3.STOPIA20�CMP.B‚#1,D2�get�actual�channel�number)ŠBGT.S‚STOPIA30‹branch�if�not�channel�0-15ŠBCLRƒD0,PIA1ACR(A0)…disable�interrupts�-�channel�0-1STOPIART‚RTS—return�to�caller.STOPIA30‚CMP.B‚#3,D2Žsee�if�channel�number�2-3!ŠBGT.S‚STOPIA40‹branch�if�not�2-33ŠBCLRƒD0,PIA1BCR(A0)…disable�interrupts�channel�2-3ŠBRA.S‚STOPIART‹and�return.STOPIA40‚CMP.B‚#5,D2Žsee�if�channel�number�4-5!ŠBGT.S‚STOPIA50‹branch�if�not�4-53ŠBCLRƒD0,PIA2ACR(A0)…disable�interrupts�channel�4-5ŠBRA.S‚STOPIART‹and�return;STOPIA50‚BCLRƒD0,PIA2BCR(A0)…disable�interrupts�channel�6-7ŠBRA.S‚STOPIART‹and�returnŠPAGE**‰channel�8-15*(STOPIA60‚MOVE.L�D2,D0Žget�channel�number!ŠSUB.L‚#8,D0Žmake�0-7�type�number5ŠBCLRƒ#2,PIA2BCR(A0)…select�output�direction�register"ŠBCLRƒD0,PIA2BDR(A0)…set�for�input0ŠBSETƒ#2,PIA2BCR(A0)…select�output�data�register,ŠBCLRƒD0,PIA2BDR(A0)…deactivate�this�channelŠRTS—return�to�callerŠPAGEF************************************************************************‰OUTON�-�TURN�ON�RELAY�COMMAND;*‰This�command�activates�relays�for�specified�channels�that9*‰have�previously�been�opened�for�output�by�the�same�task<*‰requesting�this�activation.‚The�parameter�block�is�checked9*‰for�errors�before�any�relay�is�activated.‚No�channel�is!*‰activated�if�an�error�is�found.9*‰All�channels�within�a�PIA�are�activated�sumultaneously.>*‰Outon�reads�the�pia�data�register�to�find�the�current�state.*%*‰RIO�OUTPUT�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�034*‰DS.Wƒ1ƒbit�mask�containing�channel�#'s�to�activate*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�DOOUT**L*****************************************************************************OUTON:ŠPUSHPOINT‘save�all�pointers3ŠCLR.L‚D3‘flag�to�ck�para.�blk.�before�doing�output.OUTON10ƒMOVE.L�#4,D1Žbump�past�RIO-ID�in�table!ŠCLR.L‚D2‘use�for�channel�counterŠCLR.L‚D0‘clear�for�use+ŠMOVE.W�CMDCHN(A3),D0†get�channels�to�start8ŠMOVE.WƒCMDCHN(A3),D3„copy�ON�request�to�check�register.)OUTON20ƒBTSTƒD2,D0Žactivate�this�channel?0ŠBEQ.S‚OUTON30Œbranch�if�no�-�check�next�channel5ŠCMP.L‚RIOTCB(A12 ,D1),A6ƒchannel�belonge�to�this�user?"ŠBNE.S‚OUTONERŒbranch�if�no,�error3ŠMOVE.W�RIOCNIF(A1,D1),D4‚get�channel�configurationŠBTST‚#0,D4�an�output�channel?+ŠBEQ.S‚OUTONER1‹branch�if�not�output,�error.ŠBCLRƒD2,D3Žnegate�check�flag�for�this�channel$ŠTST„D3‘is�all�of�parameter�checked?(ŠBNE.S‚OUTON30Œbranch�if�not�all�checked5ŠBSR„DOOUTŽgood�parameter�block�-�go�activate�channelŠBRA.S‚OUTONEXŒnormal�exit/OUTON30ƒADD.L‚#1,D2Žbump�to�next�channel�number-ŠADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry'ŠCMP.L‚#16,D2�checked�all�the�channels?/ŠBNE.S‚OUTON20Œbranch�if�more�channels�to�check*<*Fall into invalid command for error return (error in OUTON)*AOUTONERƒMOVE.W�#RIOICU,D0‰set�invalid�command�for�this�user�errorŠBRA.S‚OUTONRTŒand�return?OUTONER1‚MOVE.W�#RIOICC,D0‰set�invalid�command�for�this�channelŠBRA.S‚OUTONRTŒand�return$OUTONEXƒCLR.L‚D0‘set�for�good�return%OUTONRTƒPOP_POINT‘recall�all�pointersŠBRA„NRMEXITŒgo�return�to�CMR‰PAGE** DOOUT…EQU„***A*DOOUT talks directly to the PIA data reg.s and turns on outputs.**‰On�entry�to�DOOUT:8*‰D0�contains�(16�bit)�bit�mask�for�desired�ON�channels.<*‰A5�contains�address�of�CCB�from�which�I/O�base�addr�is�ob.*-“MOVE.L„A2,-(A7)Œsave�address�of�CMR�para�blk*“MOVE.L„CCBCHB(A5),A2‡get�I/O�base�address#“NOT‡D0’logic�inversion�in�RIO�ckts*“AND.B…D0,PIA2ADR(A2)†turn�on�channels�0-7%“LSR.W…#8,D0�select�data�for�ch.�8-15+“AND.B…D0,PIA2BDR(A2)†turn�on�channels�8-15-“MOVE.L„(A7)+,A2Œrestore�addr�of�CMR�para�blk“RTS‰PAGEM******************************************************************************"*‰OUTOFF�-�TURN�OFF�RELAYS�COMMAND=*‰This�command�deactivates�relays�for�specified�channels�that9*‰have�previously�been�opened�for�output�by�the�same�task<*‰requesting�this�activation.‚The�parameter�block�is�checked;*‰for�errors�before�any�relay�is�deactivated.‚No�channel�is#*‰deactivated�if�an�error�is�found.*)*‰RIO�OUTPUT�OFF�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�044*‰DS.Wƒ1ƒbit�mask�containing�channel�#'s�to�activate*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�DOOFF*L*****************************************************************************OUTOFF:ŠPUSHPOINT‘save�all�pointers2ŠCLR.L‚D3‘flag�to�ck�para.�blk.�before�stop�output.OUTOF10ƒMOVE.L�#4,D1Žbump�past�RIO-ID�in�table!ŠCLR.L‚D2‘use�for�channel�counterŠCLR.L‚D0‘clear�for�use+ŠMOVE.W�CMDCHN(A3),D0†get�channels�to�start0ŠMOVE.WƒD0,D3Œcopy�chan.�to�turn�off�to�work�reg+OUTOF20ƒBTSTƒD2,D0Ždeactivate�this�channel?0ŠBEQ.S‚OUTOF30Œbranch�if�no�-�check�next�channel5ŠCMP.L‚RIOTCB(A1,D1),A6ƒchannel�belongs�to�this�user? ŠBNE„OUTONERŒbranch�if�no,�error3ŠMOVE.W�RIOCNIF(A1,D1),D4‚get�channel�configurationŠBTST‚#0,D4�an�output�channel?)ŠBEQ„OUTONER1‹branch�if�not�output,�error.ŠBCLR…D2,D3Œnegate�check�flag�for�this�channel$ŠTST„D3‘is�all�of�parameter�checked?(ŠBNE.S‚OUTOF30Œbranch�if�not�all�checked3ŠBSR„DOOFFŽgood�para.�block�-�go�deactivate�channelŠBRA.S„OUTOFFXŠnormal�exit/OUTOF30ƒADD.L‚#1,D2Žbump�to�next�channel�number-ŠADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry'ŠCMP.L‚#16,D2�checked�all�the�channels?/ŠBNE.S‚OUTOF20Œbranch�if�more�channels�to�check ŠBRA†OUTONEROUTOFFX�EQU�*šnormal�exitŠPOP_POINT‘recall�all�pointersŠCLR.L„D0�signal�no�errorsŠBRA�NRMEXIT�normal�exit‰PAGE*** DOOFF…EQU�**B*DOOFF‚talks�directly�to�the�PIA�output�regs�and�turns�off�outputs*G* On entry: D0 has bit map of channels to turn off (a 1 means turn off)*‹A5�has�address�of�user�CCB*:*‰DOOFF�is�called�by�OUTOFF�and�pulsed�output�deactivation*/ŠMOVE.LƒA2,-(A7)Œsave�address�of�CMR�para�block3ŠMOVE.LƒCCBCHB(A5),A2‡get�memory�mapped�I/O�address*D*‚There�is�a�logical�inversion�between�PIA3 �outputs�and�final�outputs**ŠOR.B…D0,PIA2ADR(A2)†turn�off�selected�0-71ŠLSR.W„#8,D0�select�information�for�channels�8-15+ŠOR.B…D0,PIA2BDR(A2)†turn�off�selected�8-152ŠMOVE.Lƒ(A7)+,A2Œrestore�address�of�CMR�para�blockŠRTSŠPAGEM******************************************************************************!*‰STAT�-�GET�INPUT�STATUS�COMMAND;*‰This�command�reads�the�status�of�specified�input�channels=*‰that�do�not�have�interrupts�enabled.‚The�channels�must�have>*‰previously�been�opened�for�input�by�this�user.‚The�parameter>*‰block�is�checked�for�errors�before�any�input�status�is�read.A*‰The�users�parameter�block�is�modified�to�signal�active�channels<*‰by�setting�the�corresponding�bit�in�the�bit-mask�word.�The;*‰corresponding�bit�number�of�inactive�channels�is�cleared.**.*‰All�channels�in�a�PIA�side�are�read�at�once.*+*‰RIO�INPUT�STATUS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�05<*‰DS.Wƒ1ƒbit�mask�containing�channels�numbers�to�read�status$*”(�this�is�also�the�returned�field)*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�GTSTAT*M******************************************************************************STAT:ŠPUSHPOINT‘save�all�pointers(ŠCLR.L‚D5‘use�for�returned�status�values2ŠCLR.L‚D3‘flag�to�ck�para.�blk.�before�read�status.STAT10„MOVE.L�#4,D1Žbump�past�RIO-ID�in�RIOTBLŠCLR.L‚D2‘channel�counterŠCLR.L‚D0‘clear�for�use;ŠMOVE.W�CMDCHN(A3),D0†get�channel�numbers�to�read�status�on3ŠMOVE.W�D0,D3Žcopy�chan�activation�req.�bit�pattern/STAT20„BTSTƒD2,D0Žread�status�for�this�channel?ŠBEQ.S‚STAT40�branch�if�no5ŠCMP.L‚RIOTCB(A1,D1),A6ƒchannel�belongs�to�this�user?1ŠBNE„OUTONERŒbranch�if�no�-�return�with�error�set3ŠMOVE.W�RIOCNIF(A1,D1),D4‚get�channel�configurationŠBTSTƒ#0,D4Žan�input�channel?9ŠBNE„OUTONER1‹branch�if�not�input�-�return�with�error�set'ŠCMP.B‚#8,D2Žsee�if�channel�number�8-156ŠBGE.S‚STAT30�branch�if�8-15�-�do�not�check�interrupts,ŠBTSTƒ#1,D4Žis�chan�1-7,�set�for�interrupts?2ŠBEQ„OUTONER1‹branch�if�set�for�interrupts�-�error6STAT30„BCLRƒD2,D3Žclr�activation�flag�for�this�channel*ŠTST„D3‘finished�checking�parameter�block?1ŠBNE.S‚STAT40�branch�if�not�finished�checking�yet.ŠBSR„GTSTAT�go�read�status�and�save�in�REG.�D5!ŠBRA.S‚STAT50�goto�procedure�exit3STAT40„ADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry(ŠADD.L‚#1,D2Žbump�to�next�channel�number#ŠCMP.L‚#16,D2�checked�all�channels?,ŠBRA„STAT20�branch�to�channel�check�sequence�X�X‚(stamp�coupling)?*‚Return�parameters:‚none�(side�effects;�writes�to�PIA�ctl�reg)* DOENBL EQU *3‰LEA‡ENBLIRQ(PC),A1†get�address�of�enable_irq�table3‰BSR‡MODIFYPIAŒmodify�PIA�control�reg�IRQ1�ctl�bits‰RTS‰PAGE *MODIFYPIA**†It's�functions�are:0*ˆa.�To�write�interrupt�control�data�to�PIA�maps=*ˆb.�To�write�interrupt�control�data�to�PIA�control�registers*>*‹It�performs�these�two�functions�be�invoking�WRITMAP�&�DOPIA.+*‹It�DOES�NOT�MODIFY�DEBOUNCE�CONTROL�DATA.***ˆInput�parameters:/*’A1„address�of�enable�/�disable�constant�table*’D2„channel�#*’A4„RIOTBL�address*’D1„X��X�X>*ˆOutput�parameters:‚none�(side�effects;�writes�PIA�registers)*MODIFYPIA EQU * ‰CLR.L…D7‰MOVE.L„D2,D5ˆsetup�channel�#2‰MOVE.W„RIOPIA(A4),D7‡get�offset�to�user's�PIA�map ‰BTST†#0,D2…even�or�odd�channel?"‰BNE.S…MODF1…branch�on�odd�channel-‰MOVE.W„(A1),D1ƒget�even�channel�control�mask ‰BRA.S…MODF2 MODF1 EQU ***ˆstage�code�for�WRITMAP*1‰MOVE.W„2(A1),D1‚get�odd�channel�IRQ�control�mask MODF2 EQU *2‰BSR‡WRITMAPƒwrite�the�new�interrupt�status�to�map,‰BSR‡DOPIA…write�the�new�control�data�to�PIA‰RTS‰SPC�10*ENBLIRQ�EQU�*†table�for�use�by�DOENBL�only@*‚MS�byte�is�OR'ed�with�control�data,�LS�byte�is�AND'ed�with�it.%‰DC.W†$01FF…enable�irq�even�channel�#$‰DC.W†$08FF…enable�IRQ�odd�channel�#;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -ŠPAGEM******************************************************************************%*ˆDSABLE�-�DISABLE�INTERRUPTS�COMMAND>*‰This�command�disables�interrupts�for�the�specified�channels.<*‰The�channels�must�have�been�opened�for�input�by�this�user,4 ?*‰must�be�channels�0-7�only,�and�must�currently�have�interrupts;*‰enabled.‚The�parameter�block�is�checked�for�errors�before>*‰any�interrupts�are�disabled.�No�channels�are�disabled�if�any*‰error�is�found.*1*‰RIO�DISABLE�INTERRUPTS�command�parameter�block: *‰DS.Wƒ1ƒreturned�command�status*‰DS.Wƒ1ƒcommand�code�07B*‰DS.Wƒ1ƒbit�mask�containing�channel�numbers�to�disable�interrupts*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB**‚Calls:�DODSABL*M*****************************************************************************DSABLE:ŠPUSHPOINT‘save�all�pointers7DSABL10ƒMOVE.L�#4,D1Žset�D1�to�chan�config.�entry�(row)!ŠCLR.L‚D2‘use�for�channel�counter1ŠCLR.L‚D0‘clear�for�use�as�channel�activ.�bit�map4ŠMOVE.W�CMDCHN(A3),D0†get�channel�activation�bit�map+ŠCMP.W‚#$FF,D0Œcannot�specify�channels�8-153ŠBGT„ENABLERŒbranch�if�8-15�-�return�with�error�set(DSABL20ƒBTSTƒD2,D0Ždisable�this�channel?)ŠBEQ.S‚DSABL30Œbranch�if�not�this�channel-ŠCMP.L‚RIOTCB(A1,D1),A6ƒbelongs�to�this�user?0ŠBNE„OUTONERŒbranch�if�no,�return�with�error�set3ŠMOVE.W�RIOCNIF(A1,D1),D4‚get�channel�configurationŠBTSTƒ#0,D4Žan�input�channel?8ŠBNE„OUTONER1‹branch�in�not�input,�return�with�error�setŠBTSTƒ#1,D4Žinterrupts�enabled?1ŠBNE„OUTONER1‹branch�if�no,�return�with�error�set/ŠBSET…#1,D4Œdisable�interrupts�for�this�channel>ŠMOVE.WƒD4,RIOCNIF(A1,D1)ƒstore�out�irq�data�in�config.�RIOTBLŠPUSHALL“save�all�regs!ŠBSR„DODSABLŒgo�do�actual�disableŠPOPALL”restore�all(DSABL30ƒADD.L‚#1,D2Žbump�to�next�channel-ŠADD.L‚#CHANLNG,D1ˆbump�to�next�channel�entry"ŠCMP.L‚#8,D2Žchecked�all�channels?&ŠBNE.S‚DSABL20Œbranch�if�more�channels)ŠBRA†ENABLOKŠreturn�with�status�=�no�errsŠPAGE**.*DODSABL is a local subroutine for DSABLE only**ƒInput�parameters**’D2.W‚channel�#*’A4„RIOTBL�address*?*‚Return�parameters:‚none�(side�effects;�writes�to�PIA�ctl�reg)* DODSABL EQU *3‰LEA‡DSBLIRQ(PC),A1†get�address�of�enable_irq�table3‰BSR‡MODIFYPIAŒmodify�PIA�control�reg�IRQ1�ctl�bits‰RTS*** DSBLIRQ‚EQU‡*.‰DC.W†$00FE…disable�IRQ�on�even�channel�number%‰DC.W†$00F7…disable�IRQ�odd�channel�#;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -‰PAGEM*******************************************************************************ˆPLSO�-�PULSED�OUTPUT�COMMAND*)*‚Entry:�A1�=�address�of�RIO-ID�in�RIOTBL%*‰A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A4�=�address�of�RIOTBL*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB***‰Exits�to�NRMEXIT***Parameter block format for pulsed output:*0*RIO parameter block (pointed to by A3 on entry)* *ˆDS.W†1‰returned�command�status*ˆDS.W†1‰command�code*ˆDS.W†1‰number�of�channels<*ƒ---ƒ---ƒ---ƒparameters�for�individual�channelsƒ---ƒ---ƒ---*ˆDS.W†1‰first�channel�number,*ˆDS.L†1‰number�of�milliseconds�for�pulse�on*ˆ.*ˆ.*ˆDS.W†1‰nth�channel�number5*ˆDS.L†1‰number�of�milliseconds�for�nth�channel�pulse*7* EACH CHANNEL IS ACTIVATED IN TURN (NON-SYNCHRONOUSLY)**M***************************************************************************** PLSO:*@*ƒPulsed_Out(IN:LIST�OF�channel�activation�request,�pulse�times;*ˆOUT:error�code)>‰ALLOCATE�CHANID,RIOPARBK†allocate�channel�id�&�RIO�para�block3‰STORE…A3,RIOPARBK‰save�RIO�parameter�block�address**†Initiate�pulsed�output*!‰CLR.L…D6’clear�working�registers ‰CLR.L…D3’. ‰CLR.L…D2’. ‰CLR.L…D0’.*$*ˆget�number�of�channels�to�activate*<‰MOVE.W„CMDCHN(A3),D0‡get�number�of�chan's�from�RIO�para�blk**‡WHILE�channel�count�>�0*PLSO1:$‰TST.W…D0’loop�on�#�of�chan.'s�to�do ‰BEQ‡PLSOX**ˆDO**‡get�first�channel�number* ‰CLR.L…D5‰MOVE.W„NUMCHAN(A3,D6),D5$‰STORE…D5,CHANID‹save�channel�number*G* Channel ID will consist of user CCB address + chan numbe4 r in LS byte.*+‰MOVE.L„A5,D7�copy�user's�CCB�address�to�D75‰ADD.L…D7,CHANID(A7)‡CHANID�now�has�complete�chan.�ID"‰MOVE.L„D5,D7�copy�channel�#�to�D7,‰BSR‡BIN_BIT�convert�binary�to�bit�map�in�D5*)*‚IF�channel�belongs�to�current�user�THEN*6‰MULU†#CHANLNG,D7‰compute�offset�to�nth�chan�in�RIOTBL%‰ADD‡#4,D7�bump�to�user�TCB�in�RIOTBL-‰CMP.L…RIOTCB(A1,D7),A6„compare�TCB�addresses1‰BNE.S…PLSOER1�branch�on�channel�not�current�user**ˆDO'*ˆGet�channel�configuration�from�RIOTBL*8‰MOVE.W„RIOCNIF(A1,D7),D3ƒget�channel�config�from�RIOTBL*&*‚IF�channel�is�an�output�channel�THEN* ‰BTST†#0,D3.‰BEQ.S…PLSOER2ƒbranch�on�not�an�output�channel**„DO2*…Get�pulse�time�from�RIO�commmand�parameter�block*‰MOVE.L„CHNCNFG(A3),D3*%*„IF�pulse�time�>�pulse_min_time�THEN*'‰BEQ.S…PLSOER3ƒbranch�on�pulse�time�=�0**„DO-*†request�periodic�activation(this�channel�#)*2‰LEA‡PLSOFF(PC),A0‡point�to�pulse�turn�off�routine%‰CLR.L…D1’set�request�for�1�time�only6‰MOVE.B„CCBPPRIO(A5),D1…set�act.�priority�same�as�task/‰LOAD†D2,CHANID‹setup�channel�ID�to�goto�PLSOFF'‰MOVE.L„D3,A1�setup�activation�interval‰PUSHALL"‰TR0$.RQPA˜pass�request�for�wakeup*)*‚If�no�err�in�periodic�act.�request�THEN*‰BRA.S…RQPAOKŽgood�return(‰BRA.S…PLSOER4�err�in�periodic�act.�req.**†DO*RQPAOK:‰POPALL(‰PUSHALL—a�more�elegant�way�to�do�this�?*"*ˆactivate_this_channel(channel�#)*$‰MOVE.L„D5,D0�pass�bit�mask�to�DOOUT ‰BSR‡DOOUT‰POPALL**†END*ƒEND*ƒdecrement�channel�count* ‰SUB‡#1,D0**END* ‰BRA‡PLSO1**ˆError�handling*PLSOER1‚CLR.L…D00‰MOVE.B„#RIOICNS,D0‰channel�not�for�current�user ‰BRA.S…PLSOX1PLSOER2: ‰CLR.L…D00‰MOVE.B„#RIOICC,D0Šchannel�not�an�output�channel ‰BRA.S…PLSOX1PLSOER3:"‰CLR.L…D0’requested�pulse�time�=�03‰MOVE.B„#RIOCNFG,D0‰return�'bad�configuration'�code ‰BRA.S…PLSOX1PLSOER4:‰POPALL ‰CLR.L…D0+‰MOVE.B„RIOBSY,D0‹periodic�activation�error ‰BRA.S…PLSOX1Žreturn�device�busy‰SPC�2** Pulsed output good exit point*;PLSOX„LOAD†A3,RIOPARBK‰restore�RIO�para�block�address�to�A3‰CLR.L…D0ˆset�for�normal�returnPLSOX1: ‰ADD.L…#12,A7*‰BRA†NRMEXIT„goto�normal�common�exit�point‰PAGE**‡PULSED�OUTPUT�DEACTIVATION:**ˆPulsed�output�de-activation.!*ˆEntered�by�periodic�activation. *ƒOn�entry:?*ˆD1�contains�channel�ID�composed�of�user's�CCB�address�in�M.S.8*ˆ3�bytes,�and�channel�number�(0-15)�in�least�sig.�byte.*PLSOFF:‰PUSHALL&‰MOVE.B„D1,D5�save�combined�channel�ID ‰AND.B…#0,D1�recover�CCB�address+‰MOVE.L„D1,A5�stage�CCB�address�for�'DOOFF'+‰AND.L…#$000000FF,D5‡recover�channel�number,‰BSR‡BIN_BIT�convert�chan�#�to�bit�map�in�D5"‰MOVE.L„D5,D0�stage�data�for�DOOFF‰BSR‡DOOFF�turn�off�channel‰POPALL‰RTE‰PAGEBIN_BIT:*$* Binary to bit-map conversion in D5*J*Produces a 1 in D5 corresponding to the value in D5 (in binary) up to 15.@*ˆFor�input�>�15�binary�the�resultant�pattern�in�D5�is�undefined*‰ALLOCATE‚BITMAP‰CLR.L…BITMAP(A7)‰ADD.W…#1,BITMAP(A7) LOOP…SET‡* ‰TST.W…D5‰BEQ‡BINBITX�exit�on�bit�found‰ROL.W…BITMAP(A7) ‰SUB‡#1,D5 ‰BRA‡LOOP BINBITXŒEQU‡*‰MOVE.W„BITMAP(A7),D5‰DEALOC„BITMAP‰RTSŠPAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block%*‰A3�=�address�of�RIO�parameter�block*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D0�=�RIO�error�code*I**************************************************************************NRMEXIT:>ŠMOVE.W�D0,CMDSTA(A3)†set�return�status�in�RIO�parameter�blockŠRTS—return�to�CMRŠPAGEJ****************************************************************************ˆKILR�(KILLER)*4*“Routine�called�to�handle�unrecoverable�conditions.**K****************************************************************************KILR: ‰TR0$.KILLERŠPAGEF***********************************************************************B* SUBROUTINE TO CHECK ADDRESS BO5 UNDARIES TO SEE IF ENTIRELY WITHIN*ƒCALLING�TASKS�ADDRESS�SPACE.*#*�ENTRY:ƒD5‚-�NO.�OF�BYTES�TO�CHECK*ŠD6‚-�68000�ADDRESS�(LOGICAL)*ŠA1‚-�TCB�ADDRESS*** EXEC ROUTINE#* REGISTERS USED: D0-D1,D3,D6/A0-A1**7*�EXIT:„D6�-�PHYSICAL�ADDRESS�OF�BUFFER�BASE�(IF�LEGAL)*ŠRETURN�TO�PC„FOR�GOOD�ADDRESS*”PC+2‚FOR�BAD�LENGTH*”PC+4‚FOR�BAD�ADDRESS*F*********************************************************************** IOHADRCK:%ŠBTSTƒ#0,D6‘Must�be�on�work�boundary.)ŠBNE.S‚IOHADR4�Branch�if�bad�buffer�base.ŠTST.L‚D5”Length�can't�be�zero.2ŠBEQ.S‚IOHADR8�Don't�go�to�logphy�with�zero�count. IOHADR2ƒEQU„*1ŠMOVE.L�TCBTST(A1),A0‰Address�of�task�seg.�table. ŠTR0$.LOGPHY.ŠBRA.S‚IOHADR8�Branch�for�good�address�return.0ŠBRA.S‚IOHADR6�Branch�for�bad�byte�count�return.(ŠTST.L‚D5”Was�an�entry�pointer�returned.#ŠBEQ.S‚IOHADR4�Branch�if�no�-�ERROR)ŠTST.B‚7(A0,D5)ŽIs�this�an�MMIO�segment�?ŠBNE.S‚IOHADR8�Yes,�OK.3IOHADR4ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.3IOHADR6ƒADD.L‚#2,(A7)�Adjust�PC�for�invalid�return.IOHADR8ƒRTSšReturn.ŠPAGEI***************************************************************************ˆGET�TCB�ROUTINE*)*’ENTRY:�A0�=�POINTER�TO�TASK�AND�SESSION***’EXEC�ROUTINE*’REGISTERS�USED:�D0-D1/A0-A1***’EXIT:�A0�=�TCB�ADRESS**˜RETURN�TO�PC„FOR�GOOD�TASK�SPECIFICATION!*¢PC+2‚FOR�BAD�TASK�SPECIFICATION**J***************************************************************************GETTCB: ŠTR0$.GETTCB&ŠBRA.S„GETT10ŽGood�task�specification.ŠNOPšBad�task�specification.&ŠADD.L„#2,(A7)�Bad�task�specification.GETT10„RTSšReturn.ŠPAGEJ**************************************************************************** INTERRUPT SSERVICE ROUTINE*?*ƒPURPOSE:‚HANDLE�THE�RIO�INTERRUPTS�AND�NOTIFY�THE�USER�OF�THE5*�INTERRUPTS.‚OPERATES�AT�HARDWARE�INTERRUPT�PRIORITY*�LEVEL.*1*ƒENTRY:‚JSR‚FROM�INTERRUPT�HANDLER�ROUTINE�-�CMR*‹A0�-�WORK�REGISTER *‹A1�=�SELF*‹A5�=�ADDRESS�OF�CCB*‹D0�=�WORK�REGISTER*5*ƒEXIT:‚RTS�-�BACK�TO�INTERRUPT�HANDLER�ROUTINE�-�CMR*C*ŠInterrupt�handler�must�pruserve�all�data�reg.'s�&�address�reg.'s.***ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P****ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT**?*‚Debounce�on�interrupt�added�9/13/82.‚Debounce�is�0�to�512�ms,9*‚encoded�in�bits�8-14�of�the�channel�configuration�word.I*‚The�scale�factor�for�debounce�time�is�4�ms�per�count�in�ch.�config.�wd.*F*---------------------------------------------------------------------*RIOINT:*<* Find RIO TABLE module (board) name which matches CCB name:*-ˆMOVEM.L„A0-A6/D1-D7,-(A7)„save�all�except�D0:ˆALLOCATEƒRIOTADR,CHANUM,CLAIMCHKƒallocate�local�variables/ˆCLR.L†CLAIMCHK(A7)…clear�interrupt�claim�check-ˆMOVE.L…RIOTBL,A2‰get�address�of�RIOTBL�to�A2 ˆCLR.L…D76ˆMOVE.B„RIONMAX(A2),D7…get�max�number�of�RIOID's�to�D7#ˆMOVE.L„CCBMNEM(A5),D0…get�ccb�name2IOHI011�EQU�*‚find�matching�RIOID�loop�entry�point*ˆMOVE.L„RIOID(A2),D3‡get�RIOID�for�staging'ŠCMP.LƒD3,D0Ždoes�CCB�name�match�RIOID?#ŠBEQ.SƒIOHI020Œbranch�on�name�match,ŠADDA.W‚RIOOFST,A2‰add�offset�to�next�RIOTBL#ŠSUB.Bƒ#1,D7Žtest�for�end�of�RIOTBL*ŠBMI…IOHIPXŠbranch�to�exit�if�id�not�found ŠBRA�IOHI011 IOHI020ƒEQU�**F*‚Found�matching�names,�now�get�number�of�interrupting�channel�(to�D2)2*‚and�clear�hardware�interrupt�flag�in�PIA�device.*%‰STORE…A2,RIOTADRŠsave�RIOTBL�address,‰MOVE.L„#$0C010000,D2‡init�para�fields�in�D2)‰BSR‡IOHICLR�clr�irq�&�get�int.�channel�#+‰STORE…D2,CHANUM‹save�chan.�#�&�return�code*>* Compute address of field in RIOTBL having user's TCB address* ŠCLR.L„D4!ŠMOVE.BƒD2,D4�get�channel‚to�D4.B)ŠCMP.B„#8,D4�channel�must�be�<�8�or�error'ŠBEQ.S„IOHIPXŒexit�on�channel�not�found1ŠADD.L„#1,CLAIMCHK(A7)ƒmark�interrupt�acknowledge2ŠMULU…#6,D4�point�to�data�field�assoc�with�channel5ŠADD†#RIONTRY,D4‡add�offset�to�1st�channel�data�fieldŠADD†#4,D4�add�in�size�of�RIOID-ŠMOVE.LƒRIOTBL,A2‰ge5 t�address�of�RIOTBL�to�A26ŠMOVE.L‚RIOTCB(A2,D4),A6„A6�now�has�user's�TCB�address*"*IF channel requires debounce THEN*3ŠMOVE.WƒRIOCNIF(A2,D4),D0ƒget�channel�configuration(ŠAND†#$7F00,D0‹select�debounce�time�data…IF.L†ŠTHEN*„DO;*ˆRequest�periodic�activation(CCB_adr,chan_#,debounce_time)6*ˆGenerate�channel�ID�=�CCB�address�+�channel�#�to�D2:**‰MOVE.L„A5,D7�copy�board�CCB�address�to�D7‰ADD.B…D2,D7�add�channel�number/‰MOVE.L„D7,D2�stage�channel�ID�for�period.�act..‰LEA‡DEBOUNCE(PC),A0…point�to�debounce�routine!‰CLR.L…D1’request�1�periodic�act.1‰MOVE.B„CCBPPRIO(A5),D1…set�priority�same�as�task&‰LSR‡#8,D0�position�debounce�time�data-‰MULU†#4,D0�multiply�by�debounce�delay�factor ‰MOVE.L„#0,A1*‰MOVE.W„D0,A1�stage�time�for�periodic�act..‰LINK†A6,#-(ALLREGS+4)…add�some�extra�room�(4)*I* NOTE: LINK has reserved space on the stack for all registers + 4 words.A*‡Now�I�can�do�MOVEM.L�to�the�stack�without�auto�inc�or�auto�dec.B*‡and�as�long�as�I�get�back�A6�unchanged,�UNLINK�A6�will�take�care+*‡of�adjusting�the�stack�pointer�correctly.*.‰MOVEM.LƒA0-A6/D0-D7,(A7)„save�all�reg.�values ‰TR0$.RQPA*/*‡IF�no�error�returned�from�per.�act.�req.�THEN*,‰BRA.S…DBACTOK�good�return�from�per.act.req.+‰BRA.S…DBACTNG�bad�return�from�per.act.req.*‡DO*DBACTOK‚EQU‡*‰Debounce�act.�req.�return�ok**ŠDisable�IRQ�on�this�channel.%*ŽStage�arguments�for�call�to�DODSABL*0‰MOVEM.Lƒ(A7),A0-A6/D0-D7„recall�register�values.‰MOVE.L„RIOTADR+4(A6),A4„recall�RIOTBL�address#‰AND‡#$000000FF,D2‡select�channel�#+‰BSR‡DODSABL�disable�IRQ.�note:�ck'�9/15/82*DBACTNG„EQU…*‰debounce�act.�req.�return�NG*ˆENDƒdisable�IRQ0‰MOVEM.Lƒ(A7),A0-A6/D0-D7„recall�register�values‰UNLK„A6*…END†debounce�setup�sequence†ELSE**…here�if�no�debounce�required*.‰LOAD†D2,CHANUM‹recall�channel�#�&�return�code‰BSR‡NOTIFYUSR†ENDI$IOHIPX„EQU�*‡'RIOINT'�procedure�exit+‰LOAD‚D0,CLAIMCHKŒget�interrupt�claim�check#‰ADD‡#16,A7Žrelease�local�variables0‰MOVEM.Lƒ(A7)+,A0-A6/D1-D7ƒrestore�all�except�D0+‰TST.L…D0’does�RIODRV�claim�this�interrupt?‰IF.L‚�THEN(‰ORˆ#1,SR�signal�CMR�'interrupt�handled'‰ELSE2‰AND‡#$FFFE,SR‹signal�CMR�'interrupt�not�from�RIO'‰ENDI‹RTS…PAGE NOTIFYUSR:*A*ˆnotify�user�by�means�of�que�event�or�wakeup�as�specified�in�the*ˆchannel�configuration�word.**„INPUT�PARAMETERS:'*’A2:�Address�of�channel�name�in�RIOTBL;*’D4:�Offset�from�channel�name�to�channel�data�field�(base) *™in�RIOTBL.*’A5:�Address�of�channel�CCB.ÁªA³;»4ÃLË*’A6:�User's�TCB�address#*’D2:�$0C01�**@ŠMOVE.WƒRIOCNIF(A2,D4),D0�get�channel�configuration�from�channel *¤configuration�table�in�RIOTBL.)ŠBTST…#3,D0�determine:�wake-up�or�q-event ‰IF…‰THEN**ˆDO*ˆEnqueue�event;�data�staging:*$*ƒD2�=�$0C01� *ƒD3�=�RIOID*ƒD4�=�Mem�mapped�I/O�address*ƒA6�=�User's�TCB�address*8ŒMOVE.LƒCCBCHB(A5),D4…get�mem.�mapped�I/O�address�stagedŒBSR�QUEVENT�enqueue�the�eventŒRTS˜and�return�to�caller*‰ELSE*DO%ŒMOVE.LƒA6,A0Žstage�users�TCB�address#ŒTR0$.WAKEUP�,�issue�wakeup�to�user*ENDŒENDIŒRTS™return�to�caller‰PAGE=*‚IOHICLR�determines�if�the�interrupt�is�for�this�RIO�module.E*‚If�the�interrupt�is�not�for�this�channel�D2�contains�'8'�on�return.C*‚If�the�interrupt�is�for�this�RIO�module,�the�interrupting�channelI*‚number�is�returned�in�D2‚The�interrupt�in�the�PIA�is�cleared�here�also.**‚Input�parameters:%*’A5:�Points�to�the�I/O�base�address.*‚Output�parameters:(*’D2:�Contains�interrupt�channel�number.* IOHICLR EQU *0ŠMOVE.L�CCBCHB(A5),A0ˆget�I/O�base�address�to�A08ŠBTST.Bƒ#0,PIA1ACR(A0)…is�channel�#0�set�for�interrupts?/ŠBEQ.S„IOHIO01Œbranch�if�not�set�-�check�chan�18ŠBTST.Bƒ#7,PIA1ACR(A0)…set�for�int6 errupt�-�is�there�one?(ŠBNE†IOHI021Œbranch�on�IRQ�found�on�ch�0$IOHIO01ƒADD�#1,D2“bump�channel�count5ŠBTST.Bƒ#3,PIA1ACR(A0)…is�chan.�1�set�for�interrupts?/ŠBEQ.S„IOHIO02Œbranch�if�not�set�-�check�chan�28ŠBTST.Bƒ#6,PIA1ACR(A0)…set�for�interrupt�-�is�there�one?*ŠBNE.S�IOHI021�branch�on�IRQ�found�on�ch�1$IOHIO02ƒADD�#1,D2“bump�channel�count4ŠBTST.B‚#0,PIA1BCR(A0)†is�chan�2�set�for�interrupts?*ŠBEQ.SƒIOHIO03�branch�if�no�-�check�chan�38ŠBTST.Bƒ#7,PIA1BCR(A0)…set�for�interrupt�-�is�there�one?*ŠBNE.S„IOHI022Œbranch�on�IRQ�found�on�ch�2$IOHIO03ƒADD‚#1,D2’bump�channel�count4ŠBTST.B‚#3,PIA1BCR(A0)†is�chan�3�set�for�interrupts?*ŠBEQ.SƒIOHIO04�branch�if�no�-�check�chan�48ŠBTST.B‚#6,PIA1BCR(A0)†set�for�interrupt�-�is�there�one?*ŠBNE.S‚IOHI022Žbranch�on�IRQ�found�on�ch�3&IOHIO04ƒADD�#1,D2“bump�channel�counter4ŠBTST.Bƒ#0,PIA2ACR(A0)…is�chan�4�set�for�interrupts?*ŠBEQ.S„IOHIO05Œbranch�if�no�-�check�chan�58ŠBTST.Bƒ#7,PIA2ACR(A0)…set�for�interrupt�-�is�there�one?*ŠBNE.S�IOHI023�branch�on�IRQ�found�on�ch�4&IOHIO05ƒADD�#1,D2“bump�channel�counter4ŠBTST.B‚#3,PIA2ACR(A0)†is�chan�5�set�for�interrupts?-ŠBEQ.SƒIOHIO06�branch�if�no�-�go�check�chan�68ŠBTST.B‚#6,PIA2ACR(A0)†set�for�interrupt�-�is�there�one?*ŠBNE.S�IOHI023�branch�on�IRQ�found‚on�ch�5&IOHIO06ƒADD�#1,D2“bump�channel�counter4ŠBTST.B‚#0,PIA2BCR(A0)†is�chan�6�set�for�interrupts?-ŠBEQ.S„IOHIO07Œbranch�if�no�-�go�check�chan�78ŠBTST.B‚#7,PIA2BCR(A0)†set�for�interrupt�-�is�there�one?*ŠBNE.S�IOHI024�branch�on�IRQ�found‚on�ch�6&IOHIO07ƒADD�#1,D2“bump�channel�counter4ŠBTST.B‚#3,PIA2BCR(A0)†is�chan�7�set�for�interrupts?2ŠBEQ.SƒIOHIONO�branch�if�no�-this�inter�not�for�me8ŠBTST.B‚#6,PIA2BCR(A0)†set�for�interrupt�-�is�there�one?*ŠBNE.S�IOHI024�branch�on�IRQ�found‚on�ch�77IOHIONOƒADD�#1,D2“set�chan�#�=�8�=�interrupt�not�for�me ŠRTS™return�to�interrupt�handler5IOHI021ƒTST.B„PIA1ADR(A0)ˆreading�data�reg�clears�IRQŠRTS™and�return-IOHI022ƒTST.BƒPIA1BDR(A0)‰clear�the�interruptŠRTS™and�return(IOHI023ƒTST.BƒPIA2ADR(A0)‰clear�IRQ�flagŠRTS™and�return(IOHI024ƒTST.BƒPIA2BDR(A0)‰clear�IRQ�flag‰RTSšand�return‹PAGE'*‹DEBOUNCE�-�interrupt�debounce�routine3*‹Control�returns�here�when�the�periodic�activation*‹request�time�expires.*ƒInput�parameters:**’D1:�CCB�address�+�channel�#�(in�ls�byte)* DEBOUNCE:‰PUSHALL�save�all�registers*F*‚IF�(((channel�config�=�rising�edge�IRQ)�AND�(channel�state�=�up))�ORH*†((channel�config�=�falling�edge�IRQ)�AND�(channel�state�=�down)))�THEN*0*…Compute�offset�for�this�channel�in�the�RIOTBL:*5‰MOVE.L„#$0C010000,D2‡setup�data�fileds�for�NOTIFYUSR!‰CLR.L…D3’clear�working�registers ‰CLR.L…D4’. ‰CLR.L…D6’.%‰MOVE.B„D1,D4�extract�channel�#�to�D46‰MOVE.B„D4,D2�complete�stage�of�chan�data�to�NOTIFYUSR*‰MOVE.B„D4,D3�save�copy�of�channel�#�in�D35‰MULU†#6,D4�point�to�data�field�for�channel�in�RIOTBL7‰ADD‡#RIONTRY+RIOCNIF,D4�add�offset�to�1st�channel�data*'*ˆGet�channel�I/O�address�base�from�CCB*'‰AND‡#$FFFFFF00,D1‡clear�ls�byte�in�CCB#‰MOVE.L„D1,A5�put�CCB�address�on�A5*‰MOVE.L„CCBCHB(A5),A1‡get�I/O�base�address*+*ˆFind�RIOTBL�data�section�for�this�channel*+‰MOVE.L„RIOTBL,A2‹get�address�of�the�RIOTBL ‰CLR.L…D70‰MOVE.L„CCBMNEM(A5),D0†get�channel�name�from�CCB1‰MOVE.B„RIONMAX(A2),D6†get�max�number�of�RIOTBL's LOOP…SET‡*.‰MOVE.L„RIOID(A2),D5ˆget�channel�name�from�CCB%‰CMP.L…D5,D0�channel�name�=�CCB�name? ‰BEQ.S…FOUND13‰ADD.W…RIOOFST,A2Šbump�to�next�RIOID�(channel�name)!‰SUB‡#1,D6�decrement�loop�counter*‰BEQ.S…DBERR�err�if�channel�name�not�found ‰BRA�LOOPFOUND1:/‰MOVE.L„RIOTCB(A2,D4),A6†get�user's�TCB�address3‰BTST†#2,RIOCNIF+1(A2,D4)ƒconfig�=�rising�edge�IRQ? ‰IF…‡THEN*%* DO if set for rising edge interrupt*-‰BTST†D3,PIA1ADR(A1)†channel�status�=�hi�now? �IF‚ƒTHEN*9*‰DO‚notify�user�if�still�on�rising�edge�-�good�interrupt*ŒPUSHALL”save�all�regsŒBSR„NOTIFYUSRŒPOPALL•restor�all�regs**‰END„of�interrupt�on�rising�edge�sequenceˆENDIˆELSE*?*„Else�the�channel�configurati6 on�is�for�falling�edge�interrupt.!*†DO‚see�if�still�on�falling�edge*-‰BTST†D3,PIA1ADR(A1)†channel�status�=�lo�now? †IF‚ƒTHEN*5*†Channel�status�=�lo‚-�notify�user�of�good�interrupt*†DO‰PUSHALL‰BSR�NOTIFYUSR‰POPALL"*†END‚of�falling�edge�IRQ�sequence‡ENDI**‚ENDƒof�debounce�sequence*ƒENDI*"*ˆEnable�IRQ�on�debounced�channel:***BEGIN�stage�parameters�for�call�to�DOENBL*%‰AND.L…#$000000FF,D2‡select�channel�#&‰MOVE.L„A2,A4�get�RIOTBL�address�to�A4)‰CLR.L…D1’set�debounce�data�field�to�null.‰BSR�DOENBL”invoke�routine�to�enable�interrupt*END*/DBERR�EQU�*‚debounce�err;�riotbl�name�not�found+‰POPALLŽrestore�all�registers�before�return‰RTE›return�to�O.S.‰PAGE*H*‚QUEVENT‚enqueue's�event�to�driving�task�using�data�staged�in�registers *‹as�follows:**‹A6�=�user's�TCB�address&*‹D2�=�$0C01�*‹D3�=�RIOID‚(module�name)*‹D4�=�mem�mapped�I/O�address** QUEVENT EQU *‹PUSHALL”push�all�regs"‹MOVE.L…A6,A0Žstage�user's�address ‹TR0$.QEVNTI)‹BRA.SƒQUEVNTOKŒgood�return�for�que�event'‹BRA.SƒQUEVNTERŒbad�return�from�queventQUEVNTOK EQU *‹POPALL•restore�all�regs‹RTS QUEVNTER:(‹BRA�QUEVNTOK�put�a�break�here�for�debug*‰ENDééééé=/* =/*†RIOLIB.AF=/*7=/* Chain file to assemble FORTRAN-callable subroutines%=/* to interface with the RIO driver.=/*:=/* If no output argument is specified for the listing the(=/* chain file will default to RIOLIB.LS=/*=/IFC \1ƒ=ARG�RIOLIB.LS=/ENDIF=/*=ASM RIOLIB.SA,RIOLIB.RO,\1;R=/*{ Included files are:=/*ƒ--�none�--=/*}=/*=ENDééé7 éééÓFTRIO…IDNTƒ1,0�RIO�subroutines**‰FORTRAN�callable�subroutines*‰for�RIO�driver�calls*$*‰CALL�RIOCMD(rio_id,param_blk_addr)*‰where�RIOCMD�may�be:*)*‰CALL�RIOPEN(rio_id,param_blk_addr)…open**‰CALL�RIOCLS(rio_id,param_blk_addr)…close3*‰CALL�RIOOUT(rio_id,param_blk_addr)…output�latched/*‰CALL�RIOOFF(rio_id,param_blk_addr)…output�off+*‰CALL�RIOSTA(rio_id,param_blk_addr)…status6*‰CALL�RIOENB(rio_id,param_blk_addr)„enable�interrupts7*‰CALL�RIODSB(rio_id,param_blk_addr)„disable�interrupts2*‰CALL�RIOPLS(rio_id,param_blk_addr)„output�pulsed*,*‰All�arguments�for�the�calls�are�identical.7*‰The�contents�of�the�param_blk�for�each�call�is�unique*‰to�the�call.*6*‰All�the�command�subroutines�call�a�common�subroutine3*‰RIOSET�to�build�the�initiate�I/O�parameter�block.**‰STACK�FOR�ALL�CALLS:*7*‰deepest�stack:�(stack�address�stays�at�RIOSET�return)0*˜command�codeƒ2�bytes�(initiate�I/O�param.�blk) *˜n/aŒ2�bytes*˜rio_id‰4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes *˜n/aŒ4�bytes,*˜command�addrƒ4�bytes�(rio�command�address)**˜command�lng„2�bytes�(rio�command�length)-*˜RIOSET�return‚4�bytes�deepest�stack�address *˜A3�4�bytes *˜A2�4�bytes *˜A1�4�bytes *˜D0�4�bytes*‰entry�stack:ƒreturn‰4�bytes*˜^param_blk_adr�4�bytes*˜^rio-idˆ4�bytes* ŠSECTION�9!ŠXDEFƒRIOPEN,RIOCLS,RIOOUT,RIOOFF!ŠXDEFƒRIOSTA,RIOENB,RIODSB,RIOPLS*$*‰CALL�RIOPEN(rio_id,param_blk_addr)*‰open�and�configure�channels*1RIOPEN„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers3ŠBSR„RIOSET�set-up�the�initiate�I/O�parameter�block)ŠMOVE.L�#1,(A2)Œset�the�open�command�codeRIOPN00ƒCLR.L‚D0‘clear�for�use'ŠMOVE.W�4(A2),D0‹get�number�of�channelsŠASL.L‚#2,D0Žmultiply�by�4.RIOPN05ƒADD.L‚#6,D0Žadd�in�the�6�byte�overhead-RIOPN10ƒMOVE.W�D0,(A1)Œset�the�command�length-ŠMOVE.L�A3,A0ŽTRAP�#1�parameter�block�address#ŠMOVE.L�#60,D0�CMR�directive�numberŠTRAPƒ#1‘call�RMS68K'ŠMOVE.W�D0,(A2)Œset�the�returned�status)ŠMOVEM.L�(A7)+,D0/A1-A3„restore�registers!ŠMOVE.L�(A7)+,A0‹put�return�in�A0ÜAå8í ŠLEA„8(A7),A7‹clean�up�the�stackŠJMP„(A0)�return�to�user*$*‰CALL�RIOCLS(rio_id,param_blk_addr)"*‰close�all�channels�for�this�user*1RIOCLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block*ŠMOVE.L�#2,(A2)Œset�the�close�command�code&ŠMOVE.W�#4,D0ŽRIO�close�command�lengthŠBRA„RIOPN10Œgo�do�the�CMR�call*$*‰CALL�RIOOUT(rio_id,param_blk_addr)'*‰activate�output�on�requested�channels*1RIOOUT„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#3,(A2)Œset�the�output�command�code*RIOUT10ƒMOVE.Wƒ#6,D0Œset�up�command�lengthŠBRA„RIOPN10Œgo�do�the�CMR�call*$*‰CALL�RIOOFF(rio_id,param_blk_addr))*‰deactivate�output�on�specified�cha7 nnels*1RIOOFF„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block/ŠMOVE.L�#4,(A2)Œset�the�output�off�command�code4ŠBRA„RIOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�RIOSTA(rio_id,param_blk_addr))*‰read�input�status�on�specified�channels*1RIOSTA„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#5,(A2)Œset�the�status�command�code4ŠBRA„RIOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�RIOENB(rio_id,param_blk_addr).*‰enable�interrpts�on�specified�input�channels*1RIOENB„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block+ŠMOVE.L�#6,(A2)Œset�the�enable�command�code4ŠBRA„RIOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�RIODSB(rio_id,param_blk_addr)0*‰disable�interrupts�on�specified�input�channels*1RIODSB„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block,ŠMOVE.L�#7,(A2)Œset�the�disable�command�code4ŠBRA„RIOUT10Œgo�set�command�length�&�do�the�CMR�call*$*‰CALL�RIOPLS(rio_id,param_blk_addr)>*‰activate�output�for�x#�of�milliseconds�on�specified�channels*1RIOPLS„MOVEM.L�D0/A1-A3,-(A7)„save�some�registers5ŠBSR.S‚RIOSET�set-up�the�initiate�I/O�parameter�block2ŠMOVE.L�#8,(A2)Œset�the�pulsed�output�command�codeŠCLR.L‚D0‘clear�for�use,ŠMOVE.W�4(A2),D0‹get�specified�#�of�channelsŠASL.L‚#2,D0Žmultiply�by�6ŠADD.W‚4(A2),D04ŠBRA„RIOPN05Œgo�set�command�length�&�do�the�CMR�callŠPAGE*4*‰RIOSET�set�up�the�CMR�initiate�I/O�parameter�block,*‰returns:ƒA1=address�for�RIO�command�length(*”A2=RIO�command�parameter�block�address)*”A3=initiate�I/O�parameter�block�address*(RIOSET„CLR.W‚-2(A7)�clear�command�length-ŠLEA„-2(A7),A1Šsave�address�of�command�length$ŠMOVE.L�24(A7),A0Šget�param_blk_addr%ŠMOVE.L�A0,-6(A7)Šsave�param_blk_addr,ŠMOVE.L�A0,A2Žsave�param_blk_addr�for�returnŠCLR.L‚-10(A7)Œnot�usedŠCLR.L‚-14(A7)Œnot�usedŠCLR.L‚-18(A7)Œnot�usedŠMOVE.L�28(A7),A0Šget�^rio_idŠMOVE.L�(A0),-22(A7)‡get�rio_idŠCLR.W‚-24(A7)Œnot�used0ŠMOVE.W�#$0700,-26(A7)…initiate�I/O�command�code4ŠLEA„-26(A7),A3‰initiate�I/O�parameter�block�addressŠRTS—return�to�callerŠENDééé‰SPC�10!*†---†---…STANDARDƒMACROS…---…---*H*Allocate macro allocates local storage as long words on the stack,(A7).,*Up to 6 variables may be allocated by name.C*These variables may then be referred to by name offset to stack orH*they may be stored to (by macro STORE) and loaded from (by macro LOAD).*O*Prior to exit, the variables must be de-allocated by invocation of DEALLOCATE. ALLOCATE MACRO*B*Allocate reserves storage on the stack for local named variables,8*‚which�are�referred�to�as�an�offset�from�stack�pointer.\1 SET 2‰IFGT�(NARG-1)\2 SET 6‰ENDC‰IFGT�(NARG-2) \3 SET 10‰ENDC‰IFGT�(NARG-3) \4 SET 14‰ENDC‰IFGT�(NARG-4) \5 SET 18‰ENDC‰IFGT�(NARG-5) \6 SET 22‰ENDC*ƒSUB.Lƒ#(NARG*4)+4,A78 *ƒENDM*B*DEALLOCATE�MACRO‚has�to�be�named�DEALOC�to�overcome�assembler�bug DEALOC‚MACRO*>* Deallocate removes storage for local variables on the stack.ƒADD.L‚#(NARG*4)+4,A7*ƒENDMI*LOAD macro allows loading a register from local storage named variables. *The�syntax�is:‚LOAD�Rn,VARNAME.9*The storage is DYNAMICALLY ALLOCATED by macro 'ALLOCATE'* LOAD‚MACRO*‰MOVE.L„\2(A7),\1‰ENDM*H*STORE macro allows storing a register to local storage named variables.!*The�syntax�is:‚STORE�Rn,VARNAME.?*The local storage is DYNAMICALLY ALLOCATED by macro 'ALLOCATE'* STORE MACRO*‰MOVE.L„\1,\2(A7)‰ENDM*‰SPC�5PUSHPOINTŠMACRO‰MOVEM.LƒA0-A6,-(A7)‰ENDM*POP_POINTŠMACRO‰MOVEM.Lƒ(A7)+,A0-A6‰ENDM* PUSHALLŒMACRO‰MOVEM.LƒA0-A6/D0-D7,-(A7)‰ENDM* POPALLƒMACRO‰MOVEM.Lƒ(A7)+,A0-A6/D0-D7‰ENDM*4ALLREGS‚EQU‡68ˆSpace�for�all�the�reg.'s�in�the�stack** *NOW USE THEM *MACTEST:* *ˆPUSHPOINT *ˆPUSHALL&*ˆALLOCATE�COUNT,POINT,CHAR,VAL,MURPHY*ˆMOVE.L„#12345,D1*ˆSTORE†D1,COUNT*ˆLOAD‡D2,COUNT(*ˆDEALLOCATE�COUNT,POINT,CHAR,VAL,MURPHY*ˆPOPALL *ˆPOP_POINT*ˆRTS*ˆEND*‰PAGEõ`**ˆ&.M605MEM.AG*J*==========================================================================*‚Code�added�to�allocate�memory�for�table�used�by�DAC�driver.6*‚This�code�is�assembled�and�linked�in�at�sysgen�time.*>*‚06/01/84‚psg‚Changed�conditional�name�for�new�sysgen�method.*‚01/11/84‚bwn*K*==========================================================================‰IFNE„\NVME6055T0PAGAL‚EQU…4‘Page�allocation�directive�#�for�Trap�0.6‰XREF„DACTBLŒSYSPAR�location�containing�DACTBL�address ‰XDEF„M605MEM%‰INCLUDE�&.M605DRV.EQ†DAC�equate�file* ‰SECTIONƒ8 M605MEM‚EQU‡*>DCMEM1ƒMOVE.L�#\NVME605,D2‡get�number�of�DAC�modules�in�system0‰BEQ.S‚NODACS�branch�if�no�DAC�modules�on�system<‰MOVE.L�#\NU605,D3‰get�number�of�interrupt�levels�per�module$‰MOVE.L�D2,D4Žsave�number�of�modules!‰MULUƒD3,D4Žget�number�of�DAC-IDs-‰MULUƒ#DACIDLNG,D4‡get�#�of�bytes�for�DAC-IDs%‰ADD.L‚#DACNTRY,D4ˆadd�in�header�size)‰MULUƒ#IOLNG,D2‰get�#�of�bytes�for�IO�map,‰ADD.L‚D4,D2Ž#�of�bytes�needed�for�DAC�table‰MOVE.L�D2,D5Žsave�#�of�bytes'‰ADD.L‚#255,D2Œround�up�to�page�boundry‰ASR.L‚#8,D2Ž#�of�pages�needed'‰BMI.S‚DACERR�branch�if�negative,�error)‰MOVE.L�#0,A0Žclear�for�allocating�memory)‰MOVE.W�D2,A0Žnumber�of�pages�to�allocate-‰MOVE.L�#T0PAGAL,D0ˆpage�allocation�directive"‰TRAPƒ#0‘call�RMS68K�to�get�memory"‰BRA.S‚DACOKŽbranch�if�good�return1DACERRƒMOVE.L�#32,D0�fatal�error�-�go�stop�system‰TRAPƒ#08DACOK„MOVE.L�#'!DAC',DACEYE(A0)�set�DAC�table�eyecatcher)‰MOVE.W�D5,DACLNG(A0)†#�of�bytes�in�table5‰MOVE.W�#DACNTRY,DACOFST(A0)�offset�to�DAC-ID�entries&‰MOVE.W�D4,DACIO(A0)†offset�to�IO�maps'‰CLR.B‚DACNAL(A0)‰no�DACs�allocated�yet.‰MOVE.L�#\NVME605,D4‡get�number�of�DAC�modules-‰MULUƒ#\NU605,D4‰get�number�of�DAC-ID�entries-‰MOVE.B�D4,DACNMAX(A0)…max�number�of�DAC-ID's6‰MOVE.L�A0,DACTBLŠsave�table�address�in�system�params.0‰LEA„DACID(A0),A0‡start�address�of�table�entries/‰SUB.W‚#DACNTRY,D5ˆnumber�of�bytes�to�set�to�FF‰ASR.W‚#1,D5Žnumber�of�wordsþ43‰MOVE.W�#$FFFF,D4Šstore�this�in�all�entry�locations&DACCLRƒMOVE.W�D4,(A0)+‹set�the�entries‰SUB.W‚#1,D5Ždecrement�counter ‰BNE.S‚DACCLR�branch�if�not�done NODACSƒEQU„*‰ENDC*‰END8 ééééééé**ˆ&.M610MEM.AG*„IFNEƒ\NVME610+\NVME620 ŠNOFORMATŠPAGE0PAGAL…EQU„4ŽRMS68K�PAGAL�Trap�0�directive�number3KILLER„EQU„32�RMS68K�KILLER�Trap�0�directive�numberŠOPTƒCRE N*******************************************************************************:*‹Interrupt�Processing�Queue�Allocation�and�Initialization+*�for�the�Input�Module�(VME�610/620)�Driver*M*ƒThis�section�of�code�allocates�memory�for�the�Interrupt�Queue�Control�TableM* and the Interrupt Processing Queue used by the Input Module Driver. First aO* page of memory is allocated for the control table and the base address of theJ* table is stored in the INPTBL field of SYSPAR for later retrieval by theN* drivers initialization routine. The table is then initialized and the memoryO* required for the Interrupt Processing Queue is calculated and allocated basedJ* on the SYSGEN parameter M610QSIZ. If all of the required pages of memoryO* cannot be allocated, RMS68K routine KILLER is called to force a system crash.*>*ƒThis�code�is�linked�into�the‚System�Initializer�as�describedK* in the SYSgen instructions for the driver. In the following code, symbolsM* preceeded by a backslash '\' character are user specified SYSgen parametersK* that are replaced with numeric values by the SYSgen SUBS command prior toO* assembly of this source. The parameters are assumed to have been validated inA* in a separate assembly performed earlier in the SYSgen process.*O*******************************************************************************ŠSPC„25ŠXREFƒINPTBL�This�symbol�is�an�address�within�SYSPAR. ŠXDEFƒM610MEMŠSPC„2 ŠSECTION�8ŠSPC„28M610QSIZ‚EQU„\M610QSIZ�This�is�the�size�of�the�Interrupt&*£Processing�Queue�in�terms�of�maximum,*£number�of�entries�the�queue�is�to�contain.ŠSPC„2ŠINCLUDE‚&.BAB.EQ*‰INCLUDE‚&.BAB.EQŠINCLUDE‚&.M610INTQ.EQ*‰INCLUDE‚&.M610INTQ.EQ ŠSECTION‚8ŠSPC„2 M610MEM‚EQU‡*9INPMEM„CLR.L‚D0“Clear�all�registers�to�be�used�in�calling27 9 3ŠMOVE.L�D0,A0Žthe�RMS68K�memory�allocation�routine. ŠMOVE.L�D0,A1 ŠMOVE.L�D0,A6ŠSPC„22ŠADD.W‚#1,A0�Call�RMS68K�routine�PAGAL�to�allocate9ŠMOVE.B�#PAGAL,D0Š256�bytes�(1�page)�of�memory�for�global*ŠTRAPƒ#0‘variable�storage.�If�no�memory�is7ŠBRA.S‚INPM010Œavailable,�call�RMS68K�routine�KILLER�to!ŠBSR.S‚INPMKILL‹crash�the�system.ŠSPC„2>INPM010ƒMOVE.L�A0,INPTBLŒSave�the�global�variable�area�address3ŠMOVE.L�A0,A4Žreturned�by�PAGAL�in�the�input�driver'*£table�pointer�(INPTBL)�within�SYSPAR.-*£Make�a�permanent�copy�of�the�address�in�A3.ŠSPC„24ŠMOVE.W�#63,D0�Clear�the�global�variable�area�to�allINPM020ƒCLR.L‚(A0)+Žzeros.ŠDBRAƒD0,INPM020ŠPAGEI*ƒThe�following�code�uses�the�Interrupt�Queue�Control�Table�and�allocates* memory for the queue.ŠSPC„24INPM050ƒCLR.L‚D1’Clear�D1�for�use�as�work�register�.ŠSPC„28ŠMOVE.W�#M610QSIZ,D5‰Load�the�number�of�entries�that�the(*£Interrupt�Queue�is�to�contain�into�D5.ŠSPC„2<ŠMOVE.L�#'IQCT',QID(A4)†Initialize�the�ascii�ID�field�in�the(*£Interrupt�Queue�Control�Table�with�the**£mnemonic�'IQCT'.�This�mnemonic�serves�as-*£serves�as�a�visual�aide�in�analysing�memory*£dumps�for�debugging.ŠSPC„28ŠMULUƒ#IQENTLN,D5ŠCalculate�the�queue�length�in�bytes�by**£multiplying�the�number�of�entries�in�the"*£queue�by�the�queue�entry�length.ŠSPC„22ŠTST.B‚D5“Calculate�the�minimum�number�of�256�byte7ŠBEQ.S‚INPM055Œmemory�pages�necessary�to�accomodate�the1ŠADD.W‚#256,D5Œspecified�number�of�queue�entries.INPM055ƒLSR.W‚#8,D5ŠSPC„23ŠMOVE.W�#15,D0�Calculate�the�bit�number�of�the�most=INPM057ƒLSL.W‚#1,D5Žsignificant�bit�of�the�number�of�pages�to ŠDBCSƒD0,INPM057‰allocate�in�D5.ŠSPC„2/ŠBEQ.S‚INPM058ŽIf�bits�other�than�just�the�most6ŠADD.W‚#1,D0Žsignificant�bit�of�the�number�of�pages�is'*£set,�increment�the�number�of�the�most-*£significant�bit�to�the�next�higher�power�of*£two.ŠSPC„27INPM058ƒCLR.L‚D5“Set�the�number�of�pages�to�allocate�to6ŠBSETƒD0,D5Žthe�lowest�power�of�two�that�will�hold�the$*£requested�number�of�queue�entries.ŠSPC„2=INPM060ƒMOVE.L�D5,A0�Load�the�number�of�pages�to�be�allocated:ŠMOVE.L�#PAGAL,D0Šinto�A0�and�call�RMS68K�routine�PAGAL�to2ŠTRAPƒ#0‘obtain�the�memory.�If�the�required�amount6ŠBRA.S‚INPM070Œof�memory�is�not�available,�call�RMS68K>INPMKILL‚MOVE.L�#KILLER,D0‰routine�KILLER�to�crash�the�system.ŠTRAPƒ#0ŠSPC„2?INPM070ƒMOVE.L�A0,QPTR(A4)ŠStore�the�interrupt�processing�queue**£base�address�in�the�queue�control�table.ŠSPC„20ŠASL.W‚#8,D5�Convert�the�length�of�the�interrupt5ŠSUB.W‚#1,D5Žqueue�in�256�byte�pages�to�the�length�in>ŠMOVE.W�D5,QWAMSK(A4)†bytes.�Form�the�queue�wraparound�mask�by)*£decrementing�the�queue�length�and�store&*£the�mask�in�the�queue�control�entry.ŠSPC„2K*ƒThis�is�the�end�of�the�Input�Module�Driver�system�initialization�routine.*ŠFORMAT„ENDC‰ENDéééé9 **ˆ&.M615MEM.AG*J*==========================================================================*‚Code�added�to�allocate�memory�for�table�used�by�ACO�driver.H*‚This�code�is�assembled�and�linked�into�the�approprate�initializer�file*‚at�SYSGEN�time.*K*==========================================================================‰IFNE„\NVME6155T0PAGAL‚EQU…4‹Page�allocation�directive�#�for�Trap�0.6‰XREF„ACOTBL…SYSPAR�location�containing�ACOTBL�address ‰XDEF„M615MEM*&*ˆINCLUDE�&.M615DRV.EQ…ACO�equate�file%‰INCLUDE�&.M615DRV.EQ…ACO�equate�file* ‰SECTIONƒ8 M615MEM‚EQU‡*HACMEM1ƒMOVE.L�#\NVME615,D2�(NVME615)�get�number�of�ACO�modules�in�system0‰BEQ.S‚NOACOS�branch�if�no�ACO�modules�on�system?‰MOVE.L�#\NU615,D3‰(NU615)get�number�of�interrupt�levels/module$‰MOVE.L�D2,D4Žsave�number�of�modules!‰MULUƒD3,D4Žget�number�of�ACO-IDs-‰MULUƒ#ACOIDLNG,D4‡get�#�of�bytes�for�ACO-IDs%‰ADD.L‚#ACONTRY,D4ˆadd�in�header�size)‰MULUƒ#IOLNG,D2‰get�#�of�bytes�for�IO�map,‰ADD.L‚D4,D2Ž#�of�bytes�needed�for�ACO�table‰MOVE.L�D2,D5Žsave�#�of�bytes'‰ADD.L‚#255,D2Œround�up�to�page�boundry‰ASR.L‚#8,D2Ž#�of�pages�needed'‰BMI.S‚ACOERR�branch�if�negative,�error)‰MOVE.L�#0,A0Žclear�for�allocating�memory)‰MOVE.W�D2,A0Žnumber�of�pages�to�allocate-‰MOVE.L�#T0PAGAL,D0ˆpage�allocation�directive"‰TRAPƒ#0‘call�RMS68K�to�get�memory"‰BRA.S‚ACOOKŽbranch�if�good�return1ACOERRƒMOVE.L�#32,A0�fatal�error�-�go�stop�system‰TRAPƒ#08ACOOK„MOVE.L�#'!ACO',ACOEYE(A0)�set�ACO�table�eyecatcher)‰MOVE.W�D5,ACOLNG(A0)†#�of�bytes�in�table5‰MOVE.W�#ACONTRY,ACOOFST(A0)�offset�to�ACO-ID�entries&‰MOVE.W�D4,ACOIO(A0)‡offset�to�IO�maps'‰CLR.B‚ACONAL(A0)‰no�ACOs�allocated�yet8‰MOVE.L�#\NVME615,D4ƒ(NVME615)�get�number�of�ACO�modules5‰MULUƒ#\NU615,D4‰(NU615)�get�number�of�ACO-ID�entries-‰MOVE.B�D4,ACONMAX(A0)…max�number�of�ACO-ID's6‰MOVE.L�A0,ACOTBLŠsave�table�address�in�system�params.0‰LEA„ACOID(A0),A0‡start�address�of�table�entries/‰SUB.W‚#ACONTRY,D5ˆnumber�of�bytes�to�set�to�FF‰ASR.W‚#1,D5Žnumber�of�words(31 3‰MOVE.W�#$FFFF,D4Šstore�this�in�all�entry�locations&ACOCLRƒMOVE.W�D4,(A0)+‹set�the�entries‰SUB.W‚#1,D5Ždecrement�counter ‰BNE.S‚ACOCLR�branch�if�not�done NOACOSƒEQU„*‰ENDC**‰END éééééé: é**ˆ&.M625MEM.AG*J*=========================================================================*A*‚Code�added�to�allocate�memory�for�table�used�by�MVME625�driver.7*‚This�code�is�assembled�and�linked�during�SYSGEN�time.*K*==========================================================================‰IFNE„\NVME6255T0PAGAL‚EQU…4‹Page�allocation�directive�#�for�Trap�0.6‰XREF„DCOTBL…SYSPAR�location�containing�DCOTBL�address ‰XDEF„M625MEM&*ˆINCLUDE�&.M625DRV.EQ†DCO�equate�file%‰INCLUDE�&.M625DRV.EQ†DCO�equate�file* ‰SECTION�8 M625MEM‚EQU‡*>DCMEM1ƒMOVE.L�#\NVME625,D2‡get�number�of�DCO�modules�in�system0‰BEQ.S‚NODCOS�branch�if�no�DCO�modules�on�system,‰MOVE.L�#\NU625,D3‰get�number�of�user/boards$‰MOVE.L�D2,D4Žsave�number�of�modules!‰MULUƒD3,D4Žget�number�of�DCO-IDs-‰MULUƒ#DCOIDLNG,D4‡get�#�of�bytes�for�DCO-IDs%‰ADD.L‚#DCONTRY,D4ˆadd�in�header�size)‰MULUƒ#IOLNG,D2‰get�#�of�bytes�for�IO�map,‰ADD.L‚D4,D2Ž#�of�bytes�needed�for�DCO�table‰MOVE.L�D2,D5Žsave�#�of�bytes'‰ADD.L‚#255,D2Œround�up�to�page�boundry‰ASR.L‚#8,D2Ž#�of�pages�needed'‰BMI.S‚DCOERR�branch�if�negative,�error)‰MOVE.L�#0,A0Žclear�for�allocating�memory)‰MOVE.W�D2,A0Žnumber�of�pages�to�allocate-‰MOVE.L�#T0PAGAL,D0ˆpage�allocation�directive"‰TRAPƒ#0‘call�RMS68K�to�get�memory"‰BRA.S‚DCOOKŽbranch�if�good�return1DCOERRƒMOVE.L�#32,A0�fatal�error�-�go�stop�system‰TRAPƒ#08DCOOK„MOVE.L�#'!DCO',DCOEYE(A0)�set�DCO�table�eyecatcher)‰MOVE.W�D5,DCOLNG(A0)†#�of�bytes�in�table5‰MOVE.W�#DCONTRY,DCOOFST(A0)�offset�to�DCO-ID�entries&‰MOVE.W�D4,DCOIO(A0)†offset�to�IO�maps'‰CLR.B‚DCONAL(A0)‰no�DCOs�allocated�yet.‰MOVE.L�#\NVME625,D4‡get�number�of�DCO�modules-‰MULUƒ#\NU625,D4‰get�number�of�DCO-ID�entries-‰MOVE.B�D4,DCONMAX(A0)…max�number�of�DCO-ID's6‰MOVE.L�A0,DCOTBLŠsave�table�address�in�system�params.0‰LEA„DCOID(A0),A0‡start�address�of�table�entries/‰SUB.W‚#DCONTRY,D5ˆnumber�of�bytes�to�set�to�FF‰ASR.W‚#1,D5Žnumber�of�words3‰MOVE.W�#$FFFF,D4Šstore�this�in�all�entry�locations93B&DCOCLRƒMOVE.W�D4,(A0)+‹set�the�entries‰SUB.W‚#1,D5Ždecrement�counter ‰BNE.S‚DCOCLR�branch�if�not�done NODCOSƒEQU„*‰ENDC*‰ENDééééé: éé* *ˆ&.IOCINT.AG*F***********************************************************************#*�IOCINT�I/O�CHANNEL�CCB�ALLOCATION*$*�COPYRIGHTED�1982�BY�MOTOROLA,�INC.*F************************************************************************�PROGRAM�NAME:‚IOCINT*D*�REV.‚1.00‚6/14/82ƒ(RONI�WOOD)�-�ALLOCATE�ALL�CCB'S�FOR�I/O�CHANNEL*¥DEVICE�DRIVERS.*�SUPPORT�TABLES:‚CHANNEL�CONTROL�BLOCKS�(CCB)*’DEVICE�CONTROL�BLOCKS�(DCB)*F**********************************************************************‡NOLIST‡INCLUDE�&.TR1.EQ‡INCLUDE�&.EXE.EQ‡INCLUDE�&.LV5.EQ‡LIST*†INCLUDE�&.TR1.EQ*†INCLUDE�&.EXE.EQ*†INCLUDE�&.LV5.EQ*‡INCLUDE�MACRO.DCB.SI*†INCLUDE�MACRO.DCB.SI*!IOCINT‚IDNT‚1,0„I/O�CHANNEL�CCB'S‰OPTƒMEX* ‰XDEF†IOSEG* SECTION 1*9*SET UP CHANNEL CONTROL BLOCKS FOR DEVICES ON I/O CHANNEL*K****************************************************************************-*ˆINTERRUPT�VECTORS�AND�LEVELS�ON�I/O�CHANNEL*!*ˆVECTORSƒVM02†VM03†VME110„VMES10**‰IOCVEC1ƒ$71‡$49‡$19‡$41*‰IOCVEC2ƒ$72‡$4A‡$1A‡$43*‰IOCVEC3ƒ$73‡$4B‡$1B‡$44*‰IOCVEC4ƒ$74‡$4C‡$1C‡$45** *ˆLEVELS„VM02†VM03†VME110„VMES10**ˆIOCLVL1…2‰3‰1‰2*ˆIOCLVL2…3‰4‰2‰4*ˆIOCLVL3…4‰5‰3‰5*ˆIOCLVL4…5‰6‰4‰6**6*ˆINTERRUPT�VECTOR�1�CORRESPONDS�TO�INTERRUPT�LEVEL�1,*ˆAND�SO�FORTH.5*ˆPLEASE�BE�SURE�THAT�YOUR�BOARD�IS�JUMPERED�PROPERLY6*ˆTO�PRODUCE�THE�INTERRUPT�VECTOR�AND�LEVEL�CALLED�FOR*ˆIN�THE�CDB�MACRO.**ˆI/O�CHANNEL�BASE�ADDRESSES**—VM02†VM03†VME110„VMES10***ˆIOCBASE:†$F80000ƒ$FA0000ƒ$FE6000ƒ$F1C000** IOSEG EQU *H************************************************************************‰PAGEH*************************************************************************F*ƒIf�any�RAD�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CCB allocations for those boards.* ‚IFNE�\NRADŒINCLUDEƒ&.XRADIOC.SI‚ENDC‰PAGEJVSL[H*************************************************************************F*ƒIf�any�RIO�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CCB allocations for those boards.* ‚IFNE�\NRIOŒINCLUDEƒ&.XRIOIOC.SI‚ENDC‰PAGEH*************************************************************************J*ƒIf�any�VME�600�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CCB allocations for those boards.* ‚IFNE�\NVME600ŒINCLUDEƒ&.XM600IOC.SI‚ENDC‰PAGEH*************************************************************************J*ƒIf�any�VME�605�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CCB allocations for those boards.* ‚IFNE�\NVME605ŒINCLUDEƒ&.XM605IOC.SI‚ENDC‰PAGEH*************************************************************************I*ƒIf�any�VME�610�or�VME�620�boards�are�specified�in�.CNFGDRVR.CI,?* include the code to perform CCB allocations for those boards.* ‚IFNE�\NVME610+\NVME620ŒINCLUDEƒ&.XM610IOC.SI‚ENDC‰PAGEH*************************************************************************J*ƒIf�any�VME�615�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CC; B allocations for those boards.* ‚IFNE�\NVME615ŒINCLUDEƒ&.XM615IOC.SI‚ENDC‰PAGE<*************************************************************J*ƒIf�any�VME�625�boards�are�specified�in�.CNFGDRVR.CI,�include�the3* code to perform CCB allocations for those boards.*‚IFNE�\NVME625‹INCLUDE„&.XM625IOC.SI‚ENDC*I***************************************************************************‰DC.L�0�END�OF�CCB'S‰DS.B†$10‡STACK�AREA STACK„EQU‡***ˆALLOCATE�CHANNEL*ALLBLKƒDC.B…XDCALL�COMMAND�CODE‰DC.B„0“COMMAND�SUB-CODE‰DC.B„0“RESERVED'‰DC.B…XOPEXC�OPTIONS�(EXCLUSIVE�ACCESS)‰DC.L„0“CHANNEL�MNEMONIC)‰DS.B„XIOALN+(2*XIOXLN)-XIOPRM†PARAMETERS‰DC.L„0“PRECAUTION*5*ˆWALK�CCB�CHAIN�AND�ALLOCATE�ALL�KNOWN�I/O�CHANNELS.**INIT…MOVE.L‚#STACK,A7‹SET�UP�STACK�POINTER,‰MOVE.L‚#IOSEG,A1…SET�UP�POINTER�TO�CCB�LIST‰TST.Lƒ(A1)ˆANY�TO�DO?‰BEQ.S�INIT40ˆBRANCH�IF�NO0‰MOVE.L‚#ALLBLK,A0ŠSET�UP�POINTER�TO�PARAM�BLOCK2INIT10ƒMOVE.W‚XCDBOPT(A1),XIOOPT-1(A0)‚GET�OPTIONS6‰MOVE.L‚XCDBAID(A1),XIOCID(A0)�SET�UP�CHANNEL�MNEMONIC3‰MOVEM.L�XCDBPRM(A1),D0-D5/A2-A4ƒPICK�UP�PARAMETERS=‰MOVEM.L�D0-D5/A2-A4,XIOPRM(A0)„MOVE�PARAMETERS�TO�PARAM�BLOC/INIT15ƒMOVE.L‚#XCCMR,D0‹SET�UP�DIRECTIVE�NUMBER‰TRAPƒ#1“ALLOCATE�CHANNEL)INIT17ƒMOVE.L‚XCDBPTR(A1),A1†GET�NEXT�CCB ‰TST.L�(A1)‰BNE.SƒINIT10ŽNOT�FINISHEDINIT40ƒERQ.TERM**ˆABORT* KILL…EQU…*'‰MOVEM.L�D0/A0,-(A7)‰SAVE�REG�D0�AND�A0‰ERQ.ABORT‚#0�ABORT�SELF‰PAGE ‰END…INITéééé4‰CLR‡RAUSRLNX(A0)ˆClear�offset�in�'RAUSRLST'�to�next*¦available�entry.9‰MOVE†#\NURAD,RANUMUSR(A0)�Set�max�#�of�user-RAD�comb.�in-‰MOVE†#1,D2�header.‚Init�next-available-entry*¦pointer�to�1.9‰LEA‡RAUSRLST(A0),A1…Load�start�addr�of�RAUSRLST�into�A1.:RAINLP3‚CLR.L…RAUUSRNO(A1)ˆClear�user�#�entry�in�RAUSRLST.‰CLR.L…RAUUSRNO+4(A1)=‰MOVE†D2,RAURADID(A1)…Set�RAD-ID�in�RAUSRLST�to�point�to�next)*¦avail.�entry�(which�is�just�next�entry,;‰CLR‡RAURADID+2(A1)†initially).‚Clear�rest�of�RAD-ID�field.4‰CLR‡RAUSTAT(A1)‰Clear�user�status�flag�in�RAUSRLST.2‰CLR‡RAUEROPT(A1)ˆClear�error-notification�fields.‰CLR.L…RAUERSTO(A1)‰CLR.L…RAUERSUB(A1)6‰ADD.L…#RAULNG,A1ŠUpdate�ptr�to�start�of�next�entry�in0‰ADDQ†#1,D2�RAUSRLST.‚Bump�next-avail-entry�ptr.8‰CMP‡#\NURAD,D2ŠHave�we�initialized�the�whole�table�yet?"‰BLE‡RAINLP3�No--go�do�next�entry.?‰MOVE†#$FFFF,RAURADID-RAULNG(A1)„Yes--set�the�last�ptr�to�next-**¦avail-entry�to�$FFFF�to�indicate�no�more*¦left.9‰MOVE.L„A0,RAD1TBLŠPut�addr�of�RAD�tables�into�SYSPAR�loc*¦for�use�by�other�progs. ZERORADS�EQU‡*“End�of�RAD�stuff.O*==============================================================================‰END; éééc*J*=========================================================================*=*‚Code�added�to�allocate�memory�for�table�used�by�RIO�driver.=*‚This�code�is�to�merged�into�the�approprate�initializer�file4*‚as�per�the�instructions�received�with�this�driver.@*‚Edit�the�initializer�file.�Position�to�the�correct�line�in�the<*‚file.�Merge�this�file�by�the�Edit�command:�MERGE�RIOMEM.SA**K*==========================================================================6‰XREF„RIOTBL…SYSPAR�location�containing�RIOTBL�address ‰XREF„KILLER*ˆBRA.SƒRIOMEM1%*ˆINCLUDE�&.RIODRV.EQ„RIO�equate�file$‰INCLUDE�&.RIODRV.EQ„RIO�equate�file* ŠSECTION‚8ŠMOVE.L�#\NRIOINT,D3‡get�number�of�interrupt�levels�per�module$ŠMOVE.L�D2,D4Žsave�number�of�modules!ŠMULUƒD3,D4Žget�number�of�RIO-IDs-ŠMULUƒ#RIOIDLNG,D4‡get�#�of�bytes�for�RIO-IDs%ŠADD.L‚#RIONTRY,D4ˆadd�in�header�size+ŠMULUƒ#PIALNG,D2‰get�#�of�bytes�for�PIA�map,ŠADD.L‚D4,D2Ž#�of�bytes�needed�for�RIO�tableŠMOVE.L�D2,D5Žsave�#�of�bytes'ŠADD.L‚#255,D2Œround�up�to�page�boundryŠASR.L‚#8,D2Ž#�of�pages�needed'ŠBMI.S‚RIOERR�branch�if�negative,�error)ŠMOVE.L�#0,A0Žclear�for�allocating�memory)ŠMOVE.W�D2,A0Žnumber�of�pages�to�allocate'ŠMOVE.L�#4,D0Žpage�allocation�directive"ŠTRAPƒ#0‘call�RMS68K�to�get�memory"ŠBRA.S‚RIOOKŽbranch�if�good�return.RIOERR„BSR„KILLER�fatal�error�-�go�stop�system8RIOOK…MOVE.L�#'!RIO',RIOEYE(A0)�set�RIO�table�eyecatcher)ŠMOVE.W�D5,RIOLNG(A0)†#�of�bytes�in�table5ŠMOVE.W�#RIONTRY,RIOOFST(A0)�offset�to�RIO-ID�entries(ŠMOVE.W�D4,RIOPIA(A0)†offset�to�PIA�maps'ŠCLR.B‚RIONAL(A0)‰no�RIOs�allocated�yet+ŠMOVE.L�#\NRIO,D4Šget�number�of�RIO�modules/ŠMULUƒ#\NRIOINT,D4‡get�number�of�RIO-ID�entries-ŠMOVE.B�D4,RIONMAX(A0)…max�number�of�RIO-ID's6ŠMOVE.L�A0,RIOTBLŠsave�table�address�in�system�params.0ŠLEA„RIOID(A0),A0‡start�address�of�table�entries/ŠSUB.W‚#RIONTRY,D5ˆnumber�of�bytes�to�set�to�FFl0uŠASR.W‚#1,D5Žnumber�of�words3ŠMOVE.W�#$FFFF,D4Šstore�this�in�all�entry�locations&RIOCLR„MOVE.W�D4,(A0)+‹set�the�entriesŠSUB.W‚#1,D5Ždecrement�counter ŠBNE.S‚RIOCLR�branch�if�not�done NORIOS„EQU„*ŠENDéé< ééééé**ˆ&.M605MEM.CI*GMSG‰*******************************************************************#MSG‰*‚MVME605�driver�initializationGMSG‰******************************************************************* SUBSˆ&.M605MEM.AGASM‰&.M605MEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CIéééééé}* *ˆ&.RADMEM.CI*GMSG‰*******************************************************************MSG‰*‚RAD�driver�initializationGMSG‰******************************************************************* SUBSˆ&.RADMEM.AGASM‰&.RADMEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CI< éééééé†**ˆ&.M610MEM.CI*EMSG‰*****************************************************************'MSG‰*‚MVME610/620„driver�initializationDMSG‰**************************************************************** SUBSˆ&.M610MEM.AGASM‰&.M610MEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CIéééééé�= **ˆ&.M625DRV.CI*GMSG‰*******************************************************************!MSG‰**‚VME�625�DRIVER�-‚DC�OUTPUTGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF%=COPY‡VERSAPT.M625DRV.CF,VERSAPT.CF;A M625DRVƒ=�*SUBSˆ&.M625IOC.SISUBSˆ&.M625DRV.LGLINKˆ&.M625DRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.M625DRV.LOEND‰&.M625DRV.LOééééé˜**ˆ&.M615MEM.CI*GMSG‰*******************************************************************MSG‰*‚615�driver�initializationGMSG‰******************************************************************* SUBSˆ&.M615MEM.AGASM‰&.M615MEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CIééééé= é¡* *ˆ&.RIOMEM.CI*GMSG‰*******************************************************************MSG‰*‚RIO�driver�initializationGMSG‰******************************************************************* SUBSˆ&.RIOMEM.AGASM‰&.RIOMEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CIééééééª**ˆ&.M625MEM.CI*GMSG‰*******************************************************************MSG‰*‚625�driver�initializationGMSG‰******************************************************************* SUBSˆ&.M625MEM.AGASM‰&.M625MEM.AG,NEW.RO,\ASMLS IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC INCLUDE…&.ROGEN.CIééé> ééé³**ˆ&.M600DRV.CI*GMSG‰*******************************************************************3MSG‰**„VME�600�DRIVER�-‚ANALOG�TO�DIGITAL�CONVERTERGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF%=COPY‡VERSAPT.M600DRV.CF,VERSAPT.CF;A +M600DRVƒ=�*ŒMVME600/601�driver�base�address!SUBSˆ&.M600IOC.SI�CCB�allocations1SUBSˆ&.M600DRV.LG�Driver�module�LINK�command�fileLINKˆ&.M600DRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.M600DRV.LOEND‰&.M600DRV.LOééééé¼**ˆ&.M605DRV.CI*GMSG‰*******************************************************************%MSG‰**„VME�605�DRIVER�-‚ANALOG�OUTPUTGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF%=COPY‡VERSAPT.M605DRV.CF,VERSAPT.CF;A M605DRVƒ=�*SUBSˆ&.M605IOC.SISUBSˆ&.M605DRV.LGLINKˆ&.M605DRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.M605DRV.LOEND‰&.M605DRV.LO> éééééÅ ' M610DRV CIÚÚqqM615DRV CIããqqPCDRV CIììqqRADDRV CIõõqqRIODRV CIþþqqIOCI CIqqM600DRV LGqqM605DRV LGqqM610DRV LG""qqM615DRV LG++qqM625DRV LG44qqIOCINT LG==qqIOCFAIL LGFFqqRADDRV LGOOqqRIODRV LGXXqqM600DRV NWaajqqM600FORTNWnn:ÏqqM605DRV NW¯¯ŠqqM610DRV NWÈÈ"¸qqM615DRV NWññàqq**ˆ&.M610DRV.CI*GMSG‰*******************************************************************-MSG‰**‚VME�610/620�DRIVER�-�AC�INPUT/DC�INPUTGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF%=COPY‡VERSAPT.M610DRV.CF,VERSAPT.CF;A +M610DRVƒ=�*ŒMVME610/620�driver�base�address!SUBSˆ&.M610IOC.SI�CCB�allocations1SUBSˆ&.M610DRV.LG�Driver�module�LINK�command�fileLINKˆ&.M610DRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.M610DRV.LOEND‰&.M610DRV.LOééé? ééÒ**ˆ&.M615DRV.CI*GMSG‰*******************************************************************!MSG‰**„VME�615�DRIVER�-‚AC�OUTPUTGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF%=COPY‡VERSAPT.M615DRV.CF,VERSAPT.CF;A M615DRVƒ=�*SUBSˆ&.M615IOC.SISUBSˆ&.M615DRV.LGLINKˆ&.M615DRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.M615DRV.LOEND‰&.M615DRV.LOéééééÛ* *ˆ&.PCDRV.CI* IFGTˆ\NRADƒINCLUDE…&.RADMEM.CIENDC* IFGTˆ\NRIOƒINCLUDE…&.RIOMEM.CIENDC* IFGTˆ\NVME605ƒINCLUDE…&.M605MEM.CIENDC*IFGTˆ\NVME610+\NVME620ƒINCLUDE…&.M610MEM.CIENDC* IFGTˆ\NVME615ƒINCLUDE…&.M615MEM.CIENDC* IFGTˆ\NVME625ƒINCLUDE…&.M625MEM.CIENDCéé? ééééä* *ˆ&.RADDRV.CI*GMSG‰*******************************************************************MSG‰**„RAD�DRIVERGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF$=COPY‡VERSAPT.RADDRV.CF,VERSAPT.CF;A RADDRV„=�*SUBSˆ&.RADIOC.SISUBSˆ&.RADDRV.LGLINKˆ&.RADDRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.RADDRV.LOEND‰&.RADDRV.LOééééééí* *ˆ&.RIODRV.CI*GMSG‰*******************************************************************MSG‰**„RIO�DRIVERGMSG‰******************************************************************* *‚Set�Process�Control�Flag=�ON&PCDRV„=�\&PCDRV+1 5* Build VERSAdos patch chain file .VERSAPT.CF$=COPY‡VERSAPT.RIODRV.CF,VERSAPT.CF;A RIODRV„=�*SUBSˆ&.RIOIOC.SISUBSˆ&.RIODRV.LGLINKˆ&.RIODRV.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDCPROCESS…&.RIODRV.LOEND‰&.RIODRV.LO@ ééééééö* *ˆ&.IOCI.CI*MSG$MSG‰Start�of�I/O�channel�initializerMSGTASKˆ&.IOCI.LOSTATE…=�'READ' SESSIONƒ=�1PRIORITY‚=�$DA IOCISTRƒ=�* SUBSˆ&.IOCINT.AG'ASM‰&.IOCINT.AG,&.IOCINT.RO,\ASMLS;Z=50 IFEQˆ\ASMLSWƒ=COPY‡\ASMLS,\WORKLS;AENDC SUBSˆ&.IOCINT.LGLINKˆ&.IOCINT.LG IFEQˆ\LINKLSWƒ=COPY‡\LINKLS,\WORKLS;AENDC END‰&.IOCI.LOééééééÿ@ =/*=/*†&.M600DRV.LG=/*==/* Link chain file run at sysgen time to link MVME600 driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter M600DRV = \M600DRV = address at which to link driver=/* =LINK ,&.M600DRV.LO,\LINKLS;MIXHSEG M600:8 \M600DRVINPUT &.M600DRV.ROEND=/*=ENDéééééé=/*=/*†&.M605DRV.LG=/*==/* Link chain file run at sysgen time to link MVME605 driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter M605DRV = \M605DRV = address at which to link driver=/* =LINK ,&.M605DRV.LO,\LINKLS;MIXHSEG DAC1:8 \M605DRVINPUT &.M605DRV.ROINPUT &.SYSPAR.ROEND=/*=ENDéééééA é=/*=/*†&.M610DRV.LG=/*==/* Link chain file run at sysgen time to link MVME610 driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter M610DRV = \M610DRV = address at which to link driver=/* =LINK ,&.M610DRV.LO,\LINKLS;MIXHSEG SEG0:0 \M610DRVINPUT &.M610DRV.ROINPUT &.SYSPAR.ROEND=/*=ENDéééééé=/*=/*†&.M615DRV.LG=/*==/* Link chain file run at sysgen time to link MVME615 driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter M615DRV = \M615DRV = address at which to link driver=/* =LINK ,&.M615DRV.LO,\LINKLS;MIXHSEG M615:8 \M615DRVINPUT &.M615DRV.ROINPUT &.SYSPAR.ROEND=/*=ENDéééA ééé#=/*=/*†&.M625DRV.LG=/*==/* Link chain file run at sysgen time to link MVME625 driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter M625DRV = \M625DRV = address at which to link driver=/* =LINK ,&.M625DRV.LO,\LINKLS;MIXHSEG M625:8 \M625DRVINPUT &.M625DRV.ROINPUT &.SYSPAR.ROEND=/*=ENDéééééé,=/*=/*†&.IOCINT.LG=/*5=/* Link chain file run at sysgen time to link IOCINT=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter IOCISTR = \IOCISTR = address at which to link driver=/*=LINK ,&.IOCI.LO,\LINKLS;IXHMSSEGMENT IOCI:1 \IOCISTRINPUT &.IOCINT.ROEND=/*=ENDéB ééééé5=/*=/*†&.IOCFAIL.LG=/*6=/* Link chain file run at sysgen time to link IOCFAIL=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*I=/* Sysgen parameter IOCFSTR = \IOCFSTR = address at which to link driver=/*!=LINK ,&.IOCFAIL.LO,\LINKLS;IXHMSSEGMENT IOCF:0 \IOCFSTRINPUT &.IOCFAIL.ROEND=/*=ENDéééééé>=/*=/*†&.RADDRV.LG=/*5=/* Link chain file run at sysgen time to link RADDRV=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*G=/* Sysgen parameter RADDRV = \RADDRV = address at which to liB nk driver=/*=LINK ,&.RADDRV.LO,\LINKLS;MIXHSEG RAD1:8 \RADDRVINPUT &.RADDRV.ROINPUT &.SYSPAR.ROEND=/*=ENDééééééG=/*=/*†&.RIODRV.LG=/*9=/* Link chain file run at sysgen time to link RIO driver=/*D=/* Sysgen parameter LINKLS = \LINKLS = file/device to which to send=/* the linker listing=/*G=/* Sysgen parameter RIODRV = \RIODRV = address at which to link driver=/*=LINK ,&.RIODRV.LO,\LINKLS;MIXHSEG RIO1:8 \RIODRVINPUT &.RIODRV.ROINPUT &.SYSPAR.ROEND=/*=ENDééééééC PN==============================================================================F====‚NEWS�FILE�FOR�A/D…(MVME600�-�A/D�INPUT�BOARD)ƒDRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N============================================================================== 8This driver is compatible with both RMS68K and VERSAdos.   .This driver consists of the following files -- ‰MVME600�driver�files:-�9992.&.M600DRV.SA‚MVME600�driver�source�file9�9992.&.M600CMDS.SA�MVME600�source�command/interrupt�code0�9992.&.M600CMTS.SA�MVME600�source�comments�file6�9992.&.M600INTL.SA�MVME600�source�initialization�code@�9992.&.M600SERV.SA�MVME600�source�driver�vector�table/rev�table-�9992.&.M600DRV.RO‚MVME600�driver�object�file5�9992.&.M600DRV.AF‚MVME600�driver�assembly�chain�file  ‰Files�for�system�configuration:"�9992.&.M600DRV.CIˆSYSGEN�commands"�9992.&.M600IOC.SIˆCCB�allocations3�9992.&.M600DRV.LGˆChain�file�to�link�in�the�driver#�9998.VERSAPT.M600DRV.CF‚Patch�file   ‰FORTRAN�interface�subroutines:0�9992.&.M600LIB.SA…Assembly�language�source�file&�9992.&.M600LIB.AF…Assembly�chain�file�9992.&.M600LIB.RO…Object�file  ‰"News"�file:�9992.&.M600DRV.NW…News�file7�9992.&.M600FORT.NW„Documentation�for�FORTRAN�interface   %‰Files�to�generate�the�test�programs: >‰9992.M600DRV.TEST600.SA‡Assembly�language�test�program�sourceA‰9992.M600DRV.TEST600.AF‡chain�file�for�assembly�language�programA‰9992.M600DRV.TEST600.LF‡chain�file�for�link�of�asm�lang.�program7‰9992.M600DRV.TEST600.LO‡assembly�language�test�program  KThe�MVME600�driver�source�file�is:�9992.&.M600DRV.SA.‚To�assemble�this�file%use the chain file 9992.&.M600DRV.AF.  >In order to incorporate this driver into your system, you will=have to set some parameters in the .CNFGDRVR.CI file.  #This driver requires the following:;‰1)‚Memory�must�be�allocated�for�the�internal�driver�table.9‰2)‚A�channel�control�block�(CCB)�must�be�created�for�theY<b/6“commands�issued�for�each�MVME600�board�in�the�system. HThe size of the memory area set aside for the driver table is determinedJby�the�value�of�the�variable�specified�by�you�in�.CNFGDRVR.CI.‚Thevariable is "NVME600". =NVME600ƒThis�is�the�number�of�MVME600�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards6Šon�the�I/O�Channel�(which�is�where�these�boards�are),&Šthe�maximum�value�of�"NVME600"�is�16.   ?To include the MVME600 driver in your SYSgen, do the following: <‰(1)�Use�COPYSGEN�to�get�all�the�files�needed�for�the�SYSgen�into�your�SYSgen�user�number.2�NOTE:‚Make�sure�argument�5�=�PCDRV�so�the�Process+”Control�Drivers�will�be�copied�by�COPYSGEN 9‰(2)�Set�the�variable�NVME600�in�the�.CNFGDRVR.CI,�file�for�the�processor�board�you�are�using. 8‰(3)�Check�the�file�M600IOC.SI�to�be�sure�that�the�CCB's�conform�to�your�configuration. BWhen setting up the "CDB" calls please note that each ID must haveCa�unique�name.‚This�is�also�the�name�any�application�task�would�useBto�address�the�driver�for�a�board.‚The�memory-mapped�I/O�addresses"are also different for each board. JM600LIB.SA�is�assembled�using�the�M600LIB.AF�chain�file.‚M600LIB.RO�is�theEFORTRAN-callable subroutine which, when called by the user program orJFORTRAN test program, will invoke the appropriate MVME600 driver function. >After configuring your system and creating a VERSAdos with the>MVME605 driver included, you may want to run the provided C testprogram. GM600DRV.TEST600.SA is an assembly language test program which tests theDMVME600�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver. ‰ENDN==============================================================================N==============================================================================   ½31-Jan-85  + 1 MVME600 A/D Interface User Documentation:ƒEach�of�the�following�module�are�located�in�&.M600LIB.SA.  „A.‚MODULE�NAME: ŠA2DOPN „B.‚MODULE�TYPE: ŠUtility�subroutine „C.‚MODULE�PURPOSE: /ŠThis�subroutine�provides�an�interface�with�the1ŠA/D�600/601�driver,�allowing�a�user�task�written+Šin�FORTRAN�to�open�one�or�more�measurement Šchannels. „D.‚CALLING�SEQUENCE: )‰CALL�A2DOPN(CHNLMN,CMDBLK,CMDBKL,STATUS) „E.‚ENTRY�CONDITIONS: ‰CHNLMN�=�Channel�Mnemonic’(4�ASCII�characters)#‰CMDBLK�=�I/O�Command�Block�address ’(Integer*4)"‰CMDBKL�=�I/O�Command�Block�length,‰STATUS�=�Status�returned�by�the�A/D�driver.  ‰Channel�Block�Format "‹+---------------+---------------+‹|‚Status�code’|"‹+---------------+---------------+‹|‚OPEN�command�code�($0001)„|"‹+---------------+---------------+‹|‚First�channel�number‰|"‹+---------------+---------------+‹:�:�:‹:�:�:"‹+---------------+---------------+ j3o4sdw#{@aƒ+‡9‹=�=“E—7›CŸ@£d‹|‚Last�channel�numberŠ|"‹+---------------+---------------+  „F.‚EXIT�CONDITIONS: ,‰STATUS�=�Status�returned�by�the�A/D�driver.       -�1�-   ½31-Jan-85  „G.‚TABLES�USED: ‰Parameter�Block "‹+---------------+---------------+ ‹|‚Command�code�(Initiate�I/O)‚|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Length�I/O�command�block…|"‹+---------------+---------------+ „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver #„J.‚ERROR�MESSAGES�GENERATED:„None.                        -�2�-   ½31-Jan-85  „A.‚MODULE�NAME:„A2DMRS #„B.‚MODULE�TYPE:„UTILITY�SUBROUTINE „C.‚MODULE�PURPOSE: /ŠThis�subroutine�provides�an�interface�with�the1ŠA/D�600/601�driver,�allowing�a�user�task�written2Šin�FORTRAN�to�request�single-ended�measurement(s)&Šfor�specified�measurement�channel(s). „D.‚CALLING�SEQUENCE: )ˆCALL�A2DMRS(CHNLMN,CMDBLK,CMDBKL,STATUS) „E.‚ENTRY�CONDITIONS: ‰CHNLMN�=�Channel�Mnemonic’(4�ASCII�characters)#‰CMDBLK�=�I/O�Command�Block�address ’(Integer*4)"‰CMDBKL�=�I/O�Command�Block�length                                     -�3�-   ½31-Jan-85  +‰I/O�Command�Block�(MEASURE�SINGLE�command) "‹+---------------+---------------+‹|‚Status�code’|"‹+---------------+---------------+!‹|‚MEASURE�command�code�($0003)�|"‹+---------------+---------------+ ‹|‚Repeat�count�(0�=�Infinity)‚|"‹+---------------+---------------+‹|‚Time�delay�between�D sweeps„|‹+--…4�byte�fieldŠ--+‹|ƒ(omit�if�repeat�count�=�1)‚|"‹+---------------+---------------+‹|‚Command�Completion�Option„|"‹+---------------+---------------+›:•Channel�Blocks›:"‹+---------------+---------------+‹|‚Channel�number�|"‹+---------------+---------------+‹|‚Channel�Completion�Optionsƒ|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+‹|‚Buffer�address�|"‹+---------------+---------------+‹|‚Buffer�address�|"‹+---------------+---------------+‹|‚Size�of�buffer�in�bytes†|"‹+---------------+---------------+!‹|‚Trigger�Mode�and�Gain�Option�|"‹+---------------+---------------+                        -�4�-   ½31-Jan-85  „F.‚EXIT�CONDITIONS: ,‰STATUS�=�Status�returned�by�the�A/D�driver. „G.‚TABLES�USED: ‰Parameter�Block "‹+---------------+---------------+ ‹|‚Command�code�(Initiate�I/O)‚|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Length�I/O�command�block…|"‹+---------------+---------------+ „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver #„J.‚ERROR�MESSAGES�GENERATED:„None.                    -�5�-   ½31-Jan-85  „A.‚MODULE�NAME:„A2DMRD #„B.‚MODULE�TYPE:„UTILITY�SUBROUTINE „C.‚MODULE�PURPOSE: /ŠThis�subroutine�provides�an�interface�with�the1ŠA/D�600/601�driver,�allowing�a�user�task�written2Šin�FORTRAN�to�request�differential�measurement(s)&Šfor�specified�measurement�channel(s). „D.‚CALLING�SEQUENCE: )ˆCALL�A2DMRD(CHNLMN,CMDBLK,CMDBKL,STATUS) „E.‚ENTRY�CONDITIONS: ‰CHNLMN�=�Channel�Mnemonic’(4�ASCII�characters)#‰CMDBLK�=�I/O�Command�Block�address ’(Integer*4)"‰CMDBKL�=�I/O�Command�Block�length                                     -�6�-   ½31-Jan-85  1‰I/O�Command�Block�(MEASURE�DIFFERENTIAL�command) "‹+---------------+---------------+‹|‚Status�code’|"‹+---------------+---------------+!‹|‚MEASURE�command�code�($0004)�|"‹+---------------+---------------+ ‹|‚Repeat�count�(0�=�Infinity)‚|"‹+---------------+---------------+‹|‚Time�delay�between�sweeps„|‹+--…4�byte�fieldŠ--+‹|‚(omit�if�repeat�count�=�1)ƒ|"‹+---------------+---------------+‹|‚Command�Completion�Option„|"‹+---------------+---------------+›:•Channel�Blocks›:"‹+---------------+---------------+‹|‚Channel�number�|"‹+---------------+---------------+‹|‚Channel�Completion�Optionsƒ|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+‹|‚Buffer�address�|"‹+---------------+---------------+‹|‚Buffer�address�|"‹+---------------+---------------+‹|‚Size�of�buffer�in�bytes†|"‹+---------------+---------------+!‹|‚Trigger�Mode�and�Gain�Option�|"‹+---------------+---------------+                        -�7�-   ½31-Jan-85  „F.‚EXIT�CONDITIONS: ,‰STATUS�=�Status�returned�by�the�A/D�driver.  „G.‚TABLES�USED: ‰Parameter�Block "‹+---------------+---------------+ ‹|‚ComD mand�code�(Initiate�I/O)‚|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Length�I/O�command�block…|"‹+---------------+---------------+  „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver #„J.‚ERROR�MESSAGES�GENERATED:„None.                  -�8�-   ½31-Jan-85  „A.‚MODULE�NAME:„A2DSTP #„B.‚MODULE�TYPE:„UTILITY�SUBROUTINE „C.‚MODULE�PURPOSE: /ŠThis�subroutine�provides�an�interface�with�the1ŠA/D�600/601�driver,�allowing�a�user�task�written+Šin�FORTRAN�to�stop�the�measurement�for�anyŠspecified�MEASURE�command. „D.‚CALLING�SEQUENCE: )‰CALL�A2DSTP(CHNLMN,CMDBLK,CMDBKL,STATUS) „E.‚ENTRY�CONDITIONS: ‰CHNLMN�=�Channel�Mnemonic’(4�ASCII�characters)#‰CMDBLK�=�I/O�Command�Block�address ’(Integer*4)"‰CMDBKL�=�I/O�Command�Block�length ‰Channel�Block�Format "‹+---------------+---------------+‹|‚Status�code’|"‹+---------------+---------------+‹|‚STOP�command�code�($0000)„|"‹+---------------+---------------+‹|‚First�channel�number‰|"‹+---------------+---------------+‹:�:�:‹:�:�:"‹+---------------+---------------+‹|‚Last�channel�numberŠ|"‹+---------------+---------------+                      -�9�-   ½31-Jan-85  „F.‚EXIT�CONDITIONS: ,‰STATUS�=�Status�returned�by�the�A/D�driver. „G.‚TABLES�USED:ƒNone ‰Parameter�Block "‹+---------------+---------------+ ‹|‚Command�code�(Initiate�I/O)‚|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Length�I/O�command�block…|"‹+---------------+---------------+  „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver „J.‚ERROR�MESSAGES�GENERATED: ŠNone                 -�10�-   ½31-Jan-85  „A.‚MODULE�NAME: ŠA2DCLS „B.‚MODULE�TYPE: ŠUtility�subroutine „C.‚MODULE�PURPOSE: /ŠThis�subroutine�provides�an�interface�with�the1ŠA/D�600/601�driver,�allowing�a�user�task�written,Šin�FORTRAN�to�close�one�or�more�measurement Šchannels. „D.‚CALLING�SEQUENCE: )‰CALL�A2DCLS(CHNLMN,CMDBLK,CMDBKL,STATUS) „E.‚ENTRY�CONDITIONS: ‰CHNLMN�=�Channel�Mnemonic’(4�ASCII�characters)#‰CMDBLK�=�I/O�Command�Block�address ’(Integer*4)"‰CMDBKL�=�I/O�Command�Block�length ‰Channel�Block�Format "‹+---------------+---------------+‹|‚Status�code’|"‹+---------------+---------------+‹|‚CLOSE�command�code�($0002)ƒ|"‹+---------------+---------------+‹|‚First�channel�number‰|"‹+---------------+---------------+‹:�:�:‹:�:�:"‹+---------------+---------------+‹|‚Last�channel�numberŠ|"‹+---------------+---------------+  „F.‚EXIT�CONDITIONS: ,‰STATUS�=�Status�returned�by�the�A/D�driveE r.             -�11�-   ½31-Jan-85  „G.‚TABLES�USED: ‰Parameter�Block "‹+---------------+---------------+ ‹|‚Command�code�(Initiate�I/O)‚|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+‹|‚Channel�Mnemonic�(ASCII)…|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+ ‹|Šnot�used�|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Address�I/O�command�block„|"‹+---------------+---------------+‹|‚Length�I/O�command�block…|"‹+---------------+---------------+  „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver #„J.‚ERROR�MESSAGES�GENERATED:„None.                       -�12�-   ½31-Jan-85  „A.‚MODULE�NAME:„BLDCB #„B.‚MODULE�TYPE:„UTILITY�SUBROUTINE „C.‚MODULE�PURPOSE: -ŠThis�subroutine�builds�a�channel�block�entry3Šfrom�the�specified�parameters�in�the�user�provided0Šdata�area.‚This�subroutine�is�used�to�build�the+Šchannel�blocks�for�both�of�the�measurement Šroutines. „D.‚CALLING�SEQUENCE: 4ˆCALL�BLDCB(CMDBLK,CHNLNO,OPTION,BFA,BFL,SBA,TGRMOD,“RTNADR,CMDBKL) „E.‚ENTRY�CONDITIONS: #‰CMDBLK‚=�I/O�Command�Block�address “(Integer*4)‰CHNLNO‚=�Channel�number$‰OPTION‚=�Channel�completion�options‰BFA…=�Buffer�Address “(Integer*4)‰BFL…=�Buffer�Length-‰SBA…=�Subroutine�Address‚(0�if�not�required) “(Integer*4)'‰TGRMOD‚=�Trigger�Mode�and�Gain�Options-‰RTNADR‚=�Address�of�next�avail�channel�block“(Returned�by�this�subroutine) “(Integer*4)'‰CMDBKL‚=�Length�of�Channel�Block�built“(Returned�by�this�subroutine)                         -�13�-   ½31-Jan-85  ‰Channel�Block�Format "‹+---------------+---------------+‹|‚Channel�number�|"‹+---------------+---------------+‹|‚Channel�Completion�Optionsƒ|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+!‹|‚Subroutine�Address�(Optional)|"‹+---------------+---------------+‹|ˆBuffer�address‰|"‹+---------------+---------------+‹|ˆBuffer�address‰|"‹+---------------+---------------+‹|‚Size�of�buffer�in�bytes†|"‹+---------------+---------------+!‹|‚Trigger�Mode�and�Gain�Option�|"‹+---------------+---------------+                                        -�14�-   ½31-Jan-85  „F.‚EXIT�CONDITIONS: „G.‚TABLES�USED: „H.‚MODULES�USED: „I.‚MODULES�CALLING�THIS�MODULE: -ŠAny�module�requiring�interface�to�A/D�driver „J.‚ERROR�MESSAGES�GENERATED: ŠNone �END                                            -�15�- éN==============================================================================@====‚NEWS�FILE�FOR�DAC…(MVME605�-�D/A�BOARD)‰DRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N========================================================================E ====== 8This driver is compatible with both RMS68K and VERSAdos.   .This driver consists of the following files -- ‰MVME605�driver�files: -�9992.&.M605DRV.SA‚MVME605�driver�source�file-�9992.&.M605DRV.RO‚MVME605�driver�object�file5�9992.&.M605DRV.AF‚MVME605�driver�assembly�chain�file  ‰Files�for�allocating�memory:0�9992.&.M605MEM.CI‰File�included�at�SYSGEN�time.0�9992.&.M605MEM.AG‰File�assembled�at�SYSGEN�time  !‰Files�for�system�configuration�: "�9992.&.M605DRV.CIˆSYSGEN�commands"�9992.&.M605IOC.SIˆCCB�allocations3�9992.&.M605DRV.LGˆChain�file�to�link�in�the�driver#�9998.VERSAPT.M605DRV.CF‚Patch�file  ‰FORTRAN�interface�subroutines:0�9992.&.M605LIB.SAˆAssembly�language�source�file&�9992.&.M605LIB.AFˆAssembly�chain�file�9992.&.M605LIB.ROˆObject�file  9‰The�following�files�are�used�to�generate�a�test�program: >‰9992.M605DRV.TEST605.SA‡Assembly�language�test�program�sourceA‰9992.M605DRV.TEST605.AF‡chain�file�for�assembly�language�programA‰9992.M605DRV.TEST605.LF‡chain�file�for�link�of�asm�lang.�program7‰9992.M605DRV.TEST605.LO‡assembly�language�test�program  ‰"News"�file:�9992.&.M605DRV.NWˆNews�file KThe�MVME605�driver�source�file�is:�9992.&.M605DRV.SA.‚To�assemble�this�file%use the chain file 9992.&.M605DRV.AF.;The following files are used in the assembly of M605DRV.SA:�9995.&.STR.EQ�9995.&.TCB.EQ�9995.&.CCB.EQ�9995.&.LV5.EQ�9995.&.TR1RTCD.EQ�9995.&.M605DRV.EQ  >In order to incorporate this driver into your system, you will=have to set some parameters in the .CNFGDRVR.CI file.  #This driver requires the following:;‰1)‚Memory�must�be�allocated�for�the�internal�driver�table.§A°4¸9‰2)‚A�channel�control�block�(CCB)�must�be�created�for�the6“commands�issued�for�each�MVME605�board�in�the�system. HThe size of the memory area set aside for the driver table is determinedGby�the�values�of�two�variables�as�specified�by�you�in�the�SYSGEN.‚These$variables are "NVME605" and "NU605". =NVME605ƒThis�is�the�number�of�MVME605�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards6Šon�the�I/O�Channel�(which�is�where�these�boards�are),&Šthe�maximum�value�of�"NVME605"�is�16. 3NU605…This�variable�is�set�to�the�maximum�number�of7Šuser/MVME605�combinations�you�wish�to�allow�at�any�one2Štime.‚Since�it�is�possible�to�have�one�user�using;Šmore�than�one�MVME605�board,�as�well�as�more�than�one�user4Šusing�the�same�MVME605�board,�we�need�the�number�ofŠuser/MVME605�combinations.   ?Example:‚If�user�A�uses�board�#1�and�board�#2,�user�B�uses�just1Šboard�#1,�and�user�C�uses�board�#2�and�board�#3,,Šthere�would�be�5�user/board�combinations�--ŠA/1,�A/2,�B/1,�C/2,�C/3.FIf the configuration of MVME605 boards is the same as in this example,$you would set NVME605=3 and NU605=5. INote that if you set either of these variables to a larger number than isHactually�needed,�the�system�will�still�operate�normally.‚This�would�justBresult in having more memory allocated for internal tables than is necessary.  ?To include the MVME605 driver in your SYSGEN, do the following:  9‰(1)�Do�a�COPYSGEN�to�get�the�files�needed�for�the�SYSgen�into�your�sysgen�user�number.7�NOTE:‚Make�sure�that�argument�5�=�PCDRV�so�the�Process,”Control�Drivers�will�be�copied�by�COPYSGEN. D‰(2)�Set�the�variables�NVME605�and�NU605�in�the�.CNFGDRVR.CI,�file�for�the�processor�board�you�are�using. 8‰(3)�Check�the�file�M605IOC.SI�to�be�sure�that�the�CCB's�conform�to�your�configuration.   FWhen setting up the "CDB" calls please note that each DAC-ID must haveCa�unique�name.‚This�is�also�the�name�any�application�task�would�useF Bto�address�the�driver�for�a�board.‚The�memory-mapped�I/O�addresses"are also different for each board.   >After configuring your system and creating a VERSAdos with the>MVME605 driver included, you may want to run the provided testprogram. GM605DRV.TEST605.SA is an assembly language test program which tests theDMVME605�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver.  JM605LIB.SA is assembled using the M605LIB.AF chain file. M605LIB.RO is theEFORTRAN-callable subroutine which, when called by the user program orJFORTRAN test program, will invoke the appropriate MVME605 driver function. ‰ENDN==============================================================================N==============================================================================ééééN==============================================================================H====‚NEWS�FILE�FOR�AC/DCƒ(MVME610/620�-�AC/DC�BOARD)ƒDRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N============================================================================== 8This driver is compatible with both RMS68K and VERSAdos. 4This driver package consists of the following files: ‰VME�610/620�Driver�files:1�9992.&.M610DRV.SAˆMVME610/620�Driver�Source�file1�9992.&.M610DRV.ROˆMVME610/620�Driver�Object�file9�9992.&.M610DRV.AFˆMVME610/620�Driver�Assembly�Chain�file <‰Files�to�allocate�memory�for�the�Interrupt�Processing�queue0�9992.&.M610MEM.AGŠFile�assembled�at�SYSgen�time4�9992.&.M610MEM.CIŠFile�INCLUDEd�into�SYSgen�command¨file�at�SYSgen�time. ‰Files�for�system�configuration:%�9992.&.M610DRV.CIŠCommands�to�SYSgen"�9992.&.M610IOC.SIŠCCB�allocations �9992.&.M610DRV.LGŠLINK�commands#�9998.VERSAPT.M610DRV.CF„Patch�file  /‰The�driver�news�file�that�you�are�now�reading:�9992.&.M610DRV.NW‰News�file F‰MVME610/620�Driver�Command�and�Error�Code�Equate�files.�These�equatesB‹are�used�by�the�application�code�when�making�calls�to�the�driver.�9995.&.M610CMD.EQ ?‰The�following�files�are�used�to�generate�a�driver�test�program�9992.M610DRV.INPTST.LO�: 7�9992.M610DRV.INPTST.SA…Pascal�main�program�source�file?�9992.M610DRV.INTSTASM.SAƒSource�for�assembly�procedures�called¨from�Pascal�main�program5�9992.M610DRV.INPTST.PF…Pascal�compilation�chain�file-�9992.M610DRV.INTSTASM.AFƒAssembly�chain�file.�9992.M610DRV.INPTST.LF…Test�program�link�file?�9992.M610DRV.PDOLRLIB.ROƒSupplementary�Pascal�Run-time�Library @‰The�following�files�are�used�to�generate�a�second�test�program: >‰9992.M610DRV.TEST610.SA‡Assembly�language�test�program�sourceA‰9992.M610DRV.TEST610.AF‡chain�file�for�assembly�language�programA‰9992.M610DRV.TEST610.LF‡chain�file�for�link�of�asm�lang.�program7‰9992.M610DRV.TEST610.LO‡assembly�language�test�program F À3É0Ñ#Ù'á G‚The�following�files�are�used�to�assemble�and�link�the�Fortran�callable"driver command subroutine library: 0‰9992.&.M610LIB.SA�Assembly�language�source�file‰9992.&.M610LIB.RO�Object�file&‰9992.&.M610LIB.AF�Assembly�chain�file M‚To�assemble�the�MVME610/620�Driver�execute�the�chain�file�9992.&.M610DRV.AF.9The following files are required to assemble this driver: ‰9995.&.STR.EQ‰9995.&.TR1RTCD.EQ‰9995.&.TCB.EQ‰9995.&.LV5.EQ‰9995.&.BAB.EQ‰9995.&.CCB.EQ‰9995.&.M610CCB.EQ‰9995.&.M610INTQ.EQ‰9995.&.M610CMD.EQ +SYSgen Procedure for the MVME610/620 Driver+------------------------------------------- <1.‚Use�COPYSGEN�to�get�all�the�files�required�for�the�SYSgen7„to�the�user�number�where�the�SYSgen�will�be�performed.G„NOTE:‚Make�sure�that�argument�5�=�PCDRV�so�the�Process�Control�Drivers‹will�be�copied�by�COPYSGEN. K2.‚Edit�the�.CNFGDRVR.CI�file�for�generating�the�RMS68K�or�VERSAdosC„for�your�target�system.‚Modify�the�SYSgen�parameters�"NVME610"�andE„"NVME620".‚These�parameters�define�the�maximum�number�of�MVME610�andD„NVME620�boards�that�will�occupy�the�target�system.�One�other�sysgenH„parameter�that�must�be�modified�is�M610QSIZ.‚This�parameter�defines�theI„minimum�size�of�the�interrupt�processing�queue�in�terms�of�the�number�ofK„entries�that�the�queue�may�contain.‚The�driver�can�accomodate�a�maximum�ofE„2048�queue�entries.‚For�more�information�on�the�Interrupt�Processing3„Queue�consult�the�MVME610/620�Driver�Users�Manual.  I3.‚Edit�the�file�M610IOC.SI�so�that�one�call�to�the�CDB�macro�is�made�forJ„each�MVME610�or�MVME620�board�that�was�specified�in�.CNFGDRVR.CI.J„Each�CDB�must�specify�a�unique�channel�mnemonic�(i.e.�'IN01').‚The�memory=„mapped�I/O�address�offset�can�be�modified�in�IOC.ADDRESS.CI.5„The�I/O�channel�interrupt�vector�number�and�hardwareJ„interrupt�level�specified�for�each�CDB�can�also�be�modified�if�necessary.;„Consult�the�SYSgen�Users�Guide�for�additional�information.  F4. You may now run the SYSgen utility to generate a RMS68K or VERSAdos$ƒboot�module�for�your�target�system. I‚Also�provided�with�this�driver�is�a�library�of�Fortran�callable�assemblyFlanguage subroutines that allow a Fortran application program to issueIcommands directly to the MVME610/620 driver. This library is contained infile M610LIB.RO. I‚If�the�drivers�target�environment�includes�VERSAdos,�you�may�wish�to�runMthe driver test program INPTST.LO to verify that you have an operable SYSgen. L‚This�test�program�allows�you�to�create�multiple�tasks�and�to�issue�commandsGfrom these tasks to the MVME610/620 driver by responding to prompts for1input commands via a single interactive terminal. J‚When�the�program�begins�executing,�the�user�is�prompted�for�the�number�ofKtasks that are to be created. The tasks that are spawned are exact replicasJof one another. After each task initializes itself, it waits for a command)from the user to be issued to the driver. F‚The�name�of�the�first�test�task�is�displayed�and�the�user�is�asked�toNselect a command to be issued to the driver (i.e Open, Close, Enable, Disable,KStatus, or Wait). If the Open command is selected, the user is prompted forKthe channel mnemonic of the desired MVME610/620 board and the number of theFchannel to be opened by the command. The user is then prompted for theFchannel number and configuration for each channel to be opened. If theKClose, Enable, Disable, or Status command is selected, the user is promptedIfor the MVME610/620 board channel mnemonic and the mask of channels to beHaffected by the command. After each command has been issued, the commandJstatus returned by the driver is displayed. If a Status command is issued,.the returned channel status G is also displayed. G‚After�the�command�status�is�returned,�the�user�is�prompted�for�anotherLcommand for the same task. The program will continue to request commands forLthe same test task until a CR only is entered in response to the prompt. TheGuser will then be prompted for commands to the next test task. When theKprogram has prompted for commands for each of the test tasks, it begins theJcycle again by prompting for commands for the first task. This loop may beKterminated by pressing the break key on the terminal after all open channelassignments have been closed. L‚Once�an�interrupt�channel�has�been�opened�and�interrupts�have�been�enabled,Ithe user may connect an input source to the channel to test the interruptFmechanism. Whenever an interrupt generating condition is detected on aKchannel (as specified in the channel configuration), the driver informs theLtest task that opened the channel of the interrupt via an event to the tasksLASQ or by issuing a WAKEUP to the task. When an interrupt event is received,Mthe task provides an external acknowledgement of the interrupt by pulsing oneFoutputs of a MVME625 Digital Output board that is assumed to reside atKaddress $FE6001 of the I/O channel. This pulse may be detected via standardJoscilloscope or by other available means. The program will accomodate uptoKtwo MVME610/620 boards with assumed channel mnemonics of 'IN01' and 'IN02'.NThe acknowledge pulse is sent to a unique MVME625 output for each interruptingchannel as follows: "„MVME610/620ƒInput�Channel„MVME625…mnemonic‰NumberˆOutput"„-----------ƒ-------------„------- †IN01�0�0 †IN01�1�1 †IN01�2�2 †IN01�3�3 †IN02�0�4 †IN02�1�5 †IN02�2�6 †IN02�3�7 G‚When�a�task�is�to�be�notified�of�an�interrupt�via�a�Wakeup,�a�slightlyMdifferent procedure is used. After the channel has been opened and interruptsKhave been enabled, the user enters a Wait command to the task that assignedIthe channel. This command causes the task to be placed in a Wait state soKthat it can respond to the Wakeup to be issued to the driver. When a WakeupBis received, the test task pulses output 7 of the MVME625 board toGacknowledge the interrupt. Since only output 7 is used to acknowledge aNWakeup, receiving of Wakeup's by multiple tasks will result in all acknowledgeNpulses being superimposed on output 7. Also once a task has been placed in theNWait state, issuing a new command to the same task will cause the test program1to be suspended until the task recieves a Wakeup.   GM610DRV.TEST610.SA is an assembly language test program which tests theDMVME610�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver. ééééG éN==============================================================================F====‚NEWS�FILE�FOR�ACO…(MVME615�-�AC�OUTPUT�BOARD)ƒDRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N============================================================================== 8This driver is compatible with both RMS68K and VERSAdos.   .This driver consists of the following files -- ‰MVME615�driver�files:-�9992.&.M615DRV.SA†MVME615�driver�source�file-�9992.&.M615DRV.RO†MVME615�driver�object�file5�9992.&.M615DRV.AF†MVME615�driver�assembly�chain�file  ‰Files�for�allocating�memory:0�9992.&.M615MEM.CIŠFile�included�at�SYSgen�time.0�9992.&.M615MEM.AGŠFile�assembled�at�SYSgen�time   ‰Files‚for�system�configuration:"�9992.&.M615IOC.SIˆCCB�allocations"�9992.&.M615DRV.CIˆSYSGEN�commands3�9992.&.M615DRV.LGˆChain�file�to�link�in�the�driver#�9998.VERSAPT.M615DRV.CF‚Patch�file   ‰FORTRAN�interface�subroutines:0�9992.&.M615LIB.SA…Assembly�language�source�file&�9992.&.M615LIB.AF…Assembly�chain�file�9992.&.M615LIB.RO…Object�file  ‰"News"�file:�9992.&.M615DRV.NW…News�file   "‰Files�to�generate�a�test�program: ;‰9992.M615DRV.TESTAC.SAˆASSEMBLY�language�test�prog.�source=‰9992.M615DRV.TESTAC.AFˆchain�file�for�ASSEMBLY�language�asm.>‰9992.M615DRV.TESTAC.LFˆchain�file�for�LINK�of�asm.�lang.�prog6‰9992.M615DRV.TESTAC.LOˆASSEMBLY�language�test�program @‰The�following�files�are�used�to�generate�a�second�test�program: >‰9992.M615DRV.TEST615.SA‡Assembly�language�test�program�sourceA‰9992.M615DRV.TEST615.AF‡chain�file�for�assembly�language�programA‰9992.M615DRV.TEST615.LF‡chain�file�for�link�of�asm�lang.�program7‰9992.M615DRV.TEST615.LO‡assembly�language�test�program  KThe�MVME615�driver�source�file�is:�9992.&.M615DRV.SA.‚To�assemble�this�file%use the chain file 9992.&.M615DRV.AF.;The following files are used in the assembly of M615DRV.SA:�9995.&.STR.EQ�9995.&.TCB.EQ�9995.&.CCB.EQ�9995.&.LV5.EQ�9995.&.TR1RTCD.EQéAò4ú8 4�9995.&.M615DRV.EQ  >In order to incorporate this driver into your system, you will=have to set some parameters in the .CNFGDRVR.CI file. #This driver requires the following:;‰1)‚Memory�must�be�allocated�for�the�internal�driver�table.9‰2)‚A�channel�control�block�(CCB)�must�be�created�for�the6�commands�issued�for�each�MVME615�board�in�the�system. HThe size of the memory area set aside for the driver table is determinedGby�the�values�of�two�variables�as�specified�by�you�in�the�SYSGEN.‚These$variables are "NVME615" and "NU615". =NVME615ƒThis�is�the�number�of�MVME615�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards6Šon�the�I/O�Channel�(which�is�where�these�boards�are),&Šthe�maximum�value�of�"NVME615"�is�16. 3NU615…This�variable�is�set�to�the�maximum�number�of7Šuser/MVME615�combinations�you�wish�to�allow�at�any�one2Štime.‚Since�it�is�possible�to�have�one�user�using;Šmore�than�one�MVME615�board,�as�well�as�more�than�one�user4Šusing�the�same�MVME615�board,�we�need�the�number�ofŠuser/MVME615�combinations.   ?Example:‚If�user�A�uses�board�#1�and�board�#2,�user�B�uses�just1Šboard�#1,�and�user�C�uses�board�#2�and�board�#3,,Šthere�would�be�5�user/board�combinations�--ŠA/1,�A/2,�B/1,�C/2,�C/3.FIf the configuration of MVME615 boards is the same as in this example,$you would set NVME615=3 and NU615=5. INote that if you set either of these variables to a larger number than isHactually�needed,�the�system�will�still�oH perate�normally.‚This�would�justBresult in having more memory allocated for internal tables than is necessary.  ?To include the MVME615 driver in your SYSgen, do the following: <‰(1)�Use�COPYSGEN�to�get�all�the‚files�needed�for�the�SYSgen�your�SYSgen�user�number.7�NOTE:‚Make�sure�that�argument�5�=�PCDRV�so�the�Process,”Control�Drivers�will�be�copied�by�COPYSGEN. D‰(2)�Set�the�variables�NVME615�and�NU615�in�the�.CNFGDRVR.CI,�file�for�the�processor�board�you�are�using. 8‰(3)�Check�the�file�M615IOC.SI�to�be�sure�that�the�CCB's�conform�to�your�configuration.   FWhen setting up the "CDB" calls please note that each ACO-ID must haveCa�unique�name.‚This�is�also�the�name�any�application�task�would�useFto�address�the�driver�for�a�board.‚The�memory-mapped�I/O�addresses�arealso different for each board. 1After creating and booting your VERSAdos with the>MVME615 driver included, you may want to run the provided test"program to test your VME615 board.  FTESTAC.SA is an assembly language test program which tests the MVME615Cdriver. This program provides as complete and comprehensive test ofCthe driver as is possible. It tests combinations of opens, outputs,Fpulses, closes, status, and error tests, and checks outputs and errors@for�correctness.‚Please�edit�it�before�assembling�to�specify�theIcorrect ACO-ID and memory-mapped I/O address to match your configuration.   ETESTAC.SA is assembled with the chain file TESTAC.AF, and linked with1the file TESTAC.LF. The load module is TESTAC.LO.   GTo use the test program TESTAC.LO, provide an MVME615 board with output indicators on channels 0 thru 7.  +The tests made on the board are as follows:  <‰TEST1�individually�opens�each�channel�on�the�board,�outputs7�to�it,�checks�status,�turns�it�off,�checks�status,�and5�closes.�Any�errors�in�the�process�are�printed�on�the �terminal. >‰TEST2�individually�opens�each�channel,�outputs�to�it�&�checks8�status�until�all�are�on.�Then�it�individually�turns�off9�each�channel�&�checks�status�until�all�are�off.�It�turns'�all�outputs�back�on�for�the�next�test. ?‰TEST3�closes�the�channels.�The�OPERATOR�of�the�test�must�check�that�the�outputs�turn�off. =‰TEST4�opens�all�channels,�turns�the�channels�all�on,�delays,$�turns�all�channels�off,�and�closes. @‰TEST5�individually�opens�each�channel,�commands�a�pulse�output,8�delays�long�enough�to�be�able�to�see�the�pulse�end,�and�closes. ?‰TEST6�opens�four�channels,�commands�pulse�outputs�of�different9�lengths�to�each�simultaneously,�delays�to�be�able�to�see�it�happen,�and�closes. A‰TEST7�opens�channel�two�with�"queue�event"�configuration,�pulses:�output,�waits�for�queue�event,�verifies�the�message�sent, �and�closes.  ?‰TEST8�opens�channel�one�with�"wait�for�wake-up"�configuration,.�pulses�output,�waits�for�wake-up,�and�closes. ;‰TEST9�trys�OUTPUT�ON�with�channels�closed�and�verifies�the�command�error.6�trys�OUTPUT�OFF�with�channels�closed�and�verifies�the�command�error.7�trys�checking�STATUS�with�channels�closed�and�verifies�the�command�error.8�trys�PULSE�output�with�the�channels�closed�and�verifies�the�command�error. =‰TEST10�trys�opening�invalid�channel�numbers�and�verifies�the�command�errors.7�(zero�channels,�more�than�eight�channels,�channel�#�9,(�and�two�channels�with�the�same�number). :‰TEST11�opens�valid�channels�and�trys�invalid�commands�and�verifies�errors.�(�commands�0,�6,�7,�&�9). =‰TEST12�trys�opening�channels�and�then�opening�them�again�and�verifies�the�error.  ;‰Then�the�channels�are�closed.�If�all�tests�are�successful,3�a�message�is�printed�saying�so.�If�any�test�fails,�an�error�message�is�printed.<‰If�a�second�board�is�on�the�system,�it�returns�to�TEST1�and(�repeats�the�tests�for�the�second�board.=‰In�addition,�if�two�boards�are�present,�a�third�pass�through6�the�tests�alternates�between�the�boards�to�check�both�at�the�same�time.  GH M615DRV.TEST615.SA is an assembly language test program which tests theDMVME615�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver. ‰ENDN==============================================================================N==============================================================================' M625DRV NW  *>qqRADDRV NW G G¥qqRIODRV NW h hµqqM600IOC SI ‰ ‰ qqM605IOC SI ’ ’qqM610IOC SI › ›qqM615IOC SI ¤ ¤qqM625IOC SI ­ ­qqRIOIOC SI ¶ ¶ qqRADIOC SI ¿ ¿ qqIOCFAIL RO È ÈqqM600DRV RO Ñ ÑqqM600LIB RO Ú ÚqqM605DRV RO ã ãqqM605LIB RO ì ìqqM610DRV RO õ õqq610LIB ROÿÿÿÿÿÿÿÿqqN==============================================================================F====‚NEWS�FILE�FOR�DCO…(MVME625�-�DC�OUTPUT�BOARD)ƒDRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N============================================================================== 8This driver is compatible with both RMS68K and VERSAdos.   .This driver consists of the following files -- ‰MVME625�driver�files:-�9992.&.M625DRV.SA‚MVME625�driver�source�file-�9992.&.M625DRV.RO‚MVME625�driver�object�file5�9992.&.M625DRV.AF‚MVME625�driver�assembly�chain�file  ‰Files‚for�allocating�memory:/�9992.&.M625MEM.CI‰File�included�at�SYSgen�time0�9992.&.M625MEM.AG‰File�assembled�at�SYSgen�time  ‰Files�for�system�configuration:"�9992.&.M625DRV.CIˆSYSGEN�commands"�9992.&.M625IOC.SIˆCCB�allocations3�9992.&.M625DRV.LGˆChain�file�to�link�in�the�driver#�9998.VERSAPT.M625DRV.CF‚Patch�file   ‰FORTRAN�interface�subroutines:0�9992.&.M625LIB.SA…Assembly�language�source�file&�9992.&.M625LIB.AF…Assembly�chain�file�9992.&.M625LIB.RO…Object�file  ‰"News"�file:�9992.&.M625DRV.NW…News�file   %‰Files�to�generate�the�test�programs: ;‰9992.M625DRV.TESTDC.SAˆASSEMBLY�language�test�prog.�source=‰9992.M625DRV.TESTDC.AFˆchain�file�for�ASSEMBLY�language�asm.>‰9992.M625DRV.TESTDC.LFˆchain�file�for�LINK�of�asm.�lang.�prog6‰9992.M625DRV.TESTDC.LOˆASSEMBLY�language�test�program 3‰9992.M625DRV.TSTDCO.SAˆFORTRAN�test�program�source=‰9992.M625DRV.TSTDLY.SAˆFORTRAN�test�program�subrtn�for�delay?‰9992.M625DRV.TSTPR1.SAˆFORTRAN�test�program�subrtn�error�print;‰9992.M625DRV.TSTDCO.AFˆchain�file�for�FORTRAN�compile�test>‰9992.M625DRV.TSTDCO.LFˆlinks�FORTRAN�test�prog.�&�library�rtn6‰9992.M625DRV.TSTDCO.LOˆFORTRAN�test�program�load�file >‰9992.M625DRV.TEST625.SA‡Assembly�language�test�program�sourceA‰9992.M625DRV.TEST625.AF‡chain�file�for�assembly�language�programA‰9992.M625DRV.TEST625.LF‡chain�file�for�link�of�asm�lang.�program : 8 4 '7 /P 77‰9992.M625DRV.TEST625.LO‡assembly�language�test�program  KThe�MVME625�driver�source�file�is:�9992.&.M625DRV.SA.‚To�assemble�this�file%use the chain file 9992.&.M625DRV.AF.;The following files are used in the assembly of M625DRV.SA:�9995.&.I STR.EQ�9995.&.TCB.EQ�9995.&.CCB.EQ�9995.&.LV5.EQ�9995.&.TR1RTCD.EQ�9995.&.M625DRV.EQ  >In order to incorporate this driver into your system, you will=have to set some parameters in the .CNFGDRVR.CI file.  #This driver requires the following:;‰1)‚Memory�must�be�allocated�for�the�internal�driver�table.9‰2)‚A�channel�control�block�(CCB)�must�be�created�for�the6“commands�issued�for�each�MVME625�board�in�the�system. HThe size of the memory area set aside for the driver table is determinedGby�the�values�of�two�variables�as�specified�by�you�in�the�SYSGEN.‚These$variables are "NVME625" and "NU625". =NVME625ƒThis�is�the�number�of�MVME625�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards6Šon�the�I/O�Channel�(which�is�where�these�boards�are),&Šthe�maximum�value�of�"NVME625"�is�16. 3NU625…This�variable�is�set�to�the�maximum�number�of7Šuser/MVME625�combinations�you�wish�to�allow�at�any�one2Štime.‚Since�it�is�possible�to�have�one�user�using;Šmore�than�one�MVME625�board,�as�well�as�more�than�one�user4Šusing�the�same�MVME625�board,�we�need�the�number�ofŠuser/MVME625�combinations.   ?Example:‚If�user�A�uses�board�#1�and�board�#2,�user�B�uses�just1Šboard�#1,�and�user�C�uses�board�#2�and�board�#3,,Šthere�would�be�5�user/board�combinations�--ŠA/1,�A/2,�B/1,�C/2,�C/3.FIf the configuration of MVME625 boards is the same as in this example,$you would set NVME625=3 and NU625=5. INote that if you set either of these variables to a larger number than isHactually�needed,�the�system�will�still�operate�normally.‚This�would�justBresult in having more memory allocated for internal tables than is necessary.    ?To include the MVME625 driver in your SYSgen, do the following: <‰(1)�Use�COPYSGEN�to�get�all�the�files�needed�for�the�SYSgen�into�your�SYSgen�user�number.2�NOTE:‚Make�sure�argument�5�=�PCDRV�so�the�Process+”Control�Drivers�will�be�copied�by�COPYSGEN D‰(2)�Set�the�variables�NVME625�and�NU625�in�the�.CNFGDRVR.CI,�file�for�the�processor�board�you�are�using. 8‰(3)�Check�the�file�M625IOC.SI�to�be�sure�that�the�CCB's�conform�to�your�configuration. FWhen setting up the "CDB" calls please note that each DCO-ID must haveCa�unique�name.‚This�is�also�the�name�any�application�task�would�useBto�address�the�driver�for�a�board.‚The�memory-mapped�I/O�addresses"are also different for each board.  >After configuring your system and creating a VERSAdos with the>MVME625 driver included, you may want to run the provided test=programs.‚Two�are�assembly�language�and�one�requires�Fortran.ABoth�of�the�test�programs�require�VERSAdos.‚All�the�test�programs=contain the catalog name M625DRV and are in user number 9992.  FTESTDC.SA is an assembly language test program which tests the MVME625Cdriver. This program provides as complete and comprehensive test ofCthe driver as is possible. It tests combinations of opens, outputs,Fpulses, closes, status, and error tests, and checks outputs and errors@for�correctness.‚Please�edit�it�before�assembling�to�specify�theIcorrect DCO-ID and memory-mapped I/O address to match your configuration.   ETESTDC.SA is assembled with the chain file TESTDC.AF, and linked with1the file TESTDC.LF. The load module is TESTDC.LO.   GTo use the test program TESTDC.LO, provide an MVME625 board with output indicators on channels 0 thru 7.  +The tests made on the board are as follows:  <‰TEST1�individually�opens�each�channel�on�the�board,�outputs7�to�it,�checks�status,�turns�it�off,�checks�status,�and5�closes.�Any�errors�in�the�process�are�printed�on�the �terminal. >‰TEST2�individually�opens�each�channel,�outputs�to�it�&�checks8�status�until�all�are�on.�Then�it�individually�turns�off9�each�channel�&�checks�status�until�all�are�off.�It�turns'�all�outputs�back�on�for�the�next�test. ?‰TEST3�closes�the�channelsI .�The�OPERATOR�of�the�test�must�check�that�the�outputs�turn�off. =‰TEST4�opens�all�channels,�turns�the�channels�all�on,�delays,$�turns�all�channels�off,�and�closes. @‰TEST5�individually�opens�each�channel,�commands�a�pulse�output,8�delays�long�enough�to�be�able�to�see�the�pulse�end,�and�closes. ?‰TEST6�opens�four�channels,�commands�pulse�outputs�of�different9�lengths�to�each�simultaneously,�delays�to�be�able�to�see�it�happen,�and�closes. A‰TEST7�opens�channel�two�with�"queue�event"�configuration,�pulses:�output,�waits�for�queue�event,�verifies�the�message�sent, �and�closes.  ?‰TEST8�opens�channel�one�with�"wait�for�wake-up"�configuration,.�pulses�output,�waits�for�wake-up,�and�closes. ;‰TEST9�trys�OUTPUT�ON�with�channels�closed�and�verifies�the�command�error.6�trys�OUTPUT�OFF�with�channels�closed�and�verifies�the�command�error.7�trys�checking�STATUS�with�channels�closed�and�verifies�the�command�error.8�trys�PULSE�output�with�the�channels�closed�and�verifies�the�command�error. =‰TEST10�trys�opening�invalid�channel�numbers�and�verifies�the�command�errors.7�(zero�channels,�more�than�eight�channels,�channel�#�9,(�and�two�channels�with�the�same�number). :‰TEST11�opens�valid�channels�and�trys�invalid�commands�and�verifies�errors.�(�commands�0,�6,�7,�&�9). =‰TEST12�trys�opening�channels�and�then�opening�them�again�and�verifies�the�error.  ;‰Then�the�channels�are�closed.�If�all�tests�are�successful,3�a�message�is�printed�saying�so.�If�any�test�fails,�an�error�message�is�printed.<‰If�a�second�board�is�on�the�system,�it�returns�to�TEST1�and(�repeats�the�tests�for�the�second�board.=‰In�addition,�if�two�boards�are�present,�a�third�pass�through6�the�tests�alternates�between�the�boards�to�check�both�at�the�same�time.      JM625LIB.SA�is�assembled�using�the�M625LIB.AF�chain�file.‚M625LIB.RO�is�theEFORTRAN-callable subroutine which, when called by the user program orJFORTRAN test program, will invoke the appropriate MVME625 driver function.   BTSTDCO.SA is a FORTRAN example test program which uses the driver.EThe purpose in providing the FORTRAN test program is to give the userEa relatively simple way to check out a new system with software whichis known to work correctly.   FTSTDCO.SA, TSTDLY.SA, and TSTPR1.SA are Fortran compiled with the fileETSTDCO.AF.‚File�TSTDCO.LF�links�the�test�routines�with�M625LIB.RO�andFFORTLIB.RO (and FORTVMC.RO for the VMC or VME systems) and creates theprogram TSTDCO.LO.  ETo use test program TSTDCO.LO, provide a board with output indicators+on�channels�0�thru�7.‚Then�RUN�the�program.  BThe result will be observable on the output indicators as follows:  ?‰indicators�0�thru�7�will�turn�on�individually�at�approximately‰one�second�intervals.“FOR�N�=�1�to�8�OPEN�channel�N-1�turn�on�indicator�N-1�wait�one�second�read�output�status�verify�indicator�N-1�on�turn�off�indicator�N-1�CLOSE“NEXT�N A‰indicators�0�thru�7�will�turn�on�one�at�a�time�until�all�are�on.“FOR�N�=�1�to�8�OPEN�channel�N-1�turn�on�indicator�N-1�wait�one�second�read�output�status"�verify�indicators�0�to�N-1�are�on“NEXT�N“wait�one�second“CLOSE“wait�one�second “read�status“verify�outputs�are�off "‰indicators‚0�thru�7�will�turn�on. “OPEN�all“turn�on�all�indicators“wait�one�second“turn�OFF�all�indicators“verify�all�indicators�are�off“CLOSE ,‰indicators�will�be�PULSED�on�one�at�a�time.4‰(default�configuration�-�no�wake-up�or�queue�event) “OPEN�all“FOR�N�=�1�TO�8�PULSE�indicator�N-1�wait�one�second“NEXT�N“CLOSE 7‰CLOSE�all�channels�and�try�all�commands.�Verify�error.“DCOUT‚command “DCOOFFƒ" “DCOSTAƒ" “DCOPLSƒ" “DCOPENƒ"6‰Try�DCOPEN�after�it�is�already�open�and�verify�error.  ;‰Check�for�a�second�board�on�the�system�and�repeat�the�test‰if�one�is�present.  GM625DRV.TEST625.SA is an assembly language test program which J tests theDMVME625�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver. ‰ENDN==============================================================================N==============================================================================éééééN==============================================================================L====‚NEWS�FILE�FOR�RAD1�(REMOTE�ANALOG-TO-DIGITAL�BOARD)�DRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N==============================================================================   3RAD1 Driver is compatible with RMS68K and VERSAdos.   /This release consists of the following files -- ‰RAD1�Driver�files:)“9992.&.RADDRV.SA…RAD1�driver�source�file1“9992.&.RADDRV.AF…RAD1�driver�assembly�chain�file)“9992.&.RADDRV.RO…RAD1�driver�object�file ‰File�for�allocating�memory:,“9992.&.RADMEM.AG…File�for�allocating�memory.“9992.&.RADMEM.CI…File�included�at�sysgen�time ‰Files�for�system�configuration:5“9992.&.RADDRV.CI…Sysgen�include�file�for�RAD1�driver3“9992.&.RADDRV.LG…Chain�file�to�link�in�RAD1�driver!“9992.&.RADIOC.SI…CCB�allocations7“9992.&.IOCFAIL.SA„Board�failure�monitor�routine�source.“9992.&.IOCFAIL.AF„IOCFAIL�assembly�chain�file .“9992.&.IOCINT.LG…Chain�file�to�link�in�IOCINT0“9992.&.IOCFAIL.LG„Chain�file�to�link�in�IOCFAIL"“9998.VERSAPT.RADDRV.CF�Patch�file ‰Files�assembled�during�SYSGEN:4“9992.&.IOCINT.AG…CCB�allocation�routine�source�file ‰FORTRAN�interface�subroutines:/“9992.&.RADLIB.SA…Assembly�language�source�file%“9992.&.RADLIB.AF…Assembly�chain�file“9992.&.RADLIB.RO…Object�file ‰"News"�file:“9992.&.RADDRV.NW…News�file   JThe�RAD1�driver�source�file�is:‚RADDRV.SA�.‚To�assemble�this�file,�use�theKchain�file:‚RADDRV.AF�.‚The�following�equate�files�are�used�in�the�assembly of RADDRV:“9995.&.STR.EQ“9995.&.TCB.EQ“9995.&.CCB.EQ“9995.&.LV5.EQ“9995.&.RADDRV.EQ   BIn order to incorporate the RAD1 driver into your system, you will.CNFGDRVR.CI file.   'The RAD1 driver requires the following:<‰1)‚Memory�must�be�allocated�for�the�internal�driver�tables.9‰2)‚A�channel�control�block�(CCB)�must�be�created�for�the ?A H4 P$ X J 6“data�interrupt�(level�3�interrupt)�on�each�RAD1�board“in�the�system.9‰3)‚A�CCB�must�be�created�for�the�board-failure�interrupt-“(level�4�interrupt)�on�each�RAD1�board�which+“does�not�have�this�interrupt�disabled�by�a“jumper�on�the�board.   IThe size of the memory area set aside for the driver tables is determinedKby the values of two variables as specified by you in .CNFGDRVR.CI.'These variables are "NRAD" and "NURAD". 7NRAD†This�is�the�number�of�RAD1�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards9Šon�the�I/O�Channel�(which�is�where�the�RAD1�boards�are),#Šthe�maximum�value�of�"NRAD"�is�16. 3NURAD…This�variable�is�set�to�the�maximum�number�of4Šuser/RAD1�combinations�you�wish�to�allow�at�any�one2Štime.‚Since�it�is�possible�to�have�one�user�using8Šmore�than�one�RAD1�board,�as�well�as�more�than�one�user1Šusing�the�same�RAD1�board,�we�need�the�number�ofŠuser/RAD1�combinations. ,Example:‚If�user�A�uses�RAD1�#1�and�RAD1�#2,Šuser�B�uses�just�RAD1�#1,%Šand�user�C�uses�RAD1�#2�and�RAD1�#3,+Šthere�would�be�5�user/RAD1�combinations�--ŠA/1,�A/2,�B/1,�C/2,�C/3.CIf the configuration of RAD1 boards is the same as in this example,!you would set NRAD=3 and NURAD=5. INote that if you set either of these variables to a larger number than isHactually�needed,�the�system�will�still�operate�normally.‚This�would�justBresult in having more memory allocated for internal tables than is necessary. JThe variables NRAD and NURAD are defined in the file .CNFGDRVR.CI.FYou will have to edit this file to reflect the correct values of these,variables for your particular configuration.   BThe code to allocate memory for the RAD1 driver internal tables iscontained in the file RADMEM.AG   EYour SYSGEN will set up a task which will allocate the CCB's (channelAcontrol blocks) for the RAD1 boards during system initialization.IThe file IOCINT.AG is included in this release to simplify the allocation2of�the�CCB's.‚The�file�RADIOC.SI�has�been�included5to give you an example of the set-up used to pass theEinformation on each RAD1 board to the program which builds the CCB's. 8When setting up the "CDB" calls, remember the following: '1)ƒThe�RAD-ID�is�a�4-character�mnemonicE…such�as�"RA01"�for�the�first�RAD1�board,�"RA02"�for�the�second,�etc.J…Each�RAD1�board�normally�has�two�CCB's--one�for�interrupt�level�3�(normalF…interrupts)�and�one�for�interrupt�level�4�(board-failure�interrupts).H…While�each�CCB�must�have�a�different�RAD-ID,�the�level-4�CCB�for�a�RAD1H…board�must�use�for�its�RAD-ID‚$00004000�more�than�the�4-byte�ASCII�codeE…for�the�RAD-ID�of�the�corresponding�level-3�CCB.‚This�is�so�that�theI…driver�can�find�the�level-3�CCB�for�a�particular�RAD1�board�when�it�gets…a�level-4�interruptH…(board-failure�interrupt).‚For�example:�if�the�level-3�CCB�has�a�RAD-IDF…of�"RA01",�then�the�level-4�CCB�for�that�board�must�use�"RA41"�as�itsE…RAD-ID.‚Similarly,�if�"RA13"�is�the�level-3�RAD-ID,�then�the�level-4$…CCB�must�have�"RA53"�as�its�RAD-ID. M2)ƒWhen�modifying�the�.CNFGDRVR.CI�file�for�your�particular�situation&…you�should�remember�that�in�the�"CDB"E…macro�calls,�the�address�of�the�memory-mapped�I/O�space�(shared-RAM)G…is�the�same�for�both�CCB's�for�each�RAD1�board.‚Also�the�length�of�theH…memory-mapped�I/O�space�is�set�at�511�since�shared-RAM�starts�on�an�odd(…address�(from�the�68000�point�of�view).   ?IOCFAIL.SA‚is�an�optional�task�which�will�be�"called"�by�having@an event queued to it when a board-failure interrupt is receivedDby�the�driver.‚The�device�table�("DEVTBL")�in�IOCFAIL�must�be�set�upJwith the device mnemonic (RAD-ID) of all the level-4 CCB's that IOCFAIL isIto�be�attached�to.‚The�device�table�in�the�IOCFAIL�file�given�here�is�setNup for two RAD1 boards as a sample -- the level-4 CCB RAD-ID's for these beingL"RA41"�and�"RA42".‚In�its�present�form�IOCFAIL�sets�up�to�receive�the�event,K Kbut�doesn't�really�do�anything�when�the�event�is�received.‚You�will�have�toGadd whatever programming is necessary to the "receive-event" routine toIhave this program perform the processes you deem necessary in the case ofFa�RAD1�board�failure.‚If�you�choose�to�do�nothing�when�a�board�failure;occurs, this task can be left out of the SYSGEN altogether.   CRADLIB.SA‚and‚RADLIB.RO‚are�the�FORTRAN-callable�subroutines�which,Hwhen called by the user program, will invoke the appropriate RAD1 driver function. N==============================================================================éééééN==============================================================================B====‚NEWS�FILE�FOR�RIO�(REMOTE�INPUT�/�OUTPUT)�DRIVER�RELEASE‚===="====‚Last�modified�-�01/31/85¬====N==============================================================================  2RIO Driver is compatible with RMS68K and VERSAdos.   /This release consists of the following files -- ‰RIO�Driver�files:(“9992.&.RIODRV.SA„RIO�driver�source�file0“9992.&.RIODRV.AF„RIO�driver�assembly�chain�file(“9992.&.RIODRV.RO„RIO�driver�object�file-“9992.&.STDMACRO.AI‚Macros�used�in�RIO�driver ‰File�for�allocating�memory:,“9992.&.RIOMEM.AG„File�for�allocating�memory.“9992.&.RIOMEM.CI„File�included�at�sysgen�time ‰File�for�system�configuration:!“9992.&.RIOIOC.SI„CCB�allocations4“9992.&.RIODRV.CI„Sysgen�include�file�for�RIO�driver2“9992.&.RIODRV.LG„Chain�file�to�link�in�RIO�driver.“9992.&.IOCINT.LG„Chain�file�to�link�in�IOCINT"“9998.VERSAPT.RIODRV.CF�Patch�file ‰Files�assembled�during�SYSGEN:4“9992.&.IOCINT.AG„CCB�allocation�routine�source�file ‰Test�program�files/“9992.RIODRV.TESTE.SAƒExample�program�using�RIOªdriver�in�wait_for_event�mode.*“9992.RIODRV.TESTE.AFƒAssembly�chain�file.1“9992.RIODRV.TESTE.LFƒChain�file�to�link�in�TESTE4“9992.RIODRV.TESTE.LOƒAssembly�language�test�program @‰The�following�files�are�used�to�generate�a�second�test�program: =‰9992.RIODRV.TESTRIO.SA‡Assembly�language�test�program�source@‰9992.RIODRV.TESTRIO.AF‡chain�file�for�assembly�language�program@‰9992.RIODRV.TESTRIO.LF‡chain�file�for�link�of�asm�lang.�program6‰9992.RIODRV.TESTRIO.LO‡assembly�language�test�program ‰FORTRAN�interface�subroutines:/“9992.&.RIOLIB.SA„Assembly�language�source�file%“9992.&.RIOLIB.AF„Assembly�chain�file“9992.&.RIOLIB.RO„Object�file ‰"News"�file:“9992.&.RIODRV.NW„News�file  IThe�RIO�driver�source�file�is:‚RIODRV.SA�.‚To�assemble�this�file,�use�theKchain�file:‚RIODRV.AF�.‚The�following�equate�files�are�used�in�the�assembly of RIODRV:K  `: i8 q, y“9995.&.STR.EQ“9995.&.TCB.EQ“9995.&.CCB.EQ“9995.&.LV5.EQ“9995.&.RIODRV.EQ“9995.&.TR1RTCD.EQ  AIn order to incorporate the RIO driver into your system, you will6have to modify items in the .CNFGDRVR.CI file.  &The RIO driver requires the following:<‰1)‚Memory�must�be�allocated�for�the�internal�driver�tables.:‰2)‚A�channel�control�block�(CCB)�must�be�created�for�each5�interrupt�level�for�which�the�RIO�board�is�jumpered.   IThe size of the memory area set aside for the driver tables is determinedCby�two�variables�as�specified�by�you�in�.CNFGDRVR.CI.‚These$variables are "NRIO", and "NRIOINT". 6NRIO†This�is�the�number�of�RIO�boards�which�will�be�on6Šthe�system.‚Since�there�can�be�no�more�than�16�boards8Šon�the�I/O�Channel�(which�is�where�the�RIO�boards�are),#Šthe�maximum�value�of�"NRIO"�is�16. GNRIOINTƒThis�variable�is�set�to�the�number�of�hardware�interrupt�levels>Šfor�which�the�RIO�boards�will�be�jumpered.‚The�minimum�number"Šis�1�and�the�maximum�number�is�4. :Note that if you set either of these variables larger thanHactually�needed,�the�system�will�still�operate�normally.‚This�would�justBresult in having more memory allocated for internal tables than is necessary. LThe variables NRIO and NRIOINT are defined in the file .CNFGDRVR.CI.FYou will have to edit this file to reflect the correct values of these,variables for your particular configuration.   AThe code to allocate memory for the RIO driver internal tables is contained in the file RIOMEM.AG.   EYour SYSGEN will set up a task which will allocate the CCB's (channel@control blocks) for the RIO boards during system initialization.IThe file IOCINT.AG is included in this release to simplify the allocation2of�the�CCB's.‚The�file�RIOIOC.SI�has�been�included5to give you an example of the set-up used to pass theDinformation on each RIO board to the program which builds the CCB's. 8When setting up the "CDB" calls, remember the following: '1)ƒThe�RIO-ID�is�a�4-character�mnemonicE…such�as�"RIO1"�for�the�first�RIO1�board,�"RIO2"�for�the�second,�etc.  CRIOLIB.SA‚and‚RIOLIB.RO‚are�the�FORTRAN-callable�subroutines�which,Gwhen called by the user program, will invoke the appropriate RIO driver function.  FTESTE.SA is an example program written in assembly language which uses?the�RIO�driver.‚The�purpose�in�providing�the�test�program�is�to?give the user a relatively simple way to check out a new system/with software which is known to work correctly. 3To use the test program as is, provide an RIO board:with input relays in locations 0,1,2,3 and 10, and provideDoutput�relays�in�locations�5,7,8,�and�9.‚Connect�an�electronic�pulse@generator to input 0, with the ON pulse time of 10 milliseconds,�Lamp�5�will�alternate�on�/�off�at�the�pulse�repetition�rate.<„>�Lamps�7,8,9�will�turn�on�together�at�each�input�ON�pulse,9†then�will�go�out�in�sequence�7-8-9�(they�are�on�channels†performing�pulsed�output). EChannel 0 is set to cause an interrupt on falling edge, so it's inputBneeds to be low (OFF) for the period of the debounce time which isB512�milliseconds.‚With�the�pulse�generator�set�as�described�above,?this�requirement�is�met.‚If�the�input�pulse�OFF�time�is�reducedCto below 512 milliseconds, the debounce requirement will not be met%and the input signal will be ignored. millisecond�debounce.‚To�make�channel�1�signals�be�recognized,The test program disables channel 1 interrupts after recievingA10 interrupts on that channel, then re-enables them after another610 interrupts (which must come in on another channel). AThe test program sets channel 2 for interrupt on rising edge withBno debounce, and sets channel 3 for interrupt on falling edge with no debounce. EChannel 10 is set for input with interrupts disabled, and will return>it's input state to the 'returned command status' field in theRIO parameter block. FSince the test program is configured to recieve interrupt notificationBvia a 'queued event', each recognized interrupt will place a dummy@message�in�the�test�task�A.S.Q..‚The�routine�'TESTIRQ'�moves�theAmessage from the ASQ (which is not directly acessable by the user?task�'TESTE')�to�the�task�reciever�buffer,�defined�as�RCVBUF‚inTESTE. FRIODRV.TESTRIO.SA is an assembly language test program which tests the@RIO�driver.‚This�program�prompts�the�user�to�run�a�subset�of�allDcommands�available�in�the�driver.‚It�can�be�used�as�a�first�check�ofAthe hardware and as an example of writing commands to the driver. N==============================================================================ééé*‰&.M600IOC.SIG*======================================================================*E* THIS IS THE CODE NEEDED TO SET UP CCB'S FOR MVME 600 or 601 BOARDS.*@* Add a CCB definition for each additional board in your system.A* Note that the memory-mapped I/O address must be unique for eachB* board, must not conflict with any other board in the system, andF*�must�match�the�on-board�jumper�selections.‚The�I/O�Channel�interruptC* vector number and hardware interrupt level must correspond to the* jumpers on the board.*G*======================================================================*M600†EQU„\M600DRV)L600$01ƒSET„\L600$01‹Set�board�#1�address)L600$02ƒSET„\L600$02‹Set�board�#2�address***ˆSet�up�600/601�board�CCB*@ CDB XOPEXC,'AD01',$80,0,M600,0,L600$01,1,\IOCVEC1,\IOCLVL1,$FF,&0,0,0,0,0,0,0,0,0,0,0*N*-----------------------------------------------------------------------------*�IFGE…\NVME600-2**ˆSet�up�600/601�board�CCB*@ CDB XOPEXC,'AD02',$80,0,M600,0,L600$02,1,\IOCVEC1,\IOCLVL1,$FF,&0,0,0,0,0,0,0,0,0,0,0 ENDCééL é �!*ˆ&.M605IOC.SIG*======================================================================*@* THIS IS THE CODE NEEDED TO SET UP A CCB FOR ONE MVME605 BOARD.*@* Add a CCB definition for each additional board in your system.@* An address for a second MVME605 board can be offset $100 bytes* from the first.=* For example, another MVME605 board could have an address of* \IOCBASE+$1D01.A* Note that the memory mapped I/O address must be unique for eachB* board, must not conflict with any other board in the system, andB*�must�match�the�on-board�jumper�selections.‚Since�this�board�doesG* not generate interrupts it may be nice to choose the lowest interrupt5* level and software priority level for CCB chaining.*G*======================================================================*/M605†EQU„\M605DRV‹Set�the�address�of�the�driver-L605$01ƒSET„\L605$01‹Set�the�board�#1�address**J CDB XOPINH+XOPEXC,'DAC1',$80,254,M605,0,L605$01,31,\IOCVEC1,\IOCLVL1,$50,&„0,0,0,0,0,0,0,0,0,0,0éééé Š*ˆINCLUDE‚&.M610IOC.SIG*======================================================================*E* THIS IS THE CODE NEEDED TO SET UP CCB'S FOR MVME 610 or 620 BOARDS.*@* Add a CCB definition for each additional board in your system.A* Note that the memory mapped I/O address must be unique for eachB* board, must not conflict with any other board in the system, andM* must match the on-board jumper selections. The I/O Channel interrupt vectorM* number and hardware interrupt level must correspond to the interrupt jumper* on the board.*G*======================================================================*/M610†EQU„\M610DRV‹Set�the�address�of�the�driver-L610$01ƒSET„\L610$01‹Set�the�board�#1�address-L610$02ƒSET„\L610$02‹Set�the�board�#2�address**@ CDB XOPEXC,'IN01',$80,0,M610,0,L610$01,3,\IOCVEC1,\IOCLVL1,$FF,&„0,0,0,0,0,0,0,0,0,0,0**�IFGE…\NVME610-2*@ CDB XOPEXC,'IN02',$80,0,M610,0,L610$02,3,\IOCVEC2,\IOCLVL2,$FF,&„0,0,0,0,0,0,0,0,0,0,0 ENDCéM ééé “*ˆ&.M615IOC.SIG************************************************************************0*�Code�to�be�included�in‚IOCINT.AG‚to�set�up�for,*’building�the�CCB's�for�the�MVME615�boards.*G*======================================================================*@* THIS IS THE CODE NEEDED TO SET UP A CCB FOR ONE MVME615 BOARD.*@* Add a CCB definition for each additional board in your system.E* An additional board may be placed at an offset of $2 bytes from the@* first, for example, on the VME110, two boards may be placed at?* $FE6003 and $FE6005, provided these addresses do not conflict+* with any other board's memory mapped I/O.A* Note that the memory mapped I/O address must be unique for eachB* board, must not conflict with any other board in the system, andB*�must�match�the�on-board�jumper�selections.‚Since�this�board�doesG* not generate interrupts it may be nice to choose the lowest interrupt5* level and software priority level for CCB chaining.*G*======================================================================*/M615†EQU„\M615DRV‹Set�the�address�of�the�driver-L615$01ƒSET„\L615$01‹Set�the�board�#1�address**B CDB XOPEXC,'ACO1',$80,254,M615,0,L615$01,1,\IOCVEC1,\IOCLVL1,$50,&„0,0,0,0,0,0,0,0,0,0,0ééé œ*ˆ&.M625IOC.SIG************************************************************************&*�Code�to�be�included�in‚IOCINT.AGƒfor,*’building�the�CCB's�for�the�MVME625�boards.*G************************************************************************G*======================================================================*@* THIS IS THE CODE NEEDED TO SET UP A CCB FOR ONE MVME625 BOARD.*@* Add a CCB definition for each additional board in your system.E* An additional board may be placed at an offset of $2 bytes from the@* first, for example, on the VME110, two boards may be placed at?* $FE6001 and $FE6003, provided these addresses do not conflict+* with any other board's memory mapped I/O.A* Note that the memory mapped I/O addresM s must be unique for eachB* board, must not conflict with any other board in the system, andB*�must�match�the�on-board�jumper�selections.‚Since�this�board�doesG* not generate interrupts it may be nice to choose the lowest interrupt5* level and software priority level for CCB chaining.*G*======================================================================*/M625†EQU„\M625DRV‹Set�the�address�of�the�driver-L625$01ƒSET„\L625$01‹Set�the�board�#1�address**B CDB XOPEXC,'DCO1',$80,254,M625,0,L625$01,1,\IOCVEC1,\IOCLVL1,$50,&„0,0,0,0,0,0,0,0,0,0,0éé ¥ *ˆ&.RIOIOC.SI*RIO†EQU‡\RIODRVLRIO$01‚SET‡\LRIO$01*$*ˆADD�NECESSARY�CCB�INFORMATION�HERE**ˆSET�UP�RIO�CCB'S*B CDB XOPEXC,'RI01',$80,254,RIO,0,LRIO$01,31,\IOCVEC3,\IOCLVL3,$50,&0,0,0,0,0,0,0,0,0,0,0ééééééé ®  *ˆ&.RADIOC.SI*RAD†EQU‡\RADDRVLRAD$01 SET \LRAD$01**ˆSET�UP�RAD�CCB'S4*ƒ(MEMORY�LENGTH�IS�511�SINCE�WE�START�AT�ODD�ADDR.)*C CDB XOPEXC,'RA01',$80,254,RAD,0,LRAD$01,511,\IOCVEC3,\IOCLVL3,$50,&0,0,0,0,0,0,0,0,0,0,0 C CDB XOPEXC,'RN A41',$80,254,RAD,0,LRAD$01,511,\IOCVEC4,\IOCLVL4,$50,&0,0,0,0,0,0,0,0,0,0,0éééééé · K1IOCFAIL ASREL' IOCFAIL SA3(…Board Fail Montior Task 4-28-822 žF30042882 1RA41RA42OúÿþCúÿÜ IB™B™ü ü "ü Eú6"ÊBQpNAF3f>EúÿªJ’g"HüB2ü"Ú2ü B™B™p4 Ap(ÀüF3 Kèÿ"›ÀJ-sf|aþ2Lß,|Ns"m"Jj,J-sf PíqJ)`Hç~0B-s mv$I3 |aþ0Lß ~<Nu4éé É,1A2DLIB ASREL' M600LIB SA'(…e2IBLDCB ®IA2DCLS XIA2DOPN IA2DMRD ¬IA2DMRS VIA2DSTP  )" 3H3 //MúA ú0<`B6R@ @oô¼ o-P o-H1| o=Pp,, (-"¸´pg XGSfô0<ýF3 NurB‚½ñfa3¼ÿÿ\�R‚ ‚fæB€`ø m"01¼¼Nu/ >+F3 c c &_0<÷`ÄSG\‹2 Ac &_0<ö`®4,:ÊüSB/ "Naô`F3 NqLßB0<`Š F$m""WX‰Âü½ñg Lß 0<ò`j61"_*JXg. ‚ü<F3 Ìü4Hõ¯`p$ „“É2hÿþAúJ2<p"N@`6`þ/8„0à\„0QÊÿÀQÏÿ`0&_J@F3 kg NpN@``þa4B@6€B€Nu6€NuHç?>|øÿBB AÄü4Lð¯ pÂüF3 a¢Lß|üNsHçÿþ N&( B‚4< HB‚ü4pN@``LßÿNu`øfJ…g i6p3 N@`` J…gJ0PfT—T—NuNu4ééé Û;1FTDAC ASREL' M605LIB SA((…DAC subroutinesB2ILOC ŒIDACCLS ,IDAOPEN IDACNVT >)’F3 Hç€paP$¼B€0*ã€\€2€ KpJ+g&/ ?? k áJ„‚F3 (j8N”`Nq>2&_Nu k (j