From 4beb127cf08da61ae5b4e28cb666a5ed89c1285c Mon Sep 17 00:00:00 2001 From: "George Z. Zachos" Date: Sat, 30 Jan 2021 03:17:24 +0200 Subject: [PATCH] Added non-jal subroutine call detection in SV. Until now only jal instructions were used to detect subroutine calls. From now on, $ra updates and subsequent jump instructions will also be detected as subroutine calls. --- mars/tools/StackVisualizer.java | 38 ++++++++-- tests/lab03_solution-gzz-laj.asm | 124 +++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 tests/lab03_solution-gzz-laj.asm diff --git a/mars/tools/StackVisualizer.java b/mars/tools/StackVisualizer.java index a7e359e..9fdb674 100644 --- a/mars/tools/StackVisualizer.java +++ b/mars/tools/StackVisualizer.java @@ -111,6 +111,8 @@ public class StackVisualizer extends AbstractMarsToolAndApplication { */ /** Register number of stack pointer (29) */ private final int SP_REG_NUMBER = RegisterFile.STACK_POINTER_REGISTER; + /** Register number of return address (31) */ + private final int RA_REG_NUMBER = RegisterFile.getNumber("$ra"); /** Stack pointer's initial address/value */ private final int SP_INIT_ADDR = Memory.stackPointer; private final Memory memInstance = Memory.getInstance(); @@ -136,6 +138,8 @@ public class StackVisualizer extends AbstractMarsToolAndApplication { private String regNameToBeStoredInStack = null; /** Name of the (subroutine) frame to be allocated in stack segment. */ private String frameNameToBeCreated = null; + /** Whether $ra was written/updated in the last instruction. */ + private boolean raWrittenInPrevInstr = false; /** * Return Address Stack. Target addresses of jal instructions are pushed and * then are popped and matched when jr instructions are encountered. @@ -419,7 +423,7 @@ protected void initializePostGUI() { @Override public void actionPerformed(ActionEvent e) { if (connectButton.isConnected()) { - restoreBackStepper(); // TODO We really need this? + restoreBackStepper(); } else { /* * User program should be recompiled (and executed) after @@ -547,6 +551,7 @@ protected void addAsObserver() { */ addAsObserver(RegisterFile.getRegisters()[SP_REG_NUMBER]); addAsObserver(Memory.textBaseAddress, Memory.textLimitAddress); + addAsObserver(RegisterFile.getRegisters()[RA_REG_NUMBER]); } @@ -579,7 +584,7 @@ else if (notice instanceof RegisterAccessNotice) { private void processRegisterAccessNotice(RegisterAccessNotice notice) { - // Currently only $sp is observed + // Currently only $sp is observed ($ra also but not for stack modification ops) // TODO: What about observing frame pointer? if (notice.getAccessType() == AccessNotice.READ) return; @@ -597,6 +602,8 @@ private void processRegisterAccessNotice(RegisterAccessNotice notice) { addNewTableRows(5); } table.repaint(); // Required for coloring $sp position during popping. + } else if (notice.getRegisterName().equals("$ra")) { + raWrittenInPrevInstr = true; } } @@ -722,14 +729,16 @@ private void processTextMemoryUpdate(MemoryAccessNotice notice) { // System.out.println(); regNameToBeStoredInStack = RegisterFile.getRegisters()[operands[I_RS_OPERAND_LIST_INDEX]].getName(); } - else if (isJumpInstruction(instrName) || isJumpAndLinkInstruction(instrName)) { // TODO handle jal equivalent? + else if (isJumpInstruction(instrName) || isJumpAndLinkInstruction(instrName)) { int targetAdrress = stmnt.getOperand(J_ADDR_OPERAND_LIST_INDEX) * WORD_LENGTH_BYTES; String targetLabel = addrToTextSymbol(targetAdrress); if (isJumpAndLinkInstruction(instrName)) { - ras.add(stmnt.getAddress()); - frameNameToBeCreated = targetLabel; - Integer count = activeFunctionCallStats.addCall(targetLabel); - frameNameToBeCreated += " (" + count + ")"; + registerNewSubroutineCall(stmnt, targetLabel); + } else if (isJumpInstruction(instrName)) { + if (raWrittenInPrevInstr == true) { + raWrittenInPrevInstr = false; + registerNewSubroutineCall(stmnt, targetLabel); + } } if (targetLabel != null) { if (debug) { @@ -783,6 +792,19 @@ else if (isJumpRegInstruction(instrName)) { } + /** + * Update {@code ras}, {@code activeFunctionCallStats} and {@code frameNameToBeCreated} + * as of a new subroutine call. + * @param stmnt the jump/jal instruction statement that invokes the new subroutine call. + * @param targetLabel the name/label of the new subroutine that is called. + */ + private void registerNewSubroutineCall(ProgramStatement stmnt, String targetLabel) { + ras.add(stmnt.getAddress()); + Integer count = activeFunctionCallStats.addCall(targetLabel); + frameNameToBeCreated = targetLabel + " (" + count + ")"; + } + + /** * @param instrName instruction name. * @@ -1036,7 +1058,7 @@ private void onSimulationStart() { if (!isObserving()) return; // System.err.println("SIMULATION - END: " + inSteppedExecution()); - if (VenusUI.getReset()) { // TODO verify + if (VenusUI.getReset()) { ras.clear(); activeFunctionCallStats.reset(); resetStoredRegAndFrameNameColumns(0, numberOfRows-1); diff --git a/tests/lab03_solution-gzz-laj.asm b/tests/lab03_solution-gzz-laj.asm new file mode 100644 index 0000000..7b9cbc2 --- /dev/null +++ b/tests/lab03_solution-gzz-laj.asm @@ -0,0 +1,124 @@ +# Calculate the product of data elements of a list +# for MYΥ-505 - Computer Architecture +# Department of Computer Engineering, University of Ioannina +# Aris Efthymiou + +# Same as lab03_solution-gzz.asm but jal instructions are replaced by la and j. + + .globl mulproc, listProd # declare the label main as global. + + ############################################################################### + # Data input. + ############################################################################### + .data +# Leaving a 2 word (= 1 list node) offset so that the address of n1_d isn't 0x0 (null pointer) +# in "Compact, Data at Address 0" memory configuration. +offset_d: .word 0x7777 +offset_n: .word 0x7777 + +# 1st item - head of the list! +n1_d: .word 1 +n1_n: .word n2_d # point to (beginning of) n2 + +# 3rd item +n3_d: .word 3 +n3_n: .word n4_d + +# 2nd item +n2_d: .word 2 +n2_n: .word n3_d + +# 5th item +n5_d: .word 5 +n5_n: .word 0 # This is the last iterm in the list + +# 4th item +n4_d: .word 4 +n4_n: .word n5_d + +# Alternative head of list. Value 0 to test mult by 0 +na_d: .word 0 +na_n: .word n2_d # point to (beginning of) n2 + + .text + # These are for providing input and testing, don't change in your + # final submission + la $a0, n1_d + la $ra, t1 + j listProd +t1: + addu $s0, $v0, $zero # Move the result to s0 + # Try it with a null pointer + addu $a0, $zero, $zero + la $ra, t2 + j listProd +t2: + addu $s1, $v0, $zero # Move the result to s1 + # Try it with 1 item list + la $a0, n5_d + la $ra, t3 + j listProd +t3: + addu $s2, $v0, $zero # Move the result to s2 + # ----- Try mult by 0 + la $a0, na_d + la $ra, t4 + j listProd +t4: + addu $s3, $v0, $zero # Move the result to s3 + + + addiu $v0, $zero, 10 # system service 10 is exit + syscall # we are outta here. + ######################################################################## + # Write your code here. Leave main as is. + ######################################################################## + +# Only works for unsigned numbers +mulproc: + addiu $sp, $sp, -12 + sw $ra, 0x8($sp) + sw $a0, 0x4($sp) + sw $a1, 0x0($sp) + addu $v0, $zero, $zero # result = 0 + sltu $t0, $a0, $a1 + bne $t0, $zero, loop_mult + # swap by xor + xor $a0, $a0, $a1 + xor $a1, $a1, $a0 + xor $a0, $a0, $a1 + # now a0 < a1 +loop_mult: + beq $a0, $zero, leave_mult + addu $v0, $v0, $a1 + addiu $a0, $a0, -1 + j loop_mult +leave_mult: + lw $a1, 0x0($sp) + lw $a0, 0x4($sp) + lw $ra, 0x8($sp) + addiu $sp, $sp, 12 + jr $ra # return + + +listProd: + addiu $sp, $sp, -8 + sw $ra, 0x4($sp) + sw $a0, 0x0($sp) + addiu $v0, $zero, 1 + beq $a0, $zero, leave_listProd + lw $a0, 4($a0) # get next address + la $ra, t5 + j listProd +t5: + addu $a1, $v0, $zero # move result into a1 + lw $a0, 0x0($sp) # get my original parameter + lw $a0, 0($a0) # get data + la $ra, leave_listProd + j mulproc +leave_listProd: + lw $ra, 0x4($sp) + addiu $sp, $sp, 8 + jr $ra + +