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

#### 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 quitthirdprep: 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 continueprompt:    mov bx, message2continue: 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 »

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### 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 quitthirdprep: 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 continueprompt:    mov bx, message2continue: 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 skipadd dl, 7 ; or 27 if you like lowercaseskip:`; 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

#### 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]."

#### encryptor256

• Full Member
• Posts: 250
• Country:
• Win64 .
##### 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 2011This VGA/VBE Bios is released under the GNU LGPLPlease visit : . http://bochs.sourceforge.net . http://www.nongnu.org/vgabiosBochs VBE Display Adapter enabledBochs BIOS - build: 11/11/12\$Revision: 11545 \$ \$Date: 2012-11-11 09:11:17 +0100 (So, 11. Nov 2012) \$Options: apmbios pcibios pnpbios eltorito rombios32ata0 master: Generic 1234 ATA-6 Hard-Disk (  10 MBytes)Press F12 for boot menu.Booting from Hard Disk...Input 10 digit number:1Input 10 digit number:10101010100682LA`
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 16jmp 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!

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 2011This VGA/VBE Bios is released under the GNU LGPLPlease visit : . http://bochs.sourceforge.net . http://www.nongnu.org/vgabiosBochs VBE Display Adapter enabledBochs BIOS - build: 11/11/12\$Revision: 11545 \$ \$Date: 2012-11-11 09:11:17 +0100 (So, 11. Nov 2012) \$Options: apmbios pcibios pnpbios eltorito rombios32ata0 master: Generic 1234 ATA-6 Hard-Disk (  10 MBytes)Press F12 for boot menu.Booting from Hard Disk...Input 10 digit number:11111111111023VV`

Bye, Encryptor256!!!

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

#### Frank Kotler

• NASM Developer
• Hero Member
• Posts: 2667
• Country:
##### 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 bxcmp bx, input + 10je 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

#### encryptor256

• Full Member
• Posts: 250
• Country:
• Win64 .
##### 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.

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

#### 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. 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]
`.data11 byte data buffer: [00000000000].textget 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 countermov eax, 0  ;will use to store number resultmov edx, buffer ;address of buffer[0]  ;alternately pass from caller in register, I'm x64 minded about this stuff.parseLoop:cmp BYTE PTR [edx], 0x30je .zerocmp BYTE PTR [edx], 0x31je .onecall InvalidInput  ;this would be a call to error message on any input !='0' or '1'..zero:shl eax, 1jmp .end.one:shl eax, 1inc eax.end:inc ecxinc edxcmp 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 ecxjne .parseLoopret/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.