diff --git a/beautiful-racket/br/demo/hdl/Dmux4Way.hdl.rkt b/beautiful-racket/br/demo/hdl/Dmux4Way.hdl.rkt index d49265e..0095b0c 100644 --- a/beautiful-racket/br/demo/hdl/Dmux4Way.hdl.rkt +++ b/beautiful-racket/br/demo/hdl/Dmux4Way.hdl.rkt @@ -19,8 +19,8 @@ CHIP DMux4Way { OUT a, b, c, d; PARTS: - DMux(in=in, sel[0]=sel, a=a, b=b); - DMux(in=in, sel[1]=sel, a=c, b=d); + DMux(in=in, sel=sel[0], a=a, b=b); + DMux(in=in, sel=sel[1], a=c, b=d); /* // the right answer: note that subscripting on right always means "read this bit"; // subscripting on left means "write this bit" diff --git a/beautiful-racket/br/demo/hdl/expander.rkt b/beautiful-racket/br/demo/hdl/expander.rkt index 850fd0b..0f1b4f9 100644 --- a/beautiful-racket/br/demo/hdl/expander.rkt +++ b/beautiful-racket/br/demo/hdl/expander.rkt @@ -1,10 +1,7 @@ #lang br (require "helper.rkt" (for-syntax racket/base racket/syntax "helper.rkt" racket/list racket/require-transform)) -(provide #%top-interaction (rename-out [mb #%module-begin]) #%app #%datum and or (all-defined-out)) +(provide #%top-interaction #%module-begin #%app #%datum and or (all-defined-out)) -(define #'(mb _arg ...) - #'(#%module-begin - _arg ...)) (define #'(chip-program _chipname (in-spec (_input-pin _input-width ...) ...) diff --git a/beautiful-racket/br/demo/hdl/helper.rkt b/beautiful-racket/br/demo/hdl/helper.rkt index 0cd69ef..05a37bd 100644 --- a/beautiful-racket/br/demo/hdl/helper.rkt +++ b/beautiful-racket/br/demo/hdl/helper.rkt @@ -40,11 +40,18 @@ (bitwise-bit-field int i (add1 i))))) (define max-bus-width 16) +(define default-bus-width 1) + (define (check-bit-against-width bus-name bit width) (unless (< bit width) (raise-argument-error bus-name (format "bit less than bus width ~a" width) bit))) +(define (check-val-against-width bus-name val width) + (when (and val (> val (sub1 (expt 2 width)))) + (raise-argument-error bus-name + (format "~a-bit value (0 to ~a inclusive)" width (sub1 (expt 2 width))) val))) + (require sugar/debug) (define (make-input-bus bus-name [width 1]) (impersonate-procedure @@ -53,17 +60,14 @@ [bus-val 0]) (unless (<= bus-width max-bus-width) (raise-argument-error bus-name (format "bus width <= max width ~a" max-bus-width) bus-width)) - (define (check-val-against-width val width) - (when (and val (> val (sub1 (expt 2 width)))) - (raise-argument-error bus-name - (format "~a-bit value (0 to ~a inclusive)" width (sub1 (expt 2 width))) val))) + (define func (case-lambda [() bus-val] [(new-val-in) (define new-val (cond [(boolean? new-val-in) - (if new-val-in (sub1 (expt 2 bus-width)) 0)] + (if new-val-in (sub1 (expt 2 bus-width)) 0)] [(or (input-bus? new-val-in) (output-bus? new-val-in)) (new-val-in)] [else new-val-in])) (check-val-against-width new-val bus-width) @@ -73,7 +77,7 @@ (define bit-range-width (add1 (- last-bit first-bit))) (define new-val (cond [(boolean? new-val-in) - (if new-val-in (sub1 (expt 2 bit-range-width)) 0)] + (if new-val-in (sub1 (expt 2 bit-range-width)) 0)] [(or (input-bus? new-val-in) (output-bus? new-val-in)) (new-val-in)] [else new-val-in])) (unless (<= first-bit last-bit) @@ -88,94 +92,146 @@ bus-name) #f input-bus #t)) -(define-syntax-rule (define-input-bus id arg ...) - (define id (make-input-bus 'id arg ...))) -(module+ test - (define-input-bus in-bus) - (define other (λ () (+ 2 2))) - (check-true (input-bus? in-bus)) - (check-false (input-bus? other)) - - (define-input-bus ib 4) - (check-exn exn:fail? (λ () (define-input-bus ib 17) ib)) ; exceeds 16-bit width - (check-equal? (ib) 0) - (ib 11) ; set whole value - (check-exn exn:fail? (λ () (ib #b11111))) ; overflow - (ib 2 1) ; set bit - (check-equal? (ib) #b1111) - (ib 0 #b0) ; set bit - (ib 1 #b0) ; set bit - (ib 2 #b0) ; set bit - (check-equal? (ib) #b1000) - (check-exn exn:fail? (λ () (ib 5 1 #b0))) ; last index smaller than first - (check-exn exn:fail? (λ () (ib 1 300 #b0))) ; overlarge bit index - (check-exn exn:fail? (λ () (ib 300 500 #b0))) ; overlarge bit index - (check-exn exn:fail? (λ () (ib 1 #b11111))) ; overflow value - (ib 0) - (ib 1 2 #b11) - (check-equal? (ib) #b0110) - (ib 3 3 #b1) - (ib 0 0 #b1) - (check-equal? (ib) #b1111) - (check-exn exn:fail? (λ () (ib 0 300 #b0))) ; overlarge bit index - (check-exn exn:fail? (λ () (ib 1 1 #b11111))) ; overflow value - (ib 0) - (ib 1 2 #t) ; using #t to fill certain bits - (check-equal? (ib) #b0110) - (ib 2 2 #f) ; using #f to fill certain bits - (check-equal? (ib) #b0010) - (ib 0) - (ib #t) ; using #t to fill all bits - (check-equal? (ib) #b1111) - (ib #f) ; using #f to fill all bits - (check-equal? (ib) #b0000) - (define-input-bus ib2 4) - (check-exn exn:fail? (λ () (ib2 16))) ; overflow value - (ib2 #b1100) - (ib ib2) ; using bus as input value - (check-equal? (ib) (ib2)) - ) +(require (for-syntax racket/base racket/syntax)) +(define-syntax (define-input-bus stx) + (syntax-case stx () + [(macro-name id) + #'(macro-name id void default-bus-width)] + [(macro-name id width) + #'(macro-name id void width)] + [(macro-name id thunk width) + (with-syntax ([id-write (format-id #'id "~a-write" #'id)]) + #'(begin + (define-output-bus id thunk width) + ))])) + +#;(module+ test + (define-input-bus in-bus) + (define other (λ () (+ 2 2))) + (check-true (input-bus? in-bus)) + (check-false (input-bus? other)) + + (define-input-bus ib 4) + (check-exn exn:fail? (λ () (define-input-bus ib 17) ib)) ; exceeds 16-bit width + (check-equal? (ib-read) 0) + (ib-write 11) ; set whole value + (check-exn exn:fail? (λ () (ib-write #b11111))) ; overflow + (ib-write 2 1) ; set bit + (check-equal? (ib) #b1111) + (ib-write 0 #b0) ; set bit + (ib-write 1 #b0) ; set bit + (ib-write 2 #b0) ; set bit + (check-equal? (ib-read) #b1000) + (check-exn exn:fail? (λ () (ib-write 5 1 #b0))) ; last index smaller than first + (check-exn exn:fail? (λ () (ib-write 1 300 #b0))) ; overlarge bit index + (check-exn exn:fail? (λ () (ib-write 300 500 #b0))) ; overlarge bit index + (check-exn exn:fail? (λ () (ib-write 1 #b11111))) ; overflow value + (ib-write 0) + (ib-write 1 2 #b11) + (check-equal? (ib-read) #b0110) + (ib-write 3 3 #b1) + (ib-write 0 0 #b1) + (check-equal? (ib-read) #b1111) + (check-exn exn:fail? (λ () (ib-write 0 300 #b0))) ; overlarge bit index + (check-exn exn:fail? (λ () (ib-write 1 1 #b11111))) ; overflow value + (ib-write 0) + (ib-write 1 2 #t) ; using #t to fill certain bits + (check-equal? (ib-read) #b0110) + (ib-write 2 2 #f) ; using #f to fill certain bits + (check-equal? (ib-read) #b0010) + (ib-write 0) + (ib-write #t) ; using #t to fill all bits + (check-equal? (ib-read) #b1111) + (ib-write #f) ; using #f to fill all bits + (check-equal? (ib-read) #b0000) + (define-input-bus ib2 4) + (check-exn exn:fail? (λ () (ib2-write 16))) ; overflow value + (ib2-write #b1100) + (ib-write (ib2-read)) ; using bus as input value + (check-equal? (ib-read) (ib2)) + ) (define-values (output-bus output-bus? output-bus-get) (make-impersonator-property 'output-bus)) -(define (make-output-bus bus-name thunk [width 1]) - (impersonate-procedure - (procedure-rename - (let ([bus-width width]) - (unless (<= bus-width max-bus-width) - (raise-argument-error bus-name (format "bus width <= max width ~a" max-bus-width) bus-width)) - (define func - (case-lambda - [() (func 0 (sub1 bus-width))] - [(bit) (func bit bit)] - [(first-bit last-bit) - (unless (<= first-bit last-bit) - (raise-argument-error bus-name (format "last bit greater than or equal to first bit ~a" first-bit) last-bit)) - (check-bit-against-width bus-name first-bit bus-width) - (check-bit-against-width bus-name last-bit bus-width) - (bitwise-bit-field (thunk) first-bit (add1 last-bit))])) - func) - bus-name) - #f output-bus #t)) +(define (make-read-bus bus-name thunk bus-width) + (unless (<= bus-width max-bus-width) + (raise-argument-error bus-name (format "bus width <= max width ~a" max-bus-width) bus-width)) + (impersonate-procedure (procedure-rename thunk bus-name) #f output-bus #t)) + +(define (make-bus-reader reader-name id-val thunk width) + (define bus-reader-func + (case-lambda + [() (bus-reader-func 0 (sub1 width))] + [(bit) (bus-reader-func bit bit)] + [(first-bit last-bit) + (unless (<= first-bit last-bit) + (raise-argument-error reader-name (format "last bit greater than or equal to first bit ~a" first-bit) last-bit)) + (check-bit-against-width reader-name first-bit width) + (check-bit-against-width reader-name last-bit width) + (set! id-val (thunk)) + (bitwise-bit-field id-val first-bit (add1 last-bit))])) + bus-reader-func) + +(define (make-bus-writer writer-name id width) + (define bus-writer-func + (case-lambda + [() (raise-argument-error writer-name "new value" empty)] + [(new-val-in) + (define new-val (cond + [(boolean? new-val-in) + (if new-val-in (sub1 (expt 2 width)) 0)] + [(or (input-bus? new-val-in) (output-bus? new-val-in)) (new-val-in)] + [else new-val-in])) + (check-val-against-width 'id new-val width) + (set! id new-val)] + [(bit new-val) (bus-writer-func bit bit new-val)] + [(first-bit last-bit new-val-in) + (define bit-range-width (add1 (- last-bit first-bit))) + (define new-val (cond + [(boolean? new-val-in) + (if new-val-in (sub1 (expt 2 bit-range-width)) 0)] + [(or (input-bus? new-val-in) (output-bus? new-val-in)) (new-val-in)] + [else new-val-in])) + (unless (<= first-bit last-bit) + (raise-argument-error writer-name (format "last bit greater than or equal to first bit ~a" first-bit) last-bit)) + (check-bit-against-width writer-name first-bit width) + (check-bit-against-width writer-name last-bit width) + (check-val-against-width new-val bit-range-width) + (for ([bit (in-range first-bit (add1 last-bit))] + [new-bit-val (in-list (integer->bitvals new-val bit-range-width))]) + (set! id ((if (= 1 new-bit-val) bitwise-bit-set bitwise-bit-unset) id bit)))])) + bus-writer-func) + +(define-syntax (define-output-bus stx) + (syntax-case stx () + [(macro-name id thunk) + #'(macro-name id thunk default-bus-width)] + [(macro-name id thunk width) + (with-syntax ([id-val (format-id #'id "~a-val" #'id)] + [id-read (format-id #'id "~a-read" #'id)] + [id-write (format-id #'id "~a-write" #'id)]) + #'(begin + (define id-val 0) + (define id-read (make-bus-reader 'id-read id-val thunk width)) + (define id (make-read-bus 'id id-read width)) + (define id-write (make-bus-writer 'id-write id width))))])) -(define-syntax-rule (define-output-bus id thunk arg ...) - (define id (make-output-bus 'id thunk arg ...))) (module+ test (define-output-bus ob (λ () #b0110) 4) - (check-exn exn:fail? (λ () (define-input-bus ob (λ () #b0110) 17) ob)) ; exceeds 16-bit width - (check-equal? (ob) #b0110) - (check-equal? (ob 0) #b0) - (check-equal? (ob 1) #b1) - (check-equal? (ob 2) #b1) - (check-equal? (ob 3) #b0) - (check-exn exn:fail? (λ () (ob 5))) ; exceeds bus width - (check-equal? (ob 0 1) #b10) - (check-equal? (ob 1 2) #b11) - (check-equal? (ob 2 3) #b01) - (check-exn exn:fail? (λ () (ob 3 2))) ; inverted bus spec - (check-exn exn:fail? (λ () (ob 5 10))) ; exceeds bus width + (check-exn exn:fail? (λ () (define-output-bus ob (λ () #b0110) 17) ob)) ; exceeds 16-bit width + (check-equal? (ob-read) #b0110) + (check-equal? (ob-read 0) #b0) + (check-equal? (ob-read 1) #b1) + (check-equal? (ob-read 2) #b1) + (check-equal? (ob-read 3) #b0) + (check-exn exn:fail? (λ () (ob-read 5))) ; exceeds bus width + (check-equal? (ob-read 0 1) #b10) + (check-equal? (ob-read 1 2) #b11) + (check-equal? (ob-read 2 3) #b01) + (check-exn exn:fail? (λ () (ob-read 3 2))) ; inverted bus spec + (check-exn exn:fail? (λ () (ob-read 5 10))) ; exceeds bus width ) diff --git a/beautiful-racket/br/demo/hdl/parser.rkt b/beautiful-racket/br/demo/hdl/parser.rkt index 873e251..23b5fcd 100644 --- a/beautiful-racket/br/demo/hdl/parser.rkt +++ b/beautiful-racket/br/demo/hdl/parser.rkt @@ -18,11 +18,15 @@ part : partname /"(" pin-val-pair [/"," pin-val-pair]* /")" /";" @partname : ID -/pin-val-pair : ID [/"[" bus-range /"]"] /"=" pin-val +/pin-val-pair : pin-range /"=" pin-val -@bus-range : NUMBER [/"." /"." NUMBER] +@bus-range : number [/"." /"." number] -@pin-val : ID [/"[" bus-range /"]"] +@pin-range : ID [/"[" bus-range /"]"] + +@pin-val : pin-range | BINARY-NUMBER | TRUE | FALSE + +@number : BINARY-NUMBER | NUMBER \ No newline at end of file