Assembly Language

Counting Coins?

Page 1 of 1

8 Replies - 3701 Views - Last Post: 15 October 2008 - 02:35 PM

#1 Wilbur  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 26-September 08

Assembly Language

Post icon  Posted 08 October 2008 - 10:07 AM

Ok. So I am trying to write an assembly program that will ask the user to input a number of pennies, nickels, dimes, and quarters. Then, it will calculate the total number of coins, dollars it adds up to, and cents left over. Here is what i have so far...

.586
.MODEL FLAT

INCLUDE io.h		; header file for input/output

.STACK 4096

.DATA
pennies DWORD   ?
nickels DWORD   ?
dimes DWORD   ?
quarters DWORD   ?
numberOfCoins DWORD ?
total DWORD ?
prompt1 BYTE	"How many pennies do you have?", 0
prompt2 BYTE	"How many nickels do you have?", 0
prompt3 BYTE	"How many dimes do you have?", 0
prompt4 BYTE	"How many quarters do you have?", 0
string  BYTE	   40 DUP (?)
resultLbl BYTE	"Coin Information", 0
sum	 BYTE	  11 DUP (?), 0

.CODE
_MainProc PROC
		input	 prompt1, string, 40; read ASCII characters
		atod	  string	; convert to integer
		mov	  pennies, eax; store in memory

		input	 prompt2, string, 40; repeat for second number
		atod	  string
		mov	  nickels, ebx
		
		input	 prompt3, string, 40; read ASCII characters
		atod	  string	; convert to integer
		mov	  dimes, ecx; store in memory

		input	 prompt4, string, 40; repeat for second number
		atod	  string
		mov	  quarters, edx
		
		mov	 eax, pennies; pennies to EAX
		mov	numberOfCoins, eax; numberOfCoins = number of pennies
		mov	total, eax; total = pennies
		
		mov	 ebx, nickels; nickels to EBX
		add	  numberOfCoins, ebx; add numberOfNickels to numberOfCoins
		mul	  numberOfNickels, 5; multiply numberOfNickels by 5
		add	  total, ebx; total = total + 5*numberOfNickels
		
						
		mov	ecx, dimes; dimes to ECX
		add	 numberOfCoins, ecx; add numberOfDimes to numberOfCoins
		mul	 numberOfDimes, 10; total = total + 10*numberOfDimes
		add	 total, ecx
	 									
		mov	  edx, quarters; quarters to EDX
		add	   numberOfCoins, edx; add  numberOfQuarters to numberOfCoins
		mul	   numberOfQuarters, 25; total = total + 25*numberofQuarters
		add	   total, edx								
		
		dtoa	sum, eax; convert to ASCII characters
		output  resultLbl, sum; output label and sum

		mov	 eax, 0	; exit with return code 0
		ret
_MainProc ENDP
END						; end of source code




I know the mul command doesn't have the right syntax, but I have no idea how to write that command. Also, I am currently using 4 different registers. Is there a way to use just the EAX register?

Thanks in advance!

This post has been edited by Wilbur: 08 October 2008 - 10:10 AM


Is This A Good Question/Topic? 0
  • +

Replies To: Assembly Language

#2 TheFlipside  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 9
  • Joined: 09-August 07

Re: Assembly Language

Posted 09 October 2008 - 05:27 AM

Ok, first let me check if I understand it well...
You want to know if you can just use the EAX for the MUL opcode to multiply things?

Well to answer this question: Yes and there is no other way then using EAX.
MUL will put the final result of the operation in EAX, that is how the opcode is defined.

But I must confess that I don't understand your code...
First you declare the variables which is ok, but then you use in the main code several times the next command:
input	 prompt1, string, 40; read ASCII characters



And then you use different registers which suddenly appear to have the address (i suppose) as their value...
(first EAX, then EBX etc.)

A function always returns its result in the same register (probably EAX) or on the stack. To read from stack use:

POP EAX



this loads the first value from the stack into register EAX.

If this sounds all unfamiliar please read some tuts on the basics of assembler. When this is your first assembler project, then you are on the good way!

Please let me know what the exact problems and I will try to help you.
(I don't think it is usefull that I give you the correct code already, I assuming that you are trying to understand and learn, which means:
Usus Magister Est Optimus - Experience is the best teacher)
Was This Post Helpful? 0
  • +
  • -

