Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #lang racket
- (require racket/mpair)
- ;; CONSTANTS
- (define inverter-delay 2)
- (define and-gate-delay 3)
- (define or-gate-delay 5)
- ;; LOGIC FUNCTIONS
- (define (valid-signal? s) (member s '(0 1)))
- (define (logical-not s)
- (unless (valid-signal? s) (error "Invalid signal" s))
- (if (zero? s) 1 0))
- (define (logical-and s1 s2)
- (unless (valid-signal? s1) (error "Invalid signal" s1))
- (unless (valid-signal? s2) (error "Invalid signal" s2))
- (* s1 s2))
- (define (logical-or s1 s2)
- (unless (valid-signal? s1) (error "Invalid signal" s1))
- (unless (valid-signal? s2) (error "Invalid signal" s2))
- (if (positive? (+ s1 s2)) 1 0))
- ;; LOGIC GATES
- (define (inverter input output)
- (define (invert-input)
- (define new-value (logical-not (get-signal input)))
- (after-delay inverter-delay
- (lambda ()
- (set-signal! output new-value))))
- (add-action! input invert-input)
- 'ok)
- (define (and-gate a1 a2 output)
- (define (and-action-procedure)
- (define new-value (logical-and (get-signal a1) (get-signal a2)))
- (after-delay and-gate-delay
- (lambda ()
- (set-signal! output new-value))))
- (add-action! a1 and-action-procedure)
- (add-action! a2 and-action-procedure)
- 'ok)
- (define (or-gate a1 a2 output)
- (define (or-action-procedure)
- (define new-value (logical-or (get-signal a1) (get-signal a2)))
- (after-delay or-gate-delay
- (lambda ()
- (set-signal! output new-value))))
- (add-action! a1 or-action-procedure)
- (add-action! a2 or-action-procedure)
- 'ok)
- ;; ADDERS
- (define (half-adder a b s c)
- (define d (make-wire))
- (define e (make-wire))
- (or-gate a b d)
- (and-gate a b c)
- (inverter c e)
- (and-gate d e s)
- 'ok)
- (define (full-adder a b c-in sum c-out)
- (define s (make-wire))
- (define c1 (make-wire))
- (define c2 (make-wire))
- (half-adder b c-in s c1)
- (half-adder a s sum c2)
- (or-gate c2 c2 c-out)
- 'ok)
- (define (ripple-carry-adder as bs ss c)
- ; The book goes from index n to index 1; we go from n - 1 to 0.
- (unless (= (length as)
- (length bs)
- (length ss))
- (error "Lists must be same length -- RIPPLE-CARRY-ADDER" as bs ss))
- (define zero-wire (make-wire))
- (set-signal! zero-wire 0)
- (define (loop i carry)
- (cond [(< i 0) 'ok]
- [else
- ; use c for the last carry
- (define next-carry (if (zero? i) c (make-wire)))
- (full-adder (list-ref as i)
- (list-ref bs i)
- carry
- (list-ref ss i)
- next-carry)
- (loop (sub1 i) next-carry)]))
- (loop (sub1 (length as))
- zero-wire))
- ;; WIRES
- (define (make-wire)
- (define signal-value 0)
- (define action-procedures empty)
- (define (set-my-signal! new-value)
- (cond [(not (= signal-value new-value))
- (set! signal-value new-value)
- (call-each action-procedures)]
- [else 'done]))
- (define (accept-action-procedure! proc)
- (set! action-procedures (mcons proc action-procedures))
- (proc))
- (define (dispatch m)
- (cond [(eq? m 'get-signal) signal-value]
- [(eq? m 'set-signal!) set-my-signal!]
- [(eq? m 'add-action!) accept-action-procedure!]
- [else (error "Unknown operation -- WIRE" m)]))
- dispatch)
- (define (call-each procedures)
- (for ([p procedures]) (p))
- 'done)
- (define (get-signal wire)
- (wire 'get-signal))
- (define (set-signal! wire new-value)
- ((wire 'set-signal!) new-value))
- (define (add-action! wire action-procedure)
- ((wire 'add-action!) action-procedure))
- ;; QUEUES FROM 3.3.2
- (define (front-ptr queue) (mcar queue))
- (define (rear-ptr queue) (mcdr queue))
- (define (set-front-ptr! queue item) (set-mcar! queue item))
- (define (set-rear-ptr! queue item) (set-mcdr! queue item))
- (define (empty-queue? queue) (null? (front-ptr queue)))
- (define (make-queue) (mcons empty empty))
- (define (front-queue queue)
- (if (empty-queue? queue)
- (error "FRONT called with an empty queue" queue)
- (mcar (front-ptr queue))))
- (define (insert-queue! queue item)
- (define new-pair (mcons item empty))
- (cond [(empty-queue? queue)
- (set-front-ptr! queue new-pair)
- (set-rear-ptr! queue new-pair)
- queue]
- [else
- (set-mcdr! (rear-ptr queue) new-pair)
- (set-rear-ptr! queue new-pair)
- queue]))
- (define (delete-queue! queue)
- (cond [(empty-queue? queue)
- (error "DELETE! called with an empty queue" queue)]
- [else
- (set-front-ptr! queue (mcdr (front-ptr queue)))
- queue]))
- ;; AGENDAS
- ;; Segments are time, queue pairs. The queue holds all the actions to be
- ;; performed at that time.
- (define (make-time-segment time queue)
- (mcons time queue))
- (define (segment-time s) (mcar s))
- (define (segment-queue s) (mcdr s))
- ;; An agenda is a table of segments sorted by time. The head of the table is the
- ;; current time.
- (define (make-agenda) (mlist 0))
- (define (current-time agenda) (mcar agenda))
- (define (set-current-time! agenda time) (set-mcar! agenda time))
- (define (segments agenda) (mcdr agenda))
- (define (set-segments! agenda segments) (set-mcdr! agenda segments))
- (define (first-segment agenda) (mcar (segments agenda)))
- (define (rest-segments agenda) (mcdr (segments agenda)))
- (define (empty-agenda? agenda) (empty? (segments agenda)))
- (define (add-to-agenda! time action agenda)
- (define (belongs-before? segments)
- (or (empty? segments)
- (< time (segment-time (mcar segments)))))
- (define (make-new-time-segment time action)
- (define q (make-queue))
- (insert-queue! q action)
- (make-time-segment time q))
- (define (add-to-segments! segments)
- (cond [(= (segment-time (mcar segments)) time)
- (insert-queue! (segment-queue (mcar segments))
- action)]
- [else
- (define rest-sgmnts (mcdr segments))
- (if (belongs-before? rest-sgmnts)
- (set-mcdr! segments
- (mcons (make-new-time-segment time action)
- (mcdr segments)))
- (add-to-segments! rest-sgmnts))]))
- (define sgmnts (segments agenda))
- (if (belongs-before? sgmnts)
- (set-segments! agenda
- (mcons (make-new-time-segment time action)
- sgmnts))
- (add-to-segments! sgmnts)))
- (define (remove-first-agenda-item! agenda)
- (define q (segment-queue (first-segment agenda)))
- (delete-queue! q)
- (when (empty-queue? q)
- (set-segments! agenda (rest-segments agenda))))
- (define (first-agenda-item agenda)
- (cond [(empty-agenda? agenda)
- (error "Agenda is empty -- FIRST-AGENDA-ITEM")]
- [else
- (define first-seg (first-segment agenda))
- (set-current-time! agenda (segment-time first-seg))
- (front-queue (segment-queue first-seg))]))
- ;; after-delay, propagate and probe
- (define (after-delay delay action)
- (add-to-agenda! (+ delay (current-time the-agenda))
- action
- the-agenda))
- (define (propagate)
- (cond [(empty-agenda? the-agenda)
- 'done]
- [else
- (define first-item (first-agenda-item the-agenda))
- (first-item)
- (remove-first-agenda-item! the-agenda)
- (propagate)]))
- (define (probe name wire)
- (add-action! wire
- (lambda ()
- (printf "~a ~a New-value = ~a ~n"
- name
- (current-time the-agenda)
- (get-signal wire)))))
- ;; TEST
- ;; Use ripple-carry-adder to add 111 to 001 to get 1000.
- (define the-agenda (make-agenda))
- (define a1 (make-wire))
- (define a2 (make-wire))
- (define a3 (make-wire))
- (set-signal! a1 1)
- ;; 'done
- (set-signal! a2 1)
- ;; 'done
- (set-signal! a3 1)
- ;; 'done
- (define as (list a1 a2 a3))
- (define b1 (make-wire))
- (define b2 (make-wire))
- (define b3 (make-wire))
- (set-signal! b1 0)
- ;; 'done
- (set-signal! b2 0)
- ;; 'done
- (set-signal! b3 1)
- ;; 'done
- (define bs (list b1 b2 b3))
- (define s1 (make-wire))
- (define s2 (make-wire))
- (define s3 (make-wire))
- (set-signal! s1 0)
- ;; 'done
- (set-signal! s2 0)
- ;; 'done
- (set-signal! s3 0)
- ;; 'done
- (define ss (list s1 s2 s3))
- (define c (make-wire))
- (probe 's1 s1)
- ;; s1 0 New-value = 0
- (probe 's2 s2)
- ;; s2 0 New-value = 0
- (probe 's3 s3)
- ;; s3 0 New-value = 0
- (probe 'c c)
- ;; c 0 New-value = 0
- (ripple-carry-adder as bs ss c)
- ;; 'ok
- ;; Note that all the s wires and the c wire now have probe in their
- ;; action-procedures lists. So probe will run any time one of them changes state.
- (propagate)
- ;; s3 8 New-value = 1
- ;; s2 8 New-value = 1
- ;; s1 8 New-value = 1
- ;; s3 16 New-value = 0
- ;; s2 32 New-value = 0
- ;; c 48 New-value = 1
- ;; s1 48 New-value = 0
- ;; 'done
- (probe 's1 s1)
- ;; s1 48 New-value = 0
- (probe 's2 s2)
- ;; s2 48 New-value = 0
- (probe 's3 s3)
- ;; s3 48 New-value = 0
- (probe 'c c)
- ;; c 48 New-value = 1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement