2014-07-06 1 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) 

내가 사인 그리려는 내가 bxax에서 Y와 X에 필요합니다. 루프를 만들 것이기 ​​때문에 X는 문제가되지 않지만 Y는 문제가 있습니다. X는 예제 0에서 350까지입니다 (예 : 픽셀). 예를 들어 죄 (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

잘못 뭘하는지 모르겠어요. 따라서 angleX 좌표로 사용할 수 있으며 함수 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 (전체 웨이브)이 정확히 true 여야합니다. 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

관련 문제