emacs basics, Loops, JAM simulator
Emacs is a text editor. We'll be using it later in the semester and are easing you into it now. Go back to your home directory, and start emacs by either selecting it from the "editors" menu when you right-click on the root window, or typing emacs from the UNIX prompt.
There are several other text editors available. We recommend Emacs because it is the main standard in the Unix world. Also, it is the most flexible since, for better or worse, it has everything (including the kitchen sink!) in it (e.g., a mail reader, a newsreader, a web browser, games, and a fully programmable command language). Because of this flexibility, it isn't always the easiest editor to use.
Once Emacs is started, select the a built-in tutorial file via the ``Help'' menu. It's one of those things you can dabble at; we'll let you do this on your own time. In the long run, you'll find the control-keys more useful for moving around than the mouse or arrow keys.
Some common movement commands are repeated here. You can try them out immediately on the TUTORIAL file in emacs.
keystroke | meaning |
---|---|
C-b | go backward a character |
C-f | go forward a character |
M-b | go backward a word |
M-f | go forward a word |
C-a | go to the start of the line |
C-e | go to the end of the line |
C-p | go to previous line |
C-n | go to next line |
C-v | go down one screen |
M-v | go up one screen |
M-< | go to the start of the file |
M-> | go to the end of the file |
keystroke | meaning |
---|---|
Backspace | delete previous character |
C-d | delete next character |
C-k | kill (cut) from cursor to end of line |
C-y | yank (paste) back the most recently-killed text |
C-_ | undo |
Emacs has the concept of "modes". For instance, when editing a file ending in ".ss", it is in Scheme-mode, and will treat certain command (such as indent) a little differently than if you are in (say) C mode or text mode.
An emacs window is a "view" into a file which you are editing. It can be handy to have different windows so you can deal with several files at once.
keystroke | meaning |
---|---|
C-x C-f | find file (space bar completes name) |
C-x C-s | save file |
C-x b | switch buffer (show other file) |
C-x 2 | split-window |
C-x o | other-window |
C-x 0 | delete-window (not the associated file) |
C-x C-c | quit emacs |
If you want a 2-page summary of these and other emacs commands, you can print out the emacs reference card. There is also a handout about Emacs available in Mudd.
In lecture, you've seen versions of a for loop, where the basic idea is to keep a counter which progresses through a range (e.g., 1 to 10), and does something for each of those counters. Here is one version:
(define fori= (lambda (start stop? next body!) (if (stop? start) (void) (begin (body!) (fori= (next start) stop? next body!)))))While this is more general than having a counter just step through a range, it still keeps the idea of a "counter" around in the form of an initial value start, a final test on this "counter" (stop? start), and an "increment" of this "counter" (next start).
Here's a typical use of a for loop:
(define v (vector 3 8 10 8 1 0 12)) (define sum 0) (fori= 0 (lambda (i) (>= i (vector-length v))) add1 (lambda (i) (set! sum (+ sum (vector-ref v i)))))
There are many other kinds of loops. One of the most useful is a while loop. It is simpler than a for loop -- it has a body and a stop condition that is tested at the beginning of each iteration, but it does not provide a "counter"'s start value and next function. It can be used as follows:
(define v (vector 3 8 10 8 1 0 12)) (define sum 0) (define i 0) (while (lambda () (>= i (vector-length v))) (lambda () (begin (set! sum (+ sum (vector-ref v i))) (set! i (add1 i)))))Note that the stop test function takes zero arguments.
As shown by this example, if you need a counter, you have to define and increment it yourself when using a while loop, unlike the for loop. But you don't always need a counter, as in the following examples.
(define max-power-less-than-1000 (lambda (n) (define ([define n' n]) (while (lambda () (< n 1000)) (lambda () (set! n (* n' n)))))) (define microSillyUNIX (lambda () (while (lambda () #t) (lambda () (printf "You typed ~s.~n" (read)))
How would you define the function while? (Don't use fori=.)
(define while (lambda (stop? body!) ...))
How would you define while and fori= in terms of each other?
When should you prefer a for or while loop? Because you can write each one given the other, it is just a matter of style. However, you should definitely use a for loop if you are incrementing/decrementing a counter in some simple way. You should definitely use a while loop if you don't have a counter at all, as in microSillyUNIX.
Many languages have both a for and a while loop syntax built in. However, for most of these, a for loop is much more restricted than this. It is typically more like the following:
(define restricted-fori= (lambda (start stop increment body!) (if (> start stop) (void) (begin (body!) (restricted-fori= (+ start increment) stop increment body!)))))In that case, for loops are only used with simple numerical counters, and while loops are used for everything else.
Scheme doesn't have either a for or while loop built in because, as we've shown, each is just a special case of recursion.
Each of these loops test a stop condition at the beginning of each iteration. How would you implement a loop that tests a stop condition at the end of each iteration, such as a do-while or repeat-until loop?
Today we will discuss some of the basics of using the JAM simulator. We will use it more in a later lab.
Embarrassingly, in order to run the simulator from DrScheme, you must set the language level to Quasi-R4Rs. It's unfortunate that this language-level is necessary; if we get the problem fixed this soon, we will announce it.
To start the Jam2000 simulator, first start DrScheme, and then
evaluate the expression
(load "/home/comp210/Projects/Jam/jam.ss").
Scheme's load
function just processes the contents
of the indicated file.
You can take a look at the file jam.ss; it is
just Scheme code. (Though all it does is load some other files;
it might be more interesting to look at, e.g., jam-cpu.ss.)
Loading jam.ss defines the simulator code, and starts it running as well. You'll see:
[00000]: 00000000 (halt) %The first number in brackets is the address of the ``current'' memory bucket (0 in this case). The next number is the contents of the bucket (initially 0). If this corresponds to an encoded instruction, then the decoded (assembly) version follows in parentheses. Finally, the % is the prompt for the Jam2000 simulator. The ``current'' memory bucket is the one named by the PC, so in general the prompt should be interpreted as
[PC]: mem[PC] (disassemble mem[PC]) %where "mem[PC]" means "take the number stored in register PC, interpret it as a memory address, and fetch the contents of the indicated memory location". For example, mem[17] denotes the contents of the 17th memory location (which might happen to be 4321). "Disassemble" is a function which takes a number, and returns the assembly-code representation of that instruction.
Here is a short Jam2000 program which adds 8 and 14:
+00000849 ; (ldi 4 8) ; R4 <-- 8 +00001439 ; (ldi 3 14) ; R3 <-- 14 00034510 ; (add 5 4 3) ; R5 <-- R4 + R3 (i.e., 22)Type each of these three encoded instructions in response to a prompt. You can omit leading zeroes and the +. Notice how the display updates: every time you type a number, that number is placed into mem[PC], and the PC is incremented by 1. (This is just the process of the Jam2000 simulator interface, not the Jam2000 machine itself.) Thus you are placing these instructions into mem[0], mem[1], and mem[2].
Type ? for a list of further Jam commands. From this you can find out that typing m will ask you for a memory range, and then print those memory locations. Print the contents of memory locations 0 through 15. Similarly, press s to see the state of the PC and registers.
Now, we'll execute the program we just typed in above. How do we do that? Yep, like the help screen said, type x for "execute". Nothing seemed to happen (even after looking at the status again). Well, one small change--the program counter stepped from 4 (instruction "halt") to 5. What happened? Recall from class, what the CPU does repeatedly:
To quit the simulator, type q, and you will be back at the DrScheme prompt.
Translate the following Jam assembly code into machine code starting at location 2000, and execute it. (You'll want to use the handy JAM reference card, also available from the "Readings" link from the class page.) This program calculates 1 + 2 + 3 + ... + 10; blank lines and labels are solely to improve readability.
; r0 will contain "i", which will count 1..10 ; r1 will contain "max", which is 10 ; r2 will contain "sumSoFar" ; r3 will contain the constant 1 (ldi 0 1) ; i := 1 (ldi 1 10) ; max := 10 (ldi 2 0) ; sumSoFar := 0 (ldi 3 1) ; r3 := 1 loop: (sub 4 0 1) ; compare i with max (well, compute i-max) (bgz 4 done) ; if i-max > 0, branch to label "done" (add 2 2 0) ; sumSoFar := sumSoFar + i (add 0 0 3) ; i := i + 1 (jmpi loop) ; go back and repeat done: (print 2) ; print sumSoFar (halt)
Try modifying the above to sum the cubes of 1..10.