                Page    60,132
                Title   All-Pro Hardware Dependent Routines
                Subttl  Software Notes, Documentation and History
                Page
;                                  AllPro
;                          All-pro Hardware Interface

;       Module ...................... ALLPRO
;       Title ....................... All-pro Hardware Interface
;       Developing Engineer ......... George Gruber
;       Company ..................... Logical Devices
;       Revision Level .............. v1.10
;       Date of Last Revision ....... 3-Mar-86
;       Last Revision by ............ GDG

;       These routines are very dependent upon hardware and construction of C.
;       Please take note when making any changes!.

                Include Lmacros.h

                Include Allpro.equ

                Subttl  Unitialized Data Area and Externals
                Page
                Assume  DS:dataseg

dataseg         Segment

                Global  udi_memory_map_:byte,1024        ;udi internal memory map
                Global  analog_id_:byte,1                ;analog control id code

                Extrn   pin_driver_table_:byte

                Extrn   at_286_flag_:byte

slew_up_count   Dw      ?                       ;slew rate up/down timer count
program_count   Dw      ?                       ;program timer count

dataseg         Ends

                Subttl  Unlock Udi Interface
                Page
;       Unlock universal interface activates an interface board.

;Enter:         Nothing
;
;Call:          pump ()
;
;Return:        universal interface activated.

        procdef pump

                Mov     DX,UdiMemMapPort
                Mov     AL,high UdiSegment
                Out     DX,AL                   ;select udi interface segment
                Mov     DX,UdiLockPort0
                Mov     AL,0
                Out     DX,AL                   ;make sure udi is locked out
                Mov     DX,UdiLockPort0
                Mov     AL,0AAH
                Out     DX,AL                   ;now unlock udi
                Mov     DX,UdiLockPort1
                Mov     AL,055H
                Out     DX,AL

                pret                            ;...done

        pend    pump

                Subttl  Lock out Udi Interface
                Page
;       Lock universal interface de-activates an interface board.

;Enter:         Nothing
;
;Call:          unpump ()
;
;Return:        universal interface de-activated.

        procdef unpump

                Mov     DX,UdiLockPort0
                Mov     AL,0A5H
                Out     DX,AL                   ;lock out udi from cpu

                pret                            ;...done

        pend    unpump

                Subttl  Write Data to Memory on UDI
                Page
;       Write universal interface data byte.  This is provided primarily for
;       the diagnostics so that the DACs could be written without any adjust-
;       ments being performed on the data.

;Enter:         mem_address             = device address to write
;               mem_data                = data to write to device
;
;Call:          write_udi_mem (mem_address, mem_data)
;
;Return:        the data written to the specified device address.

        procdef udi_write_mem, <<mem_address, word>, <mem_data, byte>>

                Mov     AL,mem_data             ;get voltage to write to DAC
                Mov     BX,mem_address          ;get the device address

                Push    ES                      ;write data to device address

                Mov     DX,UdiSegment
                Mov     ES,DX
                Mov     byte ptr ES:[BX],AL

                Pop     ES

                pret                            ;...done

        pend    udi_write_mem

                Subttl  Write Data to DAC on UDI
                Page
;       Write universal device DAC (voltage) register.  Converts voltage
;       (specified in .01 volt increments) to .001 volt increments and divides
;       that down by VoltageIncremnt to yield an 8 bit value to write to device
;       address.

;       DAC compensations are as follows:
;               Supply1Dac                      4.1 + .2 volts
;               Supply2Dac                      4.1 + .2  volts
;               HpControlDac                    1.4 + .2  volts
;               MpControlDac                    2.1 + .2  volts
;               LpControlDac                    2.1 + .2  volts
;               PuControlDac                    0  + .2 volts
;               SlewRateDac                     0
;               ThreshHoldDac                   0

;       If the voltage specified is zero, no adjusting is done.

;Enter:         dac_address             = device address to write
;               device_voltage          = data to write to device

;Call:          write_udi_dac (dac_address, device_voltage)

