Friday 12 February 2021

See also, also C++ (other blog)

Studying GCSE or A-Level Computer Science?

See also: Program using C++ blog for examples of C++ on the Raspberry Pi, Apple Mac and Linux.

Programs also work on repl.it

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 );

    display:

    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 );  
  

    underline:

        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;

    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;

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;

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.)

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.

Schools and colleges in the UK don't like assembly language. It's official.


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;