See also: Program using C++ blog for examples of C++ on the Raspberry Pi, Apple Mac and Linux.
"bit-brain!" assembly language examples
Very simple assembly language programs for the (free) HLA High-Level Assembler on an Intel PC. Want to know more about assembly language and low-level programming? Read the HLA book by Randall Hyde - it's a good 'un.
Friday 12 February 2021
Friday 8 March 2019
Assembly: Calculating powers of 2 using left shifts
program powersOfTwo;
// Phil Gardner
#include( "stdlib.hhf" )
begin powersOfTwo;
// Start at 1, then double repeatedly
mov( 1, eax );
mov( 1, bl );
stdout.put( "Col no. " );
stdout.puti8( bl );
stdout.put( ": " );
mov( bl, cl );
dec( cl );
stdout.put( " 2 to the power of " );
stdout.puti8( cl );
stdout.put( " is " );
stdout.puti32( eax );
stdout.put( nl );
shl( 1, eax );
inc( bl );
cmp( bl, 16 );
jle display;
end powersOfTwo;
Sunday 3 March 2019
Assembly: Factors and primes
program factors;
// Phil Gardner
#include( "stdlib.hhf" )
begin factors;
// The value to test as prime or not
mov( 2, bl );
testPrime:
// Count of how many factors found for the value
mov( 0, dx );
// The divisor to test as a factor
mov( 1, cl );
tryFactor:
mov( bl, al );
cbw();// Is this a factor? Check remainder
div( cl );
cmp( ah, 0 );
jz isFactor;
nextFactor:
inc( cl );
cmp( cl, bl );
jle tryFactor;jg finishedSingleTest;
isFactor:
inc( dl );
stdout.puti8( cl );
stdout.put( " goes into " );
stdout.puti8( bl );
stdout.put( " " );
stdout.puti8( al );
stdout.put( " times", nl );
jmp nextFactor;
finishedSingleTest:
cmp( dl, 2 );
jz reportAsPrime;
jmp underline;
reportAsPrime:
stdout.puti8( bl );
stdout.put( " IS A PRIME", nl );
stdout.put( "- - - - - -", nl );
readyForNextTest:
inc( bl );
cmp( bl, 100 );
jle testPrime;stdout.put( nl, "Finished testing.", nl );
end factors;
Tuesday 26 February 2019
Assembly: Convert denary to 7-bit binary
program binary_shifts;
#include( "stdlib.hhf" )
// Phil Gardner
begin binary_shifts;
// Base 10 number to be converted to 7-bit binary
mov( 45, ax );
// Start at leftmost column
mov( 64, cl );
stdout.put( nl, "Convert " );
stdout.puti16( ax );
stdout.put( " to 7-bit binary:" );
stdout.put( nl );
processColumn:
// Determine whether this column fits into number
// Divides ax by cl
div( cl );
stdout.put( nl, "Place value in cl " );
stdout.puti8( cl );
stdout.put( stdio.tab, "quotient in al " );
stdout.puti8( al );
stdout.put( stdio.tab, "modulo in ah " );
stdout.puti8( ah );
// Expand the modulo into ax
mov( ah, al );
cbw();
// Update place value to use for next column
shr( 1, cl );
// Decide whether all columns now completed
cmp( cl, 0 );
jg processColumn;
finished:
stdout.put( nl, nl, "Finished.", nl );
end binary_shifts;
Monday 25 February 2019
Assembly: Calculating factorials using iteration
program factorial_iterative;
#include( "stdlib.hhf" )
// Phil Gardner
procedure factorial; @noframe; @nodisplay;
begin factorial;
cmp( ax, 0 );
// Can't deal with factorial of negative number
jl tooSmall;
// Zero or above can be displayed though
// Factorial of 0 is automatically 1
jz isZero;
// Any number larger than 1 requires working out
stdout.put( nl, "Calculating factorial of " )
stdout.puti16( ax );
stdout.put( " is " );
stdout.puti16( ax );
mov( ax, bx );
keepMultiplying:
dec( bx );
cmp( bx, 0 );
jz finishedFactorial;
mul( bx, ax );
stdout.put( " x " );
stdout.puti16( bx );
jmp keepMultiplying;
isZero:
stdout.put( nl, "Factorial of 0 is always 1" );
mov( 1, ax );
finishedFactorial:
stdout.put( nl, "Returning result ")
stdout.puti16( ax );
stdout.put( nl );
ret();
tooSmall:
stdout.put( nl, "Must be >= 0", nl );
ret();
end factorial;
// - - - - -
begin factorial_iterative;
mov( -1, cx );
keepCalculatingRange:
mov( cx, ax );
call factorial;
inc( cx );
cmp( cx, 6 );
jle keepCalculatingRange;
stdout.put( nl, "Finished.", nl );
end factorial_iterative;
Assembly: Hello World x 10
program helloLoop;
// Phil Gardner
#include( "stdlib.hhf" );
static
begin helloLoop;
// Will countdown from ten
mov( $0A, al );
countDownLoop:
stdout.put( nl, "*HeLL0 A$$emBLeD w0RLd*", nl );
dec( al );
jg countDownLoop;
end helloLoop;
Saturday 23 February 2019
Assembly: Sub-routine to display a range of characters
This program repeatedly calls a sub-routine to display a range of characters.
The first and last character to be displayed in each range can be set using the al and cl 8-bit registers before calling the sub-routine.
Code:
program display_chars;
#include( "stdlib.hhf" )
// Phil Gardner
procedure displayCharRange; @noframe; @nodisplay;
begin displayCharRange;
keepDisplaying:
stdout.put( ( type char al ), " " );
inc( al );
cmp( al, cl );
jle keepDisplaying;
end displayCharRange;
// - - - - -
begin display_chars;
// Display all upper-case letters
call displayCharRange;
stdout.put( nl );
// Display all lower-case letters
call displayCharRange;
stdout.put( nl );
// Display all numeric digits
call displayCharRange;
stdout.put( nl );
// Display punctuation symbols
call displayCharRange;
call displayCharRange;
call displayCharRange;
call displayCharRange;
stdout.put( nl );
end display_chars;
The first and last character to be displayed in each range can be set using the al and cl 8-bit registers before calling the sub-routine.
Code:
program display_chars;
#include( "stdlib.hhf" )
// Phil Gardner
procedure displayCharRange; @noframe; @nodisplay;
begin displayCharRange;
keepDisplaying:
stdout.put( ( type char al ), " " );
inc( al );
cmp( al, cl );
jle keepDisplaying;
ret();
end displayCharRange;
// - - - - -
begin display_chars;
// Display all upper-case letters
mov( $41, al );
mov( $5A, cl );call displayCharRange;
stdout.put( nl );
// Display all lower-case letters
mov( $61, al );
mov( $7A, cl );call displayCharRange;
stdout.put( nl );
// Display all numeric digits
mov( $30, al );
mov( $39, cl );call displayCharRange;
stdout.put( nl );
// Display punctuation symbols
mov( $21, al );
mov( $2F, cl );call displayCharRange;
mov( $3A, al );
mov( $40, cl );call displayCharRange;
mov( $5B, al );
mov( $60, cl );call displayCharRange;
mov( $7B, al );
mov( $7E, cl );call displayCharRange;
stdout.put( nl );
end display_chars;
Labels:
assembly language,
characters,
computer science,
HLA,
intel,
sub-routine
Friday 22 February 2019
Assembly: Push the stack over
How much data can you push on to the stack before your program falls over?
Let's have a look then...
program stack_zapper;
#include( "stdlib.hhf" )
// Phil Gardner
begin stack_zapper;
stdout.put( nl );
stdout.put( "Repeatedly push 4 byte value on to the stack." );
stdout.put( nl );
mov( $0000029A, eax );
stdout.put( "eax = " );
stdout.put( eax );
stdout.put( nl, nl );
mov( $00000000, ebx );
infiniteLoop:
stdout.put( "Stack pointer = " );
stdout.put( esp );
stdout.put( nl );
mov( $00004000, ecx );
pushBigChunk:
push( eax );
dec( ecx );
jge pushBigChunk;
stdout.put( "Pushed another 16 KB on to stack" );
stdout.put( stdio.tab );
inc( ebx );
stdout.put( ebx );
stdout.put( " x 16 KB" );
stdout.put( stdio.tab );
jmp infiniteLoop;
end stack_zapper;
Let's have a look then...
program stack_zapper;
#include( "stdlib.hhf" )
// Phil Gardner
begin stack_zapper;
stdout.put( nl );
stdout.put( "Repeatedly push 4 byte value on to the stack." );
stdout.put( nl );
mov( $0000029A, eax );
stdout.put( "eax = " );
stdout.put( eax );
stdout.put( nl, nl );
mov( $00000000, ebx );
infiniteLoop:
stdout.put( "Stack pointer = " );
stdout.put( esp );
stdout.put( nl );
mov( $00004000, ecx );
pushBigChunk:
push( eax );
dec( ecx );
jge pushBigChunk;
stdout.put( "Pushed another 16 KB on to stack" );
stdout.put( stdio.tab );
inc( ebx );
stdout.put( ebx );
stdout.put( " x 16 KB" );
stdout.put( stdio.tab );
jmp infiniteLoop;
end stack_zapper;
Assembly: Commencing countdown, engines on
How long does it take a program written in assembly language to countdown from 1 billion to zero?
Find out for yourself, lazybones:
program countdown;
#include( "stdlib.hhf" )
static
// Will countdown from 1 billion
num: dword := $3B9ACA00;
begin countdown;
mov( num, eax );
stdout.put( "Starting from " );
stdout.put( eax );
stdout.put( " (1 billion)" );
stdout.put( nl );
countDownLoop:
dec( eax );
jg countDownLoop;
stdout.put( "Reached zero. Splat." );
stdout.put( nl );
end countdown;
(Post-script: It was approx. 300 times faster than Python.)
Find out for yourself, lazybones:
program countdown;
#include( "stdlib.hhf" )
static
// Will countdown from 1 billion
num: dword := $3B9ACA00;
begin countdown;
mov( num, eax );
stdout.put( "Starting from " );
stdout.put( eax );
stdout.put( " (1 billion)" );
stdout.put( nl );
countDownLoop:
dec( eax );
jg countDownLoop;
stdout.put( "Reached zero. Splat." );
stdout.put( nl );
end countdown;
(Post-script: It was approx. 300 times faster than Python.)
Assembly: Reverse a string using a loop
Increments an index to visit each character in a string. Once the length of the string has been determined, decrements the index again to display the characters in reverse order.
program reverse_string;
#include( "stdlib.hhf" )
static
zeroTerminatedString: char; @nostorage;
byte "There and back again", 0;
begin reverse_string;
mov( &zeroTerminatedString, ebx );
stdout.put( nl );
stdout.put( "Base address where string begins is held in register ebx = " );
stdout.put( ebx );
stdout.put( nl, nl );
mov( 0, eax );
visitCharacter:
mov( ebx, ecx );
add( eax, ecx );
cmp( (type byte [ecx]), 0 );
jz outputLength;
stdout.put( "Index address eax = " );
stdout.put( eax );
stdout.put( stdio.tab );
stdout.put( "Mem address ebx+eax = " );
stdout.put( ecx );
stdout.put( stdio.tab );
stdout.put( "Contents = " );
stdout.put( ( type byte [ecx] ) );
stdout.put( stdio.tab );
stdout.put( "ASCII char = " );
stdout.put( ( type char [ecx] ) );
stdout.put( nl );
inc( eax );
jmp visitCharacter;
outputLength:
stdout.put( nl );
stdout.put( "Length of string held in register eax = " );
stdout.put( ( type uns32 eax ) );
stdout.put( nl, nl );
reverseString:
dec( eax );
revisitCharacter:
mov( ebx, ecx );
add( eax, ecx );
stdout.put( "Index address eax = " );
stdout.put( eax );
stdout.put( stdio.tab );
stdout.put( "Mem address ebx+eax = " );
stdout.put( ecx );
stdout.put( stdio.tab );
stdout.put( "Contents = " );
stdout.put( ( type byte [ecx] ) );
stdout.put( stdio.tab );
stdout.put( "ASCII char = " );
stdout.put( ( type char [ecx] ) );
stdout.put( nl );
dec( eax );
jge revisitCharacter;
end reverse_string;
Assembly: Determine length of a string
Ssshh! It's a DELIBERATELY ANNOYING LOW-LEVEL PROGRAM
This is not the sort of thing that people should EVER mess about with.
EVER.
Apparently.
Because it's written in HLA assembly language for an Intel processor.
So here's the code:
program determine_string_length;
#include( "stdlib.hhf" )
static
zeroTerminatedString: char; @nostorage;
byte "Hello from RAM", 0;
begin determine_string_length;
mov( &zeroTerminatedString, ebx );
stdout.put( nl );
stdout.put( "Base address where string begins is held in register ebx = " );
stdout.put( ebx );
stdout.put( nl, nl );
mov( 0, eax );
visitCharacter:
mov( ebx, ecx );
add( eax, ecx );
cmp( (type byte [ecx]), 0 );
jz outputLength;
stdout.put( "Index address eax = " );
stdout.put( eax );
stdout.put( stdio.tab );
stdout.put( "Mem address ebx+eax = " );
stdout.put( ecx );
stdout.put( stdio.tab );
stdout.put( "Contents = " );
stdout.put( ( type byte [ecx] ) );
stdout.put( stdio.tab );
stdout.put( "ASCII char = " );
stdout.put( ( type char [ecx] ) );
stdout.put( nl );
inc( eax );
jmp visitCharacter;
outputLength:
stdout.put( nl );
stdout.put( "Length held in register eax = " );
stdout.put( ( type uns32 eax ) );
stdout.put( nl );
end determine_string_length;
#include( "stdlib.hhf" )
static
zeroTerminatedString: char; @nostorage;
byte "Hello from RAM", 0;
begin determine_string_length;
mov( &zeroTerminatedString, ebx );
stdout.put( nl );
stdout.put( "Base address where string begins is held in register ebx = " );
stdout.put( ebx );
stdout.put( nl, nl );
mov( 0, eax );
visitCharacter:
mov( ebx, ecx );
add( eax, ecx );
cmp( (type byte [ecx]), 0 );
jz outputLength;
stdout.put( "Index address eax = " );
stdout.put( eax );
stdout.put( stdio.tab );
stdout.put( "Mem address ebx+eax = " );
stdout.put( ecx );
stdout.put( stdio.tab );
stdout.put( "Contents = " );
stdout.put( ( type byte [ecx] ) );
stdout.put( stdio.tab );
stdout.put( "ASCII char = " );
stdout.put( ( type char [ecx] ) );
stdout.put( nl );
inc( eax );
jmp visitCharacter;
outputLength:
stdout.put( nl );
stdout.put( "Length held in register eax = " );
stdout.put( ( type uns32 eax ) );
stdout.put( nl );
end determine_string_length;
Labels:
assembly language,
computer science,
HLA,
intel,
register
Location:
Unknown location.
Subscribe to:
Posts (Atom)