.rm CM
.nr PS 12
.ps 12
.nr VS 14
.vs 14
.de (C
.nr PS -2
.nr VS -2
.nr LL 5.5i
.IP
..
.de )C
.sp .5c
.nr PS +2
.nr VS +2
.nr LL 6i
..
.DS C
.LG
.LG
.sp |2c
\fBMagic Tutorial #S-2: Boxes and labels
.ds LH Magic Tutorial #S-2
.ds RH \*(DY
.ds CF - % -
.sp 1c
.NL
\fIRajit Manohar\fR
.sp 1c
Department of Computer Science
California Institute of Technology
Pasadena, CA 91125

.SM
This tutorial corresponds to Magic version 6.5-scm.


.DE
.SM
.LP
\fBTutorials to read first:\fR
.IP
#S-1
.br
.LP
\fBCommands introduced in this tutorial:\fR
.IP
getbox, box.push, box.pop, box.move, label.vert, label.horiz,
label.rename, label.search, label.find-next
.LP
\fBMacros introduced in this tutorial:\fR
.IP
none
.br
.NL
.sp 1c

.NH 1
The current box
.PP
The fundamental way scheme programs interact with magic layout is by
using magic's \fBbox\fR command. For instance,
.DS I
\fB(box 1 1 2 2)
.DE
changes the current box to the rectangle defined by the coordinates
(1,1) and (2,2) in the current edit cell. This is the standard magic
\fB:box\fR command. After moving the box to a particular position in
the layout, the area can be painted, erased, selected, etc.

.PP
The scheme function \fBgetbox\fR returns the current box as a list of
four integers. For instance,

.DS I
\fB(box 1 1 2 2)
\fB(define x (getbox))
.DE

will bind the list \fB(1 1 2 2)\fR to variable \fBx\fR.


.NH 1
Saving and restoring the box
.PP
If a scheme function moves the current box around, it is good practice
to restore the box back to its original position. This is especially
useful when writing a function that the user is likely to type on the
command line.

\fBbox.push\fR can be used to push a box onto the current stack of
boxes. \fBbox.pop\fR restores the box to the one on the top of the box
stack. The sequence

.DS I
\fB(box.push (getbox))
\fB(box 1 1 5 4)
\fB(paint poly)
\fB(box.pop)
.DE

will paint a rectangle of polysilicon from (1,1) to (5,4), restoring
the original position of the box.

.NH 1
Moving the box
.PP
Magic's built-in \fBmove\fR command is not entirely
reliable. Sometimes move commands are ignored, with disastrous
effects. (Think about what might happen if a move command was ignored
in the middle of drawing a stack of twenty transistors . . .) The
scheme function \fBbox.move\fR moves the box relative to the current
position.

.DS I
\fB(box.move 5 3)
.DE

will move the box right 5 lambda and up 3 lambda.

.NH 1
Labelling vertical and horizontal wires
.PP
Datapaths are usually designed by designing cells for a single bit of
the datapath, and then arraying those cells to obtain the complete
datapath. When simulating such designs, it is usually desirable to
label wires in the datapath with names like "name0", "name1", up to
"nameN."

.PP
There are two functions that can be used to perform such a task. The
function \fBlabel.vert\fR returns a function that can be used as a
labeller for vertically arrayed nodes. \fBlabel.horiz\fR returns a
function that can be used as a labeller for horizontally arrayed
nodes.

.DS I
\fB(define lbl (label.vert "name" 6)
.DE

The command above defines a new function \fBlbl\fR that can be used to
generate labels beginning with "name0" for nodes that are vertically
spaced by 6 lambda. The simplest way to use this function is to bind
it to a macro as follows:

.DS I
\fB(macro 1 "lbl")
.DE

Place the box over the lowest node. Every time key "1" is pressed, a
new label "nameM" is created and the box is moved up by 6
lambda. \fBlabel.horiz\fR can be used in a similar fashion for
labelling nodes that are horizontally arrayed.

.NH 1
Finding and renaming existing labels
.PP
The label macros provide functionality to search for all labels
that match a particular string. Place the box over the region of
interest. Type:

.DS I
\fB(label.search "label")
.DE

To place the box over the first occurrence of the label you searched
for, type:

.DS I
\fB(label.find-next)
.DE

Repeatedly executing this function causes the box to move to all the
labels that match the search pattern. Typically, one would bind 
\fBlabel.find-next\fR to a macro.

.PP
The command \fBlabel.rename\fR can be used to rename all labels with a
particular name. To use this command, place the box over the region of
interest. Then type

.DS I
\fB(label.rename "label1" "label2")
.DE

All occurrences of label "label1" in the current box will be
renamed to "label2".


.NH 1
Writing these functions
.PP
The functions discussed in this tutorial are not built-in. They are
user-defined functions in the default scheme file loaded in when magic
starts.

.PP
As you begin to use magic with the scheme command-line interpreter,
you will observe that commands for drawing paint on the screen are
extremely slow. This time interval is not normally noticeable because
editing is interactive. However, when one can write a scheme program
to draw twenty transistors on the screen, this delay becomes
noticeable. It is worthwhile to minimize the number of magic commands
executed, even if this involves writing more scheme code. The
\fBbox-pop\fR command has been tuned a little to not execute the
\fBbox\fR command if the box would not move as a result.

.DS I
\fB(define box.list ())

(define box.move
  (lambda (dx dy)
    (let* ((x (getbox))
	   (nllx (+ dx (car x)))
	   (nlly (+ dy (cadr x)))
	   (nurx (+ dx (caddr x)))
	   (nury (+ dy (cadddr x))))
      (box nllx nlly nurx nury)
      )
    )
  )

(define box.=?
  (lambda (b1 b2)
    (and (and (=? (car b1) (car b2)) (=? (cadr b1) (cadr b2)))
	 (and (=? (caddr b1) (caddr b2)) (=? (caddr b1) (caddr b2)))
	 )
    )
  )

(define box.push
  (lambda (pos)
	(set! box.list (cons pos box.list))
    )
  )
.DE

.DS I
\fB(define box.pop
  (lambda ()
    (if (null? box.list)
	(echo "Box list is empty")
	(let ((x (car box.list)))
	  (begin 
            (set! box.list (cdr box.list))
            (if (box.=? x (getbox)) #t (eval (cons 'box x)))
	  )
	)
      )
    )
  )
.DE
