Computer Science 3 - 2005 - 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 (4 sides).)

1. I have a memory like a sieve and cannot remember - remind me of your name (surname) and student number [1]

Pat Terry 663T0884

2. The PVM currently supports two fundamental data types - integers and booleans - and can support dynamic allocation of arrays of such elements. Suppose we wished to be able to deal with simple character data, so that we could translate programs like the following:

       void main () {
       // Reads and stores a simple sentence
       // Ima Twitt, 2005
         int n = 0;
         char ch;
         char[] sentence = new char[1000];
         repeat
           read(ch);  write(ch);
           sentence[n] = ch;
           n++;
         until (ch == '.');
       }

We would be able to do this with the addition of opcodes, say INPC and PRNC, for reading and writing a single character. Assuming the existence of these opcodes, complete the translation of the program [6].

        ; using original opcode set                   ; using optimised opcode set
         0 DSP    3                                   0 DSP    3
         2 LDA    0                                   2 LDC_0
         4 LDC    0                                   3 STL_0          ; n = 0
         6 STO          ; n = 0                       4 LDC    1000
         7 LDA    2                                   6 ANEW
         9 LDC    1000                                7 STL_2          ; char[] sentence = new...
        11 ANEW                                       8 LDA_1
        12 STO          ; char[] sentence = new ...   9 INPC           ; read(ch)
        13 LDA    1                                  10 LDL_1
        15 INPC         ; read(ch)                   11 PRNC           ; write(ch)
        16 LDA    1                                  12 LDL_2
        18 LDV                                       13 LDL_0
        19 PRNC         ; write(ch)                  14 LDXA
        20 LDA    2                                  15 LDL_1
        22 LDV                                       16 STO            ; sentence[n] = ch
        23 LDA    0                                  17 LDL_0
        25 LDV                                       18 LDC_1
        26 LDXA                                      19 ADD
        27 LDA    1                                  20 STL_0          ; n++
        29 LDV                                       21 LDL_1
        30 STO          ; sentence[n] = ch           22 LDC    46
        31 LDA    0                                  24 CEQ            ; ch == '.' ?
        33 LDA    0                                  25 BZE    8
        35 LDV                                       27 HALT
        36 LDC    1
        38 ADD
        39 STO          ; n++
        40 LDA    1
        42 LDV
        43 LDC    46
        45 CEQ          ; ch == '.' ?
        46 BZE    13
        48 HALT

3. What would be the additions to the switch statement in the emulator to support these two opcodes? (In a fit of generosity I have listed the other I/O cases below) [3+3]

The input operation is particularly simple:

            case PVM.inpc:          // character input
              adr = pop();
              if (inBounds(adr)) {
                mem[adr] = data.readChar();
                if (data.error()) ps = badData;
              }
              break;

For the PRNC case we have to "cast", and it is as well to work modulo 256 to handle values that might otherwise embarrass us by being out of range:

            case PVM.prnc:          // character output
              if (tracing) results.write(padding);
              results.write((char) (Math.abs(pop()) % (maxChar + 1)), 1);
              if (tracing) results.writeLine();
              break;

The supplied code read as follows:

            case PVM.inpi:          // integer input
              adr = pop();
              if (inBounds(adr)) {
                mem[adr] = data.readInt();
                if (data.error()) ps = badData;
              }
              break;
            case PVM.prni:          // integer output
              if (tracing) results.write(padding);
              results.write(pop(), 0);
              if (tracing) results.writeLine();
              break;
            case PVM.inpb:          // boolean input
              adr = pop();
              if (inBounds(adr)) {
                mem[adr] = data.readBool() ? 1 : 0;
                if (data.error()) ps = badData;
              }
              break;
            case PVM.prnb:          // boolean output
              if (tracing) results.write(padding);
              if (pop() != 0) results.write(" true  "); else results.write(" false ");
              if (tracing) results.writeLine();
              break;
            case PVM.prns:          // string output
              if (tracing) results.write(padding);
              loop = next();
              while (ps == running && mem[loop] != 0) {
                results.write((char) mem[loop]); loop--;
                if (loop < stackBase) ps = badMem;
              }
              if (tracing) results.writeLine();
              break;

