mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-21 05:02:24 +00:00
board_inspector: Access I/O registers on-demand and properly
The current implementation of I/O buffers have the following issues. 1. I/O buffers are filled with values on creation. This may be fine for memory-mapped I/O regions, but could be a problem to port I/O regions and indexed I/O regions. 2. While not commonly seen, it IS witnessed that some devices only allow its MMIO registers to be accessed with certain width. Accessing such registers with a larger width will not be handled by the device, causing SW to get all 1's rather than the actual values in these registers. This patch resolves the issues above as follows: 1. I/O buffers now do not access any register on creation. Instead, the register is accessed only upon requests. 2. The access width of these registers are followed to ensure that the registers are accessed properly. The classes that represents buffers when interpreting AML is also refactored to abstract the common code that manages fields within buffers. The class hierarchy now looks like this: BufferBase: Implement methods that registers, reads or writes fields Buffer(BufferBase): Implement memory buffer StreamIOBuffer(BufferBase): Implement I/Os available via /dev files IndexedIOBuffer(BufferBase): Implement I/Os via index/data registers Tracked-On: #6298 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
8c63550eb7
commit
60920bb905
@ -32,17 +32,27 @@ class OperationFieldDecl(NamedDecl):
|
||||
self.region = None
|
||||
self.offset = None
|
||||
self.length = length
|
||||
self.access_width = None
|
||||
|
||||
def set_location(self, region, offset):
|
||||
def set_location(self, region, offset, access_width):
|
||||
self.region = region
|
||||
self.offset = offset
|
||||
self.access_width = access_width
|
||||
|
||||
def set_indexed_location(self, index_register, data_register, index, access_width):
|
||||
self.region = (index_register, data_register)
|
||||
self.offset = index
|
||||
self.access_width = access_width
|
||||
|
||||
def dump(self):
|
||||
if self.region and self.offset:
|
||||
bit_index = self.offset
|
||||
byte_index = floor(bit_index / 8)
|
||||
offset_in_byte = bit_index % 8
|
||||
print(f"{self.name}: {self.__class__.__name__}, {self.region}: bit {hex(bit_index)} (byte {hex(byte_index)}.{offset_in_byte}), {self.length} bits")
|
||||
if isinstance(self.region, str):
|
||||
print(f"{self.name}: {self.__class__.__name__}, {self.region}: bit {hex(bit_index)} (byte {hex(byte_index)}.{offset_in_byte}), {self.length} bits")
|
||||
else:
|
||||
print(f"{self.name}: {self.__class__.__name__}, ({self.region[0]}, {self.region[1]}): bit {hex(bit_index)} (byte {hex(byte_index)}.{offset_in_byte}), {self.length} bits")
|
||||
else:
|
||||
print(f"{self.name}: {self.__class__.__name__}, {self.length} bits")
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
import sys
|
||||
import mmap
|
||||
import logging
|
||||
from math import floor, ceil
|
||||
@ -38,52 +39,53 @@ class UninitializedObject(Object):
|
||||
def to_string(self):
|
||||
return "Uninitialized Object"
|
||||
|
||||
class Buffer(Object):
|
||||
class BufferBase(Object):
|
||||
@staticmethod
|
||||
def bitmask(to, frm):
|
||||
return ((1 << (to + 1)) - 1) - ((1 << frm) - 1)
|
||||
|
||||
def __init__(self, data):
|
||||
assert len(data) > 0
|
||||
self.__data = bytearray(data)
|
||||
self.__fields = {} # name -> (offset, bitwidth)
|
||||
def __init__(self, length):
|
||||
self.__length = length
|
||||
self.__fields = {} # name -> (offset, bitwidth, access_width)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return bytes(self.__data)
|
||||
def read(self, norm_idx, bit_width):
|
||||
return NotImplementedError(self.__class__.__name__)
|
||||
|
||||
def create_field(self, name, offset, bitwidth):
|
||||
self.__fields[name] = (offset, bitwidth)
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
return NotImplementedError(self.__class__.__name__)
|
||||
|
||||
def create_field(self, name, offset, bitwidth, access_width):
|
||||
self.__fields[name] = (offset, bitwidth, access_width)
|
||||
|
||||
def read_field(self, name):
|
||||
offset, bitwidth = self.__fields[name]
|
||||
offset, bitwidth, access_width = self.__fields[name]
|
||||
acc = 0
|
||||
acc_bit_count = 0
|
||||
bit_idx = offset
|
||||
bit_remaining = bitwidth
|
||||
|
||||
assert offset + bitwidth <= len(self.__data) * 8, \
|
||||
assert offset + bitwidth <= self.__length * 8, \
|
||||
f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits"
|
||||
|
||||
# Bits out of byte boundary
|
||||
if bit_idx % 8 > 0:
|
||||
byte_idx = floor(bit_idx / 8)
|
||||
bit_count = (8 - bit_idx % 8)
|
||||
if bit_idx % access_width > 0:
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = (access_width - bit_idx % access_width)
|
||||
if bit_count > bit_remaining:
|
||||
bit_count = bit_remaining
|
||||
|
||||
mask = self.bitmask(bit_idx % 8 + bit_count - 1, bit_idx % 8)
|
||||
acc = (self.__data[byte_idx] & mask) >> bit_idx % 8
|
||||
mask = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width)
|
||||
acc = (self.read(norm_idx, access_width) & mask) >> (bit_idx % access_width)
|
||||
acc_bit_count += bit_count
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
|
||||
while bit_remaining > 0:
|
||||
byte_idx = floor(bit_idx / 8)
|
||||
bit_count = 8 if bit_remaining >= 8 else bit_remaining
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = access_width if bit_remaining >= access_width else bit_remaining
|
||||
|
||||
mask = self.bitmask(bit_count - 1, 0)
|
||||
acc |= (self.__data[byte_idx] & mask) << acc_bit_count
|
||||
acc |= (self.read(norm_idx, access_width) & mask) << acc_bit_count
|
||||
acc_bit_count += bit_count
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
@ -91,46 +93,69 @@ class Buffer(Object):
|
||||
return acc
|
||||
|
||||
def write_field(self, name, value):
|
||||
offset, bitwidth = self.__fields[name]
|
||||
offset, bitwidth, access_width = self.__fields[name]
|
||||
bit_idx = offset
|
||||
bit_remaining = bitwidth
|
||||
|
||||
assert offset + bitwidth <= len(self.__data) * 8, \
|
||||
assert offset + bitwidth <= self.__length * 8, \
|
||||
f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits"
|
||||
|
||||
# Bits out of byte boundary
|
||||
if bit_idx % 8 > 0:
|
||||
byte_idx = floor(bit_idx / 8)
|
||||
bit_count = (8 - bit_idx % 8)
|
||||
if bit_idx % access_width > 0:
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = (access_width - bit_idx % access_width)
|
||||
if bit_count > bit_remaining:
|
||||
bit_count = bit_remaining
|
||||
|
||||
mask = self.bitmask(bit_idx % 8 + bit_count - 1, bit_idx % 8)
|
||||
v = (value & ((1 << bit_count) - 1)) << (bit_idx % 8)
|
||||
self.__data[byte_idx] = (v & mask) | (self.__data[byte_idx] & (0xFF - mask))
|
||||
mask_of_write = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width)
|
||||
mask_of_keep = ((1 << access_width) - 1) - mask_of_write
|
||||
v = (value & ((1 << bit_count) - 1)) << (bit_idx % access_width)
|
||||
self.write(norm_idx, (v & mask_of_write) | (self.read(norm_idx, access_width) & mask_of_keep), access_width)
|
||||
|
||||
value >>= bit_count
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
|
||||
while bit_remaining > 0:
|
||||
byte_idx = floor(bit_idx / 8)
|
||||
bit_count = 8 if bit_remaining >= 8 else bit_remaining
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = access_width if bit_remaining >= access_width else bit_remaining
|
||||
|
||||
mask = self.bitmask(bit_count - 1, 0)
|
||||
mask_of_write = self.bitmask(bit_count - 1, 0)
|
||||
mask_of_keep = ((1 << access_width) - 1) - mask_of_write
|
||||
v = (value & ((1 << bit_count) - 1))
|
||||
self.__data[byte_idx] = (v & mask) | (self.__data[byte_idx] & (0xFF - mask))
|
||||
self.write(norm_idx, (v & mask_of_write) | (self.read(norm_idx, access_width) & mask_of_keep), access_width)
|
||||
|
||||
value >>= bit_count
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
|
||||
def get(self):
|
||||
return self.__data
|
||||
|
||||
def to_buffer(self):
|
||||
return self
|
||||
|
||||
class Buffer(BufferBase):
|
||||
def __init__(self, data):
|
||||
assert len(data) > 0
|
||||
super().__init__(len(data))
|
||||
self.__data = bytearray(data)
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
return bytes(self.__data)
|
||||
|
||||
def read(self, norm_idx, bit_width):
|
||||
acc = 0
|
||||
byte_width = bit_width // 8
|
||||
offset = norm_idx * byte_width
|
||||
return int.from_bytes(self.__data[offset : (offset + byte_width)], sys.byteorder)
|
||||
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
byte_width = bit_width // 8
|
||||
offset = norm_idx * byte_width
|
||||
self.__data[offset : (offset + byte_width)] = value.to_bytes(byte_width, sys.byteorder)
|
||||
|
||||
def get(self):
|
||||
return self.__data
|
||||
|
||||
def to_hex_string(self):
|
||||
result = ",".join(map(lambda x:hex(x)[2:], self.__data))
|
||||
return String(result)
|
||||
@ -144,6 +169,41 @@ class Buffer(Object):
|
||||
i -= 1
|
||||
return Integer(acc)
|
||||
|
||||
class StreamIOBuffer(BufferBase):
|
||||
def __init__(self, stream, base, length):
|
||||
super().__init__(length)
|
||||
self.__stream = stream
|
||||
self.__base = base
|
||||
|
||||
def read(self, norm_idx, bit_width):
|
||||
byte_width = bit_width // 8
|
||||
address = norm_idx * byte_width
|
||||
self.__stream.seek(self.__base + address)
|
||||
data = self.__stream.read(byte_width)
|
||||
return int.from_bytes(data, sys.byteorder)
|
||||
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
byte_width = bit_width // 8
|
||||
address = norm_idx * byte_width
|
||||
self.__stream.seek(self.__base + address)
|
||||
self.__stream.write(value.to_bytes(byte_width, sys.byteorder))
|
||||
|
||||
class IndexedIOBuffer(BufferBase):
|
||||
def __init__(self, index_register, data_register):
|
||||
# FIXME: Get the real size of an indexed I/O region
|
||||
super().__init__(256)
|
||||
self.__index_register = index_register
|
||||
self.__data_register = data_register
|
||||
|
||||
def read(self, norm_idx, bit_width):
|
||||
assert bit_width == 8, f"Indexed I/O buffers can only be read one byte at a time"
|
||||
self.__index_register.set(Integer(norm_idx, 8))
|
||||
return self.__data_register.get()
|
||||
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
# Do not allow writes to indexed I/O buffer
|
||||
assert False, "Cannot write to indexed I/O buffers"
|
||||
|
||||
class BufferField(Object):
|
||||
def __init__(self, buf, field):
|
||||
self.__buf = buf
|
||||
@ -155,11 +215,14 @@ class BufferField(Object):
|
||||
def set(self, obj):
|
||||
self.__buf.write_field(self.__field, obj.get())
|
||||
|
||||
def set_writable(self):
|
||||
self.__buf.set_field_writable(self.__field)
|
||||
|
||||
def to_integer(self):
|
||||
return Integer(self.get())
|
||||
|
||||
def to_string(self):
|
||||
return "Buffer Field"
|
||||
return f"BufferField({self.__field})"
|
||||
|
||||
# DebugObject
|
||||
|
||||
@ -237,45 +300,85 @@ class ObjectReference(Object):
|
||||
self.__obj = obj
|
||||
self.__index = index
|
||||
|
||||
class OperationRegion(Buffer):
|
||||
def __load_system_memory_space(self, offset, length):
|
||||
class OperationRegion(Object):
|
||||
devmem = None
|
||||
devport = None
|
||||
opened_indexed_regions = {}
|
||||
|
||||
@classmethod
|
||||
def open_system_memory(cls, name, offset, length):
|
||||
if not cls.devmem:
|
||||
cls.devmem = open("/dev/mem", "rb", buffering=0)
|
||||
|
||||
logging.info(f"Open system memory space {name}: [{hex(offset)}, {hex(offset + length - 1)}]")
|
||||
offset_page_aligned = (offset >> 12) << 12
|
||||
length_page_aligned = ceil(((offset & 0xFFF) + length) / 0x1000) * 0x1000
|
||||
mm = mmap.mmap(cls.devmem.fileno(), length_page_aligned, flags=mmap.MAP_PRIVATE, prot=mmap.PROT_READ, offset=offset_page_aligned)
|
||||
iobuf = StreamIOBuffer(mm, offset & 0xFFF, length)
|
||||
return OperationRegion(iobuf)
|
||||
|
||||
with open('/dev/mem', 'rb') as f:
|
||||
mm = mmap.mmap(f.fileno(), length_page_aligned, flags=mmap.MAP_PRIVATE, prot=mmap.PROT_READ, offset=offset_page_aligned)
|
||||
mm.seek(offset & 0xFFF)
|
||||
data = mm.read(length)
|
||||
super().__init__(data)
|
||||
@classmethod
|
||||
def open_system_io(cls, name, offset, length):
|
||||
if not cls.devport:
|
||||
cls.devport = open("/dev/port", "w+b", buffering=0)
|
||||
|
||||
def __load_pci_configuration_space(self, bus, device, function, offset, length):
|
||||
logging.info(f"Open system I/O space {name}: [{hex(offset)}, {hex(offset + length - 1)}]")
|
||||
iobuf = StreamIOBuffer(cls.devport, offset, length)
|
||||
return OperationRegion(iobuf)
|
||||
|
||||
@classmethod
|
||||
def open_pci_configuration_space(cls, bus_number, device_adr, offset, length):
|
||||
assert offset <= 0xFF and (offset + length) <= 0x100
|
||||
# Assume bus is 0 for now
|
||||
bus = bus_number
|
||||
device = device_adr >> 16
|
||||
function = device_adr & 0xFF
|
||||
sysfs_path = "/sys/devices/pci0000:%02x/0000:%02x:%02x.%d/config" % (bus, bus, device, function)
|
||||
try:
|
||||
with open(sysfs_path, "rb") as f:
|
||||
f.seek(offset)
|
||||
data = f.read(length)
|
||||
super().__init__(data)
|
||||
f = open(sysfs_path, "rb", buffering=0)
|
||||
iobuf = StreamIOBuffer(f, offset, length)
|
||||
return OperationRegion(iobuf)
|
||||
except FileNotFoundError:
|
||||
logging.error(f"Cannot read the configuration space of %02x:%02x.%d from {sysfs_path}. Assume the PCI device does not exist." % (bus, device, function))
|
||||
logging.warning(f"Cannot read the configuration space of %02x:%02x.%d from {sysfs_path}. Assume the PCI device does not exist." % (bus, device, function))
|
||||
data = bytearray([0xff]) * length
|
||||
super().__init__(data)
|
||||
buf = Buffer(data)
|
||||
return OperationRegion(buf)
|
||||
|
||||
def __init__(self, bus_id, device_id, name, space, offset, length):
|
||||
if space == 0x00: # SystemMemory
|
||||
logging.info(f"Loading system memory space {name}: [{hex(offset)}, {hex(offset + length - 1)}]")
|
||||
self.__load_system_memory_space(offset, length)
|
||||
elif space == 0x01: # SystemIO
|
||||
raise FutureWork("Port I/O operation region")
|
||||
elif space == 0x02: # PCI_Config
|
||||
assert offset <= 0xFF and (offset + length) <= 0x100
|
||||
# Assume bus is 0 for now
|
||||
bus = bus_id
|
||||
device = device_id >> 16
|
||||
function = device_id & 0xFF
|
||||
logging.info(f"Loading PCI configuration space {name}: 00:%02x:%d [{hex(offset)}, {hex(offset + length - 1)}]" % (device, function))
|
||||
self.__load_pci_configuration_space(bus, device, function, offset, length)
|
||||
@classmethod
|
||||
def open_indexed_region(cls, index_register, data_register):
|
||||
logging.info(f"Open I/O region indexed by index register {index_register.to_string()} and data register {data_register.to_string()}.")
|
||||
k = (str(index_register), str(data_register))
|
||||
if k not in cls.opened_indexed_regions.keys():
|
||||
iobuf = IndexedIOBuffer(index_register, data_register)
|
||||
region = OperationRegion(iobuf)
|
||||
cls.opened_indexed_regions[k] = region
|
||||
|
||||
# Mark the index register as writable
|
||||
index_register.set_writable()
|
||||
|
||||
return region
|
||||
else:
|
||||
raise NotImplementedError(f"Cannot load operation region in space {space}")
|
||||
return cls.opened_indexed_regions[k]
|
||||
|
||||
def __init__(self, iobuf):
|
||||
self.__iobuf = iobuf
|
||||
self.__writable_fields = set()
|
||||
|
||||
def create_field(self, name, offset, bitwidth, access_width):
|
||||
self.__iobuf.create_field(name, offset, bitwidth, access_width)
|
||||
|
||||
def read_field(self, name):
|
||||
return self.__iobuf.read_field(name)
|
||||
|
||||
def write_field(self, name, value):
|
||||
# Do not allow writes to stream I/O buffer unless the base is explicitly marked as writable
|
||||
if name in self.__writable_fields:
|
||||
self.__iobuf.write_field(name, value)
|
||||
else:
|
||||
logging.info(f"Skip writing 0x{value:0X} to I/O field {name}")
|
||||
|
||||
def set_field_writable(self, name):
|
||||
self.__writable_fields.add(name)
|
||||
|
||||
def to_string(self):
|
||||
return "Operation Region"
|
||||
|
@ -233,11 +233,20 @@ class ConcreteInterpreter(Interpreter):
|
||||
sym = self.context.lookup_symbol(self.context.realpath(tree.scope, name))
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
assert sym.region, f"Field {sym.name} does not belong to any operation region."
|
||||
buf = self.context.lookup_operation_region(sym.region)
|
||||
if not buf:
|
||||
buf = self.interpret(self.context.lookup_symbol(sym.region).tree)
|
||||
buf.create_field(name, sym.offset, sym.length)
|
||||
field = BufferField(buf, name)
|
||||
if isinstance(sym.region, str):
|
||||
buf = self.context.lookup_operation_region(sym.region)
|
||||
if not buf:
|
||||
buf = self.interpret(self.context.lookup_symbol(sym.region).tree)
|
||||
buf.create_field(name, sym.offset, sym.length, sym.access_width)
|
||||
field = BufferField(buf, name)
|
||||
elif isinstance(sym.region, tuple):
|
||||
index_register = self.interpret(sym.region[0].tree)
|
||||
data_register = self.interpret(sym.region[1].tree)
|
||||
buf = OperationRegion.open_indexed_region(index_register, data_register)
|
||||
buf.create_field(name, sym.offset, sym.length, sym.access_width)
|
||||
field = BufferField(buf, name)
|
||||
else:
|
||||
assert False, f"Cannot interpret the operation region: {sym.region}"
|
||||
return field
|
||||
|
||||
def create_field(self, tree, bitwidth, name_idx):
|
||||
@ -246,9 +255,10 @@ class ConcreteInterpreter(Interpreter):
|
||||
index = self.interpret(tree.children[1]).get()
|
||||
name = tree.children[name_idx].children
|
||||
if bitwidth == 1 or name_idx == 3:
|
||||
buf.create_field(name, index, bitwidth)
|
||||
buf.create_field(name, index, bitwidth, 8)
|
||||
else:
|
||||
buf.create_field(name, index * 8, bitwidth)
|
||||
# bitwidth is 8, 16, 32 or 64 in this case. Reuse it as the access width.
|
||||
buf.create_field(name, index * 8, bitwidth, bitwidth)
|
||||
obj = BufferField(buf, name)
|
||||
self.context.register_binding(name, obj)
|
||||
return obj
|
||||
@ -298,18 +308,21 @@ class ConcreteInterpreter(Interpreter):
|
||||
length = self.interpret(tree.children[3]).get()
|
||||
assert isinstance(space, int) and isinstance(offset, int) and (length, int)
|
||||
|
||||
# For PCI configuration space, try to invoke _ADR (if any) of the device containing the region to get the device
|
||||
# identifier
|
||||
bus_id = None
|
||||
device_id = None
|
||||
if space == 0x2: # PCI_Config
|
||||
if space == 0x00: # SystemMemory
|
||||
op_region = OperationRegion.open_system_memory(sym.name, offset, length)
|
||||
elif space == 0x01: # SystemIO
|
||||
op_region = OperationRegion.open_system_io(sym.name, offset, length)
|
||||
elif space == 0x02: # PCI_Config
|
||||
self.context.change_scope(tree.scope)
|
||||
device_path = self.context.parent(sym.name)
|
||||
bus_id = self.interpret_method_call(f"_BBN").get()
|
||||
device_id = self.interpret_method_call(f"{device_path}._ADR").get()
|
||||
self.context.pop_scope()
|
||||
op_region = OperationRegion.open_pci_configuration_space(bus_id, device_id, offset, length)
|
||||
pass
|
||||
else:
|
||||
raise NotImplementedError(f"Cannot load operation region in space {space}")
|
||||
|
||||
op_region = OperationRegion(bus_id, device_id, sym.name, space, offset, length)
|
||||
self.context.register_operation_region(sym.name, op_region)
|
||||
return op_region
|
||||
|
||||
|
@ -459,9 +459,21 @@ def DefExternal_hook_post(context, tree):
|
||||
sym = NamedDecl(name, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
access_width_map = {
|
||||
0: 8, # AnyAcc
|
||||
1: 8, # ByteAcc
|
||||
2: 16, # WordAcc
|
||||
3: 32, # DWordAcc
|
||||
4: 64, # QWordAcc
|
||||
5: 8, # BufferAcc
|
||||
# The other values are reserved
|
||||
}
|
||||
|
||||
def DefField_hook_post(context, tree):
|
||||
# Update the fields with region & offset info
|
||||
region_name = context.lookup_symbol(tree.children[1].children).name
|
||||
flags = tree.children[2].children[0].children
|
||||
access_width = access_width_map[flags & 0xF]
|
||||
fields = tree.children[3].children
|
||||
bit_offset = 0
|
||||
for field in fields:
|
||||
@ -471,7 +483,30 @@ def DefField_hook_post(context, tree):
|
||||
length = field.children[1].children
|
||||
sym = context.lookup_symbol(name)
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
sym.set_location(region_name, bit_offset)
|
||||
sym.set_location(region_name, bit_offset, access_width)
|
||||
bit_offset += length
|
||||
elif field.label == "ReservedField":
|
||||
length = field.children[0].children
|
||||
bit_offset += length
|
||||
else:
|
||||
break
|
||||
|
||||
def DefIndexField_hook_post(context, tree):
|
||||
# Update the fields with region & offset info
|
||||
index_register = context.lookup_symbol(tree.children[1].children)
|
||||
data_register = context.lookup_symbol(tree.children[2].children)
|
||||
flags = tree.children[3].children[0].children
|
||||
access_width = access_width_map[flags & 0xF]
|
||||
fields = tree.children[4].children
|
||||
bit_offset = 0
|
||||
for field in fields:
|
||||
field = field.children[0]
|
||||
if field.label == "NamedField":
|
||||
name = field.children[0].children
|
||||
length = field.children[1].children
|
||||
sym = context.lookup_symbol(name)
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
sym.set_indexed_location(index_register, data_register, bit_offset, access_width)
|
||||
bit_offset += length
|
||||
elif field.label == "ReservedField":
|
||||
length = field.children[0].children
|
||||
|
Loading…
Reference in New Issue
Block a user