#3 David W  Icon User is offline

  • DIC supporter
  • member icon

Reputation: 275
  • View blog
  • Posts: 1,778
  • Joined: 20-September 08

Re: Assembly Language

Posted 09 October 2008 - 07:37 AM

Quote

If this sounds all unfamiliar please read some tuts on the basics of assembler. When this is your first assembler project, then you are on the good way!

Please let me know what the exact problems and I will try to help you.
(I don't think it is usefull that I give you the correct code already, I assuming that you are trying to understand and learn, which means:
Usus Magister Est Optimus - Experience is the best teacher)


Try HLA ... a much more user friendly assember ... and here is an 'intro' course for it: ( at these links )

http://developers-he...index.php/topic,46.0.html

http://docs.google.c..._...atest&pli=1


Here is a little demo HLA program ...

program add_nums;


#include( "stdlib.hhf" )


// declare three integer variables in the static memory space

static
	num1:   int32:=	23;   	// initialize num1 to 23
	num2:   int32:=	77;   	// initialize num2 to 77
	sum:	int32;				// sum is not initialized here


begin add_nums;

	stdout.put( "The sum of ", num1, " and ", num2, " is " );
							
					// eax is a 32 bit register in the microprocessor 
	mov( num1, eax );	// move the (value of the) integer num1 into eax
	add( num2, eax );	// add the (value of the) integer num2 to (what's in) eax

	mov( eax, sum );	// move the 32 bit value now in the eax register into the 
					// 32 bit static memory that we reserved as 'sum'

	stdout.put( sum )

	//  output a newline character(s)
	stdout.newln();		

	// Also ... nl will output a newline character(s)
	stdout.put( nl "Enter an integer " ); 
	stdin.get( num1 );

	stdout.put( nl "Enter a second integer " );
	stdin.get( num2 );
	
	stdout.put( nl "The sum of ", num1, " and ", num2, " is " );

	mov( num1, eax );	
	add( num2, eax );	
	mov( eax, sum );	

	stdout.put( sum, nl nl "The end." nl nl );
	
end add_nums;

Was This Post Helpful? 0
  • +
  • -

#4 Wilbur  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 26-September 08

Re: Assembly Language

Posted 09 October 2008 - 09:17 AM

View PostTheFlipside, on 9 Oct, 2008 - 05:27 AM, said:

Please let me know what the exact problems and I will try to help you.
(I don't think it is usefull that I give you the correct code already, I assuming that you are trying to understand and learn, which means:
Usus Magister Est Optimus - Experience is the best teacher)

Thanks Flip. I definitely agree with you. As frustrating as writing good code can be, it is just something you have to mostly figure out on your own. Unless you struggle enough with it first, you will never learn anything. I will work on it some more this afternoon and repost tonight. I really appreciate your help!
~ Wilbur

This post has been edited by Wilbur: 09 October 2008 - 09:18 AM

Was This Post Helpful? 0
  • +
  • -

#5 David W  Icon User is offline

  • DIC supporter
  • member icon

Reputation: 275
  • View blog
  • Posts: 1,778
  • Joined: 20-September 08

Re: Assembly Language

Posted 10 October 2008 - 04:30 AM

Writing good code should be fun ... not frustrating.

Hey try HLA ... eh ?

See this HLA code I just put together to show you how HLA can make your work ... fun :D

program ChangeReturned;

#include( "stdlib.hhf" )

?@nodisplay := true;

procedure getCents; @returns( "eax" );
begin getCents;
	try
		stdout.puts( nl "Enter the number of cents to convert: " ); 
		stdin.flushInput();
		stdin.getu32(); // returns uns32 value input in eax 
	anyexception
		mov( 0, eax ); // return ZERO if 'bad data' entered for 'cents' ...
		stdout.puts( "Must enter a number in the range 0...(2^32 -1)." nl );
	endtry;
	
end getCents;

