HAL Architecture Specification

Introduction

The Hardware Abstraction Layer (HAL) provides a software-visible representation of openENOC hardware components and defines a standardized mechanism for accessing their Control and Status Registers (CSRs). The HAL serves as the primary interface between software and hardware, enabling configuration, monitoring, diagnostics, and runtime control of openENOC subsystems.

This document specifies the HAL architecture and CSR organization for the openENOC Switch and the openENOC Endpoint Interface. The described CSR definitions establish a common programming model for software components and serve as the authoritative reference for hardware/software integration.

CSR Specification Methodology

Within this flow, Control and Status Registers are defined using Accellera’s SystemRDL 2.0 as the authoritative specification format for all openENOC hardware components.

For artefact generation, the openENOC toolchain is based on PeakRDL, which processes the SystemRDL description and produces the corresponding CSR-related outputs used throughout the build and verification flow. Since the current PeakRDL implementation does not support all features of the SystemRDL 2.0 standard, CSR definitions are written with this limitation in mind to ensure that the complete register specification can be translated into all required generated artefacts without manual intervention or post-processing.

openENOC Switch HAL Architecture

The openENOC Switch provides frame-forwarding and management functionality within the openENOC system. Software access to switch resources is provided through the openENOC Control Interface, which exposes a memory-mapped CSR space.

The switch HAL defines the software-visible representation of switch functionality and provides a consistent programming model independent of implementation-specific details.

Architecture

The switch HAL is organized around a CSR-based management interface that exposes configuration, status, monitoring, and diagnostic functionality. Software components interact with switch resources through register accesses performed over the openENOC Control Interface. The HAL architecture establishes a clear separation between software-visible behavior and the underlying frame-forwarding implementation, allowing internal switch architectures to evolve while maintaining software compatibility.

A central configuration aspect of the switch HAL is the selection of the switch operating mode. In unmanaged mode, the switch operates autonomously and forwarding state is maintained by internal hardware logic. In this mode, the switch may learn forwarding table entries from observed traffic and update its forwarding state without software intervention. In managed mode, forwarding behavior is controlled through software-visible configuration mechanisms exposed by the openENOC Control Interface. This allows an external processor to populate, update, inspect, or invalidate forwarding table entries according to system-specific requirements.

The operating mode is controlled through switch configuration registers. These registers define whether the switch operates autonomously or under software control, and they provide the foundation for additional management functions such as forwarding table updates, status inspection, diagnostics, and event handling. Status registers expose the current operational state of the switch and allow software to determine whether the switch is active, idle, paused, or operating under a specific management mode.

The default forwarding behavior for frames that do not match any enabled forwarding table entry is defined through a dedicated register containing a destination interface bitmap. This register specifies the set of output interfaces to which unmatched frames shall be forwarded. In managed mode, this mechanism allows unmatched frames to be redirected toward a switch controller implemented on one of the openENOC endpoints. Such frames are delivered to the controller using the standard openENOC Endpoint Interface, preserving the same data-plane abstraction used by other endpoint-to-network communication.

Since forwarding table updates may affect the active forwarding behavior of the switch, the HAL includes a switch-level flow control mechanism used during managed reconfiguration. This mechanism is exposed through a Flow Control Register and allows software to temporarily stop or pause the flow of frames through the switch before modifying forwarding state. After the pause request is issued, software can observe the corresponding status indication to determine when the switch has reached a safe state for table modification.

Once the switch is paused, software may update forwarding table entries through the CSR space without interfering with active frame forwarding. After the update sequence is complete, software releases the pause condition and normal forwarding operation resumes. This mechanism provides a simple and deterministic way to perform controlled forwarding table reconfiguration while avoiding inconsistent lookup behavior during partial updates.

The flow control mechanism described here is local to switch management and should not be confused with link-level or protocol-level flow control. Its purpose is to coordinate software-driven CSR updates with the internal forwarding pipeline of the switch.

In managed mode, the HAL therefore provides both configuration access and operational control over the switch forwarding behavior. In unmanaged mode, the same hardware may operate without software intervention, and the openENOC Control Interface may be omitted if no external configuration or monitoring functionality is required.

Forwarding Table

