memory.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. ;;; Ported from Scheme 48 1.9. See file COPYING for notices and license.
  2. ;;;
  3. ;;; Port Author: Andrew Whatson
  4. ;;;
  5. ;;; Original Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Marcus
  6. ;;; Crestani David Frese, Taylor Campbell
  7. ;;;
  8. ;;; scheme48-1.9.2/scheme/prescheme/memory.scm
  9. ;;;
  10. ;;; An implementation of Pre-Scheme's memory interface that can detect some
  11. ;;; stray reads and writes. It has numerous limitiations:
  12. ;;; Allocations are always on page boundaries.
  13. ;;; No more than 16 megabytes can be allocated at once.
  14. ;;; More than 32 or 64 or so allocations result in addresses being
  15. ;;; bignums (dealloctions have no effect on this).
  16. ;;;
  17. ;;; Memory is represented as a vector of byte-vectors, with each byte-vector
  18. ;;; representing a 16-megabyte page. Allocations are always made on page
  19. ;;; boundaries, so the byte-vectors only need be as large as the allocated
  20. ;;; areas. Pages are never re-used.
  21. ;;;
  22. ;;; (Scheme 48 still calls byte-vectors code-vectors.)
  23. ;;;
  24. ;;;
  25. ;;; Addresses are distinct from integers.
  26. ;;;
  27. (define-module (prescheme memory)
  28. #:use-module (srfi srfi-9)
  29. #:use-module (prescheme scheme48)
  30. #:use-module (prescheme platform)
  31. #:use-module (prescheme prescheme)
  32. #:use-module (prescheme record-discloser)
  33. #:export (allocate-memory
  34. deallocate-memory
  35. unsigned-byte-ref unsigned-byte-set!
  36. word-ref word-set!
  37. flonum-ref flonum-set!
  38. address?
  39. null-address null-address?
  40. address+ address- address-difference
  41. address= address< address<= address> address>=
  42. address->integer integer->address
  43. copy-memory! memory-equal?
  44. char-pointer->string char-pointer->nul-terminated-string
  45. read-block write-block
  46. reinitialize-memory))
  47. (define-record-type :address
  48. (make-address index)
  49. address?
  50. (index address-index))
  51. (define-record-discloser :address
  52. (lambda (addr) (list 'address (address-index addr))))
  53. ;; We add 100000000 to addresses to make them
  54. (define address-offset 100000000)
  55. (define (address->integer addr)
  56. (+ (address-index addr) address-offset))
  57. (define (integer->address int)
  58. (make-address (- int address-offset)))
  59. (define (address+ address integer)
  60. (make-address (+ (address-index address) integer)))
  61. (define (address- address integer)
  62. (make-address (- (address-index address) integer)))
  63. (define (address-binop op)
  64. (lambda (address1 address2)
  65. (op (address-index address1) (address-index address2))))
  66. (define address-difference (address-binop -))
  67. (define address= (address-binop =))
  68. (define address< (address-binop <))
  69. (define address<= (address-binop <=))
  70. (define address> (address-binop >))
  71. (define address>= (address-binop >=))
  72. (define null-address (make-address -1))
  73. (define (null-address? address)
  74. (address= address null-address))
  75. ;; Memory
  76. (define *memory* (make-vector 16 #f)) ;; vector of pages
  77. (define log-max-size 25) ;; log of page size
  78. (define address-shift (- log-max-size)) ;; turns addresses into page indices
  79. (define max-size (arithmetic-shift 1 log-max-size)) ;; page size
  80. (define address-mask ;; mask to get address within page
  81. (- (arithmetic-shift 1 log-max-size) 1))
  82. (define *next-index* 0) ;; next available page
  83. (define (reinitialize-memory)
  84. (set! *memory* (make-vector 16 #f))
  85. (set! *next-index* 0))
  86. ;; Extend the page vector if necessary, and then make a page of the
  87. ;; appropriate size.
  88. (define (allocate-memory size)
  89. (cond ((> size max-size)
  90. null-address) ;; error result
  91. (else
  92. (if (>= *next-index* (vector-length *memory*))
  93. (let ((new (make-vector (* 2 (vector-length *memory*)))))
  94. (do ((i 0 (+ i 1)))
  95. ((>= i (vector-length *memory*)))
  96. (vector-set! new i (vector-ref *memory* i)))
  97. (set! *memory* new)))
  98. (let ((index *next-index*))
  99. (set! *next-index* (+ *next-index* 1))
  100. (vector-set! *memory* index (make-code-vector size 0))
  101. (make-address (arithmetic-shift index log-max-size))))))
  102. ;; Turning an address into a page or page index
  103. (define (address->vector address)
  104. (vector-ref *memory* (arithmetic-shift address address-shift)))
  105. (define (address->vector-index address)
  106. (bitwise-and address address-mask))
  107. ;; Throw away the page containing ADDRESS, which must be the first address in
  108. ;; that page,
  109. (define (deallocate-memory address)
  110. (let ((address (address-index address)))
  111. (let ((vector (address->vector address))
  112. (byte-address (address->vector-index address)))
  113. (if (and vector (= byte-address 0))
  114. (vector-set! *memory* (arithmetic-shift address address-shift) #f)
  115. (assertion-violation 'deallocate-memory "bad deallocation address" address)))))
  116. ;; Various ways of accessing memory
  117. (define (unsigned-byte-ref address)
  118. (let ((address (address-index address)))
  119. (code-vector-ref (address->vector address)
  120. (address->vector-index address))))
  121. (define (signed-code-vector-ref bvec i)
  122. (let ((x (code-vector-ref bvec i)))
  123. (if (< x 128)
  124. x
  125. (bitwise-ior x -128))))
  126. (define (word-ref address)
  127. (let ((address (address-index address)))
  128. (let ((vector (address->vector address))
  129. (byte-address (address->vector-index address)))
  130. (if (not (= 0 (bitwise-and byte-address (- bytes-per-cell 1))))
  131. (assertion-violation 'word-ref "unaligned address error" address)
  132. (do ((byte-offset 0 (+ byte-offset 1))
  133. (shift-offset (- bits-per-cell bits-per-byte)
  134. (- shift-offset bits-per-byte))
  135. (word 0
  136. (+ word
  137. (arithmetic-shift ((if (= 0 byte-offset)
  138. signed-code-vector-ref
  139. code-vector-ref)
  140. vector
  141. (+ byte-address byte-offset))
  142. shift-offset))))
  143. ((or (>= byte-offset bytes-per-cell) (< shift-offset 0))
  144. word))))))
  145. (define (unsigned-byte-set! address value)
  146. (let ((address (address-index address)))
  147. (code-vector-set! (address->vector address)
  148. (address->vector-index address)
  149. (bitwise-and 255 value))))
  150. (define (word-set! address value)
  151. (let ((address (address-index address)))
  152. (let ((vector (address->vector address))
  153. (byte-address (address->vector-index address)))
  154. (if (not (= 0 (bitwise-and byte-address 3)))
  155. (assertion-violation 'word-set! "unaligned address error" address))
  156. (do ((byte-offset 0 (+ byte-offset 1))
  157. (shift-offset (- bits-per-cell bits-per-byte)
  158. (- shift-offset bits-per-byte)))
  159. ((or (>= byte-offset bytes-per-cell) (< shift-offset 0)))
  160. (code-vector-set! vector
  161. (+ byte-address byte-offset)
  162. (bitwise-and 255
  163. (arithmetic-shift value
  164. (- shift-offset))))))))
  165. ;; With the right access to the flonum bits we could actually make these
  166. ;; work. Something to do later.
  167. (define (flonum-ref address)
  168. (if #t ; work around type checker bug
  169. (assertion-violation 'flonum-ref "call to FLONUM-REF" address)))
  170. (define (flonum-set! address value)
  171. (if #t ; work around type checker bug
  172. (assertion-violation 'flonum-set! "call to FLONUM-SET!" address value)))
  173. ;; Block I/O procedures.
  174. (define (write-block port address count)
  175. (let ((address (address-index address)))
  176. (let ((vector (address->vector address))
  177. (byte-address (address->vector-index address)))
  178. (do ((i 0 (+ i 1)))
  179. ((>= i count))
  180. (write-byte (code-vector-ref vector (+ i byte-address))
  181. port))
  182. (enum errors no-errors))))
  183. (define (read-block port address count)
  184. (let ((address (address-index address)))
  185. (cond ((not (byte-ready? port))
  186. (values 0 #f (enum errors no-errors)))
  187. ((eof-object? (peek-byte port))
  188. (values 0 #t (enum errors no-errors)))
  189. (else
  190. (let ((vector (address->vector address))
  191. (byte-address (address->vector-index address)))
  192. (let loop ((i 0))
  193. (if (or (= i count)
  194. (not (byte-ready? port)))
  195. (values i #f (enum errors no-errors))
  196. (let ((b (read-byte port)))
  197. (cond ((eof-object? b)
  198. (values i #f (enum errors no-errors)))
  199. (else
  200. (code-vector-set! vector
  201. (+ i byte-address)
  202. b)
  203. (loop (+ i 1))))))))))))
  204. (define (copy-memory! from to count)
  205. (let ((from (address-index from))
  206. (to (address-index to)))
  207. (let ((from-vector (address->vector from))
  208. (from-address (address->vector-index from))
  209. (to-vector (address->vector to))
  210. (to-address (address->vector-index to)))
  211. (if (>= from-address to-address)
  212. (do ((i 0 (+ i 1)))
  213. ((>= i count))
  214. (code-vector-set! to-vector
  215. (+ i to-address)
  216. (code-vector-ref from-vector
  217. (+ i from-address))))
  218. (do ((i (- count 1) (- i 1)))
  219. ((negative? i))
  220. (code-vector-set! to-vector
  221. (+ i to-address)
  222. (code-vector-ref from-vector
  223. (+ i from-address))))))))
  224. (define (memory-equal? from to count)
  225. (let ((from (address-index from))
  226. (to (address-index to)))
  227. (let ((from-vector (address->vector from))
  228. (from-address (address->vector-index from))
  229. (to-vector (address->vector to))
  230. (to-address (address->vector-index to)))
  231. (let loop ((i 0))
  232. (cond ((>= i count)
  233. #t)
  234. ((= (code-vector-ref to-vector (+ i to-address))
  235. (code-vector-ref from-vector (+ i from-address)))
  236. (loop (+ i 1)))
  237. (else
  238. #f))))))
  239. ;; Turn the LENGTH bytes starting from ADDRESS into a string.
  240. (define (char-pointer->string address length)
  241. (let ((address (address-index address)))
  242. (let ((vector (address->vector address))
  243. (byte-address (address->vector-index address))
  244. (string (make-string length)))
  245. (do ((i 0 (+ i 1)))
  246. ((= i length))
  247. (string-set! string
  248. i
  249. (ascii->char (code-vector-ref vector (+ byte-address i)))))
  250. string)))
  251. ;; Turn the bytes from ADDRESS to the next nul (byte equal to 0) into a
  252. ;; string. This is a trivial operation in C.
  253. (define (char-pointer->nul-terminated-string address)
  254. (let ((index (address-index address)))
  255. (let ((vector (address->vector index))
  256. (byte-address (address->vector-index index)))
  257. (char-pointer->string address (index-of-first-nul vector byte-address)))))
  258. (define (index-of-first-nul vector address)
  259. (let loop ((i address))
  260. (cond ((= i (code-vector-length vector))
  261. (assertion-violation 'char-pointer->string "CHAR-POINTER->STRING called on pointer with no nul termination"))
  262. ((= 0 (code-vector-ref vector i))
  263. (- i address))
  264. (else
  265. (loop (+ i 1))))))