;Return:        the voltage written to the specified DAC.

        procdef udi_write_dac, <<dac_address, word>, <device_voltage, word>>

                Mov     AX,device_voltage       ;get voltage to write to DAC
                Mov     BX,dac_address          ;get the device address
                Mov     DX,0

                Cmp     BX,SlewRateDac          ;is device slew rate dac?
                Je      WriteDacVolts           ;...yes, just set value to device

                Mov     BX,10                   ;convert .01 volt increments to .001
                Mul     BX
                Mov     BX,VoltageIncremnt      ;convert .001 volt increments to range 0 - 255
                Div     BX
                Mov     BX,dac_address          ;get the device address

                Cmp     AX,0                    ;zero volts?
                Je      WriteDacVolts           ;...yes, don't adjust at 0

                Cmp     BX,ThreshHoldDac        ;is device threshold dac?
                Je      WriteDacVolts           ;...yes, just set value to device

                Mov     DX,41
                Cmp     BX,Supply1Dac
                Je      AdjPowerVoltag

                Cmp     BX,Supply2Dac
                Je      AdjPowerVoltag

                Mov     DX,14

                Cmp     BX,HpControlDac
                Je      AdjPowerVoltag

                Mov     DX,20

                Cmp     BX,PuControlDac
                Je      AdjPowerVoltag

                Mov     DX,21

AdjPowerVoltag: Add     AX,DX                   ;add in power offset
                Add     AX,2                    ;include initial diode drop

WriteDacVolts:  Push    ES                      ;write data to device address

                Cmp     analog_id_,1            ;see if .1 or .125 volt increments
                Jne     WriteDacCont

                Mov     CX,80                   ;factor down to 80% level
                Mul     CX
                Mov     CX,100
                Div     CX

WriteDacCont:   Mov     DX,UdiSegment
                Mov     ES,DX
                Cmp     AH,0                    ;see if dac count exceeded 255
                Je      WriteDacCont1

                Mov     AL,255

WriteDacCont1:  Mov     byte ptr ES:[BX],AL
                Mov     udi_memory_map_[BX],AL

                Pop     ES

                pret                            ;...done

        pend    udi_write_dac

                Subttl  Write Bit State on UDI
                Page
;       Write universal device bit.  Changes the bit(s) specified to a speci-
;       fied state on the AnalogControl register.

;Enter:         bit_address             = bits to change in register
;               bit_state               = state bit(s) are to change to

;Call:          write_udi_bit (bit_address, bit_state)

;Return:        the data written to the specified device address.

        procdef udi_write_bit, <<bit_address, byte>, <bit_state, byte>>

                Mov     AH,bit_address          ;get device address and mask
                Mov     BX,AnalogControl        ;analog control register address
                Mov     AL,udi_memory_map_[BX]  ;get last value written
                Or      AL,AH                   ;set bit
                Cmp     bit_state,0             ;is the bit to be a zero?
                Jne     UpdateUdiBit            ;...no, write new data to map and udi

                Not     AH                      ;make bit mask
                And     AL,AH                   ;leave all bits but selected one

UpdateUdiBit:   Mov     udi_memory_map_[BX],AL  ;write new data to memory map table

                Push    ES                      ;write data to device address

                Mov     DX,UdiSegment
                Mov     ES,DX

                Mov     byte ptr ES:[BX],AL

                Pop     ES

                pret                            ;...done

        pend    udi_write_bit

                Subttl  Write Bit State on UDI Pin
                Page
;       Write universal device pin driver.  Changes the drivers for a speci-
;       fied pin changing only the drivers needed to be changed.  The argument
;       pin contains both the drivers to turn on (in upper 8 bits) and the pin
;       to be affected (lower 8 bits).

;       Exception processing occurs as follows:
;               If CutOverFlag is set and the LpDriverOn is already set,
;               nothing is changed.  If the same drivers are to be turned on
;               are already on, then nothing is changed.

;Enter:         pin                     = pin to affect
;               bit_state               = state of bit to write

;Call:          udi_write_pin (pin | bit_state)

