home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / eep15.inc < prev    next >
Text File  |  1995-06-25  |  16KB  |  579 lines

  1. ;************************************************************************;
  2. ;*                                    *;
  3. ;*            EEP15.INC                    *;
  4. ;*                                    *;
  5. ;*  EEPROM configuration routines for the ATI AT-1500 Adapters.        *;
  6. ;*                                    *;
  7. ;*  Copyright (c) 1992, 1993, Allied Telesis, Inc.  All Rights Reserved.*;
  8. ;*                                    *;
  9. ;************************************************************************;
  10.  
  11.  
  12. DATASEG SEGMENT
  13.  
  14.  
  15.     ifdef    CODE386        ; 386 "flat" model (Novell 386 server driver)
  16. POINTER_REGISTER  equ    ESI
  17.     else            ; all other models
  18. POINTER_REGISTER  equ    SI
  19.     endif
  20.  
  21.     ifndef    @Version
  22. @Version equ    000
  23.     endif
  24.  
  25.  
  26. ; Bit definitions for the PCNetISA "Vendor Specific Word", which on the
  27. ; AT-1500 controls the on-board serial EEPROM (National Semiconductor NMC95C12).
  28. DATA_IN        equ    001h    ; EEPROM serial data in (DI) - write/only
  29. CLOCK        equ    002h    ; EEPROM serial clock (SK) - write/only
  30. DATA_OUT    equ    004h    ; EEPROM serial data out - read/only
  31. CHIP_SEL    equ    008h    ; EEPROM Chip Select - write/only
  32. JUMPER_STATE    equ    008h    ; Alternate Address Jumper state - read/only
  33.  
  34. ; EEPROM command codes.
  35. READ        equ    80h    ; Read EEPROM memory at specified address
  36. WEN        equ    30h    ; Write Enable
  37. WRITE        equ    40h    ; Write EEPROM memory at specified address
  38. WRALL        equ    10h    ; Write to all EEPROM locations
  39. WDS        equ    00h    ; Write Disable
  40.  
  41. SB        equ    01h    ; "Start Bit" (command follows)
  42. ADDR_MASK    equ    3Fh    ; EEPROM memory address mask
  43.  
  44. ; EEPROM locations used for AT-1500 configuration data (all are word addresses):
  45. BOARD_TYPE_LOC        equ    0    ; ASCII product name:  12 bytes
  46. BOARD_REV_LOC        equ    6    ; board rev. level:  low-order byte
  47. BOARD_SUBTYPE_LOC    equ    6    ; board subtype code:  high-order byte
  48. FLAG_WORD_LOC        equ    32    ; Flag bits - see below
  49. SCR_SAVE_ADDR        equ    61    ; SCR (below) power-up value save loc.
  50. SCR_ADDR        equ    62    ; "Switch Configuration Register"
  51. SRR_ADDR        equ    63    ; "Switch Readback Register"
  52.  
  53. ; Configuration values for the SCR and the SCR_SAVE (word locations 61 & 62):
  54. IRQ_MASK    equ    0003h        ; bits  0-3  (switch 1): IRQ: see below
  55. DMA_MASK    equ    0030h        ; bits  4-7  (switch 2): DMA: see below
  56. IO_BASE_MASK    equ    0300h        ; bits  8-11 (switch 3): IO: see below
  57. BOOT_EN_MASK    equ    1000h        ; bits 12-15 (switch 4): BOOT: see below
  58. MAU_SEL_MASK    equ    2000h        ; bits 12-15 (switch 4): PORT: see below
  59.  
  60. ; SCR Bits 0-3:  IRQ configuration:
  61. IRQ_CHOICE_A    equ    0000h
  62. IRQ_CHOICE_B    equ    0001h
  63. IRQ_CHOICE_C    equ    0002h
  64. IRQ_CHOICE_D    equ    0003h
  65. IRQ_3        equ    IRQ_CHOICE_A
  66. IRQ_4        equ    IRQ_CHOICE_B
  67. IRQ_5        equ    IRQ_CHOICE_C
  68. IRQ_9        equ    IRQ_CHOICE_D
  69. IRQ_10        equ    IRQ_CHOICE_A        ; AT-1500xx-20 only
  70. IRQ_11        equ    IRQ_CHOICE_B        ; AT-1500xx-00/20 only
  71. IRQ_14        equ    IRQ_CHOICE_C        ; AT-1500xx-20 only
  72. IRQ_15        equ    IRQ_CHOICE_D        ; AT-1500xx-00/20 only
  73.  
  74. ; SCR Bits 4-7:  DMA configuration:
  75. DMA_3        equ    0000h
  76. DMA_5        equ    0010h
  77. DMA_6        equ    0020h
  78. DMA_7        equ    0030h
  79.  
  80. ; SCR Bits 8-11:  IO BASE configuration:
  81. BASE_IO_300    equ    0000h
  82. BASE_IO_320    equ    0100h
  83. BASE_IO_340    equ    0200h
  84. BASE_IO_360    equ    0300h
  85.  
  86. ; SCR Bits 12-15:  BOOT PROM and PORT SELECTION configuration:
  87. BOOT_ENA    equ    1000h        ; bit 12 = 1:  Enable boot PROM
  88. BOOT_DIS    equ    0000h        ; bit 12 = 0:  Disable boot PROM
  89. UTP_PORT    equ    2000h        ; bit 13 = 1:  Select UTP Port
  90. OTHER_PORT    equ    0000h        ; bit 13 = 0:  Select "Other" Port
  91.  
  92. ; Flag Word (location 32):
  93. AUTO_SENSE_BIT    equ    0001h
  94.  
  95. ; Board "Subtypes" (location 6):
  96. SUBTYPE_00    equ    1
  97. SUBTYPE_10    equ    2
  98. SUBTYPE_20    equ    3
  99.  
  100. ; PCNetISA I/O Ports:
  101. ADDR_PROM_OFFSET    equ    0    ; MAC (datalink) Address PROM
  102. RDP_OFFSET        equ    16    ; Register Data Port
  103. RAP_OFFSET        equ    18    ; Register Address Port
  104. ISACR_OFFSET        equ    22    ; ISA-Bus Control Register
  105. VSW_OFFSET        equ    24    ; Vendor Specific Word
  106.  
  107. ISACR2        equ    2        ; ISACR2 (out RAP register == ISACR2)
  108. MC_UTP_OTHER    equ    001h        ; value to select UTP or "Other" port
  109. MC_AUTO_SEL    equ    002h        ; value to select "Auto Select" function
  110.  
  111. ; Possible AT-1500 IRQ choices (varies depending on board "subtype"):
  112. IRQ_RANGE    MACRO    range_name, irq_a, irq_b, irq_c, irq_d
  113. range_name    equ    (irq_a SHL 12) + (irq_b SHL 8) + (irq_c SHL 4) + irq_d
  114.         ENDM
  115.     IRQ_RANGE  LOW_IRQ_RANGE,    3,  4,  5,  9
  116.     IRQ_RANGE  HIGH_IRQ_RANGE,  10, 11, 14, 15
  117.     IRQ_RANGE  MIXED_IRQ_RANGE,  3, 11,  5, 15
  118.  
  119.  
  120. DATASEG ENDS
  121.  
  122.  
  123. CODESEG SEGMENT
  124.  
  125.     if    @Version GE 600
  126.     ASSUME  CS:CODESEG
  127.     endif
  128.     ifdef    DATAGROUP
  129.     ASSUME  DS:DATAGROUP
  130.     endif
  131.     ifdef    STACKSEG
  132.     ASSUME  SS:STACKSEG
  133.     endif
  134.     ASSUME  ES:NOTHING
  135.  
  136. DELAY_750 MACRO
  137.     ; One CPU clock cycle = 25ns at 40Mhz CPU clock frequency
  138.     ; jmp short = (min) 8 cycles on a 386 = 200ns per jump
  139.     ; times 4 = at least 800ns on a 40Mhz 386
  140.     ; times 8 = at least 800ns on an 80Mhz 386 (!!)
  141.     jmp short $+2
  142.     jmp short $+2
  143.     jmp short $+2
  144.     jmp short $+2
  145.     jmp short $+2
  146.     jmp short $+2
  147.     jmp short $+2
  148.     jmp short $+2
  149.     ENDM
  150.  
  151. DELAY_250 MACRO
  152.     ; times 2 = at least 400ns on a 40Mhz 386
  153.     ; times 4 = at least 400ns on an 80Mhz 386 (!!)
  154.     jmp short $+2
  155.     jmp short $+2
  156.     jmp short $+2
  157.     jmp short $+2
  158.     ENDM
  159.  
  160. DEBUG_DISPLAY MACRO    display_char
  161.     push    AX
  162.     push    DX
  163.     mov    AH, 02h
  164.     mov    DL, '<'
  165.     int    21h
  166.     mov    DL, display_char
  167.     int    21h
  168.     mov    DL, '>'
  169.     int    21h
  170.     pop    DX
  171.     pop    AX
  172.     ENDM
  173.  
  174.  
  175. ;************************************************************************;
  176. ;*                                    *;
  177. ;*  VerifyBoard                                *;
  178. ;*    Function: Read the configuration of the AT-1500 board.        *;
  179. ;*    Input:  DI = base I/O address of the AT-1500 board.        *;
  180. ;*    Output: stc (carry set) if not an AT-1500 or config error;    *;
  181. ;*        clc (carry clear) if successful, and:            *;
  182. ;*            BH = configured DMA channel.            *;
  183. ;*            BL = configured IRQ.                *;
  184. ;*            CX = value to be output to the ISACR2 register.    *;
  185. ;*        Other registers used are preserved.            *;
  186. ;*                                    *;
  187. ;************************************************************************;
  188.  
  189. VerifyBoard proc    near
  190.  
  191.     push    AX            ; save caller's registers
  192.     push    DX
  193.  
  194.     ; Verify that this really is an AT-1500 board.
  195.     mov    DX, DI            ; DX = address prom I/O address
  196.     in    AX, DX            ; read the first 2 bytes of MAC address
  197.     cmp    AX, 0            ; it better be 0000
  198.     je    VB_go_on
  199.      jmp    scr_error
  200. VB_go_on:
  201.     add    DX, 2
  202.     in    AX, DX            ; read the next 2 bytes of MAC address
  203.     cmp    AL, 0F4h        ; the third byte better be F4
  204.     je    VB_its_ours
  205.      jmp    scr_error
  206. VB_its_ours:
  207.     ;  Read the SCR to get the state of the configuration "switches".
  208.     mov    BX, SCR_ADDR
  209.     call    rd_oper            ; read the Switch Configuration Register
  210.     mov    DX, AX            ; save SCR value for later
  211.  
  212.     ;  Read this board's rev level and "subtype" codes.
  213.     mov    BX, BOARD_REV_LOC    ; read "board rev code" at EEPROM loc 6
  214.     call    rd_oper            ; AL=rev level code, AH=Subtype code
  215.  
  216.     ;  Determine the configured IRQ and return this value in BL.
  217.     mov    BX, HIGH_IRQ_RANGE    ; (assume this is a Subtype 20 board)
  218.     cmp    AH, SUBTYPE_20        ; is this a Subtype 20 board ?
  219.      je    got_irq_range        ;   yes, uses High range of IRQ choices
  220.     mov    BX, MIXED_IRQ_RANGE
  221.     cmp    AH, SUBTYPE_00        ; is this a Subtype 00 board ?
  222.      je    got_irq_range        ;   yes, uses Mixed range of IRQ choices
  223.     mov    BX, LOW_IRQ_RANGE    ; must be Subtype 10: uses Low IRQ range
  224.   got_irq_range:
  225.     mov    AX, DX            ; get the SCR value again
  226.     and    AX, IRQ_MASK        ; isolate IRQ configuration bits
  227.     mov    CL, 12
  228.     cmp    AX, IRQ_CHOICE_A    ; switch based upon on of 4 IRQ choices
  229.      je    got_irq
  230.     mov    CL, 8
  231.     cmp    AX, IRQ_CHOICE_B
  232.      je    got_irq
  233.     mov    CL, 4
  234.     cmp    AX, IRQ_CHOICE_C
  235.      je    got_irq
  236.     xor    CL, CL
  237.     cmp    AX, IRQ_CHOICE_D
  238.      je    got_irq
  239.     jmp    scr_error
  240. got_irq:
  241.     shr    BX, CL            ; compute actual IRQ value
  242.     and    BL, 0Fh            ;   and return in register BL
  243.  
  244.     ;  Determine the configured DMA channel and return this value in BH.
  245.     mov    AX, DX            ; get the SCR value again
  246.     and    AX, DMA_MASK        ; isolate DMA channel configuration bits
  247.     mov    BH, 3
  248.     cmp    AX, DMA_3        ; is it DMA channel 3 ?
  249.      je    got_dma            ;    yes
  250.     mov    BH, 5
  251.     cmp    AX, DMA_5        ; is it DMA channel 5 ?
  252.      je    got_dma            ;    yes
  253.     mov    BH, 6
  254.     cmp    AX, DMA_6        ; is it DMA channel 6 ?
  255.      je    got_dma            ;    yes
  256.     mov    BH, 7
  257.     cmp    AX, DMA_7        ; is it DMA channel 7 ?
  258.      je    got_dma            ;    yes
  259.     jmp    scr_error
  260. got_dma:
  261.  
  262.     ;  Determine the proper value to be used for ISACR2 and return it in CX.
  263.     mov    CX, 0001h        ; assume ISACR2 = XMAUSEL (ext. hdw)
  264.     test    DX, UTP_PORT        ; check SCR value: is "UTP" selected ?
  265.      jz    got_mau            ;   no, "Other" port (BNC/FOIRL/AUI)
  266.     push    bx
  267.     mov    BX, FLAG_WORD_LOC    ; not the "other" port, but ...
  268.     call    rd_oper            ; read the flag word from the EEPROM
  269.     pop    bx
  270.     test    DX, AUTO_SENSE_BIT    ; is "Auto Select" configured ?
  271.      jz    got_mau            ;   no, must be the UTP port
  272.     mov    CX, 0002h        ; yes, ISACR2 = ASEL (Auto Select)
  273. got_mau:
  274.  
  275.     clc                ; set CF=0 == "success"
  276.     pop    dx            ; restore caller's registers
  277.     pop    ax
  278.     ret                ; return to caller
  279.     
  280. scr_error:
  281.     stc                ; set CF=1 == "error"
  282.     pop    dx            ; restore caller's registers
  283.     pop    ax
  284.     ret                ; return to caller
  285.         
  286. VerifyBoard endp
  287.  
  288.  
  289. ;************************************************************************;
  290. ;*                                    *;
  291. ;*  read_adr_prom                            *;
  292. ;*    Function: read the MAC (datalink) address of the board.        *;
  293. ;*    Input:    DS:(E)SI = pointer to caller's mac address buffer.    *;
  294. ;*        DI = base I/O address of the AT-1500 board        *;
  295. ;*    Output: the board's MAC address is placed in the caller's bfr.    *;
  296. ;*        registers used are preserved                *;
  297. ;*                                    *;
  298. ;************************************************************************;
  299.  
  300. read_adr_prom    proc    near
  301.  
  302.     if    @Version GE 600
  303.     ASSUME    POINTER_REGISTER : PTR BYTE
  304.     endif
  305.  
  306.     push    ax            ; save caller's registers
  307.     push    dx
  308.     mov    DX, DI            ; DX = address prom I/O address
  309.     in    ax, dx
  310.     mov    word ptr [POINTER_REGISTER], ax
  311.     add    dx, 2
  312.     in    ax, dx
  313.     mov    word ptr [POINTER_REGISTER+2], ax
  314.     add    dx, 2
  315.     in    ax, dx
  316.     mov    word ptr [POINTER_REGISTER+4], ax
  317.     pop    dx            ; restore caller's registers
  318.     pop    ax
  319.     ret                ; return to caller
  320.     
  321. read_adr_prom    endp
  322.  
  323.  
  324. ;************************************************************************;
  325. ;*                                    *;
  326. ;*  rd_oper                                *;
  327. ;*    Function: do a complete word READ operation.            *;
  328. ;*    Input:    BX = EEPROM address to be read.                *;
  329. ;*        DI = base I/O address of the AT-1500 board        *;
  330. ;*    Output: AX = data read from EEPROM.                *;
  331. ;*        registers used are preserved                *;
  332. ;*                                    *;
  333. ;************************************************************************;
  334.  
  335. rd_oper proc    near
  336.  
  337.     push    bx        ; save caller's registers
  338.     push    cx
  339.     push    dx
  340.     mov    cx, bx
  341.  
  342.     call    pulse_cs
  343.     call    prep_load    ; prepare the EEPROM for a new command
  344.     mov    dx, SB
  345.     call    wr_bit        ; write a Start Bit
  346.     mov    dl, READ
  347.     and    cl, ADDR_MASK
  348.     or    dl, cl
  349.     call    wr_byte        ; write a READ command code with the address
  350.  
  351.     xor    bx, bx        ; bx = data read
  352.     mov    cx, 16        ; reading 16 bits
  353. rd_next_bit1:
  354.     shl    bx, 1
  355.     call    rd_bit        ; read a bit
  356.     or    bx, ax        ; merge it with accumulated bits so far
  357.     loop    rd_next_bit1
  358.  
  359.     call    pulse_cs    ; pulse CHIP SELECT to terminate the command
  360.     mov    ax, bx        ; return EEPROM value in AX
  361.     pop    dx        ; restore caller's registers
  362.     pop    cx
  363.     pop    bx
  364.     ret            ; return to caller
  365.  
  366. rd_oper endp
  367.  
  368. ;************************************************************************;
  369. ;*                                    *;
  370. ;*  rd_bit                                *;
  371. ;*    Function: Read 1 bit from the eeprom DO pin.            *;
  372. ;*    Input:    AX = the least significant bit (bit 0) is the data bit    *;
  373. ;*            read.                        *;
  374. ;*        DI = base I/O address of the AT-1500 board        *;
  375. ;*    Output: nothing                            *;
  376. ;*        registers used are preserved                *;
  377. ;*                                    *;
  378. ;************************************************************************;
  379.  
  380. rd_bit    proc    near
  381.  
  382.     push    dx
  383.     xor    ax, ax
  384.     mov    al, CHIP_SEL
  385.     or    al, CLOCK
  386.     mov    dx, DI
  387.     add    dx, VSW_OFFSET
  388.     out    dx, al        ; make CLOCK go high
  389.  
  390.     in    al, dx        ; read D0
  391.     and    al, DATA_OUT
  392.     DELAY_750        ; chip requires about 750ns hold time here
  393.  
  394.     push    ax
  395.     mov    al, CHIP_SEL
  396.     out    dx, al        ; make CLOCK go low again
  397.     pop    ax
  398.  
  399.     shr    ax, 1
  400.     shr    ax, 1        ; return DO in LSB (bit 0) of AX
  401.     pop    dx
  402.     ret
  403.  
  404. rd_bit    endp
  405.  
  406.  
  407. ;************************************************************************;
  408. ;*                                    *;
  409. ;*  wr_byte                                *;
  410. ;*    Function: Write a byte to the eeprom.                *;
  411. ;*    Input:    DL = data byte to be written.                *;
  412. ;*        DI = base I/O address of the AT-1500 board.        *;
  413. ;*    Output:    nothing                            *;
  414. ;*        registers used are preserved                *;
  415. ;*                                    *;
  416. ;************************************************************************;
  417.  
  418. wr_byte proc    near
  419.  
  420.     push    ax            ; save caller's registers
  421.     push    cx
  422.  
  423.     mov    al, dl
  424.     mov    cx, 8
  425. next_bit:
  426.     rol    al, 1
  427.     mov    dl, al
  428.     and    dl, 01h            ; DL bit 0 = bit to write
  429.     call    wr_bit            ; write one bit of the byte
  430.     loop    next_bit        ; loop to write all bits
  431.  
  432.     pop    cx            ; restore caller's registers
  433.     pop    ax
  434.     ret                ; return to caller
  435.  
  436. wr_byte endp
  437.  
  438. ;************************************************************************;
  439. ;*                                    *;
  440. ;*  wr_bit                                *;
  441. ;*    Function: Write a bit to the EEPROM Data In pin.        *;
  442. ;*    Input:    DL = the least significant bit (bit 0) is the data bit    *;
  443. ;*            to be written.                    *;
  444. ;*        DI = base I/O address of the AT-1500 board.        *;
  445. ;*    Output: nothing                            *;
  446. ;*        registers used are preserved                *;
  447. ;*                                    *;
  448. ;************************************************************************;
  449.  
  450. wr_bit    proc    near
  451.  
  452.     push    ax        ; save caller's registers
  453.     push    bx
  454.     push    dx
  455.     mov    bl, dl
  456.     mov    al, CHIP_SEL
  457.     and    bl, 01h
  458.     or    al, bl
  459.     mov    dx, DI
  460.     add    dx, VSW_OFFSET
  461.     out    dx, al        ; write CS and DI out
  462.     or    al, CLOCK
  463.     out    dx, al        ; present data bit with CLOCK high
  464.     DELAY_750        ; chip requires about 750ns hold time here
  465.     mov    al, CHIP_SEL
  466.     out    dx, al        ; make the CLOCK go low again
  467.  
  468.     pop    dx        ; restore registers
  469.     pop    bx
  470.     pop    ax
  471.     ret            ; return to caller
  472.  
  473. wr_bit    endp
  474.  
  475.  
  476. ;************************************************************************;
  477. ;*                                    *;
  478. ;*  prep_load                                *;
  479. ;*    Function: Generate one clock cycle as required before sending    *;
  480. ;*            a new command code to the EEPROM.        *;
  481. ;*    Input:    DI = base I/O address of the AT-1500 board        *;
  482. ;*    Output:    nothing                            *;
  483. ;*        registers used are preserved                *;
  484. ;*                                    *;
  485. ;************************************************************************;
  486.  
  487. prep_load    proc    near
  488.  
  489.     push    ax
  490.     push    dx
  491.     mov    dx, DI
  492.     add    dx, VSW_OFFSET
  493.     mov    al, CHIP_SEL + CLOCK
  494.     out    dx, al            ; turn on CHIP SELECT and CLOCK
  495.     DELAY_250        ; chip requires about 250ns hold time here
  496.  
  497.     and    al, NOT CLOCK        ; wait for 1 clock cycle
  498.     out    dx, al            ; turn off CLOCK
  499.  
  500.     pop    dx
  501.     pop    ax
  502.     ret                ; return to caller
  503.  
  504. prep_load    endp
  505.  
  506. ;************************************************************************;
  507. ;*                                    *;
  508. ;*  pulse_cs                                *;
  509. ;*    function: to make CS pin in the eeprom go low for a short time,    *;
  510. ;*          then go high again (required between commands).    *;
  511. ;*    input:    DI = base I/O address of the AT-1500 board        *;
  512. ;*    output: nothing                            *;
  513. ;*        registers used are preserved                *;
  514. ;*                                    *;
  515. ;************************************************************************;
  516.  
  517. pulse_cs    proc    near
  518.  
  519.     pushf            ; save interrupt state
  520.     cli            ; disable interrupts
  521.     call    cs_low        ; drop CHIP_SEL for about 250ns
  522.     call    cs_high        ; raise CHIP_SEL again
  523.     popf            ; re-enable interrupts (if they were enabled)
  524.     ret            ; return to caller
  525.  
  526. pulse_cs    endp
  527.  
  528. ;************************************************************************;
  529. ;*                                    *;
  530. ;*  cs_low                                *;
  531. ;*    Function: to make the Chip Select pin in the EEPROM go low.    *;
  532. ;*    Input:    DI = base I/O address of the AT-1500 board        *;
  533. ;*    Output: nothing                            *;
  534. ;*        registers used are preserved                *;
  535. ;*                                    *;
  536. ;************************************************************************;
  537.  
  538. cs_low    proc    near
  539.  
  540.     push    ax        ; save caller's registers
  541.     push    dx
  542.     mov    dx, DI
  543.     add    dx, VSW_OFFSET
  544.     xor    ax, ax
  545.     out    dx, al        ; turn off CHIP SELECT
  546.     DELAY_250        ; chip requires about 250ns between instructions
  547.     pop    dx        ; restore caller's registers
  548.     pop    ax
  549.     ret            ; return to caller
  550.  
  551. cs_low    endp
  552.  
  553. ;************************************************************************;
  554. ;*                                    *;
  555. ;*  cs_high                                *;
  556. ;*    Function: to make the Chip Select pin in the EEPROM go high.    *;
  557. ;*    Input:    DI = base I/O address of the AT-1500 board        *;
  558. ;*    Output: nothing                            *;
  559. ;*        registers used are preserved                *;
  560. ;*                                    *;
  561. ;************************************************************************;
  562.  
  563. cs_high    proc    near
  564.  
  565.     push    ax        ; save caller's registers
  566.     push    dx
  567.     mov    dx, DI
  568.     add    dx, VSW_OFFSET
  569.     mov    al, CHIP_SEL
  570.     out    dx, al        ; turn on CHIP SELECT
  571.     pop    dx        ; restore caller's registers
  572.     pop    ax
  573.     ret            ; return to caller
  574.  
  575. cs_high    endp
  576.  
  577.  
  578. CODESEG ENDS
  579.