3.3.4 · 디지털 회로 시뮬레이터 전선은 게이트에 알리고 agenda는 지연을 시뮬레이션 시간으로 바꾼다. 가변 전선, 지연된 게이트 동작, 정렬된 agenda, 예약된 전파 지연 뒤에만 출력이 바뀌는 half-adder를 만듭니다.
생각해 볼 질문
지역 게이트 규칙은 어떻게 명시적인 시뮬레이션 시간을 따라 펼쳐지는 회로 동작으로 합쳐질까요? 각 전선 안에 신호 하나와 action 목록 저장하기 신호가 실제로 바뀔 때만 전선 action 실행하기 현재 시간과 고정 지연을 더한 시점에 게이트 갱신 예약하기 의제 이벤트를 시뮬레이션 시간의 오름차순으로 전파하기 중앙 회로 로직 없이 기본 게이트를 half-adder로 합성하기 전선은 신호와 action 프로시저 목록을 소유합니다. 게이트를 설치하면 각 입력 전선에 action을 더하고 초기 출력이 예약되도록 한 번 실행합니다. 나중 set-signal!은 신호가 달라질 때만 action을 호출합니다. 각 게이트는 현재 입력을 곧바로 읽지만 출력 변경은 더 늦은 의제 시간에 예약합니다.
half-adder는 or, and, inverter, 또 다른 and 게이트로 구성됩니다. 유한 일정은 먼저 0 입력을 안정화하고 a, b, a를 차례로 바꿉니다. 기록한 시간은 이 모형에 지정한 지연에서 나온 정확한 시뮬레이션 이벤트입니다.
SICP 코드 UTF-8 2,220 / 1,048,576바이트
( begin
( define current-time 0 )
( define agenda ' ( ) )
( define ( insert-event event events )
( cond ( ( null? events ) ( list event ) )
( ( < ( car event ) ( car ( car events ) ) )
( cons event events ) )
( else
( cons ( car events )
( insert-event event ( cdr events ) ) ) ) ) )
( define ( after-delay delay action )
( set! agenda
( insert-event
( list ( + current-time delay ) action )
agenda ) ) )
( define ( propagate )
( if ( null? agenda )
' done
( let ( ( event ( car agenda ) ) )
( set! agenda ( cdr agenda ) )
( set! current-time ( car event ) )
( ( cadr event ) )
( propagate ) ) ) )
( define ( make-wire )
( let ( ( signal 0 ) ( actions ' ( ) ) )
( define ( call-each procedures )
( if ( null? procedures )
' done
( begin
( ( car procedures ) )
( call-each ( cdr procedures ) ) ) ) )
( define ( set-signal new-value )
( if ( = signal new-value )
' unchanged
( begin
( set! signal new-value )
( call-each actions )
' changed ) ) )
( define ( add-action action )
( set! actions ( cons action actions ) )
( action )
' ok )
( lambda ( message )
( cond ( ( eq? message ' get ) signal )
( ( eq? message ' set ) set-signal )
( ( eq? message ' add-action ) add-action )
( else ' unknown-wire-message ) ) ) ) )
( define ( get-signal wire ) ( wire ' get ) )
( define ( set-signal! wire value ) ( ( wire ' set ) value ) )
( define ( add-action! wire action ) ( ( wire ' add-action ) action ) )
( define ( logical-not signal ) ( if ( = signal 0 ) 1 0 ) )
( define ( inverter input output )
( define ( action )
( let ( ( new-value ( logical-not ( get-signal input ) ) ) )
( after-delay 2
( lambda ( ) ( set-signal! output new-value ) ) ) ) )
( add-action! input action )
' ok )
( define input ( make-wire ) )
( define output ( make-wire ) )
( inverter input output )
( propagate )
( define initial-time current-time )
( define initial-output ( get-signal output ) )
( set-signal! input 1 )
( propagate )
( list initial-time
initial-output
current-time
( get-signal output ) ) ) 코드 실행Ctrl/⌘ Enter 파일 열기 코드 저장 코드 복사 편집기 지우기
예제 inverter 하나를 예약하고 전파하기 기본 게이트를 half-adder로 합성하기
실행은 브라우저 안에서 이루어지며 프로그램 결과와 실행 추적을 보여줍니다. 예상 결과 inverter는 (2 1 4 0)을 반환합니다. half-adder는 ((initial 5 0 0) (a-one 13 1 0) (both-one 21 0 1) (a-zero 29 1 0))을 반환합니다.
실행 추적에서 볼 점 즉시 입력 읽기와 지연된 출력 변경을 구분하세요. 정렬된 의제 삽입, 각 current-time 갱신, 바뀐 신호가 부른 전선 action을 따라가세요. half-adder에서는 sum과 carry의 각 전이를 어느 기본 게이트가 예약했는지 찾으세요.
직접 해보기 프로그램을 수정하고 결과를 비교해 보세요. half-adder 하나를 더하고 or gate를 사용해 full-adder를 만드세요. 유한 입력 조합 세 개를 구동하고 시뮬레이션 시간을 기록하며 같은 시간의 출력 전이가 서로 다른 예약 이벤트에서 나온 경우를 설명하세요.
힌트 보기 full-adder는 half-adder 두 개와 carry 출력의 OR로 만들 수 있습니다. 진리표를 중앙에서 계산하지 말고 모든 지연을 명시적으로 유지하세요.