@@ -1500,11 +1500,12 @@ BIOS_TOP ENDP
15001500
15011501BYTES_HERE POWER_ON ; 5 BYTES HERE
15021502
1503+
15031504 ASSUME CS :_BIOS , DS :NOTHING , ES :NOTHING , SS :NOTHING
15041505;----------------------------------------------------------------------------;
15051506; F000:E05B: Beginning of boot execution
15061507;----------------------------------------------------------------------------;
1507- ; Loosely follow these publicly-available specs for BIOS POST operations:
1508+ ; Loosely follow these specs for BIOS POST operations:
15081509;
15091510; http://minuszerodegrees.net/5160/post/5160%20-%20POST%20-%20Detailed%20breakdown.htm
15101511; http://minuszerodegrees.net/5150/post/5150%20-%20POST%20-%20Detailed%20breakdown.htm
@@ -1531,22 +1532,15 @@ POWER_ON PROC NEAR
15311532 CLI ; disable CPU interrupts
15321533 CLD ; clear direction flag
15331534
1534- ;----------------------------------------------------------------------------;
1535- ; Disable non-maskable interrupts (NMIs) from reaching the CPU.
1536- ;----------------------------------------------------------------------------;
1537- DISABLE_NMI:
1538- XOR AX , AX
1539- OUT NMI_R0 , AL ; write AL = 0 to NMI register port
1540-
15411535;----------------------------------------------------------------------------;
15421536; POST Hardware/System Tests
15431537;----------------------------------------------------------------------------;
15441538
15451539POST_CPU_TEST:
15461540;----------------------------------------------------------------------------;
1547- ; 1 - A "very thorough" test of the CPU Registers
1541+ ; [1] Test and clear all CPU Registers
15481542;----------------------------------------------------------------------------;
1549- ; Check and clear all registers
1543+ ; Check and set all registers to 0.
15501544;
15511545; On Failure: 1 long beep and 2 short beeps
15521546;----------------------------------------------------------------------------;
@@ -1566,11 +1560,17 @@ CPU_REG_TEST:
15661560 MOV BL , 21H ; on Failure: 2 short and 1 long beep
15671561 JNZ HALT_ERROR
15681562 XOR AX , AX ; otherwise repeat with AX = 0
1569- JNZ HALT_ERROR ; if ZF was not set, you're in trouble
1563+ JNZ HALT_ERROR ; if ZF was not set, it's not good
15701564 TEST DX , DX ; if zero it was second pass
15711565 JNZ CPU_REG_TEST ; Loop again to zero all registers
15721566CPU_REG_PASS:
15731567
1568+ ;----------------------------------------------------------------------------;
1569+ ; Disable non-maskable interrupts (NMIs)
1570+ ;----------------------------------------------------------------------------;
1571+ DISABLE_NMI:
1572+ OUT NMI_R0 , AL ; write AL = 0 to NMI register port
1573+
15741574;----------------------------------------------------------------------------;
15751575; [1B] A brief test of flags and CPU instructions
15761576;----------------------------------------------------------------------------;
@@ -1666,6 +1666,7 @@ RESET_PPI:
16661666;----------------------------------------------------------------------------;
16671667; [8] Checksum (8 bit) the main ROM to ensure it is not corrupt
16681668;----------------------------------------------------------------------------;
1669+ ; Input: AH = 0, DX = 0F000h
16691670; On Failure: 2 long beep and 2 short beeps
16701671;----------------------------------------------------------------------------;
16711672 JWB CHECKSUM_OK ; skip on warm boot
@@ -1674,11 +1675,11 @@ CHECKSUM_ROM:
16741675 MOV DS , DX ; DS to 0F000h BIOS segment
16751676 MOV SI , OFFSET BIOS_TOP ; offset to top of BIOS ROM
16761677 MOV CH , 10H ; checksum 8KB (in 2 byte words)
1677- XOR BX , BX ; BL = accumulator for sum
1678+ CWD ; DL = accumulator for sum, DH = 0
16781679CHECKSUM:
16791680 LODSW ; next two bytes into AL and AH
1680- ADD BL , AL
1681- ADD BL , AH ; ZF if sum is 0
1681+ ADD DL , AL
1682+ ADD DL , AH ; ZF if sum is 0
16821683 LOOP CHECKSUM ; loop through entire ROM
16831684 MOV BL , 22H ; on failure, 2 short and 2 long beeps
16841685 JNZ HALT_ERROR ; if sum not 0, fail
@@ -1692,17 +1693,6 @@ INIT_DMA1:
16921693 MOV AL , 00000100B ; Set Controller Disable bit
16931694 OUT DMA_CMD , AL ; write to DMA Command Register
16941695
1695- ;----------------------------------------------------------------------------;
1696- ; [9B] 8253 PIT Programmable Interval Timer Initialization Channel 1
1697- ;----------------------------------------------------------------------------;
1698- ; Counter 1 - DRAM Refresh
1699- ;----------------------------------------------------------------------------;
1700- INIT_PIT1:
1701- MOV AL , 01010100B ; Control Word: Counter 1
1702- ; Format: R/W low byte
1703- ; Mode: 2 Rate Gen, BCD: 0
1704- OUT PIT_CTRL , AL ; set Counter mode
1705-
17061696 IF POST_TEST_PIT_1 EQ 1
17071697;----------------------------------------------------------------------------;
17081698; [10] Test Channel #1 on 8253 timer chip.
@@ -1711,21 +1701,40 @@ INIT_PIT1:
17111701; If the test fails, beep failure code
17121702;
17131703; Test that all data lines are working by reading counter and checking
1714- ; that all bits from counter go both high and low. The result should
1715- ; be the opposite of the starting value.
1704+ ; that all bits from counter go both high and low.
17161705;----------------------------------------------------------------------------;
1717- MOV AL , 0
1718- MOV DX , 0FFH ; high byte is all 0's, low is all 1's
1719- OUT PIT_CH1 , AL
1706+ ; Use 16-bit mode to test low three address lines using high byte of counter.
1707+ ; This avoids a situation where the read counter code is a binary multiple
1708+ ; of the counter causing a bit to not be observed as changing.
1709+ ;
1710+ ; Control Word Counter 1 (port 43H) - System Timer:
1711+ ; 01 - SC: Select Counter 1
1712+ ; 11 - RW: Read/Write 2xR/2xW
1713+ ; 010 - M: Mode 2, Rate Gen
1714+ ; 0 - BCD: 0
1715+ ;
1716+ MOV AL , 01110100B ; Control Word: Counter 1
1717+ ; Format: R/W low/high byte
1718+ ; Mode: 2 Rate Gen, BCD: 0
1719+ OUT PIT_CTRL , AL ; set Counter mode
1720+ MOV DX , LOW PIT_CH1 ; DX = PIT channel 1
1721+ OUT DX , AL ; set low byte (any value)
1722+ MOV SI , 0FFH SHL 3 ; look at bits 10-3 for 1 check
1723+ MOV DI , NOT 0FFH SHL 3 ; look at bits 10-3 for 0 check
1724+ OUT DX , AL ; set high byte (any value)
17201725INIT_PIT1_TEST:
1726+ CMP SI , 0FFFFH ; have all bits flipped to 1?
1727+ JNZ INIT_PIT1_TEST_READ
1728+ TEST DI , DI ; have all bits flipped to 0?
1729+ JZ INIT_PIT1_TEST_DONE
1730+ INIT_PIT1_TEST_READ:
17211731 MOV AL , 01000000b ; latch Counter 1 command
17221732 OUT PIT_CTRL , AL ; write command to CTC
1723- CMP DX , NOT 0FFH ; have all bits flipped?
1724- JZ INIT_PIT1_TEST_DONE
1725- IO_DELAY_SHORT ; I/O delay
1726- IN AL , PIT_CH1 ; read timer counter
1727- AND DL , AL ; clear all lines received on low byte
1728- OR DH , AL ; set all lines received on high byte
1733+ IN AL , DX ; read timer LSB
1734+ XCHG AH , AL ; save LSB
1735+ IN AL , DX ; read timer MSB
1736+ AND DI , AX ; clear all lines received as 0
1737+ OR SI , AX ; set all lines received as 1
17291738 LOOP INIT_PIT1_TEST ; loop until timeout
17301739 MOV BL , 32H ; beep pattern (3 short, 2 long)
17311740HALT_ERROR:
@@ -1739,6 +1748,17 @@ HALT_ERROR:
17391748
17401749INIT_PIT1_TEST_DONE:
17411750
1751+ ;----------------------------------------------------------------------------;
1752+ ; [9B] 8253 PIT Programmable Interval Timer Initialization Channel 1
1753+ ;----------------------------------------------------------------------------;
1754+ ; Counter 1 - DRAM Refresh
1755+ ;----------------------------------------------------------------------------;
1756+ INIT_PIT1:
1757+ MOV AL , 01010100B ; Control Word: Counter 1
1758+ ; Format: R/W low byte
1759+ ; Mode: 2 Rate Gen, BCD: 0
1760+ OUT PIT_CTRL , AL ; set Counter mode
1761+
17421762;----------------------------------------------------------------------------;
17431763; [12] Reset, Clear and test DMA Offset and Block Size Registers
17441764;----------------------------------------------------------------------------;
@@ -1750,7 +1770,7 @@ INIT_PIT1_TEST_DONE:
17501770 IF POST_TEST_DMA EQ 1
17511771 MOV BH , 8 ; test 8 ports
17521772 XOR DX , DX ; starting at port 00H
1753- CALL_NS WB_TEST ; ZF if pass, NZ if failed
1773+ CALL_NS WB_TEST ; ZF and CX = 0 if pass, NZ if failed
17541774 MOV BL , 42H ; beep pattern (4 short, 2 long)
17551775 JNZ HALT_ERROR
17561776DMA_PASS:
@@ -1765,9 +1785,8 @@ DMA_PASS:
17651785;----------------------------------------------------------------------------;
17661786 MOV AL , 0FFH ; Memory refresh counter (16-bit) is 0FFFFH
17671787 OUT DMA_0_C , AL ; write low order bits
1768- IO_DELAY_SHORT
1788+ NOP ; very short I/O delay
17691789 OUT DMA_0_C , AL ; write high order bits
1770- ;IO_DELAY_SHORT ; necessary?
17711790
17721791;----------------------------------------------------------------------------;
17731792; [13] Set Mode DMA Channel 0
@@ -1780,25 +1799,21 @@ DMA_PASS:
17801799;----------------------------------------------------------------------------;
17811800 MOV AL , 01011000B ; see above
17821801 OUT DMA_MODE , AL ; write to DMA Mode Register
1783- IO_DELAY_SHORT
17841802
17851803;----------------------------------------------------------------------------;
17861804; [13B] 8253 Timer set channel #1 for DMA/DRAM refresh
17871805;----------------------------------------------------------------------------;
17881806 MOV AL , 18 ; divisor: 1.19318 MHz / 18 = 66,287.7 Hz
17891807 OUT PIT_CH1 , AL ; refresh DRAM every 2ms
1790- ;IO_DELAY_SHORT
17911808 ENDIF
17921809
17931810;----------------------------------------------------------------------------;
17941811; [13C] Enable DMA and clear mask register on Channels 0-3
17951812;----------------------------------------------------------------------------;
17961813 MOV AL , 0 ; Set Controller Enable bit
17971814 OUT DMA_CMD , AL ; write to DMA Command Register
1798- IO_DELAY_SHORT ; necessary?
1799-
1815+ MOV CL , 3 ; Set mode on Channels 1-3 for [13D]
18001816 OUT DMA_MASK , AL ; clear mask (enable) on all channels
1801- ;IO_DELAY_SHORT
18021817
18031818;----------------------------------------------------------------------------;
18041819; [13D] Set default Mode for DMA Channels 1-3
@@ -1808,9 +1823,10 @@ DMA_PASS:
18081823; 0 ; No Auto-initialization
18091824; 00 ; type: Verify
18101825; xx ; Channels 1-3
1826+ ;
1827+ ; Input: CL = 3 from [13C], CH = 0 from CALL_NS in [12]
18111828;----------------------------------------------------------------------------;
18121829 MOV AL , 01000001B ; AL = 01000001
1813- MOV CL , 3 ; Set mode on Channels 1-3
18141830DMA_SETUP_CH:
18151831 OUT DMA_MODE , AL ; write to DMA Mode Register
18161832 INC AX ; next channel
@@ -1848,14 +1864,16 @@ DMA_SETUP_CH:
18481864; On failure:
18491865; - Read/Write Error: 1 short, 3 long beeps
18501866; - Parity Error: 1 short, 4 long beeps
1867+ ;
1868+ ; Input: CX = 0 from [13D]
18511869;----------------------------------------------------------------------------;
18521870 ASSUME DS :_BDA_ABS , ES :_IVT
18531871BASE_RAM_TEST:
18541872 IN AL , PPI_B ; AL = PB0 flags
18551873 OR AL , MASK PBIO OR MASK PBPC ; disable RAM parity and I/O ch. flags
18561874 OUT PPI_B , AL
1857- XOR AX , AX ; DS and ES = IVT segment 0000
1858- MOV DS , AX
1875+ XCHG AX , CX ; AX = 0 = MEM_CHECK pattern and
1876+ MOV DS , AX ; DS and ES = IVT segment 0000
18591877 MOV ES , AX
18601878 MOV SI , OFFSET WARM_FLAG_ABS ; preserve warm boot flag
18611879 MOV DX , WORD PTR [ SI ] ; save warm boot flag
@@ -1875,8 +1893,7 @@ HALT_BEEP_1:
18751893BASE_RAM_ZERO:
18761894 MOV AX , RAM_TEST ; test pattern
18771895 CALL_NS MEM_CHECK ; write and verify test pattern
1878- JNZ BASE_RAM_ERROR
1879- XOR AX , AX ; zero
1896+ JNZ BASE_RAM_ERROR ; ZF and AX = 0 if okay
18801897 CALL_NS MEM_CHECK ; write and verify zeros
18811898 JNZ BASE_RAM_ERROR
18821899 MOV WORD PTR [ SI ], DX ; restore warm boot flag
@@ -1904,8 +1921,7 @@ BASE_RAM_TEST_DONE:
19041921 ASSUME SS :_BOOT_STACK
19051922 MOV AX , SEG STACK_TOP ; SP to temp boot stack 0030:0100
19061923 MOV SS , AX
1907- MOV AX , OFFSET STACK_TOP
1908- MOV SP , AX
1924+ MOV SP , OFFSET STACK_TOP
19091925
19101926;----------------------------------------------------------------------------;
19111927; [19] 8259A PIC Interrupt controller Initialization
@@ -1938,7 +1954,7 @@ BASE_RAM_TEST_DONE:
19381954 INC DX ; DX = PIC Port 1
19391955 MOV AL , 00001000B ; ICW2 - Port 1
19401956 OUT DX , AL
1941- NOP ; short delay
1957+ MOV BH , 1 ; short delay and test 1 port for [22]
19421958 MOV AL , 00001001B ; ICW4 - Port 1
19431959 OUT DX , AL
19441960
@@ -1948,14 +1964,13 @@ BASE_RAM_TEST_DONE:
19481964;----------------------------------------------------------------------------;
19491965; - Read and write registers (IMR) and verify result
19501966;----------------------------------------------------------------------------;
1951- MOV BH , 1 ; test 1 port
19521967 CALL WB_TEST ; walking bit test of PIC IMR register
19531968 MOV BL , 52H ; beep error 5 short, 2 long
19541969 JZ PIC_REG_PASS
19551970PIC_INT_FAIL:
19561971 JMP SHORT HALT_BEEP_1
19571972PIC_REG_PASS:
1958- DEC DX ; DX = Port 1 (21h )
1973+ DEC DX ; DX = Port 1 (0021h )
19591974 ELSE
19601975 NOP
19611976 ENDIF ; IF POST_TEST_PIC_REG EQ 1
@@ -1981,7 +1996,7 @@ PIC_VECT_TMP_LOOP:
19811996; - Mask all interrupts and ensure none are received
19821997;
19831998 MOV DI , OFFSET INT_LAST_ABS
1984- MOV [ DI ], DH ; clear last interrupt flag
1999+ MOV [ DI ], DH ; clear last interrupt flag (DH = 0)
19852000 STI ; enable interrupts
19862001 IO_DELAY ; wait for it...
19872002 CLI
@@ -1994,9 +2009,11 @@ PIC_VECT_TMP_LOOP:
19942009 JZ PIC_INT_PASS
19952010 JMP SHORT HALT_BEEP_1
19962011 ENDIF ; IF POST_TEST_PIC_REG EQ 1
1997-
19982012 ENDIF ; IF POST_TEST_PIC_INT EQ 1
19992013
2014+ MOV AL , 11111110B ; OCW1 - unmask timer
2015+ OUT DX , AL ; write IMR to PIC
2016+
20002017PIC_INT_PASS:
20012018
20022019;----------------------------------------------------------------------------;
@@ -2263,12 +2280,12 @@ VID_MODE_OK:
22632280; Clear screen and reset the video display.
22642281;
22652282RESET_VIDEO:
2266- XOR AH , AH ; AH = 0 - Set Video Mode in AL
2283+ CBW ; AH = 0 - Set Video Mode in AL
22672284 INT 10H
22682285RESET_VIDEO_DONE:
22692286
22702287;----------------------------------------------------------------------------;
2271- ; Hello Computer (just use the keyboard)
2288+ ; Hello Computer (" just use the keyboard" )
22722289;----------------------------------------------------------------------------;
22732290HELLO_WORLD:
22742291 PRINTLN_SZ VER_BANNER ; display banner
@@ -2292,7 +2309,7 @@ HELLO_WORLD:
22922309 PRINT_SZ VER ; display version
22932310 PRINT_SZ REL_DATE ; display build date
22942311 POP DX ; restore previous cursor
2295- MOV AH , 2 ; reset cursor position
2312+ MOV AH , 2 ; reset cursor position
22962313 INT 10H ; row = DH, column = DL
22972314 ELSE
22982315 PRINT_SZ VER ; display version
@@ -3799,7 +3816,7 @@ MEM_ADDR_TEST ENDP
37993816;
38003817; Clobbers AX, CX, DI
38013818;
3802- ; ZF if okay, NZ if fail
3819+ ; ZF and AX = 0 if okay, NZ if fail
38033820;----------------------------------------------------------------------------;
38043821MEM_TEST PROC
38053822 MOV AX , RAM_TEST ; test pattern
@@ -3813,7 +3830,7 @@ MEM_TEST PROC
38133830; AX = pattern to write
38143831; ES = segment for test
38153832;
3816- ; ZF if okay, NZ if fail
3833+ ; ZF and AX = 0 if okay, NZ if fail
38173834;----------------------------------------------------------------------------;
38183835MEM_CHECK:
38193836 MOV CX , 02000H ; loop 2000H WORDs
@@ -3823,6 +3840,7 @@ MEM_TEST_VERIFY:
38233840 MOV CH , 20H ; restart loop 2000H
38243841 XOR DI , DI ; start at offset 0
38253842 REPZ SCASW ; loop until CX = 0 OR WORD is not AX
3843+ XCHG AX , CX ; AX = 0 if success
38263844 RET
38273845MEM_TEST ENDP
38283846
@@ -6015,6 +6033,7 @@ INT_10_IS_CGA80 PROC
60156033INT_10_IS_CGA80_DONE:
60166034 POP DS
60176035 POP AX
6036+ INT_10_0_RET:
60186037 RET
60196038INT_10_IS_CGA80 ENDP
60206039
@@ -6083,7 +6102,7 @@ INT_1D ENDP
60836102;----------------------------------------------------------------------------;
60846103INT_10_0 PROC
60856104 CMP AL , 7 ; is new video page > 7?
6086- JA INT_10_DONE ; if so, not valid, return
6105+ JA INT_10_0_RET ; if so, not valid, return
60876106 PUSH AX
60886107 PUSH BX
60896108 PUSH DX
@@ -7835,6 +7854,7 @@ OUT_SZ ENDP
78357854; BH = number of sequential ports to test
78367855; Output:
78377856; NZ if failed
7857+ ; CX = 0 if success
78387858;
78397859; Adapted from:
78407860; https://barrgroup.com/embedded-systems/how-to/memory-test-suite-c
0 commit comments