Assignment 5, due Sept. 30Solutions
Part of
the homework for 22C:112, Fall 2013
|
On all assignments, your name must be legible as it appears on your University ID card! Assignments are due at the start of class on the day indicated (usually Friday). Exceptions will be by advance arrangement unless there is what lawyers call "an act of God" (something outside your control). Homework must be turned in on paper, either in class or in the teaching assistant's mailbox. Never push late work under someone's door!
A problem In what order do the above steps happen? (The first and final steps above are given in the correct order.) (0.5 points)
- fputc( 'x', stdout ); is called.
- 'x' is added to the user's output buffer.
- write() is called.
- 'x' is copied from the user's buffer to a system buffer.
- 'x' is put in the output data register of the printer port.
- 'x' is printed on the output page.
#define COM1DATA 0x3F8 #define COM1LSR 0x3FD #define RxRD (1 << 0) #define RxOE (1 << 1) /* overrun error */ #define RxPE (1 << 2) /* parity error */ #define RxFE (1 << 3) /* framing error */ #define RxBR (1 << 4) /* break */ #define TxDE (1 << 5) #define TxID (1 << 6)
Overrun error indicates that new data arrived before the previous data was read. The old data is lost, but the received data in COM1DATA is valid. In the case of parity and framing errors, the data in COM1DATA is not valid. parity and framing errors, the data in COM1DATA is not valid. The break condition does not itself represent an error, but is an auxilary indicator indicating that an overrun error was very long.
As in the notes, assume that you can use inp(r) to read data from device register r and outp(r,d) to output the data d to device registerr.
a) Write getcom1(), a routine to directly implement a read from com1, ignoring the possibility of error. Keep it simple! Minimize your code. Few or no comments are needed. (0.5 points)
char getcom1() { while ((in(COM1LSR) & RxRD) != 1) /* poll */; return in(COM1DATA); }
b) Revise your solution to part a) so that, in the event that the COM1DATA is invalid because of an error, the invalid value is ignored. That is, in the event of such an error, getcom1() should continue to wait for valid input. (0.5 points)
char getcom1() { int status; int data; do { /* keep trying to read a character until error-free receipt */ do { /* polling loop */ status = in( COM1LSR ); } while ((status & RxRD) != 0); data = in( COM1DATA ); } while ((status & (RxPE | RxFE)) == 0); /* note! RxBR seems to require that RxFE be set, so no need to test */ /* note! RxOE does not mean the data is invalid, so should not test */ return data; }
typedef struct file { int fd; int count; int size; char * buf; } FILE; #define putc(ch,f) ( \ buf[ f->count++ ] = ch, \ (f->count >= f->size)?( \ write( f->fd, f->buf, f->size ), \ f->count = 0 \ ):( \ 0 \ ) \ ) #define putchar(ch) (putc( ch, stdout )) void fputc( char ch, FILE * f ) { putc( ch, f ); }
In C, source lines ending with backslash (\) are concatenated to the following line. This allows a #define to span multiple lines. In C, expressons of the form (a?b:c) are conditional; if In C, expressons of the form a is true, the value is b, otherwise, the value is c. In C, x->y refers to the field named y of the structure pointed to by the pointer x.
Note that there were several small typos in the C define above; these would have interfered with compiling this code, but should not have interfered with solving this homework problem. They have been corrected here.
a) When a file f is opened for output, what is the correct initial value for f->count? (0.5 points).
zero, so that the buffer is filled fro the beginning.
b) Why not use a constant size for the buffer? That is, why would it be useful to wait until the file is opened to decide what size buffer to allocate? (0.5 points).
The optimum buffer size might depend on the device you are using.
Examples were not required, but it might be appropriate to use a really small buffer for a really slow device, while to get the most out of a very fast device, it might be best to use a large buffer.
c) Give an appropriate implementation of fflush() for this implementation of files. (Ignore the special behavior defined for a null parameter.)
void fflush( FILE * f ) { if (f->count != 0) { write( f->fd, f->buf, f->count ); f->count = 0; } }