Author Topic: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)  (Read 53692 times)

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
BEGINNING COMPUTER PROGRAMMING

 
(Using a Try it and See it approach)

                                                                                                                         
(AND ... a Computer Student's/Teacher's DREAM Introductory Computer Language - HLA)


Update: Update: please see this next link:

http://developers-heaven.net/forum/index.php/topic,2636.0.html


FREE homework help NOW available ...

You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/topic,2587.0.html


You may also want to see ...

http://developers-heaven.net/forum/index.php?topic=46.0

BEGINNING COMPUTER PROGRAMMING (using HLA and Python 3.1 and C++) 


http://developers-heaven.net/forum/index.php?topic=2599.0

Six Fast Steps to Programming in High Level Assembly (HLA)

 
 
Introduction:

 

To facilitate the solid insights provided in learning about computing by some exposure to Assembly Language, but also to provide a friendly and facile start for new programmers, HLA provides all the facility and power of Assembly Language, but with a user friendly syntax, yet offers many of the elegant structures of an HLL (High Level Language) like Pascal or C or even the OOP of a language like C++.  And so, going on to C, or C++, or any other modern HLL, will be more readily enabled, and with some real appreciation of what’s going on under the hood and inside the machine.

 

The author has successfully taught Computer Programming at a Canadian grade 7/8 Junior High and 9 to 12 High School level when PCs first became available using varied approaches, including using a personally authored simulated SIMPLE SIMON compiler running on a PC.   But his final approach, after which this course is being patterned, was the most fun, and also the most successful, for both students ... and teacher.

 

Please enjoy and profit from your work. Don't be afraid to make changes and see what happens.  Now dig in ... You may be surprised how much you will learn.

 

Shalom shalom,

David W. Zavitz

Toronto, Ontario, CANADA

dwzavitz@gmail.com

 
For arrangements to use this text beyond individual personal use, please contact the author at the above e-mail.

© (C) 2007-08-17

 

Acknowledgements:

This course and text would not be possible without the very gifted insights, teaching experiences, and programming skills of Randall Hyde,

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

the Author, Creator, and so far, the Sustainer of HLA. I also would like to acknowledge the tremendous encouragement given by my youngest son Matthew, who's recent Engineering need to know a little C++, and then Assembly ... provided the incentive for a little more then that, from dad, (which led to HLA and now this attempt to benefit beginning computer students in general.)  Also, I would like to thank my students at Scarborough Christian High School, who besides being very promising young ladies and gentlemen, provided exemplary feedback as we went along into some not yet fully charted territory.

 

 
Table of Contents:

Chapter 01: The Computer prints a message
Chapter 02: The Computer gets some input
Chapter 03: The Computer adds some numbers
Chapter 04: The Computer repeats a procedure
Chapter 05: The Basic Elements of computer programming … and low level example(s)
Chapter 06: The Computer rolls the dice … a first simulation
Chapter 07: First Memory Flow Lab
Chapter 08: Memory Flow Lab2
Chapter 09: Memory Flow Lab3
Chapter 10: HLA Data Types
Chapter 11: The Computer does some Algebra with real numbers ... and Input Data Validation
Chapter 12: Pointers, Strings, your own Types, Records, Arrays, and dynamic things on the fly!
Chapter 13: The Computer files its Records
Chapter 14: The Computer reads its Files
Chapter 15: The Computer updates (edits, deletes, sorts, chops-duplicates-in) its Files
Chapter 16: The Computer … vast OS’s … and the garbage collects?  (Operating Systems ... what is DOS?)
Chapter 17: The Computer delivers daily Manna ... (gui Canadien ... eh?)
Chapter 18: OOP ... goes the computer?
Chapter 19: OOP 2
Chapter 20: Shaping Moving OOP with HLA   ... a CLASS ACT ! (revised 2013-05-24)
« Last Edit: September 11, 2018, 01:59:31 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #1 on: May 17, 2013, 10:23:36 AM »
Chapter 01: The Computer prints a message



Teacher ... set's up each computer, (the presumption here is that you are using a Windows OS, but only minor changes may be needed to adapt this text to Linux, Mac OSX, FreeBSD, or in the future, when HLA is available for them, other OS's also), and ...

 
installs and configures HLA files in the directory c:\hla\

 
For finding everything regarding HLA:

http://216.92.238.133/Webster/

 
If you are a first-time HLA user, the best thing to do is download and run the HLA setup program hlasetup.exe. This version replaces both the HLA and freeHLA (fhla) versions from previous releases.

http://216.92.238.133/Webster/HighLevelAsm/HLADoc/HLARef/HLARef_pdf/03_InstallingHLA.pdf

 
Teacher … also, as needed, to show how to use Windows, some simple OS commands, from the command line like cd to a directory, or md or dir i.e. showing the contents of the current directory.  And also, as needed, to discuss folders, and folders inside folders, and the path to a file in some folder (i.e. the tree structure in organizing files on the disk.)

 
Student ... Create and go to the working directory c:\hla\projects  Note the use of rem indicates a remark or comment. No need for student to enter the rem or what comes after this here:

 
click start  (click on the Circle Shaped Icon in the Lower Left Corner of a Windows 7 OS Screen)
click run  (but skip to next command below here ... if you are using Windows 7 OS ... or later)

enter cmd ( i.e. type in cmd and then press the Enter key)
enter (the following lines on the command line, but not rem or what comes after):

md projects  rem md projects means make a directory called projects
cd projects  rem cd projects means change to the directory projects

md chapt01_print_message
cd chapt01_print_message


Using a text editor program (already installed on your computer) like notepad.exe enter this next line (on the command line):

notepad.exe  print_message.hla

and then select yes when asked Do you want to create a new file?


Now enter these next five lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program print_message;

#include( "stdlib.hhf" )

begin print_message;

stdout.put( "Hello World!" );

end print_message;

 
Now save this as a file with the name print_message.hla         

(Make sure notepad doesn't save it as print_message.hla.txt)

(Enter dir to see the files in that DIRectory.  If it does have a .txt on the end of it, then rename it by entering the command below … (note: ren means rename)

ren  print_message.hla.txt  print_message.hla

or               

ren  print_message.txt  *.hla

Note: the file needs to end in .hla to let it be compiled by HLA

Now enter this command on the command line to compile/assemble, (the program text file just saved):

hla print_message.hla

Now run the new executable file just produced and see the output by entering this next command:

print_message.exe

See also: http://en.wikipedia.org/wiki/High_Level_Assembly

 
There is absolutely nothing stopping a programmer from writing the "Hello World" program in low-level assembly language, should they really want to do this. However, for the beginner who is experiencing their first hour with assembly language, the former code is far more approachable than this latter code (i.e., explaining the stack and how parameters are passed to a procedure via the stack is a relatively advanced subject).

Code: [Select]
program HelloWorld;

#include( "stdlib.hhf" )

static
// nl is concated to end of string at compile time
hwString : string := "Hello World ... low_level" nl;
prsEnter : string := "Press 'Enter' to continue/exit ... ";

begin HelloWorld;

// Push the address of the "Hello World" string
push( hwString );

// Call an HLA Standard Library function that
// will print the string whose address has
// been pushed on the stack.
call stdout.puts;

push( prsEnter );
call stdout.puts;
call stdin.readLn; // keep window open until the enter key is pressed

end HelloWorld;

 
Addendum:

A user, "Kocmotex" ...

http://developers-heaven.net/forum/index.php/topic,50.msg100.html#new

pointed out a typo error in the "Hello Word", that is now fixed :  "(Was) ... the use of a colon to terminate the third line of chapter 1's program ... employed as a device to demonstrate to the reader the operation of HLA's error reporting system" ?

It may be a good, even at this point, to try out making that "typo error" in your program. See what error message the HLA compiler/assembler presents to you, to help you find errors in your HLA program, so that you might fix them ... and then successfully make ... in this case ... the "print_message.exe" file.
« Last Edit: October 14, 2015, 02:27:37 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #2 on: May 17, 2013, 11:06:40 AM »
Chapter 02: The Computer gets some input

 

Student ... (Go to the working directory)

click start
click run

enter cmd

enter (the following on the command line):

cd c:\hla\projects

md chapt02_get_input

cd chapt02_get_input

 
Using a text editor like notepad.exe enter this next line (on the command line):

notepad.exe  get_input.hla (or just enter ... notepad  get_input.hla)

and then select yes when asked Do you want to create a new file?

 
Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program get_input;

#include( "stdlib.hhf" )

// after two front slash characters, 'comments' may be inserted
// into HLA programs

// declare first_name as a string variable in static memory and
// also reserve (i.e. allocate) space for 64 (byte-size) characters there

static
// declare first_name, last_name as strings in static memory ...
// and reserve (i.e. allocate) space for 64 byte-size characters
first_name: str.strvar(64);
last_name: str.strvar(64);

begin get_input;

stdout.put( "Please enter your first name: " );
stdin.get( first_name );

stdout.put( "Now enter your last name: " );
stdin.get( last_name );

stdout.put( "Are you really ", last_name, ", ", first_name, "?" );

end get_input;


Now save this file with the name get_input.hla

Now enter this following command, on the command line, to compile/assemble  (the program text file just saved) to produce a new executable file with the default name  get_input.exe

hla get_input.hla (or just enter the command line command:  hla get_input)

Now run the file get_input.exe by entering this next command, (on the command line):

get_input.exe (or just enter:  get_input)


An example of using stdin.a_gets() to dynamically allocate space for the input string as needed.

Code: [Select]
program get_input2;

#include( "stdlib.hhf" )

// after two front slash characters, 'comments' may be inserted into HLA programs
// declare firstname; lastname as string variables in var (dynamic) memory ...

var
firstname: string;
lastname: string;

begin get_input2;

stdout.put( "Please enter your first name: " );
stdin.a_gets();
mov( eax, firstname );

stdout.put( "Now enter your last name: " );
stdin.a_gets();
mov( eax, lastname );

stdout.put( "Are you really ", lastname, ", ", firstname, "?" nl );
str.free( lastname );
str.free( firstname );

end get_input2;
« Last Edit: May 19, 2013, 01:18:27 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #3 on: May 17, 2013, 11:15:54 AM »
Chapter 03: The Computer adds some numbers

 

Student ... (Go to the working directory)

click start
click run

enter cmd

then enter (on the command line):

cd c:\hla\projects

md chapt03_add_nums

cd chapt03_add_nums

 
Using a text editor like notepad.exe enter this next line (on the command line):

notepad  add_nums.hla

and then select yes when asked Do you want to create a new file?


Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):

Code: [Select]
program add_nums;

#include( "stdlib.hhf" )

// declare three 32 bit integer variables in the HLA static memory space

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

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 bits of static memory that we reserved and called 'sum'                       

stdout.put( sum )
stdout.newln();  // output an appropriate carriage return/newline character(s)

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

// Note: ok to leave off comma here, as adjacent strings are all concatenated together
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 );
stdout.newln();  // output an appropriate carriage return/newline character(s)

