2012-04-05 10 views
8

Soy nuevo en la raqueta/esquema, así que decidí aprender mediante la implementación de un emulador para el DCPU-16, un procesador simple de 16 bits.¿Cuál es la expresión apropiada de Raqueta/Esquema para este código?

Mi pregunta es por lo tanto: ¿Cuál es una mejor manera de implementar mi solución?

Esta es la solución que pirateé para controlar los registros de la CPU. El punto principal era permitir que las funciones que modifican un registro se encadenaran entre sí. Por ejemplo:

; 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 

El texto completo de mi solución de registro está a continuación. My full program también está en github. Hay tanto repite la lógica, sé que debe haber una manera más fácil:

(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")])))) 

Actualización:

Gracias a sugerencias de oobviat He refactorizado el uso de listas. La única parte difícil fue actualizar un valor en la lista. Escribí un procedimiento para obtener un mapa que actualizaría el registro deseado y dejar a los demás con su valor original:

;; 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

¿Las estructuras no tienen procedimientos de introspección? Estoy seguro de que sí. – leppie

+0

@leppie, las estructuras no tienen sus nombres en la información de introspección. –

Respuesta

2

Esto no estaba escrito en la raqueta, por lo que puede no funcionar para usted como es .. si se lanza los errores intentan especificar el tipo de código R5RS en la parte superior del archivo. Para simplificar, haría algo como esto usando una lista alfa en lugar de estructuras.

;; 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))))) 

Estoy asumiendo que la raqueta se ha construido en como assoc que devuelve la lista adecuada desde la A-lista. Además, tenga en cuenta que *reg* se define como una variable global en este caso para que podamos simplemente definirlo una vez y luego usar set-cdr! para escribirle valores.

finalmente, esto podría hacer cosas extrañas en su registro SP. Mi esquema lo ve como 65536 ... si no está bien, puede que tenga que agregar un if a reg-write y reg-read para asegurarse de que está obteniendo los valores correctos allí.

<EDIT> Por lo tanto, leí un poco sobre los procedimientos de Racket, y este código casi seguro no se ejecutará en Racket normal porque aparentemente tienen pares mutables y no mutables. Los cambios que tendrá que realizar si desea ejecutar esto en Racket y no en R5RS son los siguientes:

En lugar de simplemente usar una lista entre comillas, probablemente necesite hacer su lista de registros con la lista mutable/constructores de pares (define *reg* (mlist (mcons 'A 0) (mcons 'B 0) ...).

En lugar de usar set-cdr!, la versión Raqueta es set-mcdr! y solo funciona en pares mutables. </EDIT>

+0

[Sí.] (Http://docs.racket-lang.org/reference/pairs.html# (def._ ((lib._racket/private/list..rkt) ._assoc))) – Taymon

+0

Sí. Pensé que era una suposición bastante segura. – oobivat

+0

Quería escribir esto sin el uso de un conjunto, para forzarme a pensar de manera diferente. Su solución de lista inspiró mi nueva implementación. –

Cuestiones relacionadas