ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

今日の進捗

長門パイプラインシステムがとりあえず動くようになった。

(add-load-path "../../src/" :relative)
(use npsv)

; initialize
(npsv-initialize! "npsv_top")

; instancation
(define inp (make-inmem-from-file "./setting/inmem.scm"))
(define sinrom (make-rom-from-file "./setting/sin.scm"))
(define outp (make-outmem-from-file  "./setting/outmem.scm"))

; wire connection
(connect inp sinrom)
(connect sinrom outp)

; output
(make-all-rtl "./output/rtl")
(make-initialize-file inp)
(make-top-testbench "./output/tb")
(make-dataflow)

こんな感じでschemeを書くとVerilogを出してくれる。

データフロー図では、データ入力用のメモリと、ROM引きのsin関数、データ出力用のメモリが接続されている。データ入力用のメモリとROMのアドレスが直結できないので変換のモジュールが自動的に入る。

f:id:natsutan:20151129155516p:plain

入力メモリに-4~+4までの値を入れて、sinを求めた結果

f:id:natsutan:20151129155823j:plain

それっぽい。

モジュール間のプロトコルは単純で、データの有効なときはvoがH、処理が終わったらfoがHになる。これを順番に渡していくと、最後のメモリに値が書き終わったときに、最後のfoがHで終了通知になる。

後は、加算とか行列計算とかのモジュールを必要な分だけ作っていけば、複雑な計算で必要な精度の試行錯誤が楽にできそう。

Lisp in Small Pieces Exercise 1.3 extend

extendをこのように定義した場合、lookupとupdate!を定義して、元のバージョンと比較しなさい。

(define exntend
  (lambda (env names values)
     (cons (cons names values) env)))

pass というかリナザウでやるのが辛かったので挫折。
メリットは環境の拡張が早い、デメリットは検索(と更新)が面倒。

definitial が、

(set! (env.global (cons (cons 'name valus) env.global)))

なので、definitial も変えないと整合が取れない。
(car env)で先頭を取り出して、listならextendで拡張した変数、そうじゃなかったらdefinitialで定義した変数とすればいけるが、そこを頑張る意味が無さそうなのでPASS。

Lisp in Small Pieces Exercise 1.2 evlis

evilsの最後の再起が無駄なのでなくしましょう。

修正前

(define evlis
  (lambda (exps env)
    (if (pair? exps)
        (let ((arg1 (evaluate (car exps) env)))
          (cons arg1 (evlis (cdr exps) env)))
       '())))

修正後

;exer 1.2
(define evlis
  (lambda (exps env)
    (let ((arg1 (evaluate (car exps) env)))
      (if (= (length exps) 1)
          (cons arg1 '()) 
          (cons arg1 (evlis (cdr exps) env))))))

Lisp in Small Pieces Exercise 1.1 Trace

トレース機能を追加しました。
実装してから、出題の意図としては俺言語の方で追加するんじゃないかとも思いましたが、素のSchemeの方で追加できるようにしました。
テストは100点を目指すよりは合格すればOKのタイプ。

まずは、トレースON/OFFを制御する信号と、トレース対象の関数名(シンボル)を保存するためのListを宣言

(define *trace-en* #f)
(define *trace-list* '())

APIっぽいの

(define trace-on
  (lambda ()
    (set! *trace-en* #t)))

(define trace-off
  (lambda ()
    (set! *trace-en* #f)))

(define trace
  (lambda (s)
    (set! *trace-list* (cons s *trace-list*))))

引数で与えられたシンボルが、トレース対象かどうかの判定関数

(define trace?
  (lambda (s)
    (and *trace-en*
         (member s *trace-list*))))

evaluateの中身(invoke周辺)

               (let ([func (car e)]
                   [args (evlis (cdr e) env)])
               (when (trace? func) (format #t "call ~A ~A~%" func args))
               (let ([result (invoke (evaluate func env) args)])
                 (when (trace? func) (format #t "rerurn ~A ~A result ~A ~%" func args result))
                 result)))]

引数が複数回評価されないように、先頭でfunc、argsに代入し、funcがトレース対象なら、呼び出し前と、呼出し後で関数名と引数、戻り値を表示していま
す。

プログラムはインタープリターに打ち込んでられないので、リストを評価するための関数も追加。長門プロンプトで、自分の処理系が出しているメッセージであることを強調しています。

(define chap1-scheme-bat
  (lambda (args)
    (dolist (s args)
            (format #t "YUKI.N> ~A~%" (evaluate s env.global)))))

あとはこんな感じで階乗を実行してみます。

(load "./chap1.scm")
(trace-on)
(trace 'fact)

(chap1-scheme-bat
 '((set! fact
         (lambda (x)
           (if (= x 1)
               1
               (* (fact (- x 1)) x))))
   (fact 5)))

これを実行すると、

call fact (5)
call fact (4)
call fact (3)
call fact (2)
call fact (1)
rerurn fact (1) result 1
rerurn fact (2) result 2
rerurn fact (3) result 6
rerurn fact (4) result 24
rerurn fact (5) result 120
YUKI.N> 120

このように表示されます。