Department of Computer Science
CSU Stanislaus
California State University

 

MarieSimR: The Marie Computer Simulator Revision

 

Xuejun Liang

September 2021

 

 

Introduction

MarieSimR is a revision of 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 addressing mode, stack, stack-relative addressing mode, 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, a revision of MarieSim called MarieSimR is developed. In MarieSimR, an assembler 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 and stack-relative addressing mode are added to support subroutine linkage via stack. The MARIE subroutine call instruction JNS is replaced by CALL which puts the return address on top of stack instead of the memory slot just before the first instruction of the subroutine. Meanwhile, the MARIE subroutine return instruction JUMPI is replaced by JR which gets the return address on top of stack. Finally, a new instruction IncSP is added for increasing or decreasing the stack pointer. Now, A stack frame can be built for a subroutine to hold the return address, input arguments, output results, local variables, etc. and thus a recursive subroutine can be supported.

In the following, the MARIE instruction set is described briefly along with the new revision. Then, two example applications are used for illustrating and comparing the differences between MarieSim and MarieSimR. 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.

 


 

My Paper and Presentation about This Computer Simulator Revision

Paper: MarieSimR: The Marie Computer Simulator Revision

Presentation Slides: MarieSimR: The Marie Computer Simulator Revision

 


MARIE Instruction Set and Revision

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 instructions (in red color) are shown in the following table.

Opcode

Instruction

Meaning

Note

0000

JnS X

Mem[X] ß PC & PC ß X+1

Deleted

Call X

Push PC & PC ß X

Added

0001

Load X

AC ß Mem[X]

 

0010

Store X

Mem[X] ß AC

 

0011

Add X

AC ß AC + Mem[X]

 

0100

Subt X

AC ß AC – Mem[X]

 

0101

Input

AC ß value from keyboard

 

0110

Output

Display value in AC on screen

 

0111

Halt

Terminate program

 

1000

Skipcond 000

Skip next instruction if AC < 0

 

Skipcond 400

Skip next instruction if AC = 0

 

Skipcond 800

Skip next instruction if AC > 0

 

1001

Jump X

PC ß X

 

1010

Clear

AC ß 0

Deleted

Limm Imm

AC ß Imm

Added

1011

AddI X

AC ß AC + Mem[Mem[X]]

 

1100

JumpI X

PC ß Mem[X]

Deleted

JR

Pop PC

Added

1101

LoadI X

AC ß Mem[Mem[X]]

 

1110

StoreI X

Mem[Mem[X]] ß AC

 

1111

IncSP Imm

Mem[SP] ß Mem[SP] + Imm

Added

 

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 MarieSimR, 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 MarieSimR 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 a 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 sequences of assembly instructions, respectively, as shown in the following table.

 

Push  X

Pop  X

IncSP  1

Load   X

StoreI SP

loadI   SP

Store   X

IncSP -1

 

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, MarieSimR does not support pseudo-instructions such as Push X and Pop X.

 

Note 6: The new instruction IncSP Imm can be implemented by the following three instructions:

Limm Imm

Load   SP

Store   SP

This indicates that the new instruction IncSP is not necessary. But the new instruction can replace three instructions so that it saves the memory space and takes less time to execute. More importantly, it simplifies the stack pointer operation so that it makes the push and pop operations easier to understand.

 

MARIE Directives and Revision

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. MarieSimR adds one more directive LAB which defines a named hexadecimal constant specified either by a hexadecimal literal or a label symbolically.

 

How to Install and Use MarieSim and MarieSimR

Please reference the MarieSim quick guide for installing and using MarieSim. You can install and use MarieSimR in the exactly same way as for MarieSim. The Simulator Jar Files (Executables) can be downloaded using the following links.

·       MarieSim (marieSim.jar)

·       MarieSimR (MarieSimR.jar)

 

Assembly Language Program Examples Using MarieSim and MarieSimR

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 MarieSimR and the right for MarieSimR only. It can be seen that the new instruction Limm and the new directive Lab are applied in the code for MarieSimR. Limm gives programmers a greater ability to deal with immediate operands and Lab makes programmers easier to deal with the address manipulation.

 

/ Code for MarieSim and MarieSimR

      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 MarieSimR

      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 MarieSimR, while the last two methods can only be applied when using MarieSimR.

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 MarieSimR can use the constant number 1 directly. 

 

// Code for MarieSim and MarieSimR

    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 MarieSimR

    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 Call for MarieSimR 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 MarieSimR

    ORG 100

    Input           //Read input

    Store    N      //N=input

    Call     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 Call. (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.

 

//Main code for MarieSimR

    ORG      100

    Input           //Read input

    Store    N      //N=input

    Push     N      //Push N on stack (need to expand)

    Call     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 in stack 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 Call instruction and decreased by 1 after running JR. In addition, you can increase or decrease the value of $ by using the instruction IncSP. For example, IncSP 5 will increase the value of $ by 5.

 

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  1, it is done. Otherwise, store N-1 at $+1 and increase $ by 1. Now, N-1 is at $ as shown in the above table 3 and is ready to call Fib(N-1). Right after Fib(N-1) returns, its result Fib(N-1) is stored at $ as shown in the above table 4. Then store N-2 at $+1 and increase $ by 1. Now N-2 is at $ as shown in the above table 5 and is ready to call Fib(N-2). Right after Fib(N-2) returns, the result Fib(N-2) is stored at $ as shown in the above table 6. Then $ is restored by decreasing by 2. Next, the result Fib(N) = Fib(N-1) + Fib(N-2) is computed and stored at $-1 as shown in the above table 7. Now it is ready for Fib(N) to return. After the return, Fib(N) is at $ as shown in the above table 8 because the return instruction JR decreases $ by 1. The assembly code is shown as below. Different colors are applied for different stages of the code as described in the above.

 

 

//Main code for MarieSimR

    ORG      100

    Input           //Read input

    Store    N      //N=input

    Push     N      //Push N on stack (need to expand)

    Call     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

    IncSP    1      // Increase SP ($) by 1

    Call     Fib    // Call F(N-1)

    Limm     -2     // AC = -2

    Add      $-2    // AC = N-2

    Store    $+1    // Store N-2 to $+1

    IncSP    1      // Increase SP ($) by 1

    Call     Fib    // Call F(N-2)

    IncSP    -2     // Decrease SP ($) by 2 (restore SP)

    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

 

 

Programming Assignments

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

 

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 input and output as well as the return address. MarieSimR should be used. 

 

PA2.C: (Bobus) Like in PA2.B, but you need to implement the subroutine Mult as a recursive function. A skeleton code is given here (MultReFuncSkeleton.mas). Note that MarieSimR 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;

}