;;;;circuits.lisp
;;;
;;;An object-oriented simulation of a number
;;;of digital circuit board elements.
;;;
;;;Author: Zach Tomaszewski
;;;Date: 06 Nov 2002
;;;
;;;CLASSES
;;The superclass of all circuit elements.
;;Includes name, value, and outputs
;;
(defclass circuit-element ()
((name :accessor name
:initarg :name
:type symbol
:documentation "The name/id of this element.")
(value :accessor value
:initarg :value
:type boolean
:initform ()
:documentation "The true/false (on/off) value of this gate.")
(outputs :accessor outputs
:initarg :outputs
:type list ;a list of circuit-elements
:initform ()
:documentation "The elements that this object is connected
and outputting to.")
)
)
;;Simulates a connecting wire,
;;particularly those entering the system
;;
(defclass hard-wire (circuit-element)
((class-name :allocation :class
:reader class-name
:initform 'hard-wire
:type symbol
:documentation "The class of this circuit-element")
)
)
;;The superclass for all unary and binary gates
;;Adds an inputs slot
;;
(defclass gate (circuit-element)
((inputs :accessor inputs
:initarg :inputs
:initform ()
:type list ;;list of circuit-elements
:documentation "The list of elements feeding their output
into this gate.")
)
)
;;The class of those gates with only one input and one output
;; such as buffer-gates and not-gates
;;
(defclass unary-gate (gate)
()
)
;;Merely holds/passes on whatever value it is given
;;
(defclass buffer-gate (unary-gate)
(
(class-name :allocation :class
:reader class-name
:initform 'buffer
:type symbol
:documentation "The class of this circuit-element")
)
)
;;Inverts whatever value it is given
;;
(defclass not-gate (unary-gate)
((class-name :allocation :class
:reader class-name
:initform 'not
:type symbol
:documentation "The class of this circuit-element")
)
)
;;Super class those gates with two inputs and one outputs,
;; such as AND, NAND, OR, NOR, and XOR
;;
(defclass binary-gate (gate)
()
)
;;AND gate
;;
(defclass and-gate (binary-gate)
((class-name :allocation :class
:reader class-name
:initform 'AND
:type symbol
:documentation "The class of this circuit-element")
)
)
;;OR gate
;;
(defclass or-gate (binary-gate)
((class-name :allocation :class
:reader class-name
:initform 'OR
:type symbol
:documentation "The class of this circuit-element")
)
)
;;XOR gate
;;
(defclass xor-gate (binary-gate)
((class-name :allocation :class
:reader class-name
:initform 'XOR
:type symbol
:documentation "The class of this circuit-element")
)
)
;;NAND gate
;;
(defclass nand-gate (binary-gate)
((class-name :allocation :class
:reader class-name
:initform 'NAND
:type symbol
:documentation "The class of this circuit-element")
)
)
;;NOR gate
;;
(defclass nor-gate (binary-gate)
((class-name :allocation :class
:reader class-name
:initform 'NOR
:type symbol
:documentation "The class of this circuit-element")
)
)
;;;METHODS
;;The methods for printing the state of circuit elements to the screen
;;(Called print-element to avoid conflicth with existing print-object)
;;
(defgeneric print-object ((elem circuit-element)(str stream))
(:documentation "Prints the state of a circuit element to the screen")
;;hard-wire
(:method ((hw hard-wire)(str stream))
(format str "[~A: hard-wire ~A]~%"
(if (slot-boundp hw 'name) (name hw) 'unbound )
(if (value hw) 1 0))
)
;;unary-gate
(:method ((ug unary-gate)(str stream))
(format str "[~A: ~A ~A=~A is ~A]~%"
(if (slot-boundp ug 'name) (name ug) 'unbound )
(class-name ug)
;input1-name
(if (null (inputs ug)) 'unbound (name (car (inputs ug))))
;input1-value
(if (null (inputs ug)) 'unbound (if (value (car (inputs ug))) 1 0))
(if (value ug) 1 0)
)
)
;;binary-gate
(:method ((bg binary-gate)(str stream))
(format str "[~A: ~A=~A ~A ~A=~A is ~A]~%"
(if (slot-boundp bg 'name) (name bg) 'unbound )
;input1-name
(if (null (inputs bg)) 'unbound (name (car (inputs bg))))
;input1-value
(if (null (inputs bg)) 'unbound (if (value (car (inputs bg))) 1 0))
;class-name
(class-name bg)
;input2-name
(if (null (cdr (inputs bg))) 'unbound (name (cadr (inputs bg))))
;input2-value
(if (null (cdr (inputs bg)))
'unbound
(if (value (cadr (inputs bg))) 1 0)
)
(if (value bg) 1 0)
)
)
)
;;Methods used by gates to compute their values based on inputs
;;
(defgeneric compute (gate)
(:documentation "Compute the value of a gate based on inputs.")
;;BUFFER
(:method ((thisgate buffer-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 1 (length (inputs thisgate)))
)
(set-gate-value thisgate
;newvalue is same as single input
(value (car (inputs thisgate)))
)
)
)
;;NOT
(:method ((thisgate not-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 1 (length (inputs thisgate)))
)
(set-gate-value thisgate
;newvalue is opposite of single input
(not (value (car (inputs thisgate))))
)
)
)
;;AND
(:method ((thisgate and-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 2 (length (inputs thisgate)))
)
(set-gate-value thisgate
(and (value (car (inputs thisgate)))
(value (cadr (inputs thisgate))))
)
)
)
;;OR
(:method ((thisgate or-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 2 (length (inputs thisgate)))
)
(set-gate-value thisgate
(or (value (car (inputs thisgate)))
(value (cadr (inputs thisgate))))
)
)
)
;;XOR
(:method ((thisgate xor-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 2 (length (inputs thisgate)))
)
(set-gate-value thisgate
;newvalue is either of the inputs but (and) not both
(and (or (value (car (inputs thisgate)))
(value (cadr (inputs thisgate))) )
(not (and (value (car (inputs thisgate)))
(value (cadr (inputs thisgate))) ))
)
)
)
)
;;NAND
(:method ((thisgate nand-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 2 (length (inputs thisgate)))
)
(set-gate-value thisgate
(not (and (value (car (inputs thisgate)))
(value (cadr (inputs thisgate)))
)
)
)
)
)
;;NOR
(:method ((thisgate nor-gate))
(when (and (slot-boundp thisgate 'inputs)
(not (null (inputs thisgate) ))
(= 2 (length (inputs thisgate)))
)
(set-gate-value thisgate
(not (or (value (car (inputs thisgate)))
(value (cadr (inputs thisgate)))
)
)
)
)
)
);end compute
;;The general method that changes a gate,
;; given the gate and a boolean newvalue for it.
;;
(defmethod set-gate-value ((thisgate gate) newvalue)
(unless (equal newvalue (value thisgate))
(setf (value thisgate) newvalue)
)
)
;;This method is called after any setf on the value of an element
;; It then updates all the values of its outputs
;;
(defmethod (setf value) :after (newvalue (thiselement circuit-element))
(mapcar 'compute (outputs thiselement))
)
;;This method is called after a gate is created.
;; It computes its value based on its inputs
;; (which in turn fires the updating of it's outputs' values)
;;
(defmethod initialize-instance :after ((thisgate gate) &rest init-args)
(compute thisgate)
)
;;An interactive half-adder, using an AND gate and XOR gate.
;;Asks for the two hardwire inputs of A and B.
;;Prints the value of S (the sum) and C (the carry)
;;
(defun half-adder ()
(let* ((a (make-instance 'Hard-Wire :name 'A))
(b (make-instance 'Hard-Wire :name 'B))
(c (make-instance 'And-Gate :name 'and1 :inputs (list a b)))
(s (make-instance 'Xor-Gate :name 'xor1 :inputs (list a b)))
)
(setf (outputs a) (list s c))
(setf (outputs b) (list s c))
(loop do (read-input a "A") ; read-input sets the gate
do (read-input b "B")
do (format t "Output: S is ~A, C is ~A~%"
(if (value s) 1 0) (if (value c) 1 0) )
while (y-or-n-p "Another computation? (y or n): ")
)
)
);end half-adder
;;An interactive full-adder.
;;Asks for the two hardwire inputs of C (incoming carry), A and B.
;;Prints the value of S (the sum) and C2 (the out-going carry).
;;
(defun full-adder ()
(let* ((c (make-instance 'Hard-Wire :name 'C))
(a (make-instance 'Hard-Wire :name 'A))
(b (make-instance 'Hard-Wire :name 'B))
(xor1 (make-instance 'Xor-Gate :name 'xor1 :inputs (list a b)))
(and1 (make-instance 'And-Gate :name 'and1 :inputs (list a b)))
(s (make-instance 'Xor-Gate :name 'xor2 :inputs (list c xor1)))
(and2 (make-instance 'And-Gate :name 'and2 :inputs (list c xor1)))
(c2 (make-instance 'Or-Gate :name 'or1 :inputs (list and1 and2)))
)
(setf (outputs c) (list s and2))
(setf (outputs a) (list xor1 and1))
(setf (outputs b) (list xor1 and1))
(setf (outputs xor1) (list s and2))
(setf (outputs and1) (list c2))
(setf (outputs and2) (list c2))
(loop do (read-input c "C")
do (read-input a "A") ; read-input sets the gate
do (read-input b "B")
do (format t "Output: S is ~A, C2 is ~A~%"
(if (value s) 1 0) (if (value c2) 1 0) )
while (y-or-n-p "Another computation? (y or n): ")
)
)
);end full-adder
;;An interactive set-reset flip-flop circuit, using two NOR gates.
;;Asks for the two hardwire inputs of S (set) and R (reset).
;;Prints the value of both the Top and Bottom gate.
;;
(defun sr-flip-flop ()
(let* ((s (make-instance 'Hard-Wire :name 'Set))
(r (make-instance 'Hard-Wire :name 'Reset))
(top (make-instance 'Nor-Gate :name 'top-nor))
(bot (make-instance 'Nor-Gate :name 'bottom-nor))
s-input r-input ;;for I/O
)
(setf (outputs s) (list top))
(setf (outputs r) (list bot))
(setf (inputs top) (list s bot))
(setf (outputs top) (list bot))
(setf (inputs bot) (list top r))
(setf (outputs bot) (list top))
(loop do (setf s-input (read-01-input "S (set)")) ;query user for values
do (setf r-input (read-01-input "R (reset)"))
do (if (= s-input r-input 1) ;;both inputs are 1
;then
(format t "Sorry, S and R cannot both be 1. ~%")
;else
(progn
(setf (value s) (eq s-input 1)) ;set to t or nil on
(setf (value r) (eq r-input 1)) ;whether input is 1 or 0
(format t "Output: Top is ~A, Bottom is ~A~%"
(if (value top) 1 0) (if (value bot) 1 0) )
);end progn
);end if
while (y-or-n-p "Another computation? (y or n): ")
)
);end let
);end sr-flip-flop
;;read-input takes a circuit element (ce)
;; and a string that explains that element to the user (printvar).
;;It asks the user for a value for printvar,
;; and uses it to updates ce's value.
;;
(defun read-input (ce printvar)
(let ( (tempvar (read-01-input printvar)) )
;tempvar is now either 1 or 0
(if (eq tempvar 1)
(setf (value ce) t)
(setf (value ce) nil)
)
);end let
);end read-input
;;read-01-input takes a string (printvar) that describes an element.
;;It asks the user for a value for printvar,
;; and returns that value.
;;It will keep asking the user until the value entered is either 0 or 1.
;;
(defun read-01-input (printvar)
(let (tempvar)
(loop do (format t "Enter input ~A (0 or 1): " printvar)
do (setf tempvar (read) )
while (not (and (integerp tempvar)
(or (eq tempvar 0) (eq tempvar 1) )
))
)
tempvar ;return tempvar
)
)
| ~ztomasze Index : TA
: Assignment 4 : Solution http://www2.hawaii.edu/~ztomasze |
Last Edited: 09 Dec 2002 ©2002 by Z. Tomaszewski. |