Algoritmo de línea 8086 ASM BRESENHAM -- beginner campo con algorithm campo con graphics campo con assembly camp codereview Relacionados El problema

8086 ASM Bresenham's Line Algorithm


7
vote

problema

Español

Como parte de un curso universitario de primer año en la arquitectura de la computadora hace algún tiempo, nos encargamos de aprender 8086 ASM. El curso final del curso requiere la creación de una pequeña animación de formas que se mueven alrededor de las pantallas que cambian de colores y similares.

Como no esperaría que nadie revisara las 720 líneas de ensamblador que voy a proporcionar mi implementación de Algoritmo de línea de Bresenham .

Tenga en cuenta que este no es todo el programa, sino una única macro del programa de trabajo.

También tenga en cuenta que en el momento de la escritura, tuve poco de experiencia en 8086 asm (todavía no lo hago), pero estoy muy interesado en saber cómo lo hice y cómo podría haberse mejorado.

Si a alguien está interesado en revisar el resto del proyecto (se puede hacer en partes pequeñas), hágamelo saber.

  ;========================================================================================================= ;                       BRESENHAM LINE ALGORITHM (lx1,ly1)-(lx2,ly2) ;========================================================================================================= line macro lx1, ly1, lx2, ly2     local ldxsetup1, ldxsetup2, ldysetup1, ldysetup2     local lxisetup1, lxisetup2, lxisetupexit, lyisetup1, lyisetup2, lyisetupexit     local numsetup1, numsetup2, numsetupexit     local lloopstart, lloopif, lloopifexit, lloopend     pushall     mov ax, lx2     sub ax, lx1     cmp ax, 0     jge ldxsetup2 ldxsetup1:     mov bx, -1     mul bx ldxsetup2:     mov ldx, ax     mov ax, ly2     sub ax, ly1     cmp ax, 0     jge ldysetup2 ldysetup1:     mov bx, -1     mul bx ldysetup2:     mov ldy, ax     mov ax, lx1     mov lx, ax     mov ax, ly1     mov ly, ax     mov ax, lx2     cmp ax, lx1     jge lxisetup1     jmp lxisetup2 lxisetup1:     mov ax, 1     jmp lxisetupexit lxisetup2:     mov ax, -1 lxisetupexit:     mov lxi1, ax     mov lxi2, ax     mov ax, ly2     cmp ax, ly1     jge lyisetup1     jmp lyisetup2 lyisetup1:     mov ax, 1     jmp lyisetupexit lyisetup2:     mov ax, -1 lyisetupexit:     mov lyi1, ax     mov lyi2, ax     mov ax, ldx     mov bx, ldy     cmp ax, bx     jge numsetup1     jmp numsetup2 numsetup1:     mov ax, 0     mov lxi1, ax     mov lyi2, ax     mov ax, ldx     mov lden, ax     mov lnumpix, ax     shr ax, 1     mov lnum, ax     mov ax, ldy     mov lnumadd, ax     jmp numsetupexit numsetup2:     mov ax, 0     mov lxi2, ax     mov lyi1, ax     mov ax, ldy     mov lden, ax     mov lnumpix, ax     shr ax, 1     mov lnum, ax     mov ax, ldx     mov lnumadd, ax numsetupexit:     mov ax, lnum     mov dx, 0 lloopstart:     cmp dx, lnumpix     jg lloopend     plot lx, ly     add ax, lnumadd     cmp ax, lden     jge lloopif     jmp lloopifexit lloopif:     sub ax, lden     mov bx, lx     add bx, lxi1     mov lx, bx     mov bx, ly     add bx, lyi1     mov ly, bx lloopifexit:     mov bx, lx     add bx, lxi2     mov lx, bx     mov bx, ly     add bx, lyi2     mov ly, bx     inc dx     jmp lloopstart lloopend:     popall endm ;=========================================================================================================   

