Our Google group is set up, based on .forward email
addresses
System
setup for SAPCs
Each
SAPC is (effectively) connected to the UNIX host “ulab” by a serial line from
COM2 on the SAPC to (effectively) a serial port on ulab. We call this the
console line. (Actually, there is a terminal concentrator involved.) When
Tutor prints a prompt, those bytes are going out COM2 and are handled by the
UNIX program “mtip” that we run on ulab.
mtip
shuttles bytes back and forth between your stdin/stdout user i/o setup and the
console line. When you type a character during an mtip session, it goes
via stdin to the mtip program, and from there out to COM2 of the connected
SAPC. If you type “~” or <esc>, the mtip escape character, mtip
takes notice and then waits for the next character to see what to do, for
example ~d (or <esc>d) for download.
Each
SAPC numbered 5 or more has its COM1 separately connected to another serial
port on ulab. This connection is used by remote gdb to provide debugging.
When
you type “~r” (or <esc>r) in mtip, the connected SAPC gets
rebooted. This works by first being interpreted by mtip, and then mtip
runs another program that sends a command via a serial port on ulab to the
“reset server”, a little machine that John Lentz built for this purpose.
It interprets the command and then generates a signal on a wire into the reset
circuitry of the right SAPC, that is, a signal equivalent to pressing the reset
button on the SAPC box.
Intro
to hw1—
Problem
1—warmup for 2. Just duplicate a given remgdb session –due Thurs,
Sept. 21
Rest
due following Oct 1--
Problem
2—UNIX gdb for hello-world problem
Problem
3--finishing an i/o library for the SAPC.
Intro
to hw1—
Problem 3 (Part 2)--finishing an i/o library for the SAPC.
As a library, it
implements certain useful functions for apps. Its API is in io_public.h:
void ioinit(void);
int read(int dev, char *buf, int nchar);
int write(int dev, char *buf, int nchar);
also “control”
Read
and write look very much like the same-named UNIX system calls, except for
“dev” instead of “fd”. The dev parameter is the device number, for the io
library. Here dev can be TTY0 (value 0, standing for COM1) or TTY1 (value 1,
standing for COM2). See tty_public.h for the following:
#define TTY0 0
#define TTY1 1
In class, we looked briefly at the provided test program testio.c, to get the idea that it calls into the library using the API quoted above.
In
"write(ldev, buf, nchar)", seen in testio.c, ldev is TTY0 or TTY1.
These numbers are defined in the header file tty_public.h provided with the hw1
project files. These device numbers are special to hw1, hw2, etc.
testio.c
is the test program calling through the API. After making sure it’s
talking to the user over a serial line, device ldev, it does ioinit() and then
write(ldev, “hi!\n”, 4) as a first test. As delivered, output works but
without using interrupts. Your job is to reimplement it with interrupts.
kprintf. Note the use of kprintf instead of printf in testio.c
and elsewhere. Kprintf (for kernel printf, currently called printk in Linux
sources) first turns off all interrupts then executes printf with the same
arguments as it was called with, and then restores interrupts to their previous
state. This means that if execution
reaches the kprintf code it will definitely print out the message, even if
interrupts are enabled in the program. That is a great help for debugging, since it’s
important to know where execution is in the code. So be sure to use kprintf
instead of printf for debugging hw1 code.
Recall
from CS341 that the SAPC device numbers COM1 (value 1) and COM2 (value 2) are
in a system of numbers set up in $pcinc/sysapi.h, which is included from
$pcinc/stdio.h, and thus is in effect in any program with “#include
<stdio.h>” or equivalent.
Note:
you should have the environment pcinc defined for you by the ulab module, so if
you can run mtip, you can also use $pcinc, for example by doing "cd
$pcinc" or "ls $pcinc" or "more $pcinc/stdio.h".
To see what it stands for, do "echo $pcinc". It's just a
directory in the UNIX filesystem. Similarly $pcex stands for the file
path to the SAPC examples directory.
The
"system defined" (via stdio.h for SAPC) devices:
#define CONSOLE 100
#define KBMON 0 <---keyboard +
monitor (we can’t use this via mtip)
#define COM1 1
#define COM2 2
CONSOLE
is the current console, where the Tutor prompt shows up, and where the user is
typing. It is possible to run Tutor with console KBMON, COM1, or COM2,
depending on what device the user types the first carriage return on at bootup
time. So by using CONSOLE, for example by fprintf(CONSOLE, “hi”); or
equivalently printf(“hi”), we can talk to our user regardless of which way they
are using our code. CONSOLE is the logical console, like stdout in UNIX.
All output via CONSOLE is sent to remote gdb as well as to the Tutor console.
When we use mtip, the Tutor console line is COM2. So fprintf(CONSOLE, “hi”) and fprintf(COM2, “hi”) both output directly to the user. You can put fprintf(COM1, “hi”) in your program, and it will work, but you won’t see the resulting output on COM1 (unless you remember a trick we used in CS341 mp5.) (If you’re using remote gdb, you’ll be messing around with its protocol connection, to its great detriment.)
Even simpler, we can just put "printf("hi")" to write to the console.
SAPC
Support Library
Uses
device numbers: COM1, COM2, CONSOLE, etc., #define’d via stdio.h for SAPC
#include
<stdio.h> includes special stdio.h for SAPC, in $pcinc.
How does this work? via compiler flag “–I <include-path>” in
makefile
In
the SAPC library, also arranged for access in the makefile:
Note
that kprintf and some other functions in the SAPC library are utilizing the
fact that our SAPC code is running in kernel mode, not user mode as is normal
for C applications. In user mode, we
cannot turn off the interrupt system, as is done in kprintf!
In
some cases we want to make sure we’re talking to the user over a serial
line. We can ask Tutor what the current console device is by using the
call “sys_get_console_dev()”. You’ll see this called in echo.c and hw1’s
testio.c.
hw1:
In problem 3, you write code suitable for an i/o library layered on top of SAPC
library.
As a library, it
implements certain useful functions for apps. Its API is in io_public.h:
void ioinit(void)
int read(int dev, char *buf, int nchar);
int write(int dev, char *buf, int nchar);
also “control”
Read
and write look very much like the same-named UNIX system calls, except for
“dev” instead of “fd”. The dev parameter is the device number, for the io
library. Here dev can be TTY0 (value 0, standing for COM1) or TTY1 (value 1,
standing for COM2
Look
at the API again. This can be called a “device-independent” i/o library
because the interface is generic, not specific to any particular device.
The actual device in use can be determined at runtime, for example, by asking
the user for a device number.
The
edits you need to make are all in tty.c, in ttyread and ttywrite and the
interrupt handler. A call to read ends up at ttyread and a call to write
at ttywrite. I’ll let you trace out how this happens. Look at io.c
and ioconf.c. This shows how device independent i/o systems work—the
device number specifies which device-specific function to actually
execute. Here the device-specific functions are ttyread and ttywrite, and
the bundle of tty-functions in tty.c is called the tty driver, or serial port
driver.
C
Objects, a quick intro/review.
Here
the Queue ADT in C is provided in the queue subdirectory, along with a unit
test testqueue.c. queue.h defines the Queue API and the Queue type.
You
know how to do objects in Java, what about in C? Recall the Chip object
in CS341. Also the Cmd object for tutor.
Example:
Rectangle objects
struct rect {
int x1, y1, x2, y2;
};
struct rect *recp;
recp->x1 = 10;
Watch
out!, there’s no (validly-allocated) memory pointed to by recp! This is a
garbage pointer, a pointer that points nowhere good. Using it
usually causes segmentation violations on UNIX and similar exceptions on
Windows. But on SAPC, all user memory is writable, so it may quietly work
to damage some memory.
Normally
under UNIX or Windows, we could malloc space for the Rectangle, but we have no
malloc in the SAPC library. Anyway, malloc is quite expensive in CPU, and
we can easily avoid using it. Just set up whole objects like this:
struct rect rect;
Now
we can put
rect.x1 = 10;
As a Java programmer, you’re used to “Rectangle
rect;” meaning rect is a ref to a Rectangle, but in C, rect is the whole
object, more like int x; in C or Java.
To make a rectangle pointer, we have to use * in the
type: “struct rect *rp;” defines rp to be a struct rect pointer.