;Return:        the drivers turn on for the specified pin.

        procdef udi_write_pin, <<pin, word>>

                Mov     AX,pin                  ;get pin number and pin drivers
                Mov     DH,AH                   ;save new state of pin drivers
                Xor     AH,AH

                Shl     AX,1                    ;...no, write to pin
                Shl     AX,1
                Mov     BX,AX
                Mov     AX,pin_driver_table_.PinDriverFlags[BX] ;check if any pins to change
                Test    DX,mask CutOverFlag                     ;cut over?
                Jz      same_drivr_chk                          ;...no, check if same drivers

                Test    AX,mask LpDriverOn                      ;low power driver already on?
                Jnz     write_pin_exit                          ;...yes, done

same_drivr_chk: Xor     AX,DX
                Jz      write_pin_exit                          ;...no, done

                Push    ES

                Mov     AX,UdiSegment
                Mov     ES,AX

                Mov     pin_driver_table_.PinDriverFlags[BX],DX ;set pin driver states
                Mov     BX,pin_driver_table_.PinBaseAddress[BX] ;get base address for pin
                Mov     udi_memory_map_[BX],DH                  ;write data to memory table
                Mov     byte ptr ES:[BX],DH     ;write data to device address

                Pop     ES

write_pin_exit: pret                            ;...done

        pend    udi_write_pin


                Subttl  Identify Board
                Page
;       This routine will read the analog board to determine the board
;       revision. The variable 'analog_id_' will be updated.

;Enter:         Nothing
;
;Call:          identify_board ()
;
;Return:        analog_id_ variable updated.

        procdef identify_board

                Push    ES                      ;read analog control id code

                Mov     BX,Supply1Dac

                Mov     DX,UdiSegment
                Mov     ES,DX
                Mov     AL,byte ptr ES:[BX]
                And     AL,0FH                  ;retain lower four bits
                Mov     analog_id_,AL

                Pop     ES

                pret                            ;...done

        pend    identify_board

                Subttl  Clock a Pin
                Page
;       Clocks a specified pin with respect to a specified logic level (i.e.
;       either it is a high true clock or a low true clock).  This assumes
;       that the pin has been initialized to an idle state with either the
;       ground driver or the pullup driver on for this pin.

;Enter:         clock_pin               = pin to clock
;               clock_logic             = logic level of clock
;                                               = 0 -> is low true clock
;                                               = 1 -> is high true clock

;Call:          udi_clock_pin (clock_pin, clock_logic)

;Return:        nothing

        procdef udi_clock_pin, <<clock_pin, word>, <clock_logic, word>>

                Mov     BX,clock_pin            ;get pin number
                Shl     BX,1
                Shl     BX,1
                Mov     BX,pin_driver_table_.PinBaseAddress[BX] ;get the base address for the pin

                Push    ES                      ;write data to device address

                Mov     AX,UdiSegment
                Mov     ES,AX

                Cmp     clock_logic,0           ;is it low true clock?
                Je      LowTrueClock            ;...yes, handle low true clock

                Mov     AH,udi_memory_map_[BX]  ;save starting state
                Mov     AL,high (mask PuDriverOn)
                Mov     ES:[BX],AL              ;turn pullup driver on
                Nop
                Nop
                Mov     ES:[BX],AH              ;turn pullup driver back off
                Jmp     short ClockDone         ;...done

LowTrueClock:   Mov     AH,udi_memory_map_[BX]  ;save starting state
                Mov     AL,high (mask GdDriverOn)
                Mov     ES:[BX],AL              ;turn pullup driver on
                Nop
                Nop
                Mov     ES:[BX],AH              ;turn pullup driver back off

ClockDone:      Pop     ES

                pret                            ;...done

        pend    udi_clock_pin

                Subttl  Read Bit State from UDI
                Page
;       Reads the state of a specified pin.  This does a lookup through
;       pin_driver_table to get the address of the pin driver then the pin
;       number is used to form the AND mask.  The data is read for the pin
;       and then ANDed with the mask and AX is either 0 if the data was zero
;       or not zero if the data was one.

;       Note:   *** This uses an absolute offset from pin_driver_table      ***
;               *** Make sure that this is changed if the table is changed! ***

;Enter:         read_pin                = pin to read

;Call:          udi_read_bit (read_pin)

