@@ -9,7 +9,9 @@ import "simics/devs/signal.dml";
99import "simics/devs/ram.dml";
1010import "simics/devs/memory-space.dml";
1111import "simics/devs/translator.dml";
12+ import "simics/model-iface/direct-memory.dml";
1213import "simics/model-iface/transaction.dml";
14+ import "simics/simulator/conf-object.dml";
1315
1416template _reg_or_field {
1517 param is_register : bool;
@@ -1393,6 +1395,157 @@ template map_target is (connect, _qname) {
13931395 }
13941396}
13951397
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+
13961549/**
13971550## Signal related templates
13981551
0 commit comments