magic/lisp/scm/prs.scm

1606 lines
40 KiB
Scheme

;-------------------------------------------------------------------------
;
; Drawing transistor stacks for production rules.
;
; (c) 1996 California Institute of Technology
; Department of Computer Science
; Pasadena, CA 91125.
;
; Permission to use, copy, modify, and distribute this software
; and its documentation for any purpose and without fee is hereby
; granted, provided that the above copyright notice appear in all
; copies. The California Institute of Technology makes no representations
; about the suitability of this software for any purpose. It is
; provided "as is" without express or implied warranty. Export of this
; software outside of the United States of America may require an
; export license.
;
; $Header$
;
;-------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
; Production rule parser
; ~~~~~~~~~~~~~~~~~~~~~~
;
; (prs.parse "production-rule-string")
;
; Returns a parse tree for the production rule, or prints out an error
; message.
;
; A production rule is of the form: expr -> rhs [+/-]
; The resulting parse tree has the following format:
;
; Top level: (expr "rhs")
; expr: (and expr expr)
; (or expr expr)
; (not id)
; id
;
; Observe that the production rules must be in negation-normal form.
;
;------------------------------------------------------------------------------
(define prs.parse ())
(letrec
(
(parse-string "") ; the current string being parsed
(parse-position 0) ; current position in the string
(parse-string-len 0) ; string length
(or-char (string-ref "|" 0)) ; constants
(and-char (string-ref "&" 0))
(not-char (string-ref "~" 0))
(plus-char (string-ref "+" 0))
(minus-char (string-ref "-" 0))
(lparens-char (string-ref "(" 0))
(rparens-char (string-ref ")" 0))
(startid? ; #t if the character is a valid
; start character for an identifier
(let ((lc-a (string-ref "a" 0))
(uc-a (string-ref "A" 0))
(lc-z (string-ref "z" 0))
(uc-z (string-ref "Z" 0))
(us (string-ref "_" 0))
)
(lambda (x)
(cond
((and (>=? x lc-a) (<=? x lc-z)) #t)
((and (>=? x uc-a) (<=? x uc-z)) #t)
((=? x us) #t)
(#t #f)
)
)
)
)
(idchar? ; #t if the character is a valid
; character in an identifier
(let ((lc-a (string-ref "a" 0))
(uc-a (string-ref "A" 0))
(lc-z (string-ref "z" 0))
(uc-z (string-ref "Z" 0))
(lbrack (string-ref "[" 0))
(rbrack (string-ref "]" 0))
(us (string-ref "_" 0))
(dot (string-ref "." 0))
(bang (string-ref "!" 0))
(zero (string-ref "0" 0))
(nine (string-ref "9" 0))
)
(lambda (x)
(cond
((and (>=? x lc-a) (<=? x lc-z)) #t)
((and (>=? x uc-a) (<=? x uc-z)) #t)
((and (>=? x zero) (<=? x nine)) #t)
((=? x us) #t)
((=? x bang) #t)
((=? x dot) #t)
((=? x lbrack) #t)
((=? x rbrack) #t)
(#t #f)
)
)
)
)
(prs.error ; Print an error message out to the
; screen, and abort evaluation
(lambda (str)
(begin
(echo
-n
(string-append
"Error"
(if (zero? parse-position)
","
(string-append
", parsed `"
(string-append (substring parse-string 0 parse-position) "',")
)
)
)
)
(echo -n "looking at: ")
(echo
(string-append
(string-append
"`"
(substring parse-string parse-position parse-string-len)
)
"'"
)
)
(error str)
)
)
)
(have? ; #t if the next character matches
; its argument exactly. If so, the
; position in the string is advanced
; and skip trailing whitespace.
(lambda (char)
(if (=? (string-ref parse-string parse-position) char)
(begin
(set! parse-position (+ parse-position 1))
#t
)
#f
)
)
)
(skipspace ; skip leading spaces
(lambda ()
(cond ((=? parse-position parse-string-len) #t)
((=? (string-ref parse-string parse-position)
(string-ref " " 0))
(begin
(set! parse-position (+ parse-position 1))
(skipspace)
)
)
(#t #t)
)
)
)
(skipchar ; Expect to see a specific character
; and skip it. Report an error if
; invalid character
(lambda (char)
(if (have? char) #t (prs.error (string-append
"Expected: "
(string-set! " " 0 char))
)
)
)
)
(skip ; Expect to see a string, and skip it
; Reports an error otherwise.
; len is the length of the string.
(lambda (str len)
(letrec
((len2 (+ len parse-position))
(helper
(lambda (pos1 pos2)
(cond
((=? pos1 len)
(begin
(set! parse-position pos2)
#t
))
((=? pos2 len2)
(prs.error (string-append "Expected: " str)))
((=? (string-ref parse-string pos2)
(string-ref str pos1))
(helper (+ pos1 1) (+ pos2 1))
)
(#t (prs.error (string-append "Expected: " str)))
)
)
)
)
(helper 0 parse-position)
)
)
)
(expr ; Parse an expression
(lambda ()
(begin
(define x (term))
(cond
((=? parse-position parse-string-len) x)
((have? or-char) (begin (skipspace) (list 'or x (expr))))
(#t x)
)
)
)
)
(term ; Parse a term
(lambda ()
(begin
(define x (factor))
(cond
((=? parse-position parse-string-len) x)
((have? and-char) (begin (skipspace) (list 'and x (term))))
(#t x)
)
)
)
)
(factor ; parse a factor
(lambda ()
(cond
((have? not-char) (begin (skipspace) (list 'not (variable))))
((have? lparens-char)
(begin
(skipspace)
(define x (expr))
(skipchar rparens-char)
(skipspace)
x
)
)
(#t (variable))
)
)
)
(variable ; parse a variable
(lambda ()
(letrec ((helper
(lambda (pos)
(cond
((=? parse-string-len pos) pos)
((idchar? (string-ref parse-string pos))
(helper (+ pos 1))
)
(#t pos)
)
)
))
(begin
(if (=? parse-string-len parse-position)
(prs.error "Expected an identifier")
#t)
(if (startid? (string-ref parse-string parse-position))
#t
(prs.error "Expected an identifier")
)
(define x (helper (+ parse-position 1)))
(define y (substring parse-string parse-position x))
(set! parse-position x)
(skipspace)
y
)
)
)
)
)
(set!
prs.parse
(lambda (str)
(begin
(set! parse-string str)
(set! parse-position 0)
(set! parse-string-len (string-length str))
(skipspace)
(define x (expr))
(skipspace)
(skip "->" 2)
(skipspace)
(define y (variable))
(collect-garbage)
(cond ((have? plus-char) (list x y))
((have? minus-char) (list x y))
(#t (prs.error "Expected a `+' or `-'"))
)
)
)
)
)
;------------------------------------------------------------------------------
;
; Drawing a production rule
; ~~~~~~~~~~~~~~~~~~~~~~~~~
;
; (prs.draw width "production-rule")
;
; Draws the transistor stacks for the specified production rules,
; with diffusion stacks "width" wide.
;
;
; (prs.mgn widthp widthn "prs1" "prs2" . . .)
;
; Draw transistor stacks for the production rules specified. The network
; is generated assuming that the rules for all the pull-up networks are
; pairwise mutually exclusive, and that the rules for all the pull-down
; networks are pairwise mutually exclusive. This permits a degree of
; gate-sharing. (Not currently implemented)
;
;------------------------------------------------------------------------------
;
; Network description:
;
; ("node" ("gate" ref-to-node)) ("gate" ref-to-node) . . .)
;
;
; A stack:
; ("node" "edge" "node" "edge" "node" "edge")
;
;
; Temporary description:
; ("node" ref-to-a-stack ref-to-e1 ref-to-e2 . . .)
;
; edge = (label ref-v1 ref-v2), or (label)
;
;
(define prs.net-add-edge ())
(define prs.net-find ())
(define prs.gen-stacks ())
(letrec
(
(stacks-so-far ()) ; stacks that have been generated
; by the algorithm so far
;------------------------------------------------------------------------
; Insert an empty list as the second element after the node for each
; node in the network. This is used for folding loops back into the main
; transistor stack chain, if possible.
;------------------------------------------------------------------------
(add-empty-path
(lambda (net)
(if (null? net) #t
(begin
(set-cdr! (car net) (cons () (cdar net)))
(add-empty-path (cdr net))
)
)
)
)
;------------------------------------------------------------------------
; Delete leading edges which have already been inspected by the stack
; generation algorithm. Inspected edges have their node references
; deleted, and so the list representing the edge has length 1.
;------------------------------------------------------------------------
(strip-used-edges
(lambda (noderef)
(cond
((null? (cddr noderef)) #t)
((=? (length (caddr noderef)) 1)
(begin (set-cdr! (cdr noderef) (cdddr noderef))
(strip-used-edges noderef)
)
)
(#t #t)
)
)
)
;------------------------------------------------------------------------
; Generate one stack, eliminating edges used from the graph. The stack
; begins from the node pointed to by network.
;------------------------------------------------------------------------
(generate-stack
(lambda (network)
(if (null? (cddr network)) (list network)
(cons network
(cons
(car (caddr network))
(begin
(define edge (caddr network))
(define n1 (cadr edge))
(define n2 (caddr edge))
(set-cdr! (caddr network) ())
(set-cdr! (cdr network) (cdddr network))
(strip-used-edges n1)
(strip-used-edges n2)
(generate-stack (if (eqv? n1 network) n2 n1))
)
)
)
)
)
)
;------------------------------------------------------------------------
; Returns the last-but-1 cons cell in a stack, setting a node to a loop
; node if it has been used in a previously defined stack.
;------------------------------------------------------------------------
(last-but-1-element
(lambda (stk)
(if (null? (cddr stk)) stk (last-but-1-element (cdr stk)))
)
)
;------------------------------------------------------------------------
; Generate all stacks. Iterate the stack generation phase until all edges
; have been inspected.
;------------------------------------------------------------------------
(all-stacks
(lambda (network)
(cond
((null? network) #t)
((null? (cddar network)) (all-stacks (cdr network)))
(#t
(begin
(define stk (generate-stack (car network)))
(set! stacks-so-far (cons stk stacks-so-far))
(all-stacks network)
)
)
)
)
)
;------------------------------------------------------------------------
; Last member of a list
;------------------------------------------------------------------------
(listlast
(lambda (l)
(if (null? (cdr l)) (car l) (listlast (cdr l)))
)
)
;------------------------------------------------------------------------
; Returns a list of all internal nodes in all stacks that need to be
; kept around. A node needs to be kept if there are two references to
; it.
;------------------------------------------------------------------------
(all-used-contacts
(lambda (stacks)
(if (null? stacks) ()
(append (loose-ends (car stacks)) (allends (cdr stacks)))
)
)
)
;------------------------------------------------------------------------
; Return #t if string val is a member of list l.
;------------------------------------------------------------------------
(ismember?
(lambda (val l)
(cond
((null? l) #f)
((string=? val (car l)) #t)
(#t (ismember? val (cdr l)))
)
)
)
;------------------------------------------------------------------------
; Strip internal nodes that are not from in list l from the transistor
; stack.
;------------------------------------------------------------------------
(stripothers-1
(lambda (stack)
(cond
((null? stack) ())
((list? (car stack))
(if (>? (cadar stack) 1)
(cons (car stack) (stripothers-1 (cdr stack)))
(stripothers-1 (cdr stack))
)
)
(#t (cons (car stack) (stripothers-1 (cdr stack))))
)
)
)
;------------------------------------------------------------------------
; Strip internal nodes that are not in list l from all the stacks.
;------------------------------------------------------------------------
(stripothers
(lambda (stacks)
(if (null? stacks) ()
(cons
(stripothers-1 (car stacks))
(stripothers (cdr stacks))
)
)
)
)
;------------------------------------------------------------------------
; #t if the character is a digit, #f otherwise.
;------------------------------------------------------------------------
(digitchar?
(let ((zero (string-ref "0" 0))
(nine (string-ref "9" 0))
)
(lambda (x)
(and (>=? x zero) (<=? x nine))
)
)
)
;------------------------------------------------------------------------
; Returns #t if the string represents an internal node
;------------------------------------------------------------------------
(internal-node?
(let ((x (string-ref "_" 0)))
(lambda (str)
(if (=? (string-ref str 0) x)
(if (>? (string-length str) 1)
(if (digitchar? (string-ref str 1))
#t
#f
)
#f
)
#f
)
)
)
)
;------------------------------------------------------------------------
; Initialize a node's usecount
;------------------------------------------------------------------------
(set-usecount-1
(lambda (stack)
(cond
((null? stack) #t)
((list? (car stack))
(begin
(set-car! (cdar stack)
(if (number? (cadar stack))
(+ 1 (cadar stack))
(if (internal-node? (caar stack)) 1 2)
)
)
(set-usecount-1 (cdr stack))
)
)
(#t (set-usecount-1 (cdr stack)))
)
)
)
(set-usecount
(lambda (stacks)
(cond
((null? stacks) #t)
((null? (car stacks)) (set-usecount (cdr stacks)))
(#t (begin (set-usecount-1 (car stacks))
(set-usecount (cdr stacks)))
)
)
)
)
;------------------------------------------------------------------------
; Eliminate all internal nodes that are not required to construct the
; transistor stacks.
;------------------------------------------------------------------------
(strip-dummy-contacts
(lambda ()
(begin
(set-usecount stacks-so-far)
(set! stacks-so-far (stripothers stacks-so-far))
)
)
)
;------------------------------------------------------------------------
; Returns #t if the stack is a loop stack.
;------------------------------------------------------------------------
(isloop?
(lambda (stack)
(eqv? (car stack) (cadr (last-but-1-element stack)))
)
)
;------------------------------------------------------------------------
; Separate loop and non-loop stacks.
;------------------------------------------------------------------------
(split-stacks
(lambda (stacks)
(if (null? stacks) (list () () )
(let ((x (split-stacks (cdr stacks))))
(if (isloop? (car stacks))
(cons (cons (car stacks) (car x)) (cdr x))
(cons (car x) (list (cons (car stacks) (cadr x))))
)
)
)
)
)
;------------------------------------------------------------------------
; Add a path to an existing stack
;------------------------------------------------------------------------
(addpath
(lambda (head stk)
(if (null? stk) #t
(begin
(if (list? (car stk))
(if (null? (cadar stk))
(set-car! (cdar stk) (list stk head))
#t
)
#t
)
(addpath head (cdr stk))
)
)
)
)
;------------------------------------------------------------------------
; See if there is a node on this path which belongs to an existing
; loop path
;------------------------------------------------------------------------
(check-path
(lambda (stack)
(cond
((null? stack) ())
((list? (car stack))
(if (null? (cadar stack)) (check-path (cdr stack)) stack)
)
(#t (check-path (cdr stack)))
)
)
)
;------------------------------------------------------------------------
; Merge loop stacks
;------------------------------------------------------------------------
(merge-loops
(lambda (stacks)
(if (null? stacks) #t
(begin
(define lb1 (last-but-1-element (car stacks)))
(define cur (check-path (car stacks)))
(addpath stacks (car stacks))
(if (null? cur) (merge-loops (cdr stacks))
(begin
(define cell (caadar cur))
(define oldcdr (cdr cell))
(define head (car stacks))
(set-cdr! cell (cdr cur))
(set-cdr! lb1 head)
(set-cdr! cur oldcdr)
(set-car! stacks ())
(merge-loops (cdr stacks))
)
)
)
)
)
)
;------------------------------------------------------------------------
; Fix non-loops.
;------------------------------------------------------------------------
(merge-nonloops
(lambda (stacks)
(if (null? stacks) #t
(begin
(define cur (check-path (car stacks)))
(if (null? cur) (merge-nonloops (cdr stacks))
(begin
(define cell (caadar cur))
(define oldcdr (cdr cur))
(define head (car (cdadar cur)))
(if (zero? (length (car head)))
#t
(begin
(define lb1 (last-but-1-element (car head)))
(set-cdr! cur (cdr cell))
(set-cdr! lb1 (car head))
(set-cdr! cell oldcdr)
(set-car! head ())
)
)
(merge-nonloops (cdr stacks))
)
)
)
)
)
)
;------------------------------------------------------------------------
; Match first/last with first/last
;------------------------------------------------------------------------
(find-stack-match-1
(lambda (first last stack)
(let ((x (car (reverse stack)))
(y (car stack)))
(cond
((eqv? first y) 1)
((eqv? first x) 2)
((eqv? last y) 3)
((eqv? last x) 4)
(#t ())
)
)
)
)
(find-stack-match
(lambda (first last stacks)
(cond ((null? stacks) ())
((null? (car stacks)) (find-stack-match first last (cdr stacks)))
(#t (let ((x (find-stack-match-1 first last (car stacks))))
(if (null? x)
(find-stack-match first last (cdr stacks))
(list x stacks)
)
)
)
)
)
)
;------------------------------------------------------------------------
; Fix straight lines that might now be linked because of the merge
; loops with non-loops phase.
;------------------------------------------------------------------------
(fix-non-loops
(lambda (stacks)
(if (null? stacks) #t
(if (null? (car stacks)) (fix-non-loops (cdr stacks))
(begin
(define stk (find-stack-match
(caar stacks)
(car (reverse (car stacks)))
(cdr stacks)
)
)
(if (null? stk) #t
(begin
(define stks-new (cadr stk))
(cond
((=? (car stk) 1)
(begin
(define x (reverse (car stacks)))
(define y (last-but-1-element x))
(set-cdr! y (car stks-new))
(set-car! stks-new x)
)
)
((=? (car stk) 2)
(begin
(define x (car stks-new))
(define y (last-but-1-element x))
(set-cdr! y (car stacks))
)
)
((=? (car stk) 3)
(begin
(define x (car stacks))
(define y (last-but-1-element x))
(set-cdr! y (car stks-new))
(set-car! stks-new x)
)
)
(#t
(begin
(define x (reverse (car stacks)))
(define y (last-but-1-element (car stks-new)))
(set-cdr! y (car x))
)
)
)
(set-car! stacks ())
)
)
(fix-non-loops (cdr stacks))
)
)
)
)
)
;------------------------------------------------------------------------
; Fix loops. Fold any loops into existing stacks, if possible.
;------------------------------------------------------------------------
(fix-loops
(lambda ()
(begin
(define both (split-stacks stacks-so-far))
(define loop (car both))
(define non-loop (cadr both))
(merge-loops loop)
(merge-nonloops non-loop)
(set! stacks-so-far (append loop non-loop))
(fix-non-loops stacks-so-far)
)
)
)
;------------------------------------------------------------------------
; Convert network node references into node names in a transistor stack.
; Given a node reference in a stack (in which case it would be a contact,
; which is represented by a ("name")---see stack.scm), the name is the
; first member of the node list.
;------------------------------------------------------------------------
(refs-to-names
(lambda (stk)
(if (null? stk) ()
(let ((x (if (list? (car stk)) (list (caar stk)) (car stk))))
(cons x (refs-to-names (cdr stk))))
)
)
)
;------------------------------------------------------------------------
; Convert all network node references into node names.
;------------------------------------------------------------------------
(cleanup-stacks
(lambda (stacks)
(cond
((null? stacks) ())
((null? (car stacks)) (cleanup-stacks (cdr stacks)))
(#t (cons (refs-to-names (car stacks)) (cleanup-stacks (cdr stacks))))
)
)
)
;------------------------------------------------------------------------
; A contact is global if it ends in a !
;------------------------------------------------------------------------
(global-node?
(let ((bang (string-ref "!" 0)))
(lambda (str)
(=? bang (string-ref str (- (string-length str) 1)))
)
)
)
;------------------------------------------------------------------------
; Locate a global variable contact if possible
;------------------------------------------------------------------------
(locate-global-contact
(lambda (stack)
(if (null? stack) ()
(if (list? (car stack))
(if (global-node? (caar stack)) stack
(locate-global-contact (cdr stack))
)
(locate-global-contact (cdr stack))
)
)
)
)
;------------------------------------------------------------------------
; Locate any contact
;------------------------------------------------------------------------
(locate-any-contact
(lambda (stack)
(if (null? stack) ()
(if (list? (car stack))
(if (internal-node? (caar stack))
(locate-any-contact (cdr stack))
stack
)
(locate-any-contact (cdr stack))
)
)
)
)
;------------------------------------------------------------------------
; Locate a contact that is not an internal node
;------------------------------------------------------------------------
(user-contact
(lambda (stack)
(begin
(define x (locate-global-contact stack))
(if (null? x) (locate-any-contact stack) x)
)
)
)
;------------------------------------------------------------------------
; Rotate a single stack if possible so that the end-point is not an
; internal node
;------------------------------------------------------------------------
(loop-unravel
(lambda (stack)
(begin
(define x (user-contact stack))
(if (null? x) stack
(begin
(define hd (list (car x)))
(define y (last-but-1-element stack))
(set-cdr! hd (cdr x))
(set-cdr! x ())
(set-cdr! y stack)
hd
)
)
)
)
)
;------------------------------------------------------------------------
; If one of the final stacks is a loop stack, then you should try to make
; sure that the end-points are not internal nodes, and are preferably
; global nodes.
;------------------------------------------------------------------------
(rotate-loops
(lambda (stacks)
(if (null? stacks) #t
(cond
((null? (car stacks)) (rotate-loops (cdr stacks)))
((isloop? (car stacks))
(begin
(cond
((internal-node? (caaar stacks))
(set-car! stacks (loop-unravel (car stacks)))
)
((not (global-node? (caaar stacks)))
(set-car! stacks (loop-unravel (car stacks)))
)
(#t #t)
)
(rotate-loops (cdr stacks))
)
)
(#t (rotate-loops (cdr stacks)))
)
)
)
)
)
(begin
;------------------------------------------------------------------------
; Exported function: generate transistor stacks from a network
; description.
;------------------------------------------------------------------------
(set!
prs.gen-stacks
(lambda (network)
(begin
(set! stacks-so-far ()) ; clear stacks
(add-empty-path network) ; add empty path
(all-stacks network) ; generate all stacks
(fix-loops) ; associate nodes with stacks
(rotate-loops stacks-so-far) ; rotate loops if possible so that
; the stack ends are existing nodes
(strip-dummy-contacts) ; eliminate dummy nodes
(set! stacks-so-far (cleanup-stacks stacks-so-far))
stacks-so-far ; return
)
)
)
;------------------------------------------------------------------------
; find a node in a network.
;------------------------------------------------------------------------
(set!
prs.net-find
(lambda (net node)
(cond
((null? net) ())
((string=? (caar net) node) (car net))
(#t (prs.net-find (cdr net) node))
)
)
)
;------------------------------------------------------------------------
; Add an edge to a network. Use this function to construct the network
; graph.
;------------------------------------------------------------------------
(set!
prs.net-add-edge
(lambda (network n1 g n2)
(begin
(define ref-n1 (prs.net-find network n1)) ; find node 1
(define ref-n2 (prs.net-find network n2)) ; find node 2
(define edge (list g ref-n1 ref-n2)) ; create edge
(set-cdr! ref-n1 (cons edge (cdr ref-n1))) ; add edge to node 1
(set-cdr! ref-n2 (cons edge (cdr ref-n2))) ; add edge to node 2
)
)
)
)
)
;------------------------------------------------------------------------
(define prs.mgn ())
(define prs.mgn-node ())
(define prs.mgn-internal-node ())
(define prs.mgn-init-p-net ())
(define prs.mgn-init-n-net ())
(define prs.mgn-edge ())
(define prs.mgn-draw-p ())
(define prs.mgn-draw-n ())
(define prs.mgn-draw-tallp ())
(define prs.mgn-draw-talln ())
(define prs.draw ())
(define prs.tallmgn ())
(define prs.talldraw ())
(define prs.draw-net ())
(letrec
(
(gate.network ())
(nodenumber 0)
;------------------------------------------------------------------------
; Generates a fresh internal node name
;------------------------------------------------------------------------
(fresh-internal-node!
(lambda ()
(begin
(define nn
(string-append (string-append "_" (number->string nodenumber)) "#")
)
(set! nodenumber (+ 1 nodenumber))
nn
)
)
)
;------------------------------------------------------------------------
; Checks if "char" is the last non-whitespace character in "str"
;------------------------------------------------------------------------
(ischarend?
(lambda (str char)
(letrec ((len (string-length str))
(space (string-ref " " 0))
(helper
(lambda (pos)
(cond
((zero? pos) #f)
((=? char (string-ref str pos)) #t)
((=? space (string-ref str pos)) (helper (- pos 1)))
(#t #f)
)
)
))
(helper (- len 1))
)
)
)
;------------------------------------------------------------------------
; Extracts production rules ending with the character specified by the
; first character in string "last". The production rules are specified
; by a list of strings.
;------------------------------------------------------------------------
(getprs
(lambda (rule-list last)
(cond ((null? rule-list) ())
((ischarend? (car rule-list) (string-ref last 0))
(cons (car rule-list) (getprs (cdr rule-list) last)))
(#t (getprs (cdr rule-list) last))
)
)
)
;------------------------------------------------------------------------
;
; Simple transistor network generation
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;
; Direct generation of a simple network for a production rule is done by
; the intuitive rules for drawing transistors for a pull-up/pull-down:
;
; Given two gate networks *-n1-* and *-n2-*, their and-combination is
; given by *-n1-+-n2-*, and their or-combination is given by
; *-n1-*
; `-n2-'
; In the first case, we need to generate a name for the intermediate
; node name in the network graph.
;
; A partial network *-n-* is represented by a list of potential edges.
; An edge (transistor) is a list (x "label" y), where x and y represent
; the end-points. If an end-point is not connected, it is a number (0).
; Connected end-points are strings.
;
; The or-combination of two networks is simply the union of the two
; networks, and the and-combination is generated by generating a new
; name for the intermediate node, connecting all right end-points of
; network n1 to that node, and connecting all left end-points of network
; n2 to the same node. The final network is the union of the two networks.
;
; The left and right end-points for the entire network corresponding to
; a pull-up/pull-down are connected to the power supply and output
; respectively.
;
;------------------------------------------------------------------------
;------------------------------------------------------------------------
; Connect the right hanging nodes to str deleting any edges that were
; generated as a result, and return the new edge list.
;------------------------------------------------------------------------
(fillright
(lambda (l str)
(cond
((null? l) ())
((number? (caddar l))
(begin
(set-car! (cddar l) str)
(if (number? (caar l))
(cons (car l) (fillright (cdr l) str))
(begin
(prs.net-add-edge gate.network (caar l) (cadar l) (caddar l))
(fillright (cdr l) str)
)
)
)
)
(#t (cons (car l) (fillright (cdr l) str)))
)
)
)
;------------------------------------------------------------------------
; Connect the left hanging edges to node str deleting any edges that
; were generated as a result, and return the new edge list.
;------------------------------------------------------------------------
(fillleft
(lambda (l str)
(cond
((null? l) ())
((number? (caar l))
(begin
(set-car! (car l) str)
(if (number? (caddar l))
(cons (car l) (fillleft (cdr l) str))
(begin
(prs.net-add-edge gate.network (caar l) (cadar l) (caddar l))
(fillleft (cdr l) str)
)
)
))
(#t (cons (car l) (fillleft (cdr l) str)))
)
)
)
;------------------------------------------------------------------------
; Generate the network for a boolean expression. "tree" is the parse tree
; for the expression, and "type" is zero for a pull-down chain and one
; for a pull-up chain.
;------------------------------------------------------------------------
(gen-1-network
(lambda (tree type)
(cond
((string? tree)
(if (zero? type)
(list (list 0 tree 0))
(error "A pull-up must use inverted variables only")
)
)
((eqv? 'not (car tree))
(if (zero? type)
(error "A pull-down must use uninverted variables only")
(list (list 0 (cadr tree) 0))
)
)
(#t
(begin
(define l (gen-1-network (cadr tree) type))
(define r (gen-1-network (caddr tree) type))
(if (eqv? 'and (car tree))
(begin
(define nn (fresh-internal-node!))
(set! gate.network (cons (list nn) gate.network))
(set! l (fillright l nn))
(set! r (fillleft r nn))
)
#t
)
(append l r)
)
)
(#t (error "This should not happen!"))
)
)
)
;------------------------------------------------------------------------
; Generate network corresponding to a production rule.
;------------------------------------------------------------------------
(gen-one-network
(lambda (rule type)
(begin
(define prs (prs.parse rule))
(define l (gen-1-network (car prs) type))
(if (null? (prs.net-find gate.network (cadr prs)))
(set! gate.network (cons (list (cadr prs)) gate.network))
#t
)
(fillleft l (if (zero? type) "GND!" "Vdd!"))
(fillright l (cadr prs))
)
)
)
;------------------------------------------------------------------------
; Generate a network corresponding to all the rules. The rules must all be
; either describing pull-ups or pull-downs.
;------------------------------------------------------------------------
(gen-network
(lambda (rules type)
(if (null? rules) #t
(begin
(gen-one-network (car rules) type)
(gen-network (cdr rules) type)
)
)
)
)
;------------------------------------------------------------------------
; Draw all the stacks in "stacks" with width "width" using function
; "draw", spaced horizontally by "spacing".
;------------------------------------------------------------------------
(drawstacks
(lambda (draw width stacks spacing)
(if (null? stacks)
(begin
(box.move (uminus spacing) 0)
()
)
(begin
(define ret-box (draw width (car stacks)))
(box.move spacing 0)
(define ret2-box (drawstacks draw width (cdr stacks) spacing))
(if (null? ret2-box)
ret-box
(list (min (car ret-box) (car ret2-box))
(min (cadr ret-box) (cadr ret2-box))
(max (caddr ret-box) (caddr ret2-box))
(max (cadddr ret-box) (cadddr ret2-box))
)
)
)
)
)
)
;------------------------------------------------------------------------
; Create and draw all the stacks for a set of rules.
;------------------------------------------------------------------------
(genstacks
(lambda (draw width rules type supply)
(begin
(echo -n "Generating network...")
(set! gate.network (list (list supply)))
(gen-network rules type)
(echo -n "generating stacks...")
(define stacks (prs.gen-stacks gate.network))
(echo "done.")
(drawstacks draw width stacks
(+ width
(max
(drc.min-spacing
(if (zero? type) "ndiff-ndiff" "pdiff-pdiff"))
(+ (drc.min-spacing "poly")
(* 2 (drc.min-overhang "gate-poly"))
)
)
)
)
)
)
)
)
(begin
(set!
prs.mgn-internal-node
(lambda ()
(begin
(define nn (fresh-internal-node!))
(set! gate.network (cons (list nn) gate.network))
nn
)
)
)
(set!
prs.mgn-node
(lambda (name)
(begin
(if (string? name) #t
(error "Usage: prs.mgn-node \"name\"")
)
(set! gate.network (cons (list name) gate.network))
name
)
)
)
(set!
prs.mgn-init-p-net
(lambda ()
(set! gate.network (list (list "Vdd!")))
)
)
(set!
prs.mgn-init-n-net
(lambda ()
(set! gate.network (list (list "GND!")))
)
)
(set!
prs.mgn-edge
(lambda (n1 lab n2)
(if (string-list? (list n1 lab n2))
(prs.net-add-edge gate.network n1 lab n2)
(error "Usage: prs.mgn-edge node1 \"gate\" node2")
)
)
)
(set!
prs.mgn-draw-p
(lambda (width)
(begin
(if (number? width)
#t
(error "Usage: prs.mgn-draw-p <width>")
)
(box.push (getbox))
(echo -n "generating stacks...")
(define stacks (prs.gen-stacks gate.network))
(echo "done.")
(define d
(drawstacks stack.p width stacks
(+ width
(max
(drc.min-spacing "pdiff-pdiff")
(+ (drc.min-spacing "poly")
(* 2 (drc.min-overhang "gate-poly"))
)
)
)
))
(box.pop)
(collect-garbage)
d
)
)
)
(set!
prs.mgn-draw-n
(lambda (width)
(begin
(if (number? width) #t
(error "Usage: prs.mgn-draw-n <width>")
)
(box.push (getbox))
(echo -n "generating stacks...")
(define stacks (prs.gen-stacks gate.network))
(echo "done.")
(define d
(drawstacks stack.n width stacks
(+ width
(max
(drc.min-spacing "ndiff-ndiff")
(+ (drc.min-spacing "poly")
(* 2 (drc.min-overhang "gate-poly"))
)
)
)
))
(box.pop)
(collect-garbage)
d
)
)
)
(set!
prs.mgn-draw-tallp
(lambda (width)
(begin
(if (number? width) #t
(error "Usage: prs.mgn-draw-tallp <width>")
)
(box.push (getbox))
(echo -n "generating stacks...")
(define stacks (prs.gen-stacks gate.network))
(echo "done.")
(define d
(drawstacks stack.tallp width stacks
(+ width
(max
(drc.min-spacing "pdiff-pdiff")
(+ (drc.min-spacing "poly")
(* 2 (drc.min-overhang "gate-poly"))
)
)
)
))
(box.pop)
(collect-garbage)
d
)
)
)
(set!
prs.mgn-draw-talln
(lambda (width)
(begin
(if (number? width) #t
(error "Usage: prs.mgn-draw-talln <width>")
)
(box.push (getbox))
(echo -n "generating stacks...")
(define stacks (prs.gen-stacks gate.network))
(echo "done.")
(define d
(drawstacks stack.talln width stacks
(+ width
(max
(drc.min-spacing "ndiff-ndiff")
(+ (drc.min-spacing "poly")
(* 2 (drc.min-overhang "gate-poly"))
)
)
)
))
(box.pop)
(collect-garbage)
d
)
)
)
(set!
prs.mgn
(eval (list
'lambda
(cons 'widthp (cons 'widthn 'rule-list))
'(let* ((p-rules (getprs rule-list "+"))
(n-rules (getprs rule-list "-"))
)
(begin
(if (and (and (number? widthp) (number? widthn))
(string-list? rule-list))
#t
(error "Usage: prs.mgn <p-width> <n-width> \"prs1\" ...")
)
(box.push (getbox))
(define r1
(genstacks stack.p widthp p-rules 1 "Vdd!")
)
(box.move (+ widthp (drc.min-spacing "pdiff-ndiff")) 0)
(define r2
(genstacks stack.n widthn n-rules 0 "GND!")
)
(box.pop)
(collect-garbage)
(list r1 r2)
)
)
)
)
)
(set!
prs.draw
(lambda (width rule)
(let
((x (list rule)))
(begin
(if (and (number? width) (string? rule)) #t
(error "Usage: prs.draw <width> \"prs\"")
)
(if (ischarend? rule (string-ref "+" 0))
(genstacks stack.p width x 1 "Vdd!")
(genstacks stack.n width x 0 "GND!")
)
)
)
)
)
(set!
prs.draw-net
(lambda (rule)
(begin
(if (string? rule) #t
(error "Usage: prs.draw-net \"prs\"")
)
(if (ischarend? rule (string-ref "+" 0))
(gen-one-network rule 1)
(gen-one-network rule 0)
)
)
)
)
(set!
prs.tallmgn
(eval (list
'lambda
(cons 'widthp (cons 'widthn 'rule-list))
'(let* ((p-rules (getprs rule-list "+"))
(n-rules (getprs rule-list "-"))
)
(begin
(if (and (and (number? widthp) (number? widthn))
(string-list? rule-list))
#t
(error "Usage: prs.tallmgn <p-width> <n-width> \"prs1\" ...")
)
(box.push (getbox))
(define r1
(genstacks stack.tallp widthp p-rules 1 "Vdd!")
)
(box.move (+ widthp (drc.min-spacing "pdiff-ndiff")) 0)
(define r2
(genstacks stack.talln widthn n-rules 0 "GND!")
)
(box.pop)
(collect-garbage)
(list r1 r2)
)
)
)
)
)
(set!
prs.talldraw
(lambda (width rule)
(let
((x (list rule)))
(begin
(if (and (number? width) (string? rule)) #t
(error "Usage: prs.talldraw <width> \"prs\"")
)
(if (ischarend? rule (string-ref "+" 0))
(genstacks stack.tallp width x 1 "Vdd!")
(genstacks stack.talln width x 0 "GND!")
)
)
)
)
)
)
)
(define prs.mgn-fresh-node
(let ((x 0))
(lambda ()
(begin
(define name (string-append
(string-append "_i" (number->string x))
"#"
)
)
(set! x (+ x 1))
(prs.mgn-node name)
)
)
)
)
(define prs.mgn-output-edge
(lambda (a b c)
(prs.mgn-edge a b c)
)
)