IMD 1.17: 11/11/2014 10:55:00 82VKXSVRDOS B* VERSADOS/RMS68K SRC/OBJ 4.4 (NOT BOOTABLE) SN=49367 7 OF 30  SR07q82VKXSVRDOS 0420¥n-h:p<xD€>ˆ;�9˜G E¨<°A¸FÀ  C*‚The�Rockwell�68560�Protocol�Communications�Controller�(MPCC)�is�aK* single channel communications device capable of full duplex, asynchronousI* or synchronous protocol. The register offsets for this device are shownE* below followed by the bit and field definitions used to program the&* R68560 for operation on the MVME050.*BMPC_DEV1‚EQU�$FF1001ˆBase�address�of�the�serial�port�1�on�MVME050.BMPC_DEV2‚EQU�$FF1041ˆBase�address�of�the�serial�port�2�on�MVME050.$*œAll�registers�have�odd�addressess.O*------------------------------------------------------------------------------&MPC_RSRƒEQU‚0�Receiver�Status�Register'MPC_RCRƒEQU‚2�Receiver�Control�Register$MPC_RDRƒEQU‚4�Receiver�Data�Register8MPC_RIVN‚EQU‚8�Receiver�Interrupt�Vector�Number�Register2MPC_RIER‚EQU‚10ŒReceiver�Interrupt�Enable�RegisterO*------------------------------------------------------------------------------*MPC_TSRƒEQU‚16ŒTransmitter�Status�Register+MPC_TCRƒEQU‚18ŒTransmitter�Control�Register(MPC_TDRƒEQU‚20ŒTranmistter�Data�Register*ƒfor�the�MPCC�driver.‚CMR�automatically�allocates�one�page�ofA*ƒmemory�($100�bytes)�for�the�CCB,�and�our�variable�EXTCCBSZ�willB*ƒreside�in�the�CMR�parameter�table�at�the�beginning�of�the�driver8*ƒto�tell�CMR�how�many�extra�pages�of�memory�are�needed.**CCBSIZEB�EQU‡*PAGESIZE�EQU‡$100L1‡SET‡CCBSIZEB+PAGESIZE-1CCBSIZE‚EQU‡L1/PAGESIZEEXTCCBSZ�EQU‡CCBSIZE-1ŠPAGEJ***************************************************************************+*‰SERVICE�VECTOR�TABLE,�REVISION�INFO,�ETC.*@*‰This�table�is�examined�by�CMR�when�the�channel�is�allocated�toC*‰determine�where�to�go�for�interrupts,�commands,�&�initialization.<*‰It�must�always�be�at�the�very�top�of�the�driver�code.‚Also>*‰included�is�a�parameter�telling�the�number�of�extra�pages�of >*‰memory�to�include�in�the�CCB,�and�information�describing�the*‰revision�of�the�driver.*L**************************************************************************** ŠSECTION‚0ŠOPT„BRS MPCCDRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!*=ŠDC.LƒINTERRUPT-MPCCDRV‚Address�of�interrupt�service�routine.9ŠDC.LƒCOMMAND-MPCCDRV„Address�of�command�service�routine.5ŠDC.LƒINIT-MPCCDRV‡Address�of�initialization�routine.ŠDC.Lƒ0’Reserved. **‚Other�CMR�parameters.*7ŠDC.BƒEXTCCBSZ‹#�of�extra�pages�in�the�CCB.‚The�CCB�may)*§be�any�size�from�1�to�256�pages�(a�page'*§is�256�bytes):‚if�this�field�is�0,�it*§will�be�1�page,�etc.ŠDC.Bƒ0,0,0ŽReserved.ŠDC.Lƒ0,0,0ŽReserved. **‚Revision�info:*/ŠDC.Bƒ'102384'‹Date�of�last�assembly�as�MMDDYY.1ŠDC.Bƒ'�'�Space�indicates�no�patches�to�.LO�file.)ŠDC.Bƒ'4'�Major�VERSAdos�revision�number.*‰PAGEO********************************************************************************;*ˆJump�table�for�use�by�the�generic�terminal�driver�TERMLIB*O******************************************************************************* ‰BRA.L…PUT_CHAR ‰BRA.L…CK_TBE‰BRA.L…DDP_RESET ‰BRA.L…SETUP‰BRA.L…CLOCK_RESET‰BRA.L…GET_STAT‰BRA.L…DDP_STOP‰BRA.L…DDP_UNSTOP‰BRA.L…DDP_BEG_BREAK‰BRA.L…DDP_END_BREAK‰PAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INITIALIZATION�ROUTINE*>*‰This�routine�is�called�by�CMR�when�the�channel�is�allocated.9*‰Its�purpose�is�to�set�up�things�for�command�service�and7*‰interrupt�service.‚The�major�functions�performed�are:*9*Š1.�Determine�if�the�second�serial�port�is�present�(some8*Žversions�of�board�may�have�just�one�port)�and�mark�the*Žchannel�down�if�its�absent.?*Š2.�Device-Independent�initialization�in�the�call�to�TERM_INIT"*�to�initialize�the�CCB�variables.9*Š3.�Device-Dependent�initialization�in�a�call�guarded�to#*�DO_INIT�to�initialize�the�device.*@*‰We�got�here�through�a�JSR�from�CMR,�and�will�exit�with�an�RTS.>*‰All�registers�have�been�saved�by�CMR�and�may�be�used�freely.?*‰Entry�is�at�interrupt�level�0,�and�we�are�in�supervisor�mode.**‰Entry:‚A5�=�address�of�CCB.*:*‰Calls:‚TERM_INIT�in�the�generic�terminal�driver�TERMLIB./*‘MARK_DOWN�in�TERMLIB�if�Port�2�doesn't�exist.*#*‰Exit:ƒCMR�(via�RTS)�if�all�is�OK.'*‘KILLER�if�exec�won't�allocate�memory,.*’or�can't�get�background�routine�entry�point.*J**************************************************************************J**************************************************************************J**************************************************************************ŠDS…0 ŠPAGEINIT:***‚Check�for�the�presence�of�serial�port�2.*2ŠMOVE.L�CCBCHB(A5),A0†Get�the�address�of�our�port.BŠCMP.B‚#$FF,MPC_PSR1(A0)‚This�value/location�guaranteed�if�absent.:ŠBEQ.S‚NO_PORT2‹Branch�out�of�INIT�because�port�not�there.*>*‚Perform�the�device-independent�initialization�by�calling�the'*‚generic�routine�TERM_INIT�in�TERMLIB.*.‰JSR‡TERM_INIT‹Do�the�device-independent�stuff2‰IFƒƒTHEN…Something�went�wrong�with�TERM_INIT.4‰IFƒƒTHEN„The�exec�call�failed�and�we�cannot�get!*œthe�scheduler's�entry�point�!!!ŽTR0$.KILLER‚,‰ELSE�RTS�The�channel�is�down�!!‰ENDI‰ENDI*;*‚Perform�the�minimum�device-deoendent�initialization�using@*‚call�guarded�to�the�EXEC�for�a�routine�resident�in�background.*5‰LEA‡DO_INIT(PC),A0†Device-dependent�routine�address.-‰MOVE.L„#T0GUARD,D0‰Call�guarded�to�the�EXEC.‰TRAP†#0‰RTS 1NO_PORT2�JSR‡MARK_DOWN‹Set�the�channel�down�flag.‰RTS‰PAGEJ**************************************************************************J************************************************************************** J****************************************************************************‰COMMAND�SERVICE�ROUTINE*>*‰We�get�entered�here�when�the�attached�task�(IOS)�invokes�CMR?*‰via�a�TRAP�1�with�an�INITIATE�I/O�parameter�block�to�process.>*‰CMR�has�already�checked�the�CMR�parameter�block�to�ensure�it<*‰resides�within�the�address�space�of�the�attached�task.‚IOSA*‰has�already�validated�the�IOCB,�except�for�the�buffer�addresses *‰therein.*@*‰We�got�here�through�a�JSR�from�CMR,�and�will�exit�with�an�RTS.>*‰All�registers�have�been�saved�by�CMR�and�may�be�used�freely.?*‰Entry�is�at�interrupt�level�0,�and�we�are�in�supervisor�mode.*5*‰Entry:�A2�=�physical�address�of�CMR�parameter�block*�A5�=�physical�address�of�CCB*9*‰Calls:�TERM_COMMAND�in�generic�terminal�driver�TERMLIB.*3*‰Exit:‚D0�=�results�of�parameter�block�validation:3*•always�0�in�our�case,�indicating�it�was�OK,�since2*•IOS�will�not�send�us�any�request�except�HALT�I/O/*•if�we�are�already�busy,�and�CMR�makes�all�the*•other�checks.**J**************************************************************************J**************************************************************************J************************************************************************** COMMAND: *,*‚Perform�any�device-dependent�stuff�here...* *=*‚We�have�received�a�command,�so�we�know�there�is�someone�outI*‚there�to�talk�to.‚If�the�guy�who�reports�breaks�is�asleep,�wake�him�up.* %ŠJSR…TERM_COMMAND†Perform�the�commandŠRTS—return�to�CMR.ŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INTERRUPT�HANDLING�ROUTINE*<*‰This�routine�completes�I/O�requests�started�by�the�command:*‰service�routine.‚It�is�entered�at�the�interrupt�priority;*‰level�of�interrupts�on�this�channel,�and�is�essentially�a9*‰subroutine�to�the�first�level�interrupt�handler�in�CMR.*:*‰Entry:�D0,A0,A1�have�been�saved�by�CMR�and�are�available*�A5�=�address�of�CCB*9*‰Exit�is�always�via�RTS,�which�takes�us�back�to�CMR.‚The3*�carry�bit�is�examined�by�CMR�to�determine�whether7*�the�driver�handled�the�interrupt�or�whether�it�should4*�pass�the�interrupt�on�to�the�next�guy�in�the�chain*�on�that�vector:*��=�'I�handled�it'**‰Stack:*�(A7)+8�.�.�. *�(A7)+4�longword�return�address6*�(A7)ƒlongword�saved�contents�of�D1�(must�be�restored*—before�exit�to�CMR)*J**************************************************************************J**************************************************************************J************************************************************************** INTERRUPT: $* Clear the interrupt at the BIM #1: 5ŠMOVE.B�CCBTYPE(A5),D0‰Get�our�channel�type�from�CCB.(ŠCMP.B�#XTMPC1,D0ŽAre�we�serial�port�#1? ŠIF��THEN’If�we're�no.�1....<‹MOVE.B�#BIM_SET,BIM_CTL0…Set�control�register�0�of�the�BIM.ŠELSEšIf�we're�no.�2....<‹MOVE.B�#BIM_SET,BIM_CTL1…Set�control�register�1�of�the�BIM.ŠENDI 3ŠMOVE.L�CCBCHB(A5),A1†A1�<--�address�of�our�device. "ŠPUSH.L�D1‘Get�some�working�space.7ŠMOVE.B�MPC_RSR(A1),D1…Copy�of�receive�status�register.ŠMOVE.B�MPC_RIER(A1),D0*ŠAND.B‚D0,D1ŽHave�we�received�a�character?+ŠBEQ.S‚INT10ŽNo�character�received�if�zero.5ŠAND.B‚#$1E,D1ŒGet�rid�of�all�bits�except�error�bits.*ŠBNE.S‚INTERR�Branch�to�process�the�error.1ŠBRA.S‚RCA�No�error,�branch�to�process�character. PAGE @INT10…MOVE.B�MPC_TSR(A1),D1…Copy�of�transmitter�status�register.ŠMOVE.B�MPC_TIER(A1),D0*ŠAND.B‚D0,D1ŽIs�our�transmit�buffer�empty?1ŠBNE.S‚TBE�Branch�to�process�empty�buffer�if�yes. 7ŠMOVE.B�MPC_SISR(A1),D1„Copy�of�serial�status�register.ŠMOVE.B�MPC_SIER(A1),D0 ŠAND.B‚D0,D17ŠBNE.S‚ESC�If��then�process�external�status�change.+ŠPOP.L‚D1‘If�we�get�here,�must�not�be�mine. NOT_FOR_ME ŠMOVEQ‚#0,D0 ŠADDQƒ#1,D0ŠRTSŠPAGE J***************************************************************************)*‰TRANSMIT�BUFFER�EMPTY�INTERRUPT�HANDLER*?*‰The�R68560's�transmit�buffer�just�became�empty,�so�if�we�have+*‰more�characters�to�send�we�can�do�it�now.*$*‰Entry:�A1�=�address�of�our�device.*�A5�=�address�of�CCB.-*�D1.B�=�copy�of�transmitter�status�register.*9*‰Calls:�TERM_TBE�in�the�generic�terminal�driver�TERMLIB.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*O******************************************************************************* TBE:<ŠMOVE.B�#0<*‰Calls:�TREM_PUT_CHAR�in�the�generic�terminal�driver�TERMLIB.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** RCA:4ŠMOVE.B�MPC_RDR(A1),D0‡Get�the�char�from�the�R68560.*ŠMOVE.B�#$FF,MPC_RSR(A1)…Clear�the�status.5ŠJSR„TERM_GOT_CHARˆDo�the�device-independent�stuff...)ŠBRA.S‚INT_EXIT�Exit�from�this�interrupt.ŠPAGEJ***************************************************************************!*‰DETECTED�EXTERNAL�STATUS�CHANGE*?*‰The�R68560�detected�a�change�in�status�on�the�DCD�input�line.8*‰We�need�to�activate�the�send�event�background�routine.*$*‰Entry:�A1�=�address�of�our�device.*�A5�=�address�of�CCB(*�D1.B�=�copy�of�serial�status�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** ESC:=‰BSET�#DCDX,MPC_SISR(A1)ˆClear�and�test�the�DCD�status�bit...3‰IFƒ�THEN�If�its�set,�then�see�if�we�handle�it.>ŠBTSTW‚#IOADCD,CONFIG+IOSATW(A5)‚If�the�attributes�word�in�the4ŠIF…�THENŠconfiguration�says�we're�reporting�DCD3‹BKGRND�BREAK�Handle�a�DCD�transition�with�a�BREAK.ŠENDI‰ENDI ‰BRA.S�INT_EXIT‰PAGEJ***************************************************************************#*‰FOUND�ERROR�ON�RECEIVED�CHARACTER*<*‰The�R68560�detected�an�error�in�the�process�of�receiving�a<*‰character.‚We�need�to�record�this�information�so�that�when<*‰the�corresponding�data�is�requested�from�the�receive�queue*‰we�can�report�an�error.*$*‰Entry:�A1�=�address�of�our�device.*�A5�=�address�of�CCB2*�D1.B�=�copy�of�receiver�status�register,�showing*—error�bits�only!*8*‰Calls:�LOG_ERR�in�the�generic�terminal�driver�TERMLIB.4*�TERM_BREAK�in�the�generic�terminal�driver�TERMLIB.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** INTERR:.ŠMOVE.B�MPC_RDR(A1),D0ˆRead�the�data�register.*ŠMOVE.B�#$FF,MPC_RSR(A1)†Clear�the�status. 'ŠBTST‚#BRK,D1�Have�we�received�a�break?1ŠIF„�THENŽIf�the�received�break�bit�is�set...!‹BRA.S‚PROCBRKŽProcess�the�break!ŠENDI /ŠBTSTƒ#OE,D1�Perhaps�this�was�an�overrun�error.0ŠIF…�THEN�If�the�overrun�error�bit�is�set.../‹PUT_BYTE�OVERRUN,D0‰Get�the�proper�error�code.‹JSR„LOG_ERRŽLog�the�error.+‹BRA„INT_EXIT�And�exit�from�this�interrupt.ŠENDI &ŠBTST„#PE,D1�How�about�a�parity�error?/ŠIF†�THENŒIf�the�parity�error�bit�is�set...0‹PUT_BYTE�PAR_FRAM,D0ˆGet�the�proper�error�code.‹JSR„LOG_ERRŽLog�the�error. *‹BRA„INT_EXIT�And�exit�from�the�interrupt.ŠENDI )ŠBTST„#FE,D1�Last�call�for�framing�error.0ŠIF†�THENŒIf�the�framing�error�bit�is�set...0‹PUT_BYTE�PAR_FRAM,D0ˆGet�the�proper�error�code.‹JSR„LOG_ERRŽLog�the�error.*‹BRA„INT_EXIT�And�exit�from�the�interrupt.ŠENDI *ŠBRA„INT_EXITŽJust�in�case�we�get�here....ŠPAGE DPROCBRKƒMOVE.B�#1<�=�transmit�buffer�not�empty*��=�transmit�buffer�empty*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*M***************************************************************************** CK_TBE:>ŠBTST.B�#TD,MPC_TSR(A1)ˆTest�transmit�buffer�empty�bit�in�TSR.*ŠRTS›Must�return�with�condition�codes�set.ŠPAGEH************************************************************************* *ˆDEVICE�DEPENDENT�RESET�ROUTINE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�toB*ˆperform�a�minimum�reset�of�the�device.�For�the�R68560�this�means6*ˆclearing�any�error�status�and�enabling�the�receiver.*;*ˆWe�are�running�in�background�when�this�routine�is�called.**ˆEntry:�A5�=�address�of�CCB**�Interrupt�level�on�entry�is�0**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*E*********************************************************************  DDP_RESET: 3ŠMOVEM.L�A1,-(A7)ŽSave�used�registers�on�the�stack..ŠMOVE.L�CCBCHB(A5),A1ŠA1�<--�addr�of�our�port.9ŠMOVE.B�#$FF,MPC_RSR(A1)‡Clear�any�receiver�error�status.<ŠMOVE.B�#$FF,MPC_TSR(A1)‡Clear�any�transmitter�error�status.2ŠMOVE.B�#1<*ˆon�the�MVME050�board.‚This�table�allows�us�to�convert�from�a@*ˆVERSAdos�baud�rate�code�to�the�baud�rate�divider�(LSH�and�MSH)C*ˆand�clock�control�code�we�need�to�write�to�the�on-board�registers*ˆof�the�R68560.*,*ˆThe�table�contains�4�parameters�per�entry:7*Œ1st�entry�is�the�least�siginificant�half�(LSH)�of�the.*’baud�rate�divider�to�be�written�to�MPC_BRD1.5*Œ2nd�entry�is�the�most�significant�half�(MSH)�of�the.*’baud�rate�divider�to�be�writtem�to�MPC_BRD2.5*Œ3rd�entry�is�the�clock�control�register�value�to�be*’written�to�MPC_CCR4*Œ4th�entry�is�undefined�at�this�time�-�set�to�zero.*8*ˆNot�all�of�the�VERSAdos�baud�rate�codes�are�supported.;*ˆThe�generic�terminal�driver�TERMLIB�does�a�check�on�valid@*ˆbaud�rates�for�a�specific�channel�so�we�should�never�be�passed9*ˆan�unsupported�baud�rate�code.‚Just�in�case,�we�set�the#*ˆunsupported�entries�to�9600�baud.*O******************************************************************************* BAUD_ASYNC‰DC.B‚0,$1D,$68,$2B‡50‰DC.B‚0,$0D,$68,$2B‡75‰DC.B‚0,$1D,$2F,$59‡110‰DC.B‚0,$0D,$39,$DF‡134.5‰DC.B‚0,$1D,$22,$B9‡150‰DC.B‚0,$0D,$1A,$0B‡3009‰DC.B‚0,$1D,$00,$8B‡600„****�not�supported�-�default�9600‰DC.B‚0,$1D,$04,$57‡1200‰DC.B‚0,$0D,$04,$57‡1800:‰DC.B‚0,$1D,$00,$8B‡2000ƒ****�not�supported�-�default�9600‰DC.B‚0,$0D,$03,$41‡2400‰DC.B‚0,$0D,$02,$2C‡3600‰DC.B‚0,$1D,$01,$16‡4800‰DC.B‚0,$0D,$01,$16‡7200‰DC.B‚0,$1D,$00,$8B‡9600‰DC.B‚0,$0D,$00,$68‡19200‰DC.B‚0,$0D,$00,$34‡38400PASSTBL‚DS.W‚0 PAGE*+*ˆSet�Protocol�Select�Register�2‚(MPC_PSR2)/*Œstart�with�byte�mode�[7]�and�async�mode�[2:0]*ŠPUT_BYTE�BYTE+ASYNC,D0  * Word length control [4:3]:ŠBTSTW�#IOABITS,IOSATW(A0)…Add�in�bits�per�character�info. ŠIF„�THEN ‹OR.B�#BIT7,D0�7�bits/character.ŠELSE ‹OR.B�#BIT8,D0�8�bits/character.ŠENDI * Stop Bit Length [6:5]:ŠBTSTW�#IOASTPB,IOSATW(A0)…Add�in�the�number�of�stop�bits. ŠIF„�THEN‹OR.B�#SB1,D0‘1�stop�bit.ŠELSE‹OR.B�#SB2,D0‘2�stop�bits.ŠENDI ,ŠMOVE.B�D0,MPC_PSR2(A1)‡Tell�it�to�the�chip. *&*ˆSet�Error�Control�Register�(MPC_ECR)%*Œstart�with�no�parity,�no�CRC�checks*ŠMOVEQ.L�#0,D0 * Parity Mode [7:6]3ŠBTSTW�#IOAUSEP,IOSATW(A0)…If�we're�using�parity... ŠIF„�THEN(‹OR.B�#PARENAB,D0�Set�enable�parity�bit.0‹BTSTW�#IOAPRTY,IOSATW(A0)„If�its�even�parity... ‹IF„�THEN&ŒOR.B�#PAREVEN,D0ŒSet�even�parity�bit.‹ENDIŠENDI +ŠMOVE.B�D0,MPC_ECR(A1)ŠTell�it�to�the�chip. PAGE**ˆSet�up�for�interrupts.* #* Set the interrupt vector numbers.6ŠMOVE.B�CCBVECT(A5),D0‰Get�the�vector�number�from�CCB.7ŠMOVE.B�D0,MPC_RIVN(A1)ˆSet�vector�number�for�receiver.:ŠMOVE.B�D0,MPC_TIVN(A1)ˆSet�vector�number�for�transmitter.5ŠMOVE.B�D0,MPC_SIVN(A1)ˆSet�vector�number�for�serial.&*§CMR�forces�us�to�use�same�for�all�3. * Program the BIM #15ŠMOVE.B�CCBTYPE(A5),D0‰Get�our�channel�type�from�CCB.(ŠCMP.B�#XTMPC1,D0ŽAre�we�serial�port�#1? ŠIF��THEN’If�we're�no.�1....<‹MOVE.B�#BIM_SET,BIM_CTL0…Set�control�register�0�of�the�BIM.ŠELSEšIf�we're�no.�2....<‹MOVE.B�#BIM_SET,BIM_CTL1…Set�control�register�1�of�the�BIM.ŠENDI**ˆClear�the�FIFO*/ŠMOVEQ‚#7,D0’There�are�eight�bytes�in�the�FIFO..CLRFIFOƒMOVE.B�MPC_RDR(A1),D1‰Read�them�out....ŠDBRAƒD0,CLRFIFO�Decrement...until�done...then9ŠMOVE.B�#$FF,MPC_RSR(A1)‡Reset�any�receiver�error�status.**ˆNow�set�our�device�as�ready.*/ŠMOVE.B‚#READY,MPC_SICR(A1)„Assert�DTR�and�RTS./ŠMOVE.B‚#0<�THEN�*6ŠMOVE.B�#UNREADY,MPC_SICR(A1)�make�our�port�'unready'.ŠENDI 2* Enable those interrupts we'd like to know about.6ŠMOVE.B�#INTR,MPC_RIER(A1)…Enable�receiver�interrupts.4ŠMOVE.B�#INTS,MPC_SIER(A1)…Enable�serial�interrupts. **ˆRestore�registers�and�return.*ŠMOVEM.Lƒ(A7)+,D0/D1/A0/A1ŠRTSŠPAGEO*********************************************************************************ˆRESET�THE�CLOCK*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to3*ˆchange�the�clock�speed�back�to�its�default�value.*;*ˆWe�are�running�in�background�when�this�routine�is�called.**ˆEntry:�A5�=�address�of�CCB*�A1�=�address�of�our�port**�Interrupt�level�on�entry�is�0**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*O******************************************************************************* CLOCK_RESET:*A*ƒThis�functionality�is�not�supported�by�the�R68560�on�the�VME050*ŠRTSŠPAGEJ****************************************************************************ˆGET�DEVICE�STATUS�BYTE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�toA*ˆprepares�the�DEVICE�STATUS�byte�which�contains�the�condition�of6*ˆthe�CTS�line�(which�indicates�device�ready/unready).*;*ˆWe�are�running�in�background�when�this�routine�is�called.*8*ˆNote:‚This�routine�does�not�set�the�break�indicator�in*�the�device�status�byte.**ˆEntry:�A5�=�address�of�CCB**�Interrupt�level�on�entry�is�0*!*ˆExit:‚D0.B�=�Device�Status�byte*�RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.* J************************************************************************** GET_STAT:,ŠMOVEM.L�D1/A1,-(A7)‹Save�working�registers.'ŠCLR.LƒD0”Device�status�to�be�returned..ŠMOVE.L‚CCBCHB(A5),A1‰A1�<--�addr�of�our�port.<ŠMOVE.B‚MPC_SISR(A1),D1‡D1�<--�status�of�VME050�input�lines.#ŠBTST„#CTSL,D1ŽTest�the�CTS�line.../ŠIF†�THEN�If�CTS�is�low,�device�is�unready.0‹BSET�#XDSNRB,D0ŽSet�unready�bit�in�status�byte.ŠENDI/ŠMOVEM.L�(A7)+,D1/A1‹Restore�working�registers.ŠRTSŠPAGEM*******************************************************************************ˆSTOP�THE�TRANSMITTING�DEVICE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�toA*ˆchange�a�hardware�output�line�to�make�our�device�look�'unready''*ˆso�the�transmitting�device�will�stop.*;*ˆWe�are�running�in�background�when�this�routine�is�called.*+*ˆEntry:�A1�=�address�of�our�side�of�device*�A5�=�address�of�CCB*5*�Interrupt�level�on�entry�is�INHIBITED�at�our�level.**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*K*************************************************************************** DDP_STOP::ŠMOVE.B‚#UNREADY,MPC_SICR(A1)�Raise�the�RTS�and�DTR�lines.ŠRTSŠPAGEK****************************************************************************$*ˆDEVICE�DEPENDENT�UNSTOP�THE�DEVICE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�toC*ˆunstop�the�transmitting�device�by�changing�a�hardware�output�line"*ˆto�make�our�device�look�'ready'.*;*ˆWe�are�running�in�background�when�this�routine�is�called.*+*ˆEntry:�A1�=�address�of�our�side�of�device*�A5�=�address�of�CCB*5*�Interrupt�level�on�entry�is�INHIBITED�at�our�level.**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*J************************************************************************** DDP_UNSTOP:8ŠMOVE.B‚#READY,MPC_SICR(A1)ƒLower�the�RTS�and�DTR�lines.ŠRTSŠPAGEK****************************************************************************&*ˆDEVICE�DEPENDENT�BEGIN�BREAK�ROUTINE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to@*ˆgive�a�command�to�start�sending�break�condition�to�our�device.*;*ˆWe�are�running�in�background�when�this�routine�is�called.*+*ˆEntry:�A1�=�address�of�our�side�of�device*�A5�=�address�of�CCB*5*�Interrupt�level�on�entry�is�INHIBITED�at�our�level.**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*E*********************************************************************  DDP_BEG_BREAK:7ŠBSET.B�#TI,MPC_TCR(A1)‡Give�an�transmit�break�command.ŠRTSŠPAGEK****************************************************************************$*ˆDEVICE�DEPENDENT�END�BREAK�ROUTINE*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to?*ˆgive�a�command�to�stop�sending�break�condition�to�our�device.*;*ˆWe�are�running�in�background�when�this�routine�is�called.*+*ˆEntry:�A1�=�address�of�our�side�of�device*�A5�=�address�of�CCB*5*�Interrupt�level�on�entry�is�INHIBITED�at�our�level.**ˆExit:‚RTS�to�caller*0*ˆThis�routine�must�preserve�all�registers�used.0*ˆThe�interrupt�level�upon�exit�must�be�the�same*ˆas�it�was�upon�entry.*L**************************************************************************** DDP_END_BREAK:9ŠBCLR.B�#TI,MPC_TCR(A1)‡Clear�the�transmit�break�command.ŠRTS SPC 10 O******************************************************************************** *‰END�ROUTINES�CALLED�BY�TERMLIB*O*******************************************************************************ŠPAGEO*********************************************************************************“B�A�C�K�G�R�O�U�N�D**šAND**‘C�A�L�L�__�G�U�A�R�D�E�D**–R�O�U�T�I�N�E�S**•(DEVICE-DEPENDENT)*O*******************************************************************************ŠPAGEO*********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*A*‰The�initialization�routine�has�gone�around�resetting�everythingD*‰it�can,�but�the�routines�RESET�and�DDP_RESET�should�only�be�called>*‰from�within�the�background.‚So�he�invoked�this�routine�to�do *‰it�for�him.*?*‰In�addition,�these�other�device-dependent�things�MUST�be�done>*‰before�we�can�handle�commands.‚They�probably�could�have�been?*‰done�in�INIT�at�the�start�of�the�driver�but�are�handled�here.*5*‰1.‚Put�the�start�address�of�the�driver�into�the�CCB*�variable�DRV_ADDR.>*‰2.‚Set�up�the�device-dependent�BABs�using�the�macro�SET_BAB.;*‰3.‚Put�the�address�of�the�A-side�of�a�dual�channel�device6*�into�the�CCB�variable�ADRSIDEA.‚If�not�dual�channel,**�put�the�address�of�Port�1�into�ADRSIDEA.**‰Entry:�A5�=�address�of�CCB.*6*‰Calls:�RESET�in�the�generic�terminal�driver�TERMLIB.*�DDP_RESET�in�this�driver.6*�MARK_DOWN�in�the�generic�terminal�driver�if�failure.*O******************************************************************************* DO_INIT:**‚Inhibit�interrupts*‰PUSH†SR‰INHIBIT*)*‚Get�address�of�start�of�driver�into�CCB*ŠLEA‡MPCCDRV(PC),A4ŠMOVE.L„A4,DRV_ADDR(A5)*>*‚Set�up�the�address�of�A-side�with�the�address�of�our�device.*@ŠMOVE.L�CCBCHB(A5),ADRSIDEA(A5)‚Move�device�address�into�A-side. ŠJSR„RESETŽReset�everything.ŠBSR.L‚DDP_RESETŠPOP„SR ŠRTS 7FAIL†JSR„MARK_DOWNŠMark�the�channel�down�using�TERMLIB.ŠPOP„SRŠRTSŠPAGE*********************** *‚PATCH�SPACE***********************ŠDS.Wƒ30ŠEND  ééééééé =/*=/*†MPSCDRV.AF=/*6=/* Chain file to assemble NEC 7201 subordinate driver=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to MPSCDRV.LS=/*=/IFC \1ƒ=ARG�MPSCDRV.LS=/ENDIF=/*$=ASM MPSCDRV.SA,MPSCDRV.RO,\1;RZ=150=/*{ Included files are:=/*ƒ9995.&.MVME400.EQ=/*ƒ9995.&.NEC7201.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.BAB.EQ=/*ƒ9995.&.TERMINAL.EQ=/*ƒ9995.&.UTILITY.MC=/*ƒ9995.&.TERMCCB.EQ=/*}=/*=ENDéééééÈ>MPSCDRVƒIDNTƒ4,1‡VERSADOS�7201�TERMINAL�DRIVER�WITH�TYPE-AHEAD;ŠTTL„MPSCDRV:‚VERSADOS�7201�TERMINAL�DRIVER�WITH�TYPE-AHEAD ŠLLENƒ120J**************************************************************************J**************************************************************************J**************************************************************************J***************************************************************************9*‰MPSCDRV:‚VERSAdos�7201�terminal�driver�with�type-ahead.*8*‰Purpose:‚VERSAdos�device�driver�to�handle�asynchronous3*�terminals�(of�any�type)�over�the�NEC�7201�chip�on*�the�following�boards:*’VM02‚VM03‚MVME�400**‰Revision�history:*1*�10/23/84‚All�BSR's�to�TERMLIB�now�JSR's�in�case.*šTERMLIB�is�located�more�than�32K�bytes�away.+*‘10/9/84‚Added�baud�rate�support�for�VM03.<*‘9/17/84‚Removed�references�to�MENU�and�TR_MODE�in�MPSCDRV,*šput�into�TERMLIB3*‘8/30/84‚Fixed�SPR�concerning�SETUP.‚Commented�out(*šthe�code�that�tests�the�modem�bit.‚Now**šif�the�off�hook�bit�is�set,�the�DTR�line&*šis�set�low,‚whether�or�not�the�modem *šbit�is�set.1*‘8/29/84‚MPSCDRV�has�jump�table�at�beginning�for*šuse�by�TERMLIB.0*‘6/�6/84‚Split�MPSCDRV�into�MPSCDRV�and�TERMLIB.*šMPSCDRV�contains�only�device�dependent�code.)*‘8/�9/83‚Fixed�bug�in�overrun�detection.5*‘7/13/83‚Fix�bugs:‚7�bit�char's�in�transparent�mode;*¥XOFF/XOFF�lockup�problem.8*‘5/25/83‚Implementation�of�DCD�notification,�auto-baud-**šrate-detect,�and�transparent�mode�logic.7*�10/19/82‚Major�repairs�so�that�interrupts�will�not�be3*˜disabled�so�long�as�to�screw�up�SDLC.‚Revision�1.**‘9/16/82‚Initial�release�by�Steve�Franck.*J**************************************************************************J**************************** **********************************************J**************************************************************************J************************************************************************** PAGE**‚XREF's�from�TERMLIB* ‰XREF†LOG_ERRÑ1ÚSâ8êEòAú50 ;3B"F*92L:9BHJDRFZJb@jHrFzM‚;ŠD’LšH¢ ‰XREF†RESET‰XREF†TERM_INIT‰XREF†TERM_COMMAND‰XREF†TERM_TBE‰XREF†TERM_BREAK‰XREF†TERM_GOT_CHAR‰XREF†TERM_UNRDY‰XREF†MARK_DOWN *C*‚Equates�for�the�variable�BOARD�defined�in�TERMCCB.EQ.�This�driverA*‚calculates�BOARD�from�the�variable�CCBTYPE�defined�in�CCB.EQ�asF*‚CCBTYPE�divided�by�2.�This�driver�uses�BOARD�to�make�board-dependent3*‚decisions,�i.e.�software�selecting�the�baud�rate.* VM02†EQU„$30MVME400ƒEQU„$32 VM03†EQU„$3AGVM03_BRCR�EQU„$F80071…Address�of�the�baud�rate�control�register�on�VM03 *?*‚Masks�delineating�all�recognized�(REC)�and�unrecognized�(UNR)(*‚attributes�(ATT)�and�parameters�(PAR).*C*REC_ATTƒEQU„%1011111111111111‚1�bits�represent�defined�attributes.D*UNR_ATTƒEQU„$FFFF-REC_ATT†The�1's�complement�of�that�are�undefined. C*REC_PARƒEQU„%0111111111111111‚1�bits�represent�defined�parameters.D*UNR_PARƒEQU„$FFFF-REC_PAR†The�1's�complement�of�that�are�undefined.***‚Equate�files�included:* *‰MVME400.EQ *‰NEC7201.EQ*‰STR*‰TCB*‰CCB*ˆ9995..BAB.EQ*‰IOE*‰NIO*‰LV5#*‰TERMINAL.EQˆEquates�for�terminals *‰UTILITY.MC:*‰TERMCCB.EQ‰Offsets�and�equates�for�CCBDDP�for�terminals.*ŠPAGEŠINCLUDE�9995.&.MVME400.EQŠINCLUDE�9995.&.NEC7201.EQŠNOLIST ŠTTL…STR.EQŠINCLUDE�9995.&.STR.EQŠNOLISTŠINCLUDE�9995.&.TCB.EQŠNOLISTŠINCLUDE�9995.&.CCB.EQŠNOLISTŠINCLUDE�9995.&.IOE.EQ‰NOLISTŠINCLUDE�9995.&.NIO.EQŠNOLISTŠINCLUDE�9995.&.LV5.EQ‰NOLIST‰INCLUDEƒ9995.&.BAB.EQŠLISTŠINCLUDE�9995.&.TERMINAL.EQŠINCLUDE�9995.&.UTILITY.MCŠINCLUDE�9995.&.TERMCCB.EQŠLIST‰OFFSET„TERMDDP */*‚Device�dependent�Background�activation�blocks*<�RESERVE.12‰DSR_BABŒRoutine�to�handle�a�DSR�line�transition.7�RESERVE.12‰DCD_BABŒRoutine�to�handle�a�DCD�transition.*7�RESERVE.1�R4_7201’Image�of�7201�register�4,�needed�for%*§changing�the�clock�rate�between�x16'*§and�x64.‚To�change�register�4,�change$*§it�here�and�then�move�this�byte�to *§the�7201. 7�RESERVE.1�R5_7201’Image�of�7201�register�5,�needed�for"*§changing�the�RTS�&�DTR�lines.‚If'*§you�need�to�change�register�5,�change$*§it�here�and�then�move�this�byte�to *§the�7201. <�RESERVE.1�PIA_ASAV‘Used�only�for�MVME�400�boards,�this�byte"*§is�updated�whenever�a�command�is(*§received�or�an�interrupt�occurs.‚It�is'*§a�copy�of�the�PIA's�A-side�peripheral'*§data�register.‚It�will�be�mainly�used$*§for�determining�whether�or�not�the'*§device�is�ready�(via�the�DSR�status).   =�RESERVE.1�EXT_STATUS�Image�of�the�7201's�external�status.‚We(*§compare�this�copy�with�the�fresh�stuff'*§from�the�7201�when�an�external�status'*§interrupt�occurs�to�see�what�changed. ;�RESERVE.1�CLOCK_64‘If�this�flag�is�0,�we�are�using�the�x16%*§clock�on�the�7201.‚If�it�is�nonzero)*§(true),�then�we're�using�the�x64�clock,)*§which�effectively�divides�the�baud�rate'*§by�4.‚This�flag�should�be�kept�synch-&*§ronized�with�R4_7201,�which�actually*§controls�the�7201's�clock. *E*‚There�are�two�additional�interrupt�types�with�a�7201.‚These�are�theB*‚states�(notice�these�are�only�byte�values)�for�those�interrupts.*2*%%%%%%%%%%%%%%‚BWNƒ8/16/84‚MOVED�ES_ST�TO�TERMLIB$**�RESERVE.1�ES_ST”ES‚process�state.$�RESERVE.1�DSR_ST“DSR�process�state.*@*ƒCompute�the�number�of�pages�of�memory�that�we�need�for�one�CCB>*ƒfor�the�MPSC�driver.‚CMR�automatically�allocates�one�page�ofA*ƒmemory�($100�bytes)�for�the�CCB,�and�our�variable�EXTCCBSZ�willB*ƒreside�in�the�CMR�parameter�table�at�the�begin ning�of�the�driver8*ƒto�tell�CMR�how�many�extra�pages�of�memory�are�needed.**CCBSIZEB�EQU‡*PAGESIZE�EQU‡$100L1‡SET‡CCBSIZEB+PAGESIZE-1CCBSIZE‚EQU‡L1/PAGESIZEEXTCCBSZ�EQU‡CCBSIZE-1;ŠTTL„MPSCDRV:‚VERSADOS�7201�TERMINAL�DRIVER�WITH�TYPE-AHEADŠPAGEJ***************************************************************************+*‰SERVICE�VECTOR�TABLE,�REVISION�INFO,�ETC.*@*‰This�table�is�examined�by�CMR�when�the�channel�is�allocated�toC*‰determine�where�to�go�for�interrupts,�commands,�&�initialization.<*‰It�must�always�be�at�the�very�top�of�the�driver�code.‚Also>*‰included�is�a�parameter�telling�the�number�of�extra�pages�of>*‰memory�to�include�in�the�CCB,�and�information�describing�the*‰revision�of�the�driver.*L**************************************************************************** ŠSECTION‚0ŠOPT„BRS MPSCDRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!*=ŠDC.LƒINTERRUPT-MPSCDRV‚Address�of�interrupt�service�routine.9ŠDC.LƒCOMMAND-MPSCDRV„Address�of�command�service�routine.5ŠDC.LƒINIT-MPSCDRV‡Address�of�initialization�routine.ŠDC.Lƒ0’Reserved. **‚Other�CMR�parameters.*7ŠDC.BƒEXTCCBSZ‹#�of�extra�pages�in�the�CCB.‚The�CCB�may)*§be�any�size�from�1�to�256�pages�(a�page'*§is�256�bytes):‚if�this�field�is�0,�it*§will�be�1�page,�etc.ŠDC.Bƒ0,0,0ŽReserved.ŠDC.Lƒ0,0,0ŽReserved. **‚Revision�info:*/ŠDC.Bƒ'102384'‹Date�of�last�assembly�as�MMDDYY.1ŠDC.Bƒ'�'�Space�indicates�no�patches�to�.LO�file.)ŠDC.Bƒ'4'�Major�VERSAdos�revision�number.*‰PAGE*+*‚Jump�table�for�use�by�the�generic�TERMLIB*‰BRA.L…PUT_CHAR ‰BRA.L…CK_TBE‰BRA.L…DDP_RESET ‰BRA.L…SETUP‰BRA.L…CLOCK_RESET‰BRA.L…GET_STAT‰BRA.L…DDP_STOP‰BRA.L…DDP_UNSTOP‰BRA.L…DDP_BEG_BREAK‰BRA.L…DDP_END_BREAK **‰PAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INITIALIZATION�ROUTINE*>*‰This�routine�is�called�by�CMR�when�the�channel�is�allocated.9*‰Its�purpose�is�to�set�up�things�for�command�service�and7*‰interrupt�service.‚The�major�functions�performed�are:"*�Validate�the�channel�type�field.+*�Get�memory�for�transmit�&�receive�queues..*�Initialize�flags,�pointers,�etc.�in�the�CCB.*�Initialize�the�7201.4*�If�the�board�is�an�MVME�400,�test�the�7201�and�PIA!*“and�initialize�the�PIA�as�well.*@*‰We�got�here�through�a�JSR�from�CMR,�and�will�exit�with�an�RTS.>*‰All�registers�have�been�saved�by�CMR�and�may�be�used�freely.?*‰Entry�is�at�interrupt�level�0,�and�we�are�in�supervisor�mode.**‰Entry:�A5�=�address�of�CCB.*'*‰Exits�to:‚CMR�(via�RTS)�if�all�is�OK.'*”KILLER�if�exec�won't�allocate�memory.*J**************************************************************************J**************************************************************************J************************************************************************** ŠDS…0 INIT: )********************************************D***‚THIS�IS�TEMPORARY�JUNK�FOR�DEBUGGING.‚In�order�that�VERSAbug�notF***‚mess�with�port�B�of�the�7201,�we�have�to�set�his�'alternate�serialH***‚port�2�address'�to�point�to�an�innocuous�location.‚Set�the�alternate2***‚address�to�$F70014�so�he'll�blow�away�$F70018.***:***‡MOVE.L�#$F70014,$65A†To�simplify�debugging!!!!!!!!!!!!***7***‚Here�is�some�reserved�space�so�you�can�patch�it�in:ŠNOPŠNOPŠNOPŠNOP****.‰JSR‡TERM_INIT‹Do�the�device-independent�stuff*%%%%%%%%%%%%%%ƒbwn‚8/13/842‰IFƒƒTHEN…Something�went�wrong�with�TERM_INIT.4‰IFƒƒTHEN„The�exec�call�failed�and�we�cannot�get!*œthe�scheduler's�entry�point�!!!ŽTR0$.KILLER‚,‰ELSE�RTS�The�channel�is�down�!!‰ENDI‰ENDI*?*‚Call�guarded�for�the�device�dependent�initialization�routi ne.**‰LEA‡DO_INIT(PC),A0‰MOVE.L„#T0GUARD,D0‰TRAP†#0 ‰RTS)*****************************************ŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰COMMAND�SERVICE�ROUTINE*>*‰We�get�entered�here�when�the�attached�task�(IOS)�invokes�CMR?*‰via�a�TRAP�1�with�an�INITIATE�I/O�parameter�block�to�process.>*‰CMR�has�already�checked�the�CMR�parameter�block�to�ensure�it<*‰resides�within�the�address�space�of�the�attached�task.‚IOSA*‰has�already�validated�the�IOCB,�except�for�the�buffer�addresses *‰therein.*@*‰We�got�here�through�a�JSR�from�CMR,�and�will�exit�with�an�RTS.>*‰All�registers�have�been�saved�by�CMR�and�may�be�used�freely.?*‰Entry�is�at�interrupt�level�0,�and�we�are�in�supervisor�mode.*5*‰Entry:�A2�=�physical�address�of�CMR�parameter�block*�A5�=�physical�address�of�CCB*3*‰Exit:‚D0�=�results�of�parameter�block�validation:3*•always�0�in�our�case,�indicating�it�was�OK,�since2*•IOS�will�not�send�us�any�request�except�HALT�I/O/*•if�we�are�already�busy,�and�CMR�makes�all�the*•other�checks.*A*‰Note:‚TERMLIB�does�not�recognize�CMR�commands�for�HALT�&�RESET.B*‰HALT�can�still�be�accomplished�through�use�of�the�HALT�I/O�IOCB.*J**************************************************************************J**************************************************************************J************************************************************************** COMMAND:   *E*‚If�this�is�an�MVME�400�board,�read�the�PIA's�A-side�peripheral�data0*‚register�and�save�it�in�the�CCB�for�later�use.*:ŠIF.B�BOARD(A5)��#MVME400�THENƒIf�this�is�an�MVME�400,?ŠMOVE.L�ADRSIDEA(A5),A0ˆA0�<--�addr�of�7201�A-side�control�reg.DŠMOVE.B�PIAPER_A(A0),PIA_ASAV(A5)‚Get�a�fresh�copy�of�the�peripheralŠENDIšdata�register. *C*‚Now�that�we�have�received�a�command,�we�know�there�is�someone�outI*‚there�to�talk�to.‚If�the�guy�who�reports�breaks�is�asleep,�wake�him�up.*F**ˆMOVE.B�#S_REPORT,ES_ST(A5)�Report�incoming�breaks�to�attached�task. ‹JSR…TERM_COMMAND ŠRTS—return�to�CMR.  J**************************************************************************K***************************************************************************ŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INTERRUPT�HANDLING�ROUTINE*<*‰This�routine�completes�I/O�requests�started�by�the�command:*‰service�routine.‚It�is�entered�at�the�interrupt�priority;*‰level�of�interrupts�on�this�channel,�and�is�essentially�a9*‰subroutine�to�the�first�level�interrupt�handler�in�CMR.=*‰Remember,�however,�that�this�is�a�subordinate�driver--hence=*‰the�interrupt�was�fielded�first�by�the�supervisor�used�with(*‰whatever�type�of�board�we're�handling.*:*‰Entry:�D0,A0,A1�have�been�saved�by�CMR�and�are�available3*�D1�has�been�saved�by�the�supervisor�driver�and�is7*�available,�but�must�be�restored�upon�exit�(POP.L�D1).*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*9*‰Exit�is�always�via�RTS,�which�takes�us�back�to�CMR.‚The3*�carry�bit�is�examined�by�CMR�to�determine�whether7*�the�driver�handled�the�interrupt�or�whether�it�should4*�pass�the�interrupt�on�to�the�next�guy�in�the�chain*�on�that�vector:*��=�'I�handled�it'**‰Stack:*�(A7)+8�.�.�. *�(A7)+4�longword�return�address6*�(A7)ƒlongword�saved�contents�of�D1�(must�be�restored*—before�exit�to�CMR)*J**************************************************************************J**************************************************** ********************** INTERRUPT: *E*‚Note:‚this�driver�requires�a�supervisor�driver�since�it�handles�theF*‚7201.‚The�supervisor�driver�originally�written�for�use�with�this�oneF*‚is�MPSCSUP,�which�branches�to�the�appropriate�longword�in�this�tableI*‚depending�on�interrupt�type.‚Also,�the�supervisor�will�not�pass�controlA*‚to�this�driver�unless�there�is�in�fact�an�interrupt�on�my�port.**‚VM02�and�VM03�entry�points:'ŠBRA.S‚TBE�My�transmit�buffer�is�empty.ŠNOP,ŠBRA.L‚ES‘External/status�change�on�my�port.%ŠBRA.S‚RCA�Character�received�for�me.ŠNOP,ŠBRA.L‚SRC�Special�receive�condition�for�me.*‚MVME�400�entry�points:*ŠBRA.S‚TBE400�My�transmit�buffer�is�empty.ŠNOP/ŠBRA.L‚ES400ŽExternal/status�change�on�my�port.(ŠBRA.S‚RCA400�Character�received�for�me.ŠNOP/ŠBRA.L‚SRC400�Special�receive�condition�for�me.0ŠBRA.L‚RI400ŽMy�RI‚line�went�high�(low�at�chip).(ŠBRA.L‚DSR400�My�DSR�line�did�something.4ŠBRA.L‚DSR400�My�DSR�and�RI�lines�both�did�something"*©(only�worry�about�the�DSR�line).ŠPAGEJ***************************************************************************)*‰TRANSMIT�BUFFER�EMPTY�INTERRUPT�HANDLER*=*‰The�7201's�transmit�buffer�just�became�empty,�so�if�we�have+*‰more�characters�to�send�we�can�do�it�now.*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** TBE400:BŠMOVE.B�D1,PIA_ASAV(A5)„Save�the�PIA's�A-side�peripheral�register. :TBE:†MOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�side�of�7201. ;ŠMOVE.B�#NCW0RTI,CREG(A1)‚Reset�TBE�interrupts�on�our�side.DŠMOVE.B�#NCW0EOI,CREG(A0)‚Clear�the�interrupt�(EOI�to�side�A�reg�0). *%%%%%%%%%%ƒBWN‚9/17/84*F*‚Call�the�device-independent�routine�that�deals�with�transparent�mode)*‚or�invokes�the�XMIT�background�routine.* ‰JSR‡TERM_TBE‰BRA.L…INT_EXITŠPAGEJ***************************************************************************(*‰RECEIVED�CHARACTER�AVAILABLE�INTERRUPT*=*‰The�7201�has�just�received�a�character,�and�it�is�available=*‰for�reading.‚We�will�do�that�now,�and�the�result�will�go�in$*‰the�receive�queue�if�there's�room.*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** RCA400:DŠMOVE.B�D1,PIA_ASAVA(A5)ƒSave�the�image�of�the�PIA's�peripheral�reg. :RCA:†MOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�side�of�7201. 8ŠMOVE.B�DREG(A1),D0ˆGet�the�char�from�the�7201�and�reset>ŠMOVE.B�#NCW0EOI,CREG(A0)‚the�interrupt�(EOI�to�side�A�reg�0). *%%%%%%%%%%%%‚BWN�9/17/84*A*‚We�only�get�into�auto�baud�rate�detect�mode�if�we�have�received:*‚a�DCD�transition�interrupt�while�we�are�configured�to�doD*‚auto�baud�rate�detection.‚If�we�are�also�in�transparent�mode,�this *‚character�will�be�thrown�away.G*‚We�have�modified�the�BREAK�routine�in�TERMLIB�so�that�it�does�nothing *‚if�we�are�in�transparent�mode.*<ŠTST.B‚AUTO_BAUD(A5)†If�we're�in�auto�baud�rate�detect�mode, ŠBNE„DETECT_BAUDˆgo�handle�that. *C*‚Call�the�device�independent�routine�to�check�for�transparent�modeG*‚and�do�the�stuff�for�transparent�mode�or�if�not�in�tranparent�mode�toG*‚check�for�any�special�characters�such�as�XON,�XOFF,�BREAK�EQUIVALENT,G*‚or�DISCARD�OUTPUT.�Otherwise,�put�the�character�in�the�receive�queue.* ‰JSR‡TERM_GOT_CHAR‰BRA.L…INT_EXIT ŠPAGEO*********************************************************************************‰AUTO�BAUD�RATE�DETECTION*?*‰We�come�he  re�when�characters�are�received�while�we're�in�autoB*‰baud�rate�detect�mode.‚This�routine�looks�at�the�incoming�char's@*‰to�see�if�it�can�establish�the�clock�rate�(x16�or�x64)�to�use.*B*‰The�#�of�milliseconds�to�wait�for�the�receiver�to�be�flushed�wasA*‰determined�as�follows.‚The�slowest�pair�of�baud�rates�(of�those@*‰which�can�be�generated�using�our�baud�rate�generator)�that�canB*‰work�with�this�x16/x64�clock�rate�trick�is�75�baud�and�300�baud.C*‰The�buffer�will�need�to�be�flushed�if�we�are�sampling�at�300�baud=*‰but�the�data�is�coming�in�at�75�baud.‚The�largest�amount�ofA*‰garbage�we�have�to�worry�about�is�a�start�bit,�8�data�bits,�andA*‰a�parity�bit--the�stop�bits�will�not�cause�a�problem.‚Therefore8*‰we�need�to�wait�for�10�bit-times�at�75�baud,�which�is:**•1�second…1000�msecs3*‰10�bits‚*‚--------‚*‚----------„=„about�133�msecs*•75�bits†1�second*>*‰Actually�we�don't�need�to�wait�quite�that�long�since�we�have?*‰already�received�a�whole�char�at�the�faster�baud�rate,�but�it!*‰makes�for�a�nice�safety�margin.**‰Entry:*‹D0.B�=�the�char�received.$*‹A1ƒ=�addr�of�our�side�of�the�7201.*‹A5ƒ=�addr�of�our�CCB.*O******************************************************************************* DETECT_BAUD: *B*‚If�we're�currently�flushing�the�receiver,�just�ignore�this�char.*&ŠTST.B‚FLUSHING(A5)‡If�we're�flushing,(ŠBNE.L‚INT_EXIT‹exit�from�the�interrupt. *<*‚We're�not�flushing;�is�this�char�the�CR�we're�looking�for?*7ŠAND.B‚CHAR_MSK(A5),D0„Strip�off�parity�if�7�bits/char. +ŠIF.B�D0��#CR�THEN…If�the�char�is�a�CR, -ŠSF…AUTO_BAUD(A5)†Take�us�out�of�detect�mode,*%%%%%%%%%%%%%%%%% BWN 7/9/84 ŽBKGRND„BREAK‰BRA.L…INT_EXITE**ˆBSETW‚#W_BREAK,WORK(A5)‚and�invoke�the�background�break�routine�to"**ˆBRA.L‚BKG_EXEC‹notify�somebody.*%%%%%%%%%%%%%%%%%%%%%%%%%%%% ŠENDI–*  *C*‚That�wasn't�a�hit;�get�ready�to�try�again�at�the�other�baud�rate.*<ŠNOT.B‚CLOCK_64(A5)‡Switch�to�the�other�clock�divisor�value.%ŠIF…�THENŠIf�we're�now�doing�x16,ŠBSR„CLOCK16Œset�us�up�for�x16;!ŠELSE–Else�(we're�now�doing�x64),ŠBSR„CLOCK64Œset�us�up�for�x64.ŠENDI–* *I*‚Now�wait�to�make�sure�there�isn't�some�garbage�left�hanging�around�from!*‚the�erroneous�char�we�received.*<ŠST…FLUSHING(A5)‡Set�the�flag�so�we'll�know�to�ignore�char's*§that�come�in. 3ŠENABLE”We�can�do�the�rest�with�interrupts�enabled. <ŠLEA„FLUSHED(PC),A0…A0�<--�addr�to�go�to�when�timer�expires.BŠMOVE.L�#10*1000/75,A1…A1�<--�#�of�millisec's�to�wait�for�receiver*§to�be�completely�flushed.7ŠMOVE.L�#1,D1ŽD1�<--�interrupt�level�for�timer�routine.7ŠMOVE.L�A5,D2ŽD2�<--�timer�ID;�we'll�need�the�CCB�addr.'ŠTR0$.RQPA�,�Ask�exec�to�set�the�timer.,ŠBRA„WAIT_FLUSH‰.‚All�is�well,�so�just�wait.8ŠSF…FLUSHING(A5)‡.‚Timer�was�not�set,�so�clear�the�flag.2WAIT_FLUSH�BRA.L�INT_EXIT‹Exit�from�the�interrupt.ŠPAGEO********************************************************************************2*‰ROUTINES�TO�SET�THE�CLOCK�DIVISOR�TO�x16�AND�x64*:*‰Entry�point�CLOCK16�sets�the�clock�divisor�to�x16,�while4*‰Entry�point�CLOCK64�sets�the�clock�divisor�to�x64.**‰Entry:$*‹A1ƒ=�addr�of�our�side�of�the�7201.*‹A5ƒ=�addr�of�our�CCB.**‰Exit:*O******************************************************************************* **‚Set�clock�divisor�to�x16.*CLOCK16:CLOCK_RESETˆEQU‡* !ŠPUSH.L�D0‘Save�registers�and�SR. ŠPUSHƒSR‘*ŠINHIBIT“Inhibit�interrupts.3ŠSF…CLOCK_64(A5)‡Mark�that�we're�using�a�x16�clock.:ŠPUT_BYTE�NCW4C16,D0‡Load�the�register�value�for�x16�clockŠBRA„SET_CLOCKŠand�go�set�it.  **‚Set�clock�divisor�to�x64.*CLOCK64: !ŠPUSH.L�D0‘Save�registers�and�SR. ŠPUSHƒSR‘*ŠINHIBIT“Inhibit�interrupts.3ŠST…CLOCK_64(A5)‡Mark�that�we're�using�a�x64�clock.;ŠPUT_BYTE�NCW4C64,D0‡Load�the�register�value�for�x64�clock.  *4*‚Set�the�clock�divisor�according�to�the�bits�in�D0.  *LSET_CLOCK�AND.B‚#$FF-NCW4CLK,R4_7201(A5)‚Set�the�clock�divisor�field�to�0's.1ŠOR.BƒD0,R4_7201(A5)…Or�in�the�chosen�clock�rate.AŠMOVE.B�#NCW0RG4,CREG(A1)‚Now�give�the�prepared�register�image�to&ŠMOVE.B�R4_7201(A5),CREG(A1)‚the�7201. **‚Exit.*!ŠPOP„SR‘Restore�SR�and�registers, ŠPOP.L‚D0‘*ŠRTS—and�return.ŠPAGEO********************************************************************************C*‰TIMER�INTERRUPT�ROUTINE�FOR�FLUSHING�RECEIVER�ON�BAUD�RATE�DETECT*B*‰Routine�DETECT_BAUD�sets�a�flag�to�indicate�that�incoming�char's@*‰should�be�discarded�and�sets�a�timer.‚When�the�timer�goes�off,G*‰we�come�here�to�clear�the�flag�(because�the�flushing�period�is�over).**‰Entry:9*‹D0,A0,A1�have�been�saved�by�the�exec�and�are�available.7*‹D1ƒ=�addr�of�CCB�(because�we�made�that�the�timer�ID).**‰Exit:*O******************************************************************************* FLUSHED: ŠPUSH.L�A5‘Save�A5./ŠMOVE.L�D1,A5ŽPut�the�address�of�our�CCB�in�A5.<ŠSF…FLUSHING(A5)‡Turn�off�the�flag�that�says�we're�flushing.ŠPOP.L‚A5‘Restore�A5. %ŠRTE—Return�from�the�timer�interrupt.ŠPAGEJ***************************************************************************"*‰EXTERNAL/STATUS�CHANGE�INTERRUPT*:*‰This�interrupt�from�the�7201�can�be�caused�several�ways:;*‰a�break�signal�starts;�a�break�signal�ends;�either�CTS�or7*‰DCD�changed.‚The�only�condition�we�care�about�in�this8*‰driver�is�when�a�break�signal�starts,�in�which�case�we>*‰have�to�get�an�appropriate�event�to�the�attached�task�(IOS).*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** ES400:DŠMOVE.B�D1,PIA_ASAVA(A5)ƒSave�the�image�of�the�PIA's�peripheral�reg. 9ES:‡MOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�side�of�7201. 9ŠMOVE.B�EXT_STATUS(A5),D0‚D0�<--�the�old�external�status.3ŠMOVE.B�SREG(A1),D1ˆD1�<--�the�new�external�status.;ŠMOVE.B�D1,EXT_STATUS(A5)‚Save�it�in�the�CCB�for�next�time.1ŠEOR.B‚D1,D0ŽD0�<--�those�things�which�changed�in"*§external�status�since�last�time. EŠMOVE.B�#NCW0REX,CREG(A1)‚Reset�the�ES�condition�to�latch�new�values.9ŠMOVE.B�#NCW0EOI,CREG(A0)‚Issue�end-of-interrupt�command. *%%%%%%%%%%‚BWN�9/17/84**‚Check�for�a�DCD�transition.*-‰PUT_BYTE‚NCR0DCD,D1ŠIf�the�bit�just�changed, ‰AND.B…D0,D1.‰IF‚‚THEN�call�the�DCD�background�handler. �BKGRNDƒDCD‰ENDI **‚Check�for�a�break.*7‰AND.B…#NCR0BRK,D0‰If�the�BREAK�DETECT�bit�just�changed,‰AND.B…EXT_STATUS(A5),D0ƒand�it�is�now�high, ‰IFƒƒTHEN3ŽJSR†TERM_BREAK†call�the�device-independent�routine*¦to�take�care�of�a�break.‰ENDI ‰BRA.L…INT_EXITŠPAGEJ***************************************************************************%*‰SPECIAL�RECEIVE�CONDITION�INTERRUPT*:*‰The�7201�detected�an�error�in�the�process�of�receiving�a<*‰character.‚We�need�to�record�this�information�so�that�when<*‰the�corresponding�data�is�requested�from�the�receive�queue*‰we�can�report�an�error.*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*J************************************************************************** SRC400:DŠMOVE.B�D1,PIA_ASAVA(A5)ƒSave�the�image�of�the�PIA's�peripheral�reg. :SRC:†MOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�side�of�7201. <ŠMOVE.B�#NCW0RG1,CREG(A1)‚Get�SRC�condition�from�7201�statusŠMOVE.B�SREG(A1),D0ˆregister�1. BŠMOVE.B�#NCW0ERR,CREG(A1)‚Clear�the�error�and�reset�the�interrupt.ŠMOVE.B�#NCW0EOI,CREG(A0)‚* ?ŠPUT_BYTE�NCR1CRC+NCR1PER,D1‚If�  it's�a�framing�or�parity�error,ŠAND.B‚D0,D1Ž*ŠIF…�THENŠ* 1ŠPUT_BYTE�PAR_FRAM,D0†Log�a�parity/framing�error; ŠJSR„LOG_ERR ŠBRA†INT_EXIT "ŠELSE–else�(not�parity�or�framing) .ŠPUT_BYTE�NCR1RCU,D1‡If�it's�an�overrun�error,ŠAND.B‚D0,D1Ž*ŠIF…�THENŠ**ŠPUT_BYTE�OVERRUN,D0‡Log�an�overrun�error. ŠJSR„LOG_ERR ŠBRA„INT_EXITŠENDI–* ŠENDI  ŠBRA„INT_EXIT‹Exit.ŠPAGEO*********************************************************************************‰DSR�INTERRUPT*?*‰The�RS232�line�Data�Set�Ready�has�made�the�transition�we�were=*‰waiting�for�(low�to�high�or�high�to�low),�so�we'll�probably<*‰want�to�send�an�event.‚This�is�detected�through�the�PIA�on*‰the�MVME�400�board.*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*O******************************************************************************* DSR400:DŠMOVE.B�D1,PIA_ASAVA(A5)ƒSave�the�image�of�the�PIA's�peripheral�reg. *%%%%%%%%%%% BWN 7/9/84 ‰BKGRND„DSR ‰BRA‡INT_EXIT:**ˆBSETW‚#W_DSR,WORK(A5)„Mark�work�for�the�DSR�routine�and&**ˆBRA„BKG_EXEC‹invoke�the�background.*%%%%%%%%%%%%%%%%%%%%%%%ŠPAGEO*********************************************************************************‰RI�INTERRUPT*>*‰The�RS232�line�Ring�Indicator�has�gone�high,�indicating�that9*‰the�modem�we�are�connected�to�is�ringing.‚That�means�we<*‰want�to�wait�for�DSR�to�go�high�(which�means�the�phone�has<*‰been�answered�by�the�modem).‚This�condition�is�detected�by *‰the�PIA�on�the�MVME�400�board.*'*‰Entry:�A0�=�address�of�A�side�of�7201*�A5�=�address�of�CCB5*�if�this�is�an�MVME�400,�D1�contains�the�contents�of,*�the�PIA's�A-side�peripheral�data�register.*<*‰Since�this�is�not�a�subroutine,�registers�at�exit�are�just-*‰the�entry�requirements�of�the�next�routine.*O******************************************************************************* RI400:DŠMOVE.B�D1,PIA_ASAVA(A5)ƒSave�the�image�of�the�PIA's�peripheral�reg. @ŠBTST.B�#0,CCBTYPE(A5)…If�we're�handling�the�A�side�of�the�7201,ŠIF…�THENŠ*3ŠADD.B‚D1,D1Žshift�bit�6�of�PIA's�A-side�peripheral#*§data�reg.�to�get�status�of�port�A*§DSR�line�in�bit�7;BŠBCLR�#DSR_FALLING,PIACTL_A(A0)‚set�the�A-side�control�register�to-ŠELSE–wait�for�DSR�to�go�high,�else�(we're�B)BŠBCLR�#DSR_FALLING,PIACTL_B(A0)‚set�the�B-side�control�register�toŠENDI–wait�for�DSR�to�go�high. ?ŠMOVE.B�#S_WT4RDY,DSR_ST(A5)ƒSet�up�DSR�process�to�wait�for�DSR$*§to�go�high�(modem�answered�phone). *;*‚It's�possible�that�DSR�has�already�gone�high;�if�so,�just2*‚invoke�the�DSR�transition�handler�in�background.*2ŠTST.B‚D1‘If�bit�7�of�D1�(DSR�status�for�our�port)(ŠBMI„INT_EXIT‹is�1�(DSR�low),�just�exit. *%%%%%%%%%%% BWN 7/9/84 ‰BKGRND„DSR ‰BRA‡INT_EXITD**ˆBSETW‚#W_DSR,WORK(A5)‚DSR�is�hi:‚mark�work�for�the�DSR�transition2**ˆBRA„BKG_EXEC‹handler�and�invoke�the�background.*%%%%%%%%%%%%%%%%%%%%%%ŠNOPŠPAGE*E*‚Now�exit�as�from�an�interrupt.‚We�may�in�fact�have�been�called�fromF*‚command�service�or�initialization,�but�they�had�to�set�it�up�to�look*‚like�an�interrupt,�too.*INT_EXIT:�POP.L‚D1‘Restore�D1,7ŠMOVEQ‚#1,D0Žset�carry�bit�to�tell�CMR�'we�handled�it,' ŠSUBQƒ#2,D0Ž*ŠRTS—and�return.ŠPAGE*%%%%%%%%%%%%%%%%%�BWN‚7/13/84‰PAGEK*****************************************************************************!*�R�O�U�T�I�N�E�S„C�A�L�L�E�D„B�Y**–T�E�R�M�L�I�B**F**********************************************************************‰PAGEL******************************************************************************ˆTRANSMIT�THE�CHARACTER*?*ˆThis�is�the�device�dependent�routine�that�actually�writes�the*ˆcharacter�to�the�device.*F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.*-*ˆ  Entry:„A1�=�address�of�our�side�of�the�chip*’A5�=�address�of�CCB*’D0.B�=�character�to�transmit*ˆInterrupt�level�on�entry:�0**C*ˆExit:…All�registers�are�preserved,�including�the�status�register.<*’It�is�important�to�keep�the�interrupt�level�the�same�as�it*’was�upon�entry.**J************************************************************************** PUT_CHAR:‰MOVE.B„D0,DREG(A1)‰RTS*J**************************************************************************‰PAGEM******************************************************************************$*ˆCHECK�THE�DEVICE'S�TRANSMIT�BUFFER*F*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installed�at*ˆthe�beginning�of�the�driver.<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.*-*ˆEntry:�A1�=�address�of�our�side�of�the�chip*�A5�=�address�of�CCB*ˆInterrupt�level�on�entry:�0**ˆExit:‚Condition�codes:"*��=�transmit�buffer�not�empty*��=�transmit�buffer�empty**M*****************************************************************************CK_TBE:‰BTST.B„#2,SREG(A1)‰RTSJ**************************************************************************‰PAGEH************************************************************************* *ˆDEVICE�DEPENDENT�RESET�ROUTINE*9*ˆThis�is�the�device-dependent�part�of�the�reset�routine.F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.****ˆEntry:�A5�=�addr�of�CCB*ˆInterrupt�level�on�entry:�0*$*ˆExit:�All�registers�are�preserved.*<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.*E********************************************************************* DDP_RESET: 6ŠMOVEM.L�A1/D0,-(A7)‡save�used�registers�on�the�stack.*B*‚If�this�is�an�MVME�400�board,�we�must�initialize�the�PIA�control@*‚register�for�our�side�to�wait�for�DSR�to�go�low�(unready)�and,2*‚if�we�are�configured�for�a�modem,�RI�to�go�high.*:ŠIF.B�BOARD(A5)��#MVME400�THEN‚If�this�is�an�MVME�400, CŠMOVE.B�#S_WT4UNR,DSR_ST(A5)ƒChange�DSR�state�to�await�DSR�unready.4ŠMOVE.B�#1<�THENŠ*8ŠBSET�#RI_ENABLE,D0ˆEnable�interrupts�for�RI�to�go�high.ŠENDI–* *M*‚D0�now�has�the�proper�initialization�value.‚Put�it�in�our�control�register.*AŠMOVE.L�ADRSIDEA(A5),A1„A1�<--�addr�of�7201�A-side�ctrl�register.4ŠBTST.B�#0,CCBTYPE(A5)…If�we're�handling�the�A�side,ŠIF…�THENŠ*;ŠMOVE.B�D0,PIACTL_A(A1)„initialize�the�PIA's�A-side�controlŠELSE–register,�else:ŠMOVE.B�D0,PIACTL_B(A1)„initialize�the�B-side�control�reg.ŠENDI–* ŠENDI–*  0ŠMOVEM.L�(A7)+,A1/D0‡Restore�saved�registers�and ŠRTS—exit.ŠPAGEJ***************************************************************************@*‰SUBROUTINE�TO�SET�UP�THE�DEVICE�ACCORDING�TO�THE�CONFIGURATION*;*‰Uses�the�working�configuration�(in�the�CCB)�to�set�up�the;*‰device,�and�some�configuration-related�fields�in�the�CCB.*F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.**‰Entry:�A5�=�address�of�CCB*ˆInterrupt�level�on�entry:�0**‰Exit:<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.*J************************************************************************** SETUP: <ŠMOVEM.L�D0-D2/A0-A3,-(A7)�Save�some�registers�on�the�stack. ŠPUSHƒSR **‚First�set�up�addresses.*4ŠLEA„CONFIG(A5),A0†A0�<--�addr�of�CCB�configuration.3ŠMOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�7201�port.3ŠMOVE.L�ADRSIDEA(A5),A2„A2�<--�addr�of�7201�A�port.)ŠLEA„2(A2),A3‹A3�<--�addr�of�7201�B�port. *2*‚[4]„x16�or�x64�clock�rate�according�to�the�flag,(*‰stop�bits�&�parity�from�configuration.*0ŠPUT_BYTE�NCW4C1  6,D0‡Start�with�x16�clock�in�D0.;ŠTST.B‚CLOCK_64(A5)‡If�the�flag�is�set�saying�we're�using�aŠIF…�THENŠx64�clock,)ŠPUT_BYTE�NCW4C64,D0‡put�x64�clock�in�D0.ŠENDI–* :ŠBTSTW‚#IOASTPB,IOSATW(A0)�Add�in�the�number�of�stop�bits. ŠIF…�THENŠOR.Bƒ#NCW4SB1,D0ˆ(1�stop�bit)ŠELSEŠOR.Bƒ#NCW4SB2,D0ˆ(2�stop�bits)ŠENDI >ŠBTSTW‚#IOAUSEP,IOSATW(A0)�If�we're�using�parity,�enable�it... ŠIF…�THENŠOR.Bƒ#NCW4PEE,D0:ŠBTSTW‚#IOAPRTY,IOSATW(A0)�and�if�we're�using�even�parity,ŠIF…�THENŠset�it�up.ŠOR.Bƒ#NCW4PEO,D0ŠENDIŠENDI ŠINHIBITBŠMOVE.B�#NCW0RG4,CREG(A1)‚Point�to�control�register�4�on�our�port.ŠMOVE.B�D0,CREG(A1)ˆ[4]�<--�D09ŠMOVE.B�D0,R4_7201(A5)…Save�the�image�in�the�CCB�as�well. ŠMOVEƒ(A7),SR ***‚[3]„auto�enables�mode,�receiver�enabled,*‰bits/char�from�configuration.*DŠPUT_BYTE�NCW3AUE+NCW3RXE,D0�Start�with�auto�enables�mode�&�receiver*§enabled�in�D0. 1ŠBTSTW‚#IOABITS,IOSATW(A0)�Add�in�bits/char�info. ŠIF…�THENŠOR.Bƒ#NCW3BT7,D0ˆ(7�bits/char)ŠELSEŠOR.Bƒ#NCW3BT8,D0ˆ(8�bits/char)ŠENDI ŠINHIBITBŠMOVE.B�#NCW0RG3,CREG(A1)‚Point�to�control�register�3�on�our�port.ŠMOVE.B�D0,CREG(A1)ˆ[3]�<--�D0 ŠMOVEƒ(A7),SR *0*‚[5]„RTS�&�DTR�lines�high,�transmitter�enabled,*‰bits/char�from�configuration.*>ŠPUT_BYTE�NCW5DTR+NCW5RTS+NCW5TXE,D0�Start�with�RTS�&�DTR�high$*§and�the�transmitter�enabled�in�D0. *%%%%%%%%%%ƒBWN‚8/30/84A**ˆBTSTW‚#IOAMODM,IOSATW(A0)„If�this�is�a�modem�we're�talking�to,**ˆIF…�THENŽ*8ŠBTSTW‚#IOAOFFH,IOSATW(A0)„and�the�guy�wants�it�offhook,ŠIF…�THENŽ*,ŠAND.B‚#$FF-NCW5DTR,D0ˆset�the�DTR�line�low.ŠENDIš* **ˆENDIš* 1ŠBTSTW‚#IOABITS,IOSATW(A0)�Add�in�bits/char�info. ŠIF…�THENŠOR.Bƒ#NCW5TX7,D0ˆ(7�bits/char)ŠELSEŠOR.Bƒ#NCW5TX8,D0ˆ(8�bits/char)ŠENDI ŠINHIBITBŠMOVE.B�#NCW0RG5,CREG(A1)‚Point�to�control�register�5�on�our�port.ŠMOVE.B�D0,CREG(A1)ˆ[5]�<--�D0@ŠMOVE.B�D0,R5_7201(A5)…Also�save�this�one�in�the�CCB�(we'll�have&*§to�dink�with�it�every�time�we�change*§DTR�or�RTS). *G*‚[1]„condition�affects�vector,�interrupt�on�all�char's�&�parity�error,E*‰transmitter�interrupts�enabled,�external/status�interrupts�enabled.*BŠMOVE.B�#NCW0RG1,CREG(A1)‚Point�to�control�register�1�on�our�port.1ŠMOVE.B�#NCW1STV+NCW1IRP+NCW1TXI+NCW1EXI,CREG(A1)*§[1]�<--�all�that�junk.ŠPOP„SR *I*‚If�this�is�an�MVME�400�board,�set�up�the�baud�rate�controls�on�the�PIA.*@ŠIF.B�BOARD(A5)��#MVME400�THENƒIf�this�is�an�MVME�400�board, 6ŠMOVE.B�IOSBRT(A0),D0†D0�<--�the�configured�baud�rate.;ŠPUT_BYTE�$F0,D1‹D1�<--�mask�to�clear�low�4�bits�of�a�byte./ŠBTSTƒ#0,CCBTYPE(A5)…If�this�is�an�A-side�port,ŠIF…�THENŠ*8ŠLSL.B‚#4,D0Žget�the�value�in�the�high�4�bits�and�change3ŠPUT_BYTE�$0F,D1‹the�mask�to�clear�the�high�4�bits.ŠENDI–*?ŠAND.B‚D1,PIAPER_B(A2)„Replace�the�current�4-bit�value�with�the%ŠOR.BƒD0,PIAPER_B(A2)„baud�rate�code. ŠENDI *A*‚If�this�is�a�VM03�board,�set�up�the�baud�rate�control�register.*8ŠIF.B�BOARD(A5)��#VM03�THENƒIf�this�is�a�VM03�board, 6ŠMOVE.B�IOSBRT(A0),D0†D0�<--�the�configured�baud�rate.;ŠPUT_BYTE�$F0,D1‹D1�<--�mask�to�clear�low�4�bits�of�a�byte./ŠBTSTƒ#0,CCBTYPE(A5)…If�this�is�an�B-side�port,ŠIF…�THENŠ*8ŠLSL.B‚#4,D0Žget�the�value�in�the�high�4�bits�and�change3ŠPUT_BYTE�$0F,D1‹the�mask�to�clear�the�high�4�bits.ŠENDI–*<ŠMOVE.B�VM03_BRCR,D2‡Read�the�current�baud�rate�control�reg.5ŠAND.B‚D1,D2ŽReplace�the�current�4-bit�value�with�theŠOR.BƒD0,D2Žbaud�rate�code.;ŠMOVE.B�D2,VM03_BRCR‡Write�it�back�to�the�control�register. ŠENDI * **‚Restore�registers�and�return.*8ŠMOVEM.L�(A7)+,D0-D2/A0-A3�Restore�registers�from�stack.ŠRTSŠPAGEJ****************************************************************************‰GET�DEVICE�STATUS�BYTE*8*‰Prepares�the�DEVICE�STATUS�byte�which�contains,�if�the:*‰board�is�capable�of�sensing�it,�the�condition�of�the�DSR8*‰line�(which�indicates�device�ready/unready).‚Note�that:*‰with�the�MVME�400�this  �info�cannot�be�read�directly�from<*‰the�device�during�an�interrupt�tour,�but�it�has�been�saved*‰in�the�CCB�under�PIA_ASAV.*8*‰Note:‚this�routine�does�not�set�the�break�indicator�in*�the�device�status�byte.F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.**<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.**‰Entry:�A5�=�address�of�CCB*ˆInterrupt�level�on�entry:�0**&*‰Exit:‚D0.B�=�the�device�status�byte.*�D1‚is�saved�and�restored.*J************************************************************************** GET_STAT: ŠCLR.B‚D0‰MOVE.L‚D1,-(SP) **‚Add�in�the�status�of�DCD.*5ŠPUT_BYTE�NCR0DCD,D1‡If�DCD�is�high�at�the�connector,ŠAND.B‚EXT_STATUS(A5),D1‚*ŠIF…�THENŠ*6ŠBSETƒ#XDSDCD,D0‰set�the�DCD�bit�in�the�device�status.ŠENDI–* *6*‚Add�in�whether�or�not�we're�detecting�the�baud�rate.*@ŠTST.B‚AUTO_BAUD(A5)†If�we're�currently�in�AUTO�BAUD�RATE�DETECTŠIF…�THENŠmode,2ŠBSETƒ#XDSABR,D0‰set�the�bit�in�the�device�status.ŠENDI–* *I*‚Is�this�an�MVME�400�board?‚If�so,�get�DSR�status�from�the�PIA.‚We�can'tK*‚really�go�out�and�read�the�PIA�at�this�point�(we�might�accidentally�clearG*‚a�pending�interrupt),�so�we�look�instead�at�the�last�version�of�it�we*‚saved�in�the�CCB.*9ŠIF.B�BOARD(A5)��#MVME400�THEN‚If�this�is�an�MVME400, BŠMOVE.B�PIA_ASAV(A5),D1„D1�<--�saved�copy�of�A-side�per.�data�reg.2ŠBTSTƒ#0,CCBTYPE(A5)…If�we're�handling�the�A�side,ŠIF…�THENŠ*1ŠADD.B‚D1,D1Žshift�bit�6�into�the�bit�7�position.ŠENDI–* 0ŠTST.B‚D1‘If�bit�7�is�set�(indicating�DSR�is�low/ŠIF…�THENŠand�hence�the�device�is�unready),:ŠBSETƒ#XDSNRB,D0‰set�the�unready�bit�in�the�device�status.ŠENDI–* ŠENDI–* ‰MOVE.L‚(A7)+,D1 ŠRTS—Return.ŠPAGEM******************************************************************************5*ˆDEVICE�DEPENDENT�STUFF�FOR�LOWERING�A�HARDWARE�LINE*ˆTO�STOP�THE�TRANSMITTER.*<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.*F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.***ˆEntry:$*’A1�=�address�of�our�side�of�device*’A5�=�address�of�CCB3*ˆInterrupt�level�on�entry:�INHIBITED�at�our�level.*K*************************************************************************** DDP_STOP:CŠAND.B‚#$FF-NCW5DTR,R5_7201(A5)‚Change�our�image�of�7201�register�5*§to�show�DTR�low,%*£and�put�it�in�7201�register�5�while2ŠMOVE.B�#NCW0RG5,CREG(A1)‚interrupts�are�disabled.ŠMOVE.B�R5_7201(A5),CREG(A1)‚*‰RTS9*********************************************************‰PAGEK****************************************************************************$*ˆDEVICE�DEPENDENT�UNSTOP�THE�DEVICE*=*ˆWhen�we�are�not�using�XOFF/XON,�we�unstop�the�device�in�our*ˆown�device�dependent�way.*;*ˆWe�are�running�in�background�when�this�routine�is�called.*?*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning*ˆof�the�driver.*<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.*/*ˆEntry:„A1�=�address�of�our�side�of�the�device*’A5�=�address�of�the�CCB5*ˆIneterrupt�level�upon�entry:�INHIBITED�at�our�level*J************************************************************************** DDP_UNSTOP:*AŠOR.Bƒ#NCW5DTR,R5_7201(A5)�Set�the�DTR�line�high�(using�the�imageCŠMOVE.B�#NCW0RG5,CREG(A1)‚of�control�register�5�stored�in�the�CCB).ŠMOVE.B�R5_7201(A5),CREG(A1)�* ‰RTS‰PAGEK****************************************************************************&*ˆDEVICE�DEPENDENT�BEGIN�BREAK�ROUTINE*F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.*<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.**ˆEntry:„A5�=�addr�of�CCB!*’A1�=�addr�of�our�side�of�device4*ˆInterrupt�level�upon�entry:�INHIBITED�at�our�level**ˆExit:* *ˆUses�D0*E**************************************  *******************************  DDP_BEG_BREAK:‰SAVE†D0>ˆMOVEQ‚#NCW5BRK,D0ˆCreate�an�image�of�the�7201's�control�reg�5>ˆOR.BƒR5_7201(A5),D0…with�the�TRANSMIT�BREAK�bit�set�and�writeDˆMOVE.B�#NCW0RG5,CREG(A1)‚that�out�to�control�register�5�of�our�side ˆMOVE.B�D0,CREG(A1)ˆof�the�7201. ‰RESTOREƒD0‰RTS  ‰PAGEK****************************************************************************$*ˆDEVICE�DEPENDENT�END�BREAK�ROUTINE*F*ˆThe�offset�to�this�routine�must�be�installed�at�the�beginning�of�the *ˆdriver.*<*ˆIt�is�important�to�keep�the�interrupt�level�the�same�as�it*ˆwas�upon�entry.**ˆEntry:„A5�=�addr�of�CCB!*’A1�=�addr�of�our�side�of�device5*ˆInterrupt�level�upon�entry:�INHIBITED�at�our�level.**ˆExit:*L**************************************************************************** DDP_END_BREAK:‰MOVE.B„#NCW0RG5,CREG(A1)‰MOVE.B„R5_7201(A5),CREG(A1)‰RTS ‰PAGEI***************************************************************************“B�A�C�K�G�R�O�U�N�D**šAND**‘C�A�L�L�__�G�U�A�R�D�E�D**–R�O�U�T�I�N�E�S**•(DEVICE-DEPENDENT)*E*********************************************************************ŠPAGEO*********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*A*‰The�initialization�routine�has�gone�around�resetting�everythingD*‰it�can,�but�the�routines�RESET�and�DDP_RESET�should�only�be�called>*‰from�within�the�background.‚So�he�invoked�this�routine�to�do *‰it�for�him.*?*‰In�addition,�these�other�device-dependent�things�MUST�be�done>*‰before�we�can�handle�commands.‚They�probably�could�have�been?*‰done�in�INIT�at�the�start�of�the�driver�but�are�handled�here.*5*‰1.‚Put�the�start�address�of�the�driver�into�the�CCB*�variable�DRV_ADDR.>*‰2.‚Set�up�the�device-dependent�BABs�using�the�macro�SET_BAB.;*‰3.‚Put�the�address�of�the�A-side�of�a�dual�channel�device6*�into�the�CCB�variable�ADRSIDEA.‚If�not�dual�channel,**�put�the�address�of�Port�1�into�ADRSIDEA.**‰Entry:*�A5�=�address�of�CCB.*O******************************************************************************* DO_INIT:**‚Inhibit�interrupts*‰PUSH†SR‰INHIBIT*)*‚Get�address�of�start�of�driver�into�CCB*‰LEA‡MPSCDRV(PC),A4‰MOVE.L„A4,DRV_ADDR(A5)*$*‚Set�up�the�device�dependent�BAB's.*‰SET_BABƒDCD0,DCD‰SET_BABƒDSR0,DSR *6*‚Set�up�the�address�of�the�A�side�of�the�Serial�port.*?ŠMOVE.L�CCBCHB(A5),ADRSIDEA(A5)‚Move�address�of�our�side�of�the;ŠBTST.B�#0,CCBTYPE(A5)…7201�to�CCB�as�address�of�A�side.‚If3ŠIF…�THENŠthe�channel�type�says�we're�really�B,=ŠSUB.L‚#2,ADRSIDEA(A5)„subtract�2�from�the�address�to�make�itŠENDI–the�A�side. *%%%%%%%%%%%% BWN 6/25/84* DEVICE DEPENDENT STUFF*H*‚Determine�the�board�type.‚If�it's�an�MVME�400�(which�has�a�PIA�on�it),!*‚test�it�and�initialize�the�PIA.*:ŠIF.B�BOARD(A5)‚�#MVME400�THEN‚If�this�is�an�MVME�400, AŠMOVE.L�ADRSIDEA(A5),A0„A0�<--�addr�of�7201�port�A�ctrl�register.7ŠLEA„2(A0),A1‹A1�<--�addr�of�7201�port�B�ctrl�register.-ŠSEL_PER�A‘See�if�the�fail�LED�is�on.‚If�not,<ŠBTSTƒ#LED_STAT,PIAPER_A(A0)‚someone�else�has�already�set�up$ŠIF…�THENŠthe�7201.‚If�it�is�on, :ŠBSETƒ#LED_CTRL,PIAPER_A(A0)‚Set�the�fail�light�bit�in�the*§Peripheral�Data�Register. 1ŠSEL_DDR�A‘Set�up�the�PIA's�A-side�Data�Direction>ŠMOVE.B�#DDR_A,PIADDR_A(A0)‚Register.‚If�it�does�not�read�back+ŠCMP.B‚#DDR_A,PIADDR_A(A0)‚correctly,�fail. ŠBNE„FAIL�* -ŠSEL_DDR�B‘Set�up�the�Data�Direction�Register*ŠMOVE.B�#DDR_B,PIADDR_B(A0)‚on�the�B�side. DŠMOVE.B�#NCW0RG1,CREG(A1)‚Make�sure�the�CONDITION�AFFECTS�VECTOR�bit6ŠMOVE.B�#0,CREG(A1)ˆis�off�in�register�1B�of�the�7201.@ŠMOVE.B�#NCW0RG2,CREG(A1)‚Write�the�test�value�out�to�the�7201'sAŠMOVE.B�#TEST_VAL,CREG(A1)�vector�register�(2B)�and�read�it�back.5ŠMOVE.B�#NCW0RG2,CREG(A1)‚If�it's�not�the�same,�fail.ŠCMP  .B‚#TEST_VAL,CREG(A1)�* ŠBNE„FAIL�* 3ŠSEL_PER�A‘Leave�the�PIA�pointing�to�the�Peripheral$ŠSEL_PER�B‘Data�Registers�(always!).3ŠBCLRƒ#LED_CTRL,PIAPER_A(A0)ƒTurn�off�the�fail�LED! ŠENDI ŠENDI 0*‚Now�actually�do�the�minimum�setup�on�the�7201.*6ŠMOVE.L�CCBCHB(A5),A1†A1�<--�addr�of�our�side�of�7201.6ŠMOVE.L�ADRSIDEA(A5),A2„A2�<--�addr�of�A�side�of�7201.,ŠLEA„2(A2),A3‹A3�<--�addr�of�B�side�of�7201. 1ŠMOVE.B�#NCW0RCN,CREG(A1)‚Reset�our�7201�channel.  **ˆINHIBIT0**ˆCLR.B‚ES_ST(A5)ŠSet�ES�process�state�to�IDLE. *A*‚[2A]ƒpriority�relationship�RxA�>�RxB�>�TxA�>�TxB�>�ExTA�>�ExTB.*@ŠMOVE.B�#NCW0RG2,CREG(A2)‚Point�to�control�register�2�on�port�A.9ŠMOVE.B�#NCW2PRI,CREG(A2)‚[2A]�<--�priority�relationship. **‚[2B]ƒinterrupt�vector�is�0.*@ŠMOVE.B�#NCW0RG2,CREG(A3)‚Point�to�control�register�2�on�port�B.ŠMOVE.B�#0,CREG(A3)ˆ[2B]�<--�0 * *‚[1B]ƒcondition�affects�vector.*@ŠMOVE.B�#NCW0RG1,CREG(A3)‚Point�to�control�register�1�on�port�B.<ŠMOVE.B�#NCW1STV,CREG(A3)‚[1B]�<--�condition�affects�vector. *%%%%%%%%%%%%%%%%%%%%%%%%*K*‚We�have�to�set�up�a�few�things�in�the�CCB�before�invoking�the�background.*@ŠMOVE.B�SREG(A1),EXT_STATUS(A5)‚Get�the�current�external�status.7ŠSF…CLOCK_64(A5)‡We're�starting�out�with�the�x16�clock. ŠJSR„RESETŽReset�everything.ŠBSR.L‚DDP_RESET6*‰BSR.L‚SETUPŽSet�up�the�7201�according�to�the�config.**‚Enable�interrupts�now.* **‡ENABLE‰POP‡SR **ˆBRA.L‚CHECK_WORK‰And�exit.‰RTS*%%%%%%%%%%%% BWN 9/17/84FAIL…JSR‡MARK_DOWN**‡MOVE.B„#M_DOWN,MENU(A5)**‡MOVE.B„#ISTAUNR,DOWN_ERR(A5)*%%%%%%%%%%%%%% BWN 7/9/84**‡BRA‡CHECK_WORK **‡ENABLE‰POP‡SR‰RTS*%%%%%%%%%%%%%%%%%%%%%%%%*%%%%%%%%%%%%%%ŠPAGEO*********************************************************************************‰DSR�TRANSITION�HANDLER*?*‰This�part�of�the�background�runs�when�the�PIA�senses�a�change@*‰on�the�DSR�line.‚This�either�means�that�it�(terminal�or�modem)?*‰is�just�going�ready�or�just�going�unready.‚If�it's�just�going;*‰ready,�then�a�modem�just�answered�the�phone.‚If�it's�justC*‰going�unready,�somebody�hung�up�or�did�something�to�the�terminal./*‰It's�very�likely�we'll�want�to�send�an�event.*B*‰This�routine�is�called�using�BACKGROUND�so�we�enter�at�interrupt6*‰level�0,�and�we�must�must�exit�at�interrupt�level�0.6*‰We�must�also�restore�register�A7�if�we�mess�with�it.@*‰Other�than�that,�we�are�free�to�return�whatever�we�like�in�the *‰registers.** *‰DSR0�(background)�entry�point:-*�A1�=�address�of�background�activation�block**‰DSR�entry�point:*‰Entry:#*�A1�=�address�of�our�side�of�7201.%*�A4�=�address�of�start�of�our�driver*�A5�=�address�of�CCB.**‰Exit:*�A0�=�garbage.*O******************************************************************************* *%%%%%%%%%%%%%%%%%�bwn‚7/9/84DSR0:**ƒSet�up�A5�and�A1.<*ƒWhen�the�exec�calls�this�routine,�A1�=�address�of�the�BAB.* (‰LEA‡-DSR_BAB(A1),A5„A5�<---�CCB�address9‰MOVE.L„CCBCHB(A5),A1‡A1�<---�address�of�our�side�of�72011‰MOVE.L„DRV_ADDR(A5),A4…A4�<---�address�of�driver*"*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%DSR: **ˆPUSH.L�A1‘Save�A1. D*‚If�we�were�waiting�for�DSR�to�go�high�(because�of�a�RI�interrupt),E*‚then�the�phone�has�been�answered�and�we�can�generate�a�break�event.D*‚Before�we�do,�though,�set�things�up�to�interrupt�when�DSR�goes�low.*‚so�we�know�when�the�device�is�going�unready.*CŠIF.B�DSR_ST(A5)��#S_WT4RDY�THENƒIf�we're�waiting�for�DSR�high, *%%%%%%%%%%%ƒBWN‚9/12/84ŠMOVE.L‚ADRSIDEA(A5),A0 *%%%%%%%%%%%@ŠBTST.B�#0,CCBTYPE(A5)…If�we're�handling�the�A�side�of�the�7201,ŠIF…�THENŠ*CŠBSET�#DSR_FALLING,PIACTL_A(A0)‚set�the�A-side�control�reg.�to�wait'ŠELSE–for�DSR�to�go�low,�else�(we're�B)CŠBSET�#DSR_FALLING,PIACTL_B(A0)‚set�the�B-side�control�reg.�to�waitŠENDI–for�DSR�to�go�low. CŠMOVE.B�#S_WT4UNR,DSR_ST(A5)ƒChange�state�back�to�wait�for�DSR�low,*%%%%%%%%%%%%%%%%%�bwn‚7/9/84?**ˆBSETW‚#W_BREAK,WORK(A  5)‚and�flag�work�for�the�break�handler. ŽBKGRND„BREAK*%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ŠELSE *A*‚We�were�waiting�for�DSR�to�go�low,�so�this�interrupt�means�that?*‚the�terminal�is�unready.‚If�we�were�doing�I/O,�send�an�event.* ŠJSR„TERM_UNRDY ŠIF‚‚THENŽTR0$.KILLER�,ŠENDI ŠENDI   **ˆPOP.L‚A1‘Restore�A1.*%%%%%%%%%%%%%%%%%�bwn‚7/9/844**ˆBRA„CHECK_WORK‰Return�to�the�background�executor.‰RTS!*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%ŠPAGEO*********************************************************************************‰HANDLE�A�DCD�TRANSITION*?*‰There�was�a�transition�on�the�DCD�line.‚We�may�need�to�notify;*‰the�user,�and�we�may�need�to�start�auto�baud�rate�detect.*B*‰This�routine�is�called�using�BACKGROUND�so�we�enter�at�interrupt6*‰level�0,�and�we�must�must�exit�at�interrupt�level�0.6*‰We�must�also�restore�register�A7�if�we�mess�with�it.@*‰Other�than�that,�we�are�free�to�return�whatever�we�like�in�the *‰registers.* *‰DCD0�(background)�entry�point:-*�A1�=�adrress�of�background�activation�block**‰DO_DCD�entry�point:*‰Entry:#*�A1�=�address�of�our�side�of�7201.%*�A4�=�address�of�start�of�our�driver*�A5�=�address�of�CCB.*O********************************************************************************%%%%%%%%%%%%%%%%%�bwn‚7/9/84DCD0:**ƒSet�up�A5�and�A1.<*ƒWhen�the�exec�calls�this�routine,�A1�=�address�of�the�BAB.*(‰LEA‡-DCD_BAB(A1),A5„A5�<---�CCB�address9‰MOVE.L„CCBCHB(A5),A1‡A1�<---�address�of�our�side�of�72011‰MOVE.L„DRV_ADDR(A5),A4…A4�<---�address�of�driver*"*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DO_DCD: */*‚Report�the�transition�if�we're�configured�to.*>ŠBTSTW‚#IOADCD,CONFIG+IOSATW(A5)‚If�the�attributes�word�in�the4ŠIF…�THENŠconfiguration�says�we're�reporting�DCD*§transitions,*%%%%%%%%%%%%%‚BWN�7/16/84 �BKGRND„BREAK;**ˆBSETW‚#W_BREAK,WORK(A5)‚mark�work�for�the�break�routine.*%%%%%%%%%%%%%%%%%%%ŠENDI–* */*‚Start�up�auto�baud�rate�detect�if�we�need�to.*?ŠPUT_BYTE�NCR0DCD,D0‡If�DCD�is�currently�high�at�the�connector,ŠAND.B‚EXT_STATUS(A5),D0‚*ŠIF…�THENŠ* @ŠBTSTW‚#IOAAUTO,CONFIG+IOSATW(A5)‚If�we're�configured�to�do�auto"ŠIF…�THENŠbaud�rate�detection, .ŠJSR„RESETŽReset�things�to�an�innocuous�state.ŠBSR.L‚DDP_RESET5ŠBSR.L‚CLOCK16ŒSet�the�clock�divisor�to�x16�to�start.;ŠST…AUTO_BAUD(A5)†Mark�that�we're�in�auto�baud�detect�mode. ŠENDI ŠENDI ‰RTS ‰PAGE*********************** *‚PATCH�SPACE***********************ŠDS.Wƒ30ŠEND  ééééé  éé=/*=/*†MPSCSPR.AF=/*K=/* Chain file to assemble NEC 7201 supervisor driver for the MVME400 board=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to MPSCSPR.LS=/*=/IFC \1ƒ=ARG�MPSCSPR.LS=/ENDIF=/*$=ASM MPSCSPR.SA,MPSCSPR.RO,\1;RZ=106=/*{ Included files are:=/*ƒ9995.&.NEC7201.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.CCB.EQ=/*}=/*=ENDééééééª*‰Working�storage�for�the�driver�is�defined�in�the�bottom�part *‰of�the�CCB.*J************************************************************************** *D*‡At�a�fixed�location�in�the�CCB�we�will�have�some�fields�which�willD*‚interface�us�to�SDLC.‚When�the�system�is�booted,�we�may�in�fact�beE*‚using�both�terminals.‚But�sometime�later�SDLC�may�be�brought�up,�atI*‚which�time�he�will�capture�the�vector�for�the�7201�and�set�the�SDLCACTVF*‚in�our�CCB.‚When�an�interrupt�occurs,�then,�he�gets�it.‚If�it�is�notF*‚for�him,�he�puts�the�contents�of�register�2B�(which�may�only�be�readF*‚once�for�a�given�interrupt)�and�puts�them�in�our�CCB,�and�then�jumps**‚into�our�CCB�so�as�to�fake�an�interrupt.@*‡When�we�get�control,�we�have�to�look�at�the�SDLCACTV�to�see�ifF*‚we�should�read�the�actual�chip�or�not.‚From�there�things�happen�just.*‚like�always�(the�subordinate�isn't�changed).* ŠOFFSET�$FE ŠIFGTƒCCBDDP-*'ŠFAILƒ499�Have�to�move�SDLC�stuff�down!ŠENDC ;SDLCACTV‚DS.Bƒ1’Flag�indicating�presence�of�SDLC�on�system.&*§0�=�SDLC�not�present;�read�the�chip.&*§nonzero�=�SDLC�present;�get�register*§2B�from�the�CCB.:REG2BSAVE�DS.Bƒ1’If�SDLC�is�active�and�an�interrupt�for�us&*§occurred,�here�is�where�he�saved�the*§contents�of�7201�register�2B.‰PAGEO*********************************************************************************ˆMACROS*O******************************************************************************* *.*‚Macros�to�push�and�pop�using�the�stack�(A7).*‚e.g.,„PUSH.B�#'*'ƒorƒPOP.L�D0* PUSH…MACRO‰MOVE.\0ƒ\1,-(A7)‰ENDM POP†MACRO‰MOVE.\0ƒ(A7)+,\1‰ENDM *$*‚Macros�to�create�the�offset�table.M*‚GEN16OFFSET�just�calls�GEN1OFFSET�16�times�so�I�don't�have�to�type�so�much.I*‚GEN1OFFSET�increments�VALUE�and�figures�out�whether�that�value,�if�readN*‚from�a�PIA�control�register,�would�indicate�a�DSR�interrupt,�a�RI�interrupt,/*‚or�both,�and�generates�an�appropriate�offset:?*„-4�=�no�interrupt…0�=�RI�interrupt…4�=�DSR�interrupt„8�=�bothC*‚If�the�control�register�fits�%1xxxxxx1,�a�DSR�interrupt�occurred.K*‚If�the�control�register�fits�%x10x1xxx,�a�RI‚interrupt�occurred�(the�0�isB*‚to�select�that�pin�as�an�interrupt�input�rather�than�an�output).*GEN16OFFSET MACRO GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET GEN1OFFSET ENDM GEN1OFFSET MACRO OFFSET SET -4N IFEQ (%01101000&VALUE)-%01001000 if RI interrupts enabled and flag is set....OFFSET SET OFFSET+4 ENDCO IFEQ (%10000001&VALUE)-%10000001 if DSR interrupts enabled and flag is set....OFFSET SET OFFSET+8 ENDC LIST VALUE SET VALUE Control register DC.B OFFSET ... and offset. NOLISTVALUE SE T VALUE+1 ENDMŠPAGE*4*‚Equates�relating�to�the�PIA�on�the�MVME�400�board.*?*‰offsets�from�the�address�of�the�7201�A-side�control�register:*6PIADDR_A‚EQU„-$C�PIA's�A-side�Data�Direction�Register.*‰included�is�a�parameter�telling�the�number�of�extra�pages�of>*‰memory�to�include�in�the�CCB,�and�information�describing�the*‰revision�of�the�driver.*L**************************************************************************** ŠSECTION‚0ŠOPT„BRS MPSCSPR: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!*=ŠDC.LƒINTERRUPT-MPSCSPR‚Address�of�interrupt�service�routine.9ŠDC.LƒCOMMAND-MPSCSPR„Address�of�command�service�routine.5ŠDC.LƒINIT-MPSCSPR‡Address�of�initialization�routine.ŠDC.Lƒ0’Reserved. **‚Other�CMR�parameters.*0ŠDC.Bƒ0’#�of�extra�pages�in�the�CCB.‚The�CCB�may)*§be�any�size�from�1�to�256�pages�(a�page'*§is�256�bytes):‚if�this�field�is�0,�it*§will�be�1�page,�etc.ŠDC.Bƒ0,0,0ŽReserved.ŠDC.Lƒ0,0,0ŽReserved. **‚Revision�info:*/ŠDC.Bƒ'�52383'‹Date�of�last�assembly�as�MMDDYY.1ŠDC.Bƒ'�'�Space�indicates�no�patches�to�.LO�file.)ŠDC.Bƒ'4'�Major�VERSAdos�revision�number.ŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INITIALIZATION�ROUTINE*'*‰Entry:�All�registers�have�been�saved.*�A5�=�address�of�CCB.**‰Exits�to�CMR�(via�RTS).*J**************************************************************************J**************************************************************************J**************************************************************************  INIT: *1*‚We�don't�have�anything�to�do�in�initialization.*ŠRTSŠPAGEJ**************************************************************************J**************************************************************************J****************************** **********************************************‰COMMAND�SERVICE�ROUTINE*J**************************************************************************J**************************************************************************J************************************************************************** COMMAND: *D*‚We�should�never�be�called�for�command�service!‚Since�we�have�been,*‚crash�the�system.* ŠTR0$.KILLERŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INTERRUPT�HANDLING�ROUTINE*;*‰This�routine�gets�control�whenever�an�interrupt�occurs�on;*‰this�vector�(unless�another�handler,�earlier�on�the�chain*‰for�this�vector,�claimed�it).*+*‰It�is�the�task�of�the�supervisor�(me)�to:7*�--�determine�whether�the�interrupt�is�from�my�devices*“(7201�and�PIA)2*�--�if�not,�return�to�CMR�with�the�carry�bit�0�to)*“indicate�that�the�interrupt�wasn't�mine7*�--�if�so,�set�up�the�environment�for�and�pass�control3*“to�the�appropriate�subordinate�handler,�depending3*“upon�which�device�&�side�the�interrupt�came�from.*<*‰If�SDLC�is�active,�instead�of�reading�register�2B�from�the8*‰7201,�we�get�the�copy�saved�for�us�in�our�CCB�by�SDLC.*J**************************************************************************J**************************************************************************J************************************************************************** INTERRUPT: ŠPUSH.L�D1‘Save�D1�on�the�stack.4ŠMOVE.L�CCBCHB(A5),A0†A0�<--�addr�of�A�side�of�7201. *.*‚Is�the�interrupt�from�the�A�side�of�our�PIA?*)ŠCLR.W‚D0‘D0�<--�A-side�control�register.ŠMOVE.B�PIACTL_A(A0),D0„*:ŠMOVE.B�PIAPER_A(A0),D1„D1�<--�A-side�peripheral�register.!*§This�also�clears�the�PIA�A-side%*§interrupt�if�there�was�one�pending.AŠMOVE.B�OFFSET_TABLE(PC,D0),D0‚D0�<--�the�offset�corresponding�to%*§the�control�register�value�we�read. 2ŠIF…�THENŠIf�it's�>=�0,�we've�got�an�interrupt*§for�the�A�side,�so ;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�A-side�handler.=ŠMOVE.L�CCBRTNI(A5),A1…A1�<--�entry�point�for�A-side�handler.:ŠJMP„8*4(A1,D0.W)‡Jump�into�the�branch�table�(the�8*4�gets'*§us�past�the�first�8�branches�into�the'*§PIA-caused�branches�for�the�MVME�400) ŠENDI *;*‚It's�not�from�the�A�side�of�the�PIA;�is�it�from�our�7201?L*‚If�SDLC�has�taken�over�the�vector,�get�the�7201�vector�from�the�CCB�ratherK*‚than�from�the�7201.‚Be�sure�to�mask�off�the�unwanted�bits�from�the�vector*‚in�either�case.*7ŠMOVEQ‚#$1C,D0ŒD0�<--�mask�to�get�rid�of�unwanted�bits. &ŠTST.B‚SDLCACTV(A5)‡If�SDLC�is�active,ŠIF…�THENŠ* AŠAND.B‚REG2BSAVE(A5),D0ƒD0�<--�vector�from�CCB�where�SDLC�put�it. ŠELSE–else�(SDLC�not�up), :ŠMOVE.B�#NCW0RG2,CREG+2(A0)�Point�to�register�2�on�port�B.1ŠAND.B‚SREG+2(A0),D0†D0�<--�vector�from�the�7201. ŠENDI–* :ŠBTST.B�#1,SREG(A0)ˆIf�the�interrupt�pending�bit�(bit�1�of3ŠIF…�THENŠstatus�register�0A)�is�set,�then�it's*§an�interrupt�from�our�7201. ;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�A-side�handler.3ŠBCLRƒ#4,D0ŽClear�the�B-side/A-side�bit�of�the�72017ŠIF…�THENŠvector.‚If�it�was�already�clear�(B-side),;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�B-side�handler.ŠENDI–* =ŠMOVE.L�CCBRTNI(A5),A1…A1�<--�entry�point�for�chosen�handler.:ŠJMP„4*4(A1,D0.W)‡Branch�into�the�user's�branch�table�(the$*§4*4�gets�us�past�the�VM02�branches*§into�the�MVME�400�branches). ŠENDI *I*‚The�interrupt�is�not�from�the�A�side�of�our�PIA�or�from�our�7201;�is�it*‚from�the�B�side�of�our�PIA?*7ŠMOVE.B�PIACTL_B(A0),D0„D0�<--�B-side�control�register.AŠMOVE.B�OFFSET_TABLE(PC,D0),D0‚D0�<--�offset�corresponding�to�the!*§control�register�value�we�read.4ŠIF…�THENŠIf�it's�>=�0,�we�have�an�interrupt,�so 6ŠTST.B ‚PIAPER_B(A0)‡Clear�the�interrupt�by�reading�the"*§B-side�peripheral�data�register.;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�A-side�handler.;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�B-side�handler.=ŠMOVE.L�CCBRTNI(A5),A1…A1�<--�entry�point�for�B-side�handler.:ŠJMP„8*4(A1,D0.W)‡Jump�into�the�branch�table�(the�8*4�gets'*§us�past�the�first�8�branches�into�the'*§PIA-caused�branches�for�the�MVME�400) ŠENDI *1*‚The�interrupt�was�not�for�me,�so�return�to�CMR.*1ŠPOP.L‚D1‘Restore�D1�and�return�to�CMR.‚The�carry-ŠRTS—bit�is�0�from�the�AND,�which�will�signal-*£to�CMR�that�we�didn't�handle�the�interrupt.  *G*‚NOTE:‚the�subordinate�channel's�interrupt�entry�point�must�begin�with*‚code�like�the�following:* *‚INTERUPT:*‚*…VM02�interrupts *ŒBRA.L‚TBE *ŒBRA.L‚ES *ŒBRA.L‚RCA *ŒBRA.L‚SRC*‚*…MVME�400�interrupts*ŒBRA.L‚TBE400 *ŒBRA.L‚ES400*ŒBRA.L‚RCA400*ŒBRA.L‚SRC400 *ŒBRA.L‚RI *ŒBRA.L‚DSR3*ŒBRA.L‚RIANDDSR…(RI�and�DSR�both�occurred�at�once)*E*‚The�subordinate�channel�may�use�freely�(without�PUSHing)�any�of�the)*‚following�registers:…D0,�D1,�A0,�A1,�A5*E*‚A0�contains�the�address�of�the�A�side�control�register�of�the�7201.3*‚A5�contains�the�address�of�the�subordinate's�CCB.H*‚D1�contains�the�contents�of�the�PIA's�A-side�peripheral�data�register,A*…which�you�might�want�to�save�away�in�case�DSR�status�is�needed.*C*‚D1�must�be�restored�(via�a�POP.L�D1)�before�the�subordinate�exits*‚from�its�interrupt�tour.*ŠPAGEO*******************************************************************************O********************************************************************************.*‰OFFSET�TABLE�FOR�PIA�CONTROL�REGISTER�VALUES*<*‰The�following�procedure�is�used�to�determine�whether�a�PIA$*‰is�interrupting�on�a�certain�side:=*‰1)�the�8-bit�value�from�the�PIA's�control�register�is�read.6*‰2)�the�corresponding�offset�is�read�from�this�table.A*‰3)�if�the�offset�is�-4=$FC,�there�is�no�interrupt�on�that�side;%*Œotherwise�the�offset�is�as�follows:*Œ0�=�RI�interrupt.*Œ4�=�DSR�interrupt.*Œ8�=�RI�and�DSR�interrupts.*0*‰Read�the�hex�part�of�a�table�entry�as�follows: *”000000XX*‰0�YYYYYYYY�ZZ*,*‰XX�=�the�control�register�value�(00�-�FF).:*‰YYYYYYYY�=�the�location�of�this�entry�within�the�driver.%*‰ZZ�=�the�offset�(FC,�00,�04,�or�08)*O*******************************************************************************O******************************************************************************* OFFSET_TABLE: ŠNOLIST VALUE…SET„0 ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSET ŠGEN16OFFSETŠLIST ŠEND=/*=/*†MPSCSUP.AF=/*B=/* Chain file to assemble NEC 7201 supervisor driver for the VM02=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to MPSCSUP.LS=/*=/IFC \1ƒ=ARG�MPSCSUP.LS=/ENDIF=/*$=ASM MPSCSUP.SA,MPSCSUP.RO,\1;RZ=106=/*{ Included files are:=/*ƒ9995.&.NEC7201.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.CCB.EQ=/*}=/*=ENDéé ééééô9MPSCSUPƒIDNTƒ4,0‡NEC7201�SUPERVISOR�DRIVER�FOR�VM02�BOARD6ŠTTL„MPSCSUP:‚NEC7201�SUPERVISOR�DRIVER�FOR�VM02�BOARD ŠLLENƒ120J**************************************************************************J**************************************************************************J**************************************************************************J***************************************************************************<*‰MPSCSUP:‚Supervisor�channel�driver�for�NEC�7201�drivers�on*�the�VM02�board.*=*‰Purpose:‚VERSAdos�device�driver�to�take�interrupts�from�the1*�NEC�7201�chip�on�a�VM02�and�pass�control�to�the"*�appropriate�subordinate�channel.**‰Revision�history:**�9/16/82‚Initial�release�by�Steve�Franck.*;*‰Interface:‚This�driver�does�not�service�commands.‚When�an4*�interrupt�occurs,�this�driver�checks�whether�it�is3*�from�the�7201�for�which�it�is�responsible.‚If�so,1*�it�determines�which�side�of�the�7201�caused�the1*�interrupt�and�passes�control�to�the�appropriate8*�subordinate�handler,�using�the�CCBSUB�link�in�the�CCB.**‰RMS68K�routines�used: *�TR0$.KILLER**‰Other�notes:4*�This�supervisor�requires�that�subordinate�channels6*�for�both�of�the�7201�ports�be�allocated�and�that�the(*�channel�for�port�A�be�allocated�first.*�This�code�is�ROMable.'*�Assemble�using�chain�file�MPSCSUP.AF.*J**************************************************************************J**************************************************************************J**************************************************************************J**************************************************************************  **‚Equate�files�included:* *‰NEC7201*‰9995.&.STR.EQ*‰CCB*ŠNOLISTŠINCLUDE�9995.&.NEC7201.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.CCB.EQŠLIST‰PAGEO*********************************************************************************ˆMACROS*O******************************************************************************* ý<9B;(*.*‚Macros�to�push�and�pop�using�the�stack�(A7).*‚e.g.,„PUSH.B�#'*'ƒorƒPOP.L�D0* PUSH…MACRO‰MOVE.\0ƒ\1,-(A7)‰ENDM POP†MACRO‰MOVE.\0ƒ(A7)+,\1‰ENDMŠPAGEJ***************************************************************************!*‰CCB�--�DEVICE�DEPENDENT�PORTION*>*‰Working�storage�for�the�driver�is�defined�in�the�bottom�part *‰of�the�CCB.*J************************************************************************** *D*‡At�a�fixed�location�in�the�CCB�we�will �have�some�fields�which�willD*‚interface�us�to�SDLC.‚When�the�system�is�booted,�we�may�in�fact�beE*‚using�both�terminals.‚But�sometime�later�SDLC�may�be�brought�up,�atI*‚which�time�he�will�capture�the�vector�for�the�7201�and�set�the�SDLCACTVF*‚in�our�CCB.‚When�an�interrupt�occurs,�then,�he�gets�it.‚If�it�is�notF*‚for�him,�he�puts�the�contents�of�register�2B�(which�may�only�be�readF*‚once�for�a�given�interrupt)�and�puts�them�in�our�CCB,�and�then�jumps**‚into�our�CCB�so�as�to�fake�an�interrupt.@*‡When�we�get�control,�we�have�to�look�at�the�SDLCACTV�to�see�ifF*‚we�should�read�the�actual�chip�or�not.‚From�there�things�happen�just.*‚like�always�(the�subordinate�isn't�changed).* ŠOFFSET�$FE ŠIFGTƒCCBDDP-*'ŠFAILƒ499�Have�to�move�SDLC�stuff�down!ŠENDC ;SDLCACTV‚DS.Bƒ1’Flag�indicating�presence�of�SDLC�on�system.&*§0�=�SDLC�not�present;�read�the�chip.&*§nonzero�=�SDLC�present;�get�register*§2B�from�the�CC.:REG2BSAVE�DS.Bƒ1’If�SDLC�is�active�and�an�interrupt�for�us&*§occurred,�here�is�where�he�saved�the*§contents�of�7201�register�2B.ŠPAGEJ***************************************************************************+*‰SERVICE�VECTOR�TABLE,�REVISION�INFO,�ETC.*@*‰This�table�is�examined�by�CMR�when�the�channel�is�allocated�toC*‰determine�where�to�go�for�interrupts,�commands,�&�initialization.<*‰It�must�always�be�at�the�very�top�of�the�driver�code.‚Also>*‰included�is�a�parameter�telling�the�number�of�extra�pages�of>*‰memory�to�include�in�the�CCB,�and�information�describing�the*‰revision�of�the�driver.*L**************************************************************************** ŠSECTION‚0ŠOPT„BRS MPSCSUP: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!*=ŠDC.LƒINTERRUPT-MPSCSUP‚Address�of�interrupt�service�routine.9ŠDC.LƒCOMMAND-MPSCSUP„Address�of�command�service�routine.5ŠDC.LƒINIT-MPSCSUP‡Address�of�initialization�routine.ŠDC.Lƒ0’Reserved. **‚Other�CMR�parameters.*0ŠDC.Bƒ0’#�of�extra�pages�in�the�CCB.‚The�CCB�may)*§be�any�size�from�1�to�256�pages�(a�page'*§is�256�bytes):‚if�this�field�is�0,�it*§will�be�1�page,�etc.ŠDC.Bƒ0,0,0ŽReserved.ŠDC.Lƒ0,0,0ŽReserved. **‚Revision�info:*/ŠDC.Bƒ'091682'‹Date�of�last�assembly�as�MMDDYY.1ŠDC.Bƒ'�'�Space�indicates�no�patches�to�.LO�file.)ŠDC.Bƒ'4'�Major�VERSAdos�revision�number.ŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰INITIALIZATION�ROUTINE*'*‰Entry:�All�registers�have�been�saved.*�A5�=�address�of�CCB.**‰Exits�to�CMR�(via�RTS).*J**************************************************************************J**************************************************************************J**************************************************************************  INIT: *1*‚We�don't�have�anything�to�do�in�initialization.*ŠRTSŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************************‰COMMAND�SERVICE�ROUTINE*J**************************************************************************J**************************************************************************J************************************************************************** COMMAND: *D*‚We�should�never�be�called�for�command�service!‚Since�we�have�been,*‚crash�the�system.* ŠTR0$.KILLERŠPAGEJ**************************************************************************J**************************************************************************J****************************************************************** **********‰INTERRUPT�HANDLING�ROUTINE*;*‰This�routine�gets�control�whenever�an�interrupt�occurs�on;*‰this�vector�(unless�another�handler,�earlier�on�the�chain*‰for�this�vector,�claimed�it).*+*‰It�is�the�task�of�the�supervisor�(me)�to:4*�--�determine�whether�the�interrupt�is�from�my�72012*�--�if�not,�return�to�CMR�with�the�carry�bit�0�to)*“indicate�that�the�interrupt�wasn't�mine7*�--�if�so,�set�up�the�environment�for�and�pass�control3*“to�the�appropriate�subordinate�handler,�depending**“upon�which�side�the�interrupt�came�from.*<*‰If�SDLC�is�active,�instead�of�reading�register�2B�from�the8*‰7201,�we�get�the�copy�saved�for�us�in�our�CCB�by�SDLC.*J**************************************************************************J**************************************************************************J************************************************************************** INTERRUPT: 4ŠMOVE.L�CCBCHB(A5),A0†A0�<--�addr�of�A�side�of�7201. *L*‚If�SDLC�has�taken�over�the�vector,�get�the�7201�vector�from�the�CCB�ratherK*‚than�from�the�7201.‚Be�sure�to�mask�off�the�unwanted�bits�from�the�vector*‚in�either�case.*7ŠMOVEQ‚#$1C,D0ŒD0�<--�mask�to�get�rid�of�unwanted�bits. &ŠTST.B‚SDLCACTV(A5)‡If�SDLC�is�active,ŠIF…�THENŠ* AŠAND.B‚REG2BSAVE(A5),D0ƒD0�<--�vector�from�CCB�where�SDLC�put�it. ŠELSE–else�(SDLC�not�up), :ŠMOVE.B�#NCW0RG2,CREG+2(A0)�Point�to�register�2�on�port�B.1ŠAND.B‚SREG+2(A0),D0†D0�<--�vector�from�the�7201. ŠENDI–* **‚Is�the�interrupt�for�us?*:ŠBTST.B�#1,SREG(A0)ˆIf�the�interrupt�pending�bit�(bit�1�of5ŠIF…�THENŠstatus�register�0A)�is�not�set,�then�it)ŠRTS—isn't�an�interrupt�from�our�7201,�so,ŠENDI–return�to�CMR�(the�carry�bit�is�0�from*§the�AND�operation). ŠPUSH.L�D1‘Save�D1�on�the�stack.;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�A-side�handler.3ŠBCLRƒ#4,D0ŽClear�the�B-side/A-side�bit�of�the�72017ŠIF…�THENŠvector.‚If�it�was�already�clear�(B-side),;ŠMOVE.L�CCBSUB(A5),A5†A5�<--�addr�of�CCB�of�B-side�handler.ŠENDI–* =ŠMOVE.L�CCBRTNI(A5),A1…A1�<--�entry�point�for�chosen�handler.4ŠJMP„0(A1,D0.W)‰Branch�into�the�user's�branch�table. *G*‚NOTE:‚the�subordinate�channel's�interrupt�entry�point�must�begin�with*‚code�like�the�following:* *‚INTERRUPT: *ŒBRA.L‚TBE *ŒBRA.L‚ES *ŒBRA.L‚RCA *ŒBRA.L‚SRC*D*‚The�subordinate�channel�may�use�freely�(without�saving)�any�of�the)*‚following�registers:…D0,�D1,�A0,�A1,�A5*E*‚A0�contains�the�address�of�the�A�side�control�register�of�the�7201.3*‚A5�contains�the�address�of�the�subordinate's�CCB.*C*‚D1�must�be�restored�(via�a�POP.L�D1)�before�the�subordinate�exits*‚from�its�interrupt�tour.* ŠENDééé=/*=/*†P050DRV.AF=/*>=/* Chain file to assemble printer driver for the VME050 board=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to P050DRV.LS=/*=/IFC \1ƒ=ARG�P050DRV.LS=/ENDIF=/*%=ASM P050DRV.SA,P050DRV.RO,\1;MRZ=146=/*{ Included files are:=/*ƒ9995.&.TRACE.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ=/*ƒ9995.&.LV5.EQ=/*}=/*=END éééééé&ŠPAGEKP050DRVƒIDNTƒ4,0�VERSAdos�Local�Printer�I/O�Handler�Process�V4.0�-�09/13/82?ŠTTL„VERSADOS…LOCAL�PRINTER�I/O�HANDLER�PROCESS�V4.0�-�09/13/82 ŠLLENƒ120*‰INCLUDE�files�are:**‰9995.&.TRACE.EQ*‰9995.&.STR.EQ*‰9995.&.TCB.EQ*‰9995.&.CCB.EQ*‰9995.&.IOE.EQ*‰9995.&.NIO.EQ*‰9995.&.LV5.EQŠNOLISTŠINCLUDE�9995.&.TRACE.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.TCB.EQŠINCLUDE�9995.&.CCB.EQŠINCLUDE�9995.&.IOE.EQŠINCLUDE�9995.&.NIO.EQŠINCLUDE�9995.&.LV5.EQŠLISTJ****************************************************************************1* PRT -- REV. 1.00 02NOV81 (TL09) JIM SMITH - IOH9*ˆREV.�1.01�01FEB82�(TL09)�JIM�SMITH�-�VECTOR�CHAIN�(IOH)5*ˆREV.�1.02�23FEB82�(TL09)�JIM�SMITH�-�IOCB�USE�(IOH)5*ˆREV.�2.00�15APR82�(TL09)�JIM�SMITH�-�PRINTER�DRIVER5*ˆREV.�2.01�01JUN82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER5*ˆREV.�2.10�15JUL82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER-*ˆREV‚2.20�18JAN84ˆMARC�BRIEL-�PRINTER�DRIVER@*ˆREV.�2.30�17JUL84ˆKENT�GOTT�-�Adapted�for�VME050�parallel�port;*ˆREV‚2.31�17DEC84ˆMIKE�DUH‚-�Removed�ENABL�at�PRTINRTN�for *­SPR�1178�(Epson�RX80�printer).*«-�Fixed�HALT�routine.=*ˆREV‚2.32�19DEC84ˆMIKE�DUH‚-�Increased�timeout�to�10�seconds*­for�use�with�slow�printers.ééé /&8)@GH@PCXI`?h>pBx7€0ˆ9�>˜= Q¨1°=¸<À?È ÐFØ7àDè 4*ˆREV‚2.33�18FEB85ˆMIKE�DUH�-‚Changed�Printer�STROBE*­instructions�to�use�a�MOVE*­instead�of�BCLR�and�BSET.‚The *­STROBE�register�is�write�only.7*ˆREV‚2.34�8MAR85‰DICK�V.…Halt�routine�register�changes*'*ƒPURPOSE:‚CHANNEL�(DEVICE)�I/O�HANDLER*�****�PRINTER�DRIVER�*****/*ƒENTRY:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒEXIT:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION***ƒCODE�IS�RE-ENTRANT**H*-----------------------------------------------------------------------*PRTORG:ŠPAGE*(****************************************(* EQUATES FOR SPECIAL ASCII CHARACTERS *(*****************************************NUL‡EQU„$00�NullBEL‡EQU„$07�BellBSˆEQU„$08�BackspaceLFˆEQU„$0A�Line�feedFFˆEQU„$0C�Form�feedCRˆEQU„$0D�Carriage�returnSPACE…EQU„$20�Blank ******************** DEVICE EQUATES ********************(DEV1AD„EQU„0’A-side�data�register�offsetéééé+DEV1AC„EQU„2’A-side�control�register�offset(DEV1BD„EQU„4’B-side�data�register�offset+DEV1BC„EQU„6’B-side�control�register�offset*-STRBSY„EQU„%00000100ŠDevice�busyŠVME050�fault4STROUT„EQU„%00000010ŠDevice�out�of�paper‚VME050�busy/STRSEL„EQU„%00000001ŠDevice�selected†VME050�sel*6DSDVIA„EQU„$3C�Disabled�A-side�interrupts‚*1/17/84�MLB)DSDVIB„EQU„$3C�Disabled�B-side�interrupts*4BIM_CTL3‚EQU„$FF10C7ŒAddress�of�BIM�#1�control�reg�33BIM_VEC3‚EQU„$FF10CFŒAddress�of�BIM�#1�vector�reg�3&IRE‡EQU„4’Interrupt�request�enable�bit *************************** MISCELLANEOUS EQUATES ***************************IOEVCD„EQU„1’I/O�event�codeDVALATM„EQU„1<ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�command�packet�(IOCB).6ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�command�packet.+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚PRTU010ŒGood�return.)ŠMOVE.B�#ISTAIP,D1‰Set�up�IOS�error�code.ŠBRA„NRMEXITŒExit.=PRTU010ƒMOVE.L�D6,A3ŽSave�physical�address�of�command�packet.**‚Check�for�HALT�command.*(ŠCMP.W‚#IOHALT,IOSFCT(A3)�HALT�command�?!ŠBEQ„HALT�Branch�if�HALT�command.** See if channel is busy.*)ŠBTSTW‚#CCBFGBSY,CCBFG(A5)�Channel�busy�?ŠBEQ.S‚PRTU020ŒBranch�if�no.6ŠMOVE.B�#XSTBSY,D0‰Busy,�set�up�channel�error�code�andŠBRA„IOHUSRTN‹Return.ŠPAGE*K****************************************************************************(*‚Find�the�command�in�the�command�table.*** PRTU020:8ŠMOVE.W�IOSOPT(A3),CCBCOPT(A5)�Save�IOCB�options�in�CCB.6ŠMOVE.L�XIOUID(A2),CCBCID(A5)�Save�DCB�pointer�in�CCB.(ŠMOVE.L�A3,CCBCCB(A5)†Save�IOCB�pointer.*ŠMOVE.L�XIOUID(A2),A4†Pick�up�DCB�pointer.9ŠMOVE.L�CCBTASKA(A5),CCBTASKB(A5)�Set�up�buffer�task�TCB. -ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table./ŠMOVE.W�IOSFCT(A3),D6†Set�up�user�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. ?CMDERR„MOVE.B�#ISTAIF,D1‰We�didn't�find�it,�so�exit�with�error. ŠBRA„NRMEXITŠPAGEL******************************************************************************‰WRITE**,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB%*‰A6�=�address�of�attached�task's�TCB***L*****************************************************************************WRITE:5ŠBSR„IOSCOMNŒDo�the�stuff�common�to�all�I/O�commands. -ŠBSETW‚#CCBFGBSY,CCBFG(A5)�Mark�channel�busy.6ŠCLR.L‚CCBRLEN(A5)ˆInitialize�the�output�byte�counter.1ŠMOVE.L�CCBCHB(A5),A1†Set�up�device�base�address. ŠBSR„DEVINIT1‹Set�up�the�device.ŠSPC„2=ŠMOVE.L�CCBTASKB(A5),A0„Pick�up�the�TCB�address�of�IOCB�owner;ŠADD.B‚#1,TCBIOCNT(A0)„and�increment�his�pending�I/O�count.ŠSPC„2,ŠMOVE.L�CCBPTR(A5),A0†Set�up�buffer�pointer.ŠSPC„2@ŠBTSTW‚#IOASNFF,CCBCFIG+IOSATW(A5)�If�the�form�feed�after�assign4ŠBNE.S‚WRIT010Œattribute�is�0�send�a�FF�character�if)*£this�is�the�first�output�in�the�current *£assignment.ŠSPC„20ŠTST.B‚DCBBCT(A4)‰Do�we�need�to�do�a�form�feed�?ŠBNE.S‚WRIT010ŒBranch�if�no."ŠST…DCBBCT(A4)‰Set�form�feed�flag.(ŠMOVE.B�#FF,D0�Yes,�set�up�FF�character.!ŠBSR„PRTOUT1ŒGo�output�to�device.ŠBRA.S‚WRIT020ŒReturn. 'WRIT010ƒBSR„PRTOUT�Start�buffer�output. !WRIT020ƒUNMASK�Enable�interrupts.ŠBRA„CMDEXITŒGO�FINISH�UPŠPAGE M*******************************************************************************‰REQUEST�STATUS*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M******************************************************************************REQSTAT: *E*‚Get�the�address�of�his�data�block�and�move�our�configuration�there.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�block.ŠSPC„24ŠBSR.S‚STATYP�Setup�the�device�status,�channel�type,&*£device�type,�and�driver�codes�in�the*£user's�configure�block.ŠSPC„2>ŠMOVE.W�#VALATM,IOSATM(A0)�Return�the�supported�attributes�andBŠMOVE.W�#VALPRM,IOSPRM(A0)�parameters�masks�in�the�users�configure*£block.ŠSPC„2BŠMOVE.L�#(IOSPLN/2)-1,D0ƒD0�<--�loop�control�to�move�entire�block.'REQLOOPƒMOVE.W�(A0)+,(A1)+ˆMove�a�word.5ŠDBRAƒD0,REQLOOP‰Keep�moving�until�whole�block�moved. 'ŠMOVE.B�#ISTAOK,D1‰Exit�with�OK�status.ŠBRA„NRMEXITŒ*ŠSPC„2*A*„This�subroutine�stores�the�current�device�status(always�ready),E*‚channel�type,�device�type,�and�driver�code�into�the�users�configureL*‚block.�Note�that�these�values�are�returned�only�on�RETRIEVE�DEVICE�STATUS/K*‚CONFIGURATION,CONFIGURE�DEVICE,�and�CHANGE�DEFAULT�CONFIGURATION�requests/*‚only�when�no�configurtion�error�was�detected.*5STATYP„CLR.B‚IOSDST(A0)‰Return�on-line�device�status.AŠMOVE.B�CCBTYPE(A5),IOSCTP(A0)�Return�the�channel�type�defined�in *¨the�CCB.2ŠMOVE.B�#XDSPRT,IOSDTP(A0)�Device�type�is�PRINTER.>ŠMOVE.B�#IODLPRT,IOSDRC(A0)�This�is�a�local�Centronics�printer&*¨driver�for�use�on�the�EXORmacs�DEBUG#*¨PIA�port�or�an�MVME410�PIA�on�the*¨I/O�Channel.ŠRTSŠPAGEM****************************************************************************** *‰CONFIGURE*@*‰This�command�changes�the�CCB�configuration,�the�one�from�which<*‰the�driver�sets�up�the�device�and�under�which�it�performs.*,*‰Entry:�A2�=�address�of�CMR�parameter�block*�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M****************************************************************************** CONFIGUR: *B*‚Get�the�physical�address�of�the�user's�configuration�data�block.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�data�block.ŠSPC„21ŠMOVE.L�XIOUID(A2),A4†A4�<--�base�address�of�DCB. =ŠMOVE.B�#CECCDO,D2‰If�he's�trying�to�change�the�write�timeout?ŠBTSTW‚#IOSWTOB,IOSPRM(A1)�value,�return�a�configuration�error. ŠBNE„CNFGERRŠSPC„2DŠMOVE.L�DCBDEV+IOSWTO(A4),IOSWTO(A0)�Update�(in�the�CCB)�the�timeout/ŠBRA.S‚CMNCNFGŒvalues�from�the�DCB,�so�they�can,*£be�copied,�and�do�the�common�configuration *£processing.ŠPAGEM*******************************************************************************‰CHANGE�DEFAULT�CONFIGURATION*6*‰This�command�changes�the�DCB�configuration,�to�which4*‰IOS�will�restore�us�(via�a�CONFIGURE�command)�when/*‰FHS�closes�the�last�allocation�of�the�device.*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M***************************************************************************** CHNGDEF: *H*‚First�get�the�physical�address�of�the�user's�configuration�data�block.*8ŠBSR„CNFGADR2‹Get�the�address�of�the�users�configuration,*£data�block.�This�entry�point�preserves�A0.ŠSPC„27ŠMOVE.L�XIOUID(A2),A0†Load�the�address�of�the�DCB�in�A46ŠMOVE.L�A0,A4Žand�the�address�of�the�DCB�configurationŠADD.L‚#DCBDEV,A0‰block�in�A0. ŠPAGEM*******************************************************************************‰COMMON�CONFIGURATION�ROUTINE*7*‰This�routine�does�the�work�common�to�the�two�commands-*‰CONFIGURE�and�CHANGE�DEFAULT�CONFIGURATION.*7*‰Entry:�A0�=�Address�of�CCB�or�DCB�configuration�block,*�A1�=�Address�of�user's�configuration�block*M***************************************************************************** CMNCNFG:*L*ƒFirst,�both�the�attributes�and�parameters�masks�are�checked�to�see�if�bits L* corresponding to unsupported attributes or parameters are set. If any such2* bits are set, a configuration error is returned.*7ŠMOVE.W�#CECUAP,D2‰Set�up�for�an�error�exit�in�case�the&*£user�is�trying�to�change�unsupported*£attributes�or�parameters.ŠSPC„29ŠMOVE.W�#NVALATM,D0ˆZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSATM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„29ŠMOVE.W�#NVALPRM,D0ˆZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSPRM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„2E*‚Next�we�need�to�see�what�his�proposed�configuration�will�look�like.D*‚Plug�into�his�data�block�the�current�values�for�those�attributes�&?*‚parameters�he�doesn't�want�to�change.‚The�appropriate�current(*‚configuration�is�at�A0�and�he's�at�A1.*ŠOPT„BRS6ŠMOVE.W�IOSATM(A1),D0†Set�up�the�users�attribute�mask.;ŠAND.W‚D0,IOSATW(A1)†Zero�out�the�attributes�of�his�that�he.ŠNOT.W‚D0‘doesn't�want�to�change,�zero�out�the<ŠAND.W‚IOSATW(A0),D0†attributes�of�mine�that�he�does�want�to:ŠOR.WƒD0,IOSATW(A1)†change,�and�combine�them�in�his�space. @ŠMOVE.W�IOSPRM(A1),D0†Get�mask�of�parameters�he�wants�to�change. 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINE�WIDTH,'ŠIF…�THEN™copy�the�current�setting.�MOVE.W�IOSREC(A0),IOSREC(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINES/PAGE,'ŠIF…�THEN™copy�the�current�setting.�MOVE.L�IOSRSZ(A0),IOSRSZ(A1)ŠENDI 3ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�WRITE�TIMEOUT.ŠIF…�THEN•value,�copy�the�current�setting.�MOVE.L�IOSWTO(A0),IOSWTO(A1)ŠENDI 3ŠLSR.W‚#2,D0ŽSkip�over�the�READ�TIMEOUT�bit.�If�the'*£LOGICAL�RECORD�LENGTH�bit�is�not�set,*£copy�the�current�setting.ŠIF…�THENŠ�MOVE.W�IOSLRL(A0),IOSLRL(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�END-OF-LINE/ŠIF…�THEN”STRING,�copy�the�current�setting.�MOVE.B�IOSELC(A0),IOSELC(A1)ŠENDIŠOPT„BRL*I*ƒNow�that�the�users�configuration�block�contains�the�proposed�attributesG* and parameters, they will be checked for validity before copying them* into the DCB or CCB.*8ŠMOVE.B�#CECPNI,D2‰If�the�auto-linefeed�attribute�is�set@ŠBTSTW‚#IOALNFD,IOSATW(A1)�and�the�end�of�line�character�is�null,ŠBEQ.S‚CMNC001Œreturn�a�configuration�error.ŠTST.B‚IOSELC(A1)ŠBEQ.S‚CNFGERRŠSPC„2CCMNC001ƒMOVE.B�#CECPRLZ,D2ˆIf�either�the�logical�or�physical�record<ŠMOVE.W�IOSREC(A1),D0†length�is�zero,�return�a�configurationŠBEQ.S‚CNFGERRŒerror.ŠMOVE.W�IOSLRL(A1),D3ŠBEQ.S‚CNFGERRŠSPC„24ŠCMP.W‚D3,D0ŽIf�the�logical�record�length�is�greater5ŠBHS.S‚OKCNFG�than�the�physical�record�length,�return*ŠMOVE.B�#CECPLGP,D2ˆa�configuration�error.ŠSPC„2ACNFGERRƒMOVE.B�#ISTACFG,D1ˆReturn�a�configuration�error�status�in>ŠMOVE.B�D2,IOSCEC(A1)†the�users�IOS�parameter�block�and�return8ŠBRA.S‚CNFGEXIT‹the�specific�configuration�error�code�in *£the�users�configuration�block.ŠSPC„2F*…Set�the�configuration�flag�byte�in�the�device�DCB�to�indicate�that�aK*‚CONFIGURE�or�CONFIGURE�DEFAULTS�request�was�processed.�FHS�will�check�theM*‚flag�when�it�closes�the�last�assignment�to�the�device�to�see�if�it�needs�toH*‚tell�IOS�to�issue�a�configure�request.�IOS�will�then�issue�a�CONFIGUREJ*‚request�using�the�device�DCB�default�configuration�parameters.�This�willI*‚always�force�the�current�configuration�to�the�default�whenever�the�last*‚assignment�is�closed.*I*…Subroutine�STATYP�is�called�to�store�the�current�device�status,�channelH*‚type,�device�type,�and�driver�code�into�the�users�configuration�block.*ŠMOVE.B�CCBRLEN(A5),IOSLEN(A3)�Update�users�IOCB�length�field.ŠCLR.L‚CCBRLEN(A5)ŠSPC„2=ŠMOVE.L�CCBTASKB(A5),A0„Pick�up�the�TCB�address�of�IOCB�owner;ŠSUB.B‚#1,TCBIOCNT(A0)„and�decrement�his�pending�I/O�count.ŠSPC„2*!*‚Prepare�the�event�and�queue�it.*8ŠMOVE.B�#ISTATO,IOSSTA(A3)�Update�the�IOCB�status�field.,ŠMOVE.W�#ISTATO,D3‰Set�up�event�status�field-ŠMOVE.B�#XPSHLT,D1‰Set�up�event�status�value.!ŠMOVE.L�#6,D0ŽSet�up�info�length.&ŠMOVE.L�CCBCID(A5),D2†Set�up�event�ID..ŠLEA„CCBPKT(A5),A4†Set�up�event�build�pointer.ŠBSR„QEVNTŽQueue�event.ŠBRA„CMDEXITŒRETURN ŠPAGEL******************************************************************************C*‰ROUTINE�COMMON�TO�ALL�I/O�COMMANDS�(READ,�WRITE,�OUTPUT�W/�INPUT)**‚Entry:�A3�=�address�of�IOCB*‰A5�=�address�of�CCB**L*****************************************************************************IOSCOMN:?ŠBTSTW‚#IOPTSKB,IOSOPT(A3)�If�the�buffers�reside�in�a�different"ŠBEQ.S‚IOSC005Œtask�from�the�IOCB, 9ŠLEA„IOSTSK(A3),A0†Point�to�the�taskname�&�session�of�the7ŠTR0$.GETTCB�,�buffer�owner�&�call�exec�to�get�address."ŠBRA.S‚OKTCBŽIf�it's�good,�branch.ŠNOP—If�it's�bad,6ŠMOVE.B�#XSTADB,D1‰set�status�in�IOCB�to�address�errorŠTST.L‚(A7)+Žadjust�stackŠBRA.S‚NRMEXITŒand�exit�to�CMR. :OKTCB…MOVE.L�A0,CCBTASKB(A5)„Save�physical�address�of�TCB. *<*‚Validate�the�info�in�the�IOCB�about�the�primary�buffer�and *‚convert�to�physical�addresses.*BIOSC005ƒMOVE.L�IOSSAD(A3),D6†D6�<--�buffer�physical�start�address.+ŠMOVE.L�IOSEAD(A3),D5†D5�<--�buffer�length.ŠSUB.L‚D6,D5Ž* ŠADDQƒ#1,D5Ž*ŠSPC„25ŠMOVE.L�D5,-(A7)‹Save�the�buffer�length�on�the�stack.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.$ŠBRA.S‚IOSC010ŒIf�it's�good,�branch.9ŠADDQ.L�#8,A7ŽIf�it's�a�bad�base�address,�remove�saved�D5&*£and�adjust�the�stack�return�address.ŠSPC„24ŠMOVE.B�#ISTAADD,D1ˆSet�IOCB�status�to�ADDRESS�ERROR6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status. @IOSC010ƒMOVE.L�D6,CCBPTR(A5)†Save�physical�start�address�in�CCB. 2ŠADD.L‚(A7)+,D6‹Save�the�physical�end�address�plus&ŠMOVE.L�D6,CCBEAP1(A5)…one�in�the�CCB.ŠRTSŠPAGEK****************************************************************************=*‰VALIDATE�CONFIGURATION�BUFFER�ADDRESS�&�CONVERT�TO�PHYSICAL*$*‰Entry:�D5�=�buffer�length�in�bytes-*�D6�=�buffer�logical�start�addr�(to�convert)*�A3�=�address�of�IOCB*�A5�=�address�of�CCB***‰Exit:‚D6ƒ=�buffer�physical�start�address*�D5ƒ=�buffer�length*K****************************************************************************CCNFGADRƒLEA.L‚CCBCFIG(A5),A0…This�entry�point�loads�the�CCB�config.*£data�block�into�A0.ŠSPC„2.CNFGADR2‚MOVE.L�A0,-(A7)‹Save�A0�on�the�stack.?ŠMOVE.L�IOSDBP(A3),D6†D6�<--�logical�addr�of�user's�data�block./ŠMOVE.L�#IOSPLN,D5‰D5�<--�length�of�data�block.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.%ŠBRA.S‚CNFGADR3‹If�it's�good,�branch.ŠSPC„27ŠADD.L‚#8,A7ŽIf�the�address�or�length�is�bad,�clean�the<ŠMOVE.B�#ISTAADD,D1ˆstack,�set�IOCB�status�to�ADDRESS�ERROR,6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status.ŠSPC„2=CNFGADR3‚MOVE.L�D6,A1ŽStore�the�physical�address�of�the�users9ŠMOVE.L�(A7)+,A0‹data�block�in�A1,�restore�A0�and�return.ŠRTSŠPAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D1�=�IOS�error�code*I**************************************************************************NRMEXIT:*ŠLEA„CCBPKT(A5),A4†Set�up�queue�work�area.!ŠMOVE.L�#6,D0ŽSet�up�packet�size.#ŠMOVE.L�XIOUID(A2),D2†Set�up�PB�id.#ŠAND.W‚#$FF,D1ŒMask�for�word�value."ŠMOVE.W�D1,D3ŽSet�up�status�value./ŠMOVE.B�D1,IOSSTA(A3)†Update�IOCB�status�field.%ŠMOVE.B�#XPSNRM,D1‰Set�up�event�type.ŠBSR„QEVNTŽGo�queue�event.CMDEXITƒCLR.L‚D0*8* User request side of IOH always exits from this point.*IOHUSRTN‚EQU„*ŠRTS—RETURN�TO�MAINLINEŠPAGEK****************************************************************************B*ƒSubroutine�to�check�address�boundaries�to�see�if�entirely�within* calling tasks address space.*&*‚Entry:�D5�-‚number�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‚IOHADR6Œ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.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.ŠPAGEL******************************************************************************‚PRTOUT*%*ˆThis�is�the�printer�output�routine.***ˆENTRY:‚A0�=�address�of�buffer*�A1�=�address�of�device�base*�A3�=�address�of�IOCB*�A4�=�address�of�DCB*�A5�=�address�of�CCB*.* PRTOUT1 ENTRY: D0.B = character to be output*—other�registers�as�above* M******************************************************************************CPRTIMG„ADD.L‚#1,CCBRLEN(A5)…For�image�mode,�count�each�byte�sent�to>ŠCMP.L‚CCBEAP1(A5),A0…the�printer�whether�printable�or�not.�If6ŠBEQ.S‚PRT070�the�end�of�the�buffer�is�reached,�do�the *£request�completion�processing.ŠSPC„2PRTOUT:0ŠMOVE.B�(A0)+,D0‹Get�next�data�byte�from�buffer.,ŠMOVE.L�A0,CCBPTR(A5)†Update�buffer�pointer.ŠSPC„2;ŠBTSTW‚#IOPFORB,CCBCOPT(A5)�For�image�mode�output,�skip�the,ŠBNE.S‚PRTOUT1Œspecial�character�processing.ŠSPC„20ŠCMP.B‚#CR,D0�If�the�current�buffer�character�is,ŠBEQ.S‚PRT030�a�CR,�proceed�with�end-of-line *£processing.ŠSPC„2+PRTOUT1ƒBSR.L‚DEVOUTSŒOutput�the�data�byte.ŠSPC„2EPRT010„BTSTW‚#IOPFORB,CCBCOPT(A5)�If�the�output�is�bring�performed�in1ŠBNE.S‚PRTIMG�image�mode,�transfer�control�to�the%*£top�of�the�output�loop�to�check�for*£end�of�buffer.ŠSPC„25ŠCMP.B‚#'�',-1(A0)ˆIf�the�current�buffer�character�is,ŠBLT.S‚PRT017�non-printing,�do�not�check�for(*£end-of-line�or�increment�the�character*£countŠSPC„25ŠADD.L‚#1,CCBRLEN(A5)…Increment�the�printed�character*£count.ŠSPC„29ŠMOVE.L�CCBRLEN(A5),D2…Divide�the�printed�character�countAŠDIVUƒCCBCFIG+IOSLRL(A5),D2�by�the�logical�line�length.�Store�the+ŠSWAPƒD2‘remainder�in�the�lower�half�of�D2.ŠSPC„2*ŠTST.W‚D2‘If�an�exact�logical�and�physical4ŠBNE.S‚PRT017�end-of-line�has�been�reached,�output�aN* The following line was added to the VME050 printer driver to fix the problemL*�of�the�original�driver.‚It�did�a�comparison�of�the�physical�line�length�toH*�register�D3.‚This�register�was�never�set�up.‚I�think�the�intent�was�to>* compare the physical line length to the logical line length.:ŠMOVE.W�CCBCFIG+IOSLRL(A5),D3�Load�the�logical�line�length*@ŠCMP.W‚CCBCFIG+IOSREC(A5),D3�linefeed�for�non-auto-LF�device.�If3ŠBEQ.S‚PRT013�only�the�logical�line�length�has�been3ŠBSR.S‚PRTEOL�reached,�output�a�logical�end-of-line2ŠBRA.S‚PRT015�sequence.�If�neither�length�has�been&*£reached�proceed�to�the�end-of-buffer*£check.ŠSPC„2GPRT013„BTSTW‚#IOALNFD,CCBCFIG+IOSATW(A5)�If�the�device�does�not�support0ŠBNE.S‚PRT015�auto�line�feed,�output�a�line�feed5ŠMOVE.B�#LF,D0�if�the�byte�count�is�an�exact�multiple"ŠBSR.S‚DEVOUTSŒof�the�line�length.ŠSPC„2FPRT015„BTSTW‚#IOATPLL,CCBCFIG+IOSATW(A5)�Since�an�end-of-line�has�been/ŠBNE.S‚PRT070�reached,�terminate�the�request�if!*£the�truncate�print�attribute�is*£set.ŠSPC„2=PRT017„CMP.L‚CCBEAP1(A5),A0…If�the�end�of�buffer�has�not�been/ŠBLT„PRTOUT�reached,�output�the�next�character.ŠSPC„2:PRT030„BSR.S‚PRTEOL�Output�a�logical�end-of-line�sequence.ŠPAGEPRT070:*2*‚Finished�transfer,�now�queue�event�to�requestor.*+ŠBCLRW‚#CCBFGBSY,CCBFG(A5)�Clear�busy�flag.,ŠMOVE.L�CCBTASKB(A5),A0„Pick�up�TCB�address.3ŠSUB.B‚#1,TCBIOCNT(A0)„Decrement�I/O�pending�count. -ŠMOVE.W�#ISTAOK,D3‰Set�up�ok�IOS�status�code.#ŠAND.B‚#$01,D0ŒOnly�worry�about�sel!ŠCMP.B‚#$01,D0ŒCheck�for�selected ŠBEQ.S‚PRT0801ŠMOVE.W�#ISTANR,D3‰Fault,�set�up�IOS�status�code.-PRT080„MOVE.L�#6,D0ŽSet�up�event�info�length.*ŠMOVE.B�#XPSNRM,D1‰Set�up�event�type�code.)ŠMOVE.L�CCBCID(A5),D2†Set�up�DCB�address./ŠMOVE.B�D3,IOSSTA(A3)†Update�IOCB�status�field.8ŠMOVE.L�CCBRLEN(A5),IOSLEN(A3)�Update�IOCB�length�field. *ŠLEA„CCBPKT(A5),A4†Set�up�event�data�area./ŠBSR„QEVNTŽQueue�completion�event�to�requestor. !ŠIF.BƒCCBPTRTE(A5)�ƒ#0�THEN.S�RTS�ELSE.S �BRA„PRTINRTEŠENDIŠPAGE*E*‹This�subroutine�outputs�either�a�LF-CR�sequence�or�an�EOL�character6*‰based�on�the�setting�of�the�auto-linefeed�attribute.*#PRTEOL„MOVE.B�CCBCFIG+IOSELC(A5),D0?ŠBTSTW‚#IOALNFD,CCBCFIG+IOSATW(A5)�If�not�an�exact�end-of-line,4ŠBNE.S‚DEVOUTSŒoutput�the�EOL�character�if�the�auto-(*§linefeed�attribute�is�set.�Else�output*§a�LF�and�CR.ŠSPC„2/ŠMOVE.B�#LF,D0�Call�DEVOUT�to�output�a�linefeed.ŠBSR.S‚DEVOUT�character.�If�an�error�status�is1ŠTST.B‚D3‘returned�in�D3,�transfer�control�to�theŠBNE.S‚DEVOUTEŒerror�exit.ŠSPC„2 6ŠMOVE.B�#CR,D0�Set�up�carriage�return�character�in�D0.ŠSPC„2*E*‹This�routine�is�called�as�a�subroutine�from�PRTOUT�to�output�singleF*‰characters�from�D0�with�automatic�request�termination�if�an�error�isD*‰detected�in�the�DEVOUT�subroutine.�Execution�also�falls�through�to*‰here�from�PRTEOL.*8DEVOUTSƒBSR.S‚DEVOUT�Call�DEVOUT�to�output�the�character5ŠTST.B‚D3‘in�D0.�If�the�status�returned�in�D3�is�non-'ŠBEQ.S‚DEVOUTOK‹zero,�do�an�error�exit.ŠSPC„2:DEVOUTEƒTST.L‚(A7)+ŽIf�an�error�occurs�transfer�control�to-ŠPEA.L‚PRT070�the�request�completion�routine.ŠSPC„2+DEVOUTOK‚RTS—Return�to�the�calling�routine.ŠPAGEO*********************************************************************************‚DEVOUT(*�****MODIFIED�1/27/83�BY�M.�BRIEL*******<*†1.Check�for�a�device�fault�(not-selected�or�out�of�paper).=*ˆIf�a�fault�is�present,�terminate�the�request�with�an�error.*F*†2.�If�an�Printer�Acknowledge�is�expected,�wait�for�the�ACK�pulse�for@*‰approx.�100�us.�If�the�pulse�does�not�arrive�in�100�us,�enable0*‰the�Acknowledge�interrupt�and�exit�the�driver.*4*†3.�Output�the�next�character�and�pulse�Data�Strobe**ˆENTRY:„D0‚=�data�byte*’A1‚=�device�base�address*‘(SP)�=�return�address*�4(SP)�=�PRTOUT�return�address*�DEVICE�=�Interrupts�disabled*,*ˆEXIT:…D0‚=�Device�status�register�contents*�NORMAL�=�(SP)�return*�FAULT�=�(SP)+2�return5*‘BUSY�=�4(SP)�PRTOUT�return�address�(device�enabled)*K****************************************************************************DEVOUT:.ŠCLR.B‚D3‘Clear�D3�in�preparation�for�a�normal *£return.ŠSPC„2 ŠCLR.L‚D1.ŠMOVE.B�DEV1BD(A1),D1†Pick�up�status�register. ŠMOVE.L�D1,D2ŽMake�another�copy.&ŠAND.B‚#$01,D1ŒMask�uninterested�bits.'ŠCMP.B‚#$01,D1ŒIs�the�printer�selected?ŠBNE.S‚DEV010�Fault�exit�if�no.ŠSPC„2:ŠTST.B‚CCBACKP(A5)ˆIf�a�printer�acknowledge�is�not�pending,ŠBEQ.S‚DEV020�proceed�with�character�output.ŠSPC„2:ŠMOVE.W�#32,D1�Repeatedly�test�for�the�printer�acknowledgeDEVACKŠBTST.B�#7,DEV1BD(A1);ŠDBNEƒD1,DEVACKŠthe�loop�times�out�(approx.�100�us)�proceed**£with�character�output.�Otherwise,�enable**£the�Acknowledge�pulse�interrupt�and�exit *£the�driver.ŠSPC„2 ŠBNE.S‚DEV020 * Enable ACK Interrupt and Exit. :ŠMOVE.B�D0,CCBSAVB(A5)…The�device�is�busy,�save�data�byte..ŠMOVE.L�(A7)+,CCBIRTN(A5)‚Save�return�address.-ŠSUB.L‚#2,CCBIRTN(A5)…Adjust�service�address.ŠSPC„2AŠMOVE.L�(A7)+,CCBISTK(A5)‚Save�subroutine�return�address�into�CCBŠSPC„2 *;*ƒSet�up�TIMEOUT�call�in�case�of�a�fault�(No�ACK�interrupt)*CŠMOVEM.L�D0-D2/A0-A1,-(A7)�Save�registers�used�by�TIMEOUT�(EXRQPA)./ŠMOVE.L�#34,D0�Service�request�code�for�EXRQPA.ŠCLR.L‚D1‘HSKP-ŠMOVE.B�CCBPPRIO(A5),D1„Save�interrupt�level.ŠMOVE.L�A5,D2ŽAddress�of�CCB.ŠLEA„PTIMOUT(PC),A0…Address�of�wakeup�routine.9ŠMOVE.L�#10000,A1Š***�12/19/84‚Set�for�10000�millisecondsŠTRAPƒ#0ŠNOP—Assume�the�call�was�taken,ŠMOVEM.L�(A7)+,D0-D2/A0-A1�Restore�registers3ŠST.BƒCCBTIMED(A5)‡Set�TIMEOUT�request�needed�flag. ŠINHIB‚DisableŒinterrupts.1ŠBSETƒ#IRE,BIM_CTL3†Enable�device�ACK�interrupts. ŠRTS—Return. * Fault Exit +DEV010„MOVE.L�D2,D0ŽSet�up�status�register.1ŠBSR„DEVINIT1‹Reprogram�device�for�no�interrupts.ŠSPC„2’1/17/84�MLB*:ŠCLR.B‚CCBACKP(A5)ˆClear�pending�printer�acknowledge�flag.ŠTST.B‚DEV1AC(A1)ŠSPC„2’1/17/84�MLB*+ŠST…D3‘Set�D3�non-zero�to�indicate�an�error$ŠBRA.S‚DEVOEX�and�prepare�to�return.ŠPAGE*(*�Output�the�next�character�1/17/84�MLB**DEV020ŠTST.B‚DEV1AC(A1)ŠSPC„2’1/17/84�MLB*'ŠMOVE.B�D0,DEV1AD(A1)†Output�data�byte.** data strobe:** CHANGED 02/18/85.K*�Use�MOVE�instructions�for�the�STROBE�instead�of�BCLR�and�BSET.‚The�STROBEJ*�register�is�WRITE�only.‚Reading�this�register�will�clear�the�ACKNOWLEDGE9*�flag.‚BCLR�and�BSET�are�READ-MODIFY-WRITE�instructions.*3ŠMOVE.B�#0,DEV1AC(A1)†***�02/18/85�changed�to�MOVE. +ŠMOVE.B�#8,DEV1AC(A1)†Strobe�the�data�byte.ŠSPC„2’1/17/84�MLB*8ŠST…CCBACKP(A5)ˆSet�the�printer�acknowledge�pending�flagŠSPC„2’1/17/84�MLB*0ŠMOVE.B�DEV1BD(A1),D0†Get�status�register�again.ŠSPC„20DEVOEX„ENABL‚Enable�interrupts�and�return�to�theŠRTS—calling�routine.ŠPAGEJ**************************************************************************éééééé*!* INTERRUPT SIDE FOR PRT 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**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P****ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT*F*---------------------------------------------------------------------*4* If channel is off-line or not attached, just exit.*PRTISR:.ŠMOVE.L�CCBCHB(A5),A1†Get�device�base�address.2ŠBTST.B�#IRE,BIM_CTL3†Are�the�interrupts�enabled�?ŠBEQ.S‚PRTI005ŒIf�not�then�exit*ŠMOVE.B�DEV1BD(A1),D0†Read�the�status�bits#ŠAND.B‚#$80,D0ŒOnly�worry�about�ACKŠBNE.S‚PRTI0109PRTI005ƒAND.W‚#$FFFE,SRŠNo�interrupt�so�set�condition�and ŠRTS—return. 5PRTI010ƒCLR.B‚CCBTIMED(A5)‡Clear�TIMEOUT�needed�flag.&ŠBTSTW‚#CCBFGOFF,CCBSTR(A5)�Off-line�?ŠBNE.S‚PRTI020ŒBranch�if�yes.5ŠBTSTW‚#CCBFGATH,CCBSTR(A5)�Is�the�channel�attached�?ŠBEQ.S‚PRTI020ŒBranch�if�no.(ŠBTSTW‚#CCBFGBSY,CCBFG(A5)�I/O�pending�?ŠBNE.S‚PRTI100ŒBranch�if�yes. 8PRTI020ƒMOVE.L�CCBCHB(A5),A1†Set�up�device�base�address.(ŠBSR„DEVINIT1‹Disable�device�interrupts. ŠENABL!ŠOR.Wƒ#$0001,SRŠSet�condition�and ŠRTS—return.ŠPAGEN******************************************************************************** INTERRUPT LEVEL PROCESSING*0*ˆIt�has�been�determined�that�I/O�is�in�progress*ˆand�the�interrupt�is�ours.**N*******************************************************************************PRTI100:=ŠMOVEM.L�D1-D7/A2-A4/A6,-(A7)�Save�the�rest�of�the�registers.1ŠBSR„DEVINIT1‹Reprogram�device�for�no�interrupts.ŠSPC„2’1/17/84�MLB*>ŠCLR.B‚CCBACKP(A5)ˆClear�the�printer�acknowledge�pending�flag.ŠTST.B‚DEV1AC(A1)ŠSPC„2’1/17/84�MLB*-ŠMOVE.L�CCBPTR(A5),A0†Restore�buffer�pointer. 1ŠMOVE.B�CCBSAVB(A5),D0…Restore�current�data�byte.5ŠMOVE.L�CCBIRTN(A5),A2…Get�interrupt�service�address.'ŠMOVE.L�CCBCCB(A5),A3†Get�IOCB�address.&ŠMOVE.L�CCBCID(A5),A4†Get�DCB�address.8ŠADD.B‚#1,CCBICNT(A5)…Increment�pending�interrupt�count.:ŠPEA„PRTINRTN(PC)‡Stack�the�interrupt�routine�exit�address>ŠMOVE.L�CCBISTK(A5),-(A7)‚Restore�subroutine�return�address�on*£stack.!ŠJMP„(A2)�Jump�to�output�routine. *.* PRT interrupt handler exits from this point.* PRTINRTN:7ŠSUB.B‚#1,CCBICNT(A5)…Decrement�pending�interrupt�count0ŠMOVEM.L�(A7)+,D1-D7/A2-A4/A6�Restore�registers./***‡ENABL•Let�CMR�enable�interrupts�later,�this%***¡fix�is�for�EPSON�RX80�(SPR�1178).(ŠOR.Wƒ#$0001,SRŠSet�return�condition�and!ŠRTS—return�to�interrupt�handler. 2PRTINRTE‚CLR.B‚CCBPTRTE(A5)‡Clear�RTE�needed�flag..ŠCLR.B‚CCBTIMED(A5)‡Clear�TIMEOUT�needed�flag.ŠENABL0ŠMOVEM.L�(A7)+,D2-D7/A2-A6�Restore�the�registersŠRTEŠPAGEJ*************************************************************************** * PTIMOUT*E*ƒPURPOSE:‚This�is�the�entry�point�for�a�wakeup�call.‚It�is�set�up�in?*�the�DEVOUT�routine�when�an�ACKNOWLEDGE�has�not�been�received.;*�This�routine�will�be�entered�even�if�an�ACKNOWLEDGE�comes<*�during�the�TIMEOUT.‚The�flag�CCBTIMED�is�checked�to�see�if8*�a�TIMEOUT�is�still�needed.‚This�flag�is�cleared�in�the *�ACKNOWLEDGE�interrupt�routine.**ƒENTRY:‚From�the�EXEC.*‹D1�-�Address�of�the�CCB*?*ƒEXIT:ƒRTE�-�Must�save�D2-D7/A2-A6�and�restore�before�the�RTE.*J**************************************************************************PTIMOUT:-ŠMOVEM.L�D2-D7/A2-A6,-(A7)�Save�the�registers&ŠMOVE.L�D1,A5ŽPick�up�the�CCB�address.'ŠMOVE.L�CCBCCB(A5),A3†Get�IOCB�address.&ŠMOVE.L�CCBCID(A5),A4†Get�DCB�address.2ŠST.BƒCCBPTRTE(A5)‡Flag�to�process�an�RTE�on�exit.1ŠTST.B‚CCBTIMED(A5)‡Do�we�still�need�the�TIMEOUT?/ŠBEQ.S‚PRTINRTE‹No�-�must�have�received�an�ACK. (ŠBSR„DEVINIT1‹Disable�device�interrupts.-ŠCLR.B‚D0‘Make�the�status�look�like�it�is�notŠBRA„PRT070�selected.ŠPAGEJ**************************************************************************** QEVNT**„Place�message�on�user's�ASQ.**ˆA4�=�address�of�event�area*ˆA5�=�address�of�CCB'*ˆD0�=�event�length�(minus�header�info)*ˆD1�=�event�type*ˆD2�=�4�byte�id�(DCB)*ˆD3�=�status�value�(2�bytes)*ˆD4�=�device�status�(2�bytes)*ˆD5�=�device�number�(1�byte)*J***************************************************************************QEVNT:ŠMOVE.L�D0,D6ŽSave�length.5ŠMOVE.L�#2,D7ŽOffset�for�staging�(no�service�vector)./ŠMOVE.B�#IOEVCD,1(A4)†Code�(no�service�vector).)ŠMOVE.L�CCBSVVC(A5),2(A4)‚Service�vector.+ŠBEQ.S‚QEVNT10ŒBranch�if�no�service�vector./ŠADD.L‚#4,D0ŽCorrect�length�for�service�vector.7ŠADD.L‚#4,D7ŽCorrect�offset�staging�for�service�vector.2ŠADD.L‚#$00800000,(A4)„Correct�for�service�vector. 1QEVNT10ƒMOVE.B�D1,0(A4,D7)ˆCompletion�event�type.*ŠMOVE.B�CCBKEY(A5),1(A4,D7)�User's�id�key.-ŠADD.L‚#4,D0ŽComplete�length�of�return�event.6ŠCMP.B‚CCBASQL(A5),D0…User's�maximum�ASQ�entry�length.#ŠBLS.S‚QEVNT20ŒBranch�if�length�ok.0ŠMOVE.B�CCBASQL(A5),D0…User's�length�is�smaller. &QEVNT20ƒMOVE.B�D0,(A4)ŒCorrect�length. /QEVNT40ƒMOVE.L�D2,2(A4,D7)ˆSet�up�status�value.$ŠMOVE.W�D3,6(A4,D7)ˆSet�up�id�(DCB).ŠCMP.B‚#6,D6Ž6�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.)ŠMOVE.W�D4,8(A4,D7)ˆSet�up�device�status.ŠCMP.B‚#8,D6Ž8�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.*ŠMOVE.B�D5,10(A4,D7)‡Set�up�device�number.&ŠCLR.B‚11(A4,D7)ŠClear�reserved�field.*I* Now let's put the completion into registers and send event to the task.* QEVNT50ƒEQU„*ŠMOVEM.L�(A4),D2-D7ŠBSR.S‚IOHQEVNTŠRTSŠ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**************************************************************************** IOHQEVNT:$ŠMOVEM.L�A3-A5,-(A7)‡Ssve�registers.-ŠMOVE.L�CCBRQSTA(A5),A0„Caller's�TCB�address.ŠSPC„26ŠMOVE.L�#T0QEVNTI,D0‡If�this�routine�was�called�during6ŠTST.B‚CCBICNT(A5)ˆinterrupt�processing,�use�the�QEVNT3ŠBNE.S‚IOHQ4Žinterrupt�routine,�else�use�the�normal#ŠMOVE.L�#T0QEVNTT,D0‡QEVNT�routine. IOHQ4…TRAPƒ#0#ŠBRA.S‚IOHQ5ŽBranch�if�queueing�ok.'ŠMOVEM.L�(A7)+,A3-A5‡Restore�registers.9ŠMOVE.L�(A7),CCBQVER1(A5)‚Save�callers�address�for�debug.ŠBRA.S‚IOHQRTN ,IOHQ5…MOVEM.L�(A7)+,A3-A5‡Restore�registers..ŠCLR.L‚CCBQVER1(A5)‡Clear�queue�error�address. IOHQRTNƒRTS—RETURNŠENDééééé=/*=/*†P115DRV.AF=/*B=/* Chain file to assemble the printer driver for the VME115 board=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to P115DRV.LS=/*=/IFC \1ƒ=ARG�P115DRV.LS=/ENDIF=/*%=ASM P115DRV.SA,P115DRV.RO,\1;MRZ=146=/*{ Included files are:=/*ƒ9995.&.TRACE.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9999.M68230.M68230.EQ=/*}=/*=ENDéééééé ðŠPAGEJP115DRVƒIDNTƒ4,4�VERSAdos�VME115�Local�Printer�I/O�Process�V4.4�-�08/28/84AŠTTL„VERSADOS�VME115�LOCAL�PRINTER�HANDLER�PROCESS�V4.4�-08/28/84 ŠLLENƒ120ŠNOLISTŠINCLUDE�9995.&.TRACE.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.TCB.EQŠINCLUDE�9995.&.CCB.EQŠINCLUDE�9995.&.IOE.EQŠINCLUDE�9995.&.NIO.EQŠINCLUDE�9995.&.LV5.EQŠLIST ŠNOFORMATJ****************************************************************************1* PRT -- REV. 1.00 02NOV81 (TL09) JIM SMITH - IOH9*ˆREV.�1.01�01FEB82�(TL09)�JIM�SMITH�-�VECTOR�CHAIN�(IOH)5*ˆREV.�1.02�23FEB82�(TL09)�JIM�SMITH�-�IOCB�USE�(IOH)5*ˆREV.�2.00�15APR82�(TL09)�JIM�SMITH�-�PRINTER�DRIVER5*ˆREV.�2.01�01JUN82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER5*ˆREV.�2.10�15JUL82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER-*ˆREV‚2.20�18JAN84ˆMARC�BRIEL-�PRINTER�DRIVER0*ˆREV‚3.00�28AUG84ˆMIKE�DUH‚-�ADAPTED�FOR�VME115;*ˆREV‚3.01�17DEC84ˆMIKE�DUH‚-�Removed�ENABL�at�PRTINRTN�for *­SPR�1178�(Epson�RX80�printer).*«-�Fixed�HALT�routine.=*ˆREV‚3.02�19DEC84ˆMIKE�DUH‚-�Increased�timeout�to�10�seconds*­for�use�with�slow�printers.ééé ù+ DE@"H*C2?:>B9J*R=Z=b>jNr2z;‚9Š6’Aš0¢<ª+8*ˆREV‚3.03�8MAR85‰DICK�V.ƒ-�HALT�ROUTINE�REGISTER�CHANGE*&*ƒPURPOSE:‚VME115�LOCAL�PRINTER�DRIVER*/*ƒENTRY:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒEXIT:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION***ƒCODE�IS�RE-ENTRANT**H*-----------------------------------------------------------------------**‚INCLUDED�FILES:**„INCLUDE�9995.&.TRACE.EQ*„INCLUDE�9995.&.STR.EQ*„INCLUDE�9995.&.TCB.EQ*„INCLUDE�9995.&.CCB.EQ*„INCLUDE�9995.&.IOE.EQ*„INCLUDE�9995.&.NIO.EQ*„INCLUDE�9995.&.LV5.EQ*„INCLUDE�9999.M68230.M68230.EQ*PRTORG:‰INCLUDE�9999.M68230.M68230.EQ‰PAGE(****************************************(* EQUATES FOR SPECIAL ASCII CHARACTERS *(*****************************************NUL†EQU‡$00‘NullBEL†EQU‡$07‘BellBS‡EQU‡$08‘BackspaceLF‡EQU‡$0A‘Line�feedFF‡EQU‡$0C‘Form�feedCR‡EQU‡$0D‘Carriage�returnSPACE„EQU‡$20‘Blank*************************** MISCELLANEOUS EQUATES *éé éé**************************IOEVCD„EQU„1’I/O�event�codeDVALATM„EQU„1<ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�command�packet�(IOCB).6ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�command�packet.+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚PRTU010ŒGood�return.)ŠMOVE.B�#ISTAIP,D1‰Set�up�IOS�error�code.ŠBRA„NRMEXITŒExit.=PRTU010ƒMOVE.L�D6,A3ŽSave�physical�address�of�command�packet.**‚Check�for�HALT�command.*(ŠCMP.Wƒ#IOHALT,IOSFCT(A3)…HALT�command�?!ŠBEQ…HALT“Branch�if�HALT�command.** See if channel is busy.*)ŠBTSTW‚#CCBFGBSY,CCBFG(A5)‚Channel�busy�?ŠBEQ.S‚PRTU020ŽBranch�if�no.6ŠMOVE.B�#XSTBSY,D0‹Busy, �set�up�channel�error�code�andŠBRA„IOHUSRTN�Return.ŠPAGE*K****************************************************************************(*‚Find�the�command�in�the�command�table.*** PRTU020:8ŠMOVE.W�IOSOPT(A3),CCBCOPT(A5)�Save�IOCB�options�in�CCB.6ŠMOVE.L�XIOUID(A2),CCBCID(A5)‚Save�DCB�pointer�in�CCB.(ŠMOVE.L�A3,CCBCCB(A5)†Save�IOCB�pointer.*ŠMOVE.L�XIOUID(A2),A4†Pick�up�DCB�pointer.9ŠMOVE.L�CCBTASKA(A5),CCBTASKB(A5)‚Set�up�buffer�task�TCB. -ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table./ŠMOVE.W�IOSFCT(A3),D6†Set�up�user�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. ?CMDERR„MOVE.B�#ISTAIF,D1‰We�didn't�find�it,�so�exit�with�error. ŠBRA„NRMEXITŠPAGEL******************************************************************************‰WRITE**,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB%*‰A6�=�address�of�attached�task's�TCB***L*****************************************************************************WRITE:5‰BSR‡IOSCOMN�Do�the�stuff�common�to�all�I/O�commands. -‰BSETW…#CCBFGBSY,CCBFG(A5)�Mark�channel�busy.6‰CLR.L…CCBRLEN(A5)‰Initialize�the�output�byte�counter.1‰MOVE.L„CCBCHB(A5),A1‡Set�up�device�base�address. ‰BSR‡DEVINIT1ŒSet�up�the�device.‰SPC‡2=‰MOVE.L„CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;‰ADD.B…#1,TCBIOCNT(A0)…and�increment�his�pending�I/O�count.‰SPC‡2,‰MOVE.L„CCBPTR(A5),A0‡Set�up�buffer�pointer.‰SPC‡2@‰BTSTW…#IOASNFF,CCBCFIG+IOSATW(A5)�If�the�form�feed�after�assign4‰BNE.S…WRIT010�attribute�is�0�send�a�FF�character�if)*¦this�is�the�first�output�in�the�current *¦assignment.‰SPC‡20‰TST.B…DCBBCT(A4)ŠDo�we�need�to�do�a�form�feed�?‰BNE.S…WRIT010�Branch�if�no."‰STˆDCBBCT(A4)ŠSet�form�feed�flag.(‰MOVE.B„#FF,D0ŽYes,�set�up�FF�character.!‰BSR‡PRTOUT1�Go�output�to�device.‰BRA.S…WRIT020�Return. 'WRIT010‚BSR‡PRTOUTŽStart�buffer�output. !WRIT020‚UNMASK˜Enable�interrupts.‰BRA‡CMDEXIT�GO�FINISH�UP‰PAGEM*******************************************************************************‰REQUEST�STATUS*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M******************************************************************************REQSTAT: *E*‚Get�the�address�of�his�data�block�and�move�our�configuration�there.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�block.ŠSPC„24ŠBSR.S‚STATYP�Setup�the�device�status,�channel�type,&*£device�type,�and�driver�codes�in�the*£user's�configure�block.ŠSPC„2>ŠMOVE.W�#VALATM,IOSATM(A0)„Return�the�supported�attributes�andBŠMOVE.W�#VALPRM,IOSPRM(A0)‚parameters�masks�in�the�users�configure*¤block.ŠSPC„2BŠMOVE.L�#(IOSPLN/2)-1,D0ƒD0�<--�loop�control�to�move�entire�block.'REQLOOPƒMOVE.W�(A0)+,(A1)+ˆMove�a�word.5ŠDBRAƒD0,REQLOOP‰Keep�moving�until�whole�block�moved. 'ŠMOVE.B�#ISTAOK,D1‰Exit�with�OK�status.ŠBRA„NRMEXITŒ*ŠSPC„2*A*„This�subroutine�stores�the�current�device�status(always�ready),E*‚channel�type,�device�type,�and�driver�code�into�the�users�configureL*‚block.�Note�that�these�values�are�returned�only�on�RETRIEVE�DEVICE�STATUS/K*‚CONFIGURATION,CONFIGURE�DEVICE,�and�CHANGE�DEFAULT�CONFIGURATION�requests/*‚only�when�no�configurtion�error�was�detected.*5STATYP„CLR.B‚IOSDST(A0)ŽReturn�on-line�device�status.AŠMOVE.B�CCBTYPE(A5),IOSCTP(A0)‚Return�the�channel�type�defined�in *¨the�CCB.2ŠMOVE.B�#XDSPRT,IOSDTP(A0)†Device�type�is�PRINTER.?ŠMOVE.B�#IODLPRT,IOSDRC(A0)…This�is�a�local�Centronics�printer.ŠRTSŠPAGEM****************************************************************************** *‰CONFIGURE*@*‰This�c ommand�changes�the�CCB�configuration,�the�one�from�which<*‰the�driver�sets�up�the�device�and�under�which�it�performs.*,*‰Entry:�A2�=�address�of�CMR�parameter�block*�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M****************************************************************************** CONFIGUR: *B*‚Get�the�physical�address�of�the�user's�configuration�data�block.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�data�block.ŠSPC„21ŠMOVE.L�XIOUID(A2),A4†A4�<--�base�address�of�DCB. =ŠMOVE.B�#CECCDO,D2ŠIf�he's�trying�to�change�the�write�timeout?ŠBTSTW‚#IOSWTOB,IOSPRM(A1)�value,�return�a�configuration�error. ŠBNE„CNFGERRŠSPC„2DŠMOVE.L�DCBDEV+IOSWTO(A4),IOSWTO(A0)�Update�(in�the�CCB)�the�timeout/ŠBRA.S‚CMNCNFGŒvalues�from�the�DCB,�so�they�can,*£be�copied,�and�do�the�common�configuration *£processing.ŠPAGEM*******************************************************************************‰CHANGE�DEFAULT�CONFIGURATION*6*‰This�command�changes�the�DCB�configuration,�to�which4*‰IOS�will�restore�us�(via�a�CONFIGURE�command)�when/*‰FHS�closes�the�last�allocation�of�the�device.*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M***************************************************************************** CHNGDEF: *H*‚First�get�the�physical�address�of�the�user's�configuration�data�block.*8ŠBSR„CNFGADR2‹Get�the�address�of�the�users�configuration,*£data�block.�This�entry�point�preserves�A0.ŠSPC„27ŠMOVE.L�XIOUID(A2),A0ˆLoad�the�address�of�the�DCB�in�A46ŠMOVE.L�A0,A4Žand�the�address�of�the�DCB�configurationŠADD.L‚#DCBDEV,A0‰block�in�A0. ŠPAGEM*******************************************************************************‰COMMON�CONFIGURATION�ROUTINE*7*‰This�routine�does�the�work�common�to�the�two�commands-*‰CONFIGURE�and�CHANGE�DEFAULT�CONFIGURATION.*7*‰Entry:�A0�=�Address�of�CCB�or�DCB�configuration�block,*�A1�=�Address�of�user's�configuration�block*M***************************************************************************** CMNCNFG:*L*ƒFirst,�both�the�attributes�and�parameters�masks�are�checked�to�see�if�bitsL* corresponding to unsupported attributes or parameters are set. If any such2* bits are set, a configuration error is returned.*7ŠMOVE.W�#CECUAP,D2‹Set�up�for�an�error�exit�in�case�the&*£user�is�trying�to�change�unsupported*£attributes�or�parameters.ŠSPC„29ŠMOVE.W�#NVALATM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSATM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„29ŠMOVE.W�#NVALPRM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSPRM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„2E*‚Next�we�need�to�see�what�his�proposed�configuration�will�look�like.D*‚Plug�into�his�data�block�the�current�values�for�those�attributes�&?*‚parameters�he�doesn't�want�to�change.‚The�appropriate�current(*‚configuration�is�at�A0�and�he's�at�A1.*ŠOPT„BRS6ŠMOVE.W�IOSATM(A1),D0†Set�up�the�users�attribute�mask.;ŠAND.W‚D0,IOSATW(A1)†Zero�out�the�attributes�of�his�that�he.ŠNOT.W‚D0‘doesn't�want�to�change,�zero�out�the<ŠAND.W‚IOSATW(A0),D0†attributes�of�mine�that�he�does�want�to:ŠOR.WƒD0,IOSATW(A1)†change,�and�combine�them�in�his�space. @ŠMOVE.W�IOSPRM(A1),D0†Get�mask�of�parameters�he�wants�to�change. 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINE�WIDTH,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.W�IOSREC(A0),IOSREC(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINES/PAGE,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.L�IOSRSZ(A0),IOSRSZ(A1)ŠENDI 3ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�WRITE�TIMEOUT.ŠIF��THENŽvalue,�copy�the�current�setting.ŠMOVE.L�IOSWTO(A0),IOSWTO(A1)ŠENDI 3ŠLSR.W‚#2,D0ŽSkip�over�the�READ�TIMEOUT�bit.�If�the'*£LOGICAL�RECORD�LEN GTH�bit�is�not�set,*£copy�the�current�setting. ŠIF��THEN�MOVE.W‚IOSLRL(A0),IOSLRL(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�END-OF-LINE/ŠIF��THENŽSTRING,�copy�the�current�setting.ŒMOVE.B�IOSELC(A0),IOSELC(A1)ŠENDIŠOPT„BRL*I*ƒNow�that�the�users�configuration�block�contains�the�proposed�attributesG* and parameters, they will be checked for validity before copying them* into the DCB or CCB.*8ŠMOVE.B�#CECPNI,D2ŒIf�the�auto-linefeed�attribute�is�set@ŠBTSTW‚#IOALNFD,IOSATW(A1)�and�the�end�of�line�character�is�null,ŠBEQ.S‚CMNC001�return�a�configuration�error.ŠTST.B‚IOSELC(A1)ŠBEQ.S‚CNFGERRŠSPC„2CCMNC001ƒMOVE.B�#CECPRLZ,D2ŠIf�either�the�logical�or�physical�record<ŠMOVE.W�IOSREC(A1),D0†length�is�zero,�return�a�configurationŠBEQ.S‚CNFGERRŒerror.ŠMOVE.W�IOSLRL(A1),D3ŠBEQ.S‚CNFGERRŠSPC„24ŠCMP.W‚D3,D0�If�the�logical�record�length�is�greater5ŠBHS.S‚OKCNFG�than�the�physical�record�length,�return*ŠMOVE.B�#CECPLGP,D2ˆa�configuration�error.ŠSPC„2ACNFGERRƒMOVE.B�#ISTACFG,D1‰Return�a�configuration�error�status�in>ŠMOVE.B�D2,IOSCEC(A1)†the�users�IOS�parameter�block�and�return8ŠBRA.S‚CNFGEXIT‹the�specific�configuration�error�code�in *£the�users�configuration�block.ŠSPC„2F*…Set�the�configuration�flag�byte�in�the�device�DCB�to�indicate�that�aK*‚CONFIGURE�or�CONFIGURE�DEFAULTS�request�was�processed.�FHS�will�check�theM*‚flag�when�it�closes�the�last�assignment�to�the�device�to�see�if�it�needs�toH*‚tell�IOS�to�issue�a�configure�request.�IOS�will�then�issue�a�CONFIGUREJ*‚request�using�the�device�DCB�default�configuration�parameters.�This�willI*‚always�force�the�current�configuration�to�the�default�whenever�the�last*‚assignment�is�closed.*I*…Subroutine�STATYP�is�called�to�store�the�current�device�status,�channelH*‚type,�device�type,�and�driver�code�into�the�users�configuration�block.*ŠMOVE.B�CCBRLEN(A5),IOSLEN(A3)�Update�users�IOCB�length�field.ŠCLR.L‚CCBRLEN(A5)ŠSPC„2=ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;ŠSUB.B‚#1,TCBIOCNT(A0)‡and�decrement�his�pending�I/O�count.ŠSPC„2*!*‚Prepare�the�event�and�queue�it.*8ŠMOVE.B‚#ISTATO,IOSSTA(A3)ƒUpdate�the�IOCB�status�field.,ŠMOVE.W‚#ISTATO,D3‹Set�up�event�status�field-ŠMOVE.B‚#XPSHLT,D1‹Set�up�event�status�value.!ŠMOVE.L‚#6,D0�Set�up�info�length.&ŠMOVE.L‚CCBCID(A5),D2ˆSet�up�event�ID..ŠLEA…CCBPKT(A5),A4ˆSet�up�event�build�pointer.ŠBSR…QEVNT�Queue�event.ŠBRA…CMDEXITŽRETURN ŠPAGEL******************************************************************************C*‰ROUTINE�COMMON�TO�ALL�I/O�COMMANDS�(READ,�WRITE,�OUTPUT�W/�INPUT)**‚Entry:�A3�=�address�of�IOCB*‰A5�=�address�of�CCB**L*****************************************************************************IOSCOMN:?ŠBTSTW‚#IOPTSKB,IOSOPT(A3)�If�the�buffers�reside�in�a�different"ŠBEQ.S‚IOSC005Œtask�from�the�IOCB, 9ŠLEA„IOSTSK(A3),A0†Point�to�the�taskname�&�session�of�the7ŠTR0$.GETTCB‚,Œbuffer�owner�&�call�exec�to�get�address."ŠBRA.S‚OKTCBŽIf�it's�good,�branch.ŠNOP—If�it's�bad,6ŠMOVE.B�#XSTADB,D1‰set�status�in�IOCB�to�address�errorŠTST.L‚(A7)+Žadjust�stackŠBRA.S‚NRMEXITŒand�exit�to�CMR. :OKTCB…MOVE.L�A0,CCBTASKB(A5)„Save�physical�address�of�TCB. *<*‚Validate�the�info�in�the�IOCB�about�the�primary�buffer�and *‚convert�to�physical�addresses.*BIOSC005ƒMOVE.L�IOSSAD(A3),D6†D6�<--�buffer�physical�start�address.+ŠMOVE.L�IOSEAD(A3),D5†D5�<--�buffer�length.ŠSUB.L‚D6,D5Ž* ŠADDQƒ#1,D5Ž*ŠSPC„25ŠMOVE.L�D5,-(A7)‹Save�the�buffer�length�on�the�stack.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.$ŠBRA.S‚IOSC010ŒIf�it's�good,�branch.9ŠADDQ.L�#8,A7ŽIf�it's�a�bad�base�address,�remove�saved�D5&*£and�adjust�the�stack�return�address.ŠSPC„25ŠMOVE.B�#ISTAADD,D1ˆSet�IOCB�status�to�ADDRESS�ERROR.6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status. @IOSC010ƒMOVE.L�D6,CCBPTR(A5)†Save�physical�start�address�in�CCB.2ŠADD.L‚(A7)+,D6‹Save�the�physical�end�address�plus&ŠMOVE.L�D6,CCBEAP1(A5)…one�in�the�CCB.ŠRTSŠPAGEK****************************************************************************=*‰VALIDATE�CONFIGURATION�BUFFER�ADDRESS�&�CONVERT�TO�PHYSICAL*$*‰Entry:�D5�=�buffer�length�in�bytes-*�D6�=�buffer�logical�start�addr�(to�convert)*�A3�=�address�of�IOCB*�A5�=�address�of�CCB***‰Exit:‚D6ƒ=�buffer�physical�start�address*�D5ƒ=�buffer�length*K****************************************************************************CCNFGADRƒLEA.L‚CCBCFIG(A5),A0…This�entry�point�loads�the�CCB�config.*£data�block�into�A0.ŠSPC„2.CNFGADR2‚MOVE.L�A0,-(A7)‹Save�A0�on�the�stack.?ŠMOVE.L�IOSDBP(A3),D6†D6�<--�logical�addr�of�user's�data�block./ŠMOVE.L�#IOSPLN,D5‰D5�<--�length�of�data�block.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.%ŠBRA.S‚CNFGADR3‹If�it's�good,�branch.ŠSPC„27ŠADD.L‚#8,A7ŽIf�the�address�or�length�is�bad,�clean�the<ŠMOVE.B�#ISTAADD,D1ˆstack,�set�IOCB�status�to�ADDRESS�ERROR,6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status.ŠSPC„2=CNFGADR3‚MOVE.L�D6,A1ŽStore�the�physical�address�of�the�users9ŠMOVE.L�(A7)+,A0‹data�block�in�A1,�restore�A0�and�return.ŠRTSŠPAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D1�=�IOS�error�code*I**************************************************************************NRMEXIT:*‰LEA‡CCBPKT(A5),A4‡Set�up�queue�work�area.!‰MOVE.L„#6,D0�Se t�up�packet�size.#‰MOVE.L„XIOUID(A2),D2‡Set�up�PB�id.#‰AND.W…#$FF,D1�Mask�for�word�value."‰MOVE.W„D1,D3�Set�up�status�value./‰MOVE.B„D1,IOSSTA(A3)‡Update�IOCB�status�field.%‰MOVE.B„#XPSNRM,D1ŠSet�up�event�type.‰BSR‡QEVNT�Go�queue�event.CMDEXIT‚CLR.L…D0*8* User request side of IOH always exits from this point.*IOHUSRTN‚EQU„*ŠRTS—RETURN�TO�MAINLINEŠPAGEK****************************************************************************B*ƒSubroutine�to�check�address�boundaries�to�see�if�entirely�within* calling tasks address space.*&*‚Entry:�D5�-‚number�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‚IOHADR6�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.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.ŠPAGEL******************************************************************************‚PRTOUT*%*ˆThis�is�the�printer�output�routine.***ˆENTRY:‚A0�=�address�of�buffer*�A1�=�address�of�device�base*�A3�=�address�of�IOCB*�A4�=�address�of�DCB*�A5�=�address�of�CCB*.* PRTOUT1 ENTRY: D0.B = character to be output*—other�registers�as�above*M******************************************************************************CPRTIMG„ADD.L‚#1,CCBRLEN(A5)†For�image�mode,�count�each�byte�sent�to>ŠCMP.L‚CCBEAP1(A5),A0„the�printer�whether�printable�or�not.�If6ŠBEQ.S‚PRT070Œthe�end�of�the�buffer�is�reached,�do�the *¢request�completion�processing.ŠSPC„2PRTOUT:0ŠMOVE.B‚(A0)+,D0ŽGet�next�data�byte�from�buffer.,ŠMOVE.L‚A0,CCBPTR(A5)‰Update�buffer�pointer.ŠSPC…2;ŠBTSTWƒ#IOPFORB,CCBCOPT(A5)„For�image�mode�output,�skip�the,ŠBNE.SƒPRTOUT1�special�character�processing.ŠSPC…20ŠCMP.B‚#CR,D0“If�the�current�buffer�character�is,ŠBEQ.S‚PRT030‘a�CR,�proceed�with�end-of-line *§processing.ŠSPC…2+PRTOUT1ƒBSR.LƒDEVOUTS�Output�the�data�byte.ŠSPC„2?ŠBTSTWƒ#IOPFORB,CCBCOPT(A5)„If�the�output�is�bring�performed�in1ŠBNE.SƒPRTIMG�image�mode,�transfer�control�to�the%*§top�of�the�output�loop�to�check�for*§end�of�buffer.ŠSPC…25ŠCMP.Bƒ#'�',-1(A0)�If�the�current�buffer�character�is,ŠBLT.SƒPRT017�non-printing,�do�not�check�for(*¦end-of-line�or�increment�the�character*¦countŠPAGE<ŠADD.L‚#1,CCBRLEN(A5)ŠIncrement�the�printed�character�count.9ŠMOVE.L�CCBRLEN(A5),D2ŠDivide�the�printed�character�countAŠDIVUƒCCBCFIG+IOSLRL(A5),D2‚by�the�logical�line�length.�Store�the+ŠSWAP„D2”remainder�in�the�lower�half�of�D2.ŠSPC…1*ŠTST.W‚D2—If�an�exact�logical�and�physical4ŠBNE.S‚PRT017‘end-of-line�has�been�reached,�output�a*N* THE FOLLOWING LINE WAS ADDED TO THE VME115 PRINTER DRIVER TO FIX THE PROBLEML*�OF�THE�ORIGINAL�DRIVER.‚IT�DID�A�COMPARISON�OF�THE�PHYSICAL�LINE�LENGTH�TOH*�REGISTER�D3.‚THIS�REGISTER�WAS�NEVER�SET�UP.‚I�THINK�THE�INTENT�WAS�TO>* COMPARE THE PHYSICAL LINE LENGTH TO THE LOGICAL LINE LENGTH.BŠMOVE.W�CCBCFIG+IOSLRL(A5),D3‚(FIRST�LOAD�TH E�LOGICAL�LINE�LENGTH)*@ŠCMP.W‚CCBCFIG+IOSREC(A5),D3‚linefeed�for�non-auto-LF�device.�If3ŠBEQ.S‚PRT013‘only�the�logical�line�length�has�been3ŠBSR.S‚PRTEOL‘reached,�output�a�logical�end-of-line2ŠBRA.S‚PRT015‘sequence.�If�neither�length�has�been&*§reached�proceed�to�the�end-of-buffer*§check.ŠSPC„2GPRT013„BTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�the�device�does�not�support0ŠBNE.SƒPRT015�auto�line�feed,�output�a�line�feed5ŠMOVE.B�#LF,D0‘if�the�byte�count�is�an�exact�multiple"ŠBSR.SƒDEVOUTS�of�the�line�length.ŠSPC…2FPRT015„BTSTW‚#IOATPLL,CCBCFIG+IOSATW(A5)�Since�an�end-of-line�has�been/ŠBNE.SƒPRT070“reached,�terminate�the�request�if!*ªthe�truncate�print�attribute�is*ªset.ŠSPC„2=PRT017„CMP.LƒCCBEAP1(A5),A0ŠIf�the�end�of�buffer�has�not�been/ŠBLT…PRTOUT�reached,�output�the�next�character.ŠSPC…2:PRT030„BSR.SƒPRTEOL‘Output�a�logical�end-of-line�sequence.ŠPAGEPRT070:*2*‚Finished�transfer,�now�queue�event�to�requestor.*+ŠBCLRW‚#CCBFGBSY,CCBFG(A5)ƒClear�busy�flag.,ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�TCB�address.3ŠSUB.B‚#1,TCBIOCNT(A0)‡Decrement�I/O�pending�count. -ŠMOVE.W�#ISTAOK,D3ŒSet�up�ok�IOS�status�code.6ŠAND.B‚#%00000110,D0‰Keep�SELECTED�and�PAPER�OUT�bits.7ŠCMP.B‚#%00000100,D0‰See�if�SELECTED�and�PAPER�not�out."ŠBEQ.S‚PRT080�Branch�if�no�faults.1ŠMOVE.W�#ISTANR,D3ŒFault,�set�up�IOS�status�code.-PRT080„MOVE.L�#6,D0‘Set�up�event�info�length.*ŠMOVE.B�#XPSNRM,D1ŒSet�up�event�type�code.)ŠMOVE.L�CCBCID(A5),D2‰Set�up�DCB�address./ŠMOVE.B�D3,IOSSTA(A3)‰Update�IOCB�status�field.8ŠMOVE.L�CCBRLEN(A5),IOSLEN(A3)‚Update�IOCB�length�field. *ŠLEA„CCBPKT(A5),A4‰Set�up�event�data�area./ŠBSR„QEVNT‘Queue�completion�event�to�requestor. !ŠIF.BƒCCBPTRTE(A5)��#0�THEN.SŒRTSŠELSE.S ŒBRA‚PRTINRTEŠENDIŠPAGE*E*‹This�subroutine�outputs�either�a�LF-CR�sequence�or�an�EOL�character6*‰based�on�the�setting�of�the�auto-linefeed�attribute.*#PRTEOL„MOVE.B�CCBCFIG+IOSELC(A5),D0?ŠBTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�not�an�exact�end-of-line,4ŠBNE.SƒDEVOUTS�output�the�EOL�character�if�the�auto-(*§linefeed�attribute�is�set.�Else�output*§a�LF�and�CR.ŠSPC…2/ŠMOVE.B‚#LF,D0’Call�DEVOUT�to�output�a�linefeed.ŠBSR.SƒDEVOUT�character.�If�an�error�status�is1ŠTST.BƒD3”returned�in�D3,�transfer�control�to�theŠBNE.SƒDEVOUTE�error�exit.ŠSPC„26ŠMOVE.B‚#CR,D0�Set�up�carriage�return�character�in�D0.ŠSPC„2*E*‹This�routine�is�called�as�a�subroutine�from�PRTOUT�to�output�singleF*‰characters�from�D0�with�automatic�request�termination�if�an�error�isD*‰detected�in�the�DEVOUT�subroutine.�Execution�also�falls�through�to*‰here�from�PRTEOL.*8DEVOUTSƒBSR.S‚DEVOUT�Call�DEVOUT�to�output�the�character5ŠTST.B‚D3‘in�D0.�If�the�status�returned�in�D3�is�non-'ŠBEQ.S‚DEVOUTOK‹zero,�do�an�error�exit.ŠSPC„2:DEVOUTEƒTST.L‚(A7)+�If�an�error�occurs�transfer�control�to-ŠPEA.L‚PRT070�the�request�completion�routine.ŠSPC„2+DEVOUTOK‚RTS™Return�to�the�calling�routine.ŠPAGEO*********************************************************************************‚DEVOUT(*�****MODIFIED�1/27/83�BY�M.�BRIEL*******<*†1.Check�for�a�device�fault�(not-selected�or�out�of�paper).=*ˆIf�a�fault�is�present,�terminate�the�request�with�an�error.*F*†2.�If�an�Printer�Acknowledge�is�expected,�wait�for�the�ACK�pulse�for@*‰approx.�100�us.�If�the�pulse�does�not�arrive�in�100�us,�enable0*‰the�Acknowledge�interrupt�and�exit�the�driver.*4*†3.�Output�the�next�character�and�pulse�Data�Strobe**ˆENTRY:„D0‚=�data�byte*’A1‚=�device�base�address*‘(SP)�=�return�address*�4(SP)�=�PRTOUT�return�address*�DEVICE�=�Interrupts�disabled*,*ˆEXIT:…D0‚=�Device�status�register�contents*�NORMAL�=�(SP)�return*�FAULT�=�(SP)+2�return5*‘BUSY�=�4(SP)�PRTOUT�return�address�(device�enabled)*K****************************************************************************DEVOUT:.‰CLR.BƒD3“Clear�D3�in�preparation�for�a�normal *£return.‰SPC…2 ‰CLR.LƒD1,‰MOVE.B‚PBDR(A1),D1‹Pick�up�stat us�register. ‰MOVE.L‚D1,D2‘Make�another�copy.,‰AND.Bƒ#%00000110,D1‰Mask�uninterested�bits.3‰CMP.Bƒ#%00000100,D1‰Selected�and�not�Out-of-Paper?‰BNE.SƒDEV010�Fault�exit�if�no.‰SPC…2:ŠTST.B‚CCBACKP(A5)ŠIf�a�printer�acknowledge�is�not�pending,ŠBEQ.S‚DEV020�proceed�with�character�output.ŠSPC„2:ŠMOVE.W�#32,D1�Repeatedly�test�for�the�printer�acknowledgeADEVACK„BTST.B�#1,PSR(A1)‰pulse.�If�the�acknowledge�arrives�before;ŠDBNEƒD1,DEVACKŠthe�loop�times�out�(approx.�100�us)�proceed**£with�character�output.�Otherwise,�enable**£the�Acknowledge�pulse�interrupt�and�exit *£the�driver.ŠSPC„2 ŠBNE.S‚DEV020*(* Enable ACKNOWLEDGE Interrupt and Exit.:‰MOVE.B‚D0,CCBSAVB(A5)ˆThe�device�is�busy,�save�data�byte..‰MOVE.L‚(A7)+,CCBIRTN(A5)…Save�return�address.-‰SUB.Lƒ#2,CCBIRTN(A5)ˆAdjust�service�address.A‰MOVE.L‚(A7)+,CCBISTK(A5)…Save�subroutine�return�address�into�CCB*<*‚SET�UP�TIMEOUT�CALL�IN�CASE�OF�A�FAULT�(NO�ACK�INTERRUPT):C‰MOVEM.L�D0-D2/A0-A1,-(A7)…Save�registers�used�by�TIMEOUT�(EXRQPA).3‰MOVE.L‚#T0RQPA,D0ŒService�request�code�for�EXRQPA. ‰CLR.LƒD1-‰MOVE.B‚CCBPPRIO(A5),D1‡Save�interrupt�level.#‰MOVE.L‚A5,D2‘Save�our�CCB�address..‰LEA…PTIMOUT(PC),A0ˆAddress�of�wakeup�routine.6‰MOVE.L‚#10000,A1�***�12/19/84‚Set�for�10000�millisec.‰TRAP„#0‰NOP›Assume�the�call�was�taken.-‰MOVEM.L�(A7)+,D0-D2/A0-A1…Restore�registers.1‰ST†CCBTIMED(A5)ŠSet�TIMEOUT�REGUEST�NEEDED�flag.*(*‚NOW�ENABLE�THE�EXPECTED�ACK�INTERRUPT:‰INHIB™Disable�interrupts./‰BSET„#2,PACR(A1)‹Enable�device�ACK�interrupts. ‰RTS›Return.* * Fault Exit+DEV010ƒMOVE.L‚D2,D0‘Set�up�status�register.1‰BSR…DEVINIT1ŽReprogram�device�for�no�interrupts.:ŠCLR.B‚CCBACKP(A5)‰Clear�pending�printer�acknowledge�flag.@ŠMOVE.B�#%00000010,PSR(A1)‚Clear�Acknowledge�interrupt�IRQ�flag.+‰ST†D3”Set�D3�non-zero�to�indicate�an�error$‰BRA.SƒDEVOEX�and�prepare�to�return.*(*�Output�the�next�character�1/17/84�MLB*FDEV020ƒMOVE.B‚#%00000010,PSR(A1)„Clear�Acknowledge�interrupt�IRQ�flag.%‰MOVE.B‚D0,PADR(A1)‹Output�data�byte.‰BCLR„#0,PCDR(A1)'‰BSET„#0,PCDR(A1)‹Strobe�the�data�byte.8‰ST†CCBACKP(A5)‹Set�the�printer�acknowledge�pending�flag.‰MOVE.B‚PBDR(A1),D0‹Get�status�register�again.‰SPC…20DEVOEXƒENABL™Enable�interrupts�and�return�to�the‰RTS™calling�routine.‰PAGEJ***************************************************************************!* INTERRUPT SIDE FOR PRT 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**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P****ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT*F*---------------------------------------------------------------------*4* If channel is off-line or not attached, just exit.*PRTISR:.ŠMOVE.L�CCBCHB(A5),A1‰Get�device�base�address.+ŠMOVE.B�PSR(A1),D0ŒPick�up�status�register.)ŠAND.B‚#%00000010,D0‰Mask�interrupt�bits.4ŠCMP.B‚#%00000010,D0‰ACKNOWLEDGE�Interrupt�pending�?ŠBEQ.S‚PRTI010�Branch�if�yes. 2ŠAND.W‚#$FFFE,SR�No�interrupt�so�set�condition�and ŠRTSšreturn.*C*‚SINCE�AN�ACK�WAS�RECEIVED�THERE�IS�NO�NEED�FOR�A�TIMEOUT�REQUEST:5PRTI010ƒCLR.B‚CCBTIMED(A5)ŠClear�TIMEOUT�needed�flag.&ŠBTSTW‚#CCBFGOFF,CCBSTR(A5)‚Off-line�?ŠBNE.S‚PRTI020�Branch�if�yes.5ŠBTSTW‚#CCBFGATH,CCBSTR(A5)‚Is�the�channel�attached�?ŠBEQ.S‚PRTI020�Branch�if�no.(ŠBTSTW‚#CCBFGBSY,CCBFG(A5)ƒI/O�pending�?ŠBNE.S‚PRTI100�Branch�if�yes. 8PRTI020ƒMOVE.L�CCBCHB(A5),A1‰Set�up�device�base�address.(ŠBSR„DEVINIT1ŽDisable�device�interrupts.ŠENABL!ŠOR.Wƒ#$0001,SR�Set�condition�and ŠRTSšreturn.ŠPAGEN******************************************************************************** INTERRUPT LEVEL PROCESSING*0*ˆIt�has�been�de termined�that�I/O�is�in�progress*ˆand�the�interrupt�is�ours.**N*******************************************************************************PRTI100:=ŠMOVEM.L�D1-D7/A2-A4/A6,-(A7)�Save�the�rest�of�the�registers.1ŠBSR…DEVINIT1�Reprogram�device�for�no�interrupts.=ŠCLR.B‚CCBACKP(A5)‰Clear�the�printer�acknowledge�pending�flagBŠMOVE.B�#%00000010,PSR(A1)‚Clear�DEVICE�Acknowledge�interrupt�IRQ.ŠSPC„1–1/17/84�MLB*-ŠMOVE.L‚CCBPTR(A5),A0ˆRestore�buffer�pointer.1ŠMOVE.B‚CCBSAVB(A5),D0‡Restore�current�data�byte.5ŠMOVE.L‚CCBIRTN(A5),A2‡Get�interrupt�service�address.'ŠMOVE.L‚CCBCCB(A5),A3ˆGet�IOCB�address.&ŠMOVE.L‚CCBCID(A5),A4ˆGet�DCB�address.8ŠADD.Bƒ#1,CCBICNT(A5)‡Increment�pending�interrupt�count.:ŠPEA…PRTINRTN(PC)‰Stack�the�interrupt�routine�exit�addressAŠMOVE.L‚CCBISTK(A5),-(A7)„Restore�subroutine�return�on�the�stack.!ŠJMP…(A2)‘Jump�to�output�routine.*.* PRT interrupt handler exits from this point. PRTINRTN:7ŠSUB.Bƒ#1,CCBICNT(A5)‡Decrement�pending�interrupt�count0ŠMOVEM.L�(A7)+,D1-D7/A2-A4/A6�Restore�registers./***‡ENABL˜Let�CMR�enable�interrupts�later,�this%***¤fix�is�for�EPSON�RX80�(SPR�1178).(ŠOR.W„#$0001,SRŒSet�return�condition�and!ŠRTSšreturn�to�interrupt�handler.ŠPAGEJ*************************************************************************** * PTIMOUT*E*ƒPURPOSE:‚This�is�the�entry�point�for�a�wakeup�call.‚It�is�set�up�in?*�the�DEVOUT�routine�when�an�ACKNOWLEDGE�has�not�been�received.;*�This�routine�will�be�entered�even�if�an�ACKNOWLEDGE�comes<*�during�the�TIMEOUT.‚The�flag�CCBTIMED�is�checked�to�see�if8*�a�TIMEOUT�is�still�needed.‚This�flag�is�cleared�in�the *�ACKNOWLEDGE�interrupt�routine.**ƒENTRY:„From�the�EXEC.*�D1�-�Address�of�the�CCB*?*ƒEXIT:…RTE�-�must�save�D2-D7/A2-A6�and�restore�before�the�RTE.*J**************************************************************************PTIMOUT:*ŠMOVEM.L�D2-D7/A2-A6,-(A7)„Save�registers.&ŠMOVE.L‚D1,A5�Pick�up�the�CCB�address..ŠMOVE.L‚CCBCHB(A5),A1ˆGet�device�base�address.'ŠMOVE.L‚CCBCCB(A5),A3ˆGet�IOCB�address.&ŠMOVE.L‚CCBCID(A5),A4ˆGet�DCB�address./ŠST†CCBPTRTE(A5)‰Flag�to�process�a�RTE�on�exit.1ŠTST.BƒCCBTIMED(A5)‰Do�we�still�need�the�TIMEOUT?/ŠBEQ.SƒPRTINRTE�No�-�must�have�received�an�ACK.*J* A TIMEOUT has occurred and NO acknowledge was received from the printer.H*�THIS�SHOULD�BE�A�FAULT�CONDITION.‚If�the�cable�was�disconnected�AT�THEK* VME115 board an actual fault would be missed if the FAULT line were to beH*�checked�here.‚This�is�because�there�is�no�pull-down�resistor�on�board.J* The assumption is made here that since a TIMEOUT has occurred there must;* be a problem, so queue the 'DEVICE NOT READY' error back.*ŠBSR…DEVINIT1�Reset�the�device.-ŠCLR.BƒD0“Make�the�status�look�like�it�is�not,ŠBRA…PRT070�selected.�Then�queue�event�back.ŠSPC�2*!* TIMEOUT exits here with an RTE:2PRTINRTE‚CLR.BƒCCBPTRTE(A5)‰Clear�RTE�needed�flag..ŠCLR.BƒCCBTIMED(A5)‰Clear�TIMEOUT�needed�flag.ŠENABL1ŠMOVEM.L�(A7)+,D2-D7/A2-A6„Restore�the�registers.ŠRTEŠPAGEJ**************************************************************************** QEVNT**„Place�message�on�user's�ASQ.**ˆA4�=�address�of�event�area*ˆA5�=�address�of�CCB'*ˆD0�=�event�length�(minus�header�info)*ˆD1�=�event�type*ˆD2�=�4�byte�id�(DCB)*ˆD3�=�status�value�(2�bytes)*ˆD4�=�device�status�(2�bytes)*ˆD5�=�device�number�(1�byte)*J***************************************************************************QEVNT:ŠMOVE.L�D0,D6ŽSave�length.5ŠMOVE.L�#2,D7ŽOffset�for�staging�(no�service�vector)./ŠMOVE.B�#IOEVCD,1(A4)†Code�(no�service�vector).)ŠMOVE.L�CCBSVVC(A5),2(A4)‚Service�vector.+ŠBEQ.S‚QEVNT10ŒBranch�if�no�service�vector./ŠADD.L‚#4,D0ŽCorrect�length�for�service�vector.7ŠADD.L‚#4,D7ŽCorrect�offset�staging�for�service�vector.2ŠADD.L‚#$00800000,(A4)„Correct�for�service�vector. 1QEVNT10ƒMOVE.B�D1,0(A4,D7)ˆCompletion�event�type.*ŠMOVE.B�CCBKEY(A5),1(A4,D7)�User's�id�key.-ŠADD.L‚#4,D0ŽComplete�leng th�of�return�event.6ŠCMP.B‚CCBASQL(A5),D0…User's�maximum�ASQ�entry�length.#ŠBLS.S‚QEVNT20ŒBranch�if�length�ok.0ŠMOVE.B�CCBASQL(A5),D0…User's�length�is�smaller. &QEVNT20ƒMOVE.B�D0,(A4)ŒCorrect�length. /QEVNT40ƒMOVE.L�D2,2(A4,D7)ˆSet�up�status�value.$ŠMOVE.W�D3,6(A4,D7)ˆSet�up�id�(DCB).ŠCMP.B‚#6,D6Ž6�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.)ŠMOVE.W�D4,8(A4,D7)ˆSet�up�device�status.ŠCMP.B‚#8,D6Ž8�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.*ŠMOVE.B�D5,10(A4,D7)‡Set�up�device�number.&ŠCLR.B‚11(A4,D7)ŠClear�reserved�field.*I* Now let's put the completion into registers and send event to the task.* QEVNT50ƒEQU„*ŠMOVEM.L�(A4),D2-D7ŠBSR.S‚IOHQEVNTŠRTSŠ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**************************************************************************** IOHQEVNT:$ŠMOVEM.L�A3-A5,-(A7)‡Ssve�registers.-ŠMOVE.L�CCBRQSTA(A5),A0„Caller's�TCB�address.ŠSPC„26ŠMOVE.L�#T0QEVNTI,D0‰If�this�routine�was�called�during6ŠTST.B‚CCBICNT(A5)ˆinterrupt�processing,�use�the�QEVNT3ŠBNE.S‚IOHQ4Žinterrupt�routine,�else�use�the�normal#ŠMOVE.L�#T0QEVNTT,D0‡QEVNT�routine. IOHQ4…TRAPƒ#0#ŠBRA.S‚IOHQ5ŽBranch�if�queueing�ok.'ŠMOVEM.L�(A7)+,A3-A5‡Restore�registers.9ŠMOVE.L�(A7),CCBQVER1(A5)‚Save�callers�address�for�debug.ŠBRA.S‚IOHQRTN ,IOHQ5…MOVEM.L�(A7)+,A3-A5‡Restore�registers..ŠCLR.L‚CCBQVER1(A5)‡Clear�queue�error�address. IOHQRTNƒRTS—RETURNŠENDééé=/* =/*†PIADRV.AF=/*8=/* Chain file to assemble the printer driver for a PIA.=/*:=/* If no output argument is specified for the listing the(=/* chain file will default to PIADRV.LS=/*=/IFC \1ƒ=ARG�PIADRV.LS=/ENDIF=/*#=ASM PIADRV.SA,PIADRV.RO,\1;MRZ=146=/*{ Included files are:=/*ƒ9995.&.TRACE.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ=/*ƒ9995.&.LV5.EQ=/*}=/*=ENDéééé é鲊PAGEJPIADRV„IDNTƒ4,0�VERSAdos�Local�Printer�I/O�Handler�Process�V4.0�-�09/13/82?ŠTTL„VERSADOS�LOCAL�PRINTER�I/O�HANDLER�PROCESS�V4.0�-�09/13/82 ŠLLENƒ120ŠNOLISTŠINCLUDE�9995.&.TRACE.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.TCB.EQŠINCLUDE�9995.&.CCB.EQŠINCLUDE�9995.&.IOE.EQŠINCLUDE�9995.&.NIO.EQŠINCLUDE�9995.&.LV5.EQŠLIST ŠNOFORMATJ****************************************************************************1* PRT -- REV. 1.00 02NOV81 (TL09) JIM SMITH - IOH9*ˆREV.�1.01�01FEB82�(TL09)�JIM�SMITH�-�VECTOR�CHAIN�(IOH)5*ˆREV.�1.02�23FEB82�(TL09)�JIM�SMITH�-�IOCB�USE�(IOH)5*ˆREV.�2.00�15APR82�(TL09)�JIM�SMITH�-�PRINTER�DRIVER5*ˆREV.�2.01�01JUN82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER5*ˆREV.�2.10�15JUL82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER-*ˆREV‚2.20�18JAN84ˆMARC�BRIEL-�PRINTER�DRIVER;*ˆREV‚2.21�17DEC84ˆMIKE�DUH‚-�Removed�ENABL�at�PRTINRTN�for *­SPR�1178�(Epson�RX80�printer).*«-�Fixed�HALT�routine.8*ˆREV‚2.22�8MAR85‰DICK�V.ƒ-�Halt�routine�register�changeéééé »Ä-ÌEÔEÜ@äFì@ô@üC7 37>$<,R46<9D=LBT>\>d!*'*ƒPURPOSE:‚CHANNEL�(DEVICE)�I/O�HANDLER*�****�PRINTER�DRIVER�*****/*ƒENTRY:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒEXIT:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION***ƒCODE�IS�RE-ENTRANT**H*-----------------------------------------------------------------------*PRTORG:ŠPAGE*(****************************************(* EQUATES FOR SPECIAL ASCII CHARACTERS *(*****************************************NUL†EQU‡$00‘NullBEL†EQU‡$07‘BellBS‡EQU‡$08‘BackspaceLF‡EQU‡$0A‘Line�feedFF‡EQU‡$0C‘Form�feedCR‡EQU‡$0D‘Carriage�returnSPACE„EQU‡$20‘Blank ******************** DEVICE EQUATES ********************+DEV1ACƒEQU‡2“A-side�control�register�offset+DEV1BCƒEQU‡6“B-side�control�register�offset(DEV1ADƒEQU‡0“A-side�data�register�offset(DEV1BDƒEQU‡4“B-side�data�register�offset* STRBSYƒEQU‡%00000100‹Device�busy(STROUTƒEQU‡%00000010‹Device�out�of�paper$STRSELƒEQU‡%00000001‹Device�selected*6DSDVIAƒEQU‡$3C‘Dis abled�A-side�interrupts‚*1/17/84�MLBééé)DSDVIBƒEQU‡$3C‘Disabled�B-side�interrupts *************************** MISCELLANEOUS EQUATES ***************************IOEVCD„EQU„1’I/O�event�codeDVALATM„EQU„1<*ƒCA2�DATA�STB�DATA�STROBE„OUTPUT…LOW„PULSE�TO�CLOCK�DATA�FROM*³PIA�TO�PRINTER�LOGIC<*ƒCA1�ACKNLGƒACKNOWLEDGE„INPUT†LOW„PULSE�INDICATING�INPUT�OF*³CHARACTER�INTO�PRINTER*³MEMORY�OR�END�OF�FUNTION1*ƒPB2�BUSY…BUSY‹INPUT†HIGHƒPRINTER�CANNOT�RECEIVE*³DATA.<*ƒPB1�OUT-PPƒOUT�OF�PAPERƒINPUT†HIGHƒPRINTER�IS�OUT�OF�PAPER/*ƒPB0�SEL†SELECT‰INPUT†HIGHƒPRINTER�IS�SELECTED*K****************************************************************************DEVINIT:1‰MOVE.L„CCBCHB(A5),A1‡Set�up�device�base�address.5‰MOVE.B„#00,DEV1AC(A1)†Select�the�DDR�for�the�A-side.5‰MOVE.B„#00,DEV1BC(A1)†Select�the�DDR�for�the�B-side.;‰MOVE.B„#$FF,DEV1AD(A1)…Set�A-side�data�direction�(output). +‰CMP.B…#XTPRTL,CCBTYPE(A5)�RTTLIO�channel�?‰BNE.S…DEVINIT0ŒBranch�if�no.3‰MOVE.B„#$80,DEV1BD(A1)…PB7�output�for�LED�control.‰BRA.S„DEVINITAŠSPC„2¼*FDEVINIT0�MOVE.B„#00,DEV1BD(A1)†Set�B-side�data�direction�(status�inputŠSPC„2HDEVINITA�MOVE.B„#$04,DEV1AC(A1)…Select�A-side�data�register�1/17/84�MLB*9‰TST.B…DEV1AD(A1)ŠRead�data�reg.�to�clear�ACK�interrupt‚*ŠSPC„2¼*HDEVINIT1�MOVE.B„#$04,DEV1BC(A1)…Clear�interrupt�on�B-side.�1/17/84�MLB�*8‰TST.B…DEV1BD(A1)ŠRead�data�register�to�clear�interrupt.*‰MOVE.B„#DSDVIA,DEV1AC(A1)‚Program�A-side.*‰MOVE.B„#DSDVIB,DEV1BC(A1)‚Program�B-side.‰SPC‡2*‰CMP.B…#XTPRTL,CCBTYPE(A5)�RTTLIO�channel?‰BNE.S…DEVINIT2ŒBranch�if�not.?‰MOVE.B„#00,DEV1BD(A1)†Turn�off�RTTLIO�LED�(won't�hurt�others).‰SPC‡29DEVINIT2�BCLR†#0,DEV1AC(A1)‡Disable�interrupts�on�A-side.1‰BCLR†#0,DEV1BC(A1)‡Disable�interrupts�on�B-side. ‰RTS›Return.‰PAGEJ***************************************************************************%*ˆTHIS�IS�THE�COMMAND�SERVICE�ROUTINE*6*‹PARAMETER�ADDRESS�AND�BOUNDARY�CHECKS�HAVE�BEEN�MADE**ƒ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�=�CAMMAND�PACKET�(IOCB)�POINTER *”A6�=�REQUESTOR�TCB�ADDRESS**ƒEXEC�ROUTINES�CALLED:‚QEVENTT**ƒCODE�IS�RE-ENTRANT*J***************************************************************************PRTUSER:*)* Convert logical PB address to physical.* ŠCLR.L‚D5>ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�command�packet�(IOCB).6ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�command�packet.+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚PRTU010ŒGood�return.)ŠMOVE.B�#ISTAIP,D1‰Set�up�IOS�error�code.ŠBRA„NRMEXITŒExit.=PRTU010ƒMOVE.L�D6,A3ŽSave�physical�address�of�command�packet.**‚Check�for�HALT�command.*(ŠCMP.Wƒ#IOHALT,IOSFCT(A3)…HALT�command�?!ŠBEQ…HALT“Branch�if�HALT�command.** See if channel is busy.*)ŠBTSTW‚#CCBFGBSY,CCBFG(A5)‚Channel�busy�?ŠBEQ.S‚PRTU020ŽBranch�if�no.6ŠMOVE.B�#XSTBSY,D0‹Busy,�set�up�channel�error�code�andŠBRA„IOHUSRTN�Return.ŠPAGE*K****************************************************************************(*‚Find�the�command�in�the�command�table.*** PRTU020:8ŠMOVE.W�IOSOPT(A3),CCBCOPT(A5)�Save�IOCB�options�in�CCB.6ŠMOVE.L�XIOUID(A2),CCBCID(A5)‚Save�DCB�pointer�in�CCB.(ŠMOVE.L�A3,CCBCCB(A5)†Save�IOCB�pointer.*ŠMOVE.L�XIOUID(A2),A4†Pick�up�DCB�pointer.9ŠMOVE.L�CCBTASKA(A5),CCBTASKB(A5)‚Set�up�buffer�task�TCB. -ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table./ŠMOVE.W�IOSFCT(A3),D6†Set�up�user�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. ?CMDERR„MOVE.B�#ISTAIF,D1‰We�didn't�find�it,�so�exit�with�error. ŠBRA„NRMEXITŠPAGEL******************************************************************************‰WRITE**,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB%*‰A6�=�address�of�attached�task's�TCB***L*****************************************************************************WRITE:5‰BSR‡IOSCOMN�Do�the�stuff�common�to�all�I/O�commands. -‰BSETW…#CCBFGBSY,CCBFG(A5)�Mark�channel�busy.6‰CLR.L…CCBRLEN(A5)‰Initialize�the�output�byte�counter.1‰MOVE.L„CCBCHB(A5),A1‡Set�up�device�base�address. ‰BSR‡DEVINIT1ŒSet�up�the�device.‰SPC‡2=‰MOVE.L„CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;‰ADD.B…#1,TCBIOCNT(A0)…and�increment�his�pending�I/O�count.‰SPC‡2,‰MOVE.L„CCBPTR(A5),A0‡Set�up�buffer�pointer.‰SPC‡2@‰BTSTW…#IOASNFF,CCBCFIG+IOSATW(A5)�If�the�form�feed�after�assign4‰BNE.S…WRIT010�attribute�is�0�send�a�FF�character�if)*¦this�is�the�first�output�in�the�current *¦assignment.‰SPC‡20‰TST.B…DCBBCT(A4)ŠDo�we�need�to�do�a�form�feed�?‰BNE.S…WRIT010�Branch�if�no."‰STˆDCBBCT(A4)ŠSet�form�feed�flag.(‰MOVE.B„#FF,D0ŽYes,�set�up�FF�character.!‰BSR‡PRTOUT1�Go�output�to�device.‰BRA.S…WRIT020�Return. 'WRIT010‚BSR‡PRTOUTŽStart�buffer�output. !WRIT020‚UNMASK˜Enable�interrupts.‰BRA‡CMDEXIT�GO�FINISH�UP‰PAGEM*******************************************************************************‰REQUEST�STATUS*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M******************************************************************************REQSTAT: *E*‚Get�the�address�of�his�data�block�and�move�our�configuration�there.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�block.ŠSPC„24ŠBSR.S‚STATYP�Setup�the�device�status,�channel�type,&*£device�type,�and�driver�codes�in�the*£user's�configure�block.ŠSPC„2>ŠMOVE.W�#VALATM,IOSATM(A0)„Return�the�supported�attributes�andBŠMOVE.W�#VALPRM,IOSPRM(A0)‚parameters�masks�in�the�users�configure*¤block.ŠSPC„2BŠMOVE.L�#(IOSPLN/2)-1,D0ƒD0�<--�loop�control�to�move�entire�block.'REQLOOPƒMOVE.W�(A0)+,(A1)+ˆMove�  a�word.5ŠDBRAƒD0,REQLOOP‰Keep�moving�until�whole�block�moved. 'ŠMOVE.B�#ISTAOK,D1‰Exit�with�OK�status.ŠBRA„NRMEXITŒ*ŠSPC„2*A*„This�subroutine�stores�the�current�device�status(always�ready),E*‚channel�type,�device�type,�and�driver�code�into�the�users�configureL*‚block.�Note�that�these�values�are�returned�only�on�RETRIEVE�DEVICE�STATUS/K*‚CONFIGURATION,CONFIGURE�DEVICE,�and�CHANGE�DEFAULT�CONFIGURATION�requests/*‚only�when�no�configurtion�error�was�detected.*5STATYP„CLR.B‚IOSDST(A0)ŽReturn�on-line�device�status.AŠMOVE.B�CCBTYPE(A5),IOSCTP(A0)‚Return�the�channel�type�defined�in *¨the�CCB.2ŠMOVE.B�#XDSPRT,IOSDTP(A0)†Device�type�is�PRINTER.>ŠMOVE.B�#IODLPRT,IOSDRC(A0)…This�is�a�local�Centronics�printer&*¨driver�for�use�on�the�EXORmacs�DEBUG#*¨PIA�port�or�an�MVME410�PIA�on�the*¨I/O�Channel.ŠRTSŠPAGEM****************************************************************************** *‰CONFIGURE*@*‰This�command�changes�the�CCB�configuration,�the�one�from�which<*‰the�driver�sets�up�the�device�and�under�which�it�performs.*,*‰Entry:�A2�=�address�of�CMR�parameter�block*�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M****************************************************************************** CONFIGUR: *B*‚Get�the�physical�address�of�the�user's�configuration�data�block.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�data�block.ŠSPC„21ŠMOVE.L�XIOUID(A2),A4†A4�<--�base�address�of�DCB. =ŠMOVE.B�#CECCDO,D2ŠIf�he's�trying�to�change�the�write�timeout?ŠBTSTW‚#IOSWTOB,IOSPRM(A1)�value,�return�a�configuration�error. ŠBNE„CNFGERRŠSPC„2DŠMOVE.L�DCBDEV+IOSWTO(A4),IOSWTO(A0)�Update�(in�the�CCB)�the�timeout/ŠBRA.S‚CMNCNFGŒvalues�from�the�DCB,�so�they�can,*£be�copied,�and�do�the�common�configuration *£processing.ŠPAGEM*******************************************************************************‰CHANGE�DEFAULT�CONFIGURATION*6*‰This�command�changes�the�DCB�configuration,�to�which4*‰IOS�will�restore�us�(via�a�CONFIGURE�command)�when/*‰FHS�closes�the�last�allocation�of�the�device.*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M***************************************************************************** CHNGDEF: *H*‚First�get�the�physical�address�of�the�user's�configuration�data�block.*8ŠBSR„CNFGADR2‹Get�the�address�of�the�users�configuration,*£data�block.�This�entry�point�preserves�A0.ŠSPC„27ŠMOVE.L�XIOUID(A2),A0ˆLoad�the�address�of�the�DCB�in�A46ŠMOVE.L�A0,A4Žand�the�address�of�the�DCB�configurationŠADD.L‚#DCBDEV,A0‰block�in�A0. ŠPAGEM*******************************************************************************‰COMMON�CONFIGURATION�ROUTINE*7*‰This�routine�does�the�work�common�to�the�two�commands-*‰CONFIGURE�and�CHANGE�DEFAULT�CONFIGURATION.*7*‰Entry:�A0�=�Address�of�CCB�or�DCB�configuration�block,*�A1�=�Address�of�user's�configuration�block*M***************************************************************************** CMNCNFG:*L*ƒFirst,�both�the�attributes�and�parameters�masks�are�checked�to�see�if�bitsL* corresponding to unsupported attributes or parameters are set. If any such2* bits are set, a configuration error is returned.*7ŠMOVE.W�#CECUAP,D2‹Set�up�for�an�error�exit�in�case�the&*£user�is�trying�to�change�unsupported*£attributes�or�parameters.ŠSPC„29ŠMOVE.W�#NVALATM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSATM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„29ŠMOVE.W�#NVALPRM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSPRM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„2E*‚Next�we�need�to�see�what�his�proposed�configuration�will�look�like.D*‚Plug�into�his�data�block�the�current�values�for�those�attributes�&?*‚parameters�he�doesn'  t�want�to�change.‚The�appropriate�current(*‚configuration�is�at�A0�and�he's�at�A1.*ŠOPT„BRS6ŠMOVE.W�IOSATM(A1),D0†Set�up�the�users�attribute�mask.;ŠAND.W‚D0,IOSATW(A1)†Zero�out�the�attributes�of�his�that�he.ŠNOT.W‚D0‘doesn't�want�to�change,�zero�out�the<ŠAND.W‚IOSATW(A0),D0†attributes�of�mine�that�he�does�want�to:ŠOR.WƒD0,IOSATW(A1)†change,�and�combine�them�in�his�space. @ŠMOVE.W�IOSPRM(A1),D0†Get�mask�of�parameters�he�wants�to�change. 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINE�WIDTH,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.W�IOSREC(A0),IOSREC(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINES/PAGE,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.L�IOSRSZ(A0),IOSRSZ(A1)ŠENDI 3ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�WRITE�TIMEOUT.ŠIF��THENŽvalue,�copy�the�current�setting.ŠMOVE.L�IOSWTO(A0),IOSWTO(A1)ŠENDI 3ŠLSR.W‚#2,D0ŽSkip�over�the�READ�TIMEOUT�bit.�If�the'*£LOGICAL�RECORD�LENGTH�bit�is�not�set,*£copy�the�current�setting. ŠIF��THEN�MOVE.W‚IOSLRL(A0),IOSLRL(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�END-OF-LINE/ŠIF��THENŽSTRING,�copy�the�current�setting.ŒMOVE.B�IOSELC(A0),IOSELC(A1)ŠENDIŠOPT„BRL*I*ƒNow�that�the�users�configuration�block�contains�the�proposed�attributesG* and parameters, they will be checked for validity before copying them* into the DCB or CCB.*8ŠMOVE.B�#CECPNI,D2ŒIf�the�auto-linefeed�attribute�is�set@ŠBTSTW‚#IOALNFD,IOSATW(A1)�and�the�end�of�line�character�is�null,ŠBEQ.S‚CMNC001�return�a�configuration�error.ŠTST.B‚IOSELC(A1)ŠBEQ.S‚CNFGERRŠSPC„2CCMNC001ƒMOVE.B�#CECPRLZ,D2ŠIf�either�the�logical�or�physical�record<ŠMOVE.W�IOSREC(A1),D0†length�is�zero,�return�a�configurationŠBEQ.S‚CNFGERRŒerror.ŠMOVE.W�IOSLRL(A1),D3ŠBEQ.S‚CNFGERRŠSPC„24ŠCMP.W‚D3,D0�If�the�logical�record�length�is�greater5ŠBHS.S‚OKCNFG�than�the�physical�record�length,�return*ŠMOVE.B�#CECPLGP,D2ˆa�configuration�error.ŠSPC„2ACNFGERRƒMOVE.B�#ISTACFG,D1‰Return�a�configuration�error�status�in>ŠMOVE.B�D2,IOSCEC(A1)†the�users�IOS�parameter�block�and�return8ŠBRA.S‚CNFGEXIT‹the�specific�configuration�error�code�in *£the�users�configuration�block.ŠSPC„2F*…Set�the�configuration�flag�byte�in�the�device�DCB�to�indicate�that�aK*‚CONFIGURE�or�CONFIGURE�DEFAULTS�request�was�processed.�FHS�will�check�theM*‚flag�when�it�closes�the�last�assignment�to�the�device�to�see�if�it�needs�toH*‚tell�IOS�to�issue�a�configure�request.�IOS�will�then�issue�a�CONFIGUREJ*‚request�using�the�device�DCB�default�configuration�parameters.�This�willI*‚always�force�the�current�configuration�to�the�default�whenever�the�last*‚assignment�is�closed.*I*…Subroutine�STATYP�is�called�to�store�the�current�device�status,�channelH*‚type,�device�type,�and�driver�code�into�the�users�configuration�block.*ŠMOVE.B�CCBRLEN(A5),IOSLEN(A3)�Update�users�IOCB�length�field.ŠCLR.L‚CCBRLEN(A5)ŠSPC„2=ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;ŠSUB.B‚#1,TCBIOCNT(A0)‡and�decrement�his�pending�I/O�count.ŠSPC„2*!*‚Prepare�the�event�and�queue�it.*8ŠMOVE.B‚#ISTATO,IOSSTA(A3)ƒUpdate�the�IOCB�status�field.,ŠMOVE.W‚#ISTATO,D3‹Set�up�event�status�field-ŠMOVE.B‚#XPSHLT,D1‹Set�up�event�status�value.!ŠMOVE.L‚#6,D0�Set�up�info�length.&ŠMOVE.L‚CCBCID(A5),D2ˆSet�up�event�ID..ŠLEA…CCBPKT(A5),A4ˆSet�up�event�build�pointer.ŠBSR…QEVNT�Queue�event.ŠBRA…CMDEXITŽRETURN ŠPAGEL******************************************************************************C*‰ROUTINE�COMMON�TO�ALL�I/O�COMMANDS�(READ,�WRITE,�OUTPUT�W/�INPUT)**‚Entry:�A3�=�address�of�IOCB*‰A5�=�address�of�CCB**L*****************************************************************************IOSCOMN:?ŠBTSTW‚#IOPTSKB,IOSOPT(A3)�If�the�buffers�reside�in�a�different"ŠBEQ.S‚IOSC005Œtask�from�the�IOCB, 9ŠLEA„IOSTSK(A3),A0†Point�to�the�taskname�&�session�of�the7ŠTR0$.GETTCB‚,Œbuffer�owner�&�call�exec�to�get�address."ŠBRA.S‚OKTCBŽIf�it's�good,�branch.ŠNOP—If�it's�bad,6ŠMOVE.B�#XSTADB,D1‰set�status�in�IOCB�to�address�errorŠTST.L‚(A7)+Žadjust�stackŠBRA.S‚NRMEXITŒand�exit�to�CMR. :OKTCB…MOVE.L�A0,CCBTASKB(A5)„Save�physical�address�of�TCB. *<*‚Validate�the�info�in�the�IOCB�about�the�primary�buffer�and *‚convert�to�physical�addresses.*BIOSC005ƒMOVE.L�IOSSAD(A3),D6†D6�<--�buffer�physical�start�address.+ŠMOVE.L�IOSEAD(A3),D5†D5�<--�buffer�length.ŠSUB.L‚D6,D5Ž* ŠADDQƒ#1,D5Ž*ŠSPC„25ŠMOVE.L�D5,-(A7)‹Save�the�buffer�length�on�the�stack.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.$ŠBRA.S‚IOSC010ŒIf�it's�good,�branch.9ŠADDQ.L�#8,A7ŽIf�it's�a�bad�base�address,�remove�saved�D5&*£and�adjust�the�stack�return�address.ŠSPC„24ŠMOVE.B�#ISTAADD,D1ˆSet�IOCB�status�to�ADDRESS�ERROR6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status. @IOSC010ƒMOVE.L�D6,CCBPTR(A5)†Save�physical�start�address�in�CCB.2ŠADD.L‚(A7)+,D6‹Save�the�physical�end�address�plus&ŠMOVE.L�D6,CCBEAP1(A5)…one�in�the�CCB.ŠRTSŠPAGEK****************************************************************************=*‰VALIDATE�CONFIGURATION�BUFFER�ADDRESS�&�CONVERT�TO�PHYSICAL*$*‰Entry:�D5�=�buffer�length�in�bytes-*�D6�=�buffer�logical�start�addr�(to�convert)*�A3�=�address�of�IOCB*�A5�=�address�of�CCB***‰Exit:‚D6ƒ=�buffer�physical�start�address*�D5ƒ=�buffer�length*K****************************************************************************CCNFGADRƒLEA.L‚CCBCFIG(A5),A0…This�entry�point�loads�the�CCB�config.*£data�block�into�A0.ŠSPC„2.CNFGADR2‚MOVE.L�A0,-(A7)‹Save�A0�on�the�stack.?ŠMOVE.L�IOSDBP(A3),D6†D6�<--�logical�addr�of�user's�data�block./ŠMOVE.L�#IOSPLN,D5‰D5�<--�length�of�data�block.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHAD! RCK‹Check�the�address.%ŠBRA.S‚CNFGADR3‹If�it's�good,�branch.ŠSPC„27ŠADD.L‚#8,A7ŽIf�the�address�or�length�is�bad,�clean�the<ŠMOVE.B�#ISTAADD,D1ˆstack,�set�IOCB�status�to�ADDRESS�ERROR,6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status.ŠSPC„2=CNFGADR3‚MOVE.L�D6,A1ŽStore�the�physical�address�of�the�users9ŠMOVE.L�(A7)+,A0‹data�block�in�A1,�restore�A0�and�return.ŠRTSŠPAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D1�=�IOS�error�code*I**************************************************************************NRMEXIT:*‰LEA‡CCBPKT(A5),A4‡Set�up�queue�work�area.!‰MOVE.L„#6,D0�Set�up�packet�size.#‰MOVE.L„XIOUID(A2),D2‡Set�up�PB�id.#‰AND.W…#$FF,D1�Mask�for�word�value."‰MOVE.W„D1,D3�Set�up�status�value./‰MOVE.B„D1,IOSSTA(A3)‡Update�IOCB�status�field.%‰MOVE.B„#XPSNRM,D1ŠSet�up�event�type.‰BSR‡QEVNT�Go�queue�event.CMDEXIT‚CLR.L…D0*8* User request side of IOH always exits from this point.*IOHUSRTN‚EQU„*ŠRTS—RETURN�TO�MAINLINEŠPAGEK****************************************************************************B*ƒSubroutine�to�check�address�boundaries�to�see�if�entirely�within* calling tasks address space.*&*‚Entry:�D5�-‚number�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‚IOHADR6�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.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.ŠPAGEL******************************************************************************‚PRTOUT*%*ˆThis�is�the�printer�output�routine.***ˆENTRY:‚A0�=�address�of�buffer*�A1�=�address�of�device�base*�A3�=�address�of�IOCB*�A4�=�address�of�DCB*�A5�=�address�of�CCB*.* PRTOUT1 ENTRY: D0.B = character to be output*—other�registers�as�above*M******************************************************************************CPRTIMG„ADD.L‚#1,CCBRLEN(A5)†For�image�mode,�count�each�byte�sent�to>ŠCMP.L‚CCBEAP1(A5),A0„the�printer�whether�printable�or�not.�If6ŠBEQ.S‚PRT070Œthe�end�of�the�buffer�is�reached,�do�the *¢request�completion�processing.ŠSPC„2PRTOUT:0ŠMOVE.B‚(A0)+,D0ŽGet�next�data�byte�from�buffer.,ŠMOVE.L‚A0,CCBPTR(A5)‰Update�buffer�pointer.ŠSPC…2;ŠBTSTWƒ#IOPFORB,CCBCOPT(A5)„For�image�mode�output,�skip�the,ŠBNE.SƒPRTOUT1�special�character�processing.ŠSPC…20ŠCMP.B‚#CR,D0“If�the�current�buffer�character�is,ŠBEQ.S‚PRT030‘a�CR,�proceed�with�end-of-line *§processing.ŠSPC…2+PRTOUT1ƒBSR.LƒDEVOUTS�Output�the�data�byte.ŠSPC„2EPRT010„BTSTWƒ#IOPFORB,CCBCOPT(A5)„If�the�output�is�bring�performed�in1ŠBNE.SƒPRTIMG�image�mode,�transfer�control�to�the%*§top�of�the�output�loop�to�check�for*§end�of�buffer.ŠSPC…25ŠCMP.Bƒ#'�',-1(A0)�If�the�curren" t�buffer�character�is,ŠBLT.SƒPRT017�non-printing,�do�not�check�for(*¦end-of-line�or�increment�the�character*¦countŠSPC…25ŠADD.L‚#1,CCBRLEN(A5)‹Increment�the�printed�character*§count.ŠSPC…29ŠMOVE.L�CCBRLEN(A5),D2‹Divide�the�printed�character�countAŠDIVUƒCCBCFIG+IOSLRL(A5),D2‚by�the�logical�line�length.�Store�the+ŠSWAP„D2”remainder�in�the�lower�half�of�D2.ŠSPC…2*ŠTST.W‚D2—If�an�exact�logical�and�physical4ŠBNE.S‚PRT017‘end-of-line�has�been�reached,�output�a@ŠCMP.W‚CCBCFIG+IOSREC(A5),D3‚linefeed�for�non-auto-LF�device.�If3ŠBEQ.S‚PRT013‘only�the�logical�line�length�has�been3ŠBSR.S‚PRTEOL‘reached,�output�a�logical�end-of-line2ŠBRA.S‚PRT015‘sequence.�If�neither�length�has�been&*§reached�proceed�to�the�end-of-buffer*§check.ŠSPC„2GPRT013„BTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�the�device�does�not�support0ŠBNE.SƒPRT015�auto�line�feed,�output�a�line�feed5ŠMOVE.B�#LF,D0‘if�the�byte�count�is�an�exact�multiple"ŠBSR.SƒDEVOUTS�of�the�line�length.ŠSPC…2FPRT015„BTSTW‚#IOATPLL,CCBCFIG+IOSATW(A5)�Since�an�end-of-line�has�been/ŠBNE.SƒPRT070“reached,�terminate�the�request�if!*ªthe�truncate�print�attribute�is*ªset.ŠSPC„2=PRT017„CMP.LƒCCBEAP1(A5),A0ŠIf�the�end�of�buffer�has�not�been/ŠBLT…PRTOUT�reached,�output�the�next�character.ŠSPC…2:PRT030„BSR.SƒPRTEOL‘Output�a�logical�end-of-line�sequence.ŠPAGEPRT070:*2*‚Finished�transfer,�now�queue�event�to�requestor.*+ŠBCLRW‚#CCBFGBSY,CCBFG(A5)ƒClear�busy�flag.,ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�TCB�address.3ŠSUB.B‚#1,TCBIOCNT(A0)‡Decrement�I/O�pending�count. -ŠMOVE.W�#ISTAOK,D3ŒSet�up�ok�IOS�status�code..ŠAND.B‚#3,D0‘Mask�fault�bits�of�device�status.ŠCMP.B‚#1,D0‘Any�faults�?"ŠBEQ.S‚PRT080�Branch�if�no�faults.1ŠMOVE.W�#ISTANR,D3ŒFault,�set�up�IOS�status�code.-PRT080„MOVE.L�#6,D0‘Set�up�event�info�length.*ŠMOVE.B�#XPSNRM,D1ŒSet�up�event�type�code.)ŠMOVE.L�CCBCID(A5),D2‰Set�up�DCB�address./ŠMOVE.B�D3,IOSSTA(A3)‰Update�IOCB�status�field.8ŠMOVE.L�CCBRLEN(A5),IOSLEN(A3)‚Update�IOCB�length�field. *ŠLEA„CCBPKT(A5),A4‰Set�up�event�data�area./ŠBSR„QEVNT‘Queue�completion�event�to�requestor. ŠRTSŠPAGE*E*‹This�subroutine�outputs�either�a�LF-CR�sequence�or�an�EOL�character6*‰based�on�the�setting�of�the�auto-linefeed�attribute.*#PRTEOL„MOVE.B�CCBCFIG+IOSELC(A5),D0?ŠBTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�not�an�exact�end-of-line,4ŠBNE.SƒDEVOUTS�output�the�EOL�character�if�the�auto-(*§linefeed�attribute�is�set.�Else�output*§a�LF�and�CR.ŠSPC…2/ŠMOVE.B‚#LF,D0’Call�DEVOUT�to�output�a�linefeed.ŠBSR.SƒDEVOUT�character.�If�an�error�status�is1ŠTST.BƒD3”returned�in�D3,�transfer�control�to�theŠBNE.SƒDEVOUTE�error�exit.ŠSPC„26ŠMOVE.B‚#CR,D0�Set�up�carriage�return�character�in�D0.ŠSPC„2*E*‹This�routine�is�called�as�a�subroutine�from�PRTOUT�to�output�singleF*‰characters�from�D0�with�automatic�request�termination�if�an�error�isD*‰detected�in�the�DEVOUT�subroutine.�Execution�also�falls�through�to*‰here�from�PRTEOL.*8DEVOUTSƒBSR.S‚DEVOUT�Call�DEVOUT�to�output�the�character5ŠTST.B‚D3‘in�D0.�If�the�status�returned�in�D3�is�non-'ŠBEQ.S‚DEVOUTOK‹zero,�do�an�error�exit.ŠSPC„2:DEVOUTEƒTST.L‚(A7)+�If�an�error�occurs�transfer�control�to-ŠPEA.L‚PRT070�the�request�completion�routine.ŠSPC„2+DEVOUTOK‚RTS™Return�to�the�calling�routine.ŠPAGEO*********************************************************************************‚DEVOUT(*�****MODIFIED�1/27/83�BY�M.�BRIEL*******<*†1.Check�for�a�device�fault�(not-selected�or�out�of�paper).=*ˆIf�a�fault�is�present,�terminate�the�request�with�an�error.*F*†2.�If�an�Printer�Acknowledge�is�expected,�wait�for�the�ACK�pulse�for@*‰approx.�100�us.�If�the�pulse�does�not�arrive�in�100�us,�enable0*‰the�Acknowledge�interrupt�and�exit�the�driver.*4*†3.�Output�the�next�character�and�pulse�Data�Strobe**ˆENTRY:„D0‚=�data�byte*’A1‚=�device�base�address*‘(SP)�=�return�address*�4(SP)�=�PRTOUT�return�address*�DEVICE�=�Interrupts�disabled*,*ˆEXIT:…D0‚=�Dev" ice�status�register�contents*�NORMAL�=�(SP)�return*�FAULT�=�(SP)+2�return5*‘BUSY�=�4(SP)�PRTOUT�return�address�(device�enabled)*K****************************************************************************DEVOUT:.‰CLR.BƒD3“Clear�D3�in�preparation�for�a�normal *£return.‰SPC…2 ‰CLR.LƒD1.‰MOVE.B‚DEV1BD(A1),D1‰Pick�up�status�register. ‰MOVE.L‚D1,D2‘Make�another�copy.&‰AND.Bƒ#$03,D1�Mask�uninterested�bits.-‰CMP.Bƒ#$01,D1�Selected�and�not�Out-of-Paper?‰BNE.SƒDEV010�Fault�exit�if�no.‰SPC…2:ŠTST.B‚CCBACKP(A5)ŠIf�a�printer�acknowledge�is�not�pending,ŠBEQ.S‚DEV020�proceed�with�character�output.ŠSPC„2:ŠMOVE.W�#32,D1�Repeatedly�test�for�the�printer�acknowledgeDDEVACK„BTST.B�#7,DEV1AC(A1)†pulse.�If�the�acknowledge�arrives�before;ŠDBNEƒD1,DEVACKŠthe�loop�times�out�(approx.�100�us)�proceed**£with�character�output.�Otherwise,�enable**£the�Acknowledge�pulse�interrupt�and�exit *£the�driver.ŠSPC„2 ŠBNE.S‚DEV020 * Enable Interrupts and Exit. :‰MOVE.B‚D0,CCBSAVB(A5)ˆThe�device�is�busy,�save�data�byte..‰MOVE.L‚(A7)+,CCBIRTN(A5)…Save�return�address.-‰SUB.Lƒ#2,CCBIRTN(A5)ˆAdjust�service�address.‰SPC…2A‰MOVE.L‚(A7)+,CCBISTK(A5)…Save�subroutine�return�address�into�CCB‰SPC…2‰INHIB™Disable�interrupts.3‰BSET„#0,DEV1BC(A1)‰Enable�device�fault�interrupts.1‰BSET„#0,DEV1AC(A1)‰Enable�device�ACK�interrupts. ‰RTS›Return. * Fault Exit +DEV010ƒMOVE.L‚D2,D0‘Set�up�status�register.1‰BSR…DEVINIT1ŽReprogram�device�for�no�interrupts.ŠSPC„2°1/17/84�MLB*:ŠCLR.B‚CCBACKP(A5)ˆClear�pending�printer�acknowledge�flag.=ŠTST.B‚DEV1AD(A1)‰Clear�Acknowledge�interrupt�IRQ�flag�in�PIAŠSPC„2°1/17/84�MLB*+‰ST†D3”Set�D3�non-zero�to�indicate�an�error$‰BRA.SƒDEVOEX�and�prepare�to�return. (*�Output�the�next�character�1/17/84�MLB* @DEV020ƒTST.BƒDEV1AD(A1)ŒClear�PIA�Acknowledge�interrupt�IRQ�flagŠSPC„2˜1/17/84�MLB*'‰MOVE.B‚D0,DEV1AD(A1)‰Output�data�byte. 1* data strobe (this technique for RTTLIO support) ‰BCLR„#3,DEV1AC(A1))‰BSET„#3,DEV1AC(A1)‰Strobe�the�data�byte.‰SPC…2—1/17/84�MLB*8‰ST†CCBACKP(A5)‹Set�the�printer�acknowledge�pending�flag‰SPC…2—1/17/84�MLB*0‰MOVE.B‚DEV1BD(A1),D0‰Get�status�register�again.‰SPC…20DEVOEXƒENABL™Enable�interrupts�and�return�to�the‰RTS™calling�routine.‰PAGEJ***************************************************************************!* INTERRUPT SIDE FOR PRT 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**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P****ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT*F*---------------------------------------------------------------------*4* If channel is off-line or not attached, just exit.*PRTISR:.ŠMOVE.L�CCBCHB(A5),A1‰Get�device�base�address. 5ŠMOVE.B�DEV1AC(A1),D0‰Pick�up�A-side�status�register.#ŠAND.B‚#$81,D0�Mask�interrupt�bits."ŠCMP.B‚#$81,D0�Interrupt�pending�?ŠBEQ.S‚PRTI010�Branch�if�yes.5ŠMOVE.B�DEV1BC(A1),D0‰Pick�up�B-side�status�register.#ŠAND.B‚#$81,D0�Mask�interrupt�bits."ŠCMP.B‚#$81,D0�Interrupt�pending�?ŠBEQ.S‚PRTI010�Branch�if�yes. 2ŠAND.W‚#$FFFE,SR�No�interrupt�so�set�condition�and ŠRTSšreturn. -PRTI010ƒBTSTW‚#CCBFGOFF,CCBSTR(A5)‚Off-line�?ŠBNE.S‚PRTI020�Branch�if�yes.5ŠBTSTW‚#CCBFGATH,CCBSTR(A5)‚Is�the�channel�attached�?ŠBEQ.S‚PRTI020�Branch�if�no.(ŠBTSTW‚#CCBFGBSY,CCBFG(A5)ƒI/O�pending�?ŠBNE.S‚PRTI100�Branch�if�yes. 8PRTI020ƒMOVE.L�CCBCHB(A5),A1‰Set�up�device�base�address.(ŠBSR„DEVINIT1ŽDisable�device�interrupts. ŠENABL!ŠOR.Wƒ#$0001,SR�Set�condition�and ŠRTSšreturn.ŠPAGEN******************************************************************************** INTE# RRUPT LEVEL PROCESSING*0*ˆIt�has�been�determined�that�I/O�is�in�progress*ˆand�the�interrupt�is�ours.**N*******************************************************************************PRTI100:=ŠMOVEM.L�D1-D7/A2-A4/A6,-(A7)�Save�the�rest�of�the�registers.1ŠBSR…DEVINIT1�Reprogram�device�for�no�interrupts.ŠSPC„2–1/17/84�MLB*>ŠCLR.B‚CCBACKP(A5)ˆClear�the�printer�acknowledge�pending�flag.;ŠTST.B‚DEV1AD(A1)‰Clear�PIA�Acknowledge�interrupt�IRQ�flag.ŠSPC„2–1/17/84�MLB*-ŠMOVE.L‚CCBPTR(A5),A0ˆRestore�buffer�pointer.1ŠMOVE.B‚CCBSAVB(A5),D0‡Restore�current�data�byte.5ŠMOVE.L‚CCBIRTN(A5),A2‡Get�interrupt�service�address.'ŠMOVE.L‚CCBCCB(A5),A3ˆGet�IOCB�address.&ŠMOVE.L‚CCBCID(A5),A4ˆGet�DCB�address.8ŠADD.Bƒ#1,CCBICNT(A5)‡Increment�pending�interrupt�count.:ŠPEA…PRTINRTN(PC)‰Stack�the�interrupt�routine�exit�address>ŠMOVE.L‚CCBISTK(A5),-(A7)„Restore�subroutine�return�address�on*¦stack.!ŠJMP…(A2)‘Jump�to�output�routine. *.* PRT interrupt handler exits from this point.* PRTINRTN:7ŠSUB.Bƒ#1,CCBICNT(A5)‡Decrement�pending�interrupt�count0ŠMOVEM.L�(A7)+,D1-D7/A2-A4/A6�Restore�registers./***‡ENABL˜Let�CMR�enable�interrupts�later,�this%***¤fix�is�for�EPSON�RX80�(SPR�1178).(ŠOR.Wƒ#$0001,SR�Set�return�condition�and!ŠRTSšreturn�to�interrupt�handler.ŠPAGEJ**************************************************************************** QEVNT**„Place�message�on�user's�ASQ.**ˆA4�=�address�of�event�area*ˆA5�=�address�of�CCB'*ˆD0�=�event�length�(minus�header�info)*ˆD1�=�event�type*ˆD2�=�4�byte�id�(DCB)*ˆD3�=�status�value�(2�bytes)*ˆD4�=�device�status�(2�bytes)*ˆD5�=�device�number�(1�byte)*J***************************************************************************QEVNT:ŠMOVE.L�D0,D6ŽSave�length.5ŠMOVE.L�#2,D7ŽOffset�for�staging�(no�service�vector)./ŠMOVE.B�#IOEVCD,1(A4)†Code�(no�service�vector).)ŠMOVE.L�CCBSVVC(A5),2(A4)‚Service�vector.+ŠBEQ.S‚QEVNT10ŒBranch�if�no�service�vector./ŠADD.L‚#4,D0ŽCorrect�length�for�service�vector.7ŠADD.L‚#4,D7ŽCorrect�offset�staging�for�service�vector.2ŠADD.L‚#$00800000,(A4)„Correct�for�service�vector. 1QEVNT10ƒMOVE.B�D1,0(A4,D7)ˆCompletion�event�type.*ŠMOVE.B�CCBKEY(A5),1(A4,D7)�User's�id�key.-ŠADD.L‚#4,D0ŽComplete�length�of�return�event.6ŠCMP.B‚CCBASQL(A5),D0…User's�maximum�ASQ�entry�length.#ŠBLS.S‚QEVNT20ŒBranch�if�length�ok.0ŠMOVE.B�CCBASQL(A5),D0…User's�length�is�smaller. &QEVNT20ƒMOVE.B�D0,(A4)ŒCorrect�length. /QEVNT40ƒMOVE.L�D2,2(A4,D7)ˆSet�up�status�value.$ŠMOVE.W�D3,6(A4,D7)ˆSet�up�id�(DCB).ŠCMP.B‚#6,D6Ž6�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.)ŠMOVE.W�D4,8(A4,D7)ˆSet�up�device�status.ŠCMP.B‚#8,D6Ž8�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.*ŠMOVE.B�D5,10(A4,D7)‡Set�up�device�number.&ŠCLR.B‚11(A4,D7)ŠClear�reserved�field.*I* Now let's put the completion into registers and send event to the task.* QEVNT50ƒEQU„*ŠMOVEM.L�(A4),D2-D7ŠBSR.S‚IOHQEVNTŠRTSŠ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**************************************************************************** IOHQEVNT:$ŠMOVEM.L�A3-A5,-(A7)‡Ssve�registers.-ŠMOVE.L�CCBRQSTA(A5),A0„Caller's�TCB�address.ŠSPC„26ŠMOVE.L�#T0QEVNTI,D0‰If�this�routine�was�called�during6ŠTST.B‚CCBICNT(A5)ˆinterrupt�processing,�use�the�QEVNT3ŠBNE.S‚IOHQ4Žinterrupt�routine,�else�use�the�normal#ŠMOVE.L�#T0QEVNTT,D0‡QEVNT�routine. IOHQ4…TRAPƒ#0#ŠBRA.S‚IOHQ5ŽBranch�if�queueing�ok.'ŠMOVEM.L�(A7)+,A3-A5‡Restore�registers.9ŠMOVE.L�(A7),CCBQVER1(A5)‚Save�callers�address�for�debug.ŠBRA.S‚IOHQRTN ,IOHQ5…MOVEM.L�(A7)+,A3-A5‡Restore�registers..ŠCLR.L‚CCBQVER1(A5)‡Clear�queue�error�address. IOHQRTNƒRTS—RETURNŠEND# éééé=/*=/*†PV01DRV.AF=/*@=/* Chain file to assemble the printer driver for the VM01 board=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to PV01DRV.LS=/*=/IFC \1ƒ=ARG�PV01DRV.LS=/ENDIF=/*%=ASM PV01DRV.SA,PV01DRV.RO,\1;MRZ=146=/*{ Included files are:=/*ƒ9995.&.TRACE.EQ=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ=/*ƒ9995.&.LV5.EQ=/*}=/*=ENDéééééélŠPAGEKPV01DRVƒIDNTƒ4,4�VERSAdos�Local�Printer�I/O�Handler�Process�V4.4�-�09/04/848ŠTTL„VERSADOS�VM01�LOCAL�PRINTER�PROCESS�V4.4�-�09/04/84 ŠLLENƒ120ŠNOLISTŠINCLUDE�9995.&.TRACE.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.TCB.EQŠINCLUDE�9995.&.CCB.EQŠINCLUDE�9995.&.IOE.EQŠINCLUDE�9995.&.NIO.EQŠINCLUDE�9995.&.LV5.EQŠLIST ŠNOFORMATJ****************************************************************************1* PRT -- REV. 1.00 02NOV81 (TL09) JIM SMITH - IOH9*ˆREV.�1.01�01FEB82�(TL09)�JIM�SMITH�-�VECTOR�CHAIN�(IOH)5*ˆREV.�1.02�23FEB82�(TL09)�JIM�SMITH�-�IOCB�USE�(IOH)5*ˆREV.�2.00�15APR82�(TL09)�JIM�SMITH�-�PRINTER�DRIVER5*ˆREV.�2.01�01JUN82�(TL09)�MARC�BRIEL-�PRINTER�DRIVER5*ˆREV.�2.10�15JUL82�(TL09)�MARC�BRIEL-�PRINTER$ �DRIVER-*ˆREV‚2.20�18JAN84ˆMARC�BRIEL-�PRINTER�DRIVER.*ˆREV‚3.00�04SEP84ˆMIKE�DUH‚-�ADAPTED�FOR�VM01;*ˆREV‚3.01�17DEC84ˆMIKE�DUH‚-�Removed�ENABL�at�PRTINRTN�for *­SPR�1178�(Epson�RX80�printer).*«-�Fixed�HALT�routine.8*ˆREV‚3.02�8MAR85‰DICK�V.ƒ-�HALT�ROUTINE�REGISTER�CHANGEééé u~.†CŽC–@žJ¦>®>¶C¾7Æ0Î7Ö?Þ<æSî2ö;þ93C:@*$*ƒPURPOSE:‚VM01�LOCAL�PRINTER�DRIVER*/*ƒENTRY:‚JSR�FROM�CMR�HANDLER�(COMMAND�SERVICE) *‹JSR�FROM�CMR�INTERRUPT�HANDLER*-*ƒEXIT:�-�ALWAYS�EXITS�WITH�A�RTS�INSTRUCTION***ƒCODE�IS�RE-ENTRANT**H*-----------------------------------------------------------------------**‚INCLUDED�FILES:**‰INCLUDE�9995.&.TRACE.EQ*‰INCLUDE�9995.&.STR.EQ*‰INCLUDE�9995.&.TCB.EQ*‰INCLUDE�9995.&.CCB.EQ*‰INCLUDE�9995.&.IOE.EQ*‰INCLUDE�9995.&.NIO.EQ*‰INCLUDE�9995.&.LV5.EQ*PRTORG:ŠPAGE(****************************************(* EQUATES FOR SPECIAL ASCII CHARACTERS *(*****************************************NUL†EQU‡$00‘NullBEL†EQU‡$07‘BellBS‡EQU‡$08‘BackspaceLF‡EQU‡$0A‘Line�feedFF‡EQU‡$0C‘Form�feedCR‡EQU‡$0D‘Carriage�returnSPACE„EQU‡$20‘Blank ******************* DEVICE EQUATES ********************DEV1ADƒEQU‡1“Printer�data�buss./DEV1BDƒEQU‡0“Printer�status�(paper�out,�select)0DEV1ACƒEQU‡5“READ‚bit�7�=�ACKNOWLEDGE�interrupt.#*¦WRITE�bit�3�=�DATA�STROBE�output.éééH* note: ACKNOWLEDGE interrupt flag (bit 7) is cleared by reading DEV1AD.*DEV1BCƒEQU‡4“READ‚bit�7�=�FAULT�interrupt.#*¦WRITE�bit�3�=�INPUT�PRIME�output.B* note: FAULT interrupt flag (bit 7) is cleared by reading DEV1BD. ************************** MISCELLANEOUS EQUATES ***************************IOEVCD„EQU„1’I/O�event�codeDVALATM„EQU„1<ŠMOVE.L�XIOCPK(A2),D6†Set�up�address�of�command�packet�(IOCB).6ŠMOVE.W�XIOPLN(A2),D5†Set�up�length�of�command�packet.+ŠMOVE.L�CCBTASKA(A5),A1„Set�up�TCB�pointer.&ŠBSR„IOHADRCK‹Call�conversion�routine.ŠBRA.S‚PRTU010ŒGood�return.)ŠMOVE.B�#ISTAIP,D1‰Set�up�IOS�error�code.ŠBRA„NRMEXITŒExit.=PRTU010ƒMOVE.L�D6,A3ŽSave�physical�address�of�command�packet.**‚Check�for�HALT�command.*(ŠCMP.Wƒ#IOHALT,IOSFCT(A3)…HALT�command�?!ŠBEQ…HALT“Branch�if�HALT�command.** See if channel is busy.*)ŠBTSTW‚#CCBFGBSY,CCBFG(A5)‚Channel�busy�?ŠBEQ.S‚PRTU020ŽBranch�if�no.6ŠMOVE.B�#XSTBSY,D0‹Busy,�set�up�channel�error�code�andŠBRA„IOHUSRTN�Return.ŠPAGE*K****************************************************************************(*‚Find�the�command�in�the�command�table.*** PRTU020:8ŠMOVE.W�IOSOPT(A3),CCBCOPT(A5)�Save�IOCB�options�in�CCB.6ŠMOVE.L�XIOUID(A2),CCBCID(A5)‚Save�DCB�pointer�in�CCB.(ŠMOVE.L�A3,CCBCCB(A5)†Save�IOCB�pointer.*ŠMOVE.L�XIOUID(A2),A4†Pick�up�DCB�pointer.9ŠMOVE.L�CCBTASKA(A5),CCBTASKB(A5)‚Set�up�buffer�task�TCB. -ŠMOVEQ‚#NUMCMDS-1,D0†Set�up�the�loop�counter./ŠLEA„CMDTBL,A0ŠA0�<--�address�of�command�table./ŠMOVE.W�IOSFCT(A3),D6†Set�up�user�command�code. 8CMDSRCHƒCMP.W‚(A0)+,D6‹Search�the�table�for�the�command.ŠDBEQƒD0,CMDSRCH‰* 3ŠB% NE.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.B�#ISTAIF,D1‰We�didn't�find�it,�so�exit�with�error. ŠBRA„NRMEXITŠPAGEL******************************************************************************‰WRITE**,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB%*‰A6�=�address�of�attached�task's�TCB***L*****************************************************************************WRITE:5‰BSR‡IOSCOMN�Do�the�stuff�common�to�all�I/O�commands. -‰BSETW…#CCBFGBSY,CCBFG(A5)�Mark�channel�busy.6‰CLR.L…CCBRLEN(A5)‰Initialize�the�output�byte�counter.1‰MOVE.L„CCBCHB(A5),A1‡Set�up�device�base�address. ‰BSR‡DEVINIT1ŒSet�up�the�device.‰SPC‡2=‰MOVE.L„CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;‰ADD.B…#1,TCBIOCNT(A0)…and�increment�his�pending�I/O�count.‰SPC‡2,‰MOVE.L„CCBPTR(A5),A0‡Set�up�buffer�pointer.‰SPC‡2@‰BTSTW…#IOASNFF,CCBCFIG+IOSATW(A5)�If�the�form�feed�after�assign4‰BNE.S…WRIT010�attribute�is�0�send�a�FF�character�if)*¦this�is�the�first�output�in�the�current *¦assignment.‰SPC‡20‰TST.B…DCBBCT(A4)ŠDo�we�need�to�do�a�form�feed�?‰BNE.S…WRIT010�Branch�if�no."‰STˆDCBBCT(A4)ŠSet�form�feed�flag.(‰MOVE.B„#FF,D0ŽYes,�set�up�FF�character.!‰BSR‡PRTOUT1�Go�output�to�device.‰BRA.S…WRIT020�Return. 'WRIT010‚BSR‡PRTOUTŽStart�buffer�output. !WRIT020‚UNMASK˜Enable�interrupts.‰BRA‡CMDEXIT�GO�FINISH�UP‰PAGEM*******************************************************************************‰REQUEST�STATUS*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M******************************************************************************REQSTAT: *E*‚Get�the�address�of�his�data�block�and�move�our�configuration�there.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�block.ŠSPC„24ŠBSR.S‚STATYP�Setup�the�device�status,�channel�type,&*£device�type,�and�driver�codes�in�the*£user's�configure�block.ŠSPC„2>ŠMOVE.W�#VALATM,IOSATM(A0)„Return�the�supported�attributes�andBŠMOVE.W�#VALPRM,IOSPRM(A0)‚parameters�masks�in�the�users�configure*¤block.ŠSPC„2BŠMOVE.L�#(IOSPLN/2)-1,D0ƒD0�<--�loop�control�to�move�entire�block.'REQLOOPƒMOVE.W�(A0)+,(A1)+ˆMove�a�word.5ŠDBRAƒD0,REQLOOP‰Keep�moving�until�whole�block�moved. 'ŠMOVE.B�#ISTAOK,D1‰Exit�with�OK�status.ŠBRA„NRMEXITŒ*ŠSPC„2*A*„This�subroutine�stores�the�current�device�status(always�ready),E*‚channel�type,�device�type,�and�driver�code�into�the�users�configureL*‚block.�Note�that�these�values�are�returned�only�on�RETRIEVE�DEVICE�STATUS/K*‚CONFIGURATION,CONFIGURE�DEVICE,�and�CHANGE�DEFAULT�CONFIGURATION�requests/*‚only�when�no�configurtion�error�was�detected.*5STATYP„CLR.B‚IOSDST(A0)ŽReturn�on-line�device�status.AŠMOVE.B�CCBTYPE(A5),IOSCTP(A0)‚Return�the�channel�type�defined�in *¨the�CCB.2ŠMOVE.B�#XDSPRT,IOSDTP(A0)†Device�type�is�PRINTER.?ŠMOVE.B�#IODLPRT,IOSDRC(A0)…This�is�a�local�Centronics�printer.ŠRTSŠPAGEM****************************************************************************** *‰CONFIGURE*@*‰This�command�changes�the�CCB�configuration,�the�one�from�which<*‰the�driver�sets�up�the�device�and�under�which�it�performs.*,*‰Entry:�A2�=�address�of�CMR�parameter�block*�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M****************************************************************************** CONFIGUR: *B*‚Get�the�physical�address�of�the�user's�configuration�data�block.*2ŠBSR„CNFGADRŒGet�the�physical�address�of�the�users*£configuration�data�block.ŠSPC„21ŠMOVE.L�XIOUID(A2),A4†A4�<--�base�address�of�DCB. =ŠMOVE.B�#CECCDO,D2ŠIf�he's�trying�to�change�the�write�timeout?ŠBTSTW‚#IOSWTOB,IOSPRM(A1)�value,�return�a�configuration�error. ŠBNE& „CNFGERRŠSPC„2DŠMOVE.L�DCBDEV+IOSWTO(A4),IOSWTO(A0)�Update�(in�the�CCB)�the�timeout/ŠBRA.S‚CMNCNFGŒvalues�from�the�DCB,�so�they�can,*£be�copied,�and�do�the�common�configuration *£processing.ŠPAGEM*******************************************************************************‰CHANGE�DEFAULT�CONFIGURATION*6*‰This�command�changes�the�DCB�configuration,�to�which4*‰IOS�will�restore�us�(via�a�CONFIGURE�command)�when/*‰FHS�closes�the�last�allocation�of�the�device.*$*‰Entry:�A3�=�address�of�user's�IOCB*�A5�=�address�of�my�CCB**‰Exits�to�NRMEXIT*M***************************************************************************** CHNGDEF: *H*‚First�get�the�physical�address�of�the�user's�configuration�data�block.*8ŠBSR„CNFGADR2‹Get�the�address�of�the�users�configuration,*£data�block.�This�entry�point�preserves�A0.ŠSPC„27ŠMOVE.L�XIOUID(A2),A0ˆLoad�the�address�of�the�DCB�in�A46ŠMOVE.L�A0,A4Žand�the�address�of�the�DCB�configurationŠADD.L‚#DCBDEV,A0‰block�in�A0. ŠPAGEM*******************************************************************************‰COMMON�CONFIGURATION�ROUTINE*7*‰This�routine�does�the�work�common�to�the�two�commands-*‰CONFIGURE�and�CHANGE�DEFAULT�CONFIGURATION.*7*‰Entry:�A0�=�Address�of�CCB�or�DCB�configuration�block,*�A1�=�Address�of�user's�configuration�block*M***************************************************************************** CMNCNFG:*L*ƒFirst,�both�the�attributes�and�parameters�masks�are�checked�to�see�if�bitsL* corresponding to unsupported attributes or parameters are set. If any such2* bits are set, a configuration error is returned.*7ŠMOVE.W�#CECUAP,D2‹Set�up�for�an�error�exit�in�case�the&*£user�is�trying�to�change�unsupported*£attributes�or�parameters.ŠSPC„29ŠMOVE.W�#NVALATM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSATM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„29ŠMOVE.W�#NVALPRM,D0ŠZero�the�bits�of�the�users�attributes<ŠAND.W‚IOSPRM(A1),D0†mask�that�correspond�to�supported�para-5ŠBNE.S‚CNFGERRŒmeters.�If�any�remaining�bits�are�set,*£return�an�error.ŠSPC„2E*‚Next�we�need�to�see�what�his�proposed�configuration�will�look�like.D*‚Plug�into�his�data�block�the�current�values�for�those�attributes�&?*‚parameters�he�doesn't�want�to�change.‚The�appropriate�current(*‚configuration�is�at�A0�and�he's�at�A1.*ŠOPT„BRS6ŠMOVE.W�IOSATM(A1),D0†Set�up�the�users�attribute�mask.;ŠAND.W‚D0,IOSATW(A1)†Zero�out�the�attributes�of�his�that�he.ŠNOT.W‚D0‘doesn't�want�to�change,�zero�out�the<ŠAND.W‚IOSATW(A0),D0†attributes�of�mine�that�he�does�want�to:ŠOR.WƒD0,IOSATW(A1)†change,�and�combine�them�in�his�space. @ŠMOVE.W�IOSPRM(A1),D0†Get�mask�of�parameters�he�wants�to�change. 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINE�WIDTH,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.W�IOSREC(A0),IOSREC(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINES/PAGE,'ŠIF��THEN�copy�the�current�setting.ŠMOVE.L�IOSRSZ(A0),IOSRSZ(A1)ŠENDI 3ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�WRITE�TIMEOUT.ŠIF��THENŽvalue,�copy�the�current�setting.ŠMOVE.L�IOSWTO(A0),IOSWTO(A1)ŠENDI 3ŠLSR.W‚#2,D0ŽSkip�over�the�READ�TIMEOUT�bit.�If�the'*£LOGICAL�RECORD�LENGTH�bit�is�not�set,*£copy�the�current�setting. ŠIF��THEN�MOVE.W‚IOSLRL(A0),IOSLRL(A1)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�END-OF-LINE/ŠIF��THENŽSTRING,�copy�the�current�setting.ŒMOVE.B�IOSELC(A0),IOSELC(A1)ŠENDIŠOPT„BRL*I*ƒNow�that�the�users�configuration�block�contains�the�proposed�attributesG* and parameters, they will be checked for validity before copying them* into the DCB or CCB.*8ŠMOVE.B�#CECPNI,D2ŒIf�the�auto-linefeed�attribute�is�set@ŠBTSTW‚#IOALNFD,IOSATW(A1)�and�the�end�of�line�character�is�null,ŠBEQ.S‚CMNC001�return�a�configuration�error.ŠTST.B‚IOSELC(A1)ŠBEQ.S‚CNFGERRŠSPC„2CCMNC001ƒMOVE.B& �#CECPRLZ,D2ŠIf�either�the�logical�or�physical�record<ŠMOVE.W�IOSREC(A1),D0†length�is�zero,�return�a�configurationŠBEQ.S‚CNFGERRŒerror.ŠMOVE.W�IOSLRL(A1),D3ŠBEQ.S‚CNFGERRŠSPC„24ŠCMP.W‚D3,D0�If�the�logical�record�length�is�greater5ŠBHS.S‚OKCNFG�than�the�physical�record�length,�return*ŠMOVE.B�#CECPLGP,D2ˆa�configuration�error.ŠSPC„2ACNFGERRƒMOVE.B�#ISTACFG,D1‰Return�a�configuration�error�status�in>ŠMOVE.B�D2,IOSCEC(A1)†the�users�IOS�parameter�block�and�return8ŠBRA.S‚CNFGEXIT‹the�specific�configuration�error�code�in *£the�users�configuration�block.ŠSPC„2F*…Set�the�configuration�flag�byte�in�the�device�DCB�to�indicate�that�aK*‚CONFIGURE�or�CONFIGURE�DEFAULTS�request�was�processed.�FHS�will�check�theM*‚flag�when�it�closes�the�last�assignment�to�the�device�to�see�if�it�needs�toH*‚tell�IOS�to�issue�a�configure�request.�IOS�will�then�issue�a�CONFIGUREJ*‚request�using�the�device�DCB�default�configuration�parameters.�This�willI*‚always�force�the�current�configuration�to�the�default�whenever�the�last*‚assignment�is�closed.*I*…Subroutine�STATYP�is�called�to�store�the�current�device�status,�channelH*‚type,�device�type,�and�driver�code�into�the�users�configuration�block.*ŠMOVE.B�CCBRLEN(A5),IOSLEN(A3)�Update�users�IOCB�length�field.ŠCLR.L‚CCBRLEN(A5)ŠSPC„2=ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�the�TCB�address�of�IOCB�owner;ŠSUB.B‚#1,TCBIOCNT(A0)‡and�decrement�his�pending�I/O�count.ŠSPC„2*!*‚Prepare�the�event�and�queue�it.*8ŠMOVE.B‚#ISTATO,IOSSTA(A3)ƒUpdate�the�IOCB�status�field.,ŠMOVE.W‚#ISTATO,D3‹Set�up�event�status�field-ŠMOVE.B‚#XPSHLT,D1‹Set�up�event�status�value.!ŠMOVE.L‚#6,D0�Set�up�info�length.&ŠMOVE.L‚CCBCID(A5),D2ˆSet�up�event�ID..ŠLEA…CCBPKT(A5),A4ˆSet�up�event�build�pointer.ŠBSR…QEVNT�Queue�event.ŠB' RA…CMDEXITŽRETURN ŠPAGEL******************************************************************************C*‰ROUTINE�COMMON�TO�ALL�I/O�COMMANDS�(READ,�WRITE,�OUTPUT�W/�INPUT)**‚Entry:�A3�=�address�of�IOCB*‰A5�=�address�of�CCB**L*****************************************************************************IOSCOMN:?ŠBTSTW‚#IOPTSKB,IOSOPT(A3)�If�the�buffers�reside�in�a�different"ŠBEQ.S‚IOSC005Œtask�from�the�IOCB, 9ŠLEA„IOSTSK(A3),A0†Point�to�the�taskname�&�session�of�the7ŠTR0$.GETTCB‚,Œbuffer�owner�&�call�exec�to�get�address."ŠBRA.S‚OKTCBŽIf�it's�good,�branch.ŠNOP—If�it's�bad,6ŠMOVE.B�#XSTADB,D1‰set�status�in�IOCB�to�address�errorŠTST.L‚(A7)+Žadjust�stackŠBRA.S‚NRMEXITŒand�exit�to�CMR. :OKTCB…MOVE.L�A0,CCBTASKB(A5)„Save�physical�address�of�TCB. *<*‚Validate�the�info�in�the�IOCB�about�the�primary�buffer�and *‚convert�to�physical�addresses.*BIOSC005ƒMOVE.L�IOSSAD(A3),D6†D6�<--�buffer�physical�start�address.+ŠMOVE.L�IOSEAD(A3),D5†D5�<--�buffer�length.ŠSUB.L‚D6,D5Ž* ŠADDQƒ#1,D5Ž*ŠSPC„25ŠMOVE.L�D5,-(A7)‹Save�the�buffer�length�on�the�stack.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.$ŠBRA.S‚IOSC010ŒIf�it's�good,�branch.9ŠADDQ.L�#8,A7ŽIf�it's�a�bad�base�address,�remove�saved�D5&*£and�adjust�the�stack�return�address.ŠSPC„24ŠMOVE.B�#ISTAADD,D1ˆSet�IOCB�status�to�ADDRESS�ERROR6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status. @IOSC010ƒMOVE.L�D6,CCBPTR(A5)†Save�physical�start�address�in�CCB.2ŠADD.L‚(A7)+,D6‹Save�the�physical�end�address�plus&ŠMOVE.L�D6,CCBEAP1(A5)…one�in�the�CCB.ŠRTSŠPAGEK****************************************************************************=*‰VALIDATE�CONFIGURATION�BUFFER�ADDRESS�&�CONVERT�TO�PHYSICAL*$*‰Entry:�D5�=�buffer�length�in�bytes-*�D6�=�buffer�logical�start�addr�(to�convert)*�A3�=�address�of�IOCB*�A5�=�address�of�CCB***‰Exit:‚D6ƒ=�buffer�physical�start�address*�D5ƒ=�buffer�length*K****************************************************************************CCNFGADRƒLEA.L‚CCBCFIG(A5),A0…This�entry�point�loads�the�CCB�config.*£data�block�into�A0.ŠSPC„2.CNFGADR2‚MOVE.L�A0,-(A7)‹Save�A0�on�the�stack.?ŠMOVE.L�IOSDBP(A3),D6†D6�<--�logical�addr�of�user's�data�block./ŠMOVE.L�#IOSPLN,D5‰D5�<--�length�of�data�block.ŠSPC„2>ŠMOVE.L�CCBTASKB(A5),A1„A1�<--�address�of�TCB�of�buffer�owner."ŠBSR.S‚IOHADRCK‹Check�the�address.%ŠBRA.S‚CNFGADR3‹If�it's�good,�branch.ŠSPC„27ŠADD.L‚#8,A7ŽIf�the�address�or�length�is�bad,�clean�the<ŠMOVE.B�#ISTAADD,D1ˆstack,�set�IOCB�status�to�ADDRESS�ERROR,6ŠBRA.S‚NRMEXITŒand�exit�with�appropriate�error�status.ŠSPC„2=CNFGADR3‚MOVE.L�D6,A1ŽStore�the�physical�address�of�the�users9ŠMOVE.L�(A7)+,A0‹data�block�in�A1,�restore�A0�and�return.ŠRTSŠPAGEO******************************************************************************** *ˆNORMAL�EXIT*,*‚Entry:�A2�=�address�of�CMR�parameter�block*‰A3�=�address�of�IOCB*‰A4�=�address�of�DCB*‰A5�=�address�of�CCB*‰A6�=�address�of�users�TCB*‰D1�=�IOS�error�code*I**************************************************************************NRMEXIT:*‰LEA‡CCBPKT(A5),A4‡Set�up�queue�work�area.!‰MOVE.L„#6,D0�Set�up�packet�size.#‰MOVE.L„XIOUID(A2),D2‡Set�up�PB�id.#‰AND.W…#$FF,D1�Mask�for�word�value."‰MOVE.W„D1,D3�Set�up�status�value./‰MOVE.B„D1,IOSSTA(A3)‡Update�IOCB�status�field.%‰MOVE.B„#XPSNRM,D1ŠSet�up�event�type.‰BSR‡QEVNT�Go�queue�event.CMDEXIT‚CLR.L…D0*8* User request side of IOH always exits from this point.*IOHUSRTN‚EQU„*ŠRTS—RETURN�TO�MAINLINEŠPAGEK****************************************************************************B*ƒSubroutine�to�check�address�boundaries�to�see�if�entirely�within* calling tasks address space.*&*‚Entry:�D5�-‚number�of�bytes�to�check*‰D6�-‚68000�address(logical)*‰A1�-‚TCB�address***** EXEC ROUTINE#* REGISTERS USED: D0-D1,D3,D6/A0-A1**7*�EXIT:„D6�-�PHYSICA' L�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‚IOHADR6�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.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.ŠPAGEL******************************************************************************‚PRTOUT*%*ˆThis�is�the�printer�output�routine.***ˆENTRY:‚A0�=�address�of�buffer*�A1�=�address�of�device�base*�A3�=�address�of�IOCB*�A4�=�address�of�DCB*�A5�=�address�of�CCB*.* PRTOUT1 ENTRY: D0.B = character to be output*—other�registers�as�above*M******************************************************************************CPRTIMG„ADD.L‚#1,CCBRLEN(A5)†For�image�mode,�count�each�byte�sent�to>ŠCMP.L‚CCBEAP1(A5),A0„the�printer�whether�printable�or�not.�If6ŠBEQ.S‚PRT070Œthe�end�of�the�buffer�is�reached,�do�the *¢request�completion�processing.ŠSPC„2PRTOUT:0ŠMOVE.B‚(A0)+,D0ŽGet�next�data�byte�from�buffer.,ŠMOVE.L‚A0,CCBPTR(A5)‰Update�buffer�pointer.ŠSPC…2;ŠBTSTWƒ#IOPFORB,CCBCOPT(A5)„For�image�mode�output,�skip�the,ŠBNE.SƒPRTOUT1�special�character�processing.ŠSPC…20ŠCMP.B‚#CR,D0“If�the�current�buffer�character�is,ŠBEQ.S‚PRT030‘a�CR,�proceed�with�end-of-line *§processing.ŠSPC…2+PRTOUT1ƒBSR.LƒDEVOUTS�Output�the�data�byte.ŠSPC„2EPRT010„BTSTWƒ#IOPFORB,CCBCOPT(A5)„If�the�output�is�bring�performed�in1ŠBNE.SƒPRTIMG�image�mode,�transfer�control�to�the%*§top�of�the�output�loop�to�check�for*§end�of�buffer.ŠSPC…25ŠCMP.Bƒ#'�',-1(A0)�If�the�current�buffer�character�is,ŠBLT.SƒPRT017�non-printing,�do�not�check�for(*¦end-of-line�or�increment�the�character*¦countŠSPC…25ŠADD.L‚#1,CCBRLEN(A5)‹Increment�the�printed�character*§count.ŠSPC…29ŠMOVE.L�CCBRLEN(A5),D2‹Divide�the�printed�character�countAŠDIVUƒCCBCFIG+IOSLRL(A5),D2‚by�the�logical�line�length.�Store�the+ŠSWAP„D2”remainder�in�the�lower�half�of�D2.ŠSPC…2*ŠTST.W‚D2—If�an�exact�logical�and�physical4ŠBNE.S‚PRT017‘end-of-line�has�been�reached,�output�a*G*‚THE�FOLLOWING�WAS�ADDED�TO�THE�VM01�PRINTER�DRIVER�TO�FIX�THE�PROBLEML*‚OF�THE�ORIGINAL�DRIVER.‚IT�DID�A�COMPARISON�OF�THE�PHYSICAL�LINE�LENGTH�TOH*‚REGISTER�D3.‚THIS�REGISTER�WAS�NEVER�SET�UP.‚I�THINK�THE�INTENT�WAS�TO>*‚COMPARE�THE�PHYSICAL�LINE�LENGTH�TO�THE�LOGICAL�LINE�LENGTH.BŠMOVE.W�CCBCFIG+IOSLRL(A5),D3‚(FIRST�LOAD�THE�LOGICAL�LINE�LENGTH)*@ŠCMP.W‚CCBCFIG+IOSREC(A5),D3‚linefeed�for�non-auto-LF�device.�If3ŠBEQ.S‚PRT013‘only�the�logical�line�length�has�been3ŠBSR.S‚PRTEOL‘reached,�output�a�logical�end-of-line2ŠBRA.S‚PRT015‘sequence.�If�neither�length�has�been&*§reached�proceed�to�the�end-of-buffer*§check.ŠSPC„2GPRT013„BTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�the�device�does�not�support0ŠBNE.SƒPRT015�auto�line�feed,�output�a�line�feed5ŠMOVE.B�#LF,D0‘if�the�byte�count�is�an�exact�multiple"ŠBSR.SƒDEVOUTS�of�the�line�length.ŠSPC…2FPRT015„BTSTW‚#IOATPLL,CCBCFIG+IOSATW(A5)�Since�an�end-of-line�has�been/ŠBNE.SƒPRT070“reached,�terminate�the�request�if!*ªthe�truncate�print�attribute�is*ªset.ŠSPC„2=PRT017„CMP.LƒCCBEAP1(A5),A0ŠIf�the�end�of�buffer�has�n( ot�been/ŠBLT…PRTOUT�reached,�output�the�next�character.ŠSPC…2:PRT030„BSR.SƒPRTEOL‘Output�a�logical�end-of-line�sequence.ŠPAGEPRT070:*2*‚Finished�transfer,�now�queue�event�to�requestor.*+ŠBCLRW‚#CCBFGBSY,CCBFG(A5)ƒClear�busy�flag.,ŠMOVE.L�CCBTASKB(A5),A0‡Pick�up�TCB�address.3ŠSUB.B‚#1,TCBIOCNT(A0)‡Decrement�I/O�pending�count. -ŠMOVE.W�#ISTAOK,D3ŒSet�up�ok�IOS�status�code..ŠAND.B‚#3,D0‘Mask�fault�bits�of�device�status.ŠCMP.B‚#1,D0‘Any�faults�?"ŠBEQ.S‚PRT080�Branch�if�no�faults.1ŠMOVE.W�#ISTANR,D3ŒFault,�set�up�IOS�status�code.-PRT080„MOVE.L�#6,D0‘Set�up�event�info�length.*ŠMOVE.B�#XPSNRM,D1ŒSet�up�event�type�code.)ŠMOVE.L�CCBCID(A5),D2‰Set�up�DCB�address./ŠMOVE.B�D3,IOSSTA(A3)‰Update�IOCB�status�field.8ŠMOVE.L�CCBRLEN(A5),IOSLEN(A3)‚Update�IOCB�length�field. *ŠLEA„CCBPKT(A5),A4‰Set�up�event�data�area./ŠBSR„QEVNT‘Queue�completion�event�to�requestor. ŠRTSŠPAGE*E*‹This�subroutine�outputs�either�a�LF-CR�sequence�or�an�EOL�character6*‰based�on�the�setting�of�the�auto-linefeed�attribute.*#PRTEOL„MOVE.B�CCBCFIG+IOSELC(A5),D0?ŠBTSTWƒ#IOALNFD,CCBCFIG+IOSATW(A5)�If�not�an�exact�end-of-line,4ŠBNE.SƒDEVOUTS�output�the�EOL�character�if�the�auto-(*§linefeed�attribute�is�set.�Else�output*§a�LF�and�CR.ŠSPC…2/ŠMOVE.B‚#LF,D0’Call�DEVOUT�to�output�a�linefeed.ŠBSR.SƒDEVOUT�character.�If�an�error�status�is1ŠTST.BƒD3”returned�in�D3,�transfer�control�to�theŠBNE.SƒDEVOUTE�error�exit.ŠSPC„26ŠMOVE.B‚#CR,D0�Set�up�carriage�return�character�in�D0.ŠSPC„2*E*‹This�routine�is�called�as�a�subroutine�from�PRTOUT�to�output�singleF*‰characters�from�D0�with�automatic�request�termination�if�an�error�isD*‰detected�in�the�DEVOUT�subroutine.�Execution�also�falls�through�to*‰here�from�PRTEOL.*8DEVOUTSƒBSR.S‚DEVOUT�Call�DEVOUT�to�output�the�character5ŠTST.B‚D3‘in�D0.�If�the�status�returned�in�D3�is�non-'ŠBEQ.S‚DEVOUTOK‹zero,�do�an�error�exit.ŠSPC„2:DEVOUTEƒTST.L‚(A7)+�If�an�error�occurs�transfer�control�to-ŠPEA.L‚PRT070�the�request�completion�routine.ŠSPC„2+DEVOUTOK‚RTS™Return�to�the�calling�routine.ŠPAGEO*********************************************************************************‚DEVOUT(*�****MODIFIED�1/27/83�BY�M.�BRIEL*******<*†1.Check�for�a�device�fault�(not-selected�or�out�of�paper).=*ˆIf�a�fault�is�present,�terminate�the�request�with�an�error.*F*†2.�If�an�Printer�Acknowledge�is�expected,�wait�for�the�ACK�pulse�for@*‰approx.�100�us.�If�the�pulse�does�not�arrive�in�100�us,�enable0*‰the�Acknowledge�interrupt�and�exit�the�driver.*4*†3.�Output�the�next�character�and�pulse�Data�Strobe**ˆENTRY:„D0‚=�data�byte*’A1‚=�device�base�address*‘(SP)�=�return�address*�4(SP)�=�PRTOUT�return�address*�DEVICE�=�Interrupts�disabled*,*ˆEXIT:…D0‚=�Device�status�register�contents*�NORMAL�=�(SP)�return*�FAULT�=�(SP)+2�return5*‘BUSY�=�4(SP)�PRTOUT�return�address�(device�enabled)*K****************************************************************************DEVOUT:'‰CLR.BƒD3“Clear�D3�for�a�normal�return.* ‰CLR.LƒD1.‰MOVE.B‚DEV1BD(A1),D1‰Pick�up�status�register. ‰MOVE.L‚D1,D2‘Make�another�copy.&‰AND.Bƒ#$03,D1�Mask�uninterested�bits.-‰CMP.Bƒ#$01,D1�Selected�and�not�Out-of-Paper?‰BNE.SƒDEV010�Fault�exit�if�no.*:ŠTST.B‚CCBACKP(A5)ŠIf�a�printer�acknowledge�is�not�pending,ŠBEQ.S‚DEV020�proceed�with�character�output.*:ŠMOVE.W�#32,D1‹Repeatedly�test�for�the�printer�acknowledge:DEVACK„SUBQƒ#1,D1Œpulse.�If�the�acknowledge�arrives�before9ŠBEQ.S‚DEV005‹the�loop�times�out�(approx.�100�us)�proceed=ŠTST.B‚CCBACKP(A5)†with�character�output.�Otherwise,�exit�the4ŠBNE.S‚DEVACK‹driver.‚A�FAULT�or�an�ACKNOWLEDGE�WILL*¡ALWAYS�CLEAR�CCBACK.*N*‚Since�interrupts�cannot�be�masked,�we�must�check�to�see�if�an�interrupt�cameL*‚in.‚This�interrupt�will�clear�the�interrupt�flag�bit�(bit�7)�and�will�alsoK*‚clear�CCBACKP.‚Because�CCBACKP�was�tested�above�and�found�to�be�clear,�an6*‚interrupt�(either�FAULT�or�ACKNOWLEDGE)�did�come�in.,ŠBRA.S‚DEVOU( T�Go�see�which�interrupt�it�was.* DEV005„INHIB6ŠTST.B‚CCBACKP(A5)ˆCheck�one�more�time�to�make�sure...(ŠBNE.S‚DEV008�If�STILL�set,�go�bail�out.ŠENABL4ŠBRA.S‚DEVOUT�Else,�go�check�which�interrupt�it�was.ŠSPC„2*L* No interrupts - so set up the return address and exit, waiting for a FAULT)* or an ACKNOWLEDGE interrupt to come in.*@DEV008ƒMOVE.B‚D0,CCBSAVB(A5)ˆThe�device�is�busy,�save�data�byte..‰MOVE.L‚(A7)+,CCBIRTN(A5)…Save�return�address.-‰SUB.Lƒ#2,CCBIRTN(A5)ˆAdjust�service�address.*A‰MOVE.L‚(A7)+,CCBISTK(A5)…Save�subroutine�return�address�into�CCB*L* Set a flag to tell the interrupt routine that the next interrupt should beB*�processed.‚Remember,�we�will�get�an�interrupt�on�each�character.1‰ST.B„CCBINREQ(A5)ŠSet�'INTERRUPT�REQUIRED'�flag. ‰RTS›Return.* * Fault Exit+DEV010ƒMOVE.L‚D2,D0�Set�up�status�register.*‰BSR…DEVINIT1ŠClear�any�pending�interrupt.:‰CLR.B‚CCBACKP(A5)ˆClear�pending�printer�acknowledge�flag.7‰TST.B‚DEV1AD(A1)‰Clear�Acknowledge�interrupt�IRQ�flag.+‰ST†D3�Set�D3�non-zero�to�indicate�an�error$‰BRA.SƒDEVOEXŒand�prepare�to�return.*(*�Output�the�next�character�1/17/84�MLB*=DEV020ƒTST.BƒDEV1AD(A1)ŒClear�Acknowledge�interrupt�IRQ�flag.'‰MOVE.B‚D0,DEV1AD(A1)‰Output�data�byte.‰INHIB* * data strobe‰MOVE.B‚#%00000000,DEV1AC(A1)3‰MOVE.B‚#%00001000,DEV1AC(A1)ƒStrobe�the�data�byte.8‰ST†CCBACKP(A5)‹Set�the�printer�acknowledge�pending�flag0‰MOVE.B‚DEV1BD(A1),D0‰Get�status�register�again.0DEVOEXƒENABL™Enable�interrupts�and�return�to�the‰RTS™calling�routine.‰PAGEJ***************************************************************************!* INTERRUPT SIDE FOR PRT 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**ƒREGISTERS�USED:ƒ01234567 *”D******** *”A*****P****ƒEXEC�ROUTINES�CALLED:‚QEVENTI**ƒCODE�IS�RE-ENTRANT*F*---------------------------------------------------------------------*4* If channel is off-line or not attached, just exit.*PRTISR:.ŠMOVE.L�CCBCHB(A5),A1‰Get�device�base�address.5ŠMOVE.B�DEV1AC(A1),D0‰Pick�up�A-side�status�register.#ŠAND.B‚#$80,D0�Mask�interrupt�bits..ŠCMP.B‚#$80,D0�ACKNOWLEDGE�interrupt�pending�?ŠBEQ.S‚PRTI010�Branch�if�yes.5ŠMOVE.B�DEV1BC(A1),D0‰Pick�up�B-side�status�register.#ŠAND.B‚#$80,D0�Mask�interrupt�bits.(ŠCMP.B‚#$80,D0�FAULT�interrupt�pending�?ŠBEQ.S‚PRTI010�Branch�if�yes. 2ŠAND.W‚#$FFFE,SR�No�interrupt�so�set�condition�and ŠRTSšreturn. -PRTI010ƒBTSTW‚#CCBFGOFF,CCBSTR(A5)‚Off-line�?ŠBNE.S‚PRTI020�Branch�if�yes.5ŠBTSTW‚#CCBFGATH,CCBSTR(A5)‚Is�the�channel�attached�?ŠBEQ.S‚PRTI020�Branch�if�no.(ŠBTSTW‚#CCBFGBSY,CCBFG(A5)ƒI/O�pending�?ŠBNE.S‚PRTI100�Branch�if�yes. 8PRTI020ƒMOVE.L�CCBCHB(A5),A1‰Set�up�device�base�address.(ŠBSR„DEVINIT1ŽClear�any�FAULT�interrupt.2ŠTST.B‚DEV1AD(A1)ŒClear�any�ACKNOWLEDGE�interrupt.6ŠCLR.B‚CCBACKP(A5)‹Clear�the�ACKNOWLEDGE�pending�flag.ŠENABL!ŠOR.Wƒ#$0001,SR�Set�condition�and ŠRTSšreturn.ŠPAGEN******************************************************************************** INTERRUPT LEVEL PROCESSING*0*ˆIt�has�been�determined�that�I/O�is�in�progress*ˆand�the�interrupt�is�ours.**N*******************************************************************************PRTI100:(ŠBSR…DEVINIT1‰Clear�any�FAULT�interrupt.2ŠTST.BƒDEV1AD(A1)‡Clear�any�ACKNOWLEDGE�interrupt.>ŠCLR.BƒCCBACKP(A5)†Clear�the�printer�ACKNOWLEDGE�pending�flag.;ŠTST.BƒCCBINREQ(A5)…See�if�this�interrupt�is�really�needed.-ŠBEQ.SƒPRTI200ŠBranch�if�no�interrupt�needed..ŠCLR.BƒCCBINREQ(A5)…Else,�clear�for�next�time.*=ŠMOVEM.L�D1-D7/A2-A4/A6,-(A7)�Save�the�rest�of�the�registers.ŠSPC„2–1/17/84�MLB*-ŠMOVE.L‚CC) BPTR(A5),A0ˆRestore�buffer�pointer.1ŠMOVE.B‚CCBSAVB(A5),D0‡Restore�current�data�byte.5ŠMOVE.L‚CCBIRTN(A5),A2‡Get�interrupt�service�address.'ŠMOVE.L‚CCBCCB(A5),A3ˆGet�IOCB�address.&ŠMOVE.L‚CCBCID(A5),A4ˆGet�DCB�address.8ŠADD.Bƒ#1,CCBICNT(A5)‡Increment�pending�interrupt�count.:ŠPEA…PRTINRTN(PC)‰Stack�the�interrupt�routine�exit�address>ŠMOVE.L‚CCBISTK(A5),-(A7)„Restore�subroutine�return�address�on*¦stack.!ŠJMP…(A2)‘Jump�to�output�routine. *.* PRT interrupt handler exits from this point.* PRTINRTN:7ŠSUB.Bƒ#1,CCBICNT(A5)‡Decrement�pending�interrupt�count0ŠMOVEM.L�(A7)+,D1-D7/A2-A4/A6�Restore�registers.PRTI200:/***‡ENABL˜Let�CMR�enable�interrupts�later,�this%***¤fix�is�for�EPSON�RX80�(SPR�1178).(ŠOR.Wƒ#$0001,SR�Set�return�condition�and!ŠRTSšreturn�to�interrupt�handler.ŠPAGEJ**************************************************************************** QEVNT**„Place�message�on�user's�ASQ.**ˆA4�=�address�of�event�area*ˆA5�=�address�of�CCB'*ˆD0�=�event�length�(minus�header�info)*ˆD1�=�event�type*ˆD2�=�4�byte�id�(DCB)*ˆD3�=�status�value�(2�bytes)*ˆD4�=�device�status�(2�bytes)*ˆD5�=�device�number�(1�byte)*J***************************************************************************QEVNT:ŠMOVE.L�D0,D6ŽSave�length.5ŠMOVE.L�#2,D7ŽOffset�for�staging�(no�service�vector)./ŠMOVE.B�#IOEVCD,1(A4)†Code�(no�service�vector).)ŠMOVE.L�CCBSVVC(A5),2(A4)‚Service�vector.+ŠBEQ.S‚QEVNT10ŒBranch�if�no�service�vector./ŠADD.L‚#4,D0ŽCorrect�length�for�service�vector.7ŠADD.L‚#4,D7ŽCorrect�offset�staging�for�service�vector.2ŠADD.L‚#$00800000,(A4)„Correct�for�service�vector. 1QEVNT10ƒMOVE.B�D1,0(A4,D7)ˆCompletion�event�type.*ŠMOVE.B�CCBKEY(A5),1(A4,D7)�User's�id�key.-ŠADD.L‚#4,D0ŽComplete�length�of�return�event.6ŠCMP.B‚CCBASQL(A5),D0…User's�maximum�ASQ�entry�length.#ŠBLS.S‚QEVNT20ŒBranch�if�length�ok.0ŠMOVE.B�CCBASQL(A5),D0…User's�length�is�smaller. &QEVNT20ƒMOVE.B�D0,(A4)ŒCorrect�length. /QEVNT40ƒMOVE.L�D2,2(A4,D7)ˆSet�up�status�value.$ŠMOVE.W�D3,6(A4,D7)ˆSet�up�id�(DCB).ŠCMP.B‚#6,D6Ž6�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.)ŠMOVE.W�D4,8(A4,D7)ˆSet�up�device�status.ŠCMP.B‚#8,D6Ž8�byte�info�?ŠBEQ.S‚QEVNT50ŒBranch�if�yes.*ŠMOVE.B�D5,10(A4,D7)‡Set�up�device�number.&ŠCLR.B‚11(A4,D7)ŠClear�reserved�field.*I* Now let's put the completion into registers and send event to the task.* QEVNT50ƒEQU„*ŠMOVEM.L�(A4),D2-D7ŠBSR.S‚IOHQEVNTŠRTSŠ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**************************************************************************** IOHQEVNT:$ŠMOVEM.L�A3-A5,-(A7)‡Ssve�registers.-ŠMOVE.L�CCBRQSTA(A5),A0„Caller's�TCB�address.ŠSPC„26ŠMOVE.L�#T0QEVNTI,D0‰If�this�routine�was�called�during6ŠTST.B‚CCBICNT(A5)ˆinterrupt�processing,�use�the�QEVNT3ŠBNE.S‚IOHQ4Žinterrupt�routine,�else�use�the�normal#ŠMOVE.L�#T0QEVNTT,D0‡QEVNT�routine. IOHQ4…TRAPƒ#0#ŠBRA.S‚IOHQ5ŽBranch�if�queueing�ok.'ŠMOVEM.L�(A7)+,A3-A5‡Restore�registers.9ŠMOVE.L�(A7),CCBQVER1(A5)‚Save�callers�address�for�debug.ŠBRA.S‚IOHQRTN ,IOHQ5…MOVEM.L�(A7)+,A3-A5‡Restore�registers..ŠCLR.L‚CCBQVER1(A5)‡Clear�queue�error�address. IOHQRTNƒRTS—RETURNŠEND=/*=/*†RWINDRV.AF=/*:=/* Chain file to assemble the RWIN disk controller driver=/*:=/* If no output argument is specified for the listing the)=/* chain file will default to RWINDRV.LS=/*=/IFC \1ƒ=ARG�RWINDRV.LS=/ENDIF=/*&=ASM RWINDRV.SA,RWINDRV.RO,\1;-WRZ=186=/*{ Included files are:=/*ƒ9995.&.STR.EQ=/*ƒ9995.&.TCB.EQ=/*ƒ9995.&.CCB.EQ=/*ƒ9995.&.LV5.EQ=/*ƒ9995.&.IOE.EQ=/*ƒ9995.&.NIO.EQ =/*ƒCOMCMD.AI=/*ƒRWININT.AI=/*}=/*=END) éééééé&‰TTL‡RWINDRV.SA >*ˆJAHƒ2/25/85ƒIn�COMCMD:‚Use�no.�of�cylinders�on�media�for�the'*˜configure�command�on�hard�disks�only.9*ˆJAHƒ2/18/85ƒIn�COMCMD:‚Limit�the�pre-compensation�value.*˜to�$FF�-�the�most�that�will�fit�in�one�byte.ééééééé/8:@:HDP9X8`=h,p+x:€7ˆ6�:˜A :¨6°.¸9À;È8Ð8Ø4à8è:ð6ø<Q* *ˆBWNƒ2/13/84‡PJD�9/18/84 *ˆRV�10/17/84�retry�option�check<*ˆBWN‚10/25/84:‚Fixed�so�that�correct�sector�number�returned*˜when�an�error�is�found.3*˜RWCOMMON:‚Do�not�increment�LSN�unless�all�sectors.*˜have�been�processed�for�the�current�command.+*˜CHECKERR:�Do�not�decrement�LSN�for�retry.4*˜STATERR:‚Do�not�decrement�LSN�for�reporting�error.*;*ˆBWNƒ11/7/84ƒIn�COMCMD:‚Make�a�check�to�see�that�bytes�per-*˜sector,�sectors�per�track,�and�data�density4*˜have�consistent�values�for�a�floppy�disk�of�5�1/4".*˜and�8"�sizes.‚If�not,�return�error�code�$47.*D*ˆBWNƒ12/21/84‚Yet�another�fix�for�the�elusive�correct�sector�number *˜return:0*˜Seems�that�the�last�"fix"�caused�us�to�put�bad3*˜stuff�into�the�user's�buffer�when�reading�sectors-*˜in�track�0�of�a�double�density�floppy�disk.5*˜This�occured�when�there�was�a�CRC�error�in�track�0.&*˜The�setup�for�retry�was�not�correct.4*˜Hopefully�this�will�fix�the�problem�of�the�correct'*˜sector�numbers�getting�returned�for�a.*˜CRC�error�and�track/sector�ID�error�as�well.*˜(1)�in�RWCOMMON:**œput�back�in�the�code�that�added�1�to�LSN'*œand�subtracted�1�from�CMDSECTS�in�the*œcommand�packet.*˜(2)�near�the�label�RD_WR::+*œIf�an�error�occurs�here,�branch�direct�to,*œSTATERR�instead�of�CHECKERR.‚At�this�point *œwe�have�the�current�LSN�in�the*œcommand�packet.*˜(3)�in�CHECKERR:**œIf�the�data�is�correctible,�and�CMDSECTS1*œis�positive�(which�I�don't�think�could�happen‚-'*œneeds�more�analysis)�then�the�LSN�and$*œCMDSECTS�will�be�set�up�correctly.&*œIf�the�data�is�not�correctible,�then3*œwhether�we�retry�or�report�the�error,�we�need�the0*œcurrent�LSN�and�CMDSECTS�in�the�command�packet.*œso�move�the�subtract�1�from�LSN�and�add�1�to**œCMDSECTS�commands�up�to�the�label�L0555.*** ŠOPT�CRE,PCS **‰MISC�EQUATES*"DRIVESƒEQU‡4“#�of�drives�per�boardEXEC…EQU‡0“RMS68K�trap�# %DTYPE„EQU‡1”Conditional�assembly�flag*¦0�=�assemble�for�SASI�driver$*¦1�=�assemble�for�Winchester�driver*K*****************************************************************************ˆBWN‡2/13/84ƒPJD‚9/18/84*1GOODCODE�EQU‡0“Opcode�for�format�sector�as�"good"1BADCODE‚EQU‡$80‘Opcode�for�format�sector�as�"bad"7ALTCODE‚EQU‡$40‘Opcode�for�format�sector�as�"alternate"*O*******************************************************************************   **ˆMACROS�USED�BY�THIS�DRIVER*4LONGWORD�MACRO„.–This�macro�skips�zero�or�more�bytes'*¦in�memory�(if�necessary)�to�align�the)*¦assembler's�location�counter�to�a�long-&*¦word�boundary.‚We�define�a�long-word)*¦boundary�to�be�a�location�whose�address*¦is�evenly�divisible�by�4.‰DS.W…00‰IFNE…*/4*4-*�If�the�location�counter�isn't�on�a-‰DS.W…1”long-word�boundary,�advance�it�by�one/‰ENDC….”word�to�put�it�on�a�long-word�boundary.‰ENDM 3MOVEIAƒMACRO„.–This�macro�is�useful�when�we�want�to%*¦put�an�immediate�value�into�an� *¦register."*¦[