end add_nums;

 
Now save this file with the name add_nums.hla

Now enter this command on the command line to compile/assemble, (the program text file just saved), producing the executable file with the name add_nums.exe

hla add_nums.hla  (or just enter:  hla add_nums)

Now run the file add_nums.exe by entering this next command (on the command line), and observe:

add_nums.exe (or just enter the now executable command:  add_nums)
« Last Edit: May 19, 2013, 01:24:39 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #4 on: May 17, 2013, 11:27:35 AM »
Chapter 04: The Computer repeats a procedure

 

Student ... (Go to the working directory)

click start
click run

enter cmd

then enter (on the command line):

cd c:\hla\projects

md chapt04_repeat_proc

cd chapt04_repeat_proc


Using a text editor like notepad.exe enter this next line (on the command line):

notepad  repeat_proc.hla

and then select yes when asked Do you want to create a new file?


Now enter these lines into the text editor workspace, (i.e. copy and paste the lines into the text editor workspace):
 
Code: [Select]
program repeat_proc;

#include( "stdlib.hhf" )

static
done: boolean:= false; 

// The above reserves a byte of static memory and those 8 bits of
// memory space are now referred to (by the name) 'done' ...
// The value is initialized to 'false' i.e. 0000_0000

// Note: HLA can presently address 2^32 bytes of memory, so it takes a 32 bit
// variable to be able to address each byte of memory available. The highest
// address addressable, 1111_1111_1111_1111_1111_1111_1111_1111, has all 32
// binary bits set.

// Note: the address to get to the memory location 'done' is a 32 bit address, but
// the memory space reserved for the boolean variable 'done' is just one byte


// The following procedure asks for two integers to be entered and then finds
// their sum. It then prints out the two integers just input, and also their sum.

procedure get_nums_find_sum;

// Now declare three 'automatic' variables to hold 32 bit integers
// This is done in this area AFTER the top 'procedure ...' line
// but BEFORE the 'begin ...' line

var
num1: int32; // These 'automatic' variables, inside the procedure's
num2: int32; // declaration section, are created EACH time 'called'.
sum: int32; // And when the procedure is EXITed, they are 'lost'

begin get_nums_find_sum;

stdout.put( "Enter an integer: " );
stdin.flushInput(); // clears the 'stdin' input buffer
stdin.get( num1 );

stdout.put( "Enter a second integer: " );
stdin.get( num2 );

stdout.put( "The sum of ", num1, " and ", num2, " is " );

mov( num1, eax );
add( num2, eax );
mov( eax, sum ); // the int32 (in 'var' memory) with label 'sum'
                    // now holds the 32 bit value of (num1 + num2)
    stdout.put( sum );

end get_nums_find_sum;

 

begin repeat_proc; // Ok now ... start the 'main' section of this program.

// This section is where the 'repeat_proc.exe' program file begins to
// execute, when it first starts to run, after it is loaded into memory.

repeat // This marks the top of the repeat loop structure.

get_nums_find_sum(); // now execute this procedure we defined above

// We could call the 'macro' stdout.put which passes two nl
// OS appropriate codes and the string "Again (y/n) ? " ... each to
// appropriate procedure calls of the stdout library 'put' function ...

// but here, ok to use "stdout.puts( someString );" since the ...

stdout.puts( nl nl "More (y/n) ? " ); // strings here all get concatenated together by the compiler

// flushInput() is a library procedure and is in
// the 'stdin' namespace in HLA
stdin.flushInput(); // this flushes any characters like 'nl' that were
// left in the stdin buffered input stream

stdin.getc(); // puts the first character entered into 'al' (al is an 8 bit register,
// the lowest 8 bit byte of 'eax', eax is a 32 bit register)

if( al = 'n' ) then // if the 8 bits in 'al' match the eight bits in
// the ASCII representation of the character 'n' ... then

mov( true, done );

// move the 8 bit value for 'true' into the 8 bits of memory the computer
// refers to by (the name of) 'done'

elseif( al = 'N' ) then // now check, if need to,
// if a capital 'N' character was entered
mov( true, done );

else // if, and only if, neither of above two checks were true,
// then do this section ...
// output a string (that gets all concatenated together
// before assembled by HLA)
stdout.puts( nl "Ok ... Here we go again." nl );

endif;  // This marks the 'end' of the if..elseif...elseif..else..endif structure.

until( done ); // This marks the bottom of the 'repeat/until' structure.

// This 'repeat..until' structure is always traversed at least once,
// since the 'condition' to exit is NOT tested UNTIL the end.

// If the value of the boolean variable is 'true'
// the loop is exited. Otherwise, it begins again
// right after the top 'repeat' (address in the memory).

end repeat_proc;


Now save this text file with the name repeat_proc.hla

Now enter the following command on the command line to compile/assemble, (the program text file just saved), producing the executable file with the name repeat_proc.exe

hla repeat_proc.hla  (or just enter this command:  hla repeat_proc)

Now run the file repeat_proc.exe by entering this next command (on the command line).  Then supply suitable input and observe:

repeat_proc.exe  (or just enter:  repeat_proc)



Notice the 'done' procedure call used below, an example of an HLA function, (a procedure that returns a value.)

Code: [Select]
program repeat_proc2;

#include( "stdlib.hhf" )

procedure get_nums_find_sum;
begin get_nums_find_sum;
stdout.puts( "Enter an integer: " );
stdin.flushInput();
stdin.geti32();
mov( eax, ebx );

stdout.puts( "Enter a second integer: " );
stdin.flushInput();
stdin.geti32();

stdout.put( "The sum of ", (type int32 ebx), " and ", (type int32 eax), " is " );
add( ebx, eax );
stdout.puti32( eax );
end get_nums_find_sum;

procedure done; @returns( "al" );
begin done;
stdout.puts( nl "Done (y/n) ? " );
stdin.flushInput();
stdin.getc();
if( al == 'y' || al == 'Y' ) then
mov( 1, eax);
else
stdout.puts( "Ok ... Here we go again." nl );
mov( 0, eax );
endif;
end done;


begin repeat_proc2;

repeat
get_nums_find_sum();
until( done() );

end repeat_proc2;



And note the input validation procedure (function) added below ... Now the program won't crash on bad numeric input,

Code: [Select]
program repeat_proc3;

#include( "stdlib.hhf" )

procedure getValidInt( msg:string ); @returns( "eax" );
begin getValidInt;
forever
try
stdout.put( msg );
stdin.flushInput();
stdin.geti32(); // May raise an exception.
unprotected
break;
exception( ex.ValueOutOfRange )
stdout.put( "Value was out of range, re-enter please ..." nl );
exception( ex.ConversionError )
stdout.put( "Value contained illegal char's, re-enter please ..." nl );
endtry;
endfor;
end getValidInt;

procedure get_nums_find_sum;
begin get_nums_find_sum;

mov( getValidInt( "Enter a first integer: " ), ebx );
getValidInt( "Enter a second integer: " );

stdout.put( "The sum of ", (type int32 ebx), " and ", (type int32 eax), " is " );
add( ebx, eax );
stdout.puti32( eax );
end get_nums_find_sum;

procedure done; @returns( "al" );
begin done;
stdout.puts( nl "Done (y/n) ? " );
stdin.flushInput();
stdin.getc();
if( al == 'y' || al == 'Y' ) then
mov( 1, eax);
else
stdout.puts( "Ok ... Here we go again." nl );
mov( 0, eax );
endif;
end done;


begin repeat_proc3;

repeat
get_nums_find_sum();
until( done() );

end repeat_proc3;
« Last Edit: May 19, 2013, 01:21:25 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #5 on: May 17, 2013, 11:28:25 AM »
Chapter 05 : The Basic Elements of a program & low level examples of branching

 

So far … we have

executed instructions in sequence,

executed a block of instructions if and only if a certain condition was met using an if..elseif..else..endif structure,

repeatedly executed a block of instructions until a condition was met.

labelled a block of instructions with a procedure name, and called for the execution of that block of instructions by using the procedure name as a command to execute that block, at the place where it is called from, in our program.

You may be surprised that all programs are mostly just various combinations of the above.

We have also learned some rudimentary house keeping:

We have told the computer where the program begins and where it ends:

Code: [Select]
program someProgramName; // The program starts here

begin someProgramName;   // program execution starts here, when program is run

 

end someProgramName;     // The program ends here

 
Notice the semi-colon characters that tell the compiler that we have finished an instruction, (similar to the period at the end of a sentence.)

See: http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda2.html#1011925


We have also told the computer which  (library of) functions it is to recognize.

Code: [Select]
program  testing123;

#include(  "stdlib.hhf"  ) // include the file stdlib.hhf from the HLA include folder

begin testing123;

    stdout.put("Ok. Testing ", 1234567890 );  // just to give some output

end testing123;

 
Notice the # character. It instructs the compiler here to include the standard library header file.  Also notice that a semi-colon, at the end of that instruction to the compiler, is NOT used.

If you wanted to break up a long program file into sections, or store some procedure in a file to be reused later, for example, if you had the declaration/definition of say,  procedure myDoIt, saved in a text file in your working directory, or in the HLA include directory, with the name myDoIt.hhf, you could then ask the compiler to include that file like this:

#include (  "myDoIt.hhf"  )

You could insert this line in your .hla file in the include section, (like thus):

#include( "stdlib.hhf")
#include ( "myDoIt.hhf" )

Then, at compile time, the HLA compiler/assembler will insert the text of that file into the program(s) then being compiled, just as if you had copied and pasted in that text - at that location, (and then saved your thus modified someName.hla program, before compiling.)


Also, we have told the computer where (and how) to place some data in memory so that it can be accessed where ever appropriate in the program, by name:

Code: [Select]
program compNamNum;

#include(  "stdlib.hhf"  )

static
cName: string:= "Dumb Computer"; // the 32 bit address in static
// memory of the 14+ byte constant
// character string in readonly
// memory

cNumb: int32:= 1234567890; // the 32 bit space in static
// memory for an integer


