; .EnTete "Le-Lisp (c) version 15.2" " " "Le chargeur me'moire SPS9"
; .EnPied " " "%" " "
; .sp 2
; .SuperTitre "Le Chargeur Me'moire SPS9"
;
; .Centre "*****************************************************************"
; .Centre " Ce fichier est en lecture seule hors du projet ALE de l'INRIA.  "
; .Centre " Il est maintenu par ILOG SA, 2 Avenue Gallie'ni, 94250 Gentilly "
; .Centre " (c) Le-Lisp est une marque de'pose'e de l'INRIA                 "
; .Centre "*****************************************************************"

; .Centre "$Header: lapsps9.ll,v 4.1 88/01/13 12:21:17 kuczynsk Rel $"

; Assemble et charge pour un SPS9 une liste d'instructions LLM3
; en 1 seule passe et avec du code relogeable.

(unless (>= (version) 15.2)
        (error 'load 'erricf 'lapsps9))

(defvar #:sys-package:colon 'ldsps9)

(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 (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` 32k ?!?!?
; ?!?!?     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 #:ld:special-case-loader ())  ; cas spe'cial pour charger le chargeur

(defvar #:ld:shared-strings ())       ; rend les constantes de chai↑ne EQ

; .Section "Les variables globales du chargeur"
 
(defvar :Ecode 
        ; fin de la zone code.
        (subadr (#:system:ecode) 64))
 
(defvar :mem-access
        ; noms symboliques des acce`s indexe's
        '(val     car     cdr     cval    pname
          plist   fval    alink   pkgc    oval    typ))

(defvar :locnil (loc ()))               ; adresse du symbole ()

(defvar :adrBVAR `(adr ,(loc 'sys-package))) ; a modifier si modif dans llinit

(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 :localstack :valaux :f :nwl obj
            obj1 obj2 obj3])))

; .Section "Les constantes propres au SPS9"

(dmd :defvalue (nom val)
     ; de'finition d'une constante SPS9
     `(putprop ',nom ,val ':value))

(de :getvalue (nom)
    ; recherche d'une constante SPS9
    (cond ((null nom) (:error ':getvalue nom))
          ((fixp nom) nom)
          ((symbolp nom) 
                (let ((val (getprop nom ':value)))
                     (if val (:getvalue val)
                         (:error ':getvalue nom))))
          (t (:error ':getvalue nom))))


; .SSection "Les registres"

(de :register? (obj)
    ; teste si l'argument est un registre SPS9   
    (memq obj '(x1 a1 a4 sp a2 a3 x2
                rbfloat rbvect rbstrg KNIL rbsymb rbcons x3 x4 x5)))

(:defvalue x1 0)
(:defvalue x2 1)
(:defvalue x3 2)
(:defvalue x4 3)
(:defvalue rbstrg 4)
(:defvalue a1 5)
(:defvalue a2 6)
(:defvalue a3 7)
(:defvalue a4 8)
(:defvalue rbfloat 9)
(:defvalue rbvect 10)
(:defvalue x5 11)
(:defvalue KNIL 12)
(:defvalue rbsymb 12)
(:defvalue rbcons 13)
(:defvalue sp 15)

; .SSection "Les constantes d'acce`s"

(:defvalue car 0)
(:defvalue cdr 4)

(:defvalue   cval       0)
(:defvalue   plist      4)
(:defvalue   fval       8)
(:defvalue   pkgc       12)
(:defvalue   oval       16)
(:defvalue   alink      20)
(:defvalue   pname      28)

(:defvalue   val       0)
(:defvalue   typ       4)

; .SSection "Les instructions par ordre alpha"

(:defvalue add          #$03)
(:defvalue addi         #$13)
(:defvalue and          #$0B)
(:defvalue br<>s        #$8A)
(:defvalue br<>simm     #$8E)
(:defvalue br<simm      #$85)
(:defvalue br=s         #$82)
(:defvalue br=simm      #$86)
(:defvalue br>s         #$80)
(:defvalue br>simm      #$84)
(:defvalue br>=simm     #$8D)
(:defvalue br<=s        #$88)
(:defvalue br<=simm     #$8C)
(:defvalue brs          #$8B)
(:defvalue div          #$06)
(:defvalue drcomp       #$3A)
(:defvalue laddr16      #$CE)
(:defvalue laddr16r     #$CF)
(:defvalue laddr32      #$DE)
(:defvalue laddrp16     #$EE)
(:defvalue laddrp16r    #$EF)
(:defvalue load         #$C7)  ; complet indexe' + short
(:defvalue load32abs    #$D6)
(:defvalue loadb16r     #$C1)
(:defvalue loadhp16r    #$E3)
(:defvalue loadp16r     #$C7)
(:defvalue lsl          #$60)
(:defvalue lsli         #$70)
(:defvalue lsr          #$61)
(:defvalue lsri         #$71)
(:defvalue move         #$01)
(:defvalue movei        #$11)
(:defvalue mpy          #$05)
(:defvalue neg          #$02)
(:defvalue radd         #$23)
(:defvalue rsub         #$24)
(:defvalue rdiv         #$26)
(:defvalue rem          #$07)
(:defvalue rmpy         #$25)
(:defvalue rcomp        #$2A)
(:defvalue or           #$09)
(:defvalue ret          #$57)
(:defvalue sbit         #$0D)
(:defvalue seh          #$7A)
(:defvalue storabs      #$B6) ; store absolu adresse 32 bits
(:defvalue store16r     #$A7)
(:defvalue storeb16r    #$A1)
(:defvalue sub          #$04)
(:defvalue subi         #$14)
(:defvalue xor          #$0A)

(de :immbr (cond)
    (cassq cond '((br=s . br=simm) (br<>s . br<>simm)
                  (br<=s . br<=simm) (br>s . br>simm)
                  (br>=s . br>=simm) (br<s . br<simm))))

(de :error (f a)
    ; erreur dans la fonction "f" sur l'argument "a"
    (print "** loader : " f " : " a)
    (error 'loader f a))

; .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)
          (:solverel obj))
         (t  (setq :codop (car obj)
                   :arg1  (cadr obj)
                   :arg2  (caddr obj)
                   :arg3  (cadddr obj)
                   :localstack 0)
             (selectq :codop
                 ;
                 ; les pseudos-instructions de de'claration
                 ;
                 (ABORT ; Pour re'cupe'rer de la me'moire en cas scraschhhh.
                 )
                 (ENTRY   ; (ENTRY <name> <ftype> <lparam>)
                     ; 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.
                     (:solventry :arg1)
                     (putprop :arg1 (copylist :PCcurrent) ':fval)
                     (setq :fntname :arg1))
                 (ENDL ; fin d'une fonction locale
                       (when :talkp (terpri))
                       (when :llabels-nr
                             (:error "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)))
                                    (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>)
                     ; 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 obj))))))

(de :machins (obj)
    ; re'alise le chargement de l'instruction obj
    (let ((obj1 (cadr obj)) (obj2 (caddr obj)) (obj3 (cadddr obj)))
         (selectq (car obj)
             (MOV      ; (MOV source dest)
                 (if (:register? obj2)
                     (:movsrc obj1 obj2)
                     (:movdest (:prepsrc obj1 'X1) obj2)))
             (PUSH
                  ; (PUSH <op>)  ==  subi SP 4
                  ; store16r (prepsrc obj1 'X1) SP 0
                  (setq obj1 (:prepsrc obj1 'X1))
                  (:inst 'subi 'SP 4)
                  (:inst 'store16r obj1 'SP)
                  (:val16abs 0))
             (JCALL    ; (JCALL <sym>) ==  jsb (FVAL :arg1)
                  (:inst 'subi 'SP 4)
                  (:inst 'laddrp16 'X1 0)
                  (:1word 16)
                  (:inst 'store16r 'X1 'SP)
                  (:val16abs 0)
                  (:movsrc (list 'fvalq obj1) 'X1)
                  (:inst 'ret 'X1 'X1))
             (JMP     ; (JUMP <sym>) == (JMP) (FVALQ <sym>)
                 ; en fait pour rester en absolu : laddr puis ret
                 (:movsrc (list 'fvalq obj1) 'X1)
                 (:inst 'ret 'X1 'X1))
             (CAR      
                 ; (CAR A1/A2/A3)  ==  load rx,rx,0    ?!?!? obsolete
                 (:inst 'load obj1 obj1)
                 (:val16abs 0))
             (CDR
                 ; (CDR A1/A2/A3)  ==  load rx,rx,4    ?!?!?!? obsolete
                 (:inst 'load obj1 obj1)
                 (:val16abs 4))
             (CABNE    ; (CABNE op1 op2 lab)
                 ; br<>s op1 op2 lab
                 (:instbr 'br<>s (:prepsrc obj1 'X1) (:prepsrc obj2 'X2))
                 (:val16rel obj3))
             (RETURN
                    ; (RETURN)  ==  load 'X1 SP 0; addi SP 4; ret X1 X1
                    (:inst 'load 'X1 'SP)
                    (:val16abs 0)
                    (:inst 'addi 'SP 4)
                    (:inst 'ret 'X1 'X1))
             (BRA
                 ; (BRA <lab>)  ==  br lab
                 (:inst 'brs 0 0)
                 (:val16rel obj1))
             (BTNIL    ; (BTNIL op lab)
                 (:btf1xx 'KNIL 'br=s t))
             (CABEQ    ; (CABEQ op1 op2 lab)
                 ; br=s op1 op2 lab
                 (:instbr 'br=s (:prepsrc obj1 'X1) (:prepsrc obj2 'X2))
                 (:val16rel obj3))
             (POP
                 ; (POP <op>)  == load obj1 SP 0; addi SP 4
                 (cond ((:register? obj1)
                        (:inst 'load obj1 'SP)
                        (:val16abs 0)
                        (:inst 'addi 'SP 4))
                       (t
                         (:inst 'load 'X1 'SP) 
                         (:val16abs 0)
                         (:inst 'addi 'SP 4)
                         (:movdest 'X1 obj1))))
             (BFNIL    ; (BFNIL op lab)
                 (:btf1xx 'KNIL 'br<>s ()))
             (BTCONS   ; (BTCONS op lab)
                 (:btf1xx 'RBCONS 'br>=s t))
             (BFCONS   ; (BFCONS op lab)
                 (:btf1xx 'RBCONS 'br<s ()))
             ;
             ; les tests de type
             ;
             (BTFIX   ; (BTNUMB op lab)
                 #-:31bitfloats
                 (:btf1xx 'RBFLOAT 'br<s t)
                 #+:31bitfloats
                 (:bt2xx ''0 'RBFLOAT))
             (BFFIX   ; (BFNUMB op lab)
                 #-:31bitfloats
                 (:btf1xx 'RBFLOAT 'br>=s ())
                 #+:31bitfloats
                 (:bf2xx ''0 'RBFLOAT))
             (BTFLOAT  ; (BTFLOAT op1 lab)
                 #+:31bitfloats
                 (:btf1xx ''0 'br<s t)
                 #-:31bitfloats
                 (:bt2xx 'RBFLOAT 'RBVECT))
             (BFFLOAT  ; (BFFLOAT op1 lab)
                 #+:31bitfloats
                 (:btf1xx ''0 'br>=s ())
                 #-:31bitfloats
                 (:bf2xx 'RBFLOAT 'RBVECT))
             (BTSTRG   ; (BTSTRG op1 lab)
                 (:bt2xx 'RBSTRG 'RBSYMB))
             (BFSTRG   ; (BFSTRG op1 lab)
                 (:bf2xx 'RBSTRG 'RBSYMB))
             (BTVECT   ; (BTVECT op1 lab)
                 (:bt2xx 'RBVECT 'RBSTRG))
             (BFVECT   ; (BFVECT op1 lab)
                 (:bf2xx 'RBVECT 'RBSTRG))
             (BTSYMB   ; (BTSYMB op1 lab)
                 (:bt2xx 'RBSYMB 'RBCONS))
             (BFSYMB   ; (BFSYMB op1 lab)
                 (:bf2xx 'RBSYMB 'RBCONS))
             (BTVAR    ; (BTVAR op1 lab)
                 (:bt2xx :adrBVAR 'RBCONS))
             (BFVAR    ; (BFVAR op1 lab)
                 (:bf2xx :adrBVAR 'RBCONS))
             ;
             ;  Les comparaisons entieres
             ;
             (CNBEQ    ; (CNBEQ op1 op2 lab)
                 (:cnbxxieqn 'br=s t))
             (CNBNE    ; (CNBNE op1 op2 lab)
                 (:cnbxxieqn 'br<>s ()))
             (CNBLT    ; (CNBLT op1 op2 lab)
                 (:cnbxx 'br<s t))
             (CNBLE    ; (CNBLE op1 op2 lab)
                 (:cnbxx 'br<=s ()))
             (CNBGT    ; (CNBGT op1 op2 lab)
                 (:cnbxx 'br>s t))
             (CNBGE    ; (CNBGE op1 op2 lab)
                 (:cnbxx 'br>=s ()))
             ;
             ;  Les comparaisons arithme'tiques flottantes.
             ;
             (CFBEQ    ; (CFBEQ op1 op2 lab)
                 (:comp2float 'br=s 0))
             (CFBNE    ; (CFBNE op1 op2 lab)
                 (:comp2float 'br<>s 0))
             (CFBLT    ; (CFBLT op1 op2 lab)
                 (:comp2float 'br=s -1))
             (CFBLE    ; (CFBLE op1 op2 lab)
                 (:comp2float 'br<>s 1))
             (CFBGT    ; (CFBGT op1 op2 lab)
                 (:comp2float 'br=s 1))
             (CFBGE    ; (CFBGE op1 op2 lab)
                 (:comp2float 'br<>s -1))
             ; 
             ; Les instructions arithme'tiques
             ;
             (DECR     ; (DECR op)
                 (:macaro1op 'subi 1))
             (DIFF      ; (DIFF op1 op2)
                 (:macaro2op 'sub))
             (INCR     ; (INCR op)
                 (:macaro1op 'addi 1))
             (LAND   ; (LAND op1 op2)
                     (:macaro2op 'and))
             (LOR    ; (LOR op1 op2) 
                     (:macaro2op 'or))
             (LXOR   ; (LXOR op1 op2)
                     (:macaro2op 'xor))
             (LSHIFT ; (LSHIFT circ op)
                     (:inst 'seh 'X2 (:prepsrc obj1 'X2))
                     (:inst 'seh 'X1 (:prepsrc obj2 'X1))
                     (:inst 'br>=simm 'X2 0)
                     (:val16abs 12)
                     (:inst 'neg 'X2 'X2)
                     (:inst 'lsr 'X1 'X2)
                     (:inst 'brs 0 0)
                     (:val16abs 6)
                     (:inst 'lsl 'X1 'X2)
                     (:convnb 'X1)
                     (:movdest 'X1 obj2))
             (NEGATE    ; (NEGATE op) 
                 (setq obj2 obj1)
                 (:macaro2op 'neg))
             (PLUS      ; (PLUS op1 op2)
                 (:macaro2op 'add))
             (REM
                 (:macaro2op 'rem))
             (QUO
                 (:macaro2op 'div))
             (TIMES
                   (:macaro2op 'mpy))
             ;
             ;  Les instructions arithme'tiques flottantes
             ;
             (FPLUS  (:instr2float 'radd))
             (FDIFF  (:instr2float 'rsub))
             (FTIMES (:instr2float 'rmpy))
             (FQUO   (:instr2float 'rdiv))
             ;
             ;  Les autres instructions (par ordre alpha)
             ;
             (ADJSTK   ; (ADJSTK 'nb)
                 (if (:immediat? obj1)
                     (cond ((and (ge (cadr obj1) 0) (lt (cadr obj1) 4))
                            (:inst 'addi 'SP (mul 4 (cadr obj1))))
                           ((and (le (cadr obj1) 0) (gt (cadr obj1) -4))
                            (:inst 'subi 'SP (mul 4 (sub 0 (cadr obj1)))))
                           (t
                            (:inst 'laddr16r 'SP 'SP)
                            (:val16abs (mul 4 (cadr obj1)))))
                     (:movsrc obj1 'X1)
                     (:inst 'lsli 'X1 2)
                     (:inst 'seh 'X1 'X1)
                     (:inst 'add 'SP 'X1)))
             (BRI
                 (:inst 'ret 'X1 (:prepsrc obj1 'X1)))
             (BRX ; (BRX (l1 ... ln) index)
                  (:inst 'move 'X1 (:prepsrc obj2 'X1))
                  (:inst 'lsli 'X1 3)
                  (:inst 'laddrp16r 'X1 'X1)
                  (:1word 6)
                  (:inst 'ret 'X1 'X1)
                  (while obj1
                         (:inst 'brs 0 0)
                         (:val16rel (cadr (nextl obj1)))
                         (:1word 0)))
             (CALL
                  ; (CALL <sym>)
                  (:inst 'subi 'SP 4)
                  (:inst 'laddrp16 'X1 0)
                  (:1word 14)
                  (:inst 'store16r 'X1 'SP)
                  (:val16abs 0)
                  (:inst 'brs 0 0)
                  (:val16rel obj1))
             (HBMOVX   ; (HPMOVX val string index)
                 (cond ((:small-pos? obj3)
                        ; index constant
                        (:inst 'load 'X2 (:prepsrc obj2 'X2))
                        (:val16abs 0)
                        (:inst 'storeb16r (:prepsrc obj1 'X1) 'X2)
                        (:val16abs (add 8 (cadr obj3))))
                       (t ; index calcule'
                          (:movaheabix obj2 obj3 'X2)
                          (:inst 'storeb16r (:prepsrc obj1 'X1) 'X2)
                          (:val16abs 0))))
             (HBXMOV  ; (HBXMOV string index dest) string[index] -> dest
                 (:movaheabix obj1 obj2 'X2)
                 (if (:register? obj3)
                     (progn
                           (:inst 'loadb16r obj3 'X2)
                           (:val16abs 0))
                     (:inst 'loadb16r 'X1 'X2)
                     (:val16abs 0)
                     (:movdest 'X1 obj3)))
             (HGSIZE   ; (HGSIZE vector/string arg2)
                 (:inst 'load 'X1 (:prepsrc obj1 'X1))
                 (:val16abs 0)
                 (if (:register? obj2)
                     (progn (:inst 'load obj2 'X1) (:val16abs 4))
                     (:inst 'load 'X2 'X1) (:val16abs 4)
                     (:movdest 'X2 obj2)))
             (HPMOVX   ; (HPMOVX val vector index)
                 (:movaheap obj2 obj3 'X2)
                 (:inst 'store16r (:prepsrc obj1 'X1) 'X2)
                 (:val16abs 0))
             (HPXMOV   ; (HPXMOV vector index val)
                 (:movaheap obj1 obj2 'X2)
                 (if (:register? obj3)
                     (progn (:inst 'load obj3 'X2)
                            (:val16abs 0))
                     (progn (:inst 'load 'X1 'X2)
                            (:val16abs 0)
                            (:movdest 'X1 obj3))))
             (MOVXSP   ; (MOVXSP val depl)
                 ; on ajoute le de'placement au haut de pile
                 (:movsrc obj2 'X2)
                 (:inst 'lsli 'X2 2)
                 (:inst 'add 'X2 'SP)
                 (:inst 'store16r (:prepsrc obj1 'X1) 'X2)
                 (:val16abs 0))
             (NOP
                 (:inst 'move 'X1 'X1))
             (SOBGEZ   ; (SOBGEZ op lab)
                 (let ((r1 (:prepsrc obj1 'X1)))
                      (:inst 'seh r1 r1)
                      (:inst 'subi r1 1)
                      (unless (eq r1 obj1)
                              (:movdest r1 obj1))
                      (:inst 'br>=simm r1 0)
                      (:val16rel obj2)
                      (:convnb r1)
                      (unless (eq r1 obj1)
                              (:movdest r1 obj1))))
             (SSTACK   ; (SSTACK <op>) movl op,sp
                 (:movsrc obj1 'SP))
             (STACK
                 (:movdest 'SP obj1))
             (XSPMOV   ; (XSPMOV depl val)
                 (:movsrc obj1 'X1)
                 (:inst 'lsli 'X1 2)
                 (:inst 'add 'X1 'SP)
                 (if (:register? obj2)
                     (progn (:inst 'load obj2 'X1)
                            (:val16abs 0))
                     (progn (:inst 'load 'X2 'X1)
                            (:val16abs 0)
                            (:movdest 'X2 obj2))))
             (t ; c'est donc une erreur
                (:error ':machins obj1)))))
 
; .Section "Auxiliaires de chargement"

(de :immediat? (val)
    (and (consp val)
         (eq (car val) 'quote)
         (fixp (cadr val))
         (neqn (cadr val) #$8000)))

(de :small-pos? (val)
    ; teste si l'argument est un nb positif sur 15 bits
    (and (consp val)
         (eq (car val) 'quote)
         (fixp (cadr val))
         (neqn (cadr val) #$8000)
         (ge (cadr val) 0)))

(de :small-imm? (val)
    ; teste si l'argument est une petite valeur imme'diate (4 bits)
    (and (:small-pos? val)
         (lt (cadr val) 16)))

(de :alignd ()
    (when (neqn 0 (logand 3 (or (fixp :PCcurrent) (cdr :PCcurrent))))
          (:inst 'or 'X1 'X1)))

(de :PCalignd (pc)
    (if (neqn 0 (logand 3 (or (fixp :PCcurrent) (cdr :PCcurrent))))
        (addadr pc 2)
        pc))

(de :movaheabix (op ind reg)
    ; charge l'adresse heap d'octet "op+ind" dans "reg"
    (:inst 'load reg (:prepsrc op reg))
    (:val16abs 0)
    (if (:small-pos? ind)
        (if (< (cadr ind) 8)
            (:inst 'addi reg (add 8 (cadr ind)))
            (:inst 'laddr16r reg reg)
            (:val16abs (add 8 (cadr ind))))
        (:inst 'addi reg 8)
        (:inst 'add reg (:prepsrc ind 'X1))))

(de :instr2float (instr)
    ; appel d'un instruction de base (en direct!) a` 2 arguments
#+:31bitfloats
    (cond ((:register? obj2)
           (:unrolfloat obj1 'X1)
           (:unrolfloat obj2 obj2)
           (:inst instr obj2 'X1)
           (:rolfloat obj2 'X1))
          (t
            (:unrolfloat obj1 'X1)
            (:unrolfloat obj2 'X2)
            (:inst instr 'X2 'X1)
            (:rolfloat 'X2 'X1)
            (:movdest 'X2 obj2)))
#-:31bitfloats
    (:error ':instr2float instr))

(de :unrolfloat (src reg)
    ; de'code le flottant 31 bits src et le met dans le
    ; registre reg.
    (unless (eq reg src) (:movsrc src reg))
    (:inst 'lsli reg 1))

(de :rolfloat (reg via)
    (ifn (:register? reg)
         (:error 'rolfloat reg))
    (if (eq reg via)
        (:error 'rolfloat (list reg via)))
    ; encode un flottant en flottant 31bits dans le registre reg
    ; en utilisant e'ventuellemtn le scratch via
    (:inst 'movei via 0)
    (:inst 'lsri reg 1)
    (:inst 'sbit reg via))

(de :comp2float (oper cond)
    ; appel d'une comparaison de base (en direct) a` 2 arguments flottants
    ; "oper" est l'ope'rateur, "cond" la condition.
#+:31bitfloats
    (progn
           (:unrolfloat obj1 'X1)
           (:unrolfloat obj2 'X2)
           (:inst 'rcomp 'X1 'X2))
#-:31bitfloats
    (progn
            (:loadvalfloat obj1 'X3 'X1 'X2)
            (:loadvalfloat obj2 'X4 'X3 'X4)
            (:inst 'drcomp 'X1 'X3))
    (:inst 'laddr16 'X4 0) (:val16abs cond)
    (:instbr oper 'X1 'X4)
    (:val16rel obj3))

(de :cnbxx (cond pred)
    ; comparaison arithme'tique sur 16 bits signe's
    ; on suppose que s'il y a une constante c'est en 2e`me ope'rande.
    (:inst 'seh 'X1 (:prepsrc obj1 'X1))
    (cond ((:small-imm? obj2)
           ; petit entier sur 4 bits
           (:instbr (:immbr cond) 'X1 (cadr obj2)))
          ((:small-pos? obj2)
           ; pas la peine d'e'tendre le signe de la constante 15 bits
           (:instbr cond 'X1 (:prepsrc obj2 'X2)))
          (t ; cas le plus long
           (:inst 'seh 'X2 (:prepsrc obj2 'X2))
           (:instbr cond 'X1 'X2)))
    (:val16rel obj3))

(de :cnbxxieqn (cond pred)
    ; comparaison arithme'tique sur 32 bits si = ou /=
    (cond ((:small-imm? obj1)
           (:instbr (:immbr cond) (:prepsrc obj2 'X2) (cadr obj1)))
          ((:small-imm? obj2)
           (:instbr (:immbr cond) (:prepsrc obj1 'X1) (cadr obj2)))
          (t
            (:instbr cond (:prepsrc obj1 'X1) (:prepsrc obj2 'X2))))
    (:val16rel obj3))

(de :btf1xx (borne cond pred)
    (:instbr cond (:prepsrc obj1 'X1) (:prepsrc borne 'X2))
    (:val16rel obj2))

(de :bf2xx (btype etype)
    (unless (:register? etype) (:error ':bf2xx etype))
    (setq obj1 (:prepsrc obj1 'X1))
    (if (:small-imm? btype)
        (:instbr 'br<simm obj1 (cadr btype))
        (:instbr 'br<s obj1 (:prepsrc btype 'X2)))
    (:val16rel obj2)
    (:instbr 'br>=s obj1 etype)
    (:val16rel obj2))
    
(de :bt2xx (btype etype)
    (unless (:register? etype) (:error ':bt2xx etype))
    (setq obj1 (:prepsrc obj1 'X1))
    (if (:small-imm? btype)
        (:instbr 'br<simm obj1 (cadr btype))
        (:instbr 'br<s obj1 (:prepsrc btype 'X2)))
    (:1word 10)
    (:instbr 'br<s obj1 (:prepsrc etype 'X2)) 
    (:val16rel obj2))

; .Section "Les fonctions de chargement des ope'randes"

(de :prepsrc (arg reg)
    ; pre'pare l'argument source "arg"
    ; s'il le faut range l'argument dans l'auxiliaire "reg"
    ; retourne le nume'ro de registre qui contient l'argument
    (cond ((eq arg 'nil)
           ; ope'rande nil (en fait ||)
           'KNIL)
          ((:register? arg)
           ; c'est de'ja` un registre
           arg)
          ((atom arg)
           ; c'est un mot me'moire.
           (cond ((memq arg '(LLINK DLINK ITCOUNT))
                  (:inst 'load32abs reg 0)
                  (:val32abs (symeval (symbol 'llcp arg)))
                  reg)
                 ((memq arg '(CBINDN TAG LOCK PROT))
                  (:inst 'laddr32 reg 0)
                  (:val32abs (symeval (symbol 'llcp arg)))
                  reg)
                 (t
                   ; ne doit jamais arriver pour le compilo
                   ; sauf en cas de nouvelles de'finitions.
                   (if (and (symbolp arg) 
                            (getfn1 'ld-dir arg))
                       (funcall (getfn1 'ld-dir arg) arg)
                       (:error ':prepsrc arg)))))
          ((memq (car arg) :mem-access)
           ; acce`s a` la me'moire indirect par registre
           (:inst 'load reg (cadr arg))
           (:val16abs (:getvalue (car arg)))
           reg)
          (t
            (selectq (car arg)
                (quote
                      ; constante Lisp
                      (unless (or (fixp (cadr arg))
                                  #+:31bitfloats
                                  (floatp (cadr arg))
                              )
                              ; c'est un litte'ral a` sauver
                              (ifn (stringp (cadr arg))
                                   (:add-llitt (cadr arg))
                                   (:add-llitts arg)))
                      (cond ((fixp (cadr arg)) 
                             (if (and (/= (cadr arg) #$8000)
                                      (>= (cadr arg) 0))
                                 (if (< (cadr arg) 16)
                                     ; constante sur 4 bits
                                     (:inst 'movei reg (cadr arg))
                                     ; constante sur 16 bits
                                     (:inst 'laddr16 reg 0)
                                     (:val16abs (cadr arg)))
                                 ; constante sur 32 bits
                                 ; car extension de signe
                                 (:inst 'laddr32 reg 0)
                                 (:val16abs 0)
                                 (:val16abs (cadr arg))))
                            (t ; constante symbolique sur 32 bits
                               (:inst 'laddr32 reg 0)
                               (:val32abs (loc (cadr arg)))))
                      reg)                
                (cvalq
                      ; adresse d'une CVAL de symbole
                      (ifn (symbolp (cadr arg))
                           (:error ':prepsrc arg)
                           (:inst 'load32abs reg 0)
                           (:val32abs (loc (cadr arg)))
                           (:add-llitt (cadr arg)))
                      reg)
                (fvalq
                      ; adresse d'une FVAL de symbole
                      (ifn (symbolp (cadr arg))
                           (:error ':prepsrc arg)
                           (:inst 'load32abs reg 0)
                           (:val32abs
                            (addadr (loc (cadr arg)) (:getvalue 'fval)))
                           (:add-llitt (cadr arg)))
                      reg)
                (|&|
                 (:inst 'load reg 'SP)
                 (:val16abs (mul 4 (cadr arg)))
                 reg)
                (|@|
                 (:inst 'laddrp16 reg 0)
                 (:val16rel (cadr arg))
                 reg)
                (eval
                     ; Pour calculer des ope'randes a` load time.
                     (:prepsrc (eval (cadr arg)) reg))
                (adr
                    (:inst 'laddr32 reg 0)
                    (:val32abs (cadr arg))
                    reg)
                (t (:error ':prepsrc arg))))))

(de :movsrc (arg regin)
    ; transporte l'ope'rande "arg" de n'importe quel type
    ; dans le registre de nom "regin".
    ; retourne toujours "regin" en valeur.
    (setq arg (:prepsrc arg regin))
    (unless (eq arg regin) (:inst 'move regin arg))
    regin)
                  
(de :movdest (src dest)
    ; transporte "src" (toujours registre) vers "dest"
    (cond ((:register? dest)
           ; reg -> reg
           (:inst 'move dest src))
          ((atom dest)
           (ifn (memq dest '(LLINK DLINK ITCOUNT))
                (:error 'movdest dest)
                (:inst 'storabs src 0)
                (:val32abs (symeval (symbol 'llcp dest)))))
          ((memq (car dest) :mem-access)
           ; reg -> mem
           (:inst 'store16r src (cadr dest))
           (:val16abs (:getvalue (car dest))))
          ((eq (car dest) 'cvalq)
           ; reg -> CVAL symbole
           (ifn (symbolp (cadr dest))
                (:error ':movdest dest)
                (:inst 'storabs src 0)
                (:val32abs (loc (cadr dest)))
                (:add-llitt (cadr dest))))
          ((eq (car dest) '|&|)
           (:inst 'store16r src 'SP)
           (:val16abs (mul 4 (cadr dest))))
          ((eq (car dest) 'eval)
           ; Pour calculer des ope'randes a` load time.
           (:movdest src (eval (cadr dest))))
          (t (:error ':movdest dest))))

; .Section "Les fonctions auxiliares de ge'ne'ration"

(de :macaheap (op reg)
    ; charge dans "reg" l'adresse heap de op
    (setq op (:prepsrc op reg))
    (:inst 'load reg op)
    (:val16abs 0)
    (:inst 'addi reg 8))

(de :movaheab (op ind reg)
    ; charge l'adresse heap d'octet op+ind dans reg
    (:macaheap op reg)
    (:inst 'add reg (:prepsrc ind 'X1)))

(de :movaheap (op ind reg)
    ; charge l'adresse heap de mot op+ind dans reg
    (:macaheap op reg)
    (:movsrc ind 'X1)
    (:inst 'lsli 'X1 2)
    (:inst 'add reg 'X1))

(de :convnb (reg)
    ; repasse en format 16 bits
    (:inst 'laddr32 'X3 0)
    (:val32abs '(0 . #$FFFF))
    (:inst 'and reg 'X3))

(de :macaro1op (op 2nd)
    (:movsrc obj1 'X1)
    (:inst op 'X1 2nd)
    (:convnb 'X1)
    (:movdest 'X1 obj1))

(de :macaro2op (op)
    (:inst 'seh 'X1 (:prepsrc obj2 'X1))
    (:inst 'seh 'X2 (:prepsrc obj1 'X2))
    (:inst op 'X1 'X2)
    (:convnb 'X1)
    (:movdest 'X1 obj2))

; .Section "Les fonctions auxiliaires de chargement me'moire"

(de :instbr (code op1 op2)
    ; l'instruction br<s dans le cas ou` op2 est un registre doit d'assembler
    ; en permutant op1 et op2.
    (when (and (eq code 'br<s) (:register? op2))
          (setq code 'br>s)
          (psetq op1 op2 op2 op1))
    ; de meme pout br>=s
    (when (and (eq code 'br>=s) (:register? op2))
          (setq code 'br<=s)
          (psetq op1 op2 op2 op1))
    (:inst code op1 op2))

(de :inst (code op1 op2)
    ; charge une instruction de codop "code" avec 2 ope'randes.
    (:1word
        (logor (logshift (:getvalue code) 8)
               (logor (logshift (:getvalue op1) 4) (:getvalue op2)))))
     
(de :val16abs (obj)
    ; chargement d'une valeur absolue de 16 bits
    (:1word obj))

(de :val32abs (obj)
    ; chargement d'une valeur absolue de 32 bits
    (cond ((fixp obj)
           (:1word 0)
           (:1word obj))
          ((consp obj)
            (:1word (car obj))
            (:1word (cdr obj)))
          (t (:error ':val32abs obj))))

(de :1word (obj)
    ; chargement d'un mot de 16 bits en me'moire a` l'adresse
    ; contenue dans :PCcurrent, et gestion de cette valeur.
    (when :talkp
          ; impression du code en hexade'cimal.
          (when (> :nwl 6)
                (setq :nwl 0)
                (terpri)
                (outpos 30)
                (:prinhex :PCcurrent)
                (prin "  "))
          (incr :nwl)
          (prin " ")
          (:prinhex obj))
    (if (gtadr :PCcurrent :Ecode)
        (with ((outchan ()))
              (print ERRFCOD)
              (exit #:system:toplevel-tag))
        (memory :PCcurrent obj)
        (setq :PCcurrent (incradr :PCcurrent 2))))

(de :patch32rel ()
    (let ((PCprevious (:sa :PCcurrent 2)))
         (memory PCprevious (logor #$1000 (memory PCprevious)))))

(de :val16rel (adr)
    ; charge un de'placement sur 16 bits (en fait toujours sur 32 bits!)
    (let ((l (:aa (:valrel adr) 2)))
         (:patch32rel) ; rajoute le bit rel 32 dans le mot pre'ce'dent
         (:1word (car l))
         (:1word (cdr l))))

; .Section "Fonctions de calcul d'adresse"

; .SSection "Les adresses absolues sur 32 bits"


(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  :valrel (adr)
    ; retourne un de'placement par rapport a` PC ou ()
    (let ((valadr (:valadr adr)))
         (if valadr
             (:sa valadr :PCcurrent)
             (if (and (symbolp adr) (null (assq adr :llabels)))
                 (:addentry adr (copy :PCcurrent))
                 (:addlabel adr (copy :PCcurrent)))
             0)))

(de :solve16rel (ref)
    (let ((relval
                 (:aa (:sa :PCcurrent ref) 2)))
         (memory ref (car relval))
         (memory (addadr ref 2) (cdr relval))))

(de :solverel (obj)
    (mapc ':solve16rel
          (cassq obj :llabels-nr))
    (setq :llabels-nr
          (delete (assq obj :llabels-nr) :llabels-nr)))

(de :solventry (obj)
    (mapc ':solve16rel
          (cassq obj :entries-not-resolved))
    (setq :entries-not-resolved
          (delete (assq obj :entries-not-resolved) :entries-not-resolved)))

(de :aa (a1 a2)
    (setq #:ex:regret 0)
    (xcons (ex+ 
              (if (consp a1) (cdr a1) a1)
              (if (consp a2) (cdr a2) a2))
           (ex+ 
              (if (consp a1) (car a1) 0)
              (if (consp a2) (car a2) 0))))

(de :sa (a1 a2)
    (:aa (:aa a1 1)
     (cons (if (consp a2) (ex- (car a2)) -1)
           (if (consp a2) (ex- (cdr a2)) (ex- a2)))))

; .Section "Gestion des tables"
 
(de :addlabel (sym adr)
    ; rajoute le symbole <sym> (a l'adresse <adr>)
    ; dans la table des e'tiquettes locales
    (let ((val (assq sym :llabels-nr)))
         (if val
             (rplacd val (cons adr (cdr val)))
             (newl :llabels-nr (list sym adr)))))
 
(de :addentry (sym adr)
    ; rajoute le symbole <sym> (a l'adresse <adr>)
    ; dans la table des entre'es locales
    (let ((val (assq sym :entries-not-resolved)))
         (if val
             (rplacd val (cons adr (cdr val)))
             (newl :entries-not-resolved (list sym adr)))))
 
(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)))))

; .Section "Sorties et Dumps Hexade'cimal"

(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 ':prinhex n))))
 
(de :prinhexb (n)
    ; imprime sur 2 chiffres hexa le nb n
    (cond ((not (fixp n)) (:error ':prinhexb n))
          ((< n 0) (setq n 255))
          ((< n 16) (princn #/0)))          
    (with ((obase 16)) (prin n)))

(de :memory-dump (adr n)
    ; dump la memoire en hexa de <adr> sur <n> mots
    ; attention au SWAB du SPS9! octet de poids faibles a gauche!
    (setq adr (copy adr))       ;  pour le incradr
    (until (<= n 0)
           (:prinhex adr)
           (outpos 10)
           (repeat 8 (:prinhex (memory adr))
                     (prin " ")
                     (incradr adr 2)
                     (decr n))
           (terpri)))
 
; .Section "Chargement des points d'entree speciaux du lap/llcp"

; .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
          :localstack                   ;    ?!?!?!?!?!?
          :valaux                       ;    itou pour des valeurs locales.
          :f                            ;    itou (pour des getfn1)
          (:nwl 0)                      ;    itou pour tabler le code produit.
          (#:ex:regret))                ; pour rester propre
         ; 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)))
         ()))
 
; .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) )
         () ))

(unless (or (eq (typefn 'loaderesolve) 'expr) (get 'loaderesolve 'resetfn))
    (mapc
         (lambda (m)
                 (when (typefn m)
                       (remfn m)
                       (remprop m '#:system:loaded-from-file)))
         (oblist '#.#:sys-package:colon)))