; .EnTete "Le←Lisp version 15.2" " " "Le chargeur me'moire NS 32032" ; .sp 2 ; .SuperTitre "Le Chargeur Me'moire NS" ; .Auteur "Francis Dupont" ; .INRIA ; $Header: lapns.ll,v 4.1 88/01/13 12:21:03 kuczynsk Rel $ ; Assemble et charge pour un NS 32032 une liste d'instructions LLM3 ; en 1 seule passe et avec du code relogeable. (unless (= (version) 15.2) (error 'load 'erricf 'lapns)) (defvar #:sys-package:colon 'ldns) (add-feature 'loader) ; .Section "Strate'gie de la re'solution des e'tiquettes" ; 1 - les e'tiquettes locales a` une fonction ; 2 - les e'tiquettes locales a` un module ; 3 - les e'tiquettes globales a` tout le syste`me Le←Lisp ; Ce chargeur est capable de produire du code relogeable, ce qui va ; permettre de compacter la zone code. ; .SSection "Les e'tiquettes locales a` une fonction (LOCAL)" ; Une e'tiquette nume'rique est toujours de type LOCAL. Ce trait est ; utilise' par le compilateur pour engendrer des e'tiquettes a` peu de frais. ; Une e'tiquette symbolique locale doit e↑tre de'clare'e avant sa premie`re ; utilisation au moyen de la pseudo LOCAL. Cette de'claration permet ; d'e'viter des conflits de noms, mais le compilateur n'utilise jamais ; ce trait. ; Toute re'fe'rence a` ce type d'e'tiquette engendre un de'placement ; par rapport au PC (de 8 ou de 16 bits). ; Ces e'tiquettes doivent e↑tre re'solues a` la fin ; de la liste des instructions ou a` l'apparition de la pseudo ENDL. ; Si elles ne le sont pas, le chargeur de'clenche une erreur. ; .SSection "Les e'tiquettes locales a` un module" ; Les e'tiquettes de ce type, toujours symboliques, ne sont pas de'clare'es. ; Elles sont de'finies au moyen de la pseudo ENTRY. ; Elles peuvent ne pas e↑tre re'solues entre deux appels du chargeur mais ; doivent l'e↑tre a` l'apparition de la pseudo END. ; Si elles ne le sont pas, le chargeur de'clenche une erreur. ; Ces e'tiquettes sont dans un des 2 e'tats suivants : ; 1 - elles ne sont pas de'finies : leur nom est dans la A-liste ; :entries-not-resolved qui contient en valeur la liste des adresses ; ou` il faudra charger la ve'ritable adresse quand elle apparaitra. ; Ces de'placements sont sur 16 bits actuellement! ; ?!?!? Que se passe-il avec des modules limite's a` 8k ?!?!? ; ?!?!? Y a t il beaucoup de gens que cela generait ?!?!? ; 2 - elles viennent d'apparai↑tre (ENTRY). Il n'y a plus qu'un seul ; indicateur :fval qui contient la ve'ritable adresse. ; De plus le symbole est enleve' de :entries-not-resolved et est ajoute' ; dans la liste :entry-list. ; 3 - le END survient, toutes ces e'tiquettes sont de'truites ; de la liste :entry-list, les indicateurs :fval sont de'truits. ; S'il reste des noms dans :entries-not-resolved une erreur est ; de'clenche'e. Rien ne reste donc de propre au chargeur, ces ; e'tiquettes sont des candidats de choix pour le prochain GC. ; .SSection "Les e'tiquettes globales" ; Les e'tiquettes de ce type, toujours symboliques, ne sont utilise'es ; qu'avec les instructions JCALL et JMP. ; Elles sont de'finies au moyen de la pseudo FENTRY qui charge, de`s ; cette de'finition, la FVAL/FTYPE de cette fonction. ; Elles peuvent ne pas e↑tre re'solues entre deux appels du chargeur ; qui ne s'en appercoit jamais car il engendre toujours un acce`s ; correspondant a` (FVAL 'symb), ce qui permet en plus de les rede'finir ; et de les recompiler (i.e. si je recharge le module pretty avec pprint ; comme externe, tous les autres modules continueront a` fonctionner ; avec ce nouveau module). ; Les noms des fonctions standard sont des e'tiquettes globales. ; .bp ;.Section "Les variables globales du chargeur" ; .SSection "Les indicateurs conditionnels du chargeur" (defvar :31bitfloats (eq 0. 0.)) ; les nbs flottants sur 31 bits ; (utile pour rendre les floats non litteraux) (defvar :stopcopy (typefn '#:ld:gcafter-daemon)) ; pour le Stop & Copy (defvar #:ld:special-case-loader ()) ; cas spe'cial pour charger le chargeur (defvar #:ld:shared-strings ()) ; rend les constantes de chai↑ne EQ ; .SSection "Les autres variables globales" ; adresse du de'but des flottants (unless (boundp ':bfloat) (defvar :bfloat (getglobal "bfloat"))) ; adresse du de'but des vecteurs (unless (boundp ':bvect) (defvar :bvect (getglobal "bvect"))) ; adresse du de'but des chai↑nes (unless (boundp ':bstrg) (defvar :bstrg (getglobal "bstrg"))) ; adresse du de'but des variables (unless (boundp ':bvar) (defvar :bvar (getglobal "bvar"))) (defvar :Ecode ; fin de la zone code. (subadr (#:system:ecode) 64)) (defvar :locnil (loc ())) ; adresse du symbole () (defvar :entry-list ()) ; liste des points d'entre'e locaux (defvar :entries-not-resolved ()) ; A-liste des ENTRIES non re'solus (unless (boundp ':module) ; Le nom du module en cours de charg. (defvar :module ())) (unless (boundp ':saved-by-loader) ; liste des litte'raux entre 2 ENDs. (defvar :saved-by-loader ())) (unless (boundp ':global-saved-by-loader) ; liste de vecteurs de litte'raux. (defvar :global-saved-by-loader '( ; Ces variables ne sont pas sauve'es par :clean-litt (dynamique). #[:lobj :talkp :pccurrent :llabels :llabels-nr :fntname :codop :arg1 :arg2 :arg3 :valaux :f :nwl obj]))) (unless (boundp '#:ld:cons-llitt) (defvar #:ld:cons-llitt ())) (unless (boundp ':local-cons-llitt) (defvar :local-cons-llitt ())) ; .Section "Interpre'tation d'un objet" (de :ins (obj) ; charge un objet (instruction ou pseudo) en me'moire (when :talkp (if (consp obj) (outpos 4)) (prin obj) (when (>= (outpos) 30) (terpri)) (outpos 30) (:prinhex :PCcurrent) (prin " ")) (cond ((null obj) ()) ((atom obj) ; une e'tiquette locale (symbole ou nb) : ; on la rajoute dans :llabels (newl :llabels (cons obj (copylist :PCcurrent))) ; re'solution des re'fe'rences avants (relatives) (mapc (lambda (l) (selectq (car l) (8 ; c'est une r.n.r. relative sur 8 bits (:1byterelPC (cdr l))) (16 ; c'est une r.n.r. relative sur 16 bits (:1wordrelPC (cdr l))) (32 ; c'est une r.n.r relative sur 32 bits (:1doublerelPC (cdr l))) (0 ; c'est une r.n.r absolue sur 32 bits (:1doublePC (cdr l))) (t ; c'est pour un BRX (:1wordrel (car l) (cdr l))))) (cassq obj :llabels-nr)) (setq :llabels-nr (delete (assq obj :llabels-nr) :llabels-nr))) (t (setq :codop (car obj) :arg1 (cadr obj) :arg2 (caddr obj) :arg3 (cadddr obj)) (selectq :codop ; ; les pseudos-instructions (par ordre alphabe'tique) ; (ABORT) ; Pour re'cupe'rer de la me'moire en cas scraschhhh. (ENTRY ; (ENTRY <name> <ftype> <lparam>) (:align) ; charge les indicateurs (newl :entry-list (list :arg1 (if (memq :arg2 '(SUBR0 SUBR1 SUBR2 SUBR3 NSUBR FSUBR MSUBR DMSUBR)) :arg2 (:error "ENTRY" obj)) :arg3)) ; re'solution des re'fe'rences avants. (mapc (lambda (l) (selectq (car l) (16 ; c'est une r.n.r. relative sur 16 bits (:1wordrelPC (cdr l))) (32 ; c'est une r.n.r. relative sur 32 bits (:1doublerelPC (cdr l))) (0 ; c'est une r.n.r. absolue sur 32 bits (:1doublePC (cdr l))) (t ; c'est pour un BRX (:1wordrel (car l) (cdr l))))) (cassq :arg1 :entries-not-resolved)) (setq :entries-not-resolved (delete (assq :arg1 :entries-not-resolved) :entries-not-resolved)) (putprop :arg1 (copylist :PCcurrent) ':fval) (setq :fntname :arg1)) (ENDL ; fin d'une fonction locale (when :talkp (terpri)) (when :llabels-nr (:error "Il reste des references locales non resolues " :llabels-nr))) (END ; fin d'un module ; ve'rification de l'entry-list (:ins '(ENDL)) (when :entries-not-resolved (:error "Il reste des ENTRY non resolus " :entries-not-resolved)) (while :entry-list (remprop (caar :entry-list) ':fval) (remprop (caar :entry-list) '#:llcp:ftype) (remprop (caar :entry-list) '#:llcp:fval) (remprop (caar :entry-list) '#:system:loaded-from-file) (nextl :entry-list)) (when #:ld:special-case-loader (while (and (consp #:ld:special-case-loader) (consp (car #:ld:special-case-loader))) (if (and :stopcopy (typefn ':patch-cons-llitt)) (:patch-cons-llitt)) (remprop (caar #:ld:special-case-loader) ':fval ) (remprop (caar #:ld:special-case-loader) '#:llcp:ftype ) (remprop (caar #:ld:special-case-loader) '#:llcp:fval ) (remprop (caar #:ld:special-case-loader) '#:system:loaded-from-file ) (apply 'setfn (nextl #:ld:special-case-loader)))) (:clean-llitt)) (EVAL ; (EVAL s) e'valuation a` LOAD-TIME (catcherror t (eval :arg1))) (FENTRY ; (FENTRY <name> <ftype> <lparam>) (:align) ; enle`ve les indicateurs (a` ve'rifier ?!?!?) (remprop :arg1 '#:system:loaded-from-file) (setq :valaux :PCcurrent) (if #:ld:special-case-loader (newl #:ld:special-case-loader (list :arg1 :arg2 (copylist :valaux))) (remprop :arg1 '#:llcp:ftype) (remprop :arg1 '#:llcp:fval) (setfn :arg1 :arg2 :valaux)) (newl :llabels (cons :arg1 (copylist :PCcurrent))) (setq :fntname :arg1)) (LOCAL ; (LOCAL <name>) ; rend le symbole local a` une fonction. (newl :llabels (ncons :arg1))) (TITLE ; (TITLE de'finition du nom du module) (setq :module :arg1)) ; appel de la partie de'pendante des machines! ; :machins contient le ge'ne'rateur d'instructions. ; (t (:machins)))))) (de :machins () ; re'alise le chargement de l'instruction <obj>. Fonctionne dans ; le me↑me environnement que la fonction pre'ce'dente : obj :codop ..... (selectq :codop ; ; A tout seigneur tout honneur : l'instruction la plus utilise'e ; (MOV ; (MOV source dest) (cond ((and (consp :arg1) (eq (car :arg1) '@)) (:opnsn #$27 #$A8) ; addr src,r0 / movd r0,dst (:opns-pos-depl :arg1) (:opns-dst #$17 #$00 :arg2)) ((and (consp :arg1) (eq (car :arg1) 'QUOTE) (cadr :arg1) (symbolp (cadr :arg1))) (:opnsn #$27 #$68) ; addr n(r5),r0 / movd r0,dst (:opnsquotesymb (cadr :arg1)) (:opns-dst #$17 #$00 :arg2)) (t (:opns-src-dst #$17 #$00 :arg1 :arg2)))) ; movd src,dst ; ; Les instructions de contro↑le ; (BRA ; (BRA <lab>) == br lab (:opns-branch #$EA :arg1)) (BRI ; (BRI <op>) == movd op,r0 / jump 0(r0) (:1byte #$17) (:opns-src #$00 :arg1 ()) (:opnsn #$7F #$42 #$00)) (BRX ; (BRX (<lab1> <lab2> ... <labn>) <index>) (unless (:register :arg2) (:1byte #$17) ; movd index,r0 (:opns-src #$00 :arg2 ())) (let ((pc (copylist :PCcurrent))) (:opnsn #$7D #$EF) ; casew *+4[r0:w] (:1byte (selectq :arg2 (A1 #$D9) (A2 #$DA) (A3 #$DB) (A4 #$DC) (t #$D8))) (:1byte #$04) (mapc ':opns-brx (cirlist pc) :arg1))) (CALL ; (CALL etiq) == bsr etiq (:opns-branch #$02 :arg1)) (JCALL ; (JCALL <sym>) == jsr (FVAL :arg1) (:opnsfvalq :codop :arg1)) ; jsr 0(n(r5)) (JMP ; (JMP <sym>) == jump (FVAL <sym>) (:opnsfvalq :codop :arg1)) ; jump 0(n(r5)) (RETURN ; (RETURN) == ret 0 (:opnsn #$12 #$00)) (SOBGEZ ; (SOBGEZ op lab) addqw -1,op / cmpqw 0,op / ble lab (:1byte #$8D) (:opns-src #$07 :arg1 ()) (:1byte #$1D) (:opns-src #$00 :arg1 ()) (:opns-branch #$7A :arg2)) ; ; les instructions sur la pile de donne'e ; (POP ; (POP <op>) == movd tos,op (ifn (and (consp :arg1) (eq (car :arg1) '&)) (:opns-dst #$17 #$B8 :arg1) ; le cas vicieux du (pop (& <n>)) (:opnsn #$57 #$BE) (:opns-depl (mul 4 (add1 (cadr :arg1)))))) (PUSH ; (PUSH <op>) (cond ((and (consp :arg1) (eq (car :arg1) '@)) (:opnsn #$E7 #$AD) ; addr src,tos (:opns-pos-depl :arg1)) ((and (consp :arg1) (eq (car :arg1) 'QUOTE) (cadr :arg1) (symbolp (cadr :arg1))) (:opnsn #$E7 #$6D) ; addr n(r5),tos (:opnsquotesymb (cadr :arg1))) (t (:1byte #$D7) ; movd src,tos (:opns-src #$05 :arg1 ())))) (SSTACK ; (SSTACK <op>) lprd sp,op (:1byte #$EF) (:opns-src #$04 :arg1 ())) (STACK ; (STACK <op>) == sprd sp,op (:1byte #$AF) (:opns-src #$04 :arg1 ())) (XSPMOV ; (XSPMOV depl val) (cond ((:fixp :arg1) (:opnsn #$17 #$C8) ; movd n(sp),r0 (:opns-pos-depl (mul 4 (cadr :arg1)))) (t (:1byte #$17) ; movd depl,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$17 #$F0 #$C8 #$00))) ; movd 0(sp)[r0:d],r0 (:opns-dst #$17 #$00 :arg2)) ; movd r0,val ; ; les tests de type ; (BTNIL ; (BTNIL op lab) == cmpd op,r5 / beq lab (:1byte #$47) (:opns-src #$01 :arg1 ()) (:opns-branch #$0A :arg2)) (BFNIL ; (BFNIL op lab) == cmpd op,r5 / bne lab (:1byte #$47) (:opns-src #$01 :arg1 ()) (:opns-branch #$1A :arg2)) (BTCONS ; (BTCONS op lab) == cmpd op,r6 / bge lab (:1byte #$87) (:opns-src #$01 :arg1 ()) (:opns-branch #$DA :arg2)) (BFCONS ; (BFCONS op lab) == cmpd op,r6 / blt lab (:1byte #$87) (:opns-src #$01 :arg1 ()) (:opns-branch #$CA :arg2)) (BTFIX ; (BTFIX op1 lab) == movd op,r0 / cmpd bfloat,r0 / bhi lab (:1byte #$17) (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) (:opns-pos-depl :bfloat) (:opns-branch #$4A :arg2)) (BFFIX ; (BFFIX op1 lab) == movd op,r0 / cmpd bfloat,r0 / bls lab (:1byte #$17) (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) (:opns-pos-depl :bfloat) (:opns-branch #$5A :arg2)) (BTFLOAT ; (BTFLOAT op1 lab) (ifn :31bitfloats (:brt2 :bfloat :bvect) (:1byte #$1F) ; cmpqd 0,op1 (:opns-src #$00 :arg1 ()) (:opns-branch #$6A :arg2))) ; bgt lab (BFFLOAT ; (BFFLOAT op1 lab) (ifn :31bitfloats (:brf2 :bfloat :bvect) (:1byte #$1F) ; cmpqd 0,op1 (:opns-src #$00 :arg1 ()) (:opns-branch #$7A :arg2))) ; ble lab (BTSTRG ; (BTSTRG op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd bstrg,r0 (:opns-pos-depl :bstrg) (:1byte #$4A) ; bhi end (let ((pc (copy :PCcurrent))) (:1byte #$00) ; sera resolu a la fin (:opnsn #$47 #$01) ; cmpd r0,r5 (:opns-branch #$AA :arg2) ; blo lab (memory pc (add1 (subadr :PCcurrent pc))))) (BFSTRG ; (BFSTRG op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd bstrg,r0 (:opns-pos-depl :bstrg) (:opns-branch #$4A :arg2) ; bhi lab (:opnsn #$47 #$01) ; cmpd r0,r5 (:opns-branch #$BA :arg2)) ; bhs lab (BTVECT ; (BTVECT op1 lab) (:brt2 :bvect :bstrg)) (BFVECT ; (BFVECT op1 lab) (:brf2 :bvect :bstrg)) (BTSYMB ; (BTSYMB op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$47 #$01) ; cmpd r0,r5 (:1byte #$AA) ; blo end (let ((pc (copy :PCcurrent))) (:1byte #$00) ; sera resolu a la fin (:opnsn #$87 #$01) ; cmpd r0,r6 (:opns-branch #$AA :arg2) ; blo lab (memory pc (add1 (subadr :PCcurrent pc))))) (BFSYMB ; (BFSYMB op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$47 #$01) ; cmpd r0,r5 (:opns-branch #$AA :arg2) ; blo lab (:opnsn #$87 #$01) ; cmpd r0,r6 (:opns-branch #$BA :arg2)) ; bhs lab (BTVAR ; (BTVAR op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd bvar,r0 (:opns-pos-depl :bvar) (:1byte #$4A) ; bhi end (let ((pc (copy :PCcurrent))) (:1byte #$00) ; sera resolu a la fin (:opnsn #$87 #$01) ; cmpd op,r6 (:opns-branch #$AA :arg2) ; blo lab (memory pc (add1 (subadr :PCcurrent pc))))) (BFVAR ; (BFVAR op1 lab) (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd bvar,r0 (:opns-pos-depl :bvar) (:opns-branch #$4A :arg2) ; bhi lab (:opnsn #$87 #$01) ; cmpd r0,r6 (:opns-branch #$BA :arg2)) ; bhs lab (CABEQ ; (CABEQ op1 op2 lab) == cmpd op1,op2 / beq lab (:opns-src-dst #$07 #$00 :arg1 :arg2) (:opns-branch #$0A :arg3)) (CABNE ; (CABNE op1 op2 lab) == cmpd op1,op2 / bne lab (:opns-src-dst #$07 #$00 :arg1 :arg2) (:opns-branch #$1A :arg3)) ; ; Les autres instructions (par ordre alpha) ; (ADJSTK ; (ADJSTK 'nb) (if (:fixp :arg1) (cond ((eq (cadr :arg1) 0)) ((and (ge (cadr :arg1) -32) (lt (cadr :arg1) 32)) (:opnsn #$7C #$A5) ; adjspb n (:1byte (sub 0 (mul 4 (cadr :arg1))))) (t (:opnsn #$7D #$A5) ; adjspw n (:1word (sub 0 (mul 4 (cadr :arg1)))))) (:opnsn #$CE #$1D) ; movxwd nb,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$4E #$23 #$00) ; negd r0,r0 (:opnsn #$4E #$17 #$A0 #$02) ; lshd 2,r0 (:opnsn #$7F #$05))) ; adjspd r0 (CAR ; (CAR A1/A2/A3/A4) == MOV 0(Ax),Ax ?!?!? obsolete (:ins `(MOV (CAR ,:arg1) ,:arg1))) (CDR ; (CDR A1/A2/A3/A4) == MOV 4(Ax),Ax ?!?!? obsolete (:ins `(MOV (CDR ,:arg1) ,:arg1))) (HBMOVX ; (HBMOVX val string index) val -> string[index] (:adrheap-r7 :arg2) ; r7 <- adr heap de arg2 (cond ((:fixp :arg3) (:1byte #$17) ; movd val,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$D4 #$03) ; movb r0,n(r7) (:opns-pos-depl (cadr :arg3))) (t (:opnsn #$17) ; movd depl,r0 (:opns-src #$00 :arg3 ()) (:1byte #$14) ; movb val,0(r7)[r0:b] (:opns-src #$07 :arg1 #$78) (:1byte #$00)))) (HBXMOV ; (HBXMOV string index dest) string[index] -> dest (:adrheap-r7 :arg1) ; r7 <- adr heap de arg2 (cond ((:fixp :arg2) (:opnsn #$14 #$78) ; movb n(r7),r0 (:opns-pos-depl (cadr :arg2))) (t (:1byte #$17) ; movd index,r0 (:opns-src #$00 :arg2 ()) (:opnsn #$14 #$E0 #$78 #$00))) ; movb 0(r7)[r0:b],r0 (:1byte #$CE) (:opns-dst #$18 #$00 :arg3)) ; movzbd r0,dest (HGSIZE ; (HGSIZE vector/string arg2) (:adrind-r0 :arg1) ; r0 <- adr ind de arg1 (:opnsn #$17 #$40 #$04) ; movd 4(r0),r0 (:opns-dst #$17 #$00 :arg2)) ; movd r0,dst (HPMOVX ; (HPMOVX val vector index) (:adrheap-r7 :arg2) ; r7 <- adr heap de arg2 (cond ((:fixp :arg3) (:1byte #$17) ; movd val,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$D7 #$03) ; movd r0,n(r7) (:opns-pos-depl (mul 4 (cadr :arg3)))) (t (:1byte #$17) ; movd depl,r0 (:opns-src #$00 :arg3 ()) (:1byte #$97) ; movd val,0(r7)[r0:d] (:opns-src #$07 :arg1 #$78) (:1byte #$00)))) (HPXMOV ; (HPXMOV vector index val) (:adrheap-r7 :arg1) ; r7 <- adr heap de arg2 (cond ((:fixp :arg2) (:opnsn #$17 #$78) ; movd n(r7),r0 (:opns-pos-depl (mul 4 (cadr :arg2)))) (t (:1byte #$17) ; movd index,r0 (:opns-src #$00 :arg2 ()) (:opnsn #$17 #$F0 #$78 #$00))) ; movd 0(r7)[r0:d],r0 (:opns-dst #$17 #$00 :arg3)) ; movd r0,val (MOVXSP ; (MOVXSP val depl) (:1byte #$D7) ; movd val,r7 (:opns-src #$01 :arg1 ()) (cond ((:fixp :arg2) (:opnsn #$57 #$3E) ; movd r7,n(sp) (:opns-pos-depl (mul 4 (cadr :arg2)))) (t (:1byte #$17) ; movd depl,r0 (:opns-src #$00 :arg2 ()) (:opnsn #$97 #$3F #$C8 #$00)))) ; movd r7,0(sp)[r0:d] (NOP ; (NOP) ne fait rien mais perd du temps et de la place (:1byte #$A2)) (XTOPST ; (XTOPST :arg1) echange du sommet de pile avec :arg1 (:opnsn #$17 #$B8) ; movd tos,r0 (:1byte #$D7) ; movd arg,tos (:opns-src #$05 :arg1 ()) (:opns-dst #$17 #$00 :arg1)) ; movd r0,arg ; ; Les comparaisons arithme'tiques entieres. cmpw op1 op2 / bnxx lab ; (CNBEQ ; (CNBEQ op1 op2 lab) (:cnbxx #$0A)) (CNBNE ; (CNBNE op1 op2 lab) (:cnbxx #$1A)) (CNBLT ; (CNBLT op1 op2 lab) (:cnbxx #$CA)) (CNBLE ; (CNBLE op1 op2 lab) (:cnbxx #$7A)) (CNBGT ; (CNBGT op1 op2 lab) (:cnbxx #$6A)) (CNBGE ; (CNBGE op1 op2 lab) (:cnbxx #$DA)) ; ; Les comparaisons arithme'tiques flottantes. ; (CFBEQ ; (CFBEQ op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:feqn :arg3) (:cfbxx #$0A))) (CFBNE ; (CFBNE op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:fneqn :arg3) (:cfbxx #$1A))) (CFBLT ; (CFBLT op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:flt :arg3) (:cfbxx #$CA))) (CFBLE ; (CFBLE op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:fle :arg3) (:cfbxx #$7A))) (CFBGT ; (CFBGT op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:fgt :arg3) (:cfbxx #$6A))) (CFBGE ; (CFBGE op1 op2 lab) (if :31bitfloats (:generatecall2subr '#:llcp:fge :arg3) (:cfbxx #$DA))) ; ; Les instructions arithme'tiques (par ordre alpha) ; (DECR ; (DECR op) == addqw -1,op (:1byte #$8D) (:opns-src #$07 :arg1 ())) (DIFF ; (DIFF op1 op2) == subw op1 op2 ; op2 - op1 -> op2 (:opns-arith #$21 #$00 :arg1 :arg2)) (INCR ; (INCR op) == addqw 1,op (:1byte #$8D) (:opns-src #$00 :arg1 ())) (LAND ; (LAND op1 op2) == andw op1,op2 (:opns-arith #$29 #$00 :arg1 :arg2)) (LOR ; (LOR op1 op2) == orw op1 op2 (:opns-arith #$19 #$00 :arg1 :arg2)) (LXOR ; (LXOR op1 op2) == xorw op1 op2 (:opns-arith #$39 #$00 :arg1 :arg2)) (LSHIFT ; (LSHIFT circ op) == lshw circ,op (:1byte #$4E) (ifn (:fixp :arg1) (:opns-arith #$15 #$00 :arg1 :arg2) (ifn (:register :arg2) (:error "LSHIFT" :arg2)) (:opns-dst #$15 #$A0 :arg2) (:1byte (logand #$FF (cadr :arg1))))) (NEGATE ; (NEGATE op) == negw op,op (:1byte #$4E) (:opns-arith #$21 #$00 :arg1 :arg1)) (PLUS ; (PLUS op1 op2) == addw op1 op2 (:opns-arith #$01 #$00 :arg1 :arg2)) (REM ; (REM op1 op2) == modw op1,op2 (:1byte #$CE) (:opns-arith #$35 #$00 :arg1 :arg2)) (QUO ; (QUO op1 op2) == divw op1 op2 (:1byte #$CE) (:opns-arith #$31 #$00 :arg1 :arg2)) (TIMES ; (TIMES op1 op2) == mulw op1 op2 (:1byte #$CE) (:opns-arith #$21 #$00 :arg1 :arg2)) ; ; Les instructions arithme'tiques flottantes ; (FPLUS (:macflotop '#:llcp:fadd)) ; (FDIFF (:macflotop '#:llcp:fsub)) ; (FTIMES (:macflotop '#:llcp:fmul)) ; (FQUO (:macflotop '#:llcp:fdiv)) ; ; ; c'est donc une erreur ; (t (if (setq :f (getfn1 'ld-codop (car obj))) (apply :f obj) (:error "MACHINS" obj))))) ;.Section "Les fonctions auxiliaires de ge'ne'ration" (de :register (arg) ; Teste si l'argument est un registre. (memq arg '(A1 A2 A3 A4))) (de :fixp (arg) ; Teste si l'ope'rande est un entier (ou pluto↑t "(QUOTE entier)") ; attention a` la triple e'valuation ... (and (consp arg) (eq (car arg) 'QUOTE) (fixp (cadr arg)))) (de :check8 (n) ; teste si le deplacement <n> tient sur 8 bits (en fait 7) ; Attention a` la tole'rance (de 3 octets de chaque co↑te'). (and (fixp n) (ge n -61) (le n 60) n)) (de :check16 (n) ; teste si le deplacement <n> tient sur 16 bits (en fait 14) ; Attention a` la tole'rance (de 3 octets de chaque co↑te'). (and (fixp n) (ge n -8190) (lt n 8190) n)) (de :adrind-r0 (arg) ; charge dans "r0" l'adresse heap de l'objet "arg" (if (:register arg) (:opnsn #$17 ; movd 0(AX),r0 (selectq arg (A1 #$48) (A2 #$50) (A3 #$58) (A4 #$60)) #$00) (:1byte #$17) ; movd arg,r0 (:opns-src #$00 arg ()) (:opnsn #$17 #$40 #$00))) ; movd 0(r0),r0 (de :adrheap-r7 (arg) ; Charge dans "r7" l'adresse heap sur la premier valeur de "arg" (if (:register arg) (:opnsn #$D7 ; movd 0(AX),r7 (selectq arg (A1 #$49) (A2 #$51) (A3 #$59) (A4 #$61)) #$00) (:1byte #$D7) ; movd arg,r7 (:opns-src #$01 arg ()) (:opnsn #$D7 #$79 #$00)) ; movd 0(r7),r7 (:opnsn #$0F #$3A #$0F #$3A)) ; addqd 4,r7 / addqd 4,r7 (de :brt2 (b1 b2) ; test de type de :arg1 a` 2 bornes : b1, b2 ; branchement a` :arg2 si vrai. (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd b1,r0 (:opns-pos-depl b1) (:1byte #$4A) ; bhi end (let ((pc (copy :PCcurrent))) (:1byte #$00) ; sera resolu a la fin (:opnsn #$07 #$A8) ; cmpd b2,r0 (:opns-pos-depl b2) (:opns-branch #$4A :arg2) ; bhi lab (memory pc (add1 (subadr :PCcurrent pc))))) (de :brf2 (b1 b2) ; test de type a` 2 bornes de :arg1 avec b1 et b2 ; branchement a` :arg2 si faux. (:1byte #$17) ; movd op,r0 (:opns-src #$00 :arg1 ()) (:opnsn #$07 #$A8) ; cmpd b1,r0 (:opns-pos-depl b1) (:opns-branch #$4A :arg2) ; bhi lab (:opnsn #$07 #$A8) ; cmpd b2,r0 (:opns-pos-depl b2) (:opns-branch #$5A :arg2)) ; bls lab (de :cnbxx (op) ; Comparaison nume'rique entie`re. (:opns-arith #$05 #$00 :arg1 :arg2) ; cmpw arg1,arg2 (:opns-branch op :arg3)) (de :cfbxx (op) ; Comparaison nume'rique flottants (:1byte #$17) ; movd arg1,r0 (:opns-src #$00 :arg1 ()) (:1byte #$D7) ; movd arg2,r7 (:opns-src #$01 :arg2 ()) (:opnsn #$BE #$C8 #$43 #$04 #$04) ; cmpl 4(r0),4(r7) (:opns-branch op :arg3)) (de :generatecall2subr (fnt lab) ; engendre un appel a` la fonction #:llcp:"fnt" avec les arguments ; :arg1 :arg2, i.e. :arg2 op :arg1 -> :arg2. ; Avec une pile de la forme suivante : ; ... / :arg2 / adr-ret / :arg1 // ; La valeur de retour remplace :arg2, adr-ret et :arg1 sont de'pile's. ; chargement de la valeur de retour dans :arg2. ; Si lab, branchement a` lab si la valeur retourne'e n'est pas 0 (:1byte #$17) ; movd \1,r0 (:opns-src #$00 :arg1 ()) (let ((:arg2 :arg2)) ; protege arg2 (:ins `(PUSH ,:arg2))) ; movd \2,tos (:opnsn #$D7 #$A5) ; movd imm,tos (:1double (addadr (copylist :PCcurrent) 15)) (:opnsn #$D7 #$05) ; movd r0,tos (:opnsfvalq 'JMP fnt) ; jump fnt (if (and (consp :arg2) (eq (car :arg2) '&)) ; le cas vicieux (setq :arg2 (list '& (add (cadr :arg2) 1)))) (ifn lab (:opns-dst #$17 #$B8 :arg2) ; movd tos,\2 (:opnsn #$17 #$B8 #$1F #$00) ; movd tos,r0 / cmpqd 0,r0 (:opns-branch #$1A lab))) ; bne lab (de :macflotop (fnt) ; ope'ration nume'rique flottante. (:generatecall2subr fnt ())) ;.Section "Les fonctions de chargement des ope'randes" (de :opns-src-dst (b0 b1 src dst) ; charge l'instruction NS b0/b1 avec ces deux operandes (let ((pc1 (car :PCcurrent))(pc2 (cdr :PCcurrent))) (:1byte b0) (:1byte b1) (setq src (:opns src)) (setq dst (:opns dst)) (:1bytePC pc1 pc2 (logor b0 (logand #$FF (logshift dst 6)))) (:1bytePC+ pc1 pc2 (logor b1 (logor (logshift src 3) (logshift dst -2)))))) (de :opns-arith (b0 b1 src dst) ; charge l'instruction NS b0/b1 avec ces deux operandes (let ((pc1 (car :PCcurrent))(pc2 (cdr :PCcurrent))) (:1byte b0) (:1byte b1) (ifn (:fixp src) (setq src (:opns src)) (:1word (cadr src)) (setq src #$14)) (ifn (:fixp dst) (setq dst (:opns dst)) (:1word (cadr dst)) (setq dst #$14)) (:1bytePC pc1 pc2 (logor b0 (logand #$FF (logshift dst 6)))) (:1bytePC+ pc1 pc2 (logor b1 (logor (logshift src 3) (logshift dst -2)))))) (de :opns-src (byte src idst) ; charge l'instruction de deuxieme octet byte avec comme source src (let ((pc1 (car :PCcurrent))(pc2 (cdr :PCcurrent))) (:1byte byte) ; cas ou il y a un octet d'index pour la destination (if idst (:1byte idst)) ; :opns ne genere jamais d'octet d'index (setq src (:opns src)) (:1bytePC pc1 pc2 (logor byte (logshift src 3))))) (de :opns-dst (b0 b1 dst) ; charge l'instruction NS b0/b1 avec comme destination dst (let ((pc1 (car :PCcurrent))(pc2 (cdr :PCcurrent))) (:1byte b0) (:1byte b1) (setq dst (:opns dst)) (:1bytePC pc1 pc2 (logor b0 (logand #$FF (logshift dst 6)))) (:1bytePC+ pc1 pc2 (logor b1 (logshift dst -2))))) ; .SSection "L'ope'rande NS ge'ne'rique" (de :opns (op) ; charge l'ope'rande NS <op> (cond ((eq op 'nil) ; ope'rande nil (en fait ||) #$05) ((eq op 'A1) ; accu Le←Lisp #$01) ((eq op 'A2) ; accu Le←Lisp #$02) ((eq op 'A3) ; accu Le←Lisp #$03) ((eq op 'A4) ; accu Le←Lisp #$04) ((memq op '(LLINK DLINK ITCOUNT)) (:opns-pos-depl (symeval (symbol 'llcp op))) #$15) ((memq op '(CBINDN TAG LOCK PROT)) (:1double (symeval (symbol 'llcp op))) #$14) ((atom op) ; ne doit jamais arriver pour le compilo ; sauf en cas de nouvelles de'finitions. (if (and (symbolp op) (setq :f (getfn1 'ld-dir op))) (funcall :f op) (:error "OPNS" op))) ((eq (car op) 'quote) ; une constante lisp imme'diate (if (and (null (cadr op)) (null (cddr op))) ; c'est en fait l'ope'rande nil (ou ||) #$05 (unless (or (fixp (cadr op)) (and :31bitfloats (floatp (cadr op)))) ; c'est un litte'ral a` sauver (if (stringp (cadr op)) (:add-llitts op) (if (and :stopcopy (consp (cadr op))) (:add-cons-llitt (cadr op) :PCcurrent) (:add-llitt (cadr op))))) (:1double (loc (cadr op))) #$14)) ((eq (car op) '@) ; une constante adresse me'moire code machine ; <lab> est touours une e'tiquette locale; ; engendre TOUJOURS un de'placement par rapport au PC. ; dans le cas du VAX doit e↑tre un de'placement 32 bits... ; Les cas utilis'es par le compilateur sont : ; MOV, PUSH et BRX qui sont traite's directement. ; ?!?! a` terminer ?!?! (:error "OPNS@" op)) ((eq (car op) '&) ; (& <n>) Le nie`me pointeur de la pile (if (or (not (fixp (cadr op))) (lt (cadr op) 0)) (:error "OPNS" op) (:opns-pos-depl (mul 4 (cadr op))) #$19)) ((memq (car op) '(CAR VAL CVAL CDR PLIST FVAL PKGC OVAL ALINK PNAME TYP)) ; adressage indirect indexe' (:1byte (selectq (car op) ((car val cval) 0) ((cdr typ plist) 4) (fval 8) (pkgc 12) (oval 16) (alink 20) (pname 28) (t (:error "OPNS" op)))) (selectq (cadr op) (A1 #$09) (A2 #$0A) (A3 #$0B) (A4 #$0C) (t (:error "OPNS" op)))) ((eq (car op) 'CVALQ) ; la C-valeur Lisp d'un symbole (ifn (symbolp (cadr op)) (:error "OPNS" op) (:opnsquotesymb (cadr op)))) ((eq (car op) 'FVALQ) ; la F-valeur Lisp d'un symbole (ifn (symbolp (cadr op)) (:error "OPNS" op) (:opnsquotesymb+8 (cadr op)))) ((eq (car op) 'EVAL) ; Pour calculer des ope'randes a` load time. (or (car (catcherror t (:opns (eval (cadr op))))) (:error "OPNS" op))) (t (if (and (symbolp (car op)) (setq :f (getfn1 'ld-ind (car op)))) (funcall :f op) (:error "OPNS" op))))) ; .SSection "Appel multiple de 1BYTE ou OPNS" (dmd :opnsn l ; appels multiples de :1byte ou :opns `(progn ,@(mapcar (lambda (l) `(:1byte ,l)) l))) ; .SSection "Ope'rande de type adresse de symbole Lisp" (de :opnsquotesymb (symb) ; charge un ope'rande de type "adresse de symbole" ; <symb> est toujours de type symbole. (:add-llitt symb) (setq :valaux (subadr (loc symb) :locnil)) (:opns-pos-depl :valaux) #$0D) (de :opnsquotesymb+8 (symb) ; charge un ope'rande de type "adresse de symbole" + 8 ; <symb> est toujours de type symbole. (:add-llitt symb) (setq :valaux (incradr (subadr (loc symb) :locnil) 8)) (:opns-pos-depl :valaux) #$0D) ; .Section "Gestion des e'tiquettes" ; .SSection "Les e'tiquettes globales (JCALL/JMP)" (de :opnsfvalq (type symb) ; la F-valeur Lisp d'un symbole pour un JCALL/JMP ; type = JMP ou JCALL (:add-llitt symb) ; temporairement (il de'gage avec :clean-llitt) (cond ((and (setq :valaux (cassq symb :llabels)) (:check16 (setq :valaux (subadr :valaux :PCcurrent)))) ; FENTRY si de'ja` de'fini dans le me↑me module et pas loin. ; Un call/jmp relatif sur 16 bits est moins cher que FVALQ (:1byte (if (eq type 'JMP) #$EA #$02)) ; br / bsr (if (:check8 :valaux) ; cas br avec byte displ (:1byte (logand #$7F :valaux)) ; cas br avec word displ (:1word (logor #$8000 (logand #$3FFF :valaux))))) (t ; Etiq globale : direct sur la FVAL ; ca coute une indirection mais fait gagner parfois (pour les ; fonctions standard toujours) 2 octets. ; gain de 6k nets apre`s llcp-std! (:opnsn #$17 #$68) ; movd n(r5),r0 (setq :valaux (subadr (loc symb) :locnil)) (:opns-pos-depl (incradr :valaux 8)) (:1byte #$7F) (:1byte (if (eq type 'JMP) #$42 #$46)) ; jump / jsr 0(r0) (:1byte #$00)))) ; .SSection "Calcul de la valeur d'une e'tiquette qui existe" (de :valadr (adr) ; calcule la valeur d'une adresse, locale a` un module, de type : ; symbole, numb ou constante de type (nh . nl) ; retourne une adresse (h . l) ou bien () si non de'finie (cond ((atom adr) ; e'tiquette symbolique ou nume'rique (cond ((cassq adr :llabels)) ; e'tiquette locale re'solue ((and (symbolp adr) (getprop adr ':fval))) ; les fonctions ENTRY de'ja` charge'es (avant END!) (t ; sinon non de'finie ()))) (t ; les constantes adresses de type (h . l) (if (and (fixp (car adr)) (fixp (cdr adr))) adr (:error "VALADR" adr))))) (de :valadrel (adr) ; retourne un de'placement par rapport a` PC ou () (when (setq adr (:valadr adr)) (subadr adr :PCcurrent))) (de :opns-brx (base adr) ; le cas special pour le BRX (if (and (consp adr) (eq (car adr) '@)) (setq adr (cadr adr)) (:error "OPNS-BRX" adr)) (setq :valaux (:valadr adr)) (if :valaux ; existe deja (ifn (:check16 (setq :valaux (subadr :valaux base))) (:error "BRX too long" adr) (:1byte (logand #$FF :valaux)) (:1byte (logand #$FF (logshift :valaux -8)))) (if (and (symbolp adr) (null (assq adr :llabels))) ; dans les ENTRY (:addentry adr base) ; dans les LOCAL (:addlabel adr base)) (:1word 0))) ; .SSection "Branchements conditionnels locaux" (de :opns-branch (code adr) ; charge le code <code> de branchement conditionnel vers <adr>. ; L'e'tiquette <adr> est toujours locale. (setq :valaux (:valadrel adr)) (cond ((:check8 :valaux) ; branchement arriere sur 8 bits (:1byte code) (:1byte (logand #$7F :valaux))) ((:check16 :valaux) ; branchement arriere sur 16 bits (:1byte code) (:1byte (logor #$80 (logand #$3F (logshift :valaux -8)))) (:1byte (logand #$FF :valaux))) (:valaux ; branchement arriere sur 32 bits (:1byte code) (cond ((consp :valaux) (:1word (logor #$C000 (logand #$3FFF (car :valaux)))) (setq :valaux (cdr :valaux))) ((ge :valaux 0) (:1word #$C000)) (t (:1word #$FFFF))) (:1word :valaux)) ((:notoofar8 adr :lobj) ; branchement avant sur 8 bits (:1byte code) (:addlabel adr 8) (:1byte 0)) ((and (or (fixp adr) (assq adr :llabels)) (:notoofar16 adr :lobj)) ; branchement avant sur 16 bits (:1byte code) (:addlabel adr 16) (:1word 0)) ((and (symbolp adr) (not (assq adr :llabels)) (:notoofar adr :lobj)) ; branchement avant sur 16 bits (:1byte code) (:addentry adr 16) (:1word 0)) (t ; branchement avant sur 32 bits (:1byte code) (if (and (symbolp adr) (null (assq adr :llabels))) ; dans les ENTRY (:addentry adr 32) ; dans les LOCAL (:addlabel adr 32)) (:1double 0)))) ; .Section "Les fonctions auxiliaires de chargement me'moire" (de :opns-depl (val) ; charge le deplacement val (cond ((fixp val) (cond ((and (ge val -64) (lt val 64)) (:1byte (logand #$7F val))) ((and (ge val -8192) (lt val 8192)) (:1word (logor #$8000 (logand #$3FFF val)))) (t (if (ge val 0) (:1word #$C000) (:1word #$FFFF)) (:1word val)))) ((and (consp val) (fixp (car val))) (:1word (logor #$C000 (logand #$3FFF (car val)))) (:1word (cdr val))) ((and (consp val) (eq (car val) '@)) (setq :valaux (:valadr (cadr val))) (if :valaux (:opns-depl :valaux) (if (and (symbolp (cadr val)) (null (assq (cadr val) :llabels))) (:addentry (cadr val) 0) (:addlabel (cadr val) 0)) (:1double 0))) (t (:error "Opns-Depl" val)))) (de :opns-pos-depl (val) ; charge le deplacement positif val (cond ((fixp val) (cond ((and (ge val 0) (lt val 64)) (:1byte (logand #$3F val))) ((and (ge val 0) (lt val 8192)) (:1word (logor #$8000 (logand #$1FFF val)))) (t (:1word #$C000) (:1word val)))) ((and (consp val) (fixp (car val))) (:1word (logor #$C000 (logand #$1FFF (car val)))) (:1word (cdr val))) ((and (consp val) (eq (car val) '@)) (setq :valaux (:valadr (cadr val))) (if :valaux (:opns-pos-depl :valaux) (if (and (symbolp (cadr val)) (null (assq (cadr val) :llabels))) (:addentry (cadr val) 0) (:addlabel (cadr val) 0)) (:1double 0))) (t (:error "Opns-Pos-Depl" val)))) ;.SSection "chargement d'1 octet" (de :1byte (obj) ; charge l'octet obj (when :talkp (when (gt :nwl 10) (setq :nwl 0) (terpri) (outpos 30) (:prinhex :PCcurrent) (prin " ")) (incr :nwl) (prin " ") (:prinhexb obj)) (memory :PCcurrent obj) (incradr :PCcurrent 1)) (de :1bytePC (pc1 pc2 val) ; ne cons pas ! (let ((adr '(0 . 0))) (rplac adr pc1 pc2) (memory adr val))) (de :1bytePC+ (pc1 pc2 val) ; ne cons pas ! (let ((adr '(0 . 0))) (rplac adr pc1 pc2) (incradr adr 1) (memory adr val))) (de :1byterelPC (adr) ; charge le de'placement relatif a` PCcurrent pour l'adresse adr (setq :valaux (incradr (subadr :PCcurrent adr) 1)) (if (or (not (fixp :valaux)) (lt :valaux -64) (ge :valaux 64)) (:error "1byterelPC" :module)) (memory adr (logand #$7F :valaux))) (de :align () ; aligne le compteur de chargement sur une ; frontie`re de mots de 32 bits (merci NS) (until (eq (logand 3 (if (fixp :PCcurrent) :PCcurrent (cdr :PCcurrent))) 0) (:1byte #$A2))) ; charge un NOP! ;.SSection "chargement d'1 seul mot de 16 bits" (de :1word (obj) ; charge 1 mot obj : attention a` l'ordre. (:1byte (logand (logshift obj -8) #$FF)) (:1byte (logand obj #$FF))) (de :1wordrel (base adr) ; charge le de'placement relatif a PCcurrent et base pour adr (setq :valaux (subadr :PCcurrent base)) (if (or (not (fixp :valaux)) (lt :valaux -8192) (ge :valaux 8192)) (:error "Brx trop gros" :module)) (memory adr (logand #$FF :valaux)) (memory (incradr adr 1) (logand #$FF (logshift :valaux -8)))) (de :1wordrelPC (adr) ; charge le de'placement relatif a` PCcurrent pour l'adresse adr (setq :valaux (incradr (subadr :PCcurrent adr) 1)) (if (or (not (fixp :valaux)) (lt :valaux -8192) (ge :valaux 8192)) (:error "Module trop gros" :module)) (memory adr (logor #$80 (logand #$3F (logshift :valaux -8)))) (memory (incradr adr 1) (logand #$FF :valaux))) ; .SSSection "Chargement par paquet de 32 bits" (de :1double (val) ; charge la valeur <val> sur 32 bits (cond ((fixp val) (:1word 0) (:1word val)) ((consp val) (:1word (car val)) (:1word (cdr val))) (t (:error "1DOUBLE" val)))) (de :1doublePC (where) ; charge PCcurrent a where (let ((adr (copylist where))) (memory adr (logor #$C0 (logand #$3F (logshift (car :PCcurrent) -8)))) (incradr adr 1) (memory adr (logand #$FF (car :PCcurrent))) (incradr adr 1) (memory adr (logshift (cdr :PCcurrent) -8)) (incradr adr 1) (memory adr (logand #$FF (cdr :PCcurrent))))) (de :1doublerelPC (adr) ; charge le de'placement relatif a` PCcurrent pour l'adresse adr (setq :valaux (incradr (subadr :PCcurrent adr) 1)) (if (fixp :valaux) (setq :valaux (cons (if (ge :valaux 0) 0 -1) :valaux))) (memory adr (logor #$C0 (logand #$3F (logshift (car :valaux) -8)))) (memory (incradr adr 1) (logand #$FF (car :valaux))) (memory (incradr adr 1) (logand #$FF (logshift (cdr :valaux) -8))) (memory (incradr adr 1) (logand #$FF (cdr :valaux)))) ; .Section "Fonctions de gestion des tables d'e'tiquettes" (defvar :long-ins '(HBMOVX HBXMOV HPMOVX HPXMOV FPLUS FDIFF FTIMES FQUO)) (de :notoofar8 (adr lobj) ; heuristique pour les branchements sur 8 bits (tag ok (let ((count 7)(e)) (while (and (gt count 0) (consp lobj)) (nextl lobj e) (cond ((atom e) (if (eq e adr) (exit ok t))) ((eq (car e) 'BRX) (exit ok ())) ((memq (car e) :long-ins) (setq count (sub count 3))) (t (setq count (sub1 count))))) ()))) (de :notoofar16 (adr lobj) ; heuristique pour les branchements sur 16 bits (tag ok (repeat 500 (when (eq (nextl lobj) adr) (exit ok t))) ())) (de :notoofar (adr lobj) ; heuristique pour les branchements (etiquette symbolique) (tag ok (repeat 500 (nextl lobj :valaux) (if (and (consp :valaux) (eq (car :valaux) 'entry) (eq (cadr :valaux) adr)) (exit ok t))) ())) (de :addlabel (sym depl) ; rajoute le symbole <sym> dans la table des re'fe'rences avants ; locales non re'solues a` l'adresse PCcurrent. ; Avec un deplacement de <depl> (8/16/32) ou 0 pour absolu ; retourne 0 (adresse inconnue) (setq :valaux (assq sym :llabels-nr)) (setq depl (cons depl (copylist :PCcurrent))) (if :valaux (rplacd :valaux (cons depl (cdr :valaux))) (newl :llabels-nr (list sym depl))) 0) (de :addentry (sym depl) ; rajoute le symbole <sym> une dans la table des re'fe'rences avants ; des ENTRY non re'solus a` l'adresse du PCcurrent. ; retourne 0 (adresse inconnue) (setq :valaux (assq sym :entries-not-resolved)) (setq depl (cons depl (copylist :PCcurrent))) (if :valaux (rplacd :valaux (cons depl (cdr :valaux))) (newl :entries-not-resolved (list sym depl))) 0) ; .Section "Gestion de la table des litte'raux" (de :clean-llitt () ; nettoie et sauve la table des litte'raux :saved-by-loader ; dans :global-saved-by-loader sous forme d'un vecteur si ; si il n'y a pas eu de TITLE dans :module sinon. ; ne doit e↑tre fait qu'au END. (let ((l :saved-by-loader) (i -1) v) (while l (if (and (symbolp (car l)) (or (boundp (car l)) (typefn (car l)))) (setq :saved-by-loader (delq (nextl l) :saved-by-loader)) (nextl l))) (when (gt (length :saved-by-loader) 0) (setq v (makevector (length :saved-by-loader) ())) (while :saved-by-loader (vset v (setq i (add i 1)) (nextl :saved-by-loader))) (if :module (putprop :module v ':saved-by-loader) (newl :global-saved-by-loader v))) (setq :module ()) )) (de :add-llitt (obj) ; rajoute un litte'ral a` la table des litte'raux :saved-by-loader (cond ((memq obj :saved-by-loader)) (t (newl :saved-by-loader obj)))) (de :add-llitts (obj) ; rajoute une chai↑ne de caracte`res a` la table des litte'raux ; en essayant de partager les chai↑nes. ; ?!?!?! Cette ide'e d'Ascander est toujours en discussion ?!?!? (let ((s (and #:ld:shared-strings (member (cadr obj) :saved-by-loader)))) (ifn s (newl :saved-by-loader (cadr obj)) (rplaca (cdr obj) (car s))))) (de :add-cons-llitt (c a) (newl :local-cons-llitt (cons (vag a) c))) ; .Section "Fonction d'impression hexa" (de :prinhex (n) ; imprime sur 4 ou 8 chiffres hexa le nb ou l'adresse n (cond ((fixp n) (:prinhexb (logand (logshift n -8) #$FF)) (:prinhexb (logand n #$FF))) ((consp n) (:prinhex (car n)) (:prinhex (cdr n))) (t (error 'memory-dump 'errnna n)))) (de :prinhexb (n) ; imprime sur 2 chiffres hexa le nb n (cond ((not (fixp n)) (error 'memory-dump 'errnna n)) ((lt n 0) (setq n 255)) ((lt n 16) (princn #/0))) (with ((obase 16)) (prin n))) ; .Section "Fonction de debug" (de memory-dump (adr n) ; dump la memoire en hexa de <adr> sur <n> mots ; attention au SWAB du NS! octet de poids faibles a gauche! (setq adr (copy adr)) ; pour le incradr (until (< n 0) (:prinhex adr) (outpos 10) (let ((adr (copylist adr))) (repeat 16 (:prinhexb (memory adr)) (prin " ") (incradr adr 1))) (prin " ") (repeat 16 (if (and (> (memory adr) 32) (< (memory adr) 128)) (princn (memory adr)) (princn #/.)) (incradr adr 1) ) (decr n) (terpri))) ; .Section "Fonction auxiliaire d'erreur" (de :error (f a) ; erreur de type <f> les argments de'fecteux sont dans <a> (terpri) (print "***** LOADER : erreur durant le chargement de : " :fntname) (print " type de l'erreur : " f) (print " arguments de'fecteux : " a) (exit :tagerr)) ;.Section "Fonctions principales de chargement" (de loaderesolve () (loader '((end)))) (de loader (:lobj . :talkp) ; <:lobj> est la liste des objets a` charger ; <:talkp> = T si on de'sire un listage hexa du chargement (when (consp :talkp) ; l'argument est optionnel! (setq :talkp (car :talkp))) (let ((:PCcurrent (#:system:ccode)) ; le compteur ordinal courant (:llabels) ; A-liste des e'tiquettes locales (:llabels-nr) ; A-L. des e'tiq. loc. non re'solues (:fntname 'loader) ; fonction en cours de chargement :codop ; variable globale de travail :arg1 ; itou :arg2 ; itou :arg3 ; itou :valaux ; itou pour des valeurs locales. :f ; itou (pour des getfn1) (:nwl 0) ; itou pour tabler le code produit. :local-cons-llitt) ; les literaux cons locaux ; le re'cupe'rateur d'erreur syste`me (catcherror t ; le re'cupe'rateur des erreurs du chargeur (tag :tagerr ; #:system:ccode ne sera actualise' ; que si tout se passe bien sans erreur (while :lobj (setq :nwl 0) (when (gtadr :PCcurrent :Ecode) (with ((outchan ())) (print ERRFCOD) (exit #:system:toplevel-tag))) (:ins (nextl :lobj)) (when :talkp (terpri))) ; test des re'fe'rences non re'solues (:ins '(ENDL))) ; actualise le nouveau de'but de la zone code (#:system:ccode :PCcurrent) ; actualise les literaux cons (if (and :stopcopy (typefn ':patch-cons-llitt)) (:patch-cons-llitt)) ; actualise #:ld:cons-llitt (setq #:ld:cons-llitt (nconc :local-cons-llitt #:ld:cons-llitt))) ())) ; .Section "Bootstrap" (when (neq (typefn '#:llcp:nlist) 'subr0) ; Les fonctions internes du compilateur (loader '( (fentry #:llcp:nlist subr0) (pop a3) (mov nil a1) (bra 4) 3 (pop a2) (jcall xcons) 4 (sobgez a4 3) (bri a3) (fentry #:llcp:errwna subr2) ; A1 <- fnt; A2 <- bad-nb-arg (mov a2 a3) (mov 'errwna a2) (jmp error) (end) ) () ) (if :stopcopy (loader '( (fentry #:ld:gcafter-daemon subr0) ; le daemon !!! (mov (cvalq #:ld:cons-llitt) a4) ; les literaux a patcher 5 (btnil a4 6) ; il en reste ? (mov (car a4) a1) ; A1 = (code . cons) (mov (cdr a4) a4) ; la suite (mov (cdr a1) a2) ; A2 = le cons (mov (car a1) a1) ; A1 = le code ; INVERSION (push '0) (push a2) (eval (:opnsn #$54 #$CE 0 7)) (eval (:opnsn #$54 #$CE 1 6)) (eval (:opnsn #$54 #$CE 2 5)) (eval (:opnsn #$54 #$CE 3 4)) (adjstk '1) (pop a2) ; INVERSE (mov a2 (car a1)) ; cons -> *code (bra 5) ; on continue 6 (return) ; c'est fini (fentry :patch-cons-llitt subr0) ; contre les courses (push a1) ; sauve les registres (push a2) (push a3) (push a4) (mov (cvalq :local-cons-llitt) a4) ; les literaux locaux (call 5) ; patche (pop a4) ; remet les registres (pop a3) (pop a2) (pop a1) (return) (end) ) () ))) (unless (or (eq (typefn 'loaderesolve) 'expr) (get 'loaderesolve 'resetfn)) (mapc (lambda (m) (when (typefn m) (remfn m) (remprop m '#:system:loaded-from-file) )) (oblist 'ldns) ))