begin compNamNum;

// stdout.put( ... ) is a function in the standard library
// in the ‘stdout’ namespace, ‘nl’ is the HLA for ‘new line’ for all OS’s
stdout.put( "The name of this computer is ", cName, nl );
stdout.put( "The number of this computer is ", cNumb, nl nl );

end compNamNum;


And we have told the computer where (and how) to place some procedures in memory so that they can be accessed by name, where ever appropriate in the program:

Code: [Select]
program  test_showNameNumb;

#include(  "stdlib.hhf"  )

// Note the syntax for passing a string and number to the following procedure ...
// (A procedure must be declared/defined before it can be called by a program.)
// 1st variable passed is a string;  2nd  is an int32; NOTE! ‘;’ separator

procedure printout( cNam: string; cNum: int32 );
begin printout;

stdout.put( "The name.number of this computer is ", cNam, ".", cNum, nl );

end printout;

 
begin test_showNameNumb;

// Note that 1st passed is a constant string, 2nd passed is a constant int
// Note the ‘,’ separator used between parameters
// when procedures are called ...

printout( "1_Dumb_Computer", 123456789 );
printout( "2_Dumb_Computer", 234567890 );
printout( "3_Dumb_Computer", 345678901 );

end test_showNameNumb;


For an assignment, create a suitable folder like c:\hla\projects\chapt05_myWork … Then,  in it:

Using your text editor, create your version, i.e. the file basic_shell2.hla, having just the 3 line (i.e. the bare bones) shell of an HLA program.  Then compile it and run it.  Is there any output? Why or why not?

  (a) Create the file compNamNum2.hla to reflect your version of an HLA program that outputs the Name and the Number of some computer of your imagination. Compile and run it.  (b) Now leave off some (for example, the last) closing semi-colon in your program and try compiling it now.  Note the error message(s) and see if you can follow them to correct the error(s). (c) Make other errors, preferably, one at a time, and see if you can follow the compiler messages to fix these syntax errors.

Create the file test_showNameNumb2.hla where you will have the program ask for a name to be input and then a number. Then display what was input and ask if they were input correctly.  If correct, quit with a message saying that they were ok.  If data was not input correctly, then ask for the data to be input again.  You may input and test individually … or input both then check if both ok.  You may use something like this: static nameStr: = str.strvar(256); // so you have enough space to hold nameStr

 Modify your version of the above, to make the file showNameNumb3.hla using another repeat .. until(..) loop to ask 3 times for a name and number, while still, as in the above,  checking each time if the data that was input was valid. Hint: static counter: int32:= 0; // 0 initial value before entering loop.  Then inside the loop inc(counter); or add( 1, counter); Then at the end of the loop, test if the counter has reached 3 yet. ( Or you can use a register like eax for your counter.  By the way, there is an ebx, an ecx, and an edx register also that you can use. These all are 32 bit registers. There are others!  ALSO, EAX has an AX part, the lower 16 bits.  AX, has an AH and AL part.  AH is the top 8 bits of AX.  AL is the bottom 8 bits of AX.  The same sort of thing happens for EBX, ECX, and EDX.  NOTE: When adding or comparing two values, or moving a value to/from a register or to/from a variable( i.e. a memory location), they must each have the same bit size; for example, they must both be 8 bits, <a byte>, 16 bits <a word>, or 32 bits, <a dword>. )

 
For (easy) bonus, how would you make your repeat .. until structure to loop forever? (Hint: There are several possible ways, that all really boil down to the same thing.) How might one exit from this forever loop? There are simpler ways to code for a forever loop. Try forever ... endfor;  NOTE! If you want to find some help on how to code something fast, just Google it. For example when I just now googled HLA forever, this came up at the top:

 

http://safari.oreilly.com/1593270658/ns1593270658-CHP-15-SECT-3
O'Reilly - Safari Books Online - 1593270658 - Write Great Code ...


The following two code fragments demonstrate an HLA forever..endfor loop (along with a breakif) and the corresponding "pure" assembly code: ...
 
Code: [Select]
forever

    // << Code to execute (at least once)
    //  prior to the termination test >>

    breakif( termination_expression );

    // << Code to execute after the loop-termination test >>

endfor;


Converting a forever..endfor loop into pure assembly language is a trivial matter. All you need is a single jmp instruction that can transfer control from the bottom of the loop back to the top of the loop. The implementation of the break statement is just as trivial, it's just a jump (or conditional jump) to the first statement following the loop. The following two code fragments demonstrate an HLA forever..endfor loop (along with a break..if) and the corresponding "pure" assembly code:

Code: [Select]
// High-level forever statement in HLA:

forever

    stdout.put("Enter an unsigned integer less than or equal to five: ");
    stdin.get( u );
    breakif( u <= 5 );
    stdout.put("Error: the value must be in range zero to five." nl);

endfor;


Code: [Select]
// Low-level coding of the forever loop in HLA:

foreverLabel:

    stdout.put("Enter an unsigned integer less than five: ");
    stdin.get( u );
    cmp( u, 5 );            // i.e. compare the value of u with 5
    jbe endForeverLabel;    // jump to the bottom label if u <= 5
    stdout.put("Error: the value must be in range zero to five" nl);
    jmp foreverLabel;       // jump to the top label

endForeverLabel:


Of course, you can also rotate this code to create a slightly more efficient version:

Code: [Select]
// Low-level coding of the forever loop in HLA using code rotation:

jmp foreverEnter;

foreverLabel:

    stdout.put("Error: the value must be in range zero to five." nl);
   
foreverEnter:

    stdout.put("Enter an unsigned integer less than five: ");
    stdin.get( u );
    cmp( u, 5 );

ja foreverLabel; // jump to top label if u > 5


And yes … for more than you may ever need to know about HLA ... try this link:

http://webster.cs.ucr.edu/


And in particular, to see MUCH MORE about loops follow these links at:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.html

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/LowLevelControlStructsa4.html


A test program, containing the code snippet from the previous page (slightly enhanced) follows:

Code: [Select]
program lowlevel2; // my test program (of the code snippet-further optimized/commented)

#include( "stdlib.hhf" )

static
u: uns32;

begin lowlevel2;

// Low-level coding of the forever loop in HLA using code rotation:
jmp foreverEnter;

foreverLabel:
stdout.puts("Error: the value must be in the range 0..5" nl);

foreverEnter:
stdout.puts("Enter an unsigned integer less than or equal to five: ");
stdin.getu32(); // returns uns32 number in eax register
// mov( eax, u );
// cmp( u, 5 );
cmp( eax, 5 );
ja foreverLabel; // jump to top label if u > 5
mov( eax, u ); // since good data now ...
stdout.put( nl "Ok ... good data ... you entered: ", u, nl );

end lowlevel2;
« Last Edit: May 19, 2013, 01:27:02 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #6 on: May 17, 2013, 12:09:21 PM »
Chapter 06: The Computer rolls the dice … a first simulation

 

Ok … here is an interactive project with a little Google research to find out about the random function in the HLA library.

Create a sub folder in the \hla\projects\ folder with the name chapt06_randomNumber

With your text editor, start a new file called guessIt.hla and cut and paste a shell of an HLA program into it. Save it. Compile it to make sure it is good so far, (or fix it … so that it will compile with no significant error messages.)

Now let’s think about the bare bones of what we want the program to do:

I.     Announce what the program is about.

II.    Ask the user to input a guess in the range 2-12.

III.   Get the computer to select randomly a number in that range.

IV.   See if the number guessed matches the total on the die that the computer rolled

V.    Report the results

VI.   Ask if user wants to try again … or quit

 
Ok … let's get a shell started …

Code: [Select]
program  guessIt;

#include(  "stdlib.hhf"  )

// Note: procedure playgame is the main game ...

procedure playgame;

var
userNum: uns32;
die1: uns32;
die2: uns32;
diceSum: uns32;

begin playgame;

stdout.puts
(
nl
"THE COMPUTER will roll the dice AFTER" nl
"YOU ENTER a number in the RANGE 2..12" nl
"Ok ... what is your guess: "
);
stdin.flushInput();
stdin.get( userNum );

// The following tasks are yet to be coded:
// 1. get two random numbers 1..6 for each die
// 2. see if sum of die matches the number the user guessed
// 3. report success or falure

stdout.put( "You entered ", userNum, nl );

end playgame;

 
 
begin guessIt;

repeat // since we presume that the user wants to play at least
// one time, we can use the repeat..until structure
playgame();       
stdout.puts( nl "Play again (y/n) ? " );
stdin.flushInput();
stdin.getc(); // recall first character returned in lowest 8 bits of eax
// i.e. the al register
until( al = 'n' || al = 'N' ); // i.e. until n or N entered

end guessIt;


Ok … it compiles and runs ok so far, but did you notice that the user can enter numbers that are way out of range?


Let’s fix that this way: (We will pass the value to a function to validate it.)

Code: [Select]
// this 'function' returns true in al if x <= 12, otherwise it returns false

procedure isValid( x:uns32 ); @returns("al");

begin isValid;

    if(x <=12) then
        mov( true, al );
    else
        mov( false, al);
    endif

endisvalid;


Ok … let’s plug that in and check it out so far …

Code: [Select]
program  guessIt2;


#include(  "stdlib.hhf"  )


// this 'function' returns true in al if x <= 12, otherwise it returns false
procedure isValid( x:int32 ); @returns("al");
begin isValid;
if( x <= 12 ) then
mov( true, al );
else
mov( false, al);
endif;
end isValid;


// Note: procedure playgame is the main game …
procedure playgame;

var
userNum: int32;
die1: int32;
die2: int32;
diceSum: int32;

begin playgame;

stdout.puts
(             
nl "THE COMPUTER will roll the dice AFTER" nl
"YOU ENTER a number in the RANGE 2 to 12 ..." nl
);

repeat
stdout.puts( "Your guess 2..12 : " );
stdin.flushInput();
stdin.get( userNum );
until( isValid( userNum ) );

// the following is to do yet ...
// get two random numbers 1..6 for each die
// see if sum matches then ...  report success or falure

stdout.put( "You entered ", userNum, nl );

end playgame;

 

begin guessIt2;

repeat // since we presume that the user wants to play at least
// one time, we can use the repeat..until structure
playgame();       
stdout.puts( nl "Play again (y/n) ? " );
stdin.flushInput();
stdin.getc(); // recall first character returned in lowest 8 bits of eax                                                           
// i.e. the al register
until( al = 'n' || al = 'N' );

end guessIt2;


