Computer Science 3 - 2007 - Test on Prac 20 - Solutions

This should take no longer than 25 minutes and is simply intended to probe whether you have understood the material in the prac. Use your textbook if you think it will help. Answer on the question sheet (3 sides).)

1. I have a memory like my friend Eratosqenes and his sief and cannot remember - remind me of your name (surname) and student number [1]

Pat Terry 63T0844

2. In the prac you were invited to note that sequences like

         LDA   X          and   LDA   Y
         LDV                    <code>
                                STO

occurred so frequently that it was worth introducing special opcodes LDL X and STL Y instead. By now you will recognise something of the Terry perversity - maybe the PVM was originally defined to have LDA, LDV and STO opcodes rather than simply having only LDL and STL opcodes for no other reason than that it makes for lots of fun late at night to add these opcodes to the machine. But maybe not? If you have LDL and STL, could you completely remove LDA, LDV and STO from the opcode list, or would you still need to have them available? Justify your answer. [3]

If every LDV was preceded by an LDA one could get away with using LDL instead of LDA + LDV, and if every other use of LDA was followed by a STO one could get away without LDA. But this is not the case. Consider the following code:

           read(i); list[i] = list[j];

which, even if we use every LDL and STL we can, translates to

           LDA   i
           INPI         ; read(i)
           LDL   list
           LDL   i
           INXA         ; address of list[i]
           LDL   list
           LDL   j
           INXA         ; address of list[j]
           LDV          ; value of list[j]
           STO          ; list[i = list[j]

3. The following algorithm is meant to read a list of numbers and then report on which was the greatest in magnitude. It is not quite right. Make the minimal change needed to correct it. [2]

       void main () {
       // Reads a list of non-zero numbers and reports on which had the
       // greatest magnitude
       // Example: for 1 45 -7 60 -7 0  should report 60
       // Example: for 1 45 -7 60 -70 0  should report -70
       // Ivan Idear, 2007
         int n, max = 0;
         repeat
           read(n);
           if (abs(n) > max) max = n;
         until (n == 0);
         write("largest number was ", max);
       }

All we need is to change the if statement:

           if (abs(n) > abs(max)) max = n;

4. Suppose that the PVM could be extended to incorporate a new opcode PVM.abs for dealing with the abs(n) function in the above code. What addition would be needed to the switch statement in the emulator (as it appears on pages 62 - 65 of the text) to support this new opcode? [3]

      case PVM.abs:
        Push(Math.abs(Pop());
        break;

or even

      case PVM.abs:
        tos = Pop();
        if (tos >= 0) Push(tos); else Push(-tos);
        break;

or even

      case PVM.abs:
        mem[cpu.sp] = Math.abs(mem[cpu.sp]);
        break;

or even

      case PVM.abs:
        if (mem[cpu.sp] < 0) mem[cpu.sp] = -mem[cpu.sp];
        break;

5. Show how the corrected algorithm could be coded into PVM code, making use of PVM.abs. [9]

Hint: you will be able to write a shorter translation if you make use of the LDL N and STL N opcodes mentioned in question 2, so feel free to do so.

     0  DSP   2    ; variable 0 is n, variable 1 is max     0  DSP   2    ; variable 0 is n, variable 1 is max
     2  LDA   1                                             2  LDC   0
     4  LDC   0                                             4  STL   1    ; max = 0;
     6  STO        ; max = 0;                               6  LDA   0    ; repeat
     7  LDA   0    ; repeat                                 8  INPI       ;   read(n);
     9  INPI       ;   read(n);                             9  LDL   0
    10  LDA   0                                            11  ABS        ;   // abs(n)
    12  LDV                                                12  LDL   1
    13  ABS        ;   // abs(n)                           14  ABS        ;   // abs(max)
    14  LDA   1                                            15  CGT
    16  LDV                                                16  BZE   22   ;   if (abs(n) > abs(max)
    17  ABS        ;   // abs(max)                         18  LDL   0
    18  CGT                                                20  STL   1    ;     max = n;
    19  BZE   27   ;   if (abs(n) > abs(max)               22  LDL   0
    21  LDA   1                                            24  LDC   0
    23  LDA   0                                            26  CEQ
    25  LDV                                                27  BZE   6    ; until (n == 0;
    26  STO        ;     max = n;                          29  PRNS  "largest number was "
    27  LDA   0                                            31  LDL   1
    29  LDV                                                33  PRNI       ; write(max)
    30  LDC   0                                            34  HALT       ; exit
    32  CEQ
    33  BZE   7    ; until (n == 0;
    35  PRNS  "largest number was "
    37  LDA   1
    39  LDV
    40  PRNI       ; write(max)
    41  HALT       ; exit

6. Briefly indicate where, if anywhere, you would have to make other changes to the PVM.java file to handle this new opcode [2].

We should have to add an internal value for abs to the "enumeration" at the start of the file, and we should have to add the corresponding initialisation of the element of the mnemonic look-up array (at the end of the file). Since this is a "zero address" instruction, it does not give rise to further changes in the parts of the file responsible for tracing or for listing code.

7. Suppose you could not introduce or use the PVM.abs opcode. How would you then code an algorithm like the following in PVM code, using only one PVM.prni opcode? [5]

       void main () {
         int i;
         read(i);
         write(abs(i));
       }

     0  DSP   1    ; variable 0 is i              0  DSP   1    ; variable 0 is i
     2  LDA   0                                   2  LDA   0
     4  INPI       ; read(i)                      4  INPI       ; read(i)
     5  LDA   0                                   5  LDL   0
     7  LDV                                       7  LDC   0
     8  LDC   0                                   9  CGT
    10  CGT                                      10  BZE   16  ; if (i > 0)
    11  BZE   18   ; if (i > 0)                  12  LDL   0    ;   i on tos
    13  LDA   0                                  14  BRN   19
    15  LDV        ;   i on tos                  16  LDL   0    ;   i on tos
    16  BRN   22                                 18  NEG        ;  -i on tos
    18  LDA   0    ;   i on tos                  19  PRNI       ; write(abs(i));
    20  LDV                                      20  HALT       ; exit
    21  NEG        ;  -i on tos
    22  PRNI       ; write(abs(i));
    23  HALT       ; exit

8. When doing the practical you should have noticed that the numeric values associated with the opcodes influence the performance of the interpreter. In developing a serious interpreter, one might "profile" the system, by computing a frequency count for each opcode using a set of test programs and then use this information to tweak the mnemonic to opcode mapping. Briefly suggest how and where one would modify the interpreter to perform such a frequency count as a program was interpreted and report it after execution was complete. [5]

Introduce an array in which to store the frequency counts for each instruction:

      public static int[] freq = new int[PVM.nul + 1];

Modify the start of the interpreter and the fetch-execute cycle to clear the counts as the program commences and then increment the appropriate count for each opcode encountered:

      for (int i = 0; i <= PVM.nul; i++) freq[i] = 0; // +++++++ prepare to gather statistics
      ps = running;               // prepare to execute
      do {
        pcNow = cpu.pc;           // retain for tracing/postmortem
        if (cpu.pc < 0 || cpu.pc >= codeLen) {
          ps = badAdr;
          break;
        }
        cpu.ir = next();          // fetch
        if (tracing) trace(results, pcNow);
        freq[cpu.ir]++;                               // +++++++ gather statistics
        switch (cpu.ir) {         // execute
          ...

When interpretation is complete, display the statistics for each valid opcode:

      ...
      if (ps != finished) postMortem(results, pcNow);

      for (int l = 0; l <= PVM.nul; l++)              // +++++++ display statistics
        if (!mnemonics[l].equals("")) {
          results.write(mnemonics[l], -6);
          results.writeLine(freq[l], 10);
        }

A more sophisticated system might sort this array before displaying it, or perform further analysis. For the sample programs in the prac kit one will find that some opcodes are executed far more than others!


Home  © P.D. Terry