A central software-visible structure of the openENOC Switch is the forwarding table, which defines how frames are forwarded based on their destination MAC address. The table is exposed through the CSR space and can be configured by software using the openENOC Control Interface.

The forwarding table contains entries aligned to a 32-bit data bus. Each forwarding table entry is represented in the CSR space by fields containing a destination MAC address, an N-bit destination interface bitmap, a single enable bit, and padding bits required for alignment to the 32-bit bus width. The destination interface bitmap defines the set of output interfaces to which a matching frame shall be forwarded.

_images/openENOC-SwitchForwardingTable.svg

Example forwarding table for an 8-port openENOC Switch

The figure illustrates an example forwarding table for an openENOC Switch with 8 ports. The table contains several representative forwarding rules. Rule (1) defines unicast forwarding of frames with destination address 0x020E0C000011 to the first output interface. Rule (2) represents a disabled unicast rule that remains present in the table but is not applied during forwarding lookup. Rule (3) defines multicast forwarding of frames with destination address 0x030E0C330000 to the first, third, fifth, and seventh output interfaces. Rule (4) defines frame dropping for destination address 0x020E0C123456 by means of an enabled entry with an empty destination interface bitmap. Rule (M) defines the broadcast forwarding rule for frames with destination address 0xFFFFFFFFFFFF.

Register Definitions and CSR Memory Map

The SystemRDL source shown below defines the CSR structure of the openENOC Switch. This source file is the maintained register specification used by the PeakRDL-based generation flow.

