News:

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

Help with base converter program

Started by drumsmoke, July 27, 2006, 12:26:58 PM

Previous topic - Next topic

drumsmoke

Hi there, obviously a newb to these forums and like many other beginners am struggling and in need of some assistance.

I have been asked to write an assembler program to allow conversion of 2 base numbers, unusualy i have been asked to convert base 4 to base 6 and vice versa, the scenario is an alien race one of whom has 4 fingers the other has 6, and they are building an intergalactic space stationa nd need a program to do conversions, very strange scenario i know but our tutor is quite out there if you know what i mean!!

I have compiled in the past a template to help with previous assignments, can i use the code in this template, the routine readnum and displaynum?

TITLE      (.asm)

; This program
; Last update:

.model large
.stack 4096
.386
.data


firstno   word 0000h

.code
main PROC
   mov ax,@data
   mov ds,ax

   call readnum
   mov firstno,bx
   call readnum
   add bx,firstno
   call dispnum   

stop:
   mov ah,4ch
   int 21h

main ENDP
;-----------------------------------------------------------------
readNum PROC
.data
numin   word 0000h

.code

   push dx
   push cx
;   push bx
   push ax
   push si
   push di
;      read digit
L1:
   mov ah,1
   int 21h
;      check for <ESC> or <RET>
   cmp al,1bh
   je  Onward
   cmp al,0dh
   je  Onward
;      check for digit
   and ax,000fh
   cmp al,09h
   jg onward
;      multiply stored value by 10
;      and add digit read
   mov bx,numin
   sal bx,3
   add bx,numin
   add bx,numin
   add bx,ax
   mov ax,bx
;      store result
   mov numin,ax

   jmp L1
Onward:
   mov bx,numin
   pop di
   pop si
   pop ax
;   pop bx
   pop cx
   pop dx
   ret
   
readNum ENDP
;-----------------------------------------------------------------
dispNum PROC
.data
thou   byte 30h
cent   byte 30h
tens   byte 30h
unit   byte 30h

vthou   word 03e8h
vcent   word 0064h
vtens   word 000ah
vunit   word 0001h

value   word 0000h

toobigno byte "number too large",0dh,0ah,"$"

leadzf   byte   00h

.code
;         save registers
   push dx
   push cx
   push bx
   push ax
   push si
   push di
;         reset digit values to 0
   mov al,30h
   mov thou,al
   mov cent,al
   mov tens,al
   mov unit,al
;         check whether number is less than 9,999
   xor ax,ax
   mov leadzf,al
   cmp bx,0000h
   jl  toobig
   cmp bx,270Fh
   jg  toobig
;         determine no of thousands
   dec thou
L1000:
   inc thou
   sub bx,vthou
   jge L1000

   add bx,vthou
   mov ah,6
   mov dl,thou
   cmp dl,30h
   je  Over1
   int 21h
   mov leadzf,1
over1:
   xor ax,ax
   dec cent

L100:
   inc cent
   sub bx,vcent
   jge L100

   add bx,vcent
   mov ah,6
   mov dl,cent
   cmp dl,30h
   je  Over2
o2:
   int 21h
   mov leadzf,1
   jmp o2a
over2:
   cmp leadzf,0
   jne o2
o2a:
   xor ax,ax
   dec tens
L10:
   inc tens
   sub bx,vtens
   jge L10

   add bx,vtens
   mov ah,6
   mov dl,tens
   cmp dl,30h
   je  Over3
o3:
   int 21h
   mov leadzf,1
   jmp o3a
over3:
   cmp leadzf,0
   jne o3
o3a:   xor ax,ax
   dec unit
L1:
   inc unit
   sub bx,vunit
   jge L1

   add bx,vunit
   mov ah,6
   mov dl,unit
   int 21h

   mov ah,6
   mov dl," "
   int 21h

   pop di
   pop si
   pop ax
   pop bx
   pop cx
   pop dx
   
   ret
toobig:

   mov ah,9
   mov dx,OFFSET toobigno
   int 21h

   pop di
   pop si
   pop ax
   pop bx
   pop cx
   pop dx
   
   ret

dispNum ENDP
;-----------------------------------------------------------------
registers PROC
.data
Axmsg byte "AX: $"
Bxmsg byte "BX: $"
Cxmsg byte "CX: $"
Dxmsg byte "DX: $"
crlf byte 0dh,0ah,"$"
.code
   push dx
   push cx
   push bx
   push ax

   push dx
   push cx
   push bx
   push ax

   mov ah,9
   mov dx,OFFSET crlf
   int 21h

   mov ah,9
   mov dx,OFFSET Axmsg
   int 21h
   pop ax
   call display

   mov ah,9
   mov dx,OFFSET Bxmsg
   int 21h
   pop ax
   call display

   mov ah,9
   mov dx,OFFSET Cxmsg
   int 21h
   pop ax
   call display

   mov ah,9
   mov dx,OFFSET Dxmsg
   int 21h
   pop ax
   call display

   mov ah,9
   mov dx,OFFSET crlf
   int 21h

   pop ax
   pop bx
   pop cx
   pop dx

   ret

