MICE-5103, 萬利出品的 8051 EMULATOR, 解決 Divide Overflow


http://wp.me/ph3BR-KM

 

Divide Overflow, 除法錯誤, 怎樣解決呢? 類似的問題又出現, 所以順道學習一下, 到底編譯程序為何有 BUG, 只要能夠了解成因, 就可以 DIY 解決了

REVIEW:

MICE-5103, 萬利出品的 8051 EMULATOR, http://blog.yahoo.com/xiao-laba/articles/382570

再來套用這個例子, 因為沒有486的PC了, 所以這個程序運行有問題, 2010年曾經寫信詢問這家製造商, 結果是沒有任何回應. 因此也不再寄望他們能夠提供協助, 畢竟是很老的玩具, 他們沒有資源或者忽略這種查詢也是合理的, 不過個人覺得有點那個, 不過呢, 現在哪家製造商不是這樣 !?

486PC沒有, DOS 沒有, DEBUG.EXE 沒有, 1.44 FLOOPY DISK 讀寫不行, 格式化也有問題

現有的工具, NOTEBOOK FUJITSU S6311, 有 DOCKING 提供 COM1, 有 CD-ROM

下載 FREEDOS, gzip, 把 FREEDOS 和 MBUG05 包裝到同一個 可啟動 的 CD IMAGE, 燒成一張 8x 的 CD ROM, 啟動 PC 和 FREEDOS

這樣就可以在 686 PC 上使用 FREEDOS, DEBUG 和 MBUG 都可以運行了

就可以看到到底是哪一行出現 Divide Overflow 同時讓 MBUG 無預警退出 ( 因為運行失敗 )

終於看到了, 是行號 xxxx:0920

nEO_IMG_DSCF3944

.

.

REVERSE ENGINNERING MBUG.exe, 看到反編譯的 ASM CODE, xxxx:0920

seg002:08FD             ; =============== S U B R O U T I N E =======================================
seg002:08FD
seg002:08FD
seg002:08FD             read_ticks_bios_timer_area proc near    ; CODE XREF: seg002:loc_2A4_799p
seg002:08FD B8 40 00                    mov     ax, 40h ; '@'
seg002:0900 8E D8                       mov     ds, ax          ; DS = 40h
seg002:0902                             assume ds:nothing
seg002:0902 BB 6C 00                    mov     bx, 6Ch ; 'l'   ; BX = 6C
seg002:0902                                                     ; 40:6C dword Daily timer counter,
seg002:0902                                                     ; equal to zero at midnight;
seg002:0902                                                     ; incremented by INT 8; read/set by INT 1A
seg002:0902                                                     ; ;---------------[Timer data area]---------------;
seg002:0902                                                     ;         dw      ?               ; 40:6C         ; Ticks since midnite (lo)
seg002:0902                                                     ;         dw      ?               ; 40:6E         ; Ticks since midnite (hi)
seg002:0902                                                     ;         db      ?               ; 40:70         ; Non-zero if new day
seg002:0902                                                     ;
seg002:0902                                                     ;
seg002:0902                                                     ; Read more: http://www.intel-assembler.it/portale
seg002:0902                                                     ; /5/8088-bios-source-code-masm
seg002:0902                                                     ; /8088-bios-source-code-masm.asp#ixzz2Hpwey0dE
seg002:0902                                                     ;
seg002:0905 33 C0                       xor     ax, ax
seg002:0907 33 D2                       xor     dx, dx
seg002:0909
seg002:0909             ticks_1:                                ; load time stamp 1
seg002:0909 8A 2F                       mov     ch, [bx]
seg002:090B
seg002:090B             ticks_2:                                ; CODE XREF: read_ticks_bios_timer_area+12j
seg002:090B 8A 0F                       mov     cl, [bx]        ; load 40:6c
seg002:090D 32 CD                       xor     cl, ch          ; CH = CL, xor CL,CH will be 0
seg002:090F 74 FA                       jz      short ticks_2   ; load 40:6c
seg002:0911
seg002:0911             ticks_3:
seg002:0911 8A 2F                       mov     ch, [bx]
seg002:0913
seg002:0913             count_FFFFxFFFF:                        ; CODE XREF: read_ticks_bios_timer_area+1Ej
seg002:0913 40                          inc     ax
seg002:0914 75 01                       jnz     short ticks_4
seg002:0916 42                          inc     dx
seg002:0917
seg002:0917             ticks_4:                                ; CODE XREF: read_ticks_bios_timer_area+17j
seg002:0917 8A 0F                       mov     cl, [bx]
seg002:0919 32 CD                       xor     cl, ch          ; if time_stamp_c = time_stamp_d, count more
seg002:091B 74 F6                       jz      short count_FFFFxFFFF
seg002:091D
seg002:091D             time_dely_enough:                       ; time_dely_enough, AX = something
seg002:091D B9 40 00                    mov     cx, 40h ; '@'   ; AX = AX / 40
seg002:0920 F7 F1                       div     cx              ; divide overflow bug if 486 above
seg002:0922 0E                          push    cs
seg002:0923 1F                          pop     ds
seg002:0924                             assume ds:seg002
seg002:0924 A3 51 07                    mov     how_many_ticks, ax
seg002:0927 C3                          retn
seg002:0927             read_ticks_bios_timer_area endp