So far … so good. But let’s do that research on the HLA random function, (if HLA has one?)

Ok … google HLA random and here is what came up on top just now (2007-08-19):

rand.randomize(); // or call rand.randomize; (but this form used  here)

This function "randomizes" the seed used by the random number generators.  If you call rand.randomize, the random number generators should begin generating a sequence starting at a random point in the normal sequence put out by the random number generator.  The randomization function is based on the number of CPU clock cycles that have occurred since the CPU was last powered up.  This function uses the Pentium's RDTSC instruction, hence you should only call this function on machines that have this instruction available (Intel Pentium and later as well as other manufacturer's CPUs that have this instruction).  Because of the nature of the RDTSC instruction, you should not call rand.randomize frequently or you will compromise the quality of the random numbers (indeed, it's generally not a good idea to "randomize" a random number generator more than once per program invocation).

rand.range( startRange:int32; endRange:int32 ); @returns( "eax" );

This function generates a uniformly distributed random number in the range "startRange..endRange" (inclusive). This function generates its random numbers using the rand.random function. This function returns the value in the EAX register.

Or try this link: .... (to find new one)

Random Number Generators (rand.hhf)


Now let’s see if we can plug it in and get it working in our program … (and notice some changes? / deletions? / improvements? … that were made also.)

Code: [Select]
program  guessIt3;

 
#include(  "stdlib.hhf"  )

 
// This 'function' returns true in al if x is in the range 2..12,
// otherwise it returns false. The @display is turned off since it is
// not needed here.  This makes this procedure call more efficient.

procedure isValid( x:int32 ); @nodisplay; @returns("al");

begin isValid;

    if( x >= 2 && x <= 12 ) then  //  i.e. if x in range 2..12
        mov( true, al );
    else
        mov( false, al);
    endif;

end isValid;

 
// Note: procedure playgame is the main game

procedure playgame; @nodisplay;

var

    userNum:    int32;
    die1:       int32;
    die2:       int32;

begin playgame;

    stdout.puts
    (             
        nl
        "THE COMPUTER will roll the dice AFTER" nl
        "YOU ENTER a number in the RANGE 2 to12." nl nl
    );

    repeat

        stdout.puts( "Your guess 2..12 : " );
        stdin.flushInput();
        stdin.get( userNum );

    until( isValid( userNum ) );    // Note: userNum is first passed to isValid
                                    // Then isValid returns true or false               
                                    // get two random numbers 1..6 for each die
    rand.range( 1, 6 );             // returns random num 1..6 in eax
    mov( eax, die1 );               // and move value into die1
    rand.range( 1, 6 );             // returns random num 1..6 in eax
    mov( eax, die2 );               // and move value into die2
    add( die1, eax );               // eax now holds sum

    // see if sum matches
    if( eax = userNum ) then           
        stdout.puts( "MATCH!" nl );     // report success
    else
        stdout.puts( "NO match!" nl );  // report failure
    endif;
                     
    stdout.put
    (
        "You entered ", userNum, nl
        "And the computer rolled ", die1, " & ", die2,
        " or ", (type int32 eax), "." nl
    );

end playgame;


begin guessIt3;

    rand.randomize();   // We just want to call this once in our program,
                        // as per above info.

    repeat  // Since we presume that the user wants to play at least
            // one time, we can use the repeat..until structure.

            playgame(); // We pick two unique random numbers in range 1..6
                        // in each call.

            stdout.puts( nl "Play again (y/n) ? " );
            stdin.flushInput();
            stdin.getc();   // Recall, the first character is returned in
                            // lowest 8 bits of eax
                            // i.e. the al register
                           
    until( al = 'n' || al = 'N' );

end guessIt3;
« Last Edit: May 19, 2013, 01:28:11 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #7 on: May 17, 2013, 02:23:50 PM »
Chapter 06: The Computer rolls the dice … a first simulation ... continued ...



Well, these functions are working ok … but let’s make some more enhancements:

Let’s add a counter to keep track of the number of games.  And suppose that you started out with so many cents, say 100, at the beginning and win the number of cents, (the value you guessed), when there is a match … but lose the number (the same number of cents) you guess for the sum of the dice if there is NO match … (Let’s use global variable’s for these to keep the design simple, and also we can use registers, so we won’t have to pass these values back and forth to/from the procedures or to use pass by reference syntax, since this is supposed to be a simple simulation?)

 
The game will be over when all your starting cents are used up, … or … if you choose to quit, (or if by some long shot, the computer loses all its cents!)

Make a final report of the success or failure. (What you started out with. How much you were up/down.  Your new total and the computers new total. The number of games played.)

 
Are you ready to start programming?

Code: [Select]
program  guessIt4;               

#include( "stdlib.hhf" )

static // below are used as global variables
    cCents: int32;
    pCents: int32;
    cWins: int32:= 0;
    pWins: int32:= 0;         
    numGames: int32:= 0;


procedure getValidInt( msg:string; low:int32; high:int32  );@nodisplay;@returns( "eax" );
begin getValidInt;
    push( ebx );
    push( edx );
    forever
        try
            stdout.puts( msg );
            stdin.flushInput();
            stdin.geti32(); // May raise an exception.
        unprotected
            breakif( eax >= low && eax <= high );
            stdout.put( "Value was out of range ", low, "..", high, ", re-enter please ... " nl );
        exception( ex.ValueOutOfRange )
            stdout.put( "Value was out of range, re-enter please ... " nl );
        exception( ex.ConversionError )
            stdout.put( "Value contained illegal char's, re-enter please ..." nl );
        endtry;
    endfor;
    pop( edx );
    pop( ebx );
end getValidInt;
 

procedure playgame; @nodisplay; // Note: procedure playgame is the main game ...
var
    userNum:    int32;
    die1:       int32;
    die2:       int32;
begin playgame;

    stdout.puts
    (             
        nl "THE COMPUTER will roll the dice AFTER "
        "YOU ENTER a number in the RANGE 2 to 12." nl nl
    );

    mov( getValidInt( "Your guess 2..12 : ", 2, 12 ), userNum );

    // get two random numbers 1..6 for each die
    rand.range( 1, 6 ); // returns random num 1..6 in eax
    mov( eax, die1 ); // and move value into die1
    rand.range( 1, 6 ); // returns random num 1..6 in eax
    mov( eax, die2 ); // and move value into die2
    add( die1, eax ); // eax now holds sum

    // see if sum matches ...
    if( eax == userNum ) then       
        // note that edx and ebx were given initial values in the 'main' program section
        stdout.puts( "MATCH!" nl ); // report
        add( userNum, edx ); // player wins
        sub( userNum, ebx ); // computer loses
    else
        stdout.puts( "NO match!" nl ); // report failure
        sub( userNum, edx ); // player loses
        add( userNum, ebx ); // computer wins
    endif;

    stdout.put
    (
        "You entered ", userNum, nl
        "And the computer rolled ", die1, " & ", die2,
        " or ", (type int32 eax), "." nl
    );

end playgame;



begin guessIt4;

    rand.randomize();   // we just want to call this once in our program,
                        // as per above info

    mov( getValidInt( nl "Computer stakes 100..1000 (cents) : ", 100, 1000 ), cCents );
    mov( cCents, ebx ); // working copy in ebx

    mov( getValidInt( nl "Player stakes 100..1000 (cents) : ", 100, 1000 ), pCents );
    mov( pCents, edx ); // working copy in edx

    // since we presume that the user wants to play at least
    // one time, we can use the repeat..until structure
    repeat
    inc( numGames );   // here we go again so increment numGames
    playgame();        // we pick two unique random numbers
                       // in range 1..6 in each call
    stdout.puts( nl "Play again (y/n) ? " );
    stdin.flushInput();
    stdin.getc(); // recall first character returned in the lowest 8 bits of eax (i.e. the al register)
    until
(
        al == 'n' || al == 'N' || // i.e. until n or N selected ... or
        (type int32 ebx) <= 0 ||  // the value, taken as an integer, in ebx <= 0 ... or
        (type int32 edx) <= 0     // the value, taken as an integer, in edx <= 0
);

// don't allow, (i.e. correct for), 'in-hole' stuations ...

    if( (type int32 edx) < 0 ) then     // player in hole
        add( edx, ebx );                // i.e. decrease computer balance
        mov( 0, edx );                  // so now can up balance of player to zero
    elseif( (type int32 ebx) < 0 ) then // computer in hole
        add( ebx, edx );                // decrease player balance
        mov( 0, ebx );                  // so now can up balance of computer to zero
    endif;

stdout.put
(
nl "After ", numGames, " games, the computer has ",
(type int32 ebx), " cents", nl
"and the player has ", (type int32 edx), " cents", nl
);

    // Recall cCents, and pCents hold the starting staked values

    mov( ebx, eax );        // calculate the computer winnings
    sub( cCents, eax );
    mov( eax, cWins );

    mov( edx, eax );        // calculate the player winnings
    sub( pCents, eax );
    mov( eax, pWins );

if( cWins > 0 ) then  // computer wins

neg( pWins );  // take the negative of ( )
stdout.put
(
"The computer wins ", cWins,
" and the player loses ", pWins, nl
);
else // computer loses
neg( cWins );
stdout.put( "The player wins ", pWins, " and the computer loses ", cWins, nl );
endif;

stdout.puts( nl "Press 'Enter' to continue/exit ... " );
stdin.flushInput();
stdin.getc();

end guessIt4;


Here is a fun program using random numbers that I modified a little …

Code: [Select]
program testRandom;

// adapted from ...
// http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/IntegerArithmetic3.html

#include( "stdlib.hhf" )

/*
    Note:
    console.black   := 0;
    console.red     := 1;
    console.green   := 2;
    console.yellow  := 3;
    console.blue    := 4;
    console.magenta := 5;
    console.cyan    := 6;
    console.white   := 7;
*/

begin testRandom;

    console.cls();
    mov( 10_000, ecx );

    call rand.randomize;            // or rand.randomize();

    repeat

        // Generate a random X-coordinate
        // using rand.range.
        rand.range( 1, 78 );
        mov( eax, ebx );            // Save the X-coordinate for now.

        // Generate a random Y-coordinate
        // using rand.urange
        rand.urange( 1, 23 );
        mov( eax, edx );

        // Print an asterisk at
        // the specified coordinate on the screen.
        console.gotoxy( ebx, edx );
        rand.range( 0, 6 );         // no white foreground
        console.setAttrs( eax, 7 ); // all white background
        stdout.puts( "*" );

        // Repeat this 10,000 times to get
        // a good distribution of values.
        dec( ecx );

    until( @z ); // zero flag set when ecx becomes zero

    // Position the cursor at the bottom of the
    // screen so we can observe the results.
    console.gotoxy( 0, 23 );
   
    stdin.readLn();

end testRandom;
« Last Edit: May 18, 2013, 11:50:39 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #8 on: May 17, 2013, 03:21:44 PM »
Chapter 07: Memory Flow Lab

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab.hla

4.  Compile the program and run it. Study the comments and questions that are in the hla program, as well as the questions, (and answers), that appear on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab;

/*
 Also see:
 http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.html
*/

#include("stdlib.hhf")

static
    myCharArray:char[255];              // reserve 255 bytes of memory for 255 char's
    myChr:  char;                       // reserve 1 byte of memory for 1 character               
    myInt:  int32:= 12345;              // reserve 4 bytes, i.e. 32 bits, for an int

    // the following shows how to declare a 'pointer' type variable ...
    myP:    pointer to int32:= &myInt;  // now myP holds address of myInt

begin memoryFlowLab;

    // Note below that the ':' character notifies the compiler that
    // 'top' IS to be known, from here on, (in the program), as A LABEL
    // So now the running program HAS a label, (i.e. a name), to
    // refer to, if it needs to go to THAT ADDRESS.

top:
   
    // Note below, the 'no op', i.e. nop() means 'no operation'         

    // 1. How many bytes of program execution
    // memory does this nop(); take?

    // 2. How many bytes of program execution memory
    // do all these comments in the source file take?

    // 3. How many bytes of program execution memory
    // are BETWEEN the addresses given by 'top' and 'bot' ?

top2:
    nop(); 
next:
    add( myInt, eax );
next2:

    mov( & top, eax );       // '&' means 'take the address of'
    stdout.put( nl "The address of label top is ", eax );

    mov( &top2, eax );
    stdout.put( nl "The address of label top2 is ", eax );

    stdout.puts( nl "So how much space do 'comments' take in the '.exe' file?" );

    mov( &next, eax );
    stdout.put( nl nl "The address of label next is ", eax );
    stdout.puts( nl "How many bytes does the instruction nop() take in memory?" );

    mov( &next2, eax );
    stdout.put( nl nl "The address of label next2 is ", eax );
    stdout.puts( nl "How many bytes are used by the instruction 'add( myInt, eax )' ? " );
    sub( &next, eax );
    stdout.put( nl "(The answer, in hexidecimal ... ", eax, ")" );

    mov( &myCharArray, eax );
    stdout.put( nl nl "The address of variable myCharArray is ", eax );

    mov( &myChr, eax );
    stdout.put( nl "The address of variable myChr is ", eax );;

    mov( &myInt, eax );
    stdout.put( nl nl "The address of variable myInt is ", eax );

    mov( myP, eax );
    stdout.put( nl "And ALSO, value of variable myP= ", eax );
                     

    mov( &top, eax );           // eax holds address of 'top' label
    mov( &bot, ebx );           // ebx holds address of 'bot' label
    mov( ebx, ecx );            // now ecx ALSO holds the address of bot2

    sub( eax, ecx );            // i.e. subtract eax from ecx and
                                // store result in ecx

                                // ecx now holds the number of bytes
                                // from top to bot in the programs
                                // memory (while the program is runing
                                // i.e. executing in the computers 'ram')

    stdout.put
    (
        nl nl
        "What to learn:" nl nl    // Note: the compiler concatenates ADJACENT strings ... ok:)

        "The address of label 'top' is ", EAX, nl
        "The address of label 'bot' is ", EBX, nl,                     

        ebx, " - ", eax, " = ", ecx, " = ",
        (type int32 ecx) , nl nl

        "So there are ", ecx, " (in hex) bytes inside the running program,"
        nl "from the label 'top' to the label 'bot'." nl

        nl  "As the program flows, (i.e. executes), as we have written it "
        "from "
        nl "the address labelled 'top' to the address labelled 'bot' ... "             
        nl  "do the values of the addresses in memory decrease or increase? "
        nl nl "Press 'Enter' to continue/exit ... "
    );
   
    stdin.readLn();

bot:
   
end memoryFlowLab;
« Last Edit: May 19, 2013, 01:28:56 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #9 on: May 17, 2013, 03:23:32 PM »
Chapter 08: Memory Flow Lab2

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab2

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab2.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab2;

#include("stdlib.hhf")

// An example of initializing at the same time as declaring variables.
// We have printed out the value of the memory addresses of some variables, so
// lets ALSO print out the (typed) values in these addresses ...
static
    // reserve 256 bytes of memory for 256 char's. Note: (32*8) = 256
    // Note: '32 dup' means to duplicate [ .. ] 32 times in memory
    myCharArray:char[]:= 32 dup [ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ];

    // reserve 1 byte of memory for 1 character
    myChr:  char:= 'z';   
    // set p, a pointer to 'char', to hold the address of the first element in myCharArray
    p:      pointer to char:= &myCharArray;

begin memoryFlowLab2;

    mov( & myCharArray, eax );
    stdout.put( "The address of variable myCharArray is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray );
    mov( & myCharArray[0], eax );
    stdout.put( nl nl "The address of variable myCharArray[0] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[0] );
    mov( & myCharArray[1], eax );
    stdout.put( nl nl "The address of variable myCharArray[1] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[1] );
    mov( & myCharArray[254], eax );
    stdout.put( nl nl "The address of variable myCharArray[254] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[254] );
    mov( & myCharArray[255], eax );
    stdout.put( nl nl "The address of variable myCharArray[255] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[255] )
    mov( & myCharArray[256], eax );
    stdout.put( nl nl "The address of variable myCharArray[256] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myCharArray[256] )
    mov( & myChr, eax );
    stdout.put( nl nl "The address of variable myChr is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myChr, nl nl  );

    // ok here is an example using the HLA for..endfor loop structure
    // let's use a register as a counter to give the maximum speed counting ...
    for( mov( 0, ecx); ecx < 39; inc( ecx ) ) do
        stdout.put( myCharArray[ ecx ], " " );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all the above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl nl
    );

    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do
        lea( eax, myCharArray[ ecx ] ); // take address of each element and put it in eax
        stdout.put( " ", eax, myCharArray[ ecx ]:10,  nl );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all these above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...

    // Now ... print out some headers, right-adjusted in 10 character wide fields.

    stdout.put
    (
        nl nl, "address":10, "value":10, nl
    );

    mov( p, eax ); // move address of first byte into eax
    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do

        // (type char [ eax ]) = go to the address held in eax and ...
        // intrepret the byte, at that address, as a char
        stdout.put( " ", eax, (type char [ eax ]):10,  nl );
        inc( eax ); // go to next byte (address)

    endfor;

    mov( p, eax );
    add( 256, eax );
    stdout.put( nl " ", eax, (type char [ eax ]):10,  nl );
   
    stdout.put( nl nl "Press 'Enter' to continue/exit ... " );
    stdin.readLn();

end memoryFlowLab2;
« Last Edit: May 19, 2013, 01:29:21 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #10 on: May 17, 2013, 03:26:52 PM »
Chapter 09: Memory Flow Lab3

 
 
1.  Create (md) a sub-directory in the project folder.  Give it the name memoryFlowLab3

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name memoryFlowLab3.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program memoryFlowLab3;

#include("stdlib.hhf")

// An example of initializing at the same time as declaring variables.
// We have printed out the value of the memory addresses of some variables, so
// lets ALSO print out the (typed) values in these addresses ...

static

    // reserves 80 bytes of memory for 20 int32's. Note: (2*10*4bytes) = 80bytes
    // Note: '2 dup' means to duplicate [ .. ] 2 times in memory
    myInt32Array:   int32[]:=   2 dup [ 1,2,3,4,5,6,7,8,9,0 ];
    myInt32:        int32:=     987654321;

    // set p, a pointer to 'int32', to hold the address of the first element in myInt32Array
    p:  pointer to int32 :=     &myInt32Array;

begin memoryFlowLab3;

    mov( & myInt32Array, eax );
    stdout.put( "The address of variable myInt32Array is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array );

    mov( & myInt32Array[0], eax );
    stdout.put( nl nl "The address of variable myInt32Array[0] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[0] );

    mov( & myInt32Array[1*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[1*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[1*4] );

    mov( & myInt32Array[18*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[18*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[18*4] );

    mov( & myInt32Array[19*4], eax );
    stdout.put( nl nl "The address of variable myInt32Array[19*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[19*4] )

    mov( & myInt32Array[20*4], eax ); // overflow example ...
    stdout.put( nl nl "The address of variable myInt32Array[20*4] is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32Array[20*4] )

    mov( & myInt32, eax );
    stdout.put( nl nl "The address of variable myInt32 is ", eax );
    stdout.put( nl "The VALUE IN THAT ADDRESS is ", myInt32, nl nl  );

    // ok here is an example using the HLA for..endfor loop structure
    // let's use a register as a counter to give the maximum speed counting ...
    for( mov( 0, ecx); ecx < 20; inc( ecx ) ) do
        stdout.put( myInt32Array[ ecx*4 ], " " );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all the above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...
   
   

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl nl
    );

    for( mov( 0, ecx ); ecx < 20*4; add( 4, ecx ) ) do // add 4 since 4 bytes used for each int32
        lea( eax, myInt32Array[ ecx ] ); // take address of each element and put it in eax
        stdout.put( " ", eax, myInt32Array[ ecx ]:10, nl );
    endfor;

    stdout.puts
    (
        nl "Can you figure out all these above outputs?  Press 'Enter' to continue ... "
    );

    stdin.readLn(); // wait for 'Enter' key to be pressed ...
   
   

    // Now ... print out some headers, right-adjusted in 10 character wide fields.
    stdout.put
    (
        nl nl, "address":10, "value":10, nl
    );

    mov( p, eax ); // move address of first int32 into eax
    for( mov( 0, ecx ); ecx < 20; inc( ecx ) ) do
        // (type int32 [ eax ]) ... means to go to the address held in eax ...
        //  and then to intrepret the 4 bytes, at that address, as an int32
        stdout.put( " ", eax, (type int32 [ eax ]):10,  nl );
        add( 4, eax ); // go to next int32 (address)
    endfor;

    mov( p, eax );
    add( 20*4, eax );   // note: compiler/assembler does this calulation of 20*4
                        // when compiling/assembling the 'xxx.hla' file into the 'xxx.exe' file

    stdout.put( nl " ", eax, (type int32 [ eax ]):10,  nl );   

    // recall '[eax]' means to goto the address held in eax
    // (type int32 [ eax ]) means to interpret as an int32 the 4 bytes at the address (pointed to by the value) in eax
    // eax, without square brackets, means take the value in eax
    // (type int32 eax ) would mean to interpret as an int32 the 4 bytes in eax

end memoryFlowLab3;
« Last Edit: May 19, 2013, 12:46:36 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #11 on: May 17, 2013, 03:29:59 PM »
Chapter 10: HLA Data Types

 

1.  Create (md) a sub-directory in the project folder.  Give it the name hlaTypes

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program the name hlaTypes.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run (execute) the program.

Code: [Select]
program types; // some HLA data types

#include( "stdlib.hhf" )

static

    b:      byte:=  65;
    u8:     uns8:=  $ff;
    i8:     int8:=  127;
    ca:     char:=  'a';
    cz:     char:=  'z';
    ccA:    char:=  'A';
    ccZ:    char:=  'Z';
    w:      word:=  $ffff;
    u16:    uns16:= $FFFF;
    i16:    int16:= $7fff;
    dw:     dword:= $ffff_ffff;
    u32:    uns32:= $ffffffff;
    i32:    int32:= $7fff_ffff;

    r32:    real32:= 1234567890.123e-47;
    r64:    real64:= 1234567890.123e-316;
    s:      string:= "Pausing now. Press 'Enter' to continue ...";

    len_s:  int32;

begin types;

    str.length( s ); // library function returns string length in eax
    mov( eax, len_s );
   
    stdout.put
    (
        "b=", b, " as byte (i.e. hex)"
        " =", (type uns8 b), " as uns8"           
        " =", (type char b), " as char" nl
        "u8=", u8, nl
        "i8=", i8, nl nl
        "ca=", ca,
        " =", (type byte ca), " as byte"
        " =", (type uns8 ca), " as uns8" nl
        "cz=", cz, nl
        "ccA=", ccA,
        " =", (type byte ccA), " as byte"
        " =", (type uns8 ccA), " as uns8" nl
        "ccZ=", ccZ, nl nl
        "w=", w, nl
        "u16=", u16, " (max uns16)" nl
        "i16=", i16, " (max int16)" nl nl
        "dw=", dw, nl
        "u32=", u32, " (max uns32)" nl
        "i32=", i32, " (max int32)" nl nl
        "r32=", r32,  nl
        "r64=", r64,  nl nl,
        "s='", s, "' (The string length of s =", len_s, ") "
    );
 
    stdin.readLn(); stdout.newln();

    for( mov( '0', cl ); cl <= '9'; inc( cl ) ) do
        stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( '0', cl ); cl <= '9'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln(); stdout.newln();

    for( mov( 'A', cl ); cl <= 'Z'; inc( cl ) ) do
       stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( 'A', cl ); cl <= 'Z'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln();

    for( mov( 'a', cl ); cl <= 'z'; inc( cl ) ) do
        stdout.put( (type char cl), "  " );
    endfor;

    stdout.newln();

    for( mov( 'a', cl ); cl <= 'z'; inc( cl ) ) do
        stdout.put( cl, " " );
    endfor;

    stdout.newln();
    stdin.readLn();

end types;
« Last Edit: May 19, 2013, 01:30:02 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #12 on: May 17, 2013, 03:41:16 PM »
Chapter 11: The Computer does some Algebra with real numbers ... and Input Data Validation

 

1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt11_realMath

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name realMath.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.

Code: [Select]
program realMath; // finds the running average of test scores

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;

begin realMath;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions.

    finit();                // initialize floating point (math) unit

    stdout.puts
    (         
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate:"
        nl nl
    );

    repeat
   
        inc(count);
        stdout.puts( "Enter score: " );
        stdin.flushInput();
        stdin.get( score );
        mov( score, eax );
        add( eax, totScores );

        stdout.puts( "Enter outOf: " );
        stdin.get( outOf );
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores );  // float integer load
        fild( totOutOf );

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.

        fdivp(); // find totScores / totOutOf and leave result on top of FPU stack (in st0)

        // The FSTP instruction POPS and copies the value on the top of the floating
        // point register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the
        // 80 bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.

        fstp( average ); // POP and store sto, the top of the FPU stack, into average

        stdout.put
        (
            "The average of ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is: ", average:8:3, nl nl
        );

        stdout.puts( "Another (y/n) ? " );
        stdin.flushInput();
       
    until( stdin.getc() == 'n' );

end realMath;



See also:  Floating Point Arithmetic ...


http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/RealArithmetic.html#998833


Let’s add some enhancements to the above program that finds a running average.  Did you notice that if you enter a non-number, when a number is expected for input, the program stops with an error message?  With HLA, we can easily trap those errors.  The following demonstrates how:

 
See also:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/HelloWorlda3.html#998851

 
The TRY..EXCEPTION..ENDTRY Statement

 
The HLA TRY..EXCEPTION..ENDTRY statement provides very powerful exception handling capabilities. The syntax for this statement is the following: ...


Here is a short example:

Code: [Select]
repeat

            // initialize to false at start of repeat loop, 'goodInteger' is assumed
            // to have been declared previously as a boolean variable

            mov( false, goodInteger );       
            try

                stdout.put( "Enter an integer: " );
                // i is presumed to have been declared previously as an integer
                stdin.get( i );               
                mov( true, goodInteger );

            exception( ex.ConversionError );
                tdout.put( "Illegal numeric value, please re-enter", nl );

            exception( ex.ValueOutOfRange );
                tdout.put( "Value is out of range, please re-enter", nl );
               
        endtry;

until( goodInteger );


Now let’s put this into our program:

Code: [Select]
program realMath2;

// finds the running average of test scores
// this version checks for/and handles non-numeric input

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;

    good:       boolean;

// In the following macro, 'message' is presumed to be the input message-string
// passed to the macro, and 'num' is some previously declared type of number
// that is passed to the macro, and back again. Note: A macro, is just as if
// that code was inserted into the place from where the macro is called.
// Thus, this macro behaves similar to an 'inline' function call in C++ ...
// NOTE! It is also an 'overloaded' function, in that the type of number
// validated, will be the type of number passed in.

#macro getNumber( message, num );
    repeat
        // initialize to false at start of repeat loop, 'good' is assumed
        // to have been declared previously as a boolean (global) variable
        mov( false, good );         

        try
            stdout.puts( message ); // or more generally, could use stdout.put()
            stdin.flushInput();

            // (the value passed to) num is presumed to have been declared
            // previously with some type
            stdin.get( num );                     
            mov( true, good ); // if no exception jumped to, then accept data
           
        exception( ex.ConversionError );
            stdout.put( "Illegal numeric value, please re-enter", nl );

        exception( ex.ValueOutOfRange );
            stdout.put( "Value is out of range, please re-enter", nl );

        endtry;
       
    until( good );
#endmacro

 

begin realMath2;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions.

    finit();        // initialize floating point (math) unit

    stdout.puts
    (         
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate:"
        nl nl
    );

    repeat

        inc(count); // increment count by one each time a new score is obtained
           
        getNumber( "Enter score: ", score );
        mov( score, eax );
        add( eax, totScores );

        getNumber( "Enter outOf: ", outOf );
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores ); // float integer load
        fild( totOutOf );

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.
       
        fdivp(); // find totScores/totoutOf and leave result on top of FPU stack (in st0)

        // The FSTP instruction POPS and copies the value on the top of the floating
        // point register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the
        // 80 bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.
       
        fstp( average ); // POP and store sto, the top of the FPU stack, into average

        stdout.put
        (
            "The average of ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is: ", average:8:3, nl nl
        );

        stdout.puts( "Another (y/n) ? " );
        stdin.flushInput();
       
    until( stdin.getc() = 'n' );

end realMath2;

 

The following version also limits the range of user input values and applies some logic, (like the test score input can't be greater than the total score.) It also illustrates some low-level coding for error-checking and looping.

And note how we have been using a macro to make the code more modular.  The macro is called twice in the main program. Note where the macro definition is placed. (The same place as procedures or global variables ... Note also that the macro must be defined before it can be called.)

Code: [Select]
program realMath3;

// finds the running average of test scores
// This version checks for/and handles non-numeric input, and ...
// also limits the range of user input to proscribed values/logic

#include( "stdlib.hhf" )

static
    score:      int32;
    outOf:      int32;
    totScores:  int32:= 0;
    totOutOf:   int32:= 0;
    average:    real64;
    count:      int32:= 0;
    one00:      int32:= 100;

// In the following macro, 'message' is presumed to be the input message-
// string passed to the macro, and 'num' is some previously declared type of
// number that is passed to the macro,and back again. Note: A macro, is just
// as if that code was inserted into the place from where the macro is
// called. Thus, this macro behaves similarly to an 'inline' function call
// in C++ ... NOTE! It is also an 'overloaded' function, in that the type of
// number validated, will be the same type of number as the type of the
// number that was passed in. (Here it is an int32)

#macro getNumber( message, num, low, high );

    forever
        try
            stdout.puts( message ); // or more generally, could use stdout.put( )
            stdin.flushInput();
            stdin.get( num );       // the value passed to num is expected to be
                                    // a type int32 just as num was declared

            // don't accept numbers less than low or more than high
            if( num < low || num > high ) then
                raise( ex.ValueOutOfRange );
            endif;
           
        unprotected;
            break;  // IF we arrive here, NO exception was raised above,
                    // so break out of loop right now ...

        exception( ex.ConversionError );
            stdout.put( "Illegal numeric value, please re-enter", nl );

        exception( ex.ValueOutOfRange );
            stdout.put( "Value is out of range, please re-enter", nl );
           
        endtry;
    endfor;

#endmacro

 

begin realMath3;

    // The FINIT instruction initializes the FPU for proper operation. Your applications
    // should execute this instruction before executing any other FPU instructions

    finit(); // initialize floating point (math) unit

    console.setAttrs( console.blue, console.cyan );
    console.cls();

    stdout.puts
    (             
        "The following program asks for input of test scores" nl
        "and then finds the average of the scores todate ..." nl nl
    );

    repeat

        inc(count); // increment count by one each time a new score is obtained

        // An example of low level coding follows ... in the outer loop
        // ... but for the inner loop, the HLA 'repeat..until' is used

        jmp startGetNumber;   

    errorGetNumber1:
        stdout.put( nl "NOT valid entry ... 'out of' must be at least as big as ",
                    score, nl );
        jmp startGetNumber;

    errorGetNumber2:
        stdout.puts( nl "Entry aborted ... here we go again ..." nl );

    startGetNumber:
        getNumber( "Enter score: ", score, 0, 100 );

        // Don't allow zero entry for 'outOf'. Also, don't allow divide by zero
        repeat // This 'repeat..until' loop is an example of High Level coding

            getNumber( "Enter outOf: ", outOf, 0, 100  );
            if( outOf <= 0 ) then
                stdout.puts
                (
                    "'<=0' not allowed here. Please enter valid data." nl
                );
            endif;

        until( outOf > 0 );

        // Also don't allow a score greater than outOf
        mov( score, eax );
        cmp( eax, outOf );
        ja errorGetNumber1;     // i.e. jump to top label if score > outOf

        // Now one LAST check to confirm the data input was correct ...
        stdout.put
        (
            "You entered a score of ", score, " out of ", outOf,
            "  <===  OK  (y/n)  ? "
        );
        stdin.flushInput();
        stdin.getc();
        chars.toLower( al );    // Converts 'Y'to 'y'
        cmp( al, 'y' );
        jne errorGetNumber2;    // loop back to TOP error handling message block

    // endof low level loop

        mov( score, eax );
        add( eax, totScores );               
        mov( outOf, eax );
        add( eax, totOutOf );

        // The FILD (integer load) instruction converts a 16, 32, or 64 bit two's
        // complement integer to the 80 bit extended precision format and pushes the
        // result onto the stack. This instruction always expects a single operand. This
        // operand must be the address of a word, double word, or quad word integer
        // variable.

        fild( totScores );  // float integer load
        fild( one00 );      // will multiply by 100 to convert to percent

        // With no operands, the FMULP instruction pops ST0 and ST1,
        // computes the product and pushes the result back onto the stack
       
        fmulp();
        fild( totOutOf );   // now in STO ... and totScores*100 now in ST1

        // With no operands, the FDIVP instruction pops ST0 and ST1,
        // computes ST1/ST0, and pushes the result back onto the stack.

        fdivp(); // find totScores*100/totoutOf; (result in stack top i.e. st0)

        // The FST and FSTP instructions copy the value on the top of the floating point
        // register stack to another floating point register or to a 32, 64, or 80 bit
        // memory variable. When copying data to a 32 or 64 bit memory variable, the 80
        // bit extended precision value on the top of stack is rounded to the smaller
        // format as specified by the rounding control bits in the FPU control register.
        // The FSTP instruction POPS the value off the top of stack when moving it to
        // the destination location. It does this by incrementing the top of stack
        // pointer in the status register after accessing the data in ST0. If the
        // destination operand is a floating point register, the FPU stores the
        // value at the specified register number before popping the data off
        // the top of the stack.

        fstp( average ); // POP and store STO, the top of the FPU stack, into average     
        stdout.put
        (
            nl "The average so far in ", count, " test(s) with ",
            totScores, " marks out of ", totOutOf,
            " is ", average:7:1, "%" nl nl
        );

        repeat
       
            stdout.puts( "Another (y/n) ? " );
            stdin.flushInput();
            stdin.getc();           // recall returns char in 'al' register
            chars.toUpper( al );    // Converts 'y', 'n' to 'Y', 'N"

            if( al not in { 'Y', 'N' } ) then
                stdout.puts( "Only 'y' or 'n' accepted here ... " );
            endif;
           
        // NOTE: empty char is in every set ... so IS IN { 'Y', 'N' }
        until( !( al not in { 'Y', 'N' } ) );

    until( al = 'N' );

    stdout.put
    (
        nl "The FINAL AVERAGE IS ", average:7:1, "% in ", count,
        " test(s) with ", totScores, " marks out of ", totOutOf, "." nl
    );
   
end realMath3;
« Last Edit: May 19, 2013, 07:10:29 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #13 on: May 17, 2013, 03:52:43 PM »
Chapter 12: Pointers, Strings, my own Types, Records, Arrays, and dynamic things on the fly

 

1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt12_records

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name records.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.

Code: [Select]
program records;

#include( "stdlib.hhf" )

const   
    MaxCount:   int32:= 3; // to keep testing short/simple

type
    MyContact: record
                    theName:string;
                    thePhone:string;
                endrecord;
             
static
    MyBBook: MyContact[ MaxCount ];

 

// tot.num of contacts returned in ecx
procedure getBook; @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    begin takeIn;
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets(); // now eax holds the address of the string just entered
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < MaxCount ) do
   
        mov( @size( MyContact ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContact )

        // recall takeIn( .. ) returns a pointer to the string in eax
        mov( takeIn( "Enter name  " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );
    endwhile;
   
end getBook;

 

procedure printBook; @nodisplay; // Note: assumes ecx holds size of array

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";   

begin printBook;

    for( mov( 0, ecx ); ecx < edx ; inc( ecx ) ) do

        mov( @size( MyContact ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContact )
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.theName[ebx] );
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.thePhone[ebx] );
        stdout.newln();

    endfor;

end printBook;

 
begin records;

    getBook();          // returns number of contacts in ecx
    mov( ecx, edx );    // edx now holds the tot.num of contacts,
   
    stdout.puts( nl "Your 'book'  :" );
    printBook();        // value in edx ready for next procedure called
    stdout.put( nl "Note! The size of each MyContact, @size(MyContact) = " );
    stdout.putu32( @size( MyContact ) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContact' is really only a 4 byte pointer." nl
    );

    stdin.readLn();

end records;


So … what has been happening above?
 
1.  We defined our own type of variable and gave it the name myContacts.

2.  We further defined myContacts to be a record of two strings.  Now since HLA strings are really pointers to the (address of the) first byte in that string, and as you may recall addresses in HLA are 4 bytes or 32 bits, thus each ‘pointer’ takes 4 bytes … and thus each record of 2 pointers takes 8 bytes.

3.  But there is more … Each string was given enough memory to hold its (allocated memory) by the stdin.a_gets() HLA library function. The ‘a_’ in the function call indicates that … and so sufficient memory was allocated and a pointer (i.e. the address) to that memory was returned in eax, by that HLA stdlib call.

4.  So here we are allocating memory on the fly … cool eh?

5.  Cool as long as we don’t run out. (We can free it when we don’t need it - look this up - and see str.free( ..) used in last example here.)

6.  Note how we access the parts of a record with the dot operator, for example: ‘myBBook.theName[0]’ … (i.e. ebx = 0) …  refers to the base address of the array myBBook and the ‘.theName’ would be with NO-offset from there, whereas the ‘.thePhone’ would have a 4-byte-in offset from that referenced address.

7.  The next record in would be myBBook.theName[8], i.e. 8-bytes-in … and with respect to there, the ‘.theName’ would be the 4 bytes right there, whereas the ‘.thePhone’ would fetch the next 4 bytes in … and so on. This is why we need to step though the array, using the size in bytes of each record. In this case 8 bytes.  See how this was done using these two commands:  mov( szContact, ebx ); intmul( ecx, ebx ); Note that, for example,  intmul( ecx, ebx ) allows one to multiple ebx BY ecx with the answer put into ebx. Thus … myBBook.theName[ebx] gives each base address in as ebx steps through 0, 8, 16, … The ‘.theName’ or the ‘.thePhone’ gives the ‘offset’ from there.


Now ...the above, but without using GLOBAL variables ...

Code: [Select]
program records; // demo using NO global var's //

#include( "stdlib.hhf" )

type
    MyContact:  record
                    theName:string;
                    thePhone:string;
                endrecord;
               
    pMyContact: pointer to MyContact;
   

// tot.num of contacts returned in ecx
procedure getBook( pC: pMyContact in ebx; size: int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    begin takeIn;
        stdout.put( message, ":  " );
        stdin.flushInput();
        stdin.a_gets(); // now eax holds the address of the string just entered
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < size ) do
   
        mov( @size( MyContact ), edx );
        intmul( ecx, edx ); // edx := ecx*@size( MyContact )

        // recall takeIn( .. ) returns a pointer to the string in eax
        mov( takeIn( "Enter name  " ), ( type string [ebx+edx] ) );
        add( @size(MyContact.theName),  edx );
        mov( takeIn( "Enter phone " ), ( type string [ebx+edx] ) );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );
    endwhile;
   
end getBook;

 

procedure printBook( pC: pMyContact in ebx; size: int32  ); @nodisplay;

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";

begin printBook;

    for( mov( 0, ecx ); ecx < size ; inc( ecx ) ) do

        mov( @size( MyContact ), edx );
        intmul( ecx, edx ); // edx := ecx*@size( MyContact )
        stdout.puts( nlTab2 ); stdout.puts( ( type string [ebx+edx]  ) );
        add( @size(MyContact.theName), edx );
        stdout.puts( nlTab2 ); stdout.puts( ( type string [ebx+edx] ) );
        stdout.newln();

    endfor;

end printBook;


procedure mainProc; @nodisplay;

const   
    MaxCount:   int32:= 3; // to keep testing short/simple

static
    MyBBook: MyContact[ MaxCount ];
    size: int32;
   
begin mainProc;

    getBook( &MyBBook, MaxCount ); // returns number of contacts in ecx
    mov( ecx, size );
   
    stdout.puts( nl "Your 'book'  :" );
    printBook( &MyBBook, size );
    stdout.put( nl "Note! The size of each MyContact, @size(MyContact) = " );
    stdout.putu32( @size( MyContact ) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContact' is really only a 4 byte pointer." nl
    );

    stdin.readLn();


end mainProc;


begin records;

    mainProc();

end records;


Or see this ... with some data input validation:

Code: [Select]
program records3;

#include( "stdlib.hhf" )

const 
    MaxCount:   int32 :=    3; // to keep testing short/simple

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;

static
    MyBBook:    MyContacts[ MaxCount ];

         
// count of contacts entered returned in ecx ...
procedure getBook( maxSize:int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:    string;
    begin takeIn;
        forever
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input '", (type string eax), "' ... Ok (y/n) ? " );
            mov( eax, s ); // get a copy of pointer into s ...
            stdin.getc();
            if( al == 'y' || al == 'Y' ) then
                mov( s, eax );
                break;
            else str.free( s );
            endif;
        endfor;
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < maxSize ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )

        mov( takeIn( "Enter name   " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );

    endwhile;

end getBook;


procedure printBook( numRecs:int32 ); @nodisplay;

const // text string composed of nl and 2 tabs
    nlTab2: text:="nl stdio.tab stdio.tab";   

begin printBook;

    for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // now ebx := ecx*@size( MyContacts )
   
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.theName[ebx] );
        stdout.puts( nlTab2 ); stdout.puts( MyBBook.thePhone[ebx] );
        stdout.newln();
    endfor;
           
end printBook;




begin records3;

    getBook( MaxCount );  // recall, returns the record count in ecx

    stdout.puts( nl "Your 'book'  :" );
    printBook( ecx ); // recall, ecx holds number of records ...

    stdout.put
    (
        nl "Note! The size of each MyContacts, @size(MyContacts) = "
    );
    stdout.putu32( @size(MyContacts) );
    stdout.put
    (
        ", since each of the" nl
        "2 strings in the record 'MyContacts' is really only a "
        "4 byte pointer ... " nl nl
        "Press 'Enter' to quit ... "
    );
   
    stdin.readLn();

end records3;


For further reference on HLA strings, see ... HLA strings …

http://216.92.238.133/Webster/www.artofasm.com/AoAExtra/HLAStrs.html


Also ...

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/CharacterStringsa2.html



2.6 The HLA String Module and Other String-Related Routines ...


And a little further on down the first page was ( a link to an other HLA user site that has backed up some AoA info - But .... the link is no longer available ...The info was copied here for easy reference.)



Chapter Five Records, Unions, and Name Spaces

5.1 Chapter Overview

This chapter discusses how to declare and use record (structures), unions, and name spaces in your programs. After strings and arrays, records are among the most commonly used composite data types; indeed, records are the mechanism you use to create user-defined composite data types. Many assembly language programmers never bother to learn how to use records in assembly language, yet would never consider not using them in high level language programs. This is somewhat inconsistent since records (structures) are just as useful in assembly language programs as in high level language programs. Given that you use records in assembly language (and especially HLA) in a manner quite similar to high level languages, there really is no reason for excluding this important tool from your programmer's tool chest. Although you'll use unions and name spaces far less often than records, their presence in the HLA language is crucial for many advanced applications. This brief chapter provides all the information you need to successfully use records, unions, and name spaces within your HLA programs.

5.2 Records

Another major composite data structure is the Pascal  record or C/C++  structure 1  . The Pascal terminology is probably better, since it tends to avoid confusion with the more general term  data structure. Since HLA uses the term "record" we'll adopt that term here.

Whereas an array is homogeneous, whose elements are all the same, the elements in a record can be of any type. Arrays let you select a particular element via an integer index. With records, you must select an element (known as a  field) by name.

The whole purpose of a record is to let you encapsulate different, but logically related, data into a single package. The Pascal record declaration for a student is probably the most typical example:

Code: [Select]
student =

 record

 Name: string [64];

 Major: integer;

 SSN: string[11];

 Midterm1: integer;

 Midterm2: integer;

 Final: integer;

 Homework: integer;

 Projects: integer;

 end;


Most Pascal compilers allocate each field in a record to contiguous memory locations. This means that Pascal will reserve the first 65 bytes for the name 2 , the next two bytes hold the major code, the next 12 the Social Security Number, etc.

In HLA, you can also create structure types using the RECORD/ENDRECORD declaration. You would encode the above record in HLA as follows:

Code: [Select]
type

 student: record

 Name: char[65];

 Major: int16;

 SSN: char[12];

 Midterm1: int16;

 Midterm2: int16;

 Final: int16;

 Homework: int16;

 Projects: int16;

endrecord;


As you can see, the HLA declaration is very similar to the Pascal declaration. Note that, to be true to the Pascal declaration, this example uses character arrays rather than strings for the  Name and  SSN (U.S Social Security Number) fields. In a real HLA record declaration you'd probably use a string type for at least the name (keeping in mind that a string variable is only a four byte pointer).

The field names within the record must be unique. That is, the same name may not appear two or more times in the same record. However, all field names are local to that record. Therefore, you may reuse those field names elsewhere in the program.

The RECORD/ENDRECORD type declaration may appear in a variable declaration section (e.g., STATIC or VAR) or in a TYPE declaration section. In the previous example the  Student declaration appears in the TYPE section, so this does not actually allocate any storage for a  Student variable. Instead, you have to explicitly declare a variable of type  Student. The following example demonstrates how to do this:  (Click on the above link to see graphics and the rest ...)


Also here is a good place to start looking for an answer to any HLA How do I code for ... type question:

http://216.92.238.133/Webster/www.artofasm.com/Windows/HTML/AoATOC.html


For a little fun assignment, write a short HLA program, using the above student record type ... and output the record size.  ( Hint: use the HLA function @size( student ); )  Does your output agree with the bytes you added up for the record in your head?  (Recall int16 uses 2 bytes.)


Here is a little demo program, but don’t look until you have tried your own.

Code: [Select]
program studentRec;

#include( "stdlib.hhf" )

type
    student:    record

                    // NOTE! 'Name' is a reserved word, so used Fullname

                    Fullname:       char[68];
                    Major:          int16;
                    SSN:            char[12];
                    Midterm1:       int16;
                    Midterm2:       int16;
                    Final:          int16;
                    Homework:       int16;
                    Projects:       int16;

                endrecord;
               
static
    stRecSize:  int32:= @size ( student );  // figured out at compile time
    i32:        int32;

begin studentRec;

            mov( @size( student ), eax );
            mov( eax, i32 );                    // figured out at run time
            stdout.put
            (
                        "The number of bytes in each student record here is : ", i32,
                        nl "stRecSize is : ", i32, nl "Yep! It is : "
            );

            // The HLA compiler/assembler can recognize this value here ...
            // It is inside a procedure/function call & not the stdout.put(..) macro.
            // '@size ( student )' is replaced by 'its value' at compile time
            stdout.puti32( @size ( student ) );
           
end studentRec;
« Last Edit: May 19, 2013, 09:03:45 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: BEGINNING COMPUTER PROGRAMMING WITH HLA (High Level Assembly)
« Reply #14 on: May 17, 2013, 04:32:14 PM »
Chapter 13: The Computer files its Records



1.  Create (md) a sub-directory in the project folder.  Give it the name Chapt13_fileRecords

2.  Go (cd) to that new directory.

3.  Using your text editor, create the following program file in that folder.  Give the program file the name fileRecords.hla

4.  Compile the program and run it. Study the comments that are in the hla program, as well as the output that appears on the screen when you run the program.


Notice that we are starting out with the same program with which we ended in the previous chapter. For a simple start … we will just add … and then let the program always call a procedure to file the records at the end, before exiting. (Later, we will add another procedure to read these records into an array of records, when we first run our program, if there is an existing file, that is … with records to read.)


Here is a simple ‘pattern’ (to guide us), from AoA, of the HLA functionality we wish to add:

Code: [Select]
program simpleFileOutput;

#include( "stdlib.hhf" )

 
static
    outputHandle:   dword;

           

begin simpleFileOutput;

    fileio.openNew( "myfile.txt" );
    mov( eax, outputHandle );

    for( mov( 0, ebx ); ebx < 10; inc( ebx ) ) do
        fileio.put( outputHandle, ( type uns32 ebx ), nl );
    endfor;

    fileio.close( outputHandle );

end simpleFileOutput;


Ok ... here is out first program to demo how to file our Records ...

Code: [Select]
program fileRecords;
 
#include( "stdlib.hhf" )
 
const 
    MaxCount:   int32 :=    3; // to keep testing short/simple
    FNAME:      text :=     """records.dat""";

type
    MyContacts: record
                    theName:    string;
                    thePhone:   string;
                endrecord;

static
    MyBBook:    MyContacts[ MaxCount ];

         
// count of contacts entered returned in ecx ...
procedure getBook( maxSize:int32 ); @nodisplay; @returns("ecx");

    // nested procedures are allowed in HLA
    procedure takeIn( message:string ); @nodisplay; @returns("eax");
    var
        s:    string;
    begin takeIn;
        forever
            stdout.put( message, ":  " );
            stdin.flushInput();
            stdin.a_gets();
            stdout.put("You input '", (type string eax), "' ... Ok (y/n) ? " );
            mov( eax, s ); // get a copy of pointer into s ...
            stdin.getc();
            if( al == 'y' || al == 'Y' ) then
                mov( s, eax );
                break;
            else str.free( s );
            endif;
        endfor;
    end takeIn;

begin getBook;

    mov( 0, ecx );
    while( ecx < maxSize ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )

        mov( takeIn( "Enter name   " ), MyBBook.theName[ebx] );
        mov( takeIn( "Enter phone  " ), MyBBook.thePhone[ebx] );
        inc( ecx );

        stdout.puts( "More y/n ? " );
        stdin.flushInput();
        stdin.getc();
        breakif ( al == 'n' || al == 'N' );

    endwhile;

end getBook;

procedure printBook( numRecs:int32 ); @nodisplay;
begin printBook;

    for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do

        mov( @size( MyContacts ), ebx );
        intmul( ecx, ebx ); // now ebx := ecx*@size( MyContacts )
        stdout.put( stdio.tab, MyBBook.theName[ebx]:-20, " ", MyBBook.thePhone[ebx], nl )

    endfor;
           
end printBook;
 
procedure fileBook( numRecs:int32 ); @nodisplay;
var
    outFileHandle:  dword;

begin fileBook;
    try
        fileio.openNew( FNAME );
        mov( eax, outFileHandle );
        for( mov( 0, ecx ); ecx < numRecs; inc( ecx ) ) do
            mov( @size( MyContacts ), ebx );
            intmul( ecx, ebx ); // ebx := ecx*@size( MyContacts )
            fileio.put( outFileHandle, MyBBook.theName[ebx], nl );
            fileio.put( outFileHandle, MyBBook.thePhone[ebx], nl );
        endfor;
        fileio.close( outFileHandle );
    anyexception
        stdout.put( "There was some problem opening file ", FNAME, " for output." );
    endtry;
end fileBook;
 
 
begin fileRecords;
 
    getBook( MaxCount );    // recall, returns the record count in ecx
    stdout.puts( nl "Your 'book' ..." nl );
    printBook( ecx );
    fileBook( ecx );
    stdout.put( nl, (type int32 ecx),  " records were filed.  Press 'Enter' to exit ... " );
    stdin.readLn();

end fileRecords;


To continue, click on the '2' icon for page '2' ... in the the lower left window.
« Last Edit: May 19, 2013, 09:08:47 AM by David »