News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

FTOA example

Started by avcaballero, February 10, 2012, 12:54:12 PM

Previous topic - Next topic

avcaballero

Hello, from time to time always someone ask for any FTOA example, here it is my version. Ah, yes, change vdNumero value to prove outut...

Masm version

; ----------------------------------------------------------------------------
; -      TITULO  : Prints a real number on the screen                        -
; -----                                                                  -----
; -      AUTOR   : Alfonso Víctor Caballero Hurtado                          -
; -----                                                                  -----
; -      VERSION : 1.0                                                       -
; -----                                                                  -----
; -      (c) 2012. Abre los Ojos al Ensamblador                              -
; -      http://www.abreojosensamblador.net/                                 -
; -      You can use it but, credit ;), don't be a lamer                     -
; -      Compile with: ML.EXE /Fl /AT RealCM01.asm                           -
; ----------------------------------------------------------------------------

; 1.005
; 0 01111111 00000001010001111010111b = 3F 80 A3 D7h

; 0.0005
; 0 01110100 00000110001001001101111b = 3A 03 12 6Fh
; 2^(116-127) * 1.00000110001001001101111

; 1 10000111 00110001101000000000000b = C3 98 D0 00h
; -1 * 2^(135-127) * 1.00110001101 = -100110001.101 = -305.625


