Annotation of coherent/d/conf/tboot/cpuid.m, revision 1.1

1.1     ! root        1: / 
        !             2: / FLG_PIQL      Pre-fetch instruction queue length, 0 => 4-byte, 1 => 6-byte
        !             3: / FLG_08                Intel 808x
        !             4: / FLG_NEC       NEC V20 or V30
        !             5: / FLG_18                Intel 8018x
        !             6: / FLG_28                Intel 8028x
        !             7: / FLG_38                Intel 8038x
        !             8: / 
        !             9: / FLG_87                Intel 8087
        !            10: / FLG_287       Intel 80287
        !            11: / FLG_387       Intel 80387
        !            12: / 
        !            13: / FLG_1167      Weitek 1167
        !            14: / 
        !            15: / $FLG_CERR     Faulty CPU
        !            16: / $FLG_NERR     Faulty NDP switch setting
        !            17: 
        !            18: FLG     record  $RSVD:6,$FLG_NERR:1,$FLG_CERR:1,$FLG_WTK:1,$FLG_NDP:3,$FLG_CPU:4
        !            19: 
        !            20: / CPU-related flags
        !            21: 
        !            22: FLG_PIQL equ    0001b shl $FLG_CPU
        !            23: FLG_08  equ     0000b shl $FLG_CPU
        !            24: FLG_NEC  equ    0010b shl $FLG_CPU
        !            25: FLG_18  equ     0100b shl $FLG_CPU
        !            26: FLG_28  equ     0110b shl $FLG_CPU
        !            27: FLG_38  equ     1000b shl $FLG_CPU
        !            28: 
        !            29: FLG_8088 equ    FLG_08
        !            30: FLG_8086 equ    FLG_08 or FLG_PIQL
        !            31: FLG_V20  equ    FLG_NEC
        !            32: FLG_V30  equ    FLG_NEC or FLG_PIQL
        !            33: FLG_80188 equ   FLG_18
        !            34: FLG_80186 equ   FLG_18 or FLG_PIQL
        !            35: FLG_80286 equ   FLG_28 or FLG_PIQL
        !            36: FLG_80386 equ   FLG_38 or FLG_PIQL
        !            37: 
        !            38: / NDP-related flags
        !            39: 
        !            40: FLG_NDPX equ    000b shl $FLG_NDP      / Not present
        !            41: FLG_NDPU equ    001b shl $FLG_NDP      / Untested
        !            42: FLG_87  equ     010b shl $FLG_NDP
        !            43: FLG_287  equ    011b shl $FLG_NDP
        !            44: FLG_387  equ    100b shl $FLG_NDP
        !            45: 
        !            46: FLG_1167 equ    mask $FLG_WTK
        !            47: 
        !            48: CPUID   proc    near           / Start CPUID procedure
        !            49: 
        !            50: / This procedure determines the type of CPU and NDP (if any) in use.
        !            51: / 
        !            52: / The possibilities include:
        !            53: / 
        !            54: / Intel 8086
        !            55: / Intel 8088
        !            56: / NEC   V20
        !            57: / NEC   V30
        !            58: / Intel 80186
        !            59: / Intel 80188
        !            60: / Intel 80286
        !            61: / Intel 80386
        !            62: / Intel 8087
        !            63: / Intel 80287
        !            64: / Intel 80387
        !            65: / 
        !            66: /    Also checked is whether or not the CPU allows interrupts after
        !            67: / changing the SS segment register.  If the CPU does, it is faulty and
        !            68: / should be replaced.
        !            69: / 
        !            70: /    Further, if an NDP is installed, non-AT machines should have a
        !            71: / system board switch set correspondingly.  Such a discrepancy is
        !            72: / reported upon.
        !            73: / 
        !            74: /    On exit, BX contains flag settings (as defined in $FLG record) which
        !            75: / the caller can check.  For example, to test for an Intel 80286, use
        !            76: / 
        !            77: /       and     bx,mask $FLAG_CPU
        !            78: / 
        !            79: /       cmp     bx,FLG_80286
        !            80: /       je      ITSA286
        !            81: / 
        !            82: 
        !            83:        push    ax / Save registers
        !            84:        push    cx
        !            85:        push    di
        !            86:        push    ds
        !            87:        push    es
        !            88: 
        !            89: / Test for 80286/386 -- these CPUs execute PUSH SP by first storing SP on stack,
        !            90: / then decrementing it.  Earlier CPUs first decrement then store.
        !            91: 
        !            92:         push    sp             / Only 286 pushes pre-push SP
        !            93:         pop     ax             / Get it back
        !            94: 
        !            95:         cmp     ax,sp          / Check for same
        !            96:         jne     CHECK_18x      / They aren't, try next class
        !            97: 
        !            98:         call    DIST_286or386  / Distinguish a 286 from 386
        !            99:         jmp     short CHECK_PIQL / Join common code
        !           100: 
        !           101: / Test for 80186/80188 -- 18x and later CPUs mask shift/rotate operations
        !           102: / mod 32/ earlier CPUs use all 8 bits of CL.
        !           103: 
        !           104: CHECK_18x:
        !           105:         mov     bx,FLG_18      / Assume it's an 8018x
        !           106:         mov     cl,32+1        / 18x masks shift counts mod 32
        !           107:                                / Note we can't use just 32 in CL
        !           108:         mov     al,0FFh        / Start with all bits set
        !           109: 
        !           110:         shl     al,cl          / Shift one position if 18x
        !           111:         jnz     CHECK_PIQL     / Some bits still on, so it's a 18x or later/
        !           112:                                / check PIQL
        !           113: 
        !           114:         mov     bx,FLG_NEC     / Assume it's an NEC V-series CPU
        !           115:         call    CHECK_NEC      / See if it's an NEC chip
        !           116:         jcxz    CHECK_PIQL     / Good guess, check PIQL
        !           117: 
        !           118:         mov     bx,FLG_08      / It's an 808x
        !           119: /      subttl  Check Length Of Pre-fetch Instruction Queue
        !           120: /      page
        !           121: 
        !           122: / Check the length of the pre-fetch instruction queue (PIQ).
        !           123: / 
        !           124: / xxxx6 CPUs have a PIQ length of 6 bytes,
        !           125: / xxxx8 CPUs   "     "     "      4   "
        !           126: / 
        !           127: / Self-modifying code is used to distinguish the two PIQ lengths.
        !           128: / 
        !           129: / To overcome write pipelining in 286/386 chips, the largest value
        !           130: / over several executions of the subroutine is used.
        !           131: 
        !           132: CHECK_PIQL:
        !           133:         call    PIQL_SUB       / Handled via subroutine
        !           134: 
        !           135:         cmp     cx,PIQL        / Use the larger of the two
        !           136:         jbe     CHECK_PIQL1    / CX is smaller
        !           137: 
        !           138:         mov     PIQL,cx        / Save to report on later
        !           139: CHECK_PIQL1:
        !           140:         dec     PIQL_CNT       / One fewer times through the loop
        !           141:         jnz     CHECK_PIQL     / Jump if
        !           142: 
        !           143:         cmp     PIQL,4         / Check PIQL
        !           144:         jbe     CHECK_ERR      / Jump if xxxx8
        !           145: 
        !           146:         or      bx,FLG_PIQL    / PIQ length is 5 or longer
        !           147: /      subttl  Check For Allowing Interrupts After POP SS
        !           148: /      page
        !           149: 
        !           150: / Test for faulty chip (allows interrupts after change to SS register)
        !           151: 
        !           152: CHECK_ERR:
        !           153:         call    ERR_SUB        / Handled via subroutine
        !           154:         jcxz    CHECK_NDP      / If CX is 0, the DEC was executed,
        !           155:                                / and the CPU is OK
        !           156:         or      bx,mask $FLG_CERR / It's a faulty chip
        !           157: /      subttl  Check For Numeric Data Processor
        !           158: /      page
        !           159: CHECK_NDP:
        !           160:         call    NDP_SUB        / Handled via subroutine
        !           161: 
        !           162:         pop    es / Restore registers
        !           163:         pop    ds
        !           164:         pop    di
        !           165:         pop    cx
        !           166:         pop    ax
        !           167: 
        !           168:         ret                    / Return to caller
        !           169: 
        !           170: CPUID   endp                   / End CPUID procedure
        !           171: /      subttl  Distinguish A 286 From 386
        !           172: /      page
        !           173: DIST_286or386 proc   near
        !           174: 
        !           175: / The test for 286 vs. 386 is done by attempting to set flag bits in
        !           176: / the high-order nibble of the flag word.  If that's successful, it's a
        !           177: / 386/ otherwise it's a 286.
        !           178: 
        !           179: 
        !           180:         push   ax              / Save register
        !           181: 
        !           182:         pushf                  / Save flags for a moment
        !           183: 
        !           184:         mov     ax,0F000h      / Try to set high bits in flag register
        !           185: 
        !           186:         push    ax             / Move into flag register
        !           187:         popf
        !           188: 
        !           189:         pushf                  / Get flags back into AX
        !           190:         pop     ax
        !           191: 
        !           192:         popf                   / Restore original flags
        !           193: 
        !           194:         test    ax,0F000h      / Any bits set?
        !           195:         jz      ITSA286        / No, so it's a 286
        !           196: 
        !           197:         or      bx,FLG_38      / It's a 38x
        !           198:         jmp     short DIST_286or386_EXIT / Join common exit code
        !           199: ITSA286:
        !           200:         or      bx,FLG_28      / It's a 28x
        !           201: DIST_286or386_EXIT:
        !           202:         pop ax         / Restore
        !           203: 
        !           204:         ret                    / Return to caller
        !           205: 
        !           206: DIST_286or386 endp             / End DIST_286or386 procedure
        !           207: /      subttl  Check For NEC V20/V30
        !           208: /      page
        !           209: CHECK_NEC proc  near
        !           210: /    The NEC V20/V30 CPUs are very compatible with the Intel 8086/8088.
        !           211: / The only point of "incompatiblity" is that they do not contain a bug
        !           212: / found in the Intel CPUs.  Specifically, the NEC CPUs correctly restart
        !           213: / an interrupted multi-prefix string instruction at the start of the
        !           214: / instruction.  The Intel CPUs incorrectly restart it in the middle of
        !           215: / the instruction.  This routine tests for that situation by executing
        !           216: / such an instruction for a sufficiently long period of time for a timer
        !           217: / interrupt to occur.  If at the end of the instruction, CX is zero,
        !           218: / it must be an NEC CPU/ if not, it's an Intel CPU.
        !           219: / 
        !           220: /    Note that we're counting on the timer interrupt to do its thing
        !           221: / every 18.2 times per second.
        !           222: / 
        !           223: /    Here's a worst case analysis:  An Intel 8086/8088 executes 65535
        !           224: / iterations of LODSB ES:[SI] in 2+9+13*65535 = 851,966 clock ticks.  If
        !           225: / the Intel 8086/8088 is running at 15 MHz, each clock tick is 66.67
        !           226: / nanoseconds, hence the entire operation takes 56.8 milliseconds.  If the
        !           227: / timer is running at normal speed, it interrupts the CPU every 55
        !           228: / millseconds and so should interrupt the repeated string instruction at
        !           229: / least once.
        !           230: 
        !           231:         mov     cx,0FFFFh      / Move a lot of data
        !           232:         sti                    / Ensure timer enabled
        !           233: 
        !           234: /  Execute multi-prefix instruction.  Note that the value of ES as
        !           235: /  well as the direction flag setting is irrelevant.
        !           236: 
        !           237:         push    ax             / Save registers
        !           238:         push    si
        !           239:      rep lods   byte ptr es:[si]
        !           240:         pop     si             / Restore
        !           241:         pop     ax
        !           242: 
        !           243: / On exit, if CX is zero, it's an NEC CPU, otherwise it's an Intel CPU
        !           244: 
        !           245:         ret                    / Return to caller
        !           246: 
        !           247: CHECK_NEC endp
        !           248: /      subttl  Pre-fetch Instruction Queue Subroutine
        !           249: /      page
        !           250: PIQL_SUB proc   near
        !           251: /    This subroutine attempts to discern the length of the CPU's
        !           252: / pre-fetch instruction queue (PIQ).
        !           253: / 
        !           254: /    It stores a new instruction into the instruction stream
        !           255: / following the STOSB.  The loop proceeds backwards from the end
        !           256: / of the stream to the beginning.  At the point the inserted
        !           257: / instruction is not executed, we have found the last byte in
        !           258: / the PIQ.  The value in CX at that time is then the PIQ length.
        !           259: 
        !           260:         push   ax / Save registers
        !           261:         push   bx
        !           262:         push   dx
        !           263:         push   si
        !           264:         push   di
        !           265: 
        !           266: @REP    equ     64             / Maximum length of PIQ
        !           267:                                / we can handle
        !           268: 
        !           269:         std                    / Store backwards
        !           270: 
        !           271:         mov     cx,@REP        / Loop counter
        !           272:         lea     di,LAB_NOP+@REP-1 / ES:DI ==> PIQL last byte
        !           273:                                / in fill area
        !           274: 
        !           275:         mov     al,ds:LAB_INC  / Change to INC BX
        !           276:         mov     ah,ds:LAB_NOP  / Save a NOP here to restore
        !           277:         mov     si,1           / Divisor
        !           278:         xor     dx,dx          / Zero high-order word for divide
        !           279:         cli                    / Ensure interrupts are disabled, otherwise
        !           280:                                / a timer tick could disturb the PIQ filling
        !           281:         even                   / Ensure word alignment for LAB_FILL
        !           282:         nop
        !           283: PIQL_SUB_NEXT:
        !           284:         xor     bx,bx          / Initialize flag
        !           285:         div     si             / Take up some time and
        !           286:                                / refill the queue
        !           287:         stosb                  / Change the instruction
        !           288: 
        !           289: / The PIQ begins filling here
        !           290: 
        !           291: LAB_NOP  label  byte
        !           292:         rept    @REP
        !           293:         nop                    // Fill byte
        !           294:         endm
        !           295: 
        !           296:         mov     es:[di+1],ah   / Restore the NOP
        !           297: 
        !           298:         and     bx,bx          / Did we execute it?
        !           299:         loopnz  PIQL_SUB_NEXT  / Go around again if we did
        !           300:                                / and loop not finished
        !           301:         inc     cx             / Count in last byte
        !           302: 
        !           303:         sti                    / Restore interrupts
        !           304:         cld                    / Restore direction flag
        !           305: 
        !           306:         pop    di / Restore
        !           307:         pop    si
        !           308:         pop    dx
        !           309:         pop    bx
        !           310:         pop    ax
        !           311: 
        !           312: / At the end, CX has the length of the PIQ
        !           313: 
        !           314:         ret                    / Return to caller
        !           315: 
        !           316: LAB_INC  label  byte
        !           317:         inc     bx             / Increment counter
        !           318: 
        !           319: PIQL_SUB endp                  / End PIQL_SUB procedure
        !           320: /       subttl  Check For Faulty Interrupts
        !           321: /       page
        !           322: ERR_SUB  proc   near
        !           323: / Test for faulty chip (allows interrupts after change to SS register).
        !           324: / Setup a handler for INT 01h (single-step interrupt) and turn on that
        !           325: / flag just before executing a POP SS.  If the CPU allows a single-step
        !           326: / interrupt after the POP SS, it's faulty.
        !           327: / 
        !           328: / On exit:
        !           329: / 
        !           330: / CX    =       1 if CPU is faulty
        !           331: /       =       0 if OK
        !           332: 
        !           333: 
        !           334: 
        !           335:         push   ax      / Save registers
        !           336:         push   ds
        !           337: 
        !           338:         xor     ax,ax          / Prepare to address interrupt vector segment
        !           339:         mov     ds,ax          / DS points to segment 0
        !           340: 
        !           341:         cli                    / Nobody move while we swap
        !           342: 
        !           343:         lea     ax,INT01       / Point to our own handler
        !           344:         xchg    ax,INT01_OFF   / Get and swap offset
        !           345:         mov     OLDINT01_OFF,ax / Save to restore later
        !           346: 
        !           347:         mov     ax,cs          / Our handler's segment
        !           348:         xchg    ax,INT01_SEG   / Get and swap segment
        !           349:         mov     OLDINT01_SEG,ax / Save to restore later
        !           350: 
        !           351: / Note we continue with interrupts disabled to avoid an external interrupt
        !           352: / occurring during this test.
        !           353: 
        !           354:         mov     cx,1           / Initialize a register
        !           355:         push    ss             / Save SS to store back into itself
        !           356: 
        !           357:         pushf                  / Move flags
        !           358:         pop     ax             / ...into AX
        !           359:         or      ax,mask $TF    / Set trap flag
        !           360:         push    ax             / Place onto stack
        !           361:         POPFF                  / ...and then into effect
        !           362:                                / Some CPUs effect the trap flag immediately,
        !           363:                                /   some wait one instruction.
        !           364:         nop                    / Allow interrupt to take effect
        !           365: POST_NOP:
        !           366:         pop     ss             / Change the stack segment register (to itself)
        !           367:         dec     cx             / Normal CPUs execute this instruction before
        !           368:                                / recognizing the single-step interrupt
        !           369:         hlt                    / We never get here
        !           370: INT01:
        !           371: 
        !           372: / Note IF=TF=0
        !           373: 
        !           374: / If we're stopped at or before POST_NOP, continue on
        !           375: 
        !           376:         push    bp             / Prepare to address the stack
        !           377:         mov     bp,sp          / Hello, Mr. Stack
        !           378: 
        !           379:         cmp     [bp].ARG_OFF,offset cs:POST_NOP / Check offset
        !           380:         pop     bp             / Restore
        !           381:         ja      INT01_DONE     / We're done
        !           382: 
        !           383:         iret                   / Return to caller
        !           384: INT01_DONE:
        !           385: 
        !           386: / Restore old INT 01h handler
        !           387: 
        !           388:         push    es             / Save for a moment
        !           389:         les     ax,OLDINT01_VEC / ES:AX ==> old INT 01h handler
        !           390:         mov     INT01_OFF,ax   / Restore offset
        !           391:         mov     INT01_SEG,es   / ...and segment
        !           392:         pop     es             / Restore
        !           393: 
        !           394:         sti                    / Allow interrupts again (IF=1)
        !           395: 
        !           396:         add     sp,3*2         / Strip IP, CS, and Flags from stack
        !           397: 
        !           398:         pop    ds      / Restore
        !           399:         pop    ax
        !           400: 
        !           401:         ret                    / Return to caller
        !           402: 
        !           403: ERR_SUB  endp                  / End ERR_SUB procedure
        !           404: /       subttl  Check For Numeric Data Processor
        !           405: /       page
        !           406: NDP_SUB  proc   near
        !           407: /    Test for a Numeric Data Processor -- Intel 8087, 80287, or 80387.
        !           408: / An 8087 allows FDISI, an 80287/80387 ignores it.  The 80287 and 80387
        !           409: / can be distinguished through their different treatment of the infinity
        !           410: / closure setting.
        !           411: / 
        !           412: /    In general, the technique used is passive -- it leaves the NDP in
        !           413: / the same state in which it is found.
        !           414: / 
        !           415: /    Unfortunately, some IBM PC/ATs and 3270/ATs without an NDP don't
        !           416: / handle floating-point instructions correctly.  In particular, when
        !           417: / no-WAIT NDP instruction is executed on those systems, they wipe out
        !           418: / the memory location and all bytes following in the same segment.  To
        !           419: / overcome this bug, Dan Lewis has suggested a technique which computes
        !           420: / the segment and offset of the location into which the store is made
        !           421: / such that the offset is in the last paragraph of the segment.  This
        !           422: / way, the wipe out is harmless.
        !           423: / 
        !           424: / On exit:
        !           425: / 
        !           426: / BX    =       $FLG_NDP & $FLG_NERR bits set as appropriate.
        !           427: 
        !           428:         push   ax      / Save registers
        !           429:         push   cx
        !           430:         push   di
        !           431: 
        !           432:         call    CHECK_1167     / See if there's a Weitek 1167 in the system
        !           433: 
        !           434: / Because some IBM PC/ATs and 3270/ATs without an NDP don't handle
        !           435: / floating-point instructions correctly, we check for a 286 explicitly
        !           436: / and rely upon the equipment flags to tell us if there's an NDP installed.
        !           437: / This behavior is also present on some 386s.
        !           438: 
        !           439:         test    LCL_FLAGS,@LCL_REAL / Use real code or not?
        !           440:         jnz     NDP_SUB1       / It's real
        !           441: 
        !           442:         mov     ax,bx          / Copy CPUID bits for destructive testing
        !           443:         and     ax,(mask $FLG_CPU) and not FLG_PIQL / Isolate CPU bits
        !           444: 
        !           445:         cmp     ax,FLG_28      / Izit a 28x?
        !           446:         je      NDP_SUB0       / Yes, skip NDP instructions
        !           447: 
        !           448:         cmp     ax,FLG_38      / Izit a 38x?
        !           449:         jne     NDP_SUB1       / Not this time
        !           450: NDP_SUB0:
        !           451:         test    LCL_FLAGS,@LCL_I11H / Skip INT 11h test?
        !           452:         jnz     NDP_SUB_UN     / Yes
        !           453: 
        !           454:         int     11h            / Get equipment flags into AX
        !           455: 
        !           456:         test    ax,mask $I11_NDP / Check NDP-installed bit
        !           457:         jz      NDP_SUB_EXIT0  / Not installed
        !           458: 
        !           459:         call    DIST_287or387  / Distinguish a 287 from a 387
        !           460: NDP_SUB_EXIT0:
        !           461:         jmp     NDP_SUB_EXIT   / Join common exit code
        !           462: 
        !           463: NDP_SUB_UN:
        !           464:         or      bx,FLG_NDPU    / Mark as untested
        !           465: 
        !           466:         jmp     NDP_SUB_EXIT   / Join common exit code
        !           467: 
        !           468: NDP_SUB1:
        !           469:         push    es             / Save for a moment
        !           470: 
        !           471:         lea     di,NDP_ENV+(size NDP_ENV)-1 / Offset of end of environment
        !           472:         call    MAX_OFFSET     / Return with ES:DI ==> NDP_ENV and DI largest
        !           473:         sub     di,(size NDP_ENV)-1 / Back off to start of NDP_ENV
        !           474: 
        !           475:         cli                    / Protect FNSTENV
        !           476:         fnstenv es:[di]        / If NDP present, save current environment,
        !           477:                                / otherwise, this instruction is ignored
        !           478:         sti                    / Allow interrupts
        !           479: 
        !           480:         pop     es             / Restore
        !           481: 
        !           482:         mov     cx,50/7        / Cycle this many times
        !           483:         loop    $              / Wait for result to be stored
        !           484: 
        !           485:         fninit                 / Initialize processor to known state
        !           486:         jmp     short $+2      / Wait for initialization
        !           487: 
        !           488:         push    es             / Save for a moment
        !           489: 
        !           490:         lea     di,NDP_CW+(size NDP_CW)-1 / Offset of end of control word
        !           491:         call    MAX_OFFSET     / Return with ES:DI ==> NDP_CW and DI largest
        !           492:         sub     di,(size NDP_CW)-1 / Back off to start of control word
        !           493: 
        !           494:         fnstcw  es:[di]        / Save control word
        !           495: 
        !           496:         pop     es             / Restore
        !           497: 
        !           498:         jmp     short $+2      / Wait for result to be stored
        !           499:         jmp     short $+2
        !           500: 
        !           501:         and     NDP_CW,not mask $IC / Turn off infinity control in case of 387
        !           502: 
        !           503:         cmp     NDP_CW_HI,03h  / Check for NDP initial control word
        !           504:         jne     NDP_SUB_NONE   / No NDP installed
        !           505: 
        !           506:         test    LCL_FLAGS,@LCL_I11H / Skip INT 11h test?
        !           507:         jnz     NDP_SUB2       / Yes
        !           508: 
        !           509:         int     11h            / Get equipment flags into AX
        !           510: 
        !           511:         test    ax,mask $I11_NDP / Check NDP-installed bit
        !           512:         jnz     NDP_SUB2       / It's correctly set
        !           513: 
        !           514:         or      bx,mask $FLG_NERR / Mark as in error
        !           515: NDP_SUB2:
        !           516:         and     NDP_CW,not mask $IEM / Enable interrupts (IEM=0, 8087 only)
        !           517:         fldcw   NDP_CW         / Reload control word
        !           518:         fdisi                  / Disable interrupts (IEM=1) on 8087,
        !           519:                                / ignored by 80287/80387
        !           520:         fstcw   NDP_CW         / Save control word
        !           521:         fldenv  NDP_ENV        / Restore original NDP environment
        !           522:                                / No need to wait for environment to be loaded
        !           523: 
        !           524:         test    NDP_CW,mask $IEM / Check Interrupt Enable Mask (8087 only)
        !           525:         jnz     NDP_SUB_8087   / It changed, hence NDP is an 8087
        !           526: 
        !           527:         call    DIST_287or387  / Distinguish a 287 from a 387
        !           528: 
        !           529:         jmp     short NDP_SUB_EXIT / Exit with flags in BX
        !           530: NDP_SUB_8087:
        !           531:         or      bx,FLG_87      / NDP is an 8087
        !           532: 
        !           533:         jmp     short NDP_SUB_EXIT / Join common exit code
        !           534: NDP_SUB_NONE:
        !           535:         test    LCL_FLAGS,@LCL_I11H / Skip INT 11h test?
        !           536:         jnz     NDP_SUB_EXIT   / Yes
        !           537: 
        !           538:         int     11h            / Get equipment flags into AX
        !           539: 
        !           540:         test    ax,mask $I11_NDP / Check NDP-installed bit
        !           541:         jz      NDP_SUB_EXIT   / It's correctly set
        !           542: 
        !           543:         or      bx,mask $FLG_NERR / Mark as in error
        !           544: NDP_SUB_EXIT:
        !           545:         pop    di      / Restore
        !           546:         pop    cx
        !           547:         pop    ax
        !           548: 
        !           549:         ret                    / Return to caller
        !           550: 
        !           551: NDP_SUB  endp                  / End NDP_SUB procedure
        !           552: /       subttl  Check For Weitek 1167
        !           553: /       page
        !           554: CHECK_1167 proc near
        !           555: / See if there's a Weitek 1167 in the system.
        !           556: / 
        !           557: / To determine that, clear EAX, call INT 11h, and test bit 24
        !           558: / in EAX.  If set, the coprocessor is present/ if not, then
        !           559: / it's not.  Obviously, we must be running on a 386.
        !           560: 
        !           561:         test    LCL_FLAGS,@LCL_I11H / Skip INT 11h test?
        !           562:         jnz     CHECK_1167_EXIT / Yes, 1167 untested
        !           563: 
        !           564:         test    bx,FLG_38      / Are we on a 38x?
        !           565:         jz      CHECK_1167_EXIT / No, thus no 1167
        !           566: 
        !           567:         db      66h            / Use EAX
        !           568:         push    ax             / Save for a moment
        !           569: 
        !           570:         db      66h            / Use EAX
        !           571:         xor     ax,ax          / Clear entire register
        !           572: 
        !           573:         int     11h            / Get equipment flags
        !           574: 
        !           575:         db      66h            / Use EAX
        !           576:         test    ax,0000h
        !           577:         dw      0100h          / Test bit 24
        !           578:         jz      CHECK_1167_EXIT0 / Not present
        !           579: 
        !           580:         or      bx,FLG_1167    / Mark as present
        !           581: CHECK_1167_EXIT0:
        !           582:         db      66h            / Use EAX
        !           583:         pop     ax             / Restore
        !           584: CHECK_1167_EXIT:
        !           585:         ret                    / Return to caller
        !           586: 
        !           587: CHECK_1167 endp                / End CHECK_1167 procedure
        !           588: /      subttl  Distinguish A 287 From 387
        !           589: /      page
        !           590: DIST_287or387 proc near
        !           591: /    Distinguish a 287 from a 387.
        !           592: / 
        !           593: /    Both the 80287 and 80387 are initialized with the infinity closure
        !           594: / bit set to one.  However, only the 80287 is sensitive to the value of
        !           595: / this bit.  Ordinarily when this bit is set to one, the chip uses
        !           596: / projective closure/ when it is cleared to zero, the chip uses affine
        !           597: / closure.  Thus the 80287 is initialized to use projective closure, but
        !           598: / that state can be changed through the infinity closure bit in the
        !           599: / control word.  On the other hand, the 80387 is initialized to use
        !           600: / affine closure and remains in that state independent of the setting of
        !           601: / the infinity closure bit.  The two NDPs can be distinguished by
        !           602: / executing code which is sensitive to the setting of the infinity
        !           603: / closure bit.
        !           604: 
        !           605:    The algorithm used is based upon one published by Intel on how to
        !           606: detect the 80387.
        !           607: 
        !           608: On exit:
        !           609: 
        !           610: BX      =       $FLG_NDP bits set as appropriate.
        !           611: 
        !           612: |
        !           613: 
        !           614: .287
        !           615:         fstenv  NDP_ENV        / Save current environment
        !           616:         finit                  / Initialize processor to known state
        !           617:                                / The 80287 is using projective
        !           618:                                / closure for arithmetic, the 80387 is
        !           619:                                / using affine closure
        !           620: 
        !           621:         fld1                   / Generate infinity
        !           622:         fldz                   /  by dividing zero into one
        !           623:         fdiv                   / ST0 = +infinity
        !           624:         fld     st(0)          / Copy it
        !           625:         fchs                   / ST0 = -infinity, ST1 = +infinity
        !           626:         fcompp                 / Compare them and pop both from stack
        !           627:         fstsw   ax             / Get status word
        !           628:         fldenv  NDP_ENV        / Restore original NDP environment
        !           629:         sahf                   / Copy into flags
        !           630:         jz      DIST_287or387_PROJ / Jump if the two are equal
        !           631:                                / (projective closure)
        !           632: 
        !           633:         or      bx,FLG_387     / NDP is an 80387
        !           634: 
        !           635:         jmp     short DIST_287or387_EXIT / Join common exit code
        !           636: 
        !           637: DIST_287or387_PROJ:
        !           638:         or      bx,FLG_287     / NDP is an 80287
        !           639: DIST_287or387_EXIT:
        !           640:         ret                    / Return to caller
        !           641: .8087
        !           642: DIST_287or387 endp             / End DIST_287or387 procedure
        !           643: /      subttl  Calculate Maximum Offset
        !           644: /      page
        !           645: MAX_OFFSET proc  near
        !           646: 
        !           647: / On entry:
        !           648: / 
        !           649: / ES:DI         ==>     memory offset
        !           650: / 
        !           651: / On exit:
        !           652: / 
        !           653: / ES:DI         ==>     same location but with DI as large as possible
        !           654: 
        !           655: 
        !           656: MAXOFF  equ     0FFF0h
        !           657: 
        !           658:         push   ax      / Save registers
        !           659:         push   cx
        !           660: 
        !           661:         push    di
        !           662: 
        !           663:         mov     cl,4           / Shift amount
        !           664:         shr     di,cl          / Isolate para of control word
        !           665:         mov     ax,es          / Get current segment
        !           666:         add     ax,di          / Add in segment of control word
        !           667:         sub     ax,MAXOFF shr 4 / Less a lot of paras
        !           668:         mov     es,ax          / Save as segment of control word
        !           669: 
        !           670:         pop     di             / Restore
        !           671: 
        !           672:         or      di,MAXOFF      / Include paras subtracted out above
        !           673: 
        !           674:         pop    cx      / Restore
        !           675:         pop    ax
        !           676: 
        !           677:         ret                    / Return to caller
        !           678: 
        !           679: MAX_OFFSET endp                / End MAX_OFFSET procedure
        !           680: 
        !           681: CODE    ends                   / End CODE segment
        !           682: 
        !           683:         if1
        !           684: %OUT Pass 1 complete
        !           685:         else
        !           686: %OUT Pass 2 complete
        !           687:         endif
        !           688: 
        !           689:         end     INITIAL        / End CPUID module

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.