Author Topic: help for a school assignment! So hard..  (Read 4889 times)

Offline asdfasdf

  • Jr. Member
  • *
  • Posts: 2
help for a school assignment! So hard..
« on: November 28, 2013, 03:40:33 AM »
:-[, HI, nasm, how do you write a program to convert a 10 digit binary number into decimal and to base 32 (0-9, A-V )

Requirement #1: Your program should clearly prompt the user with a message to enter an exactly 10 digit binary number, which you should store as a null-terminated string (i.e., 11 characters total).

Requirement #2: If the user types fewer than 10 binary digits before pressing return, then your program should prompt for a 10 digit binary number again.  Otherwise, your program should efficiently convert the 10 character string of binary digits into an actual numeric value (0 to 1023) and store this in a word variable.

Requirement #3: Using a loop, convert the numeric value in the word variable into a string representation of the decimal value.  Store this in another null-terminated string (5 characters max, including the null).

Requirement #4: Display the decimal string result.

Requirement #5: Convert the numeric value in the word variable into a 2 character string of duotrigesimal digits.  Store this in another null-terminated string (3 characters total).

Requirement #6: Display the 2 character duotrigesimal string result.
 
Requirement #7: Your program should terminate once the results are displayed.

I THINK I NEED TO USE "SHR" TO CONVERT BINARY TO DECIMAL
AND FOR SOME REASONS, I awalys get illegal instruction error when I tried to input binary number...

Code: [Select]
org 100h

section .text
 
start:
    mov  bx, message    ; get address of first char in message
 
firstloop:
    mov dl, [bx]        ; get char at address in BX
    inc bx              ; point BX to next char in message
    cmp dl, 0            ; Is DL = null (that is, 0)?
    je  secondprep          ; If yes, then quit
    mov ah, 06          ; If no, then call int 21h service 06h
    int 21h              ; to print the character
    jmp firstloop

secondprep:

mov  bx, input          ; get address of first char of input

secondloop:               ; storing the value in input
mov ah , 00h              ; service 00h (get keystroke)
int 16h                   ; call interrupt 16h (ah=00h
cmp al , 0dh              ; is AL = 0DH?
                       
je 20h                    
   
mov [bx], al              ;if no, then store the character
mov dl, al
mov ah, 06h
int 21h
inc bx                    ; increment bx
jmp secondloop            ;repeat for the next character
   

thirdloop:
cmp al, 0Dh      ; Is AL = 0Dh? (ASCII 13 = Return)
    je  quit        ; If yes, then quit

thirdprep:

mov ax, bx ; moving ten digit input in BX into AX
mov bl, 1 ; BL= counter
mov bx, binary  ; get first adress of binary

fourthloop:
    cmp bx,11
je prompt                 ;compare bx to 11characters
mov bx, message2          ; if not equal to 11 characters, then display message2

jmp continue

prompt:
    mov bx, message2

continue:


quit: 
    int 20h ; terminate program
 
section .data
message db "Enter a 10-digit binary number:", 10, 13, 0
message2 db "Please enter EXACTLY 10-digit binary number", 10, 13, 0
input  TIMES 11 db  0,0,0,0,0,0,0,0,0,0,0
base32 db  0,0,0,0
decimal db 0,0,0,0,0,0
binary db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
:)
« Last Edit: November 28, 2013, 04:22:51 AM by Frank Kotler »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2373
  • Country: us
Re: help for a school assignment! So hard..
« Reply #1 on: November 28, 2013, 07:21:18 AM »
I put "code tags" around your code for ya. Just the word "code" in square brackets at the beginning and "/code" in square brackets at the end. Makes it easier to cut-and-paste, and may improve the formatting. Not a big deal, but we like "code tags" around here.

You start off well...
Code: [Select]
org 100h

section .text
 
start:
    mov  bx, message    ; get address of first char in message
 
firstloop:
    mov dl, [bx]        ; get char at address in BX
    inc bx              ; point BX to next char in message
    cmp dl, 0            ; Is DL = null (that is, 0)?
    je  secondprep          ; If yes, then quit
    mov ah, 06          ; If no, then call int 21h service 06h
    int 21h              ; to print the character
    jmp firstloop

secondprep:

mov  bx, input          ; get address of first char of input

secondloop:               ; storing the value in input
mov ah , 00h              ; service 00h (get keystroke)
int 16h                   ; call interrupt 16h (ah=00h
cmp al , 0dh              ; is AL = 0DH?
                       
je 20h                    
... but at this point, you lose me. This is going to jump into the middle of your PSP (Program Segment Prefix - the first 100h bytes of your .com file). This is probably where the "illegal instruction" comes from. At this point, the user is done. We want to check that the user has entered exactly ten digits (you do this later), and we want to zero-terminate the string (which you don't seem to do). If not 0Dh...
Code: [Select]
mov [bx], al              ;if no, then store the character
mov dl, al
mov ah, 06h
int 21h
inc bx                    ; increment bx
jmp secondloop            ;repeat for the next character
You might want to check bx right after the "inc", to make sure it doesn't get too big. It is a grave mistake to let user input overflow the buffer - that's what's wrong with "gets()". Don't do it!

Keep in mind that we start counting at zero. The "first" character is at [input + 0], the "tenth" character is at [input + 9]. When bx gets to 10, the pesky user has hit "enter" or has screwed up. You might even want to prompt "that's enough, thank you" before he hits "enter". :) In any case, we want to zero-terminate the string at [input + 10].

Code: [Select]
thirdloop:
cmp al, 0Dh      ; Is AL = 0Dh? (ASCII 13 = Return)
    je  quit        ; If yes, then quit

thirdprep:

mov ax, bx ; moving ten digit input in BX into AX
mov bl, 1 ; BL= counter
I don't know what you propose to count here, but bl (and bh) are part of bx, so it gets clobbered.
Code: [Select]
mov bx, binary  ; get first adress of binary

fourthloop:
    cmp bx,11
je prompt                 ;compare bx to 11characters
mov bx, message2          ; if not equal to 11 characters, then display message2

jmp continue

prompt:
    mov bx, message2

continue:


quit: 
    int 20h ; terminate program
 
section .data
message db "Enter a 10-digit binary number:", 10, 13, 0
message2 db "Please enter EXACTLY 10-digit binary number", 10, 13, 0
input  TIMES 11 db  0,0,0,0,0,0,0,0,0,0,0
This is defining eleven copies of eleven zeros. More than you need, but it won't hurt.
Code: [Select]
base32 db  0,0,0,0
decimal db 0,0,0,0,0,0
binary db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

You're going to want to verify that a character is either a '0' or a '1' in your "convert string of binary to number" routine anyway, but you might want to do it before even putting it in the buffer - prompt with a definition of "binary number" if the user screws up.

Once you've got the string, "efficiently" convert to a number. The principles of converting a string to a number are similar...

; set a "result so far" to zero
top:
; get a character from the string
; make sure it's a valid character for our base
; if not bail out - zero is expected, else spank user?
; convert the character to a number
  ; for decimal digits - including binary - subtract '0' (the character '0', not the number 0!)
  ; hex or "duotrigesimal" characters are more complicated
; multiply the result-so-far by the base
  ; for binary, or other power of two, "shl"?
; add the number we got to result-so-far
; until done

Then store the result in a variable - you don't seem to have one yet - "number dw 0" (or "number resw 1" in "section .bss").

Converting a number to a string representing that number in different bases...

; divide the number by the base
; convert the remainder to a character
; here's how I'd do hex
Code: [Select]
add dl, '0'
cmp dl, '9'
jle skip
add dl, 7 ; or 27 if you like lowercase
skip:
; store the character in the string
; we're getting characters from right to left - store 'em that way!
; if quotient  is zero, we're done
; if not, do it again

Examples for decimal and hex shouldn't be too hard to find. Duotrigesimal, not so much. I suspect that was the idea. But a hex routine ought to work, with minimal modification. Give it a shot!

Best,
Frank


Offline asdfasdf

  • Jr. Member
  • *
  • Posts: 2
Re: help for a school assignment! So hard..
« Reply #2 on: November 29, 2013, 02:50:08 PM »
thank you for the prompt reply, :)
but I still don't get how you can input exactly 10 binary digits, since i am a absolute newbie.
[input + 0],

what do you mean by "You might want to check bx right after the "inc", to make sure it doesn't get too big. It is a grave mistake to let user input overflow the buffer - that's what's wrong with "gets()". Don't do it!

Keep in mind that we start counting at zero. The "first" character is at [input + 0], the "tenth" character is at [input + 9]. When bx gets to 10, the pesky user has hit "enter" or has screwed up. You might even want to prompt "that's enough, thank you" before he hits "enter". In any case, we want to zero-terminate the string at [input + 10]."

Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: help for a school assignment! So hard..
« Reply #3 on: November 29, 2013, 07:26:36 PM »
Hi!

Architecture: x16, x32

Nice task, it was fun to do, to make things harder i was not inspired by any code elsewere.

I used Bochs emulator to emulate 16 bit code, implemented like a bootloader code.

This is output of my example,
program accepts non-numpad '1', '0', Enter:

Full bochs output:
Code: [Select]
Plex86/Bochs VGABios (PCI) 0.7a 30 Oct 2011
This VGA/VBE Bios is released under the GNU LGPL

Please visit :
 . http://bochs.sourceforge.net
 . http://www.nongnu.org/vgabios

Bochs VBE Display Adapter enabled

Bochs BIOS - build: 11/11/12
$Revision: 11545 $ $Date: 2012-11-11 09:11:17 +0100 (So, 11. Nov 2012) $
Options: apmbios pcibios pnpbios eltorito rombios32

ata0 master: Generic 1234 ATA-6 Hard-Disk (  10 MBytes)

Press F12 for boot menu.

Booting from Hard Disk...

Input 10 digit number:1
Input 10 digit number:1010101010
0682
LA

Output explain:
A. Requirement #1 and #2
"Input 10 digit number:1" - Error.
"Input 10 digit number:1010101010" - Success.

B. Requirement #4
0682

C. Requirement #6
LA

Source code:
Code: [Select]
bits 16

jmp start

; http://webpages.charter.net/danrollins/techhelp/0057.HTM

KEY_ENTER equ (28)
KEY_NUMBER_ONE equ ('1')
KEY_NUMBER_ZERO equ ('0')

input10_msg: db 13,10,"Input 10 digit number:",0
input10_done: db 13,10,"Input:",0
newLine: db 13,10,0

rq1Num10String: times 11 db (0)
rq1BinaryNumber: dw (0)
rq3Num4String: times 5 db (0)
rq5Num2String: times 3 db (0)

printMessage:
push ax
.mainloop:
lodsb
or al,al
jz .quitloop
mov ah,0x0E
int 0x10
jmp .mainloop
.quitloop:
pop ax
ret




start:
cli

mov ax,0x07C0
mov ds,ax
mov gs,ax
mov fs,ax
mov es,ax

mov ax,0x07E0
mov ss,ax
mov bp,ax
mov sp,0xFF

sti

; Requirement #1 -------------------------
; Requirement #2 -------------------------

.rq1:
; Print message
mov si,input10_msg
call printMessage

cld ; Clear direction flag
mov bx,0 ; This will hold binary number
mov di,rq1Num10String ; Setup buffer
mov cx,10 ; Setup loop cycles
.rq1loop:


xor ax,ax
int 0x16 ; Get char
cmp al,KEY_NUMBER_ONE ; Test char: KEY_NUMBER_ONE
je .rq1loopcontinue
cmp al,KEY_NUMBER_ZERO ; Test char: KEY_NUMBER_ZERO
jne .rq1

.rq1loopcontinue:
stosb ; update buffer

sub al,0x30
or bl,al ; update number
shl bx,1

add al,0x30
mov ah,0x0E
int 0x10 ; print char
loop .rq1loop ; continue loop

xor ax,ax
int 0x16 ; Get char
cmp ah,KEY_ENTER ; Check char: ENTER
jne .rq1

shr bx,1 ; Reverse last shift on bx
mov [rq1BinaryNumber],bx

; Requirement #3 -------------------------

; bx remains set
mov cx,4 ; loop count
mov dx,1000 ; base
mov di,rq3Num4String ; buffer
.rq3:
push cx
push dx ; save base
mov ax,bx
mov bx,dx
mov dx,0
div bx ; divide number by base
mov bx,dx ; set remainder
pop dx ; restore base

add al,0x30
stosb

; decrease base
push bx
mov ax,dx
mov dx,0
mov bx,10
div bx
mov dx,ax
pop bx
pop cx
loop .rq3

; Requirement #4 -------------------------

mov si,newLine
call printMessage
mov si,rq3Num4String
call printMessage

; Requirement #5 -------------------------
mov di,rq5Num2String

; Get number
mov bx,[rq1BinaryNumber]

; Divide
mov ax,bx
mov dx,0
mov cx,32
div cx

; Save remainder dx
push dx

; First duotrigesimal - digit
add al,0x30
cmp al,'9'
jle .jumpHere0
add al,7
.jumpHere0:
; Update buffer
stosb

; Restore dx into ax
pop ax

; Second duotrigesimal - digit
add al,0x30
cmp al,'9'
jle .jumpHere1
add al,7
.jumpHere1:
; Update buffer
stosb


; Requirement #6 -------------------------

mov si,newLine
call printMessage
mov si,rq5Num2String
call printMessage


cli
hlt


times 510-($-$$) db (0)
db 0x55
db 0xAA

times 1024*1024*10 db (0)

Need to explain something? No? Fine! :D

Attachment:
Added full source code, + bochs config file, to run example.

Bochs:
How to config bochs and create, run bootloader, you can find on youtube: NASM Bootloader x86 The Netwide Assembler Bochs Emulator

Edit, Here is one extra bochs output example:
Code: [Select]
Plex86/Bochs VGABios (PCI) 0.7a 30 Oct 2011
This VGA/VBE Bios is released under the GNU LGPL

Please visit :
 . http://bochs.sourceforge.net
 . http://www.nongnu.org/vgabios

Bochs VBE Display Adapter enabled

Bochs BIOS - build: 11/11/12
$Revision: 11545 $ $Date: 2012-11-11 09:11:17 +0100 (So, 11. Nov 2012) $
Options: apmbios pcibios pnpbios eltorito rombios32

ata0 master: Generic 1234 ATA-6 Hard-Disk (  10 MBytes)

Press F12 for boot menu.

Booting from Hard Disk...

Input 10 digit number:1111111111
1023
VV


Bye, Encryptor256!!!

« Last Edit: November 29, 2013, 07:31:18 PM by encryptor256 »
Encryptor256's Investigation \ Research Department.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2373
  • Country: us
Re: help for a school assignment! So hard..
« Reply #4 on: November 29, 2013, 08:52:07 PM »
Beautiful! Well... "mov sp, 0xFF"... Why would you deliberately misalign the stack? I guess your code is small enough that the stack won't bump into it. Generally, zero is a nice round number for an initial sp - use the whole segment. Asdfasdf won't have to worry about that - DOS loads a .com file with your segments all set up.

What I had in mind was just...
Code: [Select]
inc bx
cmp bx, input + 10
je got_enough
or perhaps compare to "input + 11" and jump to "too much" - reprompt. There are different ways to do it. Might be worthwhile to keep a separate counter. Don't forget to zero-terminate the string. We know how long it is anyway, but the assignment requires it!

Best,
Frank


Offline encryptor256

  • Full Member
  • **
  • Posts: 250
  • Country: lv
  • Win64 .
    • On Youtube: encryptor256
Re: help for a school assignment! So hard..
« Reply #5 on: November 30, 2013, 08:10:14 AM »
Hi!

Beautiful! Well... "mov sp, 0xFF"... Why would you deliberately misalign the stack? I guess your code is small enough that the stack won't bump into it. Generally, zero is a nice round number for an initial sp - use the whole segment.

Well yes, i agree.

Misaligned stack: mov sp,255
Fix, aligned stack: mov sp,254

Code is "263 bytes (263 bytes)" of len.

Stack should not bump into code, because,
i'm using conventional memory address for stack, Memory Map (x86):
Code: [Select]
0x00007E00 0x0007FFFF 480.5 KiB RAM (guaranteed free for use) Conventional memory
Quote
What I had in mind was just...
Well, loop ten times,
each time ask for input, if it is not '0' or '1', then ask to input again - from start,
after, successful, 10x loop times, ask for input, if it's not 'Enter', then go back to "loop ten times".

Quote
Why would you deliberately misalign the stack?
It was an easter egg. :D

Bye, Encryptor256!!!
Encryptor256's Investigation \ Research Department.

Offline 0xFF

  • Jr. Member
  • *
  • Posts: 15
Re: help for a school assignment! So hard..
« Reply #6 on: December 01, 2013, 05:57:59 AM »
thank you for the prompt reply, :)
but I still don't get how you can input exactly 10 binary digits, since i am a absolute newbie.
[input + 0],

