;;; -*- Mode:LISP; Package:SIM-DEBUG; Base:10; Readtable:CL -*-

;;;;;;;;;;;;;;;;;;;;;;;
;;; Null paging device
;;;;;;;;;;;;;;;;;;;;;;;

;;; this paging device only allowes open, close and status, anything else is an error

(defstruct (null-paging-device (:include paging-devices::paging-device)
			       (:conc-name "NPD-")
			       (:constructor make-npd-internal))
  state)

(defun npd-opener (device)
  (setf (npd-state device) :open))

(defun npd-closer (device)
  (setf (npd-state device) :close))

(defun npd-illegal-op (device &rest ignore)
  (illop "Attempted paging operation to fake paging device ~a" device))

(defun make-null-paging-device ()
  (make-npd-internal
    :state :closed
    :status-generator		'npd-state
    :opener			'npd-opener
    :closer			'npd-closer
    :quantum-allocator 		'npd-illegal-op
    :quantum-deallocator	'npd-illegal-op
    :reader-initializer		'npd-illegal-op
    :writer-initializer		'npd-illegal-op
    :next-cluster-reader	'npd-illegal-op
    :next-cluster-writer	'npd-illegal-op
    :reader-activate		'npd-illegal-op
    :writer-activate		'npd-illegal-op
    :operation-completer	'npd-illegal-op))

;;; swap device for memory system simulator

;;;;;;;;;;;;;;;;;;;;;;;
;;; Fake paging device
;;;;;;;;;;;;;;;;;;;;;;;

(defstruct (lambda-disk-partition-paging-device
	     (:include paging-devices::paging-device)
	     (:conc-name "LDP-")
	     (:constructor make-ldp-paging-device-internal))
  state
  disk-unit
  partition-name
  partition-offset
  partition-size
  quantum-bitmap
  accumulated-physical-cluster-swap-list
  dqin-for-this-operation
  this-op-cluster
  this-op-cluster-count
  this-op-rqb)

(defconstant *number-of-qs-in-disk-block* si:page-size)
(defconstant *disk-blocks-per-cluster* (floor *qs-in-cluster* *number-of-qs-in-disk-block*))
(defconstant *disk-blocks-per-quantum* (* *clusters-in-quantum* *disk-blocks-per-cluster*))

(defun error-unless-open (device)
  (when (eq (ldp-state device) :closed)
    (illop "this device isn't open"))
  (unless (eq (ldp-state device) :open)
    (illop "this device has an operation in progress")))

(defun ldp-status (device)
  (list (ldp-state		device)
	(ldp-disk-unit 		device)
	(ldp-partition-name 	device)
	(ldp-partition-offset 	device)
	(ldp-partition-size 	device)
	(ldp-quantum-bitmap 	device)
	(ldp-accumulated-physical-cluster-swap-list device)
	(ldp-dqin-for-this-operation device)
	(ldp-this-op-cluster 	device)
	(ldp-this-op-cluster-count device)
	(ldp-this-op-rqb 	device)))

(defun ldp-open (device)
  (unless (eq (ldp-state device) :closed)
    (ferror nil "device already opened"))
  (multiple-value-bind (p-off p-size)
    (si:find-disk-partition (ldp-partition-name device) nil (ldp-disk-unit device))
    (setf (ldp-partition-offset device) p-off)
    (setf (ldp-partition-size device) p-size))
  (setf (ldp-quantum-bitmap device)
	(global::make-array (floor (ldp-partition-size device) *disk-blocks-per-quantum*)
		    :type art-1b :initial-element 0))
  (setf (ldp-state device) :open)
  t)

(defun ldp-close (device)
  (error-unless-open device)
  (setf (ldp-state device) :closed)
  t)

(defun ldp-quantum-allocator (device)
  (error-unless-open device)
  (dotimes (i (array-dimension (ldp-quantum-bitmap device) 0) nil)
    (when (zerop (aref (ldp-quantum-bitmap device) i))
      (aset 1 (ldp-quantum-bitmap device) i)
      (return i))))

(defun ldp-quantum-deallocator (device device-quantum-id-number)
  device
  (error-unless-open device)
  (if (= 1 (aref (ldp-quantum-bitmap device) device-quantum-id-number))
      (progn (aset 0 (ldp-quantum-bitmap device) device-quantum-id-number)
	     t)
    (ferror nil "quantum not allocated")))

(defun ldp-start-read (device dqin cluster-in-quantum)
  (error-unless-open device)
  (setf (ldp-dqin-for-this-operation device) dqin)
  (setf (ldp-this-op-cluster device) cluster-in-quantum)
  (setf (ldp-state device) :read-started)
  t)

(defun ldp-next-cluster-read (device physical-cluster-number)
  device
  (unless (eq (ldp-state device) :read-started)
    (ferror nil "a read operation has not been started for this device"))
  (incf (ldp-this-op-cluster-count device)) 
  (push physical-cluster-number (ldp-accumulated-physical-cluster-swap-list device))
  t)

(defun ldp-activate-read (device)
  device
  (unless (eq (ldp-state device) :read-started)
    (ferror nil "a read operation has not been started for this device"))
  (let* ((transfer-size (* (ldp-this-op-cluster-count device) *disk-blocks-per-cluster*))
	 (part-offset (+ (* (ldp-this-op-cluster device) *disk-blocks-per-cluster*)
			 (* (ldp-dqin-for-this-operation device) *disk-blocks-per-quantum*))))
    (when (>= (+ part-offset transfer-size) (ldp-partition-size device))
      (ferror nil "transfer outside of partition boundaries"))
    (setf (ldp-this-op-rqb device) (si:get-disk-rqb transfer-size))
    (si:disk-read (ldp-this-op-rqb device)
		  (ldp-disk-unit device) (+ (ldp-partition-offset device) part-offset))
    (setf (ldp-state device) :read-in-progress)
    ;disk-read doesn't return until the operation is complete
    (paging-devices::operation-complete device)
    t))

(defun ldp-start-write (device dqin cluster-in-quantum)
  (error-unless-open device)
  (setf (ldp-dqin-for-this-operation device) dqin)
  (setf (ldp-this-op-cluster device) cluster-in-quantum)
  (setf (ldp-state device) :write-started)
  t)

(defun ldp-next-cluster-write (device physical-cluster-number)
  device
  (unless (eq (ldp-state device) :write-started)
    (ferror nil "a write operation has not been started for this device"))
  (push physical-cluster-number (ldp-accumulated-physical-cluster-swap-list device))
  t)

(defun ldp-activate-write (device)
  device
  (unless (eq (ldp-state device) :write-started)
    (ferror nil "a write operation has not been started for this device"))
  (let* ((transfer-size (* (ldp-this-op-cluster-count device) *disk-blocks-per-cluster*))
	 (part-offset (+ (* (ldp-this-op-cluster device) *disk-blocks-per-cluster*)
			 (* (ldp-dqin-for-this-operation device) *disk-blocks-per-quantum*))))
    (when (>= (+ part-offset transfer-size) (ldp-partition-size device))
      (ferror nil "transfer outside of partition boundaries"))
    (setf (ldp-this-op-rqb device) (si:get-disk-rqb transfer-size))
    (si:disk-write (ldp-this-op-rqb device)
		   (ldp-disk-unit device) (+ (ldp-partition-offset device) part-offset))
    (setf (ldp-state device) :write-in-progress)
    (paging-devices::operation-complete device)))

(defun ldp-operation-complete (device)
  device
  (let ((clusters (nreverse (ldp-accumulated-physical-cluster-swap-list device)))
	(buf (si:rqb-buffer (ldp-this-op-rqb device))))
    (dotimes (i (ldp-this-op-cluster-count device))
      (let ((cluster (pop clusters)))
	(copy-array-portion buf (* 2 i *qs-in-cluster*)
			    (* 2 (1+ i) *qs-in-cluster*)
			    (global::make-array (* 2 sys:page-size) :type art-16b
					:displaced-to
					(+ simulator::*physical-memory-region-origin*
					   (* cluster *qs-in-cluster*)))
			    0 (* 2 sys:page-size))))
    (si:return-disk-rqb (ldp-this-op-rqb device))
    (setf (ldp-accumulated-physical-cluster-swap-list device) nil)
    (setf (ldp-dqin-for-this-operation device) nil)
    (setf (ldp-this-op-cluster device) nil)
    (setf (ldp-this-op-cluster-count device) 0)
    (setf (ldp-this-op-rqb device) nil)
    (setf (ldp-state device) :open)
    t))

(defun make-lambda-disk-partition-paging-device (unit part)
  (make-ldp-paging-device-internal
    :state 			:closed
    :disk-unit 			unit
    :partition-name	 	part
    :accumulated-physical-cluster-swap-list 	nil
    :this-op-cluster-count 	0
    
    :status-generator		'ldp-status
    :opener			'ldp-open
    :closer			'ldp-close
    :quantum-allocator 		'ldp-quantum-allocator
    :quantum-deallocator	'ldp-quantum-deallocator
    :reader-initializer		'ldp-start-read
    :writer-initializer		'ldp-start-write
    :next-cluster-reader	'ldp-next-cluster-read
    :next-cluster-writer	'ldp-next-cluster-write
    :reader-activate		'ldp-activate-read
    :writer-activate		'ldp-activate-write
    :operation-completer	'ldp-operation-complete))

;;; For the purposes of simulation, the quantum map devices
;;; will be offsets into this vector which will point to
;;; quantum devices.

(defvar *quantum-devices* '())

(defvar *null-paging-device*)
(defvar *fake-paging-device*)

(defun initialize-paging-devices ()
  (when (not (boundp '*null-paging-device*))
    (setq *null-paging-device* (make-null-paging-device))
    (push *null-paging-device* *quantum-devices*))
  (when (not (boundp '*fake-paging-device*))
    (setq *fake-paging-device*
	  (make-lambda-disk-partition-paging-device 0 "METR"))
    (push *fake-paging-device* *quantum-devices*)))

(eval-when (load)
  (initialize-paging-devices))

(defconstant *quantum-device-vector* (make-array 16.))

;;;;;;;;;;;;;;;
;;; Memory Map
;;;;;;;;;;;;;;;

;;; The parenthesized map values are marginal.
;;; They have the same effect, but should never
;;; be used.
(defconstant map-status-values
	     #("read-mar"
	       "read-only"
	       "aged-to-read-mar"
	       "direct-mapped"
	       "(read-mar)"
	       "(read-only)"
	       "aged-to-read-only"
	       "(normal)"
	       "swapped-out"
	       "(read-only)"
	       "(unused)"
	       "(normal)"
	       "(swapped-out)"
	       "(read-only)"
	       "aged-to-normal"
	       "normal"))

(defun map-status->string (map-status)
  (aref map-status-values map-status))

(defun show-map (entry stream)
  (let ((bits (map::read-map entry)))
    (format stream "~&~5,48d ~:[NUBUS ~7,48d~*~;LOCAL    ~*~4,48d~] ~
               Volatility ~D ~
               ~15a ~@[~*Fresh~]"
	    entry
	    (map::map-local-memory?      bits)
	    (map::map-off-board-address  bits)
	    (map::map-on-board-address   bits)
	    (map::map-cluster-volatility bits)
	    (aref map-status-values (map::extract-map-status bits))
	    (map::cluster-is-fresh? bits))))

(defun show-gc-ram (quantum stream)
  (hw:write-md-unboxed (ash quantum (byte-position hw:%%gc-ram-md-byte)))
  (let ((bits (hw:read-gc-ram)))
    (format stream "~&~4,48d Volatility ~d ~:[not oldspace~;oldspace~]" quantum 
	    (ldb hw:%%gc-ram-quantum-volatility bits)
	    (= (ldb hw:%%gc-ram-quantum-oldspace bits) hw:$$oldspace))))

;;;;;;;;
;;; PCD
;;;;;;;;

(defconstant pcd-status-values
	     #("invalid"
	       "wired"
	       "normal"
	       "age-1"
	       "age-2"
	       "age-3"				;
	       "flushable"
	       "pre-paged"))

(defun decode-pcd (entry)
  (list (ldb pcd::%%pcd-virtual-cluster-number entry)
	(aref pcd-status-values (ldb pcd::%%pcd-status entry))
	(ldb-test pcd::%%pcd-clean-bit     entry)
	(ldb-test pcd::%%pcd-read-only-bit entry)
	(ldb-test pcd::%%pcd-write-mar-bit entry)
	(ldb-test pcd::%%pcd-read-mar-bit  entry)))

(defun show-pcd (index stream)
  (apply #'format stream "~&~4,48d ~5,48d ~9a ~
                                          ~:[    ~;not-~]modified ~
                                          read-~:[write~;only ~] ~
                                          ~@[~*write-mar~] ~
                                          ~@[~*read-mar~]"
	 index (decode-pcd (pcd::read-pcd index))))

;;;;;;;;;;;;;;;;;;;;;;;
;;; Simulation startup
;;;;;;;;;;;;;;;;;;;;;;;

;;; Fake up the initial memory.
(defun cold-boot-simulation ()
  (sim::reset-simulation)
  (setq sim::*memory-status*
	(sim:k-dpb sim::$$16meg-or-less sim::%%k-memory-status-16meg 0.))

  (setq trap::trap-mask (1- (ash 1. 32.)))
  (setq sim::*trap* 0.)

  (format t "~&Direct mapping ...")
  (map:direct-map)

  (format t " done.~&Loading memory ...")
  (load-boot-vector)
  (load-initial-physical-cluster-data)
  (load-boot-gc-ram-data)
  (load-initial-map-data)

;  (load-boot-transporter-ram-data)
  (load-boot-quantum-map)
  (load-boot-region-bits)
  (map-boot-vector 0.)
  (format t " done.")
  (when (y-or-n-p "~&Cold boot?")
    (boot::cold-boot-function)))

;;; NIL is at virtual address 0.
;;; The Boot vector is an art-32b whose data begins at location 512.
;;; in the middle of cluster 0.  We assume that the cold load builder
;;; will place a header of the appropriate type before it.

;;; The physical cluster table will go in quantum 1.
;;; It takes up half of a quantum.
;;; In the second half of the quantum, we put
;;; the quantum map and the region bits.  Each of
;;; these takes up a quater of the quantum.

;;; Physical locations of the initial data.

(defparameter *boot-vector-origin*                             512.)	;absolute.

;; Cluster addresses
(defparameter *initial-map-data-physical-location*  (cluster->address 2.))	;64 clusters

(defparameter *quantum-map-physical-location*                   66.)
(defparameter *quantum-map-clusters*                             4.)

(defparameter *region-bits-physical-location*                   70.)
(defparameter *region-bits-clusters*                             4.)

(defparameter *initial-physical-cluster-data-physical-location* 74.)	;1 cluster

(defparameter *initial-gc-ram-data-physical-location*           (cluster->address 75.))	;1 cluster

(defparameter *initial-transporter-ram-data-physical-location*  76.)    ;1 cluster

;;; Virtual addresses of nifty things.

;;; Quantum 0.
;;; Cluster 1.
(defparameter *temporary-map-entry-location*            (ash 1. (byte-position %%cluster-number)))


;;; Quantum 1.
;;; Clusters 0. 7.
(defparameter *physical-cluster-table-location*        (* 1 (ash 1 (byte-position %%quantum-number))))

;;; Clusters 8. 11.
(defparameter *quantum-map-virtual-location*            (+ *physical-cluster-table-location*
							  (ash 1. (1- (byte-position %%quantum-number)))))
;;; Clusters 12. 15.
(defparameter *region-bits-virtual-location*            (+ *quantum-map-virtual-location*
							  (ash 1 (- (byte-position %%quantum-number) 2))))


;;; The microcode assumes that all physical clusters
;;; beyond this one are free.

(defparameter *boot-physical-cluster-free-pointer* 50.)

;;; Someday, I'll figure out how to do this right.

(defun get-boot-vector-entries ()
	(list 
	  (list 'boot::*initial-map-data*
		*initial-map-data-physical-location*)
	  (list 'boot::*initial-gc-ram-data*
		*initial-gc-ram-data-physical-location*)
	  (list 'vmem::*physical-cluster-free-pointer*
		*boot-physical-cluster-free-pointer*)
	  (list 'vmem::*temporary-map-entry* *temporary-map-entry-location*)
	  (list 'vmem::*physical-cluster-initially-wired-pointer*
		*initial-physical-cluster-data-physical-location*)
	  (list 'vmem::*physical-cluster-data-table*
		*physical-cluster-table-location*)
	  (list 'vmem::*physical-cluster-free-list*     0.)
	  (list 'vmem::*physical-cluster-free-clusters* 0.)
	  (list 'vmem::*quantum-map*
		*quantum-map-virtual-location*)
	  (list 'vmem::*region-bits*
		*region-bits-virtual-location*)
	  ))

;;; Fake up boot vector for simulation.

(defun load-boot-vector ()
  (do ((tail     (get-boot-vector-entries) (rest tail))
       (location *boot-vector-origin*  (1+ location)))
      ((null tail) `())
    (micro::physical-memory-write-direct location (second (first tail)))))

(defun map-boot-vector (physical-cluster)
  (map::associate-local-memory physical-cluster 0 map::$$map-status-direct-mapped))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Initial physical cluster data
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun get-initial-physical-cluster-data ()
	(list 

	  (list *quantum-map-physical-location*
		*quantum-map-virtual-location*
		pcd::$$init-map-wired
		*quantum-map-clusters*)

	  (list *region-bits-physical-location*
		*region-bits-virtual-location*
		pcd::$$init-map-wired
		*region-bits-clusters*)

	  ;; This must be last.  It maps NIL.
	  (list 0.
		0.
		pcd::$$init-map-wired-read-only
		1.)))
	   

;;; This function fakes up the initial physical cluster data.
(defun load-initial-physical-cluster-data ()
  (let ((pointer (1- *initial-physical-cluster-data-physical-location*)))
  (dolist (record (get-initial-physical-cluster-data))
    (micro::physical-memory-write-direct (incf pointer) (first  record))
    (micro::physical-memory-write-direct (incf pointer)
					 (cluster-number (second record)))
    (micro::physical-memory-write-direct (incf pointer) (third  record))
    (micro::physical-memory-write-direct (incf pointer) (fourth record)))))

(defun get-boot-gc-ram-data ()
  (list
    ;; quantum, volatility, oldspace
    ;; Resident symbols
    (list 0. 1. hw:$$not-oldspace)
    ;; Paging tables
    (list 1. 0. hw:$$not-oldspace)))

(defun load-boot-gc-ram-data ()
  (dotimes (i gc-ram::*number-of-gc-ram-entries*)
    (micro::physical-memory-write-direct
      (+ i  *initial-gc-ram-data-physical-location*)
      (dpb-multiple-unboxed
	0.                hw:%%gc-ram-quantum-volatility
	hw:$$not-oldspace hw:%%gc-ram-quantum-oldspace
	0.)))
  (dolist (record (get-boot-gc-ram-data))
    (micro::physical-memory-write-direct
      (+ (first record) *initial-gc-ram-data-physical-location*)
      (dpb-multiple-unboxed
	(second record) hw:%%gc-ram-quantum-volatility
	(third  record) hw:%%gc-ram-quantum-oldspace
	0.))))

;(defun load-boot-transporter-ram-data ()
;  ;; All unused entries trap.
;  (dotimes (mode transporter-ram::*number-of-transporter-modes*)
;    (dotimes (type transporter-ram::*number-of-transport-types*)
;      (dotimes (md-byte transporter-ram::*number-of-transporter-md-byte-values*)
;	(let ((transporter-data 0.))
;	  (dotimes (vma-boxed 2.)
;	    (dotimes (md-boxed 2.)
;	      (setq transporter-data
;		    (sim:k-dpb
;		      (sim:k-ldb
;			(sim:k-dpb
;			  hw::$$trappable-pointer    sim::%%k-transporter-ram-trappable-pointer
;			  (sim:k-dpb
;			    hw::$$trap-if-oldspace     sim::%%k-transporter-ram-trap-if-oldspace
;			    (sim:k-dpb
;			      hw::$$trap-if-not-oldspace sim::%%k-transporter-ram-trap-if-not-oldspace
;			      (sim:k-dpb
;				hw::$$box-error            sim::%%k-transporter-ram-box-error
;				0))))
;			(byte 4. 4.)
;			0.)
;		      (byte 4. (* 4. (+ (* vma-boxed 2) md-boxed)))
;		      transporter-data))))
;	  (micro::physical-memory-write-direct
;	    (+ (cluster->address *initial-transporter-ram-data-physical-location*)
;	       (sim:k-dpb
;		 md-byte (byte (byte-size sim::%%k-transporter-md-byte) 0.)
;		 (sim:k-dpb
;		   type    (byte (byte-size sim::%%k-memory-status-transport-ram-bits)
;				 (byte-size sim::%%k-transporter-md-byte))
;		   (sim:k-dpb
;		     mode    (byte (byte-size sim::%%k-memory-control-transporter-mode)
;				   (+ (byte-size sim::%%k-memory-status-transport-ram-bits)
;				      (byte-size sim::%%k-transporter-md-byte)))
;		     0.))
;		 transporter-data)))))

;  ;; Normal mode, all unboxed never traps.
;  (let ((mode      $$transport-mode-normal)
;	(vma-boxed $$unboxed)
;	(md-boxed  $$unboxed))
;    (dotimes (type *number-of-transport-types*)
;      (dotimes (md-byte *number-of-transporter-md-byte-values*)
;	(let* ((location
;		 (+ (cluster->address *initial-transporter-ram-data-physical-location*)
;		    (dpb-multiple-unboxed
;		      md-byte (byte (byte-size %%k-transporter-md-byte) 0.)
;		      type    (byte (byte-size %%k-memory-status-transport-type)
;				    (byte-size %%k-transporter-md-byte))
;		      mode    (byte (byte-size %%k-memory-control-transporter-mode)
;				    (+ (byte-size %%k-memory-status-transport-type)
;				       (byte-size %%k-transporter-md-byte)))
;		      0.)))
;	       (transporter-data (micro::physical-memory-read-direct location)))
;	  (setq transporter-data
;		(%dpb
;		  (%ldb
;		    (dpb-multiple-unboxed
;		      $$non-trappable-pointer     %%k-transporter-ram-trappable-pointer
;		      $$dont-trap-if-oldspace     %%k-transporter-ram-trap-if-oldspace
;		      $$dont-trap-if-not-oldspace %%k-transporter-ram-trap-if-not-oldspace
;		      $$no-box-error              %%k-transporter-ram-box-error
;		      0.)
;		    (byte 4. 4.)
;		    0.)
;		  (byte 4. (* 4. (+ (* vma-boxed 2) md-boxed)))
;		  transporter-data))
;	  (micro::physical-memory-write-direct location transporter-data)))))

;  ;; Normal mode, type no-transport, never trans trap.
;  (let ((mode $$transport-mode-normal)
;	(type $$transport-type-no-transport))
;    (dotimes (md-byte *number-of-transporter-md-byte-values*)
;      (let* ((location
;	       (+ (cluster->address *initial-transporter-ram-data-physical-location*)
;		  (dpb-multiple-unboxed
;		    md-byte (byte (byte-size %%k-transporter-md-byte) 0.)
;		    type    (byte (byte-size %%k-memory-status-transport-type)
;				  (byte-size %%k-transporter-md-byte))
;		    mode    (byte (byte-size %%k-memory-control-transporter-mode)
;				  (+ (byte-size %%k-memory-status-transport-type)
;				     (byte-size %%k-transporter-md-byte)))
;		    0.)))
;	     (transporter-data (micro::physical-memory-read-direct location)))
;	(dotimes (vma-boxed 2.)
;	  (dotimes (md-boxed 2.)
;	    (setq transporter-data
;		  (%dpb
;		    (%ldb
;		      (dpb-multiple-unboxed
;			$$dont-trap-if-oldspace     %%k-transporter-ram-trap-if-oldspace
;			$$dont-trap-if-not-oldspace %%k-transporter-ram-trap-if-not-oldspace
;			$$no-box-error              %%k-transporter-ram-box-error
;			(%ldb transporter-data (byte 4. (* 4. (+ (* vma-boxed 2) md-boxed))) 0.))
;		      (byte 4. 4.)
;		      0.)
;		    (byte 4. (* 4. (+ (* vma-boxed 2) md-boxed)))
;		    transporter-data))))
;	(micro::physical-memory-write-direct location transporter-data)))))


(defparameter *boot-quanta*
	     (list
	       (list 0. *null-paging-device* 0)
	       (list 1. *null-paging-device* 1)))

(defun load-boot-quantum-map ()
  (do ((devices (reverse *quantum-devices*) (if devices (rest devices) nil))
       (devnum  0                 (1+ devnum)))
      ((or (null devices) (= devnum 16.))
       (when devices
	 (ferror nil "Too many quantum devices")))
    (setf (aref *quantum-device-vector* devnum)
	  (if devices
	      (first devices)
	      *null-paging-device*
	      )))

  ;; Zero all quanta.
  (dotimes (i *number-of-quanta*)
    (micro::physical-memory-write-direct
      (+ i (cluster->address *quantum-map-physical-location*))
      0.))

  ;; Write initial quanta.
  (dolist (q *boot-quanta*)
    (micro::physical-memory-write-direct
      (+ (first q) (cluster->address *quantum-map-physical-location*))
      (dpb-multiple-unboxed
	(find-position-in-list (second q) *quantum-devices*)
	                               quantum-map::%%quantum-map-device
	(third  q)                     quantum-map::%%quantum-map-region-origin
	quantum-map::$$quantum-mapped  quantum-map::%%Quantum-map-status
	0.))))

(defun init-boot-vector-macro ()
  (do ((tail (get-boot-vector-entries) (rest tail))
       (count 0 (1+ count))
       (code '() (cons `(SETQ ,(first (first tail)) (BOOT::READ-BOOT-VECTOR ,count)) code)))
      ((null tail) `(PROGN ,@(reverse code)))))

(defun initialize-from-boot-vector ()
  (eval (init-boot-vector-macro)))		;GAK! CHOKE! ARGH!

(defun load-initial-map-data ()

  ;; Make everything volatility 0.
  (dotimes (i map::*number-of-map-entries*)
    (micro::physical-memory-write-direct
      (+ i *initial-map-data-physical-location*)
      (dpb-multiple-unboxed
	0.                     hw:%%map-volatility
	map::$$cluster-fresh map::%%map-fresh-cluster
      0.)))

  ;; Cluster 0 is volatility 1.
  (micro::physical-memory-write-direct
     *initial-map-data-physical-location*
    (dpb-multiple-unboxed
      1.                         hw:%%map-volatility
      map::$$cluster-not-fresh map::%%map-fresh-cluster
      0.)))

;;;;;;;;;;;;;;;;
;;; Region bits
;;;;;;;;;;;;;;;;

(defun get-boot-regions ()
	(list

	  ;; Resident symbols
	  (list 0.				;quantum 0
		1.				;one quantum long
		(region-bits:parameters->region-bits
		  region-bits:$$region-space-fixed
		  region-bits:$$scavenge-enabled
		  region-bits:$$region-read-only
		  0.))				;swapin quantum 0

	  ;; Paging tables
	  (list 1.				;quantum 1
		1.				;one quantum long
		(region-bits:parameters->region-bits
		  region-bits:$$region-space-fixed
		  region-bits:$$scavenge-disabled
		  region-bits:$$region-read-write
		  0.))				;swapin quantum 0
	  ))

(defun load-boot-region-bits ()
  ;; Zero all the region bits.
  (dotimes (i region-bits:*number-of-regions*)
    (micro::physical-memory-write-direct (+ i (cluster->address *region-bits-physical-location*))
      (region-bits:parameters->region-bits
	region-bits:$$region-space-free
	region-bits:$$scavenge-disabled
	region-bits:$$region-read-only 
	0.)))

  (dolist (record (get-boot-regions))
    (let ((quantum-start      (first  record))
	  (quantum-count      (second record))
	  (region-bits        (third  record)))
      (do ((quantum quantum-start (1+ quantum))
	   (count   quantum-count (1- count)))
	  ((zerop count))
	(micro::physical-memory-write-direct (+ quantum (cluster->address *region-bits-physical-location*))
	  region-bits)))))

(defun read-region-bits-from-gc-ram (region)
  (hw:write-md-unboxed (hw:dpb region hw:%%gc-ram-md-byte 0))
  (hw:read-gc-ram))

(defun show-region-bits (region stream)
  (let ((region-bits (region-bits::read-region-bits region))
	(gc-ram-bits (read-region-bits-from-gc-ram  region)))
    (format stream "~&~4,48D Volatility ~D ~:[~
                    ~[FREE-~;STATIC-~;FIXED-~;COPY~;NEW-LIST-~;NEW-STRUCTURE-~;ERROR~;ERROR~]~
                    ~;OLD~*~]SPACE ~
                    Scavenge ~:[Dis~;En~]abled ~
                    Read-~:[Write~;Only~] ~
                    ~2,48D"
	    region
	    (hw:ldb gc-ram-bits hw:%%gc-ram-quantum-volatility 0)
	    (= (hw:ldb gc-ram-bits hw:%%gc-ram-quantum-oldspace   0) hw:$$oldspace)
	    (region-bits::region-space-type       region-bits)
	    (region-bits::region-scavenge-enable? region-bits)
	    (region-bits::region-read-only?       region-bits)
	    (region-bits::region-swapin-quantum   region-bits))))

(defun show-quantum-map (quantum stream)
  (let ((bits (quantum-map::read-quantum-map quantum)))
    (format stream "~&~4,48D ~[EMPTY    ~;ALLOCATED~;ERROR    ~;MAPPED   ~] ~4,48D ~2,48D ~4,48D"
	    quantum
	    (quantum-map::quantum-status-bits bits)
	    (quantum-map::region-origin      bits)
	    (quantum-map::quantum-device     bits)
	    (quantum-map::quantum-dqin       bits))))

;;;;;;;;;;;;;;;;
;;; Region data
;;;;;;;;;;;;;;;;

(defun show-region (region stream)
  (let* ((quantum-bits (quantum-map::read-quantum-map region))
	 (origin (if (quantum-map::quantum-empty? quantum-bits)
		     (progn (format stream "~&Region ~D is not in the quantum map." region)
			    region)
		     (let ((origin (quantum-map:quantum-region-origin region)))
		       (when (not (= origin region))
			 (format stream "~&Region ~D seems to begin at ~D" region origin))
		       origin))))
    (show-region-bits origin stream)
    (format stream "~&Origin: ~8D, Free Pointer: ~8D, GC pointer: ~8D End: ~8D"
	    (quantum->address    origin)
	    (region-data:region-free-pointer origin)
	    (region-data:region-gc-pointer   origin)
	    (region-data:region-end          origin)
	    )))

(defun create-region-data-for-cold-load ()
  (let ((region-data (region-bits:make-region
		       (ceiling (* region-bits:*number-of-regions* 4.) *qs-in-quantum*)
		       (region-bits:parameters->region-bits
			 region-bits:$$region-space-fixed
			 region-bits:$$scavenge-disabled
			 region-bits:$$region-read-write 
			 15.)			;Swapin entire thing.
		       0.)))			;volatility 0.

    (setq region-data::*region-free-pointer*      (quantum->address region-data))
    (setq region-data::*region-allocation-status* (+ region-data::*region-free-pointer*
						     region-bits:*number-of-regions*))
    (setq region-data::*region-end*               (+ region-data::*region-allocation-status*
						     region-bits:*number-of-regions*))
    (setq region-data::*region-gc-pointer*        (+ region-data::*region-end*
						     region-bits:*number-of-regions*))

    ;; Bash data for initial regions.  Do this right someday.
    (setf (region-data:region-free-pointer      0) (hw:dpb 1. %%quantum-number  0.))
    (setf (region-data:region-allocation-status 0) 0)
    (setf (region-data:region-end               0) (hw:dpb 1. %%quantum-number  0.))
    (setf (region-data:region-gc-pointer        0) (hw:dpb 1. %%quantum-number  0.))

    (setf (region-data:region-free-pointer      1) (hw:dpb 2. %%quantum-number  0.))
    (setf (region-data:region-allocation-status 1) 0)
    (setf (region-data:region-end               1) (hw:dpb 2. %%quantum-number  0.))
    (setf (region-data:region-gc-pointer        1) (hw:dpb 2. %%quantum-number  0.))

    ;; We ourselves is full.
    (setf (region-data:region-free-pointer region-data)
	  (+ region-data::*region-gc-pointer* region-bits:*number-of-regions*))
    (setf (region-data:region-allocation-status region-data) 0)
    (setf (region-data:region-end region-data)
	  (+ region-data::*region-gc-pointer* region-bits:*number-of-regions*))
    (setf (region-data:region-gc-pointer region-data)
	  (+ region-data::*region-gc-pointer* region-bits:*number-of-regions*))
    
    region-data
    ))

(defun create-area-data-for-cold-load (region-data-region)
  (let* ((qs-needed (+ mem:*number-of-regions*	;Region list thread
		       mem:*number-of-areas*	;Area region data
		       mem:*number-of-areas*	;Area region bits
		       mem:*number-of-areas*	;Area region size
		       ))
	 (quanta-needed (ceiling qs-needed *qs-in-quantum*))
	 (region-bits (region-bits:parameters->region-bits
			region-bits:$$region-space-fixed
			region-bits:$$scavenge-disabled
			region-bits:$$region-read-write
			(max 15. (1- (* quanta-needed *clusters-in-quantum*)))))
	 (region (region-data:make-region quanta-needed region-bits 1)))
    
    (setq memlow:*region-list-thread* (region-data::region-free-pointer region))
    (region-data::advance-free-pointer region mem:*number-of-regions*)

    (setq memlow:*area-region-data* (region-data::region-free-pointer region))
    (region-data::advance-free-pointer region mem:*number-of-areas*)

    (setq memlow::*area-region-bits* (region-data::region-free-pointer region))
    (region-data::advance-free-pointer region mem:*number-of-areas*)

    (setq memlow::*area-region-size* (region-data::region-free-pointer region))
    (region-data::advance-free-pointer region mem:*number-of-areas*)

    (setf (region-data::region-gc-pointer region) (region-data::region-free-pointer region))

    ;;; Zero out the area tables
    (dotimes (area mem:*number-of-areas*)
      (setf (area-data::area-region-data area)
	    (hw:dpb area-data::$$area-free area-data::%%area-data-area-status 0.)))

    ;;; Setup RESIDENT SYMBOL AREA
    (setf (area-data::area-region-data   0.)
	  (dpb-multiple-boxed
	    area-data::$$area-fixed area-data::%%area-data-area-status
	    0.                      area-data::%%area-data-region-thread
	    0.))
    (setf (area-data::region-list-thread 0.)
	  (hw:dpb-boxed area-data::$$thread-ends area-data::%%region-list-thread-end-flag 0.))
    (setf (area-data::area-region-size   0.) 0.)
    (setf (area-data::area-region-bits   0.)
	  (dpb-multiple-boxed
	    (region-bits::parameters->region-bits
	      region-bits::$$region-space-fixed
	      region-bits::$$scavenge-enabled
	      region-bits::$$region-read-only
	      0.)))

    ;;; Setup PAGING TABLE AREA
    (setf (area-data::area-region-data   1.)
	  (dpb-multiple-boxed
	    area-data::$$area-fixed area-data::%%area-data-area-status
	    1.                      area-data::%%area-data-region-thread
	    0.))
    (setf (area-data::region-list-thread 1.)
	  (hw:dpb-boxed area-data::$$thread-ends area-data::%%region-list-thread-end-flag 1.))
    (setf (area-data::area-region-size   1.) 0.)
    (setf (area-data::area-region-bits   1.)
	  (dpb-multiple-boxed
	    (region-bits::parameters->region-bits
	      region-bits::$$region-space-fixed
	      region-bits::$$scavenge-enabled
	      region-bits::$$region-read-only
	      0.)))

    ;;; Setup MEMORY MANAGEMENT AREA
    (setf (area-data::area-region-data   2.)
	  (dpb-multiple-boxed
	    area-data::$$area-fixed area-data::%%area-data-area-status
	    region-data-region      area-data::%%area-data-region-thread
	    0.))
    (setf (area-data::region-list-thread region-data-region)
	  (hw:dpb-boxed area-data::$$thread-continues area-data::%%region-list-thread-end-flag region))
    (setf (area-data::region-list-thread region)
	  (hw:dpb-boxed area-data::$$thread-ends area-data::%%region-list-thread-end-flag region-data-region))
    (setf (area-data::area-region-size 2.) 0.)
    (setf (area-data::area-region-bits 2.) region-bits)))

(defun show-area (area stream)
  (let ((bits (area-data::area-region-bits area))
	(data (area-data::area-region-data area))
	(size (area-data::area-region-size area)))
    (let ((status (hw:ldb data area-data::%%area-data-area-status 0))
	  (thread (hw:ldb data area-data::%%area-data-region-thread 0))
	  (rbits  (hw:ldb bits area-data::%%area-region-bits-the-bits 0))
	  (vol    (hw:ldb bits area-data::%%area-region-bits-volatility 0)))
    (format stream "~&Area ~D ~[Free~;Empty~;~;Fixed~]. Regions will be Volatility ~D. ~D quanta."
	    area
	    status
	    vol
	    size)
    (when (= 1 (hw:ldb data area-data::%%area-data-area-has-regions 0))
      (let (region)
	(tagbody
	 loop
	    (setq region (hw:ldb thread (byte (byte-size quantum-map::%%quantum-map-region-origin) 0) 0))
	    (when (= area-data::$$thread-ends (hw:ldb thread area-data::%%region-list-thread-end-flag 0))
	      (when (not (= region area)) (format t "~&Thread does not re-connect!"))
	      (return-from show-area nil))
	    (show-region region stream)
	    (setq thread (area-data::region-list-thread region))
	    (go loop)))))))