codigo SEGMENT PARA PUBLIC 'CODE'
  ASSUME CS:codigo, DS:codigo, ES:codigo, SS:codigo
 
  ORG 100h
  .486
 
  Entrada PROC             
    mov    eax, dword ptr [vdNumero]

    ; Recogemos el signo (1 bit: extremo izquierda)
    mov    byte ptr [rbSigno], 0  ; Suponemos sin signo
    shl    eax, 1
    jnc    @Sgte1
      mov    byte ptr [rbSigno], 1
    @Sgte1:
   
    ; Recuperamos el exponente (8 bits siguientes)
    mov    ebx, eax
    shr    ebx, 23+1
    sub    ebx, 127
    mov    word ptr [rwExpon], bx
   
    xor    cx, cx       ; Suponemos exponente positivo
    or     bx, bx
    jns    @ExpPositivo
      mov    cx, bx
      neg    cx
      mov    word ptr [rwExpon], 0
    @ExpPositivo:
   
    ; Recuperamos la mantisa
    shl    eax, 7      ; Eliminamos el exponente
    or     eax, 10000000000000000000000000000000b  ; Ponemos el 1.
    shr    eax, 9      ; Lo ponemos su sitio, ya sin exponente
    call   CheckExpNeg
    mov    ecx, 0
    @Sin_Exp:          ; Eliminamos los ceros a la derecha
      inc    ecx
      mov    ebx, eax
      shr    eax, 1
    jnc    @Sin_Exp
    mov    eax, ebx
    mov    dword ptr [vdLonMantisa], 23
    sub    dword ptr [vdLonMantisa], ecx
   
    ; Recogemos la parte entera
    mov    ebx, eax                 ; eax ya tiene el 1. y no tiene ceros a la derecha
    mov    cx, word ptr [vdLonMantisa]
    sub    cx, word ptr [rwExpon]
    and    ecx, 0FFFFh              ; Eliminamos la parte de arriba, por si acaso
    mov    dword ptr [vdLonDecimal], ecx
    shr    ebx, cl                  ; Eliminamos decimales, sólo queda parte entera
    mov    word ptr [rwEntera], bx      ; Parte entera
   
    ; Recogemos la parte decimal
    mov    ebx, eax                 ; eax ya tiene el 1. y no tiene ceros a la derecha
    mov    cx, 32   ; 16
    sub    cx, word ptr [vdLonDecimal]
    shl    ebx, cl                  ; Eliminamos la parte entera
    shr    ebx, cl                  ; Ponemos parte decimal contra borde derecho
   
    ; ** Aquí ya hemos desmenuzado el número real,
    ; ** ahora hay que convertirlo a ascii
    ; Parte decimal
    call   InitSum
    mov    ecx, dword ptr [vdLonDecimal] ; Contador de posiciones
    @B_Decimal:
      shr    ebx, 1
      jnc    @B_Sgte1
        call   Divide               ; Resultado en vmBufDivision
        call   Suma                 ; Resultado en vdSumaFinal
      @B_Sgte1:
      dec    ecx
    jnz    @B_Decimal
    call   Sum2ASCII                ; Convierte la suma en ASCII
    call   CopiaSumaMatFinal        ; Copiamos la suma en la matriz final
   
    ; Separador
    mov    byte ptr [di], '.'
    dec    di
   
    ; Parte entera
    mov    ax, [rwEntera]
    call   Bin2ASCII
   
    ; Signo
    cmp    [rbSigno], 1
    jnz    @Fin
      mov    byte ptr [di], '-'
    @Fin:
   
    ; Imprimimos el número
    mov    ah, 9
    mov    dx, di
    int    21h
   
    ; Salimos al DOS
    MOV   AX, 4c00h                       ; Servicio 4Ch, mensaje 0
    INT   21h                             ; volvemos AL DOS
  Entrada ENDP
   
  CheckExpNeg PROC
    ; Propósito: Chequeamos si el exponente fuera negativo para acomodar mantisa
    ; Entrada  : eax: Número, cx: Exponente (0 si positivo, otro caso negativo)
    ;            eax ya tiene el 1 a la izquierda y sin exponente
    ; Salida   : eax
    ; Destruye : eax
    or     cx, cx
    jz     @cen_Fin
      shr    eax, cl
    @cen_Fin:
    ret
  CheckExpNeg ENDP
 
  BaseDecimal PROC
    ; Propósito: devuelve la base para los decimales
    ; Entrada  : eax
    ; Salida   : edx: la base
    ; Destruye : Ninguna
    push   eax
    push   ebx
    push   esi
    mov    ebx, 10
    @b_bucle:
      mul    ebx
      dec    esi
    jnz    @b_bucle
    mov    edx, eax
    pop    esi
    pop    ebx
    pop    eax
    ret
  BaseDecimal ENDP
 
  Bin2ASCII PROC
    ; Propósito: convierte binario a ascii y lo va metiendo en di
    ; Entrada  : eax: num a convertir, di: donde empieza a meter en el búfer
    ; Salida   : di donde ha terminado de meter en el búfer
    ; Destruye : eax, edi
    push   ebx
    push   edx
    mov    ebx, 10
    @Bucle1:
      cmp    eax, 0
      jz     @Salir
      xor    edx, edx
      div    ebx
      or     dl, 30h
      mov    byte ptr [di], dl
      dec    di
    jmp    @Bucle1
    @Salir:
    pop    edx
    pop    ebx
    ret
  Bin2ASCII ENDP
 
  Sum2ASCII PROC
    ; Propósito: Inicializa con ceros el búfer de la suma (8 bytes)
    ; Entrada  : Ninguna
    ; Salida   : Ninguna
    ; Destruye : eax
    or      dword ptr [vdSumaFinal], 30303030h
    or      dword ptr [vdSumaFinal+4], 30303030h
    ret
  Sum2ASCII ENDP
 
  CopiaSumaMatFinal PROC
    ; Propósito: Copia el búfer de la suma en rbNumASCII
    ; Entrada  : Ninguna
    ; Salida   : edi
    ; Destruye : esi, edi
    std                             ; Decrementamos
    mov    esi, offset vdSumaFinal + 7
    mov    edi, offset rbNumASCII + 19
    mov    ecx, 7
    rep    movsb
    ret
  CopiaSumaMatFinal ENDP
 
  InitSum PROC
    ; Propósito: Inicializa con ceros el búfer de la suma (8 bytes)
    ; Entrada  : Ninguna
    ; Salida   : Ninguna
    ; Destruye : eax
    push    ecx
    push    edi
    mov     eax, 0
    mov     ecx, 2
    mov     edi, offset vdSumaFinal
    rep     stosd
    pop     edi
    pop     ecx
    ret
  InitSum ENDP
 
  Suma PROC
    ; Propósito: Suma en bytes vmBufDivision con vdSumaFinal y lo deja aquí
    ; Entrada  : Ninguna
    ; Salida   : vdSumaFinal
    ; Destruye : eax
    push    ebx
    push    ecx
    push    edx
    push    esi
    push    edi
    mov     esi, offset vmBufDivision+7
    mov     edi, offset vdSumaFinal+7
    mov     ecx, 8
    mov     dl, 0
    @Bucle:
      mov     al, byte ptr [esi]
      mov     ah, byte ptr [edi]
      add     al, ah
      add     al, dl
      mov     dl, 0
      cmp     al, 10
      jb      @Next
        mov     dl, 1
        sub     al, 10
      @Next:
      mov     byte ptr [edi], al
      dec     edi
      dec     esi
    loop    @Bucle
    pop     edi
    pop     esi
    pop     edx
    pop     ecx
    pop     ebx
    ret
  Suma ENDP
 
  Divide PROC
    ; Propósito: Divide 10000000 por 2^cl y lo trocea en bytes
    ; Entrada  : ecx: exponente de 2
    ; Salida   : vmBufDivision
    ; Destruye : eax
    push  ebx
    push  ecx
    push  edx
    push  edi
    ; Limpiamos el búfer
    push  ecx
    mov   edi, offset vmBufDivision
    mov   eax, 0
    mov   ecx, 8/4
    rep   stosd
    pop   ecx
    ;
    mov   eax, 10000000     ; Esto es lo que dividiremos
    shr   eax, cl           ; Hademos la división por 2^cl
    ; Ahora troceamos la división en bytes
    mov   edi, offset vmBufDivision+7 ; Dirección donde empezamos a escribir
    mov   ebx, 10           ; Establecemos el divisor
    @d_Bucle:
      cmp   eax, 0          ; ¿Hemos terminado?
      jz    @d_Fin
      xor   edx, edx        ; Limpiamos de nuevo la parte superior
      div   ebx             ; Divisimos -> cociente en edx
      mov   byte ptr [edi], dl  ; Guardamos el byte
      dec   edi             ; Actualizamos puntero
    jmp   @d_Bucle
    @d_Fin:
    pop   edi
    pop   edx
    pop   ecx
    pop   ebx
    ret
  Divide ENDP
 
  ; vdNumero      dd 305.625
  vdNumero      real4    0.0005
  vdAcumDec     dd       0
  vdSumaFinal   dd       8 dup(0)
  vmBufDivision db       8 dup(0)
  vdLonMantisa  dd       1 dup(0)
  vdLonDecimal  dd       1 dup(0)
  rwEntera      dw       1 dup(0)
  rdDecimal     dw       1 dup(0)
  rwExpon       dw       1 dup(0)
  rbSigno       db       1 dup(0)
  rbNumASCII    db       20 dup(' ')
                db       "$"
