;;; -*- 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) (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) (defun keyword->num (keyword) (selectq keyword (:DEFAULT 0) ;keywords for options (:WILD 1) (:UNSPECIFIC 2) (:NEWEST 3) (:OLDEST 4) (:NEW-VERSION 5) (:INPUT 6) (:OUTPUT 7) (:PROBE 8) (:PROBE-DIRECTORY 9) (:ERROR 10) (:SUPERSEDE 11) (:OVERWRITE 12) (:TRUNCATE 13) (:APPEND 14) (:RENAME 15) (:RENAME-AND-DELETE 16) (:CREATE 17) (:ABORT 18) (:ROOT 19) (:LOOKUP 20) (t (ferror "MAC: keyword inconnu")))) (defun num->keyword (num) (selectq num (0 :DEFAULT) (1 :WILD) (2 :UNSPECIFIC) (3 :NEWEST) (4 :OLDEST) (5 :new-VERSION) (6 :OPEN) (6 :INPUT) (7 :OUTPUT) (8 :PROBE) (9 :PROBE-DIRECTORY) (10 :ERROR) (11 :SUPERSEDE) (12 :OVERWRITE) (13 :TRUNCATE) (14 :APPEND) (15 :RENAME) (16 :RENAME-AND-DELETE) (17 :CREATE) (18 :ABORT) (19 :ROOT) (20 :lookup) (t (ferror "MAC: keyword inconnu")))) (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-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 ;;; (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) (defstruct (command :conc-name (:type (:bc-struct (:size 25))) (: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)))))) ;;; ;;; 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) ;;; ;;; 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 (:size 50))) (: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 (:size 75))) (: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)))) (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 :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) (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 (:size 200))) (: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)))) (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) (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-blks (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-unsettable-properties) (ferror "MAC error: trying to change an unsettable property.")) ((memq (car prop) mac-settable-properties) (push (cadr prop) file-plist) (push (car prop) file-plist)) (t (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) in file-plist when (memq prop mac-settable-properties) (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) (num->expr value))) (:dont-delete (setf (info-dont-delete struct) (num->expr 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 string-adr length)))))) ;;; ;;; Allocation and manipulation of the Chained IObuffers ;;; (defconst kmac-header-Buffer-number #x52060028) (defconst *buffer-descriptor-size* 36) (defconst *buffer-data-size* 512) (defconst *nb-input-iobuffer* 3) (defconst *nb-pre-allocated-buffers* 15) (defconst *buffer-size* (+ 4 *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-FILLED) next-buffer alloc-start alloc-end start end Master-scan Slave-scan Error-byte) (defun allocate-buffers () (setq *free-buffer-list* (loop repeat *nb-pre-allocated-buffers* collect (make-buffer :state ST-FILLED :alloc-start (alloc-BC-memory *buffer-data-size*))))) (defun get-buffer () (let (buffer) (process-wait "Wait free buffer" #'(lambda () (not (null *free-buffer-list*)))) (without-interrupts (setq buffer (pop *free-buffer-list*)) (setf (Buffer-state buffer) ST-FILLED) (setf (Buffer-start buffer) (Buffer-alloc-start buffer)) (setf (Buffer-end buffer) 0) (setf (Buffer-alloc-end buffer) (+ *buffer-data-size* (Buffer-alloc-start buffer)))) buffer)) (defun release-buffer (buffer) (without-interrupts (push buffer *free-buffer-list*))) (defun get-chained-iobuffers (how-many) (loop with first-buffer = (get-buffer) with buffer = first-buffer with next-buffer repeat (1- how-many) do (setq next-buffer (get-buffer)) (setf (Buffer-next-buffer buffer) next-buffer) (setq buffer next-buffer) finally (setf (Buffer-next-buffer buffer) first-buffer) (return first-buffer))) (defun release-chained-iobuffers (first-buffer) (loop with buffer = first-buffer with next = (Buffer-next-buffer first-buffer) do (release-buffer buffer) until (= next first-buffer) do (setq buffer next next (Buffer-next-buffer 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 (:size 20))) (: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) (defun allocate-communication-root() (let (KBD-buffer) (setq Header-Table (make-header-table)) (setf (Major-CMD-blk Header-Table) (make-command :header kmac-header-CMD-number)) (setf (major-Mac-CMD-blk Header-Table) (make-command :header kmac-header-Mac-CMD-number)) (setf (paging-CMD-blk Header-Table) (make-command :header kmac-header-Paging-number)) (setq KBD-buffer (alloc-BC-memory *Kbd-ring-buffer-size*)) (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 :name #&FILE )) (setf (Network-table Header-Table) (make-Dev-tab :name #ÐR )) (setf (Serial-table Header-Table) (make-Dev-tab :name #&SERD )) (setf (printer-table Header-Table) (make-Dev-tab :name #&PRNT )) (setf (Screen-table Header-Table) (make-Dev-tab :name #&SCRN )) (setf (Dev-tab-blks (Screen-table Header-Table)) (make-sd)) (setf (Dev-tab-blks (Screen-table Header-Table) 4) (make-sd))))