SystemRDL specification of the openENOC Switch CSR map
  1// SPDX-FileCopyrightText: 2026 Enio Kaljic
  2// SPDX-License-Identifier: CERN-OHL-S-2.0
  3
  4addrmap openenoc_switch #(
  5    longint unsigned NUM_OF_INTERFACES = 1,
  6    longint unsigned TABLE_DEPTH = 1,
  7    string INST_NAME = "openenoc_switch"
  8) {
  9    name = INST_NAME;
 10    desc = "Control and status register map for an openENOC Switch instance. It includes configuration registers and a forwarding table used to map destination MAC address keys to output interface selections for frame forwarding.";
 11
 12    littleendian;
 13    default accesswidth = 32;
 14    default regwidth = 32;
 15    default alignment = 4;
 16    addressing = regalign;
 17
 18    reg info {
 19        name = {INST_NAME, ".info"};
 20        desc = "Read-only information register for this openENOC Switch instance.";
 21
 22        field {
 23            name = {INST_NAME, ".info.num_of_interfaces[21:16]"};
 24            desc = "Number of interfaces in this openENOC Switch instance. This field reflects the NUM_OF_INTERFACES parameter value.";
 25
 26            sw = r;
 27            hw = r;
 28        } num_of_interfaces[21:16] = NUM_OF_INTERFACES;
 29
 30        field {
 31            name = {INST_NAME, ".info.table_depth[15:0]"};
 32            desc = "Depth of the forwarding table in this openENOC Switch instance. This field reflects the TABLE_DEPTH parameter value.";
 33
 34            sw = r;
 35            hw = r;
 36        } table_depth[15:0] = TABLE_DEPTH;
 37    } info;
 38
 39    reg forwarding_control {
 40        name = {INST_NAME, ".forwarding_control"};
 41        desc = "Forwarding control register for the openENOC Switch instance.";
 42
 43        field {
 44            name = {INST_NAME, ".forwarding_control.operation_mode[0:0]"};
 45            desc = "Mode of operation for the openENOC Switch instance. When set to 1, the switch operates in managed mode, allowing software to configure the forwarding table and control forwarding operations. When set to 0, the switch operates in unmanaged mode, where forwarding state is maintained autonomously by internal hardware logic without software intervention.";
 46
 47            sw = rw;
 48            hw = r;
 49        } operation_mode[0:0] = 0;
 50
 51        field {
 52            name = {INST_NAME, ".forwarding_control.pause_request[7:7]"};
 53            desc = "Pause request for the forwarding logic. When set, this field requests the switch to pause frame forwarding and clear its internal pipeline before forwarding table updates are performed.";
 54
 55
 56            sw = rw;
 57            hw = r;
 58        } pause_request[7:7] = 0;
 59
 60        field {
 61            name = {INST_NAME, ".forwarding_control.pause_done[15:15]"};
 62            desc = "Pause done status. When set, this field indicates that the switch has paused frame forwarding and reached a safe state for forwarding table modification.";
 63
 64            sw = r;
 65            hw = w;
 66        } pause_done[15:15];
 67    } forwarding_control;
 68
 69    reg default_forwarding {
 70        name = {INST_NAME, ".default_forwarding"};
 71        desc = "Defines the destination interface or interfaces for frames that do not match any enabled forwarding table entry.";
 72
 73        field {
 74            name = {INST_NAME, ".default_forwarding.bitmap[NUM_OF_INTERFACES-1:0]"};
 75            desc = "Bitmap selecting the output interface or interfaces to which frames that do not match any enabled forwarding table entry are forwarded. Bit NUM_OF_INTERFACES-1, the MSB, corresponds to the first interface; bit 0 corresponds to the last interface.";
 76
 77            sw = rw;
 78            hw = r;
 79        } bitmap[NUM_OF_INTERFACES-1:0] = 0;
 80    } default_forwarding;
 81
 82    external regfile forwarding_table {
 83        name = {INST_NAME, ".forwarding_table"};
 84        desc = "Forwarding table used to map MAC addresses to output interface selections for frame forwarding.";
 85
 86        regfile entry {
 87            name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1]"};
 88            desc = "Forwarding table entry containing the MAC address key, output interface selection, and entry configuration.";
 89
 90            reg mac_address {
 91                name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].mac_address"};
 92                desc = "48-bit destination MAC address used as the key for this forwarding table entry.";
 93
 94                regwidth = 64;
 95
 96                field {
 97                    name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].mac_address.hi_word[47:32]"};
 98                    desc = "Upper 16 bits [47:32] of the 48-bit MAC address stored in this forwarding table entry.";
 99
100                    sw = rw;
101                    hw = rw;
102                } hi_word[47:32];
103
104                field {
105                    name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].mac_address.lo_word[31:0]"};
106                    desc = "Lower 32 bits [31:0] of the 48-bit MAC address stored in this forwarding table entry.";
107
108                    sw = rw;
109                    hw = rw;
110                } lo_word[31:0];
111            } mac_address;
112
113            reg iface {
114                name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].iface"};
115                desc = "Forwarding interface information associated with this forwarding table entry.";
116
117                field {
118                    name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].iface.bitmap[NUM_OF_INTERFACES-1:0]"};
119                    desc = "Bitmap selecting the output interface or interfaces to which a matching frame is forwarded. Bit NUM_OF_INTERFACES-1, the MSB, corresponds to the first interface; bit 0 corresponds to the last interface.";
120
121                    sw = rw;
122                    hw = rw;
123                } bitmap[NUM_OF_INTERFACES-1:0];
124            } iface;
125
126            reg config {
127                name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].config"};
128                desc = "Configuration information associated with this forwarding table entry.";
129
130                field {
131                    name = {INST_NAME, ".forwarding_table.entry[0..TABLE_DEPTH-1].config.enabled"};
132                    desc = "Enables this forwarding table entry. When cleared, the entry is ignored during forwarding table lookup.";
133
134                    sw = rw;
135                    hw = rw;
136                } enabled;
137            } config;
138        } entry[TABLE_DEPTH];
139    } forwarding_table;
140};

The openENOC Switch CSR memory map and detailed register documentation are derived directly from this SystemRDL specification. The generated CSR documentation provides the corresponding human-readable description of the register hierarchy, address offsets, field layouts, access permissions, reset values, and associated register semantics.

The complete generated CSR documentation is available in openenoc_switch address map.

openENOC Endpoint Interface HAL Architecture

The openENOC Endpoint Interface provides the connection between processing elements and the openENOC network. It exposes endpoint control, status monitoring, and communication management functionality through a dedicated CSR space.

The endpoint HAL establishes a uniform software interface for accessing endpoint resources and controlling interactions with the network.

Architecture

