使用NASM x86组件绘制余弦波

时间:2016-12-15 01:03:53

标签: assembly x86 nasm x86-64 cosine

我必须使用汇编语言绘制简单的余弦(x)波。我按照教授的指示完成了项目的所有步骤,但我无法正确打印程序。这是我得到的输出,

linux2[14]% cat plot4.out
*****************************************

但应该是......

                  *****                  
                 *     *                 
                *       *                
               *         *               
              *           *              
             *             *             

            *               *            
           *                 *           

          *                   *          

         *                     *         
        *                       *        

       *                         *       
      *                           *      
     *                             *     
    *                               *    
  **                                 **  
**                                     **

这是我的代码。任何帮助将不胜感激。

      SECTION .data         ; Data section, initialized variables
nrow:           dq 21       ; 21 rows
ncol:           dq 41       ; 41 columns
fmtc:           db "%c", 0  ; print one character at a time
fmtend:         db 10, 0    ; end a line
star:           db '*'      ; one character '*'
fmtendLen:  equ $-fmtend
pStar:      db  "*"
starLen:    equ $-pStar
pSpace:     db  " "
spaceLen:   equ $-pSpace
len:            equ $-star
spc:            db ' '
af:         dq 1.0, 0.0, -0.5 ; coefficients of polynomial, a_0 first
            dq 0.0, 0.041667, 0.0, -0.001389, 0.0, 0.000025
XF:         dq 0.0      ; computed
Y:          dq 0.0      ; computed
N:          dq 8        ; power of polynomial
X0:         dq -3.14159     ; start XF
DX0:            dq 0.15708      ; increment for XF  ncol-1  times
one:            dq 1.0
ten:            dq 10.0
none:           dq -1.0
nten:           dq -10.0
twenty:         dq 20.0
zero:           dq 0.0
newline:    db 10

    section .bss

a2: resb    21*41       ; two dimensional array of bytes
i:  resq    1       ; row subscript
j:  resq    1       ; col subscript
k:  resq    1

    SECTION .text   ; Code section.

    global _start   ; the standard gcc entry point
_start:                     ; the program label for the entry point


;;;   clear a2 to space
    mov     rax,0           ; i=0
    mov     [i],rax

loopi:
    mov     rax,[i]
    mov     rbx,0       ; j=0
    mov     [j],rbx
loopj:
    mov     rax,[i]
    mov     rbx,[j]
    imul    rax,[ncol]  ; i*ncol
    add     rax, rbx    ; i*ncol + j
    mov     dl, [spc]   ; need just character, byte
    mov     [a2+rax],dl ; store space

    mov     rbx,[j]
    inc     rbx         ; j++
    mov     [j],rbx
    cmp     rbx,[ncol]  ; j<ncol
    jne     loopj

    mov     rax,[i]
    inc     rax         ; i++
    mov     [i],rax
    cmp     rax,[nrow]      ; i<ncol
    jne     loopi

;;;   end clear a2 to space

    mov     rax, 0          ;i = 0
    mov     [i], rax
    mov     rbx, 0          ;j = 0
    mov     [j], rbx

cos:
    mov     rcx,[N]         ; loop iteration count initialization, n
    fld     qword [af+8*rcx] ; accumulate value here, get coefficient a_
h5loop:
    fmul    qword [XF]  ; * XF
    fadd    qword [af+8*rcx-8] ; + aa_n-i
    loop    h5loop         ; decrement rcx, jump on non zero
    fstp    qword [Y]          ; store Y


;;; ; ;  compute k
    fld qword [Y]
    fadd qword [one]
    fmul qword [ten]
    fmul qword [none]
    fadd qword [twenty]
    fistp qword [k]

;;; ; ; ; ; rax gets k * ncol + j
    mov     rax, [k]
    mov     rbx, [j]
    imul    rax, [ncol]
    add     rax, rbx

;;; ; ; put "*" in dl, then dl into [a2+rax]
    mov     dl, [star]
    mov     [a2+rax], dl

;;; ; ; XF = XF + DX0
    fld     qword [XF]
    fadd    qword [DX0]
    fistp   qword [XF]


    mov     rbx, [j]
    inc     rbx         ; j++

    mov     [j], rbx
    cmp     rbx,[ncol]  ; j<ncol
    jne     cos

;;;   print
    mov     rax,0       ; i=0
    mov     [i],rax

ploopi:
    mov     rax,[i]
    mov     rbx,0       ; j=0
    mov     [j],rbx

ploopj:

    mov rax,[i]
    mov rbx,[j]
    mov dl, [spc]

    imul    rax,[ncol]
    add     rax, rbx


    mov     rax, [i]        ; a2+i*ncol+j  is byte
    imul    rax, [ncol]
    add     rax, [j]
    add     rax, a2
    mov     rsi, rax ; address of character to print
    mov     rax, 1       ; system call 1 is write
    mov     rdi, 1       ; file handle 1 is stdout
    mov rdx, 1       ; number of bytes
    syscall          ; invoke operating system to do the write

