1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2001-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway.
6 ;;;; For distribution policy, see the accompanying file COPYING.
8 ;;;; Filename: io-port.lisp
10 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
11 ;;;; Created at: Wed Mar 21 22:14:08 2001
13 ;;;; $Id: io-port.lisp,v 1.20 2005/09/18 16:21:25 ffjeld Exp $
15 ;;;;------------------------------------------------------------------
17 (require :muerte
/basic-macros
)
18 (require :muerte
/setf
)
19 (require :muerte
/loop
)
20 (require :muerte
/equalp
)
21 (provide :muerte
/io-port
)
25 (define-compiler-macro io-port
(&whole form port type
&environment env
)
26 (if (not (movitz:movitz-constantp type env
))
28 (ecase (movitz:movitz-eval type env
)
30 `(with-inline-assembly-case (:type
(unsigned-byte 8))
31 (do-case (:untagged-fixnum-ecx
:untagged-fixnum-ecx
)
32 (:compile-form
(:result-mode
:edx
) ,port
)
33 (:std
) ; only EBX is now GC root
34 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
42 (:compile-form
(:result-mode
:edx
) ,port
)
43 (:std
) ; only EBX is now GC root
44 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
47 (:shll
,movitz
:+movitz-fixnum-shift
+ :eax
)
51 `(with-inline-assembly-case (:type
(unsigned-byte 16))
52 (do-case (:untagged-fixnum-ecx
:untagged-fixnum-ecx
)
53 (:compile-form
(:result-mode
:edx
) ,port
)
55 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
63 (:compile-form
(:result-mode
:edx
) ,port
)
65 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
68 (:shll
,movitz
:+movitz-fixnum-shift
+ :eax
)
72 `(with-inline-assembly (:returns
:untagged-fixnum-ecx
73 :type
(unsigned-byte 32))
74 (:compile-form
(:result-mode
:edx
) ,port
)
76 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
83 `(with-inline-assembly (:returns
:eax
:type fixnum
)
84 (:compile-form
(:result-mode
:edx
) ,port
)
86 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
92 `(with-inline-assembly (:returns
:eax
)
93 (:compile-form
(:result-mode
:edx
) ,port
)
95 (:shrl
,movitz
:+movitz-fixnum-shift
+ :edx
)
99 (:movb
,(movitz::tag
:character
) :al
)
103 (defun io-port (port type
)
106 (io-port port
:unsigned-byte8
))
108 (io-port port
:unsigned-byte16
))
110 (io-port port
:unsigned-byte32
))
112 (io-port port
:location
))
114 (io-port port
:character
))))
116 (define-compiler-macro (setf io-port
) (&whole form value port type
&environment env
)
117 (let ((value-var (gensym "(setf io-port)-value-"))
118 (port-var (gensym "(setf io-port)-port-")))
120 ((and (movitz:movitz-constantp type env
)
121 (movitz:movitz-constantp port env
))
122 (let ((the-port (movitz:movitz-eval port env
))
123 (the-type (movitz:movitz-eval type env
)))
125 ((unsigned-byte 8) ; short form of outb can be used
128 `(let ((,value-var
,value
))
129 (with-inline-assembly (:returns
:nothing
)
130 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
132 (:shrl
,movitz
:+movitz-fixnum-shift
+ :eax
)
133 (:outb
:al
,the-port
)
139 `(let ((,value-var
,value
))
140 (with-inline-assembly (:returns
:nothing
)
141 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
143 (:shrl
,movitz
:+movitz-fixnum-shift
+ :eax
)
144 (:outw
:ax
,the-port
)
149 ((unsigned-byte 16) ; indirect (by DX) form of outb must be used
152 `(let ((,value-var
,value
))
153 (with-inline-assembly (:returns
:nothing
)
154 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
156 ,@(movitz::make-immediate-move the-port
:edx
)
157 (:shrl
,movitz
:+movitz-fixnum-shift
+ :eax
)
159 ,@(unless (= 0 (mod the-port
4))
160 `((:movl
:edi
:edx
)))
165 `(let ((,value-var
,value
))
166 (with-inline-assembly (:returns
:nothing
)
167 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
169 ,@(movitz::make-immediate-move the-port
:edx
)
170 (:shrl
,movitz
:+movitz-fixnum-shift
+ :eax
)
172 ,@(unless (= 0 (mod the-port
4))
173 `((:movl
:edi
:edx
)))
176 ((and (movitz:movitz-constantp type env
)
177 (movitz:movitz-constantp value env
))
178 (let ((value (movitz:movitz-eval value env
)))
179 (ecase (movitz:movitz-eval type env
)
181 (check-type value
(unsigned-byte 8))
182 `(let ((,port-var
,port
))
183 (with-inline-assembly (:returns
:nothing
)
184 (:load-lexical
(:lexical-binding
,port-var
) :untagged-fixnum-ecx
)
194 (check-type value
(unsigned-byte 16))
195 `(let ((,port-var
,port
))
196 (with-inline-assembly (:returns
:nothing
)
197 (:load-lexical
(:lexical-binding
,port-var
) :untagged-fixnum-ecx
)
207 `(let ((,port-var
,port
))
208 (with-inline-assembly (:returns
:nothing
)
209 (:load-lexical
(:lexical-binding
,port-var
) :untagged-fixnum-ecx
)
219 `(let ((,port-var
,port
))
220 (check-type value character
)
221 (with-inline-assembly (:returns
:nothing
)
222 (:load-lexical
(:lexical-binding
,port-var
) :untagged-fixnum-ecx
)
225 (:movb
,(char-code value
) :al
)
231 ((movitz:movitz-constantp type env
)
232 (ecase (movitz:movitz-eval type env
)
234 `(let ((,value-var
,value
)
236 (with-inline-assembly (:returns
:nothing
)
237 (:load-lexical
(:lexical-binding
,port-var
) :edx
)
238 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
240 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
241 (:shrl
,movitz
::+movitz-fixnum-shift
+ :eax
)
248 `(let ((,value-var
,value
)
250 (with-inline-assembly (:returns
:nothing
)
251 (:load-lexical
(:lexical-binding
,port-var
) :edx
)
252 (:load-lexical
(:lexical-binding
,value-var
) :untagged-fixnum-ecx
)
254 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
262 `(let ((,value-var
,value
)
264 (with-inline-assembly (:returns
:untagged-fixnum-ecx
)
265 (:load-lexical
(:lexical-binding
,port-var
) :edx
)
266 (:load-lexical
(:lexical-binding
,value-var
) :untagged-fixnum-ecx
)
268 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
275 `(let ((,value-var
,value
)
277 (with-inline-assembly (:returns
:nothing
)
278 (:load-lexical
(:lexical-binding
,port-var
) :edx
)
279 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
282 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
289 `(let ((,value-var
,value
)
291 (with-inline-assembly (:returns
:nothing
)
292 (:load-lexical
(:lexical-binding
,port-var
) :edx
)
293 (:load-lexical
(:lexical-binding
,value-var
) :eax
)
295 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
304 (defun (setf io-port
) (value port type
)
307 (setf (io-port port
:unsigned-byte8
) value
))
309 (setf (io-port port
:unsigned-byte16
) value
))
311 (setf (io-port port
:unsigned-byte32
) value
))
313 (setf (io-port port
:location
) value
))
315 (setf (io-port port
:character
) value
))))
317 ;;; The io-registerX functions are just syntactic sugar that matches the
318 ;;; most frequent use of io-port.
320 (define-compiler-macro io-register8
(io-base io-offset
)
321 `(io-port (+ ,io-base
,io-offset
) :unsigned-byte8
))
323 (defun io-register8 (io-base io-offset
)
324 "Read from single-octet IO-port io-base + io-offset."
325 (io-register8 io-base io-offset
))
327 (define-compiler-macro (setf io-register8
) (value io-base io-offset
)
328 `(setf (io-port (+ ,io-base
,io-offset
) :unsigned-byte8
) ,value
))
330 (defun (setf io-register8
) (value io-base io-offset
)
331 "Write to single-octet IO-port io-base + io-offset."
332 (setf (io-register8 io-base io-offset
) value
))
334 (defmacro with-io-register-syntax
((name io-base-form
) &body body
)
335 "Syntax for easy access to IO registers. <name> is installed as a local macro
336 that reads from <io-base-form> plus some offset."
337 (let ((io-var (gensym "io-base-")))
338 `(let ((,io-var
(check-the (unsigned-byte 16) ,io-base-form
)))
339 (let ((,name
,io-var
))
340 (declare (ignorable ,name
))
341 (macrolet ((,name
(offset &optional
(type :unsigned-byte8
))
342 `(io-port (+ ,',io-var
,offset
) ,type
)))
345 (define-compiler-macro io-register8x2
(io-base offset-hi offset-lo
)
346 `(let ((io-base ,io-base
))
347 (dpb (io-register8 io-base
,offset-hi
)
349 (io-register8 io-base
,offset-lo
))))
351 (defun io-register8x2 (io-base offset-hi offset-lo
)
352 (io-register8x2 io-base offset-hi offset-lo
))
354 (define-compiler-macro (setf io-register8x2
) (&environment env value io-base offset-hi offset-lo
)
355 `(let ((value ,value
))
356 (setf (io-register8 ,io-base
,offset-hi
) (ldb (byte 8 8) value
)
357 (io-register8 ,io-base
,offset-lo
) (ldb (byte 8 0) value
))
360 (defun (setf io-register8x2
) (value io-base offset-hi offset-lo
)
361 (setf (io-register8x2 io-base offset-hi offset-lo
) value
))
365 (defun io-delay (&optional
(x 1000))
367 (with-inline-assembly (:returns
:nothing
) (:nop
))))
369 (define-compiler-macro %io-port-read-succession
(&whole form port object offset start end byte-size
371 (if (not (movitz:movitz-constantp byte-size env
))
373 (let ((port-var (gensym "port-var-"))
374 (object-var (gensym "object-var-"))
375 (byte-size (movitz:movitz-eval byte-size env
)))
377 ((and (movitz:movitz-constantp offset env
)
378 (movitz:movitz-constantp start env
)
379 (movitz:movitz-constantp end env
))
380 (let* ((offset (movitz:movitz-eval offset env
))
381 (start (movitz:movitz-eval start env
))
382 (end (movitz:movitz-eval end env
))
383 (count (- end start
)))
384 (check-type count
(integer 0 #x10000
))
387 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
389 `(let ((,port-var
,port
)
390 (,object-var
,object
))
391 (with-inline-assembly-case ()
393 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
395 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
396 ,@(loop for i from start below end
399 (:movl
:eax
(:ebx
,(+ offset
(* 4 i
))))))
403 `(let ((,port-var
,port
)
404 (,object-var
,object
))
405 (with-inline-assembly-case ()
406 (do-case (t :eax
:labels
(io-read-loop end-io-read-loop not-fixnum
))
407 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
409 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
410 (:movl
,(cl:* movitz
::+movitz-fixnum-factor
+ start
) :ecx
)
412 (:cmpl
:ecx
,(cl:* movitz
::+movitz-fixnum-factor
+ end
))
413 (:jbe
'end-io-read-loop
)
416 (:movl
:eax
(:ebx
,(+ offset -
4) :ecx
))
422 (:movl
:ebx
:eax
))))))
424 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
425 (if (and t
(<= 1 count
20))
426 `(let ((,port-var
,port
)
427 (,object-var
,object
))
428 (with-inline-assembly-case ()
431 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
432 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
433 ,@(loop for i from start below end
436 (:movw
:ax
(:ebx
,(+ offset
(* 2 i
))))))
440 `(let ((,port-var
,port
)
441 (,object-var
,object
))
442 (with-inline-assembly-case ()
443 (do-case (t :eax
:labels
(io-read-loop end-io-read-loop not-fixnum
))
445 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
446 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
447 (:movl
,(cl:* 1 start
) :ecx
)
450 (:ja
'end-io-read-loop
)
453 (:movw
:ax
(:ebx
,(+ offset -
2) (:ecx
2)))
459 (t (error "~S byte-size ~S not implemented." (car form
) byte-size
)))))
460 ((and (movitz:movitz-constantp offset env
))
461 (let ((start-var (gensym "start-"))
462 (end-var (gensym "end-"))
463 (offset (movitz:movitz-eval offset env
)))
466 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
467 `(let ((,port-var
,port
)
468 (,object-var
,object
)
471 (with-inline-assembly-case ()
472 (do-case (t :eax
:labels
(io-read-loop not-fixnum zero-length
))
474 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
475 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
476 (:subl
:ecx
:eax
) ; EAX = length
479 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
480 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
484 (:subl
,movitz
:+movitz-fixnum-factor
+ :esi
)
485 (:movb
:al
(:ebx
,(+ offset -
1) (:ecx
1)))
491 (:movl
:ebx
:eax
)))))
493 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
494 `(let ((,port-var
,port
)
495 (,object-var
,object
)
498 (with-inline-assembly-case ()
499 (do-case (t :eax
:labels
(io-read-loop not-fixnum zero-length
))
500 (:std
) ; only EBX is GC root now
501 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
502 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
505 (:movl
:eax
:esi
) ; ESI = length
506 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
507 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
511 (:movw
:ax
(:ebx
,(+ offset -
2) (:ecx
1)))
512 (:subl
,(* 2 movitz
:+movitz-fixnum-factor
+) :esi
)
515 (:movl
:edi
:edx
) ; safe value
519 (:movl
(:ebp -
4) :esi
)))))
521 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
522 `(let ((,port-var
,port
)
523 (,object-var
,object
)
526 (with-inline-assembly-case ()
527 (do-case (t :eax
:labels
(io-read-loop end-io-read-loop not-fixnum
))
528 (:std
) ; only EBX is GC root now
529 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
530 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
531 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
532 (:pushl
:eax
) ; keep end in (:esp)
535 (:jbe
'end-io-read-loop
)
538 (:movw
:ax
(:ebx
,(+ offset -
4) :ecx
))
541 (:popl
:edx
) ; increment :esp, and put a lispval in :edx.
544 (t (error "~S byte-size ~S not implemented." (car form
) byte-size
)))))
545 (t (error "Variable offset not implemented."))))))
547 (defun %io-port-read-succession
(port object offset start end byte-size
)
549 (error "Only offset 2 implemented."))
552 (%io-port-read-succession port object
2 start end
:8-bit
))
554 (%io-port-read-succession port object
2 start end
:16-bit
))
556 (%io-port-read-succession port object
2 start end
:32-bit
))
557 (t (error "Unknown byte-size ~S." byte-size
))))
559 (define-compiler-macro %io-port-write-succession
(&whole form port object offset start end byte-size
561 (if (not (movitz:movitz-constantp byte-size env
))
563 (let ((port-var (gensym "port-var-"))
564 (object-var (gensym "object-var-"))
565 (byte-size (movitz:movitz-eval byte-size env
)))
567 ((and (movitz:movitz-constantp offset env
)
568 (movitz:movitz-constantp start env
)
569 (movitz:movitz-constantp end env
))
570 (let* ((offset (movitz:movitz-eval offset env
))
571 (start (movitz:movitz-eval start env
))
572 (end (movitz:movitz-eval end env
))
573 (count (- end start
)))
574 (check-type count
(integer 0 #x10000
))
577 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
579 `(let ((,port-var
,port
)
580 (,object-var
,object
))
581 (with-inline-assembly-case ()
584 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
585 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
586 ,@(loop for i from start below end
588 `((:movl
(:ebx
,(+ offset
(* 4 i
))) :eax
)
593 `(let ((,port-var
,port
)
594 (,object-var
,object
))
595 (with-inline-assembly-case ()
596 (do-case (t :eax
:labels
(io-read-loop end-io-read-loop not-fixnum
))
598 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
599 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
600 (:movl
,(cl:* movitz
::+movitz-fixnum-factor
+ start
) :ecx
)
602 (:cmpl
:ecx
,(cl:* movitz
::+movitz-fixnum-factor
+ end
)) ; XXX
603 (:jbe
'end-io-read-loop
)
605 (:movl
(:ebx
,(+ offset -
4) :ecx
) :eax
)
612 (t (error "~S byte-size ~S not implemented." (car form
) byte-size
)))))
613 ((and (movitz:movitz-constantp offset env
))
614 (let ((start-var (gensym "start-"))
615 (end-var (gensym "end-"))
616 (offset (movitz:movitz-eval offset env
)))
619 `(let ((,port-var
,port
)
620 (,object-var
,object
)
623 (with-inline-assembly-case ()
624 (do-case (t :eax
:labels
(io-read-loop not-fixnum zero-length
))
626 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
627 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
628 (:subl
:ecx
:eax
) ; EAX = length
630 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
631 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
632 (:pushl
:eax
) ; keep end in (:esp)
635 (:subl
,movitz
:+movitz-fixnum-factor
+ (:esp
))
636 (:movb
(:ebx
,(+ offset -
1) (:ecx
1)) :al
)
639 (:popl
:edx
) ; increment :esp, and put a lispval in :edx.
644 `(let ((,port-var
,port
)
645 (,object-var
,object
)
648 (with-inline-assembly-case ()
649 (do-case (t :eax
:labels
(io-read-loop not-fixnum zero-length
))
651 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
652 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
655 (:movl
:eax
:esi
) ; ESI = length
656 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
657 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
660 (:movw
(:ebx
,(+ offset -
2) (:ecx
1)) :ax
)
662 (:subl
,(* 2 movitz
:+movitz-fixnum-factor
+) :esi
)
669 (:movl
(:ebp -
4) :esi
)))))
671 (assert (= 4 movitz
:+movitz-fixnum-factor
+))
672 `(let ((,port-var
,port
)
673 (,object-var
,object
)
676 (with-inline-assembly-case ()
677 (do-case (t :eax
:labels
(io-read-loop not-fixnum end-io-read-loop
))
679 (:compile-two-forms
(:edx
:ebx
) ,port-var
,object-var
)
680 (:compile-two-forms
(:ecx
:eax
) ,start-var
,end-var
)
681 (:shrl
,movitz
::+movitz-fixnum-shift
+ :edx
)
682 (:shrl
,movitz
::+movitz-fixnum-shift
+ :ecx
)
683 (:pushl
:eax
) ; keep end in (:esp)
686 (:jbe
'end-io-read-loop
)
688 (:movl
(:ebx
,(+ offset -
4) (:ecx
1)) :eax
)
692 (:popl
:edx
) ; increment :esp, and put a lispval in :edx.
695 (t (error "~S byte-size ~S not implemented." (car form
) byte-size
)))))
696 (t (error "Variable offset not implemented."))))))
698 (defun %io-port-write-succession
(port object offset start end byte-size
)
700 (error "Only offset 2 implemented."))
703 (%io-port-write-succession port object
2 start end
:8-bit
))
705 (%io-port-write-succession port object
2 start end
:16-bit
))
707 (%io-port-write-succession port object
2 start end
:32-bit
))
708 (t (error "Unknown byte-size ~S." byte-size
))))