2014-07-06 15 views
1

我正在尋找示例如何使用協處理器計算正弦。 我發現功能:彙編計算正弦例子。 nasm 16 dos

CalcSin 
     fld  long [angle]   ; st(0) = angle 
     fsin       ; st(0) = sin(angle) (angle is in radians) 
     fstp long [SinX]    ; SinX = sin(angle) 

我想畫正弦和我需要的Y ax和X在bx。 X將是沒有問題的,因爲我會做循環,但是對於Y我有一個問題。 X將從示例0到350(如像素)。 如果例如sin(30度)是1/2,如何計算它並使像素爲Y. 如何將結果放在一起以獲得良好的座標?


編輯: 我很抱歉,但我當我運行代碼,它讓我沒有竇,但2號線。我不知道我做錯了什麼,現在

segment .data 

    segment .code 
..start: 
    mov ax, 13h 
    int 10h    ; switch to 320x200 mode 

    mov ax, 0a000h  ; The offset to video memory 
    mov es, ax   ; We load it to ES through AX, 
          ; because immediate operation 
          ; is not allowed on ES 

;;;;;;;;;;;;;;;;;;;;;; 

DrawWave: 
    mov ebx, y ; EBX = &y 
    mov ecx, 0 

    ; let st(1) = 2*PI/640 
    fldpi    ; st(0) = PI 
    fidiv dword [step] ; st(0)/160 = 0.009817... 
    fldz    ; st(0) = 0.0, st(1) = 0.00045... 

    .loop: 
     fld st0 ; duplicate the x on the top 
     fsin  ; st(0) = sin x 

     fimul dword [imgHeight]  ; st(0) = y*240 
     fiadd dword [imgHeight]  ; eliminate negative coordinate by translating the wave vertically   
     fistp dword [y]    ; store y to ´y´ 

     fadd st0, st1   ; add the step value to x, doing the step 

     ;draw pixel at [*EAX:ECX] 
     push ax 
     push bx 
     push cx 
     call DrawPixel 
     pop cx 
     pop bx 
     pop ax 

     inc ecx 
     cmp ecx, 320 ; perform 640 steps to draw a single sine wave 
     jl .loop 

     fstp st0 ;clean up 
     fstp st0 ;clean up 
    ret 

;;;;;;;;;;;;;;;;;;;;;;;;; 

    xor ah, ah 
    int 16h    ; keyboard (wait for key) 

    mov ax, 3 
    int 10h    ; go to text mode 

    mov ax, 4c00h 
    int 21h    ; return to DOS, exit code 0 

;;;;;;;;;;;;;;;;;;;;; 

; EBX = in &CoordY 
; ECX = CoordX 
;DrawPixel: 
    ; draw a pixel at [*EBX:ECX] 
; ret 
DrawPixel: 
    push dx    ; mul changes dx too 
    mov ax, cx   ; ax is X coord copy from cx 
    mov cx, 320 
    mul cx    ; multiply Y (ax) by 320 (one row) 
    add ax, bx   ; and add X (bx) (result= dx:ax) 
    mov di, ax 
    pop dx 
    mov dl, 4 
    mov [es:di], dl  ; store color/pixel 
    ret 

    ;CONSTANTS: 

step: dw 160  ; 2/320 = 160 
imgWidth: dw 320 ; 320px 
imgHeight: dw 200/2 ; 200px on half, because Y also gets negative 
;VARIABLES: 
x: dw 0  ; a tmp place to save X 
y: dw 0  ; a tmp place to save Y 
+0

'我要畫正弦' - 你是什麼意思?正弦波? – user35443

+0

是的。這將是後來的正弦波動畫。但我想從正弦波 – kkkkk

+0

開始我正在研究我的答案。 – user35443

回答

1

如果我理解你正確,你想畫沒有任何的平移和縮放正弦波。因此,您可以將angle作爲X座標,並且從函數f(x) = sin x獲得的值是您的Y座標。