procedure computeCoins( denomination: uns32; var amountLeft: uns32 ); @returns( "eax" );
begin computeCoins;
	push( ebx );
	push( edx );
	
	mov( amountLeft, ebx ); // ebx holds the address of the value
	mov( (type uns32 [ebx]), eax ); // eax now holds the VALUE of amountLeft //*1*//

	// 'DIV' divides the 64 bit value in EDX:EAX by the operand
	// leaving the quotient in EAX and the remainder in EDX.
	// 'div' is used below ...
	
	// Firstly, finish initializing the  'edx:eax' 64 bit 'register' ...
	mov( 0, edx );
	
	// int number = amountLeft / denomination;
	div( denomination, edx:eax ); // Note that eax was set at //*1*// above
	// mov( eax, number ); //Note: eax now holds the quotient i.e. the 'return value' 
	
	// and 'update' ... amountLeft = amountLeft % denomination;
	mov( edx, (type uns32 [ebx]) ); // amountLeft value returned by ref
	
	pop( edx );
	pop( ebx );
	// return number
	// mov( number, eax ); // eax already holds the 'number'
end computeCoins;

procedure again; @returns( "al" );
begin again;
	stdout.puts( nl nl "More (y/n) ? " ); 
	stdin.flushInput();
	stdin.getc();
	if( !( al == 'n' || al =='N') ) then
		mov( true, al );
	else
		mov( false, al );
	endif; 
end again;

procedure computeAndDisplay( cents: uns32 ); 
begin computeAndDisplay;

 	stdout.puts( nl stdio.tab "loonies	  : " ); 
 	stdout.putu32( computeCoins(100, cents) );
 	
	stdout.puts( nl stdio.tab "half-dollars : " );
	stdout.putu32(  computeCoins(50, cents) ); 
	
 	stdout.puts( nl stdio.tab "quarters	 : " ); 
 	stdout.putu32(  computeCoins(25, cents) );	
 	
 	stdout.puts( nl stdio.tab "dimes		: " );
 	stdout.putu32(  computeCoins(10, cents) );
 	
	stdout.puts( nl stdio.tab "nickles	  : " );
	stdout.putu32(  computeCoins( 5, cents) );
	
	stdout.puts( nl stdio.tab "pennies	  : " );
	stdout.putu32(  cents ); 
	
end computeAndDisplay;



begin ChangeReturned;

	stdout.puts
	(
		"This program is intended to take 1-99 or more cents " 
		"and tell you how many" nl nl
		stdio.tab "loonies	  :" nl
		stdio.tab "half-dollars :" nl
		stdio.tab "quarters	 :" nl
		stdio.tab "dimes		:" nl
		stdio.tab "nickles	  :" nl
		stdio.tab "pennies	  :" nl
	);
	repeat
		computeAndDisplay( getCents() );
	until( !again() ); 
	
end ChangeReturned;

This post has been edited by David W: 10 October 2008 - 02:52 PM

Was This Post Helpful? 0
  • +
  • -

#6 Wilbur  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 26-September 08

Re: Assembly Language

Posted 14 October 2008 - 11:13 AM

That does make a lot more sense. However, I need it written in 80x86 assembly language and I really don't understand how the mul operator is supposed to be used. I have worked with this program over the weekend and just have no idea where to go next. Any ideas/help would be greatly appreciated! This is my new code, although not much as changed other than changing all the registers to EAX.

; Purpose: Counting coins problem

.586
.MODEL FLAT

INCLUDE io.h		  ; header file for input/output

.STACK 4096

.DATA
pennies DWORD   ?
nickels DWORD   ?
dimes DWORD   ?
quarters DWORD   ?
numberOfCoins DWORD ?
total DWORD ?
prompt1 BYTE	"How many pennies do you have?", 0
prompt2 BYTE	"How many nickels do you have?", 0
prompt3 BYTE	"How many dimes do you have?", 0
prompt4 BYTE	"How many quarters do you have?", 0
string  BYTE	40 DUP (?)
resultLbl BYTE  "Coin Information", 0
sum	 BYTE	11 DUP (?), 0