codigo ENDS
END Entrada


and JWasm version (this is the first time I use JWasm and it seems to work fine...)

; ----------------------------------------------------------------------------
; -      TITULO  : Prints a real number on the screen                        -
; -----                                                                  -----
; -      AUTOR   : Alfonso Víctor Caballero Hurtado                          -
; -----                                                                  -----
; -      VERSION : 1.0                                                       -
; -----                                                                  -----
; -      (c) 2012. Abre los Ojos al Ensamblador                              -
; -      http://www.abreojosensamblador.net/                                 -
; -      You can use it but, credit ;), don't be a lamer                     -
; -      Compile with: jwasm -bin -Fo RealCJ01.com RealCJ01.asm              -
; ----------------------------------------------------------------------------

; 1.005
; 0 01111111 00000001010001111010111b = 3F 80 A3 D7h

; 0.0005
; 0 01110100 00000110001001001101111b = 3A 03 12 6Fh
; 2^(116-127) * 1.00000110001001001101111

; 1 10000111 00110001101000000000000b = C3 98 D0 00h
; -1 * 2^(135-127) * 1.00110001101 = -100110001.101 = -305.625

.model tiny
.386

.data
    ; vdNumero      dd 305.625
    vdNumero      real4    0.0005
    vdAcumDec     dd       0
    vdSumaFinal   dd       8 dup(0)
    vmBufDivision db       8 dup(0)
    vdLonMantisa  dd       1 dup(0)
    vdLonDecimal  dd       1 dup(0)
    rwEntera      dw       1 dup(0)
    rdDecimal     dw       1 dup(0)
    rwExpon       dw       1 dup(0)
    rbSigno       db       1 dup(0)
    rbNumASCII    db       20 dup(' '), "$"

