2016-12-15 15 views
0

Мне нужно построить простую косинусоидальную (х) волну, используя язык ассемблера. Я выполнил все шаги проекта в соответствии с инструкциями моего преподавателя, но я не могу заставить программу печатать правильно. Это выход я получаю,построение косинусоидальной волны с использованием сборки NASM x86

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 
+0

Используйте отладчик для одного шага вашей программы и посмотреть, куда это идет не так. – Jester

+0

это может быть очень глупо ... но не могли бы вы сказать мне, как это сделать? – marz123

+2

Если вы не знакомы с отладчиком, его может быть проще всего захватить с помощью графического интерфейса, например 'ddd'. Затем загрузите свою программу и нажмите кнопку, но тонн. Надеюсь, вы сами это узнаете, не можете научить вас использовать отладчик в комментарии здесь. – Jester

ответ

3

код не работает, как ожидалось, потому что [XF] обновление является неправильным:

fistp qword [XF] ; will store integer. 

После исправит XF, это приведет к краху, потому что расчетное значение у получает вне [0,0] -> [41,21].

Вы можете сделать свой код более надежным, добавив минимальные координаты кодов, прежде чем рисовать звезды, поэтому, если ваш расчет порождает неправильные [x, y], он не будет записывать звезду в какую-то память, а что-то еще (я ставлю '#' при y = 0, чтобы увидеть, где ваш график не соответствует действительности).

После этого вы, вероятно, захотите исправить график ... это зависит от вас.

Во всяком случае, у меня есть еще несколько комментариев к вашей технике Ассамблеи (или, как я заметил из комментариев, технику вашего инструктора). Я могу терпеть это как студенческую работу, но только так.

Чтобы стать программистом, вы не должны просто переводить каждую глупость буквально в компьютерные команды. Если бы люди так программировали, сортировка была бы по-прежнему полной O (n^2) в каждом случае, и никто бы никогда не создал какой-либо алгоритм сжатия. Вы должны принципиально понять, какой расчет вы хотите достичь, и попытаться упростить, где это возможно.

Позвольте привести пример из вашего кода. Начальная часть помещает пробел в каждую позицию массива a2. Так что в основном это делает:

for (i = 0; i < 21; ++i) 
    for (j = 0; j < 41; ++j) 
    a2[i * ncol + j] = ' '; 

Есть небольшая проблема, с которой я столкнулся. Это делается буквально. Как и каждый знак f * cking в каждом выражении, и все загружается/сохраняется в память взад и вперед, например, регистры на CPU не существуют.

Но это еще хуже, у меня также есть большая проблема с этим. Если вы включите ваш программист и подумайте, что происходит в этой части, вы должны выяснить конечное состояние этого вычисления, что вся память, выделенная для a2, заполнена значением 32 (' '). А 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 с пробелами. Если эти циклы будут проходить по столбцам, то этот код будет заполнять его по-разному, по строкам. Но если вас интересует только результат вычисления (весь массив установлен в ' '), вам все равно, было ли это сделано строками, столбцами или кругами.

etc, etc ...в этом коде есть еще какие-то странные вещи, но я не хочу переписывать их на свой вкус, надеюсь, этого достаточно, чтобы проиллюстрировать то, что у меня на уме.


Кстати, я не ожидал бы, что студент немедленно прекратить с rep stosb вариантом (и даже то, что может быть дополнительно оптимизировано для работы путем наложения a2 быть 16 или 32 размера умножения, и заполнить его с некоторой SSE инструкции или не менее 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; впереди обоих 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 инструкции как петли (потому что вы не знаете rep stosb), я бы прекрасно с ней (она будет выполнена в примерно в то же время).

Но делать 21 * 41 imul инструкции как ... богохульство. Было время, когда 800 умножений на 32-битные числа занимали около 3-5 секунд. Теперь кто-то использует эту вычислительную мощность для очистки последовательного массива байтов. Боль ...


BTW, это выход из исходного кода (после фиксации [XF] обновления и зажимая значения ... и я заменил пространство с точками, и зажимаюсь значения Y превратить * в #.

.......................*################# 
......................................... 
......................................... 
......................................... 
......................................... 
*.....................*.................. 
.*....................................... 
..*...................................... 
......................................... 
...*.................*................... 
......................................... 
....*.................................... 
.....*..............*.................... 
......................................... 
......*............*..................... 
.......*................................. 
........*.........*...................... 
.........*.......*....................... 
..........*.............................. 
...........*...**........................ 
............***.......................... 
+0

Я очень ценю, что вы нашли время, чтобы объяснить все это, но на данный момент я настолько потерян, что он безнадежен.Не знаю, что будет – marz123

+1

@MohammadMarzooghian Если это школьный курс сборки, я готов поспорить, что вы начали с более простых вещей. Повторите их несколько раз. Если вы сразу начали с этого, то либо найдите некоторые учебные пособия самостоятельно, либо попросите своего учителя лучше понять. Просматривая простые учебники, вы не должны изучать инструкции, запоминая определенные шаблоны, например, тексты песен. Это ни к чему не приведет. Вам нужно понять математику в памяти CPU +, как значения бит изменяются с каждой инструкцией. И как это сопоставляется с оригинальным алгоритмом и строит выход программы. – Ped7g

+0

fld qword [X0] fstp qword [XF]; необходимо инициализировать XF до cos: fistp qword [k]; не fstp fstp qword [XF]; не фистинг – marz123