;;; -*- Mode:LISP; Package:MAC; Readtable:T; Base:10 -*- ;;; ;;; By Renaud Nadeau October 1988 ;;; ;;; ;;; Constants, variables and functions used by the BC share-memory ;;; (defconst Falcon-version-number 1) (defconst BC-base-adr #xfb000000) ; ; All transition state for the KMAC communications ; (defconst ST-IDLE 0) (defconst ST-FILLING 1) (defconst ST-FILLED 2) (defconst ST-RUN 3) (defconst ST-DONE 4) (defconst ST-ERROR 5) (defconst ST-FAULT 6) ; ; All device Status Codes for the buffered stream ; (defconst DST-CLOSED 0) (defconst DST-OPEN 1) (defconst DST-EOF 2) (defconst DST-ERROR 3) (defconst DST-CONTINUABLE-ERROR 4) (defconst CMD-QUIT 1) (defconst CMD-REBOOT 2) (defconst CMD-SHUTDOWN 3) (defconst CMD-CREATE-DEVICE 4) (defconst CMD-DELETE-DEVICE 5) (defconst CMD-OPEN 6) (defconst CMD-CLOSE 7) (defconst CMD-RENAME 8) (defconst CMD-DELETE 9) (defconst CMD-CHANGE-PROPERTIES 10) (defconst CMD-DIRECTORY-LIST 11) (defconst CMD-EXPUNGE-DIRECTORY 12) (defconst CMD-CREATE-DIR 13) (defconst CMD-COMPLETE-STRING 14) (defconst CMD-REWIND 15) (defconst CMD-SETEOF 16) (defconst CMD-PRINt 17) ;(defconst CMD-READ 101) ;(defconst CMD-WRITE 102) ;(defconst CMD-NEXT-DIRECTORY 113) ;(defconst CMD-FINISH-OUTPUT 114) ;(defconst CMD-PAGEIN 3) ;(defconst CMD-PAGEOUT 4) (declare (special *BC-memory-available* header-table)) ;;; ;;; Definition of the methods to allocate the Bus-Coupler memory ;;; (defun alloc-BC-memory (size &optional (init-list nil)) (let* ((struct *BC-memory-available*)(adr struct)) (setq *BC-memory-available* (+ (* 4 size) *BC-memory-available*)) (loop for each in init-list do (write-BC-long adr (if each each 0)) (decf size) (incf adr 4)) (loop repeat size do (write-BC-long adr 0) (incf adr 4)) struct)) ;;; ;;; Definition of the structure :bc-struct ;;; (eval-when (compile load) (defun make-ascii-number (ignore stream) (loop with char = (character (readch stream)) and n = 0 until (or (char-lessp char #/A) (char-greaterp char #/Z)) do (setq n (+ (character char) (ash n 8))) (setq char (character (readch stream))) finally (return n))) (set-syntax-#-macro-char #/& 'make-ascii-number) (si:defstruct-define-type :bc-struct (:cons-keywords :size ) (:cons (init description keywords) :list description `(alloc-bc-memory ,(* 4 (or (cdr (assq :size keywords)) (length init))) (list ,@init))) (:ref (number description address offset) description `(read-bc-long (+ ,(* 4 number) ,address ,offset)))) (defsetf read-bc-long write-bc-long)) ;;; ;;; All structure use in the communication between Mac <-> Falcon ;;; ; The organisation of the file for each structure look like ; ; Declaration of the constants related to the specific structure ; Declaration of the variables " " " " " ; Declaration of the structure " " " " " ; Declaration of the functions " " " " " ;;; (defconst kmac-header-CMD-number #X52010064) (defconst kmac-header-Mac-CMD-number #x52100064) (defconst *command-struct-var-size* 36) (defstruct (command :conc-name (:type (:bc-struct)) (:default-pointer 0)) header (state ST-IDLE) command arg-count val-count err-code err-string stream args) (defun send-cmd-wait (struct cmd narg nval &rest args) (setf (Command-state struct) ST-FILLED) (setf (Command-command struct) cmd) (setf (Command-arg-count struct) narg) (setf (Command-val-count struct) nval) (setf (Command-err-code struct) 0) (setf (Command-err-string struct) 0) (setf (Command-stream struct) 0) (loop with offset = 0 for each in args do (setf (Command-args struct offset)each) (incf offset 4)) (setf (Command-state struct) ST-FILLED) (process-wait "BC" #'(lambda () (let ((state (Command-state struct))) (or (= state ST-DONE) (= state ST-ERROR) (= state ST-FAULT))))) (if (eq ST-FAULT (Command-state struct)) (ferror "Protocol fault no: ~a in command no: ~a" (Command-err-code struct) cmd))) ;;; ;;; The keyboard and mouse is a fixe structure ;;; (defconst kmac-header-KBD-number #x5207001c) (defconst *kbd-ring-buffer-item-size* 8) (defconst *kbd-ring-buffer-length* 128) (defconst *kbd-ring-buffer-size* (* *kbd-ring-buffer-item-size* *kbd-ring-buffer-length*)) (defstruct (KBD :conc-name (:type :bc-struct) (:default-pointer 0)) (header kmac-header-KBD-number) buffer-start buffer-end buffer-input buffer-output mouse-x mouse-y) (defstruct (kbd-entry :conc-name (:type :bc-struct) (:default-pointer 0)) type-modifiers char-or-mouse) ;;; ;;; cold-stream buffer ;;; (defconst kmac-header-cold-stream #X52200014) (defconst *cold-ring-buffer-item-size* 8) (defconst *cold-ring-buffer-length* 128) (defconst *cold-ring-buffer-size* (* *cold-ring-buffer-item-size* *cold-ring-buffer-length*)) (defstruct (cold-str :conc-name (:type :bc-struct) (:default-pointer 0)) (header kmac-header-cold-stream) buffer-start buffer-end buffer-input buffer-output) ;;; ;;; The device table is create by the Falcon but ;;; it is maintains by the Mac aplication ;;; (defconst kmac-header-Dev-Table-number #x520200c8) (defstruct (Dev-Tab :conc-name (:type (:bc-struct)) (:default-pointer 0)) (header kmac-header-Dev-table-number) name blks) ;;; ;;; Allocation for the Screen Descriptor ;;; (defconst kmac-header-Screen-number #x52030024) (defstruct (SD :conc-name (:type :bc-struct) (:default-pointer 0)) (header kmac-header-Screen-number) Falcon-addr Falcon-depth Falcon-words-per-row Falcon-width Falcon-height Priority-CMD-blk CMD-blk Mac-window) ;;; ;;; Allocation of pathname free-list ;;; (defconst kmac-header-pathname #x5211012c) ;75 -> 300 (defconst *nb-pre-allocated-pathname* 15) (defconst *pathname-struct-var-size* 28 ) (defvar *pathname-free-list*) (defstruct (path :conc-name (:type (:bc-struct)) (:default-pointer 0)) (header kmac-header-pathname) host device name type version nb-dirs dirs) (defun write-pathname-blk (struct directory name type version) (let* ((offset 0) (length 0) (ndirs 1) (string-adr 0)) (setf (path-header struct) kmac-header-pathname) (setf (path-host struct) 0) (setf (path-device struct) 0) (if (not (listp directory)) (setq directory (list directory)) (setq ndirs (length directory))) (setq string-adr (+ *pathname-struct-var-size* (* 4 ndirs))) (setf (path-nb-dirs struct) ndirs) (loop for each-name in directory do (if (not (stringp each-name)) (setf (path-dirs struct offset) (expr->num each-name)) (setq length (string-length each-name)) (setf (path-dirs struct offset) (dpb ISA-STRING (byte 8 24.) string-adr)) (write-BC-mac-string (+ struct string-adr) each-name length) (incf string-adr (1+ length))) (incf offset 4)) (if (not (stringp name)) (setf (path-name struct) (expr->num name)) (setq length (string-length name)) (setf (path-name struct) (dpb ISA-STRING (byte 8 24.) string-adr)) (write-BC-mac-string (+ struct string-adr) name length) (incf string-adr (1+ length))) (if (not (stringp type)) (setf (path-type struct) (expr->num type)) (setq length (string-length type)) (setf (path-type struct) (dpb ISA-STRING (byte 8 24.) string-adr)) (write-BC-mac-string (+ struct string-adr) type length)) (setf (path-version struct) (expr->num version)))) (defun read-pathname-blk (struct) (let* (name type version (offset 0) (directory nil) (ndirs (path-nb-dirs struct))) (loop repeat ndirs do (setq directory (cons (num->expr (path-dirs struct offset) struct) directory)) (incf offset 4)) (setq directory (reverse directory) name (num->expr (path-name struct) struct) type (num->expr (path-type struct) struct) version (num->expr (path-version struct))) (if (= 1(length directory)) (setq directory (car directory))) (values directory name type version))) (defun init-pathname-free-list () (setq *pathname-free-list* (loop repeat *nb-pre-allocated-pathname* collect (make-path :size 75)))) (defun new-pathname-blk () (process-wait "Wait free pathname" #'(lambda () (not (null *pathname-free-list*)))) (pop *pathname-free-list*)) (defun release-pathname-blk (blk) (push blk *pathname-free-list*)) ;;; ;;; Allocation of device free-list ;;; ;;; (defconst kmac-header-Paging-number #x52040000) (defconst kmac-header-Device-number #x52050028) (defconst kmac-header-Network-number #x52080000) (defconst *nb-pre-allocated-dev-blk* 15) (defvar *device-free-list*) (defstruct (Dev :conc-name (:type :bc-struct) (:default-pointer 0)) (header kmac-header-Device-number) (status DST-CLOSED) flags Buffer-chain Current-Mac-buffer Current-Lisp-buffer Mac-state Owing-Process pathname cmd-blk) (defun init-device-free-list () (setq *device-free-list* (loop repeat *nb-pre-allocated-dev-blk* collect (make-dev :cmd-blk (make-command :size 25 :header kmac-header-CMD-number))))) (defun new-device-blk () (process-wait "Wait free Dev" #'(lambda () (not (null *device-free-list*)))) (pop *device-free-list*)) (defun release-device-blk (blk) (without-interrupts (push blk *device-free-list*))) ;;; ;;; Allocation for the file information ;;; (defconst kmac-header-info #X52120320) (defconst *info-struct-var-size* 80) (defconst *nb-pre-allocated-info-blk* 15) (defvar *info-free-list*) (defvar mac-properties '(:author :byte-size :characters :deleted :dont-delete :dont-reap :qfasl :creation-date :modification-date :not-backup :length-in-bytes :length-in-blocks :mac-type :directory)) (defvar mac-unsettable-properties '(:byte-size :characters :dont-reap :qfasl :not-backup :length-in-bytes :length-in-blocks :directory) "Unsettable properties are those which are uniquely determined by the text of the file.") (defvar mac-settable-properties (reverse (set-difference mac-properties mac-unsettable-properties))) (defstruct (info :conc-name (:type (:bc-struct)) (:default-pointer 0)) (header kmac-header-info) author byte-size characters deleted dont-delete dont-reap qfasl creation-date modification-date not-backup length-in-bytes length-in-blocks mac-type directory name type version user-plist-size user-plist) (defun init-info-free-list () (setq *info-free-list* (loop repeat *nb-pre-allocated-info-blk* collect (make-info :size 200)))) (defun new-info-blk () (process-wait "Wait free info blk" #'(lambda () (not (null *info-free-list*)))) (pop *info-free-list*)) (defun release-info-blk (blk) (without-interrupts (push blk *info-free-list*))) (defun read-info-blk (struct) (let* ((plist-size (info-user-plist-size struct)) (plist-addr (ldb (byte 24. 0) (info-user-plist struct)))) (append (list ':author (num->expr (info-author struct) struct) ':characters (num->expr (info-characters struct)) ':deleted (num->expr (info-deleted struct)) ':dont-delete (num->expr (info-dont-delete struct)) ':dont-reap (num->expr (info-dont-reap struct)) ':qfasl (num->expr (info-qfasl struct)) ':not-backup (num->expr (info-not-backup struct)) ':directory (num->expr (info-directory struct)) ':byte-size (info-byte-size struct) ':creation-date (info-creation-date struct) ':modification-date (info-modification-date struct) ':length-in-bytes (info-length-in-bytes struct) ':length-in-blocks (info-length-in-blocks struct) ':mac-type (info-mac-type struct)) (if (> plist-size 0) (let ((string (make-string plist-size))) (read-BC-in-string (+ struct plist-addr) string plist-size) (with-input-from-string (stream string) (fs:read-property-list stream))))))) (defun dissect-property-list (property-list) "Separates a plist into file properties and user properties, and verifies if the properties are settable." (let ((plist (copy-list property-list)) file-plist user-plist) (do ((prop plist (cddr prop))) ((null prop) (values file-plist user-plist)) (cond ((memq (car prop) mac-settable-properties) (push (cadr prop) file-plist) (push (car prop) file-plist)) ((not (memq (car prop) mac-unsettable-properties)) (push (cadr prop) user-plist) (push (car prop) user-plist)))))) (defun write-info-blk (struct plist) (let ((string-adr *info-struct-var-size*)) (multiple-value-bind (file-plist user-plist) (dissect-property-list plist) (loop for (prop value) on file-plist by 'cddr do (selectq prop (:author (let (length) (if (or (not (stringp value)) (> (setq length (string-length value)) 15)) (ferror "MAC error: Maximum length of author string is 15")) (setf (info-author struct) (dpb ISA-STRING (byte 8 24.) string-adr)) (write-BC-mac-string (+ struct string-adr) value length) (incf string-adr (1+ length)))) (:deleted (setf (info-deleted struct) (expr->num value))) (:dont-delete (setf (info-dont-delete struct) (expr->num value))) (:mac-type (setf (info-mac-type struct) value)) (:creation-date (setf (info-creation-date struct) value)) (:modification-date (setf (info-modification-date struct) value)))) (when user-plist (let* ((string (with-output-to-string (stream) (fs:write-property-list stream user-plist))) (length (string-length string))) (setf (info-user-plist-size struct) length) (setf (info-user-plist struct) (dpb ISA-TEXT (byte 8 24.) string-adr)) (write-BC-from-string string (+ struct string-adr) length)))))) ;;; ;;; Allocation and manipulation of the Chained IObuffers ;;; (defconst kmac-header-Buffer-number #x52060028) (defconst *buffer-descriptor-size* 40) (defconst *buffer-data-size* 512) (defconst *nb-pre-allocated-buffers* 15) (defconst *buffer-size* (+ *buffer-descriptor-size* *buffer-data-size*)) (defvar *free-buffer-list*) (defvar *nb-input-IObuffer* 2) (defvar *nb-output-IObuffer* 2) (defstruct (Buffer :conc-name (:type (:bc-struct)) (:default-pointer 0)) (header kmac-header-Buffer-number) (state ST-IDLE) next-buffer alloc-start alloc-end start end Falcon-scan Mac-scan Error-byte) (defun allocate-buffers () (setq *free-buffer-list* (loop with buffer repeat *nb-pre-allocated-buffers* do (setq buffer (make-buffer :size 138)) (setf (buffer-alloc-start buffer) buffer) (setf (buffer-alloc-end buffer) (+ buffer *buffer-size*)) (setf (buffer-start buffer) (+ buffer *buffer-descriptor-size*)) (setf (buffer-end buffer) (+ (buffer-start buffer) *buffer-data-size*)) collect buffer))) (defun get-buffer (direction) (let (buffer) (process-wait "Wait free buffer" #'(lambda () (not (null *free-buffer-list*)))) (without-interrupts (setq buffer (pop *free-buffer-list*)) (select direction (:input (setf (Buffer-state buffer) ST-DONE)) (:output (setf (Buffer-state buffer) ST-IDLE))) buffer))) (defun release-buffer (buffer) (without-interrupts (push buffer *free-buffer-list*))) (defun get-chained-iobuffers (how-many direction) (loop with first-buffer = (get-buffer direction) with next-buffer = first-buffer repeat (1- how-many) do (setf (Buffer-next-buffer next-buffer) (get-buffer direction)) (setq next-buffer (Buffer-next-buffer next-buffer)) finally (setf (Buffer-next-buffer next-buffer) first-buffer) (return first-buffer))) (defun release-chained-iobuffers (first-buffer) (when (> first-buffer 0) (loop with next = (Buffer-next-buffer first-buffer) until (= next first-buffer) do (release-buffer next) (setq next (Buffer-next-buffer next)) finally (release-buffer first-buffer)))) ;(defun how-many-chained-iobuffers (first-buffer) ; (loop with buffer = first-buffer ; summing 1 ; do (setq buffer (Buffer-next-buffer buffer)) ; until (= buffer first-buffer))) ;;; ;;; ;;; (defconst kmac-header-header-number #x52000050) (defstruct (Header-Table (:type (:bc-struct)) (:default-pointer 0)) (kmac-header-header kmac-header-header-number) falcon-protocol-version mac-protocol-version Major-CMD-blk major-Mac-CMD-blk paging-CMD-blk KBD-mouse-descriptor Screen-table File-stream-table Network-table Serial-table printer-table cold-stream) (defun allocate-communication-root() (let (KBD-buffer cold-buffer) (setq Header-Table (make-header-table :size 20)) (setf (Major-CMD-blk Header-Table) (make-command :size 25 :header kmac-header-CMD-number)) (setf (major-Mac-CMD-blk Header-Table) (make-command :size 25 :header kmac-header-Mac-CMD-number)) (setf (paging-CMD-blk Header-Table) (make-command :size 25 :header kmac-header-Paging-number)) (setq KBD-buffer (alloc-BC-memory (// *Kbd-ring-buffer-size* 4))) (setf (KBD-mouse-descriptor Header-Table) (make-KBD :buffer-start KBD-buffer :buffer-end (+ KBD-buffer *kbd-ring-buffer-size*) :buffer-input KBD-buffer :buffer-output KBD-buffer)) (setf (File-stream-table Header-Table) (make-Dev-tab :size 50 :name #&FILE )) (setf (Network-table Header-Table) (make-Dev-tab :size 50 :name #ÐR )) (setf (Serial-table Header-Table) (make-Dev-tab :size 50 :name #&SERD )) (setf (printer-table Header-Table) (make-Dev-tab :size 50 :name #&PRNT )) (setf (Screen-table Header-Table) (make-Dev-tab :size 50 :name #&SCRN )) (setq cold-buffer (alloc-BC-memory (// *cold-ring-buffer-size* 4))) (setf (cold-stream Header-Table) (make-cold-str :buffer-start cold-buffer :buffer-end (+ cold-buffer *cold-ring-buffer-size*) :buffer-input cold-buffer :buffer-output cold-buffer)) (setf (Dev-tab-blks (Screen-table Header-Table)) (make-sd)) (setf (Dev-tab-blks (Screen-table Header-Table) 4) (make-sd))))