2012-04-05 22 views
8

私はracket/schemeの新人です。そのため、単純な16ビットプロセッサのDCPU-16のエミュレータを実装して学習することにしました。このコードの適切なラケット/スキームのイディオムは何ですか?

質問:私のソリューションを実装するためのより良い方法は何ですか?

これは、私がCPUのレジスタを制御するために一緒にハッキングした解決策です。主なポイントは、レジスタを変更する関数を連鎖させることでした。例:

; Increment value stored in register r-id 
; returns the updated register 
; 
; Reg - the register structure 
; (reg-inc Reg 'SP) 
(define (reg-inc reg r-id) 
    (reg-write reg r-id (+ (reg-read reg r-id) 1))) 

; chain them together 
;(reg-inc (reg-inc Reg 'SP) 
;   'PC) 
; 
; returns structure with both 'SP and 'PC incremented 

私の登録ソリューションの全文は以下のとおりです。 My full programもgithubにあります。そんなにロジックが繰り返され、私はもっと簡単な方法があるに違いありません知っている:

(struct registers (A B C X Y Z I J SP PC O Pa Pb Paadr Pbadr CLK) 
    #:transparent) 

(define Reg (registers 0 0 0 0 0 0 0 0 #x10000 0 0 0 0 0 0 0)) 

(define (reg-name n) 
    (case n 
    [(0) 'A] 
    [(1) 'B] 
    [(2) 'C] 
    [(3) 'X] 
    [(4) 'Y] 
    [(5) 'Z] 
    [(6) 'I] 
    [(7) 'J] 
    [(8) 'SP] 
    [(9) 'PC] 
    [(10) 'O] 
    [(11) 'Pa] 
    [(12) 'Pb] 
    [(13) 'Paadr] 
    [(14) 'Pbadr] 
    [(15) 'CLK] 
    [else (error "Invalid register")])) 

(define (reg-id s) 
    (cond 
    [(eq? 'A s) 0] 
    [(eq? 'B s) 1] 
    [(eq? 'C s) 2] 
    [(eq? 'X s) 3] 
    [(eq? 'Y s) 4] 
    [(eq? 'Z s) 5] 
    [(eq? 'I s) 6] 
    [(eq? 'J s) 7] 
    [(eq? 'SP s) 8] 
    [(eq? 'PC s) 9] 
    [(eq? 'O s) 10] 
    [(eq? 'Pa s) 11] 
    [(eq? 'Pb s) 12] 
    [(eq? 'Paadr s) 13] 
    [(eq? 'Pbadr s) 14] 
    [(eq? 'CLK s) 15])) 

(define (reg-read reg r) 
    (if (symbol? r) 
     (reg-read reg (reg-id r)) 
     (case r 
     [(0) (registers-A reg)] 
     [(1) (registers-B reg)] 
     [(2) (registers-C reg)] 
     [(3) (registers-X reg)] 
     [(4) (registers-Y reg)] 
     [(5) (registers-Z reg)] 
     [(6) (registers-I reg)] 
     [(7) (registers-J reg)] 
     [(8) (registers-SP reg)] 
     [(9) (registers-PC reg)] 
     [(10) (registers-O reg)] 
     [(11) (registers-Pa reg)] 
     [(12) (registers-Pb reg)] 
     [(13) (registers-Paadr reg)] 
     [(14) (registers-Pbadr reg)] 
     [(15) (registers-CLK reg)] 
     [else (error "Invalid register")]))) 

(define (reg-write reg r val) 
    (if (symbol? r) 
     (reg-write reg (reg-id r) val) 
     (let ([mask-val (bitwise-and val #xffff)]) 
     (case r 
      [(0) (struct-copy registers reg [A mask-val])] 
      [(1) (struct-copy registers reg [B mask-val])] 
      [(2) (struct-copy registers reg [C mask-val])] 
      [(3) (struct-copy registers reg [X mask-val])] 
      [(4) (struct-copy registers reg [Y mask-val])] 
      [(5) (struct-copy registers reg [Z mask-val])] 
      [(6) (struct-copy registers reg [I mask-val])] 
      [(7) (struct-copy registers reg [J mask-val])] 
      [(8) (struct-copy registers reg [SP mask-val])] 
      [(9) (struct-copy registers reg [PC mask-val])] 
      [(10) (struct-copy registers reg [O mask-val])] 
      [(11) (struct-copy registers reg [Pa mask-val])] 
      [(12) (struct-copy registers reg [Pb mask-val])] 
      [(13) (struct-copy registers reg [Paadr mask-val])] 
      [(14) (struct-copy registers reg [Pbadr mask-val])] 
      [(15) (struct-copy registers reg [CLK mask-val])] 
      [else (error "Invalid register")])))) 

アップデート:私はリストを使用してリファクタリングしましたoobviatのsugestionsに

感謝。トリッキーな部分は、リストの値を更新することだけでした。私は、所望のレジスタを更新し、元の値と他の人を残してマップするための手順を書いた:

;; a-list of registers and initial values 
(define (build-reg) 
    '((A . 0) (B . 0)  (C . 0)  (X . 0) 
    (Y . 0) (Z . 0)  (I . 0)  (J . 0) 
    (SP . 0) (PC . 0) (O . 0)  (Pa . 0) 
    (Pb . 0) (Paadr . 0) (Pbadr . 0) (CLK . 0))) 

(define *REF-REG* (build-reg)) ; used to determine structure 

(define (reg-name n) 
    (if (symbol? n) 
     n 
     (car (list-ref *REF-REG* n)))) 

(define (reg-id s) 
    (- (length *REF-REG*) 
    (length (memf (lambda (arg) 
        (eq? s (car arg))) 
        *REF-REG*)))) 

(define (reg-write reg r val) 
    (let ([r-name (reg-name r)]) 
    (define (reg-write-helper entry) 
     (if (eq? r-name 
       (car entry)) 
      (cons r-name val) 
      entry)) 
    (map reg-write-helper reg))) 

(define (reg-read reg r) 
    (cdr (assoc (reg-name r) reg))) 
+0

構造体にイントロスペクションプロシージャはありませんか?私はそれが確信しています。 – leppie

+0

@leppie、構造体イントロスペクション情報に名前がありません。 –

答えて

2

これはラケットで書かれていなかった、そうであるとして、それをスローした場合に、それは..あなたのために動作しない場合がありますエラーは、ファイルの先頭にR5RSコードタイプを指定してみてください。簡単にするために、私は構造体ではなくa-listを使ってこのようなことを行います。

;; a-list of registers and initial values 
(define *reg* 
    '((A . 0) (B . 0) (C . 0) (X . 0) (Y . 0) (Z . 0) 
    (I . 0) (J . 0) (SP . #X10000) (PC . 0) (O . 0) 
    (Pa . 0) (Pb . 0) (Paadr . 0) (Pbadr . 0) (CLK . 0))) 

(define (reg-write register val) 
    (set-cdr! (assoc register *reg*) val) ;write new value to register 
    val) ; return newly written value 

(define (reg-read register) 
    (cdr (assoc register *reg*))) 

(define (reg-inc register) 
    (reg-write register (+ 1 (reg-read register)))) 

;; to do many operations 
;; input: a list of registers 
;; EX: '(a b x) 
(define (do-incs registers) 
    (if (null? registers) 
     'done  ; return something when the incs are done 
     (begin  ; lets you evaluate multiple expressions since `if` doesn't   
     (reg-inc (car registers)) 
     (do-incs (cdr registers))))) 

私はそのラケットは、A-リストから適切なリストを返しますassocなどに組み込まれていると仮定しています。また、この場合は*reg*がグローバル変数として定義されているため、一度定義してからset-cdr!を使用して値を書き込むことができます。

最後に、これはあなたのSPレジスタに奇妙なことをするかもしれません。私の計画では65536と表示されています。それが正しくない場合は、とreg-readifを追加して、適切な値が得られるようにする必要があります。

<EDIT> だから、私はラケットの手続き上の少しを読んで、彼らは明らかに可変と非可変の両方のペアを持っているので、このコードは、ほぼ確実に、通常のラケットでは実行されません。

引用されたリストを使用するのではなく、変更可能なリスト/ペアのコンストラクタを使用してレジスタのリストを作成する必要があるかもしれません(これはおそらくR5RSではなくRacketで実行する必要があります) (define *reg* (mlist (mcons 'A 0) (mcons 'B 0) ...)

set-cdr!の代わりに、Racketのバージョンはset-mcdr!であり、変更可能なペアでのみ動作します。 </EDIT>

+0

[それは。](http://docs.racket-lang.org/reference/pairs.html#(def._((lib._rackset/private/list..rkt)._assoc)))) – Taymon

+0

うん。それはかなり安全な仮定だったと思った。 – oobivat

+0

私はセットを使わずにこれを書いて、違った考え方を強要したかったのです。リストソリューションは私の新しい実装に影響を与えました。 –

関連する問題