** **

¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾¾

**Points**: 100 points

**Due**: Week 5, Tuesday, September 23, 2003

- (30 pnts) After you read
**carefully**the man page of exec system call regarding running script files (or called interpreter files), answer the following questions (assuming a UNIX system).

a)
(5
pnts) Why does a script file always start with “#!”?

To be recognized as a script file by the exec system call, a script must start with “#!”. In other words, this is given by the exec system call.

b)
(10
pnts) Suppose we have a Perl script file named “simple-perl.pl” under the
current working directory, which is given below.

#!/usr/bin/perl -w

@a = (1, 2, 3, 4, 5);

foreach $b (@a)

{

$b
*=3;

print
"b" . $b . "\n";

print
"a" . @a . "\n";

}

What is the equivalent command to “./simple-perl.pl” if we want to run “/usr/bin/perl” directly?

/usr/bin/perl –w ./simple-perl.pl

c) (15 pnts) Outline the changes you need to make to the simple-shell.cc program given in the class so that it can be used as a command interpreter. The resulting interpreter accepts the internal commands and runs external programs.

Step1. Redirect the standard input to the script file, by doing the following

Fd = open(script-file,RD_ONLY);

Close(0); dup(fd); close(fd);

Note that this changes the standard input for the shell program, not a child process.

Step 2. Ignore any line starting with “#”

2. (15
pnts) Problem 7 in the textbook on page 149: part **a** only, i.e., only the
algorithm for summing two floating-point numbers.

1.
(Note
that there are different ways to deal with the sign on the mantissa and
exponent such as 2's complement, 1's complement, or sign-magnitude. The sign-magnitude solution given requires
slightly more complicated logic, but has a very intuitive representation. Also, the exponent is often biased to remove
the explicit sign bit. Any of these
solutions are acceptable.)

Assume
a sign-magnitude floating point representation for a 32 bit word (single
precision) as follows:

<mantissa
sign:1 bit><mantissa:22 bits><exp sign:1 bit><exp:8 bits>

So,
a real number has value a=mr^{e} (where m=mantissa, r=radix or base,
and e=exponent). The mantissa is a
fraction

(0.0
£
m < 1.0) and e is a positive
integer. This floating point
representation allows for real values in the range +/-(1-2^{-21})*2^{(2^7-1)}
= +/-1.7*10^{38}.

For
example, 45.625 = 101101.101. In
normalized form, the mantissa is less than 1.0, but the mantissa has its
leftmost digit = 1. (Normalization
eliminates leading zeros such that the mantissa always contains the maximum
number of significant digits.) Here is
the number after it has been normalized:

(0.101101101)*2^{6}. The number can be represented in the 32-bit
format given above as

0
1011011010000000000000 00000110.

Addition Procedure

i. Scale the first floating point number, fp1, and the second floating point number, fp2, such that they have equal exponents, by shifting the smaller floating point number's mantissa right and incrementing its exponent until the two exponents are equal.

ii. Check the mantissa sign, if it is the same for fp1 and fp2, then add scaled mantissas; otherwise subtract the negative floating point number's mantissa from the positive floating point number's mantissa.

iii. If mantissas are added, check for overflow and renormalize if necessary. If they are subtracted, check underflow and renormalize if needed.

Note that the following is not required and this just gives you an example how complicated this can be if you need to handle all the details.

/* C code for addition of 2 sign-magnitude
fp numbers */

#define
SIGN 2147483648

#define
MANTISSA 2147483136

#define
EXPSIGN 256

#define EXP 255

unsigned int
exp1, exp2, exp3, mant1, mant2, mant3, sign3; unsigned int expsign3;

smfloat
(smfloat fp1, fp2)