The endpoint HAL is organized around a CSR-based management interface that exposes endpoint configuration, software-visible stream access, remote peer configuration, DMA control, and a virtual remote-memory region. Software components interact with endpoint resources through register accesses performed over the openENOC Control Interface. The HAL architecture establishes a clear separation between software-visible endpoint behavior and the underlying oETP frame handling, allowing internal buffering, DMA scheduling, and protocol processing logic to evolve while maintaining software compatibility.

A central configuration aspect of the endpoint HAL is the description of the local endpoint instance and the set of remote peers that it can access. The read-only information register exposes implementation parameters such as the total depth of the virtual remote-memory region and the number of supported remote peers. These values allow software to discover the size and structure of the endpoint address space without relying on hard-coded assumptions.

The endpoint configuration registers define the local MAC address used by the endpoint when exchanging frames with the openENOC network. Remote communication targets are described through a peer table, where each entry contains the MAC address of a remote peer, the offset of the corresponding virtual remote-memory region, the local memory base address, the remote memory base address, and the size of the region. This structure allows software to describe how local memory resources are related to remote memory regions visible through the endpoint.

The HAL supports two complementary access models. The first model is a software-visible AXI4-Stream access path exposed through source and sink register files. The source register file allows software to provide stream data words, assert the corresponding valid indication, and mark the last word of a frame. Software observes the ready status to determine when the endpoint can accept the next transfer. Conversely, the sink register file allows hardware to present received stream data to software, together with valid and last indications, while software acknowledges reception through the ready control field.

This CSR-mapped AXI4-Stream interface mirrors the basic AXI4-Stream handshake semantics in software-visible form. It is useful for low-bandwidth communication, diagnostics, initialization sequences, and simple software-driven frame exchange. The mechanism does not prescribe the internal implementation of the endpoint datapath; it only defines how stream-oriented transfers are exposed through the HAL.

The second access model is memory-oriented communication through the virtual remote-memory region. This region provides a software-visible address space representing memory associated with one or more remote peers. The mapping between a remote peer and its corresponding portion of the virtual memory space is defined by the peer configuration registers. Accesses to this region may be handled directly or used as the basis for DMA-driven transfers, depending on the configured DMA mode for the selected peer.

DMA behavior is controlled independently for each peer. When DMA operation is disabled, the peer entry remains configured but no automatic transfer is performed. In transparent mode, accesses to the virtual remote-memory region are translated into corresponding accesses to the remote peer memory region on a word-by-word basis. This mode is suitable when software requires a direct memory-mapped view of remote resources and when simple access semantics are preferred over bulk synchronization.

The endpoint HAL also supports mirrored transfer modes. In mirror-to-local mode, the local memory region is used as the software-visible representation of the remote peer memory, and the state of the remote memory region is fetched from the remote peer on demand or periodically. In mirror-to-remote mode, the remote memory region is used as the destination representation, and the state of the local memory region is sent to the remote peer on demand or periodically. These modes allow software to configure endpoint-to-endpoint memory synchronization without directly managing individual transport frames.

DMA transfers are initiated through a peer-specific request field. The corresponding status fields indicate whether the DMA engine is idle, whether the requested transfer has completed successfully, or whether an error has occurred. A typical software sequence therefore consists of configuring the peer address mapping, selecting the DMA mode, issuing a transfer request, and observing the idle, done, and error status indications until the operation reaches a terminal state.

The DMA control mechanism described here is local to endpoint management and should not be confused with Ethernet link-level or protocol-level flow control. Its purpose is to coordinate software-visible memory mappings and transfer requests with the internal endpoint datapath, DMA engine, and oETP processing logic.

The endpoint HAL therefore provides both a stream-oriented and a memory-oriented abstraction for communication with the openENOC network. The AXI4-Stream register interface offers a simple CSR-accessible path for direct frame exchange, while the peer table, virtual remote-memory region, and DMA controls provide a scalable mechanism for accessing and synchronizing memory resources across endpoints.

Register Definitions and CSR Memory Map

The SystemRDL source shown below defines the CSR structure of the openENOC Endpoint Interface. This source file is the maintained register specification used by the PeakRDL-based generation flow.

