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:
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>