@@ -11,8 +11,10 @@ local dsda = {
11
11
12
12
13
13
-- Constants ---
14
- local NULL_OBJECT <const> = 0x88888888 -- no object at that index
15
- local OUT_OF_BOUNDS <const> = 0xFFFFFFFF -- no such index
14
+ local NULL_OBJECT <const> = 0x88888888 -- no object at that index
15
+ local OUT_OF_BOUNDS <const> = 0xFFFFFFFF -- no such index
16
+ local WBX_POINTER_HI <const> = 0x36F
17
+ local BusDomain <const> = " System Bus"
16
18
17
19
dsda .MAX_PLAYERS = 4
18
20
-- sizes in bytes
@@ -41,6 +43,11 @@ function dsda.read_s64_le(addr, domain)
41
43
return read_u32 (addr , domain ) | read_u32 (addr + 4 , domain ) << 32
42
44
end
43
45
46
+ -- Returns the lower 4 bytes of an 8 byte pointer
47
+ function dsda .read_ptr (addr , domain )
48
+ return read_u32 (addr , domain )
49
+ end
50
+
44
51
function dsda .read_bool (addr , domain )
45
52
return read_u32 (addr , domain ) ~= 0
46
53
end
@@ -62,10 +69,17 @@ function dsda.struct_layout(struct, padded_size, domain, max_count)
62
69
struct .offsets = {}
63
70
struct .items = {} -- This should be iterated with pairs()
64
71
65
- max_count = max_count or math.floor (memory .getmemorydomainsize (domain ) / padded_size )
66
- local max_address = (max_count - 1 ) * padded_size
67
- struct .max_count = max_count
68
- struct .max_address = max_address
72
+ assert ((padded_size ~= nil ) == (domain ~= nil ), " padded_size and domain must be specified together" )
73
+
74
+ local max_address
75
+ if domain then
76
+ max_count = max_count or math.floor (memory .getmemorydomainsize (domain ) / padded_size )
77
+ max_address = (max_count - 1 ) * padded_size
78
+ struct .max_count = max_count
79
+ struct .max_address = max_address
80
+ else
81
+ max_address = 0xFFFFFFFF
82
+ end
69
83
70
84
local items_meta = {}
71
85
local item_props = {}
@@ -119,9 +133,27 @@ function dsda.struct_layout(struct, padded_size, domain, max_count)
119
133
end
120
134
return struct
121
135
end
136
+ function struct .ptrto (name , target_struct )
137
+ local size = struct .size
138
+ struct .ptr (name .. " _ptr" )
139
+ struct .size = size
140
+ struct .add (name , 8 , true , function (addr , domain )
141
+ local ptr = dsda .read_ptr (addr , domain )
142
+ return target_struct .from_pointer (ptr )
143
+ end )
144
+ return struct
145
+ end
122
146
123
-
147
+ local function create_item (address , domain )
148
+ local item = {
149
+ _address = address ,
150
+ _domain = domain ,
151
+ }
152
+ setmetatable (item , item_meta )
153
+ return item
154
+ end
124
155
local function get_item (address )
156
+ assert (domain ~= nil , " Struct can only be accessed by pointer" )
125
157
assertf (address >= 0 and address <= max_address and address % padded_size == 0 ,
126
158
" Invalid %s address %X" , domain , address )
127
159
@@ -134,11 +166,7 @@ function dsda.struct_layout(struct, padded_size, domain, max_count)
134
166
return false
135
167
end
136
168
137
- local item = {
138
- _address = address ,
139
- }
140
- setmetatable (item , item_meta )
141
- return item
169
+ return create_item (address , domain )
142
170
end
143
171
144
172
-- iterator for each instance of the struct in the domain
@@ -162,12 +190,20 @@ function dsda.struct_layout(struct, padded_size, domain, max_count)
162
190
return next_key , item [next_key ]
163
191
end
164
192
193
+ -- Get a struct instance from its dedicated memory domain
165
194
function struct .from_address (address )
166
195
return get_item (address ) or nil
167
196
end
168
197
198
+ -- Get a struct instance from its dedicated memory domain
169
199
function struct .from_index (index )
170
- return get_item ((index - 1 ) * padded_size ) or nil
200
+ return get_item ((index - 1 ) * (padded_size or 0 )) or nil
201
+ end
202
+
203
+ -- Get a struct instance from the system bus
204
+ function struct .from_pointer (pointer )
205
+ assertf (pointer % struct .alignment == 0 , " Unaligned pointer %X" , pointer )
206
+ return create_item (pointer , BusDomain )
171
207
end
172
208
173
209
function items_meta :__index (index )
0 commit comments