(include-if (null (get 'chead 'version)) "../chead.l")
(Liszt-file io
   "$Header:io.l 12.0$")
   "$ACIS:io.l 12.0$")

;;; ---- 	i o				input output
;;;
;;;				-[Fri Sep  2 21:37:05 1983 by layer]-


;--- d-prelude :: emit code common to beginning of all functions
;
(defun d-prelude nil
   (let ((loada-op #+for-vax 'movab #+for-68k 'lea)
	 (sub2-op #+for-vax 'subl2 #+for-68k 'subl)
	 (add2-op #+for-vax 'addl2 #+for-68k 'addl)
	 (temp-reg #+for-68k 'a5 #+for-vax '#.fixnum-reg))
       #+for-68k (setq g-stackspace (d-genlab) g-masklab (d-genlab))
       (if g-flocal
	   then (C-push '#.olbot-reg)
		(e-write3 loada-op
			  `(,(* -4 g-currentargs) #.np-reg) '#.olbot-reg)
		(e-writel g-topsym)
	   else #+for-vax (e-write2 '".word" '0x5c0)
		#+for-68k
		(progn
		    (e-write3 'link 'a6 (concat "#-" g-stackspace))
		    (e-write2 'tstb '(-132 sp))
		    (e-write3 'moveml `($ ,g-masklab)
			      (concat "a6@(-" g-stackspace ")"))
		    (e-move '#.Nilatom '#.nil-reg))
		(if fl-profile
		    then (e-write3 loada-op 'mcounts
				   #+for-vax 'r0 #+for-68k 'a0)
			 (e-quick-call 'mcount))
		(e-write3 loada-op 'linker '#.bind-reg)
		(if (eq g-ftype 'lexpr)
		    then ; Here is the method:
			 ;  We push the number of arguments, nargs,
			 ; on the name stack twice, setting olbot-reg
			 ; to point to the second one, so that the user
			 ; has a copy that he can set, and we have
			 ; one that we can use for address calcs.
			 ;  So, the stack will look like this, after
			 ; the setup:
			 ;np    ->
			 ;olbot -> nargs (II)
			 ;      -> nargs (I)
			 ;      -> (arg nargs)
			 ;      -> (arg nargs-1)
			 ;...
			 ;      -> (arg 1)
			 ;
			 (if (null $global-reg$)
			     then (e-move '#.np-sym '#.np-reg))
			 (e-writel g-topsym)
			 (e-move '#.np-reg temp-reg)
			 (e-write3 sub2-op
				   (if $global-reg$
				       then '#.lbot-reg
				       else '#.lbot-sym) temp-reg)
			 (e-write3 add2-op (e-cvt '(fixnum 0)) temp-reg)
			 (L-push temp-reg)
			 (e-move '#.np-reg '#.olbot-reg)
			 (L-push temp-reg)
		    else ;   Set up old lbot register, base reg for variable
			 ; references, and make sure the np points where
			 ; it should since the caller might
			 ; have given too few or too many args.
			 (e-move
				   (if $global-reg$
				       then '#.lbot-reg
				       else '#.lbot-sym)
				   '#.olbot-reg)
			 #+for-68k
			 (e-write3 loada-op
				   `(,(* 4 g-currentargs) #.olbot-reg)
				   '#.np-reg)
			 (e-writel g-topsym)))))

;--- d-fini :: emit code  at end of function
;
(defun d-fini nil
   (if g-flocal
       then (C-pop '#.olbot-reg)
	    (e-write1 #+for-vax 'rsb #+for-68k 'rts)
       else #+for-68k
	    (progn
		(e-write3 'moveml (concat "a6@(-" g-stackspace ")")
			  `($ ,g-masklab))
		(e-write2 'unlk 'a6))
	    (e-return)))

;--- d-bindtab :: emit binder table when all functions compiled
;
(defun d-bindtab nil
  (setq g-skipcode nil)	  ; make sure this isnt ignored	
  (e-writel "bind_org")
  #+for-vax
  (progn
      (e-write2 ".set linker_size," (length g-lits))
      (e-write2 ".set trans_size," (length g-tran)))
  #+for-68k
  (progn
      (e-write2 "linker_size = " (length g-lits))
      (e-write2 "trans_size = " (length g-tran)))
  (do ((ll (setq g-funcs (nreverse g-funcs)) (cdr ll)))
      ((null ll))
      (if (memq (caar ll) '(lambda nlambda macro eval))
	  then (e-write2 '".long"
			 (cdr (assoc (caar ll)
				     '((lambda . 0) (nlambda . 1)
				       (macro . 2) (eval . 99)))))
	  else (comp-err " bad type in lit list " (car ll))))
  
  (e-write1 ".long -1")
  (e-writel "lit_org")
  (d-asciiout (nreverse g-lits))
  (if g-tran then (d-asciiout (nreverse g-tran)))
  (d-asciiout (mapcar '(lambda (x) (if (eq (car x) 'eval)
				       then (cadr x)
				       else (caddr x)))
		      g-funcs))
  (e-writel "lit_end"))

;--- d-asciiout :: print a list of asciz strings
;
(defun d-asciiout (args)
       (do ((lits args (cdr lits))
	    (form))
	   ((null lits))
	   (setq form (explode (car lits))
		 formsiz (length form))
	   (do ((remsiz formsiz)
		(curform form)
		(thissiz))
	       ((zerop remsiz))
	       (if (greaterp remsiz 60) then (sfilewrite '".ascii \"")
		   else (sfilewrite '".asciz \""))
	       (setq thissiz (min 60 remsiz))
	       (do ((count thissiz (1- count)))
		   ((zerop count)
		    (sfilewrite (concat '\" (ascii 10)))
		    (setq remsiz (difference remsiz thissiz)))
		   (if (eq '#.ch-newline (car curform))
		       then (sfilewrite '\\012)
		    else (if (or (eq '\\ (car curform))
				 (eq '\" (car curform)))
			     then (sfilewrite '\\))
			 (sfilewrite (car curform)))
		   (setq curform (cdr curform))))))

;--- d-autorunhead
;
; Here is the C program to generate the assembly language:
;	(after some cleaning up)
;
;main(argc,argv,arge)
;register char *argv[];
;register char **arge;
;{
;	*--argv = "-f";
;	*--argv = "/usr/ucb/lisp";
;	execve("/usr/ucb/lisp",argv,arge);
;	exit(0);
;}
;
(defun d-printautorun nil
   (let ((readtable (makereadtable t))	; in raw readtable
	 tport ar-file)
      (setsyntax #/; 'vsplicing-macro 'zapline)
      (setq ar-file (concat lisp-library-directory
			    #+for-vax "/autorun/vax"
			    #+for-68k "/autorun/68k"))
      (if (null (errset (setq tport (infile ar-file))))
	 then (comp-err "Can't open autorun header file " ar-file))
      (do ((x (read tport '<eof>) (read tport '<eof>)))
	  ((eq '<eof> x) (close tport))
	  (sfilewrite x))))

(defun e-cvt (arg)
   (if     (eq 'reg arg) then #+for-vax 'r0 #+for-68k 'd0
    elseif (eq 'areg arg) then #+for-vax 'r0 #+for-68k 'a0
    elseif (eq 'Nil arg) then #+for-vax '($ 0) #+for-68k '#.nil-reg
    elseif (eq 'T arg)
       then (if g-trueloc
		thenret
		else (setq g-trueloc (e-cvt (d-loclit t nil))))
    elseif (eq 'stack arg) then '(+ #.np-reg)
    elseif (eq 'unstack arg) then '(- #.np-reg)
    elseif (or (atom arg) (symbolp arg)) then arg
    elseif (dtpr arg)
       then (caseq (car arg)
		   (stack	`(,(* 4 (1- (cadr arg))) #.olbot-reg))
		   (vstack	`(* ,(* 4 (1- (cadr arg))) #.olbot-reg))
		   (bind	`(* ,(* 4 (1- (cadr arg))) #.bind-reg))
		   (lbind	`(,(* 4 (1- (cadr arg))) #.bind-reg))
		   (fixnum	`(\# ,(cadr arg)))
		   (immed	`($ ,(cadr arg)))
		   (racc	(cdr arg))
		   (t		(comp-err " bad arg to e-cvt : "
					  (or arg))))
       else  (comp-warn "bad arg to e-cvt : " (or arg))))

;--- e-uncvt :: inverse of e-cvt, used for making comments pretty
;
(defun e-uncvt (arg)
   (if (atom arg)
       then (if (eq 'Nil arg)
		then nil
		else arg)
    elseif (eq 'stack (car arg))
       then (do ((i g-loccnt)
		 (ll g-locs))
		((and (equal i (cadr arg)) (atom (car ll))) (car ll))
		(if (atom (car ll))
		    then (setq ll (cdr ll)
			       i (1- i))
		    else (setq ll (cdr ll))))
    elseif (or (eq 'bind (car arg)) (eq 'lbind (car arg)))
       then (do ((i g-litcnt (1- i))
		 (ll g-lits (cdr ll)))
		((equal i (cadr arg))
		 (cond ((eq 'lbind (car arg))
			(list 'quote (car ll)))
		       (t (car ll)))))
       else arg))

;--- e-cvtas :: convert an EIADR to vax unix assembler fmt and print it
;	- form : an EIADR form
;
#+for-vax
(defun e-cvtas (form)
  (if (atom form)
      then (sfilewrite form)
      else (if (eq '* (car form))
	       then (if (eq '\# (cadr form))
			then (setq form `($ ,(caddr form)))
			else (sfilewrite "*")
			     (setq form (cdr form))))
	   (if (numberp (car form))
	       then (sfilewrite (car form))
		    (sfilewrite "(")
		    (sfilewrite (cadr form))
		    (sfilewrite ")")
		    (if (caddr form)
			then (sfilewrite "[")
			     (sfilewrite (caddr form))
			     (sfilewrite "]"))
	    elseif (eq '+ (car form))
	       then (sfilewrite '"(")
		    (sfilewrite (cadr form))
		    (sfilewrite '")+")
	    elseif (eq '- (car form))
	       then (sfilewrite '"-(")
		    (sfilewrite (cadr form))
		    (sfilewrite '")")
	    elseif (eq '\# (car form))	; 5120 is base of small fixnums
	       then (sfilewrite (concat "$" (+ (* (cadr form) 4) 5120)))
	    elseif (eq '$ (car form))
	       then (sfilewrite '"$")
		    (sfilewrite (cadr form)))))

#+for-68k
(defun e-cvtas (form)
   (if (atom form)
       then (sfilewrite form)
       else (if (eq '* (car form))
		then (if (eq '\# (cadr form))
			 then (setq form `($ ,(caddr form)))))
	    (if (numberp (car form))
		then (sfilewrite (cadr form))
		     (sfilewrite "@")
		     (if (not (zerop (car form)))
			 then (sfilewrite "(")
			      (sfilewrite (car form))
			      (sfilewrite ")"))
	    elseif (eq '% (car form))
	       then (setq form (cdr form))
		    (sfilewrite (cadr form))
		    (sfilewrite "@(")
		    (sfilewrite (car form))
		    (sfilewrite ",")
		    (sfilewrite (caddr form))
		    (sfilewrite ":L)")
	     elseif (eq '+ (car form))
		then (sfilewrite (cadr form))
		     (sfilewrite '"@+")
	     elseif (eq '- (car form))
		then (sfilewrite (cadr form))
		     (sfilewrite '"@-")
	     elseif (eq '\# (car form))
		then (sfilewrite (concat '#.Nilatom "+0x1400"
					 (if (null (signp l (cadr form)))
					     then "+" else "")
					 (* (cadr form) 4)))
	     elseif (eq '$ (car form))
		then (sfilewrite '"#")
		     (sfilewrite (cadr form))
	       else (comp-err " bad arg to e-cvtas : " (or form)))))

;--- e-docomment :: print any comment lines
;
(defun e-docomment nil
  (if g-comments
      then (do ((ll (nreverse g-comments) (cdr ll)))
	       ((null ll))
	       (sfilewrite "	")
	       (sfilewrite #.comment-char)
	       (do ((ll (exploden (car ll)) (cdr ll)))
		   ((null ll))
		   (tyo (car ll) vp-sfile)
		   (cond ((eq #\newline (car ll))
			  (sfilewrite #.comment-char))))
	       (terpr vp-sfile))
	   (setq g-comments nil)
     else (terpr vp-sfile)))

;--- e-goto :: emit code to jump to the location given
;
(defun e-goto (lbl)
  (e-jump lbl))

;--- e-gotonil :: emit code to jump if nil was last computed
;
(defun e-gotonil (lbl)
  (e-write2 g-falseop lbl))

;--- e-gotot :: emit code to jump if t was last computed
(defun e-gotot (lbl)
  (e-write2  g-trueop lbl))

;--- e-label :: emit a label
(defun e-label (lbl)
  (setq g-skipcode nil)
  (e-writel lbl))

;--- e-pop :: pop the given number of args from the stack
; g-locs is not! fixed
;
(defun e-pop (nargs)
  (if (greaterp nargs 0)
      then (e-dropnp nargs)))

;--- e-pushnil :: push a given number of nils on the stack
;
#+for-vax
(defun e-pushnil (nargs)
   (do ((i nargs))
       ((zerop i))
       (if (>& i 1)
	   then (e-write2 'clrq '#.np-plus)
		(setq i (- i 2))
	elseif (equal i 1)
	   then (e-write2 'clrl '#.np-plus)
		(setq i (1- i)))))

#+for-68k
(defun e-pushnil (nargs)
  (do ((i nargs))
      ((zerop i))
      (L-push '#.nil-reg)
      (setq i (1- i))))

;--- e-setupbind :: setup for shallow binding
;
(defun e-setupbind nil
  (e-move '#.bnp-sym '#.bnp-reg))

;--- e-unsetupbind :: restore temp value of bnp to real loc
;
(defun e-unsetupbind nil
  (e-move '#.bnp-reg '#.bnp-sym))

;--- e-shallowbind :: shallow bind value of variable and initialize it
;	- name : variable name
;	- val : IADR value for variable
;
(defun e-shallowbind (name val)
  (let ((vloc (d-loclit name t)))
       (e-move (e-cvt vloc) '(+ #.bnp-reg))	; store old val
       (e-move (e-cvt `(lbind ,@(cdr vloc)))
		       '(+ #.bnp-reg))		; now name
       (d-move val vloc)))		

;--- e-unshallowbind :: un shallow bind n variable from top of stack
;
#+for-vax
(defun e-unshallowbind (n)
  (e-setupbind)		; set up binding register
  (do ((i 1 (1+ i)))
      ((greaterp i n))
      (e-move `(,(* -8 i) #.bnp-reg) `(* ,(+ 4 (* -8 i)) #.bnp-reg)))
  (e-sub3 `($ ,(* 8 n)) '#.bnp-reg '#.bnp-sym))

#+for-68k
(defun e-unshallowbind (n)
  (makecomment "e-unshallowbind begin...")
  (e-setupbind)		; set up binding register
  (do ((i 1 (1+ i)))
      ((greaterp i n))
      (e-move `(,(* -8 i) #.bnp-reg) `(* ,(+ 4 (* -8 i)) #.bnp-reg)))
  (e-move '#.bnp-reg '#.bnp-sym)
  (e-sub `($ ,(* 8 n)) '#.bnp-sym)
  (makecomment "...end e-unshallowbind"))

;----------- very low level routines
; all output to the assembler file goes through these routines.
; They filter out obviously extraneous instructions as well as 
; combine sequential drops of np.

;--- e-dropnp :: unstack n values from np.
; rather than output the instruction now, we just remember that it
; must be done before any other instructions are done.  This will
; enable us to catch sequential e-dropnp's
;
(defun e-dropnp (n)
  (if (not g-skipcode)
      then (setq g-dropnpcnt (+ n (if g-dropnpcnt thenret else 0)))))

;--- em-checknpdrop :: check if we have a pending npdrop
; and do it if so.
;
(defmacro em-checknpdrop nil
   `(if g-dropnpcnt
	then (let ((dr g-dropnpcnt))
		 (setq g-dropnpcnt nil)
		 (e-sub `($ ,(* dr 4)) '#.np-reg))))

;--- em-checkskip :: check if we are skipping this code due to jump
;
(defmacro em-checkskip nil
  '(if g-skipcode then (sfilewrite #.comment-char)))


;--- e-jump :: jump to given label
; and set g-skipcode so that all code following until the next label
; will be skipped.
;
(defun e-jump (l)
  (em-checknpdrop)
  (e-write2 #+for-vax 'jbr #+for-68k 'jra l)
  (setq g-skipcode t))

;--- e-return :: do return, and dont check for np drop
;
(defun e-return nil
  (setq g-dropnpcnt nil)  ; we dont need to worry about nps
  #+for-vax (e-write1 'ret)
  #+for-68k (progn  (e-write1 'rts)
		    (sfilewrite
		       (concat g-masklab " = " (d-makemask) '#.ch-newline))
		    (sfilewrite
		       (concat g-stackspace " = "
			       (Cstackspace) '#.ch-newline))))

;--- e-writel :: write out a label
;
(defun e-writel (label)
  (setq g-skipcode nil)
  (em-checknpdrop)
  (sfilewrite label)
  (sfilewrite ":")
  (e-docomment))

;--- e-write1 :: write out one litteral
;
(defun e-write1 (lit)
  (em-checkskip)
  (em-checknpdrop)
  (sfilewrite "	")
  (sfilewrite lit)
  (e-docomment))

;--- e-write2 :: write one one litteral, and one operand
;
#+for-vax
(defun e-write2 (lit frm)
  (em-checkskip)
  (em-checknpdrop)
  (sfilewrite "	")
  (sfilewrite lit)
  (sfilewrite "	")
  (e-cvtas frm)
  (e-docomment))

#+for-68k
(defun e-write2 (lit frm)
  (em-checkskip)
  (em-checknpdrop)
  (if (and (dtpr frm) (eq (car frm) '*))
      then (e-move (cdr frm) 'a5)
	   (sfilewrite "	")
	   (sfilewrite lit)
	   (sfilewrite '"	")
	   (e-cvtas '(0 a5))
      else (sfilewrite "	")
	   (sfilewrite lit)
	   (sfilewrite '"	")
	   (e-cvtas frm))
  (e-docomment))

;--- e-write3 :: write one one litteral, and two operands
;
#+for-vax
(defun e-write3 (lit frm1 frm2)
  (em-checkskip)
  (em-checknpdrop)
  (sfilewrite "	")
  (sfilewrite lit)
  (sfilewrite "	")
  (e-cvtas frm1)
  (sfilewrite ",")
  (e-cvtas frm2)
  (e-docomment))

#+for-68k
(defun e-write3 (lit frm1 frm2)
   (em-checkskip)
   (em-checknpdrop)
   (if (and (dtpr frm1) (eq (car frm1) '*)
	    (not (and (dtpr frm2) (eq (car frm2) '*))))
       then (e-move (cdr frm1) 'a5)
	    (sfilewrite "	")
	    (sfilewrite lit)
	    (sfilewrite '"	")
	    (e-cvtas '(0 a5))
	    (sfilewrite '",")
	    (e-cvtas frm2)
	    (e-docomment)
    elseif (and (not (and (dtpr frm1) (eq (car frm1) '*)))
		(dtpr frm2) (eq (car frm2) '*))
       then (e-move (cdr frm2) 'a5)
	    (sfilewrite "	")
	    (sfilewrite lit)
	    (sfilewrite '"	")
	    (e-cvtas frm1)
	    (sfilewrite '",")
	    (e-cvtas '(0 a5))
	    (e-docomment)
    elseif (and (dtpr frm1) (eq (car frm1) '*)
		(dtpr frm2) (eq (car frm2) '*))
       then (d-regused 'd6)
	    (e-move (cdr frm1) 'a5)
	    (e-move '(0 a5) 'd6)
	    (e-move (cdr frm2) 'a5)
	    (sfilewrite "	")
	    (sfilewrite lit)
	    (sfilewrite '"	")
	    (e-cvtas 'd6)
	    (sfilewrite '",")
	    (e-cvtas '(0 a5))
	    (e-docomment)
       else (sfilewrite "	")
	    (sfilewrite lit)
	    (sfilewrite '"	")
	    (e-cvtas frm1)
	    (sfilewrite '",")
	    (e-cvtas frm2)
	    (e-docomment)))

;--- e-write4 :: write one one litteral, and three operands
;
#+for-vax
(defun e-write4 (lit frm1 frm2 frm3)
  (em-checkskip)
  (em-checknpdrop)
  (sfilewrite "	")
  (sfilewrite lit)
  (sfilewrite "	")
  (e-cvtas frm1)
  (sfilewrite ",")
  (e-cvtas frm2)
  (sfilewrite ",")
  (e-cvtas frm3)
  (e-docomment))


;--- e-write5 :: write one one litteral, and four operands
;
#+for-vax
(defun e-write5 (lit frm1 frm2 frm3 frm4)
  (em-checkskip)
  (em-checknpdrop)
  (sfilewrite "	")
  (sfilewrite lit)
  (sfilewrite "	")
  (e-cvtas frm1)
  (sfilewrite ",")
  (e-cvtas frm2)
  (sfilewrite ",")
  (e-cvtas frm3)
  (sfilewrite ",")
  (e-cvtas frm4)
  (e-docomment))

;--- d-printdocstuff
;
; describe this version
;
(defun d-printdocstuff nil
   (sfilewrite (concat ".data "
		       #.comment-char
		       " this is just for documentation "))
   (terpr vp-sfile)
   (sfilewrite (concat ".asciz \"@(#)Compiled by " compiler-name
                " on " (status ctime) '\"))
   (terpr vp-sfile)
   (do ((xx Liszt-file-names (cdr xx)))
       ((null xx))
       (sfilewrite (concat ".asciz \"" (car xx) '\"))
       (terpr vp-sfile)))
