2012-04-05 1 views
8

Я новичок в ракетке/схеме, поэтому решил научиться, используя эмулятор для DCPU-16, простого 16-битного процессора.Какова соответствующая идиома Ракетки/Схемы для этого кода?

Мой вопрос: таким образом, лучший способ реализовать мое решение?

Это решение, которое я взломал вместе, чтобы контролировать регистры процессора. Главное - разрешить функции, которые изменяют регистр, соединяемый вместе. Например:

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

Update:

Благодаря sugestions oobviat, я уже рефакторингу с помощью списков. Единственная сложная часть - обновление значения в списке. Я написал процедуру для карты, которая будет обновлять нужный регистр и оставить другие с их первоначальной стоимостью:

;; 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, а не structs.

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

Я предполагаю, что ракетка имеет встроенный как assoc, который возвращает нужный список из а-списка. Кроме того, обратите внимание, что в этом случае *reg* определяется как глобальная переменная, так что мы можем просто определить ее один раз, а затем использовать set-cdr! для записи в нее значений.

, наконец, это может сделать странные вещи в вашем регистре SP. Моя схема видит это как 65536 .. Если это не так, вам, возможно, придется добавить if в reg-write и reg-read, чтобы убедиться, что вы получаете правильные значения там.

<EDIT> Итак, я немного поработал над процедурами Racket, и этот код почти наверняка не будет работать в обычном Racket, потому что они, по-видимому, имеют как изменяемые, так и не изменяемые пары. Изменения, которые вы должны будете выполнить, если вы хотите запустить это под Racket, а не R5RS, следующие:

Вместо того, чтобы использовать только цитируемый список, вам, вероятно, потребуется составить список регистров с изменяемыми конструкторами списка/пары (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._racket/private/list..rkt) ._assoc))) – Taymon

+0

Да. что это было довольно безопасное предположение. – oobivat

+0

Я хотел написать это без использования набора, чтобы заставить себя думать по-другому. Ваше решение списка вдохновило мою новую реализацию. –

 Смежные вопросы

  • Нет связанных вопросов^_^