;Return:        state of the bit        = (either zero if clear or non-zero
;                                       if the bit was on)

        procdef udi_read_bit, <<read_pin, word>>

                Mov     BX,read_pin             ;get pin number
                Shl     BX,1
                Shl     BX,1
                Mov     BX,pin_driver_table_.PinBaseAddress[BX]
                Mov     CX,read_pin
                Mov     AH,01H
                Cmp     CX,25
                Jb      SetupMaskShift

                Mov     AH,10H

SetupMaskShift: Dec     CX
                And     CX,3
                Shl     AH,CL

                Push    ES                      ;read device data byte

                Mov     DX,UdiSegment
                Mov     ES,DX
                Mov     AL,byte ptr ES:[BX]

                Pop     ES

                And     AL,AH                   ;return AX = 0 if bit cleared, AX <> 0 if bit set
                Mov     AH,0

                pret                            ;...done

        pend    udi_read_bit

                Subttl  Program Fuse
                Page
;       Program Fuse.  Ramps up pin hi-power power supply and then ramps up
;       med-power power supply, holds med-power power supply for burn_time uS
;       and holds hi-power power supply for burn_time + (2 * slew_delay) uS.

;Enter:         hi-power power supply pin(s) enabled
;               med-power power supply pin(s) enabled
;               slew rate DAC set to proper slew rate
;               hi_power_volts          = voltage to slew hi-power power supply
;               med_power_volts         = voltage to slew med-power power supply
;               burn_time               = uS to hold pins at voltages
;               slew_delay              = uS to delay for voltage slew

;Call:          udi_burn_bit (hi_power_volts, med_power_volts, burn_time, slew_delay)

;Return:        nothing

        procdef udi_burn_bit, <<hi_power_volts, word>, <med_power_volts, word>, <burn_time, word>, <slew_delay, word>>

                Mov     AX,burn_time
                Sub     AX,10                   ;remove 10 uS from count
                Cwd
                Mov     BX,12
                Mul     BX
                Mov     BX,10
                Div     BX
                Mov     [program_count],AX

                Push    ES                      ;save ES

                Mov     DX,UdiSegment           ;point to udi i/o page segment
                Mov     ES,DX

                Cli                             ;disable interupts

                Mov     AX,med_power_volts      ;get voltage for med-power switch
                Mov     DX,0
                Mov     BX,10                   ;convert .01 volt increments to .001
                Mul     BX
                Mov     BL,VoltageIncremnt      ;convert .001 volt increments to range 0 - 255
                Div     BL
                Add     AX,23                   ;compensate the voltage

                Push    AX

                Mov     AX,hi_power_volts       ;get voltage for hi-power switch
                Mov     DX,0
                Mov     BX,10                   ;convert .01 volt increments to .001
                Mul     BX
                Mov     BL,VoltageIncremnt      ;convert .001 volt increments to range 0 - 255
                Div     BL
                Add     AX,16                   ;compensate the voltage

                Pop     DX                      ;restore medium

                Mov     BX,HpControlDac         ;address of hi-power switch DAC
                Mov     ES:[BX],AL              ;allow hi-power to slew up

                Nop
                Nop

BurnMedUp:      Mov     BX,MpControlDac         ;[2] address of med-power switch DAC
                Mov     ES:[BX],DL              ;[3] allow med-power to slew up

                Mov     CX,[program_count]

                Call    timer_delay

                Mov     AL,udi_memory_map_[BX]  ;[5] reset med-power switch to original voltage
                Mov     ES:[BX],AL              ;[3]
                                                ;[36] 6 uS minimum med-power total

                Nop
                Nop

BurnMedDown:    Mov     BX,HpControlDac         ;[2] reset hi-power switch to original voltage
                Mov     AL,udi_memory_map_[BX]  ;[5]
                Mov     ES:[BX],AL              ;[3]
                                                ;[78] 13 us mimimum high-power total

                Mov     CX,slew_delay           ;[3] uS to delay
                Sub     CX,2                    ;[3] precompensate number of uS

                Sti                             ;re-enable interupts

                Pop     ES                      ;restore ES

                pret                            ;...done

        pend    udi_burn_bit

                Subttl  Delay n mS
                Page