; EAX = in &CooordX 
; EBX = out &CoordY 
SinX: 
    fld  qword [eax]   ; st(0) = angle 
    fsin       ; st(0) = sin(angle) 
    fstp qword [ebx]   ; *ebx = sin(angle) 
    ret 

現在讓我們假設你想繪製一個波。這意味着x == 2*PI rad(全波)在繪製最後一個像素時必須準確無誤。對於640像素寬的屏幕,繪製循環中的x的單步是2*PI/640 = 0.009817。其餘的很簡單。

;CONSTANTS: 
step: dw 320  ; 2/640 = 320, omitted PI 
imgWidth: dw 640 ; 640px 
imgHeight: dw 480/2 ; 480px on half, because Y also gets negative 

;VARIABLES: 
y: dw 0  ; a tmp place to save Y 

DrawWave: 
    mov ebx, y ; EBX = &y 
    mov ecx, 0 

    ; let st(1) = 2*PI/640 
    fldpi    ; st(0) = PI 
    fidiv dword [step] ; st(0)/320 = 0.009817... 
    fldz    ; st(0) = 0.0, st(1) = 0.009817... 

    .loop: 
     fld st(0) ; duplicate the x on the top 
     fsin  ; st(0) = sin x 

     fimul dword [imgHeight]  ; st(0) = y*240 
     fiadd dword [imgHeight]  ; eliminate negative coordinate by translating the wave vertically   
     fistp dword [y]    ; store y to ´y´ 

     fadd st(0), st(1)   ; add the step value to x, doing the step 

     ;draw pixel at [*EAX:ECX] 
     call DrawPixel 

     inc ecx 
     cmp ecx, 640 ; perform 640 steps to draw a single sine wave 
     jl .loop 

     fstp st(0) ;clean up 
     fstp st(0) ;clean up 
    ret 

; EBX = in &CoordY 
; ECX = CoordX 
DrawPixel: 
    ; draw a pixel at [*EBX:ECX] 
    ret 
+0

我已編輯我的問題。我看不到任何結果。我使用NASM 16 DOS和模式320x200 – kkkkk

+0

這只是一種繪製正弦波的算法,不適用於繪製實際像素。您必須編輯'DrawPixel'以在被調用時在指定位置顯示像素。 – user35443

+0

我以爲X和Y在; EBX = Y ; ECX = X所以我寫程序來顯示像素(我之前使用這個),結束所有的程序我後來改變了16位 – kkkkk

0

我的兩美分;-)。 X是度數,Y是縮放的(* 50)正弦輻射。 (隱藏),X軸是在行100

segment stack stack 
    resb 0x1000 

segment .data 
    ; no data 

segment .code 
..start: 
main: 
    mov ax, data   ; Initialize DS (needed for .exe-program) 
    mov ds, ax 
    mov ax, 0x0A000   ; Segment to video memory 
    mov es, ax 

    mov ax, 13h 
    int 10h     ; switch to 320x200 mode 

    mov cx, 0 
    .l1: 
    push cx     ; store CX 
    call get_sine 
    add ax, 100    ; shift Y to position of X-axis (100) 
    mov bx, cx 
    call vector_to_memory 
    mov di, ax 
    mov al, 0x0F   ; white 
    mov [es:di], al   ; put pixel 
    pop cx     ; restore CX 
    inc cx     ; CX = CX + 1 
    cmp cx, 320    ; right boarder reached? 
    jne .l1     ; no, next degree 

    xor ah, ah 
    int 16h     ; keyboard (wait for key) 
    mov ax, 3 
    int 10h     ; go to text mode 
    mov ax, 0x4C00 
    int 21h     ; return to DOS, exit code 0 

