vm.lisp (8457B)
1 (defun make-vm (size &optional debug) 2 (cons (make-array size :initial-element 0) 3 `(;; Registres généraux. 4 (R0 . 0) 5 (R1 . 0) 6 (R2 . 0) 7 ;; Base de la pile. 8 (BP . 0) 9 ;; Sommet de la pile. 10 (SP . 0) 11 ;; Sommet du cadre de la pile 12 (FP . 0) 13 ;; Pointeur de code : fin de la mémoire. 14 (PC . ,(- size 1)) 15 ;; registres booléens = faux (nil). 16 (PP . nil) 17 (EQ . nil) 18 (PG . nil) 19 ;; Quand HALT passe à t, on arrête la machine. 20 (HALT . nil) 21 ;; Sert uniquement pour le debug 22 (DEBUG . ,debug)))) 23 24 (defun get-memory (vm index) 25 (aref (car vm) index)) 26 (defun set-memory (vm index value) 27 (setf (aref (car vm) index) value)) 28 (defun get-register-list (vm) 29 (mapcar #'car (cdr vm))) 30 (defun get-register (vm reg) 31 (cdr (assoc reg (cdr vm)))) 32 (defun set-register (vm reg value) 33 (setf (cdr (assoc reg (cdr vm))) value)) 34 (defun size-memory (vm) 35 (length (car vm))) 36 (defun get-debug-mode (vm) 37 (cdr (assoc 'debug (cdr vm)))) 38 39 ;; TODO : Reste a ajouter la resolution d'etiquette 40 (defun load-asm (asm &optional (stack-size 100) (debug nil)) 41 (let ((vm (make-vm (+ (length asm) stack-size) debug)) 42 (size-vm (+ (length asm) stack-size))) 43 (labels ((load-asm-rec (vm index asm debug) 44 (if (endp asm) 45 vm 46 (progn (set-memory vm index (car asm)) 47 (load-asm-rec vm (- index 1) (cdr asm) debug))))) 48 (load-asm-rec vm (- size-vm 1) asm debug)))) 49 50 ;;TODO : Rajouter une fonction resolve pour resoudre les differents modes d'adresssage. 51 ;; TODO : Penser a ajouter une table des opcodes 52 53 (defvar *table-operateurs* 54 '(load store move add sub mult div incr decr push pop 55 jmp jsr rtn cmp jeq jpg jpp jpe jge jne nop halt)) 56 57 (defvar *table-modes-adressage* 58 '(constant direct registre indexé indirect indirect-registre indirect-indexé)) 59 60 ;; Fonctions de manipulation de bits : 61 ;; http://psg.com/~dlamkins/sl/chapter18.html 62 ;; (integer-length n) ≡ ⎡log₂(n)⎤ 63 ;; (ash n décalage) = décalage binaire à gauche (ou droite si négatif) 64 ;; (logior a b) = ou binaire de a et b. 65 66 (defun position1 (x l) (+ 1 (position x l))) 67 68 ;; TODO : faire une fonction (append-bits n1 size2 n2 size3 n3 ... sizen nn) 69 70 (defun append-bits (&optional (n1 0) &rest rest) 71 (if (endp rest) 72 n1 73 (apply #'append-bits 74 (logior (ash n1 (car rest)) 75 (cadr rest)) 76 (cddr rest)))) 77 78 (defvar *nb-operateurs* (length *table-operateurs*)) 79 (defvar *nb-modes-adressage* (length *table-modes-adressage*)) 80 (defvar *nb-opcode-bytes* 81 (ceiling (/ (+ (integer-length (+ 1 *nb-operateurs*)) 82 (* 2 83 (integer-length (+ 1 *nb-modes-adressage*)))) 84 ;; On divise par 8 car 8 bits dans un byte. 85 8))) 86 87 (defun isn-decode (opcode) 88 opcode) 89 90 ;; Instruction est une liste 91 ;; '(operateur mode-adressage-1 valeur-1 mode-adressage-2 valeur-2) 92 ;; Si l'instruction ne prend qu'un (ou zéro) paramètre, les champs 93 ;; correspondants sont mis à nil. 94 95 (defun isn-encode (instruction) 96 (loop 97 for (operateur mode-adressage-1 valeur-1 mode-adressage-2 valeur-2) = instruction 98 return (list (append-bits (position1 operateur *table-operateurs*) 99 *nb-modes-adressage* 100 (position1 mode-adressage-1 *table-modes-adressage*) 101 *nb-modes-adressage* 102 (position1 mode-adressage-2 *table-modes-adressage*)) 103 (if (eq mode-adressage-1 'registre) 104 (position1 valeur-1 (get-register-list (make-vm 1))) 105 valeur-1) 106 (if (eq mode-adressage-2 'registre) 107 (position1 valeur-2 (get-register-list (make-vm 1))) 108 valeur-2)))) 109 110 (defun dump-vm (vm) 111 (dotimes (i (size-memory vm)) 112 (let ((val (get-memory vm i))) 113 (format T "~&~8,'0x ~2,'0x ~3d ~a" i val val (isn-decode val)))) 114 (mapcar (lambda (reg) 115 (let ((val (get-register vm reg))) 116 (format T "~&~4a ~2,'0x ~3d" (string reg) val val))) 117 (get-register-list vm)) 118 (let ((isn (get-memory vm (get-register vm 'PC)))) 119 (format T "~&Current instruction : ~2,'0x ~a~&" isn (isn-decode isn)))) 120 121 (defun ISN-LOAD (vm address register) 122 (set-register vm register (get-memory vm address))) 123 124 (defun ISN-STORE (vm register address) 125 (set-memory vm address (get-register vm register))) 126 127 (defun ISN-MOVE (vm reg1 reg2) 128 (set-register vm reg2 (get-register vm reg1))) 129 130 (defun ISN--OP- (vm op reg1 reg2) 131 (set-register vm reg2 (funcall op 132 (get-register vm reg2) 133 (get-register vm reg1)))) 134 135 (defun ISN-ADD (vm reg1 reg2) (ISN--OP- vm #'+ reg1 reg2)) 136 (defun ISN-SUB (vm reg1 reg2) (ISN--OP- vm #'- reg1 reg2)) 137 (defun ISN-MULT (vm reg1 reg2) (ISN--OP- vm #'* reg1 reg2)) 138 (defun ISN-DIV (vm reg1 reg2) (ISN--OP- vm #'/ reg1 reg2)) 139 140 (defun ISN-INCR (vm register) 141 (set-register vm register (+ (get-register vm register) 1))) 142 143 (defun ISN-DECR (vm register) 144 (set-register vm register (- (get-register vm register) 1))) 145 146 (defun ISN-PUSH (vm register) 147 (ISN-INCR vm 'SP) 148 (ISN-STORE vm register (get-register vm 'SP))) 149 150 (defun ISN-POP (vm register) 151 (ISN-LOAD vm (get-register vm 'SP) register) 152 (ISN-DECR vm 'SP)) 153 154 (defun ISN-JMP (vm dst) 155 (set-register vm 'PC (- dst 1))) 156 157 (defun ISN-JSR (vm dst) 158 (ISN-PUSH vm 'PC) 159 (ISN-JMP vm dst)) 160 161 (defun ISN-RTN (vm) 162 (ISN-POP vm 'PC)) 163 164 (defun ISN-CMP (vm reg1 reg2) 165 (set-register vm 'EQ (= (get-register vm reg1) (get-register vm reg2))) 166 (set-register vm 'PP (< (get-register vm reg1) (get-register vm reg2))) 167 (set-register vm 'PG (> (get-register vm reg1) (get-register vm reg2)))) 168 169 (defun ISN--JCOND- (pp eq pg vm dst) 170 (if (or (and eq (get-register vm 'EQ)) 171 (and pg (get-register vm 'PG)) 172 (and pp (get-register vm 'PP))) 173 (ISN-JMP vm dst))) 174 175 (defun ISN-JEQ (vm dst) 176 (ISN--JCOND- nil t nil vm dst)) 177 178 (defun ISN-JPG (vm dst) 179 (ISN--JCOND- nil nil t vm dst)) 180 181 (defun ISN-JPP (vm dst) 182 (ISN--JCOND- t nil nil vm dst)) 183 184 (defun ISN-JPE (vm dst) 185 (ISN--JCOND- t t nil vm dst)) 186 187 (defun ISN-JGE (vm dst) 188 (ISN--JCOND- nil t t vm dst)) 189 190 (defun ISN-JNE (vm dst) 191 (ISN--JCOND- t nil t vm dst)) 192 193 (defun ISN-NOP (vm) 194 vm) 195 196 (defun ISN-HALT (vm) 197 (set-register vm 'HALT t)) 198 199 200 ;;Test Unitaire 201 ;; TODO : Faire deftestvar 202 ;; TODO : Finir le test unitaire 203 (require 'test-unitaire "test-unitaire") 204 (erase-tests virtual-machine) 205 (deftestvar virtual-machine t-r0-value (+ 1 (random-test 42))) ;; r0 > 0 pour la division. 206 (deftestvar virtual-machine t-r1-value (random-test 42)) 207 (deftestvar virtual-machine t-m-value (random-test 42)) 208 (deftestvar virtual-machine t-vm-size (+ 10 (random-test 10))) 209 (deftestvar virtual-machine t-address (random-test t-vm-size)) 210 (deftestvar virtual-machine vm 211 (let ((vm (make-vm t-vm-size))) 212 (set-register vm 'R0 t-r0-value) 213 (set-register vm 'R1 t-r1-value) 214 (set-memory vm t-address t-m-value) 215 vm)) 216 217 (deftest virtual-machine 218 (progn (ISN-LOAD vm t-address 'R0) 219 (get-register vm 'R0)) 220 t-m-value) 221 222 (deftest virtual-machine 223 (progn (ISN-STORE vm 'R0 t-address) 224 (get-memory vm t-address)) 225 t-r0-value) 226 227 (deftest virtual-machine 228 (progn (ISN-MOVE vm 'R0 'R1) 229 (get-register vm 'R1)) 230 t-r0-value) 231 232 (deftest virtual-machine 233 (progn (ISN-ADD vm 'R0 'R1) 234 (get-register vm 'R1)) 235 (+ t-r1-value t-r0-value)) 236 237 (deftest virtual-machine 238 (progn (ISN-SUB vm 'R0 'R1) 239 (get-register vm 'R1)) 240 (- t-r1-value t-r0-value)) 241 242 (deftest virtual-machine 243 (progn 244 ;; Multiplication par un petit nombre (on ne 245 ;; gère pas d'éventuels overflows pour l'instant). 246 (set-register vm 'R0 2) 247 (ISN-MULT vm 'R0 'R1) 248 (get-register vm 'R1)) 249 (* 2 t-r1-value)) 250 251 (deftest virtual-machine 252 (progn (ISN-DIV vm 'R0 'R1) ;; R0 > 0 (voir t-r0-value ci-dessus). 253 (get-register vm 'R1)) 254 (/ t-r1-value t-r0-value)) 255 256 (deftest virtual-machine 257 (progn (ISN-INCR vm 'R1) 258 (get-register vm 'R1)) 259 (+ t-r1-value 1)) 260 261 (deftest virtual-machine 262 (progn (ISN-DECR vm 'R0) ;; R0 > 0 (on ne gère pas les négatifs) 263 (get-register vm 'R0)) 264 (- t-r0-value 1)) 265 266 (deftest virtual-machine 267 (progn (ISN-PUSH vm 'R1) 268 (get-memory vm (get-register vm 'SP))) 269 t-r1-value) 270 271 (provide 'vm)