.code
    ORG 100h                 
    Entrada:             
    mov    eax, dword ptr [vdNumero]

    ; Recogemos el signo (1 bit: extremo izquierda)
    mov    byte ptr [rbSigno], 0  ; Suponemos sin signo
    shl    eax, 1
    jnc    @Sgte1
      mov    byte ptr [rbSigno], 1
    @Sgte1:
   
    ; Recuperamos el exponente (8 bits siguientes)
    mov    ebx, eax
    shr    ebx, 23+1
    sub    ebx, 127
    mov    word ptr [rwExpon], bx
   
    xor    cx, cx       ; Suponemos exponente positivo
    or     bx, bx
    jns    @ExpPositivo
      mov    cx, bx
      neg    cx
      mov    word ptr [rwExpon], 0
    @ExpPositivo:
   
    ; Recuperamos la mantisa
    shl    eax, 7      ; Eliminamos el exponente
    or     eax, 10000000000000000000000000000000b  ; Ponemos el 1.
    shr    eax, 9      ; Lo ponemos su sitio, ya sin exponente
    call   CheckExpNeg
    mov    ecx, 0
    @Sin_Exp:          ; Eliminamos los ceros a la derecha
      inc    ecx
      mov    ebx, eax
      shr    eax, 1
    jnc    @Sin_Exp
    mov    eax, ebx
    mov    dword ptr [vdLonMantisa], 23
    sub    dword ptr [vdLonMantisa], ecx
   
    ; Recogemos la parte entera
    mov    ebx, eax                 ; eax ya tiene el 1. y no tiene ceros a la derecha
    mov    cx, word ptr [vdLonMantisa]
    sub    cx, word ptr [rwExpon]
    and    ecx, 0FFFFh              ; Eliminamos la parte de arriba, por si acaso
    mov    dword ptr [vdLonDecimal], ecx
    shr    ebx, cl                  ; Eliminamos decimales, sólo queda parte entera
    mov    word ptr [rwEntera], bx      ; Parte entera
   
    ; Recogemos la parte decimal
    mov    ebx, eax                 ; eax ya tiene el 1. y no tiene ceros a la derecha
    mov    cx, 32   ; 16
    sub    cx, word ptr [vdLonDecimal]
    shl    ebx, cl                  ; Eliminamos la parte entera
    shr    ebx, cl                  ; Ponemos parte decimal contra borde derecho
   
    ; ** Aquí ya hemos desmenuzado el número real,
    ; ** ahora hay que convertirlo a ascii
    ; Parte decimal
    call   InitSum
    mov    ecx, dword ptr [vdLonDecimal] ; Contador de posiciones
    @B_Decimal:
      shr    ebx, 1
      jnc    @B_Sgte1
        call   Divide               ; Resultado en vmBufDivision
        call   Suma                 ; Resultado en vdSumaFinal
      @B_Sgte1:
      dec    ecx
    jnz    @B_Decimal
    call   Sum2ASCII                ; Convierte la suma en ASCII
    call   CopiaSumaMatFinal        ; Copiamos la suma en la matriz final
   
    ; Separador
    mov    byte ptr [di], '.'
    dec    di
   
    ; Parte entera
    mov    ax, [rwEntera]
    call   Bin2ASCII
   
    ; Signo
    cmp    [rbSigno], 1
    jnz    @Fin
      mov    byte ptr [di], '-'
    @Fin:
   
    ; Imprimimos el número
    mov    ah, 9
    mov    dx, di
    int    21h
   
    ; Salimos al DOS
    MOV   AX, 4c00h                       ; Servicio 4Ch, mensaje 0
    INT   21h                             ; volvemos AL DOS
   
    CheckExpNeg PROC
      ; Propósito: Chequeamos si el exponente fuera negativo para acomodar mantisa
      ; Entrada  : eax: Número, cx: Exponente (0 si positivo, otro caso negativo)
      ;            eax ya tiene el 1 a la izquierda y sin exponente
      ; Salida   : eax
      ; Destruye : eax
      or     cx, cx
      jz     @cen_Fin
        shr    eax, cl
      @cen_Fin:
      ret
    CheckExpNeg ENDP
   
    BaseDecimal PROC
      ; Propósito: devuelve la base para los decimales
      ; Entrada  : eax
      ; Salida   : edx: la base
      ; Destruye : Ninguna
      push   eax
      push   ebx
      push   esi
      mov    ebx, 10
      @b_bucle:
        mul    ebx
        dec    esi
      jnz    @b_bucle
      mov    edx, eax
      pop    esi
      pop    ebx
      pop    eax
      ret
    BaseDecimal ENDP
   
    Bin2ASCII PROC
      ; Propósito: convierte binario a ascii y lo va metiendo en di
      ; Entrada  : eax: num a convertir, di: donde empieza a meter en el búfer
      ; Salida   : di donde ha terminado de meter en el búfer
      ; Destruye : eax, edi
      push   ebx
      push   edx
      mov    ebx, 10
      @Bucle1:
        cmp    eax, 0
        jz     @Salir
        xor    edx, edx
        div    ebx
        or     dl, 30h
        mov    byte ptr [di], dl
        dec    di
      jmp    @Bucle1
      @Salir:
      pop    edx
      pop    ebx
      ret
    Bin2ASCII ENDP
   
    Sum2ASCII PROC
      ; Propósito: Inicializa con ceros el búfer de la suma (8 bytes)
      ; Entrada  : Ninguna
      ; Salida   : Ninguna
      ; Destruye : eax
      or      dword ptr [vdSumaFinal], 30303030h
      or      dword ptr [vdSumaFinal+4], 30303030h
      ret
    Sum2ASCII ENDP
   
    CopiaSumaMatFinal PROC
      ; Propósito: Copia el búfer de la suma en rbNumASCII
      ; Entrada  : Ninguna
      ; Salida   : edi
      ; Destruye : esi, edi
      std                             ; Decrementamos
      mov    esi, offset vdSumaFinal + 7
      mov    edi, offset rbNumASCII + 19
      mov    ecx, 7
      rep    movsb
      ret
    CopiaSumaMatFinal ENDP
   
    InitSum PROC
      ; Propósito: Inicializa con ceros el búfer de la suma (8 bytes)
      ; Entrada  : Ninguna
      ; Salida   : Ninguna
      ; Destruye : eax
      push    ecx
      push    edi
      mov     eax, 0
      mov     ecx, 2
      mov     edi, offset vdSumaFinal
      rep     stosd
      pop     edi
      pop     ecx
      ret
    InitSum ENDP
   
    Suma PROC
      ; Propósito: Suma en bytes vmBufDivision con vdSumaFinal y lo deja aquí
      ; Entrada  : Ninguna
      ; Salida   : vdSumaFinal
      ; Destruye : eax
      push    ebx
      push    ecx
      push    edx
      push    esi
      push    edi
      mov     esi, offset vmBufDivision+7
      mov     edi, offset vdSumaFinal+7
      mov     ecx, 8
      mov     dl, 0
      @Bucle:
        mov     al, byte ptr [esi]
        mov     ah, byte ptr [edi]
        add     al, ah
        add     al, dl
        mov     dl, 0
        cmp     al, 10
        jb      @Next
          mov     dl, 1
          sub     al, 10
        @Next:
        mov     byte ptr [edi], al
        dec     edi
        dec     esi
      loop    @Bucle
      pop     edi
      pop     esi
      pop     edx
      pop     ecx
      pop     ebx
      ret
    Suma ENDP
   
    Divide PROC
      ; Propósito: Divide 10000000 por 2^cl y lo trocea en bytes
      ; Entrada  : ecx: exponente de 2
      ; Salida   : vmBufDivision
      ; Destruye : eax
      push  ebx
      push  ecx
      push  edx
      push  edi
      ; Limpiamos el búfer
      push  ecx
      mov   edi, offset vmBufDivision
      mov   eax, 0
      mov   ecx, 8/4
      rep   stosd
      pop   ecx
      ;
      mov   eax, 10000000     ; Esto es lo que dividiremos
      shr   eax, cl           ; Hademos la división por 2^cl
      ; Ahora troceamos la división en bytes
      mov   edi, offset vmBufDivision+7 ; Dirección donde empezamos a escribir
      mov   ebx, 10           ; Establecemos el divisor
      @d_Bucle:
        cmp   eax, 0          ; ¿Hemos terminado?
        jz    @d_Fin
        xor   edx, edx        ; Limpiamos de nuevo la parte superior
        div   ebx             ; Divisimos -> cociente en edx
        mov   byte ptr [edi], dl  ; Guardamos el byte
        dec   edi             ; Actualizamos puntero
      jmp   @d_Bucle
      @d_Fin:
      pop   edi
      pop   edx
      pop   ecx
      pop   ebx
      ret
    Divide ENDP