get_sine:     ; Args: CX = angle (degree!) 
    push cx     ; = sub sp, 2 (local stack space), mov [sp], cx 
    mov bp, sp    ; BP = SP (local stack space) for FPU-accesses 
    fild word [bp]   ; ST(0): CX 
    fldpi     ; ST(0)=Pi, ST(1)=CX 
    fmulp     ; ST(0)=Pi*CX 
    mov word [bp], 180 
    fidiv word [bp]   ; ST(0)=(Pi*CX)/180 (formula for degree to rad) 
    fsin     ; ST(0)=sine (rad) 
    mov word [bp], 50  ; Scale the result by 50 (e.g. 0.8 => 40.0) 
    fimul word [bp]   ; ST(0)=sine*scale 
    fchs     ; reverse sign because video counts from top to bottom 
    fistp word [bp]   ; store integer with rounding to local stack space 
    pop ax     ; AX = local stack space 
    ret      ; Return: AX = Y (signed!) 

vector_to_memory:   ; Args: BX = X, AX = Y 
    push dx     ; mul changes dx too 
    mov cx, 320    ; video mode width 
    mul cx     ; DX:AX = AX * CX 
    add ax, bx    ; left indentation 
    pop dx 
    ret      ; Return: AX = offset in memory 
0

另一種方法是創建和使用自己的正弦/餘弦表,我們只能存儲一個時間到文件和裝載和使用它多次。以下示例顯示如何創建自己的正弦/餘弦表。

 Grad = 360 
     Endtab = 450 

segment .data 

SINTAB DB Endtab DUP (?,?,?,?) 

TEIL DW 180, ? 
I  DW 0, 0 

TABNAM DB "Sin.tab" 

segment .code 

START: mov  ax, data 
      mov  ds, ax 
      finit 
      call TABLE 
      mov  dx, TABNAM 
      call MAKDAT 
      xor  dx, dx 
      mov  cx, Endtab*4 
      call WRITE 
      call CLOSE 
      mov  ax, 4C00h 
      int 21h 

TABLE: xor  di, di   ; Create sine table 
TAB:  fldpi 
      fimul DWORD[I] 
      fidiv DWORD[TEIL]  ; by 180(INT) 
      fsin 
      fstp DWORD[di] 
      inc WORD[I] 
      add  di, 4 
      cmp WORD[I], Endtab 
      jnz TAB 
      ret 

MAKDAT: mov  ah, 3Ch 
      xor  cx, cx 
      int 21h  ; we hope that no error occur 
      mov  bx, ax ; ....but better insert a handling for 
      ret 

WRITE: mov  ah, 40h 
      int 21h  ; ....also here 
      ret 

CLOSE: mov  ah, 3Eh 
      int 21h 
      ret 

而且還可以創建和使用的整數正弦/餘弦表。但是它的處理有點不同,因爲正弦/餘弦值是乘法的,所以我們必須用相同的乘法器乘以我們想要計算的值,最後我們必須將結果分開。

 Grad = 360 * 2 
     Endtab = 450 * 2 
     Foktor = 10000h ; for to replace/shift the floating point of the value 

segment .data 

SINTAB DB Endtab DUP (?,?,?,?) 
TEIL DW Grad/2, ? 
I  DW 0, 0 
FAKT DD Foktor 
TABNAM DB "SinInt.tab", 0 

segment .code 

START: ; same main-routine 

TABLE: xor  di, di  ; subroutine for to create an integer table 
TAB:  fldpi 
      fimul DWORD[I] 
      fidiv DWORD[TEIL] 
      fsin 
      fimul DWORD[FAKT] 
      fistp DWORD[di] 
      inc WORD[I] 
      add  di, 4 
      cmp WORD[I], Endtab 
      jnz TAB 
      ret 

; same subroutines for create, write and store file 

對於得到的計算的精度更高(例如,對於較高的屏幕分辨率,以防止孔),我們可以在360度的循環的計數器的簡單的雙值。

+0

謝謝你的回答,也支持rkhb。如果我有足夠的信譽指標,我會給你箭頭。以我的方式,我也會計算一次並使用正弦表,但在學校他們希望我知道如何使用協處理器。 – kkkkk