;       Delay n mS.  Will delay a minimum of n milli-seconds.  This does not
;       shut down any interupts to leave the system running properly.

;Enter:         delay_ms_time           = delay time in mS

;Call:          delay_ms (delay_ms_time)

;Return:        nothing                 = (time elapse minimum of n mS)

        procdef delay_ms, <<delay_ms_time, word>>

                Mov     AX,delay_ms_time        ;get number of mS to delay
                Cwd
                Mov     BX,1200
                Mul     BX
                Mov     CX,AX
                Inc     DX
                Mov     CX,AX

DelayMsLoop:    Call    timer_delay             ;delay timer 2 ticks

                Mov     CX,-1                   ;use full count from now on
                Dec     DX                      ;update mS to delay
                Jnz     DelayMsLoop             ;...delay another mS

                pret                            ;...done

        pend    delay_ms

                Subttl  Delay n uS
                Page
;       Delay n mS.  Will delay a minimum of n micro-seconds.  This does not
;       shut down any interupts to leave the system running properly.

;Enter:         delay_us_time           = delay time in uS

;Call:          delay_us (delay_us_time)

;Return:        nothing                 = (time elapse minimum of n uS)

        procdef delay_us, <<delay_us_time, word>>

                Mov     AX,delay_us_time        ;get number of uS to delay
                Cwd
                Mov     BX,12
                Mul     BX
                Mov     BX,10
                Div     BX
                Mov     CX,AX
                Inc     DX
                Mov     CX,AX

                Call    timer_delay             ;... delay timer 2 ticks

                pret                            ;...done

        pend    delay_us

                Subttl  Delay Thru Timer
                Page
;       Timer Delay.  Delays approximately CX timer 2 counts.  Pass the timer
;       2 ticks (derived by take uS * 12 and devide by 10) in CX.  If there is
;       less than 40 clocks (34 uS) for a PC type computer, no setup and wait
;       is done (provides approximately 28 uS).

;Enter:         CX                      = timer ticks to delay

;Call:          Mov     CX,(us * 12) / 10
;               Call    timer_delay

;Return:        nothing                 = (time elapse minimum of n uS)

                internal timer_delay

                Cmp     [at_286_flag_],0        ;is it AT type computer?
                Jne     AtTimerDelay            ;...yes, do AT timer delay

                Cmp     CX,40                   ;less than 34 uS?
                Jb      PcTimerDone             ;...yes, yeilds about 28 uS

                In      AL,PPI8255PortB         ;enable timer 2 gate
                Or      AL,001H
                Out     PPI8255PortB,AL
                Mov     AL,0B0H                 ;set timer 2 to mode 0 (int on term count)
                Out     CTC8253Command,AL
                Mov     AL,CL                   ;set counter 2 to count
                Out     CTC8253Timer2,AL
                Mov     AL,CH
                Out     CTC8253Timer2,AL
                Mov     CH,020H                 ;set test mask into a register

Timer8253Wait:  In      AL,PPI8255PortC         ;read 8255 port C
                Test    AL,CH                   ;timer 2 interupt set?
                Jz      Timer8253Wait           ;...no, continue to wait

PcTimerDone:    Ret                             ;...done

AtTimerDelay:   In      AL,PPI8255PortB
                Or      AL,1
                Out     PPI8255PortB,AL
                Mov     AL,0B0H                 ;set timer 2 to mode 0 (int on term count)
                Out     CTC8253Command,AL
                Mov     AL,CL                   ;set counter 2 to count
                Out     CTC8253Timer2,AL
                Mov     AL,CH
                Out     CTC8253Timer2,AL
                Mov     CL,0E8H                 ;read status command
                Mov     CH,080H                 ;set test mask into a register

Timer8254Wait:  Mov     AL,CL                   ;issue read status command
                Out     CTC8253Command,AL
                Nop
                In      AL,CTC8253Timer2        ;read the status back
                Test    AL,CH                   ;timer 2 interupt set?
                Jz      Timer8254Wait           ;...no, continue to wait

                Ret                             ;...done

timer_delay     endp

                finish

                End
