[movitz-cvs] CVS update: movitz/losp/tmp/harddisk.lisp

Frode Vatvedt Fjeld ffjeld at common-lisp.net
Wed May 5 08:26:15 UTC 2004


Update of /project/movitz/cvsroot/movitz/losp/tmp
In directory common-lisp.net:/tmp/cvs-serv10011

Modified Files:
	harddisk.lisp 
Log Message:
Checked in new version from Peter Minten.

Date: Wed May  5 04:26:14 2004
Author: ffjeld

Index: movitz/losp/tmp/harddisk.lisp
diff -u movitz/losp/tmp/harddisk.lisp:1.2 movitz/losp/tmp/harddisk.lisp:1.3
--- movitz/losp/tmp/harddisk.lisp:1.2	Sat Apr 24 11:13:26 2004
+++ movitz/losp/tmp/harddisk.lisp	Wed May  5 04:26:14 2004
@@ -1,264 +1,318 @@
-;;;; $Id: harddisk.lisp,v 1.2 2004/04/24 15:13:26 ffjeld Exp $
-
-(require :lib/named-integers)
-(provide :tmp/harddisk)
-
-(defpackage muerte.x86-pc.harddisk
-  (:use muerte.cl muerte muerte.lib muerte.x86-pc)
-  (:export make-512-vector
-           hd-read-sectors
-           hd-write-sectors
-           hd-commands
-	   ))
-
-(in-package muerte.x86-pc.harddisk)
-
-;;;
-;;; global variables
-;;;
-(defvar *hd-controllers* (vector (make-instance 'hd-controller))
-  "A vector of harddisk controllers.")
-
-;;;
-;;; constants
-;;;
-(defconstant +hd-default-first-irq+ 14)
-(defconstant +hd-default-second-irq+ 15)
-(defconstant +hd-default-first-command-base+ #x1F0)
-(defconstant +hd-default-second-command-base+ #x170)
-(defconstant +hd-default-first-control-base+ #x3F6)
-(defconstant +hd-default-second-control-base+ #x376)
-
-(define-named-integer hd-register-offset 
-    (:only-constants t)
-  (0 data)
-  (1 error)                            
-  (1 features)
-  (2 sector-count)
-  (3 lba-byte-1)                        ;bits 0-7
-  (4 lba-byte-2)                        ;bits 8-15
-  (5 lba-byte-3)                        ;bits 16-23
-  (6 lba-byte-4)                        ;bits 24-27
-  (7 status)
-  (7 command))
-
-(define-named-integer hd-commands
-    (:only-constants t)
-  (#x20 read-sectors-with-retry)
-  (#x30 write-sectors-with-retry))
-
-(define-named-integer hd-status-bits
-    (:only-constants t)
-  (0 error)
-  (1 index)
-  (2 corrected-data)
-  (3 data-request)
-  (4 drive-seek-complete)
-  (5 drive-write-fault)
-  (6 drive-ready)
-  (7 busy))
-
-;;;
-;;; classes
-;;;
-(defclass hd-controller ()
-  ((command-base :initform +hd-default-first-command-base+
-                 :initarg :command-base
-                 :type integer)
-   (control-base :initform +hd-default-first-control-base+
-                 :initarg :command-base
-                 :type integer)))
-
-;;;
-;;; waiters
-;;;
-(defun hd-controller-wait-for-drive-ready (hdc) ;wait for DRDY=1
-  (with-slots (control-base) hdc
-    (loop until (/= 0 (logand (io-port control-base :unsigned-byte8)
-                              #x40)))))  
-
-(defun hd-controller-wait-for-ready (hdc) ;wait for BSY=0
-  (with-slots (control-base) hdc
-    (loop until (= 0 (logand (io-port control-base :unsigned-byte8)
-                             #x80)))))
-
-(defun hd-controller-wait-for-data-request (hdc) ;wait for DRQ=1
-  (with-slots (control-base) hdc
-    (loop until (/= 0 (logand (io-port control-base :unsigned-byte8)
-                              #x08)))))
-
-;;;
-;;; feeders
-;;;
-(defun hd-controller-feed-lba-mode (hdc)
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-4)
-                 :unsigned-byte8)
-          (logior (io-port (hd-controller-command-register hdc 'lba-byte-4)
-                           :unsigned-byte8)
-                  #b01000000)))
-
-(defun hd-controller-feed-drive (hdc drive)
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-4)
-                 :unsigned-byte8)
-          (logior (* #b00010000 drive)
-                  (logand (io-port (hd-controller-command-register hdc 'lba-byte-4)
-                                   :unsigned-byte8)
-                          #b11101111))))
-
-(defun hd-controller-feed-lba-address (hdc lba)
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-1)
-                 :unsigned-byte8)
-          (logand lba #x000000FF))
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-2)
-                 :unsigned-byte8)
-          (logand lba #x0000FF00))
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-3)
-                               :unsigned-byte8)
-          (logand lba #x00FF0000))
-  (setf (io-port (hd-controller-command-register hdc 'lba-byte-3)
-                 :unsigned-byte8)
-          (logior (io-port (hd-controller-command-register hdc 'lba-byte-4)
-                           :unsigned-byte8)
-                  (logand lba #x000F0000))))
-
-;;;
-;;; misc
-;;;
-(defmacro while (test &body body)
-  `(do () ((not ,test))
-    , at body))
-
-(defun div (a b)
-  "Floored integer division, the painful way."
-  (let ((r 0)
-        (x a))
-    (while (>= x 0)
-      (decf x b)
-      (incf r))
-    (1- r)))
-
-(defun log2 (n)
-  (cond ((= n 256) 8)
-        ((= n 128) 7)
-        ((= n 64) 6)
-        ((= n 32) 5)
-        ((= n 16) 4)
-        ((= n 8) 3)
-        ((= n 4) 2)
-        ((= n 2) 1)
-        ((= n 1) 0)))
-        
-(defmacro with-hd-info ((hdc drive-number) hd-number &body body)
-  (let ((gs-hdnr (gensym "hd-number-")))
-    `(let* ((,gs-hdnr ,hd-number)
-            (,hdc (aref *hd-controllers* (div ,hd-number 2)))
-            (,drive-number (mod ,gs-hdnr 2)))
-      , at body)))
-
-(defun hd-controller-command-register (hdc name)
-  ;; use a case statement for now, until I learn how to use
-  ;; named-integer right
-  (+ (case name
-       ('data 0)
-       ('error 1)
-       ('features 1)
-       ('sector-count 2)
-       ('lba-byte-1 3)
-       ('lba-byte-2 4)
-       ('lba-byte-3 5)
-       ('lba-byte-4 6)
-       ('status 7)
-       ('command 7)
-       (else (error "HD command register not found ~A" name)))
-     (slot-value hdc 'command-base)))
-
-(defun error-code-meaning (code)
-  (nth (log2 code)
-       '("Address Mark Not Found"
-         "Track 0 Not Found"
-         "Media Change Requested"
-         "Aborted Command"
-         "ID Not Found"
-         "Media Changed"
-         "Uncorrectable Data Error"
-         "Bad Block Detected")))
-    
-    
-(defun hd-check-error (hdc command-name hdnr)
-  "Check and when found signal an error in task."
-  (when (/= 0 (logand (io-port (slot-value hdc 'control-base)
-                               :unsigned-byte8)
-                      #x01))
-    (error "Harddrive command ~A returned error. HD number: ~A. Error message: '~A'." 
-           command-name hdnr 
-           (error-code-meaning 
-            (io-port (hd-controller-command-register hdc 'error)
-                     :unsigned-byte8)))))
-
-;;;
-;;; hd operations
-;;;
-(defun hd-read-sectors (hdnr start-sector count)
-  (let ((data (make-array 512 :element-type :unsigned-byte8))
-        (offset 0)
-        (read-data nil))
-    (with-hd-info (hdc drive) hdnr
-      ;; set drive
-      (hd-controller-feed-drive hdc drive)
-      ;; set count
-      (setf (io-port (hd-controller-command-register hdc 'sector-count)
-                     :unsigned-byte8)
-              count)
-      ;; set LBA and address
-      (hd-controller-feed-lba-mode hdc)
-      (hd-controller-feed-lba-address hdc start-sector)
-      ;; get going
-      (setf (io-port (hd-controller-command-register hdc 'command)
-                     :unsigned-byte8)
-              +hd-commands-read-sectors-with-retry+)
-      ;; data handling
-      (while (<= offset (* count 512))
-        (hd-controller-wait-for-drive-ready hdc)
-        (hd-controller-wait-for-ready hdc)
-        (hd-check-error hdc "read-sectors" hdnr)
-        (hd-controller-wait-for-data-request hdc)
-        (dotimes (i 256)
-          (setf read-data (io-port (hd-controller-command-register hdc 'status)
-                                   :unsigned-byte16)))
-          (setf (aref data offset) (logand read-data #xFF))
-          (setf (aref data (1+ offset)) (logand read-data #xFF00))              
-          (incf offset 2))
-      ;; done
-      data)))
-
-(defun hd-write-sectors (hdnr start-sector data)
-  (let ((offset 0)
-        (write-data nil)
-        (count (div (length data) 512)))
-    (with-hd-info (hdc drive) hdnr
-      ;; set drive
-      (hd-controller-feed-drive hdc drive)
-      ;; set count
-      (setf (io-port (hd-controller-command-register hdc 'sector-count)
-                     :unsigned-byte8)
-              count)
-      ;; set LBA and address
-      (hd-controller-feed-lba-mode hdc)
-      (hd-controller-feed-lba-address hdc start-sector)
-      ;; get going
-      (setf (io-port (hd-controller-command-register hdc 'command)
-                     :unsigned-byte8)
-              +hd-commands-write-sectors-with-retry+)
-      ;; data handling
-      (while (<= offset (* count 512))
-        (hd-controller-wait-for-drive-ready hdc)
-        (hd-controller-wait-for-ready hdc)
-        (hd-check-error hdc "write-sectors" hdnr)
-        (hd-controller-wait-for-data-request hdc)
-        (dotimes (i 256)
-          (setf write-data (aref data offset))
-          (incf write-data (* #xFF (aref data (1+ offset))))
-          (setf (io-port (hd-controller-command-register hdc 'data)
-                         :unsigned-byte16)
-                  write-data)
-          (incf offset 2))))))
\ No newline at end of file
+;;;; $Id: harddisk.lisp,v 1.3 2004/05/05 08:26:14 ffjeld Exp $
+
+(require :lib/named-integers)
+
+(provide :tmp/harddisk)
+
+(defpackage muerte.x86-pc.harddisk
+  (:use muerte.cl muerte muerte.lib muerte.x86-pc)
+  (:export hdc-reset
+           hd-read-sectors
+           hd-write-sectors))
+
+(in-package muerte.x86-pc.harddisk)
+
+;;;
+;;; global variables
+;;;
+(defvar *hd-controllers* (vector (make-instance 'hd-controller))
+  "A vector of harddisk controllers.")
+
+;;;
+;;; constants
+;;;
+(defconstant +hd-default-first-irq+ 14)
+(defconstant +hd-default-second-irq+ 15)
+(defconstant +hd-default-first-command-base+ #x1F0)
+(defconstant +hd-default-second-command-base+ #x170)
+(defconstant +hd-default-first-control-base+ #x3F6)
+(defconstant +hd-default-second-control-base+ #x376)
+
+;;;
+;;; classes
+;;;
+(defclass hd-controller ()
+  ((command-base :initform +hd-default-first-command-base+
+                 :initarg :command-base
+                 :type integer)
+   (control-base :initform +hd-default-first-control-base+
+                 :initarg :command-base
+                 :type integer)))
+;;;
+;;; accessors
+;;;
+
+(defmacro data-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 0) :unsigned-byte16))
+
+(defmacro features-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 1) :unsigned-byte8))
+
+(defmacro error-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 1) :unsigned-byte8))
+
+(defmacro sector-count-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 2) :unsigned-byte8))
+
+(defmacro lba-low-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 3) :unsigned-byte8))
+
+(defmacro lba-mid-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 4) :unsigned-byte8))
+
+(defmacro lba-high-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 5) :unsigned-byte8))
+
+(defmacro device-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 6) :unsigned-byte8))
+
+(defmacro command-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 7) :unsigned-byte8))
+
+(defmacro status-register (hdc)
+  `(io-port (+ (slot-value ,hdc 'command-base) 7) :unsigned-byte8))
+
+(defmacro alt-status-register (hdc)
+  `(io-port (slot-value ,hdc 'control-base) :unsigned-byte8))
+
+;;;
+;;; getters
+;;;
+(defun reg-bsy (hdc)
+  (get-bit 7 (status-register hdc)))
+
+(defun reg-drdy (hdc)
+  (get-bit 6 (status-register hdc)))
+
+(defun reg-drq (hdc)
+  (get-bit 3 (status-register hdc)))
+
+(defun reg-err (hdc)
+  (get-bit 0 (status-register hdc)))
+
+(defun reg-alt-bsy (hdc)
+  (get-bit 7 (alt-status-register hdc)))
+
+(defun reg-alt-drdy (hdc)
+  (get-bit 6 (alt-status-register hdc)))
+
+(defun reg-alt-drq (hdc)
+  (get-bit 3 (alt-status-register hdc)))
+
+(defun reg-alt-err (hdc)
+  (get-bit 3 (alt-status-register hdc)))
+
+;;;
+;;; setters
+;;;
+(defun set-drive-number (hdc drive)
+  (set-bit 4 (/= drive 0) (device-register hdc)))
+
+(defun set-intrq-mode (hdc mode)
+  (set-bit 1 (not mode) (device-register hdc)))
+
+(defun set-lba-mode (hdc mode)
+  (set-bit 6 mode (device-register hdc)))
+
+(defun set-lba-address (hdc lba)
+  (setf (lba-low-register hdc) (ldb (byte 8 0) lba))
+  (setf (lba-mid-register hdc) (ldb (byte 8 8) lba))
+  (setf (lba-high-register hdc) (ldb (byte 8 16) lba))
+  (setf (device-register hdc) (dpb (ash (ldb (byte 4 24) lba) -24)
+                                   (byte 4 0)
+                                   (device-register hdc))))
+
+(defun set-sector-count (hdc count)
+  (setf (sector-count-register hdc) count))
+
+(defun set-command (hdc command)
+  (let ((command-code (case command
+                        ('read-sectors-with-retry #x20)
+                        ('write-sectors-with-retry #x30)
+                        ('identify-drive #xCE))))
+  (setf (command-register hdc) command-code)))
+          
+;;;
+;;; misc
+;;;
+(defun get-bit (number place)
+  (/= 0 (ldb (byte 1 number) place)))
+
+(defmacro set-bit (number value place)
+  (let ((gs-number (gensym "number-")))
+    `(if ,value
+      (let ((,gs-number ,number))
+        (setf ,place (dpb (ash 1 ,gs-number) (byte 1 ,gs-number) ,place)))
+      (setf ,place (dpb 0 (byte 1 ,number) ,place)))))
+
+(defmacro while (test &body body)
+  `(do () ((not ,test))
+    , at body))
+
+(defun log2 (n)
+  (cond ((= n 256) 8)
+        ((= n 128) 7)
+        ((= n 64) 6)
+        ((= n 32) 5)
+        ((= n 16) 4)
+        ((= n 8) 3)
+        ((= n 4) 2)
+        ((= n 2) 1)
+        ((= n 1) 0)))
+  
+(defmacro with-hd-info ((hdc drive-number) hd-number &body body)
+  (let ((gs-hdnr (gensym "hd-number-")))
+    `(let* ((,gs-hdnr ,hd-number)
+            (,hdc (aref *hd-controllers* (truncate ,hd-number 2)))
+            (,drive-number (mod ,gs-hdnr 2)))
+      , at body)))
+
+(defun error-code-meaning (code)
+  (if (< 0 code 257)
+      (nth (log2 code)
+           '("Address Mark Not Found"
+             "Track 0 Not Found"
+             "Media Change Requested"
+             "Aborted Command"
+             "ID Not Found"
+             "Media Changed"
+             "Uncorrectable Data Error"
+             "Bad Block Detected"))
+      "No error"))
+    
+(defun hdc-error (hdc command-name hdnr)
+  (puts "In HDC error")
+  (error "Harddrive command ~A returned error. HD number: ~A. Error message: '~A'." 
+         command-name hdnr 
+         (error-code-meaning 
+          (io-port (error-register hdc) :unsigned-byte8))))
+
+(defun puts (s)
+  (fresh-line)
+  (format t s)
+  (terpri))
+
+;;;
+;;; hd operations
+;;;
+(defun hdc-reset (hdcnr)
+  "Reset the harddisk controller. Must be done at startup to
+initialize the harddisk controller."
+  ;; set SRST
+  ;; wait > 2ms
+  ;; continue when BSY=0
+  (let ((hdc (aref *hd-controllers* hdcnr)))
+    (setf (device-register hdc) #x04)
+    (loop for x from 1 to 2500)
+    (loop while (reg-bsy hdc))))
+
+(defun hd-read-sectors (hdnr start-sector count)
+  (let ((data (make-array (* count 512) :element-type :unsigned-byte8))
+        (offset 0)
+        input)
+    (with-hd-info (hdc drive) hdnr
+      (tagbody
+;        (puts "in entry")
+        ;; drive must be ready
+        ;; drive number must be set
+        ;; intrq's must not be used
+        ;; LBA mode must be on
+        ;; LBA must be set
+        ;; sector-count must be set
+        ;; command must be entered
+        ;; 400 nsec must be waited before checking BSY
+        (loop until (reg-drdy hdc))
+        (loop while (reg-alt-bsy hdc))
+        (set-drive-number hdc drive)
+        (set-intrq-mode hdc nil)
+        (set-lba-mode hdc t)
+        (set-lba-address hdc start-sector)
+        (set-sector-count hdc count)
+        (set-command hdc 'read-sectors-with-retry)
+        (dotimes (x 500))              ;aught to be enough waiting
+        (go :check-status)
+        ;;;;;;;;;;;;;;;;;;
+        :check-status
+;        (puts "in check-status")
+        ;; if BSY=0 and DRQ=0 then error
+        ;; if BSY=0 and DRQ=1 then go transfer-data
+        ;; if BSY=1 then go check-state
+        (let ((status (status-register hdc)))
+          (if (get-bit 7 status)       ;if BSY = 1
+              (go :check-status)
+              (if (get-bit 3 status)   ;if DRQ = 1
+                  (go :transfer-data)
+                  (progn
+                    (hdc-error hdc "read-sectors" hdnr)))))
+        ;;;;;;;;;;;;;;;;;;
+        :transfer-data
+;        (puts "in transfer-data")        
+        ;; read the data register
+        (setf input (data-register hdc))
+        (setf (aref data offset) (ldb (byte 8 0) input))
+        (incf offset)
+        (setf (aref data offset) (ldb (byte 8 8) input))
+        (incf offset)
+        ;; read the status register to determine if we're done
+        (if (reg-drq hdc)
+            (if (/= 0 (mod offset 512))
+                (go :transfer-data)     ;data block not completely transfered
+                (progn
+                  (alt-status-register hdc) ;read and ignore
+                  (go :check-status)))
+            (return-from hd-read-sectors data))))))
+
+(defun hd-write-sectors (hdnr start-sector data)
+  (check-type hdnr (integer 0 *))
+  (check-type start-sector (integer 0 *))
+  (check-type data vector)
+  (let ((count (truncate (length data) 512))
+        (offset 0))
+    (with-hd-info (hdc drive) hdnr
+      (tagbody
+;        (puts "in entry")
+        ;; drive must be ready
+        ;; drive number must be set
+        ;; intrq's must not be used
+        ;; LBA mode must be on
+        ;; LBA must be set
+        ;; sector-count must be set
+        ;; command must be entered
+        ;; 400 nsec must be waited before checking BSY
+        (loop until (reg-drdy hdc))
+        (loop while (reg-alt-bsy hdc))
+        (set-drive-number hdc drive)
+        (set-intrq-mode hdc nil)
+        (set-lba-mode hdc t)
+        (set-lba-address hdc start-sector)
+        (set-sector-count hdc count)
+        (set-command hdc 'write-sectors-with-retry)
+        (dotimes (x 500))              ;aught to be enough waiting
+        (go :check-status)
+        ;;;;;;;;;;;;;;;;;;
+        :check-status
+;        (puts "in check-status")
+        ;; if BSY=0 and DRQ=0 then error
+        ;; if BSY=0 and DRQ=1 then go transfer-data
+        ;; if BSY=1 then go 
+        (let ((status (status-register hdc)))
+          (if (get-bit 7 status)       ;if BSY = 1
+              (go :check-status)
+              (if (get-bit 3 status)   ;if DRQ = 1
+                  (go :transfer-data)
+                  (hdc-error hdc "write-sectors" hdnr))))
+        ;;;;;;;;;;;;;;;;;;
+        :transfer-data
+;        (puts "in transfer-data")
+        ;; read the data register
+        (setf (data-register hdc) (+ (aref data offset)
+                                     (ash (aref data (1+ offset)) 8)))
+        (incf offset 2)
+        ;; read the status register to determine if we're done
+        (if (reg-drq hdc)
+            (if (/= 0 (mod offset 512))
+                (go :transfer-data)     ;data block not completely transfered
+                (progn
+                  (alt-status-register hdc) ;read and ignore
+                  (go :check-status)))
+	  (return-from hd-write-sectors nil))))))





More information about the Movitz-cvs mailing list