registers ENDP

display PROC
.data

msg2 byte  "h  ","$"
hex byte "0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"

.code
   push ax
   push bx
   push cx
   push dx
;         display first nibble
   mov bx,ax
   shr ax,12
   lea di,hex
   add di,ax
   mov dl,[di]
   mov ah,2
   int 21h
;         display second nibble
   mov ax,bx
   shr ax,8
   shl ax,12
   shr ax,12
   lea di,hex
   add di,ax
   mov dl,[di]
   mov ah,2
   int 21h
;         display third nibble
   mov ax,bx
   shr ax,4
   shl ax,12
   shr ax,12
   lea di,hex
   add di,ax
   mov dl,[di]
   mov ah,2
   int 21h
;         display fourth nibble
   mov al,bl
   shl ax,12
   shr ax,12
   lea di,hex
   add di,ax
   mov dl,[di]
   mov ah,2
   int 21h

   mov ah,9
   mov dx,OFFSET msg2
   int 21h

   pop dx
   pop cx
   pop bx
   pop ax
   ret

display ENDP
END main

I take it the conversion is a question of multiplying or dividing by 2? Is that with shift instructions? Also the maximum value to avoid overflowing is 330(6) or 1332(4).

Am a bit stuck and im not asking anyone to do the work for me but give me some pointers, been 4 months since i touched assembly language and am really struggling.

Maybe you can help me along whilst i complete it?? Any help appreciated, thanks guys

Paul


MichaelW

If you are starting and ending with strings, then the conversion could consist of converting a base 4 or 6 string to a binary value, and then converting the binary value to a base 4 or 6 string. Your readNum code could be easily adapted to do the first conversion, but your dispNum code would require major changes to accommodate a different base. One simple, easy to understand method of converting a numeric value to a string is to extract the digit values in reverse order by taking the remainder when the number is divided by the base, continuing until the quotient is zero. For example, using base 10:
123 / 10 = 12 remainder 3
12 / 10 = 1 remainder 2
1 / 10 = 0 remainder 1
Then starting with the last value extracted, convert each digit value to a character code (by adding the character code value for "0" for base <=10) and either display each character or add it to a string. The stack provides a convenient method of reversing the order of the digit values. This method could be implemented as two loops. The first loop would perform the divisions, push the digit values onto the stack, and update a digit counter that would be used to control the second loop. The second loop would pop the digit values from the stack, convert them to characters, and display the characters or add them to a string.
eschew obfuscation

dsouza123

A version extremely similar to what MichaelW described, only used arrays instead of the stack
with full source code in MASM32 and Turbo Pascal (16 bit DOS)/Delphi (32 bit Windows)
along with the MASM32 executable.


.data
  fbase dd 4
  tbase dd 6
  farr  db 8 dup (255)
  tarr  db 8 dup (255)
  szbf  db 8 dup (0)
  szC   db "Base Conversion", 0

.code
start:
  mov farr+0, 1   ; fill in base 4 value as a series of bytes ending with a 255 byte
  mov farr+1, 3
  mov farr+2, 3
  mov farr+3, 2

  mov esi, 0  ; copy to a zero terminated string for display in a MessageBox
  .repeat
    .if farr[esi] != 255
       mov al, farr[esi]
       mov szbf[esi], al
       add szbf[esi], 48
       inc esi
    .endif
  .until farr[esi] == 255
 
  invoke MessageBox, NULL, addr szbf, addr szC, MB_OK

  mov edx, 0  ; convert base 4 byte series into a value held in eax
  mov eax, 0

  mov esi, 0
  mov ecx, fbase

  .repeat
    .if byte ptr farr[esi] != 255
       mul ecx
       movzx ebx, byte ptr farr[esi]
       add eax, ebx
       inc esi
    .endif
  .until byte ptr farr[esi] == 255

  mov ebx, eax  ; convert to a base 6 value as a series of bytes with a 255 byte terminator
  mov ecx, tbase
  mov esi, 0
  .if ebx == 0
     mov tarr[esi], 0
     inc esi
  .else
     .repeat
       .if ebx > 0
          mov edx, 0
          mov eax, ebx
          div ecx
          mov tarr[esi], dl
          mov ebx, eax
          inc esi
       .endif
     .until ebx == 0
  .endif

  mov dword ptr szbf+0, 0
  mov dword ptr szbf+4, 0

  mov edi, 0  ; copy in reverse order using length of base 6 bytes to a zero terminated string for the MessageBox
  dec esi
  .repeat
    .if esi >= 0
       mov al, tarr[esi]
       add szbf[edi], al
       add szbf[edi], 48
       inc edi
       dec esi
    .endif
  .until esi == -1

  invoke MessageBox, NULL, addr szbf, addr szC, MB_OK

  invoke ExitProcess,0
end start

[attachment deleted by admin]

drumsmoke

Hey guys, you lot are ace, very helpful indeed, 2 approaches to the same problem, will have a play about this weekend with it all. Just finshed work so time for a few beers, if i lived by you i would buy you both one!! Thanks again for the help, will let you know how i got on with it all.

Diolch ym fawr

Paul :U