Department of Computer
Science
CSU
Stanislaus
California
State University
MarieSimEx: The
Marie Computer Simulator Extension Xuejun Liang June 2021 |
MarieSimEx is an extension to MarieSim which is a computer architecture simulator based on the MARIE architecture and designed to teach beginning computer organization and architecture. Using MarieSim, a simple accumulator-based assembly language program can be assembled and run. Users can track the values of internal CPU registers and the memory contents in MarieSim environment as each instruction is executed. But, MarieSim is too simple and thus unable to support some important concepts in computer architecture such as immediate and indexed addressing modes, stack, and recursive subroutine. Meanwhile, MarieSim does not support of defining a label (symbol) to hold the address of another label (symbol) symbolically. Programmers have to compute (count) the address of a label manually and then hardcoded it into their code. In order to solve these problems, an extension to MarieSim, called MarieSimEx, is developed. In MarieSimEx, a directive LAB is added for defining a label to hold the address of another label symbolically. An instruction LIMM is added for loading an immediate constant into the accumulator AC. This instruction is apparently an extension of MARIE instruction CLEAR which loads zero into AC. More importantly, a stack pointer is added to support subroutine linkage via stack. A stack frame can be built for a subroutine to hold the return address, input arguments, output results, local variables, etc. Therefore, the MARIE subroutine call instruction JNS is revised to put the return address on top of stack instead of the memory slot just before the first instruction of the subroutine. Finally, a new instruction JR is added for subroutine return. In the following, the MARIE instruction set is described briefly along with the new extension. Then, two example applications are used for illustrating and comparing the differences between MarieSim and MarieSimEx. The first application is to compute the sum of an array of numbers and the second is to compute Fibonacci numbers. Different programming techniques are used to compute Fibonacci numbers so that students can have a better understanding of global variables, local variables, stack, subroutine, and recursion. Finally, two programming assignments are also provided for student practice. |
The MARIE architecture has the
following characteristics:
· Binary, two's complement data representation.
· Stored program, fixed word length data and instructions.
· 4K words of word-addressable main memory.
· 16-bit data words.
· 16-bit instructions, 4 for the opcode and 12 for the address.
· A 16-bit arithmetic logic unit (ALU).
·
Seven registers for control and data movement.
The MARIE architecture is shown graphically as below.
The MARIE instruction encoding format is shown as below.
The MARIE instructions along with the new extension (in red color) are shown in the following table.
Opcode |
Instruction |
Meaning |
Address mode |
|
MarieSim |
MarieSimEx |
|||
0000 |
JnS X |
Mem[X] ß PC & PC ß X+1 |
Direct |
|
JnS X |
Push PC & PC ß X |
|
Direct |
|
0001 |
Load X |
AC ß Mem[X] |
Direct |
Direct, Indexed |
0010 |
Store X |
Mem[X] ß AC |
Direct |
Direct, Indexed |
0011 |
Add X |
AC ß AC + Mem[X] |
Direct |
Direct, Indexed |
0100 |
Subt X |
AC ß AC – Mem[X] |
Direct |
Direct, Indexed |
0101 |
Input |
AC ß value from keyboard |
N/A |
N/A |
0110 |
Output |
Display value in AC on screen |
N/A |
N/A |
0111 |
Halt |
Terminate program |
N/A |
N/A |
1000 |
Skipcond 000 |
Skip next instruction if AC < 0 |
N/A |
N/A |
Skipcond 400 |
Skip next instruction if AC = 0 |
N/A |
N/A |
|
Skipcond 800 |
Skip next instruction if AC > 0 |
N/A |
N/A |
|
1001 |
Jump X |
PC ß X |
Direct |
Direct, Indexed |
1010 |
Clear |
AC ß 0 |
N/A |
|
Limm Imm |
AC ß Imm |
|
Immediate |
|
1011 |
AddI X |
AC ß AC + Mem[Mem[X]] |
Indirect |
(Indexed) Indirect |
1100 |
JumpI X |
PC ß Mem[X] |
Indirect |
(Indexed) Indirect |
1101 |
LoadI X |
AC ß Mem[Mem[X]] |
Indirect |
(Indexed) Indirect |
1110 |
StoreI X |
Mem[Mem[X]] ß AC |
Indirect |
(Indexed) Indirect |
1111 |
JR |
Pop PC |
|
N/A |
Note 1: X can be either a hexadecimal literal or a label (symbol) and is used as a memory address in MarieSim and Mem[X] represents the content at the memory location X. Note 2: In MarieSimEx, Imm is a 12-bit decimal constant integer. When using direct addressing, X is the same as that in MarieSim. But when using stack-relative addressing, X has the format: $±Offset, where $ represents the stack pointer (the address of top of stack) which is stored in a reserved memory location SP and Offset is a 10-bit decimal constant integer. The two bits right before Offset inside an instruction are set to be 11. This indicates that stack-relative addressing is used. The memory address represented by $±Offset can be computed by Mem[SP]±Offset. Please note that using a reserved memory location to hold the stack pointer instead of using a dedicated register will have no impact on the original MARIE architecture including its micro architecture so that the user interface of MarieSim can be used for MarieSimEx with a minor modification. Both the value of stack pointer and the contents in stack can be observed from the memory monitor area of the MarieSim environment. If using a dedicated register, then the MARIE datapath has to be changed. Note 3: The MARIE architecture has 4K words of word-addressable main memory. The stack grows towards higher memory address end and starting from 3072. Therefore, the stack occupies 1K out of 4K MARIE word-addressable memory space. A valid MARIE memory address is still in between 0 and 4095. It is possible that the user program code and/data will occupy (overwrite) the stack memory. So, when your program utilizes the stack, please make sure your program code and data are located in memory from address 0 to address 3070. The stack pointer is located at memory location 3071. Note 4: Two important operations on stack are push and pop. Push X operation (or pseudo-instruction) will push memory content at memory address X, i.e. Mem[X], on top of stack and Pop X operation (or pseudo-instruction) will store the content on top of stack in memory location X and remove it from stack. These two pseudo-instructions can be implemented by (or equivalent with) sequences of assembly instructions, respectively, as shown in the following table. |
Push X |
Pop X |
Limm 1 Add SP Store SP Load X StoreI SP |
loadI SP Store X Limm -1 Add SP Store SP |
Note 5: The pseudo-instructions Push X and Pop X will be used in the assembly language programs in this article for the sake of saving space. In order to assemble and to run your programs, you must expand Push X and Pop X, i.e., replace them with their corresponding sequences of instructions as shown above, respectively. Currently, MarieSimEx does not support pseudo-instructions such as Push X and Pop X. |
Directives are instructions to assemblers. MarieSim has five directives. Directive ORG defines the starting address of the program. Directives DEC, OCT, and HEX define named constant in decimal, octadecimal, and hexadecimal, respectively. Directive END indicates the end of the program. MarieSimEx adds one more directive LAB which defines a named hexadecimal constant specified either by a hexadecimal literal or a label symbolically. |
Please reference the MarieSim quick guide for installing and using MarieSim. You can install and use MarieSimEx in the exactly same way as for MarieSim. The Simulator Jar Files (Executables) can be downloaded using the following links. · MarieSim (marieSim.jar) · MarieSimEx (marieSimEx.jar) |
Example 1: This example is to compute sum of an array of numbers. The code in the left of the following table is for MarieSim and MarieSimEx and the right for MareiSimEx only. It can be seen that the new instruction Limm and the new directive LAB are applied in the code for MarieSimEx. These two new extensions make programmers easier to deal with address manipulation and give programmers a greater ability to deal with immediate operands. |
/
Code for MarieSim and MarieSimEx
ORG 100 /Program
starts from 0x100
Load Addr /Load
address of first number to be added
Store Next /Store
this address is our Next pointer Load Num /Load the number of items to be
added Subt One /Decrement
Store Ctr /Store
this value in Ctr to control looping Loop,
Load Sum /Load
the Sum into AC
AddI Next /Add
the value pointed to by location Next
Store Sum /Store
this sum Load Next /Load Next Add One /Increment by one to point to next
address
Store Next /Store
in our pointer Next Load Ctr /Load the loop control variable Subt One /Subtract one from the loop control
variable
Store Ctr /Store
this new value in loop control variable
Skipcond 000 /If control variable < 0, skip
next instruction
Jump Loop /Otherwise,
go to Loop
Halt /Terminate program Addr, Hex 117 /Numbers to be summed start at
location 117 Next,
Hex 0 /A
pointer to the next number to add Num, Dec 5
/The number of values to add Sum, Dec 0
/The sum Ctr, Hex 0 /The
loop control variable One, Dec
1 /Used to increment and decrement by 1 Dat, Dec
-10 /The values to be added together
Dec 15
Dec -20
Dec 25 Dec 30 |
/
Code for MarieSimEx
ORG 100
Load Addr Store
Next Limm -1 Add
Num
Store Ctr Loop,
Load Sum
AddI Next
Store Sum Limm 1 Add
Next
Store Next Limm -1 Add
Ctr
Store Ctr
Skipcond 000
Jump Loop
Halt Addr, Lab Dat Next,
Hex 0 Num, Dec 5 Sum, Dec 0 Ctr, Hex 0 Dat, Dec -10
Dec 15
Dec -20
Dec 25
Dec 30 |
Example 2: Compute the Fibonacci number which is defined by
A C++ code that computes Fibonacci number using a loop is shown below. The algorithm used in this C++ code will be used (translated) in the assembly language programs later so that comparisons can be made. Note that variable A is used for Fib(N-2), B for Fib(N-1), C for Fib(N), and I for the loop control. |
int
main() { //compute Fib(N) int I, A,
B, C, N std::cin
>> N; //get input N, say 10. if (N < 2) C = N; else { A = 0; B = 1;
for (I = 2; I <= N; I++) { C
= B + A; A = B; B = C; } } std::cout << C; return 0; } |
Four methods will be used to compute Fibonacci numbers. The first is using a loop, the second using a function with global variables, the third using a function with local variables, and the fourth using a recursive function. The first two methods can be applied when using either MarieSim or MarieSimEx, while the last methods can be applied when using MarieSimEx only. Method 1 (Using Loop): This is done by simply translating the above C++ code into MARIE assembly code directly. Five variables with the same names as in C++ are defined with initial values. The program gets input N first, then computes the Fibonacci number and saves into C, and finally prints the result C. Note that code for MarieSim has to define an extra variable One to hold a constant number 1, while the code for MarieSimEx can use the constant number 1 directly. |
//
Code for MarieSim and MarieSimEx
ORG 100
Input // Read input
Store N //
N=input
Store C //
C=N
Subt I //
AC = N-1
SKIPCOND 800 // if N-1 > 0
JUMP L3
L2, Load B //
AC=B
ADD A //
AC=B+A
Store C //
C=B+A
Load B //
AC=B
Store A //
A=B
Load C //
AC=C
Store B //
B=C
Load I // AC=1
ADD One //
AC=I+1
Store I //
I=I+1
SUBT N //
AC=I-N
SKIPCOND 400 // if I=N, done
Jump L2 //
otherwise, continue
L3, Load C //
print result
Output
Halt // stop
// Variable Declarations
I, DEC 1 //
index
N, DEC 0 //
N
C, DEC
0 // f(N)
B, DEC 1 //
f(N-1)
A, DEC 0 //
f(N-2)
One, DEC 1 // Used for increment by 1
|
//
Code for MarieSimEx
ORG 100
Input // Read input
Store N //
N=input
Store C //
C=N
Subt I //
AC = N-1
SKIPCOND 800 // if N-1 > 0
JUMP L3
L2, Load B //
AC=B
ADD A //
AC=B+A
Store C //
C=B+A
Load B //
AC=B
Store A //
A=B
Load C //
AC=C
Store B //
B=C
LIMM 1 // AC=1
ADD I //
AC=I+1
Store I //
I=I+1
SUBT N //
AC=I-N
SKIPCOND 400 // if I=N, done
Jump L2 //
otherwise, continue
L3, Load C //
print result
Output
Halt // stop
// Variable Declarations
I, DEC 1 //
index
N, DEC 0 //
N
C, DEC
0 // f(N)
B, DEC 1 //
f(N-1)
A, DEC
0 // f(N-2)
|
Method 2 (Using Function and Global Variables): This method defines the computation part in the above code as a function called Fib. The program has the same variables as in above code. The function Fib gets input from N and save its result in C. The program gets input N first, then calls the function Fib, and finally prints the result C. Note that the subroutine call instruction JNS for MarieSim saves the return address at Fib and the first instruction of the function starts at Fib+1. The instruction JumpI Fib will allow the subroutine return. On the other hand, the subroutine call instruction JNS for MarieSimEx saves the return address in the stack and the first instruction of the function starts at Fib. The instruction JR will allow the subroutine return and remove the return address from the stack. Please also note that the calling routine and subroutine use global variables to pass the information between them. |
// Code for MarieSim
ORG 100
Input //Read
input
Store
N //N=input
JNS Fib //Call
subroutine Fib
Load
C //Print result
Output
Halt //Terminate
//
Subroutine Fib
Fib, HEX 0 //for storing return addr
Load
N
Store
C //C=N
Subt
I //AC = N-1
SKIPCOND 800 //if N-1 > 0
JUMP
L3
L2, Load
B //AC=B
ADD
A //AC=B+A
Store
C //C=B+A
Load
B //AC=B
Store
A //A=B
Load
C //AC=C
Store
B //B=C
Load I //AC=1
ADD
One //AC=I+1
Store
I //I=I+1
SUBT
N //AC=I-N
SKIPCOND 400 //if I=N, done
Jump
L2 //otherwise, continue
L3, JumpI Fib
// Global
Variable Declarations
I, DEC
1 //index
N, DEC
0 //N -- input to Fib
C, DEC
0 //f(N)-- output from Fib
B, DEC
1 //f(N-1)
A, DEC
0 //f(N-2)
One, DEC 1 //used for increment by 1
|
// Code for MarieSimEx
ORG 100
Input //Read
input
Store
N //N=input
JNS
Fib //Call subroutine Fib
Load
C //Print result
Output
Halt //Terminate
//
Subroutine Fib
Fib,
Load N
Store
C //C=N
Subt
I //AC = N-1
SKIPCOND 800 //if N-1 > 0
JUMP
L3
L2, Load
B //AC=B
ADD
A //AC=B+A
Store
C //C=B+A
Load
B //AC=B
Store
A //A=B
Load
C //AC=C
Store
B //B=C
Limm 1 //AC=1
ADD
I //AC=I+1
Store
I //I=I+1
SUBT
N //AC=I-N
SKIPCOND 400 //if I=N, done
Jump
L2 //otherwise, continue
L3, JR
// Global
Variable Declarations
I, DEC
1 //index
N, DEC
0 //N -- input to Fib
C, DEC
0 //f(N)-- output from Fib
B, DEC
1 //f(N-1)
A, DEC
0 //f(N-2)
|
Method 3 (Using Function and Local Variables): This method will use local variables (I, A, B, C) inside the subroutine Fib. These local variables are allocated in the stack. Meanwhile, the input and output of the subroutine Fib are also passed via stack. The following tables show the values in stack at several important timestamps related to subroutines: (1) Right before calling Fib, (2) Right after calling Fib, (3) Right before Fib return, and (4) Right after Fib return. |
(1) Right before calling Fib |
Memory address |
Used for |
$ |
Mem[SP] |
Input N |
(2) Right after calling Fib |
Memory address |
Used for |
$-1 $ $+1 $+2 $+3 $+4 |
Mem[SP]-1 Mem[SP] Mem[SP]+1 Mem[SP]+2 Mem[SP]+3 Mem[SP]+4 |
Input N Return address Local variable I Local variable A Local variable B Local variable C |
(3) Right before Fib return |
Memory address |
Used for |
$-1 $ $+1 $+2 $+3 $+4 |
Mem[SP]-1 Mem[SP] Mem[SP]+1 Mem[SP]+2 Mem[SP]+3 Mem[SP]+4 |
Output Fib(N) Return address Local variable I Local variable A Local variable B Local variable C |
(4) Right after Fib return |
Memory address |
Used for |
$ |
Mem[SP] |
Output Fib(N) |
As shown above, (1) Right before calling Fib, the main code pushes the input N on stack. Then the subroutine Fib is called. Note that when a subroutine is called, its return address is pushed on stack by the subroutine call instruction JNS. (2) Right after calling Fib, the return address is just put on top of stack. So, the value of stack pointer $ (or Mem[PS]) is creased by 1 and thus the input N is now located at $-1. Then the subroutine Fib uses four memory locations $+1, $+2, $+3, and $+4 from the stack area of memory space for its local variables I, A, B, and C, respectively. Therefore, the stack frame for the subroutine Fib consists of six memory words as shown in (2). (3) Right before the subroutine Fib returns, it stores the result Fib(N) in stack and overwrites the input N. Then it returns. Note that the subroutine return instruction JR will pop (remove) the return address from stack. (4) Right after the subroutine Fib returns, the return address is just removed from stack. So, the value of stack pointer $ (or Mem[PS]) is decreased by 1 and thus the result Fib(N) is now on top of stack (i.e. located at $). Then the main code pops the result into C. Finally, it prints the result. The assembly language code is shown as below. |
ORG 100 Input //Read input Store N //N=input Push N //Push
N on stack (need to expand) JnS Fib //Call
subroutine Fib Pop C //Pop
result into C (need to expand) Load C //print
result Output Halt //terminate program //Subroutine Fib Fib, Limm 1 Store $+1 //I=1 Store $+3 //B=1 Limm 0 Store $+2 //A=0 load $-1 //AC=N SUBT $+1 //N-1 SKIPCOND 800 //if N-1 > 0 JUMP L3 L2, Load $+3 //AC=B ADD $+2 //AC=B+A Store $+4 //C=B+A Load $+3 //AC=B Store $+2 //A=B Load $+4 //AC=C Store $+3 //B=C Limm 1 ADD $+1 //AC=I+1 Store $+1 //I=I+1 SUBT $-1 //AC=I-N SKIPCOND 400 //if I=N, done Jump L2 //otherwise,
continue Load $+4 //AC=C Store $-1 //Save
result L3, JR //Global Variable Declarations N, DEC 0 //N
-- input to Fib C, DEC 0 //f(N)--
output from Fib |
Method 4 (Using Recursive Function): This method will implement the subroutine Fib as a recursive function. Like in the method 3, we are going to use the same memory location of stack to store both input N and output Fib(N). Before calling the function Fib, the input N must be on top of stack (i.e., it is located at $.), and after returning from function Fib, the result Fib(N) must be on top of stack as well. The stack contents before calling and after calling are illustrated by the following tables (1) and (8). Because of Fib(N) = Fib(N-2) + Fib(N-1), we will need to call Fib(N-1) and Fib(N-2) inside Fib(N). Therefore, we need two more local memory spaces inside the stack frame of Fib(N) to store (N-1)/Fib(N-1) and (N-2)/Fib(N-2). We always need one stack space for the return address. So, the stack frame for Fib(N) needs four memory spaces on as illustrated in the following tables from (2) to (7). |
(1) Right before calling Fib(N) |
Memory address |
Used for |
$ |
Mem[SP] |
Input N |
(2) Right after calling Fib(N) |
Memory address |
Used for |
$-1 $+0 $+1 $+2 |
Mem[SP]-1 Mem[SP] Mem[SP]+1 Mem[SP]+2 |
Input N Return address of Fib(N) |
(3) Right before calling
Fib(N-1) |
Memory address |
Used for |
$-2 $-1 $ $+1 |
Mem[SP]-2 Mem[SP]-1 Mem[SP] Mem[SP]+1 |
Input N Return address of Fib(N) N-1 |
(4) Right after Fib(N-1) return |
Memory address |
Used for |
$-2 $-1 $ $+1 |
Mem[SP]-2 Mem[SP]-1 Mem[SP] Mem[SP]+1 |
Input N Return address Fib(N-1) |
(5) Right before calling
Fib(N-2) |
Memory address |
Used for |
$-3 $-2 $-1 $ |
Mem[SP]-3 Mem[SP]-2 Mem[SP]-1 Mem[SP] |
Input N Return address Fib(N-1) N-2 |
(6) Right after Fib(N-2) return |
Memory address |
Used for |
$-3 $-2 $-1 $ |
Mem[SP]-3 Mem[SP]-2 Mem[SP]-1 Mem[SP] |
Input N Return address Fib(N-1) Fib(N-2) |
(7) Right before Fib(N) return |
Memory address |
Used for |
$-1 $ $+1 $+2 |
Mem[SP]-1 Mem[SP] Mem[SP]+1 Mem[SP]+2 |
Fib(N) Return address Fib(N-1) Fib(N-2) |
(8) Right after Fib(N) return |
Memory address |
Used for |
$ |
Mem[SP] |
Fib(N) |
You may notice immediately that the value of $ in tables (2) - (7) changes from time to time after running certain instructions. As you may already notice that $ will be increased by 1 after running JNS instruction and decreased by 1 after running JR. In addition, you can increase or decrease the value of $ or Mem[SP] very easily. Because SP is a reserved memory address (label), you can use SP in your program like any other addresses (labels). For example, if you want to increase the value of $ by 5, you can perform the following three instructions. |
Limm 5 Add SP Store SP |
As
shown below, the main code is the same as that in method 3. Right after calling
Fib(N), the stack frame is shown as in the above table 2. If N |
//Main code for MarieSimEx ORG 100 Input //Read
input Store N //N=input Push
N //Push N on stack (need to
expand) JnS Fib //Call subroutine Fib Pop
C //Pop result into C (need
to expand) Load C //print result Output Halt //terminate
program //Subroutine Fib Fib, Limm -1 Add $-1 // AC = N-1 Skipcond 800 // if N
> 1 jump L1 // done Store $+1 //
store N-1 to $+1 Limm
1 // AC = 1 Add
SP // AC = SP + 1 Store
SP // Increase SP ($) by 1 JNS Fib // Call F(N-1) Limm -2 //
AC = -2 Add
$-2 // AC = N-2 Store
$+1 // Store N-2 to $+1 Limm
1 // AC = 1 Add
SP // AC = SP + 1 Store
SP // Increase SP ($) by 1 JNS Fib // Call F(N-2) Limm
-2 // AC = -2 Add
SP // AC = SP-2 Store
SP // restore SP (decrese by 2) Load
$+1 // AC = Fib(N-1) ADD
$+2 // AC = F(N-1) + F(N-2) =
F(N) Store
$-1 // store Fib(N) to $-1 L1, JR //Global Variable Declarations N, DEC 0 //N -- input to Fib C, DEC 0 //f(N)-- output from Fib |
Two programming assignments are given as below.
PA1: Add all positive integers in a given array and print the sum. A skeleton code is given and can be downloaded here (array_skeleton.mas). Note that the extension name of the skeleton file is .txt. You should change it back to .mas in order to assemble and run the code. |
PA2: Multiply two integers entered from keyboard and print the product. As MARIE architecture does not have multiplication instruction, we have to use addition to compute multiplication. A formular for this computation is given as below. |
When B is a non-negative integer, then
(2)
The following C++ code shows to compute multiplication of two integers by using the formular (2). It gets two input integers X and Y from the keyboard. Then compute the absolute value of Y and save it in Z. Next, compute the product of X and Z and save it in C by using a loop based on formular (2). Next, if Y < 0, then the final product should be -C. Finally print result. |
int main(){ int X, Y, Z, C; cout
<< "Please enter two
integers:" << endl; cin
>> X >> Y; // Z = absolute value of Y if (Y < 0) Z = -Y; else Z = Y; // C = product of X and Z C = 0; while (Z>0) { C = C + X; Z = Z - 1; } // If Y < 0, then C = -C if (Y < 0) C = -C; cout
<< C << endl; // Print result return 0; } |
PA2.A: Your assignment is to convert the above C++ code into a MARIE assembly language code. A skeleton code is given here (MultLoopSkeleton.mas). You just need to fill in a part of code that computes the product of X and Z by using a while loop. |
The following C++ code shows to compute multiplication of two integers by using the formular (2). It is the same with the above C++ code except it uses a function to the product of X and Z. |
int main(){ int X, Y, Z, C; cout
<< "Please enter two
integers:" << endl; cin
>> X >> Y; // Z = absolute value of Y if (Y < 0) Z = -Y; else Z = Y; C = Mult(X, Z); // If Y < 0, then C = -C if (Y < 0) C = -C; cout
<< C << endl; return 0; |
// Return the product of A and B, // where A is an integer and // B is a non-negative integer int Mult(int A, int B) { int P; P = 0; while (B > 0) { P = P + A; B = B - 1; } return P; } |
PA2.B: Your assignment is to convert the above C++ code into a MARIE assembly language code. A skeleton code is given here (MultFuncSkeleton.mas). You just need to fill in a part of code that computes the product of X and Z by using a function. That is to write a subroutine called Mult. Note that you need to use stacks that will hold the function’s inputs as and output as well as the return address. MarieSimEx should be used. |
PA2.C: (Bobus) Like in PA2.B, but you need to implement the subroutine Mult as a recursive function. You can use the same skeleton file in PA2.B and then rename it as MultRecFuncSkeleton.txt. Note that MarieSimEx must be used. A C++ recursive function Mult is shown as below for your reference. |
// Recursive function // Return the product of A and B, // where A is an integer and B is a non-negative integer int Mult(int A, int B) { int P; if (B == 0) P = 0; else P = A + Mult(A,
B-1); return P; } |