home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / sampler0 / memtest.asm < prev    next >
Assembly Source File  |  1989-09-04  |  26KB  |  1,181 lines

  1.     page 82,120
  2.     title MemTest - Test Main & Extended Memory
  3.     .MODEL    SMALL
  4.     .386p
  5.  
  6. ;    Gene Czarcinski,  4 Sep 89
  7. ;
  8. ;    This program is designed to test main and extended (not expanded)
  9. ;    (ram) memory on a 386 or 386SX.  It was developed on a Wave Mate
  10. ;    Bullet-386SX and some of the ports or hardware values may differ on
  11. ;    different systems.  Because it was developed on a 386, some of the
  12. ;    specific characteristics of a 386 are used (however, it should be
  13. ;    possible to convert this program to a 286 with some effort).
  14. ;
  15. ;    NOTE that this program operates in REAL mode to test main memory
  16. ;         and in 386 PROTECTED mode to test extended memory.
  17. ;
  18. ;    This program owes some of its features and code to some other
  19. ;    programs and some books (with programs):
  20. ;            - RAMHAM by Clifford A. McCullough
  21. ;            - 80386 A Programming and Design Handbook, 2nd Ed.
  22. ;              by Penn Brumm and Don Brumm
  23. ;            - Dr. Dobb's Toolbook of 80286/80386 Programming
  24. ;              Edited by Phillip Robinson
  25. ;    Finding enough CORRECT information to write this program was a bit
  26. ;    of a problem - much of it was trial and error (plus the usual set
  27. ;    of coding/typing errors -- interesting results when a segment reg
  28. ;    is incorrect in protected mode).
  29. ;
  30. ;    Writing this program was motivated by some memory errors on my
  31. ;    Wave Mate system board.  The bad memory caused a Parity Error
  32. ;    but not until after the system was up (it did not fail the BIOS
  33. ;    memory test).  The error turned out to be a bad 1meg chip which
  34. ;    had a bad section of memory (1 chip, 1 bit, 256k bits).  This program
  35. ;    found the error and when I replaced the chip, I had no more problems.
  36. ;    I hope this may be of use to others.
  37. ;
  38. ;    Note that error handling is VERY PRIMATIVE - the objective was to
  39. ;    find the memory errors in the extended memory, not to create a full
  40. ;    environment for the 386 (although some interrupt handling, etc. is
  41. ;    necessary).  This is NOT a turn-key program and some "fiddling" will
  42. ;    be necessary to get it to work on other systems.
  43. ;
  44. ;    The NMI Parity Error Disable/Enable value may differ.  The port
  45. ;    and values (bit) which indicate a Parity Error may (will) differ -
  46. ;    these were quessed at since they were added AFTER the problem was
  47. ;    fixed.
  48. ;
  49. ;    Some simple run-time options:
  50. ;
  51. ;        -f .. fast mode, very short display pause if error
  52. ;        -x .. skip check for parity error
  53. ;        -a ..  20 cycles of main memory checking
  54. ;        -b .. 100 cycles of main memory checking
  55. ;        -c ..  20 cycles of extended memory checking
  56. ;        -d .. 100 cycles of extended memory checking
  57. ;    default is 10 cycles each
  58. ;
  59. ;    Note that errors or program completion cause the program to
  60. ;    hang in a spin-loop which will require a RESET or the Big-Red-
  61. ;    Switch power cycle to "terminate" (this was simple) so that messages
  62. ;    are left on the video screen.
  63.  
  64. ; Equates
  65.  
  66. Line00    equ    0        ; Video Ram Displacements
  67. Line01    equ    160
  68. Line02    equ    160*2
  69. Line03    equ    160*3
  70. Line04    equ    160*4
  71. Line05    equ    160*5
  72. Line06    equ    160*6
  73. Line07    equ    160*7
  74. Line08    equ    160*8
  75. Line09    equ    160*9
  76. Line10    equ    160*10
  77. Line11    equ    160*11
  78. Line12    equ    160*12
  79. Line13    equ    160*13
  80. Line14    equ    160*14
  81. Line15    equ    160*15
  82. Line16    equ    160*16
  83. Line17    equ    160*17
  84. Line18    equ    160*18
  85. Line19    equ    160*19
  86. Line20    equ    160*20
  87. Line21    equ    160*21
  88. Line22    equ    160*22
  89. Line23    equ    160*23
  90. Line24    equ    160*24
  91. INTa01    equ    021h        ; 8259 Controller #1
  92. INTa02    equ    0A1h        ; 8259 Controller #2
  93.  
  94. Port_a    equ    060h        ; 8042 Port A
  95. Port_b    equ    061h        ; 8042 Port B
  96. Port_c    equ    062h        ; 8042 Port C
  97. Port_Status equ 064h        ; 8042 Status Port
  98.  
  99. Port_Par equ    061h        ; on WaveMate, others use 062h
  100. Bits_Par equ    080h        ; on WaveMate 062h, other use 0C0h on 62h
  101.  
  102. NMIPort equ    070h        ; to disable/enable parity checking
  103. Port_cmos equ    070h        ;
  104.  
  105. bit20_disable    equ    11011101b    ; 8042 function code to degate A20
  106. bit20_enable    equ    11011111b    ; 8042 function code to GATE A20
  107. ; to run protected on AT, need to enable bit20 so 386 controls the
  108. ; address line.
  109.  
  110. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  111. ;; Macros and Structures ;;
  112. ;;;;;;;;;;;;;;;;;;;;;;;;;;;
  113.  
  114. ; Convert 8086 segment register value to a linear address
  115.  
  116. segadr    macro    segr
  117.     sub    eax,eax     ; clear reg
  118.     mov    AX,&segr    ; get the segment reg
  119.     shl    EAX,4        ; convert to a linear addr
  120.     endm
  121.  
  122. ; Convert an 8086 segment to linear addr in a segment descriptor
  123.  
  124. segcvt    macro    segr,segm
  125.     segadr    segr
  126.     mov    segm&.base_l,AX ; get base of data
  127.     shr    EAX,8        ; to AH
  128.     mov    segm&.base_m,AH ; and set mid-range byte
  129.     endm
  130.  
  131. ; Display Message
  132.  
  133. Vtype    macro    msg,len,line
  134.     mov    si,offset msg    ; addr of msg
  135.     mov    cx,len        ; length of message
  136.     mov    di,line     ; offset into screen
  137.     call    Video_Output
  138.     endm
  139.  
  140. ; Define Descriptor Structure
  141.  
  142. desc    struc
  143. limit    dw    0    ; offset to last byte
  144. base_l    dw    0    ; low 16 bits of base addr
  145. base_m    db    0    ; bits 16-23 of base addr
  146. access    db    0    ; access privledges
  147. gran    db    0    ; Granularity and limit
  148. base_h    db    0    ; bits 24-31 of base addr
  149. desc    ends
  150.  
  151. ; Similar to a descriptor, describe the GATE control block
  152.  
  153. gate    struc
  154. addr_l    dw    0    ; Destinations's offset 0...15
  155. select    dw    0    ; Destinations's Segment Selector
  156.     db    0
  157. gate_t    db    8Eh    ; type, DPL
  158. addr_h    dw    0    ; offset 16...31
  159. gate    ends
  160.  
  161. ; Describe the stack of the level 0 interrrupt handler.
  162.  
  163. stkdef    struc
  164. oldip    dw    0    ; 0..15 of EIP
  165.     dw    0
  166. oldcs    dw    0    ; CS
  167.     dw    0
  168. oldfl    dw    0    ; 0..15 of EFLAGS
  169.     dw    0
  170. oldsp    dw    0    ; 0..15 of SP
  171.     dw    0
  172. oldss    dw    0    ; SP
  173.     dw    0
  174. oldes    dw    0    ; ES
  175.     dw    0
  176. oldds    dw    0    ; DS
  177.     dw    0
  178. oldfs    dw    0    ; FS
  179.     dw    0
  180. oldgs    dw    0    ; GS
  181.     dw    0
  182. stkdef    ends
  183.  
  184.  
  185.     .CODE
  186.     assume cs:_text, ds:_text, es:_text, ss:_text
  187.  
  188.     org    80h
  189. command label    byte        ; tail of DOS command line
  190.  
  191.     org    100h        ; this is a COM file
  192. Start:    jmp    Main
  193.  
  194.     ALIGN    4
  195. stack    dw    800h dup(0)
  196. stacke    dw    0,0
  197.  
  198. dtsize    dw    0
  199. dtload    dd    0
  200. dsaddr    dd    0
  201.  
  202. Vram    dw    0b800h        ; real seg of video ram
  203.  
  204. work    dw    0,0,0,0
  205.  
  206. Cycle    dw    0        ; Memory Test Cycles
  207. CycleMm dw    10        ; Max Cycles for a pass Main
  208. CycleEm dw    10        ; Max Cycles for a pass Extended
  209. Errors    dw    0        ; number of errors which occured
  210. LoopCnt dw    0
  211. Pause_Cnt dw    20        ; Error Pause Loop Count
  212. Flag_CheckParity db 1        ;
  213.  
  214.  
  215.     ALIGN    4
  216. MemExtnd label    DWORD
  217. MemOff    dw    0        ; Current Offset
  218. MemSeg    dw    0        ; Current Segment
  219.  
  220. lastPat dw    0
  221.  
  222. Mem_Val db    0
  223. Mem_Pat db    0
  224. Mem_Par db    0,0
  225.  
  226. Msize    dw    0        ; Main memory size
  227. Esize    dw    0        ; Extended memory size
  228.  
  229. Main_S    dw    0        ; Start for main memory
  230. Main_L    dw    0        ; Limit for main memory
  231.  
  232. Extnd_Sw label     WORD
  233. Extnd_S  dd     100000h    ; Extended Memory Start (normal 1M or 100000h)
  234. Extnd_Lw label     WORD
  235. Extnd_L  dd     0        ; Extended Memory Limit
  236.  
  237. savecs    dw    0
  238. savess    dw    0
  239. savesp    dw    0
  240. i8259_1 db    0        ; save int status
  241. i8259_2 db    0        ; save int status
  242.  
  243.  
  244. ; Memory Test Patterns
  245. pattern     db    10110010b    ;par = e, B2
  246.         db    11011001b    ;par = o, D9
  247.         db    01101100b    ;par = e, 6C
  248.         db    10110110b    ;par = o, B6
  249.         db    01011011b    ;par = o, 5B
  250.         db    00101101b    ;par = e, 2D
  251.         db    10010110b    ;par = e, 96
  252.         db    11001011b    ;par = o, CB
  253.         db    01100101b    ;par = e, 65
  254. pattern_len    equ    $-pattern-1
  255.  
  256. msgd1    db    'Main Memory Test Done'
  257. msgd1L    equ    $-msgd1
  258. msgd2    db    'Extended Memory Test Done'
  259. msgd2L    equ    $-msgd2
  260. msgd2o    equ    80
  261. msgd3    db    'All Testing Complete'
  262. msgd3L    equ    $-msgd3
  263.  
  264. Msg1    db    'MemTest (09/04/89)  Main='
  265. Msg1a    db    'xxxxxK/'
  266. Msg1ax    db    'xxxx, Extended='
  267. Msg1b    db    'xxxxxK/'
  268. Msg1bx    db    'xxxx  -f='
  269. Msg1c    db    '  -x='
  270. Msg1d    db    '  '
  271. Msg1Len equ    $-Msg1
  272. Msg2    db    ' *** To Terminate: Reset or BRS -- Re-Boot the System ***'
  273. Msg2Len equ    $-Msg2
  274. MsgTst    db    ' Test'
  275. MsgTstL equ    $-MsgTst
  276. Msg3    db    'Write     Main Segment='
  277. Msg3ao    equ    ($-Msg3)*2
  278. Msg3a    db    'xxxx:0000'
  279. Msg3Len equ    $-Msg3
  280. Msg3Leno equ    ($-Msg3+4)*2
  281. Msg4    db    'Write Extended Segment='
  282. Msg4ao    equ    ($-Msg4)*2
  283. Msg4a    db    'xxxx:'
  284. Msg4b    db    'xxxx'
  285. Msg4Len equ    $-Msg4
  286. Msg4Leno equ    ($-Msg4+4)*2
  287. Msg5    db    '** Error:  Address='
  288. Msg5a    db    'xxxx:'
  289. Msg5b    db    'xxxx    Pattern:'
  290. Msg5c    db    'xx, Memory:'
  291. Msg5d    db    'xx, Parity:'
  292. Msg5e    db    'xx'
  293. msg5Len equ    $-Msg5
  294. Msg7    db    '    Main Memory Test Segment Start='
  295. Msg7a    db    'xxxx       Limit='
  296. Msg7b    db    'xxxx       Max Cycles='
  297. Msg7d    db    'xxxxx'
  298. Msg7Len equ    $-Msg7
  299. Msg8    db    'Extended Memory Test Segment Start='
  300. Msg8a    db    '0010:'
  301. Msg8a2    db    '0000  Limit='
  302. Msg8b    db    'xxxx:'
  303. Msg8c    db    'xxxx  Max Cycles='
  304. Msg8d    db    'xxxxx'
  305. Msg8Len equ    $-Msg8
  306. Msg9    db    'Cycle='
  307. Msg9ao    equ    ($-Msg9)*2
  308. Msg9a    db    'xxxxx, Errors='
  309. Msg9bo    equ    ($-Msg9)*2
  310. Msg9b    db    'xxxxx'
  311. Msg9Len equ    $-Msg9
  312.  
  313. Emsg3    db    'Address Line A20 failed to gate open'
  314. Emsg3L    equ    $-Emsg3
  315.  
  316.  
  317.  
  318.  
  319. ; 386 Protected Mode Tables, etc.
  320.  
  321. ; Define the Global Descriptor Table (GDT)
  322.  
  323.     ALIGN    8
  324. gdt_def LABEL    word
  325. d_gdt    desc    <>    ; first one is a dummy
  326. d_cs    desc    <0ffffh,0,0,10011010b,00001111b,0>    ; Code
  327. s_cs    equ    d_cs-gdt_def
  328. d_ds    desc    <0ffffh,0,0,10010010b,00001111b,0>    ; Data
  329. s_ds    equ    d_ds-gdt_def
  330. d_ss    desc    <0,0,0,10010110b,00000000b,0>        ; Stack
  331. s_ss    equ    d_ss-gdt_def
  332. d_crt    desc    <0fffh,0,0,10010010b,00001111b,0>    ; CRT
  333. s_crt    equ    d_crt-gdt_def
  334. d_mem    desc    <0fffh,0,0,10010010b,10000000b,0>    ; To ref hi memory
  335. s_mem    equ    d_mem-gdt_def
  336. gdt_size equ    $-gdt_def
  337.  
  338. ; Define the Interrupt Descriptor Table (IDT)
  339.  
  340.     ALIGN    8
  341. idt_def LABEL    WORD
  342.     gate    <int00,s_cs,0,8Eh,0>    ; Divide
  343.     .SALL
  344.     gate    <int01,s_cs,0,8Eh,0>    ; Debug
  345.     gate    <int02,s_cs,0,8Eh,0>    ; NMI
  346.     gate    <int03,s_cs,0,8Eh,0>    ; BrkPt
  347.     gate    <int04,s_cs,0,8Eh,0>    ; Overflow
  348.     gate    <int05,s_cs,0,8Eh,0>    ; Bounds
  349.     gate    <int06,s_cs,0,8Eh,0>    ; Invalid Opcode
  350.     gate    <int07,s_cs,0,8Eh,0>    ; CoProcessor Error
  351.     gate    <int08,s_cs,0,8Eh,0>    ; Double Fault
  352.     gate    <int09,s_cs,0,8Eh,0>    ; Coproc Segment Overrun
  353.     gate    <int10,s_cs,0,8Eh,0>    ; Invalid TSS
  354.     gate    <int11,s_cs,0,8Eh,0>    ; Segment Not Present
  355.     gate    <int12,s_cs,0,8Eh,0>    ; Stack Exception
  356.     gate    <int13,s_cs,0,8Eh,0>    ; General Protection
  357.     gate    <int14,s_cs,0,8Eh,0>    ; Page Fault
  358.     gate    <intxx,s_cs,0,8Eh,0>    ;
  359.     gate    <int16,s_cs,0,8Eh,0>    ; Coproc Error
  360.     gate    <intxx,s_cs,0,8Eh,0>    ; 17
  361.     gate    <intxx,s_cs,0,8Eh,0>    ; 18
  362.     gate    <intxx,s_cs,0,8Eh,0>    ; 19
  363.     gate    <intxx,s_cs,0,8Eh,0>    ; 20
  364.     gate    <intxx,s_cs,0,8Eh,0>    ; 21
  365.     gate    <intxx,s_cs,0,8Eh,0>    ; 22
  366.     gate    <intxx,s_cs,0,8Eh,0>    ; 23
  367.     gate    <intxx,s_cs,0,8Eh,0>    ; 24
  368.     gate    <intxx,s_cs,0,8Eh,0>    ; 25
  369.     gate    <intxx,s_cs,0,8Eh,0>    ; 26
  370.     gate    <intxx,s_cs,0,8Eh,0>    ; 27
  371.     gate    <intxx,s_cs,0,8Eh,0>    ; 28
  372.     gate    <intxx,s_cs,0,8Eh,0>    ; 29
  373.     gate    <intxx,s_cs,0,8Eh,0>    ; 30
  374.     gate    <intxx,s_cs,0,8Eh,0>    ; 31
  375.     REPT    224
  376.     gate    <intxx,s_cs,0,8Eh,0>    ; PE Interrupt Gates
  377.     ENDM
  378. idt_size equ    $-idt_def
  379.     .XALL
  380.  
  381. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  382. ;        Entry                            ;
  383. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  384.  
  385. Main    proc    near
  386.     mov    ax,cs        ; init real-mode seg addr
  387.     mov    ss,ax
  388.     mov    ds,ax
  389.     mov    es,ax
  390.     mov    sp,stacke-_text  ; set our stack
  391.  
  392.     mov    ah,00h        ; initialize display
  393.     mov    al,3        ; video mode 3
  394.     int    10h
  395.  
  396.     mov    si,offset command+1    ; process any run-time options
  397.     cld
  398. opt1:    lodsb
  399.     cmp    al,0dh        ; C/R is end
  400.     je    optend
  401.     cmp    al,'-'          ; option marker
  402.     jne    opt1
  403.     lodsb            ; option found, get next char
  404.     or    al,20h        ; fold to lower case
  405.     cmp    al,'f'          ; fast mode?
  406.     jne    short opt2
  407.     mov    pause_cnt,1
  408.     jmp    opt1
  409. opt2:    cmp    al,'x'          ; skip parity check
  410.     jne    short opt3
  411.     mov    flag_CheckParity,0
  412.     jmp    opt1
  413. opt3:    cmp    al,'a'          ; CycleMm=20  Main
  414.     jne    short opt4
  415.     mov    CycleMm,20
  416.     jmp    opt1
  417. opt4:    cmp    al,'b'          ; CycleMm=100 Main
  418.     jne    short opt5
  419.     mov    CycleMm,100
  420.     jmp    opt1
  421. opt5:    cmp    al,'c'          ; CycleEm=10  Extended
  422.     jne    short opt6
  423.     mov    CycleEm,20
  424.     jmp    opt1
  425. opt6:    cmp    al,'d'          ; CycleEm=100 Extended
  426.     jne    short opt7
  427.     mov    CycleEm,100
  428.     jmp    opt1
  429. opt7:
  430.     jmp    opt1
  431. optend: cmp    Pause_cnt,1
  432.     jne    short optend1
  433.     mov    Msg1c,'f'
  434. optend1:cmp    flag_checkparity,0
  435.     jne    short optend2
  436.     mov    Msg1d,'x'
  437. optend2:mov    ax,cycleMm
  438.     mov    bx,offset Msg7d
  439.     call    Convert_Decimal
  440.     mov    ax,cycleEm
  441.     mov    bx,offset Msg8d
  442.     call    Convert_Decimal
  443.  
  444.     int    12h        ; get size of convensional memory
  445.     mov    Msize,ax
  446.     mov    bx,offset Msg1a
  447.     call    Convert_Decimal
  448.     mov    ax,Msize
  449.     mov    bx,offset Msg1ax
  450.     call    Convert_Hex
  451.  
  452.     mov    ah,88h        ; get size of extended memory
  453.     int    15h
  454.     mov    Esize,ax
  455.     mov    bx,offset Msg1b
  456.     call    Convert_Decimal
  457.     mov    ax,Esize
  458.     mov    bx,offset Msg1bx
  459.     call    Convert_Hex
  460.  
  461.     vtype    Msg1,Msg1Len,Line03
  462.  
  463.     mov    Main_S,cs      ; calc start of testing.
  464.     mov    ax,Progend-_text
  465.     add    ax,4020h
  466.     shr    ax,4
  467.     add    ax,Main_S
  468.     and    ax,0fc00h
  469.     mov    Main_S,ax
  470.     mov    bx,offset Msg7a
  471.     call    Convert_Hex
  472.     mov    ax,Msize
  473.     shl    ax,6
  474.     mov    Main_L,ax
  475.     mov    bx,offset Msg7b
  476.     call    Convert_hex
  477.  
  478.     Vtype    Msg7,Msg7Len,Line04    ;    Intro Msg
  479.  
  480.     sub    eax,eax
  481.     mov    ax,Esize     ; setup extended memory
  482.     or    ax,ax
  483.     jz    Main5        ; NO Extended Memory
  484.     add    ax,0400h
  485.     shl    eax,10        ; in K, mpy by 1024 to get megs
  486.     dec    eax        ; limit is minus 1
  487.     mov    Extnd_L,EAX
  488.     mov    ax,Extnd_Lw+2
  489.     mov    bx,offset Msg8b
  490.     call    Convert_Hex
  491.     mov    ax,Extnd_Lw
  492.     mov    bx,offset Msg8c
  493.     call    Convert_Hex
  494.     mov    ax,Extnd_Sw+2
  495.     mov    bx,offset Msg8a
  496.     call    Convert_Hex
  497.     mov    ax,Extnd_Sw
  498.     mov    bx,offset Msg8a2
  499.     call    Convert_Hex
  500.     Vtype    Msg8,Msg8Len,Line05
  501.     Vtype    Msg2,Msg2Len,Line23
  502.  
  503. Main5:
  504.     mov    al,80h        ; disable the NMI interrupt
  505.     out    NMIport,al
  506.  
  507.     call    Check_Main
  508.     mov    ax,Esize
  509.     or    ax,ax
  510.     jz    Done        ; NO Extended Memory
  511.     call    Exec_Prot    ; Yes, enter PE and Check it.
  512.  
  513. Done:
  514.     int    20h        ; for now
  515. Main    endp
  516.  
  517. ; Output a message directly to the screen - bypass any use of the BIOS
  518. ; SI=offset to msg, CX-msglength, DI=offset into screen
  519. Video_Output proc    near
  520.     push    ES
  521.     mov    ah,7        ; video attribute
  522.     mov    ES,Vram     ; video ram segment (addr or selector)
  523.     cld            ; incrementing
  524. Vout1:    lodsb
  525.     stosw
  526.     dec    cx
  527.     jnz    Vout1
  528.     pop    ES
  529.     ret
  530. Video_Output endp
  531.  
  532. ; Convert number in AX to 5 digit decimal/ASCII equivalent into
  533. ; the area (offset) pointed to by BX.
  534. Convert_Decimal proc near
  535.     push    cx
  536.     push    dx
  537.     push    si
  538.     mov    cx,5
  539. Conv1:    mov    byte ptr [BX],' '       ; clear buffer
  540.     inc    bx
  541.     loop    Conv1
  542.     mov    si,10        ; to get digits
  543.     or    ax,ax        ; positive numbers only
  544.     jns    Conv5
  545.     neg    ax
  546. Conv5:    sub    dx,dx
  547.     div    si
  548.     add    dx,'0'
  549.     dec    bx
  550.     mov    [bx],dl
  551.     or    ax,ax        ; done if zero
  552.     jnz    Conv5
  553.     pop    si
  554.     pop    dx
  555.     pop    cx
  556.     ret
  557. Convert_Decimal endp
  558.  
  559. ; Convert number in AL to 2 digit hex/ASCII equivalent into
  560. ; the area (offset) pointed to by BX.
  561. Hexit    proc near
  562.     push    ax
  563.     and    al,0fh
  564.     or    al,30h
  565.     cmp    al,3ah
  566.     jl    Hex_al
  567.     add    al,7
  568. Hex_al: mov    1[bx],al
  569.     pop    ax
  570.     shr    ax,4
  571.     and    al,0fh
  572.     or    al,30h
  573.     cmp    al,3ah
  574.     jl    Hex_ah
  575.     add    al,7
  576. Hex_ah: mov    [bx],al
  577.     ret
  578. Hexit    endp
  579.  
  580. ; Convert number in AX to 4 digit hex/ASCII equivalent into
  581. ; the area (offset) pointed to by BX.
  582. Convert_Hex proc near
  583.     push    bx
  584.     push    ax
  585.     mov    al,ah
  586.     call    Hexit
  587.     pop    ax
  588.     add    bx,2
  589.     call    Hexit
  590.     pop    bx
  591.     ret
  592. Convert_Hex endp
  593.  
  594. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  595. ; Memory bad, report error ;
  596. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  597.  
  598. Bad_Mem proc near
  599.     push    cx
  600.     push    si
  601.     push    di
  602.     push    bx
  603.     mov    ax,Errors
  604.     mov    bx,offset Msg9b
  605.     call    Convert_Decimal
  606.     Vtype    Msg9b,5,Line10+Msg9bo
  607.  
  608.     mov    ax,MemSeg
  609.     mov    bx,offset Msg5a
  610.     call    Convert_Hex
  611.     mov    ax,MemOff
  612.     mov    bx,offset Msg5b
  613.     call    Convert_Hex
  614.     mov    al,Mem_Pat
  615.     mov    bx,offset Msg5c
  616.     call    Hexit
  617.     mov    al,Mem_Val
  618.     mov    bx,offset Msg5d
  619.     call    Hexit
  620.     mov    al,Mem_Par
  621.     mov    bx,offset Msg5e
  622.     call    Hexit
  623.     Vtype    Msg5,Msg5Len,Line14
  624.     mov    bx,pause_cnt           ; pause to display msg
  625. pause1: sub    cx,cx
  626. pause2: dec    cx
  627.     jnz    pause2
  628.     dec    bx
  629.     jnz    pause1
  630.     pop    bx
  631.     pop    di
  632.     pop    si
  633.     pop    cx
  634.     ret
  635. Bad_Mem endp
  636.  
  637. ;;;;;;;;;;;;;;;;;;;;;
  638. ; Check Main Memory ;
  639. ;;;;;;;;;;;;;;;;;;;;;
  640.  
  641. Check_Main proc near
  642.     mov    ax,Main_S      ; setup
  643.     mov    MemSeg,ax
  644.     mov    Cycle,1
  645.     mov    Errors,0
  646.     mov    ax,Errors
  647.     mov    bx,offset Msg9b
  648.     call    Convert_Decimal
  649.  
  650.     Vtype    Msg3,Msg3Len,Line07
  651.     Vtype    Msg9,Msg9Len,Line10
  652.  
  653. Main_Loop:
  654.     mov    ax,Cycle
  655.     mov    bx,offset Msg9a
  656.     call    Convert_Decimal
  657.     Vtype    Msg9a,5,Line10+Msg9ao
  658.  
  659.     mov    ax,LastPat
  660.     dec    ax        ; start at different place each time
  661.     jge    short ml1
  662.     mov    ax,pattern_len
  663. ml1:    mov    LastPat,ax
  664.  
  665.     Vtype    Msg3,MsgTstL,Line07
  666.  
  667.     mov    ax,Main_S      ; re-init for writing
  668.     mov    MemSeg,ax
  669. ; now write data to main memory
  670.     cld
  671.     mov    ax,LastPat
  672.     add    ax,offset pattern
  673.     mov    si,ax
  674.  
  675. wm1:    push    si
  676.     mov    ax,MemSeg
  677.     mov    bx,offset Msg3a
  678.     call    Convert_Hex
  679.     Vtype    Msg3a,4,Line07+Msg3ao
  680.     pop    si
  681.     mov    es,MemSeg      ; point to segment to be written
  682.     mov    cx,1000h    ; 4K block
  683.     sub    di,di        ; start at zero offset
  684. wm5:    lodsb            ; put pattern byte into memory
  685.     mov    es:[di],al
  686.     inc    di
  687.     cmp    si,offset pattern+pattern_len
  688.     jle    short wm6
  689.     mov    si,offset pattern
  690. wm6:    loop    wm5
  691.     mov    ax,MemSeg      ; bump up 4k
  692.     add    ax,0100h
  693.     mov    MemSeg,ax
  694.     add    ax,0ffh
  695.     cmp    ax,Main_L
  696.     jb    wm1
  697.  
  698.     mov    bx,pause_cnt           ; pause to display msg
  699. wm_x1:    sub    cx,cx
  700. wm_x2:    dec    cx
  701.     jnz    wm_x2
  702.     dec    bx
  703.     jnz    wm_x1
  704.     Vtype    MsgTst,MsgTstL,Line07
  705.  
  706.     mov    ax,Main_S      ; re-init for testing
  707.     mov    MemSeg,ax
  708. ; now test the data in main memory
  709.     cld
  710.     mov    ax,LastPat
  711.     add    ax,offset pattern
  712.     mov    si,ax
  713.  
  714. tm1:    push    si
  715.     mov    ax,MemSeg
  716.     mov    bx,offset Msg3a
  717.     call    Convert_Hex
  718.     Vtype    Msg3a,4,Line07+Msg3ao
  719.  
  720.     pop    si
  721.     mov    es,MemSeg      ; point to segment to be tested
  722.     mov    cx,1000h    ; 4K block
  723.     sub    di,di        ; start at zero offset
  724. tm3:    mov    al,es:[di]    ; check pattern byte against memory
  725.     cmp    al,[si]
  726.     jne    tm7        ; bad byte
  727.     mov    Mem_Val,al    ; save if bad parity
  728.     in    al,Port_Par    ; check parity
  729.     test    al,Bits_Par    ; shows parity error
  730.     jnz    tm8
  731. tm4:    inc    si
  732.     inc    di
  733.     cmp    si,offset pattern+pattern_len
  734.     jle    tm6
  735.     mov    si,offset pattern
  736. tm6:    loop    tm3
  737.     jmp    tm9
  738. tm7:    inc    Errors
  739.     mov    MemOff,di
  740.     mov    Mem_Val,al
  741.     in    al,Port_Par
  742.     mov    Mem_Par,al
  743.     mov    al,[si]
  744.     mov    Mem_Pat,al
  745.     call    Bad_Mem        ; display
  746.     jmp    tm4
  747. tm8:    inc    Errors
  748.     mov    MemOff,di
  749.     mov    MemSeg,ES
  750.     mov    Mem_Par,al
  751.     mov    al,[si]
  752.     mov    Mem_Pat,al
  753.     call    Bad_Mem        ; display
  754.     jmp    tm4
  755. tm9:    mov    ax,MemSeg      ; bump up 4k
  756.     add    ax,0100h
  757.     mov    MemSeg,ax
  758.     add    ax,0ffh
  759.     cmp    ax,Main_L
  760.     jb    tm1
  761.  
  762.     mov    bx,pause_cnt           ; pause to display msg
  763. tm_x1:    sub    cx,cx
  764. tm_x2:    dec    cx
  765.     jnz    tm_x2
  766.     dec    bx
  767.     jnz    tm_x1
  768.  
  769.     mov    ax,Main_S      ; re-init
  770.     mov    MemSeg,ax
  771.     mov    ax,Cycle
  772.     inc    ax
  773.     mov    Cycle,ax
  774.     cmp    ax,CycleMm
  775.     jle    Main_loop
  776.     Vtype    msgd1,msgd1L,line21
  777.     Vtype    Msg9,Msg9Len,Line07+Msg3Leno
  778.     ret
  779. Check_Main endp
  780.  
  781. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  782. ;; Initialize and Enter Protected Mode ;;
  783. ;; ... Then call Check_Extended        ;;
  784. ;; ... Finally, return to real mode    ;;
  785. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  786.  
  787.  
  788. Check_Extended proc near
  789.     mov    ax,s_mem    ; init segment
  790.     mov    GS,ax
  791.     mov    Cycle,1
  792.     mov    errors,0
  793.     mov    ax,Errors
  794.     mov    bx,offset Msg9b
  795.     call    Convert_Decimal
  796.  
  797.     Vtype    Msg4,Msg4Len,Line08
  798.     Vtype    Msg9,Msg9Len,Line10
  799.  
  800. ce1:    mov    ax,Cycle
  801.     mov    bx,offset Msg9a
  802.     call    Convert_Decimal
  803.     Vtype    Msg9a,5,Line10+Msg9ao
  804.  
  805.     mov    ax,LastPat
  806.     dec    ax        ; start at different place each time
  807.     jge    short ce2
  808.     mov    ax,pattern_len
  809. ce2:    mov    LastPat,ax
  810.  
  811.     Vtype    Msg4,MsgTstL,Line08
  812.  
  813.     mov    eax,Extnd_S      ; re-init for writing
  814.     mov    MemExtnd,eax
  815.     mov    LoopCnt,0
  816. ; now write the data to memory
  817.     cld
  818.     mov    ax,LastPat
  819.     add    ax,offset pattern
  820.     mov    si,ax
  821. we1:    push    si
  822.     mov    ax,MemSeg
  823.     mov    bx,offset Msg4a
  824.     call    Convert_Hex
  825.     mov    ax,MemOff
  826.     mov    bx,offset Msg4b
  827.     call    Convert_Hex
  828.     Vtype    MSg4a,9,Line08+Msg4ao
  829.     pop    si
  830.     mov    cx,LoopCnt
  831.     mov    edi,MemExtnd     ; start
  832. we5:    lodsb            ; put pattern byte into memory
  833.     mov    gs:[edi],al
  834.     inc    edi
  835.     cmp    si,offset pattern+pattern_len
  836.     jle    short we6
  837.     mov    si,offset pattern
  838. we6:    loop    we5
  839.     mov    MemExtnd,EDI
  840.     cmp    edi,Extnd_L    ; at end?
  841.     jnb    short we_x
  842.     add    edi,10000h
  843.     cmp    edi,Extnd_L    ; at end?
  844.     jb    we1
  845.     mov    edi,Extnd_L
  846.     sub    edi,MemExtnd
  847.     mov    LoopCnt,DI
  848.     jmp    we1
  849.  
  850. we_x:    mov    bx,pause_cnt           ; pause to display msg
  851. we_x1:    sub    cx,cx
  852. we_x2:    dec    cx
  853.     jnz    we_x2
  854.     dec    bx
  855.     jnz    we_x1
  856.     Vtype    MsgTst,MsgTstL,Line08
  857.  
  858.     mov    eax,Extnd_S      ; re-init for testing
  859.     mov    MemExtnd,eax
  860.     mov    LoopCnt,0
  861. ; now test the memory
  862.     cld
  863.     mov    ax,LastPat
  864.     add    ax,offset pattern
  865.     mov    si,ax
  866. te1:    push    si
  867.     mov    ax,MemSeg
  868.     mov    bx,offset Msg4a
  869.     call    Convert_Hex
  870.     mov    ax,MemOff
  871.     mov    bx,offset Msg4b
  872.     call    Convert_Hex
  873.     Vtype    Msg4a,9,Line08+Msg4ao
  874.     pop    si
  875.     mov    cx,LoopCnt
  876.     mov    edi,MemExtnd     ; start
  877. te3:    mov    al,GS:[EDI]    ; check pattern byte against memory
  878.     cmp    al,[si]
  879.     jne    te7        ; bad byte
  880.     cmp    flag_CheckParity,0
  881.     je    short te4
  882.     mov    Mem_Val,al    ; save if bad parity
  883.     in    al,Port_Par    ; check parity
  884.     test    al,Bits_Par    ; shows parity error
  885.     jnz    te8
  886. te4:    inc    si
  887.     inc    edi
  888.     cmp    si,offset pattern+pattern_len
  889.     jle    short te6
  890.     mov    si,offset pattern
  891. te6:    loop    te3
  892.     jmp    te9
  893. te7:    inc    Errors        ; memory did not compare
  894.     mov    Mem_Val,al
  895.     mov    MemExtnd,EDI
  896.     mov    MemExtnd,EDI
  897.     in    al,Port_Par
  898.     mov    Mem_Par,al
  899.     mov    al,[si]
  900.     mov    Mem_Pat,al
  901.     call    Bad_Mem     ; display info
  902.     call    Empty_8042
  903.     jmp    te4
  904. te8:    inc    Errors        ; memory compared but parity error
  905.     mov    MemExtnd,EDI
  906.     mov    MemExtnd,EDI
  907.     mov    Mem_Par,al
  908.     mov    al,[si]
  909.     mov    Mem_Pat,al
  910.     call    Bad_Mem     ; display info
  911.     call    Empty_8042
  912.     jmp    te4
  913. te9:    mov    MemExtnd,edi     ; at end?
  914.     cmp    edi,Extnd_L
  915.     jnb    short te_x
  916.     add    edi,10000h
  917.     cmp    edi,Extnd_L
  918.     jb    te1
  919.     mov    edi,Extnd_L
  920.     sub    edi,MemExtnd
  921.     mov    LoopCnt,DI
  922.     jmp    te1
  923.  
  924. te_x:    push    si
  925.     mov    ax,MemSeg
  926.     mov    bx,offset Msg4a
  927.     call    Convert_Hex
  928.     mov    ax,MemOff
  929.     mov    bx,offset Msg4b
  930.     call    Convert_Hex
  931.     Vtype    Msg4a,9,Line08+Msg4ao
  932.     pop    si
  933.     mov    bx,pause_cnt           ; pause to display msg
  934. te_x1:    sub    cx,cx
  935. te_x2:    dec    cx
  936.     jnz    te_x2
  937.     dec    bx
  938.     jnz    te_x1
  939.  
  940.     mov    eax,Extnd_S      ; re-init
  941.     mov    MemExtnd,eax
  942.     mov    ax,Cycle
  943.     inc    ax
  944.     mov    Cycle,ax
  945.     cmp    ax,CycleEm
  946.     jle    ce1
  947.     Vtype    msgd2,msgd2L,line21+msgd2o
  948.     Vtype    Msg9,Msg9Len,Line08+Msg3Leno
  949.     ret
  950. Check_Extended endp
  951.  
  952. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  953. ;        Interrupt Handlers
  954. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  955.  
  956.  
  957. intspv    equ    1800h        ; base value of interrupt handler stack
  958. intspv1 equ    17e0h        ; if no code on stack
  959. intspv2 equ    intspv1-4    ; if code IS stored
  960. int_rdisp dw    0        ; to check SP
  961. intcod1 dw    0        ; interrupt code word 1
  962. intcod2 dw    0        ; interrupt code word 2
  963.  
  964. xmsg08    db    'Double Fault'
  965. xmsg08l equ    $-xmsg08
  966. xmsg1    db    'Fault '
  967. xmsg1a    db    'xx'
  968. xmsg1l    equ    $-xmsg1
  969.  
  970. ; Interrupt Fault Handlers
  971.  
  972. int00:    mov    cx,0
  973.     mov    si,0
  974.     jmp    int_comm
  975. int01:    mov    cx,1
  976.     mov    si,0
  977.     jmp    int_comm
  978. int02:    mov    cx,2
  979.     mov    si,0
  980.     jmp    int_comm
  981. int03:    mov    cx,3
  982.     mov    si,0
  983.     jmp    int_comm
  984. int04:    mov    cx,4
  985.     mov    si,0
  986.     jmp    int_comm
  987. int05:    mov    cx,5
  988.     mov    si,0
  989.     jmp    int_comm
  990. int06:    mov    cx,6
  991.     mov    si,0
  992.     jmp    int_comm
  993. int07:    mov    cx,7
  994.     mov    si,0
  995.     jmp    int_comm
  996. int08:    mov    cx,8        ; Double Fault
  997.     mov    AX,s_ds     ; get some addressability
  998.     mov    DS,AX
  999.     Vtype    xmsg08,xmsg08l,line02
  1000.     jmp    $        ; SPIN - go no further
  1001. int09:    mov    cx,9
  1002.     mov    si,0
  1003.     jmp    int_comm
  1004. int10:    mov    cx,10
  1005.     mov    si,0
  1006.     jmp    int_comm
  1007. int11:    mov    cx,11
  1008.     mov    si,0
  1009.     jmp    int_comm
  1010. int12:    mov    cx,12
  1011.     mov    si,0
  1012.     jmp    int_comm
  1013. int13:    mov    cx,13
  1014.     mov    si,0
  1015.     jmp    int_comm
  1016. int14:    mov    cx,14
  1017.     mov    si,0
  1018.     jmp    int_comm
  1019. int15:    mov    cx,15
  1020.     mov    si,0
  1021.     jmp    int_comm
  1022. int16:    mov    cx,16
  1023.     mov    si,0
  1024.     jmp    int_comm
  1025.  
  1026. ; Misc Interrupt Handler
  1027.  
  1028. intxx:    mov    cx,255
  1029.     mov    si,0
  1030.     jmp    int_comm
  1031.  
  1032. ; Common routine for handling interrupts
  1033. int_comm:
  1034.     push    AX        ; temp get a reg
  1035.     mov    ax,s_ds     ; to get addressability
  1036.     mov    DS,AX
  1037.     pop    AX
  1038.     pusha            ; save all regs
  1039.     mov    AX,CX
  1040.     mov    BX,offset xmsg1a
  1041.     call    Hexit
  1042.     Vtype    xmsg1,xmsg1l,Line00
  1043.     jmp    $        ; ****DEBUG**** SPIN
  1044.     popa
  1045.     IretD
  1046.  
  1047.  
  1048. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1049. ;
  1050. ; This controls a signal which gates address bit 20.
  1051. ;
  1052. ; The gate A20 signal is an output of the 8042 slave processor.
  1053. ; Address bit 20 should be gated ON before entering protect
  1054. ; mode so that memory is addressed properly (if not, then odd numbered
  1055. ; megs are mapped to the next lowest even numbered meg!!.  When
  1056. ; exiting protect mode (going back to real mode), the address A20
  1057. ; should be gated back off.
  1058. ;
  1059. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1060.  
  1061.  
  1062. Empty_8042 proc near
  1063.     mov    ecx,100000h    ; for timeout (big number)
  1064. empty:    in    al,port_status    ; read the 8042 status port
  1065.     and    al,00000010b    ; test input buffer full flag
  1066.     loopnz    empty        ; loop until empty or timeout
  1067.     ret
  1068. Empty_8042 endp
  1069.  
  1070. Gate_A20 proc near
  1071. ;
  1072. ; On entry, AH contains the code (enable or disable)
  1073. ;
  1074.     call    Empty_8042
  1075.     jnz    short exit_8042 ; yes
  1076.     mov    al,0D1h     ; 8042 command to write output port (I hope)
  1077.     out    port_status,al
  1078.     call    empty_8042
  1079.     jnz    short exit_8042
  1080.     mov    al,ah
  1081.     out    port_a,al    ; output gate signal
  1082.     call    empty_8042
  1083. Exit_8042:
  1084.     ret
  1085. Gate_A20 endp
  1086.  
  1087.  
  1088. Exec_Prot  proc near        ; Setup and switch to PE
  1089.     cld
  1090.     cli
  1091.     mov    savecs,CS
  1092.     mov    savess,SS
  1093.     mov    savesp,SP
  1094.  
  1095. ; First, Enable the A20 line
  1096.     mov    ah,bit20_enable
  1097.     call    gate_a20
  1098.     or    al,al        ; zero if OK
  1099.     jz    A20_ON
  1100.     Vtype    Emsg3,Emsg3L,Line24
  1101.     ret
  1102. A20_ON:
  1103.  
  1104. ; Convert segment regs into linear addresses.
  1105.     mov    ES,Vram
  1106.     segcvt    ES,d_crt
  1107.     mov    Vram,s_crt      ; Protected Mode Video
  1108.     segcvt    CS,d_cs
  1109.     segcvt    DS,d_ds
  1110.     segcvt    SS,d_ss
  1111.  
  1112.  
  1113. ; Setup GDT, IDT, etc. to run protected
  1114.  
  1115.     segadr    DS
  1116.     mov    dsaddr,EAX
  1117.     sub    EBX,EBX
  1118.     lea    EBX,gdt_def
  1119.     add    EBX,EAX
  1120.     mov    dtload,EBX    ; set addr
  1121.     mov    dtsize,gdt_size-1
  1122.     LGDT    FWORD PTR dtsize
  1123.  
  1124.     sub    EBX,EBX
  1125.     lea    EBX,idt_def
  1126.     add    EBX,EAX
  1127.     mov    dtload,EBX    ; set addr
  1128.     mov    dtsize,idt_size-1
  1129.     LIDT    FWORD PTR dtsize
  1130.  
  1131.     mov    EAX,CR0     ; get control reg
  1132.     or    AL,1        ; turn PE on
  1133.     mov    CR0,EAX     ; set it
  1134.     jmp    short @f    ; clear pipeline, etc.
  1135. @@:    nop
  1136.  
  1137.     mov    AX,s_ds     ; and seg regs
  1138.     mov    DS,AX
  1139.     mov    ES,AX
  1140.     mov    FS,AX
  1141.     mov    GS,AX
  1142.     mov    AX,s_ss
  1143.     mov    SS,AX
  1144.     db    0eah        ; do far jump to set CS
  1145.     dw    go_prot_2-_text,s_cs
  1146. go_prot_2:
  1147.  
  1148.     mov    al,80h        ; disable the NMI interrupt
  1149.     out    NMIport,al
  1150.  
  1151.     call    Check_Extended
  1152.  
  1153. ; restore for real mode
  1154.     cld
  1155.     cli
  1156.     mov    EAX,CR0     ; get control reg
  1157.     and    AL,0FEh     ; turn PE off
  1158.     mov    CR0,EAX     ; set it
  1159.     jmp    go_real
  1160. go_real:
  1161.     mov    SS,savess
  1162.     mov    SP,savesp
  1163.     mov    AX,savecs
  1164.     mov    DS,AX
  1165.     mov    ES,AX
  1166.     mov    FS,AX
  1167.     mov    GS,AX
  1168.     mov    Vram,0b800h    ; Restore Real Mode Video
  1169.     Vtype    msgd3,msgd3L,Line22
  1170.     jmp    $        ; SPIN - pending interrupts screwed up,
  1171. ;                     leave video display up rather
  1172. ;                     than re-booting.
  1173.     sti
  1174.     ret
  1175. Exec_Prot  endp
  1176.  
  1177. ProgEnd equ    $
  1178.  
  1179. _text    ends
  1180.     end    start
  1181.