{

exp1 = EXP & fp1;

exp 2 = EXP & fp2;

mant1 = (MANTISSA & fp1) >> 9;

mant2 = (MANTISSA & fp2) >> 9;

/* step i: fp
scaling prior to addition */

if ((EXPSIGN & fp1) == (EXPSIGN &
fp2)) {

if (exp1 > exp2) {

mant2 = mant2 >> (exp1 -
exp2);

exp2 = exp1;

}

else if (exp2 > exp1) {

mant1 = mant1 >> (exp2 - exp1);

exp1 = exp2;

}

}

else

if (EXPSIGN & fp1) {

mant1 = mant1 >> (exp1 + exp2);

exp1 = exp2;

} else {

mant2 = mant2 >> (exp1 + exp2)

exp2 = exp1;

}

/* step ii
addition of scaled fp numbers */

if ((SIGN
& fp1) == (SIGN & fp2)) {

mant3 = mant 1 + mant2;

exp3 = exp1;

sign3 = (SIGN & fp1);

}

else

if (SIGN & fp1) {

mant3 = mant2 - mant1;

exp3 = exp1;

if (mant3 < 0) {sign3=1; mant3=-mant3;}

else sign3=0;

}

else {

mant3 = mant1 - mant2;

exp3 = exp1;

if (mant3 < 0) {sign3=1; mant3=-mant3;}

else sign3=0;

}

expsign3 =
EXPSIGN & fp1;

renormalize(&mant3,
&exp3, &expsign3);

return
((sign3*SIGN)+(mant3<<9)+(expsign3*EXPSIGN)+exp3);

}

#define
MSB 2097152

#define
OVERFLOWLIM 4194303

#define
UNDERFLOWLIM 2097152

#define
SIZEMANT 22

void
renormalize(unsigned int *mant, *exp, *expsign) [2 pts]

{

int count = 0;

while (mant > OVERFLOWLIM) {

mant = mant >> 1;

if (expsign) exp = exp - 1; else exp = exp
+ 1;

}

while (!(mant & MSB) && (count
< SIZEMANT)) {

mant = mant << 1;

if (expsign) exp = exp + 1; else exp = exp
- 1;

count++;

}

if (exp >= 0) expsign=0; else {expsign=1;
exp=-exp;}

}

3. (15 pnts) Problem 8 in the textbook on page 150.

Here is a solution

/* The
C code */

for(i=0; i<100; i++) a[i] = 0;

;
Pseudo assembly language code generated

load r1, =0 ; r1 is
the index

store r1, i

load r2, =100

loop: load
r1, i

bge
r1, r2, out

load r3, =0

store r3, a[r1]

incr r1

store r1, i

br loop

out:

Approximately 3 + 100*7 = 703 instructions will be executed. This will require about 703 * 2.5 cycles = 1757.5 cycles. For example, on a 25 MHz machine, this is about 100 ns per cycle, or 70.3 microseconds.

4. (15 pnts) Problem 9 in the textbook on page 150.

Millisecond accuracy implies that the memory cell must be updated at least once every 10^(-3) seconds, i.e., the memory cell is updated 1000 times per second. Each update take 100 microseconds, thus 100 microseconds x 1000 = 100 ms per second of time is used to maintain the clock, leaving 900 ms per second for other computation. That is 10% of the time is spent maintaining the clock.

To maintain a clock to the closest 100 microseconds using only the interrupts, the clock routing must be called 10,000 times per second. Thus 100 microseconds x 10000 = 1000 ms per second = 1 second of time is used to maintain the clock, leaving no time for other computation. That is 100% of the time is spent maintaining the clock.

If the clock interrupt frequency is to be higher, then the time to update the clock would have to be less. In other words, the 10 microsecond resolution is not possible in the current setting.

Certain microprocessor chips now contain a cycle counter. Some operating systems use a relatively large grained interrupt frequency (Linux uses 10 millisecond), but then when gettimeofday() is called, it corrects the millisecond grained clock by checking the cycle counter and adding an offset to the interrupt

determined time.

5. (10
pnts) Problem 2 in the textbook on page 188. (Note that for a procecss t_{compute}
and t_{device} can be requested in any order; in other words, a process
may perform I/O first and computation.)

60-70 p1 p_{3}

70-95 idle
p_{3}

6. (15 pnts) Problem 11 in the textbook on page 189.

a. FCFS visits blocks in the order of 84, 155, 103, 96, and 197, and total steps across 13+71+52+7+101 = 244 steps.

b. SCAN visits the tracks in the order 97, 103, 155, 197, 199, 96, 84 incurring 6+52+42+2+103+12 = 217 steps.

c. LOOK visits the tracks in the order 97, 103, 155, 197, 96, 84 incurring 6+52+42+101+12 = 213 steps.