END Entrada



Regards

FORTRANS

Hi,

   Thanks.  I will use your code to outline a similar set of routines.
It was something I have been putting off.

Regards,

Steve N.


        COMMENT @
   Maybe someone will find this useful.

   The REAL4 binary number is a single precision real value.  ~From (2, 1).
┌────┬────────┬────────┐
│ 31 │ 30..23 │ 22...0 │  Eight bit exponent is biased by 7FH (127).
├────┼────────┼────────┤  Twenty-three bit fraction has implied 1.0 bit.
│Sign│Exponent│Fraction│
└────┴────────┴────────┘
   The double precision real value.
┌────┬────────┬────────┐
│ 63 │ 62..52 │ 51...0 │  Eleven bit exponent is biased by 3FFH (1023).
├────┼────────┼────────┤  Fifty-two bit fraction has implied 1.0 bit.
│Sign│Exponent│Fraction│
└────┴────────┴────────┘
   The extended precision real value.
┌────┬────────┬────────┐
│ 79 │ 78..64 │ 63...0 │  Fifteen bit exponent is biased by 3FFFH (16383).
├────┼────────┼────────┤  Sixty-four bit fraction has explicit 1.0 bit.
│Sign│Exponent│Fraction│
└────┴────────┴────────┘
                @

dedndave

