aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristofer Jonsson <kristofer.jonsson@arm.com>2022-09-29 11:52:22 +0200
committerKristofer Jonsson <kristofer.jonsson@arm.com>2022-10-19 09:18:46 +0200
commite56b6e4bd75c7ccec69f20b17c1e2d48b7c0892c (patch)
treeaa7838114949917bcd8846a448d7f7921522711f
parent01c32d4768d8176a32c193f44069da1f43fbf513 (diff)
downloadethos-u-core-platform-e56b6e4bd75c7ccec69f20b17c1e2d48b7c0892c.tar.gz
Ethos-U PMU monitor
Add Python script demonstrating how to download performance data from device. Write baremetal PMU events to Event Recorder ring buffer and increase the systick sample rate. Change-Id: Ib73c56100a8de2d7b74c455d8f80cda0b59383da
-rw-r--r--.gitignore1
-rw-r--r--applications/baremetal/main.cpp9
-rwxr-xr-xscripts/ethosu_monitor.py149
-rw-r--r--scripts/ethosumonitor/elf.py47
-rw-r--r--scripts/ethosumonitor/inputs.py173
-rw-r--r--scripts/ethosumonitor/outputs.py83
-rw-r--r--scripts/ethosumonitor/sample.json19
-rw-r--r--scripts/ethosumonitor/types.py129
-rw-r--r--targets/corstone-300/CMakeLists.txt5
-rw-r--r--targets/corstone-300/event_recorder/EventRecorderConf.h47
10 files changed, 655 insertions, 7 deletions
diff --git a/.gitignore b/.gitignore
index 796b96d..f284d11 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
/build
+__pycache__
diff --git a/applications/baremetal/main.cpp b/applications/baremetal/main.cpp
index ab365c6..6ed7cbe 100644
--- a/applications/baremetal/main.cpp
+++ b/applications/baremetal/main.cpp
@@ -72,20 +72,15 @@ uint8_t outputData[sizeof(expectedOutputData)] __attribute__((aligned(16), secti
#endif
#ifdef ETHOSU
-constexpr int32_t EventComponentNo = 0x00;
namespace {
std::vector<ethosu_pmu_event_type> pmuEventConfig{ethosu_pmu_event_type(ETHOSU_PMU_EVENT_0),
ethosu_pmu_event_type(ETHOSU_PMU_EVENT_1),
ethosu_pmu_event_type(ETHOSU_PMU_EVENT_2),
ethosu_pmu_event_type(ETHOSU_PMU_EVENT_3)};
-std::vector<int32_t> eventRecMessageIds{EventID(EventLevelDetail, EventComponentNo, ETHOSU_PMU_EVENT_0),
- EventID(EventLevelDetail, EventComponentNo, ETHOSU_PMU_EVENT_1),
- EventID(EventLevelDetail, EventComponentNo, ETHOSU_PMU_EVENT_2),
- EventID(EventLevelDetail, EventComponentNo, ETHOSU_PMU_EVENT_3)};
-const uint32_t delayMs = SystemCoreClock / 60ul;
+const uint32_t delayMs = SystemCoreClock / 1000ul;
struct ethosu_driver *ethosuDrv;
-EthosUMonitor ethosuMonitor(eventRecMessageIds, EthosUMonitor::Backend::PRINTF);
+EthosUMonitor ethosuMonitor(EthosUMonitor::Backend::EVENT_RECORDER);
} // namespace
extern "C" {
diff --git a/scripts/ethosu_monitor.py b/scripts/ethosu_monitor.py
new file mode 100755
index 0000000..60f0bdf
--- /dev/null
+++ b/scripts/ethosu_monitor.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+
+#
+# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from ethosumonitor.inputs import *
+from ethosumonitor.outputs import *
+from sys import stderr, exit
+
+def eventLoop(input: InputInterface, output: OutputInterface):
+ count = 0
+
+ try:
+ while(True):
+ for record in input.readEventRecord():
+ output.writeEventRecord(record)
+ count = count + 1
+ except KeyboardInterrupt:
+ stderr.write(f'count={count}, input={input}\n')
+ pass
+ except EOFError:
+ pass
+
+ output.flush()
+
+def getDAPLink(args):
+ return InputDAPLink(args.elf)
+
+def getMem(args):
+ return InputMem(args.elf, args.memory_map)
+
+def getFile(args):
+ return InputFile(args.file)
+
+def getOutput(args):
+ if args.output_format == 'binary':
+ return OutputBinary(args.output)
+ else:
+ return OutputJson(args.output)
+
+def addOutputArguments(parser):
+ parser.add_argument('--output-format', choices=['binary', 'json'], default='json', help='Output format.')
+ parser.add_argument('-o', '--output', default='/dev/stdout', help='Output file.')
+
+def main():
+ import argparse
+
+ parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='Ethos-U monitor downloading profiling data.',
+ epilog='''
+Event Recorder:
+ The Event Recorder library is used to write performance data to a ring buffer
+ in memory. The ring buffer has a limited size and must be continuously
+ streamed to a host machine before it overflows.
+
+ This script demonstrates how to stream performance data using DAPLink or
+ /dev/mem. Support for other technologies can be added implementing the
+ InputInterface class in inputs.py.
+''')
+ subparsers = parser.add_subparsers()
+
+ subparser = subparsers.add_parser('daplink',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='Download performance data using DAPLink.',
+ epilog='''
+DAPLink:
+ Arm Mbed DAPLink is an open source project that enables programming and
+ debugging application software running on an Arm Cortex CPU. A host machine
+ can connect to the target device using for example USB or JTAG.
+
+ This script demonstrates how DAPLink can be used to stream Event Recorder
+ data from a target device. The ELF file passed to the script must be the
+ same application that is running on the device, and is used to find the
+ location of the Event Recorder ring buffer.
+
+ $ ethosu_monitor.py daplink --target mps3_an540 myapplication.elf
+''')
+ subparser.set_defaults(getInput=getDAPLink)
+ subparser.add_argument('--target', default='mps3_an540', help='DAPLink target platform.')
+ subparser.add_argument('elf', help='Elf file running on the target.')
+ addOutputArguments(subparser)
+
+ subparser = subparsers.add_parser('memory',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='Download performance data using /dev/mem.',
+ epilog='''
+/dev/mem:
+ For a Linux based system the Event Recorder buffer should be stored in shared
+ memory accessible from Linux. This allows Linux to read device the Event
+ Recorder ring buffer using /dev/mem.
+
+ The address of the Event Recorder ring buffer is found parsing the ELF
+ file. Because the device and Linux do not share the same address space a
+ memory map is required to translate device addresses into host addresses.
+ Please see sample.json for reference.
+
+ $ ethosu_monitor.py memory --memory-map config.json myapplication.elf
+''')
+ subparser.set_defaults(getInput=getMem)
+ subparser.add_argument('--memory-map', required=True, help='JSON file describing physical memory map of target.')
+ subparser.add_argument('elf', help='Elf file running on the target.')
+ addOutputArguments(subparser)
+
+ subparser = subparsers.add_parser('file',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description='Replay performance data stored in binary file.',
+ epilog='''
+file:
+ Event Recorder data can be written in binary format for later processing.
+ This will likely have less latency than the default JSON format, reducing
+ the risk over ring buffer overflows.
+
+ $ ethosu_monitor.py daplink --output-format binary --output samples.bin myapplication.elf
+
+ The binary data can later be unpacked to JSON.
+
+ $ ethosu_monitor.py file samples.bin --output-format json
+''')
+ subparser.set_defaults(getInput=getFile)
+ subparser.add_argument('file', help='Binary file containing recorded performance data.')
+ addOutputArguments(subparser)
+
+ args = parser.parse_args()
+
+ if 'getInput' not in args:
+ parser.print_help()
+ exit(2)
+
+ input = args.getInput(args)
+ output = getOutput(args)
+ eventLoop(input, output)
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/ethosumonitor/elf.py b/scripts/ethosumonitor/elf.py
new file mode 100644
index 0000000..bf9ab39
--- /dev/null
+++ b/scripts/ethosumonitor/elf.py
@@ -0,0 +1,47 @@
+#
+# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+def elfFindSymbol(elf, name):
+ from elftools.elf.sections import SymbolTableSection
+
+ for section in elf.iter_sections():
+ if isinstance(section, SymbolTableSection):
+ symbol = section.get_symbol_by_name(name)
+ if symbol:
+ return symbol[0]
+
+ return None
+
+def elfGetData(elf, address, size):
+ for section in elf.iter_sections():
+ if address >= section.header['sh_addr'] and \
+ (address + size) < (section.header['sh_addr'] + section.header['sh_size']):
+ offset = address - section.header['sh_addr']
+ return bytearray(section.data()[offset:offset+size])
+
+ return None
+
+def elfGetSymbolData(elf, name):
+ from sys import stderr
+
+ symbol = elfFindSymbol(elf, name)
+ if not symbol:
+ stderr.write(f'Failed to find symbol {name}\n')
+ return None
+
+ return elfGetData(elf, symbol.entry.st_value, symbol.entry.st_size)
diff --git a/scripts/ethosumonitor/inputs.py b/scripts/ethosumonitor/inputs.py
new file mode 100644
index 0000000..60fb8ed
--- /dev/null
+++ b/scripts/ethosumonitor/inputs.py
@@ -0,0 +1,173 @@
+#
+# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from .elf import *
+from .types import *
+import json
+import mmap
+import os
+from sys import stderr
+
+class InputInterface:
+ def readEventRecord(self) -> EventRecord_t:
+ ...
+
+class InputFile(InputInterface):
+ def __init__(self, fname):
+ self.file = open(fname, 'rb')
+
+ def readEventRecord(self):
+ data = self.file.read(EventRecord_t.SIZE)
+ if len(data) == 0:
+ raise EOFError
+
+ yield data
+
+class InputRingBuffer(InputInterface):
+ def __init__(self, elfFile):
+ from elftools.elf.elffile import ELFFile
+
+ with open(elfFile, 'rb') as f:
+ elf = ELFFile(f)
+ symbol = elfFindSymbol(elf, 'EventRecorderInfo')
+ elfInfo = EventRecorderInfo_t(elfGetData(elf, symbol.entry.st_value, symbol.entry.st_size))
+ memInfo = EventRecorderInfo_t(self.read(symbol.entry.st_value, symbol.entry.st_size))
+
+ # Validate EventRecorder info
+ if elfInfo.protocolType != memInfo.protocolType or \
+ elfInfo.protocolVersion != memInfo.protocolVersion or \
+ elfInfo.eventBuffer != memInfo.eventBuffer or \
+ elfInfo.eventStatus != memInfo.eventStatus:
+ raise Exception(f'EventRecorder info mismatch. elf={elfInfo}, mem={memInfo}')
+
+ self.info = elfInfo
+ status = EventStatus_t(self.read(self.info.eventStatus, EventStatus_t.SIZE))
+ self.timestamp = status.tsLast
+ self.recordIndex = status.recordIndex
+ self.overflow = 0
+
+ def readEventRecord(self):
+ # Read status and use timestamp to detect if there are new samples
+ status = EventStatus_t(self.read(self.info.eventStatus, EventStatus_t.SIZE))
+ if self.timestamp == status.tsLast:
+ return None
+
+ self.timestamp = status.tsLast
+
+ # Detect firmware reset
+ if self.recordIndex > status.recordIndex:
+ self.recordIndex = 0
+
+ # Detect of recordIndex has overflowed the ring buffer
+ if status.recordIndex - self.recordIndex > self.info.recordCount:
+ stderr.write('Warning: Ring buffer overflow\n')
+ self.overflow = self.overflow + 1
+ self.recordIndex = status.recordIndex
+
+ # Generate data for each event record
+ for i in range(self.recordIndex, status.recordIndex):
+ i = i % self.info.recordCount
+ yield self.read(self.info.eventBuffer + EventRecord_t.SIZE * i, EventRecord_t.SIZE)
+
+ self.recordIndex = status.recordIndex
+
+ def read(self, address, size) -> bytearray:
+ ...
+
+class InputDAPLink(InputRingBuffer):
+ def __init__(self, elfFile):
+ self._open()
+ super().__init__(elfFile)
+ self.target.reset()
+
+ def _open(self):
+ from pyocd.core.helpers import ConnectHelper
+
+ self.session = ConnectHelper.session_with_chosen_probe()
+ self.board = self.session.board
+ self.target = self.board.target
+
+ self.session.open()
+
+ def read(self, address, size):
+ from pyocd.core.exceptions import Error
+
+ for i in range(1000):
+ try:
+ return bytearray(self.target.read_memory_block8(address, size))
+ except Error:
+ pass
+
+class InputMem(InputRingBuffer):
+ def __init__(self, elfFile, jsonFile):
+ with open(jsonFile, 'r') as f:
+ jsonDoc = json.loads(f.read())
+
+ self.memoryMap = []
+ for memoryMap in jsonDoc['memoryMap']:
+ host = int(memoryMap['host'], 16)
+ device = int(memoryMap['device'], 16)
+ size = int(memoryMap['size'], 16)
+ self.memoryMap.append(DevMemDevice(host, device, size))
+
+ super().__init__(elfFile)
+
+ def read(self, device, size):
+ for memoryMap in self.memoryMap:
+ data = memoryMap.read(device, size)
+ if data:
+ return data
+
+ stderr.write(f'Warning: No mapping found for device address {hex(device)} size {size}.\n')
+ return None
+
+class DevMem:
+ def __init__(self, address, size):
+ self.base_address = address & ~(mmap.PAGESIZE - 1)
+ self.offset = address - self.base_address
+ self.size = size + self.offset
+
+ self.fd = os.open('/dev/mem', os.O_RDWR | os.O_SYNC)
+ self.mem = mmap.mmap(self.fd, self.size, mmap.MAP_SHARED, mmap.PROT_READ,
+ offset=self.base_address)
+
+ def __del__(self):
+ os.close(self.fd)
+
+ def read(self, offset, size):
+ self.mem.seek(self.offset + offset)
+
+ data = bytearray(size)
+ for i in range(size):
+ data[i] = self.mem.read_byte()
+
+ return data
+
+class DevMemDevice(DevMem):
+ def __init__(self, host, device, size):
+ super().__init__(host, size)
+
+ self.device = device
+ self.size = size
+
+ def read(self, device, size):
+ offset = device - self.device
+ if offset < 0 or (offset + size) > self.size:
+ return None
+
+ return super().read(offset, size)
diff --git a/scripts/ethosumonitor/outputs.py b/scripts/ethosumonitor/outputs.py
new file mode 100644
index 0000000..5a4101c
--- /dev/null
+++ b/scripts/ethosumonitor/outputs.py
@@ -0,0 +1,83 @@
+#
+# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from .types import *
+from sys import stderr
+
+class OutputInterface:
+ def flush(self):
+ ...
+
+ def writeEventRecord(self, data: bytearray):
+ ...
+
+class OutputBinary(OutputInterface):
+ def __init__(self, fname):
+ self.file = open(fname, 'wb')
+
+ def flush(self):
+ self.file.flush()
+
+ def writeEventRecord(self, data: bytearray):
+ self.file.write(data)
+
+class OutputJson(OutputInterface):
+ def __init__(self, fname):
+ self.file = open(fname, 'w')
+
+ self.count = 0
+ self.nextId = 0
+ self.timestamp = 0
+ self.event = []
+
+ def flush(self):
+ self.file.flush()
+
+ def writeEventRecord(self, data: bytearray):
+ record = EventRecord_t(data)
+
+ if record.first():
+ # Drop messages that don't originate from Ethos-U
+ if record.component() != EventRecord_t.ETHOSU_CID:
+ return
+
+ self.nextId = 0
+ self.timestamp = record.timestamp
+ self.eventConfig = []
+ self.eventCount = []
+
+ messageIndex = record.message()
+
+ if self.nextId != messageIndex or self.timestamp != record.timestamp:
+ stderr.write(f'Expected record id {self.nextId} and timestamp {self.timestamp} but got {messageIndex} and {record.timestamp}. count={self.count}, locked={record.locked()}, valid={record.valid()}\n')
+ stderr.write(f'record={record}\n')
+ return
+
+ self.nextId = messageIndex + 1
+
+ if messageIndex == 0:
+ self.cycleCount = record.val2 << 32 | record.val1
+ elif messageIndex == 1:
+ self.qread = record.val1
+ self.status = record.val2
+ else:
+ self.eventConfig.append(record.val1)
+ self.eventCount.append(record.val2)
+
+ if record.last():
+ self.file.write(f'{{ "timestamp": {self.timestamp}, "qread": {self.qread}, "status": {self.status}, "cycleCount": {self.cycleCount}, "eventConfig": [ {", ".join(map(str, self.eventConfig))} ], "eventCount": [ {", ".join(map(str, self.eventCount))} ] }}\n')
diff --git a/scripts/ethosumonitor/sample.json b/scripts/ethosumonitor/sample.json
new file mode 100644
index 0000000..537e95a
--- /dev/null
+++ b/scripts/ethosumonitor/sample.json
@@ -0,0 +1,19 @@
+{
+ "__comment__": [
+ "'host' is the Linux physical address accessible from /dev/mem.",
+ "'device' is the corresponding device address.",
+ "'size' is the size in bytes of the memory region."
+ ],
+ "memoryMap": [
+ {
+ "host": "0x6cf00000",
+ "device": "0x00000000",
+ "size": "0x00400000"
+ },
+ {
+ "host": "0x84000000",
+ "device": "0x64000000",
+ "size": "0x01000000"
+ }
+ ]
+}
diff --git a/scripts/ethosumonitor/types.py b/scripts/ethosumonitor/types.py
new file mode 100644
index 0000000..5116955
--- /dev/null
+++ b/scripts/ethosumonitor/types.py
@@ -0,0 +1,129 @@
+#
+# SPDX-FileCopyrightText: Copyright 2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the License); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an AS IS BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import struct
+
+class EventRecord_t:
+ SIZE = 16
+
+ INFO_ID_MASK = 0x0000FFFF
+ INFO_MESSAGE_MASK = 0x000000FF
+ INFO_COMPONENT_MASK = 0x0000FF00
+ INFO_COMPONENT_POS = 8
+ INFO_FIRST = 0x01000000
+ INFO_LAST = 0x02000000
+ INFO_LOCKED = 0x04000000
+ INFO_VALID = 0x08000000
+ INFO_MSB_TS = 0x10000000
+ INFO_MSB_VAL1 = 0x20000000
+ INFO_MSB_VAL2 = 0x40000000
+ INFO_TBIT = 0x80000000
+
+ # Component identifiers
+ EVENT_CID = 0xFF
+ ETHOSU_CID = 0x00
+
+ # Message identifiers
+ EVENT_MID_INIT = 0x00
+ EVENT_MID_START = 0x01
+ EVENT_MID_STOP = 0x02
+ EVENT_MID_CLOCK = 0x03
+
+ EVENT_ID_INIT = (EVENT_CID << 8) | EVENT_MID_INIT
+ EVENT_ID_START = (EVENT_CID << 8) | EVENT_MID_START
+ EVENT_ID_STOP = (EVENT_CID << 8) | EVENT_MID_STOP
+ EVENT_ID_CLOCK = (EVENT_CID << 8) | EVENT_MID_CLOCK
+
+ def __init__(self, data):
+ self.data = data
+
+ # Unpack the struct and restore the MSB from info to timestamp, val1 and val2
+ t = struct.unpack('IIII', data)
+ self.timestamp = t[0] & ~EventRecord_t.INFO_TBIT | (t[3] & EventRecord_t.INFO_MSB_TS) << 3
+ self.val1 = t[1] & ~EventRecord_t.INFO_TBIT | (t[3] & EventRecord_t.INFO_MSB_VAL1) << 2
+ self.val2 = t[2] & ~EventRecord_t.INFO_TBIT | (t[3] & EventRecord_t.INFO_MSB_VAL2) << 1
+ self.info = t[3]
+
+ def first(self):
+ return self.info & EventRecord_t.INFO_FIRST != 0
+
+ def last(self):
+ return self.info & EventRecord_t.INFO_LAST != 0
+
+ def component(self):
+ return (self.info & EventRecord_t.INFO_COMPONENT_MASK) >> EventRecord_t.INFO_COMPONENT_POS
+
+ def message(self):
+ return self.info & EventRecord_t.INFO_MESSAGE_MASK
+
+ def id(self):
+ return self.info & EventRecord_t.INFO_ID_MASK
+
+ def locked(self):
+ return self.info & EventRecord_t.INFO_LOCKED != 0
+
+ def valid(self):
+ return self.info & EventRecord_t.INFO_VALID != 0
+
+ def __str__(self):
+ return f'{{ "timestamp": {hex(self.timestamp)}, "val1": {hex(self.val1)}, "val2": {hex(self.val2)}, "info": "{hex(self.info)}" }}'
+
+class EventStatus_t:
+ SIZE = 36
+
+ def __init__(self, data):
+ t = struct.unpack('BBHIIIIIIII', data)
+
+ self.state = t[0]
+ self.context = t[1]
+ self.infoCrc = t[2]
+ self.recordIndex = t[3]
+ self.recordsWritten = t[4]
+ self.recordsDumped = t[5]
+ self.tsOverflow = t[6]
+ self.tsFreq = t[7]
+ self.tsLast = t[8]
+ self.initCount = t[9]
+ self.signature = t[10]
+
+ def __str__(self):
+ return f'{{ state={self.state}, context={self.context}, info_crc={self.infoCrc}, ' \
+ f'record_index={self.recordIndex}, records_written={self.recordsWritten}, records_dumped={self.recordsDumped}, ' \
+ f'ts_overflow={self.tsOverflow}, ts_freq={self.tsFreq}, ts_last={self.tsLast}, ' \
+ f'init_count={self.initCount}, signature={self.signature} }}'
+
+class EventRecorderInfo_t:
+ SIZE = 24
+
+ def __init__(self, data):
+ t = struct.unpack('BBHIIIIBBBB', data)
+
+ self.protocolType = t[0]
+ # self._reserved = t[1]
+ self.protocolVersion = t[2]
+ self.recordCount = t[3]
+ self.eventBuffer = t[4]
+ self.eventFilter = t[5]
+ self.eventStatus = t[6]
+ self.tsSource = t[7]
+ # self._reserved1 = t[8]
+ # self._reserved2 = t[9]
+ # self._reserved3 = t[10]
+
+ def __str__(self):
+ return f'{{ protocolType={hex(self.protocolType)}, protocolVersion={hex(self.protocolVersion)}, recordCount={self.recordCount}, eventBuffer={hex(self.eventBuffer)}, eventFilter={hex(self.eventFilter)}, eventStatus={hex(self.eventStatus)}, tsSource={self.tsSource} }}'
diff --git a/targets/corstone-300/CMakeLists.txt b/targets/corstone-300/CMakeLists.txt
index b129b71..b76c474 100644
--- a/targets/corstone-300/CMakeLists.txt
+++ b/targets/corstone-300/CMakeLists.txt
@@ -132,6 +132,11 @@ if (TARGET ethosu_core_driver)
ETHOSU)
endif()
+if (TARGET event_recorder)
+ target_include_directories(event_recorder BEFORE INTERFACE
+ event_recorder)
+endif()
+
###############################################################################
# Applications
###############################################################################
diff --git a/targets/corstone-300/event_recorder/EventRecorderConf.h b/targets/corstone-300/event_recorder/EventRecorderConf.h
new file mode 100644
index 0000000..396cfd9
--- /dev/null
+++ b/targets/corstone-300/event_recorder/EventRecorderConf.h
@@ -0,0 +1,47 @@
+/*
+ * SPDX-FileCopyrightText: Copyright 2016-2022 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Name: EventRecorderConf.h
+ * Purpose: Event Recorder software component configuration options
+ * Rev.: V1.1.0
+ */
+
+//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
+
+// <h>Event Recorder
+
+// <o>Number of Records
+// <8=>8 <16=>16 <32=>32 <64=>64 <128=>128 <256=>256 <512=>512 <1024=>1024
+// <2048=>2048 <4096=>4096 <8192=>8192 <16384=>16384 <32768=>32768
+// <65536=>65536
+// <i>Configures size of Event Record Buffer (each record is 16 bytes)
+// <i>Must be 2^n (min=8, max=65536)
+#define EVENT_RECORD_COUNT 1024U
+
+// <o>Time Stamp Source
+// <0=> DWT Cycle Counter <1=> SysTick <2=> CMSIS-RTOS2 System Timer
+// <3=> User Timer (Normal Reset) <4=> User Timer (Power-On Reset)
+// <i>Selects source for 32-bit time stamp
+#define EVENT_TIMESTAMP_SOURCE 0
+
+// <o>Time Stamp Clock Frequency [Hz] <0-1000000000>
+// <i>Defines initial time stamp clock frequency (0 when not used)
+#define EVENT_TIMESTAMP_FREQ 0U
+
+// </h>
+
+//------------- <<< end of configuration section >>> ---------------------------