IMD 1.17: 25/11/2014 13:11:05 82VKXBVERDOS D* BT22:0 68K VERSADOS/RMS68K OBJECT 4.5 (DS,DD 96 tpi 5.1/4" DISK) REVISED: 04/22/86 DISK 22 OF 24  BT22 82VKXBVERDOS 0420²a-@=H7PAXG *‚Equate�files�included:* *‰NEC7201*‰EQUSTR*‰EQUCCB *‰KILL.MC *‰KILLDRV.EQ ŠNOLISTŠINCLUDE�9995.&.NEC7201.EQŠINCLUDE�9995.&.STR.EQŠNOLISTŠINCLUDE�9995.&.CCB.EQŠNOLISTŠINCLUDE�9995.&.KILL.MCŠNOLISTŠINCLUDE�9995.&.KILLDRV.EQŠLISTŠ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�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 SET 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ƒ'121085'‹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.*-ŠKILL.DRIVER�MPSCSPR_ID,NOCMD_SERV,A5,#NO_DCBŠ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:*‚*…VM03�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ƒIDNTƒ45,0†NEC7201�supervisor�driver�for�VM03�board6ŠTTL„MPSCSUP:‚NEC7201�supervisor�driver�for�VM03�board ŠLLENƒ120J**************************************************************************J**************************************************************************J**************************************************************************J***************************************************************************<*‰MPSCSUP:‚Supervisor�channel�driver�for�NEC�7201�drivers�on*�the�VM03�board.*=*‰Purpose:‚VERSAdos�device�driver�to�take�interrupts�from�the1*�NEC�7201�chip�on�a�VM03�and�pass�control�to�the"*�appropriate�subordinate�channel.**‰Revision�history:**‘9/16/82‚Initial�release�by�Steve�Franck.*7*�12/10/85‚Install�NEW�Killer�modification�which�leaves,*šThe�Driver�ID�(Number)�and�Reason�(Number)2*šin�CRASHSAV�along�with�the�CCB�and�DCB�pointers.*;*‰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$.DRIVKILL**‰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 *‰KILL.MC *‰KILLDRV.EQ*ŠNOLISTŠINCLUDE�9995.&.NEC7201.EQŠINCLUDE�9995.&.STR.EQŠINCLUDE�9995.&.CCB.EQ `:i?q@y4�5ŠINCLUDE�9995.&.KILL.MCŠINCLUDE�9995.&.KILLDRV.EQŠLIST‰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Š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ƒ'121085'‹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.*-ŠKILL.DRIVER�MPSCSUP_ID,NOCMD_SERV,A5,#NO_DCBŠ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.* ŠENDN NŠPAGE1P050DRVƒIDNTƒ45,0ˆVERSAdos�MVME050�printer�driver-ŠTTL„P050DRV:„VERSAdos�MVME050�printer�driverNNNNNNN‰’Iš9¢<ª?²Gº@Â:ÊHÒ=Ú ŠLLENƒ120K***************************************************************************K***************************************************************************K***************************************************************************K****************************************************************************+*ˆP050DRV:‚VERSAdos�MVME050�printer�driver.**ˆRevision�history:**ˆ11/11/85‚Initial�release.*K***************************************************************************K***************************************************************************K***************************************************************************K***************************************************************************ŠPAGEŠOPT�CRE,PCS,BRS***‰XREF…PRNT_INIT‰XREF…PRNT_COMMAND‰XREF…INTR_REC‰XREF…FLT_TIMER **‚Equate�files�included:* *ˆ9995.&.STR.EQ*ˆ9995.&.TCB.EQ*ˆ9995.&.CCB.EQ*ˆ9995.&.IOE.EQ*ˆ9995.&.NIO.EQ*ˆ9995.&.LV5.EQ*ˆ9995.&.UTILITY.MC*ˆ9995.&.PRNT.EQ*ˆ9995.&.PRNTCCB.EQŠNOLISTŠ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�9995.&.UTILITY.MC ŠTTL…PRNT.EQŠLISTŠINCLUDE�9995.&.PRNT.EQŠTTL…PRNTCCB.EQŠINCLUDE�9995.&.PRNTCCB.EQŠTTL…P050DRV.SAŠPAGE/ŠOFFSET‚PCCBDDP�Continue�with�channel-dependent*¦CCB�variable�space.  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  *%%%Å%%%*B*%%%„Device-dependent,�channel�related,�variables�start�here.‰%%%* *%%%Å%%%**%%%™(CCB�SPACE)¡%%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*>*%%%„End�of�device�dependent,�channel�related,�variables.�%%%* *%%%Å%%%**%%%•END�OF�CCB�SPACE %%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  3CCBSIZEB�EQU†*–CCBSIZEB�defines�the�size�(in�bytes)$*¦of�a�complete�CCB�for�this�driver. %*¨CCBSIZE�defines�the�size�(in�pages)CL0080„EQU†CCBSIZEB+PAGESIZE-1‚of�a�CCB�for�the�driver,�and�EXTCCBSZ=CCBSIZE‚EQU†L0080/PAGESIZE‡defines�the�size�(in�pages)�of�the>EXTCCBSZ�EQU†CCBSIZE-1Œextended�portion�of�a�CCB.�The�extended(*¦portion�of�the�CCB�is�used�exclusively)*¦for�device-dependent�variables�that�are(*¦required�by�the�driver.‚There�are�$100'*¦bytes�per�page�of�memory,�and�the�CCB)*¦is�dynamically�allocated�as�an�integral*¦number�of�pages.‰PAGE** 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 6BIM_CTL3‚EQU†$FFFF10C7‹Address�of�BIM�#1�control�reg�35BIM_VEC3‚EQU†$FFFF10CF‹Address�of�BIM�#1�vector‚reg�3&IRE‡EQU†4“Interrupt�request�enable�bit **‚Definitions:*$*‚Name„AddressƒR/WƒLevel‡Description3*‚----„-------ƒ---ƒ-----‡--------------------------/*�DEV1ADƒFFXX81„(W)�Printer�output�data�(D0-D7)(*”(R)�Puts�$FF�into�printer�out�register6*�DEV1ACƒFFXX83„(W)ƒhigh->lowƒD3�=�printer�data�strobe%*”(R)�Clears�ACK�flag�and�printer�IRQ,*�DEV1BDƒFFXX85„(W)�Hardware�buffer�conflict*”(R)�Printer�status*šhighŠD0�=�printer�is�selected*šhighŠD1�=�printer�is�busy*šlow‹D2�=�fault�from�printer$*šhighŠD7�=�acknowledge�from�printer6*�DEV1BCƒFFXX87„(W)ƒhigh->lowƒD3�=�printer�input�prime*”(R)�no�operation*‰PAGE ‰SECTION�0O********************************************************************************1*ˆSERVICE�VECTOR�TABLE,�PARAMETERS,�REVISION�INFO*@*ˆThe�first‚several‚locations�of�every‚I/O�driver�must�contain�aB*ˆservice�vector�table�to�contain�the‚long-word�relative�addressesB*ˆof�the�three�driver�subroutines�that�CMR�uses.‚The�CMR�parameterC*ˆtable�immediately�follows�the�service�vector�table�and�includes�aA*ˆfield�telling‚CMR‚how�many�extra�pages‚to�allocate�for�the�CCB.E*ˆThe�revision�table�immediately�follows�the�the�CMR�parameter�table.*O*******************************************************************************O******************************************************************************* ‰SECTION‚0 P050DRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!* <‰DC.L…INTERUPT-P050DRV…Address�of�interrupt�service�routine.:‰DC.L…COMMANDS-P050DRV…Address�of�command�service�routine.5‰DC.L…INIT-P050DRV‰Address�of�initialization�routine.‰DC.L…0”Reserved. **‚Other�CMR�parameters.*3‰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…'111185'�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�printer�driver�PRNTLIB*O******************************************************************************* ‰BRA.L„DDP_OUTPUT‰BRA.L„GET_STAT‰BRA.L„DDP_RESET‰BRA.L„DDP_ENA_INTR‰PAGEO*******************************************************************************O** *******************************************************************************ˆINITIALIZATION�ROUTINE*B*ˆThis‚subroutine�is�called�from�CMR‚when�CMR�is�invoked�by�a�taskB*ˆ(normally�IOI)�to‚allocate�a�channel.‚Its�purpose�is�to�give�theD*ˆdriver�a�chance�to�set�up�things�for�command�service�and�interrupt-*ˆservice.‚The�basic�functions�performed�are:*5*ˆ1.‚Put�the�start�address�of�the�driver�into�the�CCB*Œvariable�DRV_ADDR.?*ˆ2.‚Device-Independent�initialization�in�the�call�to�PRNT_INIT"*Žto�initialize�the�CCB�variables.?*ˆ3.‚Device-Dependent�initialization�in�the�call�to�DO_INIT�for"*Ždevice�dependent�initialization.*B*ˆThis�subroutine�is�entered�through�a�JSR�from�CMR,�and�will�exit7*ˆwith�an�RTS.‚The�processor�is�in�the�supervisor�mode.*%*ˆEntry:„A6�=�physical�address�of�TCB*’A5�=�physical�address�of�CCB*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*.*ˆRegisters�used�in�PRNT_INIT:…0�1�2�3�4�5�6�7*¦D*¦A‚*‰P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* INIT:*)*‚Get�address�of�start�of�driver�into�CCB*ŠLEA‡P050DRV(PC),A0ŠMOVE.L„A0,DRV_ADDR(A5)*>*‚Perform�the�device-independent�initialization�by�calling�the'*‚generic�routine�PRNT_INIT�in�PRNTLIB.*/‰JSR†PRNT_INITŒDo�the�device-independent�stuff.4‰IF‚‚THEN.SŽSomething�went�wrong�with�PRNT_INIT.‹RTS™The�channel�is�down�!!‰ENDI*8*‚Perform�any�device-dependent�initialization�in�DO_INIT*/‰BSR.L„DO_INITŽDevice�dependent�initialization.‰RTS‰PAGEO*******************************************************************************O*********************************************************************************ˆCOMMAND�SERVICE�ROUTINE*C*ˆThis�subroutine�is�called�from�CMR�when�CMR�receives�a�command�toA*ˆinitiate�an‚I/O�transaction‚with�a�device�that�is�controlled�by?*ˆthis�driver.‚Its�function�is�to‚process�the‚given�command‚andB*ˆqueue�the�command�to�the�controller.‚These�functions�are�handled(*ˆby�the�generic�printer�driver�PRNTLIB.*5*ˆEntry:„A2�=�physical�address�of�CMR�parameter�block*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*1*ˆRegisters�used�by�PRNT_COMMAND:†0�1�2�3�4�5�6�7*ªD‚*�*�*�*�*�*�**ªA‚*�*�*�*�*�P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* COMMANDS: *,*‚Perform�any�device-dependent�stuff�here...* =*‚We�have�received�a�command,�so�we�know�there�is�someone�out**‚there�to�talk�to.‚Let�PRNTLIB�handle�it.*&‰JSR†PRNT_COMMAND‹Perform�the�command.‰RTS�Return�to�CMR.‰TTL‡MVME050�INTERRUPT�HANDLER‰PAGEO*******************************************************************************O*********************************************************************************ˆINTERRUPT�SERVICE�ROUTINE**ˆEntry:„JSR�from�ISR�(in�CMR)*’A5�=�Physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚S�*�*�*�*�*�*�**™A‚S�S�*�*�*�S�**(*ˆCalls:„DDP_RESET‚INTR_REC�(in�PRNTLIB)**ˆExit:…RTS�to�CMR*O*******************************************************************************O******************************************************************************* INTERUPT: .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address. 1Š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.2ŠBMI.S„PRTI010�Branch�if�ACK�interrupt�is�pending. 8PRTI005ƒAND.W„#$FFFE,SR‹Not�for�me,�so�set�condition�and ŠRTSšreturn.*K*‚It�was�for�me,�but�if�the�channel�is�off-line�or�not�attached,�just�exit.*PRTIACKƒTST.B„DEV1AC(A1)ŠClear�Acknowledge�interrupt�IRQ�flag.6ŠBTST.Bƒ#7,DEV1BD(A1)‡Test�for�ack�pending�to�go�away.#ŠBEQ.S„PRTIACK1ŒBranch�out�if�gone..ŠDBRA…D1,PRTIACKŠNot�gone,�so�decrement�timer. APRTIACK1‚ADD.B„#1,INTR_CNT(A5)…Increment�pending�interrupt�count.$ŠJSR†INTR_RECŒLet�PRNTLIB�handle�it. *2* Printer interrupt handler exits from this point.* PRTINRTN:9ŠSUB.B„#1,INTR_CNT(A5)†Decrement�pending�interrupt�count..ŠMOVEM.L‚(A7)+,INT_REGS‡Restore�the�registers.(ŠOR.W…#$0001,SRŒSet�return�condition�andŠRTS›return�to�CMR.ŠTTL†P050DRV.SAŠPAGEO********************************************************************************!*’R�O�U�T�I�N�E�SƒC�A�L�L�E�DƒB�Y**œP�R�N�T�L�I�B**O*******************************************************************************‰PAGEN*******************************************************************************0*ˆDDP_OUTPUTƒOUTPUT�THE�CHARACTER�TO�THE�PRINTER*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.*ˆoutput�the�character�in�D0.B�to�the�printer.**6*ˆEntry:�D0.B�=�character�to�be�output�to�the�printer.#*�A5ƒ=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚P�**™A„*‡P**ˆCalls:�GET_STAT‚DDP_RESET*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:-*�ˆCharacter�was�output�and�acknowledged.=*�,�‚Character�was�output�but�not�acknowledged�(yet).2*�,�‚Printer�error�condition�was�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_OUTPUT: 7ŠMOVEM.L‚D0-D1/A1,-(SP)†Save�the�registers�we�will�use. 1ŠMOVE.LƒCCBCHB(A5),A1‡A1�<--�device�base�address.'ŠBSR.L„GET_STATŒGet�the�current�status.ŠBEQ.S„PRNT_OK�Branch�if�ok.*9*‚Printer�error�condition�(out�of�paper�or�not�selected):* =ERROR_RET�BSR.L„DDP_RESET‹Reprogram�device�for�no�interrupts.3ŠMOVE.Wƒ#1,D0�Return�,��-->�error�detected.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGE*J* Output the character; but before we output, see if we are to check BUSY.*,EQ410…EQU†CONFGBLK+IOSATW…User's�attributes. GPRNT_OKƒBTSTW„#IOABUSY,EQ410(A5)‚See�if�the�user�wants�us�to�wait�until6ŠIF‚‚THEN�the�printer�is�not�BUSY�before�printing.ŒMOVE.B�DEV1BD(A1),D1.ŒAND.B‚#$07,D1�Mask�FAULT,�BUSY,�and�SELECTED.5ŒCMP.B‚#$07,D1�Wait�as�long�as�there�is�NO�FAULT,�and0ŒBEQ.S‚PRNT_OK�the�printer�is�BUSY�and�SELECTED.ŒCMP.B‚#$05,D10ŒBNE.S‚ERROR_RET‹Error�if�FAULT�or�not�SELECTED.ŠENDI +ŠMOVE.BƒD0,DEV1AD(A1)‡Output�the�data�byte.9ŠMOVE.BƒD0,DEV1AD(A1)‡Allow�data�to�settle�before�strobe.ŠMOVE.BƒD0,DEV1AD(A1)‡*ŠMOVE.BƒD0,DEV1AD(A1)‡*ŠMOVE.BƒD0,DEV1AD(A1)‡* >ŠMOVE.Bƒ#0,DEV1AC(A1)‡Strobe�pulse�goes�low�(strobe�the�data)./ŠMOVE.Bƒ#0,DEV1AC(A1)‡Stretch�the�strobe�pulse.ŠMOVE.Bƒ#0,DEV1AC(A1)‡*ŠMOVE.Bƒ#0,DEV1AC(A1)‡*ŠMOVE.Bƒ#0,DEV1AC(A1)‡* 1ŠMOVE.Bƒ#8,DEV1AC(A1)‡Strobe�pulse�back�high�now. 6ŠMOVE.Wƒ#32,D1ŽTest�for�the�printer�acknowledge�pulse.CWAIT_ACK‚BTST.Bƒ#7,DEV1BD(A1)‡If�the�acknowledge�arrives�before�the7ŠBNE.S„DEV_ACK�loop�times�out�(approx.�100�us)�proceed.)ŠDBRA… D1,WAIT_ACK‰Otherwise,�return�. 0ŠMOVE.Wƒ#-1,D0ŽReturn�,��-->�no�ACK�yet.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTS 9DEV_ACKƒMOVE.Wƒ#100,D1�Arbitrary�timeout�count.‚Clear�the=DEVACK1ƒTST.B„DEV1AC(A1)Šacknowledge�pending�and�test�for�the:ŠBTST.Bƒ#7,DEV1BD(A1)‡acknowledge�pending�to�go�away.‚When(ŠBEQ.S„OUT_OKŽit�is�gone,�exit�normally.ŠDBRA…D1,DEVACK16ŠBRA.L„ERROR_RET‹If�it�doesn't�go,�exit�with�an�error. $OUT_OK„MOVE.Bƒ#0,D0�Set��status.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGEN*******************************************************************************'*ˆGET_STAT„DETERMINE�THE�PRINTER�STATUS*C*ˆThis‚is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to9*ˆcheck�the�printer�status�for�selected�and�out-of-paper.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*�‚Printer�is�selected�and�is�not�out-of-paper.2*�‚Printer�is�not�selected�or�is�out-of-paper.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** GET_STAT: 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.2ŠMOVE.BƒDEV1BD(A1),D1‡Pick�up�the�status�register.&ŠAND.B„#$05,D1�Mask�uninterested�bits.%ŠCMP.B„#$05,D1�Selected�and�no�fault? /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.&ŠRTSšReturn�to�caller�with�status�set.ŠPAGEN*******************************************************************************.*ˆDDP_RESETƒRESET�THE�DEVICE�FOR�NO�INTERRUPTS*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>*ˆset�up�the�device�control�registers�and�turn�off�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_RESET: ŠPUSH…SRŠINHIBIT–Disable�interrupts. 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. +ŠBCLR…#IRE,BIM_CTL3‡Disable�ACK�interrupts. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.+ŠTST.B„DEV1AC(A1)ŠClear�ACK�interrupt�flag. /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.ŠPOP†SR ŠRTSšReturn.ŠPAGEN*******************************************************************************5*ˆDDP_ENA_INTRƒENABLE�FOR�INTERRUPTS�FROM�THE�PRINTER*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%*ˆenable�the�hardware�for�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.*;*�Interrupt�level�at�the�hardware�interrupt�level�(masked).*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_ENA_INTR: *ŠBSET…#IRE,BIM_CTL3‡Enable�ACK�interrupts.*K*‚Since�the�hardware�does�not�support�FAULT�interrupts,�we�use�a�timer�callH*‚to�check�for�printer�faults.‚The�routine�FLT_TIMER�in�PRNTLIB�is�used.J*‚Its�purpose�is�to�request�an�activation�call�for�us.‚When�the�activation;*‚call�comes�in,�another�routine�in�PRNTLIB�will�handle�it.*L*‚If�we�get�an�ACKNOWLEDGE�interrupt�before�the�activation�call�comes�in,�weJ*‚clear�the�flag�FLT_REQ�(in�our�interrupt�service�routine).‚This�tells�usJ*‚that�we�no�longer�need �the�activation�call.‚If�however,�no�ACK�interruptJ*‚is�received,�our�flag�FLT_REQ�will�still�be�set�when�the�activation�callI*‚comes�in.‚This�forces�a�'DEVICE�NOT�READY'�error�code�to�be�returned�to *‚the�user.*0ŠST.B…FLT_REQ(A5)‰Set�FAULT�request�needed�flag.'ŠJSR†FLT_TIMER‹Use�the�PRNTLIB�routine. ŠRTSšReturn.ŠPAGEN********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*2*‰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.*(*‰1.‚Clear�the�hardware�interrupt�flags.%*‰2.‚Turn�off�interrupts�at�the�chip.**‰Entry:�A5�=�address�of�CCB.* *‰Calls:�none*N****************************************************************************** DO_INIT: ŠPUSH…SRŠINHIBIT–Disable�interrupts. 6ŠMOVE.BƒCCBVECT(A5),BIM_VEC3„Set�up�the�vector�number.9ŠMOVE.BƒCCBPPRIO(A5),BIM_CTL3ƒSet�up�the�interrupt�level. 1ŠMOVE.LƒCCBCHB(A5),A1‡Set�up�device�base�address.+ŠBSET.Bƒ#3,DEV1AC(A1)‡Set�data�strobe�HIGH.+ŠBSET.Bƒ#3,DEV1BC(A1)‡Set�input�prime�HIGH. 1ŠBSR.S„DDP_RESET‹Dis-able�interrupts�at�the�chip. ŠPOP†SRŠRTS ŠDS.W…30ŠENDNNNNŠPAGE1P117DRVƒIDNTƒ45,0ˆVERSAdos�MVME117�printer�driverNNNNN NNâëóIû@: ;EC#<+>3K;-ŠTTL„P117DRV:„VERSAdos�MVME117�printer�driverNNNNNNN ŠLLENƒ120K***************************************************************************K***************************************************************************K***************************************************************************K****************************************************************************+*ˆP117DRV:‚VERSAdos�MVME117�printer�driver.**ˆRevision�history:**ˆ11/11/85‚Initial�release.*K***************************************************************************K***************************************************************************K***************************************************************************K***************************************************************************ŠPAGEŠOPT�CRE,PCS,BRS***‰XREF…PRNT_INIT‰XREF…PRNT_COMMAND‰XREF…INTR_REC **‚Equate�files�included:* *ˆ9995.&.STR.EQ*ˆ9995.&.TCB.EQ*ˆ9995.&.CCB.EQ*ˆ9995.&.IOE.EQ*ˆ9995.&.NIO.EQ*ˆ9995.&.LV5.EQ*ˆ9995.&.UTILITY.MC*ˆ9995.&.PRNT.EQ*ˆ9995.&.PRNTCCB.EQŠNOLISTŠ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�9995.&.UTILITY.MC ŠTTL…PRNT.EQŠLISTŠINCLUDE�9995.&.PRNT .EQŠTTL…PRNTCCB.EQŠINCLUDE�9995.&.PRNTCCB.EQŠTTL…P117DRV.SAŠPAGE/ŠOFFSET‚PCCBDDP�Continue�with�channel-dependent*¦CCB�variable�space.  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*B*%%%„Device-dependent,�channel�related,�variables�start�here.‰%%%* *%%%Å%%%**%%%™(CCB�SPACE)¡%%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*>*%%%„End�of�device�dependent,�channel�related,�variables.�%%%* *%%%Å%%%**%%%•END�OF�CCB�SPACE %%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  3CCBSIZEB�EQU†*–CCBSIZEB�defines�the�size�(in�bytes)$*¦of�a�complete�CCB�for�this�driver. %*¨CCBSIZE�defines�the�size�(in�pages)CL0080„EQU†CCBSIZEB+PAGESIZE-1‚of�a�CCB�for�the�driver,�and�EXTCCBSZ=CCBSIZE‚EQU†L0080/PAGESIZE‡defines�the�size�(in�pages)�of�the>EXTCCBSZ�EQU†CCBSIZE-1Œextended�portion�of�a�CCB.�The�extended(*¦portion�of�the�CCB�is�used�exclusively)*¦for�device-dependent�variables�that�are(*¦required�by�the�driver.‚There�are�$100'*¦bytes�per�page�of�memory,�and�the�CCB)*¦is�dynamically�allocated�as�an�integral*¦number�of�pages.‰PAGE** DEVICE EQUATES:*&PIO0…EQU‡0“Port�0�data�register�offset&PIO1…EQU‡2“Port�1�data�register�offset0PPCR…EQU‡4“Parallel�port�control�register�offset(MCR†EQU‡6“Module�control�register�offset'MSR†EQU‡8“Module�status�register�offset0CP0FLAG‚EQU‡8“Clear�port�0�flags�register�offset1CP1FLAG‚EQU†10“Clear�port�1�flags�register�offset ,INTEN0ƒEQU‡0“Interrupt�enable�bit�for�port�0,INTEN1ƒEQU‡4“Interrupt�enable�bit�for�port�1 **‚Definitions:*$*‚Name‚AddressƒR/W‡Level…Description3*‚----‚-------ƒ---‡-----…--------------------------)*‚PIO0‚F44001„R/W‘Printer�status�(port�0)*œhigh‡D5�=�printer�is�selected#*œhigh‡D6�=�printer�is�out-of-paper*œhigh‡D7�=�printer�is�busy*5*‚PIO1‚F44003„R/W‘Printer�output�data,�D0-D7�(port�1)***‚PPCR‚F44005„R/W‘Printer�control�register"*œlowˆD0�=�enable�fault�interrupts *œlowˆD4�=�enable�ack�interrupts"*œlow->hi„D6�=�printer�data�strobe%*œlowˆD7�=�program�port�1�for�outputs*.*‚MSRƒF44009„R�onlyŽPrinter�acknowledge�status'*§D7�=�ack�(port�1)�acknowledge�pending)*§D6�=�fault�(port�0)�acknowledge�pending*5*‚CP0ƒF44009„W�onlyŽClears�fault�(port�0)�acknowledge#*¦(must�wait�for�MSR[6]�to�go�high)*3*‚CP1ƒF4400B„W�onlyŽClears�ack�(port�1)�acknowledge#*¦(must�wait�for�MSR[7]�to�go�high)*‰PAGE ‰SECTION�0O********************************************************************************1*ˆSERVICE�VECTOR�TABLE,�PARAMETERS,�REVISION�INFO*@*ˆThe�first‚several‚locations�of�every‚I/O�driver�must�contain�aB*ˆservice�vector�table�to�contain�the‚long-word�relative�addressesB*ˆof�the�three�driver�subroutines�that�CMR�uses.‚The�CMR�parameterC*ˆtable�immediately�follows�the�service�vector�table�and�includes�aA*ˆfield�telling‚CMR‚how�many�extra�pages‚to�allocate�for�the�CCB.E*ˆThe�revision�table�immediately�follows�the�the�CMR�parameter�table.*O*******************************************************************************O******************************************************************************* ‰SECTION‚0 P117DRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!* <‰DC.L…INTERUPT-P117DRV…Address�of�interrupt�service�routine.:‰DC.L…COMMANDS-P117DRV…Address�of�command�service�routine.5‰DC.L…INIT-P117DRV‰Address�of�initialization�routine.‰DC.L…0”Reserved. **‚Other�CMR�parameters.*3‰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…'111185'�Date�of�last�asse mbly�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�printer�driver�PRNTLIB*O******************************************************************************* ‰BRA.L„DDP_OUTPUT‰BRA.L„GET_STAT‰BRA.L„DDP_RESET‰BRA.L„DDP_ENA_INTR‰PAGEO*******************************************************************************O*********************************************************************************ˆINITIALIZATION�ROUTINE*B*ˆThis‚subroutine�is�called�from�CMR‚when�CMR�is�invoked�by�a�taskB*ˆ(normally�IOI)�to‚allocate�a�channel.‚Its�purpose�is�to�give�theD*ˆdriver�a�chance�to�set�up�things�for�command�service�and�interrupt-*ˆservice.‚The�basic�functions�performed�are:*5*ˆ1.‚Put�the�start�address�of�the�driver�into�the�CCB*Œvariable�DRV_ADDR.?*ˆ2.‚Device-Independent�initialization�in�the�call�to�PRNT_INIT"*Žto�initialize�the�CCB�variables.?*ˆ3.‚Device-Dependent�initialization�in�the�call�to�DO_INIT�for"*Ždevice�dependent�initialization.*B*ˆThis�subroutine�is�entered�through�a�JSR�from�CMR,�and�will�exit7*ˆwith�an�RTS.‚The�processor�is�in�the�supervisor�mode.*%*ˆEntry:„A6�=�physical�address�of�TCB*’A5�=�physical�address�of�CCB*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*.*ˆRegisters�used�in�PRNT_INIT:…0�1�2�3�4�5�6�7*¦D*¦A‚*‰P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* INIT:*)*‚Get�address�of�start�of�driver�into�CCB*ŠLEA‡P117DRV(PC),A0ŠMOVE.L„A0,DRV_ADDR(A5)*>*‚Perform�the�device-independent�initialization�by�calling�the'*‚generic�routine�PRNT_INIT�in�PRNTLIB.*/‰JSR†PRNT_INITŒDo�the�device-independent�stuff.4‰IF‚‚THEN.SŽSomething�went�wrong�with�PRNT_INIT.‹RTS™The�channel�is�down�!!‰ENDI*8*‚Perform�any�device-dependent�initialization�in�DO_INIT*/‰BSR.L„DO_INITŽDevice�dependent�initialization.‰RTS‰PAGEO*******************************************************************************O*********************************************************************************ˆCOMMAND�SERVICE�ROUTINE*C*ˆThis�subroutine�is�called�from�CMR�when�CMR�receives�a�command�toA*ˆinitiate�an‚I/O�transaction‚with�a�device�that�is�controlled�by?*ˆthis�driver.‚Its�function�is�to‚process�the‚given�command‚andB*ˆqueue�the�command�to�the�controller.‚These�functions�are�handled(*ˆby�the�generic�printer�driver�PRNTLIB.*5*ˆEntry:„A2�=�physical�address�of�CMR�parameter�block*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*1*ˆRegisters�used�by�PRNT_COMMAND:†0�1�2�3�4�5�6�7*ªD‚*�*�*�*�*�*�**ªA‚*�*�*�*�*�P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* COMMANDS: *,*‚Perform�any�device-dependent�stuff�here...* =*‚We�have�received�a�command,�so�we�know�there�is�someone�out**‚there�to�talk�to.‚Let�PRNTLIB�handle�it.*&‰JSR†PRNT_COMMAND‹Perform�the�command.‰RTS�Return�to�CMR.‰TTL‡MVME117�INTERRUPT�HANDLER‰PAGEO*******************************************************************************O*********************************************************************************ˆINTERRUPT�SERVICE�ROUTINE**ˆEntry:„JSR�from�ISR�(in�CMR)*’A5�=�Physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚S�*�*�*�*�*�*�**™A‚S�S�*�*�*�S�**(*ˆCalls:„DDP_RESET‚INTR_REC�(in�PRNTLIB)**ˆExit:…RTS�to�CMR*O**************************************************************************  *****O******************************************************************************* INTERUPT: .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address. +ŠMOVE.BƒMSR(A1),D0ŠPick�up�status�register.ŠNOT.B„D0’BITS�ARE�ACTIVE�LOW!#ŠAND.B„#$C0,D0�Mask�interrupt�bits.1ŠBNE.S„PRTI010�Branch�if�an�interrupt�is�pending. 1ŠAND.W„#$FFFE,SR‹Not�for�me,�so�set�condition�and ŠRTSšreturn.*K*‚It�was�for�me,�but�if�the�channel�is�off-line�or�not�attached,�just�exit.*"PRTI010ƒBTSTW„#CCBFGOFF,CCBSTR(A5)"ŠBNE.S„PRTI020�Branch�if�off-line.ŠBTSTW„#CCBFGATH,CCBSTR(A5)1ŠBEQ.S„PRTI020�Branch�if�channel�is�not�attached.ŠTST.B„PRNTBUSY(A5)1ŠBNE.S„PRTI100�Branch�if�we�have�I/O�in�progress. 2PRTI020ƒBSR.L„DDP_RESET�Disable�device�interrupts.)ŠOR.W…#$0001,SR�We�handled�the�interrupt.ŠRTSŠPAGE*:*‚The�interrupt�is�for�me,�and�there�is�I/O�in�progress...*INT_REGS‚REG…D1-D7/A2-A4/A6 PRTI100:;ŠMOVEM.L�INT_REGS,-(SP)‡Save�the�registers�not�save�by�CMR.+ŠBSR.LƒDDP_RESETŒDisable�device�interrupts. (ŠMOVE.Wƒ#100,D1�Arbitrary�timeout�count.CPRTIACKƒMOVE.Bƒ#0,CP1FLAG(A1)†Clear�Acknowledge�interrupt�IRQ�flag.3ŠBTST.Bƒ#7,MSR(A1)ŠTest�for�ack�pending�to�go�away.#ŠBNE.S„PRTIACK1ŒBranch�out�if�gone..ŠDBRA…D1,PRTIACKŠNot�gone,�so�decrement�timer. 0PRTIACK1‚MOVE.Wƒ#100,D1�Arbitrary�timeout�count.=PRTIFLTƒMOVE.Bƒ#0,CP0FLAG(A1)†Clear�fault�interrupt�IRQ�flag.-ŠBTST.Bƒ#6,MSR(A1)ŠTest�for�fault�to�go�away.ŠBNE.S„PRTIFLT1ŒBranch�if�gone..ŠDBRA…D1,PRTIFLTŠNot�gone,�so�decrement�timer. APRTIFLT1‚ADD.B„#1,INTR_CNT(A5)…Increment�pending�interrupt�count.$ŠJSR†INTR_RECŒLet�PRNTLIB�handle�it. *2* Printer interrupt handler exits from this point.* PRTINRTN:9ŠSUB.B„#1,INTR_CNT(A5)†Decrement�pending�interrupt�count..ŠMOVEM.L‚(A7)+,INT_REGS‡Restore�the�registers.(ŠOR.W…#$0001,SRŒSet�return�condition�andŠRTS›return�to�CMR.ŠTTL†P117DRV.SAŠPAGEO********************************************************************************!*’R�O�U�T�I�N�E�SƒC�A�L�L�E�DƒB�Y**œP�R�N�T�L�I�B**O*******************************************************************************‰PAGEN*******************************************************************************0*ˆDDP_OUTPUTƒOUTPUT�THE�CHARACTER�TO�THE�PRINTER*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.*ˆoutput�the�character�in�D0.B�to�the�printer.**6*ˆEntry:�D0.B�=�character�to�be�output�to�the�printer.#*�A5ƒ=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚P�**™A„*‡P**ˆCalls:�GET_STAT‚DDP_RESET*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:-*�ˆCharacter�was�output�and�acknowledged.=*�,�‚Character�was�output�but�not�acknowledged�(yet).2*�,�‚Printer�error�condition�was�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_OUTPUT: 7ŠMOVEM.L‚D0-D1/A1,-(SP)†Save�the�registers�we�will�use. 1ŠMOVE.LƒCCBCHB(A5),A1‡A1�<--�device�base�address.'ŠBSR.L„GET_STATŒGet�the�current�status.ŠBEQ.S„PRNT_OK�Branch�if�ok.*9*‚Printer�error�condition�(out�of�paper�or�not�selected):*(ŠMOVE.Wƒ#100,D1�Arbitrary�timeout�count.>WAIT_FLT‚MOVE.Bƒ#0,CP0FLAG(A1)†Clear�fault�interrupt�IRQ�flag.1ŠBTST.Bƒ#6,MSR(A1)ŠTest�for�the�fault�to�go�away.ŠBNE.S„ERROR_RETŠDBRA…D1,WAIT_FLT =ERROR_RET�BSR.L„DDP_RESET‹Reprogram�device�for�no�interrupts.3ŠMOVE.Wƒ#1,D0�Return�,��-->�error�detected.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGE*J* Output the character; but before we output, see if we are to check BUSY.*,EQ410…EQU†CONFGBLK+IOSATW…User's�attributes. GPRNT_OKƒBTSTW„#IOABUSY,EQ410(A5)‚See�if�the�user�wants�us�to�wait�until6ŠIF‚‚THEN�the�printer�is�not�BUSY�before�printing.ŒMOVE.B�PIO0(A1),D14ŒAND  .B‚#$E0,D1�Mask�BUSY,�OUT-OF-PAPER�and�SELECTED.0ŒCMP.B‚#$A0,D1�Wait�as�long�as�we�are�BUSY,�have&ŒBEQ.S‚PRNT_OK�paper�and�are�SELECTED.ŒCMP.B‚#$20,D17ŒBNE.S‚ERROR_RET‹Error�if�OUT-OF-PAPER�or�not�SELECTED.ŠENDI )ŠMOVE.BƒD0,PIO1(A1)‰Output�the�data�byte.7ŠMOVE.BƒD0,PIO1(A1)‰Allow�data�to�settle�before�strobe.ŠMOVE.BƒD0,PIO1(A1)‰*ŠMOVE.BƒD0,PIO1(A1)‰*ŠMOVE.BƒD0,PIO1(A1)‰* :ŠBCLR…#6,PPCR(A1)‰Strobe�pulse�goes�low�(strobe�the�data).+ŠBCLR…#6,PPCR(A1)‰Stretch�the�strobe�pulse.ŠBCLR…#6,PPCR(A1)‰*ŠBCLR…#6,PPCR(A1)‰*ŠBCLR…#6,PPCR(A1)‰* -ŠBSET…#6,PPCR(A1)‰Strobe�pulse�back�high�now. 6ŠMOVE.Wƒ#32,D1ŽTest�for�the�printer�acknowledge�pulse.@WAIT_ACK‚BTST.Bƒ#7,MSR(A1)ŠIf�the�acknowledge�arrives�before�the7ŠBEQ.S„DEV_ACK�loop�times�out�(approx.�100�us)�proceed.)ŠDBRA…D1,WAIT_ACK‰Otherwise,�return�. 0ŠMOVE.Wƒ#-1,D0ŽReturn�,��-->�no�ACK�yet.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTS 9DEV_ACKƒMOVE.Wƒ#100,D1�Arbitrary�timeout�count.‚Clear�theBDEVACK1ƒMOVE.Bƒ#0,CP1FLAG(A1)†acknowledge�pending�and�test�for�the7ŠBTST.Bƒ#7,MSR(A1)Šacknowledge�pending�to�go�away.‚When(ŠBNE.S„OUT_OKŽit�is�gone,�exit�normally.ŠDBRA…D1,DEVACK16ŠBRA.L„ERROR_RET‹If�it�doesn't�go,�exit�with�an�error. $OUT_OK„MOVE.Bƒ#0,D0�Set��status.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGEN*******************************************************************************'*ˆGET_STAT„DETERMINE�THE�PRINTER�STATUS*C*ˆThis‚is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to9*ˆcheck�the�printer�status�for�selected�and�out-of-paper.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*�‚Printer�is�selected�and�is�not�out-of-paper.2*�‚Printer�is�not�selected�or�is�out-of-paper.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** GET_STAT: 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.0ŠMOVE.BƒPIO0(A1),D1‰Port�0�contains�status�bits.&ŠAND.B„#$60,D1�Mask�uninterested�bits.-ŠCMP.B„#$20,D1�Selected�and�not�Out-of-Paper? /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.&ŠRTSšReturn�to�caller�with�status�set.ŠPAGEN*******************************************************************************.*ˆDDP_RESETƒRESET�THE�DEVICE�FOR�NO�INTERRUPTS*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>*ˆset�up�the�device�control�registers�and�turn�off�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_RESET: ŠPUSH…SRŠINHIBIT–Disable�interrupts. 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.9ŠMOVE.Bƒ#$7F,PPCR(A1)‡Select�port�1�output,�port�0�input,$*¦and�disable�ACK,�FAULT�interrupts. 8ŠMOVE.Bƒ#00,CP0FLAG(A1)…Clear�FAULT�interrupt�on�port�0.6ŠMOVE.Bƒ#00,CP1FLAG(A1)…Clear�ACKƒinterrupt�on�port�1.  /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.ŠPOP†SR ŠRTSšReturn.ŠPAGEN*******************************************************************************5*ˆDDP_ENA_INTRƒENABLE�FOR�INTERRUPTS�FROM�THE�PRINTER*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%*ˆenable�the�hardware�for�interrup  ts.****ˆEntry:�A5�=�physical�address�of�the�CCB.*;*�Interrupt�level�at�the�hardware�interrupt�level�(masked).*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_ENA_INTR: 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.6ŠBCLR…#INTEN0,PPCR(A1)„Enable�device�FAULT�interrupts.4ŠBCLR…#INTEN1,PPCR(A1)„Enable�device�ACK�interrupts. /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used. ŠRTSšReturn.ŠPAGEN********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*2*‰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.*(*‰1.‚Clear�the�hardware�interrupt�flags.%*‰2.‚Turn�off�interrupts�at�the�chip.**‰Entry:�A5�=�address�of�CCB.* *‰Calls:�none*N****************************************************************************** DO_INIT: .ŠBSR.S„DDP_RESET‹Clear�and�disable�interrupts.ŠRTS ŠDS.W…30ŠENDNNNNNŠPAGE,PIADRV„IDNTƒ45,0ˆVERSAdos�PIA�printer�driverNNNN  NNNCLTK\6d9l@t@|C„?ŒB”Iœ'(ŠTTL„PIADRV:…VERSAdos�PIA�printer�driverNNNNNNN ŠLLENƒ120K***************************************************************************K***************************************************************************K***************************************************************************K****************************************************************************&*ˆPIADRV:‚VERSAdos�PIA�printer�driver.**ˆRevision�history:**ˆ11/11/85‚Initial�release.*K***************************************************************************K***************************************************************************K***************************************************************************K***************************************************************************ŠPAGEŠOPT�CRE,PCS,BRS***‰XREF…PRNT_INIT‰XREF…PRNT_COMMAND‰XREF…INTR_REC **‚Equate�files�included:* *ˆ9995.&.STR.EQ*ˆ9995.&.TCB.EQ*ˆ9995.&.CCB.EQ*ˆ9995.&.IOE.EQ*ˆ9995.&.NIO.EQ*ˆ9995.&.LV5.EQ*ˆ9995.&.UTILITY.MC*ˆ9995.&.PRNT.  EQ*ˆ9995.&.PRNTCCB.EQŠNOLISTŠ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�9995.&.UTILITY.MC ŠTTL…PRNT.EQŠLISTŠINCLUDE�9995.&.PRNT.EQŠTTL…PRNTCCB.EQŠINCLUDE�9995.&.PRNTCCB.EQŠTTL…PIADRV.SAŠPAGE/ŠOFFSET‚PCCBDDP�Continue�with�channel-dependent*¦CCB�variable�space.  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*B*%%%„Device-dependent,�channel�related,�variables�start�here.‰%%%* *%%%Å%%%**%%%™(CCB�SPACE)¡%%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*>*%%%„End�of�device�dependent,�channel�related,�variables.�%%%* *%%%Å%%%**%%%•END�OF�CCB�SPACE %%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  3CCBSIZEB�EQU†*–CCBSIZEB�defines�the�size�(in�bytes)$*¦of�a�complete�CCB�for�this�driver. %*¨CCBSIZE�defines�the�size�(in�pages)CL0080„EQU†CCBSIZEB+PAGESIZE-1‚of�a�CCB�for�the�driver,�and�EXTCCBSZ=CCBSIZE‚EQU†L0080/PAGESIZE‡defines�the�size�(in�pages)�of�the>EXTCCBSZ�EQU†CCBSIZE-1Œextended�portion�of�a�CCB.�The�extended(*¦portion�of�the�CCB�is�used�exclusively)*¦for�device-dependent�variables�that�are(*¦required�by�the�driver.‚There�are�$100'*¦bytes�per�page�of�memory,�and�the�CCB)*¦is�dynamically�allocated�as�an�integral*¦number�of�pages.‰PAGE** 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 **‚Definitions:**ƒPIA„PRINTER�LINE*ƒPIN‡NAME‰I/OƒACTIVE’USEB*ƒ---„-----------…---ƒ------‚-------------------------------------@*ƒCB2„INPUT�PRIME…out„low„Clear�printer�buffer�and�reset�printer *ƒCB1„FAULT‹in…low„Printer�fault-*ƒCA2„DATA�STROBE…out„low„Printer�data�strobe1*ƒCA1„ACKNOWLEDGE…in…low„Acknowledge�from�printer.*ƒPB2„BUSYŒin…highƒPrinter�cannot�receive�data2*ƒPB1„OUT�OF�PAPER„in…highƒPrinter�is�out�of�paper(*ƒPB0„SELECTŠin…highƒPrinter�is�selected* **‚DEV1AC�(DEV1BC)�Definition:*>*‚[7]…IRQA(B)1�flag†Goes�high�on�active�transition�of�CA1(CB1)#*�Cleared�by�reading�DEV1AD(DEV1BD)+*‚[6]…IRQA(B)2�flag†Not�used�by�this�driverI*‚[5:3]ƒCA2(CB2)�controlƒ(111)�=�CA2(CB2)�set�low‚on�Wrt-b3=0�to�CRA(CRB)+*¥CA2(CB2)�set�high�on�Wrt-b3=1�to�CRA(CRB):*‚[2]…DDR�access‰(0)ƒ=�Data�Direction�Register�is�selected(*�(1)ƒ=�Output�data�register�is�selectedD*‚[1]…CA1(CB1)�controlƒ(0)ƒ=�IRQA(B)1�set�by�high-to-low�on�CA1(CB1)/*�(1)ƒ=�IRQA(B)1�set�by�low-to-high�on�CA1(CB1)7*‚[0]…CA1(CB1)�controlƒ(0)ƒ=�Disable�IRQA(B)1�interrupt!*�(1)ƒ=�Enable‚IRQA(B)1�interrupt*?*‚The�control�registers,�DEV1AC�and�DEV1BC,�are�programmed�for:*N*‚-Data�Strobe�(CA2)�and�Input�Prime�(CB2)�follow�the�write�to�bit�3�of�CRA(B)$*‚-Select�the�output�data�registers.M*‚-Set�up�for�high-to-low�transitions�of�ACKNOWLEDGE�(CA1)�and�FAULT�(CB1)�toL*ƒgenerate�an�interrupt.‚The�transition�is�at�the�PIA�pin�not�the�connector.4*‚-Interrupts�on�ACKNOWLEDGE�and�FAULT�are�disabled.* DSDVIAƒEQU‡%00111100‹See�above.DSDVIBƒEQU‡%00111100‹See�above.‰PAGE ‰SECTION�0O********************************************************************************1*ˆSERVICE�VECTOR�TABLE,�PARAMETERS,�REVISION�INFO*@*ˆThe�first‚several‚locations�of�every‚I/O�driver�must�contain�aB*ˆservice�vector�table�to�contain�the‚long-word�relative�addressesB*ˆof�the�three�driver�subroutines�that�CMR�uses.‚The�CMR�parameterC*ˆtable�immediately�follows�the�service�vector�table�and�includes�aA*ˆfield�telling‚CMR‚how�many�extra�pages‚to�allocate�for�the�CCB.E*ˆThe�revision�table�immediately�follows�the�the�CMR�parameter�table.*O**************************************  *****************************************O******************************************************************************* ‰SECTION‚0 PIADRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!* ;‰DC.L…INTERUPT-PIADRV†Address�of�interrupt�service�routine.9‰DC.L…COMMANDS-PIADRV†Address�of�command�service�routine.4‰DC.L…INIT-PIADRVŠAddress�of�initialization�routine.‰DC.L…0”Reserved. **‚Other�CMR�parameters.*3‰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…'111185'�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�printer�driver�PRNTLIB*O******************************************************************************* ‰BRA.L„DDP_OUTPUT‰BRA.L„GET_STAT‰BRA.L„DDP_RESET‰BRA.L„DDP_ENA_INTR‰PAGEO*******************************************************************************O*********************************************************************************ˆINITIALIZATION�ROUTINE*B*ˆThis‚subroutine�is�called�from�CMR‚when�CMR�is�invoked�by�a�taskB*ˆ(normally�IOI)�to‚allocate�a�channel.‚Its�purpose�is�to�give�theD*ˆdriver�a�chance�to�set�up�things�for�command�service�and�interrupt-*ˆservice.‚The�basic�functions�performed�are:*5*ˆ1.‚Put�the�start�address�of�the�driver�into�the�CCB*Œvariable�DRV_ADDR.?*ˆ2.‚Device-Independent�initialization�in�the�call�to�PRNT_INIT"*Žto�initialize�the�CCB�variables.?*ˆ3.‚Device-Dependent�initialization�in�the�call�to�DO_INIT�for"*Ždevice�dependent�initialization.*B*ˆThis�subroutine�is�entered�through�a�JSR�from�CMR,�and�will�exit7*ˆwith�an�RTS.‚The�processor�is�in�the�supervisor�mode.*%*ˆEntry:„A6�=�physical�address�of�TCB*’A5�=�physical�address�of�CCB*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*.*ˆRegisters�used�in�PRNT_INIT:…0�1�2�3�4�5�6�7*¦D*¦A‚*‰P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* INIT:*)*‚Get�address�of�start�of�driver�into�CCB*ŠLEA‡PIADRV(PC),A0ŠMOVE.L„A0,DRV_ADDR(A5)*>*‚Perform�the�device-independent�initialization�by�calling�the'*‚generic�routine�PRNT_INIT�in�PRNTLIB.*/‰JSR†PRNT_INITŒDo�the�device-independent�stuff.4‰IF‚‚THEN.SŽSomething�went�wrong�with�PRNT_INIT.‹RTS™The�channel�is�down�!!‰ENDI*8*‚Perform�any�device-dependent�initialization�in�DO_INIT*/‰BSR.L„DO_INITŽDevice�dependent�initialization.‰RTS‰PAGEO*******************************************************************************O*********************************************************************************ˆCOMMAND�SERVICE�ROUTINE*C*ˆThis�subroutine�is�called�from�CMR�when�CMR�receives�a�command�toA*ˆinitiate�an‚I/O�transaction‚with�a�device�that�is�controlled�by?*ˆthis�driver.‚Its�function�is�to‚process�the‚given�command‚andB*ˆqueue�the�command�to�the�controller.‚These�functions�are�handled(*ˆby�the�generic�printer�driver�PRNTLIB.*5*ˆEntry:„A2�=�physical�address�of�CMR�parameter�block*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*1*ˆRegisters�used�by�PRNT_COMMAND:†0�1�2�3�4�5�6�7*ªD‚*�*�*�*�*�*�**ªA‚*�*�*�*�*�P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* COMMANDS:   *,*‚Perform�any�device-dependent�stuff�here...* =*‚We�have�received�a�command,�so�we�know�there�is�someone�out**‚there�to�talk�to.‚Let�PRNTLIB�handle�it.*&‰JSR†PRNT_COMMAND‹Perform�the�command.‰RTS�Return�to�CMR.‰TTL‡PIA�INTERRUPT�HANDLER‰PAGEO*******************************************************************************O*********************************************************************************ˆINTERRUPT�SERVICE�ROUTINE**ˆEntry:„JSR�from�ISR�(in�CMR)*’A5�=�Physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚S�*�*�*�*�*�*�**™A‚S�S�*�*�*�S�**(*ˆCalls:„DDP_RESET‚INTR_REC�(in�PRNTLIB)**ˆExit:…RTS�to�CMR*O*******************************************************************************O******************************************************************************* INTERUPT: .Š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�Acknowledge�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�Fault�interrupt�pending?ŠBEQ.S„PRTI010�Branch�if�yes. 1ŠAND.W„#$FFFE,SR‹Not�for�me,�so�set�condition�and ŠRTSšreturn.*K*‚It�was�for�me,�but�if�the�channel�is�off-line�or�not�attached,�just�exit.*"PRTI010ƒBTSTW„#CCBFGOFF,CCBSTR(A5)"ŠBNE.S„PRTI020�Branch�if�off-line.ŠBTSTW„#CCBFGATH,CCBSTR(A5)1ŠBEQ.S„PRTI020�Branch�if�channel�is�not�attached.ŠTST.B„PRNTBUSY(A5)1ŠBNE.S„PRTI100�Branch�if�we�have�I/O�in�progress. 2PRTI020ƒBSR.L„DDP_RESET�Disable�device�interrupts.)ŠOR.W…#$0001,SR�We�handled�the�interrupt.ŠRTSŠPAGE*:*‚The�interrupt�is�for�me,�and�there�is�I/O�in�progress...*INT_REGS‚REG…D1-D7/A2-A4/A6 PRTI100:;ŠMOVEM.L�INT_REGS,-(SP)‡Save�the�registers�not�save�by�CMR.+ŠBSR.LƒDDP_RESETŒDisable�device�interrupts. 9ŠADD.B„#1,INTR_CNT(A5)…Increment�pending�interrupt�count.$ŠJSR†INTR_RECŒLet�PRNTLIB�handle�it. *2* Printer interrupt handler exits from this point.* PRTINRTN:9ŠSUB.B„#1,INTR_CNT(A5)†Decrement�pending�interrupt�count..ŠMOVEM.L‚(A7)+,INT_REGS‡Restore�the�registers.(ŠOR.W…#$0001,SRŒSet�return�condition�andŠRTS›return�to�CMR.ŠTTL†PIADRV.SAŠPAGEO********************************************************************************!*’R�O�U�T�I�N�E�SƒC�A�L�L�E�DƒB�Y**œP�R�N�T�L�I�B**O*******************************************************************************‰PAGEN*******************************************************************************0*ˆDDP_OUTPUTƒOUTPUT�THE�CHARACTER�TO�THE�PRINTER*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.*ˆoutput�the�character�in�D0.B�to�the�printer.**6*ˆEntry:�D0.B�=�character�to�be�output�to�the�printer.#*�A5ƒ=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚P�**™A„*‡P**ˆCalls:�GET_STAT‚DDP_RESET*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:-*�ˆCharacter�was�output�and�acknowledged.=*�,�‚Character�was�output�but�not�acknowledged�(yet).2*�,�‚Printer�error�condition�was�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_OUTPUT: 7ŠMOVEM.L‚D0-D1/A1,-(SP)†Save�the�registers�we�will�use. 1ŠMOVE.LƒCCBCHB(A5),A1‡A1�<--�device�base�address.'ŠBSR.L„GET_STATŒGet�the�current�status.ŠBEQ.S„PRNT_OK�Branch�if�ok.*9*‚Printer�error�condition�(out�of�paper�or�not�selected):* =ERROR_RET�BSR.L„DDP_RESET‹Reprogram�device�for�no�interrupts.3ŠMOVE.Wƒ#1,D0�Return�,��-->�error�detected.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGE*J* Output the character; but before we output, see if we are to check BUSY.*  ,EQ410…EQU†CONFGBLK+IOSATW…User's�attributes. GPRNT_OKƒBTSTW„#IOABUSY,EQ410(A5)‚See�if�the�user�wants�us�to�wait�until6ŠIF‚‚THEN�the�printer�is�not�BUSY�before�printing.ŒMOVE.B�DEV1BD(A1),D14ŒAND.B‚#$07,D1�Mask�BUSY,�OUT-OF-PAPER�and�SELECTED.0ŒCMP.B‚#$05,D1�Wait�as�long�as�we�are�BUSY,�have&ŒBEQ.S‚PRNT_OK�paper�and�are�SELECTED.ŒCMP.B‚#$01,D17ŒBNE.S‚ERROR_RET‹Error�if�OUT-OF-PAPER�or�not�SELECTED.ŠENDI +ŠMOVE.BƒD0,DEV1AD(A1)‡Output�the�data�byte.9ŠMOVE.BƒD0,DEV1AD(A1)‡Allow�data�to�settle�before�strobe.ŠMOVE.BƒD0,DEV1AD(A1)‡*ŠMOVE.BƒD0,DEV1AD(A1)‡*ŠMOVE.BƒD0,DEV1AD(A1)‡* <ŠBCLR…#3,DEV1AC(A1)‡Strobe�pulse�goes�low�(strobe�the�data).-ŠBCLR…#3,DEV1AC(A1)‡Stretch�the�strobe�pulse.ŠBCLR…#3,DEV1AC(A1)‡*ŠBCLR…#3,DEV1AC(A1)‡*ŠBCLR…#3,DEV1AC(A1)‡* /ŠBSET…#3,DEV1AC(A1)‡Strobe�pulse�back�high�now. 6ŠMOVE.Wƒ#32,D1ŽTest�for�the�printer�acknowledge�pulse.CWAIT_ACK‚BTST.Bƒ#7,DEV1AC(A1)‡If�the�acknowledge�arrives�before�the6ŠBNE.S„OUT_OKŽloop�times�out�(approx.�100�us)�proceed.)ŠDBRA…D1,WAIT_ACK‰Otherwise,�return�. 0ŠMOVE.Wƒ#-1,D0ŽReturn�,��-->�no�ACK�yet.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTS =OUT_OK„TST.B„DEV1AD(A1)ŠClear�the�ACKNOWLEDGE�interrupt�flag.ŠMOVE.Bƒ#0,D0�Set��status.6ŠMOVEM.L‚(SP)+,D0-D1/A1†Restore�the�registers�we�used.ŠRTSŠPAGEN*******************************************************************************'*ˆGET_STAT„DETERMINE�THE�PRINTER�STATUS*C*ˆThis‚is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to9*ˆcheck�the�printer�status�for�selected�and�out-of-paper.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*�‚Printer�is�selected�and�is�not�out-of-paper.2*�‚Printer�is�not�selected�or�is�out-of-paper.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** GET_STAT: 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.2ŠMOVE.BƒDEV1BD(A1),D1‡Pick�up�the�status�register.&ŠAND.B„#$03,D1�Mask�uninterested�bits.-ŠCMP.B„#$01,D1�Selected�and�not�Out-of-Paper? /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.&ŠRTSšReturn�to�caller�with�status�set.ŠPAGEN*******************************************************************************.*ˆDDP_RESETƒRESET�THE�DEVICE�FOR�NO�INTERRUPTS*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>*ˆset�up�the�device�control�registers�and�turn�off�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_RESET: ŠPUSH…SRŠINHIBIT–Disable�interrupts. 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address. ?ŠMOVE.Bƒ#DSDVIA,DEV1AC(A1)‚Program�the�A-side�(interrupts�off).?ŠMOVE.Bƒ#DSDVIB,DEV1BC(A1)‚Program�the�B-side�(interrupts�off). +ŠTST.B„DEV1AD(A1)ŠClear�ACKƒinterrupt�flag.-ŠTST.B„DEV1BD(A1)ŠClear�FAULT�interrupt�flag. /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used.ŠPOP†SR ŠRTSšReturn.ŠPAGEN*******************************************************************************5*ˆDDP_ENA_INTRƒENABLE�FOR�INTERRUPTS�FROM�THE�PRINTER*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%*ˆenable�the�hardware�for�interrup  ts.****ˆEntry:�A5�=�physical�address�of�the�CCB.*;*�Interrupt�level�at�the�hardware�interrupt�level�(masked).*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„*‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** DDP_ENA_INTR: 0ŠMOVE.LƒA1,-(SP)ŒSave�the�registers�we�will�use. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.3ŠBSET…#0,DEV1BC(A1)‡Enable�device�FAULT�interrupts.1ŠBSET…#0,DEV1AC(A1)‡Enable�device�ACKƒinterrupts. /ŠMOVE.Lƒ(SP)+,A1ŒRestore�the�registers�we�used. ŠRTSšReturn.ŠPAGEN********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*2*‰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.*.*‰1.‚Program�the�PIA�pins�for�input�or�output.A*‰2.‚Program�the�PIA�for�the�desired�mode�and�disable�interrupts.2*‰3.‚Turn�off�the�LED�if�this�is�a�RTTLIO�channel.**‰Entry:�A5�=�address�of�CCB.* *‰Calls:�none*N****************************************************************************** DO_INIT: ŠPUSH…SRŠINHIBIT–Disable�interrupts. .ŠMOVE.LƒCCBCHB(A5),A1‡Get�device�base�address.>ŠMOVE.Bƒ#$00,DEV1AC(A1)…Select�A-side�Data�Direction�Register.>ŠMOVE.Bƒ#$00,DEV1BC(A1)…Select�B-side�Data�Direction�Register.=ŠMOVE.Bƒ#$FF,DEV1AD(A1)…Set�A-side�as�all�output�(data�port). *ŠCMP.B„#XTPRTL,CCBTYPE(A5)�RTTLIO�channel?0ŠIF‚‚THEN�Yes�-�set�PB7�as�an�output�for�LED;ŒMOVE.B�#$80,DEV1BD(A1)…control,�PB6-PB0�are�status�inputs.ŠELSE:ŒMOVE.B�#$00,DEV1BD(A1)…No�-�set�PB7-PB0�as�status�inputs.ŠENDI 8ŠBSR.S„DDP_RESET‹Program�the�PIA�and�disable�interrupts. *ŠCMP.B„#XTPRTL,CCBTYPE(A5)�RTTLIO�channel? ŠIF‚‚THEN5ŒMOVE.B�#00,DEV1BD(A1)†Yes�-�turn�off�the�RTTLIO�LED.ŠENDI ŠPOP†SRŠRTS ŠDS.W…30ŠENDNNN‰PAGE:PRNTLIB‚IDNT†45,0†VERSAdos�printer�driver�generic�routines6‰TTL‡PRNTLIB:‚VERSAdos�printer�driver�generic�routines ‰LLEN†120 ‰OPT‡CRE,PCS,BRSO*******************************************************************************O*******************************************************************************O********************************************************************************+*‰PRNTLIB:‚VERSAdos‚Printer‚Driver‚Routines*:*‰Purpose:‚A�collection�of�printer�driver�routines�used�to *“support�the�following�drivers: *œP050DRV *œP117DRV*œPIADRV**‰Revision�history:7*�12/06/85‚Install�NEW�Killer�modification�which�leaves,*šThe�Driver�ID�(Number)�and�Reason�(Number)2*šin�CRASHSAV�along�with�the�CCB�and�DCB�pointers.<*�11/12/85‚Extracted�from�VERSAdos�4.4�release�of�P050DRV.SA**‰RMS68K�routines�used: *�TR0$.RQPA*�TR0$.QEVENTI*�TR0$.QEVENTT *�TR0$.LOGPHY*�TR0$.DRIVKILL *�TR0$.GETTCB**‰Other�notes:0*�This�code�is�ROMable�and�position-independen  t.*O*******************************************************************************O*******************************************************************************O*******************************************************************************  * *‚INCLUDES***ˆ9995.&.IOE.EQ*ˆ9995.&.STR.EQ*ˆ9995.&.TCB.EQ*ˆ9995.&.NIO.EQ*ˆ9995.&.LV5.EQ*ˆ9995.&.CCB.EQ*ˆ9995.&.UTILITY.MC*ˆ9995.&.PRNT.EQ*ˆ9995.&.PRNTCCB.EQ*ˆ9995.&.KILL.MC*ˆ9995.&.KILLDRV.EQ*‰NOLIST‰INCLUDEƒ9995.&.IOE.EQ‰INCLUDEƒ9995.&.STR.EQ‰INCLUDEƒ9995.&.TCB.EQ‰INCLUDEƒ9995.&.NIO.EQ‰INCLUDEƒ9995.&.LV5.EQ‰INCLUDEƒ9995.&.CCB.EQ‰INCLUDEƒ9995.&.UTILITY.MC‰INCLUDEƒ9995.&.PRNT.EQ‰INCLUDEƒ9995.&.PRNTCCB.EQ‰INCLUDEƒ9995.&.KILL.MC‰INCLUDEƒ9995.&.KILLDRV.EQ‰LIST‰PAGEO********************************************************************************4*ƒEQUATES�AND�MACROS�FOR�THE�GENERIC�PRINTER�LIBRARY*¤J­NµB½KÅ2Í<Õ=Ý<å;í:õ9ý;7 :4=%>-35?=2E9MEUH]3e3m;uO*********************************************************************************@*ƒOFFSET�TO�MARK�THE�END�OF�THE�SERVICE�VECTOR�TABLE�IN�A�DRIVER*SERVECT‚EQU‡$28*=*‚A�DRIVER�THAT�WISHES�TO�USE�PRNTLIB�MUST�HAVE�THE�FOLLOWING>*‚BRANCH�TABLE�IMMEDIATELY�FOLLOWING�THE�SERVICE�VECTOR�TABLE:**†BRA.L‡DDP_OUTPUT*†BRA.L‡GET_STAT*†BRA.L‡DDP_RESET*†BRA.L‡DDP_ENA_INTR*‰OFFSET„SERVECTT_DDP_OUTPUT‡DS.L†1T_GET_STAT‰DS.L†1T_DDP_RESETˆDS.L†1T_DDP_ENA_INTR…DS.L†1** O********************************************************************************>*ƒMACRO�TO�PERFORM�THE�JUMP�TO�the�device�DEPENDENT�SUBROUTINE**ƒAssumption:‚None.**ƒCalled�by:ƒT_JSR‚ROUTINE*2*‰where‚T_ROUTINE�is�an�offset�in�the�above�table.*O******************************************************************************** T_JSR„MACRO ‰IFC�'\1','' ŒFAIL‚400ŒMEXIT‰ENDC‰MOVE.L�A4,-(SP)‰MOVE.L�DRV_ADDR(A5),A4 ‰JSR„T_\1(A4)‰MOVE.L�(SP)+,A4‰ENDM‰PAGEO********************************************************************************2*ƒDescriptions�of�the�routines�required�by�PRNTLIB*O*******************************************************************************  N*******************************************************************************0*ˆDDP_OUTPUTƒOUTPUT�THE�CHARACTER�TO�THE�PRINTER*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.*ˆoutput�the�character�in�D0.B�to�the�printer.**6*ˆEntry:�D0.B�=�character�to�be�output�to�the�printer.#*�A5ƒ=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚P*™AŒP**ˆCalls:�GET_STAT‚DDP_RESET*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:-*�ˆCharacter�was�output�and�acknowledged.=*�,�‚Character�was�output�but�not�acknowledged�(yet).2*�,�‚Printer�error�condition�was�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N******************************************************************************ŠPAGEN*******************************************************************************'*ˆGET_STAT„DETERMINE�THE�PRINTER�STATUS*C*ˆThis‚is�a�device�dependent�routine�whose�offset�must�be�installedD*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to9*ˆcheck�the�printer�status�for�selected�and�out-of-paper.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™AŒP* *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*�‚Printer�is�selected�and�is�not�out-of-paper.2 *�‚Printer�is�not�selected�or�is�out-of-paper.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N******************************************************************************ŠPAGEN*******************************************************************************.*ˆDDP_RESETƒRESET�THE�DEVICE�FOR�NO�INTERRUPTS*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>*ˆset�up�the�device�control�registers�and�turn�off�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™AŒP* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N******************************************************************************  N*******************************************************************************5*ˆDDP_ENA_INTRƒENABLE�FOR�INTERRUPTS�FROM�THE�PRINTER*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%*ˆenable�the�hardware�for�interrupts.****ˆEntry:�A5�=�physical�address�of�the�CCB.*;*�Interrupt�level�at�the�hardware�interrupt�level�(masked).*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™AŒP* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N******************************************************************************‰PAGEO********************************************************************************;*ƒDEVICE-DEPENDENT�ROUTINES‚THAT�ARE�NOT�CALLED�BY�PRNTLIB,9*ƒBUT�NEVERTHELESS�NEED�TO�DO�CERTAIN�THINGS�FOR�PRNTLIB.*O*********************************************************************************INIT:>*…This�is�the�entry�point�for�an�INITIALIZATION�call�from�CMR.*‰INIT�must�do�the�following:*6*ŽPut�the�starting�address�of�the�driver�into�the�CCB:*�LEA…MY_DRVR(PC),A0*�MOVE.L‚A0,DRV_ADDR(A5)**‘....**“RTSO*******************************************************************************‰PAGE** *‚XREF's.**C*‚This�XREF�is�from�the�driver�library�DRVLIB.RO�which�is�linked�in*‚at�SYSgen�time.*0‰XREF†LOGPHYŽConvert�logical�address�to�physical6‰XREF†I_NRM_QEVENTˆQueue�a�normal�I/O�completion�event*¦from�interrupt�handler6‰XREF†N_NRM_QEVENTˆQueue�a�normal�I/O�completion�event*¦from�command�level.4‰XREF†N_HLT_QEVENTˆQueue�a�halt�I/O�completion�event*¦from�command�level./‰XREF†SET_TIMEŒRequest�a�timer�activation�call.**L*‚These�XREF's�are�from�the�PRTTYPE�module,�table�of�valid�printer�channels.*0‰XREF†CH_TYPESŒChannel�types�for�printer�drivers0‰XREF†NUMTYPESŒNumber�of�supported�channel�types5‰XREF†NUMBYTESŒNumber�of�bytes�ber�entry�in�the�table *(*‚XDEF'S�for�the�device-dependent�module*2‰XDEF†PRNT_INIT‹Device-independent�initialization.6‰XDEF†PRNT_COMMANDˆDevice-independent�command�handler.)‰XDEF†INTR_RECŒInterrupt�handler�routine..‰XDEF†FLT_TIMER‹Printer�fault�handler�routine.  ‰SECTION�14PRNTLIB: **‚Identification�mnemonic*‰DC.B†'!PRNTLIB'**‚Revision�info:*/ŠDC.Bƒ'120685'‹Date�of�last�assembly�as�MMDDYY.1ŠDC.Bƒ'�'�Space�indicates�no�patches�to�.LO�file.)ŠDC.Bƒ'4'�Major�VERSAdos�revision�number.*ŠPAGEO*********************************************************************************‰NOTES�ON�CODING�STANDARDS*O******************************************************************************* G*‚Because�this�is�an�I/O�driver,�speed�is�of�the�utmost�importance,�andG*‚as�a�result�tradeoffs�were�made�decreasing�the�straightforwardness�ofL*‚the�code�in�favor�of�less�time�spent�processing�interrupts.‚In�particular,F*‚the�interrupt�service�portion�of�this�driver�is�not�at�all�modular--H*‚some�'routines'�have�multiple�entry�and�exit�points,�and�r eturn�is�not*‚always�to�the�caller.*G*‚One�visual�aid�used�which�may�save�you�some�work�is�the�use�of�labelsD*‚in�executable�code.‚Consider�the�following�sample�program�segment:*.*‰LABEL1:˜label�alone�on�line,�followed�by�':'*‘MOVE.B�......7*‰LABEL2:�ADD.B‚......Šlabel�not�alone,�followed�by�':'-*‰LABEL3‚CMP.B‚......Šlabel�not�alone,�no�':'*F*‚Each�way�of�writing�the�label�has�its�own�significance.‚LABEL1�marksC*‚the�beginning�of�a�logical�module,�and�nothing�falls�into�LABEL1.G*‚LABEL2�is�a�label�branched�to�from�outside�the�logical�module.‚LABEL3F*‚is�a�'local'�label,�branched�to�only�from�within�the�logical�module.  >*‚For�each�subroutine,�register�usage�is�specified�as�follows:**‰Entry:�A5�=�address�of�CCB**‰Exit:‚A0�=�garbage(*�A1�=�address�of�our�side�of�the�device*G*‚The�entry�conditions�specify�only�the�REQUIREMENTS�of�the�routine.‚InI*‚other�words,�a�register�may�be�known�to�contain�a�particular�value,�butI*‚if�it�is�not�used�by�a�routine,�it�is�not�listed�as�an�entry�condition.J*‚The�exit�conditions�list�only�those�registers�which�CHANGE.‚In�the�aboveH*‚example,�the�fact�that�A5�is�not�listed�as�an�exit�condition�indicates"*‚that�it�still�points�to�the�CCB.*J*‚If�a�module�does�not�represent�a�subroutine�(that�is,�will�not�return�toK*‚the�code�it�was�entered�from),�the�exit�conditions�for�the�registers�will*‚not�be�specified.ŠPAGEJ****************************************************************************‰COMMAND�SWITCHING�TABLE*:*‰These�are�used�by�the�command�service�routine�to�jump�to.*‰the�appropriate�routine�to�handle�a�command.*J************************************************************************** ŠDS…0 CMDTBL:$ŠDC.WƒIOSTAT�REQUEST�STATUS�command.2ŠDC.WƒIOCHDC�CHANGE�DEFAULT�CONFIGURATION�command.ŠDC.WƒIOCNFG�CONFIGURE�command.ŠDC.WƒIOWRIT�WRITE�command. =NUMCMDSƒEQU„(*-CMDTBL)/2‡The�number�of�commands�in�the�table. JMPTBL:ŠDC.WƒREQSTAT-*ŠDC.WƒDFCONFIG-*ŠDC.WƒCONFIG-*3ŠDC.WƒWRITE-*ŒBiases�to�the�corresponding�routines. 7JMPOFF„EQU„JMPTBL-CMDTBL†Offset�between�the�two�tables.'*£Having�found�the�command�in�the�first&*£table,�this�offset�is�used�to�get�to(*£the�corresponding�value�in�the�second.‰PAGEO*******************************************************************************O*******************************************************************************O*********************************************************************************ˆINITIALIZATION�ROUTINE*B*ˆThis‚subroutine�is�called�from�the�device-dependent�driver�afterA*ˆit�receives�an�initialization�call�from�CMR.‚It's�purpose�is�to?*ˆset�things�up�for�command�service�and�interrupt�service.‚It's*ˆspecific�functions�are:**Š1.�Validate�the�channel�type.4*Š2.�Fill�in�the�driver�code,�recognized�attributes,*�and�recognized�parameters.*:*ˆEntry�is�through�a�JSR�from�the�device-dependent�module.?*ˆEntry�is�at�interrupt�level�0,�and�we�are�in�supervisor�mode.*%*ˆEntry:„A6�=�physical�address�of�TCB*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:ˆ0�1�2�3�4�5�6�7*œD‚*�**œA‚*‰P*D*ˆExit:…RTS�to�the�device-dependent�module�with�condition�codes�set: *”�and�‚channel�is�down./*”‹all�went�well,�OK�to�proceed�with�device*£dependent�I/O.*O*******************************************************************************O*******************************************************************************O******************************************************************************* ‰SECTIONƒ14‰DSˆ0 PRNT_INIT:*F*‚Check�the�channel�type�field�we�are�supposed�to�be�to�make�sure�it's*‚a�type�this�driver�handles.*/ŠMOVE.B�CCBTYPE(A5),D0…D0�<--�our�channel�type.7ŠLEA„CH_TYPES,A0ˆA0�<--�addr�of�table�of�channel�types. ŠFOR.W…D1=#1‚TO‚#NUMTYPESƒDOŒCMP.Bƒ(A0)+,D0 ŒBEQ‡CH_FOUNDŒADD.L…#NUMBYTES-1,A0ŠENDF*%*„BAD�CHANNEL�TYPE�!!!„SEND�BACK�*A‰MOV E.B�#ISTAICE,CHANDOWN(A5)‚Return�Indeterminate�Channel�Error.)‰MOVE.B„#-1,D0‹Set�condition�code�to�#‰RTS˜and�return�to�calling�routine.‰PAGE**…GOOD�CHANNEL�TYPE�!!!*CH_FOUND*D*…Our�device�code�and�channel�type�matches�that�stored�in�the�table.<*…Load�DRV_CODE,�REC_ATT�and�REC_PAR�from�the�table�entries.**—Channel�type‹(byte)*ŒA0‚---->‚Drive�code�(byte)*—Recognized�attributes‚(word)*—Recognized�parameters‚(word) <‰MOVE.B„(A0)+,DRV_CODE(A5)‚Store�the�device�code�in�the�CCB.7‰MOVE.W„(A0)+,REC_ATT(A5)ƒSet�up�the�attributes�and�the6‰MOVE.W„(A0)+,REC_PAR(A5)ƒparameters�masks�in�the�CCB. (‰MOVE.B„#0,D0�Return��status�(good).‰RTS‰PAGEO*******************************************************************************O*******************************************************************************O*********************************************************************************ˆCOMMAND�SERVICE�ROUTINE*B*ˆThis�subroutine�is�called‚from�the�device-dependent‚driver�afterD*ˆit�receives�a�command�to�initiate�an�I/O�transaction�with�a�deviceB*ˆthat�is�controlled�by�that�driver.‚The�purpose‚of�this�module�is@*ˆto�perform�the‚common�tasks‚that�are‚necessary�for‚all�command@*ˆroutines,�and�to‚direct�control‚to�the‚individual�routine‚thatB*ˆprocesses�the�given�command‚through�the�command�switching‚table.*5*ˆEntry:„A2�=�physical�address�of�CMR�parameter�block*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*"*ˆRegisters�usage:„0�1�2�3�4�5�6�7 *™D‚*�*‡*�**™A‚*ƒP�R�R�P�P*$*ˆEXIT:…A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*9*ˆExits�to:�The�routine�that�processes�the�given�command.*O*******************************************************************************O*******************************************************************************O******************************************************************************* PRNT_COMMAND: 6‰MOVE.LƒSP,SAVESP(A5)ŠSave�the�stack�pointer�so�we�can$*¦later�abort�at�any�level�of�nested$*¦subroutines�and�easily�restore�the%*¦stack�environment�that�existed�when*¦this�routine�began�execution. :‰MOVE.LƒXIOCPK(A2),D6ŠGet�the�physical�address�of�the�IOCB2‰MOVEQ.L‚#0,D5�for�the�command�into�A4.‚Subroutine7‰MOVE.WƒXIOPLN(A2),D5ˆLOGPHY1�converts�the�logical�IOCB?‰MOVE.LƒCCBTASKA(A5),A0†address�(in�D6)�into�a�physical�address)‰BSR.L„LOGPHY1Žfor�us.‚Subroutine�LOGPHY11‰MOVE.LƒD6,A4�returns�the�physical�address�of�the *¦IOCB�in�D6. 9‰MOVE.LƒXIOUID(A2),A3ˆA3�<--�physical�address�of�the�DCB. 3‰MOVEQIƒISTACDN,D1�If�the�channel�is�down,�go�queue:‰TST.B„CHANDOWN(A5)‰an�event�to�the�attached�task�to�indi-8‰BNE.S„CMDEXIT2�cate�that�the�channel�is�out�of�service.‰PAGE.‰MOVE.WƒIOSFCT(A4),D6ˆD6�<--�function�of�IOCB. **‚Check�for�HALT�command.* ŠCMP.W‚#IOHALT,D6ŒHALT�command�?#ŠBEQ.L‚HALT’Branch�if�HALT�command. ,ŠMOVE.L�A3,DCBPNTR(A5)ˆSave�the�DCB�address.-ŠMOVE.L�A4,IOCBPTR(A5)ˆSave�the�IOCB�address.ŠMOVE.L�CCBTASKA(A5),D0-ŠMOVE.L�D0,TCB_ADDR(A5)‡Save�the�TCB�address.ŠMOVE.W�IOSOPT(A4),D06ŠMOVE.W�D0,IOOPTS(A5)‰Save�the�user's�command�options. ** See if channel is busy.*"ŠTST.B„PRNTBUSY(A5)ˆChannel�busy�? ŠIF‚‚THEN6ŒMOVE.B�#XSTBSY,D0ŠBusy,�set�up�channel�error�code�and ŒRTS˜return.ŠENDI -‰MOVEQ„#NUMCMDS-1,D0ˆSet�up�the�loop�counter.:‰MOVEQ„#JMPOFF,D1‹D1�<--�offset�between�cmd�and�JMP�tables/‰LEA†CMDTBL,A0ŒA0�<--�address�of�command�table. 9CMD_SRCH�CMP.W„(A0)+,D6�Search�the�table�for�the�command.‰DBEQ…D0,CMD_SRCHŠ* 3‰IF‚‚THEN�If�we�found�the�command�in�the�table,8‹ADD.W‚-2(A0,D1),D1‰get�the�corresponding�entry�from�the4‹JMP„-2(A0,D1)Œjump�table�and�jump�to�the�routine�to‰ENDIšhandle�the�command. 1‰MOVEQIƒISTAIF,D1ŒWe�didn't�find�it,�so�exit�with(‰BRA.S„CMDEXIT2�INVALID�FUNCTION�status.‰PAGEO*******************************************************************************O** ****************************************************************************** *ˆREQUEST�STATUS�COMMAND�ROUTINE*G*ˆThe�command�service�processor�invokes�the�REQSTAT�routine�in�responseE*ˆto�a�status�command.‚Its�purpose‚is�to�set�up�the�user�task's�para-E*ˆmeter�block�to�reflect�the‚drive's�current�status�and�configuration<*ˆbased�on�the�configure�block�in�the�channel�control�block.*%*ˆEntry:„A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task**!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚**™A‚*�*�*�P�P�P**ˆCalls:„STATCONF*7*ˆExit:…Falls�through�to�common�exit�routine�(CMDEXIT).*O*******************************************************************************O******************************************************************************* REQSTAT: 7ŠLEA†CONFGBLK(A5),A1‡Set�up�A1�to�point�to�the�start�of%*¦the�configuration�block�in�the�CCB. 2ŠBSR.S„STATCONFŽSet�IOSDST,�IOSCTP,�IOSDTP,�IOSDRC%*¦in�the�user�task's�parameter�block. ?ŠMOVE.WƒREC_ATT(A5),IOSATM(A1)�Set�the�supported�attributes�and<ŠMOVE.WƒREC_PAR(A5),IOSPRM(A1)�parameters�masks�in�the�users(*¦parameter�block.‚The�masks�contain�all(*¦of�the�bits�significant�to�the�driver. >ŠMOVE.Lƒ#(IOSPLN/2)-1,D0„Copy�the�current�configuration�valuesAREQLOOPƒMOVE.Wƒ(A1)+,(A2)+‰from�the�configure�block�in�the�CCB�to8ŠDBRA…D0,REQLOOPŠthe�user�task's�status�parameter�block.ŠPAGEO*********************************************************************************ˆCOMMON�EXIT�ROUTINE*B*ˆThe�CMDEXIT‚routine�is�a‚common�exit�routine�that�is�used�by�theC*ˆmany�different�paths�through�the�command�service�routine.‚ControlC*ˆcomes�to�one�of�three�entry�points�below�to�terminate�processing.*%*ˆEntry:„A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB3*’A6�=�physical�address�of�TCB�of�the�attached�task**�D1.B�=�IOSSTA�status�value*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚R�P *™A‚*…P�P�P*1*ˆExit:…Return�to�device-dependent�module�via�RTS*O*******************************************************************************  BCMDEXIT1�MOVEQIƒISTAOK,D1ŒWe've�finished�processing�a�command�with'*¦no�errors�and�we�want�to�queue�an�I/O(*¦completion�event�to�the�attached�task. ECMDEXIT2�LEA‡DO_EVENT(PC),A0…We've�finished�processing�a�command�with8‰MOVE.L„#T0GUARD,D0‰an�error�and�we�want�to�queue�an�I/O2‰TRAP†#EXEC�completion�event�to�the�attached�task.$*¦The�status�value�for�the�completed&*¦command�is�in�D1.B�when�we�get�here. "*¨We�use�CALL-GUARDED�to�queue�the&*¦event�for�command�completion�so�that&*¦it�will�be�protected�from�any�events$*¦queued�from�the�interrupt�handler. BCMDEXIT3�MOVE.LƒSAVESP(A5),SPŠRestore�the�stack�pointer,�and�clear4‰MOVEQ„#0,D0�D0�to�indicate�that�the�command�service(‰RTS›routine�has�operated�properly.‚Then$*¦return�control�to�the�routine�that"*¦called�subroutine�PRNT_COMMANDS. #*¨This�exit�is�valid�from�any�level&*¦within�the�driver�because�we�restore(*¦the�SP�as�saved�upon�entry.�The�driver*¦remains�re-entrant.‰PAGEO******************************************************************************** *ˆSTATUS/CONFIGURE�COMMON�CHORES*F*ˆThe�subroutine�STATCONF�performs�functions�that�are�common�to�status?*ˆcommands,�configure�commands,�and�default�configure�commands.*6*ˆEntry:„A1�=�pointer�to�configure�block�of�CCB�or�DCB*’A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™DŒ*�**™A‚*�P�R�P�P�P*&*ˆExit:…Return�to�the�calling�routine.<*’A2�<--�start�of�user�task's�config/status�parameter�block.*O******************************************************************************* STATCONF: ;ŠMOVE.L‚IOSDBP(A4),D6ŠGet�the�physical�address�of�the�first9ŠMOVE.L‚#IOSDLN,D5‹location�of�the�user�task's�configure/?ŠMOVE.L‚TCB_ADDR(A5),A0†status �parameter�block�into�D6.‚LOGPHY17ŠBSR.LƒLOGPHY1Žconverts�the�logical�addres�of�the�users6ŠMOVE.L‚D6,A2�parameter�block�into�a�physical�address. 1ŠCLR.BƒIOSDST(A1)ŽReturn�'on-line'�device�status.7ŠMOVE.B‚CCBTYPE(A5),IOSCTP(A1)‚Return�the�channel�type.2ŠMOVE.B‚#XDSPRT,IOSDTP(A1)†Device�type�is�PRINTER.7ŠMOVE.B‚DRV_CODE(A5),IOSDRC(A1)�Return�the�driver�code.ŠRTSŠPAGEO*******************************************************************************O*********************************************************************************ˆDEFAULT�CONFIGURE�COMMAND*H*ˆThe�command�service�processor�invokes�the�DFCONFIG�routine�in�responseG*ˆto�a�default�configure�command.‚Its�purpose�is�to�establish�or�change>*ˆthe�drive's�default�configuration,�which�is�kept�in�the�DCB.*ˆarea.*%*ˆEntry:„A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚*�*�*�**™A‚*�*�*�P�P�P**ˆCalls:„STATCONF*;*ˆExit:…Branches�to�common�configuration�chores�(CONFGCOM).*O*******************************************************************************O******************************************************************************* DFCONFIG: 5ŠLEA†DCBDEV(A3),A1‰Set�up�A1�to�point�to�the�start�of%*¦the�configuration�block�in�the�DCB. 2ŠBSR.S„STATCONFŽSet�IOSDST,�IOSCTP,�IOSDTP,�IOSDRC%*¦in�the�user�task's�parameter�block. 2ŠBRA.S„CONFGCOMŽBranch�to�the�common�configuration *¦routine.ŠPAGEO*******************************************************************************O*********************************************************************************ˆCONFIGURE�COMMAND*F*ˆThe�command�service�processor�invokes�the�CONFIG�routine�in�responseC*ˆto�a‚configure�command.‚Its�purpose�is�to�establish�or‚change�the:*ˆdrive's�current�configuration,�which�is�kept�in�the�CCB.*%*ˆEntry:„A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚*�*�*�**™A‚*�*�*�P�P�P**ˆCalls:„STATCONF*B*ˆExit:…Falls�through�to�CONFGCOM�for�common�configuration�chores.*O*******************************************************************************O******************************************************************************* CONFIG: 7ŠLEA†CONFGBLK(A5),A1‡Set�up�A1�to�point�to�the�start�of%*¦the�configuration�block�in�the�CCB. 2ŠBSR.S„STATCONFŽSet�IOSDST,�IOSCTP,�IOSDTP,�IOSDRC%*¦in�the�user�task's�parameter�block. =ŠMOVE.B�#CECCDO,D3‰If�he's�trying�to�change�the�write�timeout?ŠBTSTW‚#IOSWTOB,IOSPRM(A2)�value,�return�a�configuration�error.ŠBNE.L‚CONERROR DŠMOVE.L�DCBDEV+IOSWTO(A3),IOSWTO(A1)�Update�(in�the�CCB)�the�timeout+*£values�from�the�DCB�so�they�can�be�copied-*£and�fall�into�common�configuration�routine.ŠPAGEO*********************************************************************************ˆCOMMON�CONFIGURATION�CHORES*D*ˆThe‚CONFGCOM‚routine�is�used�by�the‚configure�(CONFIG)�and�defaultF*ˆconfigure�(DFCONFIG)�routines.‚Its�purpose�is�to�do�most�of�the�work*ˆfor�both�of�them.*6*ˆEntry:„A1�=�pointer�to�configure�block�of�CCB�or�DCB1*’A2�=�pointer�to�user�task's�configuration�block*’A3�=�physical�address�of�DCB*’A4�=�physical�address�of�IOCB*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚*�*�*�* *™A„P�P�P�P�P* *ˆCalls:„none*3*ˆExit:…Branches�to�CMDEXIT1�if�no�errors�detected.0*’Branches�to�CONERROR�for�configuration�errors.*O******************************************************************************* CONFGCOM: 7ŠMOVE.Wƒ#CECUAP,D3ŒSet�up�for�an�error�exit�in�case�the&*¦user�is�trying�to�change�unsupported*¦attribut es�or�parameters. 3ŠMOVE.WƒIOSATM(A2),D0‡D0�<--�user's�attribute�bits.3ŠMOVE.WƒIOSPRM(A2),D2‡D2�<--�user's�parameter�bits. 6ŠMOVE.Wƒ#$FFFF,D1�If�the�user's�attribute�bits�contain;ŠSUB.W„REC_ATT(A5),D1†any�bits�that�are�not�allowed�for�the4ŠAND.W„D0,D1�IOSATM�field,�abort�with�the�error�code7ŠBNE.L„CONERRORŒin�D3.B�to�be�returned�to�the�user�task*¦in�the�IOSDST�field. 6ŠMOVE.Wƒ#$FFFF,D1�If�the�user's�parameter�bits�contain;ŠSUB.W„REC_PAR(A5),D1†any�bits�that�are�not�allowed�for�the4ŠAND.W„D2,D1�IOSPAR�field,�abort�with�the�error�code7ŠBNE.L„CONERRORŒin�D3.B�to�be�returned�to�the�user�task*¦in�the�IOSDST�field. E*‚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�A1�and�he's�at�A2.*6ŠMOVE.WƒIOSATM(A2),D0‡Set�up�the�users�attribute�mask.;ŠAND.W„D0,IOSATW(A2)‡Zero�out�the�attributes�of�his�that�he.ŠNOT.W„D0’doesn't�want�to�change,�zero�out�the<ŠAND.W„IOSATW(A1),D0‡attributes�of�mine�that�he�does�want�to:ŠOR.W…D0,IOSATW(A2)‡change,�and�combine�them�in�his�space. 8ŠMOVE.WƒIOSPRM(A2),D0‡Get�parameters�he�wants�to�change. 1ŠLSR.W‚#1,D0‘If�he's�not�changing�the�LINE�WIDTH,)ŠIF…�THEN.S‹copy�the�current�setting.�MOVE.W�IOSREC(A1),IOSREC(A2)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�LINES/PAGE,)ŠIF…�THEN.Sˆcopy�the�current�setting.�MOVE.L�IOSRSZ(A1),IOSRSZ(A2)ŠENDI 3ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�WRITE�TIMEOUT0ŠIF…�THEN.Sˆvalue,�copy�the�current�setting.�MOVE.L�IOSWTO(A1),IOSWTO(A2)Š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.S�MOVE.W�IOSLRL(A1),IOSLRL(A2)ŠENDI 1ŠLSR.W‚#1,D0ŽIf�he's�not�changing�the�END-OF-LINE1ŠIF…�THEN.SˆSTRING,�copy�the�current�setting.�MOVE.B�IOSELC(A1),IOSELC(A2)ŠENDI*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,D3ŠIf�the�auto-linefeed�attribute�is�set@ŠBTSTW„#IOALNFD,IOSATW(A2)�and�the�end�of�line�character�is�null+ŠIF‚‚THEN�return�a�configuration�error.ŒTST.B‚IOSELC(A2)ŒBEQ.S‚CONERRORŠENDI <ŠMOVE.Bƒ#CECPRLZ,D3‰If�either�the�logical�or�physical�record<ŠMOVE.WƒIOSREC(A2),D0‡length�is�zero,�return�a�configurationŠBEQ.S„CONERRORŒerror.ŠMOVE.WƒIOSLRL(A2),D2ŠBEQ.S„CONERROR 4ŠCMP.W„D2,D0�If�the�logical�record�length�is�greater5ŠBHS.S„OKCNFGŽthan�the�physical�record�length,�return*ŠMOVE.Bƒ#CECPLGP,D3‰a�configuration�error.ŠBRA.S„CONERRORŠPAGE*F*…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.**ˆExit:…Branches�to�CMDEXIT3�if�no�error�detected�in�printing.,*’Branches�to�CMDEXIT2�if�error�is�detected.*O*******************************************************************************O******************************************************************************* WRITE:+ŠMOVE.LƒTCB_ADDR(A5),A0…A0�<--�TCB�address. ŠBTSTW„#IOPTSKB,IOSOPT(A4)2ŠIF‚‚THEN�If�the�buffers�reside�in�a�different5ŒLEA„IOSTSK(A4),A0‡task�from�the�IOCB,�get�the�TCB�ofŒMOVE.L�#T0GETTCB,D0ˆthat�task. ŒTRAPƒ#EXEC#ŒBRA.S‚OKTCB�Branch�if�good�return,#ŒMOVE.B�#XSTADB,D1Šelse�exec�error.ŒBRA.L‚CMDEXIT2ŠENDI :OKTCB…MOVE.LƒA0,TCB_ADDR(A5)…Save�physical�address�of�TCB. :ŠADD.B„#1,TCBIOCNT(A0)…Increment�user's�pending�I/O�count.*D*‚Validate�the�buffer�in�the�IOCB�and�convert�to�physical�addresses:*;ŠMOVE.LƒIOSSAD(A4),D6‡D6�<--�buffer�physical�start�address.+ŠMOVE.LƒIOSEAD(A4),D5‡D5�<--�buffer�length.ŠSUB.L„D6,D5�* ŠADDQ…#1,D5�*+ŠBSR.L„LOGPHY1�Convert�to�physical�address. ;ŠMOVE.LƒD6,IOBUFPTR(A5)…Save�physical�start�address�in�CCB."ŠMOVE.LƒD6,A0�A0�<--�buffer�start.0ŠADD.L„D5,D6�Save�physical�end�address�plus�1�in ŠMOVE.LƒD6,IOBUFEND(A5)…the�CCB.ŠPAGE%ŠST.B…PRNTBUSY(A5)ˆMark�channel�busy.7ŠCLR.L„CHAR_CNT(A5)ˆInitialize�the�output�byte�counter.#ŠT_JSR„DDP_RESET‹Set�up�the�device. EQ410…EQU†CONFGBLK+IOSATW7ŠBTSTW„#IOASNFF,EQ410(A5)‚If�the�form�feed�after�assign3ŠIF‚‚THEN�attribute�is�0�send�a�FF�character�if9ŒTST.B‚DCBBCT(A3)Šthis�is�the�first�output�in�the�currentŒIF‚‚THEN�assignment.ŽST.BƒDCBBCT(A3)#ŽMOVE.B�#FF,D0ŒForm�Feed�character.&ŽBSR.L‚OUTPUTŒGo�output�the�form�feed.ŒENDIŠENDI *J*‚Now�begin�to�output�the�characters�(A0�is�pointing�to�the�buffer�start):*-*‚Check�for�IMAGE�or�FORMATTED�mode�printing.*&ŠBTSTW„#IOPFORB,IOOPTS(A5)�Image�mode?4ŠIF‚‚THEN�Image�mode�does�no�special�processing.**‚Printing�IMAGE�mode...* PRT_IMAGE:0ŒMOVE.B�(A0)+,D0ŒGet�next�data�byte�from�buffer.4ŒBSR.L‚OUTPUTŽSkip�the�special�character�processing..ŒMOVE.L�A0,IOBUFPTR(A5)…Update�buffer�pointer..ŒADD.L‚#1,CHAR_CNT(A5)…Count�each�byte�sent�to?ŒCMP.L‚IOBUFEND(A5),A0…the�printer�whether�printable�or�not.�If9ŒBNE.S‚PRT_IMAGE‹the �end�of�the�buffer�is�reached,�do�the-ŒBRA.L‚PRTDONE�request�completion�processing.ŠENDIŠPAGE**‚Printing�FORMATTED�mode...*PRT_FORMATTED:0ŠMOVE.Bƒ(A0)+,D0ŒGet�next�data�byte�from�buffer.0ŠCMP.B„#CR,D0ŽIf�the�current�buffer�character�is0ŠIF‚‚THEN.S�a�CR,�do�end-of-line�processing..ŒMOVE.LƒA0,IOBUFPTR(A5)ƒUpdate�buffer�pointer. ŒBRA.S„PRTEOLŠENDI 2ŠBSR.L„OUTPUTŽOutput�the�character�to�the�printer..ŠMOVE.LƒA0,IOBUFPTR(A5)…Update�buffer�pointer. 5ŠCMP.B„#'�',-1(A0)‹If�the�current�buffer�character�is.ŠBLT.S„CHK_BUFFŒnon-printing,�do�not�check�for**¦end-of-line�or�bump�the�character�count. *H*‚We�just�printed�a�printable�character�(>=$20),�this�section�does�this:*?*„IF�not�yet�printed�a�multiple�of�the�logical�line�length�THEN$*ˆproceed�to�the�end�of�buffer�check*C*„ELSE‚(we�have�just�printed�a�multiple�of�the�logical�line�length)4*†IF�logical�line�length�=�physical�line�length�THEN>*ˆoutput�a�Line�Feed�character�(if�user's�LF�attribute�is�off)*>*†ELSE‚(logical�line�length�is�less�than�physical�line�length)$*ˆIF�user's�LF�attribute�is�set�THEN)*Šoutput�the�user's�End-of-Line�Character*ˆELSE.*Šoutput�a�Line�Feed,�Carriage�Return�sequence*H*„In�simple�words,‚when�we�get�to�the�end�of�the�logical�line,�print�theI*„end-of-line�sequence�(EOL�character�or�LF,�CR).�If�we�are�at�the�end�ofI*„the�printers�physical�line,�print�a�LF�(if�necessary�for�this�printer).*ŠPAGE.EQ610…EQU†CONFGBLK+IOSLRL…LOGICAL‚line�length./EQ620…EQU†CONFGBLK+IOSREC…PHYSICAL�line�length.3EQ630…EQU†CONFGBLK+IOSELC…END�-�OF�-�LINE�CHARACTER%EQ640…EQU†CONFGBLK+IOSATW…Attributes. =ŠADD.L„#1,CHAR_CNT(A5)…Increment�the�printed�character�count.>ŠMOVE.LƒCHAR_CNT(A5),D2…D2�<--�number�of�chars�printed�so�far.5ŠDIVU…EQ610(A5),D2ˆDivide�by�the�logical�line�length.ŠSWAP…D2)ŠTST.W„D2’If�we�are�not�at�the�end�of�the6ŠBNE.S„CHK_BUFFŒlogical�line,�go�check�for�buffer�end.*N*‚We�have�just�printed�a�multiple�of�the�logical�line,�do�end-of-line�stuff...*0ŠMOVE.WƒEQ610(A5),D3ˆD3�<--�logical�line�length.9ŠCMP.W„EQ620(A5),D3ˆCompare�logical�with�physical�length.&ŠIF‚‚THEN.S�Logical�<>�Physical...0ŒMOVE.B�EQ630(A5),D0ˆD0�<-�user's�EOL�character.8ŒBTSTW‚#IOALNFD,EQ640(A5)‚Check�the�user's�LF�attribute.ŒIF‚‚THEN.S5ŽBSR.L‚OUTPUTŒLF�attribute�set,�output�EOL�character.7ŽBRA.S‚P_TRNCATE‰Continue�at�truncate�line�check�point.ŒENDI 7ŒMOVE.Bƒ#LF,D0ŒLF�attribute�off,�output�LF,CR�sequence.+ŒBSR.L„OUTPUTŒOutput�a�Line�Feed�character.ŒMOVE.Bƒ#CR,D01ŒBSR.L„OUTPUTŒOutput�a�Carriage�Return�character.7ŒBRA.S„P_TRNCATE‰Continue�at�truncate�line�check�point.ŠENDI*D*‚Printed�a�logical�line�and�the�logical�line�=�the�physical�line...*8ŠBTSTW„#IOALNFD,EQ640(A5)‚Check�the�user's�LF�attribute. ŠIF‚‚THEN6ŒMOVE.B‚#LF,D0�Printer�does�not�support�automatic�line5ŒBSR.SƒOUTPUT�feed,�so�output�a�LF�character�for�him.ŠENDI*'*‚Now�check�the�trucate�print�option...*HP_TRNCATE�BTSTW„#IOATPLL,EQ640(A5)‚Since�we�have�reached�an�end-of-line,2ŠBNE.S„PRTDONE�terminate�the�request�if�specified. @CHK_BUFF‚CMP.L„IOBUFEND(A5),A0…If�the�end�of�buffer�has�not�been6ŠBLO†PRT_FORMATTED‡reached,�output�the�next�character.9***‡BRA.S„PRTEOLŽBUFFER�EMPTY�...�do�end�of�buffer�stuff.ŠPAGE*G*‚We�have�just�printed�the�user's�buffer�(or�found�a�Carriage�Return�in2*‚the�buffer).‚Now�output�the�end-of-line�stuff...*3EQ650…EQU†CONFGBLK+IOSELC…END�-�OF�-�LINE�CHARACTER%EQ660…EQU†CONFGBLK+IOSATW…Attributes. PRTEOL:0ŠMOVE.BƒEQ650(A5),D0ˆD0�<-�user's�EOL�character.8ŠBTSTW„#IOALNFD,EQ660(A5)‚Check�the�user's�LF�attribute.ŠIF‚‚THEN.S5ŒBSR.S‚OUTPUTŽLF�attribute�set,�output�EOL�character.+ŒBRA.S‚PRTDONE�DONE�...�go�notify�the�user.ŠENDI 7ŠMOVE.Bƒ#LF,D0ŽLF�attribute�off,�output�LF,CR�sequence.+ŠBSR.S„OUTPUTŽOutput�a�Line�Feed�character.ŠMOVE.Bƒ#CR,D01ŠBSR.S„OUTPUTŽOutput�a�Carriage�Return�character.*I*‚We�have�completed�printing,�now�notify �the�user.�If�we�have�detected�anI*‚error�while�printing,�we�enter�at�PRT_ERROR�with�an�error�code�in�D1.W.*PRTDONE:)ŠMOVE.Wƒ#ISTAOK,D1ŠSet�up�OK�status�code. PRT_ERROR:'ŠSF.B…PRNTBUSY(A5)ˆClear�our�busy�flag.,ŠMOVE.LƒTCB_ADDR(A5),A0…Pick�up�TCB�address.:ŠSUB.B„#1,TCBIOCNT(A0)…Decrement�user's�I/O�pending�count. 1ŠMOVE.BƒD1,IOSSTA(A4)‹Update�user's�status�field.:ŠMOVE.LƒCHAR_CNT(A5),IOSLEN(A4)�Update�#�of�bytes�printed. 0ŠTST.B„INTR_CNT(A5)ˆSee�if�we�took�an�interrupt. ŠIF‚‚THEN;ŒSF.BƒNONINTERRUPT(A5)„Yes�-�set�up�for�an�interrupt�event.2ŒBSR.L‚Q_EVENT�Call�the�routine�to�send�the�event. ŒIF‚‚THEN&ŽKILL.DRIVER�PRNTLIB_ID,T0QEVNTI,A5,A3ŒENDI !ŠELSE‚(It's�a�command�type�event) 1ŒST.BƒNONINTERRUPT(A5)„Set�up�for�a�normal�event.2ŒBSR.L‚Q_EVENT�Call�the�routine�to�send�the�event.)ŒSF.BƒNONINTERRUPT(A5)„Set�for�next�time. ŒIF‚‚THEN&ŽKILL.DRIVER�PRNTLIB_ID,T0QEVNTT,A5,A3ŒENDIŠENDI %ŠBRA.L„CMDEXIT3ŒReturn�to�the�caller.ŠPAGEO*********************************************************************************ˆOUTPUT�A�CHARACTER�ROUTINE*;*ˆThe�OUTPUT�routine�is�to�send�a�character�to�the�printer.*'*ˆEntry:„D0.B�=�character�to�be�printed3*’A0ƒ=�pointing�to�the�next�character�to�be�printed*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚P*™A‚P***ˆCalls:„DDP_OUTPUT‚DDP_ENA_INTR‚DDP_RESET*=*ˆExit:…RTS�back�to�the�caller,�if�the�character�was�printed.8*’CMDEXIT3�if�the�character�was�printed,�but�the�printer$*’did�not�acknowledge�the�character.1*’PRT_ERROR�if�an�error�was�detected�in�printing.*O******************************************************************************* OUTPUT:>ŠMOVE.Lƒ(SP),INTSWTCH(A5)ƒSave�the�return�address�(if�no�ACK).*E*‚If‚we‚return‚from‚the‚DDP_OUTPUT�routine�with��status,‚then�theG*‚character‚was‚printed,�but�the�printer�has�not�yet�acknowledged.ƒWhenH*‚the‚acknowledge‚interrupt�comes�in,‚the�device-dependent�routine�callsJ*‚the�INTR_REC�routine.‚INTSWTCH�is�used�to�branch�to�the�point�just�afterK*‚whoever�called�the�OUTPUT�routine�in�the�first�place.�This�action�usuallyI*‚only‚occurs‚when�we�have�just�output�something�that�takes�the�printer�a>*‚long�time�to�do�(like�a�Form�Feed�or�a�Line�Feed�character).*8ŠT_JSR„DDP_OUTPUTŠCall�the�device-depend�output�routine. ŠIF‚‚THEN-ŒRTS˜Character�was�printed,�return�to�caller.ŠENDI3ŠIF‚‚THEN�Character�was�output,�but�the�printer ŒINHIBIT”did�not�acknowlege�yet..ŒMOVE.L�A0,IOBUFPTR(A5)…Update�buffer�pointer.7ŒT_JSR‚DDP_ENA_INTRˆEnable�interrupts�from�the�printer.2ŒBRA.L‚CMDEXIT3ŒAn�interrupt�will�let�us�continue.ŠENDI 8ŠT_JSR„DDP_RESET‹None�of�the�above,�so�it�must�have�been9ŠMOVE.Wƒ#ISTANR,D1Ša�printer�error.‚Reset�the�printer�and.ŠBRA.L„PRT_ERROR‹notify�the�user�of�the�error.ŠPAGEO*******************************************************************************O*********************************************************************************ˆHALT�I/O�COMMAND�ROUTINE*D*ˆThe�command�service�processor�invokes�the�HALT�routine�in�response@*ˆto�a�halt�command.‚Its�purpose�is�to�stop�the�I/O�in�progress.*%*ˆEntry:„A3�=�physical�address�of�DCB1*’A4�=�physical�address�of�IOCB�(of�HALT�command)*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D„*ƒ* *™A‚*…P�P�P**ˆCalls:„DDP_RESET‚N_HLT_QEVENT**ˆExit:…Branches�to�CMDEXIT3.*O*******************************************************************************O******************************************************************************* HALT:%ŠTST.B„PRNTBUSY(A5)ˆAny�I/O�pending�?*ŠIF‚‚THEN�There�was�nothing�to�halt...BŒMOVE.B�#ISTAIF,IOSSTA(A4)‚Update�user's�IOCB�of�the�HALT�command.-ŒMOVE.W�#ISTAIF,D1ŠSame�code�in�event�status.ŠELSE* *‚There�was�something�to�halt...*ŒINHIBIT'ŒT_JSR‚DDP_RESET‹Initialize�the�device.2ŒSF.BƒPRNTBUSY(A5)ˆClear�our�busy�flag�in�the�CCB.8ŒSF.BƒFLT_ REQ(A5)‰Clear�fault�request�in�case�it�is�set. =ŒMOVE.L�TCB_ADDR(A5),A0…Pick�up�the�TCB�address�of�IOCB�owner;ŒSUB.B‚#1,TCBIOCNT(A0)…and�decrement�his�pending�I/O�count. ?ŒMOVE.L�IOCBPTR(A5),A0†A0�<--�user's�IOCB�for�the�original�cmd.AŒMOVE.B�#ISTATO,IOSSTA(A0)‚Update�the�original�IOCB�status�field.?ŒMOVE.L�CHAR_CNT(A5),IOSLEN(A0)�Update�users�IOCB�length�field.4ŒCLR.L‚CHAR_CNT(A5)ˆClear�the�character�count�field. AŒMOVE.B�#ISTAOK,IOSSTA(A4)‚Update�the�IOCB�status�(HALT�command).-ŒMOVE.W�#ISTATO,D1ŠSet�up�event�status�field.ŠENDI /ŠMOVE.Lƒ#0,A0�A0�<--�0�=�DO�NOT�COPY�THE�EVENT.!ŠMOVE.LƒA3,D3�D3�<--�DCB�address.1ŠBSR.L„N_HLT_QEVENTˆQueue�the�event�(use�DRVLIB). ŠIF‚‚THEN)ŠKILL.DRIVER�PRNTLIB_ID,N_HLT_QVENT,A5,A3ŠENDI%ŠBRA.L„CMDEXIT3ŒReturn�to�the�caller.ŠPAGEO********************************************************************************(*ˆLOGICAL-TO-PHYSICAL�ADDRESS�CONVERSION*F*ˆGiven�a�physical�TCB�address�and�the�logical�address�and�length�of�aE*ˆmemory�area,�subroutine‚LOGPHY�computes�the�physical�address�of�theE*ˆmemory�area.‚It�also�checks�to�make�sure�that�the�given�memory�areaE*ˆreally�belongs�to�the�task‚that�is�controlled�by�the�specified�TCB.*D*ˆThe�subroutine�will�not�return�unless�the�specified�memory�residesH*ˆentirely�within�the�memory�segment�that�belongs�to�the�specified�task.*?*ˆEntry:„A0�=�physical�address�of�TCB�of�task�containing�buffer;*’D6�=�logical�address�of�the�first�word�of�the�memory�area)*’D5�=�length�in�bytes�of�the�memory�area*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚P�P‡P�R *™A‚P�P‡P*B*ˆExit:…D6�=�physical�address�of�the�first�word�of�the�memory�area *’Return�to�the�calling�routine.*O******************************************************************************* -LOGPHY1‚BSR†LOGPHY‘Use�the�routine�in�DRVLIB. ‰IF‚�THEN.S5‹MOVEQIƒISTAADD,D1‹LOGPHY�returns�this�condition�code)‹BRA†CMDEXIT2‹if�(1)�the�specified�memory'*¦area�is�completely�outside�any�memory'*¦segment�that�belongs�to�the�specified'*¦task�or�(2)�the�specified�memory�area!*¦is�in�a�memory-mapped�I/O�area.‰ENDI *‰RTS�Control�reaches�this�point�when�we've'*¦made�a�successful�address�conversion.‰PAGEJ****************************************************************************•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�INDEPENDENT)*J************************************************************************** O*********************************************************************************‰SEND�THE�EVENT�(CALL�GUARDED)*6*‰Somebody�in�command�service�wants�to�queue�an�event,=*‰but�of�course�he�couldn't�send�it�since�the�Q_EVENT�routine;*‰can�only�be�called�from�the�background.‚So�he�asked�me�to)*‰do�it�for�him.‚I'm�such�a�nice�routine.*!*ˆEntry:„A3ƒ=‚Address�of�the�DCB.*’A4ƒ=‚Address�of�the�IOCB.*’A5ƒ=‚Address�of�the�CCB.*’D1.B�=‚Error/status�code.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D„P *™AˆP�P�P**ˆCalls:„Q_EVENT***ˆExit:…RTS�back�to�caller�if�all�is�okay.*’KILLER�if�error�is�detected.*O******************************************************************************* DO_EVENT: /ŠST‡NONINTERRUPT(A5)„Set�up�for�a�normal�event.0ŠBSR†Q_EVENT�Call�the�routine�to�send�the�event.ŠSF‡NONINTERRUPT(A5) ŠIF‚‚THEN&ŠKILL.DRIVER�PRNTLIB_ID,T0QEVNTT,A5,A3ŠENDI ŠRTSŠPAGEJ***************************************************************************5*‰QUEUE�A�COMPLETION�EVENT�TO�THE�ATTACHED�TASK�(IOS)*;*‰This�routine�calls�the�exec�to�send�a�small�event�to�IOS.;*‰It�uses�I_NRM_QEVENT�if�we're�processing�an�interrupt�and:*‰N_NRM_QEVENT�if�we're�not.‚These�routines�are�in�DRVLIB.*7*‰NOTE:�this�routine�may�only�be�called�from�within�the*�background!!!!!*!*ˆEntry:„A3ƒ=‚Address�of�the�DCB.*’A4ƒ=‚Address�of�the�IOCB.*’A5ƒ=‚Address�of�the�CCB.*’D1.B�=‚Error/status�code.4*’NONINTERRUPT�=�00�=�Proces sing�an�interrupt�event.0*’NONINTERRUPT�=�FF�=�Processing�a�normal�event.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D„P *™AˆP�P�P*#*ˆCalls:‚I_NRM_QEVENT,�N_NRM_QEVENT*7*ˆExit:ƒRTS�back�to�caller�with�the�condition�code�set:**��=�The�event�was�sucessfully�queued."*��=�Unsucessful�TRAP�#0�call.*O******************************************************************************* Q_EVENT: :‰MOVEM.LƒD3/A0,-(A7)‰Save�the�registers�we�will�blow�away. 9‰MOVE.BƒD1,IOSSTA(A4)ŠStore�the�status�code�into�the�IOCB&*¦where�it�can�be�examined�by�the�task$*¦that�originally�requested�the�I/O. **‚Set�up�A0�and�D3�for�DRVLIB:*/‰MOVE.L„#0,A0�A0�<--�0�=�DO�NOT�COPY�THE�EVENT! ‰MOVE.L„A3,D3�D3�<--�DCB�address #‰IF.BƒNONINTERRUPT(A5)‚‚#0ƒTHEN$‹BSR.LƒI_NRM_QEVENTˆInterrupt�event.‰ELSE!‹BSR.LƒN_NRM_QEVENTˆNormal�event.‰ENDI +‰MOVEM.L‚(A7)+,D3/A0ŠRestore�the�registers.‰RTS‰PAGEL*****************************************************************************/*ˆR�O�U�T�I�N�E�S„F�O�R„T�H�E…I�N�T�E�R�R�U�P�T*'*‹H�A�N�D�L�E�R…F�O�R„T�H�E…D�E�V�I�C�E**’D�E�P�E�N�D�E�N�T…M�O�D�U�L�E*L****************************************************************************ŠPAGEO*******************************************************************************O*******************************************************************************O*********************************************************************************ˆINTERRUPT�HANDLER*B*ˆThis‚subroutine‚is�called�from�the�device-dependent�driver�afterD*ˆit�receives�an�interrupt�from�the�device.�Its�purpose�is�to�return@*ˆto�the�code�that�was�executing�before�interrupts�were�enabled.*ˆSpecific�functions�are:*=*Š1.�Save�the�return�address�of�the�interrupt�routine�caller.4*Š2.�Get�the�DCB�and�IOCB�addresses�and�the�IOBUFPTR5*�variables�out�of�the�CCB�into�designated�registers.=*Š3.�Check�for�printer�errors,�if�error�exit�with�error�code.=*Š4.�Return�to�the�routine�that�was�executing�when�interrupts,*�had�to�be�enabled�(at�the�OUTPUT�routine).*%*ˆEntry:„A5�=�physical�address�of�CCB*!*ˆRegister�usage:ˆ0�1�2�3�4�5�6�7 *œD‚*�*�*�* *œA‚*�*ƒ*�*�P*.*ˆExit:…JMP�to�the�address�stored�in�INTSWTCH,:*’else�return�an�error�code�if�there�is�a�printer�problem.*O*******************************************************************************O*******************************************************************************O******************************************************************************* INTR_REC:4ŠMOVE.LƒSP,SAVESP(A5)‰Save�the�return�address�in�the)*¦interrupt�service�routine�(DDP�module). *ŠMOVE.LƒDCBPNTR(A5),A3†A3�<--�DCB�address.+ŠMOVE.LƒIOCBPTR(A5),A4†A4�<--�IOCB�address..ŠMOVE.LƒIOBUFPTR(A5),A0…Set�up�buffer�pointer. 0ŠT_JSR„GET_STATŒSee�if�there�is�a�printer�error. ŠIF‚‚THEN2ŒMOVE.W�#ISTANR,D1ŠReturn�printer�not�ready�error.ŒBRA.L‚PRT_ERRORŠENDI 6ŠMOVE.LƒINTSWTCH(A5),A1‡Branch�to�the�routine�that�was-ŠJMP†(A1)�executing�when�interrupts�had�to�be(*¦enabled.‚This�will�be�at�the�code�just**¦after�whoever�called�the�OUTPUT�routine.ŠPAGEO*******************************************************************************O*******************************************************************************O******************************************************************************** *ˆFAULT�TIMER*D*ˆThis‚subroutine�is�called�from�the�device-dependent�driver�when�itD*ˆneeds�to�set�up�a�timer�call�to�monitor�the�FAULT�line.‚It�is�usedF*ˆonly�by�those�drivers�that�cannot�be�INTERRUPTED�for�printer�FAULTS.*%*ˆEntry:„A5�=�physical�address�of�CCB*!*ˆRegister�usage:ˆ0�1�2�3�4�5�6�7*œDˆ**œAˆ*ƒP**ˆCalls:„SET_TIME�(in�DRVLIB)**ˆExit:…RTS�to�caller.*O*******************************************************************************O*******************************************************************************O******************************** *********************************************** FLT_TIMER:/ŠMOVEM.L‚D3/A3,-(SP)‰Save�any�registers�we�use. .ŠMOVE.Lƒ#FLT_DELAY,D3‡D3�<--�FAULT�time�delay.;ŠLEA†FLT_HANDLER(PC),A3‚A3�<--�our�routine�to�handle�timer.4ŠBSR.L„SET_TIMEŒThis�routine�sets�up�the�timer�call. ŠIF‚‚THEN.ŠKILL.DRIVER�PRNTLIB_ID,SET_TIM,A5,DCBPNTR(A5)ŠENDI 3ŠMOVEM.L‚(SP)+,D3/A3‰Restore�any�registers�we�used.ŠRTSŠPAGEO*********************************************************************************ˆFAULT�HANDLER*F*ˆThis�subroutine�runs�as�a�result�of�the�timer�activation�that�is�setD*ˆup‚in�the�routine�FLT_TIMER.‚It�is�used�only�by�those�drivers�thatE*ˆcannot�be�INTERRUPTED�for�printer�FAULTS.‚When�we�get�here�we�checkF*ˆthe�flag�FLT_REQ.�If�it�is�clear,�then�an�ACKNOWLEDGE�interrupt�mustD*ˆhave‚come�in,�so�we�no�longer�need�the�request.‚If�FLT_REQ�is�set,D*ˆthen�we‚did‚not�receive�an�ACKNOWLEDGE,�so�we�assume�that�there�isF*ˆsomething�wrong�with�the�printer.�The�driver�will�clear�FLT_REQ�each$*ˆtime�it�receives�an�ACK�interrupt.*E*ˆOnce�the�timer�is�set�up�(in�FLT_TIMER),�we�will�eventually�run,�soE*ˆit�is�likely�that�this�routine�will�run�even�after�the�entire�writeE*ˆrequest�has�been�handled.‚Since�FLT_REQ�will�be�clear,�we�just�RTE.*%*ˆEntry:„D1�=�physical�address�of�CCB*!*ˆRegister�usage:ˆ0�1�2�3�4�5�6�7*œD„* *œA‚*…*�*�***ˆCalls:„Q_EVENT**ˆExit:…RTE�to�caller.*O******************************************************************************* TIM_REGS‚REG†D2-D7/A2-A6 FLT_HANDLER: ?ŠMOVEM.L‚TIM_REGS,-(SP)†The�timer�has�saved�D0,�D1,�A0,�and�A1. %ŠMOVE.LƒD1,A5�A5�<--�our�CCB�address.:ŠTST.B„FLT_REQ(A5)‰Check�if�we�still�need�the�request,�the4ŠIF‚‚THEN�driver�clears�this�flag�each�time�that=ŒMOVEM.L�(SP)+,TIM_REGS…it�receives�an�ACKNOWLEDGE�interrupt.%ŒRTE˜Request�not�needed,�just�return.ŠENDIŠPAGE*F*‚The�printer�has�not�ACKNOWLEDGED�the�last�character�that�we�sent.‚WeK*‚gave�it�plenty�of�time�(FLT_DELAY),�so�there�must�be�something�wrong�withJ*‚the�printer.‚We�can't�check�the�status�of�the�FAULT�line�because�on�mostF*‚printers,�if�the�cable�is�disconnected,�it�doesn't�look�like�a�faultI*‚condition.‚The�assumption�is�made�that�since�the�time-out�has�occurred,>*‚there�is�a�problem,�so�we�return�a�'DEVICE�NOT�READY'�error.*&ŠSF.B…FLT_REQ(A5)‰Clear�for�next�time.#ŠT_JSR„DDP_RESET‹Reset�the�printer.'ŠSF.B…PRNTBUSY(A5)ˆClear�our�busy�flag.,ŠMOVE.LƒTCB_ADDR(A5),A0…Pick�up�TCB�address.:ŠSUB.B„#1,TCBIOCNT(A0)…Decrement�user's�I/O�pending�count. *ŠMOVE.LƒDCBPNTR(A5),A3†A3�<--�DCB�address.+ŠMOVE.LƒIOCBPTR(A5),A4†A4�<--�IOCB�address.1ŠMOVE.Wƒ#ISTANR,D1ŠD1.W�<--�not�ready�error�code.1ŠMOVE.BƒD1,IOSSTA(A4)‹Update�user's�status�field.:ŠMOVE.LƒCHAR_CNT(A5),IOSLEN(A4)�Update�#�of�bytes�printed. 0ŠTST.B„INTR_CNT(A5)ˆSee�if�we�took�an�interrupt. ŠIF‚‚THEN;ŒSF.BƒNONINTERRUPT(A5)„Yes�-�set�up�for�an�interrupt�event.2ŒBSR.L‚Q_EVENT�Call�the�routine�to�send�the�event. ŒIF‚‚THEN&ŽKILL.DRIVER�PRNTLIB_ID,T0QEVNTI,A5,A3ŒENDI !ŠELSE‚(It's�a�command�type�event) 1ŒST.BƒNONINTERRUPT(A5)„Set�up�for�a�normal�event.2ŒBSR.L‚Q_EVENT�Call�the�routine�to�send�the�event.)ŒSF.BƒNONINTERRUPT(A5)„Set�for�next�time. ŒIF‚‚THEN&ŽKILL.DRIVER�PRNTLIB_ID,T0QEVNTT,A5,A3ŒENDIŠENDI -ŠMOVEM.L�(SP)+,TIM_REGS‡Restore�the�registersŠRTE ŠPAGE*********************** *‚PATCH�SPACE***********************ŠDS.W…30ŠENDN NNNNN+RWINDRV‚IDNT†45,0†VERSAdos�RWIN�disk�driverNNNNNNNv}†ŽK–)ž0¦8®<¶:¾>Æ;ÎQÖ<Þ>æ;î8ö9þ9?:8C&<.367>0F6N6V8^2f='‰TTL‡RWINDRV:‚VERSAdos�RWIN�disk�driverN NNNNNNK***************************************************************************K***************************************************************************K***************************************************************************K****************************************************************************%*ˆRWINDRV:‚VERSAdos�RWIN�disk�driver.**ˆRevision�history:**ˆ10/31/85‚Initial�release.<*ˆ12/11/85‚Added�CHK_PARAM�routine�called�by�DISKlib.�R.E.M.*K***************************************************************************K***************************************************************************K***************************************************************************K***************************************************************************‰PAGE**ƒXREF'S�from�DISKLIB*ŠXREF…DISK_INITŠXREF…DISK_COMMANDŠXREF…CHAN_DONE **‚Equate�files�included:* *‰INCLUDE‚9995.&.TCB.EQ*‰INCLUDE‚9995.&.CCB.EQ*‰INCLUDE‚9995.&.LV5.EQ*‰INCLUDE‚9995.&.IOE.EQ*‰INCLUDE‚9995.&.NIO.EQ*‰INCLUDE‚9995.&.DISKCCB.EQ*‰INCLUDE‚9995.&.DISKMEM.EQ*‰INCLUDE‚9995.&.DISK.EQ*‰INCLUDE‚9995.&.UTILITY.MC  ŠOPT�CRE,PCS **‰MISC�EQUATES*3DRIVESƒEQU‡4“Total�number�of�drives�on�our�channel. **ˆ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"*‰NOLIST‰INCLUDE‚9995.&.TCB.EQ‰INCLUDE‚9995.&.CCB.EQ‰INCLUDE‚9995.&.LV5.EQ‰INCLUDE‚9995.&.IOE.EQ‰INCLUDE‚9995.&.NIO.EQ‰INCLUDE‚9995.&.UTILITY.MC ‰TTL†DISK.EQ‰LIST‰INCLUDE‚9995.&.DISK.EQ‰TTL†DISKCCB.EQ‰INCLUDE‚9995.&.DISKCCB.EQ‰TTL†RWINDRV.SA‰PAGE/‰OFFSETƒDCCBDDP�Continue�with�channel-dependent*¦CCB�variable�space.  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*B*%%%„Device-dependent,�channel�related,�variables�start�here.‰%%%* *%%%Å%%%**%%%™(CCB�SPACE)¡%%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  E*ˆThe�following�subsection�of‚the�channel-related�part�of�the�device-H*‚dependent�portion‚of‚the‚CCB�is�used�by�the�RWIN�interrupt�handler�forH*‚building�a‚command�packet�that�can�be�sent�to�the�RWIN�controller.ƒTheM*‚variables�in�the�command�packet�must�occur�in�the�exact�order�that�is�shownK*‚because�the�entire�command�packet�is�treated�as�an�indivisible�block.‚TheK*‚RWIN�c ontroller‚interprets�the�individual�fields�of�the�command�packet�as#*‚shown�in�the�illustrations�below. B*ˆThe�WINCHESTER�controller�interprets�the�command�packet�as�shown;*‚in�the�diagram�below.‚The�variables�in�the�command�packetH*‚must�occur�in�the�exact�order�that�is�shown�because�the�entire�command,*‚packet�is�treated�as�an�indivisible�block. 4*‡7‚6‚5‚4‚3‚2‚1‚0‹Byte�zero�of�a�RWIN�command�packetD*…--------------------------‡contains�the�opcode�that�tells�the�RWIN4*‚0‚|‰Opcode‰|‡controller�what�operation�to�perform.?*…|------------------------|‡Bits�7�-�5�of�byte�one�contain�the5*‚1‚|‚LUNƒ|�|‡controller-defined�logical�unit�number,3*…|---------�--|‡which�is�equivalent�to�the�channel3*‚2‚|‰Logicalˆ|‡device�number.‚Bits�4-0�of�byte�one7*…|--‡Sector‡--|‡and�all�of�bytes�two�and�three�usually/*‚3‚|‰Number‰|‡contain�a�logical�sector�number.*…|------------------------|7*‚4‚|†Sector�Count†|‰Byte�four�of�a�RWIN�command�packetB*…|------------------------|‡normally�contains�a�sector�count,�but<*‚5‚|†Control�Code†|‡byte�four�is�used�to�contain�the�inter-B*…--------------------------‡leave�factor�when�a�format�command�is*¦being�specified.*B*…|TD|SN|MF|�SCC�|DS|CIE|DMA|ˆFinally,�byte�five�of�a�RWIN�command'*¦packet�contains�a�control�code.‚Bit�7&*¦defines�track�density.�Bit�6�defines)*¦format.�Bit�5�defines�recording�method.(*¦Bits�4-3�define�the�sector�size.�Bit�2**¦defines�diskette�sides.�Bit�1�can�be�set$*¦to�enable�command�interrupt.�Bit�0*¦defines�data�request�mode.‰PAGE4*‡7‚6‚5‚4‚3‚2‚1‚0‹When�the�opcode�field�of�a�commandA*…--------------------------‡packet�specifies�the�RWIN�command�to<*‚0‚|�1‚1‚0|…Op�Codeƒ|‡configure�a�drive,�some�of�the�fieldsB*…|------------------------|‡of�the�command�packet�are�interpreted:*‚1‚|‚LUNƒ|�0‚0‚0‚0‚0�|‡a�little�differently�(as�described$*…|------------------------|‡below).*‚2‚|‚Max�HD„|‚Max�Cyl�1|?*…|------------------------|‰The�bytes�that�used�to�contain�the7*‚3‚|ˆMax�Cyl�0‡|‡logical�sector�number�now�contain�the@*…|------------------------|‡head�count�and�cyclinder�count.‚TheA*‚4‚|„Start�Precomp�Cyc�#�|‡field�that�used�to�contain�the�sectorB*…|------------------------|‡number�now�contains�the�start�precomp@*‚5‚|‚Control�Codeƒ|CIE|‚|‡cycle�number.‚The�only�meaningful�bitE*…--------------------------‡of�the�control�code�is�bit�1�which�still&*¦is�used�to�enable�interrupt�command. *‰DS.W…0–The�command�packet�must�begin�on�a'*¦word�boundary�because�we�don't�always(*¦use�byte-mode�addressing�to�access�it. 2CMDOP„DS.B…1–The�CMDOP�field�of�the�command�packet)*¦contains�the�opcode�that�tells�the�RWIN'*¦controller�what�operation�to�perform. 2CMDLSNƒDS.B…3–The�CMDLSN�field�of�a�command�packet:LSNMASK‚EQU†$001FFFFFŒoften�contains�a�logical�unit�number5LUNFIELD�EQU†5”and�a�logical�sector�number�to�specify)*¦a�particular�area�of�a�particular�disk.&*¦The�LSNMASK�value�is�a�bit�mask�that$*¦indicates�which�bits�of�the�CMDLSN(*¦field�can�be�used�for�a�logical�sector)*¦number,�and�the�LUNFIELD�value�is�a�bit)*¦number�to�indicate�that�bits�5-7�of�the)*¦first�byte�of�the�CMDLSN�field�are�used"*¦for�the�LUN�field.‚The�LUN�field)*¦contains�the�controller-defined�logical)*¦unit�number,�which�is�equivalent�to�the*¦channel�device�number. *2*ˆAdded�to�implement�alternate�sectorsŽBWN�2/16/84*LSNMSKNOTŠEQU‡$FFFFFFFF-LSNMASK 4CMDSECTS�DS.B…1–The�CMDSECTS�field�contains�a�sector8CMDILVƒEQU†CMDSECTS�count�for�a�read�or�write�operation,&*¦and�it�contains�an�interleave�factor&*¦for�a�format�operation.‚The�CMDSECTS&*¦field�always�contains�the�value�zero *¦for�a�define-format�operation.‰PAGE/MAXSECTS�EQU†255”This�label�defines�the�maximum(*¦possible�value�that�can�be�used�in�the'*¦CMDSECTS�field.‚If�an�I/O�transaction)*¦involves�more�than�MAXSECTS�sectors,�we(*¦must�break�up�the�transaction�into�two*¦or�more�smaller�transactions. "CMDCTRL‚DS.B…1”Control�code�field. -CTD†EQU‡7•The�CMDCTRL�field�of�a�RWIN�command)CS N†EQU‡6“packet�contains�a�control�code.0CMF†EQU‡5“For�all�commands�with�the�exception�of0CSS†EQU‡4“configure�a�drive,�the�WINCHESTER�uses,CDS†EQU‡2“all�bit�of�the�control�code�field. CIE†EQU‡1 CDM†EQU‡0 0CMDENDƒEQU†*–The�label�CMDEND�is�attached�to�the9CMDLENƒEQU†CMDEND-CMDOP‰byte�that�immediately�follows�the&*¦command�packet�in�memory,�and�CMDLEN(*¦specifies�the�length�(in�bytes)�of�the'*¦command�packet.‚We�sometimes�start�at'*¦location�CMDEND�and�access�the�fields&*¦in�the�command�packet�by�using�auto-*¦decrement�addressing. 7IOQUEUE‚DS.L…DRIVES‘The�IOQUEUE�is�used�to�indicate�the(*¦I/O�activities�(if�any)�that�are�lined'*¦up�waiting�to�be�done�under�interrupt(*¦control�by�the�RWIN�interrupt�handler.'*¦Since�we�can�never�have�more�than�one'*¦command�pending�for�any�single�drive,(*¦the�IOQUEUE�has�exactly�enough�entries%*¦to�accommodate�one�I/O�activity�for'*¦each�drive�that�a�RWIN�controller�can*¦possibly�control. $*¨An�entry�in�the�IOQUEUE�is�a�long-)*¦word�pointer�that�contains�the�physical(*¦address�of�a�drive's�variable�block�in**¦the�drive-associated�area�of�global�mem,(*¦and�the�values�in�the�drive's�variable&*¦block�describe�the�I/O�activity�that*¦must�be�done�with�that�drive.‰PAGE'*¨The�RWIN�driver�puts�entries�into�the'*¦IOQUEUE�in�the�order�in�which�the�I/O)*¦requests�are�received,�so�no�drive�on�a$*¦RWIN�channel�has�priority�over�any'*¦other�drive�on�the�same�channel.‚When$*¦the�RWIN�driver�receives�a�new�I/O%*¦request,�the�driver�simply�puts�the&*¦entry�for�that�request�into�the�next *¦available�slot�of�the�IOQUEUE. '*¨When�the�RWIN�driver�completes�an�I/O&*¦activity�under�interrupt�control,�it(*¦moves�all�remaining�IOQUEUE�entries�up%*¦by�one�position�in�the�IOQUEUE.‚The(*¦physical�movement�of�queue�entries�may%*¦sound�like�a�poor�approach�at�first&*¦glance,�but�it�turns�out�to�be�quite%*¦good.‚The�use�of�wrapping�front�and$*¦rear�queue�pointers�with�position-(*¦independent�code�is�rather�cumbersome,$*¦and�the�physical�movement�of�queue%*¦entries�is�a�better�technique�for�a"*¦short�queue�such�as�the�IOQUEUE. 1IOQCNTƒDS.W…1–This�variable�contains�the�count�of#*¦the�number�of�bytes�in�the�active)*¦entries�in�the�IOQUEUE,�so�IOQCNT�=�4*N)*¦where�N�is�the�number�of�active�entries(*¦in�the�IOQUEUE.‚The�value�of�IOQCNT�is$*¦always�in�the�range�from�0�through&*¦through�4*DRIVES,�so�we�could�easily&*¦use�a�single�byte�for�this�variable.(*¦However,�we�use�a�full�word�for�coding%*¦convenience.‚Notice�that�IOQCNT�can%*¦be�used�as�an�offset�pointer�to�the&*¦next�available�entry�in�the�IOQUEUE. '*¨IOQCNT�must�be�initialized�to�zero�at*¦system-initialization�time. 1BLKCNTƒDS.B…1–BLKCNT�is�used�in�the�data�transfer(*¦routines�and�is�equal�to�the�number�of'*¦128�byte�blocks�left�to�be�transfered&*¦for�the�current�sector.�This�is�only *¦used�for�read�&�write�commands 1RETRY„DS.B…1–Used�by�Winchester�interrupt�handler%*¦to�count�the�number�of�retries�when*¦executing�error�correction�in*¦completing�an�I/O�activity.‰PAGE0RETRYCNT�EQU†6–Value�used�to�initialize�RETRY�in*¦error�handling. 1SENSBYT0�DS.B…1–These�are�error�correction�status3SENSBYT1�DS.B…1”bytes�used�by�the�interrupt�handler2SENSBYT2�DS.B…1”when�executing�error�correction�in,SENSBYT3�DS.B…1”completing�and�I/O�activity.SENSBYT4�DS.B…1SENSBYT5�DS.B…1SENSBYT6�DS.B…1SENSBYT7�DS.B…1SENSBYT8�DS.B…1SENSBYT9�DS.B…1  M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* *%%%Å%%%*>*%%%„End�of�device�dependent,�channel�related,�variables.�%%%* *%%%Å%%%**%%%•END�OF�CCB�SPACE %%%* *%%%Å%%%*M*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*  3CCBSIZEB�EQU†*–CCBSIZEB�defines�the�size�(in�bytes)(*¦of�a�complete�CCB�for�the�RWIN�driver. %*¨CCBSIZE�defines�the�size�(in�pages)?L0080„EQU†CCBSIZEB+PAGESIZE-1‚of�a�CCB�for�the�RWIN�driver,�andBCCBSIZE‚ EQU†L0080/PAGESIZE‡EXTCCBSZ�defines�the�size�(in�pages)�of*ƒ15‚14‚13‚12ƒ11‚10ƒ9ƒ8„in�the�parameters�mask�are�not�used�byI*‚+---+---+---+---++---+---+---+---+‚the�RWIN�driver,�but�all�of�the�bits8*‚|‹|ƒ||ƒ|ƒ|ƒ|ƒ|‚that�are�defined�for�any�disk�drive�are;*‚+---+---+---+---++---+---+---+---+‚shown�in�the�diagrams.*„^ƒ^ƒ^ƒ^„^ƒ^ƒ^ƒ^*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ|7*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ----�1�=�IOSSOF�is�not�used�by�the�WIN.*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|1*„|ƒ|ƒ|ƒ|„|ƒ|ƒ--------�1�=�IOSPSM�is�significant. *„|ƒ|ƒ|ƒ|„|ƒ|;*„|ƒ|ƒ|ƒ|„|ƒ------------�1�=�IOSSHD�is�not�used�by�the�WIN. *„|ƒ|ƒ|ƒ|„|6*„|ƒ|ƒ|ƒ|„----------------�1�=�IOSTRKD�is�significant. *„|ƒ|ƒ|ƒ|9*„|ƒ|ƒ|ƒ---------------------�1�=�IOSPCOM�is�significant.*„|ƒ|ƒ|C*„|ƒ|ƒ-------------------------�1�=�IOSSPTD�is�not�used�by�the�WIN.*„|ƒ|D*„|ƒ-----------------------------�1�=�IOSSRB�is�not�used�by�the�WIN.*„|H*„---------------------------------�1�=�IOSRWCCB�is�not�used�by�the�WIN.   *„7ƒ6ƒ5ƒ4„3ƒ2ƒ1ƒ0$*‚+---+---+---+---++---+---+---+---+*‚|ƒ|ƒ|ƒ|ƒ||ƒ|ƒ|ƒ|ƒ|$*‚+---+---+---+---++---+---+---+---+*„^ƒ^ƒ^ƒ^„^ƒ^ƒ^ƒ^*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ|/*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ----�1�=�IOSREC�is�significant.*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|1*„|ƒ|ƒ|ƒ|„|ƒ|ƒ--------�1�=�IOSRSZ�is�significant. *„|ƒ|ƒ|ƒ|„|ƒ|;*„|ƒ|ƒ|ƒ|„|ƒ------------�1�=�IOSWTO�is�not�used�by�the�WIN. *„|ƒ|ƒ|ƒ|„|=*„|ƒ|ƒ|ƒ|„----------------�1�=�IOSRTO�is�not�used�by�the�WIN. *„|ƒ|ƒ|ƒ|8*„|ƒ|ƒ|ƒ---------------------�1�=�IOSSPT�is�significant.*„|ƒ|ƒ|:*„|ƒ|ƒ-------------------------�1�=�IOSHDS�is�significant.*„|ƒ|<*„|ƒ-----------------------------�1�=�IOSTRK�is�significant.*„|>*„---------------------------------�1�=�IOSILV�is�significant. PAGE*+*ˆATTRIBUTES�MASK�FOR�THE�WINCHESTER�DRIVER* '*¨The�individual�bits�of�the�attributes&*¦word�are�interpreted�as�shown�in�the*¦accompanying�diagrams. !*¨Notice�that�the�top�half�of�the<*ƒ15‚14‚13‚12ƒ11‚10ƒ9ƒ8„attributes�word�is�completely�unusedI*‚+---+---+---+---++---+---+---+-- -+‚for�a�RWIN‚disk,�but�the�top�half�of+*‚| |‚the�attributes�word�is�still�present.$*‚+---+---+---+---++---+---+---+---+*„^ƒ^ƒ^ƒ^„^ƒ^ƒ^ƒ^*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ|:*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ----‚1�=�Post-read/pre-write�precomp�req'd*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|�(not�used)=*„|ƒ|ƒ|ƒ|„|ƒ|ƒ--------‚1�=�8�"�floppy�disk;�0�=�5-1/4�"�disk.*„|ƒ|ƒ|ƒ|„|ƒ|‘(not�used)-*„---------------------------------‚Not�used.  *„7ƒ6ƒ5ƒ4„3ƒ2ƒ1ƒ0$*‚+---+---+---+---++---+---+---+---+*‚|‹|ƒ||ƒ|ƒ|ƒ|ƒ|$*‚+---+---+---+---++---+---+---+---+*„^ƒ^ƒ^ƒ^„^ƒ^ƒ^ƒ^*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ|<*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|ƒ----�1�=�Double�data-density�(MFM)�on�media.*„|ƒ|ƒ|ƒ|„|ƒ|ƒ|9*„|ƒ|ƒ|ƒ|„|ƒ|ƒ--------�1�=�Double�track-density�on�media. *„|ƒ|ƒ|ƒ|„|ƒ|6*„|ƒ|ƒ|ƒ|„|ƒ------------�1�=�Double-sided�floppy�disk. *„|ƒ|ƒ|ƒ|„|?*„|ƒ|ƒ|ƒ|„----------------�1�=�IBM�format;�0�=�Motorola�format. *„|ƒ|ƒ|ƒ|>*„|ƒ|ƒ|ƒ---------------------�1�=�Rigid�disk;�0�=�floppy�disk.*„|ƒ|ƒ|G*„|ƒ|ƒ-------------------------�1�=�Double�data-density�(MFM)�on�drive.*„|ƒ|¡(not�used)D*„|ƒ-----------------------------�1�=�Double�track-density�on�drive.*„|¥(not�used)K*„---------------------------------�1�=�Seek�req'd�w/�head�switch�on�drive. *ª(not�used)‰PAGE0‰OFFSETƒ-2•This�OFFSET�block�defines�the�memory-&*¦mapped�I/O�space�for�a�RWIN�channel.&*¦The�RWIN�driver�communicates�through*¦this�memory-mapped�I/O�space. #*¨The�CCBCHB�pointer�normally�would'*¦point�to�the�beginning�of�the�memory-)*¦mapped�I/O�area�(byte�0),�but�since�I/O'*¦accesses�are�to�the�odd�bytes�only�it**¦would�point�to�byte�1.�For�the�RWIN,�the"*¦CCBCHB�points�to�the�byte�3�(the)*¦RWIN�status)�which�is�always�accessible!*¦where�as�byte�1�(sense)�is�not.*¨We�use�an�offset�of�-2�in�the!*¦OFFSET�statement�to�compensate. *¨We�use�DS.B�1*2�to�define�the#*¦OFFSETS�used�the�access�the�RWIN. ************** *ƒBYTE�1ƒ***************4COMMAND‚DS.B†1*2“WRITE�register�for�sending�the�com-*¦mand�bytes�to�the�RWIN. 5SENSE„EQU‡COMMAND�READ�register�for�getting�the�sense*¦information�from�the�RWIN.'*¨COMMAND�or�SENSE�may�only�be�accessed*¦when�the�RWIN�is�not�busy. ************** *ƒBYTE�3ƒ***************4INTCTRL‚DS.B†1*2‡WRITE�register�to�enable�or�disable ** DATA REQUEST INTERRUPTS*ENBLDINT�EQU‡$01‡01�EnablesDSBLDINT�EQU‡$00‡00�Disables  PAGE 6FLAGS„EQU‡INTCTRL�READ�register�to�examine�RWIN�status*¦Bits�are�described�below:*BITCB„EQU‡7•1�=�RWIN�is�busy*¦0�=�RWIN�not�busy*,BITCI„EQU‡6•1�=�Command�completion�interrupt&*¦cleared�with�a�write�to�COMMAND�or�a*¦read�of�SENSE.*.BITFAULT�EQU‡5•1�=�A�fault�occured�in�the�last**¦command�to�RWIN.�SENSE�bytes�identify�th(*¦error.‚Cleared�with�a�write�to�COMMAND*¦or�a�read�of�SENSE.*-BITDI„EQU‡4•1�=�Data�request�interrupt�equals*¦BITDRQ�*�ENBLDINT*1BITDRQƒEQU‡3•1�=�Read�data�or�room�for�write�data*¦is�available�in�FIFO�buffer.*0BITCIEƒEQU‡2•1�=�Command�completion�interrupt�is&*¦enabled.‚Always�=�1�for�this�driver.*%BITDMAƒEQU‡1•1�=�DRQ�indicates�1�byte'*¦0�=�DRQ�indicates�1�block�(128�bytes)*¦Always�=�0�for�this�driver.*BITDIEƒEQU‡0“Copy�of�INTCTRL* ************** *ƒBYTE�5ƒ***************5RWINRSTƒDS.B†1*2‘WRITE�ONLY�register�to�reset�the�WDC  ************** *ƒBYTE�7ƒ***************‰DS.B†1*2‘NOT�USED ***************************ƒBYTES�9,�11,�13,�15‚***************************4DATA0„DS.B†1*2‘[�READ�data�from�buffer�or�WRITE�data1DATA1„DS.B†1*2‘[�to�buffer.�These�4�addresses�are3DATA2„DS.B†1*2‘[�decoded�to�the�buffer�to�allow�the.DATA3„DS.B†1*2‘[�use�of�the�MOVEP�instruction.‰PAGEO********************************************************************************1*ˆSERVICE�VECTOR�TABLE,�PARAMETERS,�REVISION�INFO*@*ˆThe�first‚several‚locations�of�every‚I/O�driver�must�contain�aB*ˆservice�vector�table�to�contain�the‚long-word�relative�addressesB*ˆof�the�three�driver�subroutines�that�CMR�uses.‚The�CMR�parameterC*ˆta ble�immediately�follows�the�service�vector�table�and�includes�aA*ˆfield�telling‚CMR‚how�many�extra�pages‚to�allocate�for�the�CCB.E*ˆThe�revision�table�immediately�follows�the�the�CMR�parameter�table.*O*******************************************************************************O******************************************************************************* ‰SECTION‚0 RWINDRV: *D*‚Service�vector�table.‚Notice�that�these�values�are�relative�to�theC*‚beginning�of�the�driver�so�the�mechanism�is�position-independent!* <‰DC.L…INTERUPT-RWINDRV…Address�of�interrupt�service�routine.:‰DC.L…COMMANDS-RWINDRV…Address�of�command�service�routine.5‰DC.L…INIT-RWINDRV‰Address�of�initialization�routine.‰DC.L…0”Reserved. **‚Other�CMR�parameters.*3‰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…'121185'�Date�of�last�assembly�as�MMDDYY.1‰DC.B…'�'’Space�indicates�no�patches�to�.LO�file.)‰DC.B…'4'’Major�VERSAdos�revision�number.‰PAGEO********************************************************************************7*ˆJump�table�for�use�by�the�generic�disk�driver�DISKLIB*O******************************************************************************* ‰BRA.L„SET_CNFG‰BRA.L„SET_CODE‰BRA.L„CHK_FLOPPY‰BRA.L„CHK_LSN‰BRA.L„BLD_PACKET‰BRA.L„DISK_START‰BRA.L„CHK_PARAM‰PAGEO*******************************************************************************O*********************************************************************************ˆINITIALIZATION�ROUTINE*B*ˆThis‚subroutine�is�called�from�CMR‚when�CMR�is�invoked�by�a�taskB*ˆ(normally�IOI)�to‚allocate�a�channel.‚Its�purpose�is�to�give�theD*ˆdriver�a�chance�to�set�up�things�for�command�service�and�interrupt-*ˆservice.‚The�basic�functions�performed�are:*5*ˆ1.‚Put�the�start�address�of�the�driver�into�the�CCB*Œvariable�DRV_ADDR.2*ˆ2.‚Put�the�total�number�of�drives�on�our�channel!*Œinto�the�CCB�variable�MAX_DRVS.8*ˆ3.‚Put�the�size�in�bytes�of�the�drive's�variable�block!*Œinto�the�CCB�variable�DRV_SIZE.?*ˆ4.‚Device-Independent�initialization�in�the�call�to�DISK_INIT"*Žto�initialize�the�CCB�variables.?*ˆ5.‚Device-Dependent�initialization�in�the�call�to�DO_INIT�for"*Ždevice�dependent�initialization.*B*ˆThis�subroutine�is�entered�through�a�JSR�from�CMR,�and�will�exit7*ˆwith�an�RTS.‚The�processor�is�in�the�supervisor�mode.*%*ˆEntry:„A6�=�physical�address�of�TCB*’A5�=�physical�address�of�CCB*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*.*ˆRegisters�used�in�DISK_INIT:…0�1�2�3�4�5�6�7*¦D‚**¦A‚*‰P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O*******************************************************************************ŠPAGEINIT: *)*‚Get�address�of�start�of�driver�into�CCB*ŠLEA‡RWINDRV(PC),A0ŠMOVE.L„A0,DRV_ADDR(A5)*9*‚Get�the�number�of�drives�supported�by�the�RWIN�channel.*ŠMOVE.W„#DRIVES,MAX_DRVS(A5)*5*‚Get�the�size�in�bytes�of�the�drive's�variable�block*ŠMOVE.W„#DRVBLKSZ,DRV_SIZE(A5)*>*‚Perform�the�device-independent�initialization�by�calling�the'*‚generic�routine�DISK_INIT�in�DISKLIB.*/‰JSR†DISK_INITŒDo�the�device-independent�stuff.4‰IF‚‚THEN.SŽSomething�went�wrong�with�DISK_INIT.‹RTS™The�channel�is�down�!!‰ENDI*8*‚Perform�any�device-dependent�initialization�in�DO_INIT*/‰BSR.L„DO_INITŽDevice�dependent�initialization.‰RTS‰PAGEO*******************************************************************************O*********************************************************************************ˆCOMMAND�SERVICE�ROUTINE*C*ˆThis�subroutine�is�called�from�CMR�when�CMR�receives�a�command�toA*ˆinitiate�an‚I/O�transaction‚with�a�device�that�is�controlled�by?*ˆth is�driver.‚Its�function�is�to‚process�the‚given�command‚andB*ˆqueue�the�command�to�the�controller.‚These�functions�are�handled%*ˆby�the�generic�disk�driver�DISKLIB.*5*ˆEntry:„A2�=�physical�address�of�CMR�parameter�block*’A5�=�physical�address�of�CCB/*’A6�=�physical�address�of�TCB�of�attached�task*5*ˆInterrupt�level�is�0.‚Registers�may�be�used�freely.*1*ˆRegisters�used�by�DISK_COMMAND:†0�1�2�3�4�5�6�7*ªD‚*�*�*�*�*�*�**ªA‚*�*�*�*�*�P**ˆExits�to:�CMR�via�RTS*O*******************************************************************************O******************************************************************************* COMMANDS: *,*‚Perform�any�device-dependent�stuff�here...* =*‚We�have�received�a�command,�so�we�know�there�is�someone�out**‚there�to�talk�to.‚Let�DISKLIB�handle�it.*&‰JSR†DISK_COMMAND‹Perform�the�command.‰RTS�Return�to�CMR.‰PAGEO*******************************************************************************O*********************************************************************************ˆRWIN�INTERRUPT�HANDLER*E*ˆControl�can�come�to�the�RWIN�interrupt‚handler�when�CMR�receives�anF*ˆinterrupt�on�the�interrupt�level�that�is�used�by�the�RWIN�controllerB*ˆIf�the‚interrupt�is�a�RWIN�interrupt,�the�RWIN‚interrupt�handlerF*ˆsets�the�C�bit�of�the�SR,�and�lowers�the�interrupt�mask�level�by�one*ˆlevel�upon�return.*=*ˆEntry:„A1�=�Physical�address�of�the�RWIN�interrupt�handler.#*’A5�=�Physical�address�of�the�CCB.1*’SR�=�Masked�at�the�level�of�the�RWIN�interrupt.*O*******************************************************************************O*******************************************************************************‰PAGEO*********************************************************************************ˆINTERRUPT�POLLING�ROUTINE*B*ˆControl�can�come�to�the‚RWIN�interrupt�handler�when�CMR�receivesC*ˆan�interrupt�on�the�interrupt�level�that�is�used�by�the�RWIN�diskC*ˆcontroller.�If�the�interrupt�is�a�RWIN�interrupt,�the�RWIN�driverA*ˆhandles�it,‚and�returns�to�CMR�with�the�C�bit�set�of�the�SR.‚IfA*ˆthe�interrupt�is�not�a�RWIN�interrupt,‚return�to�CMR�with�the�C*ˆbit�cleared.*#*ˆEntry:„JSR�from�interrupt�handler*’A5�=�physical�address�of�CCB*<*ˆThe�interrupt�level�is�at�the�level�of�the�RWIN�interrupt.8*ˆD0,�A0,�A1,�A5�have�been�saved�by�CMR.‚The�driver�must *ˆsave�any�other�registers�used.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚**™A‚*‰P**ˆExit:…RTS�back�to�CMR*O*******************************************************************************O******************************************************************************* **ˆIs�the�interrupt�for�me?* REQINTƒEQU†(1<*ˆThis�routine�is�executed�due�to�a�RWIN�interrupt�or�has�been?*ˆcalled�from�the�command�handler�to�initiate�an�I/O�operation.>*ˆWe'll�turn�off‚the�interrupts,�save�some�registers,�and�jump2*ˆto�the�previously�set�co-routine�switch�address.*7*ˆThe�interrupt�level�is�masked�at�our�channel's�level.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7(*™D‚*�#�#�#�#�=�Saved�to�use�throughout.*™A‚P�*�#�#�#�P*=*ˆExit:…Jump�to�co-routine�segment�addressed�by�INTSWTCH(A5).*O************************************************************ ******************* RWININT‚EQU‡*6‰MOVE.B�#DSBLDINT,INTCTRL(A0)‚Disable�data�interrupts.*‰BTST.B�#BITCB,FLAGS(A0)‡Is�the�RWIN�busy?2‰IF…�THEN.SŒThe�RWIN�is�not�busy,�so�clear�theCŠMOVE.B�SENSE(A0),SENSBYT0(A5)�command�completion�interrupt�and�DRQ‰ENDIšby�reading�SENSE�byte�0. @EQ430„REG†A4/A3/A2/D3/D2/D1†A5,�A1,�A0,�and�D0�have�already�been;‰MOVEM.L‚EQ430,-(SP)Šsaved�by�CMR.‚Here�we�save�the�rest�of$*§the�registers�that�we�need�to�use. =‰MOVE.L„CCBCHB(A5),A0‡A0�<---�memory-mapped�I/O�space�of�RWIN4‰MOVE.LƒIOQUEUE(A5),A1‡A1�<--�Drive's�variable�block =‰MOVE.LƒINTSWTCH(A5),A3ˆBranch�to�the�co-routine�segment�that"‰JMP†(A3)‘should�be�executed�next.‰PAGEO*********************************************************************************ˆWINCHESTER�OPCODE�TABLE*F*ˆThe�Winchester�opcode�table�contains�the�RWIN-defined�values�for�the:*ˆI/O�operations�that�are�currently�supported�by�the�RWIN.*O******************************************************************************* 0*’---------------------------�RWIN�Opcode�value.*’|*’|”------�IOFUNCT�index�value.*’|”|*’|”|*’V”V‰DC.B…$0A’-1�=�Write�disk.OPTBL„DC.B…$04“0�=�Format�disk.‰DC.B…$C0’+1�=�Configure�drive‰DC.B…$08’+2�=�Read�disk.0FTRACKƒDC.B…$06”The�opcode�for�a�format-track�or7ALTSECƒDC.B…$07’format-alternate�command�is�not�indexed/‰DS.W†0“by�the�IOFUNCT�value.�The�IOFUNCT�value&*¦for�all�format�commands�is�the�same.'*¦We�uniquely�identify�the�format-track&*¦commands�by�the�fact�that�its�IOOPTS!*¦value�is�different.‡BWN�2/13/84‰PAGEO*********************************************************************************ˆPROCESS�NEXT�QUEUE�ENTRY*E*ˆControl�comes�to�this�co-routine�segment�to�process�the�front�entryA*ˆof�the�IOQUEUE.‚We�are�guaranteed�that�the�IOQUEUE�is�non-empty%*ˆwhen�control�comes�to�this�routine.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚*�* *™A‚P�Pƒ*ƒP**ˆExit:…BSR�to�SENDCMD*O******************************************************************************* *F*ˆBuild�the�6-byte�command�packet�in�the�drive�block�of�global�memory.*>PROCQUE‚LEA†CMDEND(A5),A3ˆA3�<--�byte�that�immediately�follows(*¦the�last�byte�of�cmd�packet�in�memory.%*¦Autodecrement�addressing�is�used�to(*¦complete�the�command�packet�in�memory. >‰MOVE.BƒCTRLCODE(A1),-(A3)ƒCopy�the�control-code�into�CMDCTRL. *;* WE'LL ASSUME A READ OR WRITE COMMAND, SINCE MOST WILL BE.*7‰MOVE.LƒHALFSCTS(A1),D0†Are�any�half�sectors�specified?)‰BNE.S„L0470�YES.�READ�HALF�SECTORS�FIRST >‰MOVE.LƒIOSCTCNT(A1),D0†Get�the�total�#�of�sectors�to�transfer‰MOVE.Lƒ#MAXSECTS,D13‰CMP.L„D1,D0�Is�#�required�<=�MAX�per�RWIN�command?*‰BLS.S„L0470�Yes.�This�requires�1�command.0‰MOVE.LƒD1,D0�NO.�Transfer�Max.�in�this�command.9L0470„MOVE.BƒD0,-(A3)�Move�#�of�sectors�to�command�packet %*¨If�we're�processing�a�command�(such#*§as�a�format�command)�that�doesn't)*§involve�an�actual�I/O�transfer,�we�have*§IOSCTCNT�=�0.‰PAGE=‰MOVE.LƒIOSECTOR(A1),-(A3)…We�use�the�IOSECTOR�value�from�the?‰AND.W„#LSNMASK>>16,(A3)+ƒdisk�drive's�I/O�packet�to�set�up�the<‰MOVE.BƒDRIVENUM(A1),D1†logical�sector�number�in�the�command:‰LSL.B„#LUNFIELD,D1‰packet.‚We�also�use�the�DRIVENUM�value5‰OR.B…D1,-(A3)�from�the�drive's�I/O�packet�to�set�the(*§LUN�(Logical-Unit-Number)�field�in�the(*§command�packet.‚The�LUN�field�occupies *§the�top�few�bits�of�LSN�field. **‚Housekeeping...*<‰SUB.L„D0,IOSCTCNT(A1)ˆReduce�the�count�of�remaining�sectors'*¦by�the�number�of�sectors�that�will�be(*¦processed�as�a�result�of�this�command. :‰ADD.L„D0,IOSECTOR(A1)ˆIncrease�the�starting�sector�number'*¦by�the�number�of�sectors�that�will�be(*¦processed�as�a�result�of�this�command.&*¦This�causes�IOSECTOR�to�point�to�the)*¦sector�that�should�be�specified�for�the$*¦next�(if�any)�command� packet�after *¦this�one. ;‰MOVE.BƒIOFUNCT(A1),D0‰Get�the�IOFUNCT�code�into�D0.W�so�we+‰EXT.W„D0“can�use�it�to�index�into�the�RWIN6‰CMP.B„#FMTFUNC,D0Šopcode�table.�For�a�format�command,3‰IF��THEN.S�we�must�do�some�special�processing.**‚For�Format�Commands�ONLY:*‚THEN.SŽIf�not,�see�if�it's�a�format *¦alternate�sector�type�command.*"ŽIF‚IOOPTS(A1)��#IOPBAD�THEN.S 9“MOVEQI„ALTSEC-OPTBL,D0‚If�alternate�sector�type�command,$*¬then�set�up�to�get�ALTSEC�command. “BRA.S…L0490 ŽENDI ‰ENDI =‰MOVEQWƒFTRACK-OPTBL,D0†Adjust�D0.W�to�index�the�format-track!*¦entry�of�the�RWIN�opcode�table.‰ENDI‰PAGE*&*ˆContinue�processing�for�all�commands*;EQ483„EQU†CONFGBLK+IOSSPTˆFor�all�commands,�change�6th�byte(*¦to�single-density,�128�bytes/sector�if(*¦we�are�on�track�0�(floppy�disks�only).*/‰CLR.L„D1“Compare�the�#�of�sectors�per�track�to=‰MOVE.BƒEQ483(A1),D1‰the�starting�sector�#�in�the�cmd�packet.8‰CMP.W„1(A3),D1�When�it's�within�Track�0,�change�CMDCTRL1‰BLE.S„L0490�to�single�density,�128�bytes/sector.4CHGSSCƒEQU†$C7’Notice�A3�is�pointing�to�the�2nd�byte+‰AND.B„#CHGSSC,4(A3)ˆof�the�command�packet.&*¨This�is�valid�for�a�floppy�only.‚The)*¦starting�sector�#�will�never�be�greater!*¦than�a�word�value�for�a�floppy. L0490„EQU‡**?*ˆBecause�of�the�added�code,�we�get�a�displacement�error�on�the&*ˆcommented�out�statement.™BWN‚2/13/84**‰LEA‡OPTBL(PC),A4‰A4�<--�RWIN�opcode�table@‰MOVE.B„0(A4,D0.W),-(A3)…Fill�the�CMDOP�field�of�the�cmd�packet.>***†MOVE.BƒOPTBL(PC,D0.W),-(A3)ƒFinally,�fill�the�CMDOP�field. GSENDNEW‚BTSTW„#IOPRTYB,IOOPTS(A1)‚Check�for�no�retry�option�on�this�cmd‰BNE.S„SENDNEW12‰MOVE.Bƒ#RETRYCNT,RETRY(A5)‚Initialize�retry�count‰BRA.S„SENDAGN@SENDNEW1�MOVE.Bƒ#$01,RETRY(A5)‡Tell�firmware�'no�retries�please' 8SENDAGN‚BSR†SENDCMD�Send�the�command�packet�to�the�RWIN.$*¦controller,�and�subroutine�SENDCMD'*¦assumes�that�A0�points�to�the�memory-*¦mapped�I/O�area�for�the�RWIN.* *¨Control�falls�thru�to�the�data*¦handling�part�of�the�driver.‰PAGEO*********************************************************************************ˆDATA�HANDLER*B*ˆWe�assume�that�the�command�is�a�data�transfer�type�(i.e.�read�or?*ˆwrite)‚and�set�up�to�transfer�a�sector.ƒThis�is�wasted�if�theB*ˆcommand�is�a�configure�or�format�but�since�most�comands�are�R/W,*ˆwe�won't�worry�about�it.*O******************************************************************************* NEXTSECT�EQU†*EQ491„EQU†CONFGBLK+IOSPSM6‰MOVE.WƒEQ491(A1),D1‰D1�<--�the�number�of�bytes/sector2‰TST.L„HALFSCTS(A1)‰Any�half�sectors�this�command? ‰IF��THEN.S�No.)ŠLSR.W„#1,D1�Yes.�Divide�sector�size�by�2‰ENDI <‰LSR.W„#LCDSCTBT,D1‰D1.B�=�#�blocks/sector�for�this�command.%‰MOVE.BƒD1,BLKCNT(A5)ˆSave�the�count. 8NEXTSEC1�BSR†INTRTN�The�RWIN�controller�needs�time�to�do$*¦its�job�before�we�can�transfer�any(*¦data,�so�return�control�to�the�system.'*¦When�the�RWIN�controller�has�finished$*¦its�current�task,�we'll�receive�an&*¦interrupt�that�will�cause�control�to(*¦come�back�here.‚The�co-routine�linkage)*¦conveniently�allows�us�to�call�the�rest&*¦of�the�system�as�if�it�were�simply�a)*¦subroutine�to�be�executed�while�we�have*¦nothing�better�to�do.‰PAGEO********************************************************************************%*ˆWe�get�here�after�a�RWIN�interrupt.$*ˆWe�are�expecting�a�data�interrupt.*O******************************************************************************* <‰MOVE.LƒIOBUFPTR(A1),A3ˆPoint�A3�to�the�next�byte�of�the�I/O&*¦buffer.‚We�now�have�both�A3�and�D1.W%*¦set�up�properly�for�a�read�or�writ e'*¦transaction.‚If�we're�performing�some&*¦other�kind�of�transaction�(such�as�a(*¦format�command),�we've�simply�wasted�a(*¦little�time�by�setting�up�A3�and�D1.W. =‰MOVE.BƒIOFUNCT(A1),D2‡Setup�D2.B�with�the�I/O�function�flag..‰CMP.B„#READFUNC,D2‰Test�for�the�read�command.'‰BEQ.S„RD_WR�If�read,�go�read�the�data..‰CMP.B„#WRTFUNC,D2ŠTest�for�the�write�command.)‰BEQ.S„RD_WR�If�write,�go�write�the�data.3‰CMP.B„#CNFGFUNC,D2‰Test�for�the�configure�command.+‰BEQ†RDSTAT1ŽIf�configure,�go�check�status. /‰IF.B†IOFUNCT(A1)‚‚#FMTFUNCƒTHEN.S„Format�?**ˆFor�Format�Commands�ONLY* )ŽCMP.WŠ#IOPBAD,IOOPTS(A1)‚Format�as�bad�?ŽIFƒƒTHEN.S–Yes�...,“MOVE.W„ALTCYL(A1),D0…D0.W�<---�cylinder�no.*°of�alternate�sector6“MOVE.B„ALTHEAD(A1),D1„D1.B�<---�head�no.�of�alternate3“MOVE.B„BADSEC(A1),D2…D2.B�<---�first�bad�sector�in*°track.*,“MOVE.B„#GOODCODE,D5ˆD5.B�<---�Opcode�(good),“BSR‡SEND_BYTESŠSend�256�bytes�to�controller**¦to�mark�sectors�0�through�sector�no.�-�1(*¦as‚"good",�and�the�sectors�from�sector&*¦no.�through�31�as�"bad",�designating(*¦corresponding�sectors�on�the�alternate*¦track�as�"alternates".*?*ˆWe�want�to�disable�the�data�interrupt�because�we�are�all�doneC*ˆsending�data.�The�CMDSECTS�field,�which�is�the�same�as�the�CMDILVA*ˆ(interleave�factor)�field,�must�be�set�to�0,�as�it�is�tested�in *ˆINTRTN.*“SF.B†CMDSECTS(A5)(“BSR‡INTRTNŽWait�for�controller�to�do�it‰PAGEO********************************************************************************%*ˆWe�get�here�after�a�RWIN�interrupt.>*ˆWe�are�expecting�a�command�completion�interrupt�for�'FORMAT'*O******************************************************************************* 4“BTST.B„#BITCB,FLAGS(A0)„Is�RWIN�busy?�Shouldn't�be. “BNE‡CTRLERR/“TST.B…SENSBYT0(A5)ˆAny�errors�on�this�command?“BNE.L…CHECKERR**ˆMark�sectors�as�"alternates">*ˆWe�must�restore�the�interleave�factor�in�the�command�packet.*&“MOVE.B„CONFGBLK+IOSILV(A1),CMDILV(A5) )“BSR‡SET_UP_ALTŠSet�up�"format�alternate"*°command�packet.*;*ˆSENDCMD�expects�to�find�the�address�of�the�command�packet*ˆin�A3.*“LEA‡CMDOP(A5),A3 “BSR‡SENDCMD “BSR‡INTRTN O********************************************************************************%*ˆWe�get�here�after�a�RWIN�interrupt.B*ˆWe�are�expecting�a�data�interrupt�so�we�can�send�alternate�data.*O******************************************************************************* 2“MOVE.B„#ALTCODE,D5‡D5.B�<---�Opcode�for�alternate*)“MOVE.B„#32,D2ŽD2.B�<---�first�sector�no.*°to�be�marked�"bad".,“BSR‡SEND_BYTES‡Send�256�bytes�to�controller*°to�mark�all�sectors�of�the *°alternate�track�as�"alternate"*?*ˆWe�want�to�disable�the�data�interrupt�because�we�are�all�doneC*ˆsending�data.�The�CMDSECTS�field,�which�is�the�same�as�the�CMDILVA*ˆ(interleave�factor)�field,�must�be�set�to�0,�as�it�is�tested�in *ˆINTRTN.*“SF.B†CMDSECTS(A5) “BRA‡READSTATŽENDI‰ENDI *‰BRA‡RDSTAT1—If�control�reaches�this�point*°we�have�a�command�completion*°and�can�check�status.‰PAGE RD_WR„EQU‡*8‰MOVE.BƒFLAGS(A0),D0‹If�we're�performing�a�data�transfer *¦the�controller�should�be�BUSY.*‰BPL†CHECKERR�NOT�BUSY.�Go�to�check�error.‰BTST…#BITDRQ,D0�Is�DRQ�on.3‰BEQ†CTRLERRŽWe�don't�know�why�there's�an�interrupt* *ˆBWN‡3/5/84*A*ˆDouble�check�that�we�will�not�read�or�write�past�the�end�of�theB*ˆbuffer�on�our�next�read/write.�Starting�address�is�in�A3,�endingF*ˆaddress�is�in�IOBUFEND,�and�we�are�about�to�transfer�LCDSCTSZ�bytes.*(‰MOVE.L„A3,D0™D0�<---�Starting�address�+‰ADD.L…#LCDSCTSZ-1,D0˜128�-�1‰CMP.L…IOBUFEND(A1),D0'‰IFˆƒTHEN.S‘About�to�go�past�user's*°buffer�?�NOT�NICE�!!!“TST.B…D2’If�this�is�a�read,�then*“IFƒƒTHEN.SŒRead�bytes�into�bit�bucket˜BSR.S…READJUNK˜BRA‡RWCOMMON‡Then�continue�on.“ENDI*C*ˆIf�this�was�a�write,�and�you�miscalculated,�you�are�goin g�to�mess*ˆup�the�disk.* ‰ENDI *‰TST.B„D2•Check�for�read�or�write�command.'‰BLT.S„WRTDATAŽBRANCH�IF�WRITE�COMMAND.*¨FALL�THRU�ON�READ ‰PAGEO********************************************************************************D*ˆREAD�DATA�ROUTINE�entered�after�a�RWIN�interrupt�(DRQ)�for�a�read.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory)*’A3�=�pointer�to�next�byte�of�I/O�buffer*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚*…**™A‚P…**9*ˆExit:…Branches�to�read/write�common�routine�(RWCOMMON).*O******************************************************************************* READDATA�EQU†*.EQ546„EQU†4*8”Each�iteration�of�the�inner�loop%*¦below�transfers�4*8�=�32�data�bytes @‰MOVEQWƒLCDSCTSZ/EQ546-1,D3„Initialize�D3.W�to�control�the�inner$*¦loop.‚We'll�execute�the�inner�loop%*¦enough�times�to�transfer�128�bytes. DL0550„MOVEP.L‚DATA0(A0),D0†----ƒEach�complete�iteration�of�this�loop9‰MOVE.LƒD0,(A3)+Š|ƒtransfers�4*8�=�32�data�bytes�from�the'*§|ƒRWIN�controller�to�the�input�buffer=‰MOVEP.L‚DATA0(A0),D0†|ƒand�we�perform�just�enough�iterations9‰MOVE.LƒD0,(A3)+Š|ƒof�this�inner�loop�to�transfer�a�total *§|ƒof�LCDSCTSZ�bytes�during�one4‰MOVEP.L‚DATA0(A0),D0†|ƒiteration�of�the�outer�loop.‰MOVE.LƒD0,(A3)+Š|#*§|ƒWe�use�a�MOVEP.L�instruction�to<‰MOVEP.L‚DATA0(A0),D0†|ƒtransfer�four�consecutive�data�bytes:‰MOVE.LƒD0,(A3)+Š|ƒwith�the�maximum�possible�speed,�and�we&*§|ƒreplicate�the�code�in�this�loop�to<‰MOVEP.L‚DATA0(A0),D0†|ƒreduce�the�effects�of�loop�overhead.6‰MOVE.LƒD0,(A3)+Š|ƒWe�could�replicate�the�code�in�this'*§|ƒloop�more�times�for�even�more�speed=‰MOVEP.L‚DATA0(A0),D0†|ƒbut�diminishing�returns�begin�to�make8‰MOVE.LƒD0,(A3)+Š|ƒfurther�replications�less�attractive.*§|=‰MOVEP.L‚DATA0(A0),D0†|…The�RWIN�controller�actually�has�just7‰MOVE.LƒD0,(A3)+Š|ƒone�data�register,�but�that�register'*§|ƒappears�at�4�different�locations�in>‰MOVEP.L‚DATA0(A0),D0†|ƒthe�memory�map.�Therefore,�the�MOVEP.L9‰MOVE.LƒD0,(A3)+Š|ƒinstruction�actually�accesses�the�same%*§|ƒdata�register�four�times�with�the+‰DBRA…D3,L0550Š----‚maximum�possible�speed. 1‰BRA.S„RWCOMMON�We've�finished�reading�a�complete*¦block�of�input�data.‰PAGEO********************************************************************************C*ˆREADJUNK‚ROUTINE�entered�after�a�RWIN�interrupt�(DRQ)�for�a�read.*E*ˆWe�just�realized�that�we�are�about�to�write�past�the�user's�buffer.2*ˆWe�will�just�read�the�bytes�into�the�bit�bucket.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory)*’A3�=�pointer�to�next�byte�of�I/O�buffer*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚*…**™A‚P…**9*ˆExit:…Branches�to�read/write�common�routine�(RWCOMMON).*O******************************************************************************* READJUNK�EQU†* @‰MOVEQWƒLCDSCTSZ/EQ546-1,D3„Initialize�D3.W�to�control�the�inner$*¦loop.‚We'll�execute�the�inner�loop%*¦enough�times�to�transfer�128�bytes. FRD_LOOP‚MOVEP.L‚DATA0(A0),D0†----ƒEach�complete�iteration�of�this�loop&*§|ƒtransfers�4*8�=�32�data�bytes�from%*§|ƒRWIN�controller�to�the�BIT�BUCKET=‰MOVEP.L‚DATA0(A0),D0†|ƒand�we�perform�just�enough�iterations$*§|ƒof�this�inner�loop�to�transfer�a&*§|ƒtotal�of�LCDSCTSZ�bytes�during�one4‰MOVEP.L‚DATA0(A0),D0†|ƒiteration�of�the�outer�loop.*§|#*§|ƒWe�use�a�MOVEP.L�instruction�to<‰MOVEP.L‚DATA0(A0),D0†|ƒtransfer�four�consecutive�data�bytes'*§|ƒwith�the�maximum�possible�speed�and&*§|ƒreplicate�the�code�in�this�loop�to<‰MOVEP.L‚DATA0(A0),D0†|ƒreduce�the�effects�of�loop�overhead.'*§|ƒWe�could�replicate�the�code�in�this'*§|ƒloop�more�times�for�even�more�speed=‰MOVEP.L‚DATA0(A0),D0†|ƒbut�diminishing�returns�begin�to�make&*§|ƒmore�replications�less�attractive.*§|=‰MOVEP.L‚DAT A0(A0),D0†|…The�RWIN�controller�actually�has�just'*§|ƒone�data�register�but�that�register'*§|ƒappears�at�4�different�locations�in>‰MOVEP.L‚DATA0(A0),D0†|ƒthe�memory�map.�Therefore,�the�MOVEP.L%*§|ƒinstruction�actually�accesses�the'*§|ƒsame�data�register�4�times�with�the-‰DBRA…D3,RD_LOOPˆ----‚maximum�possible�speed.  ‰RTS‰PAGEO********************************************************************************K*…WRITE�DATA�ROUTINE�entered�when�we�have�a�RWIN�interupt�(DRQ)�for�a�write*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory)*’A3�=�pointer�to�next�byte�in�I/O�buffer*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚*…**™A‚P…**=*ˆExit:…Fall�through�to�read/write�common�routine�(RWCOMMON).*O******************************************************************************* WRTDATA‚EQU†* .EQ561„EQU†4*8”Each�iteration�of�the�inner�loop&*¦below�transfers�4*8�=�32�data�bytes. @‰MOVEQWƒLCDSCTSZ/EQ561-1,D3„Initialize�D3.W�to�control�the�inner$*¦loop.‚We'll�execute�the�inner�loop%*¦enough�times�to�transfer�128�bytes. ?L0570„MOVE.Lƒ(A3)+,D0Š----‚Each�complete�iteration�of�this�loop>‰MOVEP.L‚D0,DATA0(A0)†|ƒtransfers�4*8�=�32�data�bytes�from�the'*§|ƒoutput�buffer�to�the�RWIN�controlle8‰MOVE.Lƒ(A3)+,D0Š|ƒand�we�perform�just�enough�iterations>‰MOVEP.L‚D0,DATA0(A0)†|ƒof�this�inner�loop�to�transfer�a�total *§|ƒof�LCDSCTSZ�bytes�during�one/‰MOVE.Lƒ(A3)+,D0Š|ƒiteration�of�the�outer�loop.‰MOVEP.L‚D0,DATA0(A0)†|#*§|…We�use�a�MOVEP.L�instruction�to7‰MOVE.Lƒ(A3)+,D0Š|ƒtransfer�four�consecutive�data�bytes?‰MOVEP.L‚D0,DATA0(A0)†|ƒwith�the�maximum�possible�speed,�and�we&*§|ƒreplicate�the�code�in�this�loop�to7‰MOVE.Lƒ(A3)+,D0Š|ƒreduce�the�effects�of�loop�overhead.;‰MOVEP.L‚D0,DATA0(A0)†|ƒWe�could�replicate�the�code�in�this'*§|ƒloop�more�times�for�even�more�speed8‰MOVE.Lƒ(A3)+,D0Š|ƒbut�diminishing�returns�begin�to�make=‰MOVEP.L‚D0,DATA0(A0)†|ƒfurther�replications�less�attractive.*§|8‰MOVE.Lƒ(A3)+,D0Š|…The�RWIN�controller�actually�has�just<‰MOVEP.L‚D0,DATA0(A0)†|ƒone�data�register,�but�that�register'*§|ƒappears�at�4�different�locations�in9‰MOVE.Lƒ(A3)+,D0Š|ƒthe�memory�map.‚Therefore,�the�MOVEP.L:‰MOVEP.L‚D0,DATA0(A0)†|ƒinstruction�accesses�the�same�data%*§|ƒregister�4�consecutive�times�with/‰DBRA…D3,L0570Š----‚the�maximum�possible�speed.*©Control�falls�into�RW_COMMON‰PAGEO*********************************************************************************ˆREAD/WRITE�COMMON�ROUTINE*?*ˆEntered�after�reading�or�writing�a�block�of�data�(128�bytes).*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory-*’A3�=�pointer�to�next�byte�in�the�I/O�buffer*’A5�=�physical�address�of�CCB*@*ˆExit:…Branches�to�NEXTSEC1�to�complete�processing�this�sector.5*’Branches�to�NEXTSECT�to�complete�processing�current7*’Fall�through�to�RWINDONE�routine�to�finish�processing%*’the�current�entry�of�the�I/O�queue.*O******************************************************************************* FRWCOMMON�MOVE.LƒA3,IOBUFPTR(A1)†Update�the�I/O�buffer�pointer�to�point%*¦to�the�next�byte�of�the�I/O�buffer. 8‰SUB.B…#1,BLKCNT(A5)‡Adjust�block�count�for�this�sector.0‰BNE†NEXTSEC1�We�haven't�finished�a�sector�so�go)*¦to�continue�the�transfer�if�the�RWIN�is*¦requesting�data�transfer.*5*‚Increment�the�LSN�and�decrement�the�CMDSECTS�field:*7‰ADD.L„#1,CMDOP(A5)‹Increment�the�LSN.�This�may�be�used%*¦to�retry�if�sector�is�found�to�have*¦an�ECC/CRC�error.:‰SUB.B„#1,CMDSECTS(A5)ˆDecrement�the�count�of�sectors�that4‰BHI†NEXTSECT�remain�to�be�processed�for�the�current%*¦WDC�command�sequence.‚If�we�haven't**¦finished,�loop�back�to�process�next�one. =‰BTST.Bƒ#BITCB,FLAGS(A0)‡We've�finished�processing�all�of�the(*¦sector(s)�for�the�current�RWIN�command *¦sequence. 5‰BNE.S„READSTAT�The�RWIN�may�still�be�BUSY�because�of'*¦a� data�ECC�error�in�last�sector�read. '*¨The�RWIN�is�done.�(normal�case).�ReadE‰MOVE.BƒSENSE(A0),SENSBYT0(A5)�SENSE�BYTE�0�to�clear�command�complet-1‰BRA.S„RDSTAT1�ion�interrupt�and�go�check�status. 7READSTAT�BSR.S„INTRTN‘Return�control�to�the�system,�and)*¦wait�for�a�status-ready�RWIN�interrupt. PAGEO********************************************************************************%*ˆWe�get�here�after�a�RWIN�interrupt.2*ˆWe�are�expecting�a�command�completion�interrupt.*O******************************************************************************* 7‰BTST.Bƒ#BITCB,FLAGS(A0)…Is�RWIN�BUSY?�It�shouldn't�be.4‰BNE†CTRLERRŽYES.�Must�be�a�DRQ�interrupt�that�we're*¦not�expecting.ARDSTAT1‚TST.B„SENSBYT0(A5)‰Were�there�any�errors�in�this�command?'‰BNE.L„CHECKERR�YES.�Go�to�check�error. =XFERDONE�CLR.L„HALFSCTS(A1)‹This�clears�the�half�sector�count"*¦since�all�half�sectors�have�been%*¦transfered�any�additional�transfers&*¦for�this�I/O�packet�will�be�sectors.8‰TST.L„IOSCTCNT(A1)‹The�RWIN�controller�has�successfully1‰BNE†PROCQUEŽcompleted�the�entire�I/O�transaction(*¦that�was�specified�by�the�last�command(*¦sequence�that�we�gave�it.‚If�there�are'*¦any�sectors�remaining�to�be�processed)*¦for�the�current�entry�of�the�I/O�queue,'*¦loop�back�to�process�another�chunk�of*¦the�entire�I/O�transfer. %*¨Recall�that�IOSCTCNT�is�always�zero&*¦for�any�I/O�transaction�that�doesn't(*¦involve�the�transfer�of�any�read/write*¦data. 9‰MOVE.BƒEOVFLAG(A1),D1‰We've�now�completed�the�entire�I/O'*¦transaction�that�was�specified�by�the$*¦command�that�generated�the�current%*¦entry�of�the�I/O�queue.‚The�EOVFLAG'*¦value�that�we�get�into�D1.B�here�will#*¦be�returned�to�the�user�as�an�I/O&*¦status�code.‚If�the�I/O�transfer�was'*¦truncated�to�avoid�running�beyond�the(*¦end�of�the�disk,�we�return�the�ISTAEOV'*¦status�code.‚Otherwise,�we�return�the)*¦ISTAOK�status�code�to�indicate�that�the!*¦entire�operation�went�smoothly. %*¨Control�now�falls�into�the�RWINDONE"*¦routine�to�finish�processing�the!*¦current�entry�of�the�I/O�queue.‰PAGEO*********************************************************************************ˆFINISH�PROCESSING�QUEUE�ENTRY*F*ˆControl�comes�here�when�the�driver�is�done�with�the�current�command.D*ˆWe�call�CHAN_DONE�in‚DISKLIB�to�queue�the�I/O�completion�event�for@*ˆus,�and‚we‚remove�the�current‚entry�from‚the�queue.‚If�the�I/OD*ˆqueue�has�another�entry,‚we'll�loop�back�and�start�processing�that*ˆentry.*=*ˆEntry:„D1.B�=�VERSAdos�error�code�if�error,�otherwise�zero.9*’D2�=�Logical�sector�number�if�error,�otherwise�garbage.9*’A1�=�pointer�to�drive's�variable�block�in�global�memory*’A5�=�Physical�address�of�CCB*?*ˆThese�entry�conditions�are�required�by�the�CHAN_DONE�routine.*6*ˆCalls:„CHAN_DONE�in�the�generic�disk�driver�DISKLIB.*=*ˆExit:…Branches�to�process�next�queue�entry�if�there�is�one.0*’Falls�through�to�idle�loop�if�there�isn't�one.*O******************************************************************************* RWINDONE�EQU†* 2‰JSR†CHAN_DONEŒCall�the�generic�disk�driver�to�set"*¦fields�in�the�IOCB�and�queue�the*¦event�for�us. 6EQ640„REG†A1/A3/A4�Here�we�remove�the�front�entry�fromA‰MOVEM.L‚IOQUEUE+4(A5),EQ640‚the�I/O�queue,�and�we�simultaneouslyA‰MOVEM.L‚EQ640,IOQUEUE(A5)„set�A1�to�point�to�the�drive�block�for(*¦the�disk�drive�that�is�associated�with$*¦the�next�(if�any)�entry�of�the�I/O*¦queue. 6‰SUB.W„#4,IOQCNT(A5)ŠReduce�the�queue-count�pointer�to1‰BHI†PROCQUEŽaccount�for�the�fact�that�we've�just(*¦removed�a�four-byte�entry�from�the�I/O$*¦queue.‚If�there�is�still�an�active&*¦entry�in�the�I/O�queue,�loop�back�to"*¦start�processing�the�next�entry. $*¨If�the�I/O�queue�is�empty,�control(*¦falls�into�the�co-routine�segment�that%*¦is�potentially�active�when�the�RWIN'*¦controller�is�caught�up�and�should�be*¦idle.‰PAGEO************************************************************** *******************ˆIDLE�LOOP�ROUTINE*B*ˆThis�routine�is�entered�when�the�I/O�queue�has�been�emptied.�TheB*ˆcontroller�is�completely�caught�up�with�all�of�its�requests,�and9*ˆis�now�idle.‚We'll�simple�return�control�to�the�system.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area*’A5�=�physical�address�of�CCB*3*ˆExit:…BSR�to�INTRTN.‚It�should�never�return�here.*O******************************************************************************* :IDLELOOP�BSR.S„INTRTN‘The�I/O�queue�is�empty,�so�we�simply%*¦return�control�to�the�system.‚We've)*¦caught�up�with�all�of�the�requests�that'*¦have�been�set�up�for�processing�under*¦interrupt�control. 4‰ST.B…CHANDOWN(A5)‹If�control�ever�comes�to�this�co-%*¦routine�segment,�we�have�a�problem.#*¦Apparently,�we've�received�a�RWIN%*¦interrupt�when�we�haven't�given�the%*¦controller�anything�to�do.‚In�fact,%*¦not�only�have�we�not�given�the�RWIN'*¦controller�anything�to�do,�we�haven't*¦even�enabled�its�interrupt. #*¨It's�hard�to�tell�what�might�have$*¦caused�this�problem,�but�something$*¦serious�is�wrong.‚We�mark�the�RWIN&*¦channel�down,�and�we'll�report�it�as%*¦being�down�the�next�time�the�system*¦tries�to�access�it. 2‰BRA.S„IDLELOOP�Return�to�the�idle�loop.‚We'll�get$*¦out�of�this�loop�whenever�the�RWIN&*¦driver�receives�another�command�that(*¦requires�some�action�that�must�be�done*¦under�interrupt�control. PAGEO*********************************************************************************ˆRETURN�FROM�INTERRUPT*C*ˆThis�routine�is�called�whenever�we�want�to�return�control�to�CMR;B*ˆto�wait�for�the�next�interrupt�or�when�we've�finished�processingA*ˆall�commands.‚This�routine�is�always�called�as�a�subroutine,�so?*ˆthe�stack�contains�the�address�of�the�co-routine�segment�thatD*ˆshould�be�executed�in�response�to�the�next�interrupt.�This�routineA*ˆstores�that�address�in�INTSWTCH,�and�enables�data�interrupts�if!*ˆthere�is�data�left�to�transfer.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area*’A5�=�physical�address�of�CCB*O******************************************************************************* DINTRTNƒMOVE.Lƒ(SP)+,INTSWTCH(A5)ƒSave�the�co-routine�switch�address. AEQ440„REG†D1/D2/D3/A2/A3/A4„Restore�the�registers�that�were�saved;‰MOVEM.L‚(SP)+,EQ440Šat�the�start�of�the�interrupt�handler. 4‰TST.B„CMDSECTS(A5)‹If�all�the�sectors�have�not�been2‰IF��THEN.S�transfered,�we�want�to�enable�data7ŠMOVE.B�#ENBLDINT,INTCTRL(A0)�interrupts�from�the�RWIN.‰ENDI &*¦NOTE*‚The�CMDSECTS�field�is�non-zero$*¦for�CONFIGURE�and�FORMAT�commands,'*¦but�data�interrupts�are�not�generated)*¦so�we�don't�care�that�they�are�enabled. G*ƒ******************************…We�don't�enable�data�interrupts,�since)*¦the�last�command�to�the�RWIN�controller'*¦may�have�been�a�read�or�write�and�the&*¦RWIN�loads�and�unloads�the�FIFO�con-<*†++++++‚NOTICE‚++++++Štinueously�while�IDLEING.�This�allows%*¦a�driver�to�transmit�or�receive�all)*¦the�data�for�a�command�without�checking&*¦for�error�until�it's�done.�Of�course(*¦no�read�or�writes�to�the�disk�actually)*¦occur�after�the�error.�This�driver�does?*ƒ******************************…NOT�make�use�of�this�function. 4CARRY„EQU†1<<0“Finally,�set�the�SR.C�bit,�and�return5‰OR.B…#CARRY,CCR‹control�to�CMR.‚Setting�the�SR.C�bit&*¦indicates�that�we�have�processed�the *¦interrupt.‰RTS‰SPC�2N*******************************************************************************"*ˆEND�OF�INTERRUPT�SERVICE�ROUTINE*N******************************************************************************‰PAGEO********************************************************************************-*ˆSUBROUTINES�CALLED�BY�THE�INTERRUPT�HANDLER*O******************************************************************************* O************************************************************************** ******=*ˆSET_UP_ALT„(added�for�alternate�sector�command�BWN�2/13/84)*;*ˆSet�up�a�command�packet�for�the�format�alternate�command.:*ˆTake�the�command�packet�you�have�now,�and�substitute�the=*ˆalternate�sector�number�for�the�sector�number�in�there�now.*@*ˆEntry:„A1�=�pointer�to�drive's�variable�block�in�global�memory*’A5�=�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D„**™A„P‡P**ˆP�=�parameter�register!*ˆ*�=�saved�and�restored�register**ˆExit:…Same�as�entry*O******************************************************************************* SET_UP_ALT!‰MOVE.L„D1,-(SP)ŒSave�register�D1<‰MOVE.L„CMDOP(A5),D1ˆSave�bytes�0-3�of�command�packet�in�D1.8‰AND.L…#LSNMSKNOT,D1‡Mask�out�lower�21�bits�of�D1.‚These%*§bits�contain�the�old�sector�number.%*§The�stuff�we�want�to�save�is�in�D1.*3‰MOVE.L„IOALTSEC(A1),CMDOP(A5)ˆPut�alternate�sector*§number�into�command�packet.;‰AND.L…#LSNMASK,CMDOP(A5)ƒMask�out�upper�11�bits�of�command'*§packet.‚These�contain�Opcode�and�LUN.*:‰OR.L†D1,CMDOP(A5)ˆCombine�the�old�Opcode�and�LUN�with�the *§new�(alternate)�sector�number. $‰MOVE.L„(SP)+,D1ŒRestore�register�D1‰RTS‰PAGEO********************************************************************************D*ˆSEND_BYTES�--Send�256�bytes�of�format�descriptor�to�the�controller**@*ˆFor�each�of�the�32�sectors�(0-$1F)�on�the�track,�send�5�bytes:*+*ˆByte�0ƒ$00�if�sector�is�to�be�marked�good)*‘$40�if�sector�is�to�be�marked�alternate#*‘$80�if�sector�is�to�be�marked�bad*8*ˆByte�1„Logical�sector�number�for�this�track�(00�-�$1F)*3*ˆByte�2„Cylinder�number�(MSB)�of�alternate�sector.*3*ˆByte�3„Cylinder�number�(LSB)�of�alternate�sector.*:*ˆByte�4„Bits�7,6,5:‚Head�number�(0-7)�of�alternate�sector5*’Bits�4,3,2,1,0�:�Sector�number�(0-$1F)�of�alternate*£sector**ˆThen�send�fill�bytes�to�256.**ˆEntry:(*’A0ƒ=�address�of�memory-mapped�I/O�area4*’D0.B�=�Cylinder�number�of�alternate�sector�for�bad$*™sector�(garbage�if�no�bad�sectors)7*’D1.B�=�Head�number�of�alternate�sector�for�bad�sector*™(garbage�if�no�bad�sectors)3*’D2.B�=�Sector�number�of�first�bad�sector�on�track*’D5.B�=�Opcode�(00�or�40)**!*ˆRegister�usage:…0ƒ1�2�3�4�5�6�7*™D‚PƒP�P�*�*�P�**™A‚PƒP*’P�=�parameter�register*’R�=�return�register*’*�=�saved/restored�register***ˆExit:*’Same�as�entry**O*******************************************************************************‰PAGE SEND_BYTES:SEND_REGS�REG†D0-D6'‰MOVEM.LƒSEND_REGS,-(SP)…Save�registers/‰MOVE.W„#256,D6�D6�<---�number�of�bytes�to�send $‰CLR.B…D3’D3�will‚hold�sector�number3‰WHILE.BƒD3ƒƒD2ƒDO.S‰Mark�good�up�to�sect�no.-1*°or�mark�alternate +�MOVE.B„D5,DATA0(A0)ˆMove�opcode�(00�or�40)'�MOVE.B„D3,DATA0(A0)ˆMove�sector�number&�MOVE.B„#0,DATA0(A0)ˆMove�3�more�bytes�MOVE.B„#0,DATA0(A0)�MOVE.B„#0,DATA0(A0) ,�ADDQ.B„#1,D3ŽGet�next�sector�number�into�D3 �SUBQ.W„#5,D6‰ENDW ‰MOVE.W„D0,D4-‰LSR.W…#8,D4�D4.W‚<---�MSB�of�cylinder�number ,‰LSL.B…#5,D1�Get�head�number�into�bits�7,6,52‰ADD.B…D2,D1�Get�sector�number�into�bits�0-4�of�D1 5‰WHILE.BƒD3‚‚#32‚DO.S„Mark�sectors�to�31�as�"bad" &�MOVE.B„#BADCODE,DATA0(A0)ˆSend�opcode'�MOVE.B„D3,DATA0(A0)ŽSend�sector�number-�MOVE.B„D4,DATA0(A0)ŽSend�MSB�of�cylinder�no.-�MOVE.B„D0,DATA0(A0)ŽSend�LSB�of�cylinder�no.,�MOVE.B„D1,DATA0(A0)ŽSend�Head+sector�number �ADD.B…#1,D3 �ADD.B…#1,D1 �SUBQ.W„#5,D6 ‰ENDW*… nMwC<‡>�A—4Ÿ7§E¯<·B¿;ÇJÏ<×Eß=ç<ï=*ˆWe�have�now�sent�5*32�=�160‚bytes.�The�controller�wants�256"*ˆso�we�send�96�more,�4�at�a�time.*‰REPEAT �MOVEP.LƒD3,DATA0(A0) �SUBQ.W„#4,D6 ‰UNTIL… *‰MOVEM.Lƒ(SP)+,SEND_REGS…Restore�registers ‰RTS‰PAGEO************ *********************************************************************ˆCHECK�ERROR�ROUTINE*+*ˆSome�error�has�been�detected�by�the�RWIN.**ˆFor�a�READ�command:>*�If�the�error�is�an�ECC�error�(correctable�or�uncorrectable),+*’1.‚Compare�current�error�with�last�error.<*’2.‚If�retry�count�is�not�exhausted,�retry�from�bad�sector.;*’3.‚If�retry�count�is�exhausted,�error�is�correctable,�and7*–the�last�two�errors�were�identical,�we'll�correct�the4*–error�in�memory�and�issue�the�rest�of�the�command.*’4.‚Else�report�the�error.*+*ˆFor�all�other�commands,�report�the�error.*=*ˆEntry:„A0�=�physical�address�of�RWIN�Memory-Mapped�I/O�area9*’A1�=�pointer�to�drive's�variable�block�in�global�memory<*’A3�=�pointer�to�I/O�buffer�(except�on�last�sector�of�xfer)*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚*�*�* *™A‚P�Pƒ*�*�P**ˆExit:…Report�the�error.*O******************************************************************************* CHECKERR�EQU†*%‰SUB.B„#1,RETRY(A5)‰DECR.�RETRY�COUNT)UNCORRER�EQU†$12’UNCORRECTABLE�DATA�ERROR%CORRERƒEQU†$13’CORRECTABLE�DATA�ERROR0‰MOVE.Wƒ#8,D0�LOOP�COUNTER�TO�READ�&�COMPARE�THE*§REMAINING�9�SENSE�BYTES. 9‰LEA†SENSBYT0(A5),A4†POINTER�TO�SENSE�BYTE�0.�NOTICE�THAT$*§THE�10�SENSE�BYTES�ARE�ACCESSED�IN *§ORDER�(ei.�0..9)�BY�SEQUENTIAL!*§READS�OF�THE�SAME�MEMORY�MAPPED"*§BYTE�IN�THE�RWIN.�WE�HAVE�DONE�A#*§READ�OF�SENSE�BYTE�0�TO�CLEAR�THE&*§INTERRUPT.�WE'LL�GET�BYTE�0�FROM�THE *§SAVE�AREA,THEN�ACCESS�1�THRU�9 !‰MOVE.Bƒ(A4)+,D1�GET�SENSE�BYTE�07‰EOR.B„#CORRER,D1‹D1.B�WILL�=�0�IF�ERROR�IS�CORRECTABLE8‰OR.B…RETRY(A5),D1‰D1.B�=�0�IF�CORRECTABLE�&�RETRY�COUNT*«=�0(L0552„MOVE.BƒSENSE(A0),D2‰GET�SENSE�BYTE‰CMP.B„(A4),D2 PAGE0‰BEQ.S„L0553�BRANCH�IF�BYTE�FOR�CURRENT�ERROR�IS*§THE�SAME�AS�LAST�ERROR‰OR.B…#1,D1�SET�D1�TO�NON-ZERO2L0553„MOVE.BƒD2,(A4)+�SAVE�THE�CURRENT�ERROR�BYTES‰DBRA…D0,L0552)*¦D1.B�=�0�IF(LAST�ERROR�=�CURRENT�ERROR)*±&�(ERROR�IS�CORRECTABLE)*±&�(RETRY�COUNT�=�0) ‰TST.B„D1&‰BNE.S„L0555�BRANCH�IF�NOT�CORRECTABLE $* HERE TO CORRECT DATA IN THE BUFFEREQ554„EQU†CONFGBLK+IOSPSM:‰MOVE.LƒIOBUFPTR(A1),A3†POINTER�TO�NEXT�LOCATION�IN�BUFFER7‰SUB.W„EQ554(A1),A3‰A3�POINTS�TO�1ST�BYTE�IN�BAD�SECTOR ‰CLR.L„D1=‰MOVE.BƒSENSBYT7(A5),D1†GET�BYTE�OFFSET�FROM�THE�START�OF�THE"*§THE�SECTOR�TO�THE�1ST�ERROR�BYTE-‰ADD.W„D1,A3�BUFFER�ADDRESS�OF�1ST�ERROR�BYTE>‰MOVE.BƒSENSBYT8(A5),D1†CORRECTION�MASK�FOR�THE�1ST�ERROR�BYTE‰EOR.B„D1,(A3)+�CORRECT�BYTE)‰MOVE.BƒSENSBYT9(A5),D1†SAME�FOR�2ND�BYTE‰EOR.B„D1,(A3)0‰LEA†CMDOP(A5),A3‰POINT�A3�TO�THE�COMMAND�PACKET9‰TST.B„CMDSECTS(A5)‰ARE�ANY�MORE�SECTORS�TO�BE�TRANSFERED*§FOR�THIS�COMMAND?'‰BNE†SENDNEWŽYES.�SEND�COMMAND�FOR�REST‰BRA†XFERDONE�NO.�ALL�DONE‰PAGE*H*‚We�only�get�to�CHECKERR�if�we�read�or�wrote�the�data�and�upped�the�LSNJ*‚and�CMDSECTS�in�the�command�packet�for�preparation�for�going�to�SENDNEW.*(*‚However,�at�this�point�we�will�either:**ˆ(1)�branch�to�STATERR�if�no�more�retries7*ˆ(2)�branch�to�STATERR�if�error�is�not�code�$12�or�$13*ˆ(3)�do�a�retry*E*‚In�each�of�these�cases�we�want�to�have�the�current�LSN�and�CMDSECTSE*‚in�the�command�packet,�so�we�have�to�add�1�to�CMDSECTS�and�subtract*‚1�from�the�LSN.* *L0555„TST.B„RETRY(A5)ŒIS�RETRY�COUNT�=�0�?&‰IF‚‚THEN.SŽ&�REPORT�ERROR�IF�ZERO‹ADDQ.Bƒ#1,CMDSECTS(A5)‹SUBQ.Lƒ#1,CMDOP(A5)‹BRA.S„STATERR‰ENDI ‰MOVE.Bƒ#$FE,D1:‰AND.B„SENSBYT0(A5),D1†MASK�LSB�SO�CODES�$12�AND�$13�=�$12‰CMP.B„#UNCORRER,D12‰BNE.S„STATERRŽREPORT�ERROR�IF�NOT�CODE�$12�OR�$13 -* HERE TO DO A RETRY OF THE LAST SECTOR READ.E* THE BAD SECTOR HAS BEEN READ INTO THE BUFFER AND THE COMMAND PACKET3* IS POINTING TO THE CURRENT SECTOR. (BWN 10/25/84) ‰CLR.L„D1%‰MOVE.WƒEQ554(A1),D1‰GET�BYTES/SECTOR*‰TST.L„HALFSCTS(A1)‰IS�THIS�A�HALF�SECTOR?‰BEQ.S„L0556�NO.*‰LSR.W„#1,D1�YES.�BYTE/SECTOR�DIVIDED�BY�2GL0556„SUB.L„D1,IOBUFPTR(A1)‚RESET�BUFFER�POINTER�TO�START�OF�BAD�SECTOR7‰ADDQ.Bƒ#1,CMDSECTS(A5)‚ADD�1�TO�N UMBER�OF�SECTORS�LEFT*®FOR�CURRENT�COMMAND)‰SUB.L„#1,CMDOP(A5)ŽSET�LSN�BACK�1�SECTOR0‰LEA†CMDOP(A5),A3ŽPOINT�A3�TO�THE�COMMAND�PACKET+‰BRA†SENDAGN“GO�TO�SEND�THE�COMMAND�TO�READ*«FROM�ERROR�SECTOR.‰PAGEO*********************************************************************************ˆREPORT�ERROR�ROUTINE*B*ˆWe�get�here�when�an�error�has�been�detected�by�the�RWIN1�and�the*ˆretries,�if�any,�have�failed.*@*ˆEntry:„A1�=�pointer�to�drive's�variable�block�in�global�memory*’A5�=�physical�address�of�CCB*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D„R�*�R*™A„P‡P*"*ˆExit:‡D1.B�=�VERSAdos�error�code/*”D2.L�=�Logical�sector�number�of�error�sector.*=*ˆThese�registers�are�a�requirement�for�the�RWINDONE�routine.**ˆExits�to:�RWINDONE*O******************************************************************************* STATERR‚CLR.L„D29‰MOVE.BƒSENSBYT0(A5),D2†Get�the�error�description�to�D2.W(‰CMP.B„#1,IOFUNCT(A1)‡Configure�command?*‰BNE.S„RSTERR1ŽNo...report�error�as�usual.5‰CMP.B„#$0C,D2ŽYes..was�the�error�an�illegal�command?1‰BNE†XFERDONE�No...return�as�if�no�error�occured.)RSTERRƒEQU†$80’Check�for�self-test�error.RSTERR1‚CMP.B„#RSTERR,D2 ‰BNE.S„L0950/‰MOVE.Bƒ#ISTAUNR,D1ŠUnrecoverable�device�error. ‰BRA†RWINDONE * HERE FOR OTHER CODES?L0950„CMP.B„#ERRCEND,D2ŠRest�of�codes�>�last�entry�in�table�are *¦undefined. ‰BLS.S„L0955‰MOVE.Bƒ#ISTAICE,D1 ‰BRA†RWINDONE IL0955„MOVE.BƒERRCODE(PC,D2.W),D1‚Use�the�RWIN�error-code�as�an�index�into(*¦the�RWIN�error-code�table,�and�get�the)*¦VERSAdos�error�code�from�the�table�into*¦D1.B. 9‰MOVE.L„CMDOP(A5),D2ˆGet�the�sector�number�with�the�error3‰AND.L…#LSNMASK,D2‰from�the�command�packet�into�D2. +‰BRA†RWINDONE�Done�with�the�error�handling. PAGEO********************************************************************************8*ˆTABLE�TO�TRANSLATE�RWIN�ERROR�CODES�TO�VERSADOS�ERRORS*O******************************************************************************* *¨----‚RWIN�Error�Code.*¨|$*¨V…RWIN�Definition�and�Explanation. ?ERRCODE‚DC.B…ISTADMA‡$00„No�error.�BUT�the�driver�was�expecting&*¦to�transfer�data�to�or�from�the�RWIN%*¦when�the�RWIN�throught�it�was�done.'*¦We�report�a�controller�error�whenever$*¦we�get�this�error�code�because�the*¦situation�is�serious. 3‰DC.B…ISTAUNR‡$01„No�index�signal.‚VERSAdos�doesn't'*¦really�have�an�error�code�to�describe%*¦this�situation,�so�we�simply�report$*¦that�the�disk�unrecoverable�error. 2‰DC.B…ISTARES‡$02„No�track�000.‚Disk�restore�error '‰DC.B…ISTASAˆ$03„Invalid�sector�number. 7‰DC.B…ISTANRˆ$04„Drive�not�ready.‚We�report�an�error�to'*¦indicate�that�the�drive�is�not�ready. #‰DC.B…ISTASEK‡$05„No�seek�complete. &‰DC.B…ISTADME‡$06„ID�header�not�found. 7‰DC.B…ISTADME‡$07„Data�mark�not�found.�Report�as�ID�not$*¦found.�This�is�not�a�"DELETED�DATA*¦MARK�DETECT" 6‰DC.B…ISTABDS‡$08„Nested�alternate�sectors.�This�error%*¦is�detected�when�a�sector�is�marked%*¦defective�and�the�alternate�is�also*¦marked�defective. '‰DC.B…ISTAICE‡$09„Undefined�error�code.'‰DC.B…ISTAICE‡$0A„Undefined�error�code.'‰DC.B…ISTAICE‡$0B„Undefined�error�code. &‰DC.B…ISTAIFˆ$0C„Invalid�command�code. '‰DC.B…ISTAICE‡$0D„Undefined�error�code.'‰DC.B…ISTAICE‡$0E„Undefined�error�code.'‰DC.B…ISTAICE‡$0F„Undefined�error�code.'‰DC.B…ISTAICE‡$10„Undefined�error�code.'‰DC.B…ISTAICE‡$11„Undefined�error�code. 3‰DC.B…ISTACRC‡$12„Uncorrectable�data�ECC/CRC�error. 7‰DC.B…ISTACRC‡$13„Correctable�data�error.�The�retry�did"*¦produce�consistent�results�so�an"*¦uncorrectable�error�is�reported. (‰DC.B…ISTAWPˆ$14„Write�protected�device. 5‰DC.B…ISTAUNR‡$15„Write�fault.�This�is�reported�as�an*¦unrecoverable�device�error. '‰DC.B…ISTAICE‡$16„Undefined�error�code.'‰DC.B…ISTAICE‡$17„Undefined�error�code.'‰DC.B…ISTAICE‡$18„Undefined�error�code.'‰DC.B…ISTAICE‡$19„Undefined�error�code.'‰DC.B…ISTAICE‡$1A„Undefined�error�code.'‰DC.B…IS TAICE‡$1B„Undefined�error�code.'‰DC.B…ISTAICE‡$1C„Undefined�error�code.'‰DC.B…ISTAICE‡$1D„Undefined�error�code.'‰DC.B…ISTAICE‡$1E„Undefined�error�code.'‰DC.B…ISTAICE‡$1F„Undefined�error�code.'‰DC.B…ISTAICE‡$20„Undefined�error�code.'‰DC.B…ISTAICE‡$21„Undefined�error�code.'‰DC.B…ISTAICE‡$22„Undefined�error�code.'‰DC.B…ISTAICE‡$23„Undefined�error�code.'‰DC.B…ISTAICE‡$24„Undefined�error�code.'‰DC.B…ISTAICE‡$25„Undefined�error�code.'‰DC.B…ISTAICE‡$26„Undefined�error�code.'‰DC.B…ISTAICE‡$27„Undefined�error�code.'‰DC.B…ISTAICE‡$28„Undefined�error�code.'‰DC.B…ISTAICE‡$29„Undefined�error�code.'‰DC.B…ISTAICE‡$2A„Undefined�error�code.'‰DC.B…ISTAICE‡$2B„Undefined�error�code.'‰DC.B…ISTAICE‡$2C„Undefined�error�code.'‰DC.B…ISTAICE‡$2D„Undefined�error�code.'‰DC.B…ISTAICE‡$2E„Undefined�error�code.'‰DC.B…ISTAICE‡$2F„Undefined�error�code.'‰DC.B…ISTAICE‡$30„Undefined�error�code.'‰DC.B…ISTAICE‡$31„Undefined�error�code.'‰DC.B…ISTAICE‡$32„Undefined�error�code.'‰DC.B…ISTAICE‡$33„Undefined�error�code.'‰DC.B…ISTAICE‡$34„Undefined�error�code.'‰DC.B…ISTAICE‡$35„Undefined�error�code.'‰DC.B…ISTAICE‡$36„Undefined�error�code.'‰DC.B…ISTAICE‡$37„Undefined�error�code.'‰DC.B…ISTAICE‡$38„Undefined�error�code.'‰DC.B…ISTAICE‡$39„Undefined�error�code.'‰DC.B…ISTAICE‡$3A„Undefined�error�code.'‰DC.B…ISTAICE‡$3B„Undefined�error�code.'‰DC.B…ISTAICE‡$3C„Undefined�error�code.'‰DC.B…ISTAICE‡$3D„Undefined�error�code.'‰DC.B…ISTAICE‡$3E„Undefined�error�code.'‰DC.B…ISTAICE‡$3F„Undefined�error�code.'‰DC.B…ISTAICE‡$40„Undefined�error�code. 6‰DC.B…ISTAUNR‡$41„Floppy�controller�chip�fault.�Report *¦an�Unrecoverable�Device�Error. 6‰DC.B…ISTACNF‡$42„Illegal�floppy�format.�Configuration*¦Parameter�Error. 3‰DC.B…ISTACFG‡$43„Media/drive�incompatible.�Config.*¦Parameter�Error. 3‰DC.B…ISTAUNR‡$44„Unexpected�floppy�disk�controller *¦interrupt. ERRCEND‚EQU†*-ERRCODE K* ERROR CODES >$44 AND <=$80 ARE REPORTED AS "ISTAICE". CODE $80 IS A SELF-G* TEST ERROR AND IS REPORTED AS "ISTAUNR". THESE CHECKS ARE MADE IN THE* STATERR ROUTINE.‰PAGEO*********************************************************************************ˆCONTROLLER�ERROR�ROUTINE*@*ˆThe�purpose�of�this�routine�is�to�report�"state'�errors�of�the*ˆcontroller,�for�example:?*Š1.‚The�RWIN�wants�to�be�read�or�written�but�the�driver�is�not%*Žexpecting�to�transfer�more�data,�orE*Š2.‚The�RWIN�generated�an�interupt�but�the�condition�has�changed,�orD*Š3.‚The�RWIN�went�'busy'�before�the�entire�command�packed�was�sent.**ˆThere�are�2�entry�points:6*ŠCTRLERR1:�If�the�error�was�detected�in�a�subroutine.2*ŠCTRLERR�:�If�the�error�was�detected�in�the�main.*O******************************************************************************* 7CTRLERR1�ADDQ.Lƒ#4,SP’Control�comes�to�this�entry�point%*¦when�a�controller�error�is�detected%*¦from�within�a�subroutine.‚We�remove&*¦the�subroutine's�return�address�from(*¦the�stack,�so�the�stack�is�restored�to&*¦the�condition�that�it�had�before�the*¦subroutine�was�called.  >CTRLERR‚ST.B…CHANDOWN(A5)‹Down�the�RWIN�channel�by�setting�the"*¦variable�that�indicates�that�the#*¦controller�is�down.‚If�the�system(*¦tries�to�access�the�RWIN�channel�again#*¦without�resetting�it�first,�we'll%*¦report�an�error�indicating�that�the$*¦channel�is�down.‚The�system�really"*¦shouldn't�try�to�access�the�RWIN'*¦channel�again�without�first�resetting$*¦the�controller.‚Even�resetting�the)*¦controller�may�not�correct�the�problem,'*¦but�we'll�let�the�system�try�as�often*¦as�it�wishes. 5‰MOVEQIƒISTACNT,D1�Set�up�D1.B�for�reporting�a�status5‰BRA†RWINDONE�code�that�indicates�a�controller�error,%*¦and�go�terminate�processing�for�the!*¦current�entry�of�the�I/O�queue.‰PAGEO*********************************************************************************ˆSEND�COMMAND�ROUTINE*H*ˆThe�purpose�of�this�routine�is�to�send�the�command�packet�to�the�RWIN.*8*ˆEntry:„A0�=�addr ess�of�1st�byte�of�the�command�packet.6*’A3�=�physical�address�of�RWIN�Memory-Mapped�I/O�area*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚*�**™A‚P…**"*ˆExit:…Return�to�calling�routine.*O******************************************************************************* SENDCMD‚EQU‡*&‰MOVEQW„CMDLEN-1,D1‰Number�of�bytes�-1"EQ521„EQU‡(1<‚Drive/controller�supports�the�configure�request.?*�‚Drive/controller�does�not�support�the�configure�request.4*•D1.B�=�VERSAdos�error�code�for�the�error�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** SET_CNFG: /‰MOVEM.L‚D2/D4,-(A7)ŠSave�any�registers�we�use. $‰MOVEQ.L‚#0,D2�Clear�save�registers.‰MOVEQ.L‚#0,D4�* >CD010„EQU†CONFGBLK+IOSTRKD…No.�of�cylinders�on�drive�(floppy).;CD015„EQU†CONFGBLK+IOSTRK†No.�of�cylinders�on�media�(hard). $‰BTSTW„#IOARDISC,CONFGBLK+IOSATW(A1)‰IF‚‚THEN.SŽIf�floppy,7‹MOVE.W‚CD010(A1),D4ˆUse�the�no.�of�cylinders�on�drive.‰ELSE.S˜If�hard,7‹MOVE.W‚CD015(A1),D4ˆUse�the�no.�of�cylinders�on�media.‰ENDI %‰SUBQ…#1,D4�Max�cyl�=�no.�of�cyl�-�1.‰PAGE9CD020„EQU†CONFGBLK+IOSHDS†Read�the�no.�of�heads�on�drive.‰MOVE.BƒCD020(A1),D2‰*)‰SUBQ…#1,D2�Max�heads�=�no.�of�heads�-�1.$‰LSL.W„#8,D2�Position�in�bits�13-15.‰LSL.W„#5,D2�*!‰OR.W…D2,D4�Add�to�save�register. :CD030„EQU†CONFGBLK+IOSPCOM…Read�the�precompensation�value.‰MOVE.WƒCD030(A1),D2‰*0‰CMP.W„#$FF,D2ŽLimit�to�one�byte,�since�the�RWIN-‰IF‚‚THEN.SŽhas�only�one�byte�to�hold�the1‹MOVE.W�#$FF,D2Žpre-compensation�cylinder�number!‰ENDI %‰MOVE.LƒD2,IOSCTCNT(A1)†Save�it�away.‰MOVE.LƒD4,IOSECTOR(A1) 3‰CMP.B„D0,D0�Set��since�we�support�the�command.4‰MOVEM.L‚(A7)+,D2/D4ŠRestore�registers�that�we�used.‰RTS‰PAGEN******************************************************************************* *ˆSET_CODE*F*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installed�atE*ˆthe�beginning�of�the�driver.‚The�function�of�this�routine�is�to�setD*ˆany�media‚and/or‚drive�related�codes�in�the�drive's�variable�blockC*ˆ(device-dependent�portion)‚required�by‚the�particular‚controller.>*ˆIt�is�called�by�configure,�read,�write,�and�format�commands.**A*ˆEntry:„A1�=�pointer�to�Drive's�Variable�Block�in�global�memory.#*’A5�=�physical�address�of�the�CCB.* *’Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D‚*�*…**™A„P‡P* *ˆCalls:�none**ˆExit:‚RTS�to�caller.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon� entry.*N****************************************************************************** SET_CODE: 2‰MOVEM.L‚D0/D1/D4,-(A7)‡Save�any�registers�we�use. -‰MOVEQ„#0,D4�Use�D4�to�hold�the�control�code.6EQ652„EQU†CONFGBLK+IOSATW†Read�option�field�in�IOSATW.‰MOVE.WƒEQ652(A1),D0‰Get�it. ‰BTST…#IOATDEN,D0ŠTrack�density?'‰BEQ.S„STAG10�Leave�as�zero�for�single.&‰BSET…#CTD,D4ŽSet�that�bit�for�double. $STAG10ƒBTST…#IOAFRMT,D0ŠFormat�type?)‰BNE.S„STAG20�Leave�as�zero�for�IBM-type.-‰BSET…#CSN,D4ŽSet�that�bit�for�Motorola�type. *STAG20ƒBTST…#IOADDEN,D0ŠRecording�density?,‰BEQ.S„STAG30�Leave�as�zero�for�single�(FM).,‰BSET…#CMF,D4ŽSet�that�bit�for�double�(MFM). STAG30ƒBTST…#IOADSIDE,D0‰Sides?'‰BEQ.S„STAG35�Leave�as�zero�for�single.&‰BSET…#CDS,D4ŽSet�that�bit�for�double.‰PAGESTAG35ƒEQU†*”Label�for�branch.4STAG40ƒEQU†CONFGBLK+IOSPSM†Read�current�record�size.‰MOVE.WƒSTAG40(A1),D0ˆGet�it.$‰MOVEQ„#0,D1�Clear�working�register.3STAG45ƒSUB.W„#128,D0ŽSubtract�out�min.�record�size.-‰BEQ.S„STAG50�Size�found�when�D0�equals�zero.‰ADD.B„#1,D1�Increment�counter.‰BRA†STAG45�And�try�again.-STAG50ƒLSL.B„#3,D1�Position�sector�size�code.‰OR.B…D1,D4�Set�those�bits. &‰BCLR…#CDM,D4ŽClear�no-DMA�bit�always.+‰BSET…#CIE,D4ŽSet�command�interrupt�enable. 0‰MOVE.BƒD4,CTRLCODE(A1)†Set�up�the�control�code. 7‰MOVEM.L‚(A7)+,D0/D1/D4‡Restore�registers�that�we�used.‰RTS‰PAGEN********************************************************************************ˆCHK_FLOPPY�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�toF*ˆcheck�that�the�bytes�per�sector,‚sectors�per�track,�and�data-densityG*ˆdensity�values�are�consistent�with�each�other.�This�routine�is�called?*ˆafter�the‚user's‚configuration‚block‚has‚been‚filled‚with‚theG*ˆproposed�configuration.�Therefore,�A0�points�to�the�end�of�the�user's*ˆconfiguration�block.*0*ˆEntry:�A0�=�end�of�user's�configuration�block.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7 *™D†*�*�*ƒ*�**™A‚Pƒ** *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:-*��no�errors�in�this�configuration�check.*��an�error�was�found.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N*******************************************************************************/*‚Tables�used�to�check�the�floppy�configurationJ*‚The�RWIN�and�SASI�controllers�agree�on�their�values�for�128�byte�sectorsN*‚and�256�byte�sector.�However�there�is�a�difference�on�the�1024�byte�sectors,E*‚and�a�difference�in�what�is�supported�by�the�different�controllers.J*‚For�now,�with�only�128�or�256�bytes�sectors,�there�is�no�difference,�and*‚we�can�use�the�same�tables.**$*ƒBYTES�PER�SECTOR�--�SINGLE�DENSITY*-BPS_S„DC.W†128Š128�bytes,�single�data�density,‰DC.W†0Œwe�do�not�support�256�single�density,‰DC.W†0Œwe�do�not�support�512�single�density-‰DC.W†0Œwe�do�not�support�1024�single�density*$*ƒBYTES�PER�SECTOR�--�DOUBLE�DENSITY*5BPS_D„DC.W†0ŒRWIN�does�not�support�128�double�density(‰DC.W†256Š256�bytes,�double�data�density,‰DC.W†0Œwe�do�not�support�512�double�density-‰DC.W†0Œwe�do�not�support�1024�double�density‰PAGEƒTHEN.SŒIf�double�density,�move�pntr�to*ŽADDQ.Lƒ#BPS_DENS,A2„double�density�table.‰ENDI***6‰MOVE.W„IOSPSM-IOSDRSV(A0),D6‰D6�<---�bytes�per�sector 0‰MOVE.W�#C_TBL_SZ-1,D7�Search�for�match�in�bytes)BPS_LOOP�CMP.Wƒ(A2)+,D6’per�sector�table.‰DBEQ„D7,BPS_LOOP.‰BNE.SƒRET“If�no�match,�return�with�CCR�=�*'*‚We�are�here�because�we�found�a�match.* BPS_FOUND4‰LEA‡SPT5_S(PC),A2‡A2�<---‚pntr�to�sector�per�track,#*¦5",�single�density�table.(SPT5_S)1‰BTSTW…#IOADDEN,D4‰If�double�density,�point�A2�to-‰IFƒƒTHEN.SŒsectors�per�track,�5",�double,ŽADDQ.Lƒ#SPT_DDEN,A2„density�table.�(SPT5_D)‰ENDI.‰BTSTW…#IOASIZE,D4‰If�8"�diskette,�point�A2�to0‰IFƒƒTHEN.SŒthe�sectors�per�track,�8"�table,4ŽADDQ.Lƒ#SPT_SIZE,A2„either�single�or�double�density*‰ENDIšas�fixed�up�above.(SPT8_D�or�SPT8_S)*D*ƒNow�that�A2�is�pointing�to�the�proper�table�for�sectors�per�track,G*ƒset�up�D4�to�point�to�the�byte�offset�of�our�entry�from�the�beginning=*ƒof�the�proper�table,�and�let's�check�the�sectors�per�track.*‰MOVE.W„#C_TBL_SZ-1,D3 ‰SUB.W…D7,D37‰MOVE.B„IOSSPT-IOSDRSV(A0),D2‰D2�<---�sectors�per�track‰CMP.B…0(A2,D3.W),D2ARET†MOVEM.Lƒ(A7)+,D2/D3/D4/D6/D7/A2ƒReturn�with�CCR=�if�match‰RTS›found�and��otherwise.‰PAGEN******************************************************************************* *ˆCHK_LSN*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*ˆcheck�that‚the�requested�starting�logical‚sector�number�(in�D2.L)E*ˆis�less�than�or�same�as�the�largest�logical�sector�number�supported$*ˆby�the�particular�disk�controller.**-*ˆEntry:�D2�=�starting�logical�sector�number.* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D†P*™A* *ˆCalls:�none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*��=�starting�logical�sector�number�is�invalid.1*��=�starting�logical�sector�number�is�valid.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** CHK_LSN: :‰CMP.L„#LSNMASK+1,D2ŠSince�the�first�logical�sector�on�the)*¦disk�is�logical�sector�zero,�the�number(*¦of�the�last�logical�sector�on�the�disk&*¦is�D2-1.‚If�this�number�is�too�large)*¦to�fit�under�the�LSN�mask,�something�is'*¦wrong.‚We�can't�have�a�logical�sector(*¦number�that�is�larger�than�the�largest(*¦sector�number�that�the�RWIN�controller *¦supports.‰RTS‰PAGEN******************************************************************************* *ˆBLD_PACKET*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*ˆbuild�any� or�all‚parts�of�the�command�packet�that�can�be�built�at=*ˆinterrupt‚level�0‚which‚will�be‚used‚by�the‚particular‚disk,*ˆcontroller�to�process�the�current�command.*A*ˆEntry:„A1�=�pointer�to�Drive's�Variable�Block�in�global�memory.#*’A5�=�physical�address�of�the�CCB.* *’Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D*™A„P‡P* *ˆCalls:„none*/*ˆExit:‚RTS�to�caller�with�condition�codes�set:3*�‚No�errors�were�found�in�building�the�packet.4*�‚An�error�was�detected�in�building�the�packet.4*•D1.B�=�VERSAdos�error�code�for�the�error�detected.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N****************************************************************************** *F*‚This�function�is�not�required�by�the�RWIN�driver.‚The�command�packet8*‚is�built�with�the�interrupts�masked�in�the�co-routine.* BLD_PACKET: ‰CMP.B…D0,D0‰RTS‰PAGEN******************************************************************************* *ˆDISK_START*C*ˆThis�is�a�device�dependent�routine�whose�offset�must�be�installedE*ˆat�the�beginning�of�the�driver.�The�function�of�this�routine�is�to:*.*Š1.‚Set�up�the�device-dependent�fields�in�the*Ždrive's�variable�block.-*Š2.‚Set�up�for�command�queueing�if�required./*Š3.‚If�the�drive�is�not�busy,�tell�the�command*Žto�the�controller.**D*ˆEntry:�A1�=�address�of�the�drives�variable�block�in�global�memory.#*�A5�=�physical�address�of�the�CCB.*=*�Interrupt�level�on�entry�is�at�our�hardware�level�(masked).*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™D‚* *™A‚*�P‡P**ˆCalls:�RWININT**ˆExit:‚RTS�to�caller.*N******************************************************************************  DISK_START: ‰PUSH…SR/‰MOVEM.L‚D0/A0,-(A7)ŠSave�any�registers�we�use. 6‰LEA†IOQCNT(A5),A0ŠPut�the�pointer�to�the�drive's�area1‰MOVE.Wƒ(A0),D0Žof�memory�into�the�next�available;EQ670„EQU†IOQUEUE-IOQCNT‡queue�entry,�and�advance�the�queue=‰MOVE.LƒA1,EQ670(A0,D0.W)„pointer.‚We�don't�need�to�check�for2‰ADD.W„#4,(A0)Žqueue�overflow�because�we�can�never&*¦accumulate�more�than�one�queue�entry'*¦for�each�drive.‚We�also�don't�need�to(*¦check�for�queue�wrap-around�because�we'*¦physically�move�queue�entries�instead&*¦of�using�wrap-around�queue�pointers. -‰TST.W„D0•If�the�queue�wasn't�empty�before�we1‰BNE.S„L0410�made�the�latest�entry,�the�interrupt$*¦handler�is�already�active�and�will)*¦eventually�complete�the�I/O�transaction'*¦that�we've�just�specified.‚Otherwise,#*¦we�need�to�activate�the�interrupt *¦handler.‰PAGE8‰LEA†PROCQUE(PC),A0‰Set�up�the�co-routine�switch�pointer@‰MOVE.LƒA0,INTSWTCH(A5)†to�start�processing�new�I/O�queue�entry.:‰MOVE.LƒCCBCHB(A5),A0ˆA0�<--�RWIN�memory-mapped�I/O�space. ,‰BSR†RWININTŽTell�command�to�the�controller.*C*ƒNow�we�have�started�off�the�I/O�and�are�ready�to�return�to�CMR�to(*ƒbe�awakened�when�an�interrupt�arrives.* 9L0410„MOVEM.L‚(A7)+,D0/A0ŠRestore�registers�that�we�used.‰POP‡SR‰RTS‰SPC‡2‰PAGEN********************************************************************************ˆCHK_PARAM�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*ˆvalidate‚any‚device‚dependent‚parameters.‚This�routine�is�called?*ˆafter�the‚user's‚configuration‚block‚has‚been‚filled‚with‚theG*ˆproposed�configuration.�Therefore,�A0�points�to�the�end�of�the�user's*ˆconfiguration�block.*/*ˆEntry:�A0�=�end�of�user's�configuration�block* *�Interrupt�level�on�entry�is�0.*!*ˆRegister�usage:…0�1�2�3�4�5�6�7*™DˆR*™A‚P* *ˆCalls:�none*$*ˆExit:‚RTS�back�to�calling�routine.>*�CONDITION�CODES:��no�errors�in�this�configuration�check.* �an�error�was�found./*�D3.B�=�Returned�error�code�if�error�is�found.*F*ˆThe�interrupt�level�upon�exit�must�be�the�same�as�it�was�upon�entry.*N******************************** ********************************************** CHK_PARAM: ‰CMP.B…D0,D0�Set�condition�codes ‰RTS›Return.N******************************************************************************* *‰END�ROUTINES�CALLED�BY�DISKLIB*N******************************************************************************ŠPAGEN********************************************************************************‰FINISH�OFF�THE�INITIALIZATION*2*‰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.**‰1.‚Read�status�of�self-test.*‰2.‚Test�of�FIFO.**‰Entry:�A5�=�address�of�CCB.**‰Registers�may�be�used�freely.* *‰Calls:�none*N****************************************************************************** DO_INIT: *(*‚Read�status�of�self�test�and�test�FIFO*8‰MOVE.LƒCCBCHB(A5),A0ˆA0�<=�channel's�memory�mapped�I/O.;‰BTST…#BITCB,FLAGS(A0)…Test�the�read�register�for�not�busy.5‰BEQ.S„FIPASS�Don't�reset�or�test�buffer�if�not�busy.,‰MOVE.Bƒ#0,RWINRST(A0)‡Reset�the�controller.CWINI10ƒBTST…#BITCB,FLAGS(A0)…Poll�the�read�register�for�not�busy...,‰BNE†WINI10�...to�indicate�end�of�self-test.1‰BTST…#BITFAULT,FLAGS(A0)‚Test�the�pass/fail�bit.!‰BEQ.S„WINI20�Continue�if�passed..‰SNE.B„CHANDOWN(A5)‰Set�the�channel�down�flag.‰RTS›Return�to�CMR. !WINI20ƒMOVE.W„#4095,D1Œ4K�buffer.AFIWRITE‚MOVE.B„D1,DATA0(A0)ˆMove�data�byte�by�byte�to�the�buffer.‰DBRA†D1,FIWRITEŠ*‰MOVE.W„#4095,D1ŒRestart.BFIREADƒCMP.B…DATA0(A0),D1ˆCompare�data�byte�by�byte�in�the�buffer.&‰BNE.S…FIERROR�Branch�upon�error�only.‰DBRA†D1,FIREAD‹*‰BRA.S…FIPASSŽDone�if�passed.5FIERROR‚SNE.B…CHANDOWN(A5)ˆSet�the�channel�down�flag.FIPASSƒRTS›Return�to�CMR *********************** *‚PATCH�SPACE***********************ŠDS.Wƒ30ŠENDNNNNNNN?SCCDRV„IDNTƒ45,0…VERSAdos�Z8530�terminal�driver�with�type-ahead;ŠTTL„SCCDRV:‚VERSAdos�Z8530�terminal�driver�with�type-ahead ŠLLENƒ120J**************************************************************************J**************************************  ************************************J**************************************************************************J***************************************************************************9*‰SCCDRV:‚VERSAdos�Z8530�terminal�driver�with�type-ahead.*8*‰Purpose:‚VERSAdos�device�driver�to�handle�asynchronous0*“terminals�(of�any�type)�over�the�Z8530�chip�on *“the�MVME117�or�MVME133�boards.**‰Revision�history:*>*�02/26/86‚Modified�to�work�with�the�VME117's�and�the�VME133's2*šthat�bring�RTS,�pin�4�at�the�RS232�connector�(to3*šterminal),�to�CTS�at�the�chip.‚No�longer�supports*šthe�old�method.*2*�01/29/86‚Changed�to�work�with�the�VME133�by�BAW.*7*�12/10/85‚Install�NEW�Killer�modification�which�leaves,*šThe�Driver�ID�(Number)�and�Reason�(Number)2*šin�CRASHSAV�along�with�the�CCB�and�DCB�pointers.*'*�03/15/85‚Initial�release�by�Mike�Duh.*J**************************************************************************J**************************************************************************NN÷IY#D F(E0@88@6H:P<X:`=hAp@xJ€:ˆ �9˜@ ;¨°<¸ À:È@Ð@Ø&J**************************************************************************J**************************************************************************‰PAGE**‚XREF's�from�TERMLIB* ‰XREF†LOG_ERR‰XREF†MARK_DOWN ‰XREF†RESET‰XREF†TERM_BREAK‰XREF†TERM_COMMAND‰XREF†TERM_GOT_CHAR‰XREF†TERM_INIT‰XREF†TERM_TBE***†XREF†TERM_UNRDYŠNot�used. **‚Equate�files�included:* *‰STR.EQ*‰TCB.EQ*‰CCB.EQ*‰IOE.EQ*‰NIO.EQ*‰LV5.EQ1*‰BAB.EQ�Background�Activation�Block�description.:*‰TERMCCB.EQ‰Offsets�and�equates�for�CCBDDP�for�terminals.$*‰TERMINAL.EQˆEquates�for�terminals.*‰UTILITY.MC‰Macros. *‰KILL.MC *‰KILLDRV.EQ*ŠPAGE**‚MACRO'S�used:* *N*‚OUT_SCC�-�Output�a�byte�from�a�data�register�to�a�register�on�the�Z8530�SCC.C*ŒIt�is�required�to�write�the�desired�SCC�register�address�to�Write<*ŒRegister�0�on�the�Z8530�first,�then�write�the�data�to�WR0.5*ŒFormat:‚[