4. Briefly indicate where, if anywhere, you would have to make other changes to the PVM.java file to handle these new opcodes [2].

We should have to add internal values for inpc and prnc to the "enumeration" at the start of the file, and we should have to add the corresponding initialisation of the elements of the mnemonic look-up array (at the end of the file). Since these are "zero address" instructions, they do not give rise to further changes in the parts of the file responsible for tracing or for listing code.

5. Having a character data type is all very well, but it could get you into trouble. Consider code like

        int i = 0;
        char c = 'a';
        while (i < 1000) {
          i++; c++;
        }

Sooner or later (but, of course, when you least wanted trouble) this sort of code would cause trouble. What extensions would you suggest be made to the opcode set and/or the interpreter to allow it to catch such errors? [3]

There are various strategies we could employ. The simplest is probably to have a variation on the STO opcode (and its derivatives like STL) that will perform a range check on assignment:

            case PVM.stoc:          // character checked store
              tos = pop(); adr = pop();
              if (inBounds(adr))
                if (tos >= 0 && tos <= maxChar) mem[adr] = tos;
                else ps = badVal;
              break;

            case PVM.stlc:        // character checked pop to local variable
              tos = pop(); adr = cpu.fp - 1 - next();
              if (inBounds(adr))
                if (tos >= 0 && tos <= maxChar) mem[adr] = tos;
                else ps = badVal;
              break;

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

         LDA   X          and   LDA   Y
         LDV                    <code>
                                STO

occurred so frequently that it might be worth introducing special opcodes LDL X and STL Y instead. By now you will recognise something of the Terry perversity - maybe the machine is 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. [2]

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]

Candidates were also supplied with an ASCII table:


7-bit ASCII table

    00   0 <NUL>  10  16 <DLE>  20  32 SP   30  48 0    40  64 @    50  80 P    60  96 `    70 112 p
    01   1 <SOH>  11  17 <DC1>  21  33 !    31  49 1    41  65 A    51  81 Q    61  97 a    71 113 q
    02   2 <STX>  12  18 <DC2>  22  34 "    32  50 2    42  66 B    52  82 R    62  98 b    72 114 r
    03   3 <ETX>  13  19 <DC3>  23  35 #    33  51 3    43  67 C    53  83 S    63  99 c    73 115 s
    04   4 <EOT>  14  20 <DC4>  24  36 $    34  52 4    44  68 D    54  84 T    64 100 d    74 116 t
    05   5 <ENQ>  15  21 <NAK>  25  37 %    35  53 5    45  69 E    55  85 U    65 101 e    75 117 u
    06   6 <ACK>  16  22 <SYN>  26  38 &    36  54 6    46  70 F    56  86 V    66 102 f    76 118 v
    07   7 <BEL>  17  23 <ETB>  27  39 '    37  55 7    47  71 G    57  87 W    67 103 g    77 119 w
    08   8 <BS>   18  24 <CAN>  28  40 (    38  56 8    48  72 H    58  88 X    68 104 h    78 120 x
    09   9 <HT>   19  25 <EM>   29  41 )    39  57 9    49  73 I    59  89 Y    69 105 i    79 121 y
    0A  10 <LF>   1A  26 <SUB>  2A  42 *    3A  58 :    4A  74 J    5A  90 Z    6A 106 j    7A 122 z
    0B  11 <VT>   1B  27 <ESC>  2B  43 +    3B  59 ;    4B  75 K    5B  91 [    6B 107 k    7B 123 {
    0C  12 <FF>   1C  28 <FS>   2C  44 ,    3C  60 <    4C  76 L    5C  92 \    6C 108 l    7C 124 |
    0D  13 <CR>   1D  29 <GS>   2D  45 -    3D  61 =    4D  77 M    5D  93 ]    6D 109 m    7D 125 }
    0E  14 <SO>   1E  30 <RS>   2E  46 .    3E  62 >    4E  78 N    5E  94 ^    6E 110 n    7E 126 ~
    0F  15 <SI>   1F  31 <US>   2F  47 /    3F  63 ?    4F  79 O    5F  95 _    6F 111 o    7F 127 <DEL>


Home  © P.D. Terry