.CODE
_MainProc PROC
		input   prompt1, string, 40; read ASCII characters
		atod	string			; convert to integer
		mov	 pennies, eax	; store in memory

		input   prompt2, string, 40; repeat for second number
		atod	string
		mov	 nickels, eax
		
		input   prompt3, string, 40; read ASCII characters
		atod	string			; convert to integer
		mov	 dimes, eax		; store in memory

		input   prompt4, string, 40; repeat for second number
		atod	string
		mov	 quarters, eax
		
		
		
				mov		 eax, pennies	; pennies to EAX
				mov		numberOfCoins, eax; numberOfCoins = number of pennies
				mov		total, eax		; total = pennies
			 
				mov		eax, nickels	; nickels to EAX
		add		numberOfCoins, eax; add numberOfNickels to numberOfCoins
		mul		5			; multiply numberOfNickels by 5
		add		total, eax		; total = total + 5*numberOfNickels
								
		mov		eax, dimes		; dimes to EAX
		add		numberOfCoins, eax; add numberOfDimes to numberOfCoins
		mul		10			; total = total + 10*numberOfDimes
		add		total, eax
										
		mov		eax, quarters			  ; quarters to EAX
		add		numberOfCoins, eax		  ; add  numberOfQuarters to numberOfCoins
		mul		25					  ; total = total + 25*numberofQuarters
		add		total, eax							
		
			  dtoa	sum, eax		; convert to ASCII characters
			  output  resultLbl, sum				; output label and sum

			  mov	 eax, 0			; exit with return code 0
			  ret
_MainProc ENDP
END								; end of source code


This post has been edited by Wilbur: 14 October 2008 - 11:16 AM

Was This Post Helpful? 0
  • +
  • -

#7 Wilbur  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 26-September 08

Re: Assembly Language

Posted 14 October 2008 - 11:34 AM

The problem itself is not a difficult concept for me...it is all about the implementation of it in assembly language. Here is the code for this program written in C++. I was able to write this in about 5 minutes.

#include <iostream>
using namespace std;

int main()
{
	int pennies = 0;
	int nickels = 0;
	int dimes = 0;
	int quarters = 0;
	int dollars = 0;
	int totalCents = 0;
	int cents;
	
	cout <<"Enter # of pennies: ";
	cin >> pennies;
	cout <<"Enter # of nickels: ";
	cin >> nickels;
	cout <<"Enter # of dimes: ";
	cin >> dimes;
	cout <<"Enter # of quarters: ";
	cin >> quarters;
	
	totalCents = pennies + ( nickels * 5 ) + ( dimes * 10 )
			+ ( quarters * 25);
	
	dollars = totalCents / 100;
	cents = totalCents % 100;
			
	
	cout << "Total cents: " << totalCents << endl;
	cout << "Dollars	: " << dollars << endl;
	cout << "Cents		: " << cents << endl;
	
	return 0;
}



I really just don't understand how to do this kind of thing in assembly.
Was This Post Helpful? 0
  • +
  • -

#8 David W  Icon User is offline

  • DIC supporter
  • member icon

Reputation: 275
  • View blog
  • Posts: 1,778
  • Joined: 20-September 08

Re: Assembly Language

Posted 14 October 2008 - 01:49 PM

Quote

I really just don't understand how to do this kind of thing in assembly.


Did you take a look at the HLA code I sent you ... The idea of HLA is to use the High level coding where time is not so critical or to more quickly prototype your scheme ... and get it working and tested ... (And Randy also designed HLA to leverage your knowledge of other languages like C/C++ to fast track your way into Assembly Programming.)

Then if you need to speed some sections up a little, (actually the high level code is all now rewritten in fairly optimized low level code) ... you may be able to shave some time off, by taking each of the HLA structures that you used in HLA and re-coding each, as you wish, in low level. This is a good game plan to attack any program of much size at all. HLA was designed firstly to teach good coding style. Randy Hyde is a real pro at what he does ... The newest versions of HLA are now written in a previous version of HLA.

Shalom,

David

P.S.

This is where most of the real work gets done ...
(I use eax, ebx, and edx; ... eax returns the number of each denomination,
ebx holds a pointer, I need edx:eax to hold 64 bits when I divide a 32 bit number into it ... the quotient is left in eax ... the remainder in edx)