here's a PDF that i found very helpful
http://www.validlab.com/goldberg/paper.pdf

together with Ray's tutorial, you have a pretty good reference   :U

FORTRANS

Hi Dave,

   Thank you.  I believe I have a different version of that PDF.
I will take a look at it anyway for a refresh of the gray cells.

   It turns out that avcaballero is doing something rather different
than what I thought he was doing.  May have got me started
on a long put off project though.

Thanks,

Steve N.

dedndave

yah - there are a few different approaches to floating point base conversion
i have thought some of playing with the exponenti/logarithm method, just for fun   :P
his code is interesting in that it does not use the FPU

FORTRANS

Hi,

   Yes, the non-FPU style was what I was interested in.  My DOS
based 80186 HP 200LX does not have an FPU.  I can run an
emulator, but where's the fun in that?

   A glance at the PDF seems that it is the same or similar to
the one I read a long time ago.  The title is the same as I
remember it.

Cheers,

Steve N.

dedndave

that article was reformatted a couple times from the original text
in fact, i think the link i posted is the first re-write   :P

you can google around and find them...

goldberg.pdf - original article from March 1991 "Computng Surveys" magazine
paper.pdf, floating_point_math.pdf - different PDF's of the re-write i posted
floatingpointmath.pdf - a more recent re-write

i didn't know the 80186 was ever put into a PC - lol
we used one on an ultra-sound scanner i worked on back in the 80's at ADR Ultrasound
i thought it was a cool processor - we had a 10 MHz version, with a 10 MHz 8087
but i didn't think it was a good choice for a PC, as IBM did not follow the original intent of I/O address space and h/w INT's set forth by Intel

FORTRANS

Quote from: dedndave on February 27, 2012, 04:12:53 PM
i didn't know the 80186 was ever put into a PC - lol
we used one on an ultra-sound scanner i worked on back in the 80's at ADR Ultrasound
i thought it was a cool processor - we had a 10 MHz version, with a 10 MHz 8087

Hi

   Sounds like a nice setup.  Any OS or developer kit?

Quote
but i didn't think it was a good choice for a PC, as IBM did not follow the original intent of I/O address space and h/w INT's set forth by Intel

   The 200LX is an PC/XT compatible that fits into a pocket.
16MHz processor, runs for weeks on 2 AA batteries, and has an
LCD display with CGA graphics (sorta).  Very compatible with
most programs that use CGA or MDA output (and don't mind
only four levels of gray).

   There are some links at the bottom that have better
pictures.

http://en.wikipedia.org/wiki/HP_200LX

   Oops Daniel's page dropped the good ones.

Cheers,

Steve N.

dedndave

i didn't have anything to do with the code, but i remember seeing a listing
it was written in pascal, as i remember
they could probably use any PC compiler, as it was essentially a souped up 8086 (i.e. with goodies added)
i would think you could write code for it with MASM