我正在嘗試在匯編中創建一個畫線演算法(更具體地說是 Bresenham 的線演算法)。在嘗試了這個演算法的實作之后,即使我幾乎完全復制了這個 Wikipedia page中的 plotLineLow() 函式,該演算法也無法正常作業。
它應該在 2 個點之間畫一條線,但是當我測驗它時,它會在視窗中的隨機位置繪制點。我真的不知道會出現什么問題,因為在匯編中除錯很困難。
我正在使用 NASM 將程式轉換為二進制檔案,并在 QEMU 中運行該二進制檔案。
[bits 16] ; 16-bit mode
[org 0x7c00] ; memory origin
section .text ; code segmant
global _start ; tells the kernal where to begin the program
_start: ; where to start the program
; main
call cls ; clears the screen
update: ; main loop
mov cx, 0x0101 ; line pos 1
mov bx, 0x0115 ; line pos 2
call line ; draws the line
jmp update ; jumps to the start of the loop
; functions
cls: ; function to clear the screen
mov ah, 0x00 ; set video mode
mov al, 0x03 ; text mode (80x25 16 colours)
int 0x10 ; BIOS interrupt
ret ; returns to where it was called
point: ; function to draw a dot at a certain point (dx)
mov bx, 0x00ff ; clears the bx register and sets color
mov cx, 0x0001 ; clears the cx register and sets print times
mov ah, 0x02 ; set cursor position
int 0x10 ; BIOS interrupt
mov ah, 0x09 ; write character
mov al, ' ' ; character to write
int 0x10 ; BIOS interrupt
ret ; returns to where it was called
line: ; function to draw a line at two points (bx, cx)
push cx ; saves cx for later
push bx ; saves bx for later
sub bh, ch ; gets the value of dx
mov [dx_L], bh ; puts it into dx
sub bl, cl ; gets the value of dy
mov [dy_L], bl ; puts it into dy
mov byte [yi_L], 1 ; puts 1 into yi (positive slope)
cmp byte [dy_L], 0 ; checks if the slope is negative
jl .negative_y ; jumps to the corresponding sub-label
jmp .after_negative_y ; if not, jump to after the if
.negative_y: ; if statement destination
mov byte [yi_L], -1 ; sets yi to -1 (negative slope)
neg byte [dy_L] ; makes dy negative as well
.after_negative_y: ; else statement destination
mov ah, [dy_L] ; moves dy_L into a temporary register
add ah, ah ; multiplies it by 2
sub ah, [dx_L] ; subtracts dx from that
mov [D_L], ah ; moves the value into D
pop bx ; pops bx to take a value off
mov [y_L], bh ; moves the variable into the output
pop cx ; pops the stack back into cx
mov ah, bh ; moves x0 into ah
mov al, ch ; moves x1 into al
.loop_x: ; loop to go through every x iteration
mov dh, ah ; moves the iteration count into dh
mov dl, [y_L] ; moves the y value into dl to be plotted
call point ; calls the point function
cmp byte [D_L], 0 ; compares d to 0
jg .greater_y ; if greater, jumps to the if statement
jmp .else_greater_y ; if less, jumps to the else statement
mov bh, [dy_L] ; moves dy into a temporary register
.greater_y: ; if label
mov bl, [yi_L] ; moves yi into a temporary register
add [y_L], bl ; increments y by the slope
sub bh, [dx_L] ; dy and dx
add bh, bh ; multiplies bh by 2
add [D_L], bh ; adds bh to D
jmp .after_greater_y ; jumps to after the if statement
.else_greater_y: ; else label
add bh, bh ; multiplies bh by 2
add [D_L], bh ; adds bh to D
.after_greater_y: ; after teh if statement
inc ah ; increments the loop variable
cmp ah, al ; checks to see if the loop should end
je .end_loop_x ; if it ended jump to the end of teh loop
jmp .loop_x ; if not, jump back to the start of the loop
.end_loop_x: ; place to send the program when the loop ends
ret ; returns to where it was called
section .data ; data segmant
dx_L: db 0 ; used for drawing lines
dy_L: db 0 ; ^
yi_L: db 0 ; ^
xi_L: db 0 ; ^
D_L: db 0 ; ^
y_L: db 0 ; ^
x_L: db 0 ; ^
section .text ; code segmant
; boot the OS
times 510-($-$$) db 0 ; fills up bootloader space with empty bytess
db 0x55, 0xaa ; defines the bootloader bytes
uj5u.com熱心網友回復:
我看不到視頻模式
您在開始時設定的只是 80x25 文本 VGA 模式(模式 = 3),
cls那么如何渲染點?假設 VGA 或 VESA/VBE,您應該設定您想要的視頻模式,請參見上面的鏈接。為什么要使用 VGA BIOS 進行點渲染?
那將是slooooooooow,我不知道當沒有gfx模式存在時它會做什么。您可以通過直接訪問 VRAM(在段
A000h)來渲染點理想使用 8/16/24/32 位視頻模式,因為它們的像素與 BYTE 對齊......我最喜歡的是 320x200x256c(模式 = 19),因為它適合 64K 段,所以不需要分頁,像素是位元組。如果您使用字符而不是像素,那么您仍然可以像使用段一樣使用對 VRAM 的訪問,
B800h并且字符是 16 位(顏色和 ASCII)。自 80386 以來,整數 DDA 在 x86 CPU 上比 Bresenham 更快
大約 2 年,我沒有在 NASM 中編碼,最接近我在存檔中找到的行是:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; line: pusha ;ax=x0,bx=x1,dl=y0,dh=y1,cl=col push ax ;expecting ES = A000h mov si,bx sub si,ax sub ah,ah mov al,dl mov bx,ax mov al,dh sub ax,bx mov di,ax mov ax,320 sub dh,dh mul dx pop bx add ax,bx mov bp,ax mov ax,1 mov bx,320 cmp si,32768 jb .r0 neg si neg ax .r0: cmp di,32768 jb .r1 neg di neg bx .r1: cmp si,di ja .r2 xchg ax,bx xchg si,di .r2: mov [.ct],si .l0: mov [es:bp],cl add bp,ax sub dx,di jnc .r3 add dx,si add bp,bx .r3: dec word [.ct] jnz .l0 popa ret .ct: dw 0 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;所以你有一些東西要交叉檢查(我花了一段時間在我的檔案中找到它,因為當時我用紋理撰寫了整個 3D 多邊形引擎,所以我在 NASM 中沒有太多 2D 代碼......)
該示例需要 320x200x256c VGA 視頻模式
如果您正在撰寫 DOS
.com檔案,事情會簡單一些:段暫存器都將設定相同,您的代碼/資料在它們的偏移量 100 處。你可以以ret.[BITS 16] [ORG 100h] [SEGMENT .text] ret
As @bitRAKE and @PeterCoders pointed out in case You run this in BOOT SECTOR the org is ok. However in such case there is no OS present so if you were going to do more with the stack or any other block of memory outside your 512 bytes, you'd want to point the stack to somewhere known. (It does start out valid, though, because interrupts are enabled.)
More importantly, you need to initialize DS to match your ORG setting, so ds:org reaches a linear address of 7C00. With org 0x7c00, that means you want DS=0. Otherwise instructions like mov [dx_L], bh would be using memory at some unknown location.
[BITS 16]
[ORG 7C00h]
[SEGMENT .text]
mov ax,0000h
mov ds,ax ; DS=0 to match ORG
mov ss,ax ; if you set SS:SP at all, do it back-to-back
mov sp,7C00h ; so an interrupt can't fire half way through.
; here do your stuff
l0:
hlt ; save power
jmp l0
Hope you are using VC or NC configured as IDE for NASM and not compiling/linking manually
This one is usable in MS-DOS so if you are running BOT SECTOR you out of luck. Still You can create a *.com executable debug and once its working in dos change to BOOT SECTOR...
see Is there a way to link object files for DOS from Linux? on how to setup MS-DOS Volkov commander to automatically compile and link your asm source code just by hitting enter on it ... You can also run it just by adding line to the vc.ext line ... but I prefer not to so you can inspect error log first
Convenient debugging
You can try to use MS-DOS (DOSBox) with ancient Borland Turbo C/C or Pascal and use their inline
asm { .... }code which can be traced and stepped directly in the IDE. However it uses TASM (different syntax to NASM) and have some restrictions ...Sadly I never saw any decent IDE for asm on x86 platform. The best IDE for asm I worked with was Herkules on ZX Spectrum ... was possible to done things even modern C IDEs doesnt have.
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/443213.html
上一篇:6502裝配JMP