You can only prompt a user to give bytes, characters, from 0x00 to 0xFF. However, since you're programming, maybe you can do a little parsing and conversion? Say to represent the 1's you could use the character 0x31, which conveniently looks like a 1 when you type it. :P Also you could use the character 0x30, which looks like a 0. I'm being tongue in cheek here because all 1's and 0's on your screen ever are actually 0x31's and 0x30's, not 1's or 0's. If the user inputs a string of 0x30 and 0x31's, you could then write a function that runs through that string and magically converts that into a number (wouldn't bother with what type of number, let a computer worry about that, until you get to base32 at least). Off the top of my head, here's some pseudocode asm:

Code: [Select]
.data
11 byte data buffer: [00000000000]

.text
get input from user (not gonna code this)
store into data buffer, then call something like this:

ParseBinary:
save whatever, do stack setup if needed (my code probably won't use stack)
mov ecx, 0  ;will use for loop counter
mov eax, 0  ;will use to store number result
mov edx, buffer ;address of buffer[0]  ;alternately pass from caller in register, I'm x64 minded about this stuff

.parseLoop:
cmp BYTE PTR [edx], 0x30
je .zero
cmp BYTE PTR [edx], 0x31
je .one
call InvalidInput  ;this would be a call to error message on any input !='0' or '1'.
.zero:
shl eax, 1
jmp .end
.one:
shl eax, 1
inc eax
.end:
inc ecx
inc edx
cmp ecx, 10  ;since the check is at the end I use 10, not 9. ecx becomes 10 at the end of the 10th run (which runs with 9 as body value of ecx
jne .parseLoop
ret/jump/continue as appropriate

At that point you have a number in eax and can make it decimal, whatever you want. If you have to print it without external librariies, look into binary coded decimal conversions. For 32bit pritnting, maybe a data array will be helpful? My apologies if I've missed some architecture or system specific specification, but I believe this example of a way to parse a char buffer into a

Quote
what do you mean by "You might want to check bx right after the "inc", to make sure it doesn't get too big. It is a grave mistake to let user input overflow the buffer - that's what's wrong with "gets()". Don't do it!

If you have a 10 byte buffer wiith a register dereferencing values from it, and the register reads 12 values, what will happen to your program? What will the values be? Worse, if you're loading user input to a 10 byte buffer on the stack, that looks like this:

Code: [Select]
[but0][buf1][buf2][buf3].... [buf9][saved-ebp][saved-eip]

And the saved ebp/eip get overwritten by your loop, what happens when you ret? What happens if I put in heaps of character values that match opcodes, and over eip I point to where I've written those opcodes with your loop? Your program just became mine, and it'll do anything I want.