Skip to content

Commit 00f4e70

Browse files
committed
Provide template for an efficient private RAM
1 parent 3df0823 commit 00f4e70

File tree

3 files changed

+170
-0
lines changed

3 files changed

+170
-0
lines changed

lib/1.4/utility.dml

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import "simics/devs/signal.dml";
99
import "simics/devs/ram.dml";
1010
import "simics/devs/memory-space.dml";
1111
import "simics/devs/translator.dml";
12+
import "simics/model-iface/direct-memory.dml";
1213
import "simics/model-iface/transaction.dml";
14+
import "simics/simulator/conf-object.dml";
1315

1416
template _reg_or_field {
1517
param is_register : bool;
@@ -1393,6 +1395,141 @@ 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+
Requires a single integer parameter `size`, which must be set to a multiple of 8192.
1410+
1411+
Provides the following methods:
1412+
*/
1413+
typedef struct {
1414+
direct_memory_handle_t handle;
1415+
uint8 *data;
1416+
} _ram_page_t;
1417+
template ram {
1418+
param size;
1419+
connect ram is (init_as_subobj, destroy) {
1420+
param documentation = "dm";
1421+
interface direct_memory;
1422+
interface ram;
1423+
param page_size = 8192;
1424+
param size = parent.size;
1425+
#if (size % page_size != 0) { error "size must be a multiple of 8192"; }
1426+
param classname = "ram";
1427+
session _ram_page_t pages[size / page_size];
1428+
method init() {
1429+
default();
1430+
SIM_set_attribute_default(this.obj, "image", SIM_make_attr_nil());
1431+
SIM_set_attribute_default(
1432+
this.obj, "self_allocated_image_size", SIM_make_attr_uint64(size));
1433+
}
1434+
1435+
method invalidate(direct_memory_handle_t handle) {
1436+
local int page = cast(direct_memory.get_user_data(handle), uintptr_t);
1437+
pages[page].data = NULL;
1438+
}
1439+
method request(uint64 offs) -> (uint8 *) {
1440+
local int page = offs / page_size;
1441+
if (pages[page].data == NULL) {
1442+
if (pages[page].handle == NULL) {
1443+
pages[page].handle = direct_memory.get_handle(
1444+
parent.obj, 0, page * page_size, page_size);
1445+
direct_memory.set_user_data(
1446+
pages[page].handle, cast(cast(page, uintptr_t), void *));
1447+
}
1448+
local direct_memory_t mem = direct_memory.request(
1449+
pages[page].handle, Sim_Access_Read | Sim_Access_Write,
1450+
Sim_Access_Read | Sim_Access_Write | Sim_Access_Execute);
1451+
pages[page].data = mem.data;
1452+
}
1453+
return pages[page].data + offs % page_size;
1454+
}
1455+
1456+
method destroy() {
1457+
for (local int i = 0; i < pages.len; i++) {
1458+
if (pages[i].handle != NULL) {
1459+
direct_memory.release(pages[i].handle);
1460+
}
1461+
}
1462+
}
1463+
}
1464+
1465+
/**
1466+
* `get_u8(int64 offs) -> (uint8)`
1467+
1468+
Return a single byte from a given offset.
1469+
*/
1470+
method get_u8(uint64 offs) -> (uint8) {
1471+
assert offs < ram.size;
1472+
return *ram.request(offs);
1473+
}
1474+
/**
1475+
* `get_u8(int64 offs) -> (uint8)`
1476+
1477+
Read a 64-bit little-endian integer from a given offset
1478+
*/
1479+
method get_u64_le(uint64 offs) -> (uint64) {
1480+
assert offs + 7 < ram.size;
1481+
if ((offs & ram.page_size) != ((offs + 7) & ram.page_size)) {
1482+
local uint8 ret[8];
1483+
local uint64 split = 8 - (offs & 7);
1484+
memcpy(ret, ram.request(offs), split);
1485+
memcpy(ret + split, ram.request(offs + split), 8 - split);
1486+
return *cast(ret, uint64_le_t *);
1487+
} else {
1488+
return *cast(ram.request(offs), uint64_le_t *);
1489+
}
1490+
}
1491+
/**
1492+
* `set_u8(int64 offs) -> (uint8)`
1493+
1494+
Update a single byte at a given offset.
1495+
*/
1496+
method set_u8(uint64 offs, uint8 val) {
1497+
assert offs < ram.size;
1498+
*ram.request(offs) = val;
1499+
}
1500+
1501+
implement direct_memory_update {
1502+
method release(conf_object_t *target, direct_memory_handle_t handle,
1503+
direct_memory_ack_id_t id) {
1504+
assert target == ram.obj;
1505+
ram.invalidate(handle);
1506+
local int page = cast(
1507+
ram.direct_memory.get_user_data(handle), uintptr_t);
1508+
ram.pages[page].handle = NULL;
1509+
ram.direct_memory.ack(id);
1510+
}
1511+
method update_permission(conf_object_t *target,
1512+
direct_memory_handle_t handle,
1513+
access_t lost_access,
1514+
access_t lost_permission,
1515+
access_t lost_inhibit,
1516+
direct_memory_ack_id_t id) {
1517+
assert target == ram.obj;
1518+
ram.invalidate(handle);
1519+
ram.direct_memory.ack(id);
1520+
}
1521+
method conflicting_access(conf_object_t *target,
1522+
direct_memory_handle_t handle,
1523+
access_t conflicting_permission,
1524+
direct_memory_ack_id_t id) {
1525+
assert target == ram.obj;
1526+
ram.invalidate(handle);
1527+
ram.direct_memory.ack(id);
1528+
}
1529+
}
1530+
}
1531+
1532+
13961533
/**
13971534
## Signal related templates
13981535

test/1.4/lib/T_ram.dml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
dml 1.4;
2+
3+
device test;
4+
5+
import "utility.dml";
6+
7+
subdevice ram {
8+
is ram;
9+
param size = 65536;
10+
}
11+
12+
attribute trigger_test is bool_attr {
13+
// cannot run from init: RAM access requires queue to be set
14+
method set(attr_value_t _) throws {
15+
// integer across page boundary
16+
assert ram.ram.page_size == 0x2000;
17+
ram.set_u8(0x1ffe, 0x11);
18+
ram.set_u8(0x1fff, 0x22);
19+
ram.set_u8(0x2000, 0x33);
20+
ram.set_u8(0x2001, 0x44);
21+
assert ram.get_u64_le(0x1ff8) == 0x2211_0000_0000_0000;
22+
assert ram.get_u64_le(0x2000) == 0x4433;
23+
assert ram.get_u64_le(0x1ffe) == 0x44332211;
24+
}
25+
}

test/1.4/lib/T_ram.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
clock = SIM_create_object('clock', 'clock', freq_mhz=1)
2+
3+
obj.ram.queue = clock
4+
obj.trigger_test = True
5+
6+
b=simics.buffer_t(100)
7+
obj.ram.ram.iface.ram.read(None, 0, b, 0)
8+
print(bytes(b))

0 commit comments

Comments
 (0)