SystemRDL specification of the openENOC Endpoint Interface CSR map
  1// SPDX-FileCopyrightText: 2026 Enio Kaljic
  2// SPDX-License-Identifier: CERN-OHL-S-2.0
  3
  4addrmap openenoc_endpoint #(
  5    longint unsigned RMEM_TOTAL_DEPTH = 256,
  6    longint unsigned NUM_OF_PEERS = 1,
  7    string INST_NAME = "openenoc_endpoint"
  8) {
  9    name = INST_NAME;
 10    desc = "Control and status register map for an openENOC Endpoint Interface instance.";
 11
 12    littleendian;
 13    default accesswidth = 32;
 14    default regwidth = 32;
 15    default alignment = 4;
 16    addressing = regalign;
 17
 18    reg info {
 19        name = {INST_NAME, ".info"};
 20        desc = "Read-only information register for this openENOC Endpoint Interface instance.";
 21
 22        regwidth = 64;
 23
 24        field {
 25            name = {INST_NAME, ".info.rmem_total_depth[15:0]"};
 26            desc = "Total depth of the shared memory region for all remote peers. This field reflects the RMEM_TOTAL_DEPTH parameter value.";
 27
 28            sw = r;
 29            hw = r;
 30        } rmem_total_depth[31:0] = RMEM_TOTAL_DEPTH;
 31
 32        field {
 33            name = {INST_NAME, ".info.num_of_peers[31:16]"};
 34            desc = "Number of remote peers supported by this openENOC Endpoint Interface instance. This field reflects the NUM_OF_PEERS parameter value.";
 35
 36            sw = r;
 37            hw = r;
 38        } num_of_peers[63:32] = NUM_OF_PEERS;
 39    } info;
 40
 41    regfile config {
 42        name = {INST_NAME, ".config"};
 43        desc = "Configuration register file for this openENOC Endpoint Interface instance.";
 44
 45        reg mac_address {
 46            name = {INST_NAME, ".config.mac_address"};
 47            desc = "Local site 48-bit destination MAC address.";
 48
 49            regwidth = 64;
 50
 51            field {
 52                name = {INST_NAME, ".config.mac_address.lo_word[31:0]"};
 53                desc = "Lower 32 bits [31:0] of the 48-bit MAC address.";
 54
 55                sw = rw;
 56                hw = rw;
 57            } lo_word[31:0] = 0;
 58
 59            field {
 60                name = {INST_NAME, ".config.mac_address.hi_word[47:32]"};
 61                desc = "Upper 16 bits [47:32] of the 48-bit MAC address.";
 62
 63                sw = rw;
 64                hw = rw;
 65            } hi_word[47:32] = 0;
 66        } mac_address;
 67    } config;
 68
 69    regfile axis_if {
 70        name = {INST_NAME, ".axis_if"};
 71        desc = "Register file for the AXI4-Stream source and sink interfaces.";
 72
 73        regfile source {
 74            name = {INST_NAME, ".axis_if.source"};
 75            desc = "Register file for the AXI4-Stream source interface.";
 76
 77            reg data {
 78                name = {INST_NAME, ".axis_if.source.data"};
 79                desc = "Data register for the AXI4-Stream source interface.";
 80
 81                field {
 82                    name = {INST_NAME, ".axis_if.source.data.tdata[31:0]"};
 83                    desc = "32-bit data value for the AXI4-Stream source interface.";
 84
 85                    sw = rw;
 86                    hw = r;
 87                } tdata[31:0] = 0;
 88            } data;
 89
 90            reg control {
 91                name = {INST_NAME, ".axis_if.source.control"};
 92                desc = "Control register for the AXI4-Stream source interface.";
 93
 94                field {
 95                    name = {INST_NAME, ".axis_if.source.control.tvalid"};
 96                    desc = "Indicates that the AXI4-Stream source interface has valid data to send. This field is a single-pulse register that is automatically cleared back to zero after being written.";
 97
 98                    singlepulse = true;
 99                    sw = rw;
100                    hw = r;
101                } tvalid[0:0] = 0;
102
103                field {
104                    name = {INST_NAME, ".axis_if.source.control.tlast"};
105                    desc = "Indicates the last data word of a frame on the AXI4-Stream source interface.";
106
107                    sw = rw;
108                    hw = r;
109                } tlast[8:8] = 0;
110            } control;
111
112            reg status {
113                name = {INST_NAME, ".axis_if.source.status"};
114                desc = "Status register for the AXI4-Stream source interface.";
115
116                field {
117                    name = {INST_NAME, ".axis_if.source.status.tready"};
118                    desc = "Indicates that the destination AXI4-Stream interface is ready to receive data.";
119
120                    sw = r;
121                    hw = w;
122                } tready[0:0] = 0;
123            } status;
124        } source;
125
126        regfile sink {
127            name = {INST_NAME, ".axis_if.sink"};
128            desc = "Register file for the AXI4-Stream sink interface.";
129
130            reg data {
131                name = {INST_NAME, ".axis_if.sink.data"};
132                desc = "Data register for the AXI4-Stream sink interface.";
133
134                field {
135                    name = {INST_NAME, ".axis_if.sink.data.tdata[31:0]"};
136                    desc = "32-bit data value for the AXI4-Stream sink interface.";
137
138                    sw = r;
139                    hw = w;
140                } tdata[31:0];
141            } data;
142
143            reg control {
144                name = {INST_NAME, ".axis_if.sink.control"};
145                desc = "Control register for the AXI4-Stream sink interface.";
146
147                field {
148                    name = {INST_NAME, ".axis_if.sink.control.tready"};
149                    desc = "Indicates that the AXI4-Stream sink interface is ready to receive next data transfer.";
150
151                    singlepulse = true;
152                    sw = w;
153                    hw = r;
154                } tready[0:0] = 0;
155            } control;
156
157            reg status {
158                name = {INST_NAME, ".axis_if.sink.status"};
159                desc = "Status register for the AXI4-Stream sink interface.";
160
161                field {
162                    name = {INST_NAME, ".axis_if.sink.status.tvalid"};
163                    desc = "Indicates that the AXI4-Stream sink interface has valid data to receive.";
164
165                    sw = r;
166                    hw = w;
167                } tvalid[0:0];
168
169                field {
170                    name = {INST_NAME, ".axis_if.sink.status.tlast"};
171                    desc = "Indicates the last data word of a frame on the AXI4-Stream sink interface.";
172
173                    sw = r;
174                    hw = w;
175                } tlast[8:8];
176            } status;
177        } sink;
178    } axis_if;
179
180    regfile peers {
181        name = {INST_NAME, ".peers"};
182        desc = "Register file for remote peer configuration and memory region information.";
183
184        regfile entry {
185            name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1]"};
186            desc = "Register file for a single remote peer configuration and memory region information.";
187
188            reg mac_address {
189                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].mac_address"};
190                desc = "Remote peer 48-bit destination MAC address.";
191
192                regwidth = 64;
193
194                field {
195                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].mac_address.lo_word[31:0]"};
196                    desc = "Lower 32 bits [31:0] of the 48-bit MAC address.";
197
198                    sw = rw;
199                    hw = rw;
200                } lo_word[31:0];
201
202                field {
203                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].mac_address.hi_word[47:32]"};
204                    desc = "Upper 16 bits [47:32] of the 48-bit MAC address.";
205
206                    sw = rw;
207                    hw = rw;
208                } hi_word[47:32];
209            } mac_address;
210
211            reg rmem_address {
212                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].rmem_address"};
213                desc = "Address offset of the virtual memory region corresponding to the remote peer's memory.";
214
215                field {
216                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].rmem_address.offset[31:0]"};
217                    desc = "Word-aligned 32-bit address offset of the virtual memory region corresponding to the remote peer's memory.";
218
219                    sw = rw;
220                    hw = r;
221                } offset[31:0];
222            } rmem_address;
223
224            reg local_address {
225                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].local_address"};
226                desc = "Start address of the local memory region for DMA transfers.";
227
228                field {
229                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].local_address.base[31:0]"};
230                    desc = "Word-aligned 32-bit start address of the local memory region for DMA transfers.";
231
232                    sw = rw;
233                    hw = r;
234                } base[31:0];
235            } local_address;
236
237            reg remote_address {
238                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].remote_address"};
239                desc = "Start address of the remote peer's memory region.";
240
241                field {
242                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].remote_address.base[31:0]"};
243                    desc = "Word-aligned 32-bit start address of the remote peer's memory region.";
244
245                    sw = rw;
246                    hw = r;
247                } base[31:0];
248            } remote_address;
249
250            reg size {
251                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].size"};
252                desc = "Size of the remote peer's memory region.";
253
254                field {
255                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].size.bytes[31:0]"};
256                    desc = "32-bit size of the remote peer's memory region in bytes.";
257
258                    sw = rw;
259                    hw = r;
260                } bytes[31:0];
261            } size;
262
263            reg dma {
264                name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma"};
265                desc = "DMA configuration and control for the remote peer.";
266
267                field {
268                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma.mode[1:0]"};
269                    desc = "
270                        DMA mode for transfers to/from the remote peer:<ul>
271                        <li>0: DMA transfers to/from the remote peer are disabled.</li>
272                        <li>1: DMA transfers to/from the remote peer are enabled in transparent mode, where accesses to the virtual memory region are directly translated to corresponding accesses to the remote peer's memory region (transactions are word-by-word, i.e., per virtual memory access).</li>
273                        <li>2: DMA transfers to/from the remote peer are enabled in mirror-to-local mode, where the local memory region is used instead of the virtual memory region. The state of the remote peer's memory region (remote_address, size) is fetched from the remote peer on demand or periodically.</li>
274                        <li>3: DMA transfers to/from the remote peer are enabled in mirror-to-remote mode, where the remote memory region is used instead of the virtual memory region. The state of the local peer's memory region (local_address, size) is sent to the remote peer on demand or periodically.</li>
275                        </ul>
276                    ";
277
278                    sw = rw;
279                    hw = r;
280                } mode[1:0];
281
282                field {
283                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma.request[8:8]"};
284                    desc = "Writing a 1 to this field initiates a DMA transfer to/from the remote peer. This field is a single-pulse register that is automatically cleared back to zero after being written.";
285
286                    singlepulse = true;
287                    sw = rw;
288                    hw = r;
289                } request[8:8] = 0;
290
291                field {
292                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma.idle[16:16]"};
293                    desc = "Indicates whether the DMA transfer to/from the remote peer is idle. A value of 1 indicates that the DMA transfer is idle, while a value of 0 indicates that the DMA transfer is in progress.";
294
295                    sw = r;
296                    hw = w;
297                } idle[16:16];
298
299                field {
300                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma.done[24:24]"};
301                    desc = "Indicates whether the DMA transfer to/from the remote peer has been successful. A value of 1 indicates that the DMA transfer has completed successfully, while a value of 0 indicates that the DMA transfer is still in progress or has encountered an error.";
302
303                    sw = r;
304                    hw = w;
305                } done[24:24];
306
307                field {
308                    name = {INST_NAME, ".peers.entry[0..NUM_OF_PEERS-1].dma.error[25:25]"};
309                    desc = "Indicates whether the DMA transfer to/from the remote peer has encountered an error. A value of 1 indicates an error, while a value of 0 indicates no error.";
310
311                    sw = r;
312                    hw = w;
313                } error[25:25];
314            } dma;
315        } entry[NUM_OF_PEERS];
316    } peers;
317
318    external mem rmem {
319        name = "rmem";
320        desc = "Virtual memory region for all remote peers, with offsets and sizes defined in the peers regfile.";
321        mementries = RMEM_TOTAL_DEPTH;
322        memwidth = 32;
323    } rmem;
324};

The openENOC Endpoint Interface CSR memory map and detailed register documentation are derived directly from this SystemRDL specification. The generated CSR documentation provides the corresponding human-readable description of the register hierarchy, address offsets, field layouts, access permissions, reset values, and associated register semantics.

The complete generated CSR documentation is available in openenoc_endpoint address map.

Summary

This document defines the HAL architecture and CSR organization for the openENOC Switch and the openENOC Endpoint Interface.

The HAL establishes a consistent software-visible programming model based on memory-mapped Control and Status Registers, while the CSR specification provides the authoritative description of hardware/software interactions. Together, these mechanisms form the foundation for software development, system integration, and verification activities within the openENOC project.