.
.
既然找到了出錯的行號, 當然要試驗一下能不能避開這個錯誤, 讓 MBUG.exe 繼續運行, 不要錯誤


程序如下,

seg002:091D             time_dely_enough:                       ; time_dely_enough, AX = something
seg002:091D B9 40 00                    mov     cx, 40h ; '@'   ; AX = AX / 40
seg002:0920 F7 F1                       div     cx              ; divide overflow bug if 486 above

先用 NOP 的方法, 輸入指令如下:

debug mbug.exe
a 920 [enter]
nop [enter]
nop [enter]
[enter]

u 91d [enter]

看到以下畫面

xxxx:091D B9 40 00                    mov     cx, 40h
xxxx:0920 90                          nop
xxxx:0921 90                          nop
..
..

輸入指令如下, MBUG.EXE 將會全速運行:
g [enter]

不再出現 Divide Overflow, MBUG.EXE 繼續運行, 這個錯誤就解決了. 但是故事還沒完.

所謂 NOP 方法的理解:

原來程序, DIV CX, 占用 2 BYTE, F7, F1, CPU 會執行除法 AX = AX / CX, 但是出錯, 退出運行

seg002:0920 F7 F1 div cx ; divide overflow bug if 486 above

修改後,

xxxx:0920 90                     nop
xxxx:0921 90                     nop

占用 2 BYTE, 90, 90
意思就是 No Operation, CPU 會執行, 但是甚麼都沒有變化, 除了繼續往下執行程序以外
.

.
.
.
雖然證明了 Divide Overflow 是因為這 xxxx:0920 一行引起的, 但是還沒有完全了解他的成因, 只知道, 486DX33 的PC 運行順利, P5 的 PC 就不行了. 所以, 看看這段程序的前文後理, 希望是完全解決玩具的問題. 所以在 DEBUG 的環境裡, 試驗一個替代除法的方法, 右移位法, 果然, 執行完全沒有出現 Divide Overflow 的錯誤, PC 也開始和 MICE-5103 溝通, 因為 MICE-5103 那個 P 字在閃動, 不過, 故事還是很長, 還是無法完成 DOWNLOAD, 這就留到下一次的功課.


原程序如下,

seg002:091D             time_dely_enough:                       ; time_dely_enough, AX = something
seg002:091D B9 40 00                    mov     cx, 40h ; '@'   ; AX = AX / 40h
seg002:0920 F7 F1                       div     cx              ; divide overflow bug if 486 above

右移位的程序如下

seg002:091D             time_dely_enough:                       ; time_dely_enough, AX = something
seg002:091D B1 06                     mov     cl, 6h ; AX = AX >> 6 = AX / 40h
seg002:091F 90                        nop
seg002:0920 D3 E8                     shr ax, cl   ; AX = AX / 40h

那再仔細看看 x86 DIV 的指令解釋吧......解決問題的目標快要到達了.....

Opcode DIV

CPU: i8086+
Type of instruction: User

Instruction: DIV src

Description:
AX = AX / src;

Note: Unsigned division. Divides accumulator (AX) by "src". If divisor
is a byte value, result is put to AL and remainder to AH. If divisor is
a word value, then DX:AX is divided by "src" and result is stored in AX
and remainder is stored in DX.

Flags Affected: AF, CF, OF, PF, SF, ZF
+++++++++++++++++++++++
Clocks (i486):
DIV reg8 16
DIV reg16 24
DIV reg32 40
DIV mem8 16
DIV mem16 24
DIV mem32 40

.

.

REF:

http://www.bioscentral.com/misc/bda.htm#

http://www.z80.eu/freedoscd.html

http://www.gzip.org/#exe

http://biosengineer.blogspot.tw/2008/05/bios-data-area.html

http://www.intel-assembler.it/portale/5/8088-bios-source-code-masm/8088-bios-source-code-masm.asp

http://www.cs.virginia.edu/~evans/cs216/guides/x86.html

http://www.etfos.unios.hr/~jbognar/pozadine/temp/asembly%20tutorial/x86asm/asml1004.html

http://biosengineer.blogspot.tw/2008/05/bios-data-area.html

http://www.freedos.org/download/

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s