Source file cyclesim2_ops.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
[@@@ocaml.flambda_o3]
open Base
let run_bounds_checks = false
let bounds_check bytes address =
if address < 0 || address * 8 >= Bytes.length bytes
then raise_s [%message "Bad bounds" (address : int)]
;;
let[@inline always] set64 bytes address value =
if run_bounds_checks then bounds_check bytes address;
Bytes.unsafe_set_int64 bytes (address * 8) value
;;
let[@inline always] get64 bytes address =
if run_bounds_checks then bounds_check bytes address;
Bytes.unsafe_get_int64 bytes (address * 8)
;;
let[@inline always] get64i bytes address = get64 bytes address |> Int64.to_int_trunc
let[@inline always] int64_equal a b = if Int64.(a = b) then 1L else 0L
let[@inline always] int64_less_than a b =
if Stdlib.Int64.unsigned_compare a b = -1 then 1L else 0L
;;
let dispatch_on_width width ~less_than_64 ~exactly_64 ~more_than_64 =
if width < 64 then less_than_64 else if width = 64 then exactly_64 else more_than_64
;;
let masks =
Array.init 64 ~f:(fun i -> if i = 0 then -1L else Int64.( lsr ) (-1L) (64 - i))
;;
let num_words w = (w + 63) / 64
let add t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let mask = masks.(width_in_bits land 0b11_1111) in
let add_small () =
set64 t dst_address Int64.((get64 t src_address_a + get64 t src_address_b) land mask)
in
let add_64 () =
set64 t dst_address Int64.(get64 t src_address_a + get64 t src_address_b)
in
let add_large () =
Bits_packed.add t ~dst_address ~src_address_a ~src_address_b ~width_in_bits
in
dispatch_on_width
width_in_bits
~less_than_64:add_small
~exactly_64:add_64
~more_than_64:add_large
;;
let sub t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let mask = masks.(width_in_bits land 0b11_1111) in
let sub_small () =
set64 t dst_address Int64.((get64 t src_address_a - get64 t src_address_b) land mask)
in
let sub_64 () =
set64 t dst_address Int64.(get64 t src_address_a - get64 t src_address_b)
in
let sub_large () =
Bits_packed.sub t ~dst_address ~src_address_a ~src_address_b ~width_in_bits
in
dispatch_on_width
width_in_bits
~less_than_64:sub_small
~exactly_64:sub_64
~more_than_64:sub_large
;;
let mulu t ~dst_address ~src_address_a ~src_address_b ~width_in_bits_a ~width_in_bits_b ()
=
Bits_packed.mulu
t
~dst_address
~src_address_a
~src_address_b
~width_in_bits_a
~width_in_bits_b
;;
let muls t ~dst_address ~src_address_a ~src_address_b ~width_in_bits_a ~width_in_bits_b ()
=
Bits_packed.muls
t
~dst_address
~src_address_a
~src_address_b
~width_in_bits_a
~width_in_bits_b
;;
let and_ t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let size_in_words = num_words width_in_bits in
let and_small () =
set64 t dst_address Int64.(get64 t src_address_a land get64 t src_address_b)
in
let and_large () =
Bits_packed.and_ t ~dst_address ~src_address_a ~src_address_b ~size_in_words
in
dispatch_on_width
width_in_bits
~less_than_64:and_small
~exactly_64:and_small
~more_than_64:and_large
;;
let or_ t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let size_in_words = num_words width_in_bits in
let or_small () =
set64 t dst_address Int64.(get64 t src_address_a lor get64 t src_address_b)
in
let or_large () =
Bits_packed.or_ t ~dst_address ~src_address_a ~src_address_b ~size_in_words
in
dispatch_on_width
width_in_bits
~less_than_64:or_small
~exactly_64:or_small
~more_than_64:or_large
;;
let xor t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let size_in_words = num_words width_in_bits in
let xor_small () =
set64 t dst_address Int64.(get64 t src_address_a lxor get64 t src_address_b)
in
let xor_large () =
Bits_packed.xor t ~dst_address ~src_address_a ~src_address_b ~size_in_words
in
dispatch_on_width
width_in_bits
~less_than_64:xor_small
~exactly_64:xor_small
~more_than_64:xor_large
;;
let eq t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let size_in_words = num_words width_in_bits in
let eq_small () =
set64 t dst_address (int64_equal (get64 t src_address_a) (get64 t src_address_b))
in
let eq_large () =
Bits_packed.eq t ~dst_address ~src_address_a ~src_address_b ~size_in_words
in
dispatch_on_width
width_in_bits
~less_than_64:eq_small
~exactly_64:eq_small
~more_than_64:eq_large
;;
let lt t ~dst_address ~src_address_a ~src_address_b ~width_in_bits =
let size_in_words = num_words width_in_bits in
let lt_small () =
set64 t dst_address (int64_less_than (get64 t src_address_a) (get64 t src_address_b))
in
let lt_large () =
Bits_packed.lt t ~dst_address ~src_address_a ~src_address_b ~size_in_words
in
dispatch_on_width
width_in_bits
~less_than_64:lt_small
~exactly_64:lt_small
~more_than_64:lt_large
;;
let not_ t ~dst_address ~src_address ~width_in_bits =
let mask = masks.(width_in_bits land 0b11_1111) in
let not_small () = set64 t dst_address Int64.(get64 t src_address lxor mask) in
let not_large () = Bits_packed.not' t ~dst_address ~src_address ~width_in_bits in
dispatch_on_width
width_in_bits
~less_than_64:not_small
~exactly_64:not_small
~more_than_64:not_large
;;
let mux t ~dst_address ~select_address ~select_width ~cases ~size_in_words =
if size_in_words = 1
then (
let max = Array.length cases - 1 in
if Array.length cases = 2 && select_width = 1
then (
let case0 = cases.(0) in
let case1 = cases.(1) in
let mux2 () =
set64
t
dst_address
(get64 t (Bool.select (get64i t select_address = 0) case0 case1))
in
mux2)
else (
let mux_small () =
let select = get64i t select_address in
let select = if select > max then max else select in
set64 t dst_address (get64 t (Array.unsafe_get cases select))
in
mux_small))
else (
let mux_large () =
Bits_packed.mux t ~dst_address ~select_address ~cases ~size_in_words
in
mux_large)
;;
let cat t ~dst_address (cat_src : Bits_packed.Cat_src.t list) ~width_in_bits =
let cat_small =
let cat_src = Array.of_list cat_src in
let count = Array.length cat_src in
let cat_small () =
let acc = ref 0L in
for i = 0 to count - 1 do
let cat_src = Array.unsafe_get cat_src i in
acc := Int64.(get64 t cat_src.address lor (!acc lsl cat_src.width))
done;
set64 t dst_address !acc
in
cat_small
in
let cat_large () = Bits_packed.cat t ~dst_address cat_src ~width_in_bits in
dispatch_on_width
width_in_bits
~less_than_64:cat_small
~exactly_64:cat_small
~more_than_64:cat_large
;;
let select t ~dst_address ~src_address ~high ~low =
let dst_width = high - low + 1 in
let src_address, high, low =
let rec shift_down src_address high low =
if low < 64
then src_address, high, low
else shift_down (src_address + 1) (high - 64) (low - 64)
in
shift_down src_address high low
in
if high < 64
then (
let mask = masks.(dst_width land 0b11_1111) in
let sel_small () =
set64 t dst_address Int64.((get64 t src_address lsr low) land mask)
in
sel_small)
else (
let sel_large () = Bits_packed.select t ~dst_address ~src_address ~high ~low in
sel_large)
;;
let mem_read t ~dst_address ~read_address ~memory_address ~memory_size ~size_in_words =
if size_in_words = 1
then (
let memread1 () =
let read_address = get64i t read_address in
if read_address < memory_size
then (
let read_address = memory_address + read_address in
set64 t dst_address (get64 t read_address))
in
memread1)
else (
let memreadn () =
let read_address = get64i t read_address in
if read_address < memory_size
then
for i = 0 to size_in_words - 1 do
let read_address = memory_address + (read_address * size_in_words) in
set64 t (dst_address + i) (get64 t (read_address + i))
done
in
memreadn)
;;
type clear =
{ clear : int
; clear_value : int
; level : int
}
let reg t ~clear ~enable ~dst_address ~src_address ~size_in_words =
let copy =
let copy1 () = set64 t dst_address (get64 t src_address) in
let copyn () =
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (src_address + i))
done
in
if size_in_words = 1 then copy1 else copyn
in
let copy_enabled enable =
let copy_enabled1 () =
if get64i t enable = 1 then set64 t dst_address (get64 t src_address)
in
let copy_enabledn () =
if get64i t enable = 1
then
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (src_address + i))
done
in
if size_in_words = 1 then copy_enabled1 else copy_enabledn
in
let copy_cleared { clear; clear_value; level } =
let copy_cleared1 () =
if get64i t clear = level
then set64 t dst_address (get64 t clear_value)
else set64 t dst_address (get64 t src_address)
in
let copy_clearedn () =
if get64i t clear = level
then
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (clear_value + i))
done
else
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (src_address + i))
done
in
if size_in_words = 1 then copy_cleared1 else copy_clearedn
in
let copy_cleared_and_enabled enable { clear; clear_value; level } =
let copy_cleared_and_enabled1 () =
if get64i t clear = level
then set64 t dst_address (get64 t clear_value)
else if get64i t enable = 1
then set64 t dst_address (get64 t src_address)
in
let copy_cleared_and_enabledn () =
if get64i t clear = level
then
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (clear_value + i))
done
else if get64i t enable = 1
then
for i = 0 to size_in_words - 1 do
set64 t (dst_address + i) (get64 t (src_address + i))
done
in
if size_in_words = 1 then copy_cleared_and_enabled1 else copy_cleared_and_enabledn
in
match enable, clear with
| None, None -> copy
| Some enable, None -> copy_enabled enable
| None, Some clear -> copy_cleared clear
| Some enable, Some clear -> copy_cleared_and_enabled enable clear
;;
let mem_write_port
t
~size
~memory_address
~write_enable
~write_address
~write_data
~size_in_words
=
if size_in_words = 1
then (
let memwrite1 () =
if get64i t write_enable = 1
then (
let write_address = get64i t write_address in
if write_address < size
then (
let memory_address = memory_address + write_address in
set64 t memory_address (get64 t write_data)))
in
memwrite1)
else (
let memwriten () =
if get64i t write_enable = 1
then (
let write_address = get64i t write_address in
if write_address < size
then (
let memory_address = memory_address + (write_address * size_in_words) in
for i = 0 to size_in_words - 1 do
set64 t (memory_address + i) (get64 t (write_data + i))
done))
in
memwriten)
;;