From 54df215e2382ea9c6f189b1a2b94068bcd6e88ca Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Thu, 21 May 2026 14:43:17 +0100 Subject: [PATCH 1/4] sw: rdlgen: emit a 'none' variant with value 0 for flag enums Add a none variant with a value of 0 when generating flag enum bits. This is useful to represent "no interrupt(s)" or "no bits" to give to an enable_write/status_write function. Signed-off-by: Alice Ziuziakowska --- sw/device/lib/hal/autogen/clkmgr.h | 3 +++ sw/device/lib/hal/autogen/entropy_src.h | 2 ++ sw/device/lib/hal/autogen/i2c.h | 6 ++++++ sw/device/lib/hal/autogen/kmac.h | 2 ++ sw/device/lib/hal/autogen/rom_ctrl.h | 1 + sw/device/lib/hal/autogen/rstmgr.h | 2 ++ sw/device/lib/hal/autogen/spi_device.h | 4 ++++ sw/device/lib/hal/autogen/uart.h | 3 +++ util/rdlgenerator.py | 3 +++ 9 files changed, 26 insertions(+) diff --git a/sw/device/lib/hal/autogen/clkmgr.h b/sw/device/lib/hal/autogen/clkmgr.h index 10c6630f5..7aa4499db 100644 --- a/sw/device/lib/hal/autogen/clkmgr.h +++ b/sw/device/lib/hal/autogen/clkmgr.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] clkmgr_alert_test : uint32_t { + clkmgr_alert_test_none = (0), clkmgr_alert_test_recov_fault = (1u << 0), clkmgr_alert_test_fatal_fault = (1u << 1), } clkmgr_alert_test; @@ -66,6 +67,7 @@ typedef struct [[gnu::aligned(4)]] { } clkmgr_main_meas_ctrl_shadowed; typedef enum [[clang::flag_enum]] clkmgr_recov_err_code : uint32_t { + clkmgr_recov_err_code_none = (0), clkmgr_recov_err_code_shadow_update_err = (1u << 0), clkmgr_recov_err_code_io_measure_err = (1u << 1), clkmgr_recov_err_code_main_measure_err = (1u << 2), @@ -74,6 +76,7 @@ typedef enum [[clang::flag_enum]] clkmgr_recov_err_code : uint32_t { } clkmgr_recov_err_code; typedef enum [[clang::flag_enum]] clkmgr_fatal_err_code : uint32_t { + clkmgr_fatal_err_code_none = (0), clkmgr_fatal_err_code_reg_intg = (1u << 0), clkmgr_fatal_err_code_idle_cnt = (1u << 1), clkmgr_fatal_err_code_shadow_storage_err = (1u << 2), diff --git a/sw/device/lib/hal/autogen/entropy_src.h b/sw/device/lib/hal/autogen/entropy_src.h index c41b4ce64..cc66100f7 100644 --- a/sw/device/lib/hal/autogen/entropy_src.h +++ b/sw/device/lib/hal/autogen/entropy_src.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] entropy_src_intr : uint32_t { + entropy_src_intr_none = (0), entropy_src_intr_es_entropy_valid = (1u << 0), entropy_src_intr_es_health_test_failed = (1u << 1), entropy_src_intr_es_observe_fifo_ready = (1u << 2), @@ -16,6 +17,7 @@ typedef enum [[clang::flag_enum]] entropy_src_intr : uint32_t { } entropy_src_intr; typedef enum [[clang::flag_enum]] entropy_src_alert_test : uint32_t { + entropy_src_alert_test_none = (0), entropy_src_alert_test_recov_alert = (1u << 0), entropy_src_alert_test_fatal_alert = (1u << 1), } entropy_src_alert_test; diff --git a/sw/device/lib/hal/autogen/i2c.h b/sw/device/lib/hal/autogen/i2c.h index d656dec80..897ea4133 100644 --- a/sw/device/lib/hal/autogen/i2c.h +++ b/sw/device/lib/hal/autogen/i2c.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] i2c_intr : uint32_t { + i2c_intr_none = (0), i2c_intr_fmt_threshold = (1u << 0), i2c_intr_rx_threshold = (1u << 1), i2c_intr_acq_threshold = (1u << 2), @@ -32,6 +33,7 @@ typedef struct [[gnu::aligned(4)]] { } i2c_alert_test; typedef enum [[clang::flag_enum]] i2c_ctrl : uint32_t { + i2c_ctrl_none = (0), i2c_ctrl_enablehost = (1u << 0), i2c_ctrl_enabletarget = (1u << 1), i2c_ctrl_llpbk = (1u << 2), @@ -42,6 +44,7 @@ typedef enum [[clang::flag_enum]] i2c_ctrl : uint32_t { } i2c_ctrl; typedef enum [[clang::flag_enum]] i2c_status : uint32_t { + i2c_status_none = (0), i2c_status_fmtfull = (1u << 0), i2c_status_rxfull = (1u << 1), i2c_status_fmtempty = (1u << 2), @@ -108,6 +111,7 @@ typedef struct [[gnu::aligned(4)]] { } i2c_target_fifo_status; typedef enum [[clang::flag_enum]] i2c_ovrd : uint32_t { + i2c_ovrd_none = (0), i2c_ovrd_txovrden = (1u << 0), i2c_ovrd_sclval = (1u << 1), i2c_ovrd_sdaval = (1u << 2), @@ -210,6 +214,7 @@ typedef struct [[gnu::aligned(4)]] { } i2c_acq_fifo_next_data; typedef enum [[clang::flag_enum]] i2c_controller_events : uint32_t { + i2c_controller_events_none = (0), i2c_controller_events_nack = (1u << 0), i2c_controller_events_unhandled_nack_timeout = (1u << 1), i2c_controller_events_bus_timeout = (1u << 2), @@ -217,6 +222,7 @@ typedef enum [[clang::flag_enum]] i2c_controller_events : uint32_t { } i2c_controller_events; typedef enum [[clang::flag_enum]] i2c_target_events : uint32_t { + i2c_target_events_none = (0), i2c_target_events_tx_pending = (1u << 0), i2c_target_events_bus_timeout = (1u << 1), i2c_target_events_arbitration_lost = (1u << 2), diff --git a/sw/device/lib/hal/autogen/kmac.h b/sw/device/lib/hal/autogen/kmac.h index ea8a212a1..366823632 100644 --- a/sw/device/lib/hal/autogen/kmac.h +++ b/sw/device/lib/hal/autogen/kmac.h @@ -9,12 +9,14 @@ #include typedef enum [[clang::flag_enum]] kmac_intr : uint32_t { + kmac_intr_none = (0), kmac_intr_kmac_done = (1u << 0), kmac_intr_fifo_empty = (1u << 1), kmac_intr_kmac_err = (1u << 2), } kmac_intr; typedef enum [[clang::flag_enum]] kmac_alert_test : uint32_t { + kmac_alert_test_none = (0), kmac_alert_test_recov_operation_err = (1u << 0), kmac_alert_test_fatal_fault_err = (1u << 1), } kmac_alert_test; diff --git a/sw/device/lib/hal/autogen/rom_ctrl.h b/sw/device/lib/hal/autogen/rom_ctrl.h index b475c8b0c..6d95d6d1e 100644 --- a/sw/device/lib/hal/autogen/rom_ctrl.h +++ b/sw/device/lib/hal/autogen/rom_ctrl.h @@ -14,6 +14,7 @@ typedef struct [[gnu::aligned(4)]] { } rom_ctrl_alert_test; typedef enum [[clang::flag_enum]] rom_ctrl_fatal_alert_cause : uint32_t { + rom_ctrl_fatal_alert_cause_none = (0), rom_ctrl_fatal_alert_cause_checker_error = (1u << 0), rom_ctrl_fatal_alert_cause_integrity_error = (1u << 1), } rom_ctrl_fatal_alert_cause; diff --git a/sw/device/lib/hal/autogen/rstmgr.h b/sw/device/lib/hal/autogen/rstmgr.h index 839e699a9..b9182459c 100644 --- a/sw/device/lib/hal/autogen/rstmgr.h +++ b/sw/device/lib/hal/autogen/rstmgr.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] rstmgr_alert_test : uint32_t { + rstmgr_alert_test_none = (0), rstmgr_alert_test_fatal_fault = (1u << 0), rstmgr_alert_test_fatal_cnsty_fault = (1u << 1), } rstmgr_alert_test; @@ -71,6 +72,7 @@ typedef struct [[gnu::aligned(4)]] { } rstmgr_sw_rst_ctrl_n; typedef enum [[clang::flag_enum]] rstmgr_err_code : uint32_t { + rstmgr_err_code_none = (0), rstmgr_err_code_reg_intg_err = (1u << 0), rstmgr_err_code_reset_consistency_err = (1u << 1), rstmgr_err_code_fsm_err = (1u << 2), diff --git a/sw/device/lib/hal/autogen/spi_device.h b/sw/device/lib/hal/autogen/spi_device.h index f22b56295..40928e6dc 100644 --- a/sw/device/lib/hal/autogen/spi_device.h +++ b/sw/device/lib/hal/autogen/spi_device.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] spi_device_intr : uint32_t { + spi_device_intr_none = (0), spi_device_intr_upload_cmdfifo_not_empty = (1u << 0), spi_device_intr_upload_payload_not_empty = (1u << 1), spi_device_intr_upload_payload_overflow = (1u << 2), @@ -49,6 +50,7 @@ typedef struct [[gnu::aligned(4)]] { } spi_device_status; typedef enum [[clang::flag_enum]] spi_device_intercept_en : uint32_t { + spi_device_intercept_en_none = (0), spi_device_intercept_en_status = (1u << 0), spi_device_intercept_en_jedec = (1u << 1), spi_device_intercept_en_sfdp = (1u << 2), @@ -163,6 +165,7 @@ typedef struct [[gnu::aligned(4)]] { } spi_device_tpm_cap; typedef enum [[clang::flag_enum]] spi_device_tpm_cfg : uint32_t { + spi_device_tpm_cfg_none = (0), spi_device_tpm_cfg_en = (1u << 0), spi_device_tpm_cfg_tpm_mode = (1u << 1), spi_device_tpm_cfg_hw_reg_dis = (1u << 2), @@ -171,6 +174,7 @@ typedef enum [[clang::flag_enum]] spi_device_tpm_cfg : uint32_t { } spi_device_tpm_cfg; typedef enum [[clang::flag_enum]] spi_device_tpm_status : uint32_t { + spi_device_tpm_status_none = (0), spi_device_tpm_status_cmdaddr_notempty = (1u << 0), spi_device_tpm_status_wrfifo_pending = (1u << 1), spi_device_tpm_status_rdfifo_aborted = (1u << 2), diff --git a/sw/device/lib/hal/autogen/uart.h b/sw/device/lib/hal/autogen/uart.h index 93b384510..c92bab998 100644 --- a/sw/device/lib/hal/autogen/uart.h +++ b/sw/device/lib/hal/autogen/uart.h @@ -9,6 +9,7 @@ #include typedef enum [[clang::flag_enum]] uart_intr : uint32_t { + uart_intr_none = (0), uart_intr_tx_watermark = (1u << 0), uart_intr_rx_watermark = (1u << 1), uart_intr_tx_done = (1u << 2), @@ -40,6 +41,7 @@ typedef struct [[gnu::aligned(4)]] { } uart_ctrl; typedef enum [[clang::flag_enum]] uart_status : uint32_t { + uart_status_none = (0), uart_status_txfull = (1u << 0), uart_status_rxfull = (1u << 1), uart_status_txempty = (1u << 2), @@ -74,6 +76,7 @@ typedef struct [[gnu::aligned(4)]] { } uart_fifo_status; typedef enum [[clang::flag_enum]] uart_ovrd : uint32_t { + uart_ovrd_none = (0), uart_ovrd_txen = (1u << 0), uart_ovrd_txval = (1u << 1), } uart_ovrd; diff --git a/util/rdlgenerator.py b/util/rdlgenerator.py index cb9ac8249..d2523644a 100755 --- a/util/rdlgenerator.py +++ b/util/rdlgenerator.py @@ -266,10 +266,12 @@ def register_is_flag_enum(reg: dict) -> bool: def emit_register_flag_enum(device_name: str, reg: dict) -> str: """ Emit register as a flag enum, see 'register_is_flag_enum' predicate. + We additionally emit a 'none' variant with a value of 0. """ reg_name = reg["name"].lower() fully_qualified_type_name = "_".join([device_name, reg_name]) enum_variants = [] + enum_variants.append(f"{'_'.join([device_name, reg_name, 'none'])} = (0),") for bit, field in enumerate(fields_ascending_by_lsb(reg)): field_name = field["name"].lower() fully_qualified_field_name = "_".join([device_name, reg_name, field_name]) @@ -289,6 +291,7 @@ def emit_common_device_register_declaration( common_name = stripped_longest_common_prefix([x["name"] for x in register_set]) fully_qualified_type_name = "_".join([device_name, common_name]) enum_variants = [] + enum_variants.append(f"{'_'.join([device_name, common_name, 'none'])} = (0),") for bit, field in enumerate(fields_ascending_by_lsb(register_set[0])): field_name = field["name"].lower() fully_qualified_field_name = "_".join([device_name, common_name, field_name]) From 8d86116bdef9dcdfee940be12b8ebdbccfa9c0c8 Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Thu, 21 May 2026 15:59:05 +0100 Subject: [PATCH 2/4] sw: rdlgen: support interspersed registers and windows The SPI Host has two register windows in between other register fields, whereas before this it was assumed that all register windows come after registers. Signed-off-by: Alice Ziuziakowska --- util/rdlgenerator.py | 92 +++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 30 deletions(-) diff --git a/util/rdlgenerator.py b/util/rdlgenerator.py index d2523644a..771815a61 100755 --- a/util/rdlgenerator.py +++ b/util/rdlgenerator.py @@ -425,16 +425,31 @@ def emit_device_register_field(device_name: str, reg: dict, type_name: str) -> s def emit_device_window_field(device_name: str, window: dict) -> str: window_name = window["name"].lower() - num_u32s = window["entries"] + num_entries = window["entries"] + mem_width = window["width"] + mem_width_bytes = 0 + type_name = None + if mem_width == 32: + mem_width_bytes = 4 + type_name = "uint32_t" + elif mem_width == 64: + mem_width_bytes = 8 + type_name = "uint64_t" + else: + raise ValueError( + f"Register window '{window_name}' in device '{device_name}' " + "has entries that are not 32-bits or 64-bits wide" + ) + offset = window["offset"] - end = offset + window["size"] - 4 - offset_string = f"{hex(offset)}-{hex(end)}" + end = offset + window["size"] - mem_width_bytes + offset_string = hex(offset) if num_entries == 1 else f"{hex(offset)}-{hex(end)}" return "\n".join( indent_lines( [ f"/* {device_name}.{window_name} ({offset_string}) */", - f"{'const ' if not window['sw_writable'] else ''}uint32_t " - f"{window_name}[{num_u32s}];", + f"{'const ' if not window['sw_writable'] else ''}{type_name} " + f"{window_name}{f'[{num_entries}]' if num_entries > 1 else ''};", ] ) ) @@ -451,10 +466,19 @@ def emit_device_struct_declaration( ) -> str: """ Emit the declaration of the device's memory layout. The fields of this structure are the - device's registers, with necessary padding fields around them. + device's registers and windows, with necessary padding fields around them. """ - typed_registers_ascending_by_offset = sorted( - typed_registers, key=lambda reg: min(reg[0]["offsets"]) + # all the struct declaration fields. Tag each with a boolean value representing whether + # it is a register or not (a window). + declaration_fields = [(True, register) for register in typed_registers] + [ + (False, window) for window in windows + ] + + # sort the struct fields in ascending order by offset. the specific keys differ based + # on whether it is a register or a window. + fields_asceding_by_offset = sorted( + declaration_fields, + key=lambda field: min(field[1][0]["offsets"]) if field[0] else field[1]["offset"], ) # number of padding fields in the struct so far @@ -462,32 +486,40 @@ def emit_device_struct_declaration( # top offset of last register field, used to calculate size of padding end_of_last_reg = 0 # iterate over the register in ascending order of offset - device_struct_reg_declarations = [] - for reg, reg_type_name in typed_registers_ascending_by_offset: - offsets = reg["offsets"] - start_of_reg = min(offsets) - if (start_of_reg - end_of_last_reg) > 0: - device_struct_reg_declarations.append( - emit_device_register_padding_field(padding_field_num, end_of_last_reg, start_of_reg) - ) - padding_field_num += 1 - end_of_last_reg = max(offsets) + 4 - device_struct_reg_declarations.append( - emit_device_register_field(device_name, reg, reg_type_name) - ) - for window in windows: - start_of_reg = window["offset"] - if (start_of_reg - end_of_last_reg) > 0: - device_struct_reg_declarations.append( - emit_device_register_padding_field(padding_field_num, end_of_last_reg, start_of_reg) + device_struct_field_declarations = [] + for is_register, reg_or_window in fields_asceding_by_offset: + if is_register: + reg, reg_type_name = reg_or_window[0], reg_or_window[1] + offsets = reg["offsets"] + start_of_reg = min(offsets) + if (start_of_reg - end_of_last_reg) > 0: + device_struct_field_declarations.append( + emit_device_register_padding_field( + padding_field_num, end_of_last_reg, start_of_reg + ) + ) + padding_field_num += 1 + end_of_last_reg = max(offsets) + 4 + device_struct_field_declarations.append( + emit_device_register_field(device_name, reg, reg_type_name) ) - padding_field_num += 1 - end_of_last_reg = start_of_reg + window["size"] - device_struct_reg_declarations.append(emit_device_window_field(device_name, window)) + else: + window = reg_or_window + start_of_reg = window["offset"] + if (start_of_reg - end_of_last_reg) > 0: + device_struct_field_declarations.append( + emit_device_register_padding_field( + padding_field_num, end_of_last_reg, start_of_reg + ) + ) + padding_field_num += 1 + end_of_last_reg = start_of_reg + window["size"] + device_struct_field_declarations.append(emit_device_window_field(device_name, window)) + return "\n".join( [ f"typedef volatile struct {struct_aligned_attribute} {device_name}_memory_layout {{", - "\n\n".join(device_struct_reg_declarations), + "\n\n".join(device_struct_field_declarations), f"}} *{device_name}_t;", ] ) From 09243ed36afbecbe224494f68bf09b5eb1a9048a Mon Sep 17 00:00:00 2001 From: Alice Ziuziakowska Date: Thu, 21 May 2026 16:03:13 +0100 Subject: [PATCH 3/4] sw: rdl: autogenerate SPI Host header from RDL description Signed-off-by: Alice Ziuziakowska --- rdl/mocha.rdl | 3 +- sw/device/lib/hal/autogen/spi_host.h | 187 +++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 sw/device/lib/hal/autogen/spi_host.h diff --git a/rdl/mocha.rdl b/rdl/mocha.rdl index cb20778ea..f1382d279 100644 --- a/rdl/mocha.rdl +++ b/rdl/mocha.rdl @@ -58,7 +58,7 @@ addrmap top_mocha { rv_timer TIMER[1] @ 0x4400_0000 += 0x10000; - reserved SPI_HOST @ 0x4500_0000; + spi_host SPI_HOST[1] @ 0x4500_0000 += 0x10000; rv_plic PLIC @ 0x4800_0000; @@ -66,4 +66,3 @@ addrmap top_mocha { mementries = 0x7F00000; memwidth=64; // 1 GiB (excluding tag storage) } DRAM @ 0x8000_0000; }; - diff --git a/sw/device/lib/hal/autogen/spi_host.h b/sw/device/lib/hal/autogen/spi_host.h new file mode 100644 index 000000000..3bc37f09b --- /dev/null +++ b/sw/device/lib/hal/autogen/spi_host.h @@ -0,0 +1,187 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// Auto-generated: 'util/rdlgenerator.py gen-device-headers build/rdl/rdl.json sw/device/lib/hal/autogen' + +#pragma once + +#include +#include + +typedef enum [[clang::flag_enum]] spi_host_intr : uint32_t { + spi_host_intr_none = (0), + spi_host_intr_error = (1u << 0), + spi_host_intr_spi_event = (1u << 1), +} spi_host_intr; + +typedef struct [[gnu::aligned(4)]] { + uint32_t fatal_fault : 1; + uint32_t : 31; +} spi_host_alert_test; + +typedef struct [[gnu::aligned(4)]] { + uint32_t rx_watermark : 8; + uint32_t tx_watermark : 8; + uint32_t : 13; + uint32_t output_en : 1; + uint32_t sw_rst : 1; + uint32_t spien : 1; +} spi_host_control; + +typedef struct [[gnu::aligned(4)]] { + uint32_t txqd : 8; + uint32_t rxqd : 8; + uint32_t cmdqd : 4; + uint32_t rxwm : 1; + uint32_t : 1; + uint32_t byteorder : 1; + uint32_t rxstall : 1; + uint32_t rxempty : 1; + uint32_t rxfull : 1; + uint32_t txwm : 1; + uint32_t txstall : 1; + uint32_t txempty : 1; + uint32_t txfull : 1; + uint32_t active : 1; + uint32_t ready : 1; +} spi_host_status; + +typedef struct [[gnu::aligned(4)]] { + uint32_t clkdiv : 16; + uint32_t csnidle : 4; + uint32_t csntrail : 4; + uint32_t csnlead : 4; + uint32_t : 1; + uint32_t fullcyc : 1; + uint32_t cpha : 1; + uint32_t cpol : 1; +} spi_host_configopts; + +typedef struct [[gnu::aligned(4)]] { + uint32_t csaat : 1; + uint32_t speed : 2; + uint32_t direction : 2; + uint32_t len : 20; + uint32_t : 7; +} spi_host_command; + +typedef enum [[clang::flag_enum]] spi_host_error_enable : uint32_t { + spi_host_error_enable_none = (0), + spi_host_error_enable_cmdbusy = (1u << 0), + spi_host_error_enable_overflow = (1u << 1), + spi_host_error_enable_underflow = (1u << 2), + spi_host_error_enable_cmdinval = (1u << 3), + spi_host_error_enable_csidinval = (1u << 4), +} spi_host_error_enable; + +typedef enum [[clang::flag_enum]] spi_host_error_status : uint32_t { + spi_host_error_status_none = (0), + spi_host_error_status_cmdbusy = (1u << 0), + spi_host_error_status_overflow = (1u << 1), + spi_host_error_status_underflow = (1u << 2), + spi_host_error_status_cmdinval = (1u << 3), + spi_host_error_status_csidinval = (1u << 4), + spi_host_error_status_accessinval = (1u << 5), +} spi_host_error_status; + +typedef enum [[clang::flag_enum]] spi_host_event_enable : uint32_t { + spi_host_event_enable_none = (0), + spi_host_event_enable_rxfull = (1u << 0), + spi_host_event_enable_txempty = (1u << 1), + spi_host_event_enable_rxwm = (1u << 2), + spi_host_event_enable_txwm = (1u << 3), + spi_host_event_enable_ready = (1u << 4), + spi_host_event_enable_idle = (1u << 5), +} spi_host_event_enable; + +typedef volatile struct [[gnu::aligned(4)]] spi_host_memory_layout { + /* spi_host.intr_state (0x0) */ + spi_host_intr intr_state; + + /* spi_host.intr_enable (0x4) */ + spi_host_intr intr_enable; + + /* spi_host.intr_test (0x8) */ + spi_host_intr intr_test; + + /* spi_host.alert_test (0xc) */ + spi_host_alert_test alert_test; + + /* spi_host.control (0x10) */ + spi_host_control control; + + /* spi_host.status (0x14) */ + const spi_host_status status; + + /* spi_host.configopts (0x18) */ + spi_host_configopts configopts; + + /* spi_host.csid (0x1c) */ + uint32_t csid; + + /* spi_host.command (0x20) */ + spi_host_command command; + + /* spi_host.rxdata (0x24) */ + const uint32_t rxdata; + + /* spi_host.txdata (0x28) */ + uint32_t txdata; + + /* spi_host.error_enable (0x2c) */ + spi_host_error_enable error_enable; + + /* spi_host.error_status (0x30) */ + spi_host_error_status error_status; + + /* spi_host.event_enable (0x34) */ + spi_host_event_enable event_enable; +} *spi_host_t; + +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, intr_state) == 0x0ul, + "incorrect register intr_state offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, intr_enable) == 0x4ul, + "incorrect register intr_enable offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, intr_test) == 0x8ul, + "incorrect register intr_test offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, alert_test) == 0xcul, + "incorrect register alert_test offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, control) == 0x10ul, + "incorrect register control offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, status) == 0x14ul, + "incorrect register status offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, configopts) == 0x18ul, + "incorrect register configopts offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, csid) == 0x1cul, + "incorrect register csid offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, command) == 0x20ul, + "incorrect register command offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, error_enable) == 0x2cul, + "incorrect register error_enable offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, error_status) == 0x30ul, + "incorrect register error_status offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, event_enable) == 0x34ul, + "incorrect register event_enable offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, rxdata) == 0x24ul, + "incorrect register window rxdata offset"); +_Static_assert(__builtin_offsetof(struct spi_host_memory_layout, txdata) == 0x28ul, + "incorrect register window txdata offset"); + +_Static_assert(sizeof(spi_host_intr) == sizeof(uint32_t), + "register type spi_host_intr is not register sized"); +_Static_assert(sizeof(spi_host_alert_test) == sizeof(uint32_t), + "register type spi_host_alert_test is not register sized"); +_Static_assert(sizeof(spi_host_control) == sizeof(uint32_t), + "register type spi_host_control is not register sized"); +_Static_assert(sizeof(spi_host_status) == sizeof(uint32_t), + "register type spi_host_status is not register sized"); +_Static_assert(sizeof(spi_host_configopts) == sizeof(uint32_t), + "register type spi_host_configopts is not register sized"); +_Static_assert(sizeof(spi_host_command) == sizeof(uint32_t), + "register type spi_host_command is not register sized"); +_Static_assert(sizeof(spi_host_error_enable) == sizeof(uint32_t), + "register type spi_host_error_enable is not register sized"); +_Static_assert(sizeof(spi_host_error_status) == sizeof(uint32_t), + "register type spi_host_error_status is not register sized"); +_Static_assert(sizeof(spi_host_event_enable) == sizeof(uint32_t), + "register type spi_host_event_enable is not register sized"); From e1a42cdc7eecfdbc3e00c59f7dad1d3d3a363371 Mon Sep 17 00:00:00 2001 From: Ray Lau Date: Tue, 5 May 2026 11:46:44 +0100 Subject: [PATCH 4/4] [rdl,sw,docs] Add ethernet RDL and update memory map This includes the auto-generated ethernet driver header. --- doc/img/memmap.svg | 2 +- rdl/ip/ethernet.rdl | 294 +++++++++++++++++++++++++++ rdl/mocha.rdl | 3 +- sw/device/lib/hal/autogen/ethernet.h | 273 +++++++++++++++++++++++++ 4 files changed, 570 insertions(+), 2 deletions(-) create mode 100644 rdl/ip/ethernet.rdl create mode 100644 sw/device/lib/hal/autogen/ethernet.h diff --git a/doc/img/memmap.svg b/doc/img/memmap.svg index c828f7b2c..336d2e1de 100644 --- a/doc/img/memmap.svg +++ b/doc/img/memmap.svg @@ -1,2 +1,2 @@ -Base addressTop addressReservedFunction0x000800000x00087fff32.0 kiBROM0x100000000x1001ffff128.0 kiBSRAM0x200000000x2000ffff64.0 kiBDEBUG_MODULE0x200100000x2001ffff64.0 kiBMAILBOX0x200200000x2002ffff64.0 kiBDV_SW_IFC0x300000000x3000ffff64.0 kiBETHERNET0x400000000x4000ffff64.0 kiBGPIO0x400200000x4002ffff64.0 kiBCLKMGR0x400300000x4003ffff64.0 kiBRSTMGR0x400400000x4004ffff64.0 kiBPOWER_MANAGER0x400500000x4005ffff64.0 kiBROM_CTRL0x400600000x4006ffff64.0 kiBENTROPY_SRC0x400700000x4007ffff64.0 kiBKMAC0x410000000x4100ffff64.0 kiBUART0x420000000x4200ffff64.0 kiBI2C0x430000000x4300ffff64.0 kiBSPI_DEVICE0x440000000x4400ffff64.0 kiBTIMER0x450000000x4500ffff64.0 kiBSPI_HOST0x480000000x4c00400364.0 MiBPLIC0x800000000xbf7fffff1016.0 MiBDRAM \ No newline at end of file +Base addressTop addressReservedFunction0x000800000x00087fff32.0 kiBROM0x100000000x1001ffff128.0 kiBSRAM0x200000000x2000ffff64.0 kiBDEBUG_MODULE0x200100000x2001ffff64.0 kiBMAILBOX0x200200000x2002ffff64.0 kiBDV_SW_IFC0x300000000x30007fff32.0 kiBETHERNET0x400000000x4000ffff64.0 kiBGPIO0x400200000x4002ffff64.0 kiBCLKMGR0x400300000x4003ffff64.0 kiBRSTMGR0x400400000x4004ffff64.0 kiBPOWER_MANAGER0x400500000x4005ffff64.0 kiBROM_CTRL0x400600000x4006ffff64.0 kiBENTROPY_SRC0x400700000x4007ffff64.0 kiBKMAC0x410000000x4100ffff64.0 kiBUART0x420000000x4200ffff64.0 kiBI2C0x430000000x4300ffff64.0 kiBSPI_DEVICE0x440000000x4400ffff64.0 kiBTIMER0x450000000x4500ffff64.0 kiBSPI_HOST0x480000000x4c00400364.0 MiBPLIC0x800000000xbf7fffff1016.0 MiBDRAM \ No newline at end of file diff --git a/rdl/ip/ethernet.rdl b/rdl/ip/ethernet.rdl new file mode 100644 index 000000000..4ab48b29a --- /dev/null +++ b/rdl/ip/ethernet.rdl @@ -0,0 +1,294 @@ +/* Copyright lowRISC contributors. + * Licensed under the Apache License, Version 2.0; see LICENSE for details. + * SPDX-License-Identifier: Apache-2.0 + */ + +`include "udp.rdl" + +addrmap ethernet { + reg { + desc = "MAC address low 32-bits."; + field { + sw = rw; + hw = r; + reset = 0x00890702; + desc = "MAC address lower 32 bits."; + } MAC_ADDR_LO[31:0]; + } MACLO @ 0x800; + + reg { + desc = "MAC address high 16-bits and MAC ctrl."; + field { + sw = rw; + hw = r; + reset = 0x2301; + desc = "MAC address upper 16 bits."; + } MAC_ADDR_HI[15:0]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "Obsolete flag. Stored but not used."; + } COOKED[16:16]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "Obsolete flag. Stored but not used."; + } LOOPBACK[17:17]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "MAC spare. Obsolete. Stored but not used."; + } SPARE[21:18]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "Rx all packets (promiscuous mode)."; + } PROMISCUOUS[22:22]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "Rx packet interrupt enable."; + } IRQ_EN[23:23]; + } MACHI @ 0x808; + + reg { + desc = "Transmit Status Register."; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "Tx packet length. Write to send packet."; + } PACKET_LEN[10:0]; + field { + sw = r; + hw = rw; + reset = 0x0; + desc = "Tx frame address."; + } FRAME_ADDR[26:16]; + field { + sw = r; + hw = w; + reset = 0x0; + desc = "Tx busy."; + } BUSY[31:31]; + } TPLR @ 0x810; + + external reg { + desc = "Tx frame check sequence register."; + field { + sw = rw; + hw = w; + reset = 0xFFFFFFFF; + desc = "Tx frame check sequence (bit reversed). Write to stop transmit and reset TX packet length."; + } TX_FCS[31:0]; + } TFCS @ 0x818; + + reg { + desc = "MDIO Control Register"; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "MDIO Clock."; + } MDIOCLK[0:0]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "MDIO Output."; + } MDIOOUT[1:1]; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "MDIO Output Enable."; + } MDIOOEN[2:2]; + field { + sw = r; + hw = w; + desc = "MDIO Input."; + } MDIOIN[3:3]; + } MDIOCTRL @ 0x820; + + reg { + desc = "Rx frame check sequence register(read) and last register(write)."; + field { + sw = w; + hw = r; + reset = 0x0; + desc = "Last available Rx buffer (static)."; + } LAST_BUF[3:0]; + /* Commented out due to issues in generated header with overlapping bit positions */ + /* field { + sw = r; + hw = w; + reset = 0xFFFFFFFF; + desc = "Rx frame check sequence (bit reversed)."; + } RX_FCS[31:0]; */ + } RFCS @ 0x828; + + reg { + desc = "Rx status and reset register."; + field { + sw = rw; + hw = r; + reset = 0x0; + desc = "First available Rx buffer (static)."; + } FIRST_BUF[3:0]; + field { + sw = r; + hw = rw; + reset = 0x0; + desc = "Current Rx buffer (volatile)."; + } NEXT_BUF[7:4]; + field { + sw = r; + hw = r; + reset = 0x0; + desc = "Last available Rx buffer (static)."; + } LAST_BUF[11:8]; + field { + sw = r; + hw = rw; + reset = 0x0; + desc = "Rx packet available."; + } RX_AVAIL[12:12]; + field { + sw = r; + hw = rw; + reset = 0x0; + desc = "Rx irq."; + } RX_IRQ[13:13]; + } RSR @ 0x830; + + reg { + desc = "Rx buffer 0 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR0 @ 0x840; + + reg { + desc = "Rx buffer 1 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR1 @ 0x848; + + reg { + desc = "Rx buffer 2 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR2 @ 0x850; + + reg { + desc = "Rx buffer 3 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR3 @ 0x858; + + reg { + desc = "Rx buffer 4 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR4 @ 0x860; + + reg { + desc = "Rx buffer 5 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR5 @ 0x868; + + reg { + desc = "Rx buffer 6 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR6 @ 0x870; + + reg { + desc = "Rx buffer 7 packet length"; + field { + sw = r; + hw = w; + desc = "Rx packet length in bytes, including 4-byte FCS."; + } PACKET_LEN[10:0]; + } RPLR7 @ 0x878; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } TX_BUFFER @ 0x1000; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER0 @ 0x4000; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER1 @ 0x4800; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER2 @ 0x5000; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER3 @ 0x5800; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER4 @ 0x6000; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER5 @ 0x6800; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER6 @ 0x7000; + + external mem { + memwidth = 0x40; + mementries = 0x100; + sw = rw; + } RX_BUFFER7 @ 0x7800; +}; diff --git a/rdl/mocha.rdl b/rdl/mocha.rdl index f1382d279..fef5f887e 100644 --- a/rdl/mocha.rdl +++ b/rdl/mocha.rdl @@ -5,6 +5,7 @@ `include "ip/clkmgr.rdl" `include "ip/entropy_src.rdl" +`include "ip/ethernet.rdl" `include "ip/gpio.rdl" `include "ip/i2c.rdl" `include "ip/kmac.rdl" @@ -34,7 +35,7 @@ addrmap top_mocha { reserved DV_SW_IFC @ 0x2002_0000; - reserved ETHERNET @ 0x3000_0000; + ethernet ETHERNET @ 0x3000_0000; gpio GPIO[1] @ 0x4000_0000 += 0x10000; diff --git a/sw/device/lib/hal/autogen/ethernet.h b/sw/device/lib/hal/autogen/ethernet.h new file mode 100644 index 000000000..cd2976bc7 --- /dev/null +++ b/sw/device/lib/hal/autogen/ethernet.h @@ -0,0 +1,273 @@ +// Copyright lowRISC contributors (COSMIC project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// Auto-generated: 'util/rdlgenerator.py gen-device-headers build/rdl/rdl.json sw/device/lib/hal/autogen' + +#pragma once + +#include +#include + +typedef struct [[gnu::aligned(4)]] { + uint32_t mac_addr_hi : 16; + uint32_t cooked : 1; + uint32_t loopback : 1; + uint32_t spare : 4; + uint32_t promiscuous : 1; + uint32_t irq_en : 1; + uint32_t : 8; +} ethernet_machi; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 5; + uint32_t frame_addr : 11; + uint32_t : 4; + uint32_t busy : 1; +} ethernet_tplr; + +typedef enum [[clang::flag_enum]] ethernet_mdioctrl : uint32_t { + ethernet_mdioctrl_none = (0), + ethernet_mdioctrl_mdioclk = (1u << 0), + ethernet_mdioctrl_mdioout = (1u << 1), + ethernet_mdioctrl_mdiooen = (1u << 2), + ethernet_mdioctrl_mdioin = (1u << 3), +} ethernet_mdioctrl; + +typedef struct [[gnu::aligned(4)]] { + uint32_t last_buf : 4; + uint32_t : 28; +} ethernet_rfcs; + +typedef struct [[gnu::aligned(4)]] { + uint32_t first_buf : 4; + uint32_t next_buf : 4; + uint32_t last_buf : 4; + uint32_t rx_avail : 1; + uint32_t rx_irq : 1; + uint32_t : 18; +} ethernet_rsr; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr0; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr1; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr2; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr3; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr4; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr5; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr6; + +typedef struct [[gnu::aligned(4)]] { + uint32_t packet_len : 11; + uint32_t : 21; +} ethernet_rplr7; + +typedef volatile struct [[gnu::aligned(4)]] ethernet_memory_layout { + const uint8_t __reserved0[0x800 - 0x0]; + + /* ethernet.maclo (0x800) */ + uint32_t maclo; + + const uint8_t __reserved1[0x808 - 0x804]; + + /* ethernet.machi (0x808) */ + ethernet_machi machi; + + const uint8_t __reserved2[0x810 - 0x80c]; + + /* ethernet.tplr (0x810) */ + ethernet_tplr tplr; + + const uint8_t __reserved3[0x818 - 0x814]; + + /* ethernet.tfcs (0x818) */ + uint32_t tfcs; + + const uint8_t __reserved4[0x820 - 0x81c]; + + /* ethernet.mdioctrl (0x820) */ + ethernet_mdioctrl mdioctrl; + + const uint8_t __reserved5[0x828 - 0x824]; + + /* ethernet.rfcs (0x828) */ + ethernet_rfcs rfcs; + + const uint8_t __reserved6[0x830 - 0x82c]; + + /* ethernet.rsr (0x830) */ + ethernet_rsr rsr; + + const uint8_t __reserved7[0x840 - 0x834]; + + /* ethernet.rplr0 (0x840) */ + const ethernet_rplr0 rplr0; + + const uint8_t __reserved8[0x848 - 0x844]; + + /* ethernet.rplr1 (0x848) */ + const ethernet_rplr1 rplr1; + + const uint8_t __reserved9[0x850 - 0x84c]; + + /* ethernet.rplr2 (0x850) */ + const ethernet_rplr2 rplr2; + + const uint8_t __reserved10[0x858 - 0x854]; + + /* ethernet.rplr3 (0x858) */ + const ethernet_rplr3 rplr3; + + const uint8_t __reserved11[0x860 - 0x85c]; + + /* ethernet.rplr4 (0x860) */ + const ethernet_rplr4 rplr4; + + const uint8_t __reserved12[0x868 - 0x864]; + + /* ethernet.rplr5 (0x868) */ + const ethernet_rplr5 rplr5; + + const uint8_t __reserved13[0x870 - 0x86c]; + + /* ethernet.rplr6 (0x870) */ + const ethernet_rplr6 rplr6; + + const uint8_t __reserved14[0x878 - 0x874]; + + /* ethernet.rplr7 (0x878) */ + const ethernet_rplr7 rplr7; + + const uint8_t __reserved15[0x1000 - 0x87c]; + + /* ethernet.tx_buffer (0x1000-0x17f8) */ + uint64_t tx_buffer[256]; + + const uint8_t __reserved16[0x4000 - 0x1800]; + + /* ethernet.rx_buffer0 (0x4000-0x47f8) */ + uint64_t rx_buffer0[256]; + + /* ethernet.rx_buffer1 (0x4800-0x4ff8) */ + uint64_t rx_buffer1[256]; + + /* ethernet.rx_buffer2 (0x5000-0x57f8) */ + uint64_t rx_buffer2[256]; + + /* ethernet.rx_buffer3 (0x5800-0x5ff8) */ + uint64_t rx_buffer3[256]; + + /* ethernet.rx_buffer4 (0x6000-0x67f8) */ + uint64_t rx_buffer4[256]; + + /* ethernet.rx_buffer5 (0x6800-0x6ff8) */ + uint64_t rx_buffer5[256]; + + /* ethernet.rx_buffer6 (0x7000-0x77f8) */ + uint64_t rx_buffer6[256]; + + /* ethernet.rx_buffer7 (0x7800-0x7ff8) */ + uint64_t rx_buffer7[256]; +} *ethernet_t; + +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, maclo) == 0x800ul, + "incorrect register maclo offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, machi) == 0x808ul, + "incorrect register machi offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, tplr) == 0x810ul, + "incorrect register tplr offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, tfcs) == 0x818ul, + "incorrect register tfcs offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, mdioctrl) == 0x820ul, + "incorrect register mdioctrl offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rfcs) == 0x828ul, + "incorrect register rfcs offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rsr) == 0x830ul, + "incorrect register rsr offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr0) == 0x840ul, + "incorrect register rplr0 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr1) == 0x848ul, + "incorrect register rplr1 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr2) == 0x850ul, + "incorrect register rplr2 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr3) == 0x858ul, + "incorrect register rplr3 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr4) == 0x860ul, + "incorrect register rplr4 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr5) == 0x868ul, + "incorrect register rplr5 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr6) == 0x870ul, + "incorrect register rplr6 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rplr7) == 0x878ul, + "incorrect register rplr7 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, tx_buffer) == 0x1000ul, + "incorrect register window tx_buffer offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer0) == 0x4000ul, + "incorrect register window rx_buffer0 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer1) == 0x4800ul, + "incorrect register window rx_buffer1 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer2) == 0x5000ul, + "incorrect register window rx_buffer2 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer3) == 0x5800ul, + "incorrect register window rx_buffer3 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer4) == 0x6000ul, + "incorrect register window rx_buffer4 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer5) == 0x6800ul, + "incorrect register window rx_buffer5 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer6) == 0x7000ul, + "incorrect register window rx_buffer6 offset"); +_Static_assert(__builtin_offsetof(struct ethernet_memory_layout, rx_buffer7) == 0x7800ul, + "incorrect register window rx_buffer7 offset"); + +_Static_assert(sizeof(ethernet_machi) == sizeof(uint32_t), + "register type ethernet_machi is not register sized"); +_Static_assert(sizeof(ethernet_tplr) == sizeof(uint32_t), + "register type ethernet_tplr is not register sized"); +_Static_assert(sizeof(ethernet_mdioctrl) == sizeof(uint32_t), + "register type ethernet_mdioctrl is not register sized"); +_Static_assert(sizeof(ethernet_rfcs) == sizeof(uint32_t), + "register type ethernet_rfcs is not register sized"); +_Static_assert(sizeof(ethernet_rsr) == sizeof(uint32_t), + "register type ethernet_rsr is not register sized"); +_Static_assert(sizeof(ethernet_rplr0) == sizeof(uint32_t), + "register type ethernet_rplr0 is not register sized"); +_Static_assert(sizeof(ethernet_rplr1) == sizeof(uint32_t), + "register type ethernet_rplr1 is not register sized"); +_Static_assert(sizeof(ethernet_rplr2) == sizeof(uint32_t), + "register type ethernet_rplr2 is not register sized"); +_Static_assert(sizeof(ethernet_rplr3) == sizeof(uint32_t), + "register type ethernet_rplr3 is not register sized"); +_Static_assert(sizeof(ethernet_rplr4) == sizeof(uint32_t), + "register type ethernet_rplr4 is not register sized"); +_Static_assert(sizeof(ethernet_rplr5) == sizeof(uint32_t), + "register type ethernet_rplr5 is not register sized"); +_Static_assert(sizeof(ethernet_rplr6) == sizeof(uint32_t), + "register type ethernet_rplr6 is not register sized"); +_Static_assert(sizeof(ethernet_rplr7) == sizeof(uint32_t), + "register type ethernet_rplr7 is not register sized");