;;;  print here

    mov     rbx,[j]
    inc     rbx         ; j++
    mov     [j],rbx
    cmp     rbx,[ncol]  ; j<ncol
    jne     ploopj

    mov     rdi, fmtend
    mov     rax, 1
    mov     rdi, 1  ; file handle 1 is stdout
    mov     rsi, newline ; address of string to output
    mov     rdx, 1       ; number of bytes
    syscall

;;;  print here

    mov     rax,[i]
    inc     rax         ; i++
    mov     [i],rax
    cmp     rax,[nrow]      ; i<ncol
    jne     ploopi

;;;   print a2

    mov     eax, 60 ; system call 60 is exit
    xor     rdi, rdi    ; exit code 0
    syscall             ; invoke operating system to exit

1 个答案:

答案 0 :(得分:3)

由于[XF]更新错误,代码无法按预期工作:

fistp   qword [XF]  ; will store integer.

修复XF之后,它会崩溃,因为计算的y值超出了[0,0] - &gt; [41,21]坐标。

你可以通过在绘制星星之前添加最小/最大坐标钳位来使代码更加健壮,所以如果你的计算产生错误的[x,y],它就不会将星形写入某些内存,而是其他东西(我放在那里) {= 1}}在y = 0时查看图表出错的位置。

之后你可能想要修复图表......这取决于你。

无论如何,我对你的装配技术有了更多的评论(或者我从评论中指出,你的导师的技术)。作为学生的工作,我可以容忍这种情况,但仅限于此。

要成为计算机程序员,你不应该将每一个愚蠢的翻译成计算机命令。如果人们会这样编程,在每种情况下排序仍然是完整的O(n ^ 2),没有人会创建任何压缩算法。您应该从根本上理解要实现的计算类型,并尝试尽可能简化。

让我举几个你的代码示例。最初的部分是将空格字符放在a2数组的每个位置。所以基本上它正在做:

'#'

我遇到了一个小问题......它字面意思完成了。就像每个表达式中的每个f * cking符号一样,所有内容都来回加载/存储到内存中,就像CPU上的寄存器一样不存在。

但情况更糟,我也遇到了重大问题。如果你打开你的程序员,并考虑该部分正在进行的计算,你应该弄清楚该计算的最终状态是,为for (i = 0; i < 21; ++i) for (j = 0; j < 41; ++j) a2[i * ncol + j] = ' '; 分配的整个内存是否填充了值a232)。并且a2在内存中占据连续的21 * 41字节。

所以要做同样的事情,你可以写下这段代码:

' '

它会用空格填充整个lea rdi,[a2] ; address of first byte of a2 lea ecx,[i-a2] ; rcx = size of a2 array in bytes ; (using label "i" after it) And only ecx as 21*41 < 2^32 mov al,' ' ; space value directly (why [spc]?) rep stosb ; fill rcx bytes at rdi with al 。如果这些循环按列进行,则此代码将按行以不同方式填充它。但是,如果您只对计算结果感兴趣(整个数组设置为a2),那么您不关心是否按行,列或圆圈完成。

等等......在这段代码中有一些更奇怪的东西,但我不愿意根据自己的口味重写它,我希望这足以说明我的想法。< / p> 顺便说一下,我不希望学生立即使用' '变体结束(甚至可以通过将rep stosb填充为16或32倍的大小来进一步优化性能,然后填充它一些SSE指令或至少a2)。

但至少在每次迭代中都认识到内循环正在进行stosd ......而你可能会这样做:

i * ncol + j

......这就像最低限度。然后,如果您要调试它,您会注意到for (i = 0; i < 21; ++i) { rowindex = i*ncol + 0; for (j = 0; j < 41; ++j) { a2[rowindex] = ' '; ++rowindex; } } 等于前一行结束时已设置的值,因此您需要在rowindex = i*ncol + 0;个循环之前只执行rowindex = 0;:< / p>

for

现在您应该已经看到两个charindex = 0; for (i = 0; i < 21; ++i) for (j = 0; j < 41; ++j) a2[charindex++] = ' '; 循环可以被单个for替换...但是等一下,是不是等于for (count = 0; count < 21*41; ++count)?噢,是的。

charindex

这相当于我的for (i = 0; i < 21*41; ++i) a2[i] = ' '; ,但如果你用简单的rep stosb指令作为循环来写(因为你不知道mov/inc/dec/jnz) ,我会完全没问题(它会在大致相同的时间内执行)。

但做21 * 41 rep stosb指令就像......亵渎神明。有时间,当进行800次32位数的乘法时需要大约3-5秒。现在有人正在使用该计算能力来清除连续的字节数组。疼痛...

BTW,这是原始代码的输出(在修复imul更新后,并且钳位值...我用点替换空格,并且钳位Y值将[XF]转换为{{1 }}

*