Aquí están las definiciones de Pushall y Popall:

  ;========================================================================================================= ;                       PUSH ALL DATA TO STACK ;========================================================================================================= pushall macro     push ax     push bx     push cx     push dx endm ;========================================================================================================= ;========================================================================================================= ;                       POP ALL DATA FROM STACK ;========================================================================================================= popall macro     pop dx     pop cx     pop bx     pop ax endm ;=========================================================================================================   
Original en ingles

As part of a first year university course in computer architecture some time ago we were tasked with learning 8086 ASM. The final course work required creating a small animation of shapes moving around the screen changing colours and the like.

As I would not expect anyone to review 720 lines of assembler I'm just going to provide my implementation of Bresenham's Line Algorithm.

Note that this is not the entire program but a single macro from the working program.

Also note that at the time of writing I had little to no experience with 8086 ASM (I still don't in fact), but I'm very interested in knowing how I did and how it could have been improved upon.

If anyone is interested in reviewing the rest of the project as well (it can be done in small parts) then let me know.

;========================================================================================================= ;                       BRESENHAM LINE ALGORITHM (lx1,ly1)-(lx2,ly2) ;========================================================================================================= line macro lx1, ly1, lx2, ly2     local ldxsetup1, ldxsetup2, ldysetup1, ldysetup2     local lxisetup1, lxisetup2, lxisetupexit, lyisetup1, lyisetup2, lyisetupexit     local numsetup1, numsetup2, numsetupexit     local lloopstart, lloopif, lloopifexit, lloopend     pushall     mov ax, lx2     sub ax, lx1     cmp ax, 0     jge ldxsetup2 ldxsetup1:     mov bx, -1     mul bx ldxsetup2:     mov ldx, ax     mov ax, ly2     sub ax, ly1     cmp ax, 0     jge ldysetup2 ldysetup1:     mov bx, -1     mul bx ldysetup2:     mov ldy, ax     mov ax, lx1     mov lx, ax     mov ax, ly1     mov ly, ax     mov ax, lx2     cmp ax, lx1     jge lxisetup1     jmp lxisetup2 lxisetup1:     mov ax, 1     jmp lxisetupexit lxisetup2:     mov ax, -1 lxisetupexit:     mov lxi1, ax     mov lxi2, ax     mov ax, ly2     cmp ax, ly1     jge lyisetup1     jmp lyisetup2 lyisetup1:     mov ax, 1     jmp lyisetupexit lyisetup2:     mov ax, -1 lyisetupexit:     mov lyi1, ax     mov lyi2, ax     mov ax, ldx     mov bx, ldy     cmp ax, bx     jge numsetup1     jmp numsetup2 numsetup1:     mov ax, 0     mov lxi1, ax     mov lyi2, ax     mov ax, ldx     mov lden, ax     mov lnumpix, ax     shr ax, 1     mov lnum, ax     mov ax, ldy     mov lnumadd, ax     jmp numsetupexit numsetup2:     mov ax, 0     mov lxi2, ax     mov lyi1, ax     mov ax, ldy     mov lden, ax     mov lnumpix, ax     shr ax, 1     mov lnum, ax     mov ax, ldx     mov lnumadd, ax numsetupexit:     mov ax, lnum     mov dx, 0 lloopstart:     cmp dx, lnumpix     jg lloopend     plot lx, ly     add ax, lnumadd     cmp ax, lden     jge lloopif     jmp lloopifexit lloopif:     sub ax, lden     mov bx, lx     add bx, lxi1     mov lx, bx     mov bx, ly     add bx, lyi1     mov ly, bx lloopifexit:     mov bx, lx     add bx, lxi2     mov lx, bx     mov bx, ly     add bx, lyi2     mov ly, bx     inc dx     jmp lloopstart lloopend:     popall endm ;========================================================================================================= 

Here's the definitions of pushall and popall:

;========================================================================================================= ;                       PUSH ALL DATA TO STACK ;========================================================================================================= pushall macro     push ax     push bx     push cx     push dx endm ;========================================================================================================= ;========================================================================================================= ;                       POP ALL DATA FROM STACK ;========================================================================================================= popall macro     pop dx     pop cx     pop bx     pop ax endm ;========================================================================================================= 
           

Lista de respuestas

2
 
vote
vote
La mejor respuesta
 

Algunos comentarios rápidos

  • Porque se escribió como macro, este largo código se insertará en todas partes que necesite para dibujar una línea. Esto es un desperdicio. Es mejor escribir este tipo de código como un procedimiento que se llama.
  • Definitivamente necesitas agregar comentarios al código. ¡Los nombres utilizados para las etiquetas no compensan la falta de comentarios!
  • Debido a que una "L" minúscula y el dígito "1" son tan parecidos, lo encontré con dificultades para leer fácilmente todos los nombres de las variables que comienzan con un 'l'.

Análisis

  mov ax, lx2 sub ax, lx1 cmp ax, 0 jge ldxsetup2   

En el código, como este, no es necesario un 998877666555443311 como el 9988776665544332 "anterior, ya define todas las banderas de procesador necesarias para el funcionamiento correcto del siguiente jge ldxsetup2 < / Código>.


  ldxsetup1:   mov bx, -1   mul bx   

Esta parte es esencialmente calculando el aspecto opuesto al número en el registro AX . ¿Por qué no usar la instrucción neg ax65544336 ? Es muy adecuado para la tarea. Da un código más pequeño y no le acumula el BX y DX Registros.
También tenga en cuenta que la etiqueta ldxsetup1 no es realmente necesaria en este programa. Es ruido.


  jge ldxsetup29  

En este código hay mucho que optimizar.

PASO 1, Retire un 99887766555443310 ahora innecesario LXISETUP1 :

  cmp ax, 01  

Paso 2, simplifique aún más utilizando un registro adicional y menos saltando:

  cmp ax, 02  

Paso 3, combine el cálculo de los incrementos con el cálculo del Delta:

  cmp ax, 03  

El código resultante es mucho más pequeño y el número de etiquetas locales se reduce a la mitad.


  cmp ax, 04  

aquí una vez más, use el salto condicional opuesto y de otro modo caiga a través de:

  cmp ax, 05  

  cmp ax, 06  

Esta es la parte más extraña de su programa. Estas 4 variables se cenan a cero, nunca nuevamente se reubicadas, sin embargo, se usan felices en muchas adiciones que, como consecuencia, realmente no agregan nada. Es decir, a menos que el cmp ax, 07 la llamada macro los cambia. Hubiera sido genial ver cómo se define la trama porque ahora es casi imposible verificar que este programa realmente dibuja una línea o solo un solo punto.


Si a alguien está interesado en revisar el resto del proyecto (se puede hacer en partes pequeñas), hágamelo saber.

Me encantaría ver el resto. No encuentro mucho 720 líneas de código. Como verás desde mi perfil, tiendo a girar en papeles largos.

 

A few quick remarks

  • Because it was written as a macro, this lengthy code will be inserted everywhere that you need to draw a line. This is wasteful. Better write this kind of code as a procedure that gets called.
  • You definitely need to add comments to the code. The names used for the labels don't make up for the lack of comments!
  • Because a lowercase "l" and the digit "1" are so resemblant, I found it hard at times to easily read all those variable names that start with an 'l'.

Analysis

mov ax, lx2 sub ax, lx1 cmp ax, 0 jge ldxsetup2 

In code like this there's no need for an explicit cmp ax, 0 as the preceding sub ax, lx1 already defines all the necessary processor flags for correct operation of the following jge ldxsetup2.


ldxsetup1:   mov bx, -1   mul bx 

This part is essentially calculating the opposite of the number in the AX register. Why not use the neg ax instruction? It's well suited for the task. It gives smaller code and doesn't clobber the BX and DX registers.
Also note that the ldxsetup1 label isn't really needed in this program. It's noise.


  mov ax, lx2   cmp ax, lx1   jge lxisetup1   jmp lxisetup2 lxisetup1:   mov ax, 1   jmp lxisetupexit lxisetup2:   mov ax, -1 lxisetupexit:   mov lxi1, ax   mov lxi2, ax 

In this code there's a lot to optimize.

Step 1, remove a redundant jmp and the now unnecessary label lxisetup1:

  mov  ax, lx2   cmp  ax, lx1   jl   lxisetup2      ;Opposite conditional jump and fall through   mov  ax, 1   jmp  lxisetupexit lxisetup2:   mov  ax, -1 lxisetupexit:   mov  lxi1, ax   mov  lxi2, ax 

Step 2, simplify even more by using an extra register and less jumping around:

  mov  bx, -1      ;BX=-1 Increment if x2 < x1   mov  ax, lx2   cmp  ax, lx1   jl   lxisetupexit   neg  bx          ;BX=1  Increment if x2 >= x1 lxisetupexit:   mov  lxi1, bx   mov  lxi2, bx 

Step 3, combine the calculation of the increments with the calculation of the delta's:

  mov  bx, 1       ;BX=1  Increment if x2 >= x1   mov  ax, lx2   sub  ax, lx1   jge  ldxsetup2   neg  bx          ;BX=-1 Increment if x2 < x1   neg  ax          ;Abs(x2-x1) ldxsetup:   mov  ldx, ax   mov  lxi1, bx   mov  lxi2, bx 

The resulting code is much smaller and the number of local labels is halved.


  cmp ax, bx   jge numsetup1   jmp numsetup2 numsetup1: 

Here once again, use the opposite conditional jump and otherwise fall through:

cmp  ax, bx jl   numsetup2 

numsetup1:   mov ax, 0   mov lxi1, ax   mov lyi2, ax   ... numsetup2:   mov ax, 0   mov lxi2, ax   mov lyi1, ax 

This is the most bizarre part of your program. These 4 variables are zeroed, never again re-assigned, yet happily used in lots of additions that as a consequence don't really add anything! That is unless the plot lx, ly macro call changes them. It would have been great to see how plot is defined because now it's next to impossible to verify that this program actually draws a line or just a single dot.


If anyone is interested in reviewing the rest of the project as well (it can be done in small parts) then let me know.

I would love to see the rest. I don't find 720 lines of code much. As you'll see from my profile I tend to turn in long papers myself.

 
 
   
   
3
 
vote

Estos son solo algunos pensamientos rápidos, no un análisis detallado.

  • comentarios. Suficiente dicho.
  • Si no se toma un salto condicional (como jge ), la ejecución continúa con la siguiente instrucción. Así que esto parece redundante (igualmente con numsetup1):

      jge lxisetup1     jmp lxisetup2 lxisetup1:   

podría ser escrito como:


      jl lxisetup2   

  • Usted está moviendo repetidamente -1 en registros y usándolo de otras maneras. ¿Por qué no hacer uso de un registro adicional (por ejemplo, si )? Configújelo a -1 en la parte superior de esta rutina (recuerde presionar / POP IT si su convención de llamadas lo requiere) y úselo según sea necesario: 9988777665544334 , 9988776655544335 . < / li>
  • Un atajo común para los registros de cero es xor ax, ax
  • . Produce un código ligeramente más pequeño.
  • Mirando su bucle final, tiene:

  lloopstart:     cmp dx, lnumpix     jg lloopend     inc dx     jmp lloopstart lloopend:   

Esto significa que estará haciendo 2 saltos en una fila ( 9988776655544338 , 9988776655544339 ). Una alternativa podría ser:


      jge lxisetup1     jmp lxisetup2 lxisetup1: 0  

En lugar de tener su recuento de bucle (para X = 0 a 10), a veces, tener su cuenta de bucle hasta cero (para X = 10 a 0) puede producir (ligeramente) un código más eficiente (no estoy seguro de que funcionaría en este caso):


      jge lxisetup1     jmp lxisetup2 lxisetup1: 1  
 

These are just some quick thoughts, not a detailed analysis.

  • Comments. Enough said.
  • If a conditional jump (like jge) is not taken, execution just continues with the next instruction. So this seems redundant (likewise with numsetup1):

    jge lxisetup1     jmp lxisetup2 lxisetup1: 

could be written as:


    jl lxisetup2 

  • You are repeatedly moving -1 into registers and using it in other ways. Why not make use of an additional register (say si)? Set it to -1 at the top of this routine (remember to push/pop it if your calling convention requires it) and use it as needed: mul si, mov ax, si.
  • A common shortcut for zeroing registers is xor ax, ax. Produces slightly smaller code.
  • Looking at your final loop, you have:

lloopstart:     cmp dx, lnumpix     jg lloopend     inc dx     jmp lloopstart lloopend: 

This means that you will be doing 2 jumps in a row (jmp lloopstart, jg lloopend). An alternative might be:


    cmp dx, lnumpix     jg lloopend lloopstart:     inc dx     cmp dx, lnumpix     jle lloopstart lloopend: 

Instead of having your loop count up (for x=0 to 10), sometimes having your loop count down to zero (for x=10 to 0) can produce (slightly) more efficient code (not sure it would work in this case):


mov dx, lnumpix lloopstart:     dec dx     jnz lloopstart 
 
 

Relacionados problema

13  Programa de cuenta regresiva en X86 NASM  ( Countdown program in x86 nasm ) 
Soy bastante nuevo para la programación de idiomas de montaje y, para la práctica, me di un problema: cuenta desde 10 y justo después de 1, di "¡Blast Off!". ...

3  Leyendo todos los contenidos de archivos a través de la Asamblea X64  ( Reading all file contents via x64 assembly ) 
He surgido con el siguiente fragmento mediante la construcción de las respuestas que se le da a mi Pregunta de StackOverflow . Solo tratando de obtener otros...

5  Mostrar valor hexadecimal almacenado en un registro  ( Display hexadecimal value stored at a register ) 
Leí un libro sobre el desarrollo del sistema operativo y se enfrenta a un ejercicio simple: Escriba una función que imprime un valor hexadecimal almacenado e...

7  8086 ASM BRESENHAM LINE ALGORITHM PT2  ( 8086 asm bresenhams line algorithm pt2 ) 
Siguiendo la Revisión exitosa de mi implementación de la línea de algoritmo de Bresenham, i Se le ha pedido que cargue la implementación completa de mi proy...

3  Calculadora de RPN de NASM  ( Nasm rpn calculator ) 
He estado aprendiendo ensamblaje en los últimos días, y he hecho una simple calculadora RPN. Aquí está la lógica principal del programa, excluyendo las func...

2  X86-16 Escribiendo cadenas asciiz directamente al video  ( X86 16 writing asciiz strings directly to video ) 
Mientras desarrolla mi sistema operativo, decidí que había una necesidad de ser más verbosa sobre lo que estaba sucediendo en modo real. La idea de incrustar ...

1  X86-16 Función 01 -> Cambiar destino y / o Páginas de visualización  ( X86 16 function 01 change destination and or display pages ) 
Este código está diseñado para ser incluido con x86-16 Escribiendo cadenas asciiz directamente a video y depende de algunas de las declaraciones en ese códi...

5  Sumando todos los primos por debajo de 2,000,000 - Project Euler # 10 en ensamblaje  ( Summing all primes below 2 000 000 project euler 10 in assembly ) 
Actualmente estoy aprendiendo asambleas para la universidad, y me gustaría escuchar algunos comentarios sobre lo que he escrito. Actualmente he implementado p...

6  Encontrar el máximo de una lista dada de datos en la Asamblea GNU X86 (32 bits)  ( Finding the maximum of a given list of data in gnu assembly x86 32 bit ) 
Estoy siguiendo el libro Programación de la base hacia arriba y como respuesta a una pregunta En la sección use los conceptos del capítulo 4: Conviert...

16  X64 Assembly ClearMem / Zeromem  ( X64 assembly clearmem zeromem ) 
Acabo de empezar a aprender a la asamblea de ayer, y la primera cosa útil que he escrito es una función 99887776655544330 . Busco comentarios generales con...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos