Example 0: basic I/O, addition
Example 1: if/else if/else
Example 2: simple loop
Example 3: emulating bit shifts, powers of 2
Example 4: emulating division through shifts and adds
Example 5: emulating null terminated strings
Example 6: simple function calls/returns
Example 7: emulating arrays
Example 8: recursion using a stack we build and maintain
Example 9: self modifying code
Example 0: basic I/O, addition
A program to read two numbers and print their sum:
/ program to get two values from user / add them together, and print result / read first value into ACC / then copy into variable X input store X / read second value into ACC / then copy into variable Y input store Y add X / ACC = ACC + X output / print result halt / end program / local variables, initialized to 0 (using base 10) X, dec 0 Y, dec 0 |
Example 1: if/else if/else
A program to read and compare two numbers,
with different output based on relative values:
/ program to get x,y from user / if x < y print x then y / else if x > y print y then x / else just print x org 100 input / get value for x store X input / get value for y store Y Test1, subt X / acc = y - x skipcond 000 / if negative then x bigger, skip further tests jump Test2 load X / got here if x bigger, print x then y, then done output load Y output jump Done Test2, skipcond 800 / if positive then y bigger, skip further tests jump XYEq / if here then equal, go to XYeq print section load Y / got here if y bigger, print y then x, then done output load X / then print y output jump Done XYEq, load X / just print x, then done output Done, halt X, dec 0 / default value for x Y, dec 0 / default value for y |
Example 2: simple loop
A program to get the user to enter an integer less
than 10 (repeats until a valid response is given).
/ program to get int < 10 from user / keep reading til valid value obtained org 100 NewVal, input / get value for x store X subt TooBig / compute x - toobig skipcond 000 / if negative then x ok (less than toobig) jump NewVal / otherwise go back and try again Show, load X / got valid value, print x, then done output halt X, dec 0 / default value for x TooBig, dec 10 / X must be less than this |
Example 3: emulating bit shifts, powers of 2
A program to get the user to give two integers, X and N,
and show the result of shifting X left N bits.
Since we don't have a shift operation in Marie, we'll use the following algorithm to do it with just addition (adding x to itself doubles x, just like a single shift left).
int i=0, N, x; scanf("%d", &x); scanf("%d", &N); while (i < N) { x += x; i++; } printf("%d", x);
/ program to get integers X and N then display / results of shifting X left by N bits org 100 input / get value of X store X input / get value of N store N While, load N / compute N-I subt I skipcond 800 / if it's positive we're not done jump Done load X / double X add X store X load I / increment I add Incr store I jump While / go back to loop test Done, load X / we're done, print X output halt X, dec 0 / value being shifted N, dec 0 / number of bits to shift I, dec 0 / loop counter Incr, dec 1 / I += 1 each pass |
Example 4: emulating division through shifts and adds
A program to get the user to give two integers, N and D,
and show the result of dividing N by D. Since we don't have a divide operation
in Marie we'll just use addition, but we want to be much more efficient than
just adding D over and over until we get N.
We'll use the following algorithm, essentially using bit shifts to get the effect of multiplying D by powers of 2 and adding the results together (like one would in computing the results in binary).
int answer = 0; int N, D; scanf("%d", &N); scanf("%d", &D); int k = N; while (k > 0) { int pow = 1; int j = D; while ((j+j) < k) { j += j; pow += pow; } k -= j; answer += pow; } if (k < 0) answer--; printf("%d", answer); marie file | / get two integers, N, D, from user / compute and display results of N div D org 100 input store N / get user value for N input store D / get user value for D load N / K = N store K Outer, load K / not done if K is positive skipcond 800 jump Done / otherwise we're finished load Incr / Pow = 1 store Pow load D / J = D store J Inner, load J / not done if 2J < K add J subt K skipcond 000 jump AftIn / leave inner loop load J / J = 2*J add J store J load Pow / Pow = 2*Pow add Pow store Pow jump Inner / back to top of inner loop AftIn, load K / K = K - J subt J store K load Answer / Answer = Answer + Pow add Pow store Answer jump Outer / back to top of outer loop Done, load K / if K < 0 answer-- skipcond 000 jump Disp load Answer subt Incr Disp, load Answer / we're done, display the results output halt N, dec 0 / user value for N D, dec 0 / user value for D K, dec 0 / amount of N still left J, dec 0 / current multiple of D Pow, dec 0 / computing powers of 2 Answer, dec 0 / final result Incr, dec 1 / for ++ -- |
Example 5: emulating null terminated strings
A program to print a null terminated string using a loop
from the start of the string, and using the address of individual bytes
as we iterate.
Notes:
/ print a string through an indirect address / like a pointer / ** make sure the output mode is in unicode ** While, load AddrMsg / CurAddr = &(msg[index]) add Index store CurAddr clear / acc = msg[index] addi CurAddr skipcond 800 / if msg[index] > null go ahead and print, jump Done / otherwise we're done Print, output load Index / index++ add Incr store Index jump While / repeat loop for next char Done, halt MsgSt, dec 72 / 'H' dec 105 / 'i' Null, dec 0 / '\0' AddrMsg, hex D / addr of MsgSt Index, dec 0 / current index into msg[] CurAddr, hex 0 / addr of msg[index] Incr, dec 1 / for ++ |
Example 6: simple function calls/returns
A program that calls a subroutines (using variables to pass
parameters, store local values, and return a value). The key syntax elements are:
Jns Funcname / used to call the function
Funcname, hex 000 / used to start the function definition
JumpI Funcname / used to return from the function
/ example of creating, calling, and returning from a function / using variables to pass parameters, / to return values, and as local variables input / get user input, store in var FooParam store FooParam JnS Foo / call Foo, start running with instruction AFTER foo load FooReturn / retrieve and print whatever is returned output halt Foo, hex 000 / stores address to use when returning from foo load FooParam / get and print passed param output add FooLocal / return FooParam + FooLocal store FooReturn JumpI Foo / return from foo (to the address we stored when foo was called) FooParam, dec 0 / use to pass a param to foo FooLocal, dec 20 / use as "local" variable for foo FooReturn, dec 0 / use to return a value from foo |
Example 7: emulating arrays
A program to get an array size from the user, fill
the array with user input, then print the array content.
/ program to let the user enter an array size, / then fill the array with values, / then print the array input / get array size from user store Size load Arr / copy array address into IndexPos store IndxPos GetVal, load Size / if size > index we're not done yet subt Index skipcond 800 jump Print / we're done entering, now go print input / get next array element storeI IndxPos / store in arr[index] load IndxPos / IndxPos++ add Incr store IndxPos load Index / Index++ add Incr store Index jump GetVal / return to loop test Print, load Arr / copy array address into IndexPos store IndxPos clear / Index = 0 store Index PrtVal, load Size / if size > index we're not done yet subt Index skipcond 800 halt / we're finished loadI IndxPos / get/print next element from arr[index] output load IndxPos / IndxPos++ add Incr store IndxPos load Index / Index++ add Incr store Index jump PrtVal / return to loop test Index, hex 0 / current array index IndxPos, hex 28 / address of current array index Element, hex 0 / value of current array element Incr, hex 1 / for ++ Size, hex 0 / user chosen array size Arr, hex 28 / address for start of the array storage |
Size1, hex 0 Arr1, hex 30 Size2, hex 0 Arr2, hex 0and once we know the size of array 1 we could compute the start address for array 2 as follows (assuming we want array 2 to be stored right after array 1 in memory):
load Arr1 add Size1 store Arr2
Example 8: recursion using a stack we build and maintain
A program to recursively compute a value - maintaining a our own
stack to keep track of local variable values, passed parameters, return values,
and the return address to use when returning from a function call.
/ / Recursion example: parameter passing and return value handled through global stack / / pseudo-code view of program Uses a global stack for parameter passing / - Stack tracks address of bottom of stack / int sum(int N) - ToS tracks address of next free spot atop stack / { - caller pushes its locals* then params to pass, then calls / int result = 0; - callee pops its params, and pushes result before return / if (N > 0) { - caller pops result and its locals* after call returns / result = sum(N-1); - currently no error checks for stack full/empty / result += N; * recursive functions must store/restore return addr / } Push logic load Val / return result; - store value at ToS storeI ToS / } then ToS++ load ToS / add Incr / int main() store ToS / { / int N; Pop logic load ToS / cin >> N; - Tos-- then subt Incr / int R = sum(N); load value from ToS store Tos / cout << R; loadI ToS / } store Val / Main, input storeI ToS / push N onto stack before call load ToS / (and increment ToS) add Incr store ToS JnS Sum load ToS / pop final result for output subt Incr / (after decrementing ToS) store ToS loadI ToS output halt Sum, hex 000 / int sum(int N); clear / set result = 0 (only used for base case) store SumR load ToS / pop N off stack into local subt Incr / (after decrementing ToS) store ToS loadI ToS store SumN skipcond 800 / if N > 0 skip to body Jump Return / else we're done (go return 0) Body, load SumN / push N onto stack so we can get it back after recursive call storeI ToS / (then increment ToS) load ToS add Incr store ToS load Sum / push return addr onto stack so we can get it back after call storeI ToS / (then increment ToS) load ToS add Incr store ToS load SumN / compute and push N-1 onto stack for param subt Incr / (then increment ToS) storeI ToS load ToS add Incr store ToS JnS Sum / call sum(N-1) load ToS / pop result off stack subt Incr / (after decrementing ToS) store ToS loadI ToS store SumR load ToS / pop our stored return addr off stack subt Incr / (after decrementing ToS) store ToS loadI ToS store Sum load ToS / pop our stored N off stack subt Incr / (after decrementing ToS) store ToS loadI ToS store SumN add SumR / compute result = N + result store SumR Return, load SumR / push result onto stack storeI ToS / (then increment ToS) load ToS add Incr store ToS JumpI Sum / return SumR, hex 0 / local result within Sum SumN, hex 0 / local N within Sum Incr, hex 1 / used for ++, -- Stack, hex 43 / base of stack ToS, hex 43 / top element on stack |
Example 9: self modifying code
A simple program that overwrites part of its own code as it runs,
changing the instructions inside a function then calling the modified function.
/ self modifying program: / The foo() function, as defined, prints the value of x. / However, the first two lines of main actually overwrite / part of foo so that it computes and prints x+x instead / of computing and printing 0+x / main calls the modified function to test the results main, load instr / get the new instruction (load x) storei addr / overwrite the clear instruction (at addr 7) jns foo / run the modified function, should print 2*x halt addr, hex 7 instr, hex 100B / new instruction will be "load x" foo, hex 0 / void foo() { clear / acc = 0; add x / acc = acc + x; output / cout << acc; // i.e. prints x jumpi foo / return x, hex 5 / } |