@@ -9,7 +9,9 @@ import "simics/devs/signal.dml";
9
9
import "simics/devs/ram.dml";
10
10
import "simics/devs/memory-space.dml";
11
11
import "simics/devs/translator.dml";
12
+ import "simics/model-iface/direct-memory.dml";
12
13
import "simics/model-iface/transaction.dml";
14
+ import "simics/simulator/conf-object.dml";
13
15
14
16
template _reg_or_field {
15
17
param is_register : bool;
@@ -1393,6 +1395,157 @@ template map_target is (connect, _qname) {
1393
1395
}
1394
1396
}
1395
1397
1398
+ /**
1399
+ ### ram
1400
+
1401
+ This template can be instantiated on a `port`, `device`, `bank` or
1402
+ `subdevice` object for an efficient implementation of a private RAM
1403
+ area. This is implemented by automatically creating a separate Simics object
1404
+ of class `ram`, with an image attached to it, and using the `direct_memory`
1405
+ interface to access the image efficiently. This gives a small memory
1406
+ footprint and efficient checkpointing; this can make a visible impact for
1407
+ internal memories that are several megabytes in size.
1408
+
1409
+ This template adds an implementation of the `direct_memory_update` interface
1410
+ to the instantiating object. Because of current limitations, the `queue`
1411
+ attribute of the corresponding Simics object must be configured before the
1412
+ first RAM access.
1413
+
1414
+ The template requires a single integer parameter `size`, which must be set
1415
+ to a multiple of 8192.
1416
+
1417
+ The template provides the following methods:
1418
+ */
1419
+ typedef struct {
1420
+ direct_memory_handle_t handle;
1421
+ uint8 *data;
1422
+ } _ram_page_t;
1423
+ template ram {
1424
+ param size;
1425
+ connect ram is (init_as_subobj, destroy) {
1426
+ param documentation = "dm";
1427
+ interface direct_memory;
1428
+ interface ram;
1429
+ param page_size = 8192;
1430
+ param size = parent.size;
1431
+ #if (size % page_size != 0) { error "size must be a multiple of 8192"; }
1432
+ param classname = "ram";
1433
+ session _ram_page_t pages[size / page_size];
1434
+ method init() {
1435
+ default();
1436
+ SIM_set_attribute_default(this.obj, "image", SIM_make_attr_nil());
1437
+ SIM_set_attribute_default(
1438
+ this.obj, "self_allocated_image_size", SIM_make_attr_uint64(size));
1439
+ }
1440
+
1441
+ method invalidate(direct_memory_handle_t handle) {
1442
+ local int page = cast(direct_memory.get_user_data(handle), uintptr_t);
1443
+ pages[page].data = NULL;
1444
+ }
1445
+ method request(uint64 offs) -> (uint8 *) {
1446
+ local int page = offs / page_size;
1447
+ if (pages[page].data == NULL) {
1448
+ if (pages[page].handle == NULL) {
1449
+ pages[page].handle = direct_memory.get_handle(
1450
+ parent.obj, 0, page * page_size, page_size);
1451
+ direct_memory.set_user_data(
1452
+ pages[page].handle, cast(cast(page, uintptr_t), void *));
1453
+ }
1454
+ local direct_memory_t mem = direct_memory.request(
1455
+ pages[page].handle, Sim_Access_Read | Sim_Access_Write,
1456
+ Sim_Access_Read | Sim_Access_Write | Sim_Access_Execute);
1457
+ pages[page].data = mem.data;
1458
+ }
1459
+ return pages[page].data + offs % page_size;
1460
+ }
1461
+
1462
+ method destroy() {
1463
+ for (local int i = 0; i < pages.len; i++) {
1464
+ if (pages[i].handle != NULL) {
1465
+ direct_memory.release(pages[i].handle);
1466
+ }
1467
+ }
1468
+ }
1469
+
1470
+ method read(int64 offs, buffer_t buf) {
1471
+ assert offs + buf.len <= size;
1472
+ local int page_mask = page_size - 1;
1473
+ if (buf.len <= page_size - (offs & page_mask)) {
1474
+ memcpy(buf.data, request(offs), buf.len);
1475
+ } else {
1476
+ local size_t copied = page_size - (offs & page_mask);
1477
+ memcpy(buf.data, request(offs), copied);
1478
+ while (buf.len - copied > page_size) {
1479
+ memcpy(buf.data + copied, request(offs + copied), page_size);
1480
+ copied += page_size;
1481
+ }
1482
+ memcpy(buf.data + copied, request(offs + copied), buf.len - copied);
1483
+ }
1484
+ }
1485
+ }
1486
+
1487
+ /**
1488
+ * `get_u8(int64 offs) -> (uint8)`
1489
+
1490
+ Return a single byte from a given offset.
1491
+ */
1492
+ method get_u8(uint64 offs) -> (uint8) {
1493
+ assert offs < ram.size;
1494
+ return *ram.request(offs);
1495
+ }
1496
+
1497
+ /**
1498
+ * `get_u8(int64 offs) -> (uint8)`
1499
+
1500
+ Read a 64-bit little-endian integer from a given offset
1501
+ */
1502
+ method get_u64_le(uint64 offs) -> (uint64) {
1503
+ local uint64_le_t ret;
1504
+ ram.read(offs, {.data=cast(&ret, uint8 *), .len=8});
1505
+ return ret;
1506
+ }
1507
+ /**
1508
+ * `set_u8(int64 offs) -> (uint8)`
1509
+
1510
+ Update a single byte at a given offset.
1511
+ */
1512
+ method set_u8(uint64 offs, uint8 val) {
1513
+ assert offs < ram.size;
1514
+ *ram.request(offs) = val;
1515
+ }
1516
+
1517
+ implement direct_memory_update {
1518
+ method release(conf_object_t *target, direct_memory_handle_t handle,
1519
+ direct_memory_ack_id_t id) {
1520
+ assert target == ram.obj;
1521
+ ram.invalidate(handle);
1522
+ local int page = cast(
1523
+ ram.direct_memory.get_user_data(handle), uintptr_t);
1524
+ ram.pages[page].handle = NULL;
1525
+ ram.direct_memory.ack(id);
1526
+ }
1527
+ method update_permission(conf_object_t *target,
1528
+ direct_memory_handle_t handle,
1529
+ access_t lost_access,
1530
+ access_t lost_permission,
1531
+ access_t lost_inhibit,
1532
+ direct_memory_ack_id_t id) {
1533
+ assert target == ram.obj;
1534
+ ram.invalidate(handle);
1535
+ ram.direct_memory.ack(id);
1536
+ }
1537
+ method conflicting_access(conf_object_t *target,
1538
+ direct_memory_handle_t handle,
1539
+ access_t conflicting_permission,
1540
+ direct_memory_ack_id_t id) {
1541
+ assert target == ram.obj;
1542
+ ram.invalidate(handle);
1543
+ ram.direct_memory.ack(id);
1544
+ }
1545
+ }
1546
+ }
1547
+
1548
+
1396
1549
/**
1397
1550
## Signal related templates
1398
1551
0 commit comments