procedure computeCoins( denomination: uns32; var amountLeft: uns32 ); @returns( "eax" );
begin computeCoins;
	push( ebx );
	push( edx );
	
	mov( amountLeft, ebx ); // ebx holds the address of the value
	mov( (type uns32 [ebx]), eax ); // eax now holds the VALUE of amountLeft //*1*//

	// 'DIV' divides the 64 bit value in EDX:EAX by the operand
	// leaving the quotient in EAX and the remainder in EDX.
	// 'div' is used below ...
	
	// Firstly, finish initializing the  'edx:eax' 64 bit 'register' ...
	mov( 0, edx );
	
	// int number = amountLeft / denomination;
	div( denomination, edx:eax ); // Note that eax was set at //*1*// above
	// mov( eax, number ); //Note: eax now holds the quotient i.e. the 'return value'
	
	// and 'update' ... amountLeft = amountLeft % denomination;
	mov( edx, (type uns32 [ebx]) ); // amountLeft value returned by ref
	
	pop( edx );
	pop( ebx );
	// return number
	// mov( number, eax ); // eax already holds the 'number'
end computeCoins;



I pass in two values each time ... and two new values returned each time

The denomination, to divide by, was passed in by value, (the default in HLA)
The amount left was passed in and returned by reference ( a 'var' in HLA)
I also returned, via eax, the number of coins for that denomination

That is a BLOCK of code that keeps getting repeated. I can make it a macro, or a procedure, as I wish, in HLA. ( I choose a procedure to allow returning a value in eax, that I hand to a print function each time it is called. That print function first calls for that returned value of eax.)

Or ... I could just write the block and manage all the iterations myself ... but that may be a really bad design choice most of the time.

HLA was designed, among other things, to teach you how your procedures are actually implemented in low level code ... :) ... so you can do it yourself and you will then know ... if it's really appropriate.

This post has been edited by David W: 14 October 2008 - 02:40 PM

Was This Post Helpful? 0
  • +
  • -

#9 Wilbur  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 26-September 08

Re: Assembly Language

Posted 15 October 2008 - 02:35 PM

This code will output the number of cents, but only for the quarters.

Example input: pennies = 1. nickels = 1. dimes = 1. quarter = 1.
Example output: 25

Could someone please help me fix this? It is supposed to add up all the cents.


.MODEL FLAT

INCLUDE io.h		; header file for input/output

.STACK 4096

.DATA
pennies DWORD   ?
nickels DWORD   ?
nickel DWORD 5
dimes DWORD   ?
dime DWORD 10
quarters DWORD   ?
quarter DWORD 25
numberOfCoins DWORD ?
total DWORD ?
prompt1 BYTE	"How many pennies do you have?", 0
prompt2 BYTE	"How many nickels do you have?", 0
prompt3 BYTE	"How many dimes do you have?", 0
prompt4 BYTE	"How many quarters do you have?", 0
string  BYTE	40 DUP (?)
resultLbl BYTE  "Coin Information", 0
sum	 BYTE	11 DUP (?), 0

.CODE
_MainProc PROC
		input   prompt1, string, 40; read ASCII characters
		atod	string	; convert to integer
		mov	 pennies, eax; store in memory

		input   prompt2, string, 40; repeat for second number
		atod	string
		mov	 nickels, eax
		
		input   prompt3, string, 40; read ASCII characters
		atod	string	; convert to integer
		mov	 dimes, eax; store in memory

		input   prompt4, string, 40; repeat for second number
		atod	string
		mov	 quarters, eax
		
		
		
		mov	 eax, pennies; pennies to EAX
		mov		numberOfCoins, eax; numberOfCoins = number of pennies
		mov		total, eax; total = pennies
		
		mov		eax, nickels; nickels to EAX
		add		numberOfCoins, eax; add numberOfNickels to numberOfCoins
		mul		nickel	; multiply numberOfNickels by 5
		add		total, eax; total = total + 5*numberOfNickels
							
		mov		eax, dimes; dimes to EAX
		add		numberOfCoins, eax; add numberOfDimes to numberOfCoins
 		mul		dime	; total = total + 10*numberOfDimes
		add		total, eax
									
		mov		eax, quarters; quarters to EAX
		add		numberOfCoins, eax; add  numberOfQuarters to numberOfCoins
		mul		quarter; total = total + 25*numberofQuarters
		add		total, eax							
		
		dtoa	sum, eax					; convert to ASCII characters
		output  resultLbl, sum			; output label and sum

		mov	 eax, 0	; exit with return code 0
		ret
_MainProc ENDP
END						; end of source code


This post has been edited by Wilbur: 15 October 2008 - 07:24 PM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1