From 7e15c4a12f94dd4e8d79bc03b08bf025cf324a77 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Sat, 25 Oct 2025 23:17:28 -0600 Subject: [PATCH 01/60] Switch from desyrdl to peakrdl for sysrdl --- prbs | 2 +- rdl/Makefile | 43 +- rdl/cocotb/desyrdl/addrmap_ch0.py | 117 - rdl/msk_top_regs.h | 369 - rdl/msk_top_regs.pl | 40 - rdl/msk_top_regs.rdl | 408 - rdl/msk_top_regs_desy.rdl | 208 - rdl/outputs/c-header/msk_top_regs.h | 362 + rdl/{ => outputs/docs}/msk_top_regs.md | 122 +- rdl/{ => outputs/docs}/msk_top_regs.pdf | Bin 115023 -> 113089 bytes rdl/outputs/python/msk_top_regs/__init__.py | 1 + rdl/outputs/python/msk_top_regs/example.py | 13 + .../python/msk_top_regs/lib/__init__.py | 114 + .../python/msk_top_regs/lib/async_memory.py | 626 + .../lib/async_register_and_field.py | 1230 ++ rdl/outputs/python/msk_top_regs/lib/base.py | 942 + .../python/msk_top_regs/lib/base_field.py | 549 + .../python/msk_top_regs/lib/base_register.py | 229 + .../python/msk_top_regs/lib/callbacks.py | 363 + .../python/msk_top_regs/lib/field_encoding.py | 80 + rdl/outputs/python/msk_top_regs/lib/memory.py | 752 + .../msk_top_regs/lib/register_and_field.py | 1189 ++ .../msk_top_regs/lib/utility_functions.py | 83 + .../python/msk_top_regs/reg_model/__init__.py | 1 + .../msk_top_regs/reg_model/msk_top_regs.py | 9451 +++++++++ .../python/msk_top_regs/sim/__init__.py | 1 + .../python/msk_top_regs/sim/msk_top_regs.py | 175 + .../python/msk_top_regs/sim_lib}/__init__.py | 0 .../python/msk_top_regs/sim_lib/_callbacks.py | 79 + .../python/msk_top_regs/sim_lib/base.py | 34 + .../msk_top_regs/sim_lib/dummy_callbacks.py | 256 + .../python/msk_top_regs/sim_lib/field.py | 154 + .../python/msk_top_regs/sim_lib/memory.py | 159 + .../python/msk_top_regs/sim_lib/register.py | 211 + .../python/msk_top_regs/sim_lib/simulator.py | 500 + .../python/msk_top_regs/tests/__init__.py | 1 + .../tests/_msk_top_regs_sim_test_base.py | 50 + .../tests/_msk_top_regs_test_base.py | 121 + .../msk_top_regs/tests/test_msk_top_regs.py | 16576 ++++++++++++++++ .../tests/test_sim_msk_top_regs.py | 7518 +++++++ rdl/outputs/rtl/msk_top_regs.vhd | 2321 +++ rdl/outputs/rtl/msk_top_regs_pkg.vhd | 432 + rdl/src/axi4lite_intf_pkg.vhd | 42 + rdl/src/msk_top_regs.rdl | 552 + rdl/src/reg_utils.vhd | 232 + rdl/src/regblock_udps.rdl | 54 + sim/Makefile | 17 +- sim/desyrdl | 1 - sim/msk_test.py | 164 +- sim/msk_top_nvc.gtkw | 619 +- sim/msk_top_regs | 1 + src/cdc_resync.vhd | 103 + src/msk_top.vhd | 2 - src/msk_top_csr.vhd | 211 +- 54 files changed, 46432 insertions(+), 1448 deletions(-) delete mode 100644 rdl/cocotb/desyrdl/addrmap_ch0.py delete mode 100644 rdl/msk_top_regs.h delete mode 100755 rdl/msk_top_regs.pl delete mode 100644 rdl/msk_top_regs.rdl delete mode 100644 rdl/msk_top_regs_desy.rdl create mode 100644 rdl/outputs/c-header/msk_top_regs.h rename rdl/{ => outputs/docs}/msk_top_regs.md (87%) rename rdl/{ => outputs/docs}/msk_top_regs.pdf (60%) create mode 100644 rdl/outputs/python/msk_top_regs/__init__.py create mode 100644 rdl/outputs/python/msk_top_regs/example.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/__init__.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/async_memory.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/async_register_and_field.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/base.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/base_field.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/base_register.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/callbacks.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/field_encoding.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/memory.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/register_and_field.py create mode 100644 rdl/outputs/python/msk_top_regs/lib/utility_functions.py create mode 100644 rdl/outputs/python/msk_top_regs/reg_model/__init__.py create mode 100644 rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py create mode 100644 rdl/outputs/python/msk_top_regs/sim/__init__.py create mode 100644 rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py rename rdl/{cocotb/desyrdl => outputs/python/msk_top_regs/sim_lib}/__init__.py (100%) create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/_callbacks.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/base.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/dummy_callbacks.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/field.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/memory.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/register.py create mode 100644 rdl/outputs/python/msk_top_regs/sim_lib/simulator.py create mode 100644 rdl/outputs/python/msk_top_regs/tests/__init__.py create mode 100644 rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_sim_test_base.py create mode 100644 rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_test_base.py create mode 100644 rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py create mode 100644 rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py create mode 100644 rdl/outputs/rtl/msk_top_regs.vhd create mode 100644 rdl/outputs/rtl/msk_top_regs_pkg.vhd create mode 100644 rdl/src/axi4lite_intf_pkg.vhd create mode 100644 rdl/src/msk_top_regs.rdl create mode 100644 rdl/src/reg_utils.vhd create mode 100644 rdl/src/regblock_udps.rdl delete mode 120000 sim/desyrdl create mode 120000 sim/msk_top_regs create mode 100644 src/cdc_resync.vhd diff --git a/prbs b/prbs index 48d9d49..8e42b3e 160000 --- a/prbs +++ b/prbs @@ -1 +1 @@ -Subproject commit 48d9d49b0380a4eb18c13c230182dede94462a28 +Subproject commit 8e42b3ea00644cea5ae34b4ebba2e062bdc58be3 diff --git a/rdl/Makefile b/rdl/Makefile index c9f51ae..901e45d 100644 --- a/rdl/Makefile +++ b/rdl/Makefile @@ -1,21 +1,36 @@ -all: msk_top_regs.pdf msk_top_regs.h msk_top_regs_desy.rdl gen_files_cocotb.txt gen_files_vhdl.txt +#all: msk_top_regs.pdf msk_top_regs.h msk_top_regs_desy.rdl gen_files_cocotb.txt gen_files_vhdl.txt -gen_files_cocotb.txt : msk_top_regs_desy.rdl - desyrdl -i msk_top_regs_desy.rdl -f cocotb +SRCS = src/regblock_udps.rdl src/msk_top_regs.rdl -gen_files_vhdl.txt : msk_top_regs_desy.rdl - desyrdl -i msk_top_regs_desy.rdl -f vhdl +OUTDOCS = outputs/docs +OUTRTL = outputs/rtl +OUTPYTHON = outputs/python +OUTCHEADER = outputs/c-header -msk_top_regs_desy.rdl : msk_top_regs.rdl msk_top_regs.pl - rm msk_top_regs_desy.rdl - ./msk_top_regs.pl msk_top_regs.rdl > msk_top_regs_desy.rdl +all: $(OUTDOCS)/msk_top_regs.pdf \ + $(OUTDOCS)/msk_top_regs.md \ + $(OUTRTL)/msk_top_regs.vhd \ + $(OUTPYTHON)/__init__.py \ + $(OUTCHEADER)/msk_top_regs.h -msk_top_regs.md: msk_top_regs.rdl - peakrdl markdown msk_top_regs.rdl -o msk_top_regs.md +$(OUTDOCS)/msk_top_regs.md: $(SRCS) + peakrdl markdown $(SRCS) -o $(OUTDOCS)/msk_top_regs.md -msk_top_regs.h: msk_top_regs.rdl - peakrdl c-header msk_top_regs.rdl -o msk_top_regs.h +$(OUTCHEADER)/msk_top_regs.h: $(SRCS) + peakrdl c-header $(SRCS) -o outputs/c-header/msk_top_regs.h -msk_top_regs.pdf: msk_top_regs.md - pandoc -o msk_top_regs.pdf msk_top_regs.md +$(OUTRTL)/msk_top_regs.vhd: $(SRCS) + peakrdl regblock-vhdl $(SRCS) -o $(OUTRTL) --cpuif axi4-lite + +$(OUTDOCS)/msk_top_regs.pdf: $(OUTDOCS)/msk_top_regs.md + pandoc -o $(OUTDOCS)/msk_top_regs.pdf $(OUTDOCS)/msk_top_regs.md + +$(OUTPYTHON)/__init__.py: $(SRCS) + peakrdl python $(SRCS) --async -o $(OUTPYTHON) + +clean: + rm outputs/docs/* + rm outputs/c-header/* + rm -r outputs/python/* + rm outputs/rtl/* \ No newline at end of file diff --git a/rdl/cocotb/desyrdl/addrmap_ch0.py b/rdl/cocotb/desyrdl/addrmap_ch0.py deleted file mode 100644 index 300f4d6..0000000 --- a/rdl/cocotb/desyrdl/addrmap_ch0.py +++ /dev/null @@ -1,117 +0,0 @@ - -import numpy as np -import logging - -logging.basicConfig(level=logging.NOTSET) -logger = logging.getLogger() -logger.setLevel(logging.INFO) - - - -class AddrmapItem (): - def __init__(self, name, bus, address, size, bits, fixp, signed, access): - self.name = name - self.bus = bus - self.address = address - self.size = size - self.bits = bits - self.fixp = fixp - self.access = access - self.scaling = 1; - if fixp == "IEEE754": - self.dtype = np.float32 - elif fixp == 0 and signed == 0: - self.dtype = np.uint32 - elif fixp == 0 and signed == 1: - self.dtype = np.int32 - else: - self.scaling = 1/pow(2, fixp) - self.dtype = np.float32 - - async def read(self, count, offset): - data = await self.bus.read_dwords(self.address+offset*4, count) - return np.array(data * self.scaling, dtype=self.dtype) - - async def read_raw(self, count, offset): - data = await self.bus.read_dwords(self.address+offset*4, count) - return np.array(data, dtype=np.uint32) - - async def write(self, value, offset): - val_np = np.array(value) - if val_np.size > 1: - data = np.uint32(np.round(val_np / self.scaling)).tolist() - else: - data = [] - data.append(np.uint32(np.round(val_np / self.scaling)).tolist()) - await self.bus.write_dwords(self.address+offset*4, data) - - async def write_raw(self, value, offset): - val_np = np.array(value) - if val_np.size > 1: - data = np.uint32(np.round(val_np)).tolist() - else: - data = [] - data.append(np.uint32(np.round(val_np)).tolist()) - await self.bus.write_dwords(self.address+offset*4, data) - -class Addrmap: - def __init__(self, bus): - self.addrmap ={} - self.addrmap['msk_top_regs.Hash_ID_Low'] = AddrmapItem("msk_top_regs.Hash_ID_Low", bus, 0, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.Hash_ID_High'] = AddrmapItem("msk_top_regs.Hash_ID_High", bus, 4, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.MSK_Init'] = AddrmapItem("msk_top_regs.MSK_Init", bus, 8, 4, 3, 0, 0, "RW") - self.addrmap['msk_top_regs.MSK_Control'] = AddrmapItem("msk_top_regs.MSK_Control", bus, 12, 4, 5, 0, 0, "RW") - self.addrmap['msk_top_regs.MSK_Status'] = AddrmapItem("msk_top_regs.MSK_Status", bus, 16, 4, 4, 0, 0, "RO") - self.addrmap['msk_top_regs.Tx_Bit_Count'] = AddrmapItem("msk_top_regs.Tx_Bit_Count", bus, 20, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.Tx_Enable_Count'] = AddrmapItem("msk_top_regs.Tx_Enable_Count", bus, 24, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.Fb_FreqWord'] = AddrmapItem("msk_top_regs.Fb_FreqWord", bus, 28, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.TX_F1_FreqWord'] = AddrmapItem("msk_top_regs.TX_F1_FreqWord", bus, 32, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.TX_F2_FreqWord'] = AddrmapItem("msk_top_regs.TX_F2_FreqWord", bus, 36, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.RX_F1_FreqWord'] = AddrmapItem("msk_top_regs.RX_F1_FreqWord", bus, 40, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.RX_F2_FreqWord'] = AddrmapItem("msk_top_regs.RX_F2_FreqWord", bus, 44, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.LPF_Config_0'] = AddrmapItem("msk_top_regs.LPF_Config_0", bus, 48, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.LPF_Config_1'] = AddrmapItem("msk_top_regs.LPF_Config_1", bus, 52, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.Tx_Data_Width'] = AddrmapItem("msk_top_regs.Tx_Data_Width", bus, 56, 4, 8, 0, 0, "RW") - self.addrmap['msk_top_regs.Rx_Data_Width'] = AddrmapItem("msk_top_regs.Rx_Data_Width", bus, 60, 4, 8, 0, 0, "RW") - self.addrmap['msk_top_regs.PRBS_Control'] = AddrmapItem("msk_top_regs.PRBS_Control", bus, 64, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.PRBS_Initial_State'] = AddrmapItem("msk_top_regs.PRBS_Initial_State", bus, 68, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.PRBS_Polynomial'] = AddrmapItem("msk_top_regs.PRBS_Polynomial", bus, 72, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.PRBS_Error_Mask'] = AddrmapItem("msk_top_regs.PRBS_Error_Mask", bus, 76, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.PRBS_Bit_Count'] = AddrmapItem("msk_top_regs.PRBS_Bit_Count", bus, 80, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.PRBS_Error_Count'] = AddrmapItem("msk_top_regs.PRBS_Error_Count", bus, 84, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.LPF_Accum_F1'] = AddrmapItem("msk_top_regs.LPF_Accum_F1", bus, 88, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.LPF_Accum_F2'] = AddrmapItem("msk_top_regs.LPF_Accum_F2", bus, 92, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.axis_xfer_count'] = AddrmapItem("msk_top_regs.axis_xfer_count", bus, 96, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.Rx_Sample_Discard'] = AddrmapItem("msk_top_regs.Rx_Sample_Discard", bus, 100, 4, 16, 0, 0, "RW") - self.addrmap['msk_top_regs.LPF_Config_2'] = AddrmapItem("msk_top_regs.LPF_Config_2", bus, 104, 4, 32, 0, 0, "RW") - self.addrmap['msk_top_regs.f1_nco_adjust'] = AddrmapItem("msk_top_regs.f1_nco_adjust", bus, 108, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.f2_nco_adjust'] = AddrmapItem("msk_top_regs.f2_nco_adjust", bus, 112, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.f1_error'] = AddrmapItem("msk_top_regs.f1_error", bus, 116, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.f2_error'] = AddrmapItem("msk_top_regs.f2_error", bus, 120, 4, 32, 0, 0, "RO") - self.addrmap['msk_top_regs.Tx_Sync_Ctrl'] = AddrmapItem("msk_top_regs.Tx_Sync_Ctrl", bus, 124, 4, 4, 0, 0, "RW") - self.addrmap['msk_top_regs.Tx_Sync_Cnt'] = AddrmapItem("msk_top_regs.Tx_Sync_Cnt", bus, 128, 4, 24, 0, 0, "RW") - self.addrmap['msk_top_regs.lowpass_ema_alpha1'] = AddrmapItem("msk_top_regs.lowpass_ema_alpha1", bus, 132, 4, 18, 0, 0, "RW") - self.addrmap['msk_top_regs.lowpass_ema_alpha2'] = AddrmapItem("msk_top_regs.lowpass_ema_alpha2", bus, 136, 4, 18, 0, 0, "RW") - self.addrmap['msk_top_regs.rx_power'] = AddrmapItem("msk_top_regs.rx_power", bus, 140, 4, 23, 0, 0, "RO") - - def get_path(self, module, name): - path = module + "." + name - if path not in self.addrmap: - msg = f"Cannot find `{path}` in register dict" - logger.error(msg) - assert False - return path - - async def read(self, module, name, count=1, offset=0): - path = self.get_path(module, name) - return await self.addrmap[path].read(count, offset) - - async def write(self, module, name, value, offset=0): - path = self.get_path(module, name) - return await self.addrmap[path].write(value, offset) - async def read_raw(self, module, name, count=1, offset=0): - path = self.get_path(module, name) - return await self.addrmap[path].read_raw(count, offset) - async def write_raw(self, module, name, value, offset=0): - path = self.get_path(module, name) - return await self.addrmap[path].write_raw(value, offset) \ No newline at end of file diff --git a/rdl/msk_top_regs.h b/rdl/msk_top_regs.h deleted file mode 100644 index 1579eaf..0000000 --- a/rdl/msk_top_regs.h +++ /dev/null @@ -1,369 +0,0 @@ -// Generated by PeakRDL-cheader - A free and open-source header generator -// https://github.com/SystemRDL/PeakRDL-cheader - -#ifndef MSK_TOP_REGS_H -#define MSK_TOP_REGS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -// Reg - msk_hash_lo -#define MSK_HASH_LO__HASH_ID_LO_bm 0xffffffff -#define MSK_HASH_LO__HASH_ID_LO_bp 0 -#define MSK_HASH_LO__HASH_ID_LO_bw 32 -#define MSK_HASH_LO__HASH_ID_LO_reset 0xaaaa5555 - -// Reg - msk_hash_hi -#define MSK_HASH_HI__HASH_ID_HI_bm 0xffffffff -#define MSK_HASH_HI__HASH_ID_HI_bp 0 -#define MSK_HASH_HI__HASH_ID_HI_bw 32 -#define MSK_HASH_HI__HASH_ID_HI_reset 0x5555aaaa - -// Reg - msk_init -#define MSK_INIT__TXRXINIT_bm 0x1 -#define MSK_INIT__TXRXINIT_bp 0 -#define MSK_INIT__TXRXINIT_bw 1 -#define MSK_INIT__TXRXINIT_reset 0x1 -#define MSK_INIT__TXINIT_bm 0x2 -#define MSK_INIT__TXINIT_bp 1 -#define MSK_INIT__TXINIT_bw 1 -#define MSK_INIT__TXINIT_reset 0x1 -#define MSK_INIT__RXINIT_bm 0x4 -#define MSK_INIT__RXINIT_bp 2 -#define MSK_INIT__RXINIT_bw 1 -#define MSK_INIT__RXINIT_reset 0x1 - -// Reg - msk_ctrl -#define MSK_CTRL__PTT_bm 0x1 -#define MSK_CTRL__PTT_bp 0 -#define MSK_CTRL__PTT_bw 1 -#define MSK_CTRL__PTT_reset 0x0 -#define MSK_CTRL__LOOPBACK_ENA_bm 0x2 -#define MSK_CTRL__LOOPBACK_ENA_bp 1 -#define MSK_CTRL__LOOPBACK_ENA_bw 1 -#define MSK_CTRL__LOOPBACK_ENA_reset 0x0 -#define MSK_CTRL__RX_INVERT_bm 0x4 -#define MSK_CTRL__RX_INVERT_bp 2 -#define MSK_CTRL__RX_INVERT_bw 1 -#define MSK_CTRL__RX_INVERT_reset 0x0 -#define MSK_CTRL__CLEAR_COUNTS_bm 0x8 -#define MSK_CTRL__CLEAR_COUNTS_bp 3 -#define MSK_CTRL__CLEAR_COUNTS_bw 1 -#define MSK_CTRL__CLEAR_COUNTS_reset 0x0 -#define MSK_CTRL__DIFF_ENCODER_LOOPBACK_bm 0x10 -#define MSK_CTRL__DIFF_ENCODER_LOOPBACK_bp 4 -#define MSK_CTRL__DIFF_ENCODER_LOOPBACK_bw 1 -#define MSK_CTRL__DIFF_ENCODER_LOOPBACK_reset 0x0 - -// Reg - msk_stat_0 -#define MSK_STAT_0__DEMOD_SYNC_LOCK_bm 0x1 -#define MSK_STAT_0__DEMOD_SYNC_LOCK_bp 0 -#define MSK_STAT_0__DEMOD_SYNC_LOCK_bw 1 -#define MSK_STAT_0__DEMOD_SYNC_LOCK_reset 0x0 -#define MSK_STAT_0__TX_ENABLE_bm 0x2 -#define MSK_STAT_0__TX_ENABLE_bp 1 -#define MSK_STAT_0__TX_ENABLE_bw 1 -#define MSK_STAT_0__TX_ENABLE_reset 0x0 -#define MSK_STAT_0__RX_ENABLE_bm 0x4 -#define MSK_STAT_0__RX_ENABLE_bp 2 -#define MSK_STAT_0__RX_ENABLE_bw 1 -#define MSK_STAT_0__RX_ENABLE_reset 0x0 -#define MSK_STAT_0__TX_AXIS_VALID_bm 0x8 -#define MSK_STAT_0__TX_AXIS_VALID_bp 3 -#define MSK_STAT_0__TX_AXIS_VALID_bw 1 -#define MSK_STAT_0__TX_AXIS_VALID_reset 0x0 - -// Reg - msk_stat_1 -#define MSK_STAT_1__TX_BIT_COUNTER_bm 0xffffffff -#define MSK_STAT_1__TX_BIT_COUNTER_bp 0 -#define MSK_STAT_1__TX_BIT_COUNTER_bw 32 -#define MSK_STAT_1__TX_BIT_COUNTER_reset 0x0 - -// Reg - msk_stat_2 -#define MSK_STAT_2__TX_ENA_COUNTER_bm 0xffffffff -#define MSK_STAT_2__TX_ENA_COUNTER_bp 0 -#define MSK_STAT_2__TX_ENA_COUNTER_bw 32 -#define MSK_STAT_2__TX_ENA_COUNTER_reset 0x0 - -// Reg - config_nco_fw_desc_c4924cc6_name_0c494469 -#define CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bm 0xffffffff -#define CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bp 0 -#define CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bw 32 -#define CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_reset 0x0 - -// Reg - config_nco_fw_desc_94d7aaf5_name_84dd0c1c -#define CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bm 0xffffffff -#define CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bp 0 -#define CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bw 32 -#define CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_reset 0x0 - -// Reg - config_nco_fw_desc_42134a4f_name_d97dbd51 -#define CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bm 0xffffffff -#define CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bp 0 -#define CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bw 32 -#define CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_reset 0x0 - -// Reg - config_nco_fw_desc_16fb48c8_name_8d01a20d -#define CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bm 0xffffffff -#define CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bp 0 -#define CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bw 32 -#define CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_reset 0x0 - -// Reg - config_nco_fw_desc_43c0828f_name_bdc60ecf -#define CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bm 0xffffffff -#define CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bp 0 -#define CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bw 32 -#define CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_reset 0x0 - -// Reg - lpf_config_0 -#define LPF_CONFIG_0__LPF_FREEZE_bm 0x1 -#define LPF_CONFIG_0__LPF_FREEZE_bp 0 -#define LPF_CONFIG_0__LPF_FREEZE_bw 1 -#define LPF_CONFIG_0__LPF_FREEZE_reset 0x0 -#define LPF_CONFIG_0__LPF_ZERO_bm 0x2 -#define LPF_CONFIG_0__LPF_ZERO_bp 1 -#define LPF_CONFIG_0__LPF_ZERO_bw 1 -#define LPF_CONFIG_0__LPF_ZERO_reset 0x0 -#define LPF_CONFIG_0__PRBS_RESERVED_bm 0xfc -#define LPF_CONFIG_0__PRBS_RESERVED_bp 2 -#define LPF_CONFIG_0__PRBS_RESERVED_bw 6 -#define LPF_CONFIG_0__PRBS_RESERVED_reset 0x0 -#define LPF_CONFIG_0__LPF_ALPHA_bm 0xffffff00 -#define LPF_CONFIG_0__LPF_ALPHA_bp 8 -#define LPF_CONFIG_0__LPF_ALPHA_bw 24 -#define LPF_CONFIG_0__LPF_ALPHA_reset 0x0 - -// Reg - lpf_config_1 -#define LPF_CONFIG_1__I_GAIN_bm 0xffffff -#define LPF_CONFIG_1__I_GAIN_bp 0 -#define LPF_CONFIG_1__I_GAIN_bw 24 -#define LPF_CONFIG_1__I_GAIN_reset 0x0 -#define LPF_CONFIG_1__I_SHIFT_bm 0xff000000 -#define LPF_CONFIG_1__I_SHIFT_bp 24 -#define LPF_CONFIG_1__I_SHIFT_bw 8 -#define LPF_CONFIG_1__I_SHIFT_reset 0x0 - -// Reg - data_width_desc_58c848dd_name_2fbd8eba -#define DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bm 0xff -#define DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bp 0 -#define DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bw 8 -#define DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_reset 0x8 - -// Reg - data_width_desc_6097df38_name_4609588b -#define DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bm 0xff -#define DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bp 0 -#define DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bw 8 -#define DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_reset 0x8 - -// Reg - prbs_ctrl -#define PRBS_CTRL__PRBS_SEL_bm 0x1 -#define PRBS_CTRL__PRBS_SEL_bp 0 -#define PRBS_CTRL__PRBS_SEL_bw 1 -#define PRBS_CTRL__PRBS_SEL_reset 0x0 -#define PRBS_CTRL__PRBS_ERROR_INSERT_bm 0x2 -#define PRBS_CTRL__PRBS_ERROR_INSERT_bp 1 -#define PRBS_CTRL__PRBS_ERROR_INSERT_bw 1 -#define PRBS_CTRL__PRBS_ERROR_INSERT_reset 0x0 -#define PRBS_CTRL__PRBS_CLEAR_bm 0x4 -#define PRBS_CTRL__PRBS_CLEAR_bp 2 -#define PRBS_CTRL__PRBS_CLEAR_bw 1 -#define PRBS_CTRL__PRBS_CLEAR_reset 0x0 -#define PRBS_CTRL__PRBS_MANUAL_SYNC_bm 0x8 -#define PRBS_CTRL__PRBS_MANUAL_SYNC_bp 3 -#define PRBS_CTRL__PRBS_MANUAL_SYNC_bw 1 -#define PRBS_CTRL__PRBS_MANUAL_SYNC_reset 0x0 -#define PRBS_CTRL__PRBS_RESERVED_bm 0xfff0 -#define PRBS_CTRL__PRBS_RESERVED_bp 4 -#define PRBS_CTRL__PRBS_RESERVED_bw 12 -#define PRBS_CTRL__PRBS_RESERVED_reset 0x0 -#define PRBS_CTRL__PRBS_SYNC_THRESHOLD_bm 0xffff0000 -#define PRBS_CTRL__PRBS_SYNC_THRESHOLD_bp 16 -#define PRBS_CTRL__PRBS_SYNC_THRESHOLD_bw 16 -#define PRBS_CTRL__PRBS_SYNC_THRESHOLD_reset 0x0 - -// Reg - config_prbs_seed -#define CONFIG_PRBS_SEED__CONFIG_DATA_bm 0xffffffff -#define CONFIG_PRBS_SEED__CONFIG_DATA_bp 0 -#define CONFIG_PRBS_SEED__CONFIG_DATA_bw 32 -#define CONFIG_PRBS_SEED__CONFIG_DATA_reset 0x0 - -// Reg - config_prbs_poly -#define CONFIG_PRBS_POLY__CONFIG_DATA_bm 0xffffffff -#define CONFIG_PRBS_POLY__CONFIG_DATA_bp 0 -#define CONFIG_PRBS_POLY__CONFIG_DATA_bw 32 -#define CONFIG_PRBS_POLY__CONFIG_DATA_reset 0x0 - -// Reg - config_prbs_errmask -#define CONFIG_PRBS_ERRMASK__CONFIG_DATA_bm 0xffffffff -#define CONFIG_PRBS_ERRMASK__CONFIG_DATA_bp 0 -#define CONFIG_PRBS_ERRMASK__CONFIG_DATA_bw 32 -#define CONFIG_PRBS_ERRMASK__CONFIG_DATA_reset 0x0 - -// Reg - stat_32_bits -#define STAT_32_BITS__STATUS_DATA_bm 0xffffffff -#define STAT_32_BITS__STATUS_DATA_bp 0 -#define STAT_32_BITS__STATUS_DATA_bw 32 -#define STAT_32_BITS__STATUS_DATA_reset 0x0 - -// Reg - stat_32_errs -#define STAT_32_ERRS__STATUS_DATA_bm 0xffffffff -#define STAT_32_ERRS__STATUS_DATA_bp 0 -#define STAT_32_ERRS__STATUS_DATA_bw 32 -#define STAT_32_ERRS__STATUS_DATA_reset 0x0 - -// Reg - stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670 -#define STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bm 0xffffffff -#define STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bp 0 -#define STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bw 32 -#define STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_reset 0x0 - -// Reg - stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce -#define STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bm 0xffffffff -#define STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bp 0 -#define STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bw 32 -#define STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_reset 0x0 - -// Reg - msk_stat_3 -#define MSK_STAT_3__XFER_COUNT_bm 0xffffffff -#define MSK_STAT_3__XFER_COUNT_bp 0 -#define MSK_STAT_3__XFER_COUNT_bw 32 -#define MSK_STAT_3__XFER_COUNT_reset 0x0 - -// Reg - rx_sample_discard -#define RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bm 0xff -#define RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bp 0 -#define RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bw 8 -#define RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_reset 0x0 -#define RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bm 0xff00 -#define RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bp 8 -#define RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bw 8 -#define RX_SAMPLE_DISCARD__RX_NCO_DISCARD_reset 0x0 - -// Reg - lpf_config_2 -#define LPF_CONFIG_2__P_GAIN_bm 0xffffff -#define LPF_CONFIG_2__P_GAIN_bp 0 -#define LPF_CONFIG_2__P_GAIN_bw 24 -#define LPF_CONFIG_2__P_GAIN_reset 0x0 -#define LPF_CONFIG_2__P_SHIFT_bm 0xff000000 -#define LPF_CONFIG_2__P_SHIFT_bp 24 -#define LPF_CONFIG_2__P_SHIFT_bw 8 -#define LPF_CONFIG_2__P_SHIFT_reset 0x0 - -// Reg - observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25 -#define OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bm 0xffffffff -#define OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bp 0 -#define OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bw 32 -#define OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_reset 0x0 - -// Reg - observation_data_data_0515efaa_desc_ebde6d39_name_2c154788 -#define OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bm 0xffffffff -#define OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bp 0 -#define OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bw 32 -#define OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_reset 0x0 - -// Reg - observation_data_data_25a21249_desc_417e1c96_name_3b640507 -#define OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bm 0xffffffff -#define OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bp 0 -#define OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bw 32 -#define OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_reset 0x0 - -// Reg - observation_data_data_272a00b6_desc_70869502_name_3de9a0d3 -#define OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bm 0xffffffff -#define OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bp 0 -#define OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bw 32 -#define OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_reset 0x0 - -// Reg - tx_sync_ctrl -#define TX_SYNC_CTRL__TX_SYNC_ENA_bm 0x1 -#define TX_SYNC_CTRL__TX_SYNC_ENA_bp 0 -#define TX_SYNC_CTRL__TX_SYNC_ENA_bw 1 -#define TX_SYNC_CTRL__TX_SYNC_ENA_reset 0x0 -#define TX_SYNC_CTRL__TX_SYNC_FORCE_bm 0x2 -#define TX_SYNC_CTRL__TX_SYNC_FORCE_bp 1 -#define TX_SYNC_CTRL__TX_SYNC_FORCE_bw 1 -#define TX_SYNC_CTRL__TX_SYNC_FORCE_reset 0x0 -#define TX_SYNC_CTRL__TX_SYNC_F1_bm 0x4 -#define TX_SYNC_CTRL__TX_SYNC_F1_bp 2 -#define TX_SYNC_CTRL__TX_SYNC_F1_bw 1 -#define TX_SYNC_CTRL__TX_SYNC_F1_reset 0x0 -#define TX_SYNC_CTRL__TX_SYNC_F2_bm 0x8 -#define TX_SYNC_CTRL__TX_SYNC_F2_bp 3 -#define TX_SYNC_CTRL__TX_SYNC_F2_bw 1 -#define TX_SYNC_CTRL__TX_SYNC_F2_reset 0x0 - -// Reg - tx_sync_cnt -#define TX_SYNC_CNT__TX_SYNC_CNT_bm 0xffffff -#define TX_SYNC_CNT__TX_SYNC_CNT_bp 0 -#define TX_SYNC_CNT__TX_SYNC_CNT_bw 24 -#define TX_SYNC_CNT__TX_SYNC_CNT_reset 0x0 - -// Reg - lowpass_ema_alpha -#define LOWPASS_EMA_ALPHA__ALPHA_bm 0x3ffff -#define LOWPASS_EMA_ALPHA__ALPHA_bp 0 -#define LOWPASS_EMA_ALPHA__ALPHA_bw 18 -#define LOWPASS_EMA_ALPHA__ALPHA_reset 0x0 - -// Reg - rx_power -#define RX_POWER__RX_POWER_bm 0x7fffff -#define RX_POWER__RX_POWER_bp 0 -#define RX_POWER__RX_POWER_bw 23 -#define RX_POWER__RX_POWER_reset 0x0 - -// Addrmap - msk_top_regs -typedef struct __attribute__ ((__packed__)) { - uint32_t Hash_ID_Low; - uint32_t Hash_ID_High; - uint32_t MSK_Init; - uint32_t MSK_Control; - uint32_t MSK_Status; - uint32_t Tx_Bit_Count; - uint32_t Tx_Enable_Count; - uint32_t Fb_FreqWord; - uint32_t TX_F1_FreqWord; - uint32_t TX_F2_FreqWord; - uint32_t RX_F1_FreqWord; - uint32_t RX_F2_FreqWord; - uint32_t LPF_Config_0; - uint32_t LPF_Config_1; - uint32_t Tx_Data_Width; - uint32_t Rx_Data_Width; - uint32_t PRBS_Control; - uint32_t PRBS_Initial_State; - uint32_t PRBS_Polynomial; - uint32_t PRBS_Error_Mask; - uint32_t PRBS_Bit_Count; - uint32_t PRBS_Error_Count; - uint32_t LPF_Accum_F1; - uint32_t LPF_Accum_F2; - uint32_t axis_xfer_count; - uint32_t Rx_Sample_Discard; - uint32_t LPF_Config_2; - uint32_t f1_nco_adjust; - uint32_t f2_nco_adjust; - uint32_t f1_error; - uint32_t f2_error; - uint32_t Tx_Sync_Ctrl; - uint32_t Tx_Sync_Cnt; - uint32_t lowpass_ema_alpha1; - uint32_t lowpass_ema_alpha2; - uint32_t rx_power; -} msk_top_regs_t; - -// Addrmap - Pluto_MSK_Modem -typedef struct __attribute__ ((__packed__)) { - uint8_t RESERVED_0_43bfffff[0x43c00000]; - msk_top_regs_t pluto_msk_regs; -} Pluto_MSK_Modem_t; - - -static_assert(sizeof(Pluto_MSK_Modem_t) == 0x43c00090, "Packing error"); - -#ifdef __cplusplus -} -#endif - -#endif /* MSK_TOP_REGS_H */ diff --git a/rdl/msk_top_regs.pl b/rdl/msk_top_regs.pl deleted file mode 100755 index 5d951b3..0000000 --- a/rdl/msk_top_regs.pl +++ /dev/null @@ -1,40 +0,0 @@ -#! /usr/bin/perl - -open(FILE, "msk_top_regs.rdl"); - -while() { - - chomp; - - s/}; \/\/ //; - - $line = "$_\n"; - - if (/^\/\/.*desyrdl/) { - $line = substr $line, 2; - } - - if (/name/) { $line = ""; } - - if (/desc/) { - $line = ""; - $eoc = 1; - } - - if (/;$/) { - if ($eoc == 1) { - $eoc = 0; - $line = ""; - } - } else { - if ($eoc == 1) { - $line = ""; - } - } - - if (/Pluto_MSK_Modem/) { last; } - - print($line); - -} -close FILE; diff --git a/rdl/msk_top_regs.rdl b/rdl/msk_top_regs.rdl deleted file mode 100644 index ebe3ec0..0000000 --- a/rdl/msk_top_regs.rdl +++ /dev/null @@ -1,408 +0,0 @@ -reg msk_hash_lo { - name = "Pluto MSK FPGA Hash ID - Lower 32-bits"; - regwidth = 32; - accesswidth = 32; - field { sw = r; hw = na; } hash_id_lo[31:0] = 0xAAAA5555; - hash_id_lo->desc = "Lower 32-bits of Pluto MSK FPGA Hash ID"; - hash_id_lo->name = "Hash ID Lower 32-bits"; -}; - -reg msk_hash_hi { - name = "Pluto MSK FPGA Hash ID - Upper 32-bits"; - regwidth = 32; - accesswidth = 32; - field { sw = r; hw = na; } hash_id_hi[31:0] = 0x5555AAAA; - hash_id_hi->desc = "Upper 32-bits of Pluto MSK FPGA Hash ID"; - hash_id_hi->name = "Hash ID Upper 32-bits"; -}; - -reg msk_init { - name = "MSK Modem Control 0"; - regwidth = 32; - desc = "Synchronous initialization of MSK Modem functions, does not affect configuration registers."; - field { sw = rw; hw=r; } txrxinit = 1; - txrxinit->desc = "0 -> Normal modem operation - 1 -> Initialize Tx and Rx"; - txrxinit->name = "Tx/Rx Init Enable"; - field { sw = rw; hw=r; } txinit = 1; - txinit->desc = "0 -> Normal Tx operation - 1 -> Initialize Tx"; - txinit->name = "Tx Init Enable"; - field { sw = rw; hw=r; } rxinit = 1; - rxinit->desc = "0 -> Normal Rx operation - 1 -> Initialize Rx"; - rxinit->name = "Rx Init Enable"; -}; - -reg msk_ctrl { - name = "MSK Modem Control 1"; - regwidth = 32; - desc = "MSK Modem Configuration and Control"; - field { sw = rw; hw = r; } ptt = 0; - ptt->desc = "0 -> PTT Disabled - 1 -> PTT Enabled"; - ptt->name = "Push-to-Talk Enable"; - field { sw = rw; hw = r; } loopback_ena = 0; - loopback_ena->desc = "0 -> Modem loopback disabled - 1 -> Modem loopback enabled"; - loopback_ena->name = "Modem Loopback Enable"; - field { sw = rw; hw = r; } rx_invert = 0; - rx_invert->desc = "0 -> Rx data normal - 1 -> Rx data inverted"; - rx_invert->name = "Rx Data Invert Enable"; - field { sw = rw; hw = r; singlepulse = true; } clear_counts = 0; - clear_counts->desc = "Clear Tx Bit Counter and Tx Enable Counter"; - clear_counts->name = "Clear Status Counters"; - field { sw = rw; hw = r; } diff_encoder_loopback = 0; - diff_encoder_loopback->desc = "0 -> Differential Encoder -> Decoder loopback disabled - 1 -> Differential Encoder -> Decoder loopback enabled"; - diff_encoder_loopback->name = "Differential Encoder -> Decoder Loopback Enable"; -}; - -reg msk_stat_0 { - name = "MSK Modem Status 0"; - desc = "Modem status bits"; - regwidth = 32; - field { sw = r; hw = w; } demod_sync_lock=0; - demod_sync_lock->desc = "Demodulator Sync Status - not currently implemented"; - demod_sync_lock->name = "Demodulator Sync Status"; - field { sw = r; hw = w; } tx_enable=0; - tx_enable->name = "AD9363 DAC Interface Tx Enable Input Active"; - tx_enable->desc = "1 -> Data to DAC Enabled - 0 -> Data to DAC Disabled"; - field { sw = r; hw = w; } rx_enable=0; - rx_enable->name = "AD9363 ADC Interface Rx Enable Input Active"; - rx_enable->desc = "1 -> Data from ADC Enabled - 0 -> Data from ADC Disabled"; - field { sw = r; hw = w; } tx_axis_valid=0; - tx_axis_valid->name = "Tx S_AXIS_VALID"; - tx_axis_valid->desc = "1 -> S_AXIS_VALID Enabled - 0 -> S_AXIS_VALID Disabled"; -}; - -reg msk_stat_1 { - name = "MSK Modem Status 1"; - desc = "Modem status data"; - regwidth = 32; - field { sw = r; hw = w; } tx_bit_counter[31:0] = 0; - tx_bit_counter->desc = "Count of data requests made by modem"; - tx_bit_counter->name = "Tx Bit Count"; -}; - -reg msk_stat_2 { - name = "MSK Modem Status 2"; - desc = "Modem status data"; - regwidth = 32; - field { sw = r; hw = w; } tx_ena_counter[31:0] = 0; - tx_ena_counter->desc = "Number of clocks on which Tx Enable is active"; - tx_ena_counter->name = "Tx Enable Count"; -}; - -reg config_nco_fw { - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; - config_data->name = "Frequency Control Word"; - config_data->desc = "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate"; -}; - -reg rx_sample_discard { - name = "Rx Sample Discard"; - desc = "Configure samples discard operation for demodulator"; - regwidth = 32; - field { sw = rw; hw = r; } rx_sample_discard[7:0] = 0; - rx_sample_discard->desc = "Number of Rx samples to discard"; - rx_sample_discard->name = "Rx Sample Discard Value"; - field { sw = rw; hw = r; } rx_nco_discard[15:8] = 0; - rx_nco_discard->desc = "Number of NCO samples to discard"; - rx_nco_discard->name = "Rx NCO Sample Discard Value"; -}; - -reg lpf_config_0 { - name = "PI Controller Configuration and Low-pass Filter Configuration"; - desc = "Configure PI controller and low-pass filter"; - regwidth = 32; - field { sw = rw; hw = r; } lpf_freeze = 0; - lpf_freeze->name = "Freeze the accumulator's current value"; - lpf_freeze->desc = "0 -> Normal operation - 1 -> Freeze current value"; - field { sw = rw; hw = r; } lpf_zero = 0; - lpf_zero->name = "Hold the PI Accumulator at zero"; - lpf_zero->desc = "0 -> Normal operation - 1 -> Zero and hold accumulator"; - field { sw = w; hw = r; } prbs_reserved[7:2] = 0; - field { sw = rw; hw = r; } lpf_alpha[31:8] = 0; - lpf_alpha->name = "Lowpass IIR filter alpha"; - lpf_alpha->desc = "Value controls the filter rolloff"; -}; - -reg lpf_config_1 { - name = "PI Controller Configuration Configuration Register 1"; - desc = "Configures PI Controller I-gain and divisor"; - regwidth = 32; - field { sw = rw; hw = r; } i_gain[23:0] = 0; - i_gain->name = "Integral Gain Value"; - i_gain->desc = "Value m of 0-16,777,215 sets the integral multiplier"; - field { sw = rw; hw = r; } i_shift[31:24] = 0; - i_shift->name = "Integral Gain Bit Shift"; - i_shift->desc = "Value n of 0-32 sets the integral divisor as 2^-n"; -}; - -reg lpf_config_2 { - name = "PI Controller Configuration Configuration Register 2"; - desc = "Configures PI Controller I-gain and divisor"; - regwidth = 32; - field { sw = rw; hw = r; } p_gain[23:0] = 0; - p_gain->name = "Proportional Gain Value"; - p_gain->desc = "Value m of 0-16,777,215 sets the proportional multiplier"; - field { sw = rw; hw = r; } p_shift[31:24] = 0; - p_shift->name = "Proportional Gain Bit Shift"; - p_shift->desc = "Value n of 0-32 sets the proportional divisor as 2^-n"; -}; - -reg data_width { - regwidth = 32; - field { sw = rw; hw = r; } data_width[7:0] = 8; - data_width->name = "Modem input/output data width"; - data_width->desc = "Set the data width of the modem input/output"; -}; - -reg prbs_ctrl { - name = "PRBS Control 0"; - desc = "Configures operation of the PRBS Generator and Monitor"; - regwidth = 32; - field { sw = rw; hw = r; } prbs_sel = 0; - prbs_sel->name = "PRBS Data Select"; - prbs_sel->desc = "0 -> Select Normal Tx Data - 1 -> Select PRBS Tx Data"; - field { sw = w; hw = r; singlepulse = true; } prbs_error_insert = 0; - prbs_error_insert->name = "PRBS Error Insert"; - prbs_error_insert->desc = "0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) - 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)"; - field { sw = w; hw = r; singlepulse = true; } prbs_clear = 0; - prbs_clear->name = "PRBS Clear Counters"; - prbs_clear->desc = "0 -> 1 : Clear PRBS Counters - 1 -> 0 : Clear PRBS Counters"; - field { sw = w; hw = r; singlepulse = true; } prbs_manual_sync = 0; - prbs_manual_sync->name = "PRBS Manual Sync"; - prbs_manual_sync->desc = "0 -> 1 : Synchronize PRBS monitor - 1 -> 0 : Synchronize PRBS monitor"; - field { sw = w; hw = r; } prbs_reserved[15:4] = 0; - field { sw = w; hw = r; } prbs_sync_threshold[31:16] = 0; - prbs_sync_threshold->name = "PRBS Auto Sync Threshold"; - prbs_sync_threshold->desc = "0 : Auto Sync Disabled - N > 0 : Auto sync after N errors"; -}; - -reg config_prbs_seed { - name = "PRBS Control 1"; - desc = "PRBS Initial State"; - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; - config_data->name = "PRBS Seed"; - config_data->desc = "Sets the starting value of the PRBS generator"; -}; - -reg config_prbs_poly { - name = "PRBS Control 2"; - desc = "PRBS Polynomial"; - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; - config_data->name = "PRBS Polynomial"; - config_data->desc = "Bit positions set to '1' indicate polynomial feedback positions"; -}; - -reg config_prbs_errmask { - name = "PRBS Control 3"; - desc = "PRBS Error Mask"; - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; - config_data->name = "PRBS Error Mask"; - config_data->desc = "Bit positions set to '1' indicate bits that are inverted when a bit error is inserted"; -}; - -reg stat_32_bits { - name = "PRBS Status 0"; - desc = "PRBS Bits Received"; - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; - status_data->name = "PRBS Bits Received"; - status_data->desc = "Number of bits received by the PRBS monitor since last - BER can be calculated as the ratio of received bits to errored-bits"; -}; - -reg stat_32_errs { - name = "PRBS Status 1"; - desc = "PRBS Bit Errors"; - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; - status_data->name = "PRBS Bit Errors"; - status_data->desc = "Number of errored-bits received by the PRBS monitor since last sync - BER can be calculated as the ratio of received bits to errored-bits"; -}; - -reg stat_32_lpf_acc { - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; - status_data->name = "PI Controller Accumulator Value"; - status_data->desc = "PI Controller Accumulator Value"; -}; - -reg msk_stat_3 { - name = "MSK Modem Status 3"; - desc = "Modem status data"; - regwidth = 32; - field { sw = r; hw = w; } xfer_count[31:0] = 0; - xfer_count->desc = "Number completed S_AXIS transfers"; - xfer_count->name = "S_AXIS Transfers"; -}; - -reg tx_sync_ctrl { - name = "Transmitter Sync Control"; - desc = "Provides control bits for generation of transmitter synchronization patterns"; - regwidth = 32; - field { sw = rw; hw = r; } tx_sync_ena = 0; - tx_sync_ena->name = "Tx Sync Enable"; - tx_sync_ena->desc = "0 -> Disable sync transmission - 1 -> Enable sync transmission when PTT is asserted"; - field { sw = rw; hw = r; } tx_sync_force = 0; - tx_sync_force->name = "Tx Sync Force"; - tx_sync_force->desc = "0 : Normal operation) - 1 : Transmit synchronization pattern)"; - field { sw = rw; hw = r; } tx_sync_f1 = 0; - tx_sync_f1->name = "Tx F1 Sync Enable"; - tx_sync_f1->desc = "Enables/Disables transmission of F1 tone for receiver synchronization - 0 : F1 tone transmission disabled - 1 : F1 tone transmission enabled - Both F1 and F2 can be enabled at the same time"; - field { sw = rw; hw = r; } tx_sync_f2 = 0; - tx_sync_f2->name = "Tx F2 Sync Enable"; - tx_sync_f2->desc = "Enables/Disables transmission of F2 tone for receiver synchronization - 0 : F2 tone transmission disabled - 1 : F2 tone transmission enabled - Both F1 and F2 can be enabled at the same time"; -}; - -reg tx_sync_cnt { - name = "Transmitter Sync Duration"; - desc = "Sets the duration of the synchronization tones when enabled"; - regwidth = 32; - field { sw = rw; hw = r; } tx_sync_cnt[23:0] = 0; - tx_sync_cnt->name = "Tx sync duration"; - tx_sync_cnt->desc = "Value from 0x00_0000 to 0xFF_FFFF. This value represents the number bit-times the synchronization signal should be sent after PTT is asserted."; -}; - -reg lowpass_ema_alpha { - name = "Exponential Moving Average Alpha"; - desc = "Sets the alpha for the EMA"; - regwidth = 32; - field { sw = rw; hw = r; } alpha[17:0] = 0; - alpha->name = "EMA alpha"; - alpha->desc = "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha"; -}; - -reg rx_power { - name = "Receive Power"; - desc = "Receive power computed from I/Q ssamples"; - regwidth = 32; - field { sw = r; hw = w; } rx_power[22:0] = 0; - rx_power->name = "Receive Power"; - rx_power->desc = "Value that represent the RMS power of the incoming I;"; -}; - -field data32 { - fieldwidth = 32; - sw = r; - hw = w; -}; - -reg observation_data { - regwidth = 32; - data32 data[31:0] = 0; -}; - -addrmap msk_top_regs { - name="Pluto MSK Registers"; - desc="MSK Modem Configuration and Status Registers"; - lsb0; - default accesswidth=32; - addressing=compact; - -// desyrdl_interface = "AXI4L"; -// desyrdl_access_channel = 0; - - msk_hash_lo Hash_ID_Low; - msk_hash_hi Hash_ID_High; - msk_init MSK_Init; - msk_ctrl MSK_Control; - msk_stat_0 MSK_Status; - msk_stat_1 Tx_Bit_Count; - msk_stat_2 Tx_Enable_Count; - config_nco_fw Fb_FreqWord; - Fb_FreqWord->desc = "Set Modem Data Rate"; - Fb_FreqWord->name = "Bitrate NCO Frequency Control Word"; - config_nco_fw TX_F1_FreqWord; - TX_F1_FreqWord->desc = "Set Modulator F1 Frequency"; - TX_F1_FreqWord->name = "Tx F1 NCO Frequency Control Word"; - config_nco_fw TX_F2_FreqWord; - TX_F2_FreqWord->desc = "Set Modulator F2 Frequency"; - TX_F2_FreqWord->name = "Tx F2 NCO Frequency Control Word"; - config_nco_fw RX_F1_FreqWord; - RX_F1_FreqWord->desc = "Set Demodulator F1 Frequency"; - RX_F1_FreqWord->name = "Rx F1 NCO Frequency Control Word"; - config_nco_fw RX_F2_FreqWord; - RX_F2_FreqWord->desc = "Set Demodulator F2 Frequency"; - RX_F2_FreqWord->name = "Rx F2 NCO Frequency Control Word"; - lpf_config_0 LPF_Config_0; - lpf_config_1 LPF_Config_1; - data_width Tx_Data_Width; - Tx_Data_Width->desc = "Set the parallel data width of the parallel-to-serial converter"; - Tx_Data_Width->name = "Modem Tx Input Data Width"; - data_width Rx_Data_Width; - Rx_Data_Width->desc = "Set the parallel data width of the serial-to-parallel converter"; - Rx_Data_Width->name = "Modem Rx Output Data Width"; - prbs_ctrl PRBS_Control; - config_prbs_seed PRBS_Initial_State; - config_prbs_poly PRBS_Polynomial; - config_prbs_errmask PRBS_Error_Mask; - stat_32_bits PRBS_Bit_Count; - stat_32_errs PRBS_Error_Count; - stat_32_lpf_acc LPF_Accum_F1; - LPF_Accum_F1->name = "F1 PI Controller Accumulator"; - LPF_Accum_F1->desc = "Value of the F1 PI Controller Accumulator"; - stat_32_lpf_acc LPF_Accum_F2; - LPF_Accum_F2->name = "F2 PI Controller Accumulator"; - LPF_Accum_F2->desc = "Value of the F2 PI Controller Accumulator"; - msk_stat_3 axis_xfer_count; - rx_sample_discard Rx_Sample_Discard; - lpf_config_2 LPF_Config_2; - observation_data f1_nco_adjust; - f1_nco_adjust->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; - f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; - observation_data f2_nco_adjust; - f2_nco_adjust->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; - f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; - observation_data f1_error; - f1_error->name = "F1 Error Value"; - f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; - f1_error.data->name = "F1 Error Value"; - f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; - observation_data f2_error; - f2_error->name = "F2 Error Value"; - f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; - f2_error.data->name = "F2 Error Value"; - f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period"; - tx_sync_ctrl Tx_Sync_Ctrl; - tx_sync_cnt Tx_Sync_Cnt; - lowpass_ema_alpha lowpass_ema_alpha1; - lowpass_ema_alpha lowpass_ema_alpha2; - rx_power rx_power; - -}; - -addrmap Pluto_MSK_Modem { - msk_top_regs pluto_msk_regs @0x43C00000; -}; diff --git a/rdl/msk_top_regs_desy.rdl b/rdl/msk_top_regs_desy.rdl deleted file mode 100644 index 3204600..0000000 --- a/rdl/msk_top_regs_desy.rdl +++ /dev/null @@ -1,208 +0,0 @@ -reg msk_hash_lo { - regwidth = 32; - accesswidth = 32; - field { sw = r; hw = na; } hash_id_lo[31:0] = 0xAAAA5555; -}; - -reg msk_hash_hi { - regwidth = 32; - accesswidth = 32; - field { sw = r; hw = na; } hash_id_hi[31:0] = 0x5555AAAA; -}; - -reg msk_init { - regwidth = 32; - field { sw = rw; hw=r; } txrxinit = 1; - field { sw = rw; hw=r; } txinit = 1; - field { sw = rw; hw=r; } rxinit = 1; -}; - -reg msk_ctrl { - regwidth = 32; - field { sw = rw; hw = r; } ptt = 0; - field { sw = rw; hw = r; } loopback_ena = 0; - field { sw = rw; hw = r; } rx_invert = 0; - field { sw = rw; hw = r; singlepulse = true; } clear_counts = 0; - field { sw = rw; hw = r; } diff_encoder_loopback = 0; -}; - -reg msk_stat_0 { - regwidth = 32; - field { sw = r; hw = w; } demod_sync_lock=0; - field { sw = r; hw = w; } tx_enable=0; - field { sw = r; hw = w; } rx_enable=0; - field { sw = r; hw = w; } tx_axis_valid=0; -}; - -reg msk_stat_1 { - regwidth = 32; - field { sw = r; hw = w; } tx_bit_counter[31:0] = 0; -}; - -reg msk_stat_2 { - regwidth = 32; - field { sw = r; hw = w; } tx_ena_counter[31:0] = 0; -}; - -reg config_nco_fw { - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; -}; - -reg rx_sample_discard { - regwidth = 32; - field { sw = rw; hw = r; } rx_sample_discard[7:0] = 0; - field { sw = rw; hw = r; } rx_nco_discard[15:8] = 0; -}; - -reg lpf_config_0 { - regwidth = 32; - field { sw = rw; hw = r; } lpf_freeze = 0; - field { sw = rw; hw = r; } lpf_zero = 0; - field { sw = w; hw = r; } prbs_reserved[7:2] = 0; - field { sw = rw; hw = r; } lpf_alpha[31:8] = 0; -}; - -reg lpf_config_1 { - regwidth = 32; - field { sw = rw; hw = r; } i_gain[23:0] = 0; - field { sw = rw; hw = r; } i_shift[31:24] = 0; -}; - -reg lpf_config_2 { - regwidth = 32; - field { sw = rw; hw = r; } p_gain[23:0] = 0; - field { sw = rw; hw = r; } p_shift[31:24] = 0; -}; - -reg data_width { - regwidth = 32; - field { sw = rw; hw = r; } data_width[7:0] = 8; -}; - -reg prbs_ctrl { - regwidth = 32; - field { sw = rw; hw = r; } prbs_sel = 0; - field { sw = w; hw = r; singlepulse = true; } prbs_error_insert = 0; - field { sw = w; hw = r; singlepulse = true; } prbs_clear = 0; - field { sw = w; hw = r; singlepulse = true; } prbs_manual_sync = 0; - field { sw = w; hw = r; } prbs_reserved[15:4] = 0; - field { sw = w; hw = r; } prbs_sync_threshold[31:16] = 0; -}; - -reg config_prbs_seed { - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; -}; - -reg config_prbs_poly { - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; -}; - -reg config_prbs_errmask { - regwidth = 32; - field { sw = rw; hw = r; } config_data[31:0] = 0; -}; - -reg stat_32_bits { - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; -}; - -reg stat_32_errs { - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; -}; - -reg stat_32_lpf_acc { - regwidth = 32; - field { sw = r; hw = w; } status_data[31:0] = 0; -}; - -reg msk_stat_3 { - regwidth = 32; - field { sw = r; hw = w; } xfer_count[31:0] = 0; -}; - -reg tx_sync_ctrl { - regwidth = 32; - field { sw = rw; hw = r; } tx_sync_ena = 0; - field { sw = rw; hw = r; } tx_sync_force = 0; - field { sw = rw; hw = r; } tx_sync_f1 = 0; - field { sw = rw; hw = r; } tx_sync_f2 = 0; -}; - -reg tx_sync_cnt { - regwidth = 32; - field { sw = rw; hw = r; } tx_sync_cnt[23:0] = 0; -}; - -reg lowpass_ema_alpha { - regwidth = 32; - field { sw = rw; hw = r; } alpha[17:0] = 0; -}; - -reg rx_power { - regwidth = 32; - field { sw = r; hw = w; } rx_power[22:0] = 0; -}; - -field data32 { - fieldwidth = 32; - sw = r; - hw = w; -}; - -reg observation_data { - regwidth = 32; - data32 data[31:0] = 0; -}; - -addrmap msk_top_regs { - lsb0; - default accesswidth=32; - addressing=compact; - - desyrdl_interface = "AXI4L"; - desyrdl_access_channel = 0; - - msk_hash_lo Hash_ID_Low; - msk_hash_hi Hash_ID_High; - msk_init MSK_Init; - msk_ctrl MSK_Control; - msk_stat_0 MSK_Status; - msk_stat_1 Tx_Bit_Count; - msk_stat_2 Tx_Enable_Count; - config_nco_fw Fb_FreqWord; - config_nco_fw TX_F1_FreqWord; - config_nco_fw TX_F2_FreqWord; - config_nco_fw RX_F1_FreqWord; - config_nco_fw RX_F2_FreqWord; - lpf_config_0 LPF_Config_0; - lpf_config_1 LPF_Config_1; - data_width Tx_Data_Width; - data_width Rx_Data_Width; - prbs_ctrl PRBS_Control; - config_prbs_seed PRBS_Initial_State; - config_prbs_poly PRBS_Polynomial; - config_prbs_errmask PRBS_Error_Mask; - stat_32_bits PRBS_Bit_Count; - stat_32_errs PRBS_Error_Count; - stat_32_lpf_acc LPF_Accum_F1; - stat_32_lpf_acc LPF_Accum_F2; - msk_stat_3 axis_xfer_count; - rx_sample_discard Rx_Sample_Discard; - lpf_config_2 LPF_Config_2; - observation_data f1_nco_adjust; - observation_data f2_nco_adjust; - observation_data f1_error; - observation_data f2_error; - tx_sync_ctrl Tx_Sync_Ctrl; - tx_sync_cnt Tx_Sync_Cnt; - lowpass_ema_alpha lowpass_ema_alpha1; - lowpass_ema_alpha lowpass_ema_alpha2; - rx_power rx_power; - -}; - diff --git a/rdl/outputs/c-header/msk_top_regs.h b/rdl/outputs/c-header/msk_top_regs.h new file mode 100644 index 0000000..1d89a4a --- /dev/null +++ b/rdl/outputs/c-header/msk_top_regs.h @@ -0,0 +1,362 @@ +// Generated by PeakRDL-cheader - A free and open-source header generator +// https://github.com/SystemRDL/PeakRDL-cheader + +#ifndef MSK_TOP_REGS_H +#define MSK_TOP_REGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +// Reg - msk_top_regs::msk_hash_lo +#define MSK_TOP_REGS__MSK_HASH_LO__HASH_ID_LO_bm 0xffffffff +#define MSK_TOP_REGS__MSK_HASH_LO__HASH_ID_LO_bp 0 +#define MSK_TOP_REGS__MSK_HASH_LO__HASH_ID_LO_bw 32 +#define MSK_TOP_REGS__MSK_HASH_LO__HASH_ID_LO_reset 0xaaaa5555 + +// Reg - msk_top_regs::msk_hash_hi +#define MSK_TOP_REGS__MSK_HASH_HI__HASH_ID_HI_bm 0xffffffff +#define MSK_TOP_REGS__MSK_HASH_HI__HASH_ID_HI_bp 0 +#define MSK_TOP_REGS__MSK_HASH_HI__HASH_ID_HI_bw 32 +#define MSK_TOP_REGS__MSK_HASH_HI__HASH_ID_HI_reset 0x5555aaaa + +// Reg - msk_top_regs::msk_init +#define MSK_TOP_REGS__MSK_INIT__TXRXINIT_bm 0x1 +#define MSK_TOP_REGS__MSK_INIT__TXRXINIT_bp 0 +#define MSK_TOP_REGS__MSK_INIT__TXRXINIT_bw 1 +#define MSK_TOP_REGS__MSK_INIT__TXRXINIT_reset 0x1 +#define MSK_TOP_REGS__MSK_INIT__TXINIT_bm 0x2 +#define MSK_TOP_REGS__MSK_INIT__TXINIT_bp 1 +#define MSK_TOP_REGS__MSK_INIT__TXINIT_bw 1 +#define MSK_TOP_REGS__MSK_INIT__TXINIT_reset 0x1 +#define MSK_TOP_REGS__MSK_INIT__RXINIT_bm 0x4 +#define MSK_TOP_REGS__MSK_INIT__RXINIT_bp 2 +#define MSK_TOP_REGS__MSK_INIT__RXINIT_bw 1 +#define MSK_TOP_REGS__MSK_INIT__RXINIT_reset 0x1 + +// Reg - msk_top_regs::msk_ctrl +#define MSK_TOP_REGS__MSK_CTRL__PTT_bm 0x1 +#define MSK_TOP_REGS__MSK_CTRL__PTT_bp 0 +#define MSK_TOP_REGS__MSK_CTRL__PTT_bw 1 +#define MSK_TOP_REGS__MSK_CTRL__PTT_reset 0x0 +#define MSK_TOP_REGS__MSK_CTRL__LOOPBACK_ENA_bm 0x2 +#define MSK_TOP_REGS__MSK_CTRL__LOOPBACK_ENA_bp 1 +#define MSK_TOP_REGS__MSK_CTRL__LOOPBACK_ENA_bw 1 +#define MSK_TOP_REGS__MSK_CTRL__LOOPBACK_ENA_reset 0x0 +#define MSK_TOP_REGS__MSK_CTRL__RX_INVERT_bm 0x4 +#define MSK_TOP_REGS__MSK_CTRL__RX_INVERT_bp 2 +#define MSK_TOP_REGS__MSK_CTRL__RX_INVERT_bw 1 +#define MSK_TOP_REGS__MSK_CTRL__RX_INVERT_reset 0x0 +#define MSK_TOP_REGS__MSK_CTRL__CLEAR_COUNTS_bm 0x8 +#define MSK_TOP_REGS__MSK_CTRL__CLEAR_COUNTS_bp 3 +#define MSK_TOP_REGS__MSK_CTRL__CLEAR_COUNTS_bw 1 +#define MSK_TOP_REGS__MSK_CTRL__CLEAR_COUNTS_reset 0x0 +#define MSK_TOP_REGS__MSK_CTRL__DIFF_ENCODER_LOOPBACK_bm 0x10 +#define MSK_TOP_REGS__MSK_CTRL__DIFF_ENCODER_LOOPBACK_bp 4 +#define MSK_TOP_REGS__MSK_CTRL__DIFF_ENCODER_LOOPBACK_bw 1 +#define MSK_TOP_REGS__MSK_CTRL__DIFF_ENCODER_LOOPBACK_reset 0x0 + +// Reg - msk_top_regs::msk_stat_0 +#define MSK_TOP_REGS__MSK_STAT_0__DEMOD_SYNC_LOCK_bm 0x1 +#define MSK_TOP_REGS__MSK_STAT_0__DEMOD_SYNC_LOCK_bp 0 +#define MSK_TOP_REGS__MSK_STAT_0__DEMOD_SYNC_LOCK_bw 1 +#define MSK_TOP_REGS__MSK_STAT_0__DEMOD_SYNC_LOCK_reset 0x0 +#define MSK_TOP_REGS__MSK_STAT_0__TX_ENABLE_bm 0x2 +#define MSK_TOP_REGS__MSK_STAT_0__TX_ENABLE_bp 1 +#define MSK_TOP_REGS__MSK_STAT_0__TX_ENABLE_bw 1 +#define MSK_TOP_REGS__MSK_STAT_0__TX_ENABLE_reset 0x0 +#define MSK_TOP_REGS__MSK_STAT_0__RX_ENABLE_bm 0x4 +#define MSK_TOP_REGS__MSK_STAT_0__RX_ENABLE_bp 2 +#define MSK_TOP_REGS__MSK_STAT_0__RX_ENABLE_bw 1 +#define MSK_TOP_REGS__MSK_STAT_0__RX_ENABLE_reset 0x0 +#define MSK_TOP_REGS__MSK_STAT_0__TX_AXIS_VALID_bm 0x8 +#define MSK_TOP_REGS__MSK_STAT_0__TX_AXIS_VALID_bp 3 +#define MSK_TOP_REGS__MSK_STAT_0__TX_AXIS_VALID_bw 1 +#define MSK_TOP_REGS__MSK_STAT_0__TX_AXIS_VALID_reset 0x0 + +// Reg - msk_top_regs::msk_stat_1 +#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bp 0 +#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bw 32 + +// Reg - msk_top_regs::msk_stat_2 +#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bp 0 +#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bw 32 +#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_reset 0x0 + +// Reg - msk_top_regs::config_nco_fw_desc_c4924cc6_name_0c494469 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_nco_fw_desc_94d7aaf5_name_84dd0c1c +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_94D7AAF5_NAME_84DD0C1C__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_nco_fw_desc_42134a4f_name_d97dbd51 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_42134A4F_NAME_D97DBD51__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_nco_fw_desc_16fb48c8_name_8d01a20d +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_16FB48C8_NAME_8D01A20D__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_nco_fw_desc_43c0828f_name_bdc60ecf +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_43C0828F_NAME_BDC60ECF__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::lpf_config_0 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_FREEZE_bm 0x1 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_FREEZE_bp 0 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_FREEZE_bw 1 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_FREEZE_reset 0x0 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ZERO_bm 0x2 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ZERO_bp 1 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ZERO_bw 1 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ZERO_reset 0x0 +#define MSK_TOP_REGS__LPF_CONFIG_0__PRBS_RESERVED_bm 0xfc +#define MSK_TOP_REGS__LPF_CONFIG_0__PRBS_RESERVED_bp 2 +#define MSK_TOP_REGS__LPF_CONFIG_0__PRBS_RESERVED_bw 6 +#define MSK_TOP_REGS__LPF_CONFIG_0__PRBS_RESERVED_reset 0x0 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ALPHA_bm 0xffffff00 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ALPHA_bp 8 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ALPHA_bw 24 +#define MSK_TOP_REGS__LPF_CONFIG_0__LPF_ALPHA_reset 0x0 + +// Reg - msk_top_regs::lpf_config_1 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_GAIN_bm 0xffffff +#define MSK_TOP_REGS__LPF_CONFIG_1__I_GAIN_bp 0 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_GAIN_bw 24 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_GAIN_reset 0x0 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_SHIFT_bm 0xff000000 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_SHIFT_bp 24 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_SHIFT_bw 8 +#define MSK_TOP_REGS__LPF_CONFIG_1__I_SHIFT_reset 0x0 + +// Reg - msk_top_regs::data_width_desc_58c848dd_name_2fbd8eba +#define MSK_TOP_REGS__DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bm 0xff +#define MSK_TOP_REGS__DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bp 0 +#define MSK_TOP_REGS__DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_bw 8 +#define MSK_TOP_REGS__DATA_WIDTH_DESC_58C848DD_NAME_2FBD8EBA__DATA_WIDTH_reset 0x8 + +// Reg - msk_top_regs::data_width_desc_6097df38_name_4609588b +#define MSK_TOP_REGS__DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bm 0xff +#define MSK_TOP_REGS__DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bp 0 +#define MSK_TOP_REGS__DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_bw 8 +#define MSK_TOP_REGS__DATA_WIDTH_DESC_6097DF38_NAME_4609588B__DATA_WIDTH_reset 0x8 + +// Reg - msk_top_regs::prbs_ctrl +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SEL_bm 0x1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SEL_bp 0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SEL_bw 1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SEL_reset 0x0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_ERROR_INSERT_bm 0x2 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_ERROR_INSERT_bp 1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_ERROR_INSERT_bw 1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_ERROR_INSERT_reset 0x0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_CLEAR_bm 0x4 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_CLEAR_bp 2 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_CLEAR_bw 1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_CLEAR_reset 0x0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_MANUAL_SYNC_bm 0x8 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_MANUAL_SYNC_bp 3 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_MANUAL_SYNC_bw 1 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_MANUAL_SYNC_reset 0x0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_RESERVED_bm 0xfff0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_RESERVED_bp 4 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_RESERVED_bw 12 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_RESERVED_reset 0x0 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SYNC_THRESHOLD_bm 0xffff0000 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SYNC_THRESHOLD_bp 16 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SYNC_THRESHOLD_bw 16 +#define MSK_TOP_REGS__PRBS_CTRL__PRBS_SYNC_THRESHOLD_reset 0x0 + +// Reg - msk_top_regs::config_prbs_seed +#define MSK_TOP_REGS__CONFIG_PRBS_SEED__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_PRBS_SEED__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_PRBS_SEED__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_PRBS_SEED__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_prbs_poly +#define MSK_TOP_REGS__CONFIG_PRBS_POLY__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_PRBS_POLY__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_PRBS_POLY__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_PRBS_POLY__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::config_prbs_errmask +#define MSK_TOP_REGS__CONFIG_PRBS_ERRMASK__CONFIG_DATA_bm 0xffffffff +#define MSK_TOP_REGS__CONFIG_PRBS_ERRMASK__CONFIG_DATA_bp 0 +#define MSK_TOP_REGS__CONFIG_PRBS_ERRMASK__CONFIG_DATA_bw 32 +#define MSK_TOP_REGS__CONFIG_PRBS_ERRMASK__CONFIG_DATA_reset 0x0 + +// Reg - msk_top_regs::stat_32_bits +#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_reset 0x0 + +// Reg - msk_top_regs::stat_32_errs +#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_reset 0x0 + +// Reg - msk_top_regs::stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_reset 0x0 + +// Reg - msk_top_regs::stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_reset 0x0 + +// Reg - msk_top_regs::msk_stat_3 +#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bp 0 +#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bw 32 +#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_reset 0x0 + +// Reg - msk_top_regs::rx_sample_discard +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bm 0xff +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bp 0 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bw 8 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_reset 0x0 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bm 0xff00 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bp 8 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_NCO_DISCARD_bw 8 +#define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_NCO_DISCARD_reset 0x0 + +// Reg - msk_top_regs::lpf_config_2 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_GAIN_bm 0xffffff +#define MSK_TOP_REGS__LPF_CONFIG_2__P_GAIN_bp 0 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_GAIN_bw 24 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_GAIN_reset 0x0 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_bm 0xff000000 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_bp 24 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_bw 8 +#define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_0515efaa_desc_ebde6d39_name_2c154788 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_25a21249_desc_417e1c96_name_3b640507 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_272a00b6_desc_70869502_name_3de9a0d3 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_reset 0x0 + +// Reg - msk_top_regs::tx_sync_ctrl +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_ENA_bm 0x1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_ENA_bp 0 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_ENA_bw 1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_ENA_reset 0x0 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_FORCE_bm 0x2 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_FORCE_bp 1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_FORCE_bw 1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_FORCE_reset 0x0 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F1_bm 0x4 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F1_bp 2 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F1_bw 1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F1_reset 0x0 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F2_bm 0x8 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F2_bp 3 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F2_bw 1 +#define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_F2_reset 0x0 + +// Reg - msk_top_regs::tx_sync_cnt +#define MSK_TOP_REGS__TX_SYNC_CNT__TX_SYNC_CNT_bm 0xffffff +#define MSK_TOP_REGS__TX_SYNC_CNT__TX_SYNC_CNT_bp 0 +#define MSK_TOP_REGS__TX_SYNC_CNT__TX_SYNC_CNT_bw 24 +#define MSK_TOP_REGS__TX_SYNC_CNT__TX_SYNC_CNT_reset 0x0 + +// Reg - msk_top_regs::lowpass_ema_alpha +#define MSK_TOP_REGS__LOWPASS_EMA_ALPHA__ALPHA_bm 0x3ffff +#define MSK_TOP_REGS__LOWPASS_EMA_ALPHA__ALPHA_bp 0 +#define MSK_TOP_REGS__LOWPASS_EMA_ALPHA__ALPHA_bw 18 +#define MSK_TOP_REGS__LOWPASS_EMA_ALPHA__ALPHA_reset 0x0 + +// Reg - msk_top_regs::rx_power +#define MSK_TOP_REGS__RX_POWER__RX_POWER_bm 0x7fffff +#define MSK_TOP_REGS__RX_POWER__RX_POWER_bp 0 +#define MSK_TOP_REGS__RX_POWER__RX_POWER_bw 23 +#define MSK_TOP_REGS__RX_POWER__RX_POWER_reset 0x0 + +// Addrmap - msk_top_regs +typedef struct __attribute__ ((__packed__)) { + uint32_t Hash_ID_Low; + uint32_t Hash_ID_High; + uint32_t MSK_Init; + uint32_t MSK_Control; + uint32_t MSK_Status; + uint32_t Tx_Bit_Count; + uint32_t Tx_Enable_Count; + uint32_t Fb_FreqWord; + uint32_t TX_F1_FreqWord; + uint32_t TX_F2_FreqWord; + uint32_t RX_F1_FreqWord; + uint32_t RX_F2_FreqWord; + uint32_t LPF_Config_0; + uint32_t LPF_Config_1; + uint32_t Tx_Data_Width; + uint32_t Rx_Data_Width; + uint32_t PRBS_Control; + uint32_t PRBS_Initial_State; + uint32_t PRBS_Polynomial; + uint32_t PRBS_Error_Mask; + uint32_t PRBS_Bit_Count; + uint32_t PRBS_Error_Count; + uint32_t LPF_Accum_F1; + uint32_t LPF_Accum_F2; + uint32_t axis_xfer_count; + uint32_t Rx_Sample_Discard; + uint32_t LPF_Config_2; + uint32_t f1_nco_adjust; + uint32_t f2_nco_adjust; + uint32_t f1_error; + uint32_t f2_error; + uint32_t Tx_Sync_Ctrl; + uint32_t Tx_Sync_Cnt; + uint32_t lowpass_ema_alpha1; + uint32_t lowpass_ema_alpha2; + uint32_t rx_power; +} msk_top_regs_t; + + +static_assert(sizeof(msk_top_regs_t) == 0x90, "Packing error"); + +#ifdef __cplusplus +} +#endif + +#endif /* MSK_TOP_REGS_H */ diff --git a/rdl/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md similarity index 87% rename from rdl/msk_top_regs.md rename to rdl/outputs/docs/msk_top_regs.md index 79009bc..82c2c8d 100644 --- a/rdl/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -1,24 +1,15 @@ -## Pluto_MSK_Modem address map +## msk_top_regs address map - Absolute Address: 0x0 - Base Offset: 0x0 -- Size: 0x43C00090 - -| Offset | Identifier | Name | -|----------|--------------|-------------------| -|0x43C00000|pluto_msk_regs|Pluto MSK Registers| - -## pluto_msk_regs address map - -- Absolute Address: 0x43C00000 -- Base Offset: 0x43C00000 - Size: 0x90

MSK Modem Configuration and Status Registers

@@ -27,8 +18,8 @@ Don't override. Generated from: Pluto_MSK_Modem |------|------------------|-------------------------------------------------------------| | 0x00 | Hash_ID_Low | Pluto MSK FPGA Hash ID - Lower 32-bits | | 0x04 | Hash_ID_High | Pluto MSK FPGA Hash ID - Upper 32-bits | -| 0x08 | MSK_Init | MSK Modem Control 0 | -| 0x0C | MSK_Control | MSK Modem Control 1 | +| 0x08 | MSK_Init | MSK Modem Initialization Control | +| 0x0C | MSK_Control | MSK Modem Control | | 0x10 | MSK_Status | MSK Modem Status 0 | | 0x14 | Tx_Bit_Count | MSK Modem Status 1 | | 0x18 | Tx_Enable_Count | MSK Modem Status 2 | @@ -64,7 +55,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Hash_ID_Low register -- Absolute Address: 0x43C00000 +- Absolute Address: 0x0 - Base Offset: 0x0 - Size: 0x4 @@ -78,7 +69,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Hash_ID_High register -- Absolute Address: 0x43C00004 +- Absolute Address: 0x4 - Base Offset: 0x4 - Size: 0x4 @@ -92,7 +83,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### MSK_Init register -- Absolute Address: 0x43C00008 +- Absolute Address: 0x8 - Base Offset: 0x8 - Size: 0x4 @@ -121,7 +112,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### MSK_Control register -- Absolute Address: 0x43C0000C +- Absolute Address: 0xC - Base Offset: 0xC - Size: 0x4 @@ -130,7 +121,7 @@ Don't override. Generated from: Pluto_MSK_Modem |Bits| Identifier |Access|Reset| Name | |----|---------------------|------|-----|-----------------------------------------------| | 0 | ptt | rw | 0x0 | Push-to-Talk Enable | -| 1 | loopback_ena | rw | 0x0 | Modem Loopback Enable | +| 1 | loopback_ena | rw | 0x0 | Modem Digital Tx -> Rx Loopback Enable | | 2 | rx_invert | rw | 0x0 | Rx Data Invert Enable | | 3 | clear_counts | rw | 0x0 | Clear Status Counters | | 4 |diff_encoder_loopback| rw | 0x0 |Differential Encoder -> Decoder Loopback Enable| @@ -161,7 +152,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### MSK_Status register -- Absolute Address: 0x43C00010 +- Absolute Address: 0x10 - Base Offset: 0x10 - Size: 0x4 @@ -195,7 +186,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Tx_Bit_Count register -- Absolute Address: 0x43C00014 +- Absolute Address: 0x14 - Base Offset: 0x14 - Size: 0x4 @@ -203,7 +194,7 @@ Don't override. Generated from: Pluto_MSK_Modem |Bits| Identifier |Access|Reset| Name | |----|--------------|------|-----|------------| -|31:0|tx_bit_counter| r | 0x0 |Tx Bit Count| +|31:0|tx_bit_counter| r | — |Tx Bit Count| #### tx_bit_counter field @@ -211,7 +202,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Tx_Enable_Count register -- Absolute Address: 0x43C00018 +- Absolute Address: 0x18 - Base Offset: 0x18 - Size: 0x4 @@ -227,7 +218,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Fb_FreqWord register -- Absolute Address: 0x43C0001C +- Absolute Address: 0x1C - Base Offset: 0x1C - Size: 0x4 @@ -239,11 +230,12 @@ Don't override. Generated from: Pluto_MSK_Modem #### config_data field -

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

### TX_F1_FreqWord register -- Absolute Address: 0x43C00020 +- Absolute Address: 0x20 - Base Offset: 0x20 - Size: 0x4 @@ -255,11 +247,12 @@ Don't override. Generated from: Pluto_MSK_Modem #### config_data field -

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

### TX_F2_FreqWord register -- Absolute Address: 0x43C00024 +- Absolute Address: 0x24 - Base Offset: 0x24 - Size: 0x4 @@ -271,11 +264,12 @@ Don't override. Generated from: Pluto_MSK_Modem #### config_data field -

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

### RX_F1_FreqWord register -- Absolute Address: 0x43C00028 +- Absolute Address: 0x28 - Base Offset: 0x28 - Size: 0x4 @@ -287,11 +281,12 @@ Don't override. Generated from: Pluto_MSK_Modem #### config_data field -

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

### RX_F2_FreqWord register -- Absolute Address: 0x43C0002C +- Absolute Address: 0x2C - Base Offset: 0x2C - Size: 0x4 @@ -303,11 +298,12 @@ Don't override. Generated from: Pluto_MSK_Modem #### config_data field -

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

### LPF_Config_0 register -- Absolute Address: 0x43C00030 +- Absolute Address: 0x30 - Base Offset: 0x30 - Size: 0x4 @@ -317,7 +313,7 @@ Don't override. Generated from: Pluto_MSK_Modem |----|-------------|------|-----|--------------------------------------| | 0 | lpf_freeze | rw | 0x0 |Freeze the accumulator's current value| | 1 | lpf_zero | rw | 0x0 | Hold the PI Accumulator at zero | -| 7:2|prbs_reserved| w | 0x0 | — | +| 7:2|prbs_reserved| rw | 0x0 | Reserved | |31:8| lpf_alpha | rw | 0x0 | Lowpass IIR filter alpha | #### lpf_freeze field @@ -336,7 +332,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### LPF_Config_1 register -- Absolute Address: 0x43C00034 +- Absolute Address: 0x34 - Base Offset: 0x34 - Size: 0x4 @@ -357,7 +353,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Tx_Data_Width register -- Absolute Address: 0x43C00038 +- Absolute Address: 0x38 - Base Offset: 0x38 - Size: 0x4 @@ -373,7 +369,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### Rx_Data_Width register -- Absolute Address: 0x43C0003C +- Absolute Address: 0x3C - Base Offset: 0x3C - Size: 0x4 @@ -389,7 +385,7 @@ Don't override. Generated from: Pluto_MSK_Modem ### PRBS_Control register -- Absolute Address: 0x43C00040 +- Absolute Address: 0x40 - Base Offset: 0x40 - Size: 0x4 @@ -401,8 +397,8 @@ Don't override. Generated from: Pluto_MSK_Modem | 1 | prbs_error_insert | w | 0x0 | PRBS Error Insert | | 2 | prbs_clear | w | 0x0 | PRBS Clear Counters | | 3 | prbs_manual_sync | w | 0x0 | PRBS Manual Sync | -| 15:4| prbs_reserved | w | 0x0 | — | -|31:16|prbs_sync_threshold| w | 0x0 |PRBS Auto Sync Threshold| +| 15:4| prbs_reserved | rw | 0x0 | Reserved | +|31:16|prbs_sync_threshold| rw | 0x0 |PRBS Auto Sync Threshold| #### prbs_sel field @@ -431,7 +427,7 @@ N > 0 : Auto sync after N errors

### PRBS_Initial_State register -- Absolute Address: 0x43C00044 +- Absolute Address: 0x44 - Base Offset: 0x44 - Size: 0x4 @@ -447,7 +443,7 @@ N > 0 : Auto sync after N errors

### PRBS_Polynomial register -- Absolute Address: 0x43C00048 +- Absolute Address: 0x48 - Base Offset: 0x48 - Size: 0x4 @@ -463,7 +459,7 @@ N > 0 : Auto sync after N errors

### PRBS_Error_Mask register -- Absolute Address: 0x43C0004C +- Absolute Address: 0x4C - Base Offset: 0x4C - Size: 0x4 @@ -479,7 +475,7 @@ N > 0 : Auto sync after N errors

### PRBS_Bit_Count register -- Absolute Address: 0x43C00050 +- Absolute Address: 0x50 - Base Offset: 0x50 - Size: 0x4 @@ -496,7 +492,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### PRBS_Error_Count register -- Absolute Address: 0x43C00054 +- Absolute Address: 0x54 - Base Offset: 0x54 - Size: 0x4 @@ -513,7 +509,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### LPF_Accum_F1 register -- Absolute Address: 0x43C00058 +- Absolute Address: 0x58 - Base Offset: 0x58 - Size: 0x4 @@ -529,7 +525,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### LPF_Accum_F2 register -- Absolute Address: 0x43C0005C +- Absolute Address: 0x5C - Base Offset: 0x5C - Size: 0x4 @@ -545,7 +541,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### axis_xfer_count register -- Absolute Address: 0x43C00060 +- Absolute Address: 0x60 - Base Offset: 0x60 - Size: 0x4 @@ -561,7 +557,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### Rx_Sample_Discard register -- Absolute Address: 0x43C00064 +- Absolute Address: 0x64 - Base Offset: 0x64 - Size: 0x4 @@ -582,7 +578,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### LPF_Config_2 register -- Absolute Address: 0x43C00068 +- Absolute Address: 0x68 - Base Offset: 0x68 - Size: 0x4 @@ -603,7 +599,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### f1_nco_adjust register -- Absolute Address: 0x43C0006C +- Absolute Address: 0x6C - Base Offset: 0x6C - Size: 0x4 @@ -619,7 +615,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### f2_nco_adjust register -- Absolute Address: 0x43C00070 +- Absolute Address: 0x70 - Base Offset: 0x70 - Size: 0x4 @@ -635,7 +631,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### f1_error register -- Absolute Address: 0x43C00074 +- Absolute Address: 0x74 - Base Offset: 0x74 - Size: 0x4 @@ -651,7 +647,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### f2_error register -- Absolute Address: 0x43C00078 +- Absolute Address: 0x78 - Base Offset: 0x78 - Size: 0x4 @@ -667,7 +663,7 @@ BER can be calculated as the ratio of received bits to errored-bits

### Tx_Sync_Ctrl register -- Absolute Address: 0x43C0007C +- Absolute Address: 0x7C - Base Offset: 0x7C - Size: 0x4 @@ -706,7 +702,7 @@ Both F1 and F2 can be enabled at the same time

### Tx_Sync_Cnt register -- Absolute Address: 0x43C00080 +- Absolute Address: 0x80 - Base Offset: 0x80 - Size: 0x4 @@ -718,11 +714,13 @@ Both F1 and F2 can be enabled at the same time

#### tx_sync_cnt field -

Value from 0x00_0000 to 0xFF_FFFF. This value represents the number bit-times the synchronization signal should be sent after PTT is asserted.

+

Value from 0x00_0000 to 0xFF_FFFF. +This value represents the number bit-times the synchronization +signal should be sent after PTT is asserted.

### lowpass_ema_alpha1 register -- Absolute Address: 0x43C00084 +- Absolute Address: 0x84 - Base Offset: 0x84 - Size: 0x4 @@ -738,7 +736,7 @@ Both F1 and F2 can be enabled at the same time

### lowpass_ema_alpha2 register -- Absolute Address: 0x43C00088 +- Absolute Address: 0x88 - Base Offset: 0x88 - Size: 0x4 @@ -754,7 +752,7 @@ Both F1 and F2 can be enabled at the same time

### rx_power register -- Absolute Address: 0x43C0008C +- Absolute Address: 0x8C - Base Offset: 0x8C - Size: 0x4 diff --git a/rdl/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf similarity index 60% rename from rdl/msk_top_regs.pdf rename to rdl/outputs/docs/msk_top_regs.pdf index e4168d0f15b62638c9812e54a8f3d6db62257574..59a0dda50a5bcf17e93d29e926658db1bd86b449 100644 GIT binary patch delta 44201 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 AssI20 diff --git a/rdl/outputs/python/msk_top_regs/__init__.py b/rdl/outputs/python/msk_top_regs/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/__init__.py @@ -0,0 +1 @@ +pass diff --git a/rdl/outputs/python/msk_top_regs/example.py b/rdl/outputs/python/msk_top_regs/example.py new file mode 100644 index 0000000..80db74d --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/example.py @@ -0,0 +1,13 @@ + +from .lib import AsyncCallbackSet + +from .reg_model.msk_top_regs import msk_top_regs_cls +from .sim.msk_top_regs import msk_top_regs_simulator_cls + +if __name__ == '__main__': + + sim = msk_top_regs_simulator_cls(address=0) + + # create an instance of the class + reg_model = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=sim.read, + write_callback=sim.write)) \ No newline at end of file diff --git a/rdl/outputs/python/msk_top_regs/lib/__init__.py b/rdl/outputs/python/msk_top_regs/lib/__init__.py new file mode 100644 index 0000000..fc1b286 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/__init__.py @@ -0,0 +1,114 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This package is intended to distributed as part of automatically generated code by the PeakRDL +Python tool. It provides a set of classes used by the autogenerated code +""" + +from .callbacks import ReadCallback +from .callbacks import ReadBlockCallback +from .callbacks import WriteCallback +from .callbacks import WriteBlockCallback +from .callbacks import NormalCallbackSet, NormalCallbackSetLegacy +from .callbacks import AsyncCallbackSet, AsyncCallbackSetLegacy +from .callbacks import CallbackSet + +from .base import AddressMap +from .base import RegFile +from .base import AddressMapArray +from .base import RegFileArray + +from .base import AsyncAddressMap +from .base import AsyncRegFile +from .base import AsyncAddressMapArray +from .base import AsyncRegFileArray + +from .register_and_field import Reg +from .register_and_field import RegArray +from .register_and_field import RegisterWriteVerifyError + +from .register_and_field import RegReadOnly +from .register_and_field import RegWriteOnly +from .register_and_field import RegReadWrite +from .register_and_field import WritableRegister +from .register_and_field import ReadableRegister + +from .register_and_field import RegReadOnlyArray +from .register_and_field import RegWriteOnlyArray +from .register_and_field import RegReadWriteArray +from .register_and_field import ReadableRegisterArray +from .register_and_field import WriteableRegisterArray + +from .async_register_and_field import AsyncReg +from .async_register_and_field import AsyncRegArray +from .async_register_and_field import RegAsyncReadOnly +from .async_register_and_field import RegAsyncWriteOnly +from .async_register_and_field import RegAsyncReadWrite +from .async_register_and_field import ReadableAsyncRegister +from .async_register_and_field import WritableAsyncRegister +from .async_register_and_field import RegAsyncReadOnlyArray +from .async_register_and_field import RegAsyncWriteOnlyArray +from .async_register_and_field import RegAsyncReadWriteArray +from .async_register_and_field import ReadableAsyncRegisterArray +from .async_register_and_field import WriteableAsyncRegisterArray + +from .base_field import FieldSizeProps +from .base_field import FieldMiscProps +from .register_and_field import FieldReadOnly +from .register_and_field import FieldWriteOnly +from .register_and_field import FieldReadWrite +from .base_field import Field +from .register_and_field import FieldEnumReadOnly +from .register_and_field import FieldEnumWriteOnly +from .register_and_field import FieldEnumReadWrite +from .base_field import FieldEnum +from .field_encoding import SystemRDLEnum, SystemRDLEnumEntry +from .field_encoding import RegisterFieldJSONEncoder + +from .async_register_and_field import FieldAsyncReadOnly +from .async_register_and_field import FieldAsyncWriteOnly +from .async_register_and_field import FieldAsyncReadWrite +from .async_register_and_field import FieldEnumAsyncReadOnly +from .async_register_and_field import FieldEnumAsyncWriteOnly +from .async_register_and_field import FieldEnumAsyncReadWrite + +from .memory import MemoryReadOnly, MemoryReadOnlyLegacy +from .memory import MemoryWriteOnly, MemoryWriteOnlyLegacy +from .memory import MemoryReadWrite, MemoryReadWriteLegacy +from .memory import MemoryReadOnlyArray +from .memory import MemoryWriteOnlyArray +from .memory import MemoryReadWriteArray +from .async_memory import MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy +from .async_memory import MemoryAsyncWriteOnly, MemoryAsyncWriteOnlyLegacy +from .async_memory import MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy +from .async_memory import MemoryAsyncReadOnlyArray +from .async_memory import MemoryAsyncWriteOnlyArray +from .async_memory import MemoryAsyncReadWriteArray +from .memory import ReadableMemory, ReadableMemoryLegacy +from .memory import WritableMemory, WritableMemoryLegacy +from .memory import Memory +from .async_memory import ReadableAsyncMemory, ReadableAsyncMemoryLegacy +from .async_memory import WritableAsyncMemory, WritableAsyncMemoryLegacy +from .async_memory import AsyncMemory +from .memory import MemoryArray +from .async_memory import AsyncMemoryArray + +from .utility_functions import get_array_typecode +from .utility_functions import UnsupportedWidthError +from .base import Node +from .base import Base +from .base import UDPStruct diff --git a/rdl/outputs/python/msk_top_regs/lib/async_memory.py b/rdl/outputs/python/msk_top_regs/lib/async_memory.py new file mode 100644 index 0000000..427a3cb --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/async_memory.py @@ -0,0 +1,626 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of classes used by the autogenerated code to represent +memories +""" +from array import array as Array +from typing import Union, TYPE_CHECKING +from abc import ABC, abstractmethod +from collections.abc import Iterator +import sys + +from .base import AsyncAddressMap, NodeArray +from .memory import BaseMemory + +from .callbacks import AsyncCallbackSet, AsyncCallbackSetLegacy + +# same bit of code exists in base so flags as duplicate +# pylint: disable=duplicate-code +if sys.version_info >= (3, 10): + # type guarding was introduced in python 3.10 + from typing import TypeGuard +else: + from typing_extensions import TypeGuard +# pylint: enable=duplicate-code + + +if TYPE_CHECKING: + from .async_register_and_field import AsyncReg, AsyncRegArray + from .async_register_and_field import ReadableAsyncRegister, WritableAsyncRegister + from .async_register_and_field import ReadableAsyncRegisterArray, WriteableAsyncRegisterArray +# pylint: disable=duplicate-code + + +class AsyncMemory(BaseMemory, ABC): + """ + base class of non_async memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, 'AsyncMemoryArray']): + """ + Initialise the class + + Args: + address: address of the register + width: width of the register in bits + logger_handle: name to be used logging messages associate with thisobject + """ + if not isinstance(parent, (AsyncAddressMap, + MemoryAsyncWriteOnlyArray, MemoryAsyncReadOnlyArray, + MemoryAsyncReadWriteArray)): + raise TypeError(f'parent should be either AddressMap or Memory Array got ' + f'{type(parent)}') + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + width=width, + accesswidth=accesswidth, + entries=entries, + parent=parent) + + @abstractmethod + def get_registers(self, unroll: bool = False) -> \ + Iterator[Union['AsyncReg', 'AsyncRegArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + + +class _MemoryAsyncReadOnly(AsyncMemory, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, 'AsyncMemoryArray']): + + if not isinstance(parent, (AsyncAddressMap, MemoryAsyncWriteOnlyArray, + MemoryAsyncReadOnlyArray, MemoryAsyncReadWriteArray)): + raise TypeError('parent should be either AddressMap or Memory Array ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + entries=entries, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # pylint: enable=too-many-arguments + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + async def _read(self, start_entry: int, number_entries: int) -> list[int]: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if not isinstance(number_entries, int): + raise TypeError(f'number_entries should be an int got {type(number_entries)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if number_entries not in range(0, self.entries - start_entry + 1): + raise ValueError(f'number_entries must be in range 0 to' + f' {self.entries - start_entry:d} but got {number_entries:d}') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + addr = self.address_lookup(entry=start_entry) + data_read = \ + await read_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + length=number_entries) + + if isinstance(self._callbacks, AsyncCallbackSet): + if not isinstance(data_read, list): + raise TypeError('The read block callback is expected to return an List') + return data_read + + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + return data_read.tolist() + + raise RuntimeError(f'There is no usable callback block callback:{read_block_callback}') + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_read = [0 for _ in range(number_entries)] + + for entry in range(number_entries): + entry_address = self.address_lookup(entry=start_entry+entry) + + data_entry = await read_callback(addr=entry_address, + width=self.width, + accesswidth=self.width) + + data_read[entry] = data_entry + + return data_read + + raise RuntimeError(f'There is no usable callback, ' + f'block callback:{read_block_callback}, ' + f'normal callback:{read_callback}') + + async def _read_legacy(self, start_entry: int, number_entries: int) -> Array: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if not isinstance(number_entries, int): + raise TypeError(f'number_entries should be an int got {type(number_entries)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if number_entries not in range(0, self.entries - start_entry + 1): + raise ValueError(f'number_entries must be in range 0 to' + f' {self.entries - start_entry:d} but got {number_entries:d}') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + addr = self.address_lookup(entry=start_entry) + data_read = \ + await read_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + length=number_entries) + + if isinstance(self._callbacks, AsyncCallbackSet): + if not isinstance(data_read, list): + raise TypeError('The read block callback is expected to return an List') + return Array(self.array_typecode, data_read) + + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + return data_read + + raise RuntimeError(f'There is no usable callback block callback:{read_block_callback}') + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_read_block = Array(self.array_typecode, [0 for _ in range(number_entries)]) + + for entry in range(number_entries): + entry_address = self.address_lookup(entry=start_entry + entry) + data_entry = await read_callback(addr=entry_address, + width=self.width, + accesswidth=self.width) + + data_read_block[entry] = data_entry + + return data_read_block + + raise RuntimeError(f'There is no usable callback, ' + f'block callback:{read_block_callback}, ' + f'normal callback:{read_callback}') + + def get_readable_registers(self, unroll: bool = False) -> \ + Iterator[Union['ReadableAsyncRegister', 'ReadableAsyncRegisterArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_readable(item: Union['AsyncReg', 'AsyncRegArray']) -> \ + TypeGuard[Union['ReadableAsyncRegister', 'ReadableAsyncRegisterArray']]: + # pylint: disable-next=protected-access + return item._is_readable + + return filter(is_readable, self.get_registers(unroll=unroll)) + + +class MemoryAsyncReadOnly(_MemoryAsyncReadOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + async def read(self, start_entry: int, number_entries: int) -> list[int]: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + return await self._read(start_entry=start_entry, number_entries=number_entries) + + +class MemoryAsyncReadOnlyLegacy(_MemoryAsyncReadOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + async def read(self, start_entry: int, number_entries: int) -> Array: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + return await self._read_legacy(start_entry=start_entry, number_entries=number_entries) + + +class _MemoryAsyncWriteOnly(AsyncMemory, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, 'AsyncMemoryArray']): + + if not isinstance(parent, (AsyncAddressMap, MemoryAsyncWriteOnlyArray, + MemoryAsyncReadOnlyArray, MemoryAsyncReadWriteArray)): + raise TypeError('parent should be either AddressMap or Memory Array ' + f'got {type(parent)}') + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + entries=entries, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # pylint: enable=too-many-arguments + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + async def _write(self, start_entry: int, data: Union[Array, list[int]]) -> None: + """ + Asynchronously write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + # pylint:disable=too-many-branches + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if not isinstance(data, (list, Array)): + raise TypeError(f'data should be an array.array got {type(data)}') + + if len(data) not in range(0, self.entries - start_entry + 1): + raise ValueError(f'data length must be in range 0 to {self.entries - start_entry:d} ' + f'but got {len(data):d}') + + if self._callbacks.write_block_callback is not None: + + addr = self.address_lookup(entry=start_entry) + if isinstance(self._callbacks, AsyncCallbackSet): + if isinstance(data, Array): + await self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data.tolist()) + else: + await self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data) + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + if isinstance(data, list): + # need to convert the data to an array before calling + await self._callbacks.write_block_callback( + addr=addr, + width=self.width, + accesswidth=self.width, + data=Array(self.array_typecode, data)) + else: + await self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data) + + elif self._callbacks.write_callback is not None: + # there is not write_block_callback defined so we must used individual write + for entry_index, entry_data in enumerate(data): + entry_address = self.address_lookup(entry=start_entry+entry_index) + await self._callbacks.write_callback(addr=entry_address, + width=self.width, + accesswidth=self.width, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + def get_writable_registers(self, unroll: bool = False) -> \ + Iterator[Union['WritableAsyncRegister', 'WriteableAsyncRegisterArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_writable(item: Union['AsyncReg', 'AsyncRegArray']) -> \ + TypeGuard[Union['WritableAsyncRegister', 'WriteableAsyncRegisterArray']]: + # pylint: disable-next=protected-access + return item._is_writeable + + return filter(is_writable, self.get_registers(unroll=unroll)) + + +class MemoryAsyncWriteOnly(_MemoryAsyncWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + async def write(self, start_entry: int, data: list[int]) -> None: + """ + Asynchronously write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + if not isinstance(data, list): + raise TypeError(f'data should be an List got {type(data)}') + return await self._write(start_entry=start_entry, data=data) + + +class MemoryAsyncWriteOnlyLegacy(_MemoryAsyncWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + async def write(self, start_entry: int, data: Array) -> None: + """ + Asynchronously write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + if not isinstance(data, Array): + raise TypeError(f'data should be an Array {type(data)}') + return await self._write(start_entry=start_entry, data=data) + + +class MemoryAsyncReadWrite(MemoryAsyncReadOnly, MemoryAsyncWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + +class MemoryAsyncReadWriteLegacy(MemoryAsyncReadOnlyLegacy, MemoryAsyncWriteOnlyLegacy, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + +class MemoryAsyncReadOnlyArray(NodeArray, ABC): + """ + base class for a array of asynchronous read only memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AsyncAddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + if not isinstance(parent, AsyncAddressMap): + raise TypeError(f'parent should be either AsyncAddressMap got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class MemoryAsyncWriteOnlyArray(NodeArray, ABC): + """ + base class for a array of asynchronous write only memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AsyncAddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + if not isinstance(parent, AsyncAddressMap): + raise TypeError(f'parent should be either AsyncAddressMap got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class MemoryAsyncReadWriteArray(MemoryAsyncReadOnlyArray, MemoryAsyncWriteOnlyArray, ABC): + """ + base class for a array of asynchronous read and write memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AsyncAddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + if not isinstance(parent, AsyncAddressMap): + raise TypeError(f'parent should be either AsyncAddressMap got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +ReadableAsyncMemory = Union[MemoryAsyncReadOnly, MemoryAsyncReadWrite] +WritableAsyncMemory = Union[MemoryAsyncWriteOnly, MemoryAsyncReadWrite] +ReadableAsyncMemoryLegacy = Union[MemoryAsyncReadOnlyLegacy, MemoryAsyncReadWriteLegacy] +WritableAsyncMemoryLegacy = Union[MemoryAsyncWriteOnlyLegacy, MemoryAsyncReadWriteLegacy] +AsyncMemoryArray = Union[MemoryAsyncReadOnlyArray, MemoryAsyncWriteOnlyArray, + MemoryAsyncReadWriteArray] diff --git a/rdl/outputs/python/msk_top_regs/lib/async_register_and_field.py b/rdl/outputs/python/msk_top_regs/lib/async_register_and_field.py new file mode 100644 index 0000000..cf5bed3 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/async_register_and_field.py @@ -0,0 +1,1230 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of classes used by the autogenerated code to represent +asynchronous registers and fields +""" +from enum import Enum +from typing import Union, Optional, TypeVar, cast +from collections.abc import AsyncGenerator, Iterator +from abc import ABC, abstractmethod +from contextlib import asynccontextmanager +from array import array as Array +import sys +from warnings import warn + +from .utility_functions import get_array_typecode +from .base import AsyncAddressMap, AsyncRegFile +from .async_memory import MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite, \ + AsyncMemory, ReadableAsyncMemory, WritableAsyncMemory +from .async_memory import MemoryAsyncReadOnlyLegacy, MemoryAsyncWriteOnlyLegacy, \ + MemoryAsyncReadWriteLegacy +from .async_memory import ReadableAsyncMemoryLegacy, WritableAsyncMemoryLegacy +from .callbacks import AsyncCallbackSet, AsyncCallbackSetLegacy +from .base_register import BaseReg, BaseRegArray, RegisterWriteVerifyError +from .base_field import FieldEnum, FieldSizeProps, FieldMiscProps, \ + _FieldReadOnlyFramework, _FieldWriteOnlyFramework, FieldType + +# pylint: disable=duplicate-code +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self +# pylint: enable=duplicate-code + +# pylint: disable=duplicate-code +if sys.version_info >= (3, 10): + # type guarding was introduced in python 3.10 + from typing import TypeGuard +else: + from typing_extensions import TypeGuard +# pylint: enable=duplicate-code + +# pylint: disable=redefined-slots-in-subclass,too-many-lines + + +class AsyncReg(BaseReg, ABC): + """ + base class of async register wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile, AsyncMemory, 'AsyncRegArray']): + + if not isinstance(parent, (AsyncAddressMap, AsyncRegFile, + MemoryAsyncReadOnly, MemoryAsyncWriteOnly, + MemoryAsyncReadWrite, AsyncRegArray, MemoryAsyncReadOnlyLegacy, + MemoryAsyncWriteOnlyLegacy, + MemoryAsyncReadWriteLegacy)): + raise TypeError(f'bad parent type got: {type(parent)}') + + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, width=width, accesswidth=accesswidth, + logger_handle=logger_handle, inst_name=inst_name, parent=parent) + + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + @property + @abstractmethod + def fields(self) -> \ + Iterator[Union['FieldAsyncReadOnly', 'FieldAsyncWriteOnly', 'FieldAsyncReadWrite']]: + """ + generator that produces has all the fields within the register + """ + + +class RegAsyncReadOnly(AsyncReg, ABC): + """ + class for an async read only register + + Args: + address: address of the register + width: width of the register in bits + accesswidth: minimum access width of the register in bits + logger_handle: name to be used logging messages associate with this + object + + """ + + __slots__: list[str] = ['__in_context_manager', '__register_state'] + + # pylint: disable=too-many-arguments, duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile, ReadableAsyncMemory, + ReadableAsyncMemoryLegacy]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + + self.__in_context_manager: bool = False + self.__register_state: int = 0 + # pylint: enable=too-many-arguments, duplicate-code + + @asynccontextmanager + async def single_read(self) -> AsyncGenerator[Self]: + """ + Context manager to allow multiple field accesses to be performed with a single + read of the register + """ + self.__register_state = await self.read() + # pylint: disable=duplicate-code + self.__in_context_manager = True + # this try/finally is needed to make sure that in the event of an exception + # the state flags are not left incorrectly set + try: + yield self + finally: + self.__in_context_manager = False + + async def read(self) -> int: + """Asynchronously read value from the register + + Returns: + The value from register + + """ + # pylint: disable=duplicate-code + if self.__in_context_manager: + return self.__register_state + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + # pylint: enable=duplicate-code + + if read_callback is not None: + + return await read_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth) + + if read_block_callback is not None: + array_read_result = \ + await read_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + length=1) + return array_read_result[0] + + raise RuntimeError('This function does not have a useable callback') + + @property + def readable_fields(self) -> Iterator[Union['FieldAsyncReadOnly', 'FieldAsyncReadWrite']]: + """ + generator that produces has all the readable fields within the register + """ + def is_readable(field: Union['FieldAsyncReadOnly', + 'FieldAsyncWriteOnly', + 'FieldAsyncReadWrite']) -> \ + TypeGuard[Union['FieldAsyncReadOnly', 'FieldAsyncReadWrite']]: + return isinstance(field, (FieldAsyncReadOnly, FieldAsyncReadWrite)) + + return filter(is_readable, self.fields) + + async def read_fields(self) -> dict['str', Union[bool, Enum, int]]: + """ + asynchronously read the register and return a dictionary of the field values + """ + return_dict: dict['str', Union[bool, Enum, int]] = {} + async with self.single_read() as reg: + for field in reg.readable_fields: + return_dict[field.inst_name] = await field.read() + + return return_dict + + @property + def _is_readable(self) -> bool: + return True + + @property + def _is_writeable(self) -> bool: + return False + + +class RegAsyncWriteOnly(AsyncReg, ABC): + """ + class for an asynchronous write only register + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments, duplicate-code, useless-parent-delegation + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile, + WritableAsyncMemory, WritableAsyncMemoryLegacy]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + # pylint: enable=too-many-arguments, duplicate-code + + async def write(self, data: int) -> None: + """Asynchronously writes a value to the register + + Args: + data: data to be written + + Raises: + ValueError: if the value provided is outside the range of the + permissible values for the register + TypeError: if the type of data is wrong + """ + + # this method check the types and range checks the data + self._validate_data(data=data) + + # pylint: disable=duplicate-code + self._logger.info('Writing data:%X to %X', data, self.address) + # pylint: enable=duplicate-code + + if self._callbacks.write_callback is not None: + + await self._callbacks.write_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=data) + + elif self._callbacks.write_block_callback is not None: + + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + data_as_array = Array(get_array_typecode(self.width), [data]) + await self._callbacks.write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=data_as_array) + + if isinstance(self._callbacks, AsyncCallbackSet): + await self._callbacks.write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=[data]) + + else: + # pylint: disable-next=duplicate-code + raise RuntimeError('This function does not have a useable callback') + + @property + def writable_fields(self) -> Iterator[Union['FieldAsyncWriteOnly', 'FieldAsyncReadWrite']]: + """ + generator that produces has all the writable fields within the register + """ + def is_writable(field: Union['FieldAsyncReadOnly', + 'FieldAsyncWriteOnly', + 'FieldAsyncReadWrite']) -> \ + TypeGuard[Union['FieldAsyncWriteOnly', 'FieldAsyncReadWrite']]: + return isinstance(field, (FieldAsyncWriteOnly, FieldAsyncReadWrite)) + + return filter(is_writable, self.fields) + + @abstractmethod + async def write_fields(self, **kwargs) -> None: # type: ignore[no-untyped-def] + """ + Do an async write to the register, updating any field included in + the arguments + """ + + @property + def _is_readable(self) -> bool: + return False + + @property + def _is_writeable(self) -> bool: + return True + + +class RegAsyncReadWrite(RegAsyncReadOnly, RegAsyncWriteOnly, ABC): + """ + class for an async read and write only register + + """ + __slots__: list[str] = ['__in_read_write_context_manager', '__in_read_context_manager', + '__register_state'] + + # pylint: disable=too-many-arguments, duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile, MemoryAsyncReadWrite, + MemoryAsyncReadWriteLegacy]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + + self.__in_read_write_context_manager: bool = False + self.__in_read_context_manager: bool = False + self.__register_state: Optional[int] = None + + # pylint: enable=too-many-arguments, duplicate-code + + @asynccontextmanager + async def single_read_modify_write(self, verify: bool = False, skip_write: bool = False) -> \ + AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + + """ + # pylint: disable=duplicate-code + if self.__in_read_context_manager: + raise RuntimeError('using the `single_read_modify_write` context manager within the ' + 'single_read` is not permitted') + + if skip_write is True: + warn('The `skip_write` argument will be removed in the future, use `single_read`' + ' instead', + DeprecationWarning, stacklevel=2) + # pylint: enable=duplicate-code + + self.__register_state = await self.read() + + # pylint: disable=duplicate-code + self.__in_read_write_context_manager = True + # this try/finally is needed to make sure that in the event of an exception + # the state flags are not left incorrectly set + try: + yield self + finally: + self.__in_read_write_context_manager = False + # pylint: enable=duplicate-code + if not skip_write: + await self.write(self.__register_state, verify) + + # clear the register states at the end of the context manager + self.__register_state = None + + @asynccontextmanager + async def single_read(self) -> \ + AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads with a single register read + """ + # pylint: disable=duplicate-code + if self.__in_read_write_context_manager: + raise RuntimeError('using the `single_read` context manager within the ' + 'single_read_modify_write` is not permitted') + self.__in_read_context_manager = True + # pylint: enable=duplicate-code + try: + async with super().single_read() as reg: + yield reg + finally: + # pylint: disable=duplicate-code + self.__in_read_context_manager = False + + async def write(self, data: int, verify: bool = False) -> None: + """ + Writes a value to the register + + Args: + data: data to be written + verify: set to True to read back the register to verify the read has occurred correctly + + Raises: + ValueError: if the value provided is outside the range of the + permissible values for the register + TypeError: if the type of data is wrong + RegisterWriteVerifyError: the read back data after the write does not match the + expected value + """ + if self.__in_read_context_manager: + # pylint: disable=duplicate-code + raise RuntimeError('writes within the single read context manager are not permitted') + + if self.__in_read_write_context_manager: + # pylint: disable=duplicate-code + if self.__register_state is None: + raise RuntimeError('The internal register state should never be None in the ' + 'context manager') + self.__register_state = data + else: + await super().write(data) + if verify: + read_back = await self.read() + if read_back != data: + raise RegisterWriteVerifyError(f'Readback {read_back:X} ' + f'after writing {data:X}') + + async def read(self) -> int: + """ + Asynchronously read value from the register + """ + if self.__in_read_write_context_manager: + # pylint: disable=duplicate-code + if self.__register_state is None: + raise RuntimeError('The internal register state should never be None in the ' + 'context manager') + return self.__register_state + + # the single read context manager is handled in the base class so does need any + # handling here + + return await super().read() + + async def read_fields(self) -> dict['str', Union[bool, Enum, int]]: + """ + asynchronously read the register and return a dictionary of the field values + """ + return_dict: dict['str', Union[bool, Enum, int]] = {} + async with self.single_read() as reg: + for field in reg.readable_fields: + return_dict[field.inst_name] = await field.read() + + return return_dict + + async def write_fields(self, **kwargs) -> None: # type: ignore[no-untyped-def] + """ + asynchronously read-modify-write to the register, updating any field included in + the arguments + """ + if len(kwargs) == 0: + raise ValueError('no command args') + + async with self.single_read_modify_write() as reg: + for field_name, field_value in kwargs.items(): + if field_name not in reg.systemrdl_python_child_name_map.values(): + raise ValueError(f'{field_name} is not a member of the register') + + field = getattr(reg, field_name) + await field.write(field_value) + + @property + def _is_readable(self) -> bool: + return True + + @property + def _is_writeable(self) -> bool: + return True + + +ReadableAsyncRegister = Union[RegAsyncReadOnly, RegAsyncReadWrite] +WritableAsyncRegister = Union[RegAsyncWriteOnly, RegAsyncReadWrite] + + +# pylint: disable-next=invalid-name +AsyncRegArrayElementType= TypeVar('AsyncRegArrayElementType', bound=AsyncReg) + + +class AsyncRegArray(BaseRegArray, ABC): + """ + base class of register array wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + # pylint: disable=too-many-arguments,duplicate-code + + __slots__: list[str] = ['__in_context_manager', '__register_cache', + '__register_address_array'] + + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile, AsyncMemory], + width: int, + accesswidth: int, + address: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], AsyncRegArrayElementType]] = None): + + self.__in_context_manager: bool = False + self.__register_cache: Optional[Union[Array, list[int]]] = None + self.__register_address_array: Optional[list[int]] = None + + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + + @property + def __empty_array_cache(self) -> Array: + return Array(get_array_typecode(self.width), self.__empty_list_cache) + + @property + def __empty_list_cache(self) -> list[int]: + return [0 for _ in range(self.__number_cache_entries)] + + async def __block_read_legacy(self) -> Array: + """ + Read all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, AsyncCallbackSetLegacy): + raise RuntimeError('This function should only be used with legacy callbacks') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + + data_read = await read_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + length=self.__number_cache_entries) + + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + + return data_read + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_array = self.__empty_array_cache + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry, address in enumerate(self.__register_address_array): + data_entry = await read_callback(addr=address, + width=self.width, + accesswidth=self.accesswidth) + + data_array[entry] = data_entry + + return data_array + + raise RuntimeError('There is no usable callback') + + async def __block_write_legacy(self, data: Array, verify: bool) -> None: + """ + Write all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, AsyncCallbackSetLegacy): + raise RuntimeError('This function should only be used with legacy callbacks') + + write_block_callback = self._callbacks.write_block_callback + write_callback = self._callbacks.write_callback + + if write_block_callback is not None: + await write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.width, + data=data) + + elif write_callback is not None: + # there is not write_block_callback defined so we must used individual write + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry_index, entry_data in enumerate(data): + entry_address = self.__register_address_array[entry_index] + await write_callback(addr=entry_address, + width=self.width, + accesswidth=self.accesswidth, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + if verify: + read_back_verify_data = self.__block_read_legacy() + if read_back_verify_data != data: + raise RegisterWriteVerifyError('Read back block miss-match') + + async def __block_read(self) -> list[int]: + """ + Read all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, AsyncCallbackSet): + raise RuntimeError('This function should only be used with non-legacy callbacks') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + data_read = \ + await read_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + length=self.__number_cache_entries) + + + if not isinstance(data_read, list): + raise TypeError('The read block callback is expected to return an array') + + return data_read + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_list = self.__empty_list_cache + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry, address in enumerate(self.__register_address_array): + data = await read_callback(addr=address, + width=self.width, + accesswidth=self.accesswidth) + + data_list[entry] = data + + return data_list + + raise RuntimeError('There is no usable callback') + + async def __block_write(self, data: list[int], verify: bool) -> None: + """ + Write all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, AsyncCallbackSet): + raise RuntimeError('This function should only be used with non-legacy callbacks') + + write_block_callback = self._callbacks.write_block_callback + write_callback = self._callbacks.write_callback + + if write_block_callback is not None: + await write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.width, + data=data) + elif write_callback is not None: + # there is not write_block_callback defined so we must used individual write + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry_index, entry_data in enumerate(data): + entry_address = self.__register_address_array[entry_index] + await write_callback(addr=entry_address, + width=self.width, + accesswidth=self.accesswidth, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + if verify: + read_back_verify_data = self.__block_read() + if read_back_verify_data != data: + raise RegisterWriteVerifyError('Read back block miss-match') + + def __cache_entry(self, addr: int, width: int, accesswidth: int) -> int: + """ + Validate the data provided and determine the cache entry + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + cache entry + + """ + if not isinstance(width, int): + raise TypeError(f'Width should be an int byt got {type(width)}') + if width != self.width: + raise ValueError('Requested Read width does not match the expected value') + if not isinstance(accesswidth, int): + raise TypeError(f'accesswidth should be an int byt got {type(accesswidth)}') + if accesswidth != self.accesswidth: + raise ValueError('Requested Read accesswidth does not match the expected value') + if not isinstance(addr, int): + raise TypeError(f'addr should be an int byt got {type(addr)}') + if not self.address <= addr < (self.address + self.size): + raise ValueError(f'Requested address 0x{addr:X} is out of range 0x{self.address:X} to ' + f'0x{self.address + self.size - (self.width >> 3):X}') + cache_entry = (addr - self.address) // (self.width >> 3) + if self.__register_address_array is None: + raise RuntimeError('The address table should always be populated here') + if self.__register_address_array[cache_entry] != addr: + raise RuntimeError(f'The calculated cache entry for address 0x{addr:X}') + return cache_entry + + async def __cache_read(self, addr: int, width: int, accesswidth: int) -> int: + """ + Used to replace the normal callbacks with those that access the cache + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + value inputted by the used + """ + if self.__register_cache is None: + raise RuntimeError('The cache array should be initialised') + return self.__register_cache[self.__cache_entry(addr=addr, + width=width, + accesswidth=accesswidth)] + + async def __cache_write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + Used to replace the normal callbacks with those that access the cache + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: value to be written to the register + + Returns: + None + """ + if not isinstance(data, int): + raise TypeError(f'Data should be an int byt got {type(data)}') + if self.__register_cache is None: + raise RuntimeError('The cache array should be initialised') + self.__register_cache[self.__cache_entry(addr=addr, + width=width, + accesswidth=accesswidth)] = data + + @property + def __cache_callbacks(self) -> AsyncCallbackSet: + return AsyncCallbackSet(read_callback=self.__cache_read, + write_callback=self.__cache_write) + + @property + def __number_cache_entries(self) -> int: + return self.size // (self.width >> 3) + + async def __initialise_cache(self, skip_initial_read: bool) -> Union[Array, list[int]]: + if isinstance(self._callbacks, AsyncCallbackSet): + if skip_initial_read: + return self.__empty_list_cache + return await self.__block_read() + + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + if skip_initial_read: + return self.__empty_array_cache + return await self.__block_read_legacy() + + raise TypeError('Unhandled callback type') + + @asynccontextmanager + async def _cached_access(self, verify: bool = False, skip_write: bool = False, + skip_initial_read: bool = False) -> \ + AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + + """ + self.__register_address_array = \ + [self.address + (i * (self.width >> 3)) for i in range(self.__number_cache_entries)] + self.__register_cache = await self.__initialise_cache(skip_initial_read=skip_initial_read) + self.__in_context_manager = True + # this try/finally is needed to make sure that in the event of an exception + # the state flags are not left incorrectly set + try: + yield self + finally: + self.__in_context_manager = False + if not skip_write: + if isinstance(self._callbacks, AsyncCallbackSet): + if not isinstance(self.__register_cache, list): + raise TypeError('Register cache should be a list in non-legacy mode') + await self.__block_write(self.__register_cache, verify) + if isinstance(self._callbacks, AsyncCallbackSetLegacy): + if not isinstance(self.__register_cache, Array): + raise TypeError('Register cache should be a Array in legacy mode') + await self.__block_write_legacy(self.__register_cache, verify) + + # clear the register states at the end of the context manager + self.__register_address_array = None + self.__register_cache = None + + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.__in_context_manager: + return self.__cache_callbacks + + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + +class RegAsyncReadOnlyArray(AsyncRegArray, ABC): + """ + base class for a array of async read only registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AsyncRegFile, AsyncAddressMap, ReadableAsyncMemory, + ReadableAsyncMemoryLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegAsyncReadOnly]] = None): + + if not isinstance(parent, (AsyncRegFile, AsyncAddressMap, + MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy, + MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy)): + raise TypeError('parent should be either AsyncRegFile, AsyncAddressMap, ' + 'MemoryAsyncReadOnly, MemoryAsyncReadWrite ' + f'got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + # pylint: enable=too-many-arguments,duplicate-code + + @asynccontextmanager + async def single_read(self) -> AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + + + Returns: + + """ + async with self._cached_access(verify=False, skip_write=True, + skip_initial_read=False) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + return True + + @property + def _is_writeable(self) -> bool: + return False + + +class RegAsyncWriteOnlyArray(AsyncRegArray, ABC): + """ + base class for a array of async write only registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AsyncRegFile, AsyncAddressMap, + WritableAsyncMemory, WritableAsyncMemoryLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegAsyncWriteOnly]] = None): + + if not isinstance(parent, (AsyncRegFile, AsyncAddressMap, + MemoryAsyncWriteOnly, MemoryAsyncReadWrite, + MemoryAsyncWriteOnlyLegacy, MemoryAsyncReadWriteLegacy)): + raise TypeError('parent should be either AsyncRegFile, AsyncAddressMap, ' + 'MemoryAsyncWriteOnly, MemoryAsyncReadWrite ' + f'got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + # pylint: enable=too-many-arguments,duplicate-code + + @asynccontextmanager + async def single_write(self) -> AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + + + Returns: + + """ + async with self._cached_access(verify=False, skip_write=False, + skip_initial_read=True) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + return False + + @property + def _is_writeable(self) -> bool: + return True + + +class RegAsyncReadWriteArray(AsyncRegArray, ABC): + """ + base class for a array of read and write registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AsyncRegFile, AsyncAddressMap, + MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegAsyncReadWrite]] = None): + + if not isinstance(parent, (AsyncRegFile, AsyncAddressMap, + MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy)): + raise TypeError('parent should be either AsyncRegFile, AsyncAddressMap, ' + 'MemoryAsyncReadWrite ' + f'got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + # pylint: enable=too-many-arguments,duplicate-code + + @asynccontextmanager + async def single_read_modify_write(self, verify: bool = False, skip_write: bool = False) -> \ + AsyncGenerator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + + Returns: + + """ + if skip_write is True: + warn('The `skip_write` argument will be removed in the future, use `single_read`' + ' instead', + DeprecationWarning, stacklevel=2) + + async with self._cached_access(verify=verify, skip_write=skip_write, + skip_initial_read=False) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + return True + + @property + def _is_writeable(self) -> bool: + return True + + +ReadableAsyncRegisterArray = Union[RegAsyncReadOnlyArray, RegAsyncReadWriteArray] +WriteableAsyncRegisterArray = Union[RegAsyncWriteOnlyArray, RegAsyncReadWriteArray] + + +class FieldAsyncReadOnly(_FieldReadOnlyFramework[FieldType], ABC): + """ + class for an asynchronous read only register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: ReadableAsyncRegister, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, (RegAsyncReadWrite, RegAsyncReadOnly)): + raise TypeError(f'size_props must be of {type(RegAsyncReadWrite)} or ' + f'{type(RegAsyncReadOnly)} but got {type(parent_register)}') + + # pylint: disable=duplicate-code + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + # pylint: enable=duplicate-code + + async def read(self) -> FieldType: # pylint: disable=invalid-overridden-method + """ + Asynchronously reads the register that this field is located in and retries the field + value applying the required masking and shifting + + Returns: + field value + + """ + return self._decode_read_value(await self.parent_register.read()) + + @property + def parent_register(self) -> ReadableAsyncRegister: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(ReadableAsyncRegister, self.parent) + + +class FieldAsyncWriteOnly(_FieldWriteOnlyFramework[FieldType], ABC): + """ + class for an asynchronous write only register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: WritableAsyncRegister, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, (RegAsyncReadWrite, RegAsyncWriteOnly)): + raise TypeError(f'size_props must be of {type(RegAsyncReadWrite)} or ' + f'{type(RegAsyncWriteOnly)} but got {type(parent_register)}') + + # pylint: disable=duplicate-code + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + # pylint: enable=duplicate-code + + async def write(self, value: FieldType) -> None: # pylint: disable=invalid-overridden-method + """ + The behaviour of this method depends on whether the field is located in + a readable register or not: + + If the register is readable, the method will perform an async read-modify-write + on the register updating the field with the value provided + + If the register is not writable all other field values will be asynchronously written + with zero. + + Args: + value: field value to update to + + """ + encoded_value = self._encode_write_value(value) + + if (self.high == (self.register_data_width - 1)) and (self.low == 0): + # special case where the field occupies the whole register, + # there a straight write can be performed + new_reg_value = encoded_value + else: + # do a read, modify write + if isinstance(self.parent_register, RegAsyncReadWrite): + reg_value = await self.parent_register.read() + masked_reg_value = reg_value & self.inverse_bitmask + new_reg_value = masked_reg_value | encoded_value + elif isinstance(self.parent_register, RegAsyncWriteOnly): + new_reg_value = encoded_value + else: + raise TypeError('Unhandled parent type') + + await self.parent_register.write(new_reg_value) + + @property + def parent_register(self) -> WritableAsyncRegister: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(WritableAsyncRegister, self.parent) + + +class FieldAsyncReadWrite(FieldAsyncReadOnly[FieldType], FieldAsyncWriteOnly[FieldType], ABC): + """ + class for an asynchronous read/write register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: RegAsyncReadWrite, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, RegAsyncReadWrite): + raise TypeError(f'size_props must be of {type(RegAsyncReadWrite)} ' + f'but got {type(parent_register)}') + + # pylint: disable=duplicate-code + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + # pylint: enable=duplicate-code + + @property + def parent_register(self) -> RegAsyncReadWrite: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(RegAsyncReadWrite, self.parent) + + +class FieldEnumAsyncReadWrite(FieldAsyncReadWrite[FieldType], FieldEnum[FieldType], ABC): + """ + class for an async read/write register field with an enumerated value + """ + __slots__: list[str] = [] + + @property + def parent_register(self) -> RegAsyncReadWrite: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(RegAsyncReadWrite, self.parent) + + +class FieldEnumAsyncReadOnly(FieldAsyncReadOnly[FieldType], FieldEnum[FieldType], ABC): + """ + class for an async read only register field with an enumerated value + """ + __slots__: list[str] = [] + + +class FieldEnumAsyncWriteOnly(FieldAsyncWriteOnly[FieldType], FieldEnum[FieldType], ABC): + """ + class for an async write only register field with an enumerated value + """ + __slots__: list[str] = [] diff --git a/rdl/outputs/python/msk_top_regs/lib/base.py b/rdl/outputs/python/msk_top_regs/lib/base.py new file mode 100644 index 0000000..c99cc7e --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/base.py @@ -0,0 +1,942 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from __future__ import annotations +import logging +import warnings +from typing import Optional, Union, TYPE_CHECKING, TypeVar, Any +from collections.abc import Iterator, Sequence +from abc import ABC, abstractmethod +from itertools import product, chain +from functools import reduce +from operator import mul +import sys +from enum import IntEnum + +from .callbacks import CallbackSet, CallbackSetLegacy +from .callbacks import NormalCallbackSet, AsyncCallbackSet +from .callbacks import NormalCallbackSetLegacy, AsyncCallbackSetLegacy + +if sys.version_info >= (3, 10): + # type guarding was introduced in python 3.10 + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + +if TYPE_CHECKING: + from .memory import Memory, MemoryArray + from .async_memory import AsyncMemory, AsyncMemoryArray + from .register_and_field import Reg, RegArray + from .register_and_field import WritableRegister, ReadableRegister + from .async_register_and_field import AsyncReg, AsyncRegArray + from .async_register_and_field import ReadableAsyncRegister, WritableAsyncRegister + from .register_and_field import ReadableRegisterArray, WriteableRegisterArray + from .async_register_and_field import ReadableAsyncRegisterArray, WriteableAsyncRegisterArray + +UDPStruct = dict[str, 'UDPType'] +UDPType = Union[str, int, bool, IntEnum, UDPStruct] + +class Base(ABC): + """ + base class of for all types + """ + __slots__: list[str] = ['__logger', '__inst_name', '__parent'] + + def __init__(self, *, + logger_handle: str, inst_name: str, parent: Optional[Union['Node', 'NodeArray']]): + + if not isinstance(logger_handle, str): + raise TypeError(f'logger_handle should be str but got {type(logger_handle)}') + + self.__logger = logging.getLogger(logger_handle) + self._logger.debug('creating instance of %s', self.__class__) + + if not isinstance(inst_name, str): + raise TypeError(f'inst_name should be str but got {type(inst_name)}') + self.__inst_name = inst_name + + if parent is not None: + if not isinstance(parent, (Node, NodeArray)): + raise TypeError(f'parent should be Node or Node Array but got {type(parent)}') + self.__parent = parent + + @property + def _logger(self) -> logging.Logger: + return self.__logger + + @property + def inst_name(self) -> str: + """ + systemRDL name of the instance in the parent + """ + return self.__inst_name + + @property + def parent(self) -> Optional[Union['Node', 'NodeArray']]: + """ + parent of the node or field, or None if it has no parent + """ + return self.__parent + + @property + def full_inst_name(self) -> str: + """ + The full hierarchical systemRDL name of the instance + """ + if self.parent is not None: + if isinstance(self.parent, NodeArray): + if self.parent.parent is None: + raise RuntimeError('A node array must have a parent it can not be the ' + 'top level') + return self.parent.parent.full_inst_name + "." + self.inst_name + + return self.parent.full_inst_name + "." + self.inst_name + + return self.inst_name + + @property + def udp(self) -> UDPStruct: + """ + A dictionary of the user defined properties for the node + """ + return {} + + @property + def rdl_name(self) -> Optional[str]: + """ + The systemRDL name property for the item + """ + return None + + @property + def rdl_desc(self) -> Optional[str]: + """ + The systemRDL desc property for the item + """ + return None + + +class Node(Base, ABC): + """ + base class of for all types with an address i.e. not fields + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__ = ['__address'] + + def __init__(self, *, + address: int, + logger_handle: str, + inst_name: str, + parent: Optional[Union['Node', 'NodeArray']]): + super().__init__(logger_handle=logger_handle, inst_name=inst_name, parent=parent) + + if not isinstance(address, int): + raise TypeError(f'address should be int but got {type(address)}') + + self.__address = address + + @property + def address(self) -> int: + """ + address of the node + """ + return self.__address + + @property + @abstractmethod + def _callbacks(self) -> Union[CallbackSet, CallbackSetLegacy]: + ... + + @property + @abstractmethod + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + """ + returns a child node by its systemRDL name + + Args: + name: name of the node in the systemRDL + + Returns: Node + + """ + if not isinstance(name, str): + raise TypeError(f'name must be a string got {type(name)}') + return getattr(self, self.systemrdl_python_child_name_map[name]) + + @property + @abstractmethod + def size(self) -> int: + """ + Total Number of bytes of address the node occupies + """ + + +# pylint: disable-next=invalid-name +NodeArrayElementType = TypeVar('NodeArrayElementType', bound=Node) + + +class NodeArray(Base, Sequence[NodeArrayElementType]): + """ + base class of for all array types + """ + + # pylint: disable=too-few-public-methods + __slots__: list[str] = ['__elements', '__address', + '__stride', '__dimensions'] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, logger_handle: str, + inst_name: str, + parent: Node, + address: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], NodeArrayElementType]] = None): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, parent=parent) + + if not isinstance(address, int): + raise TypeError(f'address should be a int but got {type(dimensions)}') + self.__address = address + if not isinstance(stride, int): + raise TypeError(f'stride should be a int but got {type(dimensions)}') + self.__stride = stride + + if not isinstance(dimensions, tuple): + raise TypeError(f'dimensions should be a tuple but got {type(dimensions)}') + for dimension in dimensions: + if not isinstance(dimension, int): + raise TypeError(f'dimension should be a int but got {type(dimension)}') + self.__dimensions = dimensions + + # There are two use cases for this class: + # 1. Initial creation - elements is None in which case the data is populated + # 2. Creating a recursive version of itself, this happens when it is sliced by the parent + # in which case a subset of the elements is presented and a new instance + + if elements is not None: + self.__check_init_element(elements) + self.__elements = elements + else: + new_elements: dict[tuple[int, ...], NodeArrayElementType] = {} + for indices in product(*[range(dim) for dim in self.dimensions]): + new_elements[indices] = self._build_element(indices=indices) + + self.__elements = new_elements + + def _build_element(self, indices: tuple[int, ...]) -> NodeArrayElementType: + + return self._element_datatype( + logger_handle=self._build_element_logger_handle(indices=indices), + address=self._address_calculator(indices), + inst_name=self._build_element_inst_name(indices=indices), + parent=self) + + def _build_element_logger_handle(self, indices: tuple[int, ...]) -> str: + """ + Build the logger handle for an element in the array + + Args: + indices: element index + + Returns: + """ + return self._logger.name + '[' + ','.join([str(item) for item in indices]) + ']' + + def _build_element_inst_name(self, indices: tuple[int, ...]) -> str: + """ + Build the logger handle for an element in the array + + Args: + indices: element index + + Returns: + """ + return self.inst_name + '[' + ']['.join([str(item) for item in indices]) + ']' + + def __check_init_element(self, elements: dict[tuple[int, ...], NodeArrayElementType]) -> None: + """ + Used in the __init__ to check that the elements passed in are valid + Args: + elements: proposed element of the array + + Returns: + + """ + if not isinstance(elements, dict): + raise TypeError(f'elements should be a dictionary but got {type(elements)}') + + for index, item in elements.items(): + if not isinstance(index, tuple): + raise TypeError(f'element index should be a tuple but got {type(index)}') + + if len(index) != len(self.dimensions): + raise ValueError(f'size of index does not match index length = {len(index)}') + + for index_pos, index_item in enumerate(index): + if not isinstance(index_item, int): + raise TypeError(f'element index_item should be a int ' + f'but got {type(index_item)}') + + if not 0 <= index_item < self.dimensions[index_pos]: + raise ValueError('index outside of range of dimensions') + + if not isinstance(item, self._element_datatype): + raise TypeError(f'elements should be a {self._element_datatype} ' + f'but got {type(item)}') + + def _address_calculator(self, indices: tuple[int, ...]) -> int: + def cal_addr(dimensions: tuple[int,...], indices: tuple[int, ...], base_address: int, + stride: int) -> int: + """ + Calculates the address of an register within an array + + :param dimensions: list of the array dimensions + :param indices: list of the array indices (length must match the dimensions) + :param base_address: base address of the array + :param stride: address stride of of the array + :return: address of the register + """ + if len(dimensions) == 1: + return (indices[0] * stride) + base_address + + outer_offset = reduce(mul, dimensions[1::], 1) * stride * indices[0] + return outer_offset + cal_addr(dimensions=dimensions[1::], + indices=indices[1::], + stride=self.stride, + base_address=self.address) + + return cal_addr(self.dimensions, base_address=self.address, + stride=self.stride, indices=indices) + + def _sub_instance(self, elements: dict[tuple[int, ...], NodeArrayElementType]) -> \ + NodeArray[NodeArrayElementType]: + if not isinstance(self.parent, Node): + raise RuntimeError('Parent of a Node Array must be Node') + return self.__class__(logger_handle=self._logger.name, + inst_name=self.inst_name, + parent=self.parent, + address=self.address, + stride=self.stride, + dimensions=self.dimensions, + elements=elements) + + def __getitem__(self, item): # type: ignore[no-untyped-def] + if len(self.dimensions) > 1: + return self.__getitem_nd(item) + + if isinstance(item, tuple): + raise IndexError('attempting a multidimensional array access on a single dimension' + ' array') + + if isinstance(item, slice): + + valid_items = [(i,) for i in range(*item.indices(self.dimensions[0]))] + def filter_1d_func(to_filter:tuple[tuple[int, ...], NodeArrayElementType]) -> bool: + index, _ = to_filter + if index in valid_items: + return True + return False + + return self._sub_instance(elements=dict(filter(filter_1d_func, self.items()))) + + if isinstance(item, int): + if (item, ) not in self.__elements: + raise IndexError(f'{item:d} in in the array') + return self.__elements[(item, )] + + raise TypeError(f'Array index must either being an int or a slice, got {type(item)}') + + def __getitem_nd(self, item): # type: ignore[no-untyped-def] + + if isinstance(item, tuple): + + if len(item) != len(self.dimensions): + raise ValueError('When using a multidimensional access, the size must match the' + ' dimensions of the array, array dimensions ' + f'are {len(self.dimensions)}') + + if all(isinstance(i, int) for i in item): + # single item access + if item not in self.__elements: + msg = 'index[' + ','.join([str(i) for i in item]) + '] not in array' + raise IndexError(msg) + return self.__elements[item] + + unpack_index_set = [] + for axis, sub_index in enumerate(item): + if isinstance(sub_index, int): + if not 0 <= sub_index < self.dimensions[axis]: + raise IndexError(f'{sub_index:d} out of range for dimension {axis}') + unpack_index_set.append((sub_index,)) + continue + + if isinstance(sub_index, slice): + unpack_index_set.append(range(*sub_index.indices(self.dimensions[axis]))) + continue + + raise TypeError(f'unhandle index of {type(sub_index)} in position {axis:d}') + + valid_items = tuple(product(*unpack_index_set)) + + def filter_nd_func(to_filter: tuple[tuple[int, ...], NodeArrayElementType]) -> bool: + index, _ = to_filter + if index in valid_items: + return True + return False + + return self._sub_instance(elements=dict(filter(filter_nd_func, self.items()))) + + raise IndexError('attempting a single dimensional array access on a multidimension' + ' array') + + def __len__(self) -> int: + return len(self.__elements) + + def __iter__(self) -> Iterator[NodeArrayElementType]: + yield from self.__elements.values() + + def items(self) -> Iterator[tuple[tuple[int, ...], NodeArrayElementType]]: + """ + iterate through all the items in an array but also return the index of the array + """ + yield from self.__elements.items() + + @property + def dimensions(self) -> Union[tuple[int, ...], tuple[int]]: + """ + Dimensions of the array + """ + return self.__dimensions + + @property + @abstractmethod + def _element_datatype(self) -> type[NodeArrayElementType]: + ... + + @property + def address(self) -> int: + """ + address of the node + """ + return self.__address + + @property + def stride(self) -> int: + """ + address stride of the array + """ + return self.__stride + + @property + def _callbacks(self) -> Union[CallbackSet, CallbackSetLegacy]: + if self.parent is None: + raise RuntimeError('Parent must be set') + # pylint: disable-next=protected-access + return self.parent._callbacks + + @property + def size(self) -> int: + """ + Total Number of bytes of address the array occupies + """ + return reduce(mul, self.dimensions, 1) * self.stride + + +class BaseSection(Node, ABC): + """ + base class of non-async and sync sections (AddressMaps and RegFile) + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + @abstractmethod + def get_children(self, unroll: bool = False) -> Iterator[Union[Node, NodeArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + + +class Section(BaseSection, ABC): + """ + base class of non-async sections (AddressMaps and RegFile) + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + def get_writable_registers(self, unroll:bool=False) -> \ + Iterator[Union[WritableRegister, WriteableRegisterArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_writable(item: Union[Reg, RegArray]) -> \ + TypeGuard[Union[WritableRegister, WriteableRegisterArray]]: + # pylint: disable-next=protected-access + return item._is_writeable + + return filter(is_writable, self.get_registers(unroll=unroll)) + + def get_readable_registers(self, unroll: bool = False) -> \ + Iterator[Union[ReadableRegister, ReadableRegisterArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_readable(item: Union[Reg, RegArray]) ->\ + TypeGuard[Union[ReadableRegister, ReadableRegisterArray]]: + # pylint: disable-next=protected-access + return item._is_readable + + return filter(is_readable, self.get_registers(unroll=unroll)) + + @abstractmethod + def get_registers(self, unroll: bool = False) -> \ + Iterator[Union[Reg, RegArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + + +class AddressMap(Section, ABC): + """ + base class of address map wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = ['__callbacks'] + + def __init__(self, *, + callbacks: Optional[Union[NormalCallbackSet, NormalCallbackSetLegacy]], + address: int, + logger_handle: str, + inst_name: str, + parent: Optional['AddressMap']): + + # only the top-level address map should have callbacks assigned, everything else should + # use its parent callback + if parent is None: + if not isinstance(callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback type wrong, got {type(callbacks)}') + if isinstance(callbacks, NormalCallbackSetLegacy): + warnings.warn('Support for the legacy callback using the array types will be ' + 'withdrawn in the future, please consider changing to the list ' + 'versions', category=DeprecationWarning) + self.__callbacks = callbacks + else: + if not callbacks is None: + raise RuntimeError('Callbacks must be None when a parent is set') + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback type wrong, got {type(callbacks)}') + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + @abstractmethod + def get_sections(self, unroll: bool = False) -> \ + Iterator[Union['AddressMap', RegFile, AddressMapArray, RegFileArray]]: + """ + generator that produces all the AddressMap and RegFile children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + @abstractmethod + def get_memories(self, unroll: bool = False) -> \ + Iterator[Union['Memory', 'MemoryArray']]: + """ + generator that produces all the Memory children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + def get_children(self, unroll: bool = False) -> Iterator[Union[Node, NodeArray]]: + return chain(self.get_registers(unroll=unroll), + self.get_sections(unroll=unroll), + self.get_memories(unroll=unroll)) + + @property + def _callbacks(self) -> Union[NormalCallbackSet, NormalCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + return self.__callbacks + + if isinstance(self.parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + +class AsyncSection(BaseSection, ABC): + """ + base class of async sections (AddressMaps and RegFile) + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + def get_writable_registers(self, unroll: bool = False) -> \ + Iterator[Union[WritableAsyncRegister, WriteableAsyncRegisterArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_writable(item: Union[AsyncReg, AsyncRegArray]) -> \ + TypeGuard[Union[WritableAsyncRegister, WriteableAsyncRegisterArray]]: + # pylint: disable-next=protected-access + return item._is_writeable + + return filter(is_writable, self.get_registers(unroll=unroll)) + + def get_readable_registers(self, unroll: bool = False) -> \ + Iterator[Union[ReadableAsyncRegister, ReadableAsyncRegisterArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_readable(item: Union[AsyncReg, AsyncRegArray]) -> \ + TypeGuard[Union[ReadableAsyncRegister, ReadableAsyncRegisterArray]]: + # pylint: disable-next=protected-access + return item._is_readable + + return filter(is_readable, self.get_registers(unroll=unroll)) + + + @abstractmethod + def get_registers(self, unroll: bool = False) -> \ + Iterator[Union[AsyncReg, AsyncRegArray]]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + + @property + @abstractmethod + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + ... + + +class AsyncAddressMap(AsyncSection, ABC): + """ + base class of address map wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = ['__callbacks'] + + def __init__(self, *, + callbacks: Optional[Union[AsyncCallbackSet, AsyncCallbackSetLegacy]], + address: int, + logger_handle: str, + inst_name: str, + parent: Optional['AsyncAddressMap']): + + # only the top-level address map should have callbacks assigned, everything else should + # use its parent callback + if parent is None: + if not isinstance(callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback type wrong, got {type(callbacks)}') + if isinstance(callbacks, AsyncCallbackSetLegacy): + warnings.warn('Support for the legacy callback using the array types will be ' + 'withdrawn in the future, please consider changing to the list ' + 'versions', category=DeprecationWarning) + self.__callbacks = callbacks + else: + if not callbacks is None: + raise RuntimeError('Callbacks must be None when a parent is set') + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callback type wrong, got {type(callbacks)}') + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + @abstractmethod + def get_sections(self, unroll: bool = False) -> \ + Iterator[Union['AsyncAddressMap', AsyncRegFile, + AsyncAddressMapArray, AsyncRegFileArray]]: + """ + generator that produces all the AddressMap and RegFile children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + @abstractmethod + def get_memories(self, unroll: bool = False) -> \ + Iterator[Union['AsyncMemory', 'AsyncMemoryArray']]: + """ + generator that produces all the Memory children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + return self.__callbacks + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + def get_children(self, unroll: bool = False) -> Iterator[Union[Node, NodeArray]]: + return chain(self.get_registers(unroll=unroll), self.get_sections(unroll=unroll), + self.get_memories(unroll=unroll)) + + +class AddressMapArray(NodeArray, ABC): + """ + base class for a array of address maps + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, logger_handle: str, inst_name: str, + parent: AddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, stride=stride, dimensions=dimensions) + + +class AsyncAddressMapArray(NodeArray, ABC): + """ + base class for a array of address maps + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, logger_handle: str, inst_name: str, + parent: AsyncAddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class RegFile(Section, ABC): + """ + base class of register file wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + def __init__(self, *, + address: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, 'RegFile']): + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'parent._callbacks type wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + @abstractmethod + def get_sections(self, unroll: bool = False) -> \ + Iterator[Union['RegFile','RegFileArray']]: + """ + generator that produces all the RegFile children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + @property + def _callbacks(self) -> Union[NormalCallbackSet, NormalCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + def get_children(self, unroll: bool = False) -> Iterator[Union[Node, NodeArray]]: + return chain(self.get_registers(unroll=unroll), self.get_sections(unroll=unroll)) + + +class AsyncRegFile(AsyncSection, ABC): + """ + base class of register file wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + def __init__(self, *, + address: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap, 'AsyncRegFile']): + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + if not isinstance(parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'parent._callbacks type wrong, got {type(parent._callbacks)}') + + @abstractmethod + def get_sections(self, unroll: bool = False) -> \ + Iterator[Union['AsyncRegFile','AsyncRegFileArray']]: + """ + generator that produces all the RegFile children of this node + + Args: + unroll: Whether to unroll child array or not + + Returns: + + """ + + def get_children(self, unroll: bool = False) -> Iterator[Union[Node, NodeArray]]: + return chain(self.get_registers(unroll=unroll), self.get_sections(unroll=unroll)) + + @property + def _callbacks(self) -> Union[AsyncCallbackSet, AsyncCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + +class RegFileArray(NodeArray, ABC): + """ + base class for a array of register files + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AddressMap, RegFile], + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class AsyncRegFileArray(NodeArray, ABC): + """ + base class for a array of register files + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AsyncAddressMap, AsyncRegFile], + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) diff --git a/rdl/outputs/python/msk_top_regs/lib/base_field.py b/rdl/outputs/python/msk_top_regs/lib/base_field.py new file mode 100644 index 0000000..415747b --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/base_field.py @@ -0,0 +1,549 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides the base types for fields that are shared by non-async and async +fields +""" +from enum import IntEnum +from typing import cast, Optional, TypeVar, Generic +from abc import ABC +import warnings + +from .base import Base +from .utility_functions import swap_msb_lsb_ordering +from .base_register import BaseReg +from .field_encoding import SystemRDLEnum + + +class FieldSizeProps: + """ + class to hold the key attributes of a field + """ + __slots__ = ['__msb', '__lsb', '__width', '__high', '__low'] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, width: int, msb: int, lsb: int, high: int, low: int): + self.__width = width + self.__msb = msb + self.__lsb = lsb + self.__high = high + self.__low = low + + if self.width < 1: + raise ValueError('width must be greater than 0') + + if self.high < self.low: + raise ValueError('field high bit position can not be less than the ' + 'low bit position') + + if self.lsb < 0: + raise ValueError('field low bit position cannot be less than zero') + + @property + def lsb(self) -> int: + """ + bit position of the least significant bit (lsb) of the field in the + parent register + + Note: + fields can be defined as msb in bit 0 or as lsb in bit 0 + """ + return self.__lsb + + @property + def msb(self) -> int: + """ + bit position of the most significant bit (msb) of the field in the + parent register + + Note: + fields can be defined as msb in bit 0 or as lsb in bit 0 + """ + return self.__msb + + @property + def width(self) -> int: + """ + The width of the field in bits + """ + return self.__width + + @property + def max_value(self) -> int: + """maximum unsigned integer value that can be stored in the field + + For example: + + * 8-bit field returns 0xFF (255) + * 16-bit field returns 0xFFFF (65535) + * 32-bit field returns 0xFFFF_FFFF (4294967295) + + """ + return (2 ** self.width) - 1 + + @property + def high(self) -> int: + """ + low index of the bit range of the field in the + parent register + + Note: + The first bit in the register is bit 0 + """ + return self.__high + + @property + def low(self) -> int: + """ + low index of the bit range of the field in the + parent register + + Note: + The first bit in the register is bit 0 + """ + return self.__low + + +class FieldMiscProps: + """ + Class to hold additional attributes of a field + """ + + __slots__ = ['__default', '__is_volatile'] + + def __init__(self, default:Optional[int], is_volatile:bool): + if not isinstance(default, int) and default is not None: + raise TypeError(f'default should be int or None, got {type(default)}') + self.__default = default + self.__is_volatile = is_volatile + + @property + def default(self) -> Optional[int]: + """ + The default (reset) value of the field + + None + - if the field is not reset. + - if the register resets to a signal value tht can not be determined + """ + return self.__default + + @property + def is_volatile(self) -> bool: + """ + Volatility of the field. True if the field is hardware-writable. + """ + return self.__is_volatile + + +# The following line should be: +# FieldType = TypeVar('FieldType', bound=int|IntEnum|SystemRDLEnum) +# However, python 3.9 does not support the combination so the binding was removed +# pylint: disable-next=invalid-name +FieldType = TypeVar('FieldType') +class Field(Generic[FieldType], Base, ABC): + """ + base class of register field wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__ = ['__size_props', '__misc_props', + '__bitmask', '__msb0', '__lsb0', '__field_type'] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: BaseReg, size_props: FieldSizeProps, misc_props: FieldMiscProps, + logger_handle: str, inst_name: str, field_type:type[FieldType]): + + super().__init__(logger_handle=logger_handle, + inst_name=inst_name, parent=parent_register) + + if not isinstance(size_props, FieldSizeProps): + raise TypeError(f'size_props must be of {type(FieldSizeProps)} ' + f'but got {type(size_props)}') + self.__size_props = size_props + + if not isinstance(misc_props, FieldMiscProps): + raise TypeError(f'misc_props must be of {type(FieldMiscProps)} ' + f'but got {type(misc_props)}') + self.__misc_props = misc_props + + if not isinstance(parent_register, BaseReg): + raise TypeError(f'parent_register must be of {type(BaseReg)} ' + f'but got {type(parent_register)}') + + if self.width > self.register_data_width: + raise ValueError('width can not be greater than parent width') + + if self.high > self.register_data_width: + raise ValueError(f'field high bit position {self.high:d} must be less than the ' + f'parent register width ({self.register_data_width:d})') + + if self.low > self.register_data_width: + raise ValueError('field lsb must be less than the parent ' + 'register width') + + if self.high - self.low + 1 != self.width: + raise ValueError('field width defined by lsb and msb does not match' + ' specified width') + + if (self.msb == self.high) and (self.lsb == self.low): + self.__lsb0 = True + self.__msb0 = False + elif (self.msb == self.low) and (self.lsb == self.high): + self.__lsb0 = False + self.__msb0 = True + else: + raise ValueError('msb/lsb are inconsistent with low/high') + + self.__bitmask = 0 + for bit_position in range(self.low, self.high+1): + self.__bitmask |= (1 << bit_position) + + if not issubclass(field_type, (int, IntEnum, SystemRDLEnum)): + raise TypeError(f'Unsupported field type: {field_type}') + self.__field_type = field_type + + @property + def lsb(self) -> int: + """ + bit position of the least significant bit (lsb) of the field in the + parent register + + Note: + fields can be defined as msb in bit 0 or as lsb in bit 0 + """ + return self.__size_props.lsb + + @property + def msb(self) -> int: + """ + bit position of the most significant bit (msb) of the field in the + parent register + + Note: + fields can be defined as msb in bit 0 or as lsb in bit 0 + """ + return self.__size_props.msb + + @property + def width(self) -> int: + """ + The width of the field in bits + """ + return self.__size_props.width + + @property + def max_value(self) -> int: + """maximum unsigned integer value that can be stored in the field + + For example: + + * 8-bit field returns 0xFF (255) + * 16-bit field returns 0xFFFF (65535) + * 32-bit field returns 0xFFFF_FFFF (4294967295) + + """ + return (2 ** self.width) - 1 + + @property + def high(self) -> int: + """ + low index of the bit range of the field in the + parent register + + Note: + The first bit in the register is bit 0 + """ + return self.__size_props.high + + @property + def low(self) -> int: + """ + low index of the bit range of the field in the + parent register + + Note: + The first bit in the register is bit 0 + """ + return self.__size_props.low + + @property + def bitmask(self) -> int: + """ + The bit mask needed to extract the field from its register + + For example a register field occupying bits 7 to 4 in a 16-bit register + will have a bit mask of 0x00F0 + """ + return self.__bitmask + + @property + def register_data_width(self) -> int: + """ + The width of the register within which the field resides in bits + """ + return self.__parent_register.width + + @property + def inverse_bitmask(self) -> int: + """ + The bitwise inverse of the bitmask needed to extract the field from its + register + + For example a register field occupying bits 7 to 4 in a 16-bit register + will have a inverse bit mask of 0xFF0F + """ + return self.__parent_register.max_value ^ self.bitmask + + @property + def msb0(self) -> bool: + """ + The field can either be lsb0 or msb0 + + Returns: true if msb0 + + """ + return self.__msb0 + + @property + def lsb0(self) -> bool: + """ + The field can either be lsb0 or msb0 + + Returns: true if lsb0 + + """ + return self.__lsb0 + + @property + def default(self) -> Optional[FieldType]: + """ + The default value of the field + + This returns None: + - if the field is not reset. + - if the register resets to a signal value that can not be determined + """ + if issubclass(self._field_type, (SystemRDLEnum, IntEnum)): + int_default = self.__misc_props.default + + if int_default is not None: + if int_default not in [item.value for item in self._field_type]: + # this is a special case which can occur if the default value of the register + # does not cover the enum + msg = f'reset value {int_default:d} is not within the enumeration for the class' + self._logger.warning(msg) + warnings.warn(msg) + return None + + return_value = self._field_type(int_default) + return return_value # type: ignore[return-value] + + return None + + return self.__misc_props.default # type: ignore[return-value] + + @property + def is_volatile(self) -> bool: + """ + The HW volatility of the field + """ + return self.__misc_props.is_volatile + + @property + def __parent_register(self) -> BaseReg: + """ + parent register the field is placed in + """ + # this cast is OK because an explict typing check was done in the __init__ + return cast(BaseReg, self.parent) + + @property + def _field_type(self) -> type[FieldType]: + return self.__field_type # type: ignore[return-value] + + +class _FieldReadOnlyFramework(Field[FieldType], ABC): + """ + base class for a async or normal read only register field + """ + __slots__ : list[str] = [] + + def decode_read_value(self, value: int) -> FieldType: + """ + extracts the field value from a register value, by applying the bit + mask and shift needed + + Args: + value: value to decode, normally read from a register + + Returns: + field value + + Warning: + This method will be removed from a future version, if you have a compelling use + case for it please add a comment to the #184 ticket + + """ + # end users should not need access to the `decode_read_value` as the decoding is done + # for them, it felt like an anomaly that this was public, see #184 + warnings.warn('decode_read_value will be made private in a future version', + DeprecationWarning, stacklevel=2) + return self._decode_read_value(value=value) + + def _decode_read_value(self, value: int) -> FieldType: + """ + extracts the field value from a register value, by applying the bit + mask and shift needed + + Args: + value: value to decode, normally read from a register + + Returns: + field value + """ + if not isinstance(value, int): + raise TypeError(f'value must be an int but got {type(value)}') + + if value < 0: + raise ValueError('value to be decoded must be greater ' + 'than or equal to 0') + + if value > self.__parent_register.max_value: + raise ValueError(f'value to bede coded must be less than or equal ' + f'to {self.__parent_register.max_value:d}') + + if self.msb0 is False: + return_int_value = (value & self.bitmask) >> self.low + else: + return_int_value = swap_msb_lsb_ordering(value=(value & self.bitmask) >> self.low, + width=self.width) + + if issubclass(self._field_type, (SystemRDLEnum, IntEnum)): + return self._field_type(return_int_value) # type: ignore[return-value] + if issubclass(self._field_type, int): + return return_int_value # type: ignore[return-value] + + raise TypeError(f'unhandled field_type: {self._field_type}') + + + @property + def __parent_register(self) -> BaseReg: + """ + parent register the field is placed in + """ + # this cast is OK because an explict typing check was done in the __init__ + return cast(BaseReg, self.parent) + + +class _FieldWriteOnlyFramework(Field[FieldType], ABC): + """ + class for a write only register field + """ + __slots__ : list[str] = [] + + def _write_value_checks(self, value: int) -> None: + """ + Carries out the value for the encode_write_value and write methods + + Args: + value: proposed value to write + """ + if not isinstance(value, int): + raise TypeError(f'value must be an int but got {type(value)}') + + if value < 0: + raise ValueError('value to be written to register must be greater ' + 'than or equal to 0') + + if value > self.max_value: + raise ValueError(f'value to be written to register must be less ' + f'than or equal to {self.max_value:d}') + + + def encode_write_value(self, value: FieldType) -> int: + """ + Check that a value is legal for the field and then encode it in preparation to be written + to the register + + Args: + value: field value + + Returns: + value which can be applied to the register to update the field + + Warning: + This method will be removed from a future version, if you have a compelling use + case for it please add a comment to the #184 ticket + + """ + # end users should not need access to the `decode_read_value` as the decoding is done + # for them, it felt like an anomaly that this was public, see #184 + warnings.warn('encode_write_value will be made private in a future version', + DeprecationWarning, stacklevel=2) + return self._encode_write_value(value=value) + + def _encode_write_value(self, value: FieldType) -> int: + """ + Check that a value is legal for the field and then encode it in preparation to be written + to the register + + Args: + value: field value + + Returns: + value which can be applied to the register to update the field + + """ + if not isinstance(value, self._field_type): + raise TypeError(f'Field type is not as expected, got {type(value)},' + f' expected {self._field_type}') + + if isinstance(value, (SystemRDLEnum, IntEnum)): + int_value = value.value + elif isinstance(value, int): + int_value = value + else: + raise RuntimeError('Unhandled type configuration') + + self._write_value_checks(value=int_value) + + if self.msb0 is False: + return_value = int_value << self.low + else: + return_value = swap_msb_lsb_ordering(value=int_value, width=self.width) << self.low + + return return_value + + +class FieldEnum(Field[FieldType], ABC): + """ + class for a register field with an enumerated value + """ + __slots__: list[str] = [] + + @property + def enum_cls(self) -> type[FieldType]: + """ + The enumeration class for this field + """ + return self._field_type diff --git a/rdl/outputs/python/msk_top_regs/lib/base_register.py b/rdl/outputs/python/msk_top_regs/lib/base_register.py new file mode 100644 index 0000000..e854a86 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/base_register.py @@ -0,0 +1,229 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of classes used by the autogenerated code to represent +registers +""" +from typing import Union, Optional, TypeVar +from abc import ABC, abstractmethod + + +from .base import Node, AddressMap, RegFile, NodeArray +from .utility_functions import legal_register_width +from .base import AsyncAddressMap, AsyncRegFile +from .memory import BaseMemory + + +class RegisterWriteVerifyError(Exception): + """ + Exception that occurs when the read after a write does not match the expected value + """ + + +class BaseReg(Node, ABC): + """ + base class of register wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = ['__width', '__accesswidth'] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, AsyncAddressMap, RegFile, AsyncRegFile, BaseMemory, + 'BaseRegArray']): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + if not isinstance(width, int): + raise TypeError(f'width should be int but got {(type(width))}') + if not legal_register_width(width_in_bits=width): + raise ValueError(f'Unsupported register width {width:d}') + self.__width = width + if not isinstance(accesswidth, int): + raise TypeError(f'accesswidth should be int but got {(type(accesswidth))}') + if not legal_register_width(width_in_bits=accesswidth): + raise ValueError(f'Unsupported access width {accesswidth:d}') + self.__accesswidth = accesswidth + # pylint: enable=too-many-arguments,duplicate-code + + @property + def max_value(self) -> int: + """ + maximum unsigned integer value that can be stored in the register + + For example: + + * 8-bit register returns 0xFF (255) + * 16-bit register returns 0xFFFF (65535) + * 32-bit register returns 0xFFFF_FFFF (4294967295) + + """ + return (2 ** self.width) - 1 + + def _validate_data(self, data: int) -> None: + """ + Check that the data parameter is of valid type and range + """ + if not isinstance(data, int): + raise TypeError(f'data should be an int got {type(data)}') + + if data > self.max_value: + raise ValueError('data out of range') + + if data < 0: + raise ValueError('data out of range') + + @property + def width(self) -> int: + """ + The width of the register in bits, this uses the `regwidth` systemRDL property + """ + return self.__width + + @property + def accesswidth(self) -> int: + """ + The access width of the register in bits, this uses the `accesswidth` systemRDL property + """ + return self.__accesswidth + + @property + def size(self) -> int: + """ + Total Number of bytes of address the node occupies + """ + return self.__width >> 3 + + @property + @abstractmethod + def _is_readable(self) -> bool: + ... + + @property + @abstractmethod + def _is_writeable(self) -> bool: + ... + +# pylint: disable-next=invalid-name +BaseRegArrayElementType= TypeVar('BaseRegArrayElementType', bound=BaseReg) + + +class BaseRegArray(NodeArray[BaseRegArrayElementType], ABC): + """ + base class of register array wrappers (async and non-async) + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + # pylint: disable=too-many-arguments,duplicate-code + + __slots__: list[str] = ['__width', '__accesswidth'] + + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AddressMap, AsyncAddressMap, RegFile, AsyncRegFile, BaseMemory], + width: int, + accesswidth: int, + address: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], BaseRegArrayElementType]] = None): + + if not isinstance(width, int): + raise TypeError(f'width should be int but got {(type(width))}') + if not legal_register_width(width_in_bits=width): + raise ValueError(f'Unsupported register width {width:d}') + self.__width = width + if not isinstance(accesswidth, int): + raise TypeError(f'accesswidth should be int but got {(type(accesswidth))}') + if not legal_register_width(width_in_bits=accesswidth): + raise ValueError(f'Unsupported access width {accesswidth:d}') + self.__accesswidth = accesswidth + + if not issubclass(self._element_datatype, BaseReg): + raise TypeError(f'{self._element_datatype}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions, elements=elements) + + @property + def width(self) -> int: + """ + The width of the register in bits, this uses the `regwidth` systemRDL property + """ + return self.__width + + @property + def accesswidth(self) -> int: + """ + The access width of the register in bits, this uses the `accesswidth` systemRDL property + """ + return self.__accesswidth + + def _build_element(self, indices: tuple[int, ...]) -> BaseRegArrayElementType: + + return self._element_datatype( + logger_handle=self._build_element_logger_handle(indices=indices), + address=self._address_calculator(indices), + inst_name=self._build_element_inst_name(indices=indices), + width=self.width, + accesswidth=self.accesswidth, + parent=self) + + def _sub_instance(self, elements: dict[tuple[int, ...], BaseRegArrayElementType]) ->\ + NodeArray[BaseRegArrayElementType]: + if not isinstance(self.parent, (AddressMap, AsyncAddressMap, RegFile, + AsyncRegFile, BaseMemory)): + raise RuntimeError('Parent of a Node Array must be Node') + return self.__class__(logger_handle=self._logger.name, + inst_name=self.inst_name, + parent=self.parent, + address=self.address, + width=self.width, + accesswidth=self.accesswidth, + stride=self.stride, + dimensions=self.dimensions, + elements=elements) + + @property + @abstractmethod + def _element_datatype(self) -> type[BaseRegArrayElementType]: + ... + + @property + @abstractmethod + def _is_readable(self) -> bool: + ... + + @property + @abstractmethod + def _is_writeable(self) -> bool: + ... diff --git a/rdl/outputs/python/msk_top_regs/lib/callbacks.py b/rdl/outputs/python/msk_top_regs/lib/callbacks.py new file mode 100644 index 0000000..8c8b541 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/callbacks.py @@ -0,0 +1,363 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of types used by the autogenerated code to callbacks +""" +from array import array as Array + +from typing import Optional, Union +from typing import Protocol + + +class ReadCallback(Protocol): + """ + Callback definition for a single register read operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int) -> int: + pass + + +class WriteCallback(Protocol): + """ + Callback definition for a single register write operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int, data: int) -> None: + pass + + +class ReadBlockLegacyCallback(Protocol): + """ + Callback definition for a block read operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int, length: int) -> Array: + pass + +class ReadBlockCallback(Protocol): + """ + Callback definition for a block read operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int, length: int) -> list[int]: + pass + + +class WriteBlockCallback(Protocol): + """ + Callback definition for a block write operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int, data: list[int]) -> None: + pass + + +class WriteBlockLegacyCallback(Protocol): + """ + Callback definition for a block write operation + """ + # pylint: disable=too-few-public-methods + def __call__(self, addr: int, width: int, accesswidth: int, data: Array) -> None: + pass + + +class AsyncReadCallback(Protocol): + """ + Callback definition for a single register async read operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int) -> int: + pass + + +class AsyncWriteCallback(Protocol): + """ + Callback definition for a single register async write operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int, data: int) -> None: + pass + + +class AsyncReadBlockCallback(Protocol): + """ + Callback definition for an async block read operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int, length: int) -> list[int]: + pass + +class AsyncReadBlockLegacyCallback(Protocol): + """ + Callback definition for an async block read operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int, length: int) -> Array: + pass + + +class AsyncWriteBlockCallback(Protocol): + """ + Callback definition for an async block write operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int, data: list[int]) -> None: + pass + +class AsyncWriteBlockLegacyCallback(Protocol): + """ + Callback definition for an async block write operation + """ + # pylint: disable=too-few-public-methods,unexpected-special-method-signature + async def __call__(self, addr: int, width: int, accesswidth: int, data: Array) -> None: + pass + + +class _NormalCallbackSetBase: + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_callback', '__read_callback'] + + def __init__(self, + write_callback: Optional[WriteCallback] = None, + read_callback: Optional[ReadCallback] = None): + + self.__read_callback = read_callback + self.__write_callback = write_callback + + @property + def read_callback(self) -> Optional[ReadCallback]: + """ + single read callback function + + Returns: call back function + + """ + return self.__read_callback + + @property + def write_callback(self) -> Optional[WriteCallback]: + """ + single write callback function + + Returns: call back function + + """ + return self.__write_callback + + +class NormalCallbackSet(_NormalCallbackSetBase): + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_block_callback', '__read_block_callback'] + + def __init__(self, + write_callback: Optional[WriteCallback] = None, + read_callback: Optional[ReadCallback] = None, + write_block_callback: Optional[WriteBlockCallback] = None, + read_block_callback: Optional[ReadBlockCallback] = None): + + super().__init__(read_callback=read_callback, write_callback=write_callback) + + self.__read_block_callback = read_block_callback + self.__write_block_callback = write_block_callback + + @property + def read_block_callback(self) -> Optional[ReadBlockCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__read_block_callback + + @property + def write_block_callback(self) -> Optional[WriteBlockCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__write_block_callback + + +class NormalCallbackSetLegacy(_NormalCallbackSetBase): + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_block_callback', '__read_block_callback'] + + def __init__(self, + write_callback: Optional[WriteCallback] = None, + read_callback: Optional[ReadCallback] = None, + write_block_callback: Optional[WriteBlockLegacyCallback] = None, + read_block_callback: Optional[ReadBlockLegacyCallback] = None): + + super().__init__(read_callback=read_callback, write_callback=write_callback) + + self.__read_block_callback = read_block_callback + self.__write_block_callback = write_block_callback + + @property + def read_block_callback(self) -> Optional[ReadBlockLegacyCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__read_block_callback + + @property + def write_block_callback(self) -> Optional[WriteBlockLegacyCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__write_block_callback + +class _AsyncCallbackSetBase: + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_callback', '__read_callback'] + + def __init__(self, + write_callback: Optional[AsyncWriteCallback] = None, + read_callback: Optional[AsyncReadCallback] = None): + + self.__read_callback = read_callback + self.__write_callback = write_callback + + @property + def read_callback(self) -> Optional[AsyncReadCallback]: + """ + single read callback function + + Returns: call back function + + """ + return self.__read_callback + + @property + def write_callback(self) -> Optional[AsyncWriteCallback]: + """ + single write callback function + + Returns: call back function + + """ + return self.__write_callback + + +class AsyncCallbackSet(_AsyncCallbackSetBase): + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_block_callback', '__read_block_callback'] + + def __init__(self, + write_callback: Optional[AsyncWriteCallback] = None, + read_callback: Optional[AsyncReadCallback] = None, + write_block_callback: Optional[AsyncWriteBlockCallback] = None, + read_block_callback: Optional[AsyncReadBlockCallback] = None): + + super().__init__(read_callback=read_callback, write_callback=write_callback) + + self.__read_block_callback = read_block_callback + self.__write_block_callback = write_block_callback + + @property + def read_block_callback(self) -> Optional[AsyncReadBlockCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__read_block_callback + + @property + def write_block_callback(self) -> Optional[AsyncWriteBlockCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__write_block_callback + + +class AsyncCallbackSetLegacy(_AsyncCallbackSetBase): + """ + Class to hold a set of callbacks, this reduces the number of callback that need to be passed + around + """ + + __slots__ = ['__write_block_callback', '__read_block_callback'] + + def __init__(self, + write_callback: Optional[AsyncWriteCallback] = None, + read_callback: Optional[AsyncReadCallback] = None, + write_block_callback: Optional[AsyncWriteBlockLegacyCallback] = None, + read_block_callback: Optional[AsyncReadBlockLegacyCallback] = None): + super().__init__(read_callback=read_callback, write_callback=write_callback) + + self.__read_block_callback = read_block_callback + self.__write_block_callback = write_block_callback + + @property + def read_block_callback(self) -> Optional[AsyncReadBlockLegacyCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__read_block_callback + + @property + def write_block_callback(self) -> Optional[AsyncWriteBlockLegacyCallback]: + """ + block read callback function + + Returns: call back function + + """ + return self.__write_block_callback + + +CallbackSet = Union[AsyncCallbackSet, NormalCallbackSet] +CallbackSetLegacy = Union[AsyncCallbackSetLegacy, NormalCallbackSetLegacy] diff --git a/rdl/outputs/python/msk_top_regs/lib/field_encoding.py b/rdl/outputs/python/msk_top_regs/lib/field_encoding.py new file mode 100644 index 0000000..44d4068 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/field_encoding.py @@ -0,0 +1,80 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides the base types of field enumerations +""" +from enum import Enum +from typing import Optional +from collections import namedtuple +from json import JSONEncoder + +SystemRDLEnumEntry = namedtuple('SystemRDLEnumEntry', ['int_value', 'name', 'desc']) + +class SystemRDLEnum(Enum): + """ + A Enumeration that can also hold the system RDL properties, notably the `name` and `desc + """ + @property + def _full_value(self) -> SystemRDLEnumEntry: + """ The full field value (needed to some operation) """ + return super().value + + @property + # pylint:disable-next=invalid-overridden-method + def value(self) -> int: + """ The integer value used to encode the field value """ + return super().value.int_value + + @property + def rdl_name(self) -> Optional[str]: + """ + The systemRDL name property for the encoding entry + """ + return super().value.name + + @property + def rdl_desc(self) -> Optional[str]: + """ + The systemRDL name property for the encoding entry + """ + return super().value.desc + + @classmethod + def _missing_(cls, value): # type: ignore[no-untyped-def] + + if isinstance(value, int): + # pylint:disable-next=protected-access,no-member + int_mapping = {item.value: item._full_value for item in cls._member_map_.values()} + if value not in int_mapping: + raise ValueError(f'Enumeration has not integer value of {value}') + return cls(int_mapping[value]) + + return None + + def __str__(self) -> str: + return self.name + +class RegisterFieldJSONEncoder(JSONEncoder): + """ + JSON Encoder that supports SystemRDLEnum + """ + def default(self, o): # type: ignore[no-untyped-def] + if isinstance(o, SystemRDLEnum): + return o.name + # Let the base class default method raise the TypeError + return super().default(o) diff --git a/rdl/outputs/python/msk_top_regs/lib/memory.py b/rdl/outputs/python/msk_top_regs/lib/memory.py new file mode 100644 index 0000000..2ab3a7d --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/memory.py @@ -0,0 +1,752 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of classes used by the autogenerated code to represent +memories +""" +from array import array as Array +from typing import Union, TYPE_CHECKING +from collections.abc import Iterator +from abc import ABC, abstractmethod +import sys + +from .base import Node, AddressMap, AsyncAddressMap, NodeArray +from .utility_functions import get_array_typecode + +from .callbacks import NormalCallbackSet, NormalCallbackSetLegacy + +# same bit of code exists in base so flags as duplicate +# pylint: disable=duplicate-code +if sys.version_info >= (3, 10): + # type guarding was introduced in python 3.10 + from typing import TypeGuard +else: + from typing_extensions import TypeGuard +# pylint: enable=duplicate-code + + +if TYPE_CHECKING: + from .register_and_field import Reg, RegArray + from .register_and_field import ReadableRegister, WritableRegister + from .register_and_field import ReadableRegisterArray, WriteableRegisterArray + from .async_memory import AsyncMemoryArray + +# pylint: disable=duplicate-code + + +class BaseMemory(Node, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = ['__memwidth', '__entries', '__accesswidth'] + + # pylint: disable=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, AsyncAddressMap, 'MemoryArray', 'AsyncMemoryArray']): + """ + Initialise the class + + Args: + address: address of the register + width: width of the register in bits + logger_handle: name to be used logging messages associate with this object + """ + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + self.__memwidth = width + self.__entries = entries + self.__accesswidth = accesswidth + # pylint: enable=too-many-arguments + + @property + def width(self) -> int: + """ + The width of the memory in bits, this uses the `memwidth` systemRDL property + + Returns: memory width + + """ + return self.__memwidth + + @property + def width_in_bytes(self) -> int: + """ + The width of the memory bytes, i.e. the width in bits divided by 8 + + Returns: memory width (in bytes) + + """ + def roundup_pow2(x: int) -> int: + return 1 << (x - 1).bit_length() + + return roundup_pow2(self.width) // 8 + + @property + def entries(self) -> int: + """ + The number of entries in the memory, this uses the `mementries` systemRDL property + + Returns: memory entries + + """ + return self.__entries + + @property + def array_typecode(self) -> str: + """ + the python array.array type is initialised with a typecode. This property provides the + recommended typecode to use with this class instance (based on the memwidth) + + Returns: typecode + + """ + return get_array_typecode(self.width) + + @property + def size(self) -> int: + """ + Total Number of bytes of address the node occupies + """ + return self.entries * self.width_in_bytes + + def address_lookup(self, entry: int) -> int: + """ + provides the address for an entry in the memory. + + Examples + + Args: + entry: entry number to look up the address for + + Returns: Address + + """ + if not isinstance(entry, int): + raise TypeError(f'entry must be an int but got {type(entry)}') + + if entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries-1:d} but got {entry:d}') + + return self.address + (entry * self.width_in_bytes) + + @property + def accesswidth(self) -> int: + """ + The access width of the register in bits, this uses the `accesswidth` systemRDL property + + Returns: register access width + """ + return self.__accesswidth + + +class Memory(BaseMemory, ABC): + """ + base class of non_async memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, 'MemoryArray']): + """ + Initialise the class + + Args: + address: address of the register + width: width of the register in bits + logger_handle: name to be used logging messages associate with this object + """ + if not isinstance(parent, (AddressMap, + MemoryWriteOnlyArray, MemoryReadOnlyArray, + MemoryReadWriteArray)): + raise TypeError(f'parent should be either AddressMap or Memory Array got ' + f'{type(parent)}') + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + width=width, + accesswidth=accesswidth, + entries=entries, + parent=parent) + + @abstractmethod + def get_registers(self, unroll: bool = False) -> \ + Iterator[Union['Reg', 'RegArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + + +class _MemoryReadOnly(Memory, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, 'MemoryArray']): + + if parent is None: + raise TypeError('parent should be either AddressMap or Memory Array ' + f'got {type(parent)}') + + if not isinstance(parent, (AddressMap, MemoryWriteOnlyArray, + MemoryReadOnlyArray, MemoryReadWriteArray)): + raise TypeError('parent should be either AddressMap or Memory Array ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + entries=entries, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # pylint: enable=too-many-arguments + @property + def _callbacks(self) -> Union[NormalCallbackSet, NormalCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + def _read(self, start_entry: int, number_entries: int) -> list[int]: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if not isinstance(number_entries, int): + raise TypeError(f'number_entries should be an int got {type(number_entries)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if number_entries not in range(0, self.entries - start_entry + 1): + raise ValueError(f'number_entries must be in range 0 to' + f' {self.entries - start_entry:d} but got {number_entries:d}') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + addr = self.address_lookup(entry=start_entry) + data_read = \ + read_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + length=number_entries) + + if isinstance(self._callbacks, NormalCallbackSet): + if not isinstance(data_read, list): + if isinstance(data_read, Array): + raise TypeError( + 'The read block callback is expected to return an list, this ' + 'is likely to happen if you are using legacy callbacks without ' + 'NormalCallbackSetLegacy') + raise TypeError('The read block callback is expected to return an List') + return data_read + + if isinstance(self._callbacks, NormalCallbackSetLegacy): + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + return data_read.tolist() + + raise RuntimeError(f'There is no usable callback block callback:{read_block_callback}') + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_read = [0 for _ in range(number_entries)] + + for entry in range(number_entries): + entry_address = self.address_lookup(entry=start_entry+entry) + data_entry = read_callback(addr=entry_address, + width=self.width, + accesswidth=self.width) + + data_read[entry] = data_entry + + return data_read + + raise RuntimeError(f'There is no usable callback, ' + f'block callback:{read_block_callback}, ' + f'normal callback:{read_callback}') + + def _read_legacy(self, start_entry: int, number_entries: int) -> Array: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if not isinstance(number_entries, int): + raise TypeError(f'number_entries should be an int got {type(number_entries)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if number_entries not in range(0, self.entries - start_entry + 1): + raise ValueError(f'number_entries must be in range 0 to' + f' {self.entries - start_entry:d} but got {number_entries:d}') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + addr = self.address_lookup(entry=start_entry) + data_read = \ + read_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + length=number_entries) + + if isinstance(self._callbacks, NormalCallbackSet): + if not isinstance(data_read, list): + if isinstance(data_read, Array): + raise TypeError( + 'The read block callback is expected to return an list, this ' + 'is likely to happen if you are using legacy callbacks without ' + 'NormalCallbackSetLegacy') + raise TypeError('The read block callback is expected to return an List') + return Array(self.array_typecode, data_read) + + if isinstance(self._callbacks, NormalCallbackSetLegacy): + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + return data_read + + raise RuntimeError(f'There is no usable callback block callback:{read_block_callback}') + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_read = Array(self.array_typecode, [0 for _ in range(number_entries)]) + + for entry in range(number_entries): + entry_address = self.address_lookup(entry=start_entry+entry) + data_entry = read_callback(addr=entry_address, + width=self.width, + accesswidth=self.width) + + data_read[entry] = data_entry + + return data_read + + raise RuntimeError(f'There is no usable callback, ' + f'block callback:{read_block_callback}, ' + f'normal callback:{read_callback}') + + def get_readable_registers(self, unroll: bool = False) -> \ + Iterator[Union['ReadableRegister', 'ReadableRegisterArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_readable(item: Union['Reg', 'RegArray']) ->\ + TypeGuard[Union['ReadableRegister', 'ReadableRegisterArray']]: + # pylint: disable-next=protected-access + return item._is_readable + + return filter(is_readable, self.get_registers(unroll=unroll)) + + +class MemoryReadOnly(_MemoryReadOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + def read(self, start_entry: int, number_entries: int) -> list[int]: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + return self._read(start_entry=start_entry, number_entries=number_entries) + + +class MemoryReadOnlyLegacy(_MemoryReadOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + def read(self, start_entry: int, number_entries: int) -> Array: + """ + Read from the memory + + Args: + start_entry: index in the memory to start from, this is not the address + number_entries: number of entries to read + + Returns: data read from memory + + """ + return self._read_legacy(start_entry=start_entry, number_entries=number_entries) + + +class _MemoryWriteOnly(Memory, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + entries: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, 'MemoryArray']): + + if not isinstance(parent, (AddressMap, MemoryWriteOnlyArray, + MemoryReadOnlyArray, MemoryReadWriteArray)): + raise TypeError('parent should be either AddressMap or Memory Array ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + entries=entries, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # pylint: enable=too-many-arguments + @property + def _callbacks(self) -> Union[NormalCallbackSet, NormalCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + def _write(self, start_entry: int, data: Union[Array, list[int]]) -> None: + """ + Write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + # pylint:disable=too-many-branches + if not isinstance(start_entry, int): + raise TypeError(f'start_entry should be an int got {type(start_entry)}') + + if start_entry not in range(0, self.entries): + raise ValueError(f'entry must be in range 0 to {self.entries - 1:d} ' + f'but got {start_entry:d}') + + if not isinstance(data, (Array, list)): + raise TypeError(f'data should be an List or array.array got {type(data)}') + + if len(data) not in range(0, self.entries - start_entry + 1): + raise ValueError(f'data length must be in range 0 to {self.entries - start_entry:d} ' + f'but got {len(data):d}') + + if self._callbacks.write_block_callback is not None: + addr = self.address_lookup(entry=start_entry) + if isinstance(self._callbacks, NormalCallbackSet): + if isinstance(data, Array): + self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data.tolist()) + else: + self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data) + if isinstance(self._callbacks, NormalCallbackSetLegacy): + if isinstance(data, list): + # need to convert the data to an array before calling + self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=Array(self.array_typecode, data)) + else: + self._callbacks.write_block_callback(addr=addr, + width=self.width, + accesswidth=self.width, + data=data) + + elif self._callbacks.write_callback is not None: + # there is not write_block_callback defined so we must used individual write + for entry_index, entry_data in enumerate(data): + entry_address = self.address_lookup(entry=start_entry+entry_index) + self._callbacks.write_callback(addr=entry_address, + width=self.width, + accesswidth=self.width, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + def get_writable_registers(self, unroll: bool = False) -> \ + Iterator[Union['WritableRegister', 'WriteableRegisterArray']]: + """ + generator that produces all the readable_registers of this node + + Args: + unroll: Whether to unroll child array or not + """ + def is_writable(item: Union['Reg', 'RegArray']) -> \ + TypeGuard[Union['WritableRegister', 'WriteableRegisterArray']]: + # pylint: disable-next=protected-access + return item._is_writeable + + return filter(is_writable, self.get_registers(unroll=unroll)) + + +class MemoryWriteOnly(_MemoryWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + def write(self, start_entry: int, data: list[int]) -> None: + """ + Write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + if not isinstance(data, list): + raise TypeError(f'data should be an List got {type(data)}') + return self._write(start_entry=start_entry, data=data) + + +class MemoryWriteOnlyLegacy(_MemoryWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + __slots__: list[str] = [] + + def write(self, start_entry: int, data: Array) -> None: + """ + Write data to memory + + Args: + start_entry: index in the memory to start from, this is not the address + data: data to write + + Returns: None + + """ + if not isinstance(data, Array): + raise TypeError(f'data should be an Array {type(data)}') + return self._write(start_entry=start_entry, data=data) + + +class MemoryReadWrite(MemoryReadOnly, MemoryWriteOnly, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + +class MemoryReadWriteLegacy(MemoryReadOnlyLegacy, MemoryWriteOnlyLegacy, ABC): + """ + base class of memory wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + +class MemoryReadOnlyArray(NodeArray, ABC): + """ + base class for a array of read only memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class MemoryWriteOnlyArray(NodeArray, ABC): + """ + base class for a array of write only memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +class MemoryReadWriteArray(MemoryReadOnlyArray, MemoryWriteOnlyArray, ABC): + """ + base class for a array of read and write memories + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: AddressMap, + address: int, + stride: int, + dimensions: tuple[int, ...]): + + if not isinstance(parent, AddressMap): + raise TypeError(f'parent should be either AddressMap got {type(parent)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, + stride=stride, dimensions=dimensions) + + +ReadableMemory = Union[MemoryReadOnly, MemoryReadWrite] +WritableMemory = Union[MemoryWriteOnly, MemoryReadWrite] +ReadableMemoryLegacy = Union[MemoryReadOnlyLegacy, MemoryReadWriteLegacy] +WritableMemoryLegacy = Union[MemoryWriteOnlyLegacy, MemoryReadWriteLegacy] +MemoryArray = Union[MemoryReadOnlyArray, MemoryWriteOnlyArray, MemoryReadWriteArray] diff --git a/rdl/outputs/python/msk_top_regs/lib/register_and_field.py b/rdl/outputs/python/msk_top_regs/lib/register_and_field.py new file mode 100644 index 0000000..62df291 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/register_and_field.py @@ -0,0 +1,1189 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of classes used by the autogenerated code to represent +registers and fields +""" +from enum import Enum +from typing import Union, cast, Optional, TypeVar +from collections.abc import Generator, Iterator +from abc import ABC, abstractmethod +from contextlib import contextmanager +from array import array as Array +import sys +from warnings import warn + +from .base import AddressMap, RegFile +from .utility_functions import get_array_typecode +from .memory import MemoryReadOnly, MemoryWriteOnly, MemoryReadWrite, Memory, \ + ReadableMemory, WritableMemory +from .memory import MemoryReadOnlyLegacy, MemoryWriteOnlyLegacy, MemoryReadWriteLegacy +from .memory import ReadableMemoryLegacy, WritableMemoryLegacy +from .callbacks import NormalCallbackSet, NormalCallbackSetLegacy +from .base_register import BaseReg, BaseRegArray, RegisterWriteVerifyError +from .base_field import FieldEnum, FieldSizeProps, FieldMiscProps, \ + _FieldReadOnlyFramework, _FieldWriteOnlyFramework, FieldType + +# pylint: disable=duplicate-code +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self +# pylint: enable=duplicate-code + +# pylint: disable=duplicate-code +if sys.version_info >= (3, 10): + # type guarding was introduced in python 3.10 + from typing import TypeGuard +else: + from typing_extensions import TypeGuard +# pylint: enable=duplicate-code + +# pylint: disable=redefined-slots-in-subclass,too-many-lines + + +class Reg(BaseReg, ABC): + """ + base class of non-async register wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, RegFile, Memory, 'RegArray']): + + if not isinstance(parent, (AddressMap, RegFile, + MemoryReadOnly, MemoryWriteOnly, MemoryReadWrite, RegArray, + MemoryReadOnlyLegacy, MemoryWriteOnlyLegacy, + MemoryReadWriteLegacy)): + raise TypeError(f'bad parent type got: {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(address=address, width=width, accesswidth=accesswidth, + logger_handle=logger_handle, inst_name=inst_name, parent=parent) + + @property + def _callbacks(self) -> Union[NormalCallbackSet, NormalCallbackSetLegacy]: + # pylint: disable=protected-access + if self.parent is None: + raise RuntimeError('Parent must be set') + + if isinstance(self.parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + return self.parent._callbacks + + raise TypeError(f'unhandled parent callback type: {type(self.parent._callbacks)}') + + @property + @abstractmethod + def fields(self) -> Iterator[Union['FieldReadOnly', 'FieldWriteOnly', 'FieldReadWrite']]: + """ + generator that produces has all the fields within the register + """ + + +# pylint: disable-next=invalid-name +RegArrayElementType= TypeVar('RegArrayElementType', bound=BaseReg) + + +class RegArray(BaseRegArray, ABC): + """ + base class of register array wrappers + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + # pylint: disable=too-many-arguments,duplicate-code + + __slots__: list[str] = ['__in_context_manager', '__register_cache', + '__register_address_array'] + + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[AddressMap, RegFile, Memory], + width: int, + accesswidth: int, + address: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegArrayElementType]] = None): + + self.__in_context_manager: bool = False + self.__register_cache: Optional[Union[Array, list[int]]] = None + self.__register_address_array: Optional[list[int]] = None + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + + @property + def __empty_array_cache(self) -> Array: + return Array(get_array_typecode(self.width), self.__empty_list_cache) + + @property + def __empty_list_cache(self) -> list[int]: + return [0 for _ in range(self.__number_cache_entries)] + + def __block_read_legacy(self) -> Array: + """ + Read all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, NormalCallbackSetLegacy): + raise RuntimeError('This function should only be used with legacy callbacks') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + data_read = read_block_callback(addr=self.address, width=self.width, + accesswidth=self.accesswidth, + length=self.__number_cache_entries) + + if not isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an array') + + return data_read + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_array = self.__empty_array_cache + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry, address in enumerate(self.__register_address_array): + data_entry = read_callback(addr=address, + width=self.width, + accesswidth=self.accesswidth) + + data_array[entry] = data_entry + + return data_array + + raise RuntimeError('There is no usable callback') + + def __block_write_legacy(self, data: Array, verify: bool) -> None: + """ + Write all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, NormalCallbackSetLegacy): + raise RuntimeError('This function should only be used with legacy callbacks') + + write_block_callback = self._callbacks.write_block_callback + write_callback = self._callbacks.write_callback + + if write_block_callback is not None: + write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.width, + data=data) + + elif write_callback is not None: + # there is not write_block_callback defined so we must used individual write + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry_index, entry_data in enumerate(data): + entry_address = self.__register_address_array[entry_index] + write_callback(addr=entry_address, + width=self.width, + accesswidth=self.accesswidth, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + if verify: + read_back_verify_data = self.__block_read_legacy() + if read_back_verify_data != data: + raise RegisterWriteVerifyError('Read back block miss-match') + + def __block_read(self) -> list[int]: + """ + Read all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, NormalCallbackSet): + raise RuntimeError('This function should only be used with non-legacy callbacks') + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_block_callback is not None: + data_read = \ + read_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + length=self.__number_cache_entries) + + if not isinstance(data_read, list): + if isinstance(data_read, Array): + raise TypeError('The read block callback is expected to return an list, this ' + 'is likely to happen if you are using legacy callbacks without ' + 'NormalCallbackSetLegacy') + raise TypeError('The read block callback is expected to return an list') + return data_read + + if read_callback is not None: + # there is not read_block_callback defined so we must used individual read + data_list = self.__empty_list_cache + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry, address in enumerate(self.__register_address_array): + data_entry = read_callback(addr=address, + width=self.width, + accesswidth=self.accesswidth) + + data_list[entry] = data_entry + + return data_list + + raise RuntimeError('There is no usable callback') + + def __block_write(self, data: list[int], verify: bool) -> None: + """ + Write all the contents of the array in the most optimal way, ideally with a block operation + """ + if not isinstance(self._callbacks, NormalCallbackSet): + raise RuntimeError('This function should only be used with non-legacy callbacks') + + write_block_callback = self._callbacks.write_block_callback + write_callback = self._callbacks.write_callback + + if write_block_callback is not None: + write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.width, + data=data) + + elif write_callback is not None: + # there is not write_block_callback defined so we must used individual write + + if self.__register_address_array is None: + raise RuntimeError('This address array has not be initialised') + + for entry_index, entry_data in enumerate(data): + entry_address = self.__register_address_array[entry_index] + write_callback(addr=entry_address, + width=self.width, + accesswidth=self.accesswidth, + data=entry_data) + + else: + raise RuntimeError('No suitable callback') + + if verify: + read_back_verify_data = self.__block_read() + if read_back_verify_data != data: + raise RegisterWriteVerifyError('Read back block miss-match') + + def __cache_entry(self, addr: int, width: int, accesswidth: int) -> int: + """ + Validate the data provided and determine the cache entry + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + cache entry + + """ + if not isinstance(width, int): + raise TypeError(f'Width should be an int byt got {type(width)}') + if width != self.width: + raise ValueError('Requested Read width does not match the expected value') + if not isinstance(accesswidth, int): + raise TypeError(f'accesswidth should be an int byt got {type(accesswidth)}') + if accesswidth != self.accesswidth: + raise ValueError('Requested Read accesswidth does not match the expected value') + if not isinstance(addr, int): + raise TypeError(f'addr should be an int byt got {type(addr)}') + if not self.address <= addr < (self.address + self.size): + raise ValueError(f'Requested address 0x{addr:X} is out of range 0x{self.address:X} to ' + f'0x{self.address + self.size - (self.width >> 3):X}') + cache_entry = (addr - self.address) // (self.width >> 3) + if self.__register_address_array is None: + raise RuntimeError('The address table should always be populated here') + if self.__register_address_array[cache_entry] != addr: + raise RuntimeError(f'The calculated cache entry for address 0x{addr:X}') + return cache_entry + + def __cache_read(self, addr: int, width: int, accesswidth: int) -> int: + """ + Used to replace the normal callbacks with those that access the cache + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + value inputted by the used + """ + if self.__register_cache is None: + raise RuntimeError('The cache array should be initialised') + return self.__register_cache[self.__cache_entry(addr=addr, + width=width, + accesswidth=accesswidth)] + + def __cache_write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + Used to replace the normal callbacks with those that access the cache + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: value to be written to the register + + Returns: + None + """ + if not isinstance(data, int): + raise TypeError(f'Data should be an int byt got {type(data)}') + if self.__register_cache is None: + raise RuntimeError('The cache array should be initialised') + self.__register_cache[self.__cache_entry(addr=addr, + width=width, + accesswidth=accesswidth)] = data + + @property + def __cache_callbacks(self) -> NormalCallbackSet: + return NormalCallbackSet(read_callback=self.__cache_read, + write_callback=self.__cache_write) + + @property + def __number_cache_entries(self) -> int: + return self.size // (self.width >> 3) + + def __initialise_cache(self, skip_initial_read: bool) -> Union[Array, list[int]]: + if isinstance(self._callbacks, NormalCallbackSet): + if skip_initial_read: + return self.__empty_list_cache + return self.__block_read() + + if isinstance(self._callbacks, NormalCallbackSetLegacy): + if skip_initial_read: + return self.__empty_array_cache + return self.__block_read_legacy() + + raise TypeError('Unhandled callback type') + + @contextmanager + def _cached_access(self, verify: bool = False, skip_write: bool = False, + skip_initial_read: bool = False) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + """ + self.__register_address_array = \ + [self.address + (i * (self.width >> 3)) for i in range(self.__number_cache_entries)] + self.__register_cache = self.__initialise_cache(skip_initial_read=skip_initial_read) + self.__in_context_manager = True + # this try/finally is needed to make sure that in the event of an exception + # the state flags are not left incorrectly set + try: + yield self + finally: + self.__in_context_manager = False + if not skip_write: + if isinstance(self._callbacks, NormalCallbackSet): + if not isinstance(self.__register_cache, list): + raise TypeError('Register cache should be a list in non-legacy mode') + self.__block_write(self.__register_cache, verify) + if isinstance(self._callbacks, NormalCallbackSetLegacy): + if not isinstance(self.__register_cache, Array): + raise TypeError('Register cache should be a Array in legacy mode') + self.__block_write_legacy(self.__register_cache, verify) + + # clear the register states at the end of the context manager + self.__register_address_array = None + self.__register_cache = None + + @property + def _callbacks(self) -> NormalCallbackSet: + + if self.__in_context_manager: + return self.__cache_callbacks + + if self.parent is None: + raise RuntimeError('Parent must be set') + # This cast is OK because the type was checked in the __init__ + # pylint: disable-next=protected-access + return cast(NormalCallbackSet, self.parent._callbacks) + + +class RegReadOnly(Reg, ABC): + """ + class for a read only register + + Args: + address: address of the register + width: width of the register in bits + accesswidth: minimum access width of the register in bits + logger_handle: name to be used logging messages associate with this + object + + """ + + __slots__: list[str] = ['__in_context_manager', '__register_state'] + + # pylint: disable=too-many-arguments, duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, RegFile, ReadableMemory, ReadableMemoryLegacy ]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + + self.__in_context_manager: bool = False + self.__register_state: int = 0 + + # pylint: enable=too-many-arguments, duplicate-code + + @contextmanager + def single_read(self) -> Generator[Self]: + """ + Context manager to allow multiple field accesses to be performed with a single + read of the register + """ + self.__register_state = self.read() + self.__in_context_manager = True + # this try/finally is needed to make sure that in the event of an exception + # the state flags are not left incorrectly set + try: + yield self + finally: + self.__in_context_manager = False + + def read(self) -> int: + """ + Read value from the register + """ + if self.__in_context_manager: + return self.__register_state + + read_block_callback = self._callbacks.read_block_callback + read_callback = self._callbacks.read_callback + + if read_callback is not None: + return read_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth) + + if read_block_callback is not None: + return read_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + length=1)[0] + + raise RuntimeError('This function does not have a useable callback') + + @property + def readable_fields(self) -> Iterator[Union['FieldReadOnly', 'FieldReadWrite']]: + """ + generator that produces has all the readable fields within the register + """ + def is_readable(field: Union['FieldReadOnly', 'FieldWriteOnly', 'FieldReadWrite']) -> \ + TypeGuard[Union['FieldReadOnly', 'FieldReadWrite']]: + return isinstance(field, (FieldReadOnly, FieldReadWrite)) + + return filter(is_readable, self.fields) + + def read_fields(self) -> dict['str', Union[bool, Enum, int]]: + """ + read the register and return a dictionary of the field values + """ + return_dict: dict['str', Union[bool, Enum, int]] = {} + with self.single_read() as reg: + for field in reg.readable_fields: + return_dict[field.inst_name] = field.read() + + return return_dict + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return True + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return False + + +class RegWriteOnly(Reg, ABC): + """ + class for a write only register + """ + + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments, duplicate-code, useless-parent-delegation + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, RegFile, WritableMemory, WritableMemoryLegacy]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + # pylint: enable=too-many-arguments, duplicate-code + + def write(self, data: int) -> None: + """Writes a value to the register + + Args: + data: data to be written + + Raises: + ValueError: if the value provided is outside the range of the + permissible values for the register + TypeError: if the type of data is wrong + """ + # this method check the types and range checks the data + self._validate_data(data=data) + + self._logger.info('Writing data:%X to %X', data, self.address) + + if self._callbacks.write_callback is not None: + self._callbacks.write_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=data) # + + elif self._callbacks.write_block_callback is not None: + if isinstance(self._callbacks, NormalCallbackSetLegacy): + data_as_array = Array(get_array_typecode(self.width), [data]) + self._callbacks.write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=data_as_array) + + if isinstance(self._callbacks, NormalCallbackSet): + self._callbacks.write_block_callback(addr=self.address, + width=self.width, + accesswidth=self.accesswidth, + data=[data]) + + else: + raise RuntimeError('This function does not have a useable callback') + + @property + def writable_fields(self) -> Iterator[Union['FieldWriteOnly', 'FieldReadWrite']]: + """ + generator that produces has all the readable fields within the register + """ + def is_writable(field: Union['FieldReadOnly', 'FieldWriteOnly', 'FieldReadWrite']) -> \ + TypeGuard[Union['FieldWriteOnly', 'FieldReadWrite']]: + return isinstance(field, (FieldWriteOnly, FieldReadWrite)) + + return filter(is_writable, self.fields) + + @abstractmethod + def write_fields(self, **kwargs) -> None: # type: ignore[no-untyped-def] + """ + Do a write to the register, updating any field included in + the arguments + """ + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return False + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return True + + +class RegReadWrite(RegReadOnly, RegWriteOnly, ABC): + """ + class for a read and write only register + + """ + __slots__: list[str] = ['__in_read_write_context_manager', '__in_read_context_manager', + '__register_state'] + + # pylint: disable=too-many-arguments, duplicate-code + def __init__(self, *, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AddressMap, RegFile, MemoryReadWrite, MemoryReadWriteLegacy]): + + super().__init__(address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent, width=width, accesswidth=accesswidth) + + self.__in_read_write_context_manager: bool = False + self.__in_read_context_manager: bool = False + self.__register_state: Optional[int] = None + + # pylint: enable=too-many-arguments, duplicate-code + + @contextmanager + def single_read_modify_write(self, verify: bool = False, skip_write: bool = False) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + + """ + if self.__in_read_context_manager: + raise RuntimeError('using the `single_read_modify_write` context manager within the ' + 'single_read` is not permitted') + + if skip_write is True: + warn('The `skip_write` argument will be removed in the future, use `single_read`' + ' instead', + DeprecationWarning, stacklevel=2) + + self.__register_state = self.read() + self.__in_read_write_context_manager = True + try: + yield self + finally: + # need to make sure the state flag is cleared even if an exception occurs within + # the context + self.__in_read_write_context_manager = False + + if not skip_write: + self.write(self.__register_state, verify) + + # clear the register states at the end of the context manager + self.__register_state = None + + @contextmanager + def single_read(self) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads with a single register read + """ + if self.__in_read_write_context_manager: + raise RuntimeError('using the `single_read` context manager within the ' + 'single_read_modify_write` is not permitted') + self.__in_read_context_manager = True + try: + with super().single_read() as reg: + yield reg + finally: + self.__in_read_context_manager = False + + def write(self, data: int, verify: bool = False) -> None: # pylint: disable=arguments-differ + """ + Writes a value to the register + + Args: + data: data to be written + verify: set to True to read back the register to verify the read has occurred correctly + + Raises: + ValueError: if the value provided is outside the range of the + permissible values for the register + TypeError: if the type of data is wrong + RegisterWriteVerifyError: the read back data after the write does not match the + expected value + """ + if self.__in_read_context_manager: + raise RuntimeError('writes within the single read context manager are not permitted') + + if self.__in_read_write_context_manager: + if self.__register_state is None: + raise RuntimeError('The internal register state should never be None in the ' + 'context manager') + self.__register_state = data + else: + super().write(data) + if verify: + read_back = self.read() + if read_back != data: + raise RegisterWriteVerifyError(f'Readback {read_back:X} ' + f'after writing {data:X}') + + def read(self) -> int: + """ + Read value from the register + """ + if self.__in_read_write_context_manager: + if self.__register_state is None: + raise RuntimeError('The internal register state should never be None in the ' + 'context manager') + return self.__register_state + + # the single read context manager is handled in the base class so does need any + # handling here + + return super().read() + + def write_fields(self, **kwargs) -> None: # type: ignore[no-untyped-def] + """ + Do a read-modify-write to the register, updating any field included in + the arguments + """ + if len(kwargs) == 0: + raise ValueError('no command args') + + with self.single_read_modify_write() as reg: + for field_name, field_value in kwargs.items(): + if field_name not in reg.systemrdl_python_child_name_map.values(): + raise ValueError(f'{field_name} is not a member of the register') + + field = getattr(reg, field_name) + field.write(field_value) + + def read_fields(self) -> dict['str', Union[bool, Enum, int]]: + """ + read the register and return a dictionary of the field values + """ + return_dict: dict['str', Union[bool, Enum, int]] = {} + with self.single_read() as reg: + for field in reg.readable_fields: + return_dict[field.inst_name] = field.read() + + return return_dict + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return True + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return True + + +ReadableRegister = Union[RegReadOnly, RegReadWrite] +WritableRegister = Union[RegWriteOnly, RegReadWrite] + + +class RegReadOnlyArray(RegArray, ABC): + """ + base class for a array of read only registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[RegFile, AddressMap, ReadableMemory, ReadableMemoryLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegReadOnly]] = None): + + if not isinstance(parent, (RegFile, AddressMap, MemoryReadOnly, MemoryReadWrite, + MemoryReadOnlyLegacy, MemoryReadWriteLegacy)): + raise TypeError('parent should be either RegFile, AddressMap, ' + 'MemoryReadOnly, MemoryReadWrite ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + # pylint: enable=too-many-arguments,duplicate-code + + @contextmanager + def single_read(self) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + """ + with self._cached_access(verify=False, skip_write=True, + skip_initial_read=False) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return True + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return False + + +class RegWriteOnlyArray(RegArray, ABC): + """ + base class for a array of write only registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[RegFile, AddressMap, WritableMemory, WritableMemoryLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegWriteOnly]] = None): + + if not isinstance(parent, (RegFile, AddressMap, MemoryWriteOnly, MemoryReadWrite, + MemoryWriteOnlyLegacy, MemoryReadWriteLegacy)): + raise TypeError('parent should be either RegFile, AddressMap, MemoryWriteOnly, ' + 'MemoryReadWrite ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + # pylint: enable=too-many-arguments,duplicate-code + + @contextmanager + def single_write(self) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + """ + with self._cached_access(verify=False, skip_write=False, + skip_initial_read=True) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return False + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return True + + +class RegReadWriteArray(RegArray, ABC): + """ + base class for a array of read and write registers + """ + __slots__: list[str] = [] + + # pylint: disable=too-many-arguments,duplicate-code + def __init__(self, *, + logger_handle: str, inst_name: str, + parent: Union[RegFile, AddressMap, MemoryReadWrite, MemoryReadWriteLegacy], + address: int, + width: int, + accesswidth: int, + stride: int, + dimensions: tuple[int, ...], + elements: Optional[dict[tuple[int, ...], RegReadWrite]] = None): + + if not isinstance(parent, (RegFile, AddressMap, MemoryReadWrite, MemoryReadWriteLegacy)): + raise TypeError('parent should be either RegFile, AddressMap, MemoryReadWrite ' + f'got {type(parent)}') + + if not isinstance(parent._callbacks, (NormalCallbackSet, NormalCallbackSetLegacy)): + raise TypeError(f'callback set type is wrong, got {type(parent._callbacks)}') + + super().__init__(logger_handle=logger_handle, inst_name=inst_name, + parent=parent, address=address, width=width, accesswidth=accesswidth, + stride=stride, dimensions=dimensions, elements=elements) + + # pylint: enable=too-many-arguments,duplicate-code + + @contextmanager + def single_read_modify_write(self, verify: bool = False, skip_write: bool = False) -> \ + Generator[Self]: + """ + Context manager to allow multiple field reads/write to be done with a single set of + field operations + + Args: + verify (bool): very the write with a read afterwards + skip_write (bool): skip the write back at the end + """ + with self._cached_access(verify=verify, skip_write=skip_write, + skip_initial_read=False) as reg_array: + yield reg_array + + @property + def _is_readable(self) -> bool: + # pylint: disable=duplicate-code + return True + + @property + def _is_writeable(self) -> bool: + # pylint: disable=duplicate-code + return True + + +ReadableRegisterArray = Union[RegReadOnlyArray, RegReadWriteArray] +WriteableRegisterArray = Union[RegWriteOnlyArray, RegReadWriteArray] + + +class FieldReadOnly(_FieldReadOnlyFramework[FieldType], ABC): + """ + class for a read only register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: ReadableRegister, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, (RegReadWrite, RegReadOnly)): + raise TypeError(f'size_props must be of {type(RegReadWrite)} or {type(RegReadOnly)} ' + f'but got {type(parent_register)}') + + # pylint: disable=duplicate-code + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + # pylint: enable=duplicate-code + + def read(self) -> FieldType: + """ + Reads the register that this field is located in and retries the field + value applying the required masking and shifting + + Returns: + field value + + """ + return self._decode_read_value(self.parent_register.read()) + + @property + def parent_register(self) -> ReadableRegister: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(ReadableRegister, self.parent) + + +class FieldWriteOnly(_FieldWriteOnlyFramework[FieldType], ABC): + """ + class for a write only register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: WritableRegister, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, (RegReadWrite, RegWriteOnly)): + raise TypeError(f'size_props must be of {type(RegReadWrite)} or {type(RegWriteOnly)} ' + f'but got {type(parent_register)}') + + # pylint: disable=duplicate-code + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + # pylint: enable=duplicate-code + + def write(self, value: FieldType) -> None: + """ + The behaviour of this method depends on whether the field is located in + a readable register or not: + + If the register is readable, the method will perform a read-modify-write + on the register updating the field with the value provided + + If the register is not writable all other field values will be written + with zero. + + Args: + value: field value to update to + + """ + encoded_value = self._encode_write_value(value) + + if (self.high == (self.register_data_width - 1)) and (self.low == 0): + # special case where the field occupies the whole register, + # there a straight write can be performed + new_reg_value = encoded_value + else: + # do a read, modify write + if isinstance(self.parent_register, RegReadWrite): + reg_value = self.parent_register.read() + masked_reg_value = reg_value & self.inverse_bitmask + new_reg_value = masked_reg_value | encoded_value + elif isinstance(self.parent_register, RegWriteOnly): + new_reg_value = encoded_value + else: + raise TypeError('Unhandled parent type') + + self.parent_register.write(new_reg_value) + + @property + def parent_register(self) -> WritableRegister: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(WritableRegister, self.parent) + + +class FieldReadWrite(FieldReadOnly[FieldType], FieldWriteOnly[FieldType], ABC): + """ + class for a read/write register field + + Args: + parent_register: register within which the field resides + size_props: object defining the msb, lsb, high bit, low bit and width + logger_handle: name to be used logging messages associate with this + object + + """ + __slots__: list[str] = [] + + # pylint: disable-next=too-many-arguments + def __init__(self, *, + parent_register: RegReadWrite, + size_props: FieldSizeProps, + misc_props: FieldMiscProps, + logger_handle: str, + inst_name: str, + field_type:type[FieldType]): + + if not isinstance(parent_register, RegReadWrite): + raise TypeError(f'parent_register must be of {type(RegReadWrite)} ' + f'but got {type(parent_register)}') + + super().__init__(logger_handle=logger_handle, + size_props=size_props, + misc_props=misc_props, + parent_register=parent_register, + inst_name=inst_name, + field_type=field_type) + + @property + def parent_register(self) -> RegReadWrite: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(RegReadWrite, self.parent) + + +class FieldEnumReadWrite(FieldReadWrite[FieldType], FieldEnum[FieldType], ABC): + """ + class for a read/write register field with an enumerated value + """ + __slots__: list[str] = [] + + @property + def parent_register(self) -> RegReadWrite: + """ + parent register the field is placed in + """ + + # this cast is OK because an explict typing check was done in the __init__ + return cast(RegReadWrite, self.parent) + + +class FieldEnumReadOnly(FieldReadOnly[FieldType], FieldEnum[FieldType], ABC): + """ + class for a read only register field with an enumerated value + """ + __slots__: list[str] = [] + + +class FieldEnumWriteOnly(FieldWriteOnly[FieldType], FieldEnum[FieldType], ABC): + """ + class for a write only register field with an enumerated value + """ + __slots__: list[str] = [] diff --git a/rdl/outputs/python/msk_top_regs/lib/utility_functions.py b/rdl/outputs/python/msk_top_regs/lib/utility_functions.py new file mode 100644 index 0000000..6c9113d --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/lib/utility_functions.py @@ -0,0 +1,83 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" + + +def swap_msb_lsb_ordering(width: int, value: int) -> int: + """ + swaps the msb/lsb on a integer + + Returns: + swapped value + """ + value_to_return = 0 + for bit_positions in zip(range(0, width), range(width-1, -1, -1)): + bit_value = (value >> bit_positions[0]) & 0x1 + value_to_return |= bit_value << bit_positions[1] + + return value_to_return + + +class UnsupportedWidthError(Exception): + """ + Exception for width that can not be supported in the legacy array based API + """ + + +def get_array_typecode(width: int) -> str: + """ + python array typecode + + Args: + width: in bits + + Returns: + string to pass into the array generator + + """ + if width == 32: + return 'L' + + if width == 64: + return 'Q' + + if width == 16: + return 'I' + + if width == 8: + return 'B' + + raise UnsupportedWidthError(f'unhandled width {width:d}, consider using the new new list ' + f'based API and callbacks rather than the legacy Array versions') + + +def is_power_two(value: int) -> bool: + """ + efficient algorithm for checking if something is a power of two + """ + return (value != 0) and ((value & (value - 1)) == 0) + + +def legal_register_width(width_in_bits: int) -> bool: + """ + check if a register width is legal, see the system RDL specification 10.1 e) and f) + must be a power of 2 and greater than 8 + """ + return (width_in_bits >= 8) and is_power_two(width_in_bits) diff --git a/rdl/outputs/python/msk_top_regs/reg_model/__init__.py b/rdl/outputs/python/msk_top_regs/reg_model/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/reg_model/__init__.py @@ -0,0 +1 @@ +pass diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py new file mode 100644 index 0000000..8ea7fa8 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -0,0 +1,9451 @@ + + + +""" +Python Wrapper for the msk_top_regs register model + +This code was generated from the PeakRDL-python package version 1.4.0 + +""" + + +from enum import unique +from typing import Iterator +from typing import Optional +from typing import Union +from typing import Type +from typing import overload +from typing import Literal +from typing import Any +from typing import NoReturn +from typing import AsyncGenerator + +import warnings + + + +from contextlib import asynccontextmanager + +from ..lib import Node, Base +from ..lib import UDPStruct + +from ..lib import AddressMapArray, RegFileArray +from ..lib import AsyncMemory, AsyncMemoryArray +from ..lib import AsyncAddressMap +from ..lib import AsyncRegFile +from ..lib import AsyncAddressMapArray +from ..lib import AsyncRegFileArray +from ..lib import MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite +from ..lib import MemoryAsyncReadOnlyArray, MemoryAsyncWriteOnlyArray, MemoryAsyncReadWriteArray +from ..lib import AsyncReg, AsyncRegArray +from ..lib import RegAsyncReadOnly, RegAsyncWriteOnly, RegAsyncReadWrite +from ..lib import RegAsyncReadOnlyArray, RegAsyncWriteOnlyArray, RegAsyncReadWriteArray +from ..lib import FieldAsyncReadOnly, FieldAsyncWriteOnly, FieldAsyncReadWrite, Field + +from ..lib import ReadableAsyncRegister, WritableAsyncRegister +from ..lib import ReadableAsyncMemory, WritableAsyncMemory +from ..lib import ReadableAsyncRegisterArray, WriteableAsyncRegisterArray +from ..lib import FieldSizeProps, FieldMiscProps + + +from ..lib import SystemRDLEnum, SystemRDLEnumEntry + + + +from ..lib import AsyncCallbackSet, AsyncCallbackSetLegacy + + + + + + + + + + + + + + + + + + + +# regfile, register and field definitions + + + +class msk_top_regs_rx_power_rx_power_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Receive Power | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value that represent the RMS power of the incoming I;

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Receive Power" + @property + def rdl_desc(self) -> str: + return "Value that represent the RMS power of the incoming I;" + + + + + + +class msk_top_regs_rx_power_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Receive Power | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Receive power computed from I/Q ssamples

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__rx_power'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__rx_power:msk_top_regs_rx_power_rx_power_cls = msk_top_regs_rx_power_rx_power_cls( + parent_register=self, + size_props=FieldSizeProps( + width=23, + lsb=0, + msb=22, + low=0, + high=22), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.rx_power', + inst_name='rx_power', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.rx_power + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def rx_power(self) -> msk_top_regs_rx_power_rx_power_cls: + """ + Property to access rx_power field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Receive Power | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value that represent the RMS power of the incoming I;

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_power + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'rx_power':'rx_power', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_rx_power_rx_power_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Receive Power" + @property + def rdl_desc(self) -> str: + return "Receive power computed from I/Q ssamples" + + + + + + + +class msk_top_regs_lowpass_ema_alpha_alpha_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | EMA alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "EMA alpha" + @property + def rdl_desc(self) -> str: + return "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha" + + + + + + +class msk_top_regs_lowpass_ema_alpha_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Exponential Moving Average Alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the alpha for the EMA

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__alpha'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_cls = msk_top_regs_lowpass_ema_alpha_alpha_cls( + parent_register=self, + size_props=FieldSizeProps( + width=18, + lsb=0, + msb=17, + low=0, + high=17), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.alpha', + inst_name='alpha', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.alpha + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_cls: + """ + Property to access alpha field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | EMA alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__alpha + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'alpha':'alpha', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Exponential Moving Average Alpha" + @property + def rdl_desc(self) -> str: + return "Sets the alpha for the EMA" + + + + + + + +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | EMA alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "EMA alpha" + @property + def rdl_desc(self) -> str: + return "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha" + + + + + + +class msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Exponential Moving Average Alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the alpha for the EMA

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__alpha'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls( + parent_register=self, + size_props=FieldSizeProps( + width=18, + lsb=0, + msb=17, + low=0, + high=17), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.alpha', + inst_name='alpha', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.alpha + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls: + """ + Property to access alpha field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | EMA alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__alpha + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'alpha':'alpha', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Exponential Moving Average Alpha" + @property + def rdl_desc(self) -> str: + return "Sets the alpha for the EMA" + + + + + + + +class msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx sync duration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x00_0000 to 0xFF_FFFF. This value represents the | + | | number bit-times the synchronization signal should be sent after | + | | PTT is asserted.

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx sync duration" + @property + def rdl_desc(self) -> str: + return "Value from 0x00_0000 to 0xFF_FFFF. \nThis value represents the number bit-times the synchronization \nsignal should be sent after PTT is asserted." + + + + + + +class msk_top_regs_tx_sync_cnt_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Transmitter Sync Duration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the duration of the synchronization tones when enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__tx_sync_cnt'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__tx_sync_cnt:msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls = msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls( + parent_register=self, + size_props=FieldSizeProps( + width=24, + lsb=0, + msb=23, + low=0, + high=23), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.tx_sync_cnt', + inst_name='tx_sync_cnt', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.tx_sync_cnt + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def tx_sync_cnt(self) -> msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls: + """ + Property to access tx_sync_cnt field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx sync duration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value from 0x00_0000 to 0xFF_FFFF. This value represents the | + | | number bit-times the synchronization signal should be sent after | + | | PTT is asserted.

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_sync_cnt + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'tx_sync_cnt':'tx_sync_cnt', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Transmitter Sync Duration" + @property + def rdl_desc(self) -> str: + return "Sets the duration of the synchronization tones when enabled" + + + + + + + +class msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F2 Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Enables/Disables transmission of F2 tone for receiver | + | | synchronization 0 : F2 tone transmission disabled 1 : F2 tone | + | | transmission enabled Both F1 and F2 can be enabled at the same | + | | time

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx F2 Sync Enable" + @property + def rdl_desc(self) -> str: + return "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n1 : F2 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time" + + + + + + + +class msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F1 Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Enables/Disables transmission of F1 tone for receiver | + | | synchronization 0 : F1 tone transmission disabled 1 : F1 tone | + | | transmission enabled Both F1 and F2 can be enabled at the same | + | | time

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx F1 Sync Enable" + @property + def rdl_desc(self) -> str: + return "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n1 : F1 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time" + + + + + + + +class msk_top_regs_tx_sync_ctrl_tx_sync_force_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Sync Force | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 : Normal operation) 1 : Transmit synchronization pattern)

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx Sync Force" + @property + def rdl_desc(self) -> str: + return "0 : Normal operation)\n1 : Transmit synchronization pattern)" + + + + + + + +class msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Disable sync transmission 1 -> Enable sync | + | | transmission when PTT is asserted

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx Sync Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Disable sync transmission\n1 -\u003e Enable sync transmission when PTT is asserted" + + + + + + +class msk_top_regs_tx_sync_ctrl_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Transmitter Sync Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Provides control bits for generation of transmitter | + | | synchronization patterns

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__tx_sync_ena', '__tx_sync_force', '__tx_sync_f1', '__tx_sync_f2'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__tx_sync_ena:msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls = msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.tx_sync_ena', + inst_name='tx_sync_ena', + field_type=int) + self.__tx_sync_force:msk_top_regs_tx_sync_ctrl_tx_sync_force_cls = msk_top_regs_tx_sync_ctrl_tx_sync_force_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.tx_sync_force', + inst_name='tx_sync_force', + field_type=int) + self.__tx_sync_f1:msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls = msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=2, + msb=2, + low=2, + high=2), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.tx_sync_f1', + inst_name='tx_sync_f1', + field_type=int) + self.__tx_sync_f2:msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls = msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=3, + msb=3, + low=3, + high=3), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.tx_sync_f2', + inst_name='tx_sync_f2', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.tx_sync_ena + yield self.tx_sync_force + yield self.tx_sync_f1 + yield self.tx_sync_f2 + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def tx_sync_ena(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls: + """ + Property to access tx_sync_ena field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Disable sync transmission 1 -> Enable sync | + | | transmission when PTT is asserted

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_sync_ena + @property + def tx_sync_force(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_force_cls: + """ + Property to access tx_sync_force field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Sync Force | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 : Normal operation) 1 : Transmit synchronization pattern)

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_sync_force + @property + def tx_sync_f1(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls: + """ + Property to access tx_sync_f1 field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F1 Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Enables/Disables transmission of F1 tone for receiver | + | | synchronization 0 : F1 tone transmission disabled 1 : F1 tone | + | | transmission enabled Both F1 and F2 can be enabled at the same | + | | time

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_sync_f1 + @property + def tx_sync_f2(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls: + """ + Property to access tx_sync_f2 field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F2 Sync Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Enables/Disables transmission of F2 tone for receiver | + | | synchronization 0 : F2 tone transmission disabled 1 : F2 tone | + | | transmission enabled Both F1 and F2 can be enabled at the same | + | | time

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_sync_f2 + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'tx_sync_ena':'tx_sync_ena','tx_sync_force':'tx_sync_force','tx_sync_f1':'tx_sync_f1','tx_sync_f2':'tx_sync_f2', + } + + + + + + + + # nodes:4 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_sync_ena"]) -> msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_sync_force"]) -> msk_top_regs_tx_sync_ctrl_tx_sync_force_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_sync_f1"]) -> msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_sync_f2"]) -> msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls, msk_top_regs_tx_sync_ctrl_tx_sync_force_cls, msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls, msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "Transmitter Sync Control" + @property + def rdl_desc(self) -> str: + return "Provides control bits for generation of transmitter synchronization patterns" + + + + + + + +class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F2 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "F2 Error Value" + @property + def rdl_desc(self) -> str: + return "Error value of the F2 Costas loop after each active bit period" + + + + + + +class msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F2 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls = msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F2 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F2 Error Value" + @property + def rdl_desc(self) -> str: + return "Error value of the F2 Costas loop after each active bit period" + + + + + + + +class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F1 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "F1 Error Value" + @property + def rdl_desc(self) -> str: + return "Error value of the F1 Costas loop after each active bit period" + + + + + + +class msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F1 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_417e1c96_name_3b640507_cls = msk_top_regs_data32_desc_417e1c96_name_3b640507_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_417e1c96_name_3b640507_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F1 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_417e1c96_name_3b640507_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F1 Error Value" + @property + def rdl_desc(self) -> str: + return "Error value of the F1 Costas loop after each active bit period" + + + + + + + +class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F2 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "F2 NCO Frequency Adjust" + @property + def rdl_desc(self) -> str: + return "Frequency offet applied to the F2 NCO" + + + + + + +class msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F2 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls = msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F2 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F2 NCO Frequency Adjust" + @property + def rdl_desc(self) -> str: + return "Frequency offet applied to the F2 NCO" + + + + + + + +class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F1 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "F1 NCO Frequency Adjust" + @property + def rdl_desc(self) -> str: + return "Frequency offet applied to the F1 NCO" + + + + + + +class msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F1 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls = msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F1 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F1 NCO Frequency Adjust" + @property + def rdl_desc(self) -> str: + return "Frequency offet applied to the F1 NCO" + + + + + + + +class msk_top_regs_lpf_config_2_p_shift_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Proportional Gain Bit Shift | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value n of 0-32 sets the proportional divisor as 2^-n

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Proportional Gain Bit Shift" + @property + def rdl_desc(self) -> str: + return "Value n of 0-32 sets the proportional divisor as 2^-n" + + + + + + + +class msk_top_regs_lpf_config_2_p_gain_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Proportional Gain Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value m of 0-16,777,215 sets the proportional multiplier

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Proportional Gain Value" + @property + def rdl_desc(self) -> str: + return "Value m of 0-16,777,215 sets the proportional multiplier" + + + + + + +class msk_top_regs_lpf_config_2_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration Configuration Register 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures PI Controller I-gain and divisor

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__p_gain', '__p_shift'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__p_gain:msk_top_regs_lpf_config_2_p_gain_cls = msk_top_regs_lpf_config_2_p_gain_cls( + parent_register=self, + size_props=FieldSizeProps( + width=24, + lsb=0, + msb=23, + low=0, + high=23), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.p_gain', + inst_name='p_gain', + field_type=int) + self.__p_shift:msk_top_regs_lpf_config_2_p_shift_cls = msk_top_regs_lpf_config_2_p_shift_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=24, + msb=31, + low=24, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.p_shift', + inst_name='p_shift', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.p_gain + yield self.p_shift + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def p_gain(self) -> msk_top_regs_lpf_config_2_p_gain_cls: + """ + Property to access p_gain field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Proportional Gain Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value m of 0-16,777,215 sets the proportional multiplier

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__p_gain + @property + def p_shift(self) -> msk_top_regs_lpf_config_2_p_shift_cls: + """ + Property to access p_shift field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Proportional Gain Bit Shift | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value n of 0-32 sets the proportional divisor as 2^-n

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__p_shift + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'p_gain':'p_gain','p_shift':'p_shift', + } + + + + + + + + # nodes:2 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["p_gain"]) -> msk_top_regs_lpf_config_2_p_gain_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["p_shift"]) -> msk_top_regs_lpf_config_2_p_shift_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_lpf_config_2_p_gain_cls, msk_top_regs_lpf_config_2_p_shift_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "PI Controller Configuration Configuration Register 2" + @property + def rdl_desc(self) -> str: + return "Configures PI Controller I-gain and divisor" + + + + + + + +class msk_top_regs_rx_sample_discard_rx_nco_discard_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx NCO Sample Discard Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of NCO samples to discard

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Rx NCO Sample Discard Value" + @property + def rdl_desc(self) -> str: + return "Number of NCO samples to discard" + + + + + + + +class msk_top_regs_rx_sample_discard_rx_sample_discard_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Sample Discard Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of Rx samples to discard

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Rx Sample Discard Value" + @property + def rdl_desc(self) -> str: + return "Number of Rx samples to discard" + + + + + + +class msk_top_regs_rx_sample_discard_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Sample Discard | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configure samples discard operation for demodulator

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__rx_sample_discard', '__rx_nco_discard'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__rx_sample_discard:msk_top_regs_rx_sample_discard_rx_sample_discard_cls = msk_top_regs_rx_sample_discard_rx_sample_discard_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=0, + msb=7, + low=0, + high=7), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.rx_sample_discard', + inst_name='rx_sample_discard', + field_type=int) + self.__rx_nco_discard:msk_top_regs_rx_sample_discard_rx_nco_discard_cls = msk_top_regs_rx_sample_discard_rx_nco_discard_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=8, + msb=15, + low=8, + high=15), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.rx_nco_discard', + inst_name='rx_nco_discard', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.rx_sample_discard + yield self.rx_nco_discard + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def rx_sample_discard(self) -> msk_top_regs_rx_sample_discard_rx_sample_discard_cls: + """ + Property to access rx_sample_discard field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Sample Discard Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of Rx samples to discard

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_sample_discard + @property + def rx_nco_discard(self) -> msk_top_regs_rx_sample_discard_rx_nco_discard_cls: + """ + Property to access rx_nco_discard field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx NCO Sample Discard Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of NCO samples to discard

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_nco_discard + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'rx_sample_discard':'rx_sample_discard','rx_nco_discard':'rx_nco_discard', + } + + + + + + + + # nodes:2 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_sample_discard"]) -> msk_top_regs_rx_sample_discard_rx_sample_discard_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_nco_discard"]) -> msk_top_regs_rx_sample_discard_rx_nco_discard_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_rx_sample_discard_rx_sample_discard_cls, msk_top_regs_rx_sample_discard_rx_nco_discard_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "Rx Sample Discard" + @property + def rdl_desc(self) -> str: + return "Configure samples discard operation for demodulator" + + + + + + + +class msk_top_regs_msk_stat_3_xfer_count_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | S_AXIS Transfers | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number completed S_AXIS transfers

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "S_AXIS Transfers" + @property + def rdl_desc(self) -> str: + return "Number completed S_AXIS transfers" + + + + + + +class msk_top_regs_msk_stat_3_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 3 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__xfer_count'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__xfer_count:msk_top_regs_msk_stat_3_xfer_count_cls = msk_top_regs_msk_stat_3_xfer_count_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.xfer_count', + inst_name='xfer_count', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.xfer_count + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def xfer_count(self) -> msk_top_regs_msk_stat_3_xfer_count_cls: + """ + Property to access xfer_count field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | S_AXIS Transfers | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number completed S_AXIS transfers

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__xfer_count + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'xfer_count':'xfer_count', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_3_xfer_count_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Status 3" + @property + def rdl_desc(self) -> str: + return "Modem status data" + + + + + + + +class msk_top_regs_stat_32_lpf_acc_status_data_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Accumulator Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PI Controller Accumulator Value

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PI Controller Accumulator Value" + @property + def rdl_desc(self) -> str: + return "PI Controller Accumulator Value" + + + + + + +class msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 PI Controller Accumulator | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value of the F2 PI Controller Accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__status_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_cls = msk_top_regs_stat_32_lpf_acc_status_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.status_data', + inst_name='status_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.status_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_cls: + """ + Property to access status_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Accumulator Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PI Controller Accumulator Value

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__status_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'status_data':'status_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F2 PI Controller Accumulator" + @property + def rdl_desc(self) -> str: + return "Value of the F2 PI Controller Accumulator" + + + + + + + +class msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Accumulator Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PI Controller Accumulator Value

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PI Controller Accumulator Value" + @property + def rdl_desc(self) -> str: + return "PI Controller Accumulator Value" + + + + + + +class msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 PI Controller Accumulator | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value of the F1 PI Controller Accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__status_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.status_data', + inst_name='status_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.status_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls: + """ + Property to access status_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Accumulator Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PI Controller Accumulator Value

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__status_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'status_data':'status_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "F1 PI Controller Accumulator" + @property + def rdl_desc(self) -> str: + return "Value of the F1 PI Controller Accumulator" + + + + + + + +class msk_top_regs_stat_32_errs_status_data_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Bit Errors | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of errored-bits received by the PRBS monitor since last | + | | sync BER can be calculated as the ratio of received bits to | + | | errored-bits

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Bit Errors" + @property + def rdl_desc(self) -> str: + return "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits" + + + + + + +class msk_top_regs_stat_32_errs_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Status 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Bit Errors

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__status_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__status_data:msk_top_regs_stat_32_errs_status_data_cls = msk_top_regs_stat_32_errs_status_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.status_data', + inst_name='status_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.status_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def status_data(self) -> msk_top_regs_stat_32_errs_status_data_cls: + """ + Property to access status_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Bit Errors | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of errored-bits received by the PRBS monitor since last | + | | sync BER can be calculated as the ratio of received bits to | + | | errored-bits

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__status_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'status_data':'status_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_errs_status_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Status 1" + @property + def rdl_desc(self) -> str: + return "PRBS Bit Errors" + + + + + + + +class msk_top_regs_stat_32_bits_status_data_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Bits Received | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of bits received by the PRBS monitor since last BER can | + | | be calculated as the ratio of received bits to errored-bits

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Bits Received" + @property + def rdl_desc(self) -> str: + return "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits" + + + + + + +class msk_top_regs_stat_32_bits_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Status 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Bits Received

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__status_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__status_data:msk_top_regs_stat_32_bits_status_data_cls = msk_top_regs_stat_32_bits_status_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.status_data', + inst_name='status_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.status_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def status_data(self) -> msk_top_regs_stat_32_bits_status_data_cls: + """ + Property to access status_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Bits Received | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of bits received by the PRBS monitor since last BER can | + | | be calculated as the ratio of received bits to errored-bits

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__status_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'status_data':'status_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_bits_status_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Status 0" + @property + def rdl_desc(self) -> str: + return "PRBS Bits Received" + + + + + + + +class msk_top_regs_config_prbs_errmask_config_data_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Error Mask | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Bit positions set to '1' indicate bits that are inverted when a | + | | bit error is inserted

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Error Mask" + @property + def rdl_desc(self) -> str: + return "Bit positions set to \u00271\u0027 indicate bits that are inverted when a bit error is inserted" + + + + + + +class msk_top_regs_config_prbs_errmask_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 3 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Error Mask

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_prbs_errmask_config_data_cls = msk_top_regs_config_prbs_errmask_config_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_prbs_errmask_config_data_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Error Mask | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Bit positions set to '1' indicate bits that are inverted when a | + | | bit error is inserted

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_prbs_errmask_config_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Control 3" + @property + def rdl_desc(self) -> str: + return "PRBS Error Mask" + + + + + + + +class msk_top_regs_config_prbs_poly_config_data_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Polynomial | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Bit positions set to '1' indicate polynomial feedback | + | | positions

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Polynomial" + @property + def rdl_desc(self) -> str: + return "Bit positions set to \u00271\u0027 indicate polynomial feedback positions" + + + + + + +class msk_top_regs_config_prbs_poly_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Polynomial

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_prbs_poly_config_data_cls = msk_top_regs_config_prbs_poly_config_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_prbs_poly_config_data_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Polynomial | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Bit positions set to '1' indicate polynomial feedback | + | | positions

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_prbs_poly_config_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Control 2" + @property + def rdl_desc(self) -> str: + return "PRBS Polynomial" + + + + + + + +class msk_top_regs_config_prbs_seed_config_data_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Seed | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the starting value of the PRBS generator

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Seed" + @property + def rdl_desc(self) -> str: + return "Sets the starting value of the PRBS generator" + + + + + + +class msk_top_regs_config_prbs_seed_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Initial State

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_prbs_seed_config_data_cls = msk_top_regs_config_prbs_seed_config_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_prbs_seed_config_data_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Seed | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the starting value of the PRBS generator

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_prbs_seed_config_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Control 1" + @property + def rdl_desc(self) -> str: + return "PRBS Initial State" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Auto Sync Threshold | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 : Auto Sync Disabled N > 0 : Auto sync after N errors

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Auto Sync Threshold" + @property + def rdl_desc(self) -> str: + return "0 : Auto Sync Disabled\nN \u003e 0 : Auto sync after N errors" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_reserved_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Reserved | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Reserved" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_manual_sync_cls(FieldAsyncWriteOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Manual Sync | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Synchronize PRBS monitor 1 -> 0 : Synchronize | + | | PRBS monitor

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Manual Sync" + @property + def rdl_desc(self) -> str: + return "0 -\u003e 1 : Synchronize PRBS monitor\n1 -\u003e 0 : Synchronize PRBS monitor" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_clear_cls(FieldAsyncWriteOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Clear Counters | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Clear PRBS Counters 1 -> 0 : Clear PRBS | + | | Counters

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Clear Counters" + @property + def rdl_desc(self) -> str: + return "0 -\u003e 1 : Clear PRBS Counters\n1 -\u003e 0 : Clear PRBS Counters" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_error_insert_cls(FieldAsyncWriteOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Error Insert | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) | + | | 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Error Insert" + @property + def rdl_desc(self) -> str: + return "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)" + + + + + + + +class msk_top_regs_prbs_ctrl_prbs_sel_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Data Select | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Select Normal Tx Data 1 -> Select PRBS Tx Data

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Data Select" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Select Normal Tx Data\n1 -\u003e Select PRBS Tx Data" + + + + + + +class msk_top_regs_prbs_ctrl_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures operation of the PRBS Generator and Monitor

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__prbs_sel', '__prbs_error_insert', '__prbs_clear', '__prbs_manual_sync', '__prbs_reserved', '__prbs_sync_threshold'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__prbs_sel:msk_top_regs_prbs_ctrl_prbs_sel_cls = msk_top_regs_prbs_ctrl_prbs_sel_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_sel', + inst_name='prbs_sel', + field_type=int) + self.__prbs_error_insert:msk_top_regs_prbs_ctrl_prbs_error_insert_cls = msk_top_regs_prbs_ctrl_prbs_error_insert_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_error_insert', + inst_name='prbs_error_insert', + field_type=int) + self.__prbs_clear:msk_top_regs_prbs_ctrl_prbs_clear_cls = msk_top_regs_prbs_ctrl_prbs_clear_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=2, + msb=2, + low=2, + high=2), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_clear', + inst_name='prbs_clear', + field_type=int) + self.__prbs_manual_sync:msk_top_regs_prbs_ctrl_prbs_manual_sync_cls = msk_top_regs_prbs_ctrl_prbs_manual_sync_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=3, + msb=3, + low=3, + high=3), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_manual_sync', + inst_name='prbs_manual_sync', + field_type=int) + self.__prbs_reserved:msk_top_regs_prbs_ctrl_prbs_reserved_cls = msk_top_regs_prbs_ctrl_prbs_reserved_cls( + parent_register=self, + size_props=FieldSizeProps( + width=12, + lsb=4, + msb=15, + low=4, + high=15), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_reserved', + inst_name='prbs_reserved', + field_type=int) + self.__prbs_sync_threshold:msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls = msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls( + parent_register=self, + size_props=FieldSizeProps( + width=16, + lsb=16, + msb=31, + low=16, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_sync_threshold', + inst_name='prbs_sync_threshold', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.prbs_sel + yield self.prbs_error_insert + yield self.prbs_clear + yield self.prbs_manual_sync + yield self.prbs_reserved + yield self.prbs_sync_threshold + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def prbs_sel(self) -> msk_top_regs_prbs_ctrl_prbs_sel_cls: + """ + Property to access prbs_sel field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Data Select | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Select Normal Tx Data 1 -> Select PRBS Tx Data

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_sel + @property + def prbs_error_insert(self) -> msk_top_regs_prbs_ctrl_prbs_error_insert_cls: + """ + Property to access prbs_error_insert field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Error Insert | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) | + | | 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_error_insert + @property + def prbs_clear(self) -> msk_top_regs_prbs_ctrl_prbs_clear_cls: + """ + Property to access prbs_clear field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Clear Counters | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Clear PRBS Counters 1 -> 0 : Clear PRBS | + | | Counters

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_clear + @property + def prbs_manual_sync(self) -> msk_top_regs_prbs_ctrl_prbs_manual_sync_cls: + """ + Property to access prbs_manual_sync field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Manual Sync | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> 1 : Synchronize PRBS monitor 1 -> 0 : Synchronize | + | | PRBS monitor

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_manual_sync + @property + def prbs_reserved(self) -> msk_top_regs_prbs_ctrl_prbs_reserved_cls: + """ + Property to access prbs_reserved field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Reserved | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_reserved + @property + def prbs_sync_threshold(self) -> msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls: + """ + Property to access prbs_sync_threshold field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Auto Sync Threshold | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 : Auto Sync Disabled N > 0 : Auto sync after N errors

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_sync_threshold + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'prbs_sel':'prbs_sel','prbs_error_insert':'prbs_error_insert','prbs_clear':'prbs_clear','prbs_manual_sync':'prbs_manual_sync','prbs_reserved':'prbs_reserved','prbs_sync_threshold':'prbs_sync_threshold', + } + + + + + + + + # nodes:6 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_sel"]) -> msk_top_regs_prbs_ctrl_prbs_sel_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_error_insert"]) -> msk_top_regs_prbs_ctrl_prbs_error_insert_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_clear"]) -> msk_top_regs_prbs_ctrl_prbs_clear_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_manual_sync"]) -> msk_top_regs_prbs_ctrl_prbs_manual_sync_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_reserved"]) -> msk_top_regs_prbs_ctrl_prbs_reserved_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_sync_threshold"]) -> msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_prbs_ctrl_prbs_sel_cls, msk_top_regs_prbs_ctrl_prbs_error_insert_cls, msk_top_regs_prbs_ctrl_prbs_clear_cls, msk_top_regs_prbs_ctrl_prbs_manual_sync_cls, msk_top_regs_prbs_ctrl_prbs_reserved_cls, msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "PRBS Control 0" + @property + def rdl_desc(self) -> str: + return "Configures operation of the PRBS Generator and Monitor" + + + + + + + +class msk_top_regs_data_width_data_width_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem input/output data width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the data width of the modem input/output

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Modem input/output data width" + @property + def rdl_desc(self) -> str: + return "Set the data width of the modem input/output" + + + + + + +class msk_top_regs_data_width_desc_6097df38_name_4609588b_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Rx Output Data Width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the parallel data width of the serial-to-parallel | + | | converter

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data_width'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data_width:msk_top_regs_data_width_data_width_cls = msk_top_regs_data_width_data_width_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=0, + msb=7, + low=0, + high=7), + misc_props=FieldMiscProps( + default=8, + is_volatile=False), + logger_handle=logger_handle+'.data_width', + inst_name='data_width', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data_width + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data_width(self) -> msk_top_regs_data_width_data_width_cls: + """ + Property to access data_width field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem input/output data width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the data width of the modem input/output

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data_width + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data_width':'data_width', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Modem Rx Output Data Width" + @property + def rdl_desc(self) -> str: + return "Set the parallel data width of the serial-to-parallel converter" + + + + + + + +class msk_top_regs_data_width_data_width_0x0x106a65e2_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem input/output data width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the data width of the modem input/output

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Modem input/output data width" + @property + def rdl_desc(self) -> str: + return "Set the data width of the modem input/output" + + + + + + +class msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Tx Input Data Width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the parallel data width of the parallel-to-serial | + | | converter

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data_width'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data_width:msk_top_regs_data_width_data_width_0x0x106a65e2_cls = msk_top_regs_data_width_data_width_0x0x106a65e2_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=0, + msb=7, + low=0, + high=7), + misc_props=FieldMiscProps( + default=8, + is_volatile=False), + logger_handle=logger_handle+'.data_width', + inst_name='data_width', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data_width + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x106a65e2_cls: + """ + Property to access data_width field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem input/output data width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the data width of the modem input/output

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data_width + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data_width':'data_width', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x106a65e2_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Modem Tx Input Data Width" + @property + def rdl_desc(self) -> str: + return "Set the parallel data width of the parallel-to-serial converter" + + + + + + + +class msk_top_regs_lpf_config_1_i_shift_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Integral Gain Bit Shift | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value n of 0-32 sets the integral divisor as 2^-n

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Integral Gain Bit Shift" + @property + def rdl_desc(self) -> str: + return "Value n of 0-32 sets the integral divisor as 2^-n" + + + + + + + +class msk_top_regs_lpf_config_1_i_gain_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Integral Gain Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value m of 0-16,777,215 sets the integral multiplier

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Integral Gain Value" + @property + def rdl_desc(self) -> str: + return "Value m of 0-16,777,215 sets the integral multiplier" + + + + + + +class msk_top_regs_lpf_config_1_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration Configuration Register 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures PI Controller I-gain and divisor

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__i_gain', '__i_shift'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__i_gain:msk_top_regs_lpf_config_1_i_gain_cls = msk_top_regs_lpf_config_1_i_gain_cls( + parent_register=self, + size_props=FieldSizeProps( + width=24, + lsb=0, + msb=23, + low=0, + high=23), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.i_gain', + inst_name='i_gain', + field_type=int) + self.__i_shift:msk_top_regs_lpf_config_1_i_shift_cls = msk_top_regs_lpf_config_1_i_shift_cls( + parent_register=self, + size_props=FieldSizeProps( + width=8, + lsb=24, + msb=31, + low=24, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.i_shift', + inst_name='i_shift', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.i_gain + yield self.i_shift + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def i_gain(self) -> msk_top_regs_lpf_config_1_i_gain_cls: + """ + Property to access i_gain field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Integral Gain Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value m of 0-16,777,215 sets the integral multiplier

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__i_gain + @property + def i_shift(self) -> msk_top_regs_lpf_config_1_i_shift_cls: + """ + Property to access i_shift field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Integral Gain Bit Shift | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value n of 0-32 sets the integral divisor as 2^-n

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__i_shift + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'i_gain':'i_gain','i_shift':'i_shift', + } + + + + + + + + # nodes:2 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["i_gain"]) -> msk_top_regs_lpf_config_1_i_gain_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["i_shift"]) -> msk_top_regs_lpf_config_1_i_shift_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_lpf_config_1_i_gain_cls, msk_top_regs_lpf_config_1_i_shift_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "PI Controller Configuration Configuration Register 1" + @property + def rdl_desc(self) -> str: + return "Configures PI Controller I-gain and divisor" + + + + + + + +class msk_top_regs_lpf_config_0_lpf_alpha_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Lowpass IIR filter alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value controls the filter rolloff

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Lowpass IIR filter alpha" + @property + def rdl_desc(self) -> str: + return "Value controls the filter rolloff" + + + + + + + +class msk_top_regs_lpf_config_0_prbs_reserved_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Reserved | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Reserved" + + + + + + + +class msk_top_regs_lpf_config_0_lpf_zero_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hold the PI Accumulator at zero | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal operation 1 -> Zero and hold accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Hold the PI Accumulator at zero" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Normal operation\n1 -\u003e Zero and hold accumulator" + + + + + + + +class msk_top_regs_lpf_config_0_lpf_freeze_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Freeze the accumulator's current value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal operation 1 -> Freeze current value

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Freeze the accumulator\u0027s current value" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Normal operation\n1 -\u003e Freeze current value" + + + + + + +class msk_top_regs_lpf_config_0_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration and Low-pass Filter Configuration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configure PI controller and low-pass filter

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__lpf_freeze', '__lpf_zero', '__prbs_reserved', '__lpf_alpha'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__lpf_freeze:msk_top_regs_lpf_config_0_lpf_freeze_cls = msk_top_regs_lpf_config_0_lpf_freeze_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.lpf_freeze', + inst_name='lpf_freeze', + field_type=int) + self.__lpf_zero:msk_top_regs_lpf_config_0_lpf_zero_cls = msk_top_regs_lpf_config_0_lpf_zero_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.lpf_zero', + inst_name='lpf_zero', + field_type=int) + self.__prbs_reserved:msk_top_regs_lpf_config_0_prbs_reserved_cls = msk_top_regs_lpf_config_0_prbs_reserved_cls( + parent_register=self, + size_props=FieldSizeProps( + width=6, + lsb=2, + msb=7, + low=2, + high=7), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.prbs_reserved', + inst_name='prbs_reserved', + field_type=int) + self.__lpf_alpha:msk_top_regs_lpf_config_0_lpf_alpha_cls = msk_top_regs_lpf_config_0_lpf_alpha_cls( + parent_register=self, + size_props=FieldSizeProps( + width=24, + lsb=8, + msb=31, + low=8, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.lpf_alpha', + inst_name='lpf_alpha', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.lpf_freeze + yield self.lpf_zero + yield self.prbs_reserved + yield self.lpf_alpha + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def lpf_freeze(self) -> msk_top_regs_lpf_config_0_lpf_freeze_cls: + """ + Property to access lpf_freeze field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Freeze the accumulator's current value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal operation 1 -> Freeze current value

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__lpf_freeze + @property + def lpf_zero(self) -> msk_top_regs_lpf_config_0_lpf_zero_cls: + """ + Property to access lpf_zero field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hold the PI Accumulator at zero | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal operation 1 -> Zero and hold accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__lpf_zero + @property + def prbs_reserved(self) -> msk_top_regs_lpf_config_0_prbs_reserved_cls: + """ + Property to access prbs_reserved field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Reserved | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__prbs_reserved + @property + def lpf_alpha(self) -> msk_top_regs_lpf_config_0_lpf_alpha_cls: + """ + Property to access lpf_alpha field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Lowpass IIR filter alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value controls the filter rolloff

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__lpf_alpha + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'lpf_freeze':'lpf_freeze','lpf_zero':'lpf_zero','prbs_reserved':'prbs_reserved','lpf_alpha':'lpf_alpha', + } + + + + + + + + # nodes:4 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["lpf_freeze"]) -> msk_top_regs_lpf_config_0_lpf_freeze_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["lpf_zero"]) -> msk_top_regs_lpf_config_0_lpf_zero_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["prbs_reserved"]) -> msk_top_regs_lpf_config_0_prbs_reserved_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["lpf_alpha"]) -> msk_top_regs_lpf_config_0_lpf_alpha_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_lpf_config_0_lpf_freeze_cls, msk_top_regs_lpf_config_0_lpf_zero_cls, msk_top_regs_lpf_config_0_prbs_reserved_cls, msk_top_regs_lpf_config_0_lpf_alpha_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "PI Controller Configuration and Low-pass Filter Configuration" + @property + def rdl_desc(self) -> str: + return "Configure PI controller and low-pass filter" + + + + + + + +class msk_top_regs_config_nco_fw_config_data_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate" + + + + + + +class msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx F2 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Demodulator F2 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_nco_fw_config_data_cls = msk_top_regs_config_nco_fw_config_data_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Rx F2 NCO Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Set Demodulator F2 Frequency" + + + + + + + +class msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate" + + + + + + +class msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx F1 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Demodulator F1 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls = msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Rx F1 NCO Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Set Demodulator F1 Frequency" + + + + + + + +class msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate" + + + + + + +class msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F2 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modulator F2 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls = msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Tx F2 NCO Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Set Modulator F2 Frequency" + + + + + + + +class msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate" + + + + + + +class msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F1 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modulator F1 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls = msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Tx F1 NCO Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Set Modulator F1 Frequency" + + + + + + + +class msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate" + + + + + + +class msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Bitrate NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modem Data Rate

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__config_data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls = msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.config_data', + inst_name='config_data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.config_data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls: + """ + Property to access config_data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, | + | | where Fn is the desired NCO frequency, and Fs is the NCO sample | + | | rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__config_data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'config_data':'config_data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Bitrate NCO Frequency Control Word" + @property + def rdl_desc(self) -> str: + return "Set Modem Data Rate" + + + + + + + +class msk_top_regs_msk_stat_2_tx_ena_counter_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Enable Count | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of clocks on which Tx Enable is active

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx Enable Count" + @property + def rdl_desc(self) -> str: + return "Number of clocks on which Tx Enable is active" + + + + + + +class msk_top_regs_msk_stat_2_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__tx_ena_counter'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__tx_ena_counter:msk_top_regs_msk_stat_2_tx_ena_counter_cls = msk_top_regs_msk_stat_2_tx_ena_counter_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.tx_ena_counter', + inst_name='tx_ena_counter', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.tx_ena_counter + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def tx_ena_counter(self) -> msk_top_regs_msk_stat_2_tx_ena_counter_cls: + """ + Property to access tx_ena_counter field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Enable Count | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Number of clocks on which Tx Enable is active

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_ena_counter + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'tx_ena_counter':'tx_ena_counter', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_2_tx_ena_counter_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Status 2" + @property + def rdl_desc(self) -> str: + return "Modem status data" + + + + + + + +class msk_top_regs_msk_stat_1_tx_bit_counter_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Bit Count | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of data requests made by modem

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx Bit Count" + @property + def rdl_desc(self) -> str: + return "Count of data requests made by modem" + + + + + + +class msk_top_regs_msk_stat_1_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__tx_bit_counter'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__tx_bit_counter:msk_top_regs_msk_stat_1_tx_bit_counter_cls = msk_top_regs_msk_stat_1_tx_bit_counter_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=None, + is_volatile=True), + logger_handle=logger_handle+'.tx_bit_counter', + inst_name='tx_bit_counter', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.tx_bit_counter + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def tx_bit_counter(self) -> msk_top_regs_msk_stat_1_tx_bit_counter_cls: + """ + Property to access tx_bit_counter field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Bit Count | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of data requests made by modem

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_bit_counter + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'tx_bit_counter':'tx_bit_counter', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_1_tx_bit_counter_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Status 1" + @property + def rdl_desc(self) -> str: + return "Modem status data" + + + + + + + +class msk_top_regs_msk_stat_0_tx_axis_valid_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx S_AXIS_VALID | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> S_AXIS_VALID Enabled 0 -> S_AXIS_VALID Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx S_AXIS_VALID" + @property + def rdl_desc(self) -> str: + return "1 -\u003e S_AXIS_VALID Enabled\n0 -\u003e S_AXIS_VALID Disabled" + + + + + + + +class msk_top_regs_msk_stat_0_rx_enable_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | AD9363 ADC Interface Rx Enable Input Active | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> Data from ADC Enabled 0 -> Data from ADC | + | | Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "AD9363 ADC Interface Rx Enable Input Active" + @property + def rdl_desc(self) -> str: + return "1 -\u003e Data from ADC Enabled\n0 -\u003e Data from ADC Disabled" + + + + + + + +class msk_top_regs_msk_stat_0_tx_enable_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | AD9363 DAC Interface Tx Enable Input Active | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> Data to DAC Enabled 0 -> Data to DAC Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "AD9363 DAC Interface Tx Enable Input Active" + @property + def rdl_desc(self) -> str: + return "1 -\u003e Data to DAC Enabled\n0 -\u003e Data to DAC Disabled" + + + + + + + +class msk_top_regs_msk_stat_0_demod_sync_lock_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Demodulator Sync Status | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Demodulator Sync Status - not currently implemented

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Demodulator Sync Status" + @property + def rdl_desc(self) -> str: + return "Demodulator Sync Status - not currently implemented" + + + + + + +class msk_top_regs_msk_stat_0_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status bits

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__demod_sync_lock', '__tx_enable', '__rx_enable', '__tx_axis_valid'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__demod_sync_lock:msk_top_regs_msk_stat_0_demod_sync_lock_cls = msk_top_regs_msk_stat_0_demod_sync_lock_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.demod_sync_lock', + inst_name='demod_sync_lock', + field_type=int) + self.__tx_enable:msk_top_regs_msk_stat_0_tx_enable_cls = msk_top_regs_msk_stat_0_tx_enable_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.tx_enable', + inst_name='tx_enable', + field_type=int) + self.__rx_enable:msk_top_regs_msk_stat_0_rx_enable_cls = msk_top_regs_msk_stat_0_rx_enable_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=2, + msb=2, + low=2, + high=2), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.rx_enable', + inst_name='rx_enable', + field_type=int) + self.__tx_axis_valid:msk_top_regs_msk_stat_0_tx_axis_valid_cls = msk_top_regs_msk_stat_0_tx_axis_valid_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=3, + msb=3, + low=3, + high=3), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.tx_axis_valid', + inst_name='tx_axis_valid', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.demod_sync_lock + yield self.tx_enable + yield self.rx_enable + yield self.tx_axis_valid + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def demod_sync_lock(self) -> msk_top_regs_msk_stat_0_demod_sync_lock_cls: + """ + Property to access demod_sync_lock field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Demodulator Sync Status | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Demodulator Sync Status - not currently implemented

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__demod_sync_lock + @property + def tx_enable(self) -> msk_top_regs_msk_stat_0_tx_enable_cls: + """ + Property to access tx_enable field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | AD9363 DAC Interface Tx Enable Input Active | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> Data to DAC Enabled 0 -> Data to DAC Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_enable + @property + def rx_enable(self) -> msk_top_regs_msk_stat_0_rx_enable_cls: + """ + Property to access rx_enable field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | AD9363 ADC Interface Rx Enable Input Active | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> Data from ADC Enabled 0 -> Data from ADC | + | | Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_enable + @property + def tx_axis_valid(self) -> msk_top_regs_msk_stat_0_tx_axis_valid_cls: + """ + Property to access tx_axis_valid field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx S_AXIS_VALID | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

1 -> S_AXIS_VALID Enabled 0 -> S_AXIS_VALID Disabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_axis_valid + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'demod_sync_lock':'demod_sync_lock','tx_enable':'tx_enable','rx_enable':'rx_enable','tx_axis_valid':'tx_axis_valid', + } + + + + + + + + # nodes:4 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["demod_sync_lock"]) -> msk_top_regs_msk_stat_0_demod_sync_lock_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_enable"]) -> msk_top_regs_msk_stat_0_tx_enable_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_enable"]) -> msk_top_regs_msk_stat_0_rx_enable_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_axis_valid"]) -> msk_top_regs_msk_stat_0_tx_axis_valid_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_stat_0_demod_sync_lock_cls, msk_top_regs_msk_stat_0_tx_enable_cls, msk_top_regs_msk_stat_0_rx_enable_cls, msk_top_regs_msk_stat_0_tx_axis_valid_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Status 0" + @property + def rdl_desc(self) -> str: + return "Modem status bits" + + + + + + + +class msk_top_regs_msk_ctrl_diff_encoder_loopback_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Differential Encoder -> Decoder Loopback Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Differential Encoder -> Decoder loopback disabled 1 | + | | -> Differential Encoder -> Decoder loopback enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Differential Encoder -\u003e Decoder Loopback Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled" + + + + + + + +class msk_top_regs_msk_ctrl_clear_counts_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Clear Status Counters | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Clear Tx Bit Counter and Tx Enable Counter

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Clear Status Counters" + @property + def rdl_desc(self) -> str: + return "Clear Tx Bit Counter and Tx Enable Counter" + + + + + + + +class msk_top_regs_msk_ctrl_rx_invert_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Data Invert Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Rx data normal 1 -> Rx data inverted

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Rx Data Invert Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Rx data normal\n1 -\u003e Rx data inverted" + + + + + + + +class msk_top_regs_msk_ctrl_loopback_ena_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Digital Tx -> Rx Loopback Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Modem loopback disabled 1 -> Modem loopback | + | | enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Modem Digital Tx -\u003e Rx Loopback Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Modem loopback disabled\n1 -\u003e Modem loopback enabled" + + + + + + + +class msk_top_regs_msk_ctrl_ptt_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Push-to-Talk Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> PTT Disabled 1 -> PTT Enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Push-to-Talk Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e PTT Disabled\n1 -\u003e PTT Enabled" + + + + + + +class msk_top_regs_msk_ctrl_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

MSK Modem Configuration and Control

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__ptt', '__loopback_ena', '__rx_invert', '__clear_counts', '__diff_encoder_loopback'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__ptt:msk_top_regs_msk_ctrl_ptt_cls = msk_top_regs_msk_ctrl_ptt_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.ptt', + inst_name='ptt', + field_type=int) + self.__loopback_ena:msk_top_regs_msk_ctrl_loopback_ena_cls = msk_top_regs_msk_ctrl_loopback_ena_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.loopback_ena', + inst_name='loopback_ena', + field_type=int) + self.__rx_invert:msk_top_regs_msk_ctrl_rx_invert_cls = msk_top_regs_msk_ctrl_rx_invert_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=2, + msb=2, + low=2, + high=2), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.rx_invert', + inst_name='rx_invert', + field_type=int) + self.__clear_counts:msk_top_regs_msk_ctrl_clear_counts_cls = msk_top_regs_msk_ctrl_clear_counts_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=3, + msb=3, + low=3, + high=3), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.clear_counts', + inst_name='clear_counts', + field_type=int) + self.__diff_encoder_loopback:msk_top_regs_msk_ctrl_diff_encoder_loopback_cls = msk_top_regs_msk_ctrl_diff_encoder_loopback_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=4, + msb=4, + low=4, + high=4), + misc_props=FieldMiscProps( + default=0, + is_volatile=False), + logger_handle=logger_handle+'.diff_encoder_loopback', + inst_name='diff_encoder_loopback', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.ptt + yield self.loopback_ena + yield self.rx_invert + yield self.clear_counts + yield self.diff_encoder_loopback + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def ptt(self) -> msk_top_regs_msk_ctrl_ptt_cls: + """ + Property to access ptt field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Push-to-Talk Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> PTT Disabled 1 -> PTT Enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__ptt + @property + def loopback_ena(self) -> msk_top_regs_msk_ctrl_loopback_ena_cls: + """ + Property to access loopback_ena field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Digital Tx -> Rx Loopback Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Modem loopback disabled 1 -> Modem loopback | + | | enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__loopback_ena + @property + def rx_invert(self) -> msk_top_regs_msk_ctrl_rx_invert_cls: + """ + Property to access rx_invert field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Data Invert Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Rx data normal 1 -> Rx data inverted

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_invert + @property + def clear_counts(self) -> msk_top_regs_msk_ctrl_clear_counts_cls: + """ + Property to access clear_counts field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Clear Status Counters | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Clear Tx Bit Counter and Tx Enable Counter

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__clear_counts + @property + def diff_encoder_loopback(self) -> msk_top_regs_msk_ctrl_diff_encoder_loopback_cls: + """ + Property to access diff_encoder_loopback field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Differential Encoder -> Decoder Loopback Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Differential Encoder -> Decoder loopback disabled 1 | + | | -> Differential Encoder -> Decoder loopback enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__diff_encoder_loopback + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'ptt':'ptt','loopback_ena':'loopback_ena','rx_invert':'rx_invert','clear_counts':'clear_counts','diff_encoder_loopback':'diff_encoder_loopback', + } + + + + + + + + # nodes:5 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["ptt"]) -> msk_top_regs_msk_ctrl_ptt_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["loopback_ena"]) -> msk_top_regs_msk_ctrl_loopback_ena_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_invert"]) -> msk_top_regs_msk_ctrl_rx_invert_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["clear_counts"]) -> msk_top_regs_msk_ctrl_clear_counts_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["diff_encoder_loopback"]) -> msk_top_regs_msk_ctrl_diff_encoder_loopback_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_ctrl_ptt_cls, msk_top_regs_msk_ctrl_loopback_ena_cls, msk_top_regs_msk_ctrl_rx_invert_cls, msk_top_regs_msk_ctrl_clear_counts_cls, msk_top_regs_msk_ctrl_diff_encoder_loopback_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Control" + @property + def rdl_desc(self) -> str: + return "MSK Modem Configuration and Control" + + + + + + + +class msk_top_regs_msk_init_rxinit_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal Rx operation 1 -> Initialize Rx

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Rx Init Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Normal Rx operation \n1 -\u003e Initialize Rx" + + + + + + + +class msk_top_regs_msk_init_txinit_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal Tx operation 1 -> Initialize Tx

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx Init Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Normal Tx operation \n1 -\u003e Initialize Tx" + + + + + + + +class msk_top_regs_msk_init_txrxinit_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx/Rx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal modem operation 1 -> Initialize Tx and | + | | Rx

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Tx/Rx Init Enable" + @property + def rdl_desc(self) -> str: + return "0 -\u003e Normal modem operation \n1 -\u003e Initialize Tx and Rx" + + + + + + +class msk_top_regs_msk_init_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Initialization Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Synchronous initialization of MSK Modem functions, does not | + | | affect configuration registers.

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__txrxinit', '__txinit', '__rxinit'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__txrxinit:msk_top_regs_msk_init_txrxinit_cls = msk_top_regs_msk_init_txrxinit_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=1, + is_volatile=False), + logger_handle=logger_handle+'.txrxinit', + inst_name='txrxinit', + field_type=int) + self.__txinit:msk_top_regs_msk_init_txinit_cls = msk_top_regs_msk_init_txinit_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=1, + is_volatile=False), + logger_handle=logger_handle+'.txinit', + inst_name='txinit', + field_type=int) + self.__rxinit:msk_top_regs_msk_init_rxinit_cls = msk_top_regs_msk_init_rxinit_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=2, + msb=2, + low=2, + high=2), + misc_props=FieldMiscProps( + default=1, + is_volatile=False), + logger_handle=logger_handle+'.rxinit', + inst_name='rxinit', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.txrxinit + yield self.txinit + yield self.rxinit + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def txrxinit(self) -> msk_top_regs_msk_init_txrxinit_cls: + """ + Property to access txrxinit field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx/Rx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal modem operation 1 -> Initialize Tx and | + | | Rx

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__txrxinit + @property + def txinit(self) -> msk_top_regs_msk_init_txinit_cls: + """ + Property to access txinit field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal Tx operation 1 -> Initialize Tx

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__txinit + @property + def rxinit(self) -> msk_top_regs_msk_init_rxinit_cls: + """ + Property to access rxinit field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Init Enable | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 -> Normal Rx operation 1 -> Initialize Rx

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rxinit + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'txrxinit':'txrxinit','txinit':'txinit','rxinit':'rxinit', + } + + + + + + + + # nodes:3 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["txrxinit"]) -> msk_top_regs_msk_init_txrxinit_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["txinit"]) -> msk_top_regs_msk_init_txinit_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rxinit"]) -> msk_top_regs_msk_init_rxinit_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_init_txrxinit_cls, msk_top_regs_msk_init_txinit_cls, msk_top_regs_msk_init_rxinit_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "MSK Modem Initialization Control" + @property + def rdl_desc(self) -> str: + return "Synchronous initialization of MSK Modem functions, does not affect configuration registers." + + + + + + + +class msk_top_regs_msk_hash_hi_hash_id_hi_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hash ID Upper 32-bits | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Upper 32-bits of Pluto MSK FPGA Hash ID

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Hash ID Upper 32-bits" + @property + def rdl_desc(self) -> str: + return "Upper 32-bits of Pluto MSK FPGA Hash ID" + + + + + + +class msk_top_regs_msk_hash_hi_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Pluto MSK FPGA Hash ID - Upper 32-bits | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__hash_id_hi'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__hash_id_hi:msk_top_regs_msk_hash_hi_hash_id_hi_cls = msk_top_regs_msk_hash_hi_hash_id_hi_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=1431677610, + is_volatile=False), + logger_handle=logger_handle+'.hash_id_hi', + inst_name='hash_id_hi', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.hash_id_hi + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def hash_id_hi(self) -> msk_top_regs_msk_hash_hi_hash_id_hi_cls: + """ + Property to access hash_id_hi field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hash ID Upper 32-bits | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Upper 32-bits of Pluto MSK FPGA Hash ID

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__hash_id_hi + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'hash_id_hi':'hash_id_hi', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_hash_hi_hash_id_hi_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Pluto MSK FPGA Hash ID - Upper 32-bits" + + + + + + + +class msk_top_regs_msk_hash_lo_hash_id_lo_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hash ID Lower 32-bits | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Lower 32-bits of Pluto MSK FPGA Hash ID

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Hash ID Lower 32-bits" + @property + def rdl_desc(self) -> str: + return "Lower 32-bits of Pluto MSK FPGA Hash ID" + + + + + + +class msk_top_regs_msk_hash_lo_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Pluto MSK FPGA Hash ID - Lower 32-bits | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__hash_id_lo'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__hash_id_lo:msk_top_regs_msk_hash_lo_hash_id_lo_cls = msk_top_regs_msk_hash_lo_hash_id_lo_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=2863289685, + is_volatile=False), + logger_handle=logger_handle+'.hash_id_lo', + inst_name='hash_id_lo', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.hash_id_lo + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def hash_id_lo(self) -> msk_top_regs_msk_hash_lo_hash_id_lo_cls: + """ + Property to access hash_id_lo field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Hash ID Lower 32-bits | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Lower 32-bits of Pluto MSK FPGA Hash ID

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__hash_id_lo + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'hash_id_lo':'hash_id_lo', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_hash_lo_hash_id_lo_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Pluto MSK FPGA Hash ID - Lower 32-bits" + + + + + + +class msk_top_regs_cls(AsyncAddressMap): + """ + Class to represent a address map in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Pluto MSK Registers | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

MSK Modem Configuration and Status Registers

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__Hash_ID_Low', '__Hash_ID_High', '__MSK_Init', '__MSK_Control', '__MSK_Status', '__Tx_Bit_Count', '__Tx_Enable_Count', '__Fb_FreqWord', '__TX_F1_FreqWord', '__TX_F2_FreqWord', '__RX_F1_FreqWord', '__RX_F2_FreqWord', '__LPF_Config_0', '__LPF_Config_1', '__Tx_Data_Width', '__Rx_Data_Width', '__PRBS_Control', '__PRBS_Initial_State', '__PRBS_Polynomial', '__PRBS_Error_Mask', '__PRBS_Bit_Count', '__PRBS_Error_Count', '__LPF_Accum_F1', '__LPF_Accum_F2', '__axis_xfer_count', '__Rx_Sample_Discard', '__LPF_Config_2', '__f1_nco_adjust', '__f2_nco_adjust', '__f1_error', '__f2_error', '__Tx_Sync_Ctrl', '__Tx_Sync_Cnt', '__lowpass_ema_alpha1', '__lowpass_ema_alpha2', '__rx_power'] + + def __init__(self, *, + address:int=0, + logger_handle:str='reg_model.msk_top_regs', + inst_name:str='msk_top_regs', + callbacks: Optional[Union[AsyncCallbackSet, AsyncCallbackSetLegacy]]=None, + parent:Optional[AsyncAddressMap]=None): + + if callbacks is not None: + if not isinstance(callbacks, (AsyncCallbackSet, AsyncCallbackSetLegacy)): + raise TypeError(f'callbacks should be AsyncCallbackSet, AsyncCallbackSetLegacy got {type(callbacks)}') + + super().__init__(callbacks=callbacks, + address=address, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + + + self.__Hash_ID_Low:msk_top_regs_msk_hash_lo_cls = msk_top_regs_msk_hash_lo_cls( + address=self.address+0, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Hash_ID_Low', + inst_name='Hash_ID_Low', parent=self) + + + self.__Hash_ID_High:msk_top_regs_msk_hash_hi_cls = msk_top_regs_msk_hash_hi_cls( + address=self.address+4, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Hash_ID_High', + inst_name='Hash_ID_High', parent=self) + + + self.__MSK_Init:msk_top_regs_msk_init_cls = msk_top_regs_msk_init_cls( + address=self.address+8, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.MSK_Init', + inst_name='MSK_Init', parent=self) + + + self.__MSK_Control:msk_top_regs_msk_ctrl_cls = msk_top_regs_msk_ctrl_cls( + address=self.address+12, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.MSK_Control', + inst_name='MSK_Control', parent=self) + + + self.__MSK_Status:msk_top_regs_msk_stat_0_cls = msk_top_regs_msk_stat_0_cls( + address=self.address+16, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.MSK_Status', + inst_name='MSK_Status', parent=self) + + + self.__Tx_Bit_Count:msk_top_regs_msk_stat_1_cls = msk_top_regs_msk_stat_1_cls( + address=self.address+20, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Tx_Bit_Count', + inst_name='Tx_Bit_Count', parent=self) + + + self.__Tx_Enable_Count:msk_top_regs_msk_stat_2_cls = msk_top_regs_msk_stat_2_cls( + address=self.address+24, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Tx_Enable_Count', + inst_name='Tx_Enable_Count', parent=self) + + + self.__Fb_FreqWord:msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls = msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls( + address=self.address+28, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Fb_FreqWord', + inst_name='Fb_FreqWord', parent=self) + + + self.__TX_F1_FreqWord:msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls = msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls( + address=self.address+32, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.TX_F1_FreqWord', + inst_name='TX_F1_FreqWord', parent=self) + + + self.__TX_F2_FreqWord:msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls = msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls( + address=self.address+36, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.TX_F2_FreqWord', + inst_name='TX_F2_FreqWord', parent=self) + + + self.__RX_F1_FreqWord:msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls = msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls( + address=self.address+40, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.RX_F1_FreqWord', + inst_name='RX_F1_FreqWord', parent=self) + + + self.__RX_F2_FreqWord:msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls = msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls( + address=self.address+44, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.RX_F2_FreqWord', + inst_name='RX_F2_FreqWord', parent=self) + + + self.__LPF_Config_0:msk_top_regs_lpf_config_0_cls = msk_top_regs_lpf_config_0_cls( + address=self.address+48, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.LPF_Config_0', + inst_name='LPF_Config_0', parent=self) + + + self.__LPF_Config_1:msk_top_regs_lpf_config_1_cls = msk_top_regs_lpf_config_1_cls( + address=self.address+52, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.LPF_Config_1', + inst_name='LPF_Config_1', parent=self) + + + self.__Tx_Data_Width:msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls = msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls( + address=self.address+56, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Tx_Data_Width', + inst_name='Tx_Data_Width', parent=self) + + + self.__Rx_Data_Width:msk_top_regs_data_width_desc_6097df38_name_4609588b_cls = msk_top_regs_data_width_desc_6097df38_name_4609588b_cls( + address=self.address+60, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Rx_Data_Width', + inst_name='Rx_Data_Width', parent=self) + + + self.__PRBS_Control:msk_top_regs_prbs_ctrl_cls = msk_top_regs_prbs_ctrl_cls( + address=self.address+64, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Control', + inst_name='PRBS_Control', parent=self) + + + self.__PRBS_Initial_State:msk_top_regs_config_prbs_seed_cls = msk_top_regs_config_prbs_seed_cls( + address=self.address+68, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Initial_State', + inst_name='PRBS_Initial_State', parent=self) + + + self.__PRBS_Polynomial:msk_top_regs_config_prbs_poly_cls = msk_top_regs_config_prbs_poly_cls( + address=self.address+72, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Polynomial', + inst_name='PRBS_Polynomial', parent=self) + + + self.__PRBS_Error_Mask:msk_top_regs_config_prbs_errmask_cls = msk_top_regs_config_prbs_errmask_cls( + address=self.address+76, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Error_Mask', + inst_name='PRBS_Error_Mask', parent=self) + + + self.__PRBS_Bit_Count:msk_top_regs_stat_32_bits_cls = msk_top_regs_stat_32_bits_cls( + address=self.address+80, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Bit_Count', + inst_name='PRBS_Bit_Count', parent=self) + + + self.__PRBS_Error_Count:msk_top_regs_stat_32_errs_cls = msk_top_regs_stat_32_errs_cls( + address=self.address+84, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.PRBS_Error_Count', + inst_name='PRBS_Error_Count', parent=self) + + + self.__LPF_Accum_F1:msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls = msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls( + address=self.address+88, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.LPF_Accum_F1', + inst_name='LPF_Accum_F1', parent=self) + + + self.__LPF_Accum_F2:msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls = msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls( + address=self.address+92, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.LPF_Accum_F2', + inst_name='LPF_Accum_F2', parent=self) + + + self.__axis_xfer_count:msk_top_regs_msk_stat_3_cls = msk_top_regs_msk_stat_3_cls( + address=self.address+96, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.axis_xfer_count', + inst_name='axis_xfer_count', parent=self) + + + self.__Rx_Sample_Discard:msk_top_regs_rx_sample_discard_cls = msk_top_regs_rx_sample_discard_cls( + address=self.address+100, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Rx_Sample_Discard', + inst_name='Rx_Sample_Discard', parent=self) + + + self.__LPF_Config_2:msk_top_regs_lpf_config_2_cls = msk_top_regs_lpf_config_2_cls( + address=self.address+104, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.LPF_Config_2', + inst_name='LPF_Config_2', parent=self) + + + self.__f1_nco_adjust:msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls = msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls( + address=self.address+108, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.f1_nco_adjust', + inst_name='f1_nco_adjust', parent=self) + + + self.__f2_nco_adjust:msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls = msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls( + address=self.address+112, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.f2_nco_adjust', + inst_name='f2_nco_adjust', parent=self) + + + self.__f1_error:msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls = msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls( + address=self.address+116, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.f1_error', + inst_name='f1_error', parent=self) + + + self.__f2_error:msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls = msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls( + address=self.address+120, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.f2_error', + inst_name='f2_error', parent=self) + + + self.__Tx_Sync_Ctrl:msk_top_regs_tx_sync_ctrl_cls = msk_top_regs_tx_sync_ctrl_cls( + address=self.address+124, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Tx_Sync_Ctrl', + inst_name='Tx_Sync_Ctrl', parent=self) + + + self.__Tx_Sync_Cnt:msk_top_regs_tx_sync_cnt_cls = msk_top_regs_tx_sync_cnt_cls( + address=self.address+128, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.Tx_Sync_Cnt', + inst_name='Tx_Sync_Cnt', parent=self) + + + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls = msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls( + address=self.address+132, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.lowpass_ema_alpha1', + inst_name='lowpass_ema_alpha1', parent=self) + + + self.__lowpass_ema_alpha2:msk_top_regs_lowpass_ema_alpha_cls = msk_top_regs_lowpass_ema_alpha_cls( + address=self.address+136, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.lowpass_ema_alpha2', + inst_name='lowpass_ema_alpha2', parent=self) + + + self.__rx_power:msk_top_regs_rx_power_cls = msk_top_regs_rx_power_cls( + address=self.address+140, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.rx_power', + inst_name='rx_power', parent=self) + + + @property + def size(self) -> int: + return 144 + @property + def Hash_ID_Low(self) -> msk_top_regs_msk_hash_lo_cls: + """ + Property to access Hash_ID_Low + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Pluto MSK FPGA Hash ID - Lower 32-bits | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Hash_ID_Low + + @property + def Hash_ID_High(self) -> msk_top_regs_msk_hash_hi_cls: + """ + Property to access Hash_ID_High + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Pluto MSK FPGA Hash ID - Upper 32-bits | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Hash_ID_High + + @property + def MSK_Init(self) -> msk_top_regs_msk_init_cls: + """ + Property to access MSK_Init + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Initialization Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Synchronous initialization of MSK Modem functions, does not | + | | affect configuration registers.

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__MSK_Init + + @property + def MSK_Control(self) -> msk_top_regs_msk_ctrl_cls: + """ + Property to access MSK_Control + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

MSK Modem Configuration and Control

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__MSK_Control + + @property + def MSK_Status(self) -> msk_top_regs_msk_stat_0_cls: + """ + Property to access MSK_Status + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status bits

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__MSK_Status + + @property + def Tx_Bit_Count(self) -> msk_top_regs_msk_stat_1_cls: + """ + Property to access Tx_Bit_Count + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Tx_Bit_Count + + @property + def Tx_Enable_Count(self) -> msk_top_regs_msk_stat_2_cls: + """ + Property to access Tx_Enable_Count + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Tx_Enable_Count + + @property + def Fb_FreqWord(self) -> msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls: + """ + Property to access Fb_FreqWord + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Bitrate NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modem Data Rate

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Fb_FreqWord + + @property + def TX_F1_FreqWord(self) -> msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls: + """ + Property to access TX_F1_FreqWord + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F1 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modulator F1 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__TX_F1_FreqWord + + @property + def TX_F2_FreqWord(self) -> msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls: + """ + Property to access TX_F2_FreqWord + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx F2 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Modulator F2 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__TX_F2_FreqWord + + @property + def RX_F1_FreqWord(self) -> msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls: + """ + Property to access RX_F1_FreqWord + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx F1 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Demodulator F1 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__RX_F1_FreqWord + + @property + def RX_F2_FreqWord(self) -> msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls: + """ + Property to access RX_F2_FreqWord + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx F2 NCO Frequency Control Word | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set Demodulator F2 Frequency

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__RX_F2_FreqWord + + @property + def LPF_Config_0(self) -> msk_top_regs_lpf_config_0_cls: + """ + Property to access LPF_Config_0 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration and Low-pass Filter Configuration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configure PI controller and low-pass filter

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__LPF_Config_0 + + @property + def LPF_Config_1(self) -> msk_top_regs_lpf_config_1_cls: + """ + Property to access LPF_Config_1 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration Configuration Register 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures PI Controller I-gain and divisor

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__LPF_Config_1 + + @property + def Tx_Data_Width(self) -> msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls: + """ + Property to access Tx_Data_Width + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Tx Input Data Width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the parallel data width of the parallel-to-serial | + | | converter

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Tx_Data_Width + + @property + def Rx_Data_Width(self) -> msk_top_regs_data_width_desc_6097df38_name_4609588b_cls: + """ + Property to access Rx_Data_Width + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Modem Rx Output Data Width | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Set the parallel data width of the serial-to-parallel | + | | converter

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Rx_Data_Width + + @property + def PRBS_Control(self) -> msk_top_regs_prbs_ctrl_cls: + """ + Property to access PRBS_Control + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures operation of the PRBS Generator and Monitor

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Control + + @property + def PRBS_Initial_State(self) -> msk_top_regs_config_prbs_seed_cls: + """ + Property to access PRBS_Initial_State + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Initial State

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Initial_State + + @property + def PRBS_Polynomial(self) -> msk_top_regs_config_prbs_poly_cls: + """ + Property to access PRBS_Polynomial + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Polynomial

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Polynomial + + @property + def PRBS_Error_Mask(self) -> msk_top_regs_config_prbs_errmask_cls: + """ + Property to access PRBS_Error_Mask + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Control 3 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Error Mask

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Error_Mask + + @property + def PRBS_Bit_Count(self) -> msk_top_regs_stat_32_bits_cls: + """ + Property to access PRBS_Bit_Count + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Status 0 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Bits Received

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Bit_Count + + @property + def PRBS_Error_Count(self) -> msk_top_regs_stat_32_errs_cls: + """ + Property to access PRBS_Error_Count + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PRBS Status 1 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

PRBS Bit Errors

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__PRBS_Error_Count + + @property + def LPF_Accum_F1(self) -> msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls: + """ + Property to access LPF_Accum_F1 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 PI Controller Accumulator | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value of the F1 PI Controller Accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__LPF_Accum_F1 + + @property + def LPF_Accum_F2(self) -> msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls: + """ + Property to access LPF_Accum_F2 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 PI Controller Accumulator | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Value of the F2 PI Controller Accumulator

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__LPF_Accum_F2 + + @property + def axis_xfer_count(self) -> msk_top_regs_msk_stat_3_cls: + """ + Property to access axis_xfer_count + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | MSK Modem Status 3 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Modem status data

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__axis_xfer_count + + @property + def Rx_Sample_Discard(self) -> msk_top_regs_rx_sample_discard_cls: + """ + Property to access Rx_Sample_Discard + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx Sample Discard | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configure samples discard operation for demodulator

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Rx_Sample_Discard + + @property + def LPF_Config_2(self) -> msk_top_regs_lpf_config_2_cls: + """ + Property to access LPF_Config_2 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | PI Controller Configuration Configuration Register 2 | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Configures PI Controller I-gain and divisor

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__LPF_Config_2 + + @property + def f1_nco_adjust(self) -> msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls: + """ + Property to access f1_nco_adjust + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F1 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__f1_nco_adjust + + @property + def f2_nco_adjust(self) -> msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls: + """ + Property to access f2_nco_adjust + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 NCO Frequency Adjust | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Frequency offet applied to the F2 NCO

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__f2_nco_adjust + + @property + def f1_error(self) -> msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls: + """ + Property to access f1_error + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F1 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F1 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__f1_error + + @property + def f2_error(self) -> msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls: + """ + Property to access f2_error + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | F2 Error Value | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Error value of the F2 Costas loop after each active bit | + | | period

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__f2_error + + @property + def Tx_Sync_Ctrl(self) -> msk_top_regs_tx_sync_ctrl_cls: + """ + Property to access Tx_Sync_Ctrl + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Transmitter Sync Control | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Provides control bits for generation of transmitter | + | | synchronization patterns

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Tx_Sync_Ctrl + + @property + def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: + """ + Property to access Tx_Sync_Cnt + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Transmitter Sync Duration | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the duration of the synchronization tones when enabled

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__Tx_Sync_Cnt + + @property + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls: + """ + Property to access lowpass_ema_alpha1 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Exponential Moving Average Alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the alpha for the EMA

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__lowpass_ema_alpha1 + + @property + def lowpass_ema_alpha2(self) -> msk_top_regs_lowpass_ema_alpha_cls: + """ + Property to access lowpass_ema_alpha2 + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Exponential Moving Average Alpha | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Sets the alpha for the EMA

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__lowpass_ema_alpha2 + + @property + def rx_power(self) -> msk_top_regs_rx_power_cls: + """ + Property to access rx_power + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Receive Power | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Receive power computed from I/Q ssamples

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_power + + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'Hash_ID_Low':'Hash_ID_Low','Hash_ID_High':'Hash_ID_High','MSK_Init':'MSK_Init','MSK_Control':'MSK_Control','MSK_Status':'MSK_Status','Tx_Bit_Count':'Tx_Bit_Count','Tx_Enable_Count':'Tx_Enable_Count','Fb_FreqWord':'Fb_FreqWord','TX_F1_FreqWord':'TX_F1_FreqWord','TX_F2_FreqWord':'TX_F2_FreqWord','RX_F1_FreqWord':'RX_F1_FreqWord','RX_F2_FreqWord':'RX_F2_FreqWord','LPF_Config_0':'LPF_Config_0','LPF_Config_1':'LPF_Config_1','Tx_Data_Width':'Tx_Data_Width','Rx_Data_Width':'Rx_Data_Width','PRBS_Control':'PRBS_Control','PRBS_Initial_State':'PRBS_Initial_State','PRBS_Polynomial':'PRBS_Polynomial','PRBS_Error_Mask':'PRBS_Error_Mask','PRBS_Bit_Count':'PRBS_Bit_Count','PRBS_Error_Count':'PRBS_Error_Count','LPF_Accum_F1':'LPF_Accum_F1','LPF_Accum_F2':'LPF_Accum_F2','axis_xfer_count':'axis_xfer_count','Rx_Sample_Discard':'Rx_Sample_Discard','LPF_Config_2':'LPF_Config_2','f1_nco_adjust':'f1_nco_adjust','f2_nco_adjust':'f2_nco_adjust','f1_error':'f1_error','f2_error':'f2_error','Tx_Sync_Ctrl':'Tx_Sync_Ctrl','Tx_Sync_Cnt':'Tx_Sync_Cnt','lowpass_ema_alpha1':'lowpass_ema_alpha1','lowpass_ema_alpha2':'lowpass_ema_alpha2','rx_power':'rx_power', + } + + + + + + + + # nodes:36 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Hash_ID_Low"]) -> msk_top_regs_msk_hash_lo_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Hash_ID_High"]) -> msk_top_regs_msk_hash_hi_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["MSK_Init"]) -> msk_top_regs_msk_init_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["MSK_Control"]) -> msk_top_regs_msk_ctrl_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["MSK_Status"]) -> msk_top_regs_msk_stat_0_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Tx_Bit_Count"]) -> msk_top_regs_msk_stat_1_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Tx_Enable_Count"]) -> msk_top_regs_msk_stat_2_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Fb_FreqWord"]) -> msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["TX_F1_FreqWord"]) -> msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["TX_F2_FreqWord"]) -> msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["RX_F1_FreqWord"]) -> msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["RX_F2_FreqWord"]) -> msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["LPF_Config_0"]) -> msk_top_regs_lpf_config_0_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["LPF_Config_1"]) -> msk_top_regs_lpf_config_1_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Tx_Data_Width"]) -> msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Rx_Data_Width"]) -> msk_top_regs_data_width_desc_6097df38_name_4609588b_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Control"]) -> msk_top_regs_prbs_ctrl_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Initial_State"]) -> msk_top_regs_config_prbs_seed_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Polynomial"]) -> msk_top_regs_config_prbs_poly_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Error_Mask"]) -> msk_top_regs_config_prbs_errmask_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Bit_Count"]) -> msk_top_regs_stat_32_bits_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["PRBS_Error_Count"]) -> msk_top_regs_stat_32_errs_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["LPF_Accum_F1"]) -> msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["LPF_Accum_F2"]) -> msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["axis_xfer_count"]) -> msk_top_regs_msk_stat_3_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Rx_Sample_Discard"]) -> msk_top_regs_rx_sample_discard_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["LPF_Config_2"]) -> msk_top_regs_lpf_config_2_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["f1_nco_adjust"]) -> msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["f2_nco_adjust"]) -> msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["f1_error"]) -> msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["f2_error"]) -> msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Ctrl"]) -> msk_top_regs_tx_sync_ctrl_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_regs_tx_sync_cnt_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha2"]) -> msk_top_regs_lowpass_ema_alpha_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_power"]) -> msk_top_regs_rx_power_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "Pluto MSK Registers" + @property + def rdl_desc(self) -> str: + return "MSK Modem Configuration and Status Registers" + + + + + def get_registers(self, unroll:bool=False) -> Iterator[Union[AsyncReg, AsyncRegArray]]: + """ + generator that produces all the registers of this node + """ + + + yield self.Hash_ID_Low + + + yield self.Hash_ID_High + + + yield self.MSK_Init + + + yield self.MSK_Control + + + yield self.MSK_Status + + + yield self.Tx_Bit_Count + + + yield self.Tx_Enable_Count + + + yield self.Fb_FreqWord + + + yield self.TX_F1_FreqWord + + + yield self.TX_F2_FreqWord + + + yield self.RX_F1_FreqWord + + + yield self.RX_F2_FreqWord + + + yield self.LPF_Config_0 + + + yield self.LPF_Config_1 + + + yield self.Tx_Data_Width + + + yield self.Rx_Data_Width + + + yield self.PRBS_Control + + + yield self.PRBS_Initial_State + + + yield self.PRBS_Polynomial + + + yield self.PRBS_Error_Mask + + + yield self.PRBS_Bit_Count + + + yield self.PRBS_Error_Count + + + yield self.LPF_Accum_F1 + + + yield self.LPF_Accum_F2 + + + yield self.axis_xfer_count + + + yield self.Rx_Sample_Discard + + + yield self.LPF_Config_2 + + + yield self.f1_nco_adjust + + + yield self.f2_nco_adjust + + + yield self.f1_error + + + yield self.f2_error + + + yield self.Tx_Sync_Ctrl + + + yield self.Tx_Sync_Cnt + + + yield self.lowpass_ema_alpha1 + + + yield self.lowpass_ema_alpha2 + + + yield self.rx_power + + + # Empty generator in case there are no children of this type + if False: yield + + + def get_sections(self, unroll:bool=False) -> Iterator[Union[AsyncAddressMap, AsyncRegFile, AsyncAddressMapArray, AsyncRegFileArray]]: + """ + generator that produces all the AsyncAddressMap, AsyncRegFile, AsyncAddressMapArray, AsyncRegFileArray children of this node + """ + + + # Empty generator in case there are no children of this type + if False: yield + + def get_memories(self, unroll:bool=False) -> Iterator[Union[AsyncMemory, AsyncMemoryArray]]: + """ + generator that produces all the AsyncMemory, AsyncMemoryArray children of this node + """ + + + # Empty generator in case there are no children of this type + if False: yield + + + + + +if __name__ == '__main__': + # dummy functions to demonstrate the class + async def read_addr_space(addr: int, width: int, accesswidth: int) -> int: + """ + Callback to simulate the operation of the package, everytime the read is called, it will + request the user input the value to be read back. + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + value inputted by the used + """ + assert isinstance(addr, int) + assert isinstance(width, int) + assert isinstance(accesswidth, int) + return int(input('value to read from address:0x%X'%addr)) + + async def write_addr_space(addr: int, width: int, accesswidth: int, data: int) -> None: + """ + Callback to simulate the operation of the package, everytime the read is called, it will + request the user input the value to be read back. + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: value to be written to the register + + Returns: + None + """ + assert isinstance(addr, int) + assert isinstance(width, int) + assert isinstance(accesswidth, int) + assert isinstance(data, int) + print('write data:0x%X to address:0x%X'%(data, addr)) + + # create an instance of the class + msk_top_regs = msk_top_regs_cls(callbacks = AsyncCallbackSet(read_callback=read_addr_space, + write_callback=write_addr_space)) \ No newline at end of file diff --git a/rdl/outputs/python/msk_top_regs/sim/__init__.py b/rdl/outputs/python/msk_top_regs/sim/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim/__init__.py @@ -0,0 +1 @@ +pass diff --git a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py new file mode 100644 index 0000000..95e0aa1 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py @@ -0,0 +1,175 @@ + + + +""" +Python Wrapper for the msk_top_regs register model + +This code was generated from the PeakRDL-python package version 1.4.0 + +""" + +from typing import Union + +from ..sim_lib.register import Register, MemoryRegister +from ..sim_lib.memory import Memory +from ..sim_lib.simulator import MemoryEntry +from ..sim_lib.field import FieldDefinition +from ..sim_lib.simulator import AsyncSimulator as Simulator + + +class msk_top_regs_simulator_cls(Simulator): + + def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Register]], Union[MemoryRegister, Register]]]: + return { + 0 : + Register(width=32, full_inst_name='msk_top_regs.Hash_ID_Low', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='hash_id_lo'), + ]), + 4 : + Register(width=32, full_inst_name='msk_top_regs.Hash_ID_High', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='hash_id_hi'), + ]), + 8 : + Register(width=32, full_inst_name='msk_top_regs.MSK_Init', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='txrxinit'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='txinit'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='rxinit'), + ]), + 12 : + Register(width=32, full_inst_name='msk_top_regs.MSK_Control', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='ptt'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='loopback_ena'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='rx_invert'),FieldDefinition(high=3, low=3, msb=3, lsb=3, inst_name='clear_counts'),FieldDefinition(high=4, low=4, msb=4, lsb=4, inst_name='diff_encoder_loopback'), + ]), + 16 : + Register(width=32, full_inst_name='msk_top_regs.MSK_Status', readable=True, writable=False, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='demod_sync_lock'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='tx_enable'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='rx_enable'),FieldDefinition(high=3, low=3, msb=3, lsb=3, inst_name='tx_axis_valid'), + ]), + 20 : + Register(width=32, full_inst_name='msk_top_regs.Tx_Bit_Count', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='tx_bit_counter'), + ]), + 24 : + Register(width=32, full_inst_name='msk_top_regs.Tx_Enable_Count', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='tx_ena_counter'), + ]), + 28 : + Register(width=32, full_inst_name='msk_top_regs.Fb_FreqWord', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 32 : + Register(width=32, full_inst_name='msk_top_regs.TX_F1_FreqWord', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 36 : + Register(width=32, full_inst_name='msk_top_regs.TX_F2_FreqWord', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 40 : + Register(width=32, full_inst_name='msk_top_regs.RX_F1_FreqWord', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 44 : + Register(width=32, full_inst_name='msk_top_regs.RX_F2_FreqWord', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 48 : + Register(width=32, full_inst_name='msk_top_regs.LPF_Config_0', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='lpf_freeze'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='lpf_zero'),FieldDefinition(high=7, low=2, msb=7, lsb=2, inst_name='prbs_reserved'),FieldDefinition(high=31, low=8, msb=31, lsb=8, inst_name='lpf_alpha'), + ]), + 52 : + Register(width=32, full_inst_name='msk_top_regs.LPF_Config_1', readable=True, writable=True, + fields=[FieldDefinition(high=23, low=0, msb=23, lsb=0, inst_name='i_gain'),FieldDefinition(high=31, low=24, msb=31, lsb=24, inst_name='i_shift'), + ]), + 56 : + Register(width=32, full_inst_name='msk_top_regs.Tx_Data_Width', readable=True, writable=True, + fields=[FieldDefinition(high=7, low=0, msb=7, lsb=0, inst_name='data_width'), + ]), + 60 : + Register(width=32, full_inst_name='msk_top_regs.Rx_Data_Width', readable=True, writable=True, + fields=[FieldDefinition(high=7, low=0, msb=7, lsb=0, inst_name='data_width'), + ]), + 64 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Control', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='prbs_sel'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='prbs_error_insert'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='prbs_clear'),FieldDefinition(high=3, low=3, msb=3, lsb=3, inst_name='prbs_manual_sync'),FieldDefinition(high=15, low=4, msb=15, lsb=4, inst_name='prbs_reserved'),FieldDefinition(high=31, low=16, msb=31, lsb=16, inst_name='prbs_sync_threshold'), + ]), + 68 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Initial_State', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 72 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Polynomial', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 76 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Error_Mask', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), + ]), + 80 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Bit_Count', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + ]), + 84 : + Register(width=32, full_inst_name='msk_top_regs.PRBS_Error_Count', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + ]), + 88 : + Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F1', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + ]), + 92 : + Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F2', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + ]), + 96 : + Register(width=32, full_inst_name='msk_top_regs.axis_xfer_count', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='xfer_count'), + ]), + 100 : + Register(width=32, full_inst_name='msk_top_regs.Rx_Sample_Discard', readable=True, writable=True, + fields=[FieldDefinition(high=7, low=0, msb=7, lsb=0, inst_name='rx_sample_discard'),FieldDefinition(high=15, low=8, msb=15, lsb=8, inst_name='rx_nco_discard'), + ]), + 104 : + Register(width=32, full_inst_name='msk_top_regs.LPF_Config_2', readable=True, writable=True, + fields=[FieldDefinition(high=23, low=0, msb=23, lsb=0, inst_name='p_gain'),FieldDefinition(high=31, low=24, msb=31, lsb=24, inst_name='p_shift'), + ]), + 108 : + Register(width=32, full_inst_name='msk_top_regs.f1_nco_adjust', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), + 112 : + Register(width=32, full_inst_name='msk_top_regs.f2_nco_adjust', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), + 116 : + Register(width=32, full_inst_name='msk_top_regs.f1_error', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), + 120 : + Register(width=32, full_inst_name='msk_top_regs.f2_error', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), + 124 : + Register(width=32, full_inst_name='msk_top_regs.Tx_Sync_Ctrl', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='tx_sync_ena'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='tx_sync_force'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='tx_sync_f1'),FieldDefinition(high=3, low=3, msb=3, lsb=3, inst_name='tx_sync_f2'), + ]), + 128 : + Register(width=32, full_inst_name='msk_top_regs.Tx_Sync_Cnt', readable=True, writable=True, + fields=[FieldDefinition(high=23, low=0, msb=23, lsb=0, inst_name='tx_sync_cnt'), + ]), + 132 : + Register(width=32, full_inst_name='msk_top_regs.lowpass_ema_alpha1', readable=True, writable=True, + fields=[FieldDefinition(high=17, low=0, msb=17, lsb=0, inst_name='alpha'), + ]), + 136 : + Register(width=32, full_inst_name='msk_top_regs.lowpass_ema_alpha2', readable=True, writable=True, + fields=[FieldDefinition(high=17, low=0, msb=17, lsb=0, inst_name='alpha'), + ]), + 140 : + Register(width=32, full_inst_name='msk_top_regs.rx_power', readable=True, writable=False, + fields=[FieldDefinition(high=22, low=0, msb=22, lsb=0, inst_name='rx_power'), + ]), + } + + def _build_memories(self) -> list[MemoryEntry]: + return [ + ] + +if __name__ == '__main__': + pass diff --git a/rdl/cocotb/desyrdl/__init__.py b/rdl/outputs/python/msk_top_regs/sim_lib/__init__.py similarity index 100% rename from rdl/cocotb/desyrdl/__init__.py rename to rdl/outputs/python/msk_top_regs/sim_lib/__init__.py diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/_callbacks.py b/rdl/outputs/python/msk_top_regs/sim_lib/_callbacks.py new file mode 100644 index 0000000..e294617 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/_callbacks.py @@ -0,0 +1,79 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of types used by the autogenerated code to callbacks +""" +from typing import Protocol + + +class RegisterReadCallback(Protocol): + """ + Callback definition software read to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, value: int) -> None: + pass + + +class RegisterWriteCallback(Protocol): + """ + Callback definition software write to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, value: int) -> None: + pass + +class FieldReadCallback(Protocol): + """ + Callback definition software read to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, value: int) -> None: + pass + + +class FieldWriteCallback(Protocol): + """ + Callback definition software write to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, value: int) -> None: + pass + +class MemoryReadCallback(Protocol): + """ + Callback definition software read to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, offset: int, value: int) -> None: + pass + + +class MemoryWriteCallback(Protocol): + """ + Callback definition software write to a field, register or memory + """ + + # pylint: disable=too-few-public-methods + def __call__(self, offset: int, value: int) -> None: + pass diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/base.py b/rdl/outputs/python/msk_top_regs/sim_lib/base.py new file mode 100644 index 0000000..22077ad --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/base.py @@ -0,0 +1,34 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from abc import ABC + + +# pylint: disable=too-few-public-methods +class Base(ABC): + """ + base class for the simulator nodes + """ + + __slots__ = ['full_inst_name'] + + def __init__(self, *, + full_inst_name: str): + self.full_inst_name = full_inst_name diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/dummy_callbacks.py b/rdl/outputs/python/msk_top_regs/sim_lib/dummy_callbacks.py new file mode 100644 index 0000000..07215a8 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/dummy_callbacks.py @@ -0,0 +1,256 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module provides a set of "dummy" callbacks that provide the most basic of operations +""" +from array import array as Array +import asyncio + +from ..lib.utility_functions import get_array_typecode + +# many of the functions in this file do not use all the arguments, this is because they are stub +# functions +# pylint: disable=unused-argument + + +def dummy_read(addr: int, width: int, accesswidth: int) -> int: + """ + Callback to simulate the operation of the package, everytime the read is called, it return + an integer value of 0 + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + value inputted by the used + """ + return int(0) + + +def dummy_write(addr: int, width: int, accesswidth: int, data: int) -> None: + """ + Callback to simulate the operation of the package, everytime the write is called, it will + print the content + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: value to be written to the register + + Returns: + None + """ + # pylint: disable-next=bad-builtin + print(f'0x{data:X} written to 0x{addr:X}') + + +def dummy_read_block(addr: int, width: int, accesswidth: int, length:int) -> list[int]: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + length: number of array entries + + Returns: + an array with the correct type (based on width) populated with 0's + + """ + return [0 for x in range(length)] + + +def dummy_read_block_legacy(addr: int, width: int, accesswidth: int, length:int) -> Array: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + length: number of array entries + + Returns: + an list with the correct type (based on width) populated with 0's + + """ + return Array(get_array_typecode(width=width), [0 for x in range(length)]) + + +def dummy_write_block(addr: int, width: int, accesswidth: int, data: list[int]) -> None: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: number of array entries + + Returns: + None + + """ + # pylint: disable=unnecessary-pass + pass + + +def dummy_write_block_legacy(addr: int, width: int, accesswidth: int, data: Array) -> None: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: number of array entries + + Returns: + None + + """ + # pylint: disable=unnecessary-pass + pass + + +async def async_dummy_read(addr: int, width: int, accesswidth: int) -> int: + """ + async Callback to simulate the operation of the package, everytime the read is called, it + return an integer value of 0 + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + + Returns: + value inputted by the used + """ + await asyncio.sleep(0) + return dummy_read(addr, width, accesswidth) + + +async def async_dummy_write(addr: int, width: int, accesswidth: int, data: int) -> None: + """ + Callback to simulate the operation of the package, everytime the write is called, it will + print the content + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: value to be written to the register + + Returns: + None + """ + await asyncio.sleep(0) + return dummy_write(addr, width, accesswidth, data) + + +async def async_dummy_read_block(addr: int, + width: int, + accesswidth: int, + length: int) -> list[int]: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + length: number of array entries + + Returns: + an array with the correct type (based on width) populated with 0's + + """ + await asyncio.sleep(0) + return dummy_read_block(addr, width, accesswidth, length) + + +async def async_dummy_read_block_legacy(addr: int, + width: int, + accesswidth: int, + length: int) -> Array: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + length: number of array entries + + Returns: + an List with the correct type (based on width) populated with 0's + + """ + await asyncio.sleep(0) + return dummy_read_block_legacy(addr, width, accesswidth, length) + + +async def async_dummy_write_block(addr: int, + width: int, + accesswidth: int, data: list[int]) -> None: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: number of array entries + + Returns: + None + + """ + await asyncio.sleep(0) + return dummy_write_block(addr, width, accesswidth, data) + + +async def async_dummy_write_block_legacy(addr: int, + width: int, + accesswidth: int, data: Array) -> None: + """ + Callback to simulate the operation of the package, everytime the read_block is called, it + return an integer value of array of o's + + Args: + addr: Address to write to + width: Width of the register in bits + accesswidth: Minimum access width of the register in bits + data: number of array entries + + Returns: + None + + """ + await asyncio.sleep(0) + return dummy_write_block_legacy(addr, width, accesswidth, data) diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/field.py b/rdl/outputs/python/msk_top_regs/sim_lib/field.py new file mode 100644 index 0000000..2516905 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/field.py @@ -0,0 +1,154 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from dataclasses import dataclass +from typing import TYPE_CHECKING +from typing import Optional + +from ..lib.utility_functions import swap_msb_lsb_ordering + +from ._callbacks import FieldReadCallback, FieldWriteCallback + +from .base import Base + +if TYPE_CHECKING: + from .register import BaseRegister + +# pylint: disable=too-many-instance-attributes,too-many-arguments + + +@dataclass +class FieldDefinition: + """ + Class for an entry in the list of memories in the simulator + """ + high: int + low: int + msb: int + lsb: int + inst_name: str + +class Field(Base): + """ + class for all fields + + Note: + It is not expected that this class will be instantiated under normal + circumstances however, it is useful for type checking + """ + + __slots__ = ['__high', '__low', '__msb', '__lsb', + '__bitmask', '__inverse_bitmask', + '__msb0', '__lsb0', + '__parent_register','__parent_width', + '__read_callback', '__write_callback'] + + def __init__(self, *, low: int, high: int, msb: int, lsb: int, + parent_register: 'BaseRegister', parent_width: int, inst_name: str): + + super().__init__(full_inst_name=parent_register.full_inst_name + '.' + inst_name) + + self.__low = low + self.__high = high + + # there are a couple of properties that have been included because they may be needed in + # the future but are currently unused + # pylint: disable=unused-private-member + self.__lsb = lsb + self.__msb = msb + + if (msb == high) and (lsb == low): + self.__lsb0 = True + self.__msb0 = False + elif (msb == low) and (lsb == high): + self.__lsb0 = False + self.__msb0 = True + else: + raise ValueError('msb/lsb are inconsistent with low/high') + # pylint: enable=unused-private-member + + self.__parent_register = parent_register + self.__parent_width = parent_width + + self.__bitmask = 0 + for bit_position in range(low, high+1): + self.__bitmask |= (1 << bit_position) + + parent_max_value = (2 ** parent_width) - 1 + self.__inverse_bitmask = parent_max_value ^ self.__bitmask + + self.__read_callback: Optional[FieldReadCallback] = None + self.__write_callback: Optional[FieldWriteCallback] = None + + @property + def read_callback(self) -> Optional[FieldReadCallback]: + """ + Callback made during each read operation + """ + return self.__read_callback + + @read_callback.setter + def read_callback(self, callback: Optional[FieldReadCallback]) -> None: + self.__read_callback = callback + + @property + def write_callback(self) -> Optional[FieldWriteCallback]: + """ + Callback made during each write operation + """ + return self.__write_callback + + @write_callback.setter + def write_callback(self, callback: Optional[FieldWriteCallback]) -> None: + self.__write_callback = callback + + @property + def __width(self) -> int: + return self.__high - self.__low + 1 + + @property + def value(self) -> int: + """ + Access the register value without triggering the callbacks + """ + + reg_value = self.__parent_register.value + + if self.__msb0: + return swap_msb_lsb_ordering(value=(reg_value & self.__bitmask) >> self.__low, + width=self.__width) + + return (reg_value & self.__bitmask) >> self.__low + + @value.setter + def value(self, value: int) -> None: + + if self.__msb0: + value = swap_msb_lsb_ordering(value=value, width=self.__width) + + if (self.__high == (self.__parent_width - 1)) and (self.__low == 0): + # special case where the field occupies the whole register, + # there a straight write can be performed + self.__parent_register.value = value + else: + # do a read, modify write + reg_value = self.__parent_register.read() + self.__parent_register.value = (reg_value & self.__inverse_bitmask) | \ + (value << self.__low) diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/memory.py b/rdl/outputs/python/msk_top_regs/sim_lib/memory.py new file mode 100644 index 0000000..209f0ca --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/memory.py @@ -0,0 +1,159 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from typing import Optional + +from .base import Base +from ._callbacks import MemoryReadCallback, MemoryWriteCallback + + +class _MemoryContent: + + __slots__ = ['__value', '__default_value', '__length'] + + def __init__(self, *, + default_value: int): + self.__value:dict[int, int] = {} + self.__default_value = default_value + + def __getitem__(self, item: int) -> int: + if item in self.__value: + return self.__value[item] + + return self.__default_value + + def __setitem__(self, key: int, value: int) -> None: + self.__value[key] = value + + +class Memory(Base): + """ + Simulation of a memory, this is implemented using a sparse approach to avoid the simulator + storing every possible entry in a register map, which could be very big. + """ + __slots__ = ['__value', '__width', '__length', + '__read_callback', '__write_callback'] + + def __init__(self, *, + width: int, + length: int, + default_value: int, + full_inst_name: str): + + super().__init__(full_inst_name=full_inst_name) + + self.__value = _MemoryContent(default_value=default_value) + self.__width = width + self.__length = length + self.__read_callback: Optional[MemoryReadCallback] = None + self.__write_callback: Optional[MemoryWriteCallback] = None + + @property + def read_callback(self) -> Optional[MemoryReadCallback]: + """ + Callback made during each read operation + """ + return self.__read_callback + + @read_callback.setter + def read_callback(self, callback: Optional[MemoryReadCallback]) -> None: + self.__read_callback = callback + + @property + def write_callback(self) -> Optional[MemoryWriteCallback]: + """ + Callback made during each write operation + """ + return self.__write_callback + + @write_callback.setter + def write_callback(self, callback: Optional[MemoryWriteCallback]) -> None: + self.__write_callback = callback + + def read(self, offset: int) -> int: + """ + Read a memory word + + Args: + offset (int): Word offset in the memory + + Returns: + memory word content + + """ + self.__offset_range_check(offset) + value = self.value[offset] + if self.read_callback is not None: + # pylint does not recognise that the property is returning a callback therefore it + # is legal to call it. + # pylint: disable-next=not-callable + self.read_callback(offset=offset, value=value) + return value + + def write(self, offset: int, data: int) -> None: + """ + Write a memory word + + Args: + offset: (int): Word offset in the memory + data: data word + + Returns: + None + + """ + self.__offset_range_check(offset) + if self.write_callback is not None: + # pylint does not recognise that the property is returning a callback therefore it + # is legal to call it. + # pylint: disable-next=not-callable + self.write_callback(offset=offset, value=data) + self.value[offset] = data + + @property + def _width_in_bytes(self) -> int: + def roundup_pow2(x: int) -> int: + return 1 << (x - 1).bit_length() + + return roundup_pow2(self.__width) // 8 + + def byte_offset_to_word_offset(self, byte_offset: int) -> int: + """ + Determine a memory word offset + + Args: + byte_offset (int): byte offset from memory start + + Returns: + word offset + + """ + return byte_offset // self._width_in_bytes + + @property + def value(self) -> _MemoryContent: + """ + Access to the memory content, bypassing the callbacks + """ + return self.__value + + def __offset_range_check(self, offset: int) -> None: + if not 0 <= offset < self.__length: + raise IndexError(f'offset must in in range 0 to {self.__length-1}, got {offset:d}') diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/register.py b/rdl/outputs/python/msk_top_regs/sim_lib/register.py new file mode 100644 index 0000000..9f5b72a --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/register.py @@ -0,0 +1,211 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from abc import ABC, abstractmethod +from typing import Optional + +from .memory import Memory +from .base import Base +from .field import FieldDefinition, Field +from ._callbacks import RegisterReadCallback,RegisterWriteCallback + +# pylint: disable=too-many-arguments + +class BaseRegister(Base, ABC): + """ + Base class for registers + """ + + __slots__ = ['_width', '_readable', '_writable', 'fields', + '__read_callback', '__write_callback'] + + def __init__(self, *, + width: int, + full_inst_name: str, + readable: bool, + writable: bool, + fields: list[FieldDefinition]): + super().__init__(full_inst_name=full_inst_name) + self._width = width + self._readable = readable + self._writable = writable + self.fields = [Field(low=field_def.low, + high=field_def.high, + msb=field_def.msb, + lsb=field_def.lsb, + inst_name=field_def.inst_name, + parent_register=self, + parent_width=width) for field_def in fields] + self.__read_callback: Optional[RegisterReadCallback] = None + self.__write_callback: Optional[RegisterWriteCallback] = None + + @property + def read_callback(self) -> Optional[RegisterReadCallback]: + """ + Callback made during each read operation + """ + return self.__read_callback + + @read_callback.setter + def read_callback(self, callback: Optional[RegisterReadCallback]) -> None: + self.__read_callback = callback + + @property + def write_callback(self) -> Optional[RegisterWriteCallback]: + """ + Callback made during each write operation + """ + return self.__write_callback + + @write_callback.setter + def write_callback(self, callback: Optional[RegisterWriteCallback]) -> None: + self.__write_callback = callback + + def _action_read_callback(self) -> None: + if self.read_callback is not None: + # pylint does not recognise that the property is returning a callback therefore it + # is legal to call it. + # pylint: disable-next=not-callable + self.read_callback(value=self.value) + + for field in self.fields: + if field.read_callback is not None: + field.read_callback(value=field.value) + + def _action_write_callback(self) -> None: + if self.write_callback is not None: + # pylint does not recognise that the property is returning a callback therefore it + # is legal to call it. + # pylint: disable-next=not-callable + self.write_callback(value=self.value) + + for field in self.fields: + if field.write_callback is not None: + field.write_callback(value=field.value) + + @abstractmethod + def read(self) -> int: + """ + Read the register + + Returns: + register content + + """ + + @abstractmethod + def write(self, data: int) -> None: + """ + Write the register + + Args: + data (int): new register content + + Returns: + None + + """ + + @property + @abstractmethod + def value(self) -> int: + """ + Access the register value without triggering the callbacks + """ + + @value.setter + @abstractmethod + def value(self, value:int) -> None: + ... + + +class Register(BaseRegister): + """ + Class for Register that is created in normal logic + """ + + __slots__ = ['__value'] + + def __init__(self, *, + width: int, + full_inst_name: str, + readable: bool, + writable: bool, + fields: list[FieldDefinition]): + super().__init__(width=width, full_inst_name=full_inst_name, + readable=readable, writable=writable, fields=fields) + self.__value = 0 + + def read(self) -> int: + + self._action_read_callback() + return self.__value + + def write(self, data: int) -> None: + + self.__value = data + self._action_write_callback() + + @property + def value(self) -> int: + return self.__value + + @value.setter + def value(self, value: int) -> None: + self.__value = value + + +class MemoryRegister(BaseRegister): + """ + Class for Register that maps onto a memory + """ + + __slots__ = ['__memory', '__offset'] + + def __init__(self, *, + width: int, + full_inst_name: str, + readable: bool, + writable: bool, + memory: Memory, + memory_address_offset: int, + fields: list[FieldDefinition]): + super().__init__(width=width, full_inst_name=full_inst_name, + readable=readable, writable=writable, fields=fields) + if not isinstance(memory, Memory): + raise TypeError(f'memory type is wrong, got {type(memory)}') + self.__memory = memory + self.__offset = memory.byte_offset_to_word_offset(memory_address_offset) + + def read(self) -> int: + self._action_read_callback() + return self.__memory.read(self.__offset) + + def write(self, data: int) -> None: + self.__memory.write(self.__offset, data) + self._action_write_callback() + + @property + def value(self) -> int: + return self.__memory.value[self.__offset] + + @value.setter + def value(self, value: int) -> None: + self.__memory.value[self.__offset] = value diff --git a/rdl/outputs/python/msk_top_regs/sim_lib/simulator.py b/rdl/outputs/python/msk_top_regs/sim_lib/simulator.py new file mode 100644 index 0000000..e7cef5b --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/sim_lib/simulator.py @@ -0,0 +1,500 @@ +""" +peakrdl-python is a tool to generate Python Register Access Layer (RAL) from SystemRDL +Copyright (C) 2021 - 2023 + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +This module is intended to distributed as part of automatically generated code by the +peakrdl-python tool. It provides a set of base classes used by the autogenerated code +""" +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Optional, Union +from array import array as Array +import asyncio + +from .register import Register, MemoryRegister +from .memory import Memory +from .field import Field + +from ..lib.utility_functions import get_array_typecode + +@dataclass +class MemoryEntry: + """ + Class for an entry in the list of memories in the simulator + """ + start_address: int + end_address: int + memory: Memory + + def memory_offset(self, address: int) -> int: + """ + Convert an absolute address to word offset within a memory + + Args: + address: byte address + + Returns: memory word offset + + """ + return self.memory.byte_offset_to_word_offset(address - self.start_address) + + + def address_in_memory(self, address: int) -> bool: + """ + Determine if an address is within a memory or not + + Args: + address: byte address + + Returns: + if address is within the range of the memory + + """ + return self.start_address <= address <= self.end_address + + +class BaseSimulator(ABC): + """ + Base class of a simple simulate that can be used to test and debug peakrdl-python generated + register access layer (RAL) + """ + # pylint: disable=too-few-public-methods + + def __init__(self, address: int): + + # it is important to build the memories first as some registers may be within memories + self._memories = self._build_memories() + self._registers = self._build_registers() + self.address = address + + @abstractmethod + def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Register]], + Union[MemoryRegister, Register]]]: + """ + populate the register structure, this method is intended to implemented by the generated + code based on then design + """ + + @abstractmethod + def _build_memories(self) -> list[MemoryEntry]: + """ + populate the memory structure, this method is intended to written by the generated code + based on then design + """ + + def memory_for_address(self, address: int) -> Optional[MemoryEntry]: + """ + Find a memory entry for a given address + + Args: + address: byte address + + Returns: + None or matching memory entry + + """ + + memory_subset = list(filter(lambda x : x.address_in_memory(address=address), + self._memories)) + + if len(memory_subset) > 1: + raise RuntimeError(f'multiple memory matches on address 0x{address:X}({address:d})') + + if len(memory_subset) == 1: + return memory_subset[0] + + return None + + def memory_for_address_with_exception(self, address: int) -> MemoryEntry: + """ + Find a memory entry for a given address + + Args: + address: byte address + + Returns: + matching memory entry + + """ + + memory_entry = self.memory_for_address(address=address) + if memory_entry is None: + raise RuntimeError(f'Memory not found at address 0x{address:X}') + + return memory_entry + + def _read(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int) -> int: # pylint: disable=unused-argument + """ + function to simulate a device read, this needs to match the protocol for the callbacks + """ + + # see if the address is a register first this ensures that registers in memories are + # accessed directly + if addr in self._registers: + addr_entry = self._registers[addr] + if isinstance(addr_entry, list): + # search the list for a readable register + for inner_reg in addr_entry: + # pylint: disable-next=protected-access + if inner_reg._readable: + return inner_reg.read() + else: + return addr_entry.read() + + potential_memory = self.memory_for_address(address=addr) + if potential_memory is not None: + return potential_memory.memory.read(offset=potential_memory.memory_offset(addr)) + + # catch all for other addresses + return 0 + + def _write(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int, # pylint: disable=unused-argument + data: int) -> None: + """ + function to simulate a device write, this needs to match the protocol for the callbacks + """ + # see if the address is a register first this ensures that registers in memories are + # accessed directly + if addr in self._registers: + addr_entry = self._registers[addr] + if isinstance(addr_entry, list): + for inner_reg in addr_entry: + # pylint: disable-next=protected-access + if inner_reg._writable: + inner_reg.write(data) + else: + addr_entry.write(data) + else: + potential_memory = self.memory_for_address(address=addr) + if potential_memory is not None: + potential_memory.memory.write(offset=potential_memory.memory_offset(addr), + data=data) + + def _read_block_legacy(self, addr: int, width: int, accesswidth: int, length: int) -> Array: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + return Array(get_array_typecode(width),self._read_block(addr=addr, + width=width, + accesswidth=accesswidth, + length=length)) + + def _read_block(self, addr: int, width: int, accesswidth: int, length: int) -> list[int]: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + addresses = self._block_access_addresses(start_address=addr, width=width, length=length) + return [self._read(element_addr, + width=width, + accesswidth=accesswidth) for element_addr in addresses] + + def _write_block(self, addr: int, width: int, accesswidth: int, + data: Union[list, Array]) -> None: + """ + function to simulate a device block write, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + addresses = self._block_access_addresses(start_address=addr, + width=width, + length=len(data)) + for (element_address, element_data) in zip(addresses, data): + self._write(addr=element_address, + data=element_data, + width=width, + accesswidth=accesswidth) + + @staticmethod + def _block_access_addresses(start_address: int, width: int, length: int) -> range: + """ + + Args: + start_address: start byte address + width: word width + length: number of word in the block + + Returns: range iterator for the addresses in the block + """ + def roundup_pow2(x: int) -> int: + return 1 << (x - 1).bit_length() + + address_increment = roundup_pow2(width) // 8 + end_address = start_address + (length * address_increment) + return range(start_address, end_address, address_increment) + + def register_by_full_name(self, name: str) -> Union[MemoryRegister, Register]: + """ + Find a register in the simulator by its fully qualified name + + Args: + name: fully qualified register name + + Returns: Register + + """ + for reg in self._registers.values(): + if isinstance(reg, list): + for reg_list_entry in reg: + if reg_list_entry.full_inst_name == name: + return reg_list_entry + else: + if reg.full_inst_name == name: + return reg + + raise ValueError(f'register name not matched: {name}') + + def field_by_full_name(self, name: str) -> Field: + """ + Find a register field in the simulator by its fully qualified name + + Args: + name: fully qualified field name + + Returns: Field + + """ + for reg in self._registers.values(): + if isinstance(reg, list): + for reg_list_entry in reg: + for field in reg_list_entry.fields: + if field.full_inst_name == name: + return field + else: + for field in reg.fields: + if field.full_inst_name == name: + return field + + raise ValueError(f'field name not matched: {name}') + + def node_by_full_name(self, name: str) -> Union[Memory, MemoryRegister, Register, Field]: + """ + Find a node in the simulator by its fully qualified name + + Args: + name: fully qualified node name + + Returns: Node + + """ + + for mem in self._memories: + if mem.memory.full_inst_name == name: + return mem.memory + + for reg in self._registers.values(): + if isinstance(reg, list): + for reg_list_entry in reg: + if reg_list_entry.full_inst_name == name: + return reg_list_entry + + for field in reg_list_entry.fields: + if field.full_inst_name == name: + return field + else: + if reg.full_inst_name == name: + return reg + + for field in reg.fields: + if field.full_inst_name == name: + return field + + raise ValueError(f'node name not matched: {name}') + + +class Simulator(BaseSimulator, ABC): + """ + Base class of a simple simulator that uses non-async callbacks that can be used to test and + debug peakrdl-python generated register access layer (RAL) + """ + + def read(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int) -> int: # pylint: disable=unused-argument + """ + function to simulate a device read, this needs to match the protocol for the callbacks + """ + return self._read(addr, width, accesswidth) + + def write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + function to simulate a device write, this needs to match the protocol for the callbacks + """ + return self._write(addr, width, accesswidth, data) + + def read_block(self, addr: int, width: int, accesswidth: int, length: int) -> list[int]: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + return self._read_block(addr, width, accesswidth, length) + + def write_block(self, addr: int, width: int, accesswidth: int, data: list[int]) -> None: + """ + function to simulate a device block write, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + return self._write_block(addr, width, accesswidth, data) + + +class SimulatorLegacy(BaseSimulator, ABC): + """ + Base class of a simple simulator that uses non-async callbacks that can be used to test and + debug peakrdl-python generated register access layer (RAL) + """ + + def read(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int) -> int: # pylint: disable=unused-argument + """ + function to simulate a device read, this needs to match the protocol for the callbacks + """ + return self._read(addr, width, accesswidth) + + def write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + function to simulate a device write, this needs to match the protocol for the callbacks + """ + return self._write(addr, width, accesswidth, data) + + def read_block(self, addr: int, width: int, accesswidth: int, length: int) -> Array: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + return self._read_block_legacy(addr, width, accesswidth, length) + + def write_block(self, addr: int, width: int, accesswidth: int, data: Array) -> None: + """ + function to simulate a device block write, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + return self._write_block(addr, width, accesswidth, data) + + +class AsyncSimulator(BaseSimulator, ABC): + """ + Base class of a simple simulator that uses async callbacks that can be used to test and + debug peakrdl-python generated register access layer (RAL) + """ + + async def read(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int) -> int: # pylint: disable=unused-argument + """ + function to simulate a device read, this needs to match the protocol for the callbacks + """ + await asyncio.sleep(0) + return self._read(addr, width, accesswidth) + + async def write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + function to simulate a device write, this needs to match the protocol for the callbacks + """ + await asyncio.sleep(0) + return self._write(addr, width, accesswidth, data) + + async def read_block(self, addr: int, width: int, accesswidth: int, length: int) -> list[int]: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + await asyncio.sleep(0) + return self._read_block(addr, width, accesswidth, length) + + async def write_block(self, addr: int, width: int, accesswidth: int, data: list[int]) -> None: + """ + function to simulate a device block write, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + await asyncio.sleep(0) + return self._write_block(addr, width, accesswidth, data) + + +class AsyncSimulatorLegacy(BaseSimulator, ABC): + """ + Base class of a simple simulator that uses async callbacks that can be used to test and + debug peakrdl-python generated register access layer (RAL) + """ + + async def read(self, addr: int, + width: int, # pylint: disable=unused-argument + accesswidth: int) -> int: # pylint: disable=unused-argument + """ + function to simulate a device read, this needs to match the protocol for the callbacks + """ + await asyncio.sleep(0) + return self._read(addr, width, accesswidth) + + async def write(self, addr: int, width: int, accesswidth: int, data: int) -> None: + """ + function to simulate a device write, this needs to match the protocol for the callbacks + """ + await asyncio.sleep(0) + return self._write(addr, width, accesswidth, data) + + async def read_block(self, addr: int, width: int, accesswidth: int, length: int) -> Array: + """ + function to simulate a device block read, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + await asyncio.sleep(0) + return self._read_block_legacy(addr, width, accesswidth, length) + + async def write_block(self, addr: int, width: int, accesswidth: int, data: Array) -> None: + """ + function to simulate a device block write, this needs to match the protocol for the + callbacks + + This currently uses a simplified implementation of converting all the block operations + to discrete operations, a future enhancement could be to access slices of memories + """ + await asyncio.sleep(0) + return self._write_block(addr, width, accesswidth, data) diff --git a/rdl/outputs/python/msk_top_regs/tests/__init__.py b/rdl/outputs/python/msk_top_regs/tests/__init__.py new file mode 100644 index 0000000..2ae2839 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/tests/__init__.py @@ -0,0 +1 @@ +pass diff --git a/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_sim_test_base.py b/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_sim_test_base.py new file mode 100644 index 0000000..65350f8 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_sim_test_base.py @@ -0,0 +1,50 @@ + + + +""" +Unit Tests for the msk_top_regs register model Python Wrapper + +This code was generated from the PeakRDL-python package version 1.4.0 +""" + + +import sys +import asyncio +if sys.version_info < (3, 8): + import asynctest # type: ignore[import] +else: + import unittest + + + +from ..lib import RegisterWriteVerifyError + +from ..lib import AsyncCallbackSet + + +from ._msk_top_regs_test_base import msk_top_regs_TestCase, msk_top_regs_TestCase_BlockAccess + +from ..reg_model.msk_top_regs import msk_top_regs_cls +from ..sim.msk_top_regs import msk_top_regs_simulator_cls + +class msk_top_regs_SimTestCase(msk_top_regs_TestCase): # type: ignore[valid-type,misc] + + def setUp(self) -> None: + self.sim = msk_top_regs_simulator_cls(address=0) + self.dut = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=self.sim.read, + write_callback=self.sim.write)) + +class msk_top_regs_SimTestCase_BlockAccess(msk_top_regs_TestCase_BlockAccess): # type: ignore[valid-type,misc] + + def setUp(self) -> None: + self.sim = msk_top_regs_simulator_cls(address=0) + self.dut = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=self.sim.read, + write_callback=self.sim.write, + read_block_callback=self.sim.read_block, + write_block_callback=self.sim.write_block)) + + + + +if __name__ == '__main__': + pass \ No newline at end of file diff --git a/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_test_base.py b/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_test_base.py new file mode 100644 index 0000000..eebf57f --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/tests/_msk_top_regs_test_base.py @@ -0,0 +1,121 @@ + + + +""" +Unit Tests for the msk_top_regs register model Python Wrapper + +This code was generated from the PeakRDL-python package version 1.4.0 +""" +from array import array as Array + +import sys +import asyncio +if sys.version_info < (3, 8): + import asynctest # type: ignore[import] +else: + import unittest + +import random + + + +from ..lib import RegisterWriteVerifyError + +from ..lib import AsyncCallbackSet, AsyncCallbackSetLegacy + + + +from ..reg_model.msk_top_regs import msk_top_regs_cls + +from ..sim_lib.dummy_callbacks import async_dummy_read as read_addr_space +from ..sim_lib.dummy_callbacks import async_dummy_write as write_addr_space +from ..sim_lib.dummy_callbacks import async_dummy_read_block as read_block_addr_space +from ..sim_lib.dummy_callbacks import async_dummy_write_block as write_block_addr_space +from ..sim_lib.dummy_callbacks import async_dummy_read_block_legacy as read_block_addr_space_alt +from ..sim_lib.dummy_callbacks import async_dummy_write_block_legacy as write_block_addr_space_alt + + + +from ..lib import SystemRDLEnum, SystemRDLEnumEntry + + +async def read_callback(addr: int, width: int, accesswidth: int) -> int: + return await read_addr_space(addr=addr, width=width, accesswidth=accesswidth) + +async def read_block_callback(addr: int, width: int, accesswidth: int, length: int) -> list[int]: + return await read_block_addr_space(addr=addr, width=width, accesswidth=accesswidth, length=length) + +async def read_block_callback_alt(addr: int, width: int, accesswidth: int, length: int) -> Array: + return await read_block_addr_space_alt(addr=addr, width=width, accesswidth=accesswidth, length=length) + +async def write_callback(addr: int, width: int, accesswidth: int, data: int) -> None: + await write_addr_space(addr=addr, width=width, accesswidth=accesswidth, data=data) + +async def write_block_callback(addr: int, width: int, accesswidth: int, data: list[int]) -> None: + await write_block_addr_space(addr=addr, width=width, accesswidth=accesswidth, data=data) + +async def write_block_callback_alt(addr: int, width: int, accesswidth: int, data: Array) -> None: + await write_block_addr_space_alt(addr=addr, width=width, accesswidth=accesswidth, data=data) + +def random_enum_reg_value(enum_class: type[SystemRDLEnum]) -> SystemRDLEnum: + return random.choice(list(enum_class)) + + +if sys.version_info < (3, 8): + TestCaseBase = asynctest.TestCase +else: + TestCaseBase = unittest.IsolatedAsyncioTestCase + + +class msk_top_regs_TestCase(TestCaseBase): # type: ignore[valid-type,misc] + + def setUp(self) -> None: + self.dut = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=read_callback, + write_callback=write_callback)) + + @staticmethod + def _reverse_bits(value: int, number_bits: int) -> int: + """ + + Args: + value: value to reverse + number_bits: number of bits used in the value + + Returns: + reversed valued + """ + result = 0 + for i in range(number_bits): + if (value >> i) & 1: + result |= 1 << (number_bits - 1 - i) + return result + +class msk_top_regs_TestCase_BlockAccess(TestCaseBase): # type: ignore[valid-type,misc] + + def setUp(self) -> None: + self.dut = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=read_callback, + write_callback=write_callback, + read_block_callback=read_block_callback, + write_block_callback=write_block_callback)) + +class msk_top_regs_TestCase_AltBlockAccess(TestCaseBase): # type: ignore[valid-type,misc] + """ + Based test to use with the alternative call backs, this allow the legacy output API to be tested + with the new callbacks and visa versa. + """ + + def setUp(self) -> None: + self.dut = msk_top_regs_cls(callbacks=AsyncCallbackSetLegacy( + read_callback=read_callback, + write_callback=write_callback, + read_block_callback=read_block_callback_alt, + write_block_callback=write_block_callback_alt)) + + + + +if __name__ == '__main__': + pass + + + diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py new file mode 100644 index 0000000..9241d51 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -0,0 +1,16576 @@ + + + +""" +Unit Tests for the msk_top_regs register model Python Wrapper + +This code was generated from the PeakRDL-python package version 1.4.0 +""" +from typing import Union,Iterable +from array import array as Array + +import sys +import asyncio +import unittest +from unittest.mock import patch, call + +import random +from itertools import combinations, chain +import math + + +from ..lib import RegisterWriteVerifyError, UnsupportedWidthError + +from ..reg_model.msk_top_regs import msk_top_regs_cls + + + + +from ..lib import FieldAsyncReadOnly, FieldAsyncWriteOnly, FieldAsyncReadWrite +from ..lib import WritableAsyncRegister, ReadableAsyncRegister +from ..lib import RegAsyncReadWrite, RegAsyncReadOnly, RegAsyncWriteOnly +from ..lib import RegAsyncReadWriteArray, RegAsyncReadOnlyArray, RegAsyncWriteOnlyArray +from ..lib import MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite +from ..lib import MemoryAsyncReadOnlyArray, MemoryAsyncWriteOnlyArray, MemoryAsyncReadWriteArray +from ..lib import AsyncAddressMap, AsyncRegFile +from ..lib import AsyncAddressMapArray, AsyncRegFileArray +from ..lib import AsyncMemory + + + +from ..lib import Field +from ..lib import Reg + +from ..lib import SystemRDLEnum, SystemRDLEnumEntry + + +from ._msk_top_regs_test_base import msk_top_regs_TestCase, msk_top_regs_TestCase_BlockAccess, msk_top_regs_TestCase_AltBlockAccess +from ._msk_top_regs_test_base import __name__ as base_name +from ._msk_top_regs_test_base import random_enum_reg_value + + + +class msk_top_regs_single_access(msk_top_regs_TestCase): # type: ignore[valid-type,misc] + + def test_inst_name(self) -> None: + """ + Walk the address map and check the inst name has been correctly populated + """ + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low'): + self.assertEqual(self.dut.Hash_ID_Low.inst_name, 'Hash_ID_Low') # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_Low.full_inst_name, 'msk_top_regs.Hash_ID_Low') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_High'): + self.assertEqual(self.dut.Hash_ID_High.inst_name, 'Hash_ID_High') # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_High.full_inst_name, 'msk_top_regs.Hash_ID_High') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init'): + self.assertEqual(self.dut.MSK_Init.inst_name, 'MSK_Init') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.full_inst_name, 'msk_top_regs.MSK_Init') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control'): + self.assertEqual(self.dut.MSK_Control.inst_name, 'MSK_Control') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.full_inst_name, 'msk_top_regs.MSK_Control') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status'): + self.assertEqual(self.dut.MSK_Status.inst_name, 'MSK_Status') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.full_inst_name, 'msk_top_regs.MSK_Status') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count'): + self.assertEqual(self.dut.Tx_Bit_Count.inst_name, 'Tx_Bit_Count') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.full_inst_name, 'msk_top_regs.Tx_Bit_Count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count'): + self.assertEqual(self.dut.Tx_Enable_Count.inst_name, 'Tx_Enable_Count') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.full_inst_name, 'msk_top_regs.Tx_Enable_Count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord'): + self.assertEqual(self.dut.Fb_FreqWord.inst_name, 'Fb_FreqWord') # type: ignore[union-attr] + self.assertEqual(self.dut.Fb_FreqWord.full_inst_name, 'msk_top_regs.Fb_FreqWord') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord'): + self.assertEqual(self.dut.TX_F1_FreqWord.inst_name, 'TX_F1_FreqWord') # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F1_FreqWord.full_inst_name, 'msk_top_regs.TX_F1_FreqWord') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord'): + self.assertEqual(self.dut.TX_F2_FreqWord.inst_name, 'TX_F2_FreqWord') # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F2_FreqWord.full_inst_name, 'msk_top_regs.TX_F2_FreqWord') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord'): + self.assertEqual(self.dut.RX_F1_FreqWord.inst_name, 'RX_F1_FreqWord') # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F1_FreqWord.full_inst_name, 'msk_top_regs.RX_F1_FreqWord') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord'): + self.assertEqual(self.dut.RX_F2_FreqWord.inst_name, 'RX_F2_FreqWord') # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F2_FreqWord.full_inst_name, 'msk_top_regs.RX_F2_FreqWord') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0'): + self.assertEqual(self.dut.LPF_Config_0.inst_name, 'LPF_Config_0') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.full_inst_name, 'msk_top_regs.LPF_Config_0') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1'): + self.assertEqual(self.dut.LPF_Config_1.inst_name, 'LPF_Config_1') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.full_inst_name, 'msk_top_regs.LPF_Config_1') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width'): + self.assertEqual(self.dut.Tx_Data_Width.inst_name, 'Tx_Data_Width') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Data_Width.full_inst_name, 'msk_top_regs.Tx_Data_Width') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width'): + self.assertEqual(self.dut.Rx_Data_Width.inst_name, 'Rx_Data_Width') # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Data_Width.full_inst_name, 'msk_top_regs.Rx_Data_Width') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control'): + self.assertEqual(self.dut.PRBS_Control.inst_name, 'PRBS_Control') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.full_inst_name, 'msk_top_regs.PRBS_Control') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State'): + self.assertEqual(self.dut.PRBS_Initial_State.inst_name, 'PRBS_Initial_State') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Initial_State.full_inst_name, 'msk_top_regs.PRBS_Initial_State') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial'): + self.assertEqual(self.dut.PRBS_Polynomial.inst_name, 'PRBS_Polynomial') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Polynomial.full_inst_name, 'msk_top_regs.PRBS_Polynomial') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask'): + self.assertEqual(self.dut.PRBS_Error_Mask.inst_name, 'PRBS_Error_Mask') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Mask.full_inst_name, 'msk_top_regs.PRBS_Error_Mask') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count'): + self.assertEqual(self.dut.PRBS_Bit_Count.inst_name, 'PRBS_Bit_Count') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.full_inst_name, 'msk_top_regs.PRBS_Bit_Count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count'): + self.assertEqual(self.dut.PRBS_Error_Count.inst_name, 'PRBS_Error_Count') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.full_inst_name, 'msk_top_regs.PRBS_Error_Count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1'): + self.assertEqual(self.dut.LPF_Accum_F1.inst_name, 'LPF_Accum_F1') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.full_inst_name, 'msk_top_regs.LPF_Accum_F1') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2'): + self.assertEqual(self.dut.LPF_Accum_F2.inst_name, 'LPF_Accum_F2') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.full_inst_name, 'msk_top_regs.LPF_Accum_F2') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count'): + self.assertEqual(self.dut.axis_xfer_count.inst_name, 'axis_xfer_count') # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.full_inst_name, 'msk_top_regs.axis_xfer_count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard'): + self.assertEqual(self.dut.Rx_Sample_Discard.inst_name, 'Rx_Sample_Discard') # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.full_inst_name, 'msk_top_regs.Rx_Sample_Discard') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2'): + self.assertEqual(self.dut.LPF_Config_2.inst_name, 'LPF_Config_2') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.full_inst_name, 'msk_top_regs.LPF_Config_2') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): + self.assertEqual(self.dut.f1_nco_adjust.inst_name, 'f1_nco_adjust') # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.full_inst_name, 'msk_top_regs.f1_nco_adjust') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): + self.assertEqual(self.dut.f2_nco_adjust.inst_name, 'f2_nco_adjust') # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.full_inst_name, 'msk_top_regs.f2_nco_adjust') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_error'): + self.assertEqual(self.dut.f1_error.inst_name, 'f1_error') # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.full_inst_name, 'msk_top_regs.f1_error') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_error'): + self.assertEqual(self.dut.f2_error.inst_name, 'f2_error') # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.full_inst_name, 'msk_top_regs.f2_error') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.inst_name, 'Tx_Sync_Ctrl') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.full_inst_name, 'msk_top_regs.Tx_Sync_Ctrl') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt'): + self.assertEqual(self.dut.Tx_Sync_Cnt.inst_name, 'Tx_Sync_Cnt') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.full_inst_name, 'msk_top_regs.Tx_Sync_Cnt') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1'): + self.assertEqual(self.dut.lowpass_ema_alpha1.inst_name, 'lowpass_ema_alpha1') # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha1.full_inst_name, 'msk_top_regs.lowpass_ema_alpha1') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2'): + self.assertEqual(self.dut.lowpass_ema_alpha2.inst_name, 'lowpass_ema_alpha2') # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha2.full_inst_name, 'msk_top_regs.lowpass_ema_alpha2') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power'): + self.assertEqual(self.dut.rx_power.inst_name, 'rx_power') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.full_inst_name, 'msk_top_regs.rx_power') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): + self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.inst_name, 'hash_id_lo') # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.full_inst_name, 'msk_top_regs.Hash_ID_Low.hash_id_lo') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_High.hash_id_hi'): + self.assertEqual(self.dut.Hash_ID_High.hash_id_hi.inst_name, 'hash_id_hi') # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_High.hash_id_hi.full_inst_name, 'msk_top_regs.Hash_ID_High.hash_id_hi') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.txrxinit'): + self.assertEqual(self.dut.MSK_Init.txrxinit.inst_name, 'txrxinit') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.txrxinit.full_inst_name, 'msk_top_regs.MSK_Init.txrxinit') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.txinit'): + self.assertEqual(self.dut.MSK_Init.txinit.inst_name, 'txinit') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.txinit.full_inst_name, 'msk_top_regs.MSK_Init.txinit') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.rxinit'): + self.assertEqual(self.dut.MSK_Init.rxinit.inst_name, 'rxinit') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.rxinit.full_inst_name, 'msk_top_regs.MSK_Init.rxinit') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.ptt'): + self.assertEqual(self.dut.MSK_Control.ptt.inst_name, 'ptt') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.ptt.full_inst_name, 'msk_top_regs.MSK_Control.ptt') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.loopback_ena'): + self.assertEqual(self.dut.MSK_Control.loopback_ena.inst_name, 'loopback_ena') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.loopback_ena.full_inst_name, 'msk_top_regs.MSK_Control.loopback_ena') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.rx_invert'): + self.assertEqual(self.dut.MSK_Control.rx_invert.inst_name, 'rx_invert') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.rx_invert.full_inst_name, 'msk_top_regs.MSK_Control.rx_invert') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.clear_counts'): + self.assertEqual(self.dut.MSK_Control.clear_counts.inst_name, 'clear_counts') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.clear_counts.full_inst_name, 'msk_top_regs.MSK_Control.clear_counts') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.diff_encoder_loopback'): + self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.inst_name, 'diff_encoder_loopback') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.full_inst_name, 'msk_top_regs.MSK_Control.diff_encoder_loopback') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.demod_sync_lock'): + self.assertEqual(self.dut.MSK_Status.demod_sync_lock.inst_name, 'demod_sync_lock') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.demod_sync_lock.full_inst_name, 'msk_top_regs.MSK_Status.demod_sync_lock') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_enable'): + self.assertEqual(self.dut.MSK_Status.tx_enable.inst_name, 'tx_enable') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.tx_enable.full_inst_name, 'msk_top_regs.MSK_Status.tx_enable') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.rx_enable'): + self.assertEqual(self.dut.MSK_Status.rx_enable.inst_name, 'rx_enable') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.rx_enable.full_inst_name, 'msk_top_regs.MSK_Status.rx_enable') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): + self.assertEqual(self.dut.MSK_Status.tx_axis_valid.inst_name, 'tx_axis_valid') # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.tx_axis_valid.full_inst_name, 'msk_top_regs.MSK_Status.tx_axis_valid') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.inst_name, 'tx_bit_counter') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.full_inst_name, 'msk_top_regs.Tx_Bit_Count.tx_bit_counter') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.inst_name, 'tx_ena_counter') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.full_inst_name, 'msk_top_regs.Tx_Enable_Count.tx_ena_counter') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): + self.assertEqual(self.dut.Fb_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.Fb_FreqWord.config_data.full_inst_name, 'msk_top_regs.Fb_FreqWord.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord.config_data'): + self.assertEqual(self.dut.TX_F1_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F1_FreqWord.config_data.full_inst_name, 'msk_top_regs.TX_F1_FreqWord.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord.config_data'): + self.assertEqual(self.dut.TX_F2_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F2_FreqWord.config_data.full_inst_name, 'msk_top_regs.TX_F2_FreqWord.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord.config_data'): + self.assertEqual(self.dut.RX_F1_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F1_FreqWord.config_data.full_inst_name, 'msk_top_regs.RX_F1_FreqWord.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord.config_data'): + self.assertEqual(self.dut.RX_F2_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F2_FreqWord.config_data.full_inst_name, 'msk_top_regs.RX_F2_FreqWord.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_freeze'): + self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.inst_name, 'lpf_freeze') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.full_inst_name, 'msk_top_regs.LPF_Config_0.lpf_freeze') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_zero'): + self.assertEqual(self.dut.LPF_Config_0.lpf_zero.inst_name, 'lpf_zero') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.lpf_zero.full_inst_name, 'msk_top_regs.LPF_Config_0.lpf_zero') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.prbs_reserved'): + self.assertEqual(self.dut.LPF_Config_0.prbs_reserved.inst_name, 'prbs_reserved') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.prbs_reserved.full_inst_name, 'msk_top_regs.LPF_Config_0.prbs_reserved') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_alpha'): + self.assertEqual(self.dut.LPF_Config_0.lpf_alpha.inst_name, 'lpf_alpha') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.lpf_alpha.full_inst_name, 'msk_top_regs.LPF_Config_0.lpf_alpha') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_gain'): + self.assertEqual(self.dut.LPF_Config_1.i_gain.inst_name, 'i_gain') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.i_gain.full_inst_name, 'msk_top_regs.LPF_Config_1.i_gain') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_shift'): + self.assertEqual(self.dut.LPF_Config_1.i_shift.inst_name, 'i_shift') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.i_shift.full_inst_name, 'msk_top_regs.LPF_Config_1.i_shift') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width.data_width'): + self.assertEqual(self.dut.Tx_Data_Width.data_width.inst_name, 'data_width') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Data_Width.data_width.full_inst_name, 'msk_top_regs.Tx_Data_Width.data_width') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width.data_width'): + self.assertEqual(self.dut.Rx_Data_Width.data_width.inst_name, 'data_width') # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Data_Width.data_width.full_inst_name, 'msk_top_regs.Rx_Data_Width.data_width') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sel'): + self.assertEqual(self.dut.PRBS_Control.prbs_sel.inst_name, 'prbs_sel') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_sel.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_sel') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_error_insert'): + self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.inst_name, 'prbs_error_insert') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_error_insert') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_clear'): + self.assertEqual(self.dut.PRBS_Control.prbs_clear.inst_name, 'prbs_clear') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_clear.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_clear') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_manual_sync'): + self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.inst_name, 'prbs_manual_sync') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_manual_sync') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_reserved'): + self.assertEqual(self.dut.PRBS_Control.prbs_reserved.inst_name, 'prbs_reserved') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_reserved.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_reserved') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.inst_name, 'prbs_sync_threshold') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.full_inst_name, 'msk_top_regs.PRBS_Control.prbs_sync_threshold') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State.config_data'): + self.assertEqual(self.dut.PRBS_Initial_State.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Initial_State.config_data.full_inst_name, 'msk_top_regs.PRBS_Initial_State.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial.config_data'): + self.assertEqual(self.dut.PRBS_Polynomial.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Polynomial.config_data.full_inst_name, 'msk_top_regs.PRBS_Polynomial.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask.config_data'): + self.assertEqual(self.dut.PRBS_Error_Mask.config_data.inst_name, 'config_data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Mask.config_data.full_inst_name, 'msk_top_regs.PRBS_Error_Mask.config_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + self.assertEqual(self.dut.PRBS_Bit_Count.status_data.inst_name, 'status_data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.status_data.full_inst_name, 'msk_top_regs.PRBS_Bit_Count.status_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + self.assertEqual(self.dut.PRBS_Error_Count.status_data.inst_name, 'status_data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.status_data.full_inst_name, 'msk_top_regs.PRBS_Error_Count.status_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + self.assertEqual(self.dut.LPF_Accum_F1.status_data.inst_name, 'status_data') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.status_data.full_inst_name, 'msk_top_regs.LPF_Accum_F1.status_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + self.assertEqual(self.dut.LPF_Accum_F2.status_data.inst_name, 'status_data') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.status_data.full_inst_name, 'msk_top_regs.LPF_Accum_F2.status_data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + self.assertEqual(self.dut.axis_xfer_count.xfer_count.inst_name, 'xfer_count') # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.xfer_count.full_inst_name, 'msk_top_regs.axis_xfer_count.xfer_count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.inst_name, 'rx_sample_discard') # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.full_inst_name, 'msk_top_regs.Rx_Sample_Discard.rx_sample_discard') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + self.assertEqual(self.dut.Rx_Sample_Discard.rx_nco_discard.inst_name, 'rx_nco_discard') # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.rx_nco_discard.full_inst_name, 'msk_top_regs.Rx_Sample_Discard.rx_nco_discard') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_gain'): + self.assertEqual(self.dut.LPF_Config_2.p_gain.inst_name, 'p_gain') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.p_gain.full_inst_name, 'msk_top_regs.LPF_Config_2.p_gain') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_shift'): + self.assertEqual(self.dut.LPF_Config_2.p_shift.inst_name, 'p_shift') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.p_shift.full_inst_name, 'msk_top_regs.LPF_Config_2.p_shift') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): + self.assertEqual(self.dut.f1_nco_adjust.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.data.full_inst_name, 'msk_top_regs.f1_nco_adjust.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): + self.assertEqual(self.dut.f2_nco_adjust.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.data.full_inst_name, 'msk_top_regs.f2_nco_adjust.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_error.data'): + self.assertEqual(self.dut.f1_error.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.data.full_inst_name, 'msk_top_regs.f1_error.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_error.data'): + self.assertEqual(self.dut.f2_error.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.data.full_inst_name, 'msk_top_regs.f2_error.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.inst_name, 'tx_sync_ena') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.full_inst_name, 'msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.inst_name, 'tx_sync_force') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.full_inst_name, 'msk_top_regs.Tx_Sync_Ctrl.tx_sync_force') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.inst_name, 'tx_sync_f1') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.full_inst_name, 'msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.inst_name, 'tx_sync_f2') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.full_inst_name, 'msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.inst_name, 'tx_sync_cnt') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.full_inst_name, 'msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1.alpha'): + self.assertEqual(self.dut.lowpass_ema_alpha1.alpha.inst_name, 'alpha') # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha1.alpha.full_inst_name, 'msk_top_regs.lowpass_ema_alpha1.alpha') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2.alpha'): + self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.inst_name, 'alpha') # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.full_inst_name, 'msk_top_regs.lowpass_ema_alpha2.alpha') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + self.assertEqual(self.dut.rx_power.rx_power.inst_name, 'rx_power') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.rx_power.full_inst_name, 'msk_top_regs.rx_power.rx_power') # type: ignore[union-attr] + + + def test_name_property(self) -> None: + """ + Walk the address map and check the name property has been correctly populated + """ + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low'): + + + self.assertEqual(self.dut.Hash_ID_Low.rdl_name, "Pluto MSK FPGA Hash ID - Lower 32-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_High'): + + + self.assertEqual(self.dut.Hash_ID_High.rdl_name, "Pluto MSK FPGA Hash ID - Upper 32-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init'): + + + self.assertEqual(self.dut.MSK_Init.rdl_name, "MSK Modem Initialization Control") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control'): + + + self.assertEqual(self.dut.MSK_Control.rdl_name, "MSK Modem Control") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status'): + + + self.assertEqual(self.dut.MSK_Status.rdl_name, "MSK Modem Status 0") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count'): + + + self.assertEqual(self.dut.Tx_Bit_Count.rdl_name, "MSK Modem Status 1") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count'): + + + self.assertEqual(self.dut.Tx_Enable_Count.rdl_name, "MSK Modem Status 2") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord'): + + + self.assertEqual(self.dut.Fb_FreqWord.rdl_name, "Bitrate NCO Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord'): + + + self.assertEqual(self.dut.TX_F1_FreqWord.rdl_name, "Tx F1 NCO Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord'): + + + self.assertEqual(self.dut.TX_F2_FreqWord.rdl_name, "Tx F2 NCO Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord'): + + + self.assertEqual(self.dut.RX_F1_FreqWord.rdl_name, "Rx F1 NCO Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord'): + + + self.assertEqual(self.dut.RX_F2_FreqWord.rdl_name, "Rx F2 NCO Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0'): + + + self.assertEqual(self.dut.LPF_Config_0.rdl_name, "PI Controller Configuration and Low-pass Filter Configuration") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1'): + + + self.assertEqual(self.dut.LPF_Config_1.rdl_name, "PI Controller Configuration Configuration Register 1") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width'): + + + self.assertEqual(self.dut.Tx_Data_Width.rdl_name, "Modem Tx Input Data Width") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width'): + + + self.assertEqual(self.dut.Rx_Data_Width.rdl_name, "Modem Rx Output Data Width") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control'): + + + self.assertEqual(self.dut.PRBS_Control.rdl_name, "PRBS Control 0") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State'): + + + self.assertEqual(self.dut.PRBS_Initial_State.rdl_name, "PRBS Control 1") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial'): + + + self.assertEqual(self.dut.PRBS_Polynomial.rdl_name, "PRBS Control 2") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask'): + + + self.assertEqual(self.dut.PRBS_Error_Mask.rdl_name, "PRBS Control 3") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count'): + + + self.assertEqual(self.dut.PRBS_Bit_Count.rdl_name, "PRBS Status 0") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count'): + + + self.assertEqual(self.dut.PRBS_Error_Count.rdl_name, "PRBS Status 1") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1'): + + + self.assertEqual(self.dut.LPF_Accum_F1.rdl_name, "F1 PI Controller Accumulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2'): + + + self.assertEqual(self.dut.LPF_Accum_F2.rdl_name, "F2 PI Controller Accumulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.axis_xfer_count'): + + + self.assertEqual(self.dut.axis_xfer_count.rdl_name, "MSK Modem Status 3") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rdl_name, "Rx Sample Discard") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2'): + + + self.assertEqual(self.dut.LPF_Config_2.rdl_name, "PI Controller Configuration Configuration Register 2") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): + + + self.assertEqual(self.dut.f1_nco_adjust.rdl_name, "F1 NCO Frequency Adjust") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): + + + self.assertEqual(self.dut.f2_nco_adjust.rdl_name, "F2 NCO Frequency Adjust") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_error'): + + + self.assertEqual(self.dut.f1_error.rdl_name, "F1 Error Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_error'): + + + self.assertEqual(self.dut.f2_error.rdl_name, "F2 Error Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.rdl_name, "Transmitter Sync Control") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt'): + + + self.assertEqual(self.dut.Tx_Sync_Cnt.rdl_name, "Transmitter Sync Duration") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1'): + + + self.assertEqual(self.dut.lowpass_ema_alpha1.rdl_name, "Exponential Moving Average Alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2'): + + + self.assertEqual(self.dut.lowpass_ema_alpha2.rdl_name, "Exponential Moving Average Alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_power'): + + + self.assertEqual(self.dut.rx_power.rdl_name, "Receive Power") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): + + + self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.rdl_name, "Hash ID Lower 32-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_High.hash_id_hi'): + + + self.assertEqual(self.dut.Hash_ID_High.hash_id_hi.rdl_name, "Hash ID Upper 32-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.txrxinit'): + + + self.assertEqual(self.dut.MSK_Init.txrxinit.rdl_name, "Tx/Rx Init Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.txinit'): + + + self.assertEqual(self.dut.MSK_Init.txinit.rdl_name, "Tx Init Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.rxinit'): + + + self.assertEqual(self.dut.MSK_Init.rxinit.rdl_name, "Rx Init Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.ptt'): + + + self.assertEqual(self.dut.MSK_Control.ptt.rdl_name, "Push-to-Talk Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.loopback_ena'): + + + self.assertEqual(self.dut.MSK_Control.loopback_ena.rdl_name, "Modem Digital Tx -\u003e Rx Loopback Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.rx_invert'): + + + self.assertEqual(self.dut.MSK_Control.rx_invert.rdl_name, "Rx Data Invert Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.clear_counts'): + + + self.assertEqual(self.dut.MSK_Control.clear_counts.rdl_name, "Clear Status Counters") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.diff_encoder_loopback'): + + + self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.rdl_name, "Differential Encoder -\u003e Decoder Loopback Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.demod_sync_lock'): + + + self.assertEqual(self.dut.MSK_Status.demod_sync_lock.rdl_name, "Demodulator Sync Status") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_enable'): + + + self.assertEqual(self.dut.MSK_Status.tx_enable.rdl_name, "AD9363 DAC Interface Tx Enable Input Active") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.rx_enable'): + + + self.assertEqual(self.dut.MSK_Status.rx_enable.rdl_name, "AD9363 ADC Interface Rx Enable Input Active") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): + + + self.assertEqual(self.dut.MSK_Status.tx_axis_valid.rdl_name, "Tx S_AXIS_VALID") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + + + self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.rdl_name, "Tx Bit Count") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + + + self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.rdl_name, "Tx Enable Count") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): + + + self.assertEqual(self.dut.Fb_FreqWord.config_data.rdl_name, "Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord.config_data'): + + + self.assertEqual(self.dut.TX_F1_FreqWord.config_data.rdl_name, "Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord.config_data'): + + + self.assertEqual(self.dut.TX_F2_FreqWord.config_data.rdl_name, "Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord.config_data'): + + + self.assertEqual(self.dut.RX_F1_FreqWord.config_data.rdl_name, "Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord.config_data'): + + + self.assertEqual(self.dut.RX_F2_FreqWord.config_data.rdl_name, "Frequency Control Word") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_freeze'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.rdl_name, "Freeze the accumulator\u0027s current value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_zero'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_zero.rdl_name, "Hold the PI Accumulator at zero") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.prbs_reserved'): + + + self.assertEqual(self.dut.LPF_Config_0.prbs_reserved.rdl_name, "Reserved") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_alpha'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_alpha.rdl_name, "Lowpass IIR filter alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_gain'): + + + self.assertEqual(self.dut.LPF_Config_1.i_gain.rdl_name, "Integral Gain Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_shift'): + + + self.assertEqual(self.dut.LPF_Config_1.i_shift.rdl_name, "Integral Gain Bit Shift") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width.data_width'): + + + self.assertEqual(self.dut.Tx_Data_Width.data_width.rdl_name, "Modem input/output data width") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width.data_width'): + + + self.assertEqual(self.dut.Rx_Data_Width.data_width.rdl_name, "Modem input/output data width") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sel'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_sel.rdl_name, "PRBS Data Select") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_error_insert'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.rdl_name, "PRBS Error Insert") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_clear'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_clear.rdl_name, "PRBS Clear Counters") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_manual_sync'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.rdl_name, "PRBS Manual Sync") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_reserved'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_reserved.rdl_name, "Reserved") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.rdl_name, "PRBS Auto Sync Threshold") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State.config_data'): + + + self.assertEqual(self.dut.PRBS_Initial_State.config_data.rdl_name, "PRBS Seed") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial.config_data'): + + + self.assertEqual(self.dut.PRBS_Polynomial.config_data.rdl_name, "PRBS Polynomial") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask.config_data'): + + + self.assertEqual(self.dut.PRBS_Error_Mask.config_data.rdl_name, "PRBS Error Mask") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + + + self.assertEqual(self.dut.PRBS_Bit_Count.status_data.rdl_name, "PRBS Bits Received") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + + + self.assertEqual(self.dut.PRBS_Error_Count.status_data.rdl_name, "PRBS Bit Errors") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + + + self.assertEqual(self.dut.LPF_Accum_F1.status_data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + + + self.assertEqual(self.dut.LPF_Accum_F2.status_data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + + + self.assertEqual(self.dut.axis_xfer_count.xfer_count.rdl_name, "S_AXIS Transfers") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.rdl_name, "Rx Sample Discard Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rx_nco_discard.rdl_name, "Rx NCO Sample Discard Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_gain'): + + + self.assertEqual(self.dut.LPF_Config_2.p_gain.rdl_name, "Proportional Gain Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_shift'): + + + self.assertEqual(self.dut.LPF_Config_2.p_shift.rdl_name, "Proportional Gain Bit Shift") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): + + + self.assertEqual(self.dut.f1_nco_adjust.data.rdl_name, "F1 NCO Frequency Adjust") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): + + + self.assertEqual(self.dut.f2_nco_adjust.data.rdl_name, "F2 NCO Frequency Adjust") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_error.data'): + + + self.assertEqual(self.dut.f1_error.data.rdl_name, "F1 Error Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_error.data'): + + + self.assertEqual(self.dut.f2_error.data.rdl_name, "F2 Error Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.rdl_name, "Tx Sync Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.rdl_name, "Tx Sync Force") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.rdl_name, "Tx F1 Sync Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.rdl_name, "Tx F2 Sync Enable") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + + + self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.rdl_name, "Tx sync duration") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1.alpha'): + + + self.assertEqual(self.dut.lowpass_ema_alpha1.alpha.rdl_name, "EMA alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2.alpha'): + + + self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.rdl_name, "EMA alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + + + self.assertEqual(self.dut.rx_power.rx_power.rdl_name, "Receive Power") # type: ignore[union-attr] + + + + + + def test_desc(self) -> None: + """ + Walk the address map and check the desc property has been correctly populated + """ + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low'): + + + self.assertIsNone(self.dut.Hash_ID_Low.rdl_desc) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_High'): + + + self.assertIsNone(self.dut.Hash_ID_High.rdl_desc) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init'): + + + self.assertEqual(self.dut.MSK_Init.rdl_desc, "Synchronous initialization of MSK Modem functions, does not affect configuration registers.") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control'): + + + self.assertEqual(self.dut.MSK_Control.rdl_desc, "MSK Modem Configuration and Control") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status'): + + + self.assertEqual(self.dut.MSK_Status.rdl_desc, "Modem status bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count'): + + + self.assertEqual(self.dut.Tx_Bit_Count.rdl_desc, "Modem status data") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count'): + + + self.assertEqual(self.dut.Tx_Enable_Count.rdl_desc, "Modem status data") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord'): + + + self.assertEqual(self.dut.Fb_FreqWord.rdl_desc, "Set Modem Data Rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord'): + + + self.assertEqual(self.dut.TX_F1_FreqWord.rdl_desc, "Set Modulator F1 Frequency") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord'): + + + self.assertEqual(self.dut.TX_F2_FreqWord.rdl_desc, "Set Modulator F2 Frequency") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord'): + + + self.assertEqual(self.dut.RX_F1_FreqWord.rdl_desc, "Set Demodulator F1 Frequency") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord'): + + + self.assertEqual(self.dut.RX_F2_FreqWord.rdl_desc, "Set Demodulator F2 Frequency") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0'): + + + self.assertEqual(self.dut.LPF_Config_0.rdl_desc, "Configure PI controller and low-pass filter") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1'): + + + self.assertEqual(self.dut.LPF_Config_1.rdl_desc, "Configures PI Controller I-gain and divisor") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width'): + + + self.assertEqual(self.dut.Tx_Data_Width.rdl_desc, "Set the parallel data width of the parallel-to-serial converter") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width'): + + + self.assertEqual(self.dut.Rx_Data_Width.rdl_desc, "Set the parallel data width of the serial-to-parallel converter") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control'): + + + self.assertEqual(self.dut.PRBS_Control.rdl_desc, "Configures operation of the PRBS Generator and Monitor") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State'): + + + self.assertEqual(self.dut.PRBS_Initial_State.rdl_desc, "PRBS Initial State") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial'): + + + self.assertEqual(self.dut.PRBS_Polynomial.rdl_desc, "PRBS Polynomial") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask'): + + + self.assertEqual(self.dut.PRBS_Error_Mask.rdl_desc, "PRBS Error Mask") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count'): + + + self.assertEqual(self.dut.PRBS_Bit_Count.rdl_desc, "PRBS Bits Received") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count'): + + + self.assertEqual(self.dut.PRBS_Error_Count.rdl_desc, "PRBS Bit Errors") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1'): + + + self.assertEqual(self.dut.LPF_Accum_F1.rdl_desc, "Value of the F1 PI Controller Accumulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2'): + + + self.assertEqual(self.dut.LPF_Accum_F2.rdl_desc, "Value of the F2 PI Controller Accumulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.axis_xfer_count'): + + + self.assertEqual(self.dut.axis_xfer_count.rdl_desc, "Modem status data") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rdl_desc, "Configure samples discard operation for demodulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2'): + + + self.assertEqual(self.dut.LPF_Config_2.rdl_desc, "Configures PI Controller I-gain and divisor") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): + + + self.assertEqual(self.dut.f1_nco_adjust.rdl_desc, "Frequency offet applied to the F1 NCO") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): + + + self.assertEqual(self.dut.f2_nco_adjust.rdl_desc, "Frequency offet applied to the F2 NCO") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_error'): + + + self.assertEqual(self.dut.f1_error.rdl_desc, "Error value of the F1 Costas loop after each active bit period") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_error'): + + + self.assertEqual(self.dut.f2_error.rdl_desc, "Error value of the F2 Costas loop after each active bit period") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.rdl_desc, "Provides control bits for generation of transmitter synchronization patterns") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt'): + + + self.assertEqual(self.dut.Tx_Sync_Cnt.rdl_desc, "Sets the duration of the synchronization tones when enabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1'): + + + self.assertEqual(self.dut.lowpass_ema_alpha1.rdl_desc, "Sets the alpha for the EMA") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2'): + + + self.assertEqual(self.dut.lowpass_ema_alpha2.rdl_desc, "Sets the alpha for the EMA") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_power'): + + + self.assertEqual(self.dut.rx_power.rdl_desc, "Receive power computed from I/Q ssamples") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): + + + self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.rdl_desc, "Lower 32-bits of Pluto MSK FPGA Hash ID") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_High.hash_id_hi'): + + + self.assertEqual(self.dut.Hash_ID_High.hash_id_hi.rdl_desc, "Upper 32-bits of Pluto MSK FPGA Hash ID") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.txrxinit'): + + + self.assertEqual(self.dut.MSK_Init.txrxinit.rdl_desc, "0 -\u003e Normal modem operation \n1 -\u003e Initialize Tx and Rx") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.txinit'): + + + self.assertEqual(self.dut.MSK_Init.txinit.rdl_desc, "0 -\u003e Normal Tx operation \n1 -\u003e Initialize Tx") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Init.rxinit'): + + + self.assertEqual(self.dut.MSK_Init.rxinit.rdl_desc, "0 -\u003e Normal Rx operation \n1 -\u003e Initialize Rx") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.ptt'): + + + self.assertEqual(self.dut.MSK_Control.ptt.rdl_desc, "0 -\u003e PTT Disabled\n1 -\u003e PTT Enabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.loopback_ena'): + + + self.assertEqual(self.dut.MSK_Control.loopback_ena.rdl_desc, "0 -\u003e Modem loopback disabled\n1 -\u003e Modem loopback enabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.rx_invert'): + + + self.assertEqual(self.dut.MSK_Control.rx_invert.rdl_desc, "0 -\u003e Rx data normal\n1 -\u003e Rx data inverted") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.clear_counts'): + + + self.assertEqual(self.dut.MSK_Control.clear_counts.rdl_desc, "Clear Tx Bit Counter and Tx Enable Counter") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Control.diff_encoder_loopback'): + + + self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.rdl_desc, "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.demod_sync_lock'): + + + self.assertEqual(self.dut.MSK_Status.demod_sync_lock.rdl_desc, "Demodulator Sync Status - not currently implemented") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_enable'): + + + self.assertEqual(self.dut.MSK_Status.tx_enable.rdl_desc, "1 -\u003e Data to DAC Enabled\n0 -\u003e Data to DAC Disabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.rx_enable'): + + + self.assertEqual(self.dut.MSK_Status.rx_enable.rdl_desc, "1 -\u003e Data from ADC Enabled\n0 -\u003e Data from ADC Disabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): + + + self.assertEqual(self.dut.MSK_Status.tx_axis_valid.rdl_desc, "1 -\u003e S_AXIS_VALID Enabled\n0 -\u003e S_AXIS_VALID Disabled") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + + + self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.rdl_desc, "Count of data requests made by modem") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + + + self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.rdl_desc, "Number of clocks on which Tx Enable is active") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): + + + self.assertEqual(self.dut.Fb_FreqWord.config_data.rdl_desc, "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord.config_data'): + + + self.assertEqual(self.dut.TX_F1_FreqWord.config_data.rdl_desc, "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord.config_data'): + + + self.assertEqual(self.dut.TX_F2_FreqWord.config_data.rdl_desc, "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord.config_data'): + + + self.assertEqual(self.dut.RX_F1_FreqWord.config_data.rdl_desc, "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord.config_data'): + + + self.assertEqual(self.dut.RX_F2_FreqWord.config_data.rdl_desc, "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, \nwhere Fn is the desired NCO frequency, and Fs is the NCO sample rate") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_freeze'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.rdl_desc, "0 -\u003e Normal operation\n1 -\u003e Freeze current value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_zero'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_zero.rdl_desc, "0 -\u003e Normal operation\n1 -\u003e Zero and hold accumulator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.prbs_reserved'): + + + self.assertIsNone(self.dut.LPF_Config_0.prbs_reserved.rdl_desc) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_alpha'): + + + self.assertEqual(self.dut.LPF_Config_0.lpf_alpha.rdl_desc, "Value controls the filter rolloff") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_gain'): + + + self.assertEqual(self.dut.LPF_Config_1.i_gain.rdl_desc, "Value m of 0-16,777,215 sets the integral multiplier") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_shift'): + + + self.assertEqual(self.dut.LPF_Config_1.i_shift.rdl_desc, "Value n of 0-32 sets the integral divisor as 2^-n") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width.data_width'): + + + self.assertEqual(self.dut.Tx_Data_Width.data_width.rdl_desc, "Set the data width of the modem input/output") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width.data_width'): + + + self.assertEqual(self.dut.Rx_Data_Width.data_width.rdl_desc, "Set the data width of the modem input/output") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sel'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_sel.rdl_desc, "0 -\u003e Select Normal Tx Data\n1 -\u003e Select PRBS Tx Data") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_error_insert'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.rdl_desc, "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_clear'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_clear.rdl_desc, "0 -\u003e 1 : Clear PRBS Counters\n1 -\u003e 0 : Clear PRBS Counters") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_manual_sync'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.rdl_desc, "0 -\u003e 1 : Synchronize PRBS monitor\n1 -\u003e 0 : Synchronize PRBS monitor") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_reserved'): + + + self.assertIsNone(self.dut.PRBS_Control.prbs_reserved.rdl_desc) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + + + self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.rdl_desc, "0 : Auto Sync Disabled\nN \u003e 0 : Auto sync after N errors") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State.config_data'): + + + self.assertEqual(self.dut.PRBS_Initial_State.config_data.rdl_desc, "Sets the starting value of the PRBS generator") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial.config_data'): + + + self.assertEqual(self.dut.PRBS_Polynomial.config_data.rdl_desc, "Bit positions set to \u00271\u0027 indicate polynomial feedback positions") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask.config_data'): + + + self.assertEqual(self.dut.PRBS_Error_Mask.config_data.rdl_desc, "Bit positions set to \u00271\u0027 indicate bits that are inverted when a bit error is inserted") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + + + self.assertEqual(self.dut.PRBS_Bit_Count.status_data.rdl_desc, "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + + + self.assertEqual(self.dut.PRBS_Error_Count.status_data.rdl_desc, "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + + + self.assertEqual(self.dut.LPF_Accum_F1.status_data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + + + self.assertEqual(self.dut.LPF_Accum_F2.status_data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + + + self.assertEqual(self.dut.axis_xfer_count.xfer_count.rdl_desc, "Number completed S_AXIS transfers") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.rdl_desc, "Number of Rx samples to discard") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + + + self.assertEqual(self.dut.Rx_Sample_Discard.rx_nco_discard.rdl_desc, "Number of NCO samples to discard") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_gain'): + + + self.assertEqual(self.dut.LPF_Config_2.p_gain.rdl_desc, "Value m of 0-16,777,215 sets the proportional multiplier") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_shift'): + + + self.assertEqual(self.dut.LPF_Config_2.p_shift.rdl_desc, "Value n of 0-32 sets the proportional divisor as 2^-n") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): + + + self.assertEqual(self.dut.f1_nco_adjust.data.rdl_desc, "Frequency offet applied to the F1 NCO") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): + + + self.assertEqual(self.dut.f2_nco_adjust.data.rdl_desc, "Frequency offet applied to the F2 NCO") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f1_error.data'): + + + self.assertEqual(self.dut.f1_error.data.rdl_desc, "Error value of the F1 Costas loop after each active bit period") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.f2_error.data'): + + + self.assertEqual(self.dut.f2_error.data.rdl_desc, "Error value of the F2 Costas loop after each active bit period") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.rdl_desc, "0 -\u003e Disable sync transmission\n1 -\u003e Enable sync transmission when PTT is asserted") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.rdl_desc, "0 : Normal operation)\n1 : Transmit synchronization pattern)") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.rdl_desc, "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n1 : F1 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.rdl_desc, "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n1 : F2 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + + + self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.rdl_desc, "Value from 0x00_0000 to 0xFF_FFFF. \nThis value represents the number bit-times the synchronization \nsignal should be sent after PTT is asserted.") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1.alpha'): + + + self.assertEqual(self.dut.lowpass_ema_alpha1.alpha.rdl_desc, "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2.alpha'): + + + self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.rdl_desc, "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + + + self.assertEqual(self.dut.rx_power.rx_power.rdl_desc, "Value that represent the RMS power of the incoming I;") # type: ignore[union-attr] + + + + + + def test_sizes(self) -> None: + """ + Check that the sizes all match + """ + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low'): + self.assertEqual(self.dut.Hash_ID_Low.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_High'): + self.assertEqual(self.dut.Hash_ID_High.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init'): + self.assertEqual(self.dut.MSK_Init.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control'): + self.assertEqual(self.dut.MSK_Control.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status'): + self.assertEqual(self.dut.MSK_Status.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count'): + self.assertEqual(self.dut.Tx_Bit_Count.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count'): + self.assertEqual(self.dut.Tx_Enable_Count.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord'): + self.assertEqual(self.dut.Fb_FreqWord.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord'): + self.assertEqual(self.dut.TX_F1_FreqWord.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord'): + self.assertEqual(self.dut.TX_F2_FreqWord.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord'): + self.assertEqual(self.dut.RX_F1_FreqWord.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord'): + self.assertEqual(self.dut.RX_F2_FreqWord.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0'): + self.assertEqual(self.dut.LPF_Config_0.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1'): + self.assertEqual(self.dut.LPF_Config_1.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width'): + self.assertEqual(self.dut.Tx_Data_Width.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width'): + self.assertEqual(self.dut.Rx_Data_Width.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control'): + self.assertEqual(self.dut.PRBS_Control.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State'): + self.assertEqual(self.dut.PRBS_Initial_State.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial'): + self.assertEqual(self.dut.PRBS_Polynomial.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask'): + self.assertEqual(self.dut.PRBS_Error_Mask.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count'): + self.assertEqual(self.dut.PRBS_Bit_Count.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count'): + self.assertEqual(self.dut.PRBS_Error_Count.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1'): + self.assertEqual(self.dut.LPF_Accum_F1.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2'): + self.assertEqual(self.dut.LPF_Accum_F2.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count'): + self.assertEqual(self.dut.axis_xfer_count.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard'): + self.assertEqual(self.dut.Rx_Sample_Discard.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2'): + self.assertEqual(self.dut.LPF_Config_2.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): + self.assertEqual(self.dut.f1_nco_adjust.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): + self.assertEqual(self.dut.f2_nco_adjust.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f1_error'): + self.assertEqual(self.dut.f1_error.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.f2_error'): + self.assertEqual(self.dut.f2_error.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt'): + self.assertEqual(self.dut.Tx_Sync_Cnt.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1'): + self.assertEqual(self.dut.lowpass_ema_alpha1.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2'): + self.assertEqual(self.dut.lowpass_ema_alpha2.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power'): + self.assertEqual(self.dut.rx_power.size, 4) # type: ignore[union-attr] + + + # check the size of the address map itself + + with self.subTest(msg='node: msk_top_regs'): + self.assertEqual(self.dut.size, 144) # type: ignore[union-attr] + + + + def test_register_properties(self) -> None: + """ + Walk the address map and check the address, size and accesswidth of every register is + correct + """ + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + self.assertEqual(self.dut.Hash_ID_Low.address, 0) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_Low.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_Low.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_Low.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + self.assertEqual(self.dut.Hash_ID_High.address, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_High.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_High.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Hash_ID_High.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + self.assertEqual(self.dut.MSK_Init.address, 8) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + self.assertEqual(self.dut.MSK_Control.address, 12) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + self.assertEqual(self.dut.MSK_Status.address, 16) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + self.assertEqual(self.dut.Tx_Bit_Count.address, 20) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + self.assertEqual(self.dut.Tx_Enable_Count.address, 24) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + self.assertEqual(self.dut.Fb_FreqWord.address, 28) # type: ignore[union-attr] + self.assertEqual(self.dut.Fb_FreqWord.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Fb_FreqWord.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Fb_FreqWord.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + self.assertEqual(self.dut.TX_F1_FreqWord.address, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F1_FreqWord.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F1_FreqWord.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F1_FreqWord.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + self.assertEqual(self.dut.TX_F2_FreqWord.address, 36) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F2_FreqWord.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F2_FreqWord.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.TX_F2_FreqWord.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + self.assertEqual(self.dut.RX_F1_FreqWord.address, 40) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F1_FreqWord.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F1_FreqWord.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F1_FreqWord.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + self.assertEqual(self.dut.RX_F2_FreqWord.address, 44) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F2_FreqWord.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F2_FreqWord.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.RX_F2_FreqWord.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + self.assertEqual(self.dut.LPF_Config_0.address, 48) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + self.assertEqual(self.dut.LPF_Config_1.address, 52) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_1.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + self.assertEqual(self.dut.Tx_Data_Width.address, 56) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Data_Width.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Data_Width.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Data_Width.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + self.assertEqual(self.dut.Rx_Data_Width.address, 60) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Data_Width.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Data_Width.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Data_Width.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + self.assertEqual(self.dut.PRBS_Control.address, 64) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + self.assertEqual(self.dut.PRBS_Initial_State.address, 68) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Initial_State.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Initial_State.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Initial_State.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + self.assertEqual(self.dut.PRBS_Polynomial.address, 72) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Polynomial.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Polynomial.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Polynomial.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + self.assertEqual(self.dut.PRBS_Error_Mask.address, 76) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Mask.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Mask.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Mask.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + self.assertEqual(self.dut.PRBS_Bit_Count.address, 80) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + self.assertEqual(self.dut.PRBS_Error_Count.address, 84) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + self.assertEqual(self.dut.LPF_Accum_F1.address, 88) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + self.assertEqual(self.dut.LPF_Accum_F2.address, 92) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + self.assertEqual(self.dut.axis_xfer_count.address, 96) # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + self.assertEqual(self.dut.Rx_Sample_Discard.address, 100) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Rx_Sample_Discard.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + self.assertEqual(self.dut.LPF_Config_2.address, 104) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_2.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + self.assertEqual(self.dut.f1_nco_adjust.address, 108) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + self.assertEqual(self.dut.f2_nco_adjust.address, 112) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.f1_error'): + self.assertEqual(self.dut.f1_error.address, 116) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.f2_error'): + self.assertEqual(self.dut.f2_error.address, 120) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + self.assertEqual(self.dut.Tx_Sync_Ctrl.address, 124) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + self.assertEqual(self.dut.Tx_Sync_Cnt.address, 128) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + self.assertEqual(self.dut.lowpass_ema_alpha1.address, 132) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha1.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha1.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha1.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + self.assertEqual(self.dut.lowpass_ema_alpha2.address, 136) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha2.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha2.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.lowpass_ema_alpha2.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.rx_power'): + self.assertEqual(self.dut.rx_power.address, 140) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.accesswidth, 32) # type: ignore[union-attr] + + + def test_memory_properties(self) -> None: + """ + Walk the address map and check the address, size and accesswidth of every memory is + correct + """ + mut: AsyncMemory + + + def test_field_properties(self) -> None: + """ + walk the address map and check: + - that the lsb and msb of every field is correct + - that where default values are provided they are applied correctly + """ + fut:Field + with self.subTest(msg='field: msk_top_regs.Hash_ID_Low.hash_id_lo'): + # test properties of field: msk_top_regs.Hash_ID_Low.hash_id_lo + fut = self.dut.Hash_ID_Low.hash_id_lo # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,2863289685) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Hash_ID_High.hash_id_hi'): + # test properties of field: msk_top_regs.Hash_ID_High.hash_id_hi + fut = self.dut.Hash_ID_High.hash_id_hi # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,1431677610) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Init.txrxinit'): + # test properties of field: msk_top_regs.MSK_Init.txrxinit + fut = self.dut.MSK_Init.txrxinit # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,1) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Init.txinit'): + # test properties of field: msk_top_regs.MSK_Init.txinit + fut = self.dut.MSK_Init.txinit # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,1) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Init.rxinit'): + # test properties of field: msk_top_regs.MSK_Init.rxinit + fut = self.dut.MSK_Init.rxinit # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,2) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,2) + self.assertEqual(fut.bitmask,0x4) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFB) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,1) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Control.ptt'): + # test properties of field: msk_top_regs.MSK_Control.ptt + fut = self.dut.MSK_Control.ptt # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Control.loopback_ena'): + # test properties of field: msk_top_regs.MSK_Control.loopback_ena + fut = self.dut.MSK_Control.loopback_ena # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Control.rx_invert'): + # test properties of field: msk_top_regs.MSK_Control.rx_invert + fut = self.dut.MSK_Control.rx_invert # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,2) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,2) + self.assertEqual(fut.bitmask,0x4) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFB) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Control.clear_counts'): + # test properties of field: msk_top_regs.MSK_Control.clear_counts + fut = self.dut.MSK_Control.clear_counts # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,3) + self.assertEqual(fut.msb,3) + self.assertEqual(fut.low,3) + self.assertEqual(fut.high,3) + self.assertEqual(fut.bitmask,0x8) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFF7) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Control.diff_encoder_loopback'): + # test properties of field: msk_top_regs.MSK_Control.diff_encoder_loopback + fut = self.dut.MSK_Control.diff_encoder_loopback # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,4) + self.assertEqual(fut.msb,4) + self.assertEqual(fut.low,4) + self.assertEqual(fut.high,4) + self.assertEqual(fut.bitmask,0x10) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFEF) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.MSK_Status.demod_sync_lock'): + # test properties of field: msk_top_regs.MSK_Status.demod_sync_lock + fut = self.dut.MSK_Status.demod_sync_lock # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_enable'): + # test properties of field: msk_top_regs.MSK_Status.tx_enable + fut = self.dut.MSK_Status.tx_enable # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.MSK_Status.rx_enable'): + # test properties of field: msk_top_regs.MSK_Status.rx_enable + fut = self.dut.MSK_Status.rx_enable # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,2) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,2) + self.assertEqual(fut.bitmask,0x4) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFB) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_axis_valid'): + # test properties of field: msk_top_regs.MSK_Status.tx_axis_valid + fut = self.dut.MSK_Status.tx_axis_valid # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,3) + self.assertEqual(fut.msb,3) + self.assertEqual(fut.low,3) + self.assertEqual(fut.high,3) + self.assertEqual(fut.bitmask,0x8) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFF7) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + # test properties of field: msk_top_regs.Tx_Bit_Count.tx_bit_counter + fut = self.dut.Tx_Bit_Count.tx_bit_counter # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,None) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + # test properties of field: msk_top_regs.Tx_Enable_Count.tx_ena_counter + fut = self.dut.Tx_Enable_Count.tx_ena_counter # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.Fb_FreqWord.config_data'): + # test properties of field: msk_top_regs.Fb_FreqWord.config_data + fut = self.dut.Fb_FreqWord.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.TX_F1_FreqWord.config_data'): + # test properties of field: msk_top_regs.TX_F1_FreqWord.config_data + fut = self.dut.TX_F1_FreqWord.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.TX_F2_FreqWord.config_data'): + # test properties of field: msk_top_regs.TX_F2_FreqWord.config_data + fut = self.dut.TX_F2_FreqWord.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.RX_F1_FreqWord.config_data'): + # test properties of field: msk_top_regs.RX_F1_FreqWord.config_data + fut = self.dut.RX_F1_FreqWord.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.RX_F2_FreqWord.config_data'): + # test properties of field: msk_top_regs.RX_F2_FreqWord.config_data + fut = self.dut.RX_F2_FreqWord.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_freeze'): + # test properties of field: msk_top_regs.LPF_Config_0.lpf_freeze + fut = self.dut.LPF_Config_0.lpf_freeze # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_zero'): + # test properties of field: msk_top_regs.LPF_Config_0.lpf_zero + fut = self.dut.LPF_Config_0.lpf_zero # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.prbs_reserved'): + # test properties of field: msk_top_regs.LPF_Config_0.prbs_reserved + fut = self.dut.LPF_Config_0.prbs_reserved # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,7) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,7) + self.assertEqual(fut.bitmask,0xFC) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF03) + self.assertEqual(fut.max_value,0x3F) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_alpha'): + # test properties of field: msk_top_regs.LPF_Config_0.lpf_alpha + fut = self.dut.LPF_Config_0.lpf_alpha # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,8) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,8) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFF00) + self.assertEqual(fut.inverse_bitmask,0xFF) + self.assertEqual(fut.max_value,0xFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_gain'): + # test properties of field: msk_top_regs.LPF_Config_1.i_gain + fut = self.dut.LPF_Config_1.i_gain # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,23) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,23) + self.assertEqual(fut.bitmask,0xFFFFFF) + self.assertEqual(fut.inverse_bitmask,0xFF000000) + self.assertEqual(fut.max_value,0xFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_shift'): + # test properties of field: msk_top_regs.LPF_Config_1.i_shift + fut = self.dut.LPF_Config_1.i_shift # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,24) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,24) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFF000000) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Tx_Data_Width.data_width'): + # test properties of field: msk_top_regs.Tx_Data_Width.data_width + fut = self.dut.Tx_Data_Width.data_width # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,7) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,7) + self.assertEqual(fut.bitmask,0xFF) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF00) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,8) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Rx_Data_Width.data_width'): + # test properties of field: msk_top_regs.Rx_Data_Width.data_width + fut = self.dut.Rx_Data_Width.data_width # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,7) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,7) + self.assertEqual(fut.bitmask,0xFF) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF00) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,8) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sel'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_sel + fut = self.dut.PRBS_Control.prbs_sel # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_error_insert'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_error_insert + fut = self.dut.PRBS_Control.prbs_error_insert # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_clear'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_clear + fut = self.dut.PRBS_Control.prbs_clear # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,2) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,2) + self.assertEqual(fut.bitmask,0x4) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFB) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_manual_sync'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_manual_sync + fut = self.dut.PRBS_Control.prbs_manual_sync # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,3) + self.assertEqual(fut.msb,3) + self.assertEqual(fut.low,3) + self.assertEqual(fut.high,3) + self.assertEqual(fut.bitmask,0x8) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFF7) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_reserved'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_reserved + fut = self.dut.PRBS_Control.prbs_reserved # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,4) + self.assertEqual(fut.msb,15) + self.assertEqual(fut.low,4) + self.assertEqual(fut.high,15) + self.assertEqual(fut.bitmask,0xFFF0) + self.assertEqual(fut.inverse_bitmask,0xFFFF000F) + self.assertEqual(fut.max_value,0xFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + # test properties of field: msk_top_regs.PRBS_Control.prbs_sync_threshold + fut = self.dut.PRBS_Control.prbs_sync_threshold # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,16) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,16) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFF0000) + self.assertEqual(fut.inverse_bitmask,0xFFFF) + self.assertEqual(fut.max_value,0xFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Initial_State.config_data'): + # test properties of field: msk_top_regs.PRBS_Initial_State.config_data + fut = self.dut.PRBS_Initial_State.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Polynomial.config_data'): + # test properties of field: msk_top_regs.PRBS_Polynomial.config_data + fut = self.dut.PRBS_Polynomial.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Mask.config_data'): + # test properties of field: msk_top_regs.PRBS_Error_Mask.config_data + fut = self.dut.PRBS_Error_Mask.config_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): + # test properties of field: msk_top_regs.PRBS_Bit_Count.status_data + fut = self.dut.PRBS_Bit_Count.status_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): + # test properties of field: msk_top_regs.PRBS_Error_Count.status_data + fut = self.dut.PRBS_Error_Count.status_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): + # test properties of field: msk_top_regs.LPF_Accum_F1.status_data + fut = self.dut.LPF_Accum_F1.status_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): + # test properties of field: msk_top_regs.LPF_Accum_F2.status_data + fut = self.dut.LPF_Accum_F2.status_data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): + # test properties of field: msk_top_regs.axis_xfer_count.xfer_count + fut = self.dut.axis_xfer_count.xfer_count # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + # test properties of field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard + fut = self.dut.Rx_Sample_Discard.rx_sample_discard # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,7) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,7) + self.assertEqual(fut.bitmask,0xFF) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF00) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + # test properties of field: msk_top_regs.Rx_Sample_Discard.rx_nco_discard + fut = self.dut.Rx_Sample_Discard.rx_nco_discard # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,8) + self.assertEqual(fut.msb,15) + self.assertEqual(fut.low,8) + self.assertEqual(fut.high,15) + self.assertEqual(fut.bitmask,0xFF00) + self.assertEqual(fut.inverse_bitmask,0xFFFF00FF) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_gain'): + # test properties of field: msk_top_regs.LPF_Config_2.p_gain + fut = self.dut.LPF_Config_2.p_gain # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,23) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,23) + self.assertEqual(fut.bitmask,0xFFFFFF) + self.assertEqual(fut.inverse_bitmask,0xFF000000) + self.assertEqual(fut.max_value,0xFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_shift'): + # test properties of field: msk_top_regs.LPF_Config_2.p_shift + fut = self.dut.LPF_Config_2.p_shift # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,24) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,24) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFF000000) + self.assertEqual(fut.inverse_bitmask,0xFFFFFF) + self.assertEqual(fut.max_value,0xFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.f1_nco_adjust.data'): + # test properties of field: msk_top_regs.f1_nco_adjust.data + fut = self.dut.f1_nco_adjust.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.f2_nco_adjust.data'): + # test properties of field: msk_top_regs.f2_nco_adjust.data + fut = self.dut.f2_nco_adjust.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.f1_error.data'): + # test properties of field: msk_top_regs.f1_error.data + fut = self.dut.f1_error.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.f2_error.data'): + # test properties of field: msk_top_regs.f2_error.data + fut = self.dut.f2_error.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + # test properties of field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena + fut = self.dut.Tx_Sync_Ctrl.tx_sync_ena # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + # test properties of field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force + fut = self.dut.Tx_Sync_Ctrl.tx_sync_force # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + # test properties of field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1 + fut = self.dut.Tx_Sync_Ctrl.tx_sync_f1 # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,2) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,2) + self.assertEqual(fut.bitmask,0x4) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFB) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + # test properties of field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2 + fut = self.dut.Tx_Sync_Ctrl.tx_sync_f2 # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,3) + self.assertEqual(fut.msb,3) + self.assertEqual(fut.low,3) + self.assertEqual(fut.high,3) + self.assertEqual(fut.bitmask,0x8) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFF7) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + # test properties of field: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt + fut = self.dut.Tx_Sync_Cnt.tx_sync_cnt # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,23) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,23) + self.assertEqual(fut.bitmask,0xFFFFFF) + self.assertEqual(fut.inverse_bitmask,0xFF000000) + self.assertEqual(fut.max_value,0xFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha1.alpha'): + # test properties of field: msk_top_regs.lowpass_ema_alpha1.alpha + fut = self.dut.lowpass_ema_alpha1.alpha # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,17) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,17) + self.assertEqual(fut.bitmask,0x3FFFF) + self.assertEqual(fut.inverse_bitmask,0xFFFC0000) + self.assertEqual(fut.max_value,0x3FFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha2.alpha'): + # test properties of field: msk_top_regs.lowpass_ema_alpha2.alpha + fut = self.dut.lowpass_ema_alpha2.alpha # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,17) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,17) + self.assertEqual(fut.bitmask,0x3FFFF) + self.assertEqual(fut.inverse_bitmask,0xFFFC0000) + self.assertEqual(fut.max_value,0x3FFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,False) + with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): + # test properties of field: msk_top_regs.rx_power.rx_power + fut = self.dut.rx_power.rx_power # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,22) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,22) + self.assertEqual(fut.bitmask,0x7FFFFF) + self.assertEqual(fut.inverse_bitmask,0xFF800000) + self.assertEqual(fut.max_value,0x7FFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + + + def test_field_encoding_properties(self) -> None: + """ + Check that enumeration has the name and desc meta data from the systemRDL + """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + def test_user_defined_properties(self) -> None: + """ + Walk the address map and check user defined properties are correctly pulled up + """ + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + + self.assertDictEqual(self.dut.Hash_ID_Low.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + + self.assertDictEqual(self.dut.Hash_ID_High.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + + self.assertDictEqual(self.dut.MSK_Init.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + + self.assertDictEqual(self.dut.MSK_Control.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + + self.assertDictEqual(self.dut.MSK_Status.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + + self.assertDictEqual(self.dut.Tx_Bit_Count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + + self.assertDictEqual(self.dut.Tx_Enable_Count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + + self.assertDictEqual(self.dut.Fb_FreqWord.udp,{}) + + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + + self.assertDictEqual(self.dut.TX_F1_FreqWord.udp,{}) + + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + + self.assertDictEqual(self.dut.TX_F2_FreqWord.udp,{}) + + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + + self.assertDictEqual(self.dut.RX_F1_FreqWord.udp,{}) + + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + + self.assertDictEqual(self.dut.RX_F2_FreqWord.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + + self.assertDictEqual(self.dut.LPF_Config_0.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + + self.assertDictEqual(self.dut.LPF_Config_1.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + + self.assertDictEqual(self.dut.Tx_Data_Width.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + + self.assertDictEqual(self.dut.Rx_Data_Width.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + + self.assertDictEqual(self.dut.PRBS_Control.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + + self.assertDictEqual(self.dut.PRBS_Initial_State.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + + self.assertDictEqual(self.dut.PRBS_Polynomial.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + + self.assertDictEqual(self.dut.PRBS_Error_Mask.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + + self.assertDictEqual(self.dut.PRBS_Bit_Count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + + self.assertDictEqual(self.dut.PRBS_Error_Count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + + self.assertDictEqual(self.dut.LPF_Accum_F1.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + + self.assertDictEqual(self.dut.LPF_Accum_F2.udp,{}) + + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + + self.assertDictEqual(self.dut.axis_xfer_count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + + self.assertDictEqual(self.dut.Rx_Sample_Discard.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + + self.assertDictEqual(self.dut.LPF_Config_2.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + + self.assertDictEqual(self.dut.f1_nco_adjust.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + + self.assertDictEqual(self.dut.f2_nco_adjust.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f1_error'): + + self.assertDictEqual(self.dut.f1_error.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f2_error'): + + self.assertDictEqual(self.dut.f2_error.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + + self.assertDictEqual(self.dut.Tx_Sync_Ctrl.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + + self.assertDictEqual(self.dut.Tx_Sync_Cnt.udp,{}) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + + self.assertDictEqual(self.dut.lowpass_ema_alpha1.udp,{}) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + + self.assertDictEqual(self.dut.lowpass_ema_alpha2.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_power'): + + self.assertDictEqual(self.dut.rx_power.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low.hash_id_lo'): + + self.assertDictEqual(self.dut.Hash_ID_Low.hash_id_lo.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Hash_ID_High.hash_id_hi'): + + self.assertDictEqual(self.dut.Hash_ID_High.hash_id_hi.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Init.txrxinit'): + + self.assertDictEqual(self.dut.MSK_Init.txrxinit.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Init.txinit'): + + self.assertDictEqual(self.dut.MSK_Init.txinit.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Init.rxinit'): + + self.assertDictEqual(self.dut.MSK_Init.rxinit.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control.ptt'): + + self.assertDictEqual(self.dut.MSK_Control.ptt.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control.loopback_ena'): + + self.assertDictEqual(self.dut.MSK_Control.loopback_ena.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control.rx_invert'): + + self.assertDictEqual(self.dut.MSK_Control.rx_invert.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control.clear_counts'): + + self.assertDictEqual(self.dut.MSK_Control.clear_counts.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Control.diff_encoder_loopback'): + + self.assertDictEqual(self.dut.MSK_Control.diff_encoder_loopback.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Status.demod_sync_lock'): + + self.assertDictEqual(self.dut.MSK_Status.demod_sync_lock.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Status.tx_enable'): + + self.assertDictEqual(self.dut.MSK_Status.tx_enable.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Status.rx_enable'): + + self.assertDictEqual(self.dut.MSK_Status.rx_enable.udp,{}) + + with self.subTest(msg='register: msk_top_regs.MSK_Status.tx_axis_valid'): + + self.assertDictEqual(self.dut.MSK_Status.tx_axis_valid.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + + self.assertDictEqual(self.dut.Tx_Bit_Count.tx_bit_counter.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + + self.assertDictEqual(self.dut.Tx_Enable_Count.tx_ena_counter.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord.config_data'): + + self.assertDictEqual(self.dut.Fb_FreqWord.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord.config_data'): + + self.assertDictEqual(self.dut.TX_F1_FreqWord.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord.config_data'): + + self.assertDictEqual(self.dut.TX_F2_FreqWord.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord.config_data'): + + self.assertDictEqual(self.dut.RX_F1_FreqWord.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord.config_data'): + + self.assertDictEqual(self.dut.RX_F2_FreqWord.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0.lpf_freeze'): + + self.assertDictEqual(self.dut.LPF_Config_0.lpf_freeze.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0.lpf_zero'): + + self.assertDictEqual(self.dut.LPF_Config_0.lpf_zero.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0.prbs_reserved'): + + self.assertDictEqual(self.dut.LPF_Config_0.prbs_reserved.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0.lpf_alpha'): + + self.assertDictEqual(self.dut.LPF_Config_0.lpf_alpha.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_1.i_gain'): + + self.assertDictEqual(self.dut.LPF_Config_1.i_gain.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_1.i_shift'): + + self.assertDictEqual(self.dut.LPF_Config_1.i_shift.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width.data_width'): + + self.assertDictEqual(self.dut.Tx_Data_Width.data_width.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width.data_width'): + + self.assertDictEqual(self.dut.Rx_Data_Width.data_width.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_sel'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_sel.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_error_insert'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_error_insert.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_clear'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_clear.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_manual_sync'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_manual_sync.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_reserved'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_reserved.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + + self.assertDictEqual(self.dut.PRBS_Control.prbs_sync_threshold.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State.config_data'): + + self.assertDictEqual(self.dut.PRBS_Initial_State.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial.config_data'): + + self.assertDictEqual(self.dut.PRBS_Polynomial.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask.config_data'): + + self.assertDictEqual(self.dut.PRBS_Error_Mask.config_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count.status_data'): + + self.assertDictEqual(self.dut.PRBS_Bit_Count.status_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count.status_data'): + + self.assertDictEqual(self.dut.PRBS_Error_Count.status_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1.status_data'): + + self.assertDictEqual(self.dut.LPF_Accum_F1.status_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2.status_data'): + + self.assertDictEqual(self.dut.LPF_Accum_F2.status_data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.axis_xfer_count.xfer_count'): + + self.assertDictEqual(self.dut.axis_xfer_count.xfer_count.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + + self.assertDictEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + + self.assertDictEqual(self.dut.Rx_Sample_Discard.rx_nco_discard.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_2.p_gain'): + + self.assertDictEqual(self.dut.LPF_Config_2.p_gain.udp,{}) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_2.p_shift'): + + self.assertDictEqual(self.dut.LPF_Config_2.p_shift.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust.data'): + + self.assertDictEqual(self.dut.f1_nco_adjust.data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust.data'): + + self.assertDictEqual(self.dut.f2_nco_adjust.data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f1_error.data'): + + self.assertDictEqual(self.dut.f1_error.data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.f2_error.data'): + + self.assertDictEqual(self.dut.f2_error.data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + + self.assertDictEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + + self.assertDictEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + + self.assertDictEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + + self.assertDictEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.udp,{}) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + + self.assertDictEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.udp,{}) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1.alpha'): + + self.assertDictEqual(self.dut.lowpass_ema_alpha1.alpha.udp,{}) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2.alpha'): + + self.assertDictEqual(self.dut.lowpass_ema_alpha2.alpha.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_power.rx_power'): + + self.assertDictEqual(self.dut.rx_power.rx_power.udp,{}) + + + + async def test_register_read_and_write(self) -> None: + """ + Walk the register map and check every register can be read and written to correctly + """ + rut: Reg + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_Low + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + rut=self.dut.Hash_ID_Low # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_High + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + rut=self.dut.Hash_ID_High # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Init + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + rut=self.dut.MSK_Init # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + rut=self.dut.MSK_Control # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + rut=self.dut.MSK_Status # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Bit_Count + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + rut=self.dut.Tx_Bit_Count # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Enable_Count + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + rut=self.dut.Tx_Enable_Count # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Fb_FreqWord + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + rut=self.dut.Fb_FreqWord # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F1_FreqWord + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + rut=self.dut.TX_F1_FreqWord # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F2_FreqWord + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + rut=self.dut.TX_F2_FreqWord # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F1_FreqWord + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + rut=self.dut.RX_F1_FreqWord # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F2_FreqWord + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + rut=self.dut.RX_F2_FreqWord # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0 + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + rut=self.dut.LPF_Config_0 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_1 + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + rut=self.dut.LPF_Config_1 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Data_Width + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + rut=self.dut.Tx_Data_Width # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Data_Width + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + rut=self.dut.Rx_Data_Width # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + rut=self.dut.PRBS_Control # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Initial_State + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + rut=self.dut.PRBS_Initial_State # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Polynomial + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + rut=self.dut.PRBS_Polynomial # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Mask + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + rut=self.dut.PRBS_Error_Mask # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Bit_Count + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + rut=self.dut.PRBS_Bit_Count # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Count + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + rut=self.dut.PRBS_Error_Count # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F1 + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + rut=self.dut.LPF_Accum_F1 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F2 + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + rut=self.dut.LPF_Accum_F2 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.axis_xfer_count + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + rut=self.dut.axis_xfer_count # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + rut=self.dut.Rx_Sample_Discard # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_2 + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + rut=self.dut.LPF_Config_2 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.f1_nco_adjust + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + rut=self.dut.f1_nco_adjust # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.f2_nco_adjust + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + rut=self.dut.f2_nco_adjust # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.f1_error + with self.subTest(msg='register: msk_top_regs.f1_error'): + rut=self.dut.f1_error # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.f2_error + with self.subTest(msg='register: msk_top_regs.f2_error'): + rut=self.dut.f2_error # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + rut=self.dut.Tx_Sync_Ctrl # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Cnt + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + rut=self.dut.Tx_Sync_Cnt # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha1 + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + rut=self.dut.lowpass_ema_alpha1 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha2 + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + rut=self.dut.lowpass_ema_alpha2 # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.rx_power + with self.subTest(msg='register: msk_top_regs.rx_power'): + rut=self.dut.rx_power # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + + + async def test_int_field_read_and_write(self) -> None: + """ + Check the ability to read and write to integer (non-eumn) fields + """ + fut:Field + + + # test access operations (read and/or write) to field: + # msk_top_regs.Hash_ID_Low.hash_id_lo + with self.subTest(msg='field: msk_top_regs.Hash_ID_Low.hash_id_lo'): + fut = self.dut.Hash_ID_Low.hash_id_lo # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=0, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Hash_ID_High.hash_id_hi + with self.subTest(msg='field: msk_top_regs.Hash_ID_High.hash_id_hi'): + fut = self.dut.Hash_ID_High.hash_id_hi # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=4, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Init.txrxinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.txrxinit'): + fut = self.dut.MSK_Init.txrxinit # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Init.txrxinit.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=self.dut.MSK_Init.txrxinit.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Init.txinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.txinit'): + fut = self.dut.MSK_Init.txinit # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Init.txinit.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=self.dut.MSK_Init.txinit.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Init.rxinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.rxinit'): + fut = self.dut.MSK_Init.rxinit # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFB + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x4 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x4) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Init.rxinit.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=8, + width=32, + accesswidth=self.dut.MSK_Init.rxinit.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFB) | \ + (0x4 & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Control.ptt + with self.subTest(msg='field: msk_top_regs.MSK_Control.ptt'): + fut = self.dut.MSK_Control.ptt # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Control.ptt.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=self.dut.MSK_Control.ptt.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Control.loopback_ena + with self.subTest(msg='field: msk_top_regs.MSK_Control.loopback_ena'): + fut = self.dut.MSK_Control.loopback_ena # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Control.loopback_ena.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=self.dut.MSK_Control.loopback_ena.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Control.rx_invert + with self.subTest(msg='field: msk_top_regs.MSK_Control.rx_invert'): + fut = self.dut.MSK_Control.rx_invert # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFB + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x4 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x4) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Control.rx_invert.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=self.dut.MSK_Control.rx_invert.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFB) | \ + (0x4 & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Control.clear_counts + with self.subTest(msg='field: msk_top_regs.MSK_Control.clear_counts'): + fut = self.dut.MSK_Control.clear_counts # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFF7 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x8 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x8) >> 3 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Control.clear_counts.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=self.dut.MSK_Control.clear_counts.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFF7) | \ + (0x8 & (field_value << 3))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Control.diff_encoder_loopback + with self.subTest(msg='field: msk_top_regs.MSK_Control.diff_encoder_loopback'): + fut = self.dut.MSK_Control.diff_encoder_loopback # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFEF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x10 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x10) >> 4 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.MSK_Control.diff_encoder_loopback.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=12, + width=32, + accesswidth=self.dut.MSK_Control.diff_encoder_loopback.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFEF) | \ + (0x10 & (field_value << 4))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Status.demod_sync_lock + with self.subTest(msg='field: msk_top_regs.MSK_Status.demod_sync_lock'): + fut = self.dut.MSK_Status.demod_sync_lock # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Status.tx_enable + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_enable'): + fut = self.dut.MSK_Status.tx_enable # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Status.rx_enable + with self.subTest(msg='field: msk_top_regs.MSK_Status.rx_enable'): + fut = self.dut.MSK_Status.rx_enable # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFB + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x4 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x4) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.MSK_Status.tx_axis_valid + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_axis_valid'): + fut = self.dut.MSK_Status.tx_axis_valid # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFF7 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x8 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x8) >> 3 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=16, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Bit_Count.tx_bit_counter + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + fut = self.dut.Tx_Bit_Count.tx_bit_counter # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Enable_Count.tx_ena_counter + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + fut = self.dut.Tx_Enable_Count.tx_ena_counter # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Fb_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.Fb_FreqWord.config_data'): + fut = self.dut.Fb_FreqWord.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Fb_FreqWord.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=28, + width=32, + accesswidth=self.dut.Fb_FreqWord.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.TX_F1_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.TX_F1_FreqWord.config_data'): + fut = self.dut.TX_F1_FreqWord.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.TX_F1_FreqWord.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=32, + width=32, + accesswidth=self.dut.TX_F1_FreqWord.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.TX_F2_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.TX_F2_FreqWord.config_data'): + fut = self.dut.TX_F2_FreqWord.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.TX_F2_FreqWord.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=36, + width=32, + accesswidth=self.dut.TX_F2_FreqWord.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.RX_F1_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.RX_F1_FreqWord.config_data'): + fut = self.dut.RX_F1_FreqWord.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.RX_F1_FreqWord.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=40, + width=32, + accesswidth=self.dut.RX_F1_FreqWord.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.RX_F2_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.RX_F2_FreqWord.config_data'): + fut = self.dut.RX_F2_FreqWord.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.RX_F2_FreqWord.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=44, + width=32, + accesswidth=self.dut.RX_F2_FreqWord.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_0.lpf_freeze + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_freeze'): + fut = self.dut.LPF_Config_0.lpf_freeze # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_0.lpf_freeze.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=self.dut.LPF_Config_0.lpf_freeze.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_0.lpf_zero + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_zero'): + fut = self.dut.LPF_Config_0.lpf_zero # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_0.lpf_zero.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=self.dut.LPF_Config_0.lpf_zero.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_0.prbs_reserved + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.prbs_reserved'): + fut = self.dut.LPF_Config_0.prbs_reserved # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF03 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFC + self.assertEqual(await fut.read(), + 0x3F) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFC) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x3F + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x3F, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_0.prbs_reserved.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=self.dut.LPF_Config_0.prbs_reserved.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF03) | \ + (0xFC & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x3F + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_0.lpf_alpha + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_alpha'): + fut = self.dut.LPF_Config_0.lpf_alpha # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFF00 + self.assertEqual(await fut.read(), + 0xFFFFFF) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFF00) >> 8 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_0.lpf_alpha.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=48, + width=32, + accesswidth=self.dut.LPF_Config_0.lpf_alpha.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFF) | \ + (0xFFFFFF00 & (field_value << 8))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_1.i_gain + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_gain'): + fut = self.dut.LPF_Config_1.i_gain # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFF000000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFF) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_1.i_gain.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=self.dut.LPF_Config_1.i_gain.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFF000000) | \ + (0xFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_1.i_shift + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_shift'): + fut = self.dut.LPF_Config_1.i_shift # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF000000 + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF000000) >> 24 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_1.i_shift.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=52, + width=32, + accesswidth=self.dut.LPF_Config_1.i_shift.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF) | \ + (0xFF000000 & (field_value << 24))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Data_Width.data_width + with self.subTest(msg='field: msk_top_regs.Tx_Data_Width.data_width'): + fut = self.dut.Tx_Data_Width.data_width # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF00 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Data_Width.data_width.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=56, + width=32, + accesswidth=self.dut.Tx_Data_Width.data_width.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF00) | \ + (0xFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Rx_Data_Width.data_width + with self.subTest(msg='field: msk_top_regs.Rx_Data_Width.data_width'): + fut = self.dut.Rx_Data_Width.data_width # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF00 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Rx_Data_Width.data_width.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=60, + width=32, + accesswidth=self.dut.Rx_Data_Width.data_width.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF00) | \ + (0xFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_sel + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sel'): + fut = self.dut.PRBS_Control.prbs_sel # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_sel.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_sel.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_error_insert + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_error_insert'): + fut = self.dut.PRBS_Control.prbs_error_insert # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_error_insert.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_error_insert.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_clear + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_clear'): + fut = self.dut.PRBS_Control.prbs_clear # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_clear.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_clear.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFB) | \ + (0x4 & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_manual_sync + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_manual_sync'): + fut = self.dut.PRBS_Control.prbs_manual_sync # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_manual_sync.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_manual_sync.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFF7) | \ + (0x8 & (field_value << 3))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_reserved + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_reserved'): + fut = self.dut.PRBS_Control.prbs_reserved # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFF000F + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFF0 + self.assertEqual(await fut.read(), + 0xFFF) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFF0) >> 4 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_reserved.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_reserved.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFF000F) | \ + (0xFFF0 & (field_value << 4))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Control.prbs_sync_threshold + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + fut = self.dut.PRBS_Control.prbs_sync_threshold # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFF0000 + self.assertEqual(await fut.read(), + 0xFFFF) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFF0000) >> 16 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Control.prbs_sync_threshold.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=64, + width=32, + accesswidth=self.dut.PRBS_Control.prbs_sync_threshold.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFF) | \ + (0xFFFF0000 & (field_value << 16))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Initial_State.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Initial_State.config_data'): + fut = self.dut.PRBS_Initial_State.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Initial_State.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=68, + width=32, + accesswidth=self.dut.PRBS_Initial_State.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Polynomial.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Polynomial.config_data'): + fut = self.dut.PRBS_Polynomial.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Polynomial.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=72, + width=32, + accesswidth=self.dut.PRBS_Polynomial.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Error_Mask.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Mask.config_data'): + fut = self.dut.PRBS_Error_Mask.config_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Error_Mask.config_data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=76, + width=32, + accesswidth=self.dut.PRBS_Error_Mask.config_data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Bit_Count.status_data + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): + fut = self.dut.PRBS_Bit_Count.status_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.PRBS_Error_Count.status_data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): + fut = self.dut.PRBS_Error_Count.status_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Accum_F1.status_data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): + fut = self.dut.LPF_Accum_F1.status_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Accum_F2.status_data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): + fut = self.dut.LPF_Accum_F2.status_data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.axis_xfer_count.xfer_count + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): + fut = self.dut.axis_xfer_count.xfer_count # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Rx_Sample_Discard.rx_sample_discard + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + fut = self.dut.Rx_Sample_Discard.rx_sample_discard # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF00 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Rx_Sample_Discard.rx_sample_discard.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=self.dut.Rx_Sample_Discard.rx_sample_discard.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF00) | \ + (0xFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Rx_Sample_Discard.rx_nco_discard + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + fut = self.dut.Rx_Sample_Discard.rx_nco_discard # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFF00FF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF00 + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF00) >> 8 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Rx_Sample_Discard.rx_nco_discard.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=100, + width=32, + accesswidth=self.dut.Rx_Sample_Discard.rx_nco_discard.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFF00FF) | \ + (0xFF00 & (field_value << 8))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_2.p_gain + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_gain'): + fut = self.dut.LPF_Config_2.p_gain # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFF000000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFF) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_2.p_gain.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=self.dut.LPF_Config_2.p_gain.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFF000000) | \ + (0xFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.LPF_Config_2.p_shift + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_shift'): + fut = self.dut.LPF_Config_2.p_shift # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFF000000 + self.assertEqual(await fut.read(), + 0xFF) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFF000000) >> 24 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Config_2.p_shift.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=104, + width=32, + accesswidth=self.dut.LPF_Config_2.p_shift.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFF) | \ + (0xFF000000 & (field_value << 24))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.f1_nco_adjust.data + with self.subTest(msg='field: msk_top_regs.f1_nco_adjust.data'): + fut = self.dut.f1_nco_adjust.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.f2_nco_adjust.data + with self.subTest(msg='field: msk_top_regs.f2_nco_adjust.data'): + fut = self.dut.f2_nco_adjust.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.f1_error.data + with self.subTest(msg='field: msk_top_regs.f1_error.data'): + fut = self.dut.f1_error.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.f2_error.data + with self.subTest(msg='field: msk_top_regs.f2_error.data'): + fut = self.dut.f2_error.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + fut = self.dut.Tx_Sync_Ctrl.tx_sync_ena # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Sync_Ctrl.tx_sync_ena.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=self.dut.Tx_Sync_Ctrl.tx_sync_ena.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_force + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + fut = self.dut.Tx_Sync_Ctrl.tx_sync_force # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Sync_Ctrl.tx_sync_force.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=self.dut.Tx_Sync_Ctrl.tx_sync_force.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1 + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + fut = self.dut.Tx_Sync_Ctrl.tx_sync_f1 # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFB + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x4 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x4) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Sync_Ctrl.tx_sync_f1.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=self.dut.Tx_Sync_Ctrl.tx_sync_f1.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFB) | \ + (0x4 & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2 + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + fut = self.dut.Tx_Sync_Ctrl.tx_sync_f2 # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFF7 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x8 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x8) >> 3 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Sync_Ctrl.tx_sync_f2.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=124, + width=32, + accesswidth=self.dut.Tx_Sync_Ctrl.tx_sync_f2.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFF7) | \ + (0x8 & (field_value << 3))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + fut = self.dut.Tx_Sync_Cnt.tx_sync_cnt # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFF000000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFF) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Sync_Cnt.tx_sync_cnt.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=128, + width=32, + accesswidth=self.dut.Tx_Sync_Cnt.tx_sync_cnt.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFF000000) | \ + (0xFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.lowpass_ema_alpha1.alpha + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha1.alpha'): + fut = self.dut.lowpass_ema_alpha1.alpha # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFC0000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x3FFFF + self.assertEqual(await fut.read(), + 0x3FFFF) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x3FFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x3FFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x3FFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.lowpass_ema_alpha1.alpha.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=132, + width=32, + accesswidth=self.dut.lowpass_ema_alpha1.alpha.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFC0000) | \ + (0x3FFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x3FFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.lowpass_ema_alpha2.alpha + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha2.alpha'): + fut = self.dut.lowpass_ema_alpha2.alpha # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFC0000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x3FFFF + self.assertEqual(await fut.read(), + 0x3FFFF) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x3FFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x3FFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x3FFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.lowpass_ema_alpha2.alpha.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=136, + width=32, + accesswidth=self.dut.lowpass_ema_alpha2.alpha.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFC0000) | \ + (0x3FFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x3FFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.rx_power.rx_power + with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): + fut = self.dut.rx_power.rx_power # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFF800000 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x7FFFFF + self.assertEqual(await fut.read(), + 0x7FFFFF) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x7FFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + async def test_register_read_fields(self) -> None: + """ + Walk the register map and check every register read_fields method + """ + reference_read_fields: dict[str, Union[bool, SystemRDLEnum, int]] + + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + # test read_fields to register: + # msk_top_regs.Hash_ID_Low + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'hash_id_lo' : await self.dut.Hash_ID_Low.hash_id_lo.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Hash_ID_Low.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + # test read_fields to register: + # msk_top_regs.Hash_ID_High + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'hash_id_hi' : await self.dut.Hash_ID_High.hash_id_hi.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Hash_ID_High.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + # test read_fields to register: + # msk_top_regs.MSK_Init + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'txrxinit' : await self.dut.MSK_Init.txrxinit.read(), + 'txinit' : await self.dut.MSK_Init.txinit.read(), + 'rxinit' : await self.dut.MSK_Init.rxinit.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.MSK_Init.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + # test read_fields to register: + # msk_top_regs.MSK_Control + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFEF) | (rand_field_value << 4) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'ptt' : await self.dut.MSK_Control.ptt.read(), + 'loopback_ena' : await self.dut.MSK_Control.loopback_ena.read(), + 'rx_invert' : await self.dut.MSK_Control.rx_invert.read(), + 'clear_counts' : await self.dut.MSK_Control.clear_counts.read(), + 'diff_encoder_loopback' : await self.dut.MSK_Control.diff_encoder_loopback.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.MSK_Control.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + # test read_fields to register: + # msk_top_regs.MSK_Status + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'demod_sync_lock' : await self.dut.MSK_Status.demod_sync_lock.read(), + 'tx_enable' : await self.dut.MSK_Status.tx_enable.read(), + 'rx_enable' : await self.dut.MSK_Status.rx_enable.read(), + 'tx_axis_valid' : await self.dut.MSK_Status.tx_axis_valid.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.MSK_Status.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + # test read_fields to register: + # msk_top_regs.Tx_Bit_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'tx_bit_counter' : await self.dut.Tx_Bit_Count.tx_bit_counter.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Tx_Bit_Count.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + # test read_fields to register: + # msk_top_regs.Tx_Enable_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'tx_ena_counter' : await self.dut.Tx_Enable_Count.tx_ena_counter.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Tx_Enable_Count.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + # test read_fields to register: + # msk_top_regs.Fb_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.Fb_FreqWord.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Fb_FreqWord.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + # test read_fields to register: + # msk_top_regs.TX_F1_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.TX_F1_FreqWord.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.TX_F1_FreqWord.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + # test read_fields to register: + # msk_top_regs.TX_F2_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.TX_F2_FreqWord.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.TX_F2_FreqWord.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + # test read_fields to register: + # msk_top_regs.RX_F1_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.RX_F1_FreqWord.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.RX_F1_FreqWord.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + # test read_fields to register: + # msk_top_regs.RX_F2_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.RX_F2_FreqWord.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.RX_F2_FreqWord.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + # test read_fields to register: + # msk_top_regs.LPF_Config_0 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x3F + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF03) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF) | (rand_field_value << 8) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'lpf_freeze' : await self.dut.LPF_Config_0.lpf_freeze.read(), + 'lpf_zero' : await self.dut.LPF_Config_0.lpf_zero.read(), + 'prbs_reserved' : await self.dut.LPF_Config_0.prbs_reserved.read(), + 'lpf_alpha' : await self.dut.LPF_Config_0.lpf_alpha.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.LPF_Config_0.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + # test read_fields to register: + # msk_top_regs.LPF_Config_1 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF) | (rand_field_value << 24) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'i_gain' : await self.dut.LPF_Config_1.i_gain.read(), + 'i_shift' : await self.dut.LPF_Config_1.i_shift.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.LPF_Config_1.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + # test read_fields to register: + # msk_top_regs.Tx_Data_Width + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data_width' : await self.dut.Tx_Data_Width.data_width.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Tx_Data_Width.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + # test read_fields to register: + # msk_top_regs.Rx_Data_Width + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data_width' : await self.dut.Rx_Data_Width.data_width.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Rx_Data_Width.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + # test read_fields to register: + # msk_top_regs.PRBS_Control + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + + + + + + + + + + + + + rand_field_value = random.randrange(0, 0xFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF000F) | (rand_field_value << 4) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF) | (rand_field_value << 16) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'prbs_sel' : await self.dut.PRBS_Control.prbs_sel.read(), + 'prbs_reserved' : await self.dut.PRBS_Control.prbs_reserved.read(), + 'prbs_sync_threshold' : await self.dut.PRBS_Control.prbs_sync_threshold.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Control.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + # test read_fields to register: + # msk_top_regs.PRBS_Initial_State + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Initial_State.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Initial_State.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + # test read_fields to register: + # msk_top_regs.PRBS_Polynomial + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Polynomial.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Polynomial.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + # test read_fields to register: + # msk_top_regs.PRBS_Error_Mask + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Error_Mask.config_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Error_Mask.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + # test read_fields to register: + # msk_top_regs.PRBS_Bit_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'status_data' : await self.dut.PRBS_Bit_Count.status_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Bit_Count.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + # test read_fields to register: + # msk_top_regs.PRBS_Error_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'status_data' : await self.dut.PRBS_Error_Count.status_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.PRBS_Error_Count.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + # test read_fields to register: + # msk_top_regs.LPF_Accum_F1 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'status_data' : await self.dut.LPF_Accum_F1.status_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.LPF_Accum_F1.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + # test read_fields to register: + # msk_top_regs.LPF_Accum_F2 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'status_data' : await self.dut.LPF_Accum_F2.status_data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.LPF_Accum_F2.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + # test read_fields to register: + # msk_top_regs.axis_xfer_count + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'xfer_count' : await self.dut.axis_xfer_count.xfer_count.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.axis_xfer_count.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + # test read_fields to register: + # msk_top_regs.Rx_Sample_Discard + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF00FF) | (rand_field_value << 8) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'rx_sample_discard' : await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), + 'rx_nco_discard' : await self.dut.Rx_Sample_Discard.rx_nco_discard.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Rx_Sample_Discard.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + # test read_fields to register: + # msk_top_regs.LPF_Config_2 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF) | (rand_field_value << 24) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'p_gain' : await self.dut.LPF_Config_2.p_gain.read(), + 'p_shift' : await self.dut.LPF_Config_2.p_shift.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.LPF_Config_2.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + # test read_fields to register: + # msk_top_regs.f1_nco_adjust + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.f1_nco_adjust.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.f1_nco_adjust.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + # test read_fields to register: + # msk_top_regs.f2_nco_adjust + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.f2_nco_adjust.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.f2_nco_adjust.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.f1_error'): + # test read_fields to register: + # msk_top_regs.f1_error + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.f1_error.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.f1_error.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.f2_error'): + # test read_fields to register: + # msk_top_regs.f2_error + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.f2_error.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.f2_error.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + # test read_fields to register: + # msk_top_regs.Tx_Sync_Ctrl + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'tx_sync_ena' : await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), + 'tx_sync_force' : await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), + 'tx_sync_f1' : await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), + 'tx_sync_f2' : await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Tx_Sync_Ctrl.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + # test read_fields to register: + # msk_top_regs.Tx_Sync_Cnt + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'tx_sync_cnt' : await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Tx_Sync_Cnt.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + # test read_fields to register: + # msk_top_regs.lowpass_ema_alpha1 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x3FFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFC0000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'alpha' : await self.dut.lowpass_ema_alpha1.alpha.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.lowpass_ema_alpha1.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + # test read_fields to register: + # msk_top_regs.lowpass_ema_alpha2 + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x3FFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFC0000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'alpha' : await self.dut.lowpass_ema_alpha2.alpha.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.lowpass_ema_alpha2.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.rx_power'): + # test read_fields to register: + # msk_top_regs.rx_power + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x7FFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF800000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'rx_power' : await self.dut.rx_power.rx_power.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.rx_power.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + + async def test_register_read_context_manager(self) -> None: + """ + Walk the register map and check every register read_fields method + """ + reference_read_fields: dict[str, Union[bool, SystemRDLEnum, int]] + + # test context manager to register: + # msk_top_regs.Hash_ID_Low + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'hash_id_lo' : await self.dut.Hash_ID_Low.hash_id_lo.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Hash_ID_Low.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['hash_id_lo'], + await reg_context.get_child_by_system_rdl_name('hash_id_lo').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Hash_ID_High + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'hash_id_hi' : await self.dut.Hash_ID_High.hash_id_hi.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Hash_ID_High.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['hash_id_hi'], + await reg_context.get_child_by_system_rdl_name('hash_id_hi').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.MSK_Init + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'txrxinit' : await self.dut.MSK_Init.txrxinit.read(), # type: ignore[union-attr] + 'txinit' : await self.dut.MSK_Init.txinit.read(), # type: ignore[union-attr] + 'rxinit' : await self.dut.MSK_Init.rxinit.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.MSK_Init.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['txrxinit'], + await reg_context.get_child_by_system_rdl_name('txrxinit').read() + ) + self.assertEqual(reference_read_fields['txinit'], + await reg_context.get_child_by_system_rdl_name('txinit').read() + ) + self.assertEqual(reference_read_fields['rxinit'], + await reg_context.get_child_by_system_rdl_name('rxinit').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.MSK_Control + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFEF) | (rand_field_value << 4) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'ptt' : await self.dut.MSK_Control.ptt.read(), # type: ignore[union-attr] + 'loopback_ena' : await self.dut.MSK_Control.loopback_ena.read(), # type: ignore[union-attr] + 'rx_invert' : await self.dut.MSK_Control.rx_invert.read(), # type: ignore[union-attr] + 'clear_counts' : await self.dut.MSK_Control.clear_counts.read(), # type: ignore[union-attr] + 'diff_encoder_loopback' : await self.dut.MSK_Control.diff_encoder_loopback.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.MSK_Control.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['ptt'], + await reg_context.get_child_by_system_rdl_name('ptt').read() + ) + self.assertEqual(reference_read_fields['loopback_ena'], + await reg_context.get_child_by_system_rdl_name('loopback_ena').read() + ) + self.assertEqual(reference_read_fields['rx_invert'], + await reg_context.get_child_by_system_rdl_name('rx_invert').read() + ) + self.assertEqual(reference_read_fields['clear_counts'], + await reg_context.get_child_by_system_rdl_name('clear_counts').read() + ) + self.assertEqual(reference_read_fields['diff_encoder_loopback'], + await reg_context.get_child_by_system_rdl_name('diff_encoder_loopback').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.MSK_Status + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'demod_sync_lock' : await self.dut.MSK_Status.demod_sync_lock.read(), # type: ignore[union-attr] + 'tx_enable' : await self.dut.MSK_Status.tx_enable.read(), # type: ignore[union-attr] + 'rx_enable' : await self.dut.MSK_Status.rx_enable.read(), # type: ignore[union-attr] + 'tx_axis_valid' : await self.dut.MSK_Status.tx_axis_valid.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.MSK_Status.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['demod_sync_lock'], + await reg_context.get_child_by_system_rdl_name('demod_sync_lock').read() + ) + self.assertEqual(reference_read_fields['tx_enable'], + await reg_context.get_child_by_system_rdl_name('tx_enable').read() + ) + self.assertEqual(reference_read_fields['rx_enable'], + await reg_context.get_child_by_system_rdl_name('rx_enable').read() + ) + self.assertEqual(reference_read_fields['tx_axis_valid'], + await reg_context.get_child_by_system_rdl_name('tx_axis_valid').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Tx_Bit_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'tx_bit_counter' : await self.dut.Tx_Bit_Count.tx_bit_counter.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Tx_Bit_Count.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['tx_bit_counter'], + await reg_context.get_child_by_system_rdl_name('tx_bit_counter').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Tx_Enable_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'tx_ena_counter' : await self.dut.Tx_Enable_Count.tx_ena_counter.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Tx_Enable_Count.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['tx_ena_counter'], + await reg_context.get_child_by_system_rdl_name('tx_ena_counter').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Fb_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.Fb_FreqWord.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Fb_FreqWord.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.TX_F1_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.TX_F1_FreqWord.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.TX_F1_FreqWord.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.TX_F2_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.TX_F2_FreqWord.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.TX_F2_FreqWord.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.RX_F1_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.RX_F1_FreqWord.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.RX_F1_FreqWord.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.RX_F2_FreqWord + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.RX_F2_FreqWord.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.RX_F2_FreqWord.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.LPF_Config_0 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x3F + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF03) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF) | (rand_field_value << 8) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'lpf_freeze' : await self.dut.LPF_Config_0.lpf_freeze.read(), # type: ignore[union-attr] + 'lpf_zero' : await self.dut.LPF_Config_0.lpf_zero.read(), # type: ignore[union-attr] + 'prbs_reserved' : await self.dut.LPF_Config_0.prbs_reserved.read(), # type: ignore[union-attr] + 'lpf_alpha' : await self.dut.LPF_Config_0.lpf_alpha.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.LPF_Config_0.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['lpf_freeze'], + await reg_context.get_child_by_system_rdl_name('lpf_freeze').read() + ) + self.assertEqual(reference_read_fields['lpf_zero'], + await reg_context.get_child_by_system_rdl_name('lpf_zero').read() + ) + self.assertEqual(reference_read_fields['prbs_reserved'], + await reg_context.get_child_by_system_rdl_name('prbs_reserved').read() + ) + self.assertEqual(reference_read_fields['lpf_alpha'], + await reg_context.get_child_by_system_rdl_name('lpf_alpha').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.LPF_Config_1 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF) | (rand_field_value << 24) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'i_gain' : await self.dut.LPF_Config_1.i_gain.read(), # type: ignore[union-attr] + 'i_shift' : await self.dut.LPF_Config_1.i_shift.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.LPF_Config_1.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['i_gain'], + await reg_context.get_child_by_system_rdl_name('i_gain').read() + ) + self.assertEqual(reference_read_fields['i_shift'], + await reg_context.get_child_by_system_rdl_name('i_shift').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Tx_Data_Width + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data_width' : await self.dut.Tx_Data_Width.data_width.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Tx_Data_Width.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data_width'], + await reg_context.get_child_by_system_rdl_name('data_width').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Rx_Data_Width + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data_width' : await self.dut.Rx_Data_Width.data_width.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Rx_Data_Width.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data_width'], + await reg_context.get_child_by_system_rdl_name('data_width').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Control + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + + + + + + + + + + + + + rand_field_value = random.randrange(0, 0xFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF000F) | (rand_field_value << 4) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF) | (rand_field_value << 16) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'prbs_sel' : await self.dut.PRBS_Control.prbs_sel.read(), # type: ignore[union-attr] + 'prbs_reserved' : await self.dut.PRBS_Control.prbs_reserved.read(), # type: ignore[union-attr] + 'prbs_sync_threshold' : await self.dut.PRBS_Control.prbs_sync_threshold.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Control.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['prbs_sel'], + await reg_context.get_child_by_system_rdl_name('prbs_sel').read() + ) + self.assertEqual(reference_read_fields['prbs_reserved'], + await reg_context.get_child_by_system_rdl_name('prbs_reserved').read() + ) + self.assertEqual(reference_read_fields['prbs_sync_threshold'], + await reg_context.get_child_by_system_rdl_name('prbs_sync_threshold').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Initial_State + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Initial_State.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Initial_State.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Polynomial + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Polynomial.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Polynomial.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Error_Mask + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'config_data' : await self.dut.PRBS_Error_Mask.config_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Error_Mask.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['config_data'], + await reg_context.get_child_by_system_rdl_name('config_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Bit_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'status_data' : await self.dut.PRBS_Bit_Count.status_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Bit_Count.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['status_data'], + await reg_context.get_child_by_system_rdl_name('status_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.PRBS_Error_Count + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'status_data' : await self.dut.PRBS_Error_Count.status_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.PRBS_Error_Count.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['status_data'], + await reg_context.get_child_by_system_rdl_name('status_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.LPF_Accum_F1 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'status_data' : await self.dut.LPF_Accum_F1.status_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.LPF_Accum_F1.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['status_data'], + await reg_context.get_child_by_system_rdl_name('status_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.LPF_Accum_F2 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'status_data' : await self.dut.LPF_Accum_F2.status_data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.LPF_Accum_F2.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['status_data'], + await reg_context.get_child_by_system_rdl_name('status_data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.axis_xfer_count + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'xfer_count' : await self.dut.axis_xfer_count.xfer_count.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.axis_xfer_count.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['xfer_count'], + await reg_context.get_child_by_system_rdl_name('xfer_count').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Rx_Sample_Discard + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF00) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFF00FF) | (rand_field_value << 8) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'rx_sample_discard' : await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), # type: ignore[union-attr] + 'rx_nco_discard' : await self.dut.Rx_Sample_Discard.rx_nco_discard.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Rx_Sample_Discard.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['rx_sample_discard'], + await reg_context.get_child_by_system_rdl_name('rx_sample_discard').read() + ) + self.assertEqual(reference_read_fields['rx_nco_discard'], + await reg_context.get_child_by_system_rdl_name('rx_nco_discard').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.LPF_Config_2 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0xFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFF) | (rand_field_value << 24) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'p_gain' : await self.dut.LPF_Config_2.p_gain.read(), # type: ignore[union-attr] + 'p_shift' : await self.dut.LPF_Config_2.p_shift.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.LPF_Config_2.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['p_gain'], + await reg_context.get_child_by_system_rdl_name('p_gain').read() + ) + self.assertEqual(reference_read_fields['p_shift'], + await reg_context.get_child_by_system_rdl_name('p_shift').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.f1_nco_adjust + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.f1_nco_adjust.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.f1_nco_adjust.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.f2_nco_adjust + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.f2_nco_adjust.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.f2_nco_adjust.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.f1_error + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.f1_error'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.f1_error.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.f1_error.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.f2_error + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.f2_error'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.f2_error.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.f2_error.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Tx_Sync_Ctrl + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFB) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFF7) | (rand_field_value << 3) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'tx_sync_ena' : await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), # type: ignore[union-attr] + 'tx_sync_force' : await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), # type: ignore[union-attr] + 'tx_sync_f1' : await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), # type: ignore[union-attr] + 'tx_sync_f2' : await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Tx_Sync_Ctrl.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['tx_sync_ena'], + await reg_context.get_child_by_system_rdl_name('tx_sync_ena').read() + ) + self.assertEqual(reference_read_fields['tx_sync_force'], + await reg_context.get_child_by_system_rdl_name('tx_sync_force').read() + ) + self.assertEqual(reference_read_fields['tx_sync_f1'], + await reg_context.get_child_by_system_rdl_name('tx_sync_f1').read() + ) + self.assertEqual(reference_read_fields['tx_sync_f2'], + await reg_context.get_child_by_system_rdl_name('tx_sync_f2').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.Tx_Sync_Cnt + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF000000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'tx_sync_cnt' : await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.Tx_Sync_Cnt.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['tx_sync_cnt'], + await reg_context.get_child_by_system_rdl_name('tx_sync_cnt').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.lowpass_ema_alpha1 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x3FFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFC0000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'alpha' : await self.dut.lowpass_ema_alpha1.alpha.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.lowpass_ema_alpha1.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['alpha'], + await reg_context.get_child_by_system_rdl_name('alpha').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.lowpass_ema_alpha2 + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x3FFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFC0000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'alpha' : await self.dut.lowpass_ema_alpha2.alpha.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.lowpass_ema_alpha2.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['alpha'], + await reg_context.get_child_by_system_rdl_name('alpha').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.rx_power + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.rx_power'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x7FFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFF800000) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'rx_power' : await self.dut.rx_power.rx_power.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.rx_power.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['rx_power'], + await reg_context.get_child_by_system_rdl_name('rx_power').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + + async def test_register_write_context_manager(self) -> None: + """ + Test the read modify write context manager + """ + async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[str]) -> None: + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + # fix for #196 (excessive test time) if the number of fields is greater than 4 + # the combinations are reduced to only tests combinations of three plus the full + # set + if len(writable_fields) > 4: + perms_iterator: Iterable[int] = chain(range(1,4), [len(writable_fields)]) + else: + perms_iterator = range(1, len(writable_fields) + 1) + for fields_to_write in chain.from_iterable((combinations(writable_fields, perms) for perms in perms_iterator)): + field_values: dict[str, Union[bool, SystemRDLEnum, int]] = {} + expected_value = 0 + for field_str in fields_to_write: + field = getattr(reg, field_str) + if hasattr(field, 'enum_cls'): + rand_enum_value = random_enum_reg_value(field.enum_cls) + rand_field_value = rand_enum_value.value + field_values[field_str] = rand_enum_value + else: + rand_field_value = random.randrange(0, field.max_value + 1) + field_values[field_str] = rand_field_value + + if field.msb == field.high: + expected_value = ( expected_value & field.inverse_bitmask ) | (rand_field_value << field.low) + elif field.msb == field.low: + expected_value = ( expected_value & field.inverse_bitmask ) | (self._reverse_bits(value=rand_field_value, number_bits=field.width) << field.low) + else: + raise RuntimeError('invalid msb/lsb high/low combination') + + # read/write without verify + read_callback_mock.return_value = 0 + async with reg.single_read_modify_write(verify=False) as reg_session: + for field_name, field_value in field_values.items(): + field = getattr(reg_session, field_name) + await field.write(field_value) + + write_callback_mock.assert_called_once_with( + addr=reg.address, + width=reg.width, + accesswidth=reg.accesswidth, + data=expected_value) + read_callback_mock.assert_called_once() + write_callback_mock.reset_mock() + read_callback_mock.reset_mock() + + # read/write/verify pass + async with reg.single_read_modify_write(verify=True) as reg_session: + for field_name, field_value in field_values.items(): + field = getattr(reg_session, field_name) + await field.write(field_value) + read_callback_mock.return_value = expected_value + + write_callback_mock.assert_called_once_with( + addr=reg.address, + width=reg.width, + accesswidth=reg.accesswidth, + data=expected_value) + self.assertEqual(read_callback_mock.call_count, 2) + write_callback_mock.reset_mock() + read_callback_mock.reset_mock() + + # read/write/verify pass + with self.assertRaises(RegisterWriteVerifyError) as context: + async with reg.single_read_modify_write(verify=True) as reg_session: + for field_name, field_value in field_values.items(): + field = getattr(reg_session, field_name) + await field.write(field_value) + read_callback_mock.return_value = expected_value ^ reg_session.max_value + + write_callback_mock.reset_mock() + read_callback_mock.reset_mock() + + + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + await write_field_combinations(reg=self.dut.MSK_Init, + writable_fields = [ 'txrxinit', + 'txinit', + 'rxinit' + ]) + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + await write_field_combinations(reg=self.dut.MSK_Control, + writable_fields = [ 'ptt', + 'loopback_ena', + 'rx_invert', + 'clear_counts', + 'diff_encoder_loopback' + ]) + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + await write_field_combinations(reg=self.dut.Fb_FreqWord, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + await write_field_combinations(reg=self.dut.TX_F1_FreqWord, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + await write_field_combinations(reg=self.dut.TX_F2_FreqWord, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + await write_field_combinations(reg=self.dut.RX_F1_FreqWord, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + await write_field_combinations(reg=self.dut.RX_F2_FreqWord, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + await write_field_combinations(reg=self.dut.LPF_Config_0, + writable_fields = [ 'lpf_freeze', + 'lpf_zero', + 'prbs_reserved', + 'lpf_alpha' + ]) + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + await write_field_combinations(reg=self.dut.LPF_Config_1, + writable_fields = [ 'i_gain', + 'i_shift' + ]) + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + await write_field_combinations(reg=self.dut.Tx_Data_Width, + writable_fields = [ 'data_width' + ]) + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + await write_field_combinations(reg=self.dut.Rx_Data_Width, + writable_fields = [ 'data_width' + ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + await write_field_combinations(reg=self.dut.PRBS_Control, + writable_fields = [ 'prbs_sel', + 'prbs_error_insert', + 'prbs_clear', + 'prbs_manual_sync', + 'prbs_reserved', + 'prbs_sync_threshold' + ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + await write_field_combinations(reg=self.dut.PRBS_Initial_State, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + await write_field_combinations(reg=self.dut.PRBS_Polynomial, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + await write_field_combinations(reg=self.dut.PRBS_Error_Mask, + writable_fields = [ 'config_data' + ]) + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + await write_field_combinations(reg=self.dut.Rx_Sample_Discard, + writable_fields = [ 'rx_sample_discard', + 'rx_nco_discard' + ]) + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + await write_field_combinations(reg=self.dut.LPF_Config_2, + writable_fields = [ 'p_gain', + 'p_shift' + ]) + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + await write_field_combinations(reg=self.dut.Tx_Sync_Ctrl, + writable_fields = [ 'tx_sync_ena', + 'tx_sync_force', + 'tx_sync_f1', + 'tx_sync_f2' + ]) + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + await write_field_combinations(reg=self.dut.Tx_Sync_Cnt, + writable_fields = [ 'tx_sync_cnt' + ]) + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + await write_field_combinations(reg=self.dut.lowpass_ema_alpha1, + writable_fields = [ 'alpha' + ]) + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + await write_field_combinations(reg=self.dut.lowpass_ema_alpha2, + writable_fields = [ 'alpha' + ]) + + async def test_register_write_fields(self) -> None: + """ + Walk the register map and check every register write_fields method + """ + rand_enum_value:SystemRDLEnum + async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[str]) -> None: + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + # fix for #196 (excessive test time) if the number of fields is greater than 4 + # the combinations are reduced to only tests combinations of three plus the full + # set + if len(writable_fields) > 4: + perms_iterator: Iterable[int] = chain(range(1,4), [len(writable_fields)]) + else: + perms_iterator = range(1, len(writable_fields) + 1) + for fields_to_write in chain.from_iterable((combinations(writable_fields, perms) for perms in perms_iterator)): + kwargs: dict[str, Union[bool, SystemRDLEnum, int]] = {} + expected_value = 0 + for field_str in fields_to_write: + field = getattr(reg, field_str) + if hasattr(field, 'enum_cls'): + rand_enum_value = random_enum_reg_value(field.enum_cls) + rand_field_value = rand_enum_value.value + kwargs[field_str] = rand_enum_value + else: + rand_field_value = random.randrange(0, field.max_value + 1) + kwargs[field_str] = rand_field_value + + if field.msb == field.high: + expected_value = ( expected_value & field.inverse_bitmask ) | (rand_field_value << field.low) + elif field.msb == field.low: + expected_value = ( expected_value & field.inverse_bitmask ) | (self._reverse_bits(value=rand_field_value, number_bits=field.width) << field.low) + else: + raise RuntimeError('invalid msb/lsb high/low combination') + + await reg.write_fields(**kwargs) + write_callback_mock.assert_called_once_with( + addr=reg.address, + width=reg.width, + accesswidth=reg.accesswidth, + data=expected_value) + read_callback_mock.assert_called_once() + write_callback_mock.reset_mock() + read_callback_mock.reset_mock() + + kwargs : dict[str, Union[bool, SystemRDLEnum, int]] + + + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + # test read_fields to register: + # msk_top_regs.MSK_Init + await write_field_combinations(reg=self.dut.MSK_Init, + writable_fields = [ 'txrxinit', + 'txinit', + 'rxinit' + ]) + + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + # test read_fields to register: + # msk_top_regs.MSK_Control + await write_field_combinations(reg=self.dut.MSK_Control, + writable_fields = [ 'ptt', + 'loopback_ena', + 'rx_invert', + 'clear_counts', + 'diff_encoder_loopback' + ]) + + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + # test read_fields to register: + # msk_top_regs.Fb_FreqWord + await write_field_combinations(reg=self.dut.Fb_FreqWord, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + # test read_fields to register: + # msk_top_regs.TX_F1_FreqWord + await write_field_combinations(reg=self.dut.TX_F1_FreqWord, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + # test read_fields to register: + # msk_top_regs.TX_F2_FreqWord + await write_field_combinations(reg=self.dut.TX_F2_FreqWord, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + # test read_fields to register: + # msk_top_regs.RX_F1_FreqWord + await write_field_combinations(reg=self.dut.RX_F1_FreqWord, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + # test read_fields to register: + # msk_top_regs.RX_F2_FreqWord + await write_field_combinations(reg=self.dut.RX_F2_FreqWord, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + # test read_fields to register: + # msk_top_regs.LPF_Config_0 + await write_field_combinations(reg=self.dut.LPF_Config_0, + writable_fields = [ 'lpf_freeze', + 'lpf_zero', + 'prbs_reserved', + 'lpf_alpha' + ]) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + # test read_fields to register: + # msk_top_regs.LPF_Config_1 + await write_field_combinations(reg=self.dut.LPF_Config_1, + writable_fields = [ 'i_gain', + 'i_shift' + ]) + + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + # test read_fields to register: + # msk_top_regs.Tx_Data_Width + await write_field_combinations(reg=self.dut.Tx_Data_Width, + writable_fields = [ 'data_width' + ]) + + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + # test read_fields to register: + # msk_top_regs.Rx_Data_Width + await write_field_combinations(reg=self.dut.Rx_Data_Width, + writable_fields = [ 'data_width' + ]) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + # test read_fields to register: + # msk_top_regs.PRBS_Control + await write_field_combinations(reg=self.dut.PRBS_Control, + writable_fields = [ 'prbs_sel', + 'prbs_error_insert', + 'prbs_clear', + 'prbs_manual_sync', + 'prbs_reserved', + 'prbs_sync_threshold' + ]) + + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + # test read_fields to register: + # msk_top_regs.PRBS_Initial_State + await write_field_combinations(reg=self.dut.PRBS_Initial_State, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + # test read_fields to register: + # msk_top_regs.PRBS_Polynomial + await write_field_combinations(reg=self.dut.PRBS_Polynomial, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + # test read_fields to register: + # msk_top_regs.PRBS_Error_Mask + await write_field_combinations(reg=self.dut.PRBS_Error_Mask, + writable_fields = [ 'config_data' + ]) + + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + # test read_fields to register: + # msk_top_regs.Rx_Sample_Discard + await write_field_combinations(reg=self.dut.Rx_Sample_Discard, + writable_fields = [ 'rx_sample_discard', + 'rx_nco_discard' + ]) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + # test read_fields to register: + # msk_top_regs.LPF_Config_2 + await write_field_combinations(reg=self.dut.LPF_Config_2, + writable_fields = [ 'p_gain', + 'p_shift' + ]) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + # test read_fields to register: + # msk_top_regs.Tx_Sync_Ctrl + await write_field_combinations(reg=self.dut.Tx_Sync_Ctrl, + writable_fields = [ 'tx_sync_ena', + 'tx_sync_force', + 'tx_sync_f1', + 'tx_sync_f2' + ]) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + # test read_fields to register: + # msk_top_regs.Tx_Sync_Cnt + await write_field_combinations(reg=self.dut.Tx_Sync_Cnt, + writable_fields = [ 'tx_sync_cnt' + ]) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + # test read_fields to register: + # msk_top_regs.lowpass_ema_alpha1 + await write_field_combinations(reg=self.dut.lowpass_ema_alpha1, + writable_fields = [ 'alpha' + ]) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + # test read_fields to register: + # msk_top_regs.lowpass_ema_alpha2 + await write_field_combinations(reg=self.dut.lowpass_ema_alpha2, + writable_fields = [ 'alpha' + ]) + + + + + def test_adding_attributes(self) -> None: + """ + Walk the address map and attempt to set a new value on each node + + The attribute name: cppkbrgmgeloagvfgjjeiiushygirh was randomly generated to be unlikely to + every be a attribute name + + """ + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Hash_ID_Low.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_High'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Hash_ID_High.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Init.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Status.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Bit_Count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Enable_Count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Fb_FreqWord.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.TX_F1_FreqWord.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.TX_F2_FreqWord.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.RX_F1_FreqWord.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.RX_F2_FreqWord.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_0.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_1.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Data_Width.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Rx_Data_Width.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Initial_State.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Polynomial.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Error_Mask.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Bit_Count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Error_Count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Accum_F1.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Accum_F2.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.axis_xfer_count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Rx_Sample_Discard.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_2.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f1_nco_adjust.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f2_nco_adjust.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f1_error'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f1_error.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f2_error'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f2_error.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Ctrl.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Cnt.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.lowpass_ema_alpha1.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.lowpass_ema_alpha2.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_power.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Hash_ID_Low.hash_id_lo.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Hash_ID_High.hash_id_hi'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Hash_ID_High.hash_id_hi.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.txrxinit'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Init.txrxinit.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.txinit'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Init.txinit.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Init.rxinit'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Init.rxinit.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.ptt'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.ptt.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.loopback_ena'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.loopback_ena.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.rx_invert'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.rx_invert.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.clear_counts'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.clear_counts.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Control.diff_encoder_loopback'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Control.diff_encoder_loopback.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.demod_sync_lock'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Status.demod_sync_lock.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_enable'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Status.tx_enable.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.rx_enable'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Status.rx_enable.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.MSK_Status.tx_axis_valid.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Bit_Count.tx_bit_counter.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Enable_Count.tx_ena_counter.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Fb_FreqWord.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F1_FreqWord.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.TX_F1_FreqWord.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.TX_F2_FreqWord.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.TX_F2_FreqWord.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F1_FreqWord.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.RX_F1_FreqWord.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.RX_F2_FreqWord.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.RX_F2_FreqWord.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_freeze'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_0.lpf_freeze.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_zero'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_0.lpf_zero.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.prbs_reserved'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_0.prbs_reserved.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_alpha'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_0.lpf_alpha.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_gain'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_1.i_gain.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_1.i_shift'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_1.i_shift.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Data_Width.data_width'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Data_Width.data_width.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Data_Width.data_width'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Rx_Data_Width.data_width.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sel'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_sel.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_error_insert'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_error_insert.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_clear'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_clear.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_manual_sync'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_manual_sync.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_reserved'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_reserved.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Control.prbs_sync_threshold.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Initial_State.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Initial_State.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Polynomial.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Polynomial.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask.config_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Error_Mask.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Bit_Count.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.PRBS_Error_Count.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Accum_F1.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Accum_F2.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.axis_xfer_count.xfer_count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Rx_Sample_Discard.rx_sample_discard.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Rx_Sample_Discard.rx_nco_discard.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_gain'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_2.p_gain.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Config_2.p_shift'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.LPF_Config_2.p_shift.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f1_nco_adjust.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f2_nco_adjust.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f1_error.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f1_error.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.f2_error.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.f2_error.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Ctrl.tx_sync_ena.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Ctrl.tx_sync_force.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Ctrl.tx_sync_f1.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Ctrl.tx_sync_f2.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.Tx_Sync_Cnt.tx_sync_cnt.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha1.alpha'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.lowpass_ema_alpha1.alpha.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2.alpha'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.lowpass_ema_alpha2.alpha.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_power.rx_power.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + + + + def test_top_traversal_iterators(self) -> None: + + expected_writable_regs: list[WritableAsyncRegister] + expected_readable_regs: list[ReadableAsyncRegister] + expected_memories:list[Union[MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite]] + + + expected_sections : list[Union[AsyncAddressMap, AsyncRegFile]] + + # check the readable registers + expected_readable_regs = [self.dut.Hash_ID_Low, # type: ignore[union-attr,list-item] + + self.dut.Hash_ID_High, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control, # type: ignore[union-attr,list-item] + + self.dut.MSK_Status, # type: ignore[union-attr,list-item] + + self.dut.Tx_Bit_Count, # type: ignore[union-attr,list-item] + + self.dut.Tx_Enable_Count, # type: ignore[union-attr,list-item] + + self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.Rx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Initial_State, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Polynomial, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Bit_Count, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Count, # type: ignore[union-attr,list-item] + + self.dut.LPF_Accum_F1, # type: ignore[union-attr,list-item] + + self.dut.LPF_Accum_F2, # type: ignore[union-attr,list-item] + + self.dut.axis_xfer_count, # type: ignore[union-attr,list-item] + + self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] + + self.dut.f1_nco_adjust, # type: ignore[union-attr,list-item] + + self.dut.f2_nco_adjust, # type: ignore[union-attr,list-item] + + self.dut.f1_error, # type: ignore[union-attr,list-item] + + self.dut.f2_error, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Cnt, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha1, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] + + self.dut.rx_power, # type: ignore[union-attr,list-item] + + ] + readable_regs = [] + for readable_reg in self.dut.get_readable_registers(unroll=True): # type: ignore[union-attr] + self.assertIsInstance(readable_reg, (RegAsyncReadWrite, RegAsyncReadOnly)) + readable_regs.append(readable_reg) + self.assertCountEqual(expected_readable_regs, readable_regs) + + expected_readable_regs = [self.dut.Hash_ID_Low, # type: ignore[union-attr,list-item] + + self.dut.Hash_ID_High, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control, # type: ignore[union-attr,list-item] + + self.dut.MSK_Status, # type: ignore[union-attr,list-item] + + self.dut.Tx_Bit_Count, # type: ignore[union-attr,list-item] + + self.dut.Tx_Enable_Count, # type: ignore[union-attr,list-item] + + self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.Rx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Initial_State, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Polynomial, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Bit_Count, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Count, # type: ignore[union-attr,list-item] + + self.dut.LPF_Accum_F1, # type: ignore[union-attr,list-item] + + self.dut.LPF_Accum_F2, # type: ignore[union-attr,list-item] + + self.dut.axis_xfer_count, # type: ignore[union-attr,list-item] + + self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] + + self.dut.f1_nco_adjust, # type: ignore[union-attr,list-item] + + self.dut.f2_nco_adjust, # type: ignore[union-attr,list-item] + + self.dut.f1_error, # type: ignore[union-attr,list-item] + + self.dut.f2_error, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Cnt, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha1, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] + + self.dut.rx_power, # type: ignore[union-attr,list-item] + + ] + readable_regs = [] + for readable_reg in self.dut.get_readable_registers(unroll=False): # type: ignore[union-attr] + readable_regs.append(readable_reg) + self.assertCountEqual(expected_readable_regs, readable_regs) + + # check the writable registers + expected_writable_regs = [ + + + + self.dut.MSK_Init, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control, # type: ignore[union-attr,list-item] + + + + + + + + self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.Rx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Initial_State, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Polynomial, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] + + + + + + + + + + + + self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] + + + + + + + + + + self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Cnt, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha1, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] + + + + ] + writable_regs = [] + for writable_reg in self.dut.get_writable_registers(unroll=True): # type: ignore[union-attr] + self.assertIsInstance(writable_reg, (RegAsyncReadWrite, RegAsyncWriteOnly)) + writable_regs.append(writable_reg) + self.assertCountEqual(expected_writable_regs, writable_regs) + + expected_writable_regs = [ + + + + self.dut.MSK_Init, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control, # type: ignore[union-attr,list-item] + + + + + + + + self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.TX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F1_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.RX_F2_FreqWord, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.Rx_Data_Width, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Initial_State, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Polynomial, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] + + + + + + + + + + + + self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] + + + + + + + + + + self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Cnt, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha1, # type: ignore[union-attr,list-item] + + self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] + + + + ] + writable_regs = [] + for writable_reg in self.dut.get_writable_registers(unroll=False): # type: ignore[union-attr] + writable_regs.append(writable_reg) + self.assertCountEqual(expected_writable_regs, writable_regs) + + # check the sections + expected_sections = [ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ] + sections = [] + for section in self.dut.get_sections(unroll=True): # type: ignore[union-attr] + self.assertIsInstance(section, (AsyncAddressMap, AsyncRegFile)) + sections.append(section) + self.assertCountEqual(expected_sections, sections) + + expected_sections = [ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ] + sections = [] + for section in self.dut.get_sections(unroll=False): # type: ignore[union-attr] + sections.append(section) + self.assertCountEqual(expected_sections, sections) + + # check the memories + expected_memories = [ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ] + memories = [] + for memory in self.dut.get_memories(unroll=True): # type: ignore[union-attr] + self.assertIsInstance(memory, (MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite)) + memories.append(memory) + self.assertCountEqual(expected_memories, memories) + + expected_memories = [ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ] + memories = [] + for memory in self.dut.get_memories(unroll=False): # type: ignore[union-attr] + self.assertIsInstance(memory, (MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite, MemoryAsyncReadOnlyArray, MemoryAsyncWriteOnlyArray, MemoryAsyncReadWriteArray)) + memories.append(memory) + self.assertCountEqual(expected_memories, memories) + + + + + + + + + + + + def test_traversal_iterators(self) -> None: + """ + Walk the address map and check that the iterators for each node as as expected + """ + + expected_writable_fields: list[Union[FieldAsyncWriteOnly, FieldAsyncReadWrite]] + expected_readable_fields: list[Union[FieldAsyncReadOnly, FieldAsyncReadWrite]] + expected_fields: list[Union[FieldAsyncWriteOnly, FieldAsyncReadOnly, FieldAsyncReadWrite]] + expected_writable_regs: list[WritableAsyncRegister] + expected_readable_regs: list[ReadableAsyncRegister] + expected_memories:list[Union[MemoryAsyncReadOnly, MemoryAsyncWriteOnly, MemoryAsyncReadWrite]] + + + expected_sections : list[Union[AsyncAddressMap, AsyncRegFile]] + + # test all the registers + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + + expected_fields = [self.dut.Hash_ID_Low.hash_id_lo, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Hash_ID_Low.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.Hash_ID_Low, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.Hash_ID_Low.hash_id_lo, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Hash_ID_Low.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + + expected_fields = [self.dut.Hash_ID_High.hash_id_hi, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Hash_ID_High.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.Hash_ID_High, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.Hash_ID_High.hash_id_hi, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Hash_ID_High.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + + expected_fields = [self.dut.MSK_Init.txrxinit, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Init.txinit, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Init.rxinit, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.MSK_Init.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.MSK_Init.txrxinit, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init.txinit, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init.rxinit, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.MSK_Init.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.MSK_Init.txrxinit, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init.txinit, # type: ignore[union-attr,list-item] + + self.dut.MSK_Init.rxinit, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.MSK_Init.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + + expected_fields = [self.dut.MSK_Control.ptt, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Control.loopback_ena, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Control.rx_invert, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Control.clear_counts, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Control.diff_encoder_loopback, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.MSK_Control.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.MSK_Control.ptt, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.loopback_ena, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.rx_invert, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.clear_counts, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.diff_encoder_loopback, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.MSK_Control.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.MSK_Control.ptt, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.loopback_ena, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.rx_invert, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.clear_counts, # type: ignore[union-attr,list-item] + + self.dut.MSK_Control.diff_encoder_loopback, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.MSK_Control.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + + expected_fields = [self.dut.MSK_Status.demod_sync_lock, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Status.tx_enable, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Status.rx_enable, # type: ignore[union-attr,list-item] + + + self.dut.MSK_Status.tx_axis_valid, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.MSK_Status.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.MSK_Status, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.MSK_Status.demod_sync_lock, # type: ignore[union-attr,list-item] + + self.dut.MSK_Status.tx_enable, # type: ignore[union-attr,list-item] + + self.dut.MSK_Status.rx_enable, # type: ignore[union-attr,list-item] + + self.dut.MSK_Status.tx_axis_valid, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.MSK_Status.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + + expected_fields = [self.dut.Tx_Bit_Count.tx_bit_counter, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Tx_Bit_Count.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.Tx_Bit_Count, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.Tx_Bit_Count.tx_bit_counter, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Tx_Bit_Count.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + + expected_fields = [self.dut.Tx_Enable_Count.tx_ena_counter, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Tx_Enable_Count.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.Tx_Enable_Count, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.Tx_Enable_Count.tx_ena_counter, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Tx_Enable_Count.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + + expected_fields = [self.dut.Fb_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Fb_FreqWord.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Fb_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Fb_FreqWord.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Fb_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Fb_FreqWord.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + + expected_fields = [self.dut.TX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.TX_F1_FreqWord.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.TX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.TX_F1_FreqWord.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.TX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.TX_F1_FreqWord.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + + expected_fields = [self.dut.TX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.TX_F2_FreqWord.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.TX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.TX_F2_FreqWord.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.TX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.TX_F2_FreqWord.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + + expected_fields = [self.dut.RX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.RX_F1_FreqWord.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.RX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.RX_F1_FreqWord.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.RX_F1_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.RX_F1_FreqWord.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + + expected_fields = [self.dut.RX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.RX_F2_FreqWord.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.RX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.RX_F2_FreqWord.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.RX_F2_FreqWord.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.RX_F2_FreqWord.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + + expected_fields = [self.dut.LPF_Config_0.lpf_freeze, # type: ignore[union-attr,list-item] + + + self.dut.LPF_Config_0.lpf_zero, # type: ignore[union-attr,list-item] + + + self.dut.LPF_Config_0.prbs_reserved, # type: ignore[union-attr,list-item] + + + self.dut.LPF_Config_0.lpf_alpha, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.LPF_Config_0.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.LPF_Config_0.lpf_freeze, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.lpf_zero, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.prbs_reserved, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.lpf_alpha, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.LPF_Config_0.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.LPF_Config_0.lpf_freeze, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.lpf_zero, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.prbs_reserved, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_0.lpf_alpha, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.LPF_Config_0.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + + expected_fields = [self.dut.LPF_Config_1.i_gain, # type: ignore[union-attr,list-item] + + + self.dut.LPF_Config_1.i_shift, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.LPF_Config_1.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.LPF_Config_1.i_gain, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1.i_shift, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.LPF_Config_1.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.LPF_Config_1.i_gain, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_1.i_shift, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.LPF_Config_1.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + + expected_fields = [self.dut.Tx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Tx_Data_Width.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Tx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Tx_Data_Width.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Tx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Tx_Data_Width.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + + expected_fields = [self.dut.Rx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Rx_Data_Width.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Rx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Rx_Data_Width.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Rx_Data_Width.data_width, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Rx_Data_Width.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + + expected_fields = [self.dut.PRBS_Control.prbs_sel, # type: ignore[union-attr,list-item] + + + self.dut.PRBS_Control.prbs_error_insert, # type: ignore[union-attr,list-item] + + + self.dut.PRBS_Control.prbs_clear, # type: ignore[union-attr,list-item] + + + self.dut.PRBS_Control.prbs_manual_sync, # type: ignore[union-attr,list-item] + + + self.dut.PRBS_Control.prbs_reserved, # type: ignore[union-attr,list-item] + + + self.dut.PRBS_Control.prbs_sync_threshold, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Control.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.PRBS_Control.prbs_sel, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_error_insert, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_clear, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_manual_sync, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_reserved, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_sync_threshold, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Control.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.PRBS_Control.prbs_sel, # type: ignore[union-attr,list-item] + + + + + + + + self.dut.PRBS_Control.prbs_reserved, # type: ignore[union-attr,list-item] + + self.dut.PRBS_Control.prbs_sync_threshold, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Control.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + + expected_fields = [self.dut.PRBS_Initial_State.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Initial_State.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.PRBS_Initial_State.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Initial_State.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.PRBS_Initial_State.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Initial_State.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + + expected_fields = [self.dut.PRBS_Polynomial.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Polynomial.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.PRBS_Polynomial.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Polynomial.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.PRBS_Polynomial.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Polynomial.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + + expected_fields = [self.dut.PRBS_Error_Mask.config_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Error_Mask.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.PRBS_Error_Mask.config_data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Error_Mask.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.PRBS_Error_Mask.config_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Error_Mask.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + + expected_fields = [self.dut.PRBS_Bit_Count.status_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Bit_Count.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.PRBS_Bit_Count, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.PRBS_Bit_Count.status_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Bit_Count.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + + expected_fields = [self.dut.PRBS_Error_Count.status_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.PRBS_Error_Count.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.PRBS_Error_Count, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.PRBS_Error_Count.status_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.PRBS_Error_Count.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + + expected_fields = [self.dut.LPF_Accum_F1.status_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.LPF_Accum_F1.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.LPF_Accum_F1, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.LPF_Accum_F1.status_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.LPF_Accum_F1.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + + expected_fields = [self.dut.LPF_Accum_F2.status_data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.LPF_Accum_F2.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.LPF_Accum_F2, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.LPF_Accum_F2.status_data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.LPF_Accum_F2.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + + expected_fields = [self.dut.axis_xfer_count.xfer_count, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.axis_xfer_count.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.axis_xfer_count, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.axis_xfer_count.xfer_count, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.axis_xfer_count.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + + expected_fields = [self.dut.Rx_Sample_Discard.rx_sample_discard, # type: ignore[union-attr,list-item] + + + self.dut.Rx_Sample_Discard.rx_nco_discard, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Rx_Sample_Discard.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Rx_Sample_Discard.rx_sample_discard, # type: ignore[union-attr,list-item] + + self.dut.Rx_Sample_Discard.rx_nco_discard, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Rx_Sample_Discard.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Rx_Sample_Discard.rx_sample_discard, # type: ignore[union-attr,list-item] + + self.dut.Rx_Sample_Discard.rx_nco_discard, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Rx_Sample_Discard.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + + expected_fields = [self.dut.LPF_Config_2.p_gain, # type: ignore[union-attr,list-item] + + + self.dut.LPF_Config_2.p_shift, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.LPF_Config_2.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.LPF_Config_2.p_gain, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2.p_shift, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.LPF_Config_2.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.LPF_Config_2.p_gain, # type: ignore[union-attr,list-item] + + self.dut.LPF_Config_2.p_shift, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.LPF_Config_2.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + + expected_fields = [self.dut.f1_nco_adjust.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.f1_nco_adjust.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.f1_nco_adjust, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.f1_nco_adjust.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.f1_nco_adjust.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + + expected_fields = [self.dut.f2_nco_adjust.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.f2_nco_adjust.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.f2_nco_adjust, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.f2_nco_adjust.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.f2_nco_adjust.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.f1_error'): + + expected_fields = [self.dut.f1_error.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.f1_error.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.f1_error, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.f1_error.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.f1_error.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.f2_error'): + + expected_fields = [self.dut.f2_error.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.f2_error.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.f2_error, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.f2_error.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.f2_error.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + + expected_fields = [self.dut.Tx_Sync_Ctrl.tx_sync_ena, # type: ignore[union-attr,list-item] + + + self.dut.Tx_Sync_Ctrl.tx_sync_force, # type: ignore[union-attr,list-item] + + + self.dut.Tx_Sync_Ctrl.tx_sync_f1, # type: ignore[union-attr,list-item] + + + self.dut.Tx_Sync_Ctrl.tx_sync_f2, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Tx_Sync_Ctrl.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Tx_Sync_Ctrl.tx_sync_ena, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_force, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_f1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_f2, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Tx_Sync_Ctrl.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Tx_Sync_Ctrl.tx_sync_ena, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_force, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_f1, # type: ignore[union-attr,list-item] + + self.dut.Tx_Sync_Ctrl.tx_sync_f2, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Tx_Sync_Ctrl.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + + expected_fields = [self.dut.Tx_Sync_Cnt.tx_sync_cnt, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.Tx_Sync_Cnt.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.Tx_Sync_Cnt.tx_sync_cnt, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Tx_Sync_Cnt.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.Tx_Sync_Cnt.tx_sync_cnt, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.Tx_Sync_Cnt.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + + expected_fields = [self.dut.lowpass_ema_alpha1.alpha, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.lowpass_ema_alpha1.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.lowpass_ema_alpha1.alpha, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.lowpass_ema_alpha1.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.lowpass_ema_alpha1.alpha, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.lowpass_ema_alpha1.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + + expected_fields = [self.dut.lowpass_ema_alpha2.alpha, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.lowpass_ema_alpha2.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.lowpass_ema_alpha2.alpha, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.lowpass_ema_alpha2.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.lowpass_ema_alpha2.alpha, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.lowpass_ema_alpha2.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.rx_power'): + + expected_fields = [self.dut.rx_power.rx_power, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.rx_power.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.rx_power, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.rx_power.rx_power, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.rx_power.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + + # test all the memories + + # test all the address maps + + # test all the register files + + + def test_name_map(self) -> None: + """ + Check that the function for getting a node by its original systemRDL name works + """ + + + self.assertEqual(self.dut.Hash_ID_Low.get_child_by_system_rdl_name('hash_id_lo').inst_name, 'hash_id_lo') + + + + + + self.assertEqual(self.dut.Hash_ID_High.get_child_by_system_rdl_name('hash_id_hi').inst_name, 'hash_id_hi') + + + + + + self.assertEqual(self.dut.MSK_Init.get_child_by_system_rdl_name('txrxinit').inst_name, 'txrxinit') + + + + + self.assertEqual(self.dut.MSK_Init.get_child_by_system_rdl_name('txinit').inst_name, 'txinit') + + + + + self.assertEqual(self.dut.MSK_Init.get_child_by_system_rdl_name('rxinit').inst_name, 'rxinit') + + + + + + self.assertEqual(self.dut.MSK_Control.get_child_by_system_rdl_name('ptt').inst_name, 'ptt') + + + + + self.assertEqual(self.dut.MSK_Control.get_child_by_system_rdl_name('loopback_ena').inst_name, 'loopback_ena') + + + + + self.assertEqual(self.dut.MSK_Control.get_child_by_system_rdl_name('rx_invert').inst_name, 'rx_invert') + + + + + self.assertEqual(self.dut.MSK_Control.get_child_by_system_rdl_name('clear_counts').inst_name, 'clear_counts') + + + + + self.assertEqual(self.dut.MSK_Control.get_child_by_system_rdl_name('diff_encoder_loopback').inst_name, 'diff_encoder_loopback') + + + + + + self.assertEqual(self.dut.MSK_Status.get_child_by_system_rdl_name('demod_sync_lock').inst_name, 'demod_sync_lock') + + + + + self.assertEqual(self.dut.MSK_Status.get_child_by_system_rdl_name('tx_enable').inst_name, 'tx_enable') + + + + + self.assertEqual(self.dut.MSK_Status.get_child_by_system_rdl_name('rx_enable').inst_name, 'rx_enable') + + + + + self.assertEqual(self.dut.MSK_Status.get_child_by_system_rdl_name('tx_axis_valid').inst_name, 'tx_axis_valid') + + + + + + self.assertEqual(self.dut.Tx_Bit_Count.get_child_by_system_rdl_name('tx_bit_counter').inst_name, 'tx_bit_counter') + + + + + + self.assertEqual(self.dut.Tx_Enable_Count.get_child_by_system_rdl_name('tx_ena_counter').inst_name, 'tx_ena_counter') + + + + + + self.assertEqual(self.dut.Fb_FreqWord.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.TX_F1_FreqWord.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.TX_F2_FreqWord.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.RX_F1_FreqWord.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.RX_F2_FreqWord.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.LPF_Config_0.get_child_by_system_rdl_name('lpf_freeze').inst_name, 'lpf_freeze') + + + + + self.assertEqual(self.dut.LPF_Config_0.get_child_by_system_rdl_name('lpf_zero').inst_name, 'lpf_zero') + + + + + self.assertEqual(self.dut.LPF_Config_0.get_child_by_system_rdl_name('prbs_reserved').inst_name, 'prbs_reserved') + + + + + self.assertEqual(self.dut.LPF_Config_0.get_child_by_system_rdl_name('lpf_alpha').inst_name, 'lpf_alpha') + + + + + + self.assertEqual(self.dut.LPF_Config_1.get_child_by_system_rdl_name('i_gain').inst_name, 'i_gain') + + + + + self.assertEqual(self.dut.LPF_Config_1.get_child_by_system_rdl_name('i_shift').inst_name, 'i_shift') + + + + + + self.assertEqual(self.dut.Tx_Data_Width.get_child_by_system_rdl_name('data_width').inst_name, 'data_width') + + + + + + self.assertEqual(self.dut.Rx_Data_Width.get_child_by_system_rdl_name('data_width').inst_name, 'data_width') + + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_sel').inst_name, 'prbs_sel') + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_error_insert').inst_name, 'prbs_error_insert') + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_clear').inst_name, 'prbs_clear') + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_manual_sync').inst_name, 'prbs_manual_sync') + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_reserved').inst_name, 'prbs_reserved') + + + + + self.assertEqual(self.dut.PRBS_Control.get_child_by_system_rdl_name('prbs_sync_threshold').inst_name, 'prbs_sync_threshold') + + + + + + self.assertEqual(self.dut.PRBS_Initial_State.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.PRBS_Polynomial.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.PRBS_Error_Mask.get_child_by_system_rdl_name('config_data').inst_name, 'config_data') + + + + + + self.assertEqual(self.dut.PRBS_Bit_Count.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + + + + + + self.assertEqual(self.dut.PRBS_Error_Count.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + + + + + + self.assertEqual(self.dut.LPF_Accum_F1.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + + + + + + self.assertEqual(self.dut.LPF_Accum_F2.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + + + + + + self.assertEqual(self.dut.axis_xfer_count.get_child_by_system_rdl_name('xfer_count').inst_name, 'xfer_count') + + + + + + self.assertEqual(self.dut.Rx_Sample_Discard.get_child_by_system_rdl_name('rx_sample_discard').inst_name, 'rx_sample_discard') + + + + + self.assertEqual(self.dut.Rx_Sample_Discard.get_child_by_system_rdl_name('rx_nco_discard').inst_name, 'rx_nco_discard') + + + + + + self.assertEqual(self.dut.LPF_Config_2.get_child_by_system_rdl_name('p_gain').inst_name, 'p_gain') + + + + + self.assertEqual(self.dut.LPF_Config_2.get_child_by_system_rdl_name('p_shift').inst_name, 'p_shift') + + + + + + self.assertEqual(self.dut.f1_nco_adjust.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + self.assertEqual(self.dut.f2_nco_adjust.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + self.assertEqual(self.dut.f1_error.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + self.assertEqual(self.dut.f2_error.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.get_child_by_system_rdl_name('tx_sync_ena').inst_name, 'tx_sync_ena') + + + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.get_child_by_system_rdl_name('tx_sync_force').inst_name, 'tx_sync_force') + + + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.get_child_by_system_rdl_name('tx_sync_f1').inst_name, 'tx_sync_f1') + + + + + self.assertEqual(self.dut.Tx_Sync_Ctrl.get_child_by_system_rdl_name('tx_sync_f2').inst_name, 'tx_sync_f2') + + + + + + self.assertEqual(self.dut.Tx_Sync_Cnt.get_child_by_system_rdl_name('tx_sync_cnt').inst_name, 'tx_sync_cnt') + + + + + + self.assertEqual(self.dut.lowpass_ema_alpha1.get_child_by_system_rdl_name('alpha').inst_name, 'alpha') + + + + + + self.assertEqual(self.dut.lowpass_ema_alpha2.get_child_by_system_rdl_name('alpha').inst_name, 'alpha') + + + + + + self.assertEqual(self.dut.rx_power.get_child_by_system_rdl_name('rx_power').inst_name, 'rx_power') + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +class msk_top_regs_block_access(msk_top_regs_TestCase_BlockAccess): # type: ignore[valid-type,misc] + """ + tests for all the block access methods + """ + + + + async def test_register_array_context_manager(self) -> None: + """ + Walk the register map and check that register map context managers work correctly + """ + + +class msk_top_regs_alt_block_access(msk_top_regs_TestCase_AltBlockAccess): # type: ignore[valid-type,misc] + """ + tests for all the block access methods with the alternative callbacks, this is a simpler + version of the tests above + """ + + + async def test_register_array_context_manager(self) -> None: + """ + Walk the register map and check that register map context managers work correctly + """ + + + +if __name__ == '__main__': + + if sys.version_info < (3, 8): + asynctest.main() + else: + unittest.main() + + + + diff --git a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py new file mode 100644 index 0000000..d649ad0 --- /dev/null +++ b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py @@ -0,0 +1,7518 @@ + + + +""" +Unit Tests for the msk_top_regs register model Python Wrapper + +This code was generated from the PeakRDL-python package version 1.4.0 +""" + + +from typing import Union, cast + +import sys +import asyncio +import unittest +from unittest.mock import Mock + +import random + + +from ..sim_lib.register import Register,MemoryRegister +from ..sim_lib.field import Field + +from ._msk_top_regs_sim_test_base import msk_top_regs_SimTestCase, msk_top_regs_SimTestCase_BlockAccess +from ._msk_top_regs_sim_test_base import __name__ as base_name +from ._msk_top_regs_test_base import random_enum_reg_value + + +from ..lib import SystemRDLEnum + + +class msk_top_regs_single_access(msk_top_regs_SimTestCase): # type: ignore[valid-type,misc] + + async def test_register_read_and_write(self) -> None: + """ + Walk the register map and check every register can be read and written to correctly + """ + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_Low + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Hash_ID_Low') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_Low.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_Low.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Hash_ID_Low.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_High + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Hash_ID_High') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_High.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_High.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Hash_ID_High.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Init + with self.subTest(msg='register: msk_top_regs.MSK_Init'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Init') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.MSK_Init.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Init.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Init.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Init.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.MSK_Init.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control + with self.subTest(msg='register: msk_top_regs.MSK_Control'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.MSK_Control.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.MSK_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.MSK_Control.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status + with self.subTest(msg='register: msk_top_regs.MSK_Status'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.MSK_Status.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Bit_Count + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Bit_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Bit_Count.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Bit_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Tx_Bit_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Enable_Count + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Enable_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Enable_Count.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Enable_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Tx_Enable_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Fb_FreqWord + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Fb_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Fb_FreqWord.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Fb_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Fb_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Fb_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Fb_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Fb_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Fb_FreqWord.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F1_FreqWord + with self.subTest(msg='register: msk_top_regs.TX_F1_FreqWord'): + sim_register = self.sim.register_by_full_name('msk_top_regs.TX_F1_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F1_FreqWord.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F1_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.TX_F1_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.TX_F1_FreqWord.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F2_FreqWord + with self.subTest(msg='register: msk_top_regs.TX_F2_FreqWord'): + sim_register = self.sim.register_by_full_name('msk_top_regs.TX_F2_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F2_FreqWord.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F2_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.TX_F2_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.TX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.TX_F2_FreqWord.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F1_FreqWord + with self.subTest(msg='register: msk_top_regs.RX_F1_FreqWord'): + sim_register = self.sim.register_by_full_name('msk_top_regs.RX_F1_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F1_FreqWord.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F1_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.RX_F1_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F1_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.RX_F1_FreqWord.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F2_FreqWord + with self.subTest(msg='register: msk_top_regs.RX_F2_FreqWord'): + sim_register = self.sim.register_by_full_name('msk_top_regs.RX_F2_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F2_FreqWord.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F2_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.RX_F2_FreqWord.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.RX_F2_FreqWord.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.RX_F2_FreqWord.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0 + with self.subTest(msg='register: msk_top_regs.LPF_Config_0'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_0') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.LPF_Config_0.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_0.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_0.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_0.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.LPF_Config_0.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_1 + with self.subTest(msg='register: msk_top_regs.LPF_Config_1'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.LPF_Config_1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.LPF_Config_1.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Data_Width + with self.subTest(msg='register: msk_top_regs.Tx_Data_Width'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Data_Width') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Data_Width.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Data_Width.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Tx_Data_Width.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Tx_Data_Width.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Data_Width + with self.subTest(msg='register: msk_top_regs.Rx_Data_Width'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Data_Width') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Data_Width.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Data_Width.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Rx_Data_Width.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Data_Width.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Rx_Data_Width.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control + with self.subTest(msg='register: msk_top_regs.PRBS_Control'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Control.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Control.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Control.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Initial_State + with self.subTest(msg='register: msk_top_regs.PRBS_Initial_State'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Initial_State') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Initial_State.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Initial_State.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Initial_State.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Initial_State.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Initial_State.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Initial_State.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Initial_State.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Polynomial + with self.subTest(msg='register: msk_top_regs.PRBS_Polynomial'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Polynomial') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Polynomial.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Polynomial.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Polynomial.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Polynomial.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Polynomial.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Polynomial.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Polynomial.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Mask + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Mask'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Error_Mask') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Mask.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Mask.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Error_Mask.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Mask.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Mask.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Mask.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Error_Mask.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Bit_Count + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Bit_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Bit_Count.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Bit_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Bit_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Count + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Error_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Count.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.PRBS_Error_Count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F1 + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F1.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.LPF_Accum_F1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F2 + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F2.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.LPF_Accum_F2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.axis_xfer_count + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.axis_xfer_count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.axis_xfer_count.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Sample_Discard') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Rx_Sample_Discard.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Sample_Discard.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Sample_Discard.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Rx_Sample_Discard.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Rx_Sample_Discard.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_2 + with self.subTest(msg='register: msk_top_regs.LPF_Config_2'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.LPF_Config_2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Config_2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.LPF_Config_2.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f1_nco_adjust + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f1_nco_adjust') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f1_nco_adjust.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f1_nco_adjust.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.f1_nco_adjust.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f2_nco_adjust + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f2_nco_adjust') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f2_nco_adjust.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f2_nco_adjust.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.f2_nco_adjust.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f1_error + with self.subTest(msg='register: msk_top_regs.f1_error'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f1_error') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f1_error.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f1_error.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.f1_error.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f2_error + with self.subTest(msg='register: msk_top_regs.f2_error'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f2_error') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f2_error.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.f2_error.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.f2_error.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Ctrl') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Tx_Sync_Ctrl.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Ctrl.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Ctrl.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Ctrl.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Tx_Sync_Ctrl.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Cnt + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Cnt'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Cnt') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Cnt.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Cnt.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.Tx_Sync_Cnt.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Cnt.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Cnt.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Sync_Cnt.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Tx_Sync_Cnt.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha1 + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha1'): + sim_register = self.sim.register_by_full_name('msk_top_regs.lowpass_ema_alpha1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha1.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.lowpass_ema_alpha1.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.lowpass_ema_alpha1.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha2 + with self.subTest(msg='register: msk_top_regs.lowpass_ema_alpha2'): + sim_register = self.sim.register_by_full_name('msk_top_regs.lowpass_ema_alpha2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha2.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.lowpass_ema_alpha2.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.lowpass_ema_alpha2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.lowpass_ema_alpha2.read(), random_value) + + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_power + with self.subTest(msg='register: msk_top_regs.rx_power'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_power') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_power.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_power.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.rx_power.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + + + async def test_field_read_and_write(self) -> None: + """ + Walk the register map and check every field can be read and written to correctly + """ + random_field_value: Union[int, SystemRDLEnum] + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_Low.hash_id_lo + with self.subTest(msg='field: msk_top_regs.Hash_ID_Low.hash_id_lo'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Hash_ID_Low') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Hash_ID_Low.hash_id_lo') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_Low.hash_id_lo.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Hash_ID_Low.hash_id_lo.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Hash_ID_Low.hash_id_lo.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_Low.hash_id_lo.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Hash_ID_High.hash_id_hi + with self.subTest(msg='field: msk_top_regs.Hash_ID_High.hash_id_hi'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Hash_ID_High') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Hash_ID_High.hash_id_hi') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_High.hash_id_hi.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Hash_ID_High.hash_id_hi.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Hash_ID_High.hash_id_hi.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Hash_ID_High.hash_id_hi.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Init.txrxinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.txrxinit'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Init') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Init.txrxinit') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.txrxinit.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.MSK_Init.txrxinit.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Init.txrxinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.txrxinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txrxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txrxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txrxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Init.txinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.txinit'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Init') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Init.txinit') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.txinit.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.MSK_Init.txinit.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Init.txinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.txinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.txinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Init.rxinit + with self.subTest(msg='field: msk_top_regs.MSK_Init.rxinit'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Init') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Init.rxinit') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.rxinit.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFB) | (random_field_value << 2)) + + self.assertEqual(await self.dut.MSK_Init.rxinit.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Init.rxinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Init.rxinit.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.rxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.rxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Init.rxinit.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control.ptt + with self.subTest(msg='field: msk_top_regs.MSK_Control.ptt'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Control.ptt') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.ptt.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.MSK_Control.ptt.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Control.ptt.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.ptt.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.ptt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.ptt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.ptt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control.loopback_ena + with self.subTest(msg='field: msk_top_regs.MSK_Control.loopback_ena'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Control.loopback_ena') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.loopback_ena.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.MSK_Control.loopback_ena.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Control.loopback_ena.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.loopback_ena.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.loopback_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.loopback_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.loopback_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control.rx_invert + with self.subTest(msg='field: msk_top_regs.MSK_Control.rx_invert'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Control.rx_invert') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.rx_invert.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFB) | (random_field_value << 2)) + + self.assertEqual(await self.dut.MSK_Control.rx_invert.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Control.rx_invert.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.rx_invert.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.rx_invert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.rx_invert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.rx_invert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control.clear_counts + with self.subTest(msg='field: msk_top_regs.MSK_Control.clear_counts'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Control.clear_counts') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.clear_counts.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFF7) | (random_field_value << 3)) + + self.assertEqual(await self.dut.MSK_Control.clear_counts.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Control.clear_counts.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.clear_counts.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.clear_counts.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.clear_counts.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.clear_counts.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Control.diff_encoder_loopback + with self.subTest(msg='field: msk_top_regs.MSK_Control.diff_encoder_loopback'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Control.diff_encoder_loopback') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x10) >> 4 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.diff_encoder_loopback.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFEF) | (random_field_value << 4)) + + self.assertEqual(await self.dut.MSK_Control.diff_encoder_loopback.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x10) >> 4 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Control.diff_encoder_loopback.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x10) >> 4 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Control.diff_encoder_loopback.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.diff_encoder_loopback.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFEF) | (0x10 & (random_field_value << 4))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.diff_encoder_loopback.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFEF) | (0x10 & (random_field_value << 4))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFEF) | (0x10 & (random_field_value << 4))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.MSK_Control.diff_encoder_loopback.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFEF) | (0x10 & (random_field_value << 4))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status.demod_sync_lock + with self.subTest(msg='field: msk_top_regs.MSK_Status.demod_sync_lock'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Status.demod_sync_lock') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.demod_sync_lock.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.MSK_Status.demod_sync_lock.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Status.demod_sync_lock.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.demod_sync_lock.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status.tx_enable + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_enable'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Status.tx_enable') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.tx_enable.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.MSK_Status.tx_enable.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Status.tx_enable.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.tx_enable.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status.rx_enable + with self.subTest(msg='field: msk_top_regs.MSK_Status.rx_enable'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Status.rx_enable') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.rx_enable.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFB) | (random_field_value << 2)) + + self.assertEqual(await self.dut.MSK_Status.rx_enable.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Status.rx_enable.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.rx_enable.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.MSK_Status.tx_axis_valid + with self.subTest(msg='field: msk_top_regs.MSK_Status.tx_axis_valid'): + sim_register = self.sim.register_by_full_name('msk_top_regs.MSK_Status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.MSK_Status.tx_axis_valid') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.tx_axis_valid.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFF7) | (random_field_value << 3)) + + self.assertEqual(await self.dut.MSK_Status.tx_axis_valid.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.MSK_Status.tx_axis_valid.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.MSK_Status.tx_axis_valid.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Bit_Count.tx_bit_counter + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Bit_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Bit_Count.tx_bit_counter') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Enable_Count.tx_ena_counter + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Enable_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Enable_Count.tx_ena_counter') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Fb_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.Fb_FreqWord.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Fb_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Fb_FreqWord.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Fb_FreqWord.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Fb_FreqWord.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Fb_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Fb_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Fb_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Fb_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Fb_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F1_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.TX_F1_FreqWord.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.TX_F1_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.TX_F1_FreqWord.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F1_FreqWord.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.TX_F1_FreqWord.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.TX_F1_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F1_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.TX_F2_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.TX_F2_FreqWord.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.TX_F2_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.TX_F2_FreqWord.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F2_FreqWord.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.TX_F2_FreqWord.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.TX_F2_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.TX_F2_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.TX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F1_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.RX_F1_FreqWord.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.RX_F1_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.RX_F1_FreqWord.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F1_FreqWord.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.RX_F1_FreqWord.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.RX_F1_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F1_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F1_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.RX_F2_FreqWord.config_data + with self.subTest(msg='field: msk_top_regs.RX_F2_FreqWord.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.RX_F2_FreqWord') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.RX_F2_FreqWord.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F2_FreqWord.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.RX_F2_FreqWord.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.RX_F2_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.RX_F2_FreqWord.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.RX_F2_FreqWord.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0.lpf_freeze + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_freeze'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_0') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_0.lpf_freeze') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_freeze.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.LPF_Config_0.lpf_freeze.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_0.lpf_freeze.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_freeze.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_freeze.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_freeze.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_freeze.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0.lpf_zero + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_zero'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_0') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_0.lpf_zero') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_zero.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.LPF_Config_0.lpf_zero.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_0.lpf_zero.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_zero.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_zero.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_zero.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.LPF_Config_0.lpf_zero.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0.prbs_reserved + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.prbs_reserved'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_0') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_0.prbs_reserved') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC) >> 2 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.prbs_reserved.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x3F+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF03) | (random_field_value << 2)) + + self.assertEqual(await self.dut.LPF_Config_0.prbs_reserved.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC) >> 2 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_0.prbs_reserved.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC) >> 2 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.prbs_reserved.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.LPF_Config_0.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF03) | (0xFC & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.LPF_Config_0.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF03) | (0xFC & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF03) | (0xFC & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.LPF_Config_0.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF03) | (0xFC & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_0.lpf_alpha + with self.subTest(msg='field: msk_top_regs.LPF_Config_0.lpf_alpha'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_0') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_0.lpf_alpha') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF00) >> 8 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_alpha.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFF) | (random_field_value << 8)) + + self.assertEqual(await self.dut.LPF_Config_0.lpf_alpha.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF00) >> 8 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_0.lpf_alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF00) >> 8 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_0.lpf_alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_0.lpf_alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF) | (0xFFFFFF00 & (random_field_value << 8))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_0.lpf_alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF) | (0xFFFFFF00 & (random_field_value << 8))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFF) | (0xFFFFFF00 & (random_field_value << 8))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_0.lpf_alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF) | (0xFFFFFF00 & (random_field_value << 8))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_1.i_gain + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_gain'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_1.i_gain') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.i_gain.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFF000000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.LPF_Config_1.i_gain.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_1.i_gain.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.i_gain.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_1.i_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_1.i_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_1.i_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_1.i_shift + with self.subTest(msg='field: msk_top_regs.LPF_Config_1.i_shift'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_1.i_shift') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.i_shift.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF) | (random_field_value << 24)) + + self.assertEqual(await self.dut.LPF_Config_1.i_shift.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_1.i_shift.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_1.i_shift.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_1.i_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_1.i_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_1.i_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Data_Width.data_width + with self.subTest(msg='field: msk_top_regs.Tx_Data_Width.data_width'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Data_Width') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Data_Width.data_width') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Data_Width.data_width.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF00) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Tx_Data_Width.data_width.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Data_Width.data_width.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Data_Width.data_width.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Tx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Tx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Tx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Data_Width.data_width + with self.subTest(msg='field: msk_top_regs.Rx_Data_Width.data_width'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Data_Width') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Rx_Data_Width.data_width') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Data_Width.data_width.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF00) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Rx_Data_Width.data_width.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Rx_Data_Width.data_width.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Data_Width.data_width.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Data_Width.data_width.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_sel + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sel'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_sel') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_sel.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Control.prbs_sel.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Control.prbs_sel.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_sel.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_sel.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_sel.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_sel.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_error_insert + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_error_insert'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_error_insert') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_error_insert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_error_insert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_error_insert.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_clear + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_clear'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_clear') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_clear.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_clear.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_clear.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_manual_sync + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_manual_sync'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_manual_sync') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_manual_sync.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_manual_sync.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.PRBS_Control.prbs_manual_sync.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_reserved + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_reserved'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_reserved') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFF0) >> 4 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_reserved.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFF000F) | (random_field_value << 4)) + + self.assertEqual(await self.dut.PRBS_Control.prbs_reserved.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFF0) >> 4 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Control.prbs_reserved.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFF0) >> 4 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_reserved.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFF+1) + + await self.dut.PRBS_Control.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF000F) | (0xFFF0 & (random_field_value << 4))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFF+1) + + await self.dut.PRBS_Control.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF000F) | (0xFFF0 & (random_field_value << 4))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFF000F) | (0xFFF0 & (random_field_value << 4))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFF+1) + + await self.dut.PRBS_Control.prbs_reserved.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF000F) | (0xFFF0 & (random_field_value << 4))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Control.prbs_sync_threshold + with self.subTest(msg='field: msk_top_regs.PRBS_Control.prbs_sync_threshold'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Control') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Control.prbs_sync_threshold') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFF0000) >> 16 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_sync_threshold.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFF) | (random_field_value << 16)) + + self.assertEqual(await self.dut.PRBS_Control.prbs_sync_threshold.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFF0000) >> 16 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Control.prbs_sync_threshold.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFF0000) >> 16 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Control.prbs_sync_threshold.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFF+1) + + await self.dut.PRBS_Control.prbs_sync_threshold.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF) | (0xFFFF0000 & (random_field_value << 16))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFF+1) + + await self.dut.PRBS_Control.prbs_sync_threshold.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF) | (0xFFFF0000 & (random_field_value << 16))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFF) | (0xFFFF0000 & (random_field_value << 16))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFF+1) + + await self.dut.PRBS_Control.prbs_sync_threshold.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF) | (0xFFFF0000 & (random_field_value << 16))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Initial_State.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Initial_State.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Initial_State') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Initial_State.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Initial_State.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Initial_State.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Initial_State.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Initial_State.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Initial_State.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Initial_State.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Initial_State.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Polynomial.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Polynomial.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Polynomial') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Polynomial.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Polynomial.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Polynomial.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Polynomial.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Polynomial.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Polynomial.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Polynomial.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Polynomial.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Mask.config_data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Mask.config_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Error_Mask') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Error_Mask.config_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Mask.config_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Error_Mask.config_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Error_Mask.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Mask.config_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Mask.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Mask.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Mask.config_data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Bit_Count.status_data + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Bit_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Bit_Count.status_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.PRBS_Error_Count.status_data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Error_Count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Error_Count.status_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F1.status_data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F1.status_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Accum_F2.status_data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F2.status_data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.axis_xfer_count.xfer_count + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): + sim_register = self.sim.register_by_full_name('msk_top_regs.axis_xfer_count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.axis_xfer_count.xfer_count') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard.rx_sample_discard + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Sample_Discard') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Rx_Sample_Discard.rx_sample_discard') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF00) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_sample_discard.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_sample_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_sample_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_sample_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF00) | (0xFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard.rx_nco_discard + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_nco_discard'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Sample_Discard') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Rx_Sample_Discard.rx_nco_discard') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF00) >> 8 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_nco_discard.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFF00FF) | (random_field_value << 8)) + + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_nco_discard.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF00) >> 8 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_nco_discard.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF00) >> 8 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Rx_Sample_Discard.rx_nco_discard.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_nco_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF00FF) | (0xFF00 & (random_field_value << 8))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_nco_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF00FF) | (0xFF00 & (random_field_value << 8))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFF00FF) | (0xFF00 & (random_field_value << 8))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.Rx_Sample_Discard.rx_nco_discard.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFF00FF) | (0xFF00 & (random_field_value << 8))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_2.p_gain + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_gain'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_2.p_gain') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.p_gain.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFF000000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.LPF_Config_2.p_gain.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_2.p_gain.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.p_gain.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_2.p_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_2.p_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.LPF_Config_2.p_gain.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.LPF_Config_2.p_shift + with self.subTest(msg='field: msk_top_regs.LPF_Config_2.p_shift'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Config_2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Config_2.p_shift') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.p_shift.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFF) | (random_field_value << 24)) + + self.assertEqual(await self.dut.LPF_Config_2.p_shift.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.LPF_Config_2.p_shift.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFF000000) >> 24 + + + sim_register.value = random_value + self.assertEqual(await self.dut.LPF_Config_2.p_shift.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_2.p_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_2.p_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFF+1) + + await self.dut.LPF_Config_2.p_shift.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFF) | (0xFF000000 & (random_field_value << 24))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.f1_nco_adjust.data + with self.subTest(msg='field: msk_top_regs.f1_nco_adjust.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f1_nco_adjust') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.f1_nco_adjust.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f1_nco_adjust.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.f1_nco_adjust.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.f1_nco_adjust.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f1_nco_adjust.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f2_nco_adjust.data + with self.subTest(msg='field: msk_top_regs.f2_nco_adjust.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f2_nco_adjust') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.f2_nco_adjust.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f2_nco_adjust.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.f2_nco_adjust.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.f2_nco_adjust.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f2_nco_adjust.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f1_error.data + with self.subTest(msg='field: msk_top_regs.f1_error.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f1_error') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.f1_error.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f1_error.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.f1_error.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.f1_error.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f1_error.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.f2_error.data + with self.subTest(msg='field: msk_top_regs.f2_error.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.f2_error') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.f2_error.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f2_error.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.f2_error.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.f2_error.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.f2_error.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Ctrl') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_ena.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_ena.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_force + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Ctrl') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Sync_Ctrl.tx_sync_force') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_force.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_force.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_force.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_force.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1 + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Ctrl') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFB) | (random_field_value << 2)) + + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x4) >> 2 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f1.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f1.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f1.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f1.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFB) | (0x4 & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2 + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Ctrl') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFF7) | (random_field_value << 3)) + + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x8) >> 3 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Ctrl.tx_sync_f2.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f2.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f2.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.Tx_Sync_Ctrl.tx_sync_f2.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFF7) | (0x8 & (random_field_value << 3))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt + with self.subTest(msg='field: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Sync_Cnt') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFF000000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.Tx_Sync_Cnt.tx_sync_cnt.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.Tx_Sync_Cnt.tx_sync_cnt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.Tx_Sync_Cnt.tx_sync_cnt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.Tx_Sync_Cnt.tx_sync_cnt.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF000000) | (0xFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha1.alpha + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha1.alpha'): + sim_register = self.sim.register_by_full_name('msk_top_regs.lowpass_ema_alpha1') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.lowpass_ema_alpha1.alpha') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha1.alpha.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x3FFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFC0000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.lowpass_ema_alpha1.alpha.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.lowpass_ema_alpha1.alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha1.alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha1.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha1.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha1.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.lowpass_ema_alpha2.alpha + with self.subTest(msg='field: msk_top_regs.lowpass_ema_alpha2.alpha'): + sim_register = self.sim.register_by_full_name('msk_top_regs.lowpass_ema_alpha2') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.lowpass_ema_alpha2.alpha') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha2.alpha.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x3FFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFC0000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.lowpass_ema_alpha2.alpha.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.lowpass_ema_alpha2.alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.lowpass_ema_alpha2.alpha.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha2.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha2.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x3FFFF+1) + + await self.dut.lowpass_ema_alpha2.alpha.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFC0000) | (0x3FFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_power.rx_power + with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_power') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_power.rx_power') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x7FFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x7FFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFF800000) | (random_field_value << 0)) + + self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x7FFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x7FFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + + + + + + + +class msk_top_regs_block_access(msk_top_regs_SimTestCase_BlockAccess): # type: ignore[valid-type,misc] + """ + tests for all the block access methods + """ + + + +if __name__ == '__main__': + + if sys.version_info < (3, 8): + asynctest.main() + else: + unittest.main() + + + + diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd new file mode 100644 index 0000000..9606951 --- /dev/null +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -0,0 +1,2321 @@ +-- Generated by PeakRDL-regblock-vhdl - A free and open-source VHDL generator +-- https://github.com/SystemRDL/PeakRDL-regblock-vhdl +library ieee; +context ieee.ieee_std_context; +use ieee.fixed_pkg.all; + +use work.msk_top_regs_pkg.all; +use work.axi4lite_intf_pkg.all; +use work.reg_utils.all; + +entity msk_top_regs is + port ( + clk : in std_logic; + rst : in std_logic; + + s_axil_i : in axi4lite_slave_in_intf( + AWADDR(7 downto 0), + WDATA(31 downto 0), + WSTRB(3 downto 0), + ARADDR(7 downto 0) + ); + s_axil_o : out axi4lite_slave_out_intf( + RDATA(31 downto 0) + ); + + hwif_in : in msk_top_regs_in_t; + hwif_out : out msk_top_regs_out_t + ); +end entity msk_top_regs; + +architecture rtl of msk_top_regs is + ---------------------------------------------------------------------------- + -- CPU Bus interface signals + ---------------------------------------------------------------------------- + signal cpuif_req : std_logic; + signal cpuif_req_is_wr : std_logic; + signal cpuif_addr : std_logic_vector(7 downto 0); + signal cpuif_wr_data : std_logic_vector(31 downto 0); + signal cpuif_wr_biten : std_logic_vector(31 downto 0); + signal cpuif_req_stall_wr : std_logic; + signal cpuif_req_stall_rd : std_logic; + + signal cpuif_rd_ack : std_logic; + signal cpuif_rd_err : std_logic; + signal cpuif_rd_data : std_logic_vector(31 downto 0); + + signal cpuif_wr_ack : std_logic; + signal cpuif_wr_err : std_logic; + + signal cpuif_req_masked : std_logic; + + signal axil_n_in_flight : unsigned(1 downto 0); + signal axil_prev_was_rd : std_logic; + signal axil_arvalid : std_logic; + signal axil_araddr : std_logic_vector(7 downto 0); + signal axil_ar_accept : std_logic; + signal axil_awvalid : std_logic; + signal axil_awaddr : std_logic_vector(7 downto 0); + signal axil_wvalid : std_logic; + signal axil_wdata : std_logic_vector(31 downto 0); + signal axil_wstrb : std_logic_vector(3 downto 0); + signal axil_aw_accept : std_logic; + signal axil_resp_acked : std_logic; + type axil_resp_buffer_t is record + is_wr : std_logic; + err : std_logic; + rdata : std_logic_vector(31 downto 0); + end record axil_resp_buffer_t; + type axil_resp_buffer_array_t is array (integer range <>) of axil_resp_buffer_t; + signal axil_resp_buffer : axil_resp_buffer_array_t(1 downto 0); + signal axil_resp_wptr : unsigned(1 downto 0); + signal axil_resp_rptr : unsigned(1 downto 0); + + ---------------------------------------------------------------------------- + -- Address Decode Signals + ---------------------------------------------------------------------------- + type decoded_reg_strb_t is record + Hash_ID_Low : std_logic; + Hash_ID_High : std_logic; + MSK_Init : std_logic; + MSK_Control : std_logic; + MSK_Status : std_logic; + Tx_Bit_Count : std_logic; + Tx_Enable_Count : std_logic; + Fb_FreqWord : std_logic; + TX_F1_FreqWord : std_logic; + TX_F2_FreqWord : std_logic; + RX_F1_FreqWord : std_logic; + RX_F2_FreqWord : std_logic; + LPF_Config_0 : std_logic; + LPF_Config_1 : std_logic; + Tx_Data_Width : std_logic; + Rx_Data_Width : std_logic; + PRBS_Control : std_logic; + PRBS_Initial_State : std_logic; + PRBS_Polynomial : std_logic; + PRBS_Error_Mask : std_logic; + PRBS_Bit_Count : std_logic; + PRBS_Error_Count : std_logic; + LPF_Accum_F1 : std_logic; + LPF_Accum_F2 : std_logic; + axis_xfer_count : std_logic; + Rx_Sample_Discard : std_logic; + LPF_Config_2 : std_logic; + f1_nco_adjust : std_logic; + f2_nco_adjust : std_logic; + f1_error : std_logic; + f2_error : std_logic; + Tx_Sync_Ctrl : std_logic; + Tx_Sync_Cnt : std_logic; + lowpass_ema_alpha1 : std_logic; + lowpass_ema_alpha2 : std_logic; + rx_power : std_logic; + end record; + signal decoded_reg_strb : decoded_reg_strb_t; + signal decoded_req : std_logic; + signal decoded_req_is_wr : std_logic; + signal decoded_wr_data : std_logic_vector(31 downto 0); + signal decoded_wr_biten : std_logic_vector(31 downto 0); + + ---------------------------------------------------------------------------- + -- Field Logic Signals + ---------------------------------------------------------------------------- + -- Field Combinational Signals + type \msk_top_regs.MSK_Init.txrxinit_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Init.txinit_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Init.rxinit_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Init_combo_t\ is record + txrxinit : \msk_top_regs.MSK_Init.txrxinit_combo_t\; + txinit : \msk_top_regs.MSK_Init.txinit_combo_t\; + rxinit : \msk_top_regs.MSK_Init.rxinit_combo_t\; + end record; + + type \msk_top_regs.MSK_Control.ptt_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Control.loopback_ena_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Control.rx_invert_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Control.clear_counts_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Control.diff_encoder_loopback_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.MSK_Control_combo_t\ is record + ptt : \msk_top_regs.MSK_Control.ptt_combo_t\; + loopback_ena : \msk_top_regs.MSK_Control.loopback_ena_combo_t\; + rx_invert : \msk_top_regs.MSK_Control.rx_invert_combo_t\; + clear_counts : \msk_top_regs.MSK_Control.clear_counts_combo_t\; + diff_encoder_loopback : \msk_top_regs.MSK_Control.diff_encoder_loopback_combo_t\; + end record; + + type \msk_top_regs.Fb_FreqWord.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Fb_FreqWord_combo_t\ is record + config_data : \msk_top_regs.Fb_FreqWord.config_data_combo_t\; + end record; + + type \msk_top_regs.TX_F1_FreqWord.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.TX_F1_FreqWord_combo_t\ is record + config_data : \msk_top_regs.TX_F1_FreqWord.config_data_combo_t\; + end record; + + type \msk_top_regs.TX_F2_FreqWord.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.TX_F2_FreqWord_combo_t\ is record + config_data : \msk_top_regs.TX_F2_FreqWord.config_data_combo_t\; + end record; + + type \msk_top_regs.RX_F1_FreqWord.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.RX_F1_FreqWord_combo_t\ is record + config_data : \msk_top_regs.RX_F1_FreqWord.config_data_combo_t\; + end record; + + type \msk_top_regs.RX_F2_FreqWord.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.RX_F2_FreqWord_combo_t\ is record + config_data : \msk_top_regs.RX_F2_FreqWord.config_data_combo_t\; + end record; + + type \msk_top_regs.LPF_Config_0.lpf_freeze_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0.lpf_zero_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0.prbs_reserved_combo_t\ is record + next_q : std_logic_vector(5 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0.lpf_alpha_combo_t\ is record + next_q : std_logic_vector(23 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0_combo_t\ is record + lpf_freeze : \msk_top_regs.LPF_Config_0.lpf_freeze_combo_t\; + lpf_zero : \msk_top_regs.LPF_Config_0.lpf_zero_combo_t\; + prbs_reserved : \msk_top_regs.LPF_Config_0.prbs_reserved_combo_t\; + lpf_alpha : \msk_top_regs.LPF_Config_0.lpf_alpha_combo_t\; + end record; + + type \msk_top_regs.LPF_Config_1.i_gain_combo_t\ is record + next_q : std_logic_vector(23 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_1.i_shift_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_1_combo_t\ is record + i_gain : \msk_top_regs.LPF_Config_1.i_gain_combo_t\; + i_shift : \msk_top_regs.LPF_Config_1.i_shift_combo_t\; + end record; + + type \msk_top_regs.Tx_Data_Width.data_width_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Data_Width_combo_t\ is record + data_width : \msk_top_regs.Tx_Data_Width.data_width_combo_t\; + end record; + + type \msk_top_regs.Rx_Data_Width.data_width_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Rx_Data_Width_combo_t\ is record + data_width : \msk_top_regs.Rx_Data_Width.data_width_combo_t\; + end record; + + type \msk_top_regs.PRBS_Control.prbs_sel_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_error_insert_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_clear_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_manual_sync_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_reserved_combo_t\ is record + next_q : std_logic_vector(11 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_sync_threshold_combo_t\ is record + next_q : std_logic_vector(15 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Control_combo_t\ is record + prbs_sel : \msk_top_regs.PRBS_Control.prbs_sel_combo_t\; + prbs_error_insert : \msk_top_regs.PRBS_Control.prbs_error_insert_combo_t\; + prbs_clear : \msk_top_regs.PRBS_Control.prbs_clear_combo_t\; + prbs_manual_sync : \msk_top_regs.PRBS_Control.prbs_manual_sync_combo_t\; + prbs_reserved : \msk_top_regs.PRBS_Control.prbs_reserved_combo_t\; + prbs_sync_threshold : \msk_top_regs.PRBS_Control.prbs_sync_threshold_combo_t\; + end record; + + type \msk_top_regs.PRBS_Initial_State.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Initial_State_combo_t\ is record + config_data : \msk_top_regs.PRBS_Initial_State.config_data_combo_t\; + end record; + + type \msk_top_regs.PRBS_Polynomial.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Polynomial_combo_t\ is record + config_data : \msk_top_regs.PRBS_Polynomial.config_data_combo_t\; + end record; + + type \msk_top_regs.PRBS_Error_Mask.config_data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Error_Mask_combo_t\ is record + config_data : \msk_top_regs.PRBS_Error_Mask.config_data_combo_t\; + end record; + + type \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Rx_Sample_Discard.rx_nco_discard_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Rx_Sample_Discard_combo_t\ is record + rx_sample_discard : \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_combo_t\; + rx_nco_discard : \msk_top_regs.Rx_Sample_Discard.rx_nco_discard_combo_t\; + end record; + + type \msk_top_regs.LPF_Config_2.p_gain_combo_t\ is record + next_q : std_logic_vector(23 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_2.p_shift_combo_t\ is record + next_q : std_logic_vector(7 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Config_2_combo_t\ is record + p_gain : \msk_top_regs.LPF_Config_2.p_gain_combo_t\; + p_shift : \msk_top_regs.LPF_Config_2.p_shift_combo_t\; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_force_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl_combo_t\ is record + tx_sync_ena : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_combo_t\; + tx_sync_force : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_force_combo_t\; + tx_sync_f1 : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1_combo_t\; + tx_sync_f2 : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2_combo_t\; + end record; + + type \msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt_combo_t\ is record + next_q : std_logic_vector(23 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Cnt_combo_t\ is record + tx_sync_cnt : \msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt_combo_t\; + end record; + + type \msk_top_regs.lowpass_ema_alpha1.alpha_combo_t\ is record + next_q : std_logic_vector(17 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.lowpass_ema_alpha1_combo_t\ is record + alpha : \msk_top_regs.lowpass_ema_alpha1.alpha_combo_t\; + end record; + + type \msk_top_regs.lowpass_ema_alpha2.alpha_combo_t\ is record + next_q : std_logic_vector(17 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.lowpass_ema_alpha2_combo_t\ is record + alpha : \msk_top_regs.lowpass_ema_alpha2.alpha_combo_t\; + end record; + + type field_combo_t is record + MSK_Init : \msk_top_regs.MSK_Init_combo_t\; + MSK_Control : \msk_top_regs.MSK_Control_combo_t\; + Fb_FreqWord : \msk_top_regs.Fb_FreqWord_combo_t\; + TX_F1_FreqWord : \msk_top_regs.TX_F1_FreqWord_combo_t\; + TX_F2_FreqWord : \msk_top_regs.TX_F2_FreqWord_combo_t\; + RX_F1_FreqWord : \msk_top_regs.RX_F1_FreqWord_combo_t\; + RX_F2_FreqWord : \msk_top_regs.RX_F2_FreqWord_combo_t\; + LPF_Config_0 : \msk_top_regs.LPF_Config_0_combo_t\; + LPF_Config_1 : \msk_top_regs.LPF_Config_1_combo_t\; + Tx_Data_Width : \msk_top_regs.Tx_Data_Width_combo_t\; + Rx_Data_Width : \msk_top_regs.Rx_Data_Width_combo_t\; + PRBS_Control : \msk_top_regs.PRBS_Control_combo_t\; + PRBS_Initial_State : \msk_top_regs.PRBS_Initial_State_combo_t\; + PRBS_Polynomial : \msk_top_regs.PRBS_Polynomial_combo_t\; + PRBS_Error_Mask : \msk_top_regs.PRBS_Error_Mask_combo_t\; + Rx_Sample_Discard : \msk_top_regs.Rx_Sample_Discard_combo_t\; + LPF_Config_2 : \msk_top_regs.LPF_Config_2_combo_t\; + Tx_Sync_Ctrl : \msk_top_regs.Tx_Sync_Ctrl_combo_t\; + Tx_Sync_Cnt : \msk_top_regs.Tx_Sync_Cnt_combo_t\; + lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha1_combo_t\; + lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha2_combo_t\; + end record; + signal field_combo : field_combo_t; + + -- Field Storage Signals + type \msk_top_regs.MSK_Init.txrxinit_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Init.txinit_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Init.rxinit_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Init_storage_t\ is record + txrxinit : \msk_top_regs.MSK_Init.txrxinit_storage_t\; + txinit : \msk_top_regs.MSK_Init.txinit_storage_t\; + rxinit : \msk_top_regs.MSK_Init.rxinit_storage_t\; + end record; + + type \msk_top_regs.MSK_Control.ptt_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Control.loopback_ena_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Control.rx_invert_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Control.clear_counts_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Control.diff_encoder_loopback_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.MSK_Control_storage_t\ is record + ptt : \msk_top_regs.MSK_Control.ptt_storage_t\; + loopback_ena : \msk_top_regs.MSK_Control.loopback_ena_storage_t\; + rx_invert : \msk_top_regs.MSK_Control.rx_invert_storage_t\; + clear_counts : \msk_top_regs.MSK_Control.clear_counts_storage_t\; + diff_encoder_loopback : \msk_top_regs.MSK_Control.diff_encoder_loopback_storage_t\; + end record; + + type \msk_top_regs.Fb_FreqWord.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.Fb_FreqWord_storage_t\ is record + config_data : \msk_top_regs.Fb_FreqWord.config_data_storage_t\; + end record; + + type \msk_top_regs.TX_F1_FreqWord.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.TX_F1_FreqWord_storage_t\ is record + config_data : \msk_top_regs.TX_F1_FreqWord.config_data_storage_t\; + end record; + + type \msk_top_regs.TX_F2_FreqWord.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.TX_F2_FreqWord_storage_t\ is record + config_data : \msk_top_regs.TX_F2_FreqWord.config_data_storage_t\; + end record; + + type \msk_top_regs.RX_F1_FreqWord.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.RX_F1_FreqWord_storage_t\ is record + config_data : \msk_top_regs.RX_F1_FreqWord.config_data_storage_t\; + end record; + + type \msk_top_regs.RX_F2_FreqWord.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.RX_F2_FreqWord_storage_t\ is record + config_data : \msk_top_regs.RX_F2_FreqWord.config_data_storage_t\; + end record; + + type \msk_top_regs.LPF_Config_0.lpf_freeze_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0.lpf_zero_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.LPF_Config_0.prbs_reserved_storage_t\ is record + value : std_logic_vector(5 downto 0); + end record; + + type \msk_top_regs.LPF_Config_0.lpf_alpha_storage_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.LPF_Config_0_storage_t\ is record + lpf_freeze : \msk_top_regs.LPF_Config_0.lpf_freeze_storage_t\; + lpf_zero : \msk_top_regs.LPF_Config_0.lpf_zero_storage_t\; + prbs_reserved : \msk_top_regs.LPF_Config_0.prbs_reserved_storage_t\; + lpf_alpha : \msk_top_regs.LPF_Config_0.lpf_alpha_storage_t\; + end record; + + type \msk_top_regs.LPF_Config_1.i_gain_storage_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.LPF_Config_1.i_shift_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.LPF_Config_1_storage_t\ is record + i_gain : \msk_top_regs.LPF_Config_1.i_gain_storage_t\; + i_shift : \msk_top_regs.LPF_Config_1.i_shift_storage_t\; + end record; + + type \msk_top_regs.Tx_Data_Width.data_width_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.Tx_Data_Width_storage_t\ is record + data_width : \msk_top_regs.Tx_Data_Width.data_width_storage_t\; + end record; + + type \msk_top_regs.Rx_Data_Width.data_width_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.Rx_Data_Width_storage_t\ is record + data_width : \msk_top_regs.Rx_Data_Width.data_width_storage_t\; + end record; + + type \msk_top_regs.PRBS_Control.prbs_sel_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_error_insert_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_clear_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_manual_sync_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.PRBS_Control.prbs_reserved_storage_t\ is record + value : std_logic_vector(11 downto 0); + end record; + + type \msk_top_regs.PRBS_Control.prbs_sync_threshold_storage_t\ is record + value : std_logic_vector(15 downto 0); + end record; + + type \msk_top_regs.PRBS_Control_storage_t\ is record + prbs_sel : \msk_top_regs.PRBS_Control.prbs_sel_storage_t\; + prbs_error_insert : \msk_top_regs.PRBS_Control.prbs_error_insert_storage_t\; + prbs_clear : \msk_top_regs.PRBS_Control.prbs_clear_storage_t\; + prbs_manual_sync : \msk_top_regs.PRBS_Control.prbs_manual_sync_storage_t\; + prbs_reserved : \msk_top_regs.PRBS_Control.prbs_reserved_storage_t\; + prbs_sync_threshold : \msk_top_regs.PRBS_Control.prbs_sync_threshold_storage_t\; + end record; + + type \msk_top_regs.PRBS_Initial_State.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.PRBS_Initial_State_storage_t\ is record + config_data : \msk_top_regs.PRBS_Initial_State.config_data_storage_t\; + end record; + + type \msk_top_regs.PRBS_Polynomial.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.PRBS_Polynomial_storage_t\ is record + config_data : \msk_top_regs.PRBS_Polynomial.config_data_storage_t\; + end record; + + type \msk_top_regs.PRBS_Error_Mask.config_data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.PRBS_Error_Mask_storage_t\ is record + config_data : \msk_top_regs.PRBS_Error_Mask.config_data_storage_t\; + end record; + + type \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.Rx_Sample_Discard.rx_nco_discard_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.Rx_Sample_Discard_storage_t\ is record + rx_sample_discard : \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_storage_t\; + rx_nco_discard : \msk_top_regs.Rx_Sample_Discard.rx_nco_discard_storage_t\; + end record; + + type \msk_top_regs.LPF_Config_2.p_gain_storage_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.LPF_Config_2.p_shift_storage_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.LPF_Config_2_storage_t\ is record + p_gain : \msk_top_regs.LPF_Config_2.p_gain_storage_t\; + p_shift : \msk_top_regs.LPF_Config_2.p_shift_storage_t\; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_force_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.Tx_Sync_Ctrl_storage_t\ is record + tx_sync_ena : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_storage_t\; + tx_sync_force : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_force_storage_t\; + tx_sync_f1 : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1_storage_t\; + tx_sync_f2 : \msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2_storage_t\; + end record; + + type \msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt_storage_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.Tx_Sync_Cnt_storage_t\ is record + tx_sync_cnt : \msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt_storage_t\; + end record; + + type \msk_top_regs.lowpass_ema_alpha1.alpha_storage_t\ is record + value : std_logic_vector(17 downto 0); + end record; + + type \msk_top_regs.lowpass_ema_alpha1_storage_t\ is record + alpha : \msk_top_regs.lowpass_ema_alpha1.alpha_storage_t\; + end record; + + type \msk_top_regs.lowpass_ema_alpha2.alpha_storage_t\ is record + value : std_logic_vector(17 downto 0); + end record; + + type \msk_top_regs.lowpass_ema_alpha2_storage_t\ is record + alpha : \msk_top_regs.lowpass_ema_alpha2.alpha_storage_t\; + end record; + + type field_storage_t is record + MSK_Init : \msk_top_regs.MSK_Init_storage_t\; + MSK_Control : \msk_top_regs.MSK_Control_storage_t\; + Fb_FreqWord : \msk_top_regs.Fb_FreqWord_storage_t\; + TX_F1_FreqWord : \msk_top_regs.TX_F1_FreqWord_storage_t\; + TX_F2_FreqWord : \msk_top_regs.TX_F2_FreqWord_storage_t\; + RX_F1_FreqWord : \msk_top_regs.RX_F1_FreqWord_storage_t\; + RX_F2_FreqWord : \msk_top_regs.RX_F2_FreqWord_storage_t\; + LPF_Config_0 : \msk_top_regs.LPF_Config_0_storage_t\; + LPF_Config_1 : \msk_top_regs.LPF_Config_1_storage_t\; + Tx_Data_Width : \msk_top_regs.Tx_Data_Width_storage_t\; + Rx_Data_Width : \msk_top_regs.Rx_Data_Width_storage_t\; + PRBS_Control : \msk_top_regs.PRBS_Control_storage_t\; + PRBS_Initial_State : \msk_top_regs.PRBS_Initial_State_storage_t\; + PRBS_Polynomial : \msk_top_regs.PRBS_Polynomial_storage_t\; + PRBS_Error_Mask : \msk_top_regs.PRBS_Error_Mask_storage_t\; + Rx_Sample_Discard : \msk_top_regs.Rx_Sample_Discard_storage_t\; + LPF_Config_2 : \msk_top_regs.LPF_Config_2_storage_t\; + Tx_Sync_Ctrl : \msk_top_regs.Tx_Sync_Ctrl_storage_t\; + Tx_Sync_Cnt : \msk_top_regs.Tx_Sync_Cnt_storage_t\; + lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha1_storage_t\; + lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha2_storage_t\; + end record; + signal field_storage : field_storage_t; + + ---------------------------------------------------------------------------- + -- Readback Signals + ---------------------------------------------------------------------------- + signal readback_err : std_logic; + signal readback_done : std_logic; + signal readback_data : std_logic_vector(31 downto 0); + signal readback_array : std_logic_vector_array1(0 to 35)(31 downto 0); + +begin + + ---------------------------------------------------------------------------- + -- CPU Bus interface + ---------------------------------------------------------------------------- + -- pragma translate_off + cpuif_generics: process begin + assert_bad_addr_width: assert s_axil_i.ARADDR'length >= MSK_TOP_REGS_MIN_ADDR_WIDTH + report "Interface address width of " & integer'image(s_axil_i.ARADDR'length) & " is too small. Shall be at least " & integer'image(MSK_TOP_REGS_MIN_ADDR_WIDTH) & " bits" + severity failure; + assert_bad_data_width: assert s_axil_i.WDATA'length = MSK_TOP_REGS_DATA_WIDTH + report "Interface data width of " & integer'image(s_axil_i.WDATA'length) & " is incorrect. Shall be " & integer'image(MSK_TOP_REGS_DATA_WIDTH) & " bits" + severity failure; + wait; + end process; + -- pragma translate_on + + + -- Max Outstanding Transactions: 2 + -- Transaction request acceptance + process(clk) begin + if false then -- async reset + axil_prev_was_rd <= '0'; + axil_arvalid <= '0'; + axil_araddr <= (others => '0'); + axil_awvalid <= '0'; + axil_awaddr <= (others => '0'); + axil_wvalid <= '0'; + axil_wdata <= (others => '0'); + axil_wstrb <= (others => '0'); + axil_n_in_flight <= (others => '0'); + elsif rising_edge(clk) then + if rst then -- sync reset + axil_prev_was_rd <= '0'; + axil_arvalid <= '0'; + axil_araddr <= (others => '0'); + axil_awvalid <= '0'; + axil_awaddr <= (others => '0'); + axil_wvalid <= '0'; + axil_wdata <= (others => '0'); + axil_wstrb <= (others => '0'); + axil_n_in_flight <= (others => '0'); + else + -- AR* acceptance register + if axil_ar_accept then + axil_prev_was_rd <= '1'; + axil_arvalid <= '0'; + end if; + if s_axil_i.ARVALID and s_axil_o.ARREADY then + axil_arvalid <= '1'; + axil_araddr <= s_axil_i.ARADDR; + end if; + + -- AW* & W* acceptance registers + if axil_aw_accept then + axil_prev_was_rd <= '0'; + axil_awvalid <= '0'; + axil_wvalid <= '0'; + end if; + if s_axil_i.AWVALID and s_axil_o.AWREADY then + axil_awvalid <= '1'; + axil_awaddr <= s_axil_i.AWADDR; + end if; + if s_axil_i.WVALID and s_axil_o.WREADY then + axil_wvalid <= '1'; + axil_wdata <= s_axil_i.WDATA; + axil_wstrb <= s_axil_i.WSTRB; + end if; + + -- Keep track of in-flight transactions + if (axil_ar_accept or axil_aw_accept) and not axil_resp_acked then + axil_n_in_flight <= axil_n_in_flight + 1; + elsif not (axil_ar_accept or axil_aw_accept) and axil_resp_acked then + axil_n_in_flight <= axil_n_in_flight - 1; + end if; + end if; + end if; + end process; + + process(all) begin + s_axil_o.ARREADY <= not axil_arvalid or axil_ar_accept; + s_axil_o.AWREADY <= not axil_awvalid or axil_aw_accept; + s_axil_o.WREADY <= not axil_wvalid or axil_aw_accept; + end process; + + -- Request dispatch + process(all) begin + cpuif_wr_data <= axil_wdata; + for i in axil_wstrb'RANGE loop + cpuif_wr_biten(i*8 + 7 downto i*8) <= (others => axil_wstrb(i)); + end loop; + cpuif_req <= '0'; + cpuif_req_is_wr <= '0'; + cpuif_addr <= (others => '0'); + axil_ar_accept <= '0'; + axil_aw_accept <= '0'; + + if axil_n_in_flight < to_unsigned(2, 2) then + -- Can safely issue more transactions without overwhelming response buffer + if axil_arvalid and not axil_prev_was_rd then + cpuif_req <= '1'; + cpuif_req_is_wr <= '0'; + cpuif_addr <= (7 downto 2 => axil_araddr(7 downto 2), others => '0'); + if not cpuif_req_stall_rd then + axil_ar_accept <= '1'; + end if; + elsif axil_awvalid and axil_wvalid then + cpuif_req <= '1'; + cpuif_req_is_wr <= '1'; + cpuif_addr <= (7 downto 2 => axil_awaddr(7 downto 2), others => '0'); + if not cpuif_req_stall_wr then + axil_aw_accept <= '1'; + end if; + elsif axil_arvalid then + cpuif_req <= '1'; + cpuif_req_is_wr <= '0'; + cpuif_addr <= (7 downto 2 => axil_araddr(7 downto 2), others => '0'); + if not cpuif_req_stall_rd then + axil_ar_accept <= '1'; + end if; + end if; + end if; + end process; + -- AXI4-Lite Response Logic + process(clk) begin + if false then -- async reset + for i in axil_resp_buffer'RANGE loop + axil_resp_buffer(i).is_wr <= '0'; + axil_resp_buffer(i).err <= '0'; + axil_resp_buffer(i).rdata <= (others => '0'); + end loop; + axil_resp_wptr <= (others => '0'); + axil_resp_rptr <= (others => '0'); + elsif rising_edge(clk) then + if rst then -- sync reset + for i in axil_resp_buffer'RANGE loop + axil_resp_buffer(i).is_wr <= '0'; + axil_resp_buffer(i).err <= '0'; + axil_resp_buffer(i).rdata <= (others => '0'); + end loop; + axil_resp_wptr <= (others => '0'); + axil_resp_rptr <= (others => '0'); + else + -- Store responses in buffer until AXI response channel accepts them + if cpuif_rd_ack or cpuif_wr_ack then + if cpuif_rd_ack then + axil_resp_buffer(to_integer(axil_resp_wptr(0 downto 0))).is_wr <= '0'; + axil_resp_buffer(to_integer(axil_resp_wptr(0 downto 0))).err <= cpuif_rd_err; + axil_resp_buffer(to_integer(axil_resp_wptr(0 downto 0))).rdata <= cpuif_rd_data; + + elsif cpuif_wr_ack then + axil_resp_buffer(to_integer(axil_resp_wptr(0 downto 0))).is_wr <= '1'; + axil_resp_buffer(to_integer(axil_resp_wptr(0 downto 0))).err <= cpuif_wr_err; + end if; + axil_resp_wptr <= axil_resp_wptr + 1; + end if; + + -- Advance read pointer when acknowledged + if axil_resp_acked then + axil_resp_rptr <= axil_resp_rptr + 1; + end if; + end if; + end if; + end process; + + process(all) begin + axil_resp_acked <= '0'; + s_axil_o.BVALID <= '0'; + s_axil_o.RVALID <= '0'; + if axil_resp_rptr /= axil_resp_wptr then + if axil_resp_buffer(to_integer(axil_resp_rptr(0 downto 0))).is_wr then + s_axil_o.BVALID <= '1'; + if s_axil_i.BREADY then + axil_resp_acked <= '1'; + end if; + else + s_axil_o.RVALID <= '1'; + if s_axil_i.RREADY then + axil_resp_acked <= '1'; + end if; + end if; + end if; + + s_axil_o.RDATA <= axil_resp_buffer(to_integer(axil_resp_rptr(0 downto 0))).rdata; + if axil_resp_buffer(to_integer(axil_resp_rptr(0 downto 0))).err then + s_axil_o.BRESP <= "10"; + s_axil_o.RRESP <= "10"; + else + s_axil_o.BRESP <= "00"; + s_axil_o.RRESP <= "00"; + end if; + end process; + + -- Read & write latencies are balanced. Stalls not required + cpuif_req_stall_rd <= '0'; + cpuif_req_stall_wr <= '0'; + cpuif_req_masked <= cpuif_req + and not (not cpuif_req_is_wr and cpuif_req_stall_rd) + and not (cpuif_req_is_wr and cpuif_req_stall_wr); + + ---------------------------------------------------------------------------- + -- Address Decode + ---------------------------------------------------------------------------- + process(all) + -- overload "=" in this scope to avoid lots of type casts + function "="(L: std_logic_vector; R: integer) return std_logic is + variable result : std_logic; + begin + result := '1' when unsigned(L) = R else '0'; + return result; + end; + begin + decoded_reg_strb.Hash_ID_Low <= cpuif_req_masked and (cpuif_addr = 16#0#); + decoded_reg_strb.Hash_ID_High <= cpuif_req_masked and (cpuif_addr = 16#4#); + decoded_reg_strb.MSK_Init <= cpuif_req_masked and (cpuif_addr = 16#8#); + decoded_reg_strb.MSK_Control <= cpuif_req_masked and (cpuif_addr = 16#C#); + decoded_reg_strb.MSK_Status <= cpuif_req_masked and (cpuif_addr = 16#10#); + decoded_reg_strb.Tx_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#14#); + decoded_reg_strb.Tx_Enable_Count <= cpuif_req_masked and (cpuif_addr = 16#18#); + decoded_reg_strb.Fb_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#1C#); + decoded_reg_strb.TX_F1_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#20#); + decoded_reg_strb.TX_F2_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#24#); + decoded_reg_strb.RX_F1_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#28#); + decoded_reg_strb.RX_F2_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#2C#); + decoded_reg_strb.LPF_Config_0 <= cpuif_req_masked and (cpuif_addr = 16#30#); + decoded_reg_strb.LPF_Config_1 <= cpuif_req_masked and (cpuif_addr = 16#34#); + decoded_reg_strb.Tx_Data_Width <= cpuif_req_masked and (cpuif_addr = 16#38#); + decoded_reg_strb.Rx_Data_Width <= cpuif_req_masked and (cpuif_addr = 16#3C#); + decoded_reg_strb.PRBS_Control <= cpuif_req_masked and (cpuif_addr = 16#40#); + decoded_reg_strb.PRBS_Initial_State <= cpuif_req_masked and (cpuif_addr = 16#44#); + decoded_reg_strb.PRBS_Polynomial <= cpuif_req_masked and (cpuif_addr = 16#48#); + decoded_reg_strb.PRBS_Error_Mask <= cpuif_req_masked and (cpuif_addr = 16#4C#); + decoded_reg_strb.PRBS_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#50#); + decoded_reg_strb.PRBS_Error_Count <= cpuif_req_masked and (cpuif_addr = 16#54#); + decoded_reg_strb.LPF_Accum_F1 <= cpuif_req_masked and (cpuif_addr = 16#58#); + decoded_reg_strb.LPF_Accum_F2 <= cpuif_req_masked and (cpuif_addr = 16#5C#); + decoded_reg_strb.axis_xfer_count <= cpuif_req_masked and (cpuif_addr = 16#60#); + decoded_reg_strb.Rx_Sample_Discard <= cpuif_req_masked and (cpuif_addr = 16#64#); + decoded_reg_strb.LPF_Config_2 <= cpuif_req_masked and (cpuif_addr = 16#68#); + decoded_reg_strb.f1_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#6C#); + decoded_reg_strb.f2_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#70#); + decoded_reg_strb.f1_error <= cpuif_req_masked and (cpuif_addr = 16#74#); + decoded_reg_strb.f2_error <= cpuif_req_masked and (cpuif_addr = 16#78#); + decoded_reg_strb.Tx_Sync_Ctrl <= cpuif_req_masked and (cpuif_addr = 16#7C#); + decoded_reg_strb.Tx_Sync_Cnt <= cpuif_req_masked and (cpuif_addr = 16#80#); + decoded_reg_strb.lowpass_ema_alpha1 <= cpuif_req_masked and (cpuif_addr = 16#84#); + decoded_reg_strb.lowpass_ema_alpha2 <= cpuif_req_masked and (cpuif_addr = 16#88#); + decoded_reg_strb.rx_power <= cpuif_req_masked and (cpuif_addr = 16#8C#); + end process; + + -- Pass down signals to next stage + process(all) begin + decoded_req <= cpuif_req_masked; + decoded_req_is_wr <= cpuif_req_is_wr; + decoded_wr_data <= cpuif_wr_data; + decoded_wr_biten <= cpuif_wr_biten; + end process; + + ---------------------------------------------------------------------------- + -- Field logic + ---------------------------------------------------------------------------- + + -- Field: msk_top_regs.MSK_Init.txrxinit + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Init.txrxinit.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Init and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Init.txrxinit.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + end if; + field_combo.MSK_Init.txrxinit.next_q <= next_c; + field_combo.MSK_Init.txrxinit.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Init.txrxinit.value <= '1'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Init.txrxinit.value <= '1'; + else + if field_combo.MSK_Init.txrxinit.load_next then + field_storage.MSK_Init.txrxinit.value <= field_combo.MSK_Init.txrxinit.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Init.txrxinit.value <= field_storage.MSK_Init.txrxinit.value; + + -- Field: msk_top_regs.MSK_Init.txinit + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Init.txinit.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Init and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Init.txinit.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + end if; + field_combo.MSK_Init.txinit.next_q <= next_c; + field_combo.MSK_Init.txinit.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Init.txinit.value <= '1'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Init.txinit.value <= '1'; + else + if field_combo.MSK_Init.txinit.load_next then + field_storage.MSK_Init.txinit.value <= field_combo.MSK_Init.txinit.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Init.txinit.value <= field_storage.MSK_Init.txinit.value; + + -- Field: msk_top_regs.MSK_Init.rxinit + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Init.rxinit.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Init and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Init.rxinit.value and not decoded_wr_biten(2)) or (decoded_wr_data(2) and decoded_wr_biten(2)); + load_next_c := '1'; + end if; + field_combo.MSK_Init.rxinit.next_q <= next_c; + field_combo.MSK_Init.rxinit.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Init.rxinit.value <= '1'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Init.rxinit.value <= '1'; + else + if field_combo.MSK_Init.rxinit.load_next then + field_storage.MSK_Init.rxinit.value <= field_combo.MSK_Init.rxinit.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Init.rxinit.value <= field_storage.MSK_Init.rxinit.value; + + -- Field: msk_top_regs.MSK_Control.ptt + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Control.ptt.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Control.ptt.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + end if; + field_combo.MSK_Control.ptt.next_q <= next_c; + field_combo.MSK_Control.ptt.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Control.ptt.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Control.ptt.value <= '0'; + else + if field_combo.MSK_Control.ptt.load_next then + field_storage.MSK_Control.ptt.value <= field_combo.MSK_Control.ptt.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Control.ptt.value <= field_storage.MSK_Control.ptt.value; + + -- Field: msk_top_regs.MSK_Control.loopback_ena + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Control.loopback_ena.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Control.loopback_ena.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + end if; + field_combo.MSK_Control.loopback_ena.next_q <= next_c; + field_combo.MSK_Control.loopback_ena.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Control.loopback_ena.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Control.loopback_ena.value <= '0'; + else + if field_combo.MSK_Control.loopback_ena.load_next then + field_storage.MSK_Control.loopback_ena.value <= field_combo.MSK_Control.loopback_ena.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Control.loopback_ena.value <= field_storage.MSK_Control.loopback_ena.value; + + -- Field: msk_top_regs.MSK_Control.rx_invert + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Control.rx_invert.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Control.rx_invert.value and not decoded_wr_biten(2)) or (decoded_wr_data(2) and decoded_wr_biten(2)); + load_next_c := '1'; + end if; + field_combo.MSK_Control.rx_invert.next_q <= next_c; + field_combo.MSK_Control.rx_invert.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Control.rx_invert.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Control.rx_invert.value <= '0'; + else + if field_combo.MSK_Control.rx_invert.load_next then + field_storage.MSK_Control.rx_invert.value <= field_combo.MSK_Control.rx_invert.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Control.rx_invert.value <= field_storage.MSK_Control.rx_invert.value; + + -- Field: msk_top_regs.MSK_Control.clear_counts + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Control.clear_counts.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Control.clear_counts.value and not decoded_wr_biten(3)) or (decoded_wr_data(3) and decoded_wr_biten(3)); + load_next_c := '1'; + else -- singlepulse clears back to 0 + next_c := '0'; + load_next_c := '1'; + end if; + field_combo.MSK_Control.clear_counts.next_q <= next_c; + field_combo.MSK_Control.clear_counts.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Control.clear_counts.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Control.clear_counts.value <= '0'; + else + if field_combo.MSK_Control.clear_counts.load_next then + field_storage.MSK_Control.clear_counts.value <= field_combo.MSK_Control.clear_counts.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Control.clear_counts.value <= field_storage.MSK_Control.clear_counts.value; + + -- Field: msk_top_regs.MSK_Control.diff_encoder_loopback + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.MSK_Control.diff_encoder_loopback.value; + load_next_c := '0'; + if decoded_reg_strb.MSK_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.MSK_Control.diff_encoder_loopback.value and not decoded_wr_biten(4)) or (decoded_wr_data(4) and decoded_wr_biten(4)); + load_next_c := '1'; + end if; + field_combo.MSK_Control.diff_encoder_loopback.next_q <= next_c; + field_combo.MSK_Control.diff_encoder_loopback.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.MSK_Control.diff_encoder_loopback.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.MSK_Control.diff_encoder_loopback.value <= '0'; + else + if field_combo.MSK_Control.diff_encoder_loopback.load_next then + field_storage.MSK_Control.diff_encoder_loopback.value <= field_combo.MSK_Control.diff_encoder_loopback.next_q; + end if; + end if; + end if; + end process; + hwif_out.MSK_Control.diff_encoder_loopback.value <= field_storage.MSK_Control.diff_encoder_loopback.value; + + -- Field: msk_top_regs.Fb_FreqWord.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Fb_FreqWord.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.Fb_FreqWord and decoded_req_is_wr then -- SW write + next_c := (field_storage.Fb_FreqWord.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.Fb_FreqWord.config_data.next_q <= next_c; + field_combo.Fb_FreqWord.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Fb_FreqWord.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Fb_FreqWord.config_data.value <= 32x"0"; + else + if field_combo.Fb_FreqWord.config_data.load_next then + field_storage.Fb_FreqWord.config_data.value <= field_combo.Fb_FreqWord.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.Fb_FreqWord.config_data.value <= field_storage.Fb_FreqWord.config_data.value; + + -- Field: msk_top_regs.TX_F1_FreqWord.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.TX_F1_FreqWord.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.TX_F1_FreqWord and decoded_req_is_wr then -- SW write + next_c := (field_storage.TX_F1_FreqWord.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.TX_F1_FreqWord.config_data.next_q <= next_c; + field_combo.TX_F1_FreqWord.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.TX_F1_FreqWord.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.TX_F1_FreqWord.config_data.value <= 32x"0"; + else + if field_combo.TX_F1_FreqWord.config_data.load_next then + field_storage.TX_F1_FreqWord.config_data.value <= field_combo.TX_F1_FreqWord.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.TX_F1_FreqWord.config_data.value <= field_storage.TX_F1_FreqWord.config_data.value; + + -- Field: msk_top_regs.TX_F2_FreqWord.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.TX_F2_FreqWord.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.TX_F2_FreqWord and decoded_req_is_wr then -- SW write + next_c := (field_storage.TX_F2_FreqWord.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.TX_F2_FreqWord.config_data.next_q <= next_c; + field_combo.TX_F2_FreqWord.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.TX_F2_FreqWord.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.TX_F2_FreqWord.config_data.value <= 32x"0"; + else + if field_combo.TX_F2_FreqWord.config_data.load_next then + field_storage.TX_F2_FreqWord.config_data.value <= field_combo.TX_F2_FreqWord.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.TX_F2_FreqWord.config_data.value <= field_storage.TX_F2_FreqWord.config_data.value; + + -- Field: msk_top_regs.RX_F1_FreqWord.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.RX_F1_FreqWord.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.RX_F1_FreqWord and decoded_req_is_wr then -- SW write + next_c := (field_storage.RX_F1_FreqWord.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.RX_F1_FreqWord.config_data.next_q <= next_c; + field_combo.RX_F1_FreqWord.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.RX_F1_FreqWord.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.RX_F1_FreqWord.config_data.value <= 32x"0"; + else + if field_combo.RX_F1_FreqWord.config_data.load_next then + field_storage.RX_F1_FreqWord.config_data.value <= field_combo.RX_F1_FreqWord.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.RX_F1_FreqWord.config_data.value <= field_storage.RX_F1_FreqWord.config_data.value; + + -- Field: msk_top_regs.RX_F2_FreqWord.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.RX_F2_FreqWord.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.RX_F2_FreqWord and decoded_req_is_wr then -- SW write + next_c := (field_storage.RX_F2_FreqWord.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.RX_F2_FreqWord.config_data.next_q <= next_c; + field_combo.RX_F2_FreqWord.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.RX_F2_FreqWord.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.RX_F2_FreqWord.config_data.value <= 32x"0"; + else + if field_combo.RX_F2_FreqWord.config_data.load_next then + field_storage.RX_F2_FreqWord.config_data.value <= field_combo.RX_F2_FreqWord.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.RX_F2_FreqWord.config_data.value <= field_storage.RX_F2_FreqWord.config_data.value; + + -- Field: msk_top_regs.LPF_Config_0.lpf_freeze + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_0.lpf_freeze.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_0 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_0.lpf_freeze.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_0.lpf_freeze.next_q <= next_c; + field_combo.LPF_Config_0.lpf_freeze.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_0.lpf_freeze.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_0.lpf_freeze.value <= '0'; + else + if field_combo.LPF_Config_0.lpf_freeze.load_next then + field_storage.LPF_Config_0.lpf_freeze.value <= field_combo.LPF_Config_0.lpf_freeze.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_0.lpf_freeze.value <= field_storage.LPF_Config_0.lpf_freeze.value; + + -- Field: msk_top_regs.LPF_Config_0.lpf_zero + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_0.lpf_zero.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_0 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_0.lpf_zero.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_0.lpf_zero.next_q <= next_c; + field_combo.LPF_Config_0.lpf_zero.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_0.lpf_zero.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_0.lpf_zero.value <= '0'; + else + if field_combo.LPF_Config_0.lpf_zero.load_next then + field_storage.LPF_Config_0.lpf_zero.value <= field_combo.LPF_Config_0.lpf_zero.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_0.lpf_zero.value <= field_storage.LPF_Config_0.lpf_zero.value; + + -- Field: msk_top_regs.LPF_Config_0.prbs_reserved + process(all) + variable next_c: std_logic_vector(5 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_0.prbs_reserved.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_0 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_0.prbs_reserved.value and not decoded_wr_biten(7 downto 2)) or (decoded_wr_data(7 downto 2) and decoded_wr_biten(7 downto 2)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_0.prbs_reserved.next_q <= next_c; + field_combo.LPF_Config_0.prbs_reserved.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_0.prbs_reserved.value <= 6x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_0.prbs_reserved.value <= 6x"0"; + else + if field_combo.LPF_Config_0.prbs_reserved.load_next then + field_storage.LPF_Config_0.prbs_reserved.value <= field_combo.LPF_Config_0.prbs_reserved.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_0.prbs_reserved.value <= field_storage.LPF_Config_0.prbs_reserved.value; + + -- Field: msk_top_regs.LPF_Config_0.lpf_alpha + process(all) + variable next_c: std_logic_vector(23 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_0.lpf_alpha.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_0 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_0.lpf_alpha.value and not decoded_wr_biten(31 downto 8)) or (decoded_wr_data(31 downto 8) and decoded_wr_biten(31 downto 8)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_0.lpf_alpha.next_q <= next_c; + field_combo.LPF_Config_0.lpf_alpha.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_0.lpf_alpha.value <= 24x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_0.lpf_alpha.value <= 24x"0"; + else + if field_combo.LPF_Config_0.lpf_alpha.load_next then + field_storage.LPF_Config_0.lpf_alpha.value <= field_combo.LPF_Config_0.lpf_alpha.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_0.lpf_alpha.value <= field_storage.LPF_Config_0.lpf_alpha.value; + + -- Field: msk_top_regs.LPF_Config_1.i_gain + process(all) + variable next_c: std_logic_vector(23 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_1.i_gain.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_1 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_1.i_gain.value and not decoded_wr_biten(23 downto 0)) or (decoded_wr_data(23 downto 0) and decoded_wr_biten(23 downto 0)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_1.i_gain.next_q <= next_c; + field_combo.LPF_Config_1.i_gain.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_1.i_gain.value <= 24x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_1.i_gain.value <= 24x"0"; + else + if field_combo.LPF_Config_1.i_gain.load_next then + field_storage.LPF_Config_1.i_gain.value <= field_combo.LPF_Config_1.i_gain.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_1.i_gain.value <= field_storage.LPF_Config_1.i_gain.value; + + -- Field: msk_top_regs.LPF_Config_1.i_shift + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_1.i_shift.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_1 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_1.i_shift.value and not decoded_wr_biten(31 downto 24)) or (decoded_wr_data(31 downto 24) and decoded_wr_biten(31 downto 24)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_1.i_shift.next_q <= next_c; + field_combo.LPF_Config_1.i_shift.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_1.i_shift.value <= 8x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_1.i_shift.value <= 8x"0"; + else + if field_combo.LPF_Config_1.i_shift.load_next then + field_storage.LPF_Config_1.i_shift.value <= field_combo.LPF_Config_1.i_shift.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_1.i_shift.value <= field_storage.LPF_Config_1.i_shift.value; + + -- Field: msk_top_regs.Tx_Data_Width.data_width + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Data_Width.data_width.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Data_Width and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Data_Width.data_width.value and not decoded_wr_biten(7 downto 0)) or (decoded_wr_data(7 downto 0) and decoded_wr_biten(7 downto 0)); + load_next_c := '1'; + end if; + field_combo.Tx_Data_Width.data_width.next_q <= next_c; + field_combo.Tx_Data_Width.data_width.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Data_Width.data_width.value <= 8x"8"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Data_Width.data_width.value <= 8x"8"; + else + if field_combo.Tx_Data_Width.data_width.load_next then + field_storage.Tx_Data_Width.data_width.value <= field_combo.Tx_Data_Width.data_width.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Data_Width.data_width.value <= field_storage.Tx_Data_Width.data_width.value; + + -- Field: msk_top_regs.Rx_Data_Width.data_width + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Rx_Data_Width.data_width.value; + load_next_c := '0'; + if decoded_reg_strb.Rx_Data_Width and decoded_req_is_wr then -- SW write + next_c := (field_storage.Rx_Data_Width.data_width.value and not decoded_wr_biten(7 downto 0)) or (decoded_wr_data(7 downto 0) and decoded_wr_biten(7 downto 0)); + load_next_c := '1'; + end if; + field_combo.Rx_Data_Width.data_width.next_q <= next_c; + field_combo.Rx_Data_Width.data_width.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Rx_Data_Width.data_width.value <= 8x"8"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Rx_Data_Width.data_width.value <= 8x"8"; + else + if field_combo.Rx_Data_Width.data_width.load_next then + field_storage.Rx_Data_Width.data_width.value <= field_combo.Rx_Data_Width.data_width.next_q; + end if; + end if; + end if; + end process; + hwif_out.Rx_Data_Width.data_width.value <= field_storage.Rx_Data_Width.data_width.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_sel + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_sel.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_sel.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_sel.next_q <= next_c; + field_combo.PRBS_Control.prbs_sel.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_sel.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_sel.value <= '0'; + else + if field_combo.PRBS_Control.prbs_sel.load_next then + field_storage.PRBS_Control.prbs_sel.value <= field_combo.PRBS_Control.prbs_sel.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_sel.value <= field_storage.PRBS_Control.prbs_sel.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_error_insert + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_error_insert.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_error_insert.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + else -- singlepulse clears back to 0 + next_c := '0'; + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_error_insert.next_q <= next_c; + field_combo.PRBS_Control.prbs_error_insert.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_error_insert.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_error_insert.value <= '0'; + else + if field_combo.PRBS_Control.prbs_error_insert.load_next then + field_storage.PRBS_Control.prbs_error_insert.value <= field_combo.PRBS_Control.prbs_error_insert.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_error_insert.value <= field_storage.PRBS_Control.prbs_error_insert.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_clear + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_clear.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_clear.value and not decoded_wr_biten(2)) or (decoded_wr_data(2) and decoded_wr_biten(2)); + load_next_c := '1'; + else -- singlepulse clears back to 0 + next_c := '0'; + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_clear.next_q <= next_c; + field_combo.PRBS_Control.prbs_clear.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_clear.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_clear.value <= '0'; + else + if field_combo.PRBS_Control.prbs_clear.load_next then + field_storage.PRBS_Control.prbs_clear.value <= field_combo.PRBS_Control.prbs_clear.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_clear.value <= field_storage.PRBS_Control.prbs_clear.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_manual_sync + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_manual_sync.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_manual_sync.value and not decoded_wr_biten(3)) or (decoded_wr_data(3) and decoded_wr_biten(3)); + load_next_c := '1'; + else -- singlepulse clears back to 0 + next_c := '0'; + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_manual_sync.next_q <= next_c; + field_combo.PRBS_Control.prbs_manual_sync.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_manual_sync.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_manual_sync.value <= '0'; + else + if field_combo.PRBS_Control.prbs_manual_sync.load_next then + field_storage.PRBS_Control.prbs_manual_sync.value <= field_combo.PRBS_Control.prbs_manual_sync.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_manual_sync.value <= field_storage.PRBS_Control.prbs_manual_sync.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_reserved + process(all) + variable next_c: std_logic_vector(11 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_reserved.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_reserved.value and not decoded_wr_biten(15 downto 4)) or (decoded_wr_data(15 downto 4) and decoded_wr_biten(15 downto 4)); + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_reserved.next_q <= next_c; + field_combo.PRBS_Control.prbs_reserved.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_reserved.value <= 12x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_reserved.value <= 12x"0"; + else + if field_combo.PRBS_Control.prbs_reserved.load_next then + field_storage.PRBS_Control.prbs_reserved.value <= field_combo.PRBS_Control.prbs_reserved.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_reserved.value <= field_storage.PRBS_Control.prbs_reserved.value; + + -- Field: msk_top_regs.PRBS_Control.prbs_sync_threshold + process(all) + variable next_c: std_logic_vector(15 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Control.prbs_sync_threshold.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Control and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Control.prbs_sync_threshold.value and not decoded_wr_biten(31 downto 16)) or (decoded_wr_data(31 downto 16) and decoded_wr_biten(31 downto 16)); + load_next_c := '1'; + end if; + field_combo.PRBS_Control.prbs_sync_threshold.next_q <= next_c; + field_combo.PRBS_Control.prbs_sync_threshold.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Control.prbs_sync_threshold.value <= 16x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Control.prbs_sync_threshold.value <= 16x"0"; + else + if field_combo.PRBS_Control.prbs_sync_threshold.load_next then + field_storage.PRBS_Control.prbs_sync_threshold.value <= field_combo.PRBS_Control.prbs_sync_threshold.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Control.prbs_sync_threshold.value <= field_storage.PRBS_Control.prbs_sync_threshold.value; + + -- Field: msk_top_regs.PRBS_Initial_State.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Initial_State.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Initial_State and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Initial_State.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.PRBS_Initial_State.config_data.next_q <= next_c; + field_combo.PRBS_Initial_State.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Initial_State.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Initial_State.config_data.value <= 32x"0"; + else + if field_combo.PRBS_Initial_State.config_data.load_next then + field_storage.PRBS_Initial_State.config_data.value <= field_combo.PRBS_Initial_State.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Initial_State.config_data.value <= field_storage.PRBS_Initial_State.config_data.value; + + -- Field: msk_top_regs.PRBS_Polynomial.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Polynomial.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Polynomial and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Polynomial.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.PRBS_Polynomial.config_data.next_q <= next_c; + field_combo.PRBS_Polynomial.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Polynomial.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Polynomial.config_data.value <= 32x"0"; + else + if field_combo.PRBS_Polynomial.config_data.load_next then + field_storage.PRBS_Polynomial.config_data.value <= field_combo.PRBS_Polynomial.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Polynomial.config_data.value <= field_storage.PRBS_Polynomial.config_data.value; + + -- Field: msk_top_regs.PRBS_Error_Mask.config_data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Error_Mask.config_data.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Error_Mask and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Error_Mask.config_data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + end if; + field_combo.PRBS_Error_Mask.config_data.next_q <= next_c; + field_combo.PRBS_Error_Mask.config_data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Error_Mask.config_data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Error_Mask.config_data.value <= 32x"0"; + else + if field_combo.PRBS_Error_Mask.config_data.load_next then + field_storage.PRBS_Error_Mask.config_data.value <= field_combo.PRBS_Error_Mask.config_data.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Error_Mask.config_data.value <= field_storage.PRBS_Error_Mask.config_data.value; + + -- Field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Rx_Sample_Discard.rx_sample_discard.value; + load_next_c := '0'; + if decoded_reg_strb.Rx_Sample_Discard and decoded_req_is_wr then -- SW write + next_c := (field_storage.Rx_Sample_Discard.rx_sample_discard.value and not decoded_wr_biten(7 downto 0)) or (decoded_wr_data(7 downto 0) and decoded_wr_biten(7 downto 0)); + load_next_c := '1'; + end if; + field_combo.Rx_Sample_Discard.rx_sample_discard.next_q <= next_c; + field_combo.Rx_Sample_Discard.rx_sample_discard.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Rx_Sample_Discard.rx_sample_discard.value <= 8x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Rx_Sample_Discard.rx_sample_discard.value <= 8x"0"; + else + if field_combo.Rx_Sample_Discard.rx_sample_discard.load_next then + field_storage.Rx_Sample_Discard.rx_sample_discard.value <= field_combo.Rx_Sample_Discard.rx_sample_discard.next_q; + end if; + end if; + end if; + end process; + hwif_out.Rx_Sample_Discard.rx_sample_discard.value <= field_storage.Rx_Sample_Discard.rx_sample_discard.value; + + -- Field: msk_top_regs.Rx_Sample_Discard.rx_nco_discard + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Rx_Sample_Discard.rx_nco_discard.value; + load_next_c := '0'; + if decoded_reg_strb.Rx_Sample_Discard and decoded_req_is_wr then -- SW write + next_c := (field_storage.Rx_Sample_Discard.rx_nco_discard.value and not decoded_wr_biten(15 downto 8)) or (decoded_wr_data(15 downto 8) and decoded_wr_biten(15 downto 8)); + load_next_c := '1'; + end if; + field_combo.Rx_Sample_Discard.rx_nco_discard.next_q <= next_c; + field_combo.Rx_Sample_Discard.rx_nco_discard.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Rx_Sample_Discard.rx_nco_discard.value <= 8x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Rx_Sample_Discard.rx_nco_discard.value <= 8x"0"; + else + if field_combo.Rx_Sample_Discard.rx_nco_discard.load_next then + field_storage.Rx_Sample_Discard.rx_nco_discard.value <= field_combo.Rx_Sample_Discard.rx_nco_discard.next_q; + end if; + end if; + end if; + end process; + hwif_out.Rx_Sample_Discard.rx_nco_discard.value <= field_storage.Rx_Sample_Discard.rx_nco_discard.value; + + -- Field: msk_top_regs.LPF_Config_2.p_gain + process(all) + variable next_c: std_logic_vector(23 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_2.p_gain.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_2 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_2.p_gain.value and not decoded_wr_biten(23 downto 0)) or (decoded_wr_data(23 downto 0) and decoded_wr_biten(23 downto 0)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_2.p_gain.next_q <= next_c; + field_combo.LPF_Config_2.p_gain.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_2.p_gain.value <= 24x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_2.p_gain.value <= 24x"0"; + else + if field_combo.LPF_Config_2.p_gain.load_next then + field_storage.LPF_Config_2.p_gain.value <= field_combo.LPF_Config_2.p_gain.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_2.p_gain.value <= field_storage.LPF_Config_2.p_gain.value; + + -- Field: msk_top_regs.LPF_Config_2.p_shift + process(all) + variable next_c: std_logic_vector(7 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Config_2.p_shift.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Config_2 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Config_2.p_shift.value and not decoded_wr_biten(31 downto 24)) or (decoded_wr_data(31 downto 24) and decoded_wr_biten(31 downto 24)); + load_next_c := '1'; + end if; + field_combo.LPF_Config_2.p_shift.next_q <= next_c; + field_combo.LPF_Config_2.p_shift.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Config_2.p_shift.value <= 8x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Config_2.p_shift.value <= 8x"0"; + else + if field_combo.LPF_Config_2.p_shift.load_next then + field_storage.LPF_Config_2.p_shift.value <= field_combo.LPF_Config_2.p_shift.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Config_2.p_shift.value <= field_storage.LPF_Config_2.p_shift.value; + + -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Sync_Ctrl.tx_sync_ena.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Sync_Ctrl and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Sync_Ctrl.tx_sync_ena.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + end if; + field_combo.Tx_Sync_Ctrl.tx_sync_ena.next_q <= next_c; + field_combo.Tx_Sync_Ctrl.tx_sync_ena.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Sync_Ctrl.tx_sync_ena.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Sync_Ctrl.tx_sync_ena.value <= '0'; + else + if field_combo.Tx_Sync_Ctrl.tx_sync_ena.load_next then + field_storage.Tx_Sync_Ctrl.tx_sync_ena.value <= field_combo.Tx_Sync_Ctrl.tx_sync_ena.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Sync_Ctrl.tx_sync_ena.value <= field_storage.Tx_Sync_Ctrl.tx_sync_ena.value; + + -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Sync_Ctrl.tx_sync_force.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Sync_Ctrl and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Sync_Ctrl.tx_sync_force.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + end if; + field_combo.Tx_Sync_Ctrl.tx_sync_force.next_q <= next_c; + field_combo.Tx_Sync_Ctrl.tx_sync_force.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Sync_Ctrl.tx_sync_force.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Sync_Ctrl.tx_sync_force.value <= '0'; + else + if field_combo.Tx_Sync_Ctrl.tx_sync_force.load_next then + field_storage.Tx_Sync_Ctrl.tx_sync_force.value <= field_combo.Tx_Sync_Ctrl.tx_sync_force.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Sync_Ctrl.tx_sync_force.value <= field_storage.Tx_Sync_Ctrl.tx_sync_force.value; + + -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1 + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Sync_Ctrl.tx_sync_f1.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Sync_Ctrl and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Sync_Ctrl.tx_sync_f1.value and not decoded_wr_biten(2)) or (decoded_wr_data(2) and decoded_wr_biten(2)); + load_next_c := '1'; + end if; + field_combo.Tx_Sync_Ctrl.tx_sync_f1.next_q <= next_c; + field_combo.Tx_Sync_Ctrl.tx_sync_f1.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Sync_Ctrl.tx_sync_f1.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Sync_Ctrl.tx_sync_f1.value <= '0'; + else + if field_combo.Tx_Sync_Ctrl.tx_sync_f1.load_next then + field_storage.Tx_Sync_Ctrl.tx_sync_f1.value <= field_combo.Tx_Sync_Ctrl.tx_sync_f1.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Sync_Ctrl.tx_sync_f1.value <= field_storage.Tx_Sync_Ctrl.tx_sync_f1.value; + + -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2 + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Sync_Ctrl.tx_sync_f2.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Sync_Ctrl and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Sync_Ctrl.tx_sync_f2.value and not decoded_wr_biten(3)) or (decoded_wr_data(3) and decoded_wr_biten(3)); + load_next_c := '1'; + end if; + field_combo.Tx_Sync_Ctrl.tx_sync_f2.next_q <= next_c; + field_combo.Tx_Sync_Ctrl.tx_sync_f2.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Sync_Ctrl.tx_sync_f2.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Sync_Ctrl.tx_sync_f2.value <= '0'; + else + if field_combo.Tx_Sync_Ctrl.tx_sync_f2.load_next then + field_storage.Tx_Sync_Ctrl.tx_sync_f2.value <= field_combo.Tx_Sync_Ctrl.tx_sync_f2.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Sync_Ctrl.tx_sync_f2.value <= field_storage.Tx_Sync_Ctrl.tx_sync_f2.value; + + -- Field: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt + process(all) + variable next_c: std_logic_vector(23 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Sync_Cnt.tx_sync_cnt.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Sync_Cnt and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Sync_Cnt.tx_sync_cnt.value and not decoded_wr_biten(23 downto 0)) or (decoded_wr_data(23 downto 0) and decoded_wr_biten(23 downto 0)); + load_next_c := '1'; + end if; + field_combo.Tx_Sync_Cnt.tx_sync_cnt.next_q <= next_c; + field_combo.Tx_Sync_Cnt.tx_sync_cnt.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Sync_Cnt.tx_sync_cnt.value <= 24x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Sync_Cnt.tx_sync_cnt.value <= 24x"0"; + else + if field_combo.Tx_Sync_Cnt.tx_sync_cnt.load_next then + field_storage.Tx_Sync_Cnt.tx_sync_cnt.value <= field_combo.Tx_Sync_Cnt.tx_sync_cnt.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Sync_Cnt.tx_sync_cnt.value <= field_storage.Tx_Sync_Cnt.tx_sync_cnt.value; + + -- Field: msk_top_regs.lowpass_ema_alpha1.alpha + process(all) + variable next_c: std_logic_vector(17 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.lowpass_ema_alpha1.alpha.value; + load_next_c := '0'; + if decoded_reg_strb.lowpass_ema_alpha1 and decoded_req_is_wr then -- SW write + next_c := (field_storage.lowpass_ema_alpha1.alpha.value and not decoded_wr_biten(17 downto 0)) or (decoded_wr_data(17 downto 0) and decoded_wr_biten(17 downto 0)); + load_next_c := '1'; + end if; + field_combo.lowpass_ema_alpha1.alpha.next_q <= next_c; + field_combo.lowpass_ema_alpha1.alpha.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.lowpass_ema_alpha1.alpha.value <= 18x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.lowpass_ema_alpha1.alpha.value <= 18x"0"; + else + if field_combo.lowpass_ema_alpha1.alpha.load_next then + field_storage.lowpass_ema_alpha1.alpha.value <= field_combo.lowpass_ema_alpha1.alpha.next_q; + end if; + end if; + end if; + end process; + hwif_out.lowpass_ema_alpha1.alpha.value <= field_storage.lowpass_ema_alpha1.alpha.value; + + -- Field: msk_top_regs.lowpass_ema_alpha2.alpha + process(all) + variable next_c: std_logic_vector(17 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.lowpass_ema_alpha2.alpha.value; + load_next_c := '0'; + if decoded_reg_strb.lowpass_ema_alpha2 and decoded_req_is_wr then -- SW write + next_c := (field_storage.lowpass_ema_alpha2.alpha.value and not decoded_wr_biten(17 downto 0)) or (decoded_wr_data(17 downto 0) and decoded_wr_biten(17 downto 0)); + load_next_c := '1'; + end if; + field_combo.lowpass_ema_alpha2.alpha.next_q <= next_c; + field_combo.lowpass_ema_alpha2.alpha.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.lowpass_ema_alpha2.alpha.value <= 18x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.lowpass_ema_alpha2.alpha.value <= 18x"0"; + else + if field_combo.lowpass_ema_alpha2.alpha.load_next then + field_storage.lowpass_ema_alpha2.alpha.value <= field_combo.lowpass_ema_alpha2.alpha.next_q; + end if; + end if; + end if; + end process; + hwif_out.lowpass_ema_alpha2.alpha.value <= field_storage.lowpass_ema_alpha2.alpha.value; + + ---------------------------------------------------------------------------- + -- Write response + ---------------------------------------------------------------------------- + cpuif_wr_ack <= decoded_req and decoded_req_is_wr; + -- Writes are always granted with no error response + cpuif_wr_err <= '0'; + + ---------------------------------------------------------------------------- + -- Readback + ---------------------------------------------------------------------------- + + -- Assign readback values to a flattened array + readback_array(0)(31 downto 0) <= 32x"AAAA5555" when (decoded_reg_strb.Hash_ID_Low and not decoded_req_is_wr) else (others => '0'); + readback_array(1)(31 downto 0) <= 32x"5555AAAA" when (decoded_reg_strb.Hash_ID_High and not decoded_req_is_wr) else (others => '0'); + readback_array(2)(0 downto 0) <= to_std_logic_vector(field_storage.MSK_Init.txrxinit.value) when (decoded_reg_strb.MSK_Init and not decoded_req_is_wr) else (others => '0'); + readback_array(2)(1 downto 1) <= to_std_logic_vector(field_storage.MSK_Init.txinit.value) when (decoded_reg_strb.MSK_Init and not decoded_req_is_wr) else (others => '0'); + readback_array(2)(2 downto 2) <= to_std_logic_vector(field_storage.MSK_Init.rxinit.value) when (decoded_reg_strb.MSK_Init and not decoded_req_is_wr) else (others => '0'); + readback_array(2)(31 downto 3) <= (others => '0'); + readback_array(3)(0 downto 0) <= to_std_logic_vector(field_storage.MSK_Control.ptt.value) when (decoded_reg_strb.MSK_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(3)(1 downto 1) <= to_std_logic_vector(field_storage.MSK_Control.loopback_ena.value) when (decoded_reg_strb.MSK_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(3)(2 downto 2) <= to_std_logic_vector(field_storage.MSK_Control.rx_invert.value) when (decoded_reg_strb.MSK_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(3)(3 downto 3) <= to_std_logic_vector(field_storage.MSK_Control.clear_counts.value) when (decoded_reg_strb.MSK_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(3)(4 downto 4) <= to_std_logic_vector(field_storage.MSK_Control.diff_encoder_loopback.value) when (decoded_reg_strb.MSK_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(3)(31 downto 5) <= (others => '0'); + readback_array(4)(0 downto 0) <= to_std_logic_vector(hwif_in.MSK_Status.demod_sync_lock.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); + readback_array(4)(1 downto 1) <= to_std_logic_vector(hwif_in.MSK_Status.tx_enable.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); + readback_array(4)(2 downto 2) <= to_std_logic_vector(hwif_in.MSK_Status.rx_enable.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); + readback_array(4)(3 downto 3) <= to_std_logic_vector(hwif_in.MSK_Status.tx_axis_valid.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); + readback_array(4)(31 downto 4) <= (others => '0'); + readback_array(5)(31 downto 0) <= hwif_in.Tx_Bit_Count.tx_bit_counter.next_q when (decoded_reg_strb.Tx_Bit_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(6)(31 downto 0) <= hwif_in.Tx_Enable_Count.tx_ena_counter.next_q when (decoded_reg_strb.Tx_Enable_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(7)(31 downto 0) <= field_storage.Fb_FreqWord.config_data.value when (decoded_reg_strb.Fb_FreqWord and not decoded_req_is_wr) else (others => '0'); + readback_array(8)(31 downto 0) <= field_storage.TX_F1_FreqWord.config_data.value when (decoded_reg_strb.TX_F1_FreqWord and not decoded_req_is_wr) else (others => '0'); + readback_array(9)(31 downto 0) <= field_storage.TX_F2_FreqWord.config_data.value when (decoded_reg_strb.TX_F2_FreqWord and not decoded_req_is_wr) else (others => '0'); + readback_array(10)(31 downto 0) <= field_storage.RX_F1_FreqWord.config_data.value when (decoded_reg_strb.RX_F1_FreqWord and not decoded_req_is_wr) else (others => '0'); + readback_array(11)(31 downto 0) <= field_storage.RX_F2_FreqWord.config_data.value when (decoded_reg_strb.RX_F2_FreqWord and not decoded_req_is_wr) else (others => '0'); + readback_array(12)(0 downto 0) <= to_std_logic_vector(field_storage.LPF_Config_0.lpf_freeze.value) when (decoded_reg_strb.LPF_Config_0 and not decoded_req_is_wr) else (others => '0'); + readback_array(12)(1 downto 1) <= to_std_logic_vector(field_storage.LPF_Config_0.lpf_zero.value) when (decoded_reg_strb.LPF_Config_0 and not decoded_req_is_wr) else (others => '0'); + readback_array(12)(7 downto 2) <= field_storage.LPF_Config_0.prbs_reserved.value when (decoded_reg_strb.LPF_Config_0 and not decoded_req_is_wr) else (others => '0'); + readback_array(12)(31 downto 8) <= field_storage.LPF_Config_0.lpf_alpha.value when (decoded_reg_strb.LPF_Config_0 and not decoded_req_is_wr) else (others => '0'); + readback_array(13)(23 downto 0) <= field_storage.LPF_Config_1.i_gain.value when (decoded_reg_strb.LPF_Config_1 and not decoded_req_is_wr) else (others => '0'); + readback_array(13)(31 downto 24) <= field_storage.LPF_Config_1.i_shift.value when (decoded_reg_strb.LPF_Config_1 and not decoded_req_is_wr) else (others => '0'); + readback_array(14)(7 downto 0) <= field_storage.Tx_Data_Width.data_width.value when (decoded_reg_strb.Tx_Data_Width and not decoded_req_is_wr) else (others => '0'); + readback_array(14)(31 downto 8) <= (others => '0'); + readback_array(15)(7 downto 0) <= field_storage.Rx_Data_Width.data_width.value when (decoded_reg_strb.Rx_Data_Width and not decoded_req_is_wr) else (others => '0'); + readback_array(15)(31 downto 8) <= (others => '0'); + readback_array(16)(0 downto 0) <= to_std_logic_vector(field_storage.PRBS_Control.prbs_sel.value) when (decoded_reg_strb.PRBS_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(16)(3 downto 1) <= (others => '0'); + readback_array(16)(15 downto 4) <= field_storage.PRBS_Control.prbs_reserved.value when (decoded_reg_strb.PRBS_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(16)(31 downto 16) <= field_storage.PRBS_Control.prbs_sync_threshold.value when (decoded_reg_strb.PRBS_Control and not decoded_req_is_wr) else (others => '0'); + readback_array(17)(31 downto 0) <= field_storage.PRBS_Initial_State.config_data.value when (decoded_reg_strb.PRBS_Initial_State and not decoded_req_is_wr) else (others => '0'); + readback_array(18)(31 downto 0) <= field_storage.PRBS_Polynomial.config_data.value when (decoded_reg_strb.PRBS_Polynomial and not decoded_req_is_wr) else (others => '0'); + readback_array(19)(31 downto 0) <= field_storage.PRBS_Error_Mask.config_data.value when (decoded_reg_strb.PRBS_Error_Mask and not decoded_req_is_wr) else (others => '0'); + readback_array(20)(31 downto 0) <= hwif_in.PRBS_Bit_Count.status_data.next_q when (decoded_reg_strb.PRBS_Bit_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(21)(31 downto 0) <= hwif_in.PRBS_Error_Count.status_data.next_q when (decoded_reg_strb.PRBS_Error_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(22)(31 downto 0) <= hwif_in.LPF_Accum_F1.status_data.next_q when (decoded_reg_strb.LPF_Accum_F1 and not decoded_req_is_wr) else (others => '0'); + readback_array(23)(31 downto 0) <= hwif_in.LPF_Accum_F2.status_data.next_q when (decoded_reg_strb.LPF_Accum_F2 and not decoded_req_is_wr) else (others => '0'); + readback_array(24)(31 downto 0) <= hwif_in.axis_xfer_count.xfer_count.next_q when (decoded_reg_strb.axis_xfer_count and not decoded_req_is_wr) else (others => '0'); + readback_array(25)(7 downto 0) <= field_storage.Rx_Sample_Discard.rx_sample_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); + readback_array(25)(15 downto 8) <= field_storage.Rx_Sample_Discard.rx_nco_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); + readback_array(25)(31 downto 16) <= (others => '0'); + readback_array(26)(23 downto 0) <= field_storage.LPF_Config_2.p_gain.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); + readback_array(26)(31 downto 24) <= field_storage.LPF_Config_2.p_shift.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); + readback_array(27)(31 downto 0) <= hwif_in.f1_nco_adjust.data.next_q when (decoded_reg_strb.f1_nco_adjust and not decoded_req_is_wr) else (others => '0'); + readback_array(28)(31 downto 0) <= hwif_in.f2_nco_adjust.data.next_q when (decoded_reg_strb.f2_nco_adjust and not decoded_req_is_wr) else (others => '0'); + readback_array(29)(31 downto 0) <= hwif_in.f1_error.data.next_q when (decoded_reg_strb.f1_error and not decoded_req_is_wr) else (others => '0'); + readback_array(30)(31 downto 0) <= hwif_in.f2_error.data.next_q when (decoded_reg_strb.f2_error and not decoded_req_is_wr) else (others => '0'); + readback_array(31)(0 downto 0) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_ena.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); + readback_array(31)(1 downto 1) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_force.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); + readback_array(31)(2 downto 2) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_f1.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); + readback_array(31)(3 downto 3) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_f2.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); + readback_array(31)(31 downto 4) <= (others => '0'); + readback_array(32)(23 downto 0) <= field_storage.Tx_Sync_Cnt.tx_sync_cnt.value when (decoded_reg_strb.Tx_Sync_Cnt and not decoded_req_is_wr) else (others => '0'); + readback_array(32)(31 downto 24) <= (others => '0'); + readback_array(33)(17 downto 0) <= field_storage.lowpass_ema_alpha1.alpha.value when (decoded_reg_strb.lowpass_ema_alpha1 and not decoded_req_is_wr) else (others => '0'); + readback_array(33)(31 downto 18) <= (others => '0'); + readback_array(34)(17 downto 0) <= field_storage.lowpass_ema_alpha2.alpha.value when (decoded_reg_strb.lowpass_ema_alpha2 and not decoded_req_is_wr) else (others => '0'); + readback_array(34)(31 downto 18) <= (others => '0'); + readback_array(35)(22 downto 0) <= hwif_in.rx_power.rx_power.next_q when (decoded_reg_strb.rx_power and not decoded_req_is_wr) else (others => '0'); + readback_array(35)(31 downto 23) <= (others => '0'); + + -- Reduce the array + process(all) + variable readback_data_var : std_logic_vector(31 downto 0) := (others => '0'); + begin + readback_done <= decoded_req and not decoded_req_is_wr; + readback_err <= '0'; + readback_data_var := (others => '0'); + for i in readback_array'RANGE loop + readback_data_var := readback_data_var or readback_array(i); + end loop; + readback_data <= readback_data_var; + end process; + + cpuif_rd_ack <= readback_done; + cpuif_rd_data <= readback_data; + cpuif_rd_err <= readback_err; +end architecture rtl; diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd new file mode 100644 index 0000000..a362018 --- /dev/null +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -0,0 +1,432 @@ +-- Generated by PeakRDL-regblock-vhdl - A free and open-source VHDL generator +-- https://github.com/SystemRDL/PeakRDL-regblock-vhdl +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.fixed_pkg.all; + +package msk_top_regs_pkg is + + constant MSK_TOP_REGS_DATA_WIDTH : positive := 32; + constant MSK_TOP_REGS_MIN_ADDR_WIDTH : positive := 8; + constant MSK_TOP_REGS_SIZE : positive := 144; + + type \msk_top_regs.msk_stat_0.demod_sync_lock_in_t\ is record + next_q : std_logic; + end record; + + type \msk_top_regs.msk_stat_0.tx_enable_in_t\ is record + next_q : std_logic; + end record; + + type \msk_top_regs.msk_stat_0.rx_enable_in_t\ is record + next_q : std_logic; + end record; + + type \msk_top_regs.msk_stat_0.tx_axis_valid_in_t\ is record + next_q : std_logic; + end record; + + type \msk_top_regs.msk_stat_0_in_t\ is record + demod_sync_lock : \msk_top_regs.msk_stat_0.demod_sync_lock_in_t\; + tx_enable : \msk_top_regs.msk_stat_0.tx_enable_in_t\; + rx_enable : \msk_top_regs.msk_stat_0.rx_enable_in_t\; + tx_axis_valid : \msk_top_regs.msk_stat_0.tx_axis_valid_in_t\; + end record; + + type \msk_top_regs.msk_stat_1.tx_bit_counter_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.msk_stat_1_in_t\ is record + tx_bit_counter : \msk_top_regs.msk_stat_1.tx_bit_counter_in_t\; + end record; + + type \msk_top_regs.msk_stat_2.tx_ena_counter_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.msk_stat_2_in_t\ is record + tx_ena_counter : \msk_top_regs.msk_stat_2.tx_ena_counter_in_t\; + end record; + + type \msk_top_regs.stat_32_bits.status_data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.stat_32_bits_in_t\ is record + status_data : \msk_top_regs.stat_32_bits.status_data_in_t\; + end record; + + type \msk_top_regs.stat_32_errs.status_data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.stat_32_errs_in_t\ is record + status_data : \msk_top_regs.stat_32_errs.status_data_in_t\; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.status_data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\ is record + status_data : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.status_data_in_t\; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.status_data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\ is record + status_data : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.status_data_in_t\; + end record; + + type \msk_top_regs.msk_stat_3.xfer_count_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.msk_stat_3_in_t\ is record + xfer_count : \msk_top_regs.msk_stat_3.xfer_count_in_t\; + end record; + + type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\ is record + data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\; + end record; + + type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\ is record + data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\; + end record; + + type \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\ is record + data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\; + end record; + + type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\ is record + next_q : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\ is record + data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\; + end record; + + type \msk_top_regs.rx_power.rx_power_in_t\ is record + next_q : std_logic_vector(22 downto 0); + end record; + + type \msk_top_regs.rx_power_in_t\ is record + rx_power : \msk_top_regs.rx_power.rx_power_in_t\; + end record; + + type msk_top_regs_in_t is record + MSK_Status : \msk_top_regs.msk_stat_0_in_t\; + Tx_Bit_Count : \msk_top_regs.msk_stat_1_in_t\; + Tx_Enable_Count : \msk_top_regs.msk_stat_2_in_t\; + PRBS_Bit_Count : \msk_top_regs.stat_32_bits_in_t\; + PRBS_Error_Count : \msk_top_regs.stat_32_errs_in_t\; + LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\; + LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\; + axis_xfer_count : \msk_top_regs.msk_stat_3_in_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\; + f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\; + f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\; + rx_power : \msk_top_regs.rx_power_in_t\; + end record; + + type \msk_top_regs.msk_init.txrxinit_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_init.txinit_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_init.rxinit_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_init_out_t\ is record + txrxinit : \msk_top_regs.msk_init.txrxinit_out_t\; + txinit : \msk_top_regs.msk_init.txinit_out_t\; + rxinit : \msk_top_regs.msk_init.rxinit_out_t\; + end record; + + type \msk_top_regs.msk_ctrl.ptt_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_ctrl.loopback_ena_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_ctrl.rx_invert_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_ctrl.clear_counts_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_ctrl.diff_encoder_loopback_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.msk_ctrl_out_t\ is record + ptt : \msk_top_regs.msk_ctrl.ptt_out_t\; + loopback_ena : \msk_top_regs.msk_ctrl.loopback_ena_out_t\; + rx_invert : \msk_top_regs.msk_ctrl.rx_invert_out_t\; + clear_counts : \msk_top_regs.msk_ctrl.clear_counts_out_t\; + diff_encoder_loopback : \msk_top_regs.msk_ctrl.diff_encoder_loopback_out_t\; + end record; + + type \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469_out_t\ is record + config_data : \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469.config_data_out_t\; + end record; + + type \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c_out_t\ is record + config_data : \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c.config_data_out_t\; + end record; + + type \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51_out_t\ is record + config_data : \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51.config_data_out_t\; + end record; + + type \msk_top_regs.config_nco_fw_desc_16fb48c8_name_8d01a20d.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_nco_fw_desc_16fb48c8_name_8d01a20d_out_t\ is record + config_data : \msk_top_regs.config_nco_fw_desc_16fb48c8_name_8d01a20d.config_data_out_t\; + end record; + + type \msk_top_regs.config_nco_fw_desc_43c0828f_name_bdc60ecf.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_nco_fw_desc_43c0828f_name_bdc60ecf_out_t\ is record + config_data : \msk_top_regs.config_nco_fw_desc_43c0828f_name_bdc60ecf.config_data_out_t\; + end record; + + type \msk_top_regs.lpf_config_0.lpf_freeze_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.lpf_config_0.lpf_zero_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.lpf_config_0.prbs_reserved_out_t\ is record + value : std_logic_vector(5 downto 0); + end record; + + type \msk_top_regs.lpf_config_0.lpf_alpha_out_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.lpf_config_0_out_t\ is record + lpf_freeze : \msk_top_regs.lpf_config_0.lpf_freeze_out_t\; + lpf_zero : \msk_top_regs.lpf_config_0.lpf_zero_out_t\; + prbs_reserved : \msk_top_regs.lpf_config_0.prbs_reserved_out_t\; + lpf_alpha : \msk_top_regs.lpf_config_0.lpf_alpha_out_t\; + end record; + + type \msk_top_regs.lpf_config_1.i_gain_out_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.lpf_config_1.i_shift_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.lpf_config_1_out_t\ is record + i_gain : \msk_top_regs.lpf_config_1.i_gain_out_t\; + i_shift : \msk_top_regs.lpf_config_1.i_shift_out_t\; + end record; + + type \msk_top_regs.data_width_desc_58c848dd_name_2fbd8eba.data_width_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.data_width_desc_58c848dd_name_2fbd8eba_out_t\ is record + data_width : \msk_top_regs.data_width_desc_58c848dd_name_2fbd8eba.data_width_out_t\; + end record; + + type \msk_top_regs.data_width_desc_6097df38_name_4609588b.data_width_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.data_width_desc_6097df38_name_4609588b_out_t\ is record + data_width : \msk_top_regs.data_width_desc_6097df38_name_4609588b.data_width_out_t\; + end record; + + type \msk_top_regs.prbs_ctrl.prbs_sel_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.prbs_ctrl.prbs_error_insert_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.prbs_ctrl.prbs_clear_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.prbs_ctrl.prbs_manual_sync_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.prbs_ctrl.prbs_reserved_out_t\ is record + value : std_logic_vector(11 downto 0); + end record; + + type \msk_top_regs.prbs_ctrl.prbs_sync_threshold_out_t\ is record + value : std_logic_vector(15 downto 0); + end record; + + type \msk_top_regs.prbs_ctrl_out_t\ is record + prbs_sel : \msk_top_regs.prbs_ctrl.prbs_sel_out_t\; + prbs_error_insert : \msk_top_regs.prbs_ctrl.prbs_error_insert_out_t\; + prbs_clear : \msk_top_regs.prbs_ctrl.prbs_clear_out_t\; + prbs_manual_sync : \msk_top_regs.prbs_ctrl.prbs_manual_sync_out_t\; + prbs_reserved : \msk_top_regs.prbs_ctrl.prbs_reserved_out_t\; + prbs_sync_threshold : \msk_top_regs.prbs_ctrl.prbs_sync_threshold_out_t\; + end record; + + type \msk_top_regs.config_prbs_seed.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_prbs_seed_out_t\ is record + config_data : \msk_top_regs.config_prbs_seed.config_data_out_t\; + end record; + + type \msk_top_regs.config_prbs_poly.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_prbs_poly_out_t\ is record + config_data : \msk_top_regs.config_prbs_poly.config_data_out_t\; + end record; + + type \msk_top_regs.config_prbs_errmask.config_data_out_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.config_prbs_errmask_out_t\ is record + config_data : \msk_top_regs.config_prbs_errmask.config_data_out_t\; + end record; + + type \msk_top_regs.rx_sample_discard.rx_sample_discard_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.rx_sample_discard.rx_nco_discard_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.rx_sample_discard_out_t\ is record + rx_sample_discard : \msk_top_regs.rx_sample_discard.rx_sample_discard_out_t\; + rx_nco_discard : \msk_top_regs.rx_sample_discard.rx_nco_discard_out_t\; + end record; + + type \msk_top_regs.lpf_config_2.p_gain_out_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.lpf_config_2.p_shift_out_t\ is record + value : std_logic_vector(7 downto 0); + end record; + + type \msk_top_regs.lpf_config_2_out_t\ is record + p_gain : \msk_top_regs.lpf_config_2.p_gain_out_t\; + p_shift : \msk_top_regs.lpf_config_2.p_shift_out_t\; + end record; + + type \msk_top_regs.tx_sync_ctrl.tx_sync_ena_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.tx_sync_ctrl.tx_sync_force_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.tx_sync_ctrl.tx_sync_f1_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.tx_sync_ctrl.tx_sync_f2_out_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.tx_sync_ctrl_out_t\ is record + tx_sync_ena : \msk_top_regs.tx_sync_ctrl.tx_sync_ena_out_t\; + tx_sync_force : \msk_top_regs.tx_sync_ctrl.tx_sync_force_out_t\; + tx_sync_f1 : \msk_top_regs.tx_sync_ctrl.tx_sync_f1_out_t\; + tx_sync_f2 : \msk_top_regs.tx_sync_ctrl.tx_sync_f2_out_t\; + end record; + + type \msk_top_regs.tx_sync_cnt.tx_sync_cnt_out_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.tx_sync_cnt_out_t\ is record + tx_sync_cnt : \msk_top_regs.tx_sync_cnt.tx_sync_cnt_out_t\; + end record; + + type \msk_top_regs.lowpass_ema_alpha.alpha_out_t\ is record + value : std_logic_vector(17 downto 0); + end record; + + type \msk_top_regs.lowpass_ema_alpha_out_t\ is record + alpha : \msk_top_regs.lowpass_ema_alpha.alpha_out_t\; + end record; + + type msk_top_regs_out_t is record + MSK_Init : \msk_top_regs.msk_init_out_t\; + MSK_Control : \msk_top_regs.msk_ctrl_out_t\; + Fb_FreqWord : \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469_out_t\; + TX_F1_FreqWord : \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c_out_t\; + TX_F2_FreqWord : \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51_out_t\; + RX_F1_FreqWord : \msk_top_regs.config_nco_fw_desc_16fb48c8_name_8d01a20d_out_t\; + RX_F2_FreqWord : \msk_top_regs.config_nco_fw_desc_43c0828f_name_bdc60ecf_out_t\; + LPF_Config_0 : \msk_top_regs.lpf_config_0_out_t\; + LPF_Config_1 : \msk_top_regs.lpf_config_1_out_t\; + Tx_Data_Width : \msk_top_regs.data_width_desc_58c848dd_name_2fbd8eba_out_t\; + Rx_Data_Width : \msk_top_regs.data_width_desc_6097df38_name_4609588b_out_t\; + PRBS_Control : \msk_top_regs.prbs_ctrl_out_t\; + PRBS_Initial_State : \msk_top_regs.config_prbs_seed_out_t\; + PRBS_Polynomial : \msk_top_regs.config_prbs_poly_out_t\; + PRBS_Error_Mask : \msk_top_regs.config_prbs_errmask_out_t\; + Rx_Sample_Discard : \msk_top_regs.rx_sample_discard_out_t\; + LPF_Config_2 : \msk_top_regs.lpf_config_2_out_t\; + Tx_Sync_Ctrl : \msk_top_regs.tx_sync_ctrl_out_t\; + Tx_Sync_Cnt : \msk_top_regs.tx_sync_cnt_out_t\; + lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha_out_t\; + lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha_out_t\; + end record; +end package; diff --git a/rdl/src/axi4lite_intf_pkg.vhd b/rdl/src/axi4lite_intf_pkg.vhd new file mode 100644 index 0000000..3cd73fc --- /dev/null +++ b/rdl/src/axi4lite_intf_pkg.vhd @@ -0,0 +1,42 @@ +library ieee; +context ieee.ieee_std_context; + +package axi4lite_intf_pkg is + + type axi4lite_slave_in_intf is record + AWVALID : std_logic; + AWADDR : std_logic_vector; + AWPROT : std_logic_vector(2 downto 0); + + WVALID : std_logic; + WDATA : std_logic_vector; + WSTRB : std_logic_vector; + + BREADY : std_logic; + + ARVALID : std_logic; + ARADDR : std_logic_vector; + ARPROT : std_logic_vector(2 downto 0); + + RREADY : std_logic; + end record axi4lite_slave_in_intf; + + type axi4lite_slave_out_intf is record + AWREADY : std_logic; + + WREADY : std_logic; + + BVALID : std_logic; + BRESP : std_logic_vector(1 downto 0); + + ARREADY : std_logic; + + RVALID : std_logic; + RDATA : std_logic_vector; + RRESP : std_logic_vector(1 downto 0); + end record axi4lite_slave_out_intf; + +end package axi4lite_intf_pkg; + +-- package body axi4lite_intf_pkg is +-- end package body axi4lite_intf_pkg; \ No newline at end of file diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl new file mode 100644 index 0000000..207c848 --- /dev/null +++ b/rdl/src/msk_top_regs.rdl @@ -0,0 +1,552 @@ +//---------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------- +// _______ ________ ______ +// __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +// _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +// / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +// \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +// /_/ +// ________ _____ _____ _____ _____ +// ____ _/_______ __________ /____(_)__ /_____ ____ /______ +// __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +// __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +// /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +// +//---------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------- +// +// Copyright 2024, 2025 by M. Wishek +// +//---------------------------------------------------------------------------------------------------- +// License +//---------------------------------------------------------------------------------------------------- +// +// This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +// +// You may redistribute and modify this source and make products using it under +// the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +// +// This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +// OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +// Please see the CERN-OHL-W v2 for applicable conditions. +// +// Source location: TBD +// +// As per CERN-OHL-W v2 section 4.1, should You produce hardware based on this +// source, You must maintain the Source Location visible on the external case of +// the products you make using this source. +// +//---------------------------------------------------------------------------------------------------- +// Block name and description +//---------------------------------------------------------------------------------------------------- +// +// SystemRDL register definitions for Pluto MSK modem +// +// Documentation location: TBD +// +//---------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------- + + +addrmap msk_top_regs { + + name="Pluto MSK Registers"; + desc="MSK Modem Configuration and Status Registers"; + lsb0; + default accesswidth = 32; + default regwidth = 32; + default sw = rw; + default hw = r; + + reg msk_hash_lo { + + name = "Pluto MSK FPGA Hash ID - Lower 32-bits"; + + default sw = r; + default hw = na; + + field { + name = "Hash ID Lower 32-bits"; + desc = "Lower 32-bits of Pluto MSK FPGA Hash ID"; + } hash_id_lo[31:0] = 0xAAAA5555; + }; + + reg msk_hash_hi { + + name = "Pluto MSK FPGA Hash ID - Upper 32-bits"; + + default sw = r; + default hw = na; + + field { + name = "Hash ID Upper 32-bits"; + desc = "Upper 32-bits of Pluto MSK FPGA Hash ID"; + } hash_id_hi[31:0] = 0x5555AAAA; + }; + + reg msk_init { + + name = "MSK Modem Initialization Control"; + desc = "Synchronous initialization of MSK Modem functions, does not affect configuration registers."; + + field { + name = "Tx/Rx Init Enable"; + desc = "0 -> Normal modem operation + 1 -> Initialize Tx and Rx"; + } txrxinit = 1; + + field { + name = "Tx Init Enable"; + desc = "0 -> Normal Tx operation + 1 -> Initialize Tx"; + } txinit = 1; + + field { + name = "Rx Init Enable"; + desc = "0 -> Normal Rx operation + 1 -> Initialize Rx"; + } rxinit = 1; + }; + + reg msk_ctrl { + + name = "MSK Modem Control"; + desc = "MSK Modem Configuration and Control"; + + field { + name = "Push-to-Talk Enable"; + desc = "0 -> PTT Disabled + 1 -> PTT Enabled"; + } ptt = 0; + field { + name = "Modem Digital Tx -> Rx Loopback Enable"; + desc = "0 -> Modem loopback disabled + 1 -> Modem loopback enabled"; + } loopback_ena = 0; + field { + name = "Rx Data Invert Enable"; + desc = "0 -> Rx data normal + 1 -> Rx data inverted"; + } rx_invert = 0; + field { + desc = "Clear Tx Bit Counter and Tx Enable Counter"; + name = "Clear Status Counters"; + singlepulse = true; + } clear_counts = 0; + field { + name = "Differential Encoder -> Decoder Loopback Enable"; + desc = "0 -> Differential Encoder -> Decoder loopback disabled + 1 -> Differential Encoder -> Decoder loopback enabled"; + } diff_encoder_loopback = 0; + }; + + reg msk_stat_0 { + name = "MSK Modem Status 0"; + desc = "Modem status bits"; + regwidth = 32; + field { + name = "Demodulator Sync Status"; + desc = "Demodulator Sync Status - not currently implemented"; + sw = r; + hw = w; + } demod_sync_lock = 0; + field { + name = "AD9363 DAC Interface Tx Enable Input Active"; + desc = "1 -> Data to DAC Enabled + 0 -> Data to DAC Disabled"; + sw = r; + hw = w; + } tx_enable=0; + field { + name = "AD9363 ADC Interface Rx Enable Input Active"; + desc = "1 -> Data from ADC Enabled + 0 -> Data from ADC Disabled"; + sw = r; + hw = w; + } rx_enable = 0; + field { + name = "Tx S_AXIS_VALID"; + desc = "1 -> S_AXIS_VALID Enabled + 0 -> S_AXIS_VALID Disabled"; + sw = r; + hw = w; + } tx_axis_valid = 0; + }; + + reg msk_stat_1 { + name = "MSK Modem Status 1"; + desc = "Modem status data"; + regwidth = 32; + field { + name = "Tx Bit Count"; + desc = "Count of data requests made by modem"; + sw = r; + hw = w; + } tx_bit_counter[31:0]; + }; + + reg msk_stat_2 { + name = "MSK Modem Status 2"; + desc = "Modem status data"; + regwidth = 32; + field { + desc = "Number of clocks on which Tx Enable is active"; + name = "Tx Enable Count"; + sw = r; + hw = w; + } tx_ena_counter[31:0] = 0; + }; + + reg config_nco_fw { + regwidth = 32; + field { + name = "Frequency Control Word"; + desc = "Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, + where Fn is the desired NCO frequency, and Fs is the NCO sample rate"; + } config_data[31:0] = 0; + }; + + reg rx_sample_discard { + name = "Rx Sample Discard"; + desc = "Configure samples discard operation for demodulator"; + regwidth = 32; + field { + desc = "Number of Rx samples to discard"; + name = "Rx Sample Discard Value"; + } rx_sample_discard[7:0] = 0; + field { + desc = "Number of NCO samples to discard"; + name = "Rx NCO Sample Discard Value"; + } rx_nco_discard[15:8] = 0; + }; + + reg lpf_config_0 { + name = "PI Controller Configuration and Low-pass Filter Configuration"; + desc = "Configure PI controller and low-pass filter"; + regwidth = 32; + field { + name = "Freeze the accumulator's current value"; + desc = "0 -> Normal operation + 1 -> Freeze current value"; + } lpf_freeze = 0; + field { + name = "Hold the PI Accumulator at zero"; + desc = "0 -> Normal operation + 1 -> Zero and hold accumulator"; + } lpf_zero = 0; + field { + name = "Reserved"; + } prbs_reserved[7:2] = 0; + field { + name = "Lowpass IIR filter alpha"; + desc = "Value controls the filter rolloff"; + } lpf_alpha[31:8] = 0; + }; + + reg lpf_config_1 { + name = "PI Controller Configuration Configuration Register 1"; + desc = "Configures PI Controller I-gain and divisor"; + regwidth = 32; + field { + name = "Integral Gain Value"; + desc = "Value m of 0-16,777,215 sets the integral multiplier"; + } i_gain[23:0] = 0; + field { + name = "Integral Gain Bit Shift"; + desc = "Value n of 0-32 sets the integral divisor as 2^-n"; + } i_shift[31:24] = 0; + }; + + reg lpf_config_2 { + name = "PI Controller Configuration Configuration Register 2"; + desc = "Configures PI Controller I-gain and divisor"; + regwidth = 32; + field { + name = "Proportional Gain Value"; + desc = "Value m of 0-16,777,215 sets the proportional multiplier"; + } p_gain[23:0] = 0; + field { + name = "Proportional Gain Bit Shift"; + desc = "Value n of 0-32 sets the proportional divisor as 2^-n"; + } p_shift[31:24] = 0; + }; + + reg data_width { + regwidth = 32; + field { + name = "Modem input/output data width"; + desc = "Set the data width of the modem input/output"; + } data_width[7:0] = 8; + }; + + reg prbs_ctrl { + name = "PRBS Control 0"; + desc = "Configures operation of the PRBS Generator and Monitor"; + regwidth = 32; + field { + name = "PRBS Data Select"; + desc = "0 -> Select Normal Tx Data + 1 -> Select PRBS Tx Data"; + } prbs_sel = 0; + field { + name = "PRBS Error Insert"; + desc = "0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) + 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)"; + sw = w; + hw = r; + singlepulse = true; + } prbs_error_insert = 0; + field { + name = "PRBS Clear Counters"; + desc = "0 -> 1 : Clear PRBS Counters + 1 -> 0 : Clear PRBS Counters"; + sw = w; + hw = r; + singlepulse = true; + } prbs_clear = 0; + field { + name = "PRBS Manual Sync"; + desc = "0 -> 1 : Synchronize PRBS monitor + 1 -> 0 : Synchronize PRBS monitor"; + sw = w; + hw = r; + singlepulse = true; + } prbs_manual_sync = 0; + field { + name = "Reserved"; + } prbs_reserved[15:4] = 0; + field { + name = "PRBS Auto Sync Threshold"; + desc = "0 : Auto Sync Disabled + N > 0 : Auto sync after N errors"; + } prbs_sync_threshold[31:16] = 0; + }; + + reg config_prbs_seed { + name = "PRBS Control 1"; + desc = "PRBS Initial State"; + regwidth = 32; + field { + name = "PRBS Seed"; + desc = "Sets the starting value of the PRBS generator"; + } config_data[31:0] = 0; + }; + + reg config_prbs_poly { + name = "PRBS Control 2"; + desc = "PRBS Polynomial"; + regwidth = 32; + field { + name = "PRBS Polynomial"; + desc = "Bit positions set to '1' indicate polynomial feedback positions"; + } config_data[31:0] = 0; + }; + + reg config_prbs_errmask { + name = "PRBS Control 3"; + desc = "PRBS Error Mask"; + regwidth = 32; + field { + name = "PRBS Error Mask"; + desc = "Bit positions set to '1' indicate bits that are inverted when a bit error is inserted"; + } config_data[31:0] = 0; + }; + + reg stat_32_bits { + name = "PRBS Status 0"; + desc = "PRBS Bits Received"; + regwidth = 32; + field { + name = "PRBS Bits Received"; + desc = "Number of bits received by the PRBS monitor since last + BER can be calculated as the ratio of received bits to errored-bits"; + sw = r; + hw = w; + } status_data[31:0] = 0; + }; + + reg stat_32_errs { + name = "PRBS Status 1"; + desc = "PRBS Bit Errors"; + regwidth = 32; + field { + name = "PRBS Bit Errors"; + desc = "Number of errored-bits received by the PRBS monitor since last sync + BER can be calculated as the ratio of received bits to errored-bits"; + sw = r; + hw = w; + } status_data[31:0] = 0; + }; + + reg stat_32_lpf_acc { + regwidth = 32; + field { + name = "PI Controller Accumulator Value"; + desc = "PI Controller Accumulator Value"; + sw = r; + hw = w; + } status_data[31:0] = 0; + }; + + reg msk_stat_3 { + name = "MSK Modem Status 3"; + desc = "Modem status data"; + regwidth = 32; + field { + desc = "Number completed S_AXIS transfers"; + name = "S_AXIS Transfers"; + sw = r; + hw = w; + } xfer_count[31:0] = 0; + }; + + reg tx_sync_ctrl { + name = "Transmitter Sync Control"; + desc = "Provides control bits for generation of transmitter synchronization patterns"; + regwidth = 32; + field { + name = "Tx Sync Enable"; + desc = "0 -> Disable sync transmission + 1 -> Enable sync transmission when PTT is asserted"; + } tx_sync_ena = 0; + field { + name = "Tx Sync Force"; + desc = "0 : Normal operation) + 1 : Transmit synchronization pattern)"; + } tx_sync_force = 0; + field { + name = "Tx F1 Sync Enable"; + desc = "Enables/Disables transmission of F1 tone for receiver synchronization + 0 : F1 tone transmission disabled + 1 : F1 tone transmission enabled + Both F1 and F2 can be enabled at the same time"; + } tx_sync_f1 = 0; + field { + name = "Tx F2 Sync Enable"; + desc = "Enables/Disables transmission of F2 tone for receiver synchronization + 0 : F2 tone transmission disabled + 1 : F2 tone transmission enabled + Both F1 and F2 can be enabled at the same time"; + } tx_sync_f2 = 0; + }; + + reg tx_sync_cnt { + name = "Transmitter Sync Duration"; + desc = "Sets the duration of the synchronization tones when enabled"; + regwidth = 32; + field { + name = "Tx sync duration"; + desc = "Value from 0x00_0000 to 0xFF_FFFF. + This value represents the number bit-times the synchronization + signal should be sent after PTT is asserted."; + sw = rw; + hw = r; + } tx_sync_cnt[23:0] = 0; + }; + + reg lowpass_ema_alpha { + name = "Exponential Moving Average Alpha"; + desc = "Sets the alpha for the EMA"; + regwidth = 32; + field { + name = "EMA alpha"; + desc = "Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha"; + } alpha[17:0] = 0; + }; + + reg rx_power { + name = "Receive Power"; + desc = "Receive power computed from I/Q ssamples"; + regwidth = 32; + field { + name = "Receive Power"; + desc = "Value that represent the RMS power of the incoming I;"; + sw = r; + hw = w; + } rx_power[22:0] = 0; + }; + + field data32 { + fieldwidth = 32; + sw = r; + hw = w; + }; + + reg observation_data { + regwidth = 32; + data32 data[31:0] = 0; + }; + + + msk_hash_lo Hash_ID_Low; + msk_hash_hi Hash_ID_High; + msk_init MSK_Init; + msk_ctrl MSK_Control; + msk_stat_0 MSK_Status; + msk_stat_1 Tx_Bit_Count; + msk_stat_2 Tx_Enable_Count; + config_nco_fw Fb_FreqWord; + Fb_FreqWord->desc = "Set Modem Data Rate"; + Fb_FreqWord->name = "Bitrate NCO Frequency Control Word"; + config_nco_fw TX_F1_FreqWord; + TX_F1_FreqWord->desc = "Set Modulator F1 Frequency"; + TX_F1_FreqWord->name = "Tx F1 NCO Frequency Control Word"; + config_nco_fw TX_F2_FreqWord; + TX_F2_FreqWord->desc = "Set Modulator F2 Frequency"; + TX_F2_FreqWord->name = "Tx F2 NCO Frequency Control Word"; + config_nco_fw RX_F1_FreqWord; + RX_F1_FreqWord->desc = "Set Demodulator F1 Frequency"; + RX_F1_FreqWord->name = "Rx F1 NCO Frequency Control Word"; + config_nco_fw RX_F2_FreqWord; + RX_F2_FreqWord->desc = "Set Demodulator F2 Frequency"; + RX_F2_FreqWord->name = "Rx F2 NCO Frequency Control Word"; + lpf_config_0 LPF_Config_0; + lpf_config_1 LPF_Config_1; + data_width Tx_Data_Width; + Tx_Data_Width->desc = "Set the parallel data width of the parallel-to-serial converter"; + Tx_Data_Width->name = "Modem Tx Input Data Width"; + data_width Rx_Data_Width; + Rx_Data_Width->desc = "Set the parallel data width of the serial-to-parallel converter"; + Rx_Data_Width->name = "Modem Rx Output Data Width"; + prbs_ctrl PRBS_Control; + config_prbs_seed PRBS_Initial_State; + config_prbs_poly PRBS_Polynomial; + config_prbs_errmask PRBS_Error_Mask; + stat_32_bits PRBS_Bit_Count; + stat_32_errs PRBS_Error_Count; + stat_32_lpf_acc LPF_Accum_F1; + LPF_Accum_F1->name = "F1 PI Controller Accumulator"; + LPF_Accum_F1->desc = "Value of the F1 PI Controller Accumulator"; + stat_32_lpf_acc LPF_Accum_F2; + LPF_Accum_F2->name = "F2 PI Controller Accumulator"; + LPF_Accum_F2->desc = "Value of the F2 PI Controller Accumulator"; + msk_stat_3 axis_xfer_count; + rx_sample_discard Rx_Sample_Discard; + lpf_config_2 LPF_Config_2; + observation_data f1_nco_adjust; + f1_nco_adjust->name = "F1 NCO Frequency Adjust"; + f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; + f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; + f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; + observation_data f2_nco_adjust; + f2_nco_adjust->name = "F2 NCO Frequency Adjust"; + f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; + f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; + f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; + observation_data f1_error; + f1_error->name = "F1 Error Value"; + f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; + f1_error.data->name = "F1 Error Value"; + f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; + observation_data f2_error; + f2_error->name = "F2 Error Value"; + f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; + f2_error.data->name = "F2 Error Value"; + f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period"; + tx_sync_ctrl Tx_Sync_Ctrl; + tx_sync_cnt Tx_Sync_Cnt; + lowpass_ema_alpha lowpass_ema_alpha1; + lowpass_ema_alpha lowpass_ema_alpha2; + rx_power rx_power; + +}; diff --git a/rdl/src/reg_utils.vhd b/rdl/src/reg_utils.vhd new file mode 100644 index 0000000..d1c1748 --- /dev/null +++ b/rdl/src/reg_utils.vhd @@ -0,0 +1,232 @@ +library ieee; +context ieee.ieee_std_context; +use ieee.fixed_pkg.all; + +-- Convenience types and utility functions used by the autogenerated regblock code +package reg_utils is + + type std_logic_array1 is array(natural range<>) of std_logic; + type std_logic_array2 is array(natural range<>, natural range<>) of std_logic; + type std_logic_array3 is array(natural range<>, natural range<>, natural range<>) of std_logic; + type std_logic_array4 is array(natural range<>, natural range<>, natural range<>, natural range<>) of std_logic; + type std_logic_array5 is array(natural range<>, natural range<>, natural range<>, natural range<>, natural range<>) of std_logic; + + type std_logic_vector_array1 is array(natural range<>) of std_logic_vector; + type std_logic_vector_array2 is array(natural range<>, natural range<>) of std_logic_vector; + type std_logic_vector_array3 is array(natural range<>, natural range<>, natural range<>) of std_logic_vector; + type std_logic_vector_array4 is array(natural range<>, natural range<>, natural range<>, natural range<>) of std_logic_vector; + type std_logic_vector_array5 is array(natural range<>, natural range<>, natural range<>, natural range<>, natural range<>) of std_logic_vector; + + -- reverse bits of the input vector + function bitswap(vec: in std_logic_vector) return std_logic_vector; + function bitswap(logic: in std_logic) return std_logic; + + -- Autogenerating VHDL when dealing with programmatically defined field widths + -- can be challenging, especially when doing arithmetic. These conversion functions + -- are overloaded with various input types, allow them to work regardless + -- of the input type or width. + function to_unsigned(vec: in std_logic_vector) return unsigned; + function to_unsigned(logic: in std_logic) return unsigned; + + function to_signed(vec: in std_logic_vector) return signed; + function to_signed(logic: in std_logic) return signed; + + function to_std_logic_vector(uns: in unsigned) return std_logic_vector; + function to_std_logic_vector(sgnd: in signed) return std_logic_vector; + function to_std_logic_vector(logic: in std_logic) return std_logic_vector; + -- std_logic_vector variant provided by ieee.std_logic_1164 + -- ufixed and sfixed variants are provided by ieee.fixed_pkg + + function from_std_logic_vector(vec: in std_logic_vector; slv: in std_logic_vector) return std_logic_vector; + function from_std_logic_vector(vec: in std_logic_vector; uns: in unsigned) return unsigned; + function from_std_logic_vector(vec: in std_logic_vector; sgnd: in signed) return signed; + function from_std_logic_vector(vec: in std_logic_vector; ufx: in ufixed) return ufixed; + function from_std_logic_vector(vec: in std_logic_vector; sfx: in sfixed) return sfixed; + + function to_std_logic(bool: in boolean) return std_logic; + function to_std_logic(logic: in std_logic) return std_logic; + function to_std_logic(vec: in std_logic_vector(0 downto 0)) return std_logic; + function to_std_logic(uns: in unsigned(0 downto 0)) return std_logic; + function to_std_logic(sgnd: in signed(0 downto 0)) return std_logic; + function to_std_logic(ufx: in ufixed(0 downto 0)) return std_logic; + function to_std_logic(sfx: in sfixed(0 downto 0)) return std_logic; + + function from_std_logic(logic: in std_logic; lg: in std_logic) return std_logic; + function from_std_logic(logic: in std_logic; uns: in unsigned) return unsigned; + function from_std_logic(logic: in std_logic; sgnd: in signed) return signed; + function from_std_logic(logic: in std_logic; ufx: in ufixed) return ufixed; + function from_std_logic(logic: in std_logic; sfx: in sfixed) return sfixed; + + -- reduction OR for tools with poor VHDL 2008 support + function or_reduce(vec: in std_logic_vector) return std_logic; + function or_reduce(logic: in std_logic) return std_logic; + +end package reg_utils; + +package body reg_utils is + + function bitswap(vec: in std_logic_vector) return std_logic_vector is + variable result: std_logic_vector(vec'RANGE); + alias swapped: std_logic_vector(vec'REVERSE_RANGE) is vec; + begin + for i in swapped'RANGE loop + result(i) := swapped(i); + end loop; + return result; + end function; + + function bitswap(logic: in std_logic) return std_logic is + begin + return logic; + end function; + + function to_unsigned(vec: in std_logic_vector) return unsigned is + begin + return unsigned(vec); + end function; + + function to_unsigned(logic: in std_logic) return unsigned is + variable result: unsigned(0 downto 0); + begin + result(0) := logic; + return result; + end function; + + function to_signed(vec: in std_logic_vector) return signed is + begin + return signed(vec); + end function; + + function to_signed(logic: in std_logic) return signed is + variable result: signed(0 downto 0); + begin + result(0) := logic; + return result; + end function; + + function to_std_logic_vector(uns: in unsigned) return std_logic_vector is + begin + return std_logic_vector(uns); + end function; + + function to_std_logic_vector(sgnd: in signed) return std_logic_vector is + begin + return std_logic_vector(sgnd); + end function; + + function to_std_logic_vector(logic: in std_logic) return std_logic_vector is + variable result: std_logic_vector(0 downto 0); + begin + result(0) := logic; + return result; + end function; + + + function from_std_logic_vector(vec: in std_logic_vector; slv: in std_logic_vector) return std_logic_vector is + begin + return vec; + end function; + + function from_std_logic_vector(vec: in std_logic_vector; uns: in unsigned) return unsigned is + begin + return unsigned(vec); + end function; + + function from_std_logic_vector(vec: in std_logic_vector; sgnd: in signed) return signed is + begin + return signed(vec); + end function; + + function from_std_logic_vector(vec: in std_logic_vector; ufx: in ufixed) return ufixed is + begin + return ufixed(vec); + end function; + + function from_std_logic_vector(vec: in std_logic_vector; sfx: in sfixed) return sfixed is + begin + return sfixed(vec); + end function; + + + function to_std_logic(bool: in boolean) return std_logic is + begin + if bool = TRUE then + return '1'; + else + return '0'; + end if; + end function; + + function to_std_logic(logic: in std_logic) return std_logic is + begin + return logic; + end function; + + function to_std_logic(vec: in std_logic_vector(0 downto 0)) return std_logic is + begin + return vec(0); + end function; + + function to_std_logic(uns: in unsigned(0 downto 0)) return std_logic is + begin + return uns(0); + end function; + + function to_std_logic(sgnd: in signed(0 downto 0)) return std_logic is + begin + return sgnd(0); + end function; + + function to_std_logic(ufx: in ufixed(0 downto 0)) return std_logic is + begin + return ufx(0); + end function; + + function to_std_logic(sfx: in sfixed(0 downto 0)) return std_logic is + begin + return sfx(0); + end function; + + + function from_std_logic(logic: in std_logic; lg: in std_logic) return std_logic is + begin + return logic; + end function; + + function from_std_logic(logic: in std_logic; uns: in unsigned) return unsigned is + begin + return to_unsigned(logic); + end function; + + function from_std_logic(logic: in std_logic; sgnd: in signed) return signed is + begin + return to_signed(logic); + end function; + + function from_std_logic(logic: in std_logic; ufx: in ufixed) return ufixed is + begin + return ufixed(to_unsigned(logic)); + end function; + + function from_std_logic(logic: in std_logic; sfx: in sfixed) return sfixed is + begin + return sfixed(to_signed(logic)); + end function; + + + function or_reduce(vec: in std_logic_vector) return std_logic is + variable result: std_logic; + begin + result := '0'; + for i in vec'RANGE loop + result := result or vec(i); + end loop; + return result; + end function; + + function or_reduce(logic: in std_logic) return std_logic is + begin + return logic; + end function; + +end package body; \ No newline at end of file diff --git a/rdl/src/regblock_udps.rdl b/rdl/src/regblock_udps.rdl new file mode 100644 index 0000000..eafdc5a --- /dev/null +++ b/rdl/src/regblock_udps.rdl @@ -0,0 +1,54 @@ +/* + * This file defines several property extensions that are understood by the + * PeakRDL-Regblock-vhdl code generator. + * + * Compile this file prior to your other SystemRDL sources. + * + * For more details, see: https://peakrdl-regblock-vhdl.readthedocs.io/en/latest/udps/intro.html + */ + +property buffer_reads { + component = reg; + type = boolean; +}; + +property rbuffer_trigger { + component = reg; + type = ref; +}; + +property buffer_writes { + component = reg; + type = boolean; +}; + +property wbuffer_trigger { + component = reg; + type = ref; +}; + +property rd_swacc { + component = field; + type = boolean; +}; + +property wr_swacc { + component = field; + type = boolean; +}; + +property is_signed { + type = boolean; + component = field; + default = true; +}; + +property intwidth { + type = longint unsigned; + component = field; +}; + +property fracwidth { + type = longint unsigned; + component = field; +}; diff --git a/sim/Makefile b/sim/Makefile index ea1aa80..d983c1c 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -17,16 +17,17 @@ ifeq ($(SIM),nvc) endif SRC = ../src -RDL = ../rdl/vhdl/msk_top_regs - -VHDL_SOURCES_desyrdl = ../rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd - -VHDL_LIB_ORDER = desyrdl +RDL = ../rdl/ # use VHDL_SOURCES for VHDL files -VHDL_SOURCES += $(RDL)/msk_top_regs_decoder_axi4l.vhd \ - $(RDL)/pkg_msk_top_regs.vhd \ - $(RDL)/msk_top_regs.vhd \ +VHDL_SOURCES += $(RDL)/src/axi4lite_intf_pkg.vhd \ + $(RDL)/src/reg_utils.vhd \ + $(RDL)/outputs/rtl/msk_top_regs_pkg.vhd \ + $(RDL)/outputs/rtl/msk_top_regs.vhd \ + $(SRC)/cdc_resync.vhd \ + $(SRC)/axis_async_fifo.vhd \ + $(SRC)/axis_dma_adapter.vhd \ + $(SRC)/byte_to_bit_deserializer.vhd \ $(SRC)/msk_top_csr.vhd \ ../lowpass_ema/src/lowpass_ema.vhd \ ../power_detector/src/power_detector.vhd \ diff --git a/sim/desyrdl b/sim/desyrdl deleted file mode 120000 index 3ef65d1..0000000 --- a/sim/desyrdl +++ /dev/null @@ -1 +0,0 @@ -../rdl/cocotb/desyrdl \ No newline at end of file diff --git a/sim/msk_test.py b/sim/msk_test.py index d3d02e5..04a6aa2 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -65,7 +65,8 @@ import sys import inspect -from desyrdl import addrmap_ch0 +from msk_top_regs.reg_model.msk_top_regs import msk_top_regs_cls +from msk_top_regs.lib import AsyncCallbackSet, AsyncCallbackSetLegacy #------------------------------------------------------------------------------------------------------ # __ __ ___ __ __ ___ __ __ @@ -259,7 +260,7 @@ async def write_dwords(self,addr, data): await self.write(addr, data[0]) - async def read(self, addr): + async def read(self, addr, width, accesswidth): await RisingEdge(self.aclk) @@ -287,8 +288,10 @@ async def read(self, addr): return self.rdata.value.integer - async def write(self, addr, data): + async def write(self, addr, width, accesswidth, data): + self.dut.s_axi_awvalid.value = 1 + self.dut.s_axi_wvalid.value = 1 self.awaddr.value = addr self.wdata.value = data self.wstrb.value = 15 @@ -296,9 +299,6 @@ async def write(self, addr, data): await RisingEdge(self.aclk) - self.dut.s_axi_awvalid.value = 1 - self.dut.s_axi_wvalid.value = 1 - while self.awready.value == 0 and self.wready.value == 0: await RisingEdge(self.aclk) @@ -497,7 +497,7 @@ async def generate_data(self): while self.sim_run: data = await self.gen() - print("Data: ", data) + self.dut._log.info("Data: %s", hex(data)) await self.saxis.send(data) self.dut._log.info("...prbs generator - done") @@ -670,7 +670,7 @@ async def msk_test_1(dut): print("Instantiate registers") axi = axi_bus(dut) - regs = addrmap_ch0.Addrmap(axi) + regs = msk_top_regs_cls(callbacks=AsyncCallbackSet(read_callback=axi.read, write_callback=axi.write)) tx_samples = [] tx_time = [] @@ -679,8 +679,8 @@ async def msk_test_1(dut): rx_sample_rate = tx_sample_rate / tx_rx_sample_ratio - tx_data_width = 32 - rx_data_width = 32 + tx_data_width = 8 + rx_data_width = 8 await cocotb.start(Clock(dut.clk, tx_sample_per, units="fs").start()) @@ -718,105 +718,45 @@ async def msk_test_1(dut): dut.rx_samples_I.value = 0 dut.rx_samples_Q.value = 0 - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") - - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Fb_FreqWord", br_fcw) - # await axi.write(20, int(f1 / sample_rate * 2.0**32)) # F1 frequency word - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "TX_F1_FreqWord", f1_fcw_tx) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "TX_F2_FreqWord", f2_fcw_tx) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "RX_F1_FreqWord", f1_fcw_rx) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "RX_F2_FreqWord", f2_fcw_rx) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Rx_Sample_Discard", (tx_rx_sample_ratio-1 << 8) + tx_rx_sample_ratio-1) - # await axi.write(28, (50 << 16) + 20) # p-gain / i-gain - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "LPF_Config_0", (lpf_alpha << 8)) - # await axi.write(32, (2 << 16)) # low-pass filter alpha - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "LPF_Config_1", (i_shift << 24) + i_gain) - # await axi.write(36, 8) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "LPF_Config_2", (p_shift << 24) + p_gain) - # await axi.write(36, 8) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Tx_Data_Width", tx_data_width) - # await axi.write(40, 8) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Rx_Data_Width", rx_data_width) - # await axi.write(44, 1) # Select PRBS data path - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "PRBS_Control", (autosync_threshold << 16) + 1) - # await axi.write(48, (1 << 31) + (1 << 28)) # Polynomial - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "PRBS_Polynomial", (1 << 30) + (1 << 27)) - # await axi.write(52, 65535) # initial state - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "PRBS_Initial_State", 0x8E7589FD) - # await axi.write(56, 1) # Error Mask - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "PRBS_Error_Mask", 1) - # await axi.write(60, 0) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "lowpass_ema_alpha1", 64) - # await axi.write(60, 0) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "lowpass_ema_alpha2", 64) - # await axi.write(60, 0) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Tx_Sync_Ctrl", 0b0001) - # await axi.write(60, 0) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "Tx_Sync_Cnt", 192) - # await axi.write(60, 0) - - - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") - #print("Hash ID: ", hex(hash_id)) - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") - #print("Hash ID: ", hex(hash_id)) - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") - #print("Hash ID: ", hex(hash_id)) - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") - #print("Hash ID: ", hex(hash_id)) - hash_id = await regs.read("msk_top_regs", "Hash_ID_Low") + hash_low = await regs.Hash_ID_Low.read() + hash_high = await regs.Hash_ID_High.read() + + await regs.Fb_FreqWord.write(br_fcw) + await regs.TX_F1_FreqWord.write(f1_fcw_tx) + await regs.TX_F2_FreqWord.write(f2_fcw_tx) + await regs.RX_F1_FreqWord.write(f1_fcw_rx) + await regs.RX_F2_FreqWord.write(f2_fcw_rx) + await regs.Rx_Sample_Discard.write((tx_rx_sample_ratio-1 << 8) + tx_rx_sample_ratio-1) + await regs.LPF_Config_0.write((lpf_alpha << 8)) + await regs.LPF_Config_1.write((i_shift << 24) + i_gain) + await regs.LPF_Config_2.write((p_shift << 24) + p_gain) + await regs.Tx_Data_Width.write(tx_data_width) + await regs.Rx_Data_Width.write(rx_data_width) + await regs.PRBS_Control.write((autosync_threshold << 16) + 1) + await regs.PRBS_Polynomial.write((1 << 30) + (1 << 27)) + await regs.PRBS_Initial_State.write(0x8E7589FD) + await regs.PRBS_Error_Mask.write(1) + await regs.lowpass_ema_alpha1.write(64) + await regs.lowpass_ema_alpha2.write(64) + await regs.Tx_Sync_Ctrl.write(0b0001) + await regs.Tx_Sync_Cnt.write(192) + + + hash_id = await regs.Hash_ID_Low.read() + hash_id = await regs.Hash_ID_Low.read() + hash_id = await regs.Hash_ID_Low.read() + hash_id = await regs.Hash_ID_Low.read() + hash_id = await regs.Hash_ID_Low.read() print("Hash ID Low: ", hex(hash_id)) - hash_id = await regs.read("msk_top_regs", "Hash_ID_High") + hash_id = await regs.Hash_ID_High.read() print("Hash ID High: ", hex(hash_id)) await Timer(100, units="ns") await RisingEdge(dut.clk) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "MSK_Init", 0) - dut.s_axi_wvalid.value = 1 - dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "MSK_Control", (diff_enc_loopback << 4) + (rx_invert <<2) + ptt) + await regs.MSK_Init.write(0) + await regs.MSK_Control.write((diff_enc_loopback << 4) + (rx_invert <<2) + ptt) await RisingEdge(dut.clk) @@ -830,8 +770,8 @@ async def msk_test_1(dut): await cocotb.start(msksim.rx_sample_capture()) await cocotb.start(ducsim.upconvert()) await cocotb.start(ddcsim.downconvert()) - #await cocotb.start(pn.generate_data()) - #await cocotb.start(pn.check_data()) + await cocotb.start(pn.generate_data()) + await cocotb.start(pn.check_data()) sim_time = get_sim_time("us") sim_start = sim_time @@ -861,11 +801,11 @@ async def msk_test_1(dut): # await regs.write("msk_top_regs", "PRBS_Control", data) if sim_time_d <= sim_start + 20000 and sim_time >= sim_start + 20000: - data = await regs.read("msk_top_regs", "PRBS_Control") + data = await regs.PRBS_Control.read() data = data | 0x2 dut.s_axi_wvalid.value = 1 dut.s_axi_awvalid.value = 1 - await regs.write("msk_top_regs", "PRBS_Control", data) + await regs.PRBS_Control.write(data) # if sim_time_d <= sim_start + 3000 and sim_time >= sim_start + 3000: # await pn.resync() @@ -885,13 +825,13 @@ async def msk_test_1(dut): sim_time_d = sim_time sim_time = get_sim_time("us") - data = await regs.read("msk_top_regs", "f1_nco_adjust") + data = await regs.f1_nco_adjust.read() print("F1 NCO Adjust: ", hex(data)) - data = await regs.read("msk_top_regs", "f2_nco_adjust") + data = await regs.f2_nco_adjust.read() print("F2 NCO Adjust: ", hex(data)) - data = await regs.read("msk_top_regs", "f1_error") + data = await regs.f1_error.read() print("F1 Error: ", hex(data)) - data = await regs.read("msk_top_regs", "f2_error") + data = await regs.f2_error.read() print("F2 Error: ", hex(data)) #data = await regs.read("msk_top_regs", "LPF_Accum_F1") # print("F1 Acc: ", hex(data)) @@ -929,9 +869,9 @@ async def msk_test_1(dut): # print("Ones: ", pn.ones_count) # print("Zeros: ", pn.zeros_count) - errs = await regs.read("msk_top_regs", "PRBS_Error_Count") + errs = await regs.PRBS_Error_Count.read() print("Bit errors: ", errs) - bits = await regs.read("msk_top_regs", "PRBS_Bit_Count") + bits = await regs.PRBS_Bit_Count.read() print("Bit count: ", bits) print("BER: ", (1.0*errs)/bits) diff --git a/sim/msk_top_nvc.gtkw b/sim/msk_top_nvc.gtkw index b0ef9ee..4c86d96 100644 --- a/sim/msk_top_nvc.gtkw +++ b/sim/msk_top_nvc.gtkw @@ -1,15 +1,15 @@ [*] [*] GTKWave Analyzer v3.4.0 (w)1999-2022 BSI -[*] Fri Oct 10 05:31:31 2025 +[*] Sun Oct 26 04:27:27 2025 [*] [dumpfile] "/Users/nonlinear/dev/pluto_msk/sim/msk_top.ghw" -[dumpfile_mtime] "Fri Oct 10 05:30:38 2025" -[dumpfile_size] 217869621 +[dumpfile_mtime] "Sun Oct 26 04:27:24 2025" +[dumpfile_size] 1112248 [savefile] "/Users/nonlinear/dev/pluto_msk/sim/msk_top_nvc.gtkw" [timestart] 0 [size] 1504 828 [pos] -1 -1 -*-42.987041 3950520428800 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +*-33.240414 190000000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [markername] AA [markername] BB [markername] CC @@ -42,6 +42,8 @@ [treeopen] msk_top.u_dem.u_f2. [treeopen] msk_top.u_mod. [treeopen] msk_top.u_msk_top_csr. +[treeopen] msk_top.u_msk_top_csr.u_msk_regs. +[treeopen] msk_top.u_msk_top_csr.u_msk_regs.field_storage.fb_freqword. [sst_width] 298 [signals_width] 383 [sst_expanded] 1 @@ -69,6 +71,9 @@ msk_top.u_mod.tx_sync_force @22 msk_top.u_mod.sync_counter[23:0] msk_top.u_mod.sync_counter_next[23:0] +msk_top.u_mod.freq_word_f1[31:0] +msk_top.u_mod.freq_word_f2[31:0] +msk_top.u_mod.freq_word_tclk[31:0] @200 - @22 @@ -366,7 +371,7 @@ msk_top.u_dem.rx_data -Differential Coder Loopback @c00200 -PRBS Generator -@29 +@28 msk_top.u_prbs_gen.clk msk_top.u_prbs_gen.data_in[0] msk_top.u_prbs_gen.data_out[0] @@ -375,11 +380,11 @@ msk_top.u_prbs_gen.error_arm msk_top.u_prbs_gen.error_insert msk_top.u_prbs_gen.error_insert_d msk_top.u_prbs_gen.init -@23 +@22 msk_top.u_prbs_gen.initial_state[30:0] msk_top.u_prbs_gen.lfsr[30:0] msk_top.u_prbs_gen.polynomial[30:0] -@29 +@28 msk_top.u_prbs_gen.prbs_sel @1401200 -PRBS Generator @@ -416,5 +421,605 @@ msk_top.u_prbs_mon.sync_now msk_top.u_prbs_mon.sync_threshold[15:0] @1000200 -PRBS Monitor +@28 +msk_top.u_msk_top_csr.clear_counts +msk_top.u_msk_top_csr.clk +msk_top.u_msk_top_csr.demod_sync_lock +msk_top.u_msk_top_csr.diff_encdec_lbk_ena +@22 +msk_top.u_msk_top_csr.discard_rxnco[7:0] +msk_top.u_msk_top_csr.discard_rxsamples[7:0] +msk_top.u_msk_top_csr.f1_error[31:0] +msk_top.u_msk_top_csr.f1_nco_adjust[31:0] +msk_top.u_msk_top_csr.f2_error[31:0] +msk_top.u_msk_top_csr.f2_nco_adjust[31:0] +msk_top.u_msk_top_csr.freq_word_ft[31:0] +msk_top.u_msk_top_csr.freq_word_rx_f1[31:0] +msk_top.u_msk_top_csr.freq_word_rx_f2[31:0] +msk_top.u_msk_top_csr.freq_word_tx_f1[31:0] +msk_top.u_msk_top_csr.freq_word_tx_f2[31:0] +msk_top.u_msk_top_csr.hwif_in.axis_xfer_count.xfer_count.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.f1_error.data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.f1_nco_adjust.data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.f2_error.data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.f2_nco_adjust.data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.lpf_accum_f1.status_data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.lpf_accum_f2.status_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.hwif_in.msk_status.demod_sync_lock.next_q +msk_top.u_msk_top_csr.hwif_in.msk_status.rx_enable.next_q +msk_top.u_msk_top_csr.hwif_in.msk_status.tx_axis_valid.next_q +msk_top.u_msk_top_csr.hwif_in.msk_status.tx_enable.next_q +@22 +msk_top.u_msk_top_csr.hwif_in.prbs_bit_count.status_data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.prbs_error_count.status_data.next_q[31:0] +msk_top.u_msk_top_csr.hwif_in.rx_power.rx_power.next_q[22:0] +msk_top.u_msk_top_csr.hwif_in.tx_enable_count.tx_ena_counter.next_q[31:0] +msk_top.u_msk_top_csr.hwif_out.fb_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.lowpass_ema_alpha1.alpha.value[17:0] +msk_top.u_msk_top_csr.hwif_out.lowpass_ema_alpha2.alpha.value[17:0] +msk_top.u_msk_top_csr.hwif_out.lpf_config_0.lpf_alpha.value[23:0] +@28 +msk_top.u_msk_top_csr.hwif_out.lpf_config_0.lpf_freeze.value +msk_top.u_msk_top_csr.hwif_out.lpf_config_0.lpf_zero.value +@22 +msk_top.u_msk_top_csr.hwif_out.lpf_config_0.prbs_reserved.value[5:0] +msk_top.u_msk_top_csr.hwif_out.lpf_config_1.i_gain.value[23:0] +msk_top.u_msk_top_csr.hwif_out.lpf_config_1.i_shift.value[7:0] +msk_top.u_msk_top_csr.hwif_out.lpf_config_2.p_gain.value[23:0] +msk_top.u_msk_top_csr.hwif_out.lpf_config_2.p_shift.value[7:0] +@28 +msk_top.u_msk_top_csr.hwif_out.msk_control.clear_counts.value +msk_top.u_msk_top_csr.hwif_out.msk_control.diff_encoder_loopback.value +msk_top.u_msk_top_csr.hwif_out.msk_control.loopback_ena.value +msk_top.u_msk_top_csr.hwif_out.msk_control.ptt.value +msk_top.u_msk_top_csr.hwif_out.msk_control.rx_invert.value +msk_top.u_msk_top_csr.hwif_out.msk_init.rxinit.value +msk_top.u_msk_top_csr.hwif_out.msk_init.txinit.value +msk_top.u_msk_top_csr.hwif_out.msk_init.txrxinit.value +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_clear.value +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_error_insert.value +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_manual_sync.value +@22 +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_reserved.value[11:0] +@28 +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_sel.value +@22 +msk_top.u_msk_top_csr.hwif_out.prbs_control.prbs_sync_threshold.value[15:0] +msk_top.u_msk_top_csr.hwif_out.prbs_error_mask.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.prbs_initial_state.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.prbs_polynomial.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.rx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.hwif_out.rx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.rx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.rx_sample_discard.rx_nco_discard.value[7:0] +msk_top.u_msk_top_csr.hwif_out.rx_sample_discard.rx_sample_discard.value[7:0] +msk_top.u_msk_top_csr.hwif_out.tx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.hwif_out.tx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.tx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.hwif_out.tx_sync_cnt.tx_sync_cnt.value[23:0] +@28 +msk_top.u_msk_top_csr.hwif_out.tx_sync_ctrl.tx_sync_ena.value +msk_top.u_msk_top_csr.hwif_out.tx_sync_ctrl.tx_sync_f1.value +msk_top.u_msk_top_csr.hwif_out.tx_sync_ctrl.tx_sync_f2.value +msk_top.u_msk_top_csr.hwif_out.tx_sync_ctrl.tx_sync_force.value +msk_top.u_msk_top_csr.loopback_ena +@22 +msk_top.u_msk_top_csr.lpf_accum_f1[31:0] +msk_top.u_msk_top_csr.lpf_accum_f2[31:0] +msk_top.u_msk_top_csr.lpf_alpha[23:0] +@28 +msk_top.u_msk_top_csr.lpf_freeze +@22 +msk_top.u_msk_top_csr.lpf_i_gain[23:0] +msk_top.u_msk_top_csr.lpf_i_shift[7:0] +msk_top.u_msk_top_csr.lpf_p_gain[23:0] +msk_top.u_msk_top_csr.lpf_p_shift[7:0] +@28 +msk_top.u_msk_top_csr.lpf_zero +@22 +msk_top.u_msk_top_csr.pd_alpha1[17:0] +msk_top.u_msk_top_csr.pd_alpha2[17:0] +msk_top.u_msk_top_csr.pd_power[22:0] +msk_top.u_msk_top_csr.prbs_bits[31:0] +@28 +msk_top.u_msk_top_csr.prbs_clear +msk_top.u_msk_top_csr.prbs_err_insert +@22 +msk_top.u_msk_top_csr.prbs_err_mask[31:0] +msk_top.u_msk_top_csr.prbs_errs[31:0] +msk_top.u_msk_top_csr.prbs_initial[31:0] +@28 +msk_top.u_msk_top_csr.prbs_manual_sync +@22 +msk_top.u_msk_top_csr.prbs_poly[31:0] +@28 +msk_top.u_msk_top_csr.prbs_sel +@22 +msk_top.u_msk_top_csr.prbs_sync_threshold[15:0] +@28 +msk_top.u_msk_top_csr.ptt +@22 +msk_top.u_msk_top_csr.rx_data_w[7:0] +@28 +msk_top.u_msk_top_csr.rx_enable +msk_top.u_msk_top_csr.rx_invert +msk_top.u_msk_top_csr.rxinit +msk_top.u_msk_top_csr.s_axi_aclk +@22 +msk_top.u_msk_top_csr.s_axi_araddr[31:0] +@28 +msk_top.u_msk_top_csr.s_axi_aresetn +msk_top.u_msk_top_csr.s_axi_arprot[2:0] +msk_top.u_msk_top_csr.s_axi_arready +msk_top.u_msk_top_csr.s_axi_arvalid +@22 +msk_top.u_msk_top_csr.s_axi_awaddr[31:0] +@28 +msk_top.u_msk_top_csr.s_axi_awprot[2:0] +msk_top.u_msk_top_csr.s_axi_awready +msk_top.u_msk_top_csr.s_axi_awvalid +msk_top.u_msk_top_csr.s_axi_bready +msk_top.u_msk_top_csr.s_axi_bresp[1:0] +msk_top.u_msk_top_csr.s_axi_bvalid +@22 +msk_top.u_msk_top_csr.s_axi_rdata[31:0] +@28 +msk_top.u_msk_top_csr.s_axi_rready +msk_top.u_msk_top_csr.s_axi_rresp[1:0] +msk_top.u_msk_top_csr.s_axi_rvalid +@22 +msk_top.u_msk_top_csr.s_axi_wdata[31:0] +@28 +msk_top.u_msk_top_csr.s_axi_wready +@22 +msk_top.u_msk_top_csr.s_axi_wstrb[3:0] +@28 +msk_top.u_msk_top_csr.s_axi_wvalid +@c00023 +msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +@28 +(0)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(1)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(2)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(3)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(4)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(5)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(6)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +(7)msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +@1401201 +-group_end +@28 +msk_top.u_msk_top_csr.s_axil_i.arprot[2:0] +msk_top.u_msk_top_csr.s_axil_i.arvalid +@22 +msk_top.u_msk_top_csr.s_axil_i.awaddr[7:0] +@28 +msk_top.u_msk_top_csr.s_axil_i.awprot[2:0] +msk_top.u_msk_top_csr.s_axil_i.awvalid +msk_top.u_msk_top_csr.s_axil_i.bready +msk_top.u_msk_top_csr.s_axil_i.rready +@22 +msk_top.u_msk_top_csr.s_axil_i.wdata[31:0] +msk_top.u_msk_top_csr.s_axil_i.wstrb[3:0] +@28 +msk_top.u_msk_top_csr.s_axil_i.wvalid +msk_top.u_msk_top_csr.s_axil_o.arready +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_f1_freqword +msk_top.u_msk_top_csr.s_axil_o.awready +msk_top.u_msk_top_csr.s_axil_o.bresp[1:0] +msk_top.u_msk_top_csr.s_axil_o.bvalid +@22 +msk_top.u_msk_top_csr.s_axil_o.rdata[31:0] +@28 +msk_top.u_msk_top_csr.s_axil_o.rresp[1:0] +msk_top.u_msk_top_csr.s_axil_o.rvalid +msk_top.u_msk_top_csr.s_axil_o.wready +msk_top.u_msk_top_csr.tx_axis_valid +@22 +msk_top.u_msk_top_csr.tx_bit_counter[31:0] +msk_top.u_msk_top_csr.tx_data_w[7:0] +msk_top.u_msk_top_csr.tx_ena_counter[31:0] +@28 +msk_top.u_msk_top_csr.tx_enable +msk_top.u_msk_top_csr.tx_req +@22 +msk_top.u_msk_top_csr.tx_sync_cnt[23:0] +@28 +msk_top.u_msk_top_csr.tx_sync_ena +msk_top.u_msk_top_csr.tx_sync_f1 +msk_top.u_msk_top_csr.tx_sync_f2 +msk_top.u_msk_top_csr.tx_sync_force +msk_top.u_msk_top_csr.txinit +msk_top.u_msk_top_csr.txrxinit +msk_top.u_msk_top_csr.u01s.clk +msk_top.u_msk_top_csr.u01s.di +msk_top.u_msk_top_csr.u01s.di_s[0:1] +msk_top.u_msk_top_csr.u01s.do +msk_top.u_msk_top_csr.u02s.clk +msk_top.u_msk_top_csr.u02s.di_s[0:1] +msk_top.u_msk_top_csr.u02s.do +msk_top.u_msk_top_csr.u03s.clk +msk_top.u_msk_top_csr.u03s.di_s[0:1] +msk_top.u_msk_top_csr.u03s.do +msk_top.u_msk_top_csr.u04s.clk +msk_top.u_msk_top_csr.u04s.di +msk_top.u_msk_top_csr.u04s.di_s[0:1] +msk_top.u_msk_top_csr.u04s.do +msk_top.u_msk_top_csr.u05s.clk +msk_top.u_msk_top_csr.u05s.di +msk_top.u_msk_top_csr.u05s.di_s[0:1] +msk_top.u_msk_top_csr.u05s.do +msk_top.u_msk_top_csr.u06s.clk +msk_top.u_msk_top_csr.u06s.di +msk_top.u_msk_top_csr.u06s.di_s[0:1] +msk_top.u_msk_top_csr.u06s.do +msk_top.u_msk_top_csr.u07s.clk +msk_top.u_msk_top_csr.u07s.di +msk_top.u_msk_top_csr.u07s.di_s[0:1] +msk_top.u_msk_top_csr.u07s.do +msk_top.u_msk_top_csr.u08s.clk +msk_top.u_msk_top_csr.u08s.di +msk_top.u_msk_top_csr.u08s.di_s[0:1] +msk_top.u_msk_top_csr.u08s.do +msk_top.u_msk_top_csr.u09s.clk +msk_top.u_msk_top_csr.u09s.di +msk_top.u_msk_top_csr.u09s.di_s[0:1] +msk_top.u_msk_top_csr.u09s.do +msk_top.u_msk_top_csr.u10s.clk +msk_top.u_msk_top_csr.u10s.di +msk_top.u_msk_top_csr.u10s.di_s[0:1] +msk_top.u_msk_top_csr.u10s.do +msk_top.u_msk_top_csr.u11s.clk +msk_top.u_msk_top_csr.u11s.di +msk_top.u_msk_top_csr.u11s.di_s[0:1] +msk_top.u_msk_top_csr.u11s.do +msk_top.u_msk_top_csr.u12s.clk +msk_top.u_msk_top_csr.u12s.di +msk_top.u_msk_top_csr.u12s.di_s[0:1] +msk_top.u_msk_top_csr.u12s.do +msk_top.u_msk_top_csr.u13s.clk +msk_top.u_msk_top_csr.u13s.di +msk_top.u_msk_top_csr.u13s.di_s[0:1] +msk_top.u_msk_top_csr.u13s.do +msk_top.u_msk_top_csr.u14s.clk +msk_top.u_msk_top_csr.u14s.di +msk_top.u_msk_top_csr.u14s.di_s[0:1] +msk_top.u_msk_top_csr.u14s.do +msk_top.u_msk_top_csr.u15s.clk +msk_top.u_msk_top_csr.u15s.di +msk_top.u_msk_top_csr.u15s.di_s[0:1] +msk_top.u_msk_top_csr.u15s.do +msk_top.u_msk_top_csr.u16s.clk +msk_top.u_msk_top_csr.u16s.di +msk_top.u_msk_top_csr.u16s.di_s[0:1] +msk_top.u_msk_top_csr.u16s.do +msk_top.u_msk_top_csr.u_msk_regs.axil_ar_accept +@22 +msk_top.u_msk_top_csr.u_msk_regs.axil_araddr[7:0] +msk_top.u_msk_top_csr.s_axil_i.araddr[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.axil_arvalid +msk_top.u_msk_top_csr.u_msk_regs.axil_aw_accept +@22 +msk_top.u_msk_top_csr.u_msk_regs.axil_awaddr[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.axil_awvalid +msk_top.u_msk_top_csr.u_msk_regs.axil_n_in_flight[1:0] +msk_top.u_msk_top_csr.u_msk_regs.axil_prev_was_rd +msk_top.u_msk_top_csr.u_msk_regs.axil_resp_acked +msk_top.u_msk_top_csr.u_msk_regs.axil_resp_rptr[1:0] +msk_top.u_msk_top_csr.u_msk_regs.axil_resp_wptr[1:0] +@22 +msk_top.u_msk_top_csr.u_msk_regs.axil_wdata[31:0] +msk_top.u_msk_top_csr.u_msk_regs.axil_wstrb[3:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.axil_wvalid +msk_top.u_msk_top_csr.u_msk_regs.clk +@22 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_addr[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_rd_ack +@22 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_rd_data[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_rd_err +msk_top.u_msk_top_csr.u_msk_regs.cpuif_req +msk_top.u_msk_top_csr.u_msk_regs.cpuif_req_is_wr +msk_top.u_msk_top_csr.u_msk_regs.cpuif_req_masked +msk_top.u_msk_top_csr.u_msk_regs.cpuif_req_stall_rd +msk_top.u_msk_top_csr.u_msk_regs.cpuif_req_stall_wr +msk_top.u_msk_top_csr.u_msk_regs.cpuif_wr_ack +@22 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_wr_biten[31:0] +msk_top.u_msk_top_csr.u_msk_regs.cpuif_wr_data[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.cpuif_wr_err +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.axis_xfer_count +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.f1_error +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.f1_nco_adjust +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.f2_error +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.f2_nco_adjust +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.fb_freqword +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.hash_id_high +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.hash_id_low +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lowpass_ema_alpha1 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lowpass_ema_alpha2 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lpf_accum_f1 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lpf_accum_f2 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lpf_config_0 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lpf_config_1 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.lpf_config_2 +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.msk_control +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.msk_init +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.msk_status +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_bit_count +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_control +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_error_count +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_error_mask +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_initial_state +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.prbs_polynomial +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.rx_data_width +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.rx_f1_freqword +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.rx_f2_freqword +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.rx_power +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.rx_sample_discard +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_bit_count +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_data_width +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_enable_count +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_f1_freqword +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_f2_freqword +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_sync_cnt +msk_top.u_msk_top_csr.u_msk_regs.decoded_reg_strb.tx_sync_ctrl +msk_top.u_msk_top_csr.u_msk_regs.decoded_req +msk_top.u_msk_top_csr.u_msk_regs.decoded_req_is_wr +@22 +msk_top.u_msk_top_csr.u_msk_regs.decoded_wr_biten[31:0] +msk_top.u_msk_top_csr.u_msk_regs.decoded_wr_data[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.fb_freqword.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.fb_freqword.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lowpass_ema_alpha1.alpha.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lowpass_ema_alpha1.alpha.next_q[17:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lowpass_ema_alpha2.alpha.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lowpass_ema_alpha2.alpha.next_q[17:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_alpha.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_alpha.next_q[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_freeze.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_freeze.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_zero.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.lpf_zero.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.prbs_reserved.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_0.prbs_reserved.next_q[5:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_1.i_gain.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_1.i_gain.next_q[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_1.i_shift.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_1.i_shift.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_2.p_gain.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_2.p_gain.next_q[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_2.p_shift.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.lpf_config_2.p_shift.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.clear_counts.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.clear_counts.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.diff_encoder_loopback.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.diff_encoder_loopback.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.loopback_ena.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.loopback_ena.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.ptt.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.ptt.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.rx_invert.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_control.rx_invert.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.rxinit.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.rxinit.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.txinit.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.txinit.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.txrxinit.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.msk_init.txrxinit.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_clear.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_clear.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_error_insert.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_error_insert.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_manual_sync.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_manual_sync.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_reserved.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_reserved.next_q[11:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_sel.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_sel.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_sync_threshold.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_control.prbs_sync_threshold.next_q[15:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_error_mask.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_error_mask.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_initial_state.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_initial_state.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_polynomial.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.prbs_polynomial.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_data_width.data_width.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_data_width.data_width.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_f1_freqword.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_f1_freqword.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_f2_freqword.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_f2_freqword.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_sample_discard.rx_nco_discard.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_sample_discard.rx_nco_discard.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_sample_discard.rx_sample_discard.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.rx_sample_discard.rx_sample_discard.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_data_width.data_width.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_data_width.data_width.next_q[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_f1_freqword.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_f1_freqword.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_f2_freqword.config_data.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_f2_freqword.config_data.next_q[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_cnt.tx_sync_cnt.load_next +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_cnt.tx_sync_cnt.next_q[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_ena.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_ena.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_f1.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_f1.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_f2.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_f2.next_q +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_force.load_next +msk_top.u_msk_top_csr.u_msk_regs.field_combo.tx_sync_ctrl.tx_sync_force.next_q +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.fb_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lowpass_ema_alpha1.alpha.value[17:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lowpass_ema_alpha2.alpha.value[17:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_0.lpf_alpha.value[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_0.lpf_freeze.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_0.lpf_zero.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_0.prbs_reserved.value[5:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_1.i_gain.value[23:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_1.i_shift.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_2.p_gain.value[23:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.lpf_config_2.p_shift.value[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_control.clear_counts.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_control.diff_encoder_loopback.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_control.loopback_ena.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_control.ptt.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_control.rx_invert.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_init.rxinit.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_init.txinit.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.msk_init.txrxinit.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_clear.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_error_insert.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_manual_sync.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_reserved.value[11:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_sel.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_control.prbs_sync_threshold.value[15:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_error_mask.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_initial_state.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.prbs_polynomial.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.rx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.rx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.rx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.rx_sample_discard.rx_nco_discard.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.rx_sample_discard.rx_sample_discard.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_sync_cnt.tx_sync_cnt.value[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_sync_ctrl.tx_sync_ena.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_sync_ctrl.tx_sync_f1.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_sync_ctrl.tx_sync_f2.value +msk_top.u_msk_top_csr.u_msk_regs.field_storage.tx_sync_ctrl.tx_sync_force.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.fb_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lowpass_ema_alpha1.alpha.value[17:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lowpass_ema_alpha2.alpha.value[17:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_0.lpf_alpha.value[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_0.lpf_freeze.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_0.lpf_zero.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_0.prbs_reserved.value[5:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_1.i_gain.value[23:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_1.i_shift.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_2.p_gain.value[23:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.lpf_config_2.p_shift.value[7:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_control.clear_counts.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_control.diff_encoder_loopback.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_control.loopback_ena.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_control.ptt.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_control.rx_invert.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_init.rxinit.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_init.txinit.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.msk_init.txrxinit.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_clear.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_error_insert.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_manual_sync.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_reserved.value[11:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_sel.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_control.prbs_sync_threshold.value[15:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_error_mask.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_initial_state.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.prbs_polynomial.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.rx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.rx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.rx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.rx_sample_discard.rx_nco_discard.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.rx_sample_discard.rx_sample_discard.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_data_width.data_width.value[7:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_f1_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_f2_freqword.config_data.value[31:0] +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_sync_cnt.tx_sync_cnt.value[23:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_sync_ctrl.tx_sync_ena.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_sync_ctrl.tx_sync_f1.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_sync_ctrl.tx_sync_f2.value +msk_top.u_msk_top_csr.u_msk_regs.hwif_out.tx_sync_ctrl.tx_sync_force.value +@22 +msk_top.u_msk_top_csr.u_msk_regs.readback_data[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.readback_done +msk_top.u_msk_top_csr.u_msk_regs.readback_err +msk_top.u_msk_top_csr.u_msk_regs.rst +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.arready +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.awready +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.bresp[1:0] +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.bvalid +@22 +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.rdata[31:0] +@28 +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.rresp[1:0] +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.rvalid +msk_top.u_msk_top_csr.u_msk_regs.s_axil_o.wready +@22 +msk_top.u_msk_top_csr.xfer_count[31:0] [pattern_trace] 1 [pattern_trace] 0 diff --git a/sim/msk_top_regs b/sim/msk_top_regs new file mode 120000 index 0000000..43bc91d --- /dev/null +++ b/sim/msk_top_regs @@ -0,0 +1 @@ +../rdl/outputs/python/msk_top_regs \ No newline at end of file diff --git a/src/cdc_resync.vhd b/src/cdc_resync.vhd new file mode 100644 index 0000000..027ac44 --- /dev/null +++ b/src/cdc_resync.vhd @@ -0,0 +1,103 @@ +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- _______ ________ ______ +-- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +-- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +-- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +-- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +-- /_/ +-- ________ _____ _____ _____ _____ +-- ____ _/_______ __________ /____(_)__ /_____ ____ /______ +-- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +-- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +-- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- Copyright +------------------------------------------------------------------------------------------------------ +-- +-- Copyright 2025 by M. Wishek +-- +------------------------------------------------------------------------------------------------------ +-- License +------------------------------------------------------------------------------------------------------ +-- +-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +-- +-- You may redistribute and modify this source and make products using it under +-- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +-- +-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +-- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- Please see the CERN-OHL-W v2 for applicable conditions. +-- +-- Source location: TBD +-- +-- As per CERN-OHL-W v2 section 4.1, should You produce hardware based on this +-- source, You must maintain the Source Location visible on the external case of +-- the products you make using this source. +-- +------------------------------------------------------------------------------------------------------ +-- Block name and description +------------------------------------------------------------------------------------------------------ +-- +-- This is a wrapper block for the register module generated by DesyRDL. +-- +-- Documentation location: TBD +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ + + +------------------------------------------------------------------------------------------------------ +-- ╦ ┬┌┐ ┬─┐┌─┐┬─┐┬┌─┐┌─┐ +-- ║ │├┴┐├┬┘├─┤├┬┘│├┤ └─┐ +-- ╩═╝┴└─┘┴└─┴ ┴┴└─┴└─┘└─┘ +------------------------------------------------------------------------------------------------------ +-- Libraries + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +------------------------------------------------------------------------------------------------------ +-- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ +-- ║╣ │││ │ │ │ └┬┘ +-- ╚═╝┘└┘ ┴ ┴ ┴ ┴ +------------------------------------------------------------------------------------------------------ +-- Entity + +ENTITY cdc_resync IS + GENERIC ( + STAGES : NATURAL := 2 + ); + PORT ( + clk : IN std_logic; + resetn : IN std_logic; + + di : IN std_logic; + do : OUT std_logic + ); +END ENTITY cdc_resync; + +ARCHITECTURE rtl OF cdc_resync IS + + SIGNAL di_s : std_logic_vector(0 TO STAGES-1); + +BEGIN + + do <= di_s(STAGES -1); + + resync : PROCESS (clk, resetn) + BEGIN + IF resetn = '0' THEN + di_s <= (OTHERS => '0'); + ELSIF clk'EVENT AND clk = '1' THEN + di_s <= di & di_s(0 TO STAGES-2); + END IF; + END PROCESS resync; + +END ARCHITECTURE rtl; + + diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 41a4f65..1e5d3e7 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -64,8 +64,6 @@ LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; -USE work.pkg_msk_top_regs.ALL; - ENTITY msk_top IS GENERIC ( HASH_ID_LO : std_logic_vector := X"AAAA5555"; diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index b19e22e..b8b1780 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -61,7 +61,8 @@ LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; -USE work.pkg_msk_top_regs.ALL; +USE work.axi4lite_intf_pkg.ALL; +USE work.msk_top_regs_pkg.ALL; ------------------------------------------------------------------------------------------------------ -- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ @@ -171,120 +172,132 @@ END ENTITY msk_top_csr; ARCHITECTURE rtl OF msk_top_csr IS - SIGNAL pi_s_top : t_msk_top_regs_m2s; - SIGNAL po_s_top : t_msk_top_regs_s2m; + SIGNAL s_axil_i : axi4lite_slave_in_intf( + AWADDR(7 downto 0), + WDATA(31 downto 0), + WSTRB(3 downto 0), + ARADDR(7 downto 0) + ); + SIGNAL s_axil_o : axi4lite_slave_out_intf( + RDATA(31 downto 0) + ); - SIGNAL pi_addrmap : t_addrmap_msk_top_regs_in; - SIGNAL po_addrmap : t_addrmap_msk_top_regs_out; + SIGNAL hwif_in : msk_top_regs_in_t; + SIGNAL hwif_out : msk_top_regs_out_t; SIGNAL txrxinit : std_logic; + COMPONENT cdc_resync IS + GENERIC ( + STAGES : NATURAL := 2 + ); + PORT ( + clk : IN std_logic; + resetn : IN std_logic; + + di : IN std_logic; + do : OUT std_logic + ); + END COMPONENT cdc_resync; + BEGIN - u_msk_regs : ENTITY work.msk_top_regs(arch) + s_axil_i.AWVALID <= s_axi_awvalid; + s_axil_i.AWADDR <= s_axi_awaddr(7 DOWNTO 0); + s_axil_i.AWPROT <= s_axi_awprot; + s_axil_i.WVALID <= s_axi_wvalid; + s_axil_i.WDATA <= s_axi_wdata; + s_axil_i.WSTRB <= s_axi_wstrb; + s_axil_i.BREADY <= s_axi_bready; + s_axil_i.ARVALID <= s_axi_arvalid; + s_axil_i.ARADDR <= s_axi_araddr(7 DOWNTO 0); + s_axil_i.ARPROT <= s_axi_arprot; + s_axil_i.RREADY <= s_axi_rready; + + s_axi_awready <= s_axil_o.AWREADY; + s_axi_wready <= s_axil_o.WREADY; + s_axi_bvalid <= s_axil_o.BVALID; + s_axi_bresp <= s_axil_o.BRESP; + s_axi_arready <= s_axil_o.ARREADY; + s_axi_rvalid <= s_axil_o.RVALID; + s_axi_rdata <= s_axil_o.RDATA; + s_axi_rresp <= s_axil_o.RRESP; + + u_msk_regs : ENTITY work.msk_top_regs(rtl) PORT MAP ( - pi_clock => s_axi_aclk, - pi_reset => NOT s_axi_aresetn, - -- TOP subordinate memory mapped interface - pi_s_reset => NOT s_axi_aresetn, - pi_s_top => pi_s_top, - po_s_top => po_s_top, + clk => s_axi_aclk, + rst => NOT s_axi_aresetn, + s_axil_i => s_axil_i, + s_axil_o => s_axil_o, -- to logic interface - pi_addrmap => pi_addrmap, - po_addrmap => po_addrmap + hwif_in => hwif_in, + hwif_out => hwif_out ); - -- write address channel signals--------------------------------------------- - pi_s_top.awaddr <= s_axi_awaddr; - pi_s_top.awprot <= s_axi_awprot; - pi_s_top.awvalid <= s_axi_awvalid; - -- write data channel signals--------------------------------------------- - pi_s_top.wdata <= s_axi_wdata; - pi_s_top.wstrb <= s_axi_wstrb; - pi_s_top.wvalid <= s_axi_wvalid; - -- write response channel signals - pi_s_top.bready <= s_axi_bready; - -- read address channel signals --------------------------------------------- - pi_s_top.araddr <= s_axi_araddr; - pi_s_top.arprot <= s_axi_arprot; - pi_s_top.arvalid <= s_axi_arvalid; - -- read data channel signals--------------------------------------------- - pi_s_top.rready <= s_axi_rready; - - -- write address channel signals--------------------------------------------- - s_axi_awready <= po_s_top.awready; - -- write data channel signals--------------------------------------------- - s_axi_wready <= po_s_top.wready; - -- write response channel signals --------------------------------------------- - s_axi_bresp <= po_s_top.bresp; - s_axi_bvalid <= po_s_top.bvalid; - -- read address channel signals--------------------------------------------- - s_axi_arready <= po_s_top.arready; - -- read data channel signals--------------------------------------------- - s_axi_rdata <= po_s_top.rdata; - s_axi_rresp <= po_s_top.rresp; - s_axi_rvalid <= po_s_top.rvalid; + -- Status signals crossing from local clock domain to the AXI clock domain + hwif_in.MSK_Status.demod_sync_lock.next_q <= '0'; + hwif_in.MSK_Status.tx_enable.next_q <= tx_enable; + hwif_in.MSK_Status.rx_enable.next_q <= rx_enable; + hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; + hwif_in.Tx_Bit_Count.tx_bit_counter.next_q <= tx_bit_counter; + hwif_in.Tx_Enable_Count.tx_ena_counter.next_q <= tx_ena_counter; + hwif_in.axis_xfer_count.xfer_count.next_q <= xfer_count; + hwif_in.PRBS_Bit_Count.status_data.next_q <= prbs_bits; + hwif_in.PRBS_Error_Count.status_data.next_q <= prbs_errs; + hwif_in.LPF_Accum_F1.status_data.next_q <= lpf_accum_f1; + hwif_in.LPF_Accum_F2.status_data.next_q <= lpf_accum_f2; + hwif_in.f1_nco_adjust.data.next_q <= f1_nco_adjust; + hwif_in.f2_nco_adjust.data.next_q <= f2_nco_adjust; + hwif_in.f1_error.data.next_q <= f1_error; + hwif_in.f2_error.data.next_q <= f2_error; + hwif_in.rx_power.rx_power.next_q <= pd_power; - pi_addrmap.MSK_Status.demod_sync_lock.data(0) <= '0'; - pi_addrmap.MSK_Status.tx_enable.data(0) <= tx_enable; - pi_addrmap.MSK_Status.rx_enable.data(0) <= rx_enable; - pi_addrmap.MSK_Status.tx_axis_valid.data(0) <= tx_axis_valid; - pi_addrmap.Tx_Bit_Count.tx_bit_counter.data <= tx_bit_counter; - pi_addrmap.Tx_Enable_Count.tx_ena_counter.data <= tx_ena_counter; - pi_addrmap.axis_xfer_count.xfer_count.data <= xfer_count; - pi_addrmap.PRBS_Bit_Count.status_data.data <= prbs_bits; - pi_addrmap.PRBS_Error_Count.status_data.data <= prbs_errs; - pi_addrmap.LPF_Accum_F1.status_data.data <= lpf_accum_f1; - pi_addrmap.LPF_Accum_F2.status_data.data <= lpf_accum_f2; - pi_addrmap.f1_nco_adjust.data.data <= f1_nco_adjust; - pi_addrmap.f2_nco_adjust.data.data <= f2_nco_adjust; - pi_addrmap.f1_error.data.data <= f1_error; - pi_addrmap.f2_error.data.data <= f2_error; - pi_addrmap.rx_power.rx_power.data <= pd_power; + -- Control signals requiring re-sync from AXI clock domain to local clock domain + u01s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.txrxinit.value, txrxinit ); + u02s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.txinit.value OR txrxinit, txinit ); + u03s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.rxinit.value OR txrxinit, rxinit ); + u04s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.ptt.value, ptt ); + u05s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.loopback_ena.value, loopback_ena ); + u06s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.diff_encoder_loopback.value, diff_encdec_lbk_ena ); + u07s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.rx_invert.value, rx_invert ); + u08s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.clear_counts.value, clear_counts ); + u09s: cdc_resync PORT MAP (clk, '1', hwif_out.LPF_Config_0.lpf_freeze.value, lpf_freeze ); + u10s: cdc_resync PORT MAP (clk, '1', hwif_out.LPF_Config_0.lpf_zero.value, lpf_zero ); + u11s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_sel.value, prbs_sel ); + u12s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_clear.value, prbs_clear ); + u13s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_error_insert.value, prbs_err_insert ); + u14s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_manual_sync.value, prbs_manual_sync ); + u15s: cdc_resync PORT MAP (clk, '1', hwif_out.Tx_Sync_Ctrl.tx_sync_ena.value, tx_sync_ena ); + u16s: cdc_resync PORT MAP (clk, '1', hwif_out.Tx_Sync_Ctrl.tx_sync_force.value, tx_sync_force ); + -- The remaining control signals also cross from the AXI to the local clock domain. These are static signals + -- that are configured while the txrxinit is active. The active txrxinit hold the destination FFs to an + -- initial state preventing meta-stable conditions. + freq_word_ft <= hwif_out.Fb_FreqWord.config_data.value; + freq_word_tx_f1 <= hwif_out.TX_F1_FreqWord.config_data.value; + freq_word_tx_f2 <= hwif_out.TX_F2_FreqWord.config_data.value; + freq_word_rx_f1 <= hwif_out.RX_F1_FreqWord.config_data.value; + freq_word_rx_f2 <= hwif_out.RX_F2_FreqWord.config_data.value; + lpf_alpha <= hwif_out.LPF_Config_0.lpf_alpha.value; + lpf_i_gain <= hwif_out.LPF_Config_1.i_gain.value; + lpf_i_shift <= hwif_out.LPF_Config_1.i_shift.value; + lpf_p_gain <= hwif_out.LPF_Config_2.p_gain.value; + lpf_p_shift <= hwif_out.LPF_Config_2.p_shift.value; - txrxinit <= po_addrmap.MSK_Init.txrxinit.data(0); - txinit <= po_addrmap.MSK_Init.txinit.data(0) OR txrxinit; - rxinit <= po_addrmap.MSK_Init.rxinit.data(0) OR txrxinit; - ptt <= po_addrmap.MSK_Control.ptt.data(0); - loopback_ena <= po_addrmap.MSK_Control.loopback_ena.data(0); - diff_encdec_lbk_ena <= po_addrmap.MSK_Control.diff_encoder_loopback.data(0); - rx_invert <= po_addrmap.MSK_Control.rx_invert.data(0); - clear_counts <= po_addrmap.MSK_Control.clear_counts.data(0); - freq_word_ft <= po_addrmap.Fb_FreqWord.config_data.data; - freq_word_tx_f1 <= po_addrmap.TX_F1_FreqWord.config_data.data; - freq_word_tx_f2 <= po_addrmap.TX_F2_FreqWord.config_data.data; - freq_word_rx_f1 <= po_addrmap.RX_F1_FreqWord.config_data.data; - freq_word_rx_f2 <= po_addrmap.RX_F2_FreqWord.config_data.data; - lpf_freeze <= po_addrmap.LPF_Config_0.lpf_freeze.data(0); - lpf_zero <= po_addrmap.LPF_Config_0.lpf_zero.data(0); - lpf_alpha <= po_addrmap.LPF_Config_0.lpf_alpha.data; - lpf_i_gain <= po_addrmap.LPF_Config_1.i_gain.data; - lpf_i_shift <= po_addrmap.LPF_Config_1.i_shift.data; - lpf_p_gain <= po_addrmap.LPF_Config_2.p_gain.data; - lpf_p_shift <= po_addrmap.LPF_Config_2.p_shift.data; - tx_data_w <= po_addrmap.Tx_Data_Width.data_width.data; - rx_data_w <= po_addrmap.Rx_Data_Width.data_width.data; - discard_rxsamples <= po_addrmap.Rx_Sample_Discard.rx_sample_discard.data; - discard_rxnco <= po_addrmap.Rx_Sample_Discard.rx_nco_discard.data; + tx_data_w <= hwif_out.Tx_Data_Width.data_width.value; + rx_data_w <= hwif_out.Rx_Data_Width.data_width.value; + discard_rxsamples <= hwif_out.Rx_Sample_Discard.rx_sample_discard.value; + discard_rxnco <= hwif_out.Rx_Sample_Discard.rx_nco_discard.value; - prbs_initial <= po_addrmap.PRBS_Initial_State.config_data.data; - prbs_poly <= po_addrmap.PRBS_Polynomial.config_data.data; - prbs_err_mask <= po_addrmap.PRBS_Error_Mask.config_data.data; - prbs_err_insert <= po_addrmap.PRBS_Control.prbs_error_insert.data(0); - prbs_sel <= po_addrmap.PRBS_Control.prbs_sel.data(0); - prbs_clear <= po_addrmap.PRBS_Control.prbs_clear.data(0); - prbs_manual_sync <= po_addrmap.PRBS_Control.prbs_manual_sync.data(0); - prbs_sync_threshold <= po_addrmap.PRBS_Control.prbs_sync_threshold.data; + prbs_initial <= hwif_out.PRBS_Initial_State.config_data.value; + prbs_poly <= hwif_out.PRBS_Polynomial.config_data.value; + prbs_err_mask <= hwif_out.PRBS_Error_Mask.config_data.value; + prbs_sync_threshold <= hwif_out.PRBS_Control.prbs_sync_threshold.value; - tx_sync_ena <= po_addrmap.Tx_Sync_Ctrl.tx_sync_ena.data(0); - tx_sync_cnt <= po_addrmap.Tx_Sync_Cnt.tx_sync_cnt.data; - tx_sync_force <= po_addrmap.Tx_Sync_Ctrl.tx_sync_force.data(0); - tx_sync_f1 <= po_addrmap.Tx_Sync_Ctrl.tx_sync_f1.data(0); - tx_sync_f2 <= po_addrmap.Tx_Sync_Ctrl.tx_sync_f2.data(0); + tx_sync_cnt <= hwif_out.Tx_Sync_Cnt.tx_sync_cnt.value; - pd_alpha1 <= po_addrmap.lowpass_ema_alpha1.alpha.data; - pd_alpha2 <= po_addrmap.lowpass_ema_alpha2.alpha.data; + pd_alpha1 <= hwif_out.lowpass_ema_alpha1.alpha.value; + pd_alpha2 <= hwif_out.lowpass_ema_alpha2.alpha.value; END ARCHITECTURE rtl; From 860deaee9faf1b2305287935ccc71e219eb97715 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Sun, 26 Oct 2025 20:46:59 -0600 Subject: [PATCH 02/60] CDC updates for CSRs and PeakRDL transition complete --- rdl/outputs/docs/msk_top_regs.md | 36 ++-- rdl/outputs/docs/msk_top_regs.pdf | Bin 113089 -> 113116 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 66 +++--- rdl/outputs/rtl/msk_top_regs.vhd | 145 +++++++++++-- rdl/outputs/rtl/msk_top_regs_pkg.vhd | 204 ++++++++++-------- rdl/src/msk_top_regs.rdl | 27 +-- sim/Makefile | 2 + sim/msk_test.py | 12 +- src/cdc_resync.vhd | 21 +- src/data_capture.vhd | 102 +++++++++ src/msk_top_csr.vhd | 161 ++++++++++---- src/pulse_detect.vhd | 109 ++++++++++ 12 files changed, 663 insertions(+), 222 deletions(-) create mode 100644 src/data_capture.vhd create mode 100644 src/pulse_detect.vhd diff --git a/rdl/outputs/docs/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md index 82c2c8d..db06b21 100644 --- a/rdl/outputs/docs/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -192,9 +192,9 @@ Don't override. Generated from: msk_top_regs

Modem status data

-|Bits| Identifier |Access|Reset| Name | -|----|--------------|------|-----|------------| -|31:0|tx_bit_counter| r | — |Tx Bit Count| +|Bits| Identifier | Access |Reset| Name | +|----|--------------|--------|-----|------------| +|31:0|tx_bit_counter|r, ruser| — |Tx Bit Count| #### tx_bit_counter field @@ -208,9 +208,9 @@ Don't override. Generated from: msk_top_regs

Modem status data

-|Bits| Identifier |Access|Reset| Name | -|----|--------------|------|-----|---------------| -|31:0|tx_ena_counter| r | 0x0 |Tx Enable Count| +|Bits| Identifier | Access |Reset| Name | +|----|--------------|--------|-----|---------------| +|31:0|tx_ena_counter|r, ruser| 0x0 |Tx Enable Count| #### tx_ena_counter field @@ -605,9 +605,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Frequency offet applied to the F1 NCO

-|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|-----------------------| -|31:0| data | r | 0x0 |F1 NCO Frequency Adjust| +|Bits|Identifier| Access |Reset| Name | +|----|----------|--------|-----|-----------------------| +|31:0| data |r, ruser| 0x0 |F1 NCO Frequency Adjust| #### data field @@ -621,9 +621,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Frequency offet applied to the F2 NCO

-|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|-----------------------| -|31:0| data | r | 0x0 |F2 NCO Frequency Adjust| +|Bits|Identifier| Access |Reset| Name | +|----|----------|--------|-----|-----------------------| +|31:0| data |r, ruser| 0x0 |F2 NCO Frequency Adjust| #### data field @@ -637,9 +637,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Error value of the F1 Costas loop after each active bit period

-|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|--------------| -|31:0| data | r | 0x0 |F1 Error Value| +|Bits|Identifier| Access |Reset| Name | +|----|----------|--------|-----|--------------| +|31:0| data |r, ruser| 0x0 |F1 Error Value| #### data field @@ -653,9 +653,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Error value of the F2 Costas loop after each active bit period

-|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|--------------| -|31:0| data | r | 0x0 |F2 Error Value| +|Bits|Identifier| Access |Reset| Name | +|----|----------|--------|-----|--------------| +|31:0| data |r, ruser| 0x0 |F2 Error Value| #### data field diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index 59a0dda50a5bcf17e93d29e926658db1bd86b449..83b67bc0325497acf1db478d4c06f12ab3ce5600 100644 GIT binary patch delta 3844 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
IwDCp@o0KKj$EjP)KMd zBuo_UI;XY-Fwu-t=qPk_juV*12LLZji<&_6R45Z z`N1P(=VuOM%_qZ+0OgHC&d(gi8cU3}Mq6W!ao4zOY%&5HF^$E>Vxy?}2e?vsexs{g zjuO8Xa@AQ%%kNxumGbFN)%cgs6~4|@`2IH^V5~9Lq~%PDpqxRGkuxLWamGV3&SVJ1 z847tg^B@Xm6r|uxfdHHVFnj0h8M|}rOx(+*{8+ELT5E{^x!UAYmzcQ$APF-u3MC~) GPeuy+2txn> delta 3870 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 b(0&0={ajq><>Vl8bYMAp5J=ZVkN&>^W>z%U diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py index 8ea7fa8..8ac24d9 100644 --- a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -414,7 +414,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -452,7 +452,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -489,7 +489,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -520,7 +520,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls: """ Property to access alpha field of the register @@ -559,7 +559,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x106a859a_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls: return super().get_child_by_system_rdl_name(name) @@ -2704,7 +2704,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls(FieldAsyncReadOnly): """ Class to represent a register field in the register model @@ -2779,7 +2779,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls( + self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2810,7 +2810,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls: + def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls: """ Property to access status_data field of the register @@ -2849,7 +2849,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x106b05c7_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls: return super().get_child_by_system_rdl_name(name) @@ -4454,7 +4454,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x106a65e2_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x10645fbf_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -4530,7 +4530,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x106a65e2_cls = msk_top_regs_data_width_data_width_0x0x106a65e2_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x10645fbf_cls = msk_top_regs_data_width_data_width_0x0x10645fbf_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -4561,7 +4561,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x106a65e2_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x10645fbf_cls: """ Property to access data_width field of the register @@ -4600,7 +4600,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x106a65e2_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x10645fbf_cls: return super().get_child_by_system_rdl_name(name) @@ -5446,7 +5446,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5523,7 +5523,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls = msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5554,7 +5554,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls: """ Property to access config_data field of the register @@ -5595,7 +5595,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x106a67e3_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls: return super().get_child_by_system_rdl_name(name) @@ -5619,7 +5619,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5696,7 +5696,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls = msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5727,7 +5727,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls: """ Property to access config_data field of the register @@ -5768,7 +5768,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x106a672f_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls: return super().get_child_by_system_rdl_name(name) @@ -5792,7 +5792,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5869,7 +5869,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls = msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5900,7 +5900,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls: """ Property to access config_data field of the register @@ -5941,7 +5941,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1067ecad_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls: return super().get_child_by_system_rdl_name(name) @@ -5965,7 +5965,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6042,7 +6042,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls = msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6073,7 +6073,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls: """ Property to access config_data field of the register @@ -6114,7 +6114,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1069f40b_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls: return super().get_child_by_system_rdl_name(name) @@ -8332,7 +8332,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls = msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls = msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls( address=self.address+132, accesswidth=32, width=32, @@ -9018,7 +9018,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls: """ Property to access lowpass_ema_alpha1 @@ -9232,7 +9232,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls: ... @overload @@ -9244,7 +9244,7 @@ def get_child_by_system_rdl_name(self, name: Literal["rx_power"]) -> msk_top_reg @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x106a8591_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd index 9606951..25efa10 100644 --- a/rdl/outputs/rtl/msk_top_regs.vhd +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -70,6 +70,10 @@ architecture rtl of msk_top_regs is signal axil_resp_buffer : axil_resp_buffer_array_t(1 downto 0); signal axil_resp_wptr : unsigned(1 downto 0); signal axil_resp_rptr : unsigned(1 downto 0); + signal external_req : std_logic; + signal external_pending : std_logic; + signal external_wr_ack : std_logic; + signal external_rd_ack : std_logic; ---------------------------------------------------------------------------- -- Address Decode Signals @@ -113,6 +117,8 @@ architecture rtl of msk_top_regs is rx_power : std_logic; end record; signal decoded_reg_strb : decoded_reg_strb_t; + signal decoded_strb_is_external : std_logic; + signal decoded_req : std_logic; signal decoded_req_is_wr : std_logic; signal decoded_wr_data : std_logic_vector(31 downto 0); @@ -753,6 +759,8 @@ architecture rtl of msk_top_regs is ---------------------------------------------------------------------------- -- Readback Signals ---------------------------------------------------------------------------- + signal readback_external_rd_ack_c : std_logic; + signal readback_external_rd_ack : std_logic; signal readback_err : std_logic; signal readback_done : std_logic; signal readback_data : std_logic_vector(31 downto 0); @@ -950,10 +958,32 @@ begin s_axil_o.RRESP <= "00"; end if; end process; + process(clk) begin + if false then -- async reset + external_pending <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + external_pending <= '0'; + else + if external_req and not external_wr_ack and not external_rd_ack then + external_pending <= '1'; + elsif external_wr_ack or external_rd_ack then + external_pending <= '0'; + end if; + --pragma translate_off + assert_bad_ext_wr_ack: assert not external_wr_ack or (external_pending or external_req) + report "An external wr_ack strobe was asserted when no external request was active"; + assert_bad_ext_rd_ack: assert not external_rd_ack or (external_pending or external_req) + report "An external rd_ack strobe was asserted when no external request was active"; + --pragma translate_on + end if; + end if; + end process; -- Read & write latencies are balanced. Stalls not required - cpuif_req_stall_rd <= '0'; - cpuif_req_stall_wr <= '0'; + -- except if external + cpuif_req_stall_rd <= external_pending; + cpuif_req_stall_wr <= external_pending; cpuif_req_masked <= cpuif_req and not (not cpuif_req_is_wr and cpuif_req_stall_rd) and not (cpuif_req_is_wr and cpuif_req_stall_wr); @@ -969,14 +999,18 @@ begin result := '1' when unsigned(L) = R else '0'; return result; end; + variable is_external: std_logic; begin + is_external := '0'; decoded_reg_strb.Hash_ID_Low <= cpuif_req_masked and (cpuif_addr = 16#0#); decoded_reg_strb.Hash_ID_High <= cpuif_req_masked and (cpuif_addr = 16#4#); decoded_reg_strb.MSK_Init <= cpuif_req_masked and (cpuif_addr = 16#8#); decoded_reg_strb.MSK_Control <= cpuif_req_masked and (cpuif_addr = 16#C#); decoded_reg_strb.MSK_Status <= cpuif_req_masked and (cpuif_addr = 16#10#); decoded_reg_strb.Tx_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#14#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#14#)) and not cpuif_req_is_wr); decoded_reg_strb.Tx_Enable_Count <= cpuif_req_masked and (cpuif_addr = 16#18#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#18#)) and not cpuif_req_is_wr); decoded_reg_strb.Fb_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#1C#); decoded_reg_strb.TX_F1_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#20#); decoded_reg_strb.TX_F2_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#24#); @@ -991,21 +1025,33 @@ begin decoded_reg_strb.PRBS_Polynomial <= cpuif_req_masked and (cpuif_addr = 16#48#); decoded_reg_strb.PRBS_Error_Mask <= cpuif_req_masked and (cpuif_addr = 16#4C#); decoded_reg_strb.PRBS_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#50#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#50#)) and not cpuif_req_is_wr); decoded_reg_strb.PRBS_Error_Count <= cpuif_req_masked and (cpuif_addr = 16#54#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#54#)) and not cpuif_req_is_wr); decoded_reg_strb.LPF_Accum_F1 <= cpuif_req_masked and (cpuif_addr = 16#58#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#58#)) and not cpuif_req_is_wr); decoded_reg_strb.LPF_Accum_F2 <= cpuif_req_masked and (cpuif_addr = 16#5C#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#5C#)) and not cpuif_req_is_wr); decoded_reg_strb.axis_xfer_count <= cpuif_req_masked and (cpuif_addr = 16#60#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#60#)) and not cpuif_req_is_wr); decoded_reg_strb.Rx_Sample_Discard <= cpuif_req_masked and (cpuif_addr = 16#64#); decoded_reg_strb.LPF_Config_2 <= cpuif_req_masked and (cpuif_addr = 16#68#); decoded_reg_strb.f1_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#6C#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#6C#)) and not cpuif_req_is_wr); decoded_reg_strb.f2_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#70#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#70#)) and not cpuif_req_is_wr); decoded_reg_strb.f1_error <= cpuif_req_masked and (cpuif_addr = 16#74#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#74#)) and not cpuif_req_is_wr); decoded_reg_strb.f2_error <= cpuif_req_masked and (cpuif_addr = 16#78#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#78#)) and not cpuif_req_is_wr); decoded_reg_strb.Tx_Sync_Ctrl <= cpuif_req_masked and (cpuif_addr = 16#7C#); decoded_reg_strb.Tx_Sync_Cnt <= cpuif_req_masked and (cpuif_addr = 16#80#); decoded_reg_strb.lowpass_ema_alpha1 <= cpuif_req_masked and (cpuif_addr = 16#84#); decoded_reg_strb.lowpass_ema_alpha2 <= cpuif_req_masked and (cpuif_addr = 16#88#); decoded_reg_strb.rx_power <= cpuif_req_masked and (cpuif_addr = 16#8C#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#8C#)) and not cpuif_req_is_wr); + decoded_strb_is_external <= is_external; + external_req <= is_external; end process; -- Pass down signals to next stage @@ -1255,6 +1301,12 @@ begin end process; hwif_out.MSK_Control.diff_encoder_loopback.value <= field_storage.MSK_Control.diff_encoder_loopback.value; + hwif_out.Tx_Bit_Count.req <= decoded_reg_strb.Tx_Bit_Count when not decoded_req_is_wr else '0'; + hwif_out.Tx_Bit_Count.req_is_wr <= decoded_req_is_wr; + + hwif_out.Tx_Enable_Count.req <= decoded_reg_strb.Tx_Enable_Count when not decoded_req_is_wr else '0'; + hwif_out.Tx_Enable_Count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.Fb_FreqWord.config_data process(all) variable next_c: std_logic_vector(31 downto 0); @@ -1902,6 +1954,21 @@ begin end process; hwif_out.PRBS_Error_Mask.config_data.value <= field_storage.PRBS_Error_Mask.config_data.value; + hwif_out.PRBS_Bit_Count.req <= decoded_reg_strb.PRBS_Bit_Count when not decoded_req_is_wr else '0'; + hwif_out.PRBS_Bit_Count.req_is_wr <= decoded_req_is_wr; + + hwif_out.PRBS_Error_Count.req <= decoded_reg_strb.PRBS_Error_Count when not decoded_req_is_wr else '0'; + hwif_out.PRBS_Error_Count.req_is_wr <= decoded_req_is_wr; + + hwif_out.LPF_Accum_F1.req <= decoded_reg_strb.LPF_Accum_F1 when not decoded_req_is_wr else '0'; + hwif_out.LPF_Accum_F1.req_is_wr <= decoded_req_is_wr; + + hwif_out.LPF_Accum_F2.req <= decoded_reg_strb.LPF_Accum_F2 when not decoded_req_is_wr else '0'; + hwif_out.LPF_Accum_F2.req_is_wr <= decoded_req_is_wr; + + hwif_out.axis_xfer_count.req <= decoded_reg_strb.axis_xfer_count when not decoded_req_is_wr else '0'; + hwif_out.axis_xfer_count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard process(all) variable next_c: std_logic_vector(7 downto 0); @@ -2018,6 +2085,18 @@ begin end process; hwif_out.LPF_Config_2.p_shift.value <= field_storage.LPF_Config_2.p_shift.value; + hwif_out.f1_nco_adjust.req <= decoded_reg_strb.f1_nco_adjust when not decoded_req_is_wr else '0'; + hwif_out.f1_nco_adjust.req_is_wr <= decoded_req_is_wr; + + hwif_out.f2_nco_adjust.req <= decoded_reg_strb.f2_nco_adjust when not decoded_req_is_wr else '0'; + hwif_out.f2_nco_adjust.req_is_wr <= decoded_req_is_wr; + + hwif_out.f1_error.req <= decoded_reg_strb.f1_error when not decoded_req_is_wr else '0'; + hwif_out.f1_error.req_is_wr <= decoded_req_is_wr; + + hwif_out.f2_error.req <= decoded_reg_strb.f2_error when not decoded_req_is_wr else '0'; + hwif_out.f2_error.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena process(all) variable next_c: std_logic; @@ -2221,16 +2300,46 @@ begin end process; hwif_out.lowpass_ema_alpha2.alpha.value <= field_storage.lowpass_ema_alpha2.alpha.value; + hwif_out.rx_power.req <= decoded_reg_strb.rx_power when not decoded_req_is_wr else '0'; + hwif_out.rx_power.req_is_wr <= decoded_req_is_wr; + ---------------------------------------------------------------------------- -- Write response ---------------------------------------------------------------------------- - cpuif_wr_ack <= decoded_req and decoded_req_is_wr; + process(all) + variable wr_ack: std_logic; + begin + wr_ack := '0'; + + external_wr_ack <= wr_ack; + end process; + cpuif_wr_ack <= external_wr_ack or (decoded_req and decoded_req_is_wr and not decoded_strb_is_external); -- Writes are always granted with no error response cpuif_wr_err <= '0'; ---------------------------------------------------------------------------- -- Readback ---------------------------------------------------------------------------- + process(all) + variable rd_ack: std_logic; + begin + rd_ack := '0'; + rd_ack := rd_ack or hwif_in.Tx_Bit_Count.rd_ack; + rd_ack := rd_ack or hwif_in.Tx_Enable_Count.rd_ack; + rd_ack := rd_ack or hwif_in.PRBS_Bit_Count.rd_ack; + rd_ack := rd_ack or hwif_in.PRBS_Error_Count.rd_ack; + rd_ack := rd_ack or hwif_in.LPF_Accum_F1.rd_ack; + rd_ack := rd_ack or hwif_in.LPF_Accum_F2.rd_ack; + rd_ack := rd_ack or hwif_in.axis_xfer_count.rd_ack; + rd_ack := rd_ack or hwif_in.f1_nco_adjust.rd_ack; + rd_ack := rd_ack or hwif_in.f2_nco_adjust.rd_ack; + rd_ack := rd_ack or hwif_in.f1_error.rd_ack; + rd_ack := rd_ack or hwif_in.f2_error.rd_ack; + rd_ack := rd_ack or hwif_in.rx_power.rd_ack; + readback_external_rd_ack_c <= rd_ack; + end process; + + readback_external_rd_ack <= readback_external_rd_ack_c; -- Assign readback values to a flattened array readback_array(0)(31 downto 0) <= 32x"AAAA5555" when (decoded_reg_strb.Hash_ID_Low and not decoded_req_is_wr) else (others => '0'); @@ -2250,8 +2359,8 @@ begin readback_array(4)(2 downto 2) <= to_std_logic_vector(hwif_in.MSK_Status.rx_enable.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); readback_array(4)(3 downto 3) <= to_std_logic_vector(hwif_in.MSK_Status.tx_axis_valid.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); readback_array(4)(31 downto 4) <= (others => '0'); - readback_array(5)(31 downto 0) <= hwif_in.Tx_Bit_Count.tx_bit_counter.next_q when (decoded_reg_strb.Tx_Bit_Count and not decoded_req_is_wr) else (others => '0'); - readback_array(6)(31 downto 0) <= hwif_in.Tx_Enable_Count.tx_ena_counter.next_q when (decoded_reg_strb.Tx_Enable_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(5) <= hwif_in.Tx_Bit_Count.rd_data when hwif_in.Tx_Bit_Count.rd_ack else (others => '0'); + readback_array(6) <= hwif_in.Tx_Enable_Count.rd_data when hwif_in.Tx_Enable_Count.rd_ack else (others => '0'); readback_array(7)(31 downto 0) <= field_storage.Fb_FreqWord.config_data.value when (decoded_reg_strb.Fb_FreqWord and not decoded_req_is_wr) else (others => '0'); readback_array(8)(31 downto 0) <= field_storage.TX_F1_FreqWord.config_data.value when (decoded_reg_strb.TX_F1_FreqWord and not decoded_req_is_wr) else (others => '0'); readback_array(9)(31 downto 0) <= field_storage.TX_F2_FreqWord.config_data.value when (decoded_reg_strb.TX_F2_FreqWord and not decoded_req_is_wr) else (others => '0'); @@ -2274,20 +2383,20 @@ begin readback_array(17)(31 downto 0) <= field_storage.PRBS_Initial_State.config_data.value when (decoded_reg_strb.PRBS_Initial_State and not decoded_req_is_wr) else (others => '0'); readback_array(18)(31 downto 0) <= field_storage.PRBS_Polynomial.config_data.value when (decoded_reg_strb.PRBS_Polynomial and not decoded_req_is_wr) else (others => '0'); readback_array(19)(31 downto 0) <= field_storage.PRBS_Error_Mask.config_data.value when (decoded_reg_strb.PRBS_Error_Mask and not decoded_req_is_wr) else (others => '0'); - readback_array(20)(31 downto 0) <= hwif_in.PRBS_Bit_Count.status_data.next_q when (decoded_reg_strb.PRBS_Bit_Count and not decoded_req_is_wr) else (others => '0'); - readback_array(21)(31 downto 0) <= hwif_in.PRBS_Error_Count.status_data.next_q when (decoded_reg_strb.PRBS_Error_Count and not decoded_req_is_wr) else (others => '0'); - readback_array(22)(31 downto 0) <= hwif_in.LPF_Accum_F1.status_data.next_q when (decoded_reg_strb.LPF_Accum_F1 and not decoded_req_is_wr) else (others => '0'); - readback_array(23)(31 downto 0) <= hwif_in.LPF_Accum_F2.status_data.next_q when (decoded_reg_strb.LPF_Accum_F2 and not decoded_req_is_wr) else (others => '0'); - readback_array(24)(31 downto 0) <= hwif_in.axis_xfer_count.xfer_count.next_q when (decoded_reg_strb.axis_xfer_count and not decoded_req_is_wr) else (others => '0'); + readback_array(20) <= hwif_in.PRBS_Bit_Count.rd_data when hwif_in.PRBS_Bit_Count.rd_ack else (others => '0'); + readback_array(21) <= hwif_in.PRBS_Error_Count.rd_data when hwif_in.PRBS_Error_Count.rd_ack else (others => '0'); + readback_array(22) <= hwif_in.LPF_Accum_F1.rd_data when hwif_in.LPF_Accum_F1.rd_ack else (others => '0'); + readback_array(23) <= hwif_in.LPF_Accum_F2.rd_data when hwif_in.LPF_Accum_F2.rd_ack else (others => '0'); + readback_array(24) <= hwif_in.axis_xfer_count.rd_data when hwif_in.axis_xfer_count.rd_ack else (others => '0'); readback_array(25)(7 downto 0) <= field_storage.Rx_Sample_Discard.rx_sample_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); readback_array(25)(15 downto 8) <= field_storage.Rx_Sample_Discard.rx_nco_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); readback_array(25)(31 downto 16) <= (others => '0'); readback_array(26)(23 downto 0) <= field_storage.LPF_Config_2.p_gain.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); readback_array(26)(31 downto 24) <= field_storage.LPF_Config_2.p_shift.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); - readback_array(27)(31 downto 0) <= hwif_in.f1_nco_adjust.data.next_q when (decoded_reg_strb.f1_nco_adjust and not decoded_req_is_wr) else (others => '0'); - readback_array(28)(31 downto 0) <= hwif_in.f2_nco_adjust.data.next_q when (decoded_reg_strb.f2_nco_adjust and not decoded_req_is_wr) else (others => '0'); - readback_array(29)(31 downto 0) <= hwif_in.f1_error.data.next_q when (decoded_reg_strb.f1_error and not decoded_req_is_wr) else (others => '0'); - readback_array(30)(31 downto 0) <= hwif_in.f2_error.data.next_q when (decoded_reg_strb.f2_error and not decoded_req_is_wr) else (others => '0'); + readback_array(27) <= hwif_in.f1_nco_adjust.rd_data when hwif_in.f1_nco_adjust.rd_ack else (others => '0'); + readback_array(28) <= hwif_in.f2_nco_adjust.rd_data when hwif_in.f2_nco_adjust.rd_ack else (others => '0'); + readback_array(29) <= hwif_in.f1_error.rd_data when hwif_in.f1_error.rd_ack else (others => '0'); + readback_array(30) <= hwif_in.f2_error.rd_data when hwif_in.f2_error.rd_ack else (others => '0'); readback_array(31)(0 downto 0) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_ena.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); readback_array(31)(1 downto 1) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_force.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); readback_array(31)(2 downto 2) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_f1.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); @@ -2299,14 +2408,13 @@ begin readback_array(33)(31 downto 18) <= (others => '0'); readback_array(34)(17 downto 0) <= field_storage.lowpass_ema_alpha2.alpha.value when (decoded_reg_strb.lowpass_ema_alpha2 and not decoded_req_is_wr) else (others => '0'); readback_array(34)(31 downto 18) <= (others => '0'); - readback_array(35)(22 downto 0) <= hwif_in.rx_power.rx_power.next_q when (decoded_reg_strb.rx_power and not decoded_req_is_wr) else (others => '0'); - readback_array(35)(31 downto 23) <= (others => '0'); + readback_array(35) <= hwif_in.rx_power.rd_data when hwif_in.rx_power.rd_ack else (others => '0'); -- Reduce the array process(all) variable readback_data_var : std_logic_vector(31 downto 0) := (others => '0'); begin - readback_done <= decoded_req and not decoded_req_is_wr; + readback_done <= decoded_req and not decoded_req_is_wr and not decoded_strb_is_external; readback_err <= '0'; readback_data_var := (others => '0'); for i in readback_array'RANGE loop @@ -2315,7 +2423,8 @@ begin readback_data <= readback_data_var; end process; - cpuif_rd_ack <= readback_done; + external_rd_ack <= readback_external_rd_ack; + cpuif_rd_ack <= readback_done or readback_external_rd_ack; cpuif_rd_data <= readback_data; cpuif_rd_err <= readback_err; end architecture rtl; diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd index a362018..c00bed8 100644 --- a/rdl/outputs/rtl/msk_top_regs_pkg.vhd +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -34,116 +34,80 @@ package msk_top_regs_pkg is tx_axis_valid : \msk_top_regs.msk_stat_0.tx_axis_valid_in_t\; end record; - type \msk_top_regs.msk_stat_1.tx_bit_counter_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_1__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.msk_stat_1_in_t\ is record - tx_bit_counter : \msk_top_regs.msk_stat_1.tx_bit_counter_in_t\; + type \msk_top_regs.msk_stat_2__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.msk_stat_2.tx_ena_counter_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_bits__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.msk_stat_2_in_t\ is record - tx_ena_counter : \msk_top_regs.msk_stat_2.tx_ena_counter_in_t\; + type \msk_top_regs.stat_32_errs__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_bits.status_data_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_bits_in_t\ is record - status_data : \msk_top_regs.stat_32_bits.status_data_in_t\; + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_errs.status_data_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_3__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_errs_in_t\ is record - status_data : \msk_top_regs.stat_32_errs.status_data_in_t\; + type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.status_data_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\ is record - status_data : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.status_data_in_t\; + type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.status_data_in_t\ is record - next_q : std_logic_vector(31 downto 0); + type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; - type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\ is record - status_data : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.status_data_in_t\; - end record; - - type \msk_top_regs.msk_stat_3.xfer_count_in_t\ is record - next_q : std_logic_vector(31 downto 0); - end record; - - type \msk_top_regs.msk_stat_3_in_t\ is record - xfer_count : \msk_top_regs.msk_stat_3.xfer_count_in_t\; - end record; - - type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\ is record - next_q : std_logic_vector(31 downto 0); - end record; - - type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\ is record - data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\; - end record; - - type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\ is record - next_q : std_logic_vector(31 downto 0); - end record; - - type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\ is record - data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\; - end record; - - type \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\ is record - next_q : std_logic_vector(31 downto 0); - end record; - - type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\ is record - data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\; - end record; - - type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\ is record - next_q : std_logic_vector(31 downto 0); - end record; - - type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\ is record - data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\; - end record; - - type \msk_top_regs.rx_power.rx_power_in_t\ is record - next_q : std_logic_vector(22 downto 0); - end record; - - type \msk_top_regs.rx_power_in_t\ is record - rx_power : \msk_top_regs.rx_power.rx_power_in_t\; + type \msk_top_regs.rx_power__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); end record; type msk_top_regs_in_t is record MSK_Status : \msk_top_regs.msk_stat_0_in_t\; - Tx_Bit_Count : \msk_top_regs.msk_stat_1_in_t\; - Tx_Enable_Count : \msk_top_regs.msk_stat_2_in_t\; - PRBS_Bit_Count : \msk_top_regs.stat_32_bits_in_t\; - PRBS_Error_Count : \msk_top_regs.stat_32_errs_in_t\; - LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\; - LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\; - axis_xfer_count : \msk_top_regs.msk_stat_3_in_t\; - f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\; - f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\; - f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\; - f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\; - rx_power : \msk_top_regs.rx_power_in_t\; + Tx_Bit_Count : \msk_top_regs.msk_stat_1__external_in_t\; + Tx_Enable_Count : \msk_top_regs.msk_stat_2__external_in_t\; + PRBS_Bit_Count : \msk_top_regs.stat_32_bits__external_in_t\; + PRBS_Error_Count : \msk_top_regs.stat_32_errs__external_in_t\; + LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_in_t\; + LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_in_t\; + axis_xfer_count : \msk_top_regs.msk_stat_3__external_in_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_in_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_in_t\; + f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_in_t\; + f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_in_t\; + rx_power : \msk_top_regs.rx_power__external_in_t\; end record; type \msk_top_regs.msk_init.txrxinit_out_t\ is record @@ -192,6 +156,16 @@ package msk_top_regs_pkg is diff_encoder_loopback : \msk_top_regs.msk_ctrl.diff_encoder_loopback_out_t\; end record; + type \msk_top_regs.msk_stat_1__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.msk_stat_2__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + type \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469.config_data_out_t\ is record value : std_logic_vector(31 downto 0); end record; @@ -341,6 +315,31 @@ package msk_top_regs_pkg is config_data : \msk_top_regs.config_prbs_errmask.config_data_out_t\; end record; + type \msk_top_regs.stat_32_bits__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.stat_32_errs__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.msk_stat_3__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + type \msk_top_regs.rx_sample_discard.rx_sample_discard_out_t\ is record value : std_logic_vector(7 downto 0); end record; @@ -367,6 +366,26 @@ package msk_top_regs_pkg is p_shift : \msk_top_regs.lpf_config_2.p_shift_out_t\; end record; + type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + type \msk_top_regs.tx_sync_ctrl.tx_sync_ena_out_t\ is record value : std_logic; end record; @@ -406,9 +425,16 @@ package msk_top_regs_pkg is alpha : \msk_top_regs.lowpass_ema_alpha.alpha_out_t\; end record; + type \msk_top_regs.rx_power__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + type msk_top_regs_out_t is record MSK_Init : \msk_top_regs.msk_init_out_t\; MSK_Control : \msk_top_regs.msk_ctrl_out_t\; + Tx_Bit_Count : \msk_top_regs.msk_stat_1__external_out_t\; + Tx_Enable_Count : \msk_top_regs.msk_stat_2__external_out_t\; Fb_FreqWord : \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469_out_t\; TX_F1_FreqWord : \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c_out_t\; TX_F2_FreqWord : \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51_out_t\; @@ -422,11 +448,21 @@ package msk_top_regs_pkg is PRBS_Initial_State : \msk_top_regs.config_prbs_seed_out_t\; PRBS_Polynomial : \msk_top_regs.config_prbs_poly_out_t\; PRBS_Error_Mask : \msk_top_regs.config_prbs_errmask_out_t\; + PRBS_Bit_Count : \msk_top_regs.stat_32_bits__external_out_t\; + PRBS_Error_Count : \msk_top_regs.stat_32_errs__external_out_t\; + LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_out_t\; + LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_out_t\; + axis_xfer_count : \msk_top_regs.msk_stat_3__external_out_t\; Rx_Sample_Discard : \msk_top_regs.rx_sample_discard_out_t\; LPF_Config_2 : \msk_top_regs.lpf_config_2_out_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_out_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_out_t\; + f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_out_t\; + f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_out_t\; Tx_Sync_Ctrl : \msk_top_regs.tx_sync_ctrl_out_t\; Tx_Sync_Cnt : \msk_top_regs.tx_sync_cnt_out_t\; lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha_out_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha_out_t\; + rx_power : \msk_top_regs.rx_power__external_out_t\; end record; end package; diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index 207c848..c293d19 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -182,6 +182,7 @@ addrmap msk_top_regs { desc = "Count of data requests made by modem"; sw = r; hw = w; + onread = ruser; } tx_bit_counter[31:0]; }; @@ -194,6 +195,7 @@ addrmap msk_top_regs { name = "Tx Enable Count"; sw = r; hw = w; + onread = ruser; } tx_ena_counter[31:0] = 0; }; @@ -470,6 +472,7 @@ addrmap msk_top_regs { fieldwidth = 32; sw = r; hw = w; + onread = ruser; }; reg observation_data { @@ -483,8 +486,8 @@ addrmap msk_top_regs { msk_init MSK_Init; msk_ctrl MSK_Control; msk_stat_0 MSK_Status; - msk_stat_1 Tx_Bit_Count; - msk_stat_2 Tx_Enable_Count; + external msk_stat_1 Tx_Bit_Count; + external msk_stat_2 Tx_Enable_Count; config_nco_fw Fb_FreqWord; Fb_FreqWord->desc = "Set Modem Data Rate"; Fb_FreqWord->name = "Bitrate NCO Frequency Control Word"; @@ -512,33 +515,33 @@ addrmap msk_top_regs { config_prbs_seed PRBS_Initial_State; config_prbs_poly PRBS_Polynomial; config_prbs_errmask PRBS_Error_Mask; - stat_32_bits PRBS_Bit_Count; - stat_32_errs PRBS_Error_Count; - stat_32_lpf_acc LPF_Accum_F1; + external stat_32_bits PRBS_Bit_Count; + external stat_32_errs PRBS_Error_Count; + external stat_32_lpf_acc LPF_Accum_F1; LPF_Accum_F1->name = "F1 PI Controller Accumulator"; LPF_Accum_F1->desc = "Value of the F1 PI Controller Accumulator"; - stat_32_lpf_acc LPF_Accum_F2; + external stat_32_lpf_acc LPF_Accum_F2; LPF_Accum_F2->name = "F2 PI Controller Accumulator"; LPF_Accum_F2->desc = "Value of the F2 PI Controller Accumulator"; - msk_stat_3 axis_xfer_count; + external msk_stat_3 axis_xfer_count; rx_sample_discard Rx_Sample_Discard; lpf_config_2 LPF_Config_2; - observation_data f1_nco_adjust; + external observation_data f1_nco_adjust; f1_nco_adjust->name = "F1 NCO Frequency Adjust"; f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; - observation_data f2_nco_adjust; + external observation_data f2_nco_adjust; f2_nco_adjust->name = "F2 NCO Frequency Adjust"; f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; - observation_data f1_error; + external observation_data f1_error; f1_error->name = "F1 Error Value"; f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; f1_error.data->name = "F1 Error Value"; f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; - observation_data f2_error; + external observation_data f2_error; f2_error->name = "F2 Error Value"; f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; f2_error.data->name = "F2 Error Value"; @@ -547,6 +550,6 @@ addrmap msk_top_regs { tx_sync_cnt Tx_Sync_Cnt; lowpass_ema_alpha lowpass_ema_alpha1; lowpass_ema_alpha lowpass_ema_alpha2; - rx_power rx_power; + external rx_power rx_power; }; diff --git a/sim/Makefile b/sim/Makefile index d983c1c..b41afca 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -24,6 +24,8 @@ VHDL_SOURCES += $(RDL)/src/axi4lite_intf_pkg.vhd \ $(RDL)/src/reg_utils.vhd \ $(RDL)/outputs/rtl/msk_top_regs_pkg.vhd \ $(RDL)/outputs/rtl/msk_top_regs.vhd \ + $(SRC)/pulse_detect.vhd \ + $(SRC)/data_capture.vhd \ $(SRC)/cdc_resync.vhd \ $(SRC)/axis_async_fifo.vhd \ $(SRC)/axis_dma_adapter.vhd \ diff --git a/sim/msk_test.py b/sim/msk_test.py index 04a6aa2..f595209 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -281,11 +281,11 @@ async def read(self, addr, width, accesswidth): self.rready.value = 0 - await RisingEdge(self.aclk) - await RisingEdge(self.aclk) + read_data = self.rdata.value.integer + await RisingEdge(self.aclk) - return self.rdata.value.integer + return read_data async def write(self, addr, width, accesswidth, data): @@ -748,7 +748,7 @@ async def msk_test_1(dut): hash_id = await regs.Hash_ID_Low.read() hash_id = await regs.Hash_ID_Low.read() print("Hash ID Low: ", hex(hash_id)) - hash_id = await regs.Hash_ID_High.read() + hash_id = await regs.Hash_ID_High.read() print("Hash ID High: ", hex(hash_id)) await Timer(100, units="ns") @@ -770,8 +770,8 @@ async def msk_test_1(dut): await cocotb.start(msksim.rx_sample_capture()) await cocotb.start(ducsim.upconvert()) await cocotb.start(ddcsim.downconvert()) - await cocotb.start(pn.generate_data()) - await cocotb.start(pn.check_data()) + # await cocotb.start(pn.generate_data()) + # await cocotb.start(pn.check_data()) sim_time = get_sim_time("us") sim_start = sim_time diff --git a/src/cdc_resync.vhd b/src/cdc_resync.vhd index 027ac44..d5f7128 100644 --- a/src/cdc_resync.vhd +++ b/src/cdc_resync.vhd @@ -69,12 +69,9 @@ USE ieee.numeric_std.ALL; -- Entity ENTITY cdc_resync IS - GENERIC ( - STAGES : NATURAL := 2 - ); PORT ( clk : IN std_logic; - resetn : IN std_logic; + sync_reset : IN std_logic; di : IN std_logic; do : OUT std_logic @@ -83,18 +80,20 @@ END ENTITY cdc_resync; ARCHITECTURE rtl OF cdc_resync IS - SIGNAL di_s : std_logic_vector(0 TO STAGES-1); + SIGNAL di_s : std_logic_vector(0 TO 1); BEGIN - do <= di_s(STAGES -1); + do <= di_s(1); - resync : PROCESS (clk, resetn) + resync : PROCESS (clk) BEGIN - IF resetn = '0' THEN - di_s <= (OTHERS => '0'); - ELSIF clk'EVENT AND clk = '1' THEN - di_s <= di & di_s(0 TO STAGES-2); + IF clk'EVENT AND clk = '1' THEN + IF sync_reset = '1' THEN + di_s <= (OTHERS => '0'); + ELSE + di_s <= di & di_s(0 TO 0); + END IF; END IF; END PROCESS resync; diff --git a/src/data_capture.vhd b/src/data_capture.vhd new file mode 100644 index 0000000..71a3bc8 --- /dev/null +++ b/src/data_capture.vhd @@ -0,0 +1,102 @@ +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- _______ ________ ______ +-- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +-- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +-- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +-- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +-- /_/ +-- ________ _____ _____ _____ _____ +-- ____ _/_______ __________ /____(_)__ /_____ ____ /______ +-- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +-- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +-- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- Copyright +------------------------------------------------------------------------------------------------------ +-- +-- Copyright 2025 by M. Wishek +-- +------------------------------------------------------------------------------------------------------ +-- License +------------------------------------------------------------------------------------------------------ +-- +-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +-- +-- You may redistribute and modify this source and make products using it under +-- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +-- +-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +-- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- Please see the CERN-OHL-W v2 for applicable conditions. +-- +-- Source location: TBD +-- +-- As per CERN-OHL-W v2 section 4.1, should You produce hardware based on this +-- source, You must maintain the Source Location visible on the external case of +-- the products you make using this source. +-- +------------------------------------------------------------------------------------------------------ +-- Block name and description +------------------------------------------------------------------------------------------------------ +-- +-- This is a wrapper block for the register module generated by DesyRDL. +-- +-- Documentation location: TBD +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ + + +------------------------------------------------------------------------------------------------------ +-- ╦ ┬┌┐ ┬─┐┌─┐┬─┐┬┌─┐┌─┐ +-- ║ │├┴┐├┬┘├─┤├┬┘│├┤ └─┐ +-- ╩═╝┴└─┘┴└─┴ ┴┴└─┴└─┘└─┘ +------------------------------------------------------------------------------------------------------ +-- Libraries + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +------------------------------------------------------------------------------------------------------ +-- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ +-- ║╣ │││ │ │ │ └┬┘ +-- ╚═╝┘└┘ ┴ ┴ ┴ ┴ +------------------------------------------------------------------------------------------------------ +-- Entity + +ENTITY data_capture IS + GENERIC ( + data_width : natural := 32 + ); + PORT ( + clk : IN std_logic; + sync_reset : IN std_logic; + + capture : IN std_logic; + + di : IN std_logic_vector(data_width -1 DOWNTO 0); + do : OUT std_logic_vector(data_width -1 DOWNTO 0) + ); +END ENTITY data_capture; + +ARCHITECTURE rtl OF data_capture IS +BEGIN + + capture_proc : PROCESS (clk) + BEGIN + IF clk'EVENT AND clk = '1' THEN + IF sync_reset = '1' THEN + do <= (OTHERS => '0'); + ELSIF capture = '1' THEN + do <= di; + END IF; + END IF; + END PROCESS capture_proc; + +END ARCHITECTURE rtl; + + diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index b8b1780..9fa83bd 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -188,18 +188,57 @@ ARCHITECTURE rtl OF msk_top_csr IS SIGNAL txrxinit : std_logic; COMPONENT cdc_resync IS - GENERIC ( - STAGES : NATURAL := 2 - ); PORT ( clk : IN std_logic; - resetn : IN std_logic; + sync_reset : IN std_logic; di : IN std_logic; do : OUT std_logic ); END COMPONENT cdc_resync; + COMPONENT pulse_detect IS + PORT ( + clk : IN std_logic; + sync_reset : IN std_logic; + + di : IN std_logic; + do : OUT std_logic + ); + END COMPONENT pulse_detect; + + COMPONENT data_capture IS + GENERIC ( + data_width : natural := 32 + ); + PORT ( + clk : IN std_logic; + sync_reset : IN std_logic; + + capture : IN std_logic; + + di : IN std_logic_vector(data_width -1 DOWNTO 0); + do : OUT std_logic_vector(data_width -1 DOWNTO 0) + ); + END COMPONENT data_capture; + + SIGNAL csr_meta : std_logic; + SIGNAL csr_init : std_logic; + + SIGNAL tx_bit_counter_req : std_logic; + SIGNAL tx_ena_counter_req : std_logic; + SIGNAL f1_error_req : std_logic; + SIGNAL f2_error_req : std_logic; + SIGNAL f1_nco_adjust_req : std_logic; + SIGNAL f2_nco_adjust_req : std_logic; + + SIGNAL prbs_bits_req : std_logic; + SIGNAL prbs_errs_req : std_logic; + SIGNAL lpf_accum_f1_req : std_logic; + SIGNAL lpf_accum_f2_req : std_logic; + SIGNAL pd_power_req : std_logic; + SIGNAL axis_xfer_count_req : std_logic; + BEGIN s_axil_i.AWVALID <= s_axi_awvalid; @@ -225,7 +264,7 @@ BEGIN u_msk_regs : ENTITY work.msk_top_regs(rtl) PORT MAP ( - clk => s_axi_aclk, + clk => s_axi_aclk, rst => NOT s_axi_aresetn, s_axil_i => s_axil_i, s_axil_o => s_axil_o, @@ -234,41 +273,83 @@ BEGIN hwif_out => hwif_out ); - -- Status signals crossing from local clock domain to the AXI clock domain - hwif_in.MSK_Status.demod_sync_lock.next_q <= '0'; - hwif_in.MSK_Status.tx_enable.next_q <= tx_enable; - hwif_in.MSK_Status.rx_enable.next_q <= rx_enable; - hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; - hwif_in.Tx_Bit_Count.tx_bit_counter.next_q <= tx_bit_counter; - hwif_in.Tx_Enable_Count.tx_ena_counter.next_q <= tx_ena_counter; - hwif_in.axis_xfer_count.xfer_count.next_q <= xfer_count; - hwif_in.PRBS_Bit_Count.status_data.next_q <= prbs_bits; - hwif_in.PRBS_Error_Count.status_data.next_q <= prbs_errs; - hwif_in.LPF_Accum_F1.status_data.next_q <= lpf_accum_f1; - hwif_in.LPF_Accum_F2.status_data.next_q <= lpf_accum_f2; - hwif_in.f1_nco_adjust.data.next_q <= f1_nco_adjust; - hwif_in.f2_nco_adjust.data.next_q <= f2_nco_adjust; - hwif_in.f1_error.data.next_q <= f1_error; - hwif_in.f2_error.data.next_q <= f2_error; - hwif_in.rx_power.rx_power.next_q <= pd_power; - - -- Control signals requiring re-sync from AXI clock domain to local clock domain - u01s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.txrxinit.value, txrxinit ); - u02s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.txinit.value OR txrxinit, txinit ); - u03s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Init.rxinit.value OR txrxinit, rxinit ); - u04s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.ptt.value, ptt ); - u05s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.loopback_ena.value, loopback_ena ); - u06s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.diff_encoder_loopback.value, diff_encdec_lbk_ena ); - u07s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.rx_invert.value, rx_invert ); - u08s: cdc_resync PORT MAP (clk, '1', hwif_out.MSK_Control.clear_counts.value, clear_counts ); - u09s: cdc_resync PORT MAP (clk, '1', hwif_out.LPF_Config_0.lpf_freeze.value, lpf_freeze ); - u10s: cdc_resync PORT MAP (clk, '1', hwif_out.LPF_Config_0.lpf_zero.value, lpf_zero ); - u11s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_sel.value, prbs_sel ); - u12s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_clear.value, prbs_clear ); - u13s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_error_insert.value, prbs_err_insert ); - u14s: cdc_resync PORT MAP (clk, '1', hwif_out.PRBS_Control.prbs_manual_sync.value, prbs_manual_sync ); - u15s: cdc_resync PORT MAP (clk, '1', hwif_out.Tx_Sync_Ctrl.tx_sync_ena.value, tx_sync_ena ); - u16s: cdc_resync PORT MAP (clk, '1', hwif_out.Tx_Sync_Ctrl.tx_sync_force.value, tx_sync_force ); + csr_init_proc : PROCESS (clk, s_axi_aresetn) + BEGIN + IF s_axi_aresetn = '0' THEN + csr_meta <= '1'; + csr_init <= '1'; + ELSIF clk'EVENT AND clk = '1' THEN + csr_meta <= '0'; + csr_init <= csr_meta; + END IF; + END PROCESS csr_init_proc; + + ulck_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, '0', hwif_in.MSK_Status.demod_sync_lock.next_q); + utxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_enable, hwif_in.MSK_Status.tx_enable.next_q); + urxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_enable, hwif_in.MSK_Status.rx_enable.next_q); + + hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; + + -- Status Request from AXI to MDM + utbc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Bit_Count.req, tx_bit_counter_req ); + utbe_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Enable_Count.req, tx_ena_counter_req ); + utatc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.axis_xfer_count.req, axis_xfer_count_req ); + utf1e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_error.req, f1_error_req ); + utf2e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_error.req, f2_error_req ); + utf1a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_nco_adjust.req, f1_nco_adjust_req ); + utf2a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_nco_adjust.req, f2_nco_adjust_req ); + utprb_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Bit_Count.req, prbs_bits_req ); + utpre_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Error_Count.req, prbs_errs_req ); + utlp1_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F1.req, lpf_accum_f1_req ); + utlp2_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F2.req, lpf_accum_f2_req ); + utpwr_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_power.req, pd_power_req ); + + -- Status acknowledge from MDM to AXI + utbc_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_bit_counter_req, hwif_in.Tx_Bit_Count.rd_ack ); + utbe_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_ena_counter_req, hwif_in.Tx_Enable_Count.rd_ack ); + utatc_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, axis_xfer_count_req, hwif_in.axis_xfer_count.rd_ack ); + utf1e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_error_req, hwif_in.f1_error.rd_ack ); + utf2e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_error_req, hwif_in.f2_error.rd_ack ); + utf1a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_nco_adjust_req, hwif_in.f1_nco_adjust.rd_ack ); + utf2a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_nco_adjust_req, hwif_in.f2_nco_adjust.rd_ack ); + utprb_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_bits_req, hwif_in.PRBS_Bit_Count.rd_ack ); + utpre_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_errs_req, hwif_in.PRBS_Error_Count.rd_ack ); + utlp1_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f1_req, hwif_in.LPF_Accum_F1.rd_ack ); + utlp2_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f2_req, hwif_in.LPF_Accum_F2.rd_ack ); + utpwr_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, pd_power_req, hwif_in.rx_power.rd_ack ); + + -- Status capture from MDM to AXI + utbc_c : data_capture PORT MAP (clk, csr_init, tx_bit_counter_req, tx_bit_counter, hwif_in.Tx_Bit_Count.rd_data ); + utbe_c : data_capture PORT MAP (clk, csr_init, tx_ena_counter_req, tx_ena_counter, hwif_in.Tx_Enable_Count.rd_data ); + utatc_c: data_capture PORT MAP (clk, csr_init, axis_xfer_count_req, xfer_count, hwif_in.axis_xfer_count.rd_data ); + utf1e_c: data_capture PORT MAP (clk, csr_init, f1_error_req, f1_error, hwif_in.f1_error.rd_data ); + utf2e_c: data_capture PORT MAP (clk, csr_init, f2_error_req, f2_error, hwif_in.f2_error.rd_data ); + utf1a_c: data_capture PORT MAP (clk, csr_init, f1_nco_adjust_req, f1_nco_adjust, hwif_in.f1_nco_adjust.rd_data ); + utf2a_c: data_capture PORT MAP (clk, csr_init, f2_nco_adjust_req, f2_nco_adjust, hwif_in.f2_nco_adjust.rd_data ); + utprb_c: data_capture PORT MAP (clk, csr_init, prbs_bits_req, prbs_bits, hwif_in.PRBS_Bit_Count.rd_data ); + utpre_c: data_capture PORT MAP (clk, csr_init, prbs_errs_req, prbs_errs, hwif_in.PRBS_Error_Count.rd_data); + utlp1_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f1_req, lpf_accum_f1, hwif_in.LPF_Accum_F1.rd_data ); + utlp2_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f2_req, lpf_accum_f2, hwif_in.LPF_Accum_F2.rd_data ); + utpwr_c: data_capture PORT MAP (clk, csr_init, pd_power_req, std_logic_vector(resize(unsigned(pd_power),32)), + hwif_in.rx_power.rd_data); + + -- Control from AXI to MDM + u01s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txrxinit.value, txrxinit ); + u02s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txinit.value OR txrxinit, txinit ); + u03s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.rxinit.value OR txrxinit, rxinit ); + u04s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Control.ptt.value, ptt ); + u05s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Control.loopback_ena.value, loopback_ena ); + u06s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Control.diff_encoder_loopback.value, diff_encdec_lbk_ena ); + u07s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Control.rx_invert.value, rx_invert ); + u08s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Control.clear_counts.value, clear_counts ); + u09s: cdc_resync PORT MAP (clk, csr_init, hwif_out.LPF_Config_0.lpf_freeze.value, lpf_freeze ); + u10s: cdc_resync PORT MAP (clk, csr_init, hwif_out.LPF_Config_0.lpf_zero.value, lpf_zero ); + u11s: cdc_resync PORT MAP (clk, csr_init, hwif_out.PRBS_Control.prbs_sel.value, prbs_sel ); + u12s: cdc_resync PORT MAP (clk, csr_init, hwif_out.PRBS_Control.prbs_clear.value, prbs_clear ); + u13s: cdc_resync PORT MAP (clk, csr_init, hwif_out.PRBS_Control.prbs_error_insert.value, prbs_err_insert ); + u14s: cdc_resync PORT MAP (clk, csr_init, hwif_out.PRBS_Control.prbs_manual_sync.value, prbs_manual_sync ); + u15s: cdc_resync PORT MAP (clk, csr_init, hwif_out.Tx_Sync_Ctrl.tx_sync_ena.value, tx_sync_ena ); + u16s: cdc_resync PORT MAP (clk, csr_init, hwif_out.Tx_Sync_Ctrl.tx_sync_force.value, tx_sync_force ); -- The remaining control signals also cross from the AXI to the local clock domain. These are static signals -- that are configured while the txrxinit is active. The active txrxinit hold the destination FFs to an diff --git a/src/pulse_detect.vhd b/src/pulse_detect.vhd new file mode 100644 index 0000000..a1060f3 --- /dev/null +++ b/src/pulse_detect.vhd @@ -0,0 +1,109 @@ +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- _______ ________ ______ +-- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +-- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +-- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +-- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +-- /_/ +-- ________ _____ _____ _____ _____ +-- ____ _/_______ __________ /____(_)__ /_____ ____ /______ +-- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +-- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +-- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- Copyright +------------------------------------------------------------------------------------------------------ +-- +-- Copyright 2025 by M. Wishek +-- +------------------------------------------------------------------------------------------------------ +-- License +------------------------------------------------------------------------------------------------------ +-- +-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +-- +-- You may redistribute and modify this source and make products using it under +-- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +-- +-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +-- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- Please see the CERN-OHL-W v2 for applicable conditions. +-- +-- Source location: TBD +-- +-- As per CERN-OHL-W v2 section 4.1, should You produce hardware based on this +-- source, You must maintain the Source Location visible on the external case of +-- the products you make using this source. +-- +------------------------------------------------------------------------------------------------------ +-- Block name and description +------------------------------------------------------------------------------------------------------ +-- +-- This is a wrapper block for the register module generated by DesyRDL. +-- +-- Documentation location: TBD +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ + + +------------------------------------------------------------------------------------------------------ +-- ╦ ┬┌┐ ┬─┐┌─┐┬─┐┬┌─┐┌─┐ +-- ║ │├┴┐├┬┘├─┤├┬┘│├┤ └─┐ +-- ╩═╝┴└─┘┴└─┴ ┴┴└─┴└─┘└─┘ +------------------------------------------------------------------------------------------------------ +-- Libraries + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +------------------------------------------------------------------------------------------------------ +-- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ +-- ║╣ │││ │ │ │ └┬┘ +-- ╚═╝┘└┘ ┴ ┴ ┴ ┴ +------------------------------------------------------------------------------------------------------ +-- Entity + +ENTITY pulse_detect IS + PORT ( + clk : IN std_logic; + sync_reset : IN std_logic; + + di : IN std_logic; + do : OUT std_logic + ); +END ENTITY pulse_detect; + +ARCHITECTURE rtl OF pulse_detect IS + + SIGNAL detect_q : std_logic; + SIGNAL detect_q1 : std_logic; + SIGNAL detect_q2 : std_logic; + +BEGIN + + do <= detect_q1 AND NOT detect_q2; + + detect : PROCESS (clk, di) + BEGIN + IF di = '1' THEN + detect_q <= '1'; + ELSIF clk'EVENT AND clk = '1' THEN + IF sync_reset = '1' OR detect_q2 = '1' THEN + detect_q <= '0'; + detect_q1 <= '0'; + detect_q2 <= '0'; + ELSE + detect_q1 <= detect_q; + detect_q2 <= detect_q1; + END IF; + END IF; + END PROCESS detect; + +END ARCHITECTURE rtl; + + From 3cf82bb354d565cb1dbc504db4752f2a942a2823 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Sun, 26 Oct 2025 21:46:34 -0600 Subject: [PATCH 03/60] Resolve merge/rebase conflicts --- docs/msk_math.md | 18 ++++++-- prbs | 2 +- src/axis_async_fifo.vhd | 93 ++++++++++++++++++++++++++++++++++++++++- src/msk_top.vhd | 60 ++++++++++++++++++-------- 4 files changed, 150 insertions(+), 23 deletions(-) diff --git a/docs/msk_math.md b/docs/msk_math.md index fd03d93..186dfea 100644 --- a/docs/msk_math.md +++ b/docs/msk_math.md @@ -115,10 +115,12 @@ The four resulting values for the f1 mix are cos(2𝝿f1t)*cos(2𝝿f1t) = 1/2 [ cos(2𝝿f1t - 2𝝿f1t) + cos(2𝝿f1t + 2𝝿f1t) ] = 1/2 [ cos(0) + cos(4𝝿f1t) ] = 1/2 [ 1 + cos(4𝝿f1t)] + = 1/2 + 1/2cos(2𝝿2f1t) -cos(2𝝿f1t)*cos(2𝝿f1t) = -1/2 [ cos(2𝝿f1t - 2𝝿f1t) + cos(2𝝿f1t + 2𝝿f1t) ] = -1/2 [ cos(0) + cos(4𝝿f1t) ] = -1/2 [ 1 + cos(4𝝿f1t)] + = -1/2 - 1/2cos(2𝝿2f1t) (both the previous results are a DC value and a sinusoid at 2*f1) @@ -149,16 +151,16 @@ cos(2𝝿f1t)*sin(2𝝿f1t) = 1/2 [ sin(2𝝿f1t + 2𝝿f1t + theta) - sin(2𝝿 = 1/2 sin(4𝝿f1t + theta) --cos(2𝝿f1t)*sin(2𝝿f1t) = -1/2 [ sin(2𝝿f1t + 2𝝿f1t) - sin(2𝝿f1t - 2𝝿f1t) ] - = -1/2 [ sin(4𝝿f1t) - sin(0) ] - = -1/2 sin(4𝝿f1t) +-cos(2𝝿f1t)*sin(2𝝿f1t) = -1/2 [ sin(2𝝿f1t + 2𝝿f1t + theta) - sin(2𝝿f1t - 2𝝿f1t + theta) ] + = -1/2 [ sin(2𝝿2f1t + theta) - sin(theta) ] + = -1/2 sin(2𝝿2f1t + theta) again we only care about the DC component, which when the phases are aligned is 0. If the phases are not aligned the sin(0) term becomes sin(Δφ) a constant. cos(2𝝿f1t)*sin(2𝝿f1t) = 1/2 [ sin(2𝝿f2t + 2𝝿f1t) - sin(2𝝿f2t - 2𝝿f1t) ] - = 1/2 [ sin(2𝝿(f2+f1)t) - sin(2𝝿(f2-f1)t) ] + = 1/2 [ sin(2𝝿(f2+f1)t) - sin(2𝝿(f2-f1)t) ] cos(2𝝿f1t)*sin(2𝝿f1t) = -1/2 [ sin(2𝝿f2t + 2𝝿f1t) - sin(2𝝿f2t - 2𝝿f1t) ] @@ -166,3 +168,11 @@ cos(2𝝿f1t)*sin(2𝝿f1t) = -1/2 [ sin(2𝝿f2t + 2𝝿f1t) - sin(2𝝿f2t - 2 + +error_instant = 1/2 sin(2𝝿2f1t + theta) * sign( 1/2 + 1/2cos(2𝝿2f1t)) + = -1/2 sin(2𝝿2f1t + theta) * sign(-1/2 - 1/2cos(2𝝿2f1t)) + = 1/2 sin(2𝝿2f1t + theta) + +error = SUM_T(1/2 sin(2𝝿2f1t + theta)) = -cos(2𝝿2f1t + theta) + C + + diff --git a/prbs b/prbs index 8e42b3e..48d9d49 160000 --- a/prbs +++ b/prbs @@ -1 +1 @@ -Subproject commit 8e42b3ea00644cea5ae34b4ebba2e062bdc58be3 +Subproject commit 48d9d49b0380a4eb18c13c230182dede94462a28 diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 7db0066..ec47e82 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -35,9 +35,20 @@ ENTITY axis_async_fifo IS m_axis_tready : IN std_logic; m_axis_tlast : OUT std_logic; + -- Control signals + --prog_packet_size: IN std_logic_vector... + -- Status signals prog_full : OUT std_logic; - prog_empty : OUT std_logic + prog_empty : OUT std_logic; + status_aclk : IN std_logic; + status_aresetn : IN std_logic; + status_req : IN std_logic; + status_ack : OUT std_logic; + fifo_overflow : OUT std_logic; + fifo_underflow : OUT std_logic; + fifo_wr_ptr : OUT std_logic_vector(ADDR_WIDTH DOWNTO 0); + fifo_rd_ptr : OUT srd_logic_vector(ADDR_WIDTH DOWNTO 0) ); END ENTITY axis_async_fifo; @@ -216,4 +227,84 @@ BEGIN END IF; END PROCESS read_proc; + ------------------------------------------------------------------------------ + -- Status Clock Domain + ------------------------------------------------------------------------------ + status_proc : PROCESS (prog_aclk) + BEGIN + IF rising_edge(prog_aclk) BEGIN + IF prog_aresetn = '0' THEN + --prog_empty <= '0'; + --prog_full <= '0'; + fifo_overflow <= '0'; + fifo_underflow <= '0'; + fifo_wr_ptr <= (OTHERS => '0'); + fifo_rd_ptr <= (OTHERS => '0'); + fifo_status_ack <= '0'; + ELSE + + wr_status_ack_sync1 <= wr_status_ack; + wr_status_ack_sync2 <= wr_status_ack_sync1; + wr_status_ack_sync3 <= wr_status_ack_sync2; + + IF (wr_status_req_sync2 XOR wr_status_ack_sync3) = '1' THEN + prog_wr_status_ack <= '1'; + END IF; + + rd_status_ack_sync1 <= rd_status_ack; + rd_status_ack_sync2 <= rd_status_ack_sync1; + rd_status_ack_sync3 <= rd_status_ack_sync2; + + IF (rd_status_req_sync2 XOR rd_status_ack_sync3) = '1' THEN + prog_rd_status_ack <= '1'; + END IF; + + IF prog_wr_status_ack = '1' AND prod_rd_status_ack = '1' THEN + prog_status_ack <= '1'; + ELSE + prog_status_ack <= '0'; + END IF; + + END IF; + END IF; + END PROCESS status_proc; + + status_wrclk : PROCESS (wr_aclk) + BEGIN + IF rising_edge(wr_aclk) THEN + IF wr_aresetn = '0' THEN + wr_status_req_sync1 <= '0'; + wr_status_req_sync2 <= '0'; + wr_status_ack <= '0'; + ELSE + wr_status_req_sync1 <= prog_status_req; + wr_status_req_sync2 <= wr_status_req_sync1; + + IF wr_status_req_sync2 THEN + fifo_wr_ptr <= wr_ptr_bin; + wr_status_ack <= NOT wr_status_ack; + END IF; + END IF; + END IF; + END PROCESS status_wrclk; + + status_rdclk : PROCESS (rd_aclk) + BEGIN + IF rising_edge(rd_aclk) THEN + IF rd_aresetn = '0' THEN + rd_status_req_sync1 <= '0'; + rd_status_req_sync2 <= '0'; + rd_status_ack <= '0'; + ELSE + rd_status_req_sync1 <= prog_status_req; + rd_status_req_sync2 <= rd_status_req_sync1; + + IF rd_status_req_sync2 THEN + fifo_rd_ptr <= rd_ptr_bin; + rd_status_ack <= NOT rd_status_ack; + END IF; + END IF; + END IF; + END PROCESS status_wrclk; + END ARCHITECTURE rtl; diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 1e5d3e7..069bd1e 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -168,8 +168,24 @@ ARCHITECTURE struct OF msk_top IS SIGNAL fifo_tlast : std_logic; SIGNAL frame_complete : std_logic; - SIGNAL fifo_prog_full : std_logic; - SIGNAL fifo_prog_empty : std_logic; + + SIGNAL tx_async_fifo_prog_full : std_logic; + SIGNAL tx_async_fifo_prog_empty : std_logic; + SIGNAL tx_async_fifo_overflow : std_logic; + SIGNAL tx_async_fifo_underflow : std_logic; + SIGNAL tx_async_fifo_wr_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL tx_async_fifo_rd_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL tx_async_fifo_status_req : std_logic; + SIGNAL tx_async_fifo_status_ack : std_logic; + + SIGNAL rx_async_fifo_prog_full : std_logic; + SIGNAL rx_async_fifo_prog_empty : std_logic; + SIGNAL rx_async_fifo_overflow : std_logic; + SIGNAL rx_async_fifo_underflow : std_logic; + SIGNAL rx_async_fifo_wr_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL rx_async_fifo_rd_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL rx_async_fifo_status_req : std_logic; + SIGNAL rx_async_fifo_status_ack : std_logic; -- RX chain signals SIGNAL rx_byte : std_logic_vector(7 DOWNTO 0); @@ -322,8 +338,17 @@ BEGIN m_axis_tready => fifo_tready, m_axis_tlast => fifo_tlast, - prog_full => fifo_prog_full, - prog_empty => fifo_prog_empty + -- status signals synchronized to AXI control/status bus + prog_aclk => s_axi_aclk, + prog_aresetn => s_axi_aresetn, + prog_status_req => tx_async_fifo_status_req, + prog_status_ack => tx_async_fifo_status_ack, + prog_full => tx_async_fifo_prog_full, + prog_empty => tx_async_fifo_prog_empty, + prog_overflow => tx_async_fifo_overflow, + prog_underflow => tx_async_fifo_underflow, + prog_wr_ptr => tx_async_fifo_wr_ptr, + prog_rd_ptr => tx_async_fifo_rd_ptr ); -- Stage 3: Byte-to-Bit De-serializer (MSB-FIRST VERSION) @@ -439,13 +464,6 @@ BEGIN tx_samples_I => tx_samples_I_int, tx_samples_Q => tx_samples_Q_int ); - - - - - - - ------------------------------------------------------------------------------ -- RX Stage 2: Frame Sync Detector (MSB-FIRST VERSION) @@ -470,9 +488,9 @@ BEGIN m_axis_tvalid => sync_det_tvalid, m_axis_tready => sync_det_tready, m_axis_tlast => sync_det_tlast, - frame_sync_locked => rx_frame_sync_locked, - frames_received => rx_frames_count, - frame_sync_errors => rx_frame_sync_errors, + frame_sync_locked => rx_frame_sync_locked, + frames_received => rx_frames_count, + frame_sync_errors => rx_frame_sync_errors, buffer_overflow => rx_fifo_overflow ); @@ -504,8 +522,17 @@ BEGIN m_axis_tready => m_axis_tready, m_axis_tlast => m_axis_tlast, - prog_full => OPEN, - prog_empty => OPEN + -- status signals synchronized to AXI control/status bus + prog_aclk => s_axi_aclk, + prog_aresetn => s_axi_aresetn, + prog_status_req => rx_async_fifo_status_req, + prog_status_ack => rx_async_fifo_status_ack, + prog_full => rx_async_fifo_prog_full, + prog_empty => rx_async_fifo_prog_empty, + prog_overflow => rx_async_fifo_overflow, + prog_underflow => rx_async_fifo_underflow, + prog_wr_ptr => rx_async_fifo_wr_ptr, + prog_rd_ptr => rx_async_fifo_rd_ptr ); -- Zero-pad upper bits of m_axis_tdata if wider than 8 bits @@ -538,7 +565,6 @@ BEGIN rx_bit_corr <= rx_bit WHEN rx_invert = '0' ELSE NOT rx_bit; - ------------------------------------------------------------------------------------------------------ -- MSK DEMODULATOR ------------------------------------------------------------------------------------------------------ From ca022b93eb3ec156fc22b4ba72e34a99b794adee Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Sun, 26 Oct 2025 23:35:31 -0600 Subject: [PATCH 04/60] Add read back of async FIFO read/write pointers --- prbs | 2 +- rdl/outputs/c-header/msk_top_regs.h | 16 +- rdl/outputs/docs/msk_top_regs.md | 110 ++-- rdl/outputs/docs/msk_top_regs.pdf | Bin 113116 -> 114122 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 442 +++++++++++-- .../python/msk_top_regs/sim/msk_top_regs.py | 8 + .../msk_top_regs/tests/test_msk_top_regs.py | 598 +++++++++++++++++- .../tests/test_sim_msk_top_regs.py | 200 ++++++ rdl/outputs/rtl/msk_top_regs.vhd | 18 +- rdl/outputs/rtl/msk_top_regs_pkg.vhd | 26 +- rdl/src/msk_top_regs.rdl | 9 +- sim/Makefile | 1 + sim/msk_test.py | 23 +- src/axis_async_fifo.vhd | 80 ++- src/msk_top.vhd | 52 +- src/msk_top_csr.vhd | 23 +- 16 files changed, 1468 insertions(+), 140 deletions(-) diff --git a/prbs b/prbs index 48d9d49..935c25a 160000 --- a/prbs +++ b/prbs @@ -1 +1 @@ -Subproject commit 48d9d49b0380a4eb18c13c230182dede94462a28 +Subproject commit 935c25ab545be9102a9b5ba55b14de7f7c3bfc7c diff --git a/rdl/outputs/c-header/msk_top_regs.h b/rdl/outputs/c-header/msk_top_regs.h index 1d89a4a..accc8fb 100644 --- a/rdl/outputs/c-header/msk_top_regs.h +++ b/rdl/outputs/c-header/msk_top_regs.h @@ -312,6 +312,18 @@ extern "C" { #define MSK_TOP_REGS__RX_POWER__RX_POWER_bw 23 #define MSK_TOP_REGS__RX_POWER__RX_POWER_reset 0x0 +// Reg - msk_top_regs::observation_data_data_cf6acbd7_name_aa4ec676 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_cf6acbd7_name_8a90eed1 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_reset 0x0 + // Addrmap - msk_top_regs typedef struct __attribute__ ((__packed__)) { uint32_t Hash_ID_Low; @@ -350,10 +362,12 @@ typedef struct __attribute__ ((__packed__)) { uint32_t lowpass_ema_alpha1; uint32_t lowpass_ema_alpha2; uint32_t rx_power; + uint32_t tx_async_fifo_rd_wr_ptr; + uint32_t rx_async_fifo_rd_wr_ptr; } msk_top_regs_t; -static_assert(sizeof(msk_top_regs_t) == 0x90, "Packing error"); +static_assert(sizeof(msk_top_regs_t) == 0x98, "Packing error"); #ifdef __cplusplus } diff --git a/rdl/outputs/docs/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md index db06b21..e724aaf 100644 --- a/rdl/outputs/docs/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -10,48 +10,50 @@ Don't override. Generated from: msk_top_regs - Absolute Address: 0x0 - Base Offset: 0x0 -- Size: 0x90 +- Size: 0x98

MSK Modem Configuration and Status Registers

-|Offset| Identifier | Name | -|------|------------------|-------------------------------------------------------------| -| 0x00 | Hash_ID_Low | Pluto MSK FPGA Hash ID - Lower 32-bits | -| 0x04 | Hash_ID_High | Pluto MSK FPGA Hash ID - Upper 32-bits | -| 0x08 | MSK_Init | MSK Modem Initialization Control | -| 0x0C | MSK_Control | MSK Modem Control | -| 0x10 | MSK_Status | MSK Modem Status 0 | -| 0x14 | Tx_Bit_Count | MSK Modem Status 1 | -| 0x18 | Tx_Enable_Count | MSK Modem Status 2 | -| 0x1C | Fb_FreqWord | Bitrate NCO Frequency Control Word | -| 0x20 | TX_F1_FreqWord | Tx F1 NCO Frequency Control Word | -| 0x24 | TX_F2_FreqWord | Tx F2 NCO Frequency Control Word | -| 0x28 | RX_F1_FreqWord | Rx F1 NCO Frequency Control Word | -| 0x2C | RX_F2_FreqWord | Rx F2 NCO Frequency Control Word | -| 0x30 | LPF_Config_0 |PI Controller Configuration and Low-pass Filter Configuration| -| 0x34 | LPF_Config_1 | PI Controller Configuration Configuration Register 1 | -| 0x38 | Tx_Data_Width | Modem Tx Input Data Width | -| 0x3C | Rx_Data_Width | Modem Rx Output Data Width | -| 0x40 | PRBS_Control | PRBS Control 0 | -| 0x44 |PRBS_Initial_State| PRBS Control 1 | -| 0x48 | PRBS_Polynomial | PRBS Control 2 | -| 0x4C | PRBS_Error_Mask | PRBS Control 3 | -| 0x50 | PRBS_Bit_Count | PRBS Status 0 | -| 0x54 | PRBS_Error_Count | PRBS Status 1 | -| 0x58 | LPF_Accum_F1 | F1 PI Controller Accumulator | -| 0x5C | LPF_Accum_F2 | F2 PI Controller Accumulator | -| 0x60 | axis_xfer_count | MSK Modem Status 3 | -| 0x64 | Rx_Sample_Discard| Rx Sample Discard | -| 0x68 | LPF_Config_2 | PI Controller Configuration Configuration Register 2 | -| 0x6C | f1_nco_adjust | F1 NCO Frequency Adjust | -| 0x70 | f2_nco_adjust | F2 NCO Frequency Adjust | -| 0x74 | f1_error | F1 Error Value | -| 0x78 | f2_error | F2 Error Value | -| 0x7C | Tx_Sync_Ctrl | Transmitter Sync Control | -| 0x80 | Tx_Sync_Cnt | Transmitter Sync Duration | -| 0x84 |lowpass_ema_alpha1| Exponential Moving Average Alpha | -| 0x88 |lowpass_ema_alpha2| Exponential Moving Average Alpha | -| 0x8C | rx_power | Receive Power | +|Offset| Identifier | Name | +|------|-----------------------|-------------------------------------------------------------| +| 0x00 | Hash_ID_Low | Pluto MSK FPGA Hash ID - Lower 32-bits | +| 0x04 | Hash_ID_High | Pluto MSK FPGA Hash ID - Upper 32-bits | +| 0x08 | MSK_Init | MSK Modem Initialization Control | +| 0x0C | MSK_Control | MSK Modem Control | +| 0x10 | MSK_Status | MSK Modem Status 0 | +| 0x14 | Tx_Bit_Count | MSK Modem Status 1 | +| 0x18 | Tx_Enable_Count | MSK Modem Status 2 | +| 0x1C | Fb_FreqWord | Bitrate NCO Frequency Control Word | +| 0x20 | TX_F1_FreqWord | Tx F1 NCO Frequency Control Word | +| 0x24 | TX_F2_FreqWord | Tx F2 NCO Frequency Control Word | +| 0x28 | RX_F1_FreqWord | Rx F1 NCO Frequency Control Word | +| 0x2C | RX_F2_FreqWord | Rx F2 NCO Frequency Control Word | +| 0x30 | LPF_Config_0 |PI Controller Configuration and Low-pass Filter Configuration| +| 0x34 | LPF_Config_1 | PI Controller Configuration Configuration Register 1 | +| 0x38 | Tx_Data_Width | Modem Tx Input Data Width | +| 0x3C | Rx_Data_Width | Modem Rx Output Data Width | +| 0x40 | PRBS_Control | PRBS Control 0 | +| 0x44 | PRBS_Initial_State | PRBS Control 1 | +| 0x48 | PRBS_Polynomial | PRBS Control 2 | +| 0x4C | PRBS_Error_Mask | PRBS Control 3 | +| 0x50 | PRBS_Bit_Count | PRBS Status 0 | +| 0x54 | PRBS_Error_Count | PRBS Status 1 | +| 0x58 | LPF_Accum_F1 | F1 PI Controller Accumulator | +| 0x5C | LPF_Accum_F2 | F2 PI Controller Accumulator | +| 0x60 | axis_xfer_count | MSK Modem Status 3 | +| 0x64 | Rx_Sample_Discard | Rx Sample Discard | +| 0x68 | LPF_Config_2 | PI Controller Configuration Configuration Register 2 | +| 0x6C | f1_nco_adjust | F1 NCO Frequency Adjust | +| 0x70 | f2_nco_adjust | F2 NCO Frequency Adjust | +| 0x74 | f1_error | F1 Error Value | +| 0x78 | f2_error | F2 Error Value | +| 0x7C | Tx_Sync_Ctrl | Transmitter Sync Control | +| 0x80 | Tx_Sync_Cnt | Transmitter Sync Duration | +| 0x84 | lowpass_ema_alpha1 | Exponential Moving Average Alpha | +| 0x88 | lowpass_ema_alpha2 | Exponential Moving Average Alpha | +| 0x8C | rx_power | Receive Power | +| 0x90 |tx_async_fifo_rd_wr_ptr| Tx async FIFO read and write pointers | +| 0x94 |rx_async_fifo_rd_wr_ptr| Rx async FIFO read and write pointers | ### Hash_ID_Low register @@ -765,3 +767,33 @@ signal should be sent after PTT is asserted.

#### rx_power field

Value that represent the RMS power of the incoming I;

+ +### tx_async_fifo_rd_wr_ptr register + +- Absolute Address: 0x90 +- Base Offset: 0x90 +- Size: 0x4 + +|Bits|Identifier| Access |Reset|Name| +|----|----------|--------|-----|----| +|31:0| data |r, ruser| 0x0 | — | + +#### data field + +

Bits 31:16 -> write pointer (12-bits) +Bits 15:00 -> read pointer (12-bits)

+ +### rx_async_fifo_rd_wr_ptr register + +- Absolute Address: 0x94 +- Base Offset: 0x94 +- Size: 0x4 + +|Bits|Identifier| Access |Reset|Name| +|----|----------|--------|-----|----| +|31:0| data |r, ruser| 0x0 | — | + +#### data field + +

Bits 31:16 -> write pointer (12-bits) +Bits 15:00 -> read pointer (12-bits)

diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index 83b67bc0325497acf1db478d4c06f12ab3ce5600..6f013ede1561600e1f281f435ff699f1ec3f4a95 100644 GIT binary patch delta 22881 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

;9 zJkD*}?X=yN@u{R%*g+qm`eruiH4~LQK{H*!mtn^CP7eU+RDfr7qvZ0-E0h<8zIHQ_ zAv0i_Mcq*L;bM|uGu{kq$-j(wXIH<7z?xt<=0uh{HEr#P8BVuFAh?avLu8OPI9hvP zbfhTgta*OnF(r?Pm`{458a5nyYB@qn0?QkI9u@d9R9(9~3kI~yh#4LQyA}NC7HRs9 zseaH<#XA8ibVWCcJa(@uL&LqRb-Tkd||l?;oHeM^0hc4riMBY zR@M7QPT)m-cDZyXim*fM)g-~VYqHjc@HvAtCh1{}RBPnopjw%BfY1(>{!lj-^TNc=vl!n4sc7+*kqEz23i% z@Wlq=tJoP@n!sJ-;?TyF@pm99QEFe}~ia>!lfa!x4{D?3Z z*EGQJ%od+3*QhkmP5_Rbkb$42rY0EF=y;AEMW&6Pi=rwH1#Z6mW?JnNZMb`p z8*lt3Phg4!@aju?`9ASElzr6>+xrGrjvC-`g43IGZ6FU`@AAS6=mJlzXHE3wq7?+O zRm7I432bI}T5COpz&RKNrDe>U9aG}iw@P9X@p?z!_;F z&-dR4hzD@Sj9+$|C_Qb}NRx_` zD#~dvvCRkR@^3^7M|bp!vB#BhM@6VRzvd^x32Y2Nn!`|WA{ zM4QDMA6ztZ*2tA~JyajkJ=V@fd|RbaSdJbb+b)G5mY-7c*vCRvT-vpPhN*;kje9U-UwDMc0w)kH==r2THH7oDN5C+%-~wIxJE#uqlNWJq5`Vj zo7+|9bF-r)8ivVx8+}O{B(e>|+Q~V|2A2na$H&WbkJf=gBc*hHa?%eLz$M-8oTSA)Fx-7>HD4i57c*D*u`<9NBK_s0)bm- z__>csm8mfcRSNHhuzusVcjWtowbbKrE%gL{I}5tyTzfUb?T=Kwb{Y*qV5{!Y}_PDJmSn%M##$12GR1SxL%1$fl)F1t2nZnWZqVVi@r!Q=I7=GzN(b%*puIA%l; z_qfW@4pY||4rpT4z&Lc`-^&Ger@Lyvb&D3WMqU!Fh|EjDW=V>O;gOCGzq=;a&)&uw z9suWR{7xw3{h_6l)#J_7>8}T`ON@ZszB*~u0^lQaNo1Q+`en!upv*0IvD75jY2-3O z&Q7z7HD^`5KZN-M7}AL+GIPyx`@)i#b>JT=2EiO0O_DsUB?dH{tGt07Q@8`Z<^l9hbN7P zY9m8T_#f`>vEw0=!*L2K`*+t^Da&SoY8GP+C z{9VB<3Or8Omy=xf8`>ExuEK7w3Iz_V?NP{E0?D_$Gu% z)Y66QZGC6@Hzq5=i#h0h%bKq+pNinkFhnhe1>EHbM4|B1ukQxd+){v^zj&>go<{+k z^n@qtE={j`pD4E5&zVxD)d4Uv7+S8&0dPOec%b$Rkm_&&w;swf8fa__1i>}7uM=FK zzReym#=&PHRR^EYk4eruo98SaBXkiG23u^PxdjLL0S5%{mzIncaWQ*yarL<+4qGTQ zl|7j;D|L^Nwz}%~qynI~>TB~uX6u2J?)dxdzCFG5;!5|ma-PC{B5|s>xbL)Gq=CZo&OM_;{T&CP!#=WH3#U^PECui&Ikfda)sc#pZQxff zFz1E283HkVbv%1veXW+L`nCWz)x9%p zVN|IHpv3lIb^P*x*7lUlz3Mz$%5^|ExS-b;5E%en#mZCR(9;*~y;9OqbrB0Z=mA#& zqx0X@Ng4cy!?bkfE)rcP!A3{1@Q|53G?lC)uH&&h)^PE7Fb0KC%Bw{0d@ux~RLfPw2cDcy4#Hh{ zcyU#uJPJuDxa5klD^nb!+j|*bh5UrwjIMT=)WJ}}Gdp>RhOruWhAun$d5cmu!cZu* zNmayNGgSJUxW6#(em%NZ4490q0V;21pv&L#&RLl$En($HcOiV#xY%x#`|KD&N+;1U~qzC2fF zKuVw#j?d~cU~q~oTP!@p{B0@e(Iaa+sZB~6-+qvq7EUv^;sTXjo2D_8&1N!<|dUX(dYr&_o$m>!F}3hQZFJDfp{h zj44@t>ItkH?bd@;0X8~IhRv^t6T(2^iLgM4q1cre{3Z~uurSS56^gXucigVDgmL|q zH2@P5ZKVp1nso?AG}bkB&Q4!S*Zp%?{?Qj%wS?Kaz*`@+5rW$KkIa~s-;jtTV-b|5 zPU7~XK&qQ>hFs&YWKsmiCR*$UI{tnh_I&FI5AG2^>#x~uwufPwfB0*n2o02%i>d9dp$Q=v7Evu_^fOs5EDwx4&7 zag;+U9-I1B$~kiv`_0|Re9iHzcn`@ER`g}>$?|rdB{ApRGY@GbhMZv$+niUFfegTq zZQv2hj4?YCC}yos;o4T58SN114(JL7qDeCoV>+%!!J3Wa;gE6Dmaml+lxq~gWx2uw zIanOgI9H;5sU^dN_JOK`L*IOPgbS6M7`5%I&*F&+)(-8S3F9zX#B9n60 zLo;N>%A(APIu|Z$|r$HGpCBHA5L_O%M zZK};=^9J)4uGy`P2b^L0){)V>^Qp=0R?Wlg(lX?B)AA_k#;_0?&>Vjro5#Nmbi+gB8{L zrDnGPY!bFdaqYQUlZHx@ORhM`J+OoOz|`T4??k}>+Kt-1l?OlNY&^M<1{ zMT}YC21%d?R@{uvB%mS8XjHEtRj@%*m_ff*7*QnAF_R)HQJVe$d5X#j_o%u2fUrb? z*Y+lPt<#D4w=u(~S7ZplzxFiPPJe>iht1QSbjW*%OfxwkV!OMJ2sQU{y~+xM!L%xsio z83Kai@@mhPh zpAn%q{W8_3JNJA`02i{VSMVY$h!q{g`c08e>k&J4@QC63n7YivyW-(h?fMHSz5PDm z;cnEGb#v3#Yw39>*l$UdLcrmfy$lSLZU$O0xjMq-n?r?2a)OAD(%FE`nJ9gF=BG1# zdS@`P{`7ODqAmyUocMllJ>rSEQJ=qkF3%!KS+}2u6Jx(cJFIT?w=r86b<68-P4acV zbGDY@4!X4|_KBfm(F_^UTK5d>0*Qc7IfLt)E1oR|sVA$a7%^(CZliPCd1c9}s%|!0 zv$bw73%VVIB~`Qt1XiK}@llxo>1JU>BOEXwWbtm<#hV%6?!f$%YPPU%+o8YE0ZI1) znXEUE_VS#uKz-FXV`zDU2J_xlVTOL@!1~I(dbkNS87d0Wm;h2*iKW#;Oc64aB0m`> zF`MFJ8H8b|=1AU7nhyVco8AfPasYcM9p?*u4vZ+D8dH6rYb~OCO;Gw5`9LYzIJV9Q zKTK!ix8y3oMgNtm>JsVDUytaF*8zC`9_kQl93Hy34w;ZCvzq`IXmbtxuk&$vd&)5x z4Kv?cgSE<)$#pP2T6+UVIN++Km*I8#bbA6x(su>w?bPVfhhV_^I9Q)_>NucIfB(8f z$a_BJ0N9z1;^|67;f=U9N2U2nuuj?B=4(2rq5T)20pZBKJl##;V+T6iM@7K>-E0RH z^}EZzKiBy>TUb6d7|Z0-9W00xnhg3wRzL!^*f*6jRxk-C9@T9B3vQLF3mDg{A=@2790 zw+zY@K(z;c7=INaQY+n1{dy^V*-~U$pDLI6?pxU9Y`ygu!+dvOZ2DMP&-AWe&(ySM z*jB@b0N~Im$=ZSrEoDrl4hu$36bqql`S=|Wafe`&YMlJPnTmxeMWGlN1(fZ-%@HL) zMN@8r9@Xcj=C**TYM8g1_zHNH6V5z$PEr~quzr}oNJkWTuvxd~fL*>60!vW^LatdZ z^Tz9Bf9Ciw)9$`*WaF-$-0n~qaSsjjI+P)pgE9LlT9%#icHz(7q=!^>MidhW(4<7~ zTOzEduE$2f_Ao!^ej1zJ=&2QS5eq1wXsnb#%*j(xRb4kX%ZI9;8&vFKj3I?8(QJ8h zp~?(9Mkwjo-UG2*dRD$=qRZ=deZrj0&A_Q#XOih~h4S%uM+tok6j5kgwBJKmD{4lk zF}=?5|B?Iik$!8PAJ=5gM zlWtbI83&yVy@8v+kYtsl-g~K59d8(5x^Kos!{b0(?<%y#s?OqF>o}8ue2P0Go8f$l zOXuAfj^k4$`kJR5&Luai=7)0U))*d&3VGY&KX2sQ!3ny1tXNCT>OZWy$?lXW>-6Vx zBv0;fPlkBa#qM1c3DyMjcin(}eD3*i!e6K2+DSv@8clf4%D>J1E`_y|kffnsI?u~* zZR-1-tE*v{l@vSOoRtLujK)*cN~&ix+htPrLD7Rt&Q;YGRp;g3O3p##Wfg!5(P4@49Hjc%@ek8CSp_~Pxg|JbY9>Vh(yxmmYQxmU;KyGM5;39;WM?q7 z3km&l$Y-ZkPD4r0EU9oar`U~fA>Gg)>^u)LM5Q@HD+^wi2{B(SS-S5Vb{COr(zZk^ zX`b-+sF_d(Nrv;rz^%w3+(Z~ED8gP$6!+?Q)=%16w>1&gU4!NtA2W`8nBQ4WN%N1b zF#phBISfLC4!Oik89fH9kc0_nzpaSgfrViBsJ}*$rfD}ts5 zIWB9$=9r!5MNPblHf!s>7Gv1Mfb#Ck1CzU3Wd-{~E@tPTf0o1xnZTr`rvuy7su(C z0NohP{254&cv`i^n=_LI{egI{2p9e%0U`A?DT=vddp`r(ninbf&Z}|3@Veytv62!X z=^+h4%No0Z!s2vNh$bAOdg5RN{@AWqFO5NtXOVvc=SYV8md8$>#m5Ch?VhM4E9Ux3 zh`F6q{e@7Mav~9Cds+d2xH#jZMXEhH*g0vcj9bZriRIOG;>z0O;wyA5q3aCeEc0}6 zS|JOZ{MU0%)f#-E|EuG@T%WV3|4JL6+r%tQeV4PMN{hNs_LXy1;Xo<9gt*v&(A9UB z&yQoQ%%iEYmF=v2x3ai|&VE(a-Y)*x8NJJ!8F+%I$ziS8ChT4=6as0{`%>TExaC~J z0fVVAE7w-KwydMtYiu+BHCnyzk6EoF=3;D;3v!QbtZE6d!b_B80#PF!iUS3p)Ayfs z@Zj;)d3=F_K^~v_GdFa7`%ap$M;Q#)gAv#Q~(=RGxL zuxj|{N7&-nC@_&e)=U}X{AytB_s#DWcS+NRKzw_;zx{!MBm_o(cg9|;*qE00V;6h?tLBCN z@)wiy`++>Jk(pG~8sI5gGs{!<5f~Tnrp7_H43`U>O05reQkvyQv$b=vM!3Dhzot5? z{NHa4Tf&|I3K%;J<9{%GNmW8_gCDi~M0Ij5`Ii189(&fGUz;Lq9W-}zh)m7F0E^4_ z{o>;iGXwEC9;8ceB-{Og_Qo3;EDA}0i)X(kV_^He*=W?DB2{oeNtk0q1GBJjI8usP zdRG6|9N^igEFA-det-l=Y~w~RHKMLw)Nt$8y0WCX^V_2iW8g2q5>+9ft*&|*sldn_ zf$f(kJaL{{?Og-Sy?au>dL|?`A(KG-k_vqk?Mbx;^(W3Lm(xebHH@ubae#%&p}RQfEeKwO z9vjxk+9GXONmvI!qCTRMCQ}nXq)V3vW)vzvRKpLGK^!ZX#rV`{o{O7|!Y{=$RL`2F z-6~lY(GV7UdY4x$V4H1)hb`54h1rU4CNuN!;tR-DVW$|Co;&`=_n=$Cs zjY{G^V0m!Cq@P#P>_P+rRb=Y?l(=7(*+Doe6ePyl2^_nC$QNjWSziKd4jD=&)>Lf| zt;6uw4s9`N+?oAN=U4H71 zQ@UA2HVO~`-2HceK#TjD?RWQ|}`1@3NU!(Eomsy4N?n{4JZIj0X8a2*G98X6uHm4RgdBl6M zTaM?k7g;9uS$oLK!=Xaw^^%9WdnM*3KSaLBvzn>_+Z;<;ph$$O3ENr%rfTn;XH#gs z$aJu_r1T8P_7ZhwfW}iF?2INP;+sB)Ml8Tf8&pAi)`A3A&B=pBSE{Pr-9x+4$ya3H zVEV)o2~7#|ue}}#^e}G9TCWrsvzGNZu@6Np$mK#bFjiTw{XZ5C073UJ1f6Wz3iy&L zRk#vB)em3hc%y6qXL@?7KasYdX&{PMgkk@sMSmDlbWm~)itM6)xs}M7Fx=;T{&Unq z7?wX=Q-uV1EQZwdwlSx30T_hZWRh^4|BqziGsLDEsNxs!xJ*|1{}vuQ>;GrTgEFvi z{3l>k{l5X@WgMqj!%YYR_%b-KvZk^!Qc z?C%z?)?OcSi=0!3lOIaqxDm_-9ezC$x8HBrfx+7=Z=)h6x4L5IOljv500bBJm&sf1 z#3rb^k26HHyeQd%cAmufq#*!s6uzXPL>AyCg9PRn%ZYh!9(G?zx!_)(kx`}o5LY3l-yFIB}hqw!?80bhiBD^Ndwg->QF|ELbq;PBzRYtJTxc&sSRaeb#ilC^jt5 zCS-};ew})bDQ(A_f*i7pLK@2BR=-~t;U2c^o*T(mx0lG89X&>tJFy01Ov+_&&H6xQ z#h64q){*ZLk=-;?5|`QUUaKY)n%=n`!x+{Ee|nlvWmz2vV$rx+bbdrWU2&mmg5BqG zDeSw8P!;STL!$%cSu5!#EO3dz5`%Luzu9NZH{B>UucQd5@=HVWfhT~GLg5ou)ziljfnQTU?`8k*%hqneVL|AgkALm{8RZMW4aN8U0?jU)#iOJrQ=k)TnU< z5uZ=kCc<^g2aRdDb>rji4jA#=b-n?qgLEQ-z-Tv-oKFO(;>0Vfx8^Kc%PUgrtMDSh z{m$ro!u8$QYqPm8p=KB#K6pd5h;*+P$A|$c+oK%YJ`9&+%!QMNv?Q1n zVW{CtgMF8AGJ#dUKr7O_cM|@RQh>1iPf(XU;qWi03x4r{xrCt&-IWAd6TvH4m}GXg zzRHXQjjNps6K)1mCU<|wLo{*Nj6&nJ}KbE)g+LIG^;TAigdoVrwN=A?zJ7Cny@c zOQZ{BQ?eTmQa#C+ge!78>f61Ja8U{0YTw9w;n<=tq4$K5WkXUM_A}QBT2aOR%^G61 z8b{>GoF)gzVX)_g5}J_iEfN^B1Lh(N3|QK{ue{srM5O0Oc<9u3maX`3(i14?L=&7I z`&}1&8LLC<-hKzmZZw1W!=>#;MonNnM#LL5$k4Nam)yy#d zD46gMOs0nkf zT0`{doB|KJgCKIF`0CYx6S!$U4#lvwYqDwCSK-GD_x~_~Uvyu20n%J2kohc7(MGZ`n%Q0raR;QWVN3F(}?6CtMT=19QY-fAyIo=`vC{l zTYc|h??-YY97S8bu^js7K<4`Kr2dSWP9v7Y^RIUks-9}Kz;kVK`c^S~ zfe=Zwu|Yb{R1&tu0!HQ{kR)I3h8$AK&3b)ST@4VA={qZrUavgRI!xw%zF)I{!LqHK zanM7nTD zrbTKKRIi3U;$(^2;s8DRL0?t3O-m4=qy+g-ur4sABK42x5&seWrM>s4OU|~o4VVCU zIYm$@I)9uYHr7~}@`icdKahw4L&l?xE!L{PNwYo9c*6;=MiRmIWR6Z)r{n@OzVGp$ ze~@wLYZUM@31eW>=-7#_Y(qKTOu6e8Yh4Eo z@{9M|Z8dIBeAm8ojr1akz%l@+p-Uhri6y9L$4j~%q{3m?xdju=D(2(>&f)AQgHZ4f zFj-ICf$?g-?(Opqk%!LnX$)+$R3~ ziD@u@gT4QYLVCpMU_KQQtC>$DBv}*~rsm;)H4Bw@Rd2H$9bP%HFN*>Y^Jr*&Ah-kh zkahcW0plB0Olhyo^4lIFA zt_2()OP~NU$oCkHD+C5$NO`$^QgEuVrGfhr?pbbtWX5D~61at(cMRA><>-Oxf}3@9 ze4QRbi{89`T0|)%DQ59%IF|s@4r3?Uo8@EW&O;hX>r9By*D-htH)m5hd)YrR7)3xG z>V9FY&unGPID4j~0Q6Z_c)?1Ud8%1h$u9|Q?lYagxxoT2?+qE?%kURUnwv1UkUT`c zOBIsP^1S>W7a6(Kk9T+HDQ39(P%w;d`!il6KW#no5at(dLj9F^b#10^O$((B3_i|q zEIq7M`3mKA&Ki{B@3LD+*S~zYIV!>mPonD4)_)3#GSd)uCI40r;!oIVG;v4psNcUI`58k#%FO;_}p7%IbQl;PQHCA260|oXwcSeLay&-P@SM zou-u-3J!$yh_`EbiVh6vzyg-WM#9StvU~e+GF>B#y-&n|D?-?TWAhNVv<7>7g|po- zPe{0+p-k~_2c`l{rD*=w6>4PXi}IBM6m8;z)K;Pcm9m*NB1)fM5vrWD1jJ}8;dE)W z1fNnd{A%51-c3D+L}`)Z$MGXfbQh1{)+Vt3$$-AS6JB5ACOPO{*EK|vvz#eE|?%5YdMa2W*mA+k~lmgOYIc^oPH z&pa#pr&|bxwc~>O!B13+#GM?k@W7^zWszKJV7j91Rf`8s$L&MV%5wT*r3N6Ui0q2{ zixKyWr5~`234)>hGU`kkO`A!tqp#-&Am%x!De6%{=A5f zaI1W*UKe$y`4h<=j0G*w2?*6>r$hLReC+M)qAb8i&8i=*>ccwW@N=djOzy?$5{s`& zbMw?d6Z$qMjndT^?Ln>j)2$N>4 zCj<3kvYF3ulUx&~(SLBT1|7oq?+VG8RyZwt-)v@Tp72HDq!*K>YEQ*k`x6Ckdp^$6 z`voY6-e0fA;=vD2U&Vi_2bI_^EH0()VXYD3GqT}C2WF{YWN~(E?Mu6oh>`{S9gI|n z(*vuHVIa?wKrJmmMvX!CECOI5I^s)e{K+w#aEks4+jUcM63m?FzqHAi8C%s_&i$pkFZ@BO91XWkIxonTvcCNq`f3*1s{2Dwb`~t4r9Og5O=W*SsKKU4r3{;iMpj%4FkG?L*&{jB={P<}L`CvQC2#Mh+rGDTeox67SLa zxb0}zcm}%- zUJBN&r3O3?;R%sdHPwLCR(tSN+@+cSQh9CBZ?79!{?IYr_qZjz(~E(yGXA%X?n>RU z&=f-)zL`;)M5%Q7zPc0~6~W%D5ES>CTRtQz%m?#Vwt}2*xoPRQHh80m1Vh4zcAmC1 zHSKP8!kklGNpPX)TR+Jt{MT<%8iof8 zn7uEmSk_M z*SwIV$nA9OZ%$WnYYGs`QlXP*c0BJhj2-$j9gARGdS3a%-dCNp*l?H7u(HO3J$}4~ z98g-URGfLWAh!0sbt}wRK0ynqwM}5g1d_nvavjhF4&-TF`Cj4y=Kr2s3un zt*OldqbI_15cNK|+`_-jhu8`^B|LjZbkQ&)zEkW1d$E=ZFDPX7*mX2(p5{7R&w)RH z9UV6mfFZ+=nZ`oQk7`T2bPF4;nFFKeBP)q-_z(R;-m?i=*HWVl~>^ZEEf z;7&lc_UQeE-2L@=w$Nc%cs;h9pBsvbrG+sple=BT%q6}H6SRPO0V8F_9nP$(?EML- zCfNRoLCRQh?Le>vv>-Tv?&)aH9eaEn`F$fams6+=`4xH<7hjqyxej~qS4m3DQe+Ep7foi9L)}Q>q<0iI8+GU zo_+(ufM=rlD{kV)&j@k8JrSd*rcx2rZ44Fl1_MLD;p+M=T zyAJi0l`cEi-QFq*Zmbl5@CTAFhN|;Yx~xKDmn2nZ6;acHfVPe*zxs%7Uua7SU3M~U z9IY(>T`AK-O?Jn5RfyAR5#`7d=is`+LM|ls^kQQbR3AG`QAFFeNF`Z!+YBb0TzJOjtgk8;V=Rs71&ndb>Ie&(bHmAhhd3u zK0L%}E32`Y;m2SgAV*|79iqRB|EchVu8+9c=bQ#6MX zI_4Ome=U+r8^aO6SxaUAUvHPG3w?(Ko`6j=lU8lfYJ(Pd2XYKCat+TC#8|1iDNQJI zMe?iqPtHz$yB2+X@hZwsiAe+w-a{DOaVk% z0U=hO@C@EaC4_ytc$n)4ccUHHZ>dEkrt>l5b6Wj@I^ZdQmX$`F9|AdJ^1s^A4Pq5n zoS$lFWPj}MjV`1(g-v?-*{D&9>9nvR6JZGR@!mAHP*^KzBfIfb7ZWBT;wB@+5$y=r zN@B)+Zt98rPlES+&L#Axok!!IDvtj4n8xBUxAlCQKRFa*ml=7dItoh?XwSo|j+HtL z=5Kaqp35|V2BX6Z58P>z0?wY7o2r_KPUG1^j+`WSyTocdsM%4M7R)dZ(p0d8DB(Th zEcJ>VG6mm!izGp*p+fHu7PDi`2-T99LW^o8Wk+1>()G=3sLv2RyW;nFCP>;IFm47x zhace1mK4VXCJssvw*R*gdl?5-{={q2Hh}{(Xrsj(!dw-kbJ?3a)Fi`Cq#f_F`T4IB zTPog2GEw`%ZlA;SFy+O?giOp97?(p%;}c_=P@rTkF8d&DWaJ{#n)uf=*ho@|5G^g~ zko#@6StdiaC~-`v{I4R-wRI}%%HGD#aFEhocPt>2SzFgh-+Hc4Nk9Jhk95Svwy1e? zYDudj_BHB5w};&W#YOq~!0z-;i!~Zp(pk#d$XLkQ;S97G#=rKuW3GSR8i5&n_+(1L z16^cd>suUsxuZDV6G?(4&CV5VT&~{MxcbOF`ky4)>CNkfy2F&xuvPGt~Nb1 zJPbgUMsB;K>21?x4@b(UMSC1&W8|#F!2AW{52{8|3|z=&XRlo!V>z(+u%CaRUfbb~ z8gm}aI}!W_zQ5(h$275><)uA4Mm|LkBwjq9A}HZ)2LrtjOSyO1L(-}se-RuwJ+KhH z7FL>D3LQ77=5 z6nKYbs^ReN{<6ly$9=vf!ndi3P5I=JD+WRC`4siBy#wq>BY~3bZ~ExcufDa@=~1QF zu){Cq6`Jc0vrbc6^=9!M*E3Y0Sh#ni9FxFajwxlAQpKP-jz8_Cx2lnamsU4TWdVSu zvJ^9}itaTuEV~nh@m+cuN6LW48S8^xzQ09L%&Ba9VJ%ZcgOB4qfEH(-!hUScjpkEo z?)G82UMZ0)o$vZ{)x$ITdftU58EtRP4ky)CAvd3s3J@#O^8R`q!w@Ayd*%I>0(U7MGF1B;4?iXb+h zNm^dyXyBX;LTei|1Oe{KFg|C=uOV8jK{e2FRJ~Ql<(&Jv^eu`*wGejskku+fu~bZ6 z(n*^dsgFbk46qSof~I2i;0>w41|*9x_Ge{(oCQk9&UnE&PDlWpUop<= z&e~pa+SVgM);QkTQ~oIxsei-aC+uunl3*Sq zF)Cs?ShTD;$>vd0S8uQex-1Fgv@Dp3-WD4t`inS*ytW>iCQ3?w6}z#I54d#tc_B&I zY2mXrAGK6XBc-Qf%%#3}#t#7Wm=0Ybh*!

njW38S|Z4h2qPZxvo~SyP6#qCG8b zw%MBCh;v@IR4h-Hm3>Z1eDBMuh)hRMxmU3|3kqDd@R4AEx^d8dy$H-ukyNdOFO)7t zsVo`MBco3M<-;;{lL=lSGi>hsM%$B&43BPdM!j-#-+XMzXe%k5coGKq71fs-hQTg| zZ7E*q!TaB8@V)2Fw#_3Ym&*%hll#i6{Yu0{;{Ox^L#!bNqMwYuANn_u`?_%e2j+oH z{zL$McpP#jVPL94^|p+aUi4fh!g)SyJIj@Lr8Zy6a2X>NX8o(B>I~I&{%nH{EbxK3 zxO7KnZ<*)^j`BpBv|;Kq?X9+8RgI!D`RcG(I2<6dk^?}Wa>?@(Pz5W1nvMck|Ow5$%&F$5Y`G+vY6P6s}`X)Nw{vfTx;!=LOq zr2bmnM}T#5gmFJ#w2P}@z;#KGhza<%X&WL)2yU73Rl7s!#uTUylq@RFC!p<4^|SYv zWbfHrHR7OItrQ1RVnIG|2z)1y{BDpP^2p!H3ZN?z3RRAR%zZw_3cI##cQrbW?z45W zM&aA^KNQ^N24)K>*C!7{IC$~zL*>^>7ed94enr!^Tsa{D#P>?4;|fHD60;w19DVV# zZffAz{dySAZYzOp7c?QRdI06r*6I+iQfxq{KuKY5yYh<7c?>1Bd4Bg+;zc9JtnJb@ z0o9mFJ$Lm33Z!67CuT7UfG+&>7uVB(8qsE|KL!kx&)Q2jwwH+FX3RpULv^S#=bYV^ ziT^6Rk@KKMC$U}Mmqu&NL}$dZ-&q!eCrf66T}g$9zc50X9SaH%`x7i zjDxr5dgICF7TSSkq5M2oHpjRv5t-5YNQgXuI1;I35y10T09-rq%Wc<|UuN!uFuS;W z+C1e+>}M>)46jle_@70KtJHqipWGZJ5!W9TGL!ULa3N2i^Wo^}SuFyd5ao_um7KL6 z+gu2(T1-^4?vb_{0KkBkCFE`@#sHffC#**Mb;%hBnIRzC@u^^*%Xy_0%8JmW5zI%T zaTw#l-0D9SD)0;yy8F8Sl|x!`M3&Q&N1b7(%6BQ&`8z7q7dHaS1wZf;i}al}8tScx zS;rR=3AIb2d~9zdEH8?RCPz%XNf}BHz`@*88NN}CM}p_uF;ht&i9`BBtH4(u?({MA zo7FCJk)(6~>%&xHb4O`V+7d2r@fEU3eJ z@f*@nZElD{5J_S$2lvcOi^jI~6csL#LSlpPik z0;gR6ey6X2;gk~Vlkte=Vx(c6qjWcV1dJA$ltz(@bsq8vdb@4S%^KL?UTo9i`lJ-( zMJADa>Mb>g9?XQ_7oe7hrUJH#+sGe)ZaI5%P$u1R{ZU9m=zGI{3b^SxlqnS#-E>1=&dRU{&&ZKfsvhn zJ^@>V3HU#8$dsD45;hyE_l|DfNFhSK(-Y5tQE_1FS>q&quk^eio>oI1v!2q1^k~mb zn`Ug64hq;BKi;h5dWGi<&r2mqfdn)uv$;Ml9tmDXxk=nyl)yi zikM-LP!(X@=ySyW{w`T=6b$kiVJD(uYXdN-i*$MJ0ba~dLtRSc^nwns8u%I>J2OZ= z-uqhKIjGb<)Pmv2kcd$?3;_dfZgHgPSiG`Qs;fQ)p-gfoZm(CM=TuqP&|94V zq5AMGz`!sgXCUE-J;-NkAiH1NvK7u;UEVzK1Ti@}3uj!Np1UN_?<)Fndg+jHdh9qU z)K(t_3=9SxeJqXLt<_#!;z*_9d4hg7C;{?6W(hdSkgv09=J}#Vi(@3FbA(R4Oq9el zzd{m)AQ$8B`#~_7fCXa9p(HdS^5cSgt)M2O0JS;{Y`<|S0&_{Qxm`gx!`=q&2Ms{U zGUO2jF(5tC#P=GD!};q9f;D1f4J-oemT$`gqerOdK@{6S^*wH-qZrc+7Y9WC#@6B8(NF%$lEL=GpI(mQFK;9M*E%jpq)F z0g}qAsw`@WqnYpj8tB4q|J;#ND?`j!CLE4SS5MFI{jJgQURvEV7m!M;gJCQcG(7k} zgY(U}(2u1woBrF7SZ|c~Q#H}oFJH3AN^f!#vN1S>zM(I9{qi8P-z&`EH zEnI9&U(ACp$o=$a;z6NDXmW%YvsCfJEWvssW4ewkPCIw@wA{y{V(KjJb;^Cy@PbBD z$Am;(m|LDD?KJNsgN;!tXT$h*S}hj-oX%q|=NmV74LGWAL1X8xLmv;%SCY_d^f)*} za#Dro!?y&ol*T6m)cuK~+vktD(Sm<1j$TwhJb+Yd_Kezb|I})EINJnmB{D70{YmmxVfT5 zVsJa@ozW$$k6&6&>1LZ%6!YmDt&7g8ut$aA<2_Um|w6YIG`19Jj}K z{&`2Bb_dfFl2e@bq~=feTI+NmyhUPZ4MSC}o`l|@ePjHY*K(a)yYAX7PimjuPy#|S zv(1bDD9LiABHi%QTzX|KgyGvM?3HALMPti0MJ^uz&(rVu;z9sX9idl zg<}c|FFZt&`l6&VKFSVO)*Ko0CK^2-tc_DpW)2{ehj;e=p{lGH1<-_n| zdFKQ15MZ4)6j?v8ejW~u!|HCF+Kk|5i6XvcYaQ=~$)xAKl&!t+@*OY>RcwPydn~re zoy0<9?`(_APqb}ikL^>zv*Ivk`7O-rYy4Gyz1fTO;&US6Tl7DoQBD~__)?5H!PNQl zYAGXj_&$GsTKWb@xp(UI)W}~l^fr)_?S}A^?)`#<$6<56_n>s)>n2O1 zvyW-<=0^ODO%9JLrjw@X=uKEaTgG=lgEr%b zwWK;4l|aK=i9FdxnP;Q}uABpAj)@$Oclo=uG7<-1su?}-SE~*z7Mry~1n)GRs@dM7K~h1$Ssg;t05Ty4|#5i2@c< z6C(F2)N(&WE~_BNFP>nx)%`%B{00<%HyKYfR()hJM(H2>JsE2 zc^Rd%rWERF4v@raywc2y>NLGd6#Yd2g~aBf^xrS6M+s4kSy!ZjENIQAht6rQMH9;-82>VbOb09&J7T%)AdV0B0un?0A&7Wc#!+%UexD(wM}l7?G_imx9L+41Z5 z6X~c9+slkYFJqKRLVhht&Q_R|)#Gc($==)Wzb7l*pjoM~OOV1_P5!$KooXLonTELr zXjideWOKo?3I85)S`V#l+(U}}Sb;<~7uhZ}X|Qb<)4ushpfK}Be^(W@Z}YK}BaUOQ zcl??S9<^2cLi=+$Pn-e2EN0zf3jadR^mW}?+R`Nx0CPEZiyWQohR)AhtZ1IE3a$si z{6gxX&Mt5?{48XVr<3D1@Ab2dElq`~@Qv*}7SFkEL%3geTQ8$XsRf^w9Upp7H-PUk zx4XRx{mOT-S>MM>BBiWsqfQC=mHKJQ_0)54ydgsJWFBvjr{i!sC0H|R(BkHks=I@)iqqF``YFcdcVQa%|~*HCiijZIfv>6?nQ`LZnk{K9ZD|HR;{` z!U>#Sd*#!oHpr~Z->x@4^0wtWU7kDIZRRj3ot#)8VD;HlX6@*BOXEQ*j7@AXEPowd zB#pt8M&zaoy+>DQi5TD=GLb6zqNg(}AC#>JlQFxYxk#FK!k?apqiEX&xY-;7^I1Lk zZtt$})(-My;)*!~cwUJPMwVqh7b8}XFC2aECVMiWXUk_mFxX-LVS8S_U$*jRFJ6O4 z(x{bjB+3qGqhA5x>yJ`uy^I(lx>Dsy9kl4SQj#P9Dy8X3ZC@@9GZcdD~E5~xh`l@H=SlbtY&#>Z9LzM6#ki^2R1lC^bCGh16{8Q_$+s{c>d@r`?~uYIayWAx<4)6!F*g^qsUqV?=3VI01ZoywGvWwOD zN5i`8VxNvHu~_qgNs{Hh?F->{kY@U#9n1%FLcdpjf9j4oPVwlx>_Gw3CCS^3PGuFZ zvt)G*xyZ5^NAsHXoJDv+B|a!#xiPAFXnp&*H3z4B5}S`=tm6KblQZDV^3DXxR6hto z$^IB*3}v<)l2b^pYK1s=!c0WYqJ&U#iiOV=erW2;?w5bR(Dw|ieRi18L`m5nrS!9oMn*6 zJ3(+ycF+Iuz`{#a1YfGwYb(pdh=jU9L@rd~d2;1GprGb3*{m)yxR?M`zk=-AB?8^P zP~!C^ZI{aRVoad1&9dF>^)>}B@3)_K!OL@~J z9D5^4_B;I3s%x``6ia%PXI)k6i^#2CknlE;lgR{eFgzqc)eQdn4`lU)q;W}qXTFvE z@2^s){r=BfCR26BK9~7;9~9zd7Jc^W@ok;;8^@+a&mCG^51j}%6bY^20%w}6I@j4C z7d$nSzZCgOSFzj=4<Me~FS-;sO&#KF8{B?V;i2VC4? zIBv4JeKytzl32s_WrCzuGvx1R{G26j^h-O4tv}3V@u-v}Y%>J1JvvdX zjY9yBj8Gmj*rotCkL|+7n(f9K)u|@e8V{L+V6CnI;e(20zitaM-Km9 z_}o{q;}naC(87=X$wUF*^SF!OJgT~0V>y{1;T7Cu$8RL6Y;SeMOlQ(bB6vg4B#&J` zBs?Vj!+1{IAby-hLvnL3>D_8cXaY228PSp7V{_5{b?frXU&`Do*;IB)?#1ba+}z9` z<;Ltdu1o`#Q1AHqGedUaskYLq-15N3wJCKIMI%MHDpI&uXSNqys(5dA2s`2%6CK%x z-q)gpReLmajkTH{D@1by)}%n)yVRWa?}i zt18GCciKtx8Y4tX5(%jZdAlX6rLr)bL*0cko>xgJ4#1=W!SgC3B_0^sl%uDWWKB`U z4$`-n2V52ds4w7J)L?N@nJ*k;{tw1K#dzN1SpBstWE=EdOg6#vmF_R>o^aV_bYWNd zCg8zLK)GdVo)U&OYscoxn}0S5n`O5@a0yN6F5gv90ajAzMC#5_DjN9G#L)gJZaTF2 z#1e-6xF!0s*%NqU{R5W32DQ)>ms0jMoa<)o{u5bB*>EN>P1VOjKz_%)=zpQ4 z?I{%(m8!?D-nW!zcjjXu@=PHcT}~TM)Cgr2soBo%Sfo)3eeQiopOkq>YOj%N;ZIPG zT@pM?XjeI4Zsq&*dU#s<0b|PY&qh@tSYHgS`D}#}!a=k3-Nx-@WMj;%fg5!oykL@j zPpu~A75)3n6Pu;3B5b7O?5+b8hzPv&6iOPa-68(vEP#;dRML-#WqC9IZD=T=kjK^m z>LLhtq41m(bOcVRF@8^sO}4e0$hHadi{u7YNjSf<60^gkf`M~iH{m1>`z17QXBLQc zuZJInN=dVXF2{ay_nIq*SEdIN1-eNk+sy?(bhKa+`@5avKYzj$YZe4Q^JX?T_jP|5 zc{%=)ztaeLX`FZECGi)mpH}YYL!fb?Kt=!Ln%I$s!b(r~Luc8ktLprd?vm9-sYpUP99*tpHG_`**a@T}U zS`1_m=q3RDEwCtJvIXz}4u)8egA80k95_V45ORciFg1DH9n6i?D7*s+@46Fhbg@T18l)zxHlA@9<$NxWt z>gJ&T?nVT?X;Ji#BgdUFr=Mg4jLyd=%Q-xQ8GPj=E2K$P%MirDGAr0rt)pu~`;rue z`l4<6#9xc$z7Y}D;lS*N%(krk?bwGe><8!nx#)aLI>qVw%+{a7ltB+f`#9K)kkZ=V z_C9fV0U|WV?4*8{j79UioZ}4R$ft3O>i6BowUq88Qt}kex8W^T=CNz|mZwr11Rn}0 z{3F>@a>g`wX*L8#VZ(Jh4%9$`&~Dk<`>X_!OB}#k#n#PA{nnn|KvsZiH>o&rQY8J7 zG*Dplub6<&Yl9_GAc<3#nGj&;Rh4y}(tf94D?wS8vNxGlB+i=nxlKfH)@>nk+a>eK zp;vC!?9WM{U2tu0iXX&5UG%l4wg(oI3%BuI;RgiLM9E!t2P}f`fD!2oy4@lNtZf9K zZh_k8Pnq!=v8j|U#x4CC(+^qcsK{d8h*m~^Lu5BzTHJHy7hXt5oNqIsb~Tyf1e)XttM`NmxhxpHG#2*$0q%mGB3B5=!G*~ zK?WkR4ZsRl5Gl;ACwxx-F?;fjw}QA+tLdX^k#(9`*HoPJy)Cknfx;+wkK8&(ik_M? z&qJ-ddy?f%L_(tp1{=Ko{zQ0;?h8a4BjLxp0_pPgiCrehf;tO)0rlyK;E&KE-f`{x$ zKQogDiyw24JKZf=(t1UZ3lIuj-(ha`+tK=gE4?&DVPS4>uUlqU4E}fA1c7P?&`^Md OMTE(@xs`QQ$o~s<=R0Qr diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py index 8ac24d9..e9597a8 100644 --- a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -76,6 +76,312 @@ +class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Description | .. raw:: html | + | | | + | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | + | | pointer (12-bits)

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_desc(self) -> str: + return "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)" + + + + + + +class msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx async FIFO read and write pointers | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_7b98a70e_cls = msk_top_regs_data32_desc_7b98a70e_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_7b98a70e_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Description | .. raw:: html | + | | | + | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | + | | pointer (12-bits)

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Rx async FIFO read and write pointers" + + + + + + + +class msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls(FieldAsyncReadOnly): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Description | .. raw:: html | + | | | + | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | + | | pointer (12-bits)

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_desc(self) -> str: + return "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)" + + + + + + +class msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls(RegAsyncReadOnly): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx async FIFO read and write pointers | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__data'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__data:msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls = msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls( + parent_register=self, + size_props=FieldSizeProps( + width=32, + lsb=0, + msb=31, + low=0, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.data', + inst_name='data', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.data + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def data(self) -> msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls: + """ + Property to access data field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Description | .. raw:: html | + | | | + | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | + | | pointer (12-bits)

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__data + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'data':'data', + } + + + + + + + + + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + + @property + def rdl_name(self) -> str: + return "Tx async FIFO read and write pointers" + + + + + + + class msk_top_regs_rx_power_rx_power_cls(FieldAsyncReadOnly): """ @@ -414,7 +720,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -452,7 +758,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -489,7 +795,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -520,7 +826,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls: """ Property to access alpha field of the register @@ -559,7 +865,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1065fc05_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls: return super().get_child_by_system_rdl_name(name) @@ -2704,7 +3010,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls(FieldAsyncReadOnly): """ Class to represent a register field in the register model @@ -2779,7 +3085,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls( + self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2810,7 +3116,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls: + def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls: """ Property to access status_data field of the register @@ -2849,7 +3155,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x10647158_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls: return super().get_child_by_system_rdl_name(name) @@ -4454,7 +4760,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x10645fbf_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x107468c8_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -4530,7 +4836,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x10645fbf_cls = msk_top_regs_data_width_data_width_0x0x10645fbf_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x107468c8_cls = msk_top_regs_data_width_data_width_0x0x107468c8_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -4561,7 +4867,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x10645fbf_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x107468c8_cls: """ Property to access data_width field of the register @@ -4600,7 +4906,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x10645fbf_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x107468c8_cls: return super().get_child_by_system_rdl_name(name) @@ -5446,7 +5752,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5523,7 +5829,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls = msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5554,7 +5860,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls: """ Property to access config_data field of the register @@ -5595,7 +5901,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065dd1f_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls: return super().get_child_by_system_rdl_name(name) @@ -5619,7 +5925,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5696,7 +6002,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls = msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5727,7 +6033,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls: """ Property to access config_data field of the register @@ -5768,7 +6074,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065de03_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls: return super().get_child_by_system_rdl_name(name) @@ -5792,7 +6098,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5869,7 +6175,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls = msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5900,7 +6206,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls: """ Property to access config_data field of the register @@ -5941,7 +6247,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065df17_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls: return super().get_child_by_system_rdl_name(name) @@ -5965,7 +6271,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6042,7 +6348,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls = msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls = msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6073,7 +6379,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls: """ Property to access config_data field of the register @@ -6114,7 +6420,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1065e8ef_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls: return super().get_child_by_system_rdl_name(name) @@ -8047,7 +8353,7 @@ class msk_top_regs_cls(AsyncAddressMap): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__Hash_ID_Low', '__Hash_ID_High', '__MSK_Init', '__MSK_Control', '__MSK_Status', '__Tx_Bit_Count', '__Tx_Enable_Count', '__Fb_FreqWord', '__TX_F1_FreqWord', '__TX_F2_FreqWord', '__RX_F1_FreqWord', '__RX_F2_FreqWord', '__LPF_Config_0', '__LPF_Config_1', '__Tx_Data_Width', '__Rx_Data_Width', '__PRBS_Control', '__PRBS_Initial_State', '__PRBS_Polynomial', '__PRBS_Error_Mask', '__PRBS_Bit_Count', '__PRBS_Error_Count', '__LPF_Accum_F1', '__LPF_Accum_F2', '__axis_xfer_count', '__Rx_Sample_Discard', '__LPF_Config_2', '__f1_nco_adjust', '__f2_nco_adjust', '__f1_error', '__f2_error', '__Tx_Sync_Ctrl', '__Tx_Sync_Cnt', '__lowpass_ema_alpha1', '__lowpass_ema_alpha2', '__rx_power'] + __slots__ : list[str] = ['__Hash_ID_Low', '__Hash_ID_High', '__MSK_Init', '__MSK_Control', '__MSK_Status', '__Tx_Bit_Count', '__Tx_Enable_Count', '__Fb_FreqWord', '__TX_F1_FreqWord', '__TX_F2_FreqWord', '__RX_F1_FreqWord', '__RX_F2_FreqWord', '__LPF_Config_0', '__LPF_Config_1', '__Tx_Data_Width', '__Rx_Data_Width', '__PRBS_Control', '__PRBS_Initial_State', '__PRBS_Polynomial', '__PRBS_Error_Mask', '__PRBS_Bit_Count', '__PRBS_Error_Count', '__LPF_Accum_F1', '__LPF_Accum_F2', '__axis_xfer_count', '__Rx_Sample_Discard', '__LPF_Config_2', '__f1_nco_adjust', '__f2_nco_adjust', '__f1_error', '__f2_error', '__Tx_Sync_Ctrl', '__Tx_Sync_Cnt', '__lowpass_ema_alpha1', '__lowpass_ema_alpha2', '__rx_power', '__tx_async_fifo_rd_wr_ptr', '__rx_async_fifo_rd_wr_ptr'] def __init__(self, *, address:int=0, @@ -8332,7 +8638,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls = msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls = msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls( address=self.address+132, accesswidth=32, width=32, @@ -8355,10 +8661,26 @@ def __init__(self, *, logger_handle=logger_handle+'.rx_power', inst_name='rx_power', parent=self) + + self.__tx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls = msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls( + address=self.address+144, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.tx_async_fifo_rd_wr_ptr', + inst_name='tx_async_fifo_rd_wr_ptr', parent=self) + + + self.__rx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls = msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls( + address=self.address+148, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.rx_async_fifo_rd_wr_ptr', + inst_name='rx_async_fifo_rd_wr_ptr', parent=self) + @property def size(self) -> int: - return 144 + return 152 @property def Hash_ID_Low(self) -> msk_top_regs_msk_hash_lo_cls: """ @@ -9018,7 +9340,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls: """ Property to access lowpass_ema_alpha1 @@ -9077,6 +9399,38 @@ def rx_power(self) -> msk_top_regs_rx_power_cls: """ return self.__rx_power + @property + def tx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls: + """ + Property to access tx_async_fifo_rd_wr_ptr + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Tx async FIFO read and write pointers | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__tx_async_fifo_rd_wr_ptr + + @property + def rx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls: + """ + Property to access rx_async_fifo_rd_wr_ptr + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Rx async FIFO read and write pointers | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_async_fifo_rd_wr_ptr + @property @@ -9088,7 +9442,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'Hash_ID_Low':'Hash_ID_Low','Hash_ID_High':'Hash_ID_High','MSK_Init':'MSK_Init','MSK_Control':'MSK_Control','MSK_Status':'MSK_Status','Tx_Bit_Count':'Tx_Bit_Count','Tx_Enable_Count':'Tx_Enable_Count','Fb_FreqWord':'Fb_FreqWord','TX_F1_FreqWord':'TX_F1_FreqWord','TX_F2_FreqWord':'TX_F2_FreqWord','RX_F1_FreqWord':'RX_F1_FreqWord','RX_F2_FreqWord':'RX_F2_FreqWord','LPF_Config_0':'LPF_Config_0','LPF_Config_1':'LPF_Config_1','Tx_Data_Width':'Tx_Data_Width','Rx_Data_Width':'Rx_Data_Width','PRBS_Control':'PRBS_Control','PRBS_Initial_State':'PRBS_Initial_State','PRBS_Polynomial':'PRBS_Polynomial','PRBS_Error_Mask':'PRBS_Error_Mask','PRBS_Bit_Count':'PRBS_Bit_Count','PRBS_Error_Count':'PRBS_Error_Count','LPF_Accum_F1':'LPF_Accum_F1','LPF_Accum_F2':'LPF_Accum_F2','axis_xfer_count':'axis_xfer_count','Rx_Sample_Discard':'Rx_Sample_Discard','LPF_Config_2':'LPF_Config_2','f1_nco_adjust':'f1_nco_adjust','f2_nco_adjust':'f2_nco_adjust','f1_error':'f1_error','f2_error':'f2_error','Tx_Sync_Ctrl':'Tx_Sync_Ctrl','Tx_Sync_Cnt':'Tx_Sync_Cnt','lowpass_ema_alpha1':'lowpass_ema_alpha1','lowpass_ema_alpha2':'lowpass_ema_alpha2','rx_power':'rx_power', + return {'Hash_ID_Low':'Hash_ID_Low','Hash_ID_High':'Hash_ID_High','MSK_Init':'MSK_Init','MSK_Control':'MSK_Control','MSK_Status':'MSK_Status','Tx_Bit_Count':'Tx_Bit_Count','Tx_Enable_Count':'Tx_Enable_Count','Fb_FreqWord':'Fb_FreqWord','TX_F1_FreqWord':'TX_F1_FreqWord','TX_F2_FreqWord':'TX_F2_FreqWord','RX_F1_FreqWord':'RX_F1_FreqWord','RX_F2_FreqWord':'RX_F2_FreqWord','LPF_Config_0':'LPF_Config_0','LPF_Config_1':'LPF_Config_1','Tx_Data_Width':'Tx_Data_Width','Rx_Data_Width':'Rx_Data_Width','PRBS_Control':'PRBS_Control','PRBS_Initial_State':'PRBS_Initial_State','PRBS_Polynomial':'PRBS_Polynomial','PRBS_Error_Mask':'PRBS_Error_Mask','PRBS_Bit_Count':'PRBS_Bit_Count','PRBS_Error_Count':'PRBS_Error_Count','LPF_Accum_F1':'LPF_Accum_F1','LPF_Accum_F2':'LPF_Accum_F2','axis_xfer_count':'axis_xfer_count','Rx_Sample_Discard':'Rx_Sample_Discard','LPF_Config_2':'LPF_Config_2','f1_nco_adjust':'f1_nco_adjust','f2_nco_adjust':'f2_nco_adjust','f1_error':'f1_error','f2_error':'f2_error','Tx_Sync_Ctrl':'Tx_Sync_Ctrl','Tx_Sync_Cnt':'Tx_Sync_Cnt','lowpass_ema_alpha1':'lowpass_ema_alpha1','lowpass_ema_alpha2':'lowpass_ema_alpha2','rx_power':'rx_power','tx_async_fifo_rd_wr_ptr':'tx_async_fifo_rd_wr_ptr','rx_async_fifo_rd_wr_ptr':'rx_async_fifo_rd_wr_ptr', } @@ -9097,7 +9451,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - # nodes:36 + # nodes:38 @overload def get_child_by_system_rdl_name(self, name: Literal["Hash_ID_Low"]) -> msk_top_regs_msk_hash_lo_cls: ... @@ -9232,7 +9586,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls: ... @overload @@ -9242,9 +9596,17 @@ def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha2"]) -> m @overload def get_child_by_system_rdl_name(self, name: Literal["rx_power"]) -> msk_top_regs_rx_power_cls: ... + + @overload + def get_child_by_system_rdl_name(self, name: Literal["tx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls: ... + @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1065fc20_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls, msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) @@ -9379,6 +9741,12 @@ def get_registers(self, unroll:bool=False) -> Iterator[Union[AsyncReg, AsyncRegA yield self.rx_power + + yield self.tx_async_fifo_rd_wr_ptr + + + yield self.rx_async_fifo_rd_wr_ptr + # Empty generator in case there are no children of this type if False: yield diff --git a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py index 95e0aa1..0b442a7 100644 --- a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py @@ -165,6 +165,14 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe Register(width=32, full_inst_name='msk_top_regs.rx_power', readable=True, writable=False, fields=[FieldDefinition(high=22, low=0, msb=22, lsb=0, inst_name='rx_power'), ]), + 144 : + Register(width=32, full_inst_name='msk_top_regs.tx_async_fifo_rd_wr_ptr', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), + 148 : + Register(width=32, full_inst_name='msk_top_regs.rx_async_fifo_rd_wr_ptr', readable=True, writable=False, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), + ]), } def _build_memories(self) -> list[MemoryEntry]: diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py index 9241d51..2b9468e 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -164,6 +164,12 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.rx_power'): self.assertEqual(self.dut.rx_power.inst_name, 'rx_power') # type: ignore[union-attr] self.assertEqual(self.dut.rx_power.full_inst_name, 'msk_top_regs.rx_power') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.inst_name, 'tx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.full_inst_name, 'msk_top_regs.tx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.inst_name, 'rx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.full_inst_name, 'msk_top_regs.rx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.inst_name, 'hash_id_lo') # type: ignore[union-attr] self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.full_inst_name, 'msk_top_regs.Hash_ID_Low.hash_id_lo') # type: ignore[union-attr] @@ -341,6 +347,12 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): self.assertEqual(self.dut.rx_power.rx_power.inst_name, 'rx_power') # type: ignore[union-attr] self.assertEqual(self.dut.rx_power.rx_power.full_inst_name, 'msk_top_regs.rx_power.rx_power') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.full_inst_name, 'msk_top_regs.tx_async_fifo_rd_wr_ptr.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.full_inst_name, 'msk_top_regs.rx_async_fifo_rd_wr_ptr.data') # type: ignore[union-attr] def test_name_property(self) -> None: @@ -599,6 +611,20 @@ def test_name_property(self) -> None: + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + + + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.rdl_name, "Tx async FIFO read and write pointers") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + + + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.rdl_name, "Rx async FIFO read and write pointers") # type: ignore[union-attr] + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): @@ -1012,6 +1038,20 @@ def test_name_property(self) -> None: + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + + + self.assertIsNone(self.dut.tx_async_fifo_rd_wr_ptr.data.rdl_name) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + + + self.assertIsNone(self.dut.rx_async_fifo_rd_wr_ptr.data.rdl_name) # type: ignore[union-attr] + + + def test_desc(self) -> None: @@ -1270,6 +1310,20 @@ def test_desc(self) -> None: + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + + + self.assertIsNone(self.dut.tx_async_fifo_rd_wr_ptr.rdl_desc) # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + + + self.assertIsNone(self.dut.rx_async_fifo_rd_wr_ptr.rdl_desc) # type: ignore[union-attr] + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): @@ -1683,6 +1737,20 @@ def test_desc(self) -> None: + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + + + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.rdl_desc, "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + + + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.rdl_desc, "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)") # type: ignore[union-attr] + + + def test_sizes(self) -> None: @@ -1761,12 +1829,16 @@ def test_sizes(self) -> None: self.assertEqual(self.dut.lowpass_ema_alpha2.size, 4) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.rx_power'): self.assertEqual(self.dut.rx_power.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] # check the size of the address map itself with self.subTest(msg='node: msk_top_regs'): - self.assertEqual(self.dut.size, 144) # type: ignore[union-attr] + self.assertEqual(self.dut.size, 152) # type: ignore[union-attr] @@ -1955,6 +2027,16 @@ def test_register_properties(self) -> None: self.assertEqual(self.dut.rx_power.width, 32) # type: ignore[union-attr] self.assertEqual(self.dut.rx_power.size, 4) # type: ignore[union-attr] self.assertEqual(self.dut.rx_power.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.address, 144) # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.address, 148) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.accesswidth, 32) # type: ignore[union-attr] def test_memory_properties(self) -> None: @@ -2916,6 +2998,38 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + # test properties of field: msk_top_regs.tx_async_fifo_rd_wr_ptr.data + fut = self.dut.tx_async_fifo_rd_wr_ptr.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + # test properties of field: msk_top_regs.rx_async_fifo_rd_wr_ptr.data + fut = self.dut.rx_async_fifo_rd_wr_ptr.data # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFFFFFFFF) + self.assertEqual(fut.inverse_bitmask,0x0) + self.assertEqual(fut.max_value,0xFFFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) def test_field_encoding_properties(self) -> None: @@ -2979,6 +3093,8 @@ def test_field_encoding_properties(self) -> None: + + @@ -3131,6 +3247,14 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.rx_power.udp,{}) + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + + self.assertDictEqual(self.dut.tx_async_fifo_rd_wr_ptr.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + + self.assertDictEqual(self.dut.rx_async_fifo_rd_wr_ptr.udp,{}) + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low.hash_id_lo'): self.assertDictEqual(self.dut.Hash_ID_Low.hash_id_lo.udp,{}) @@ -3367,6 +3491,14 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.rx_power.rx_power.udp,{}) + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + + self.assertDictEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + + self.assertDictEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.udp,{}) + async def test_register_read_and_write(self) -> None: @@ -6170,6 +6302,122 @@ async def test_register_read_and_write(self) -> None: + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + rut=self.dut.tx_async_fifo_rd_wr_ptr # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + # test that a non-writable register has no write method and attempting one generates and error + with self.assertRaises(AttributeError): + await rut.write(0) # type: ignore[attr-defined] + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + rut=self.dut.rx_async_fifo_rd_wr_ptr # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + # test that a non-writable register has no write method and attempting one generates and error with self.assertRaises(AttributeError): await rut.write(0) # type: ignore[attr-defined] @@ -10344,6 +10592,102 @@ async def test_int_field_read_and_write(self) -> None: read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # test access operations (read and/or write) to field: + # msk_top_regs.tx_async_fifo_rd_wr_ptr.data + with self.subTest(msg='field: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + fut = self.dut.tx_async_fifo_rd_wr_ptr.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + # test access operations (read and/or write) to field: + # msk_top_regs.rx_async_fifo_rd_wr_ptr.data + with self.subTest(msg='field: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + fut = self.dut.rx_async_fifo_rd_wr_ptr.data # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x0 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await fut.read(), + 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + async def test_register_read_fields(self) -> None: @@ -11756,6 +12100,70 @@ async def test_register_read_fields(self) -> None: reference_read_fields) read_callback_mock.assert_called_once() write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + # test read_fields to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.tx_async_fifo_rd_wr_ptr.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.tx_async_fifo_rd_wr_ptr.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + # test read_fields to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'data' : await self.dut.rx_async_fifo_rd_wr_ptr.data.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.rx_async_fifo_rd_wr_ptr.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() async def test_register_read_context_manager(self) -> None: """ @@ -13392,6 +13800,78 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.assert_called_once() write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.tx_async_fifo_rd_wr_ptr.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.tx_async_fifo_rd_wr_ptr.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'data' : await self.dut.rx_async_fifo_rd_wr_ptr.data.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.rx_async_fifo_rd_wr_ptr.single_read() as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() async def test_register_write_context_manager(self) -> None: """ @@ -13982,6 +14462,16 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.rx_power.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.tx_async_fifo_rd_wr_ptr.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_async_fifo_rd_wr_ptr.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type @@ -14277,6 +14767,16 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.rx_power.rx_power.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.tx_async_fifo_rd_wr_ptr.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_async_fifo_rd_wr_ptr.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] @@ -14362,6 +14862,10 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_power, # type: ignore[union-attr,list-item] + self.dut.tx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + + self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + ] readable_regs = [] for readable_reg in self.dut.get_readable_registers(unroll=True): # type: ignore[union-attr] @@ -14441,6 +14945,10 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_power, # type: ignore[union-attr,list-item] + self.dut.tx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + + self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + ] readable_regs = [] for readable_reg in self.dut.get_readable_registers(unroll=False): # type: ignore[union-attr] @@ -14520,6 +15028,10 @@ def test_top_traversal_iterators(self) -> None: + + + + ] writable_regs = [] for writable_reg in self.dut.get_writable_registers(unroll=True): # type: ignore[union-attr] @@ -14599,6 +15111,10 @@ def test_top_traversal_iterators(self) -> None: + + + + ] writable_regs = [] for writable_reg in self.dut.get_writable_registers(unroll=False): # type: ignore[union-attr] @@ -14673,6 +15189,10 @@ def test_top_traversal_iterators(self) -> None: + + + + @@ -14752,6 +15272,10 @@ def test_top_traversal_iterators(self) -> None: + + + + @@ -14831,6 +15355,10 @@ def test_top_traversal_iterators(self) -> None: + + + + @@ -14910,6 +15438,10 @@ def test_top_traversal_iterators(self) -> None: + + + + @@ -16129,6 +16661,56 @@ def test_traversal_iterators(self) -> None: readable_fields.append(readable_field) self.assertCountEqual(expected_readable_fields, readable_fields) + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + + expected_fields = [self.dut.tx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.tx_async_fifo_rd_wr_ptr.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.tx_async_fifo_rd_wr_ptr, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.tx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.tx_async_fifo_rd_wr_ptr.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + + expected_fields = [self.dut.rx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.rx_async_fifo_rd_wr_ptr.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + # register should not have writable_fields attribute + self.assertFalse(hasattr(self.dut.rx_async_fifo_rd_wr_ptr, 'writable_fields')) # type: ignore[union-attr] + + + expected_readable_fields = [self.dut.rx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.rx_async_fifo_rd_wr_ptr.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + # test all the memories @@ -16474,6 +17056,20 @@ def test_name_map(self) -> None: + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.get_child_by_system_rdl_name('data').inst_name, 'data') + + + + + + + diff --git a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py index d649ad0..f4578fd 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py @@ -1700,6 +1700,74 @@ async def test_register_read_and_write(self) -> None: + # test access operations (read and/or write) to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + sim_register = self.sim.register_by_full_name('msk_top_regs.tx_async_fifo_rd_wr_ptr') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_async_fifo_rd_wr_ptr') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + + async def test_field_read_and_write(self) -> None: @@ -7492,6 +7560,138 @@ async def test_field_read_and_write(self) -> None: + # test access operations (read and/or write) to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr.data + with self.subTest(msg='field: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.tx_async_fifo_rd_wr_ptr') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.tx_async_fifo_rd_wr_ptr.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr.data + with self.subTest(msg='field: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_async_fifo_rd_wr_ptr') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_async_fifo_rd_wr_ptr.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + + diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd index 25efa10..dc0d5cb 100644 --- a/rdl/outputs/rtl/msk_top_regs.vhd +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -115,6 +115,8 @@ architecture rtl of msk_top_regs is lowpass_ema_alpha1 : std_logic; lowpass_ema_alpha2 : std_logic; rx_power : std_logic; + tx_async_fifo_rd_wr_ptr : std_logic; + rx_async_fifo_rd_wr_ptr : std_logic; end record; signal decoded_reg_strb : decoded_reg_strb_t; signal decoded_strb_is_external : std_logic; @@ -764,7 +766,7 @@ architecture rtl of msk_top_regs is signal readback_err : std_logic; signal readback_done : std_logic; signal readback_data : std_logic_vector(31 downto 0); - signal readback_array : std_logic_vector_array1(0 to 35)(31 downto 0); + signal readback_array : std_logic_vector_array1(0 to 37)(31 downto 0); begin @@ -1050,6 +1052,10 @@ begin decoded_reg_strb.lowpass_ema_alpha2 <= cpuif_req_masked and (cpuif_addr = 16#88#); decoded_reg_strb.rx_power <= cpuif_req_masked and (cpuif_addr = 16#8C#); is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#8C#)) and not cpuif_req_is_wr); + decoded_reg_strb.tx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#90#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#90#)) and not cpuif_req_is_wr); + decoded_reg_strb.rx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#94#); + is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#94#)) and not cpuif_req_is_wr); decoded_strb_is_external <= is_external; external_req <= is_external; end process; @@ -2303,6 +2309,12 @@ begin hwif_out.rx_power.req <= decoded_reg_strb.rx_power when not decoded_req_is_wr else '0'; hwif_out.rx_power.req_is_wr <= decoded_req_is_wr; + hwif_out.tx_async_fifo_rd_wr_ptr.req <= decoded_reg_strb.tx_async_fifo_rd_wr_ptr when not decoded_req_is_wr else '0'; + hwif_out.tx_async_fifo_rd_wr_ptr.req_is_wr <= decoded_req_is_wr; + + hwif_out.rx_async_fifo_rd_wr_ptr.req <= decoded_reg_strb.rx_async_fifo_rd_wr_ptr when not decoded_req_is_wr else '0'; + hwif_out.rx_async_fifo_rd_wr_ptr.req_is_wr <= decoded_req_is_wr; + ---------------------------------------------------------------------------- -- Write response ---------------------------------------------------------------------------- @@ -2336,6 +2348,8 @@ begin rd_ack := rd_ack or hwif_in.f1_error.rd_ack; rd_ack := rd_ack or hwif_in.f2_error.rd_ack; rd_ack := rd_ack or hwif_in.rx_power.rd_ack; + rd_ack := rd_ack or hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack; + rd_ack := rd_ack or hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack; readback_external_rd_ack_c <= rd_ack; end process; @@ -2409,6 +2423,8 @@ begin readback_array(34)(17 downto 0) <= field_storage.lowpass_ema_alpha2.alpha.value when (decoded_reg_strb.lowpass_ema_alpha2 and not decoded_req_is_wr) else (others => '0'); readback_array(34)(31 downto 18) <= (others => '0'); readback_array(35) <= hwif_in.rx_power.rd_data when hwif_in.rx_power.rd_ack else (others => '0'); + readback_array(36) <= hwif_in.tx_async_fifo_rd_wr_ptr.rd_data when hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack else (others => '0'); + readback_array(37) <= hwif_in.rx_async_fifo_rd_wr_ptr.rd_data when hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack else (others => '0'); -- Reduce the array process(all) diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd index c00bed8..394906e 100644 --- a/rdl/outputs/rtl/msk_top_regs_pkg.vhd +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -9,7 +9,7 @@ package msk_top_regs_pkg is constant MSK_TOP_REGS_DATA_WIDTH : positive := 32; constant MSK_TOP_REGS_MIN_ADDR_WIDTH : positive := 8; - constant MSK_TOP_REGS_SIZE : positive := 144; + constant MSK_TOP_REGS_SIZE : positive := 152; type \msk_top_regs.msk_stat_0.demod_sync_lock_in_t\ is record next_q : std_logic; @@ -94,6 +94,16 @@ package msk_top_regs_pkg is rd_data : std_logic_vector(31 downto 0); end record; + type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_in_t\ is record + rd_ack : std_logic; + rd_data : std_logic_vector(31 downto 0); + end record; + type msk_top_regs_in_t is record MSK_Status : \msk_top_regs.msk_stat_0_in_t\; Tx_Bit_Count : \msk_top_regs.msk_stat_1__external_in_t\; @@ -108,6 +118,8 @@ package msk_top_regs_pkg is f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_in_t\; f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_in_t\; rx_power : \msk_top_regs.rx_power__external_in_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_in_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_in_t\; end record; type \msk_top_regs.msk_init.txrxinit_out_t\ is record @@ -430,6 +442,16 @@ package msk_top_regs_pkg is req_is_wr : std_logic; end record; + type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + + type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_out_t\ is record + req : std_logic; + req_is_wr : std_logic; + end record; + type msk_top_regs_out_t is record MSK_Init : \msk_top_regs.msk_init_out_t\; MSK_Control : \msk_top_regs.msk_ctrl_out_t\; @@ -464,5 +486,7 @@ package msk_top_regs_pkg is lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha_out_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha_out_t\; rx_power : \msk_top_regs.rx_power__external_out_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_out_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_out_t\; end record; end package; diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index c293d19..852fc5f 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -551,5 +551,12 @@ addrmap msk_top_regs { lowpass_ema_alpha lowpass_ema_alpha1; lowpass_ema_alpha lowpass_ema_alpha2; external rx_power rx_power; - + external observation_data tx_async_fifo_rd_wr_ptr; + tx_async_fifo_rd_wr_ptr->name = "Tx async FIFO read and write pointers"; + tx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) + Bits 15:00 -> read pointer (12-bits)"; + external observation_data rx_async_fifo_rd_wr_ptr; + rx_async_fifo_rd_wr_ptr->name = "Rx async FIFO read and write pointers"; + rx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) + Bits 15:00 -> read pointer (12-bits)"; }; diff --git a/sim/Makefile b/sim/Makefile index b41afca..672cb30 100644 --- a/sim/Makefile +++ b/sim/Makefile @@ -27,6 +27,7 @@ VHDL_SOURCES += $(RDL)/src/axi4lite_intf_pkg.vhd \ $(SRC)/pulse_detect.vhd \ $(SRC)/data_capture.vhd \ $(SRC)/cdc_resync.vhd \ + $(SRC)/frame_sync_detector.vhd \ $(SRC)/axis_async_fifo.vhd \ $(SRC)/axis_dma_adapter.vhd \ $(SRC)/byte_to_bit_deserializer.vhd \ diff --git a/sim/msk_test.py b/sim/msk_test.py index f595209..788ff60 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -130,9 +130,11 @@ def __init__(self, dut): self.aclk = dut.s_axis_aclk self.aresetn = dut.s_axis_aresetn - self.tvalid = dut.s_axis_valid - self.tready = dut.s_axis_ready - self.tdata = dut.s_axis_data + self.tvalid = dut.s_axis_tvalid + self.tready = dut.s_axis_tready + self.tdata = dut.s_axis_tdata + self.tlast = dut.s_axis_tlast + self.tkeep = dut.s_axis_tkeep self.aresetn.value = 1 self.tvalid.value = 0 @@ -793,12 +795,11 @@ async def msk_test_1(dut): # dut.s_axi_awvalid.value = 1 # await regs.write("msk_top_regs", "PRBS_Control", data) - # if sim_time_d <= sim_start + 20000 and sim_time >= sim_start + 20000: - # data = await regs.read("msk_top_regs", "PRBS_Control") - # data = data ^ 0x8 - # dut.s_axi_wvalid.value = 1 - # dut.s_axi_awvalid.value = 1 - # await regs.write("msk_top_regs", "PRBS_Control", data) + # if sim_time_d <= sim_start + 30000 and sim_time >= sim_start + 30000: + # data = await regs.tx_async_fifo_rd_wr_ptr.read() + # print("Tx FIFO Pointers", hex(data)) + # data = await regs.rx_async_fifo_rd_wr_ptr.read() + # print("Rx FIFO Pointers", hex(data)) if sim_time_d <= sim_start + 20000 and sim_time >= sim_start + 20000: data = await regs.PRBS_Control.read() @@ -833,6 +834,10 @@ async def msk_test_1(dut): print("F1 Error: ", hex(data)) data = await regs.f2_error.read() print("F2 Error: ", hex(data)) + data = await regs.tx_async_fifo_rd_wr_ptr.read() + print("Tx FIFO Pointers", hex(data)) + data = await regs.rx_async_fifo_rd_wr_ptr.read() + print("Rx FIFO Pointers", hex(data)) #data = await regs.read("msk_top_regs", "LPF_Accum_F1") # print("F1 Acc: ", hex(data)) # data = await regs.read("msk_top_regs", "LPF_Accum_F2") diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index ec47e82..1ab08b4 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -48,7 +48,7 @@ ENTITY axis_async_fifo IS fifo_overflow : OUT std_logic; fifo_underflow : OUT std_logic; fifo_wr_ptr : OUT std_logic_vector(ADDR_WIDTH DOWNTO 0); - fifo_rd_ptr : OUT srd_logic_vector(ADDR_WIDTH DOWNTO 0) + fifo_rd_ptr : OUT std_logic_vector(ADDR_WIDTH DOWNTO 0) ); END ENTITY axis_async_fifo; @@ -87,6 +87,23 @@ ARCHITECTURE rtl OF axis_async_fifo IS SIGNAL prog_full_int : std_logic := '0'; SIGNAL prog_empty_int : std_logic := '0'; + -- Status resync to AXI + SIGNAL wr_status_ack : std_logic; + SIGNAL wr_status_ack_sync1 : std_logic; + SIGNAL wr_status_ack_sync2 : std_logic; + SIGNAL wr_status_req_sync1 : std_logic; + SIGNAL wr_status_req_sync2 : std_logic; + SIGNAL rd_status_ack : std_logic; + SIGNAL rd_status_ack_sync1 : std_logic; + SIGNAL rd_status_ack_sync2 : std_logic; + SIGNAL rd_status_req_sync1 : std_logic; + SIGNAL rd_status_req_sync2 : std_logic; + + SIGNAL srequest : std_logic; + + TYPE state_type IS (IDLE, WAIT_FOR_WR_ACK, WAIT_FOR_RD_ACK); + SIGNAL status_state : state_type; + -- Binary to Gray conversion FUNCTION bin_to_gray(bin : std_logic_vector) RETURN std_logic_vector IS VARIABLE gray : std_logic_vector(bin'RANGE); @@ -230,40 +247,51 @@ BEGIN ------------------------------------------------------------------------------ -- Status Clock Domain ------------------------------------------------------------------------------ - status_proc : PROCESS (prog_aclk) + + status_proc : PROCESS (status_aclk) BEGIN - IF rising_edge(prog_aclk) BEGIN - IF prog_aresetn = '0' THEN + IF rising_edge(status_aclk) THEN + IF status_aresetn = '0' THEN --prog_empty <= '0'; --prog_full <= '0'; fifo_overflow <= '0'; fifo_underflow <= '0'; fifo_wr_ptr <= (OTHERS => '0'); fifo_rd_ptr <= (OTHERS => '0'); - fifo_status_ack <= '0'; + status_ack <= '0'; ELSE + CASE status_state IS + WHEN IDLE => + srequest <= '0'; + status_ack <= '0'; + IF status_req = '1' THEN + srequest <= '1'; + status_state <= WAIT_FOR_WR_ACK; + END IF; + + WHEN WAIT_FOR_WR_ACK => + IF wr_status_ack_sync2 = '1' THEN + status_state <= WAIT_FOR_RD_ACK; + END IF; + + WHEN WAIT_FOR_RD_ACK => + IF rd_status_ack_sync2 = '1' THEN + status_ack <= '1'; + srequest <= '0'; + status_state <= IDLE; + END IF; + + WHEN OTHERS => + status_state <= IDLE; + + END CASE; + wr_status_ack_sync1 <= wr_status_ack; wr_status_ack_sync2 <= wr_status_ack_sync1; - wr_status_ack_sync3 <= wr_status_ack_sync2; - - IF (wr_status_req_sync2 XOR wr_status_ack_sync3) = '1' THEN - prog_wr_status_ack <= '1'; - END IF; rd_status_ack_sync1 <= rd_status_ack; rd_status_ack_sync2 <= rd_status_ack_sync1; - rd_status_ack_sync3 <= rd_status_ack_sync2; - - IF (rd_status_req_sync2 XOR rd_status_ack_sync3) = '1' THEN - prog_rd_status_ack <= '1'; - END IF; - - IF prog_wr_status_ack = '1' AND prod_rd_status_ack = '1' THEN - prog_status_ack <= '1'; - ELSE - prog_status_ack <= '0'; - END IF; END IF; END IF; @@ -277,12 +305,12 @@ BEGIN wr_status_req_sync2 <= '0'; wr_status_ack <= '0'; ELSE - wr_status_req_sync1 <= prog_status_req; + wr_status_req_sync1 <= srequest; wr_status_req_sync2 <= wr_status_req_sync1; + wr_status_ack <= wr_status_req_sync2; IF wr_status_req_sync2 THEN fifo_wr_ptr <= wr_ptr_bin; - wr_status_ack <= NOT wr_status_ack; END IF; END IF; END IF; @@ -296,15 +324,15 @@ BEGIN rd_status_req_sync2 <= '0'; rd_status_ack <= '0'; ELSE - rd_status_req_sync1 <= prog_status_req; + rd_status_req_sync1 <= srequest; rd_status_req_sync2 <= rd_status_req_sync1; + rd_status_ack <= rd_status_req_sync2; IF rd_status_req_sync2 THEN fifo_rd_ptr <= rd_ptr_bin; - rd_status_ack <= NOT rd_status_ack; END IF; END IF; END IF; - END PROCESS status_wrclk; + END PROCESS status_rdclk; END ARCHITECTURE rtl; diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 069bd1e..61ca0bc 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -173,8 +173,8 @@ ARCHITECTURE struct OF msk_top IS SIGNAL tx_async_fifo_prog_empty : std_logic; SIGNAL tx_async_fifo_overflow : std_logic; SIGNAL tx_async_fifo_underflow : std_logic; - SIGNAL tx_async_fifo_wr_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); - SIGNAL tx_async_fifo_rd_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL tx_async_fifo_wr_ptr : std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL tx_async_fifo_rd_ptr : std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); SIGNAL tx_async_fifo_status_req : std_logic; SIGNAL tx_async_fifo_status_ack : std_logic; @@ -182,8 +182,8 @@ ARCHITECTURE struct OF msk_top IS SIGNAL rx_async_fifo_prog_empty : std_logic; SIGNAL rx_async_fifo_overflow : std_logic; SIGNAL rx_async_fifo_underflow : std_logic; - SIGNAL rx_async_fifo_wr_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); - SIGNAL rx_async_fifo_rd_ptr : std_logic(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL rx_async_fifo_wr_ptr : std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + SIGNAL rx_async_fifo_rd_ptr : std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); SIGNAL rx_async_fifo_status_req : std_logic; SIGNAL rx_async_fifo_status_ack : std_logic; @@ -339,16 +339,16 @@ BEGIN m_axis_tlast => fifo_tlast, -- status signals synchronized to AXI control/status bus - prog_aclk => s_axi_aclk, - prog_aresetn => s_axi_aresetn, - prog_status_req => tx_async_fifo_status_req, - prog_status_ack => tx_async_fifo_status_ack, + status_aclk => s_axi_aclk, + status_aresetn => s_axi_aresetn, + status_req => tx_async_fifo_status_req, + status_ack => tx_async_fifo_status_ack, prog_full => tx_async_fifo_prog_full, prog_empty => tx_async_fifo_prog_empty, - prog_overflow => tx_async_fifo_overflow, - prog_underflow => tx_async_fifo_underflow, - prog_wr_ptr => tx_async_fifo_wr_ptr, - prog_rd_ptr => tx_async_fifo_rd_ptr + fifo_overflow => tx_async_fifo_overflow, + fifo_underflow => tx_async_fifo_underflow, + fifo_wr_ptr => tx_async_fifo_wr_ptr, + fifo_rd_ptr => tx_async_fifo_rd_ptr ); -- Stage 3: Byte-to-Bit De-serializer (MSB-FIRST VERSION) @@ -523,16 +523,16 @@ BEGIN m_axis_tlast => m_axis_tlast, -- status signals synchronized to AXI control/status bus - prog_aclk => s_axi_aclk, - prog_aresetn => s_axi_aresetn, - prog_status_req => rx_async_fifo_status_req, - prog_status_ack => rx_async_fifo_status_ack, - prog_full => rx_async_fifo_prog_full, - prog_empty => rx_async_fifo_prog_empty, - prog_overflow => rx_async_fifo_overflow, - prog_underflow => rx_async_fifo_underflow, - prog_wr_ptr => rx_async_fifo_wr_ptr, - prog_rd_ptr => rx_async_fifo_rd_ptr + status_aclk => s_axi_aclk, + status_aresetn => s_axi_aresetn, + status_req => rx_async_fifo_status_req, + status_ack => rx_async_fifo_status_ack, + prog_full => rx_async_fifo_prog_full, + prog_empty => rx_async_fifo_prog_empty, + fifo_overflow => rx_async_fifo_overflow, + fifo_underflow => rx_async_fifo_underflow, + fifo_wr_ptr => rx_async_fifo_wr_ptr, + fifo_rd_ptr => rx_async_fifo_rd_ptr ); -- Zero-pad upper bits of m_axis_tdata if wider than 8 bits @@ -767,6 +767,14 @@ BEGIN f2_nco_adjust => f2_nco_adjust, f1_error => f1_error, f2_error => f2_error, + tx_async_fifo_wr_ptr => tx_async_fifo_wr_ptr, + tx_async_fifo_rd_ptr => tx_async_fifo_rd_ptr, + tx_async_fifo_status_req => tx_async_fifo_status_req, + tx_async_fifo_status_ack => tx_async_fifo_status_ack, + rx_async_fifo_wr_ptr => rx_async_fifo_wr_ptr, + rx_async_fifo_rd_ptr => rx_async_fifo_rd_ptr, + rx_async_fifo_status_req => rx_async_fifo_status_req, + rx_async_fifo_status_ack => rx_async_fifo_status_ack, txinit => txinit, rxinit => rxinit, ptt => ptt, diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index 9fa83bd..ee86e51 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -84,7 +84,8 @@ ENTITY msk_top_csr IS SYNC_W : NATURAL := 16; C_S_AXI_DATA_WIDTH : NATURAL := 32; C_S_AXI_ADDR_WIDTH : NATURAL := 32; - SYNC_CNT_W : NATURAL := 24 + SYNC_CNT_W : NATURAL := 24; + FIFO_ADDR_WIDTH : NATURAL := 11 ); PORT ( clk : IN std_logic; @@ -128,6 +129,15 @@ ENTITY msk_top_csr IS f1_error : IN std_logic_vector(31 DOWNTO 0); f2_error : IN std_logic_vector(31 DOWNTO 0); + tx_async_fifo_wr_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + tx_async_fifo_rd_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + tx_async_fifo_status_req : OUT std_logic; + tx_async_fifo_status_ack : IN std_logic; + rx_async_fifo_wr_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + rx_async_fifo_rd_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); + rx_async_fifo_status_req : OUT std_logic; + rx_async_fifo_status_ack : IN std_logic; + txinit : out std_logic; rxinit : out std_logic; ptt : out std_logic; @@ -333,6 +343,17 @@ BEGIN utpwr_c: data_capture PORT MAP (clk, csr_init, pd_power_req, std_logic_vector(resize(unsigned(pd_power),32)), hwif_in.rx_power.rd_data); + -- FIFO status reads + rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.req; + hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack <= rx_async_fifo_status_ack; + hwif_in.rx_async_fifo_rd_wr_ptr.rd_data <= std_logic_vector(resize(unsigned(rx_async_fifo_wr_ptr), 16) & + resize(unsigned(rx_async_fifo_rd_ptr), 16)); + + tx_async_fifo_status_req <= hwif_out.tx_async_fifo_rd_wr_ptr.req; + hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack <= tx_async_fifo_status_ack; + hwif_in.tx_async_fifo_rd_wr_ptr.rd_data <= std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 16) & + resize(unsigned(tx_async_fifo_rd_ptr), 16)); + -- Control from AXI to MDM u01s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txrxinit.value, txrxinit ); u02s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txinit.value OR txrxinit, txinit ); From 4923b1f4f408e1f177aa0084735fc4843081dc32 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Sun, 26 Oct 2025 23:55:56 -0600 Subject: [PATCH 05/60] Fix fifo pointer read --- sim/msk_test.py | 10 +++++----- src/axis_async_fifo.vhd | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sim/msk_test.py b/sim/msk_test.py index 788ff60..d063eba 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -763,7 +763,7 @@ async def msk_test_1(dut): await RisingEdge(dut.clk) msksim = msk(dut, dut.clk, dut.tx_samples_I, dut.tx_samples_Q, dut.rx_sample_clk, dut.rx_samples_dec) - #pn = prbs(dut, dut.clk, axis, tx_data_width, rx_data_width, dut.rx_data, dut.rx_dvalid) + pn = prbs(dut, dut.clk, axis, tx_data_width, rx_data_width, dut.m_axis_tdata, dut.m_axis_tvalid) ducsim = duc(dut, msksim, local_osc, tx_sample_period) ddcsim = ddc(dut, msksim, ducsim, local_osc, tx_sample_period) @@ -772,8 +772,8 @@ async def msk_test_1(dut): await cocotb.start(msksim.rx_sample_capture()) await cocotb.start(ducsim.upconvert()) await cocotb.start(ddcsim.downconvert()) - # await cocotb.start(pn.generate_data()) - # await cocotb.start(pn.check_data()) + await cocotb.start(pn.generate_data()) + await cocotb.start(pn.check_data()) sim_time = get_sim_time("us") sim_start = sim_time @@ -783,8 +783,8 @@ async def msk_test_1(dut): msksim.sim_run = True - #pn.sim_run = True - #pn.sync = 100 + pn.sim_run = True + pn.sync = 100 while sim_time < run_time: #sim_start + run_time: diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 1ab08b4..497109a 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -256,8 +256,6 @@ BEGIN --prog_full <= '0'; fifo_overflow <= '0'; fifo_underflow <= '0'; - fifo_wr_ptr <= (OTHERS => '0'); - fifo_rd_ptr <= (OTHERS => '0'); status_ack <= '0'; ELSE @@ -304,6 +302,7 @@ BEGIN wr_status_req_sync1 <= '0'; wr_status_req_sync2 <= '0'; wr_status_ack <= '0'; + fifo_wr_ptr <= (OTHERS => '0'); ELSE wr_status_req_sync1 <= srequest; wr_status_req_sync2 <= wr_status_req_sync1; @@ -323,6 +322,7 @@ BEGIN rd_status_req_sync1 <= '0'; rd_status_req_sync2 <= '0'; rd_status_ack <= '0'; + fifo_rd_ptr <= (OTHERS => '0'); ELSE rd_status_req_sync1 <= srequest; rd_status_req_sync2 <= rd_status_req_sync1; From ccd7b742d111d38665d6aabaac4a37273c0b8548 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 16:14:29 -0700 Subject: [PATCH 06/60] added the = '1' so implicit type casting from std_logic to boolean won't derail the firmware build --- src/axis_async_fifo.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 497109a..b6406eb 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -308,7 +308,7 @@ BEGIN wr_status_req_sync2 <= wr_status_req_sync1; wr_status_ack <= wr_status_req_sync2; - IF wr_status_req_sync2 THEN + IF wr_status_req_sync2 = '1' THEN fifo_wr_ptr <= wr_ptr_bin; END IF; END IF; From 5da15ebc1d218984694266c77feca84ea39bd4c2 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 16:22:24 -0700 Subject: [PATCH 07/60] added = '1' to rd_status_req_sync2 test in order to gresolve implicit type cast from std_logic to boolean. Now make will work. --- src/axis_async_fifo.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index b6406eb..eed9962 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -328,7 +328,7 @@ BEGIN rd_status_req_sync2 <= rd_status_req_sync1; rd_status_ack <= rd_status_req_sync2; - IF rd_status_req_sync2 THEN + IF rd_status_req_sync2 = '1' THEN fifo_rd_ptr <= rd_ptr_bin; END IF; END IF; From a0e1f6f89c7f4ae7cbcb4c2d9963211ca13f9439 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 16:34:44 -0700 Subject: [PATCH 08/60] added /rdl/src/axi4lite_intf_pkg.vhd to the IP list in /pluto_msk/library/msk_top_ip.tcl --- library/msk_top_ip.tcl | 1 + 1 file changed, 1 insertion(+) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 36151aa..2a2733d 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -10,6 +10,7 @@ read_vhdl -library "desyrdl" "../rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ + "../rdl/src/axi4lite_intf_pkg.vhd" \ "../rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd" \ "../rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd" \ "../rdl/vhdl/msk_top_regs/msk_top_regs.vhd" \ From b23e0f8524de940f77828c3f4caf48a8209ed84f Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 17:05:08 -0700 Subject: [PATCH 09/60] putting read_vhdl pkg_msk_top_regs.vhd up above, and making sure 2008 is called out for /axi4lite_intf_pkg.vhd --- library/msk_top_ip.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 2a2733d..3b4c90f 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -7,12 +7,12 @@ source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl adi_ip_create msk_top read_vhdl -library "desyrdl" "../rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd" +read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" +read_vhdl "../rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ - "../rdl/src/axi4lite_intf_pkg.vhd" \ "../rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd" \ - "../rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd" \ "../rdl/vhdl/msk_top_regs/msk_top_regs.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ From 3558ba21b602d181cd3defaf95f24de20892f10c Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 17:16:21 -0700 Subject: [PATCH 10/60] there was a name mismatch so I changed it to match like this: USE work.axi4lite_intf_pkg.ALL; --USE work.msk_top_regs_pkg.ALL; USE work.pkg_msk_top_regs.ALL; --- src/msk_top_csr.vhd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index ee86e51..ba71d22 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -62,7 +62,8 @@ USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; USE work.axi4lite_intf_pkg.ALL; -USE work.msk_top_regs_pkg.ALL; +--USE work.msk_top_regs_pkg.ALL; +USE work.pkg_msk_top_regs.ALL; ------------------------------------------------------------------------------------------------------ -- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ From bdac6a3909269ac621bc813281b25d4bb39b2117 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Mon, 27 Oct 2025 18:57:00 -0600 Subject: [PATCH 11/60] Remove rdl/vhdl folder and contents, revert USE library to work.msk_top_regs_pkg in msk_top_csr.vhd --- rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd | 266 -- rdl/vhdl/msk_top_regs/msk_top_regs.vhd | 792 ---- .../msk_top_regs_decoder_axi4l.vhd | 536 --- rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd | 3394 ----------------- src/msk_top_csr.vhd | 3 +- 5 files changed, 1 insertion(+), 4990 deletions(-) delete mode 100644 rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd delete mode 100644 rdl/vhdl/msk_top_regs/msk_top_regs.vhd delete mode 100644 rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd delete mode 100644 rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd diff --git a/rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd b/rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd deleted file mode 100644 index b630a3b..0000000 --- a/rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd +++ /dev/null @@ -1,266 +0,0 @@ -------------------------------------------------------------------------------- --- ____ _____________ __ -- --- / __ \/ ____/ ___/\ \/ / _ _ _ -- --- / / / / __/ \__ \ \ / / \ / \ / \ -- --- / /_/ / /___ ___/ / / / = ( M | S | K )= -- --- /_____/_____//____/ /_/ \_/ \_/ \_/ -- --- -- -------------------------------------------------------------------------------- ---! @copyright Copyright 2021-2022 DESY ---! SPDX-License-Identifier: Apache-2.0 -------------------------------------------------------------------------------- ---! @date 2021-08-04 ---! @author Michael Büchler ---! @author Lukasz Butkowski -------------------------------------------------------------------------------- ---! @brief Package with common DesyRDL components -------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - --- library desy; --- use desy.common_types.all; --- use desy.common_axi.all; - -package common is - - constant C_AXI4L_ADDR_WIDTH : natural := 32; - constant C_AXI4L_DATA_WIDTH : natural := 32; - - --------------------------------------------------------------------------- - -- common type definitions - -- type t_4b_slv_array is array (integer range<>) of std_logic_vector( 3 downto 0) ; - -- type t_32b_slv_array is array (integer range<>) of std_logic_vector(31 downto 0) ; - -- type t_integer_array is array (integer range<>) of integer ; - - --============================================================================ - -- AXI4-Lite - --============================================================================ - type t_axi4l_m2s is record - -- write address channel signals--------------------------------------------- - awaddr : std_logic_vector(C_AXI4L_ADDR_WIDTH-1 downto 0); - awprot : std_logic_vector(2 downto 0); - awvalid : std_logic; - -- write data channel signals--------------------------------------------- - wdata : std_logic_vector(C_AXI4L_DATA_WIDTH-1 downto 0); - wstrb : std_logic_vector(C_AXI4L_DATA_WIDTH/8-1 downto 0); - wvalid : std_logic; - -- write response channel signals - bready : std_logic; - -- read address channel signals --------------------------------------------- - araddr : std_logic_vector(C_AXI4L_ADDR_WIDTH-1 downto 0); - arprot : std_logic_vector(2 downto 0); - arvalid : std_logic; - -- read data channel signals--------------------------------------------- - rready : std_logic; - end record t_axi4l_m2s; - - type t_axi4l_s2m is record - -- write address channel signals--------------------------------------------- - awready : std_logic; - -- write data channel signals--------------------------------------------- - wready : std_logic; - -- write response channel signals --------------------------------------------- - bresp : std_logic_vector(1 downto 0); - bvalid : std_logic; - -- read address channel signals--------------------------------------------- - arready : std_logic; - -- read data channel signals--------------------------------------------- - rdata : std_logic_vector(C_AXI4L_DATA_WIDTH-1 downto 0); - rresp : std_logic_vector(1 downto 0); - rvalid : std_logic; - end record t_axi4l_s2m; - - type t_axi4l_m2s_vector is array (integer range <>) of t_axi4l_m2s; - type t_axi4l_s2m_vector is array (integer range <>) of t_axi4l_s2m; - - constant C_AXI4L_S2M_DEFAULT : t_axi4l_s2m := ( - awready => '0', - wready => '0', - bresp => (others => '0'), - bvalid => '0', - arready => '0' , - rdata => (others => '0'), - rresp => (others => '0'), - rvalid => '0' - ); - constant C_AXI4L_M2S_DEFAULT : t_axi4l_m2s := ( - awaddr => (others => '0'), - awprot => (others => '0'), - awvalid => '0', - wdata => (others => '0'), - wstrb => (others => '0'), - wvalid => '0', - bready => '0', - araddr => (others => '0'), - arprot => (others => '0'), - arvalid => '0', - rready => '0' - ); - - --------------------------------------------------------------------------- - -- Interface definitions for IBUS - -- Internal BUS (IBUS) is the internal bus used in the applications of MSK Firmware - -- repository. - - -- Output signals of IBUS. Through this record the application send data/commands to the bus - type t_ibus_m2s is record - addr : std_logic_vector(31 downto 0); - data : std_logic_vector(31 downto 0); - rena : std_logic; - wena : std_logic; - end record t_ibus_m2s; - - -- Output signals of IBUS. Through this record the application send data/commands to the bus - type t_ibus_s2m is record - data : std_logic_vector(31 downto 0); - rack : std_logic; - wack : std_logic; - end record t_ibus_s2m; - - -- Array of IBUS outputs - type t_ibus_m2s_vector is array (integer range<>) of t_ibus_m2s; - - -- Array of IBUS inputs - type t_ibus_s2m_vector is array (integer range<>) of t_ibus_s2m; - - -- Default IBUS connections for the output (All entries equals 0) - constant C_IBUS_M2S_DEFAULT : t_ibus_m2s := ( - addr => (others => '0'), - data => (others => '0'), - rena => '0', - wena => '0' - ); - -- Default IBUS connections for the input (All entries equals 0) - constant C_IBUS_S2M_DEFAULT : t_ibus_s2m := ( - data => (others => '0'), - rack => '0', - wack => '0' - ); - - - --------------------------------------------------------------------------- - -- SystemRDL-specific definitions - --type t_field_access is (R, W, RW, NA); - subtype t_access_type is integer; - constant C_NA : integer := 1; - constant C_RW : integer := 2; - constant C_R : integer := 3; - constant C_W : integer := 4; - constant C_RW1 : integer := 5; - constant C_W1 : integer := 6; - - type t_field_type is (STORAGE, WIRE, COUNTER, INTERRUPT); - - type t_field_info is record - ftype : t_field_type; - len : integer; - upper : integer; - lower : integer; - sw : t_access_type; - hw : t_access_type; - we : integer; - incrwidth : integer; - decrwidth : integer; - defval : integer; - end record; - - type t_field_info_vector is array (integer range <>) of t_field_info; - - constant C_FIELD_NONE : t_field_info := (WIRE, 0, 0, 0, C_NA, C_NA, 0, 0, 0, 0); - - type t_reg_info is record - -- index : integer; - address : unsigned(C_AXI4L_ADDR_WIDTH-1 downto 0); - elements : integer; - index : integer; - fields : t_field_info_vector(31 downto 0); - --dim : natural; - dim_n : positive; - dim_m : positive; - end record; - - type t_reg_info_vector is array (integer range <>) of t_reg_info; - - constant C_REG_NONE : t_reg_info := (x"0000_0000", 0, 0,(others => C_FIELD_NONE),1,1); - - type t_mem_info is record - -- index : integer; - address : unsigned(C_AXI4L_ADDR_WIDTH-1 downto 0); - addrwidth : integer; - datawidth : integer; - entries : integer; - sw : t_access_type; - end record; - - type t_mem_info_vector is array (integer range <>) of t_mem_info; - - constant C_MEM_NONE : t_mem_info := (x"0000_0000", 0, 0, 0, C_NA); - - type t_ext_info is record - -- index : integer; - address : unsigned(C_AXI4L_ADDR_WIDTH-1 downto 0); - addrwidth : integer; - size : integer; - end record; - - type t_ext_info_vector is array (integer range <>) of t_ext_info; - - constant C_EXT_NONE : t_ext_info := (x"0000_0000", 0, 0); - - -- interface types - type t_if_type Is (DPM, AXI4, AXI4L, IBUS, WISHBONE, AVALON, NONE); - type t_if_type_vector is array (integer range <>) of t_if_type; - - ----------------------------------------------------------------------------- - -- bus converter components - component axi4l_to_axi4l is - port ( - pi_reset : in std_logic; - pi_clock : in std_logic; - pi_s_decoder : in t_axi4l_m2s; - po_s_decoder : out t_axi4l_s2m; - po_m_ext : out t_axi4l_m2s; - pi_m_ext : in t_axi4l_s2m); - end component axi4l_to_axi4l; - - component axi4l_to_ibus is - port ( - pi_reset : in std_logic; - pi_clock : in std_logic; - pi_s_decoder : in t_axi4l_m2s; - po_s_decoder : out t_axi4l_s2m; - po_m_ext : out t_ibus_m2s; - pi_m_ext : in t_ibus_s2m); - end component axi4l_to_ibus; - - component ibus_to_axi4l is - port ( - pi_reset : in std_logic; - pi_clock : in std_logic; - pi_s_decoder : in t_ibus_m2s; - po_s_decoder : out t_ibus_s2m; - po_m_ext : out t_axi4l_m2s; - pi_m_ext : in t_axi4l_s2m); - end component ibus_to_axi4l; - - --common functions - -- intr_or_reduce - or recuce for interrupt register - function intr_or_reduce (arg: std_logic_vector) return std_logic; - -end package common; - ---============================================================================== -package body common is - function intr_or_reduce (arg : std_logic_vector) return std_logic is - constant C_ZEROES : std_logic_vector(arg'length - 1 downto 0) := (others => '0'); - begin -- function intr_or_reduce - if (arg = C_ZEROES) then - return '0'; - else - return '1'; - end if; - end function intr_or_reduce; -end package body; \ No newline at end of file diff --git a/rdl/vhdl/msk_top_regs/msk_top_regs.vhd b/rdl/vhdl/msk_top_regs/msk_top_regs.vhd deleted file mode 100644 index a0ba184..0000000 --- a/rdl/vhdl/msk_top_regs/msk_top_regs.vhd +++ /dev/null @@ -1,792 +0,0 @@ ------------------------------------------------------------------------------- --- ____ _____________ __ -- --- / __ \/ ____/ ___/\ \/ / _ _ _ -- --- / / / / __/ \__ \ \ / / \ / \ / \ -- --- / /_/ / /___ ___/ / / / = ( M | S | K )= -- --- /_____/_____//____/ /_/ \_/ \_/ \_/ -- --- -- ------------------------------------------------------------------------------- ---! @copyright Copyright 2021-2022 DESY ---! SPDX-License-Identifier: Apache-2.0 ------------------------------------------------------------------------------- ---! @date 2021-04-07 ---! @author Michael Büchler ---! @author Lukasz Butkowski ------------------------------------------------------------------------------- ---! @brief ---! Top component of DesyRDL address space decoder for msk_top_regs ------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- TOP subordinate memory mapped interface - pi_s_reset : in std_logic := '0'; - pi_s_top : in t_msk_top_regs_m2s; - po_s_top : out t_msk_top_regs_s2m; - -- to logic interface - pi_addrmap : in t_addrmap_msk_top_regs_in; - po_addrmap : out t_addrmap_msk_top_regs_out - ); -end entity msk_top_regs; - -architecture arch of msk_top_regs is - - type t_data_out is array (natural range<>) of std_logic_vector(C_DATA_WIDTH-1 downto 0) ; - - -- - signal reg_data_out_vect : t_data_out(36-1 downto 0); - signal reg_rd_stb : std_logic_vector(36-1 downto 0); - signal reg_wr_stb : std_logic_vector(36-1 downto 0); - signal reg_data_in : std_logic_vector(C_DATA_WIDTH-1 downto 0); - signal reg_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - -begin - - ins_decoder_axi4l : entity work.msk_top_regs_decoder_axi4l - generic map ( - g_addr_width => C_ADDR_WIDTH, - g_data_width => C_DATA_WIDTH - ) - port map ( - pi_clock => pi_clock, - pi_reset => pi_reset, - - -- - po_reg_rd_stb => reg_rd_stb, - po_reg_wr_stb => reg_wr_stb, - po_reg_data => reg_data_in, - pi_reg_data => reg_data_out, - -- - -- - -- - -- - pi_s_reset => pi_s_reset, - pi_s_top => pi_s_top, - po_s_top => po_s_top - ); - -- - prs_reg_rd_mux: process(pi_clock) - begin - if rising_edge(pi_clock) then - for idx in 0 to 36-1 loop - if reg_rd_stb(idx) = '1' then - reg_data_out <= reg_data_out_vect(idx); - end if; - end loop; - end if; - end process prs_reg_rd_mux; - -- - -- - -- - - -- =========================================================================== - -- generated registers instances - -- --------------------------------------------------------------------------- - -- reg name: Hash_ID_Low reg type: msk_hash_lo - -- --------------------------------------------------------------------------- - blk_Hash_ID_Low : block - begin -- - inst_Hash_ID_Low: entity work.msk_top_regs_msk_hash_lo - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(0), - pi_decoder_wr_stb => reg_wr_stb(0), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(0), - - pi_reg => pi_addrmap.Hash_ID_Low, - po_reg => po_addrmap.Hash_ID_Low - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Hash_ID_High reg type: msk_hash_hi - -- --------------------------------------------------------------------------- - blk_Hash_ID_High : block - begin -- - inst_Hash_ID_High: entity work.msk_top_regs_msk_hash_hi - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(1), - pi_decoder_wr_stb => reg_wr_stb(1), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(1), - - pi_reg => pi_addrmap.Hash_ID_High, - po_reg => po_addrmap.Hash_ID_High - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: MSK_Init reg type: msk_init - -- --------------------------------------------------------------------------- - blk_MSK_Init : block - begin -- - inst_MSK_Init: entity work.msk_top_regs_msk_init - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(2), - pi_decoder_wr_stb => reg_wr_stb(2), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(2), - - pi_reg => pi_addrmap.MSK_Init, - po_reg => po_addrmap.MSK_Init - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: MSK_Control reg type: msk_ctrl - -- --------------------------------------------------------------------------- - blk_MSK_Control : block - begin -- - inst_MSK_Control: entity work.msk_top_regs_msk_ctrl - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(3), - pi_decoder_wr_stb => reg_wr_stb(3), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(3), - - pi_reg => pi_addrmap.MSK_Control, - po_reg => po_addrmap.MSK_Control - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: MSK_Status reg type: msk_stat_0 - -- --------------------------------------------------------------------------- - blk_MSK_Status : block - begin -- - inst_MSK_Status: entity work.msk_top_regs_msk_stat_0 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(4), - pi_decoder_wr_stb => reg_wr_stb(4), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(4), - - pi_reg => pi_addrmap.MSK_Status, - po_reg => po_addrmap.MSK_Status - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Tx_Bit_Count reg type: msk_stat_1 - -- --------------------------------------------------------------------------- - blk_Tx_Bit_Count : block - begin -- - inst_Tx_Bit_Count: entity work.msk_top_regs_msk_stat_1 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(5), - pi_decoder_wr_stb => reg_wr_stb(5), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(5), - - pi_reg => pi_addrmap.Tx_Bit_Count, - po_reg => po_addrmap.Tx_Bit_Count - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Tx_Enable_Count reg type: msk_stat_2 - -- --------------------------------------------------------------------------- - blk_Tx_Enable_Count : block - begin -- - inst_Tx_Enable_Count: entity work.msk_top_regs_msk_stat_2 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(6), - pi_decoder_wr_stb => reg_wr_stb(6), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(6), - - pi_reg => pi_addrmap.Tx_Enable_Count, - po_reg => po_addrmap.Tx_Enable_Count - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Fb_FreqWord reg type: config_nco_fw - -- --------------------------------------------------------------------------- - blk_Fb_FreqWord : block - begin -- - inst_Fb_FreqWord: entity work.msk_top_regs_config_nco_fw - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(7), - pi_decoder_wr_stb => reg_wr_stb(7), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(7), - - pi_reg => pi_addrmap.Fb_FreqWord, - po_reg => po_addrmap.Fb_FreqWord - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: TX_F1_FreqWord reg type: config_nco_fw - -- --------------------------------------------------------------------------- - blk_TX_F1_FreqWord : block - begin -- - inst_TX_F1_FreqWord: entity work.msk_top_regs_config_nco_fw - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(8), - pi_decoder_wr_stb => reg_wr_stb(8), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(8), - - pi_reg => pi_addrmap.TX_F1_FreqWord, - po_reg => po_addrmap.TX_F1_FreqWord - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: TX_F2_FreqWord reg type: config_nco_fw - -- --------------------------------------------------------------------------- - blk_TX_F2_FreqWord : block - begin -- - inst_TX_F2_FreqWord: entity work.msk_top_regs_config_nco_fw - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(9), - pi_decoder_wr_stb => reg_wr_stb(9), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(9), - - pi_reg => pi_addrmap.TX_F2_FreqWord, - po_reg => po_addrmap.TX_F2_FreqWord - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: RX_F1_FreqWord reg type: config_nco_fw - -- --------------------------------------------------------------------------- - blk_RX_F1_FreqWord : block - begin -- - inst_RX_F1_FreqWord: entity work.msk_top_regs_config_nco_fw - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(10), - pi_decoder_wr_stb => reg_wr_stb(10), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(10), - - pi_reg => pi_addrmap.RX_F1_FreqWord, - po_reg => po_addrmap.RX_F1_FreqWord - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: RX_F2_FreqWord reg type: config_nco_fw - -- --------------------------------------------------------------------------- - blk_RX_F2_FreqWord : block - begin -- - inst_RX_F2_FreqWord: entity work.msk_top_regs_config_nco_fw - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(11), - pi_decoder_wr_stb => reg_wr_stb(11), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(11), - - pi_reg => pi_addrmap.RX_F2_FreqWord, - po_reg => po_addrmap.RX_F2_FreqWord - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: LPF_Config_0 reg type: lpf_config_0 - -- --------------------------------------------------------------------------- - blk_LPF_Config_0 : block - begin -- - inst_LPF_Config_0: entity work.msk_top_regs_lpf_config_0 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(12), - pi_decoder_wr_stb => reg_wr_stb(12), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(12), - - pi_reg => pi_addrmap.LPF_Config_0, - po_reg => po_addrmap.LPF_Config_0 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: LPF_Config_1 reg type: lpf_config_1 - -- --------------------------------------------------------------------------- - blk_LPF_Config_1 : block - begin -- - inst_LPF_Config_1: entity work.msk_top_regs_lpf_config_1 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(13), - pi_decoder_wr_stb => reg_wr_stb(13), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(13), - - pi_reg => pi_addrmap.LPF_Config_1, - po_reg => po_addrmap.LPF_Config_1 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Tx_Data_Width reg type: data_width - -- --------------------------------------------------------------------------- - blk_Tx_Data_Width : block - begin -- - inst_Tx_Data_Width: entity work.msk_top_regs_data_width - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(14), - pi_decoder_wr_stb => reg_wr_stb(14), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(14), - - pi_reg => pi_addrmap.Tx_Data_Width, - po_reg => po_addrmap.Tx_Data_Width - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Rx_Data_Width reg type: data_width - -- --------------------------------------------------------------------------- - blk_Rx_Data_Width : block - begin -- - inst_Rx_Data_Width: entity work.msk_top_regs_data_width - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(15), - pi_decoder_wr_stb => reg_wr_stb(15), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(15), - - pi_reg => pi_addrmap.Rx_Data_Width, - po_reg => po_addrmap.Rx_Data_Width - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Control reg type: prbs_ctrl - -- --------------------------------------------------------------------------- - blk_PRBS_Control : block - begin -- - inst_PRBS_Control: entity work.msk_top_regs_prbs_ctrl - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(16), - pi_decoder_wr_stb => reg_wr_stb(16), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(16), - - pi_reg => pi_addrmap.PRBS_Control, - po_reg => po_addrmap.PRBS_Control - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Initial_State reg type: config_prbs_seed - -- --------------------------------------------------------------------------- - blk_PRBS_Initial_State : block - begin -- - inst_PRBS_Initial_State: entity work.msk_top_regs_config_prbs_seed - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(17), - pi_decoder_wr_stb => reg_wr_stb(17), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(17), - - pi_reg => pi_addrmap.PRBS_Initial_State, - po_reg => po_addrmap.PRBS_Initial_State - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Polynomial reg type: config_prbs_poly - -- --------------------------------------------------------------------------- - blk_PRBS_Polynomial : block - begin -- - inst_PRBS_Polynomial: entity work.msk_top_regs_config_prbs_poly - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(18), - pi_decoder_wr_stb => reg_wr_stb(18), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(18), - - pi_reg => pi_addrmap.PRBS_Polynomial, - po_reg => po_addrmap.PRBS_Polynomial - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Error_Mask reg type: config_prbs_errmask - -- --------------------------------------------------------------------------- - blk_PRBS_Error_Mask : block - begin -- - inst_PRBS_Error_Mask: entity work.msk_top_regs_config_prbs_errmask - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(19), - pi_decoder_wr_stb => reg_wr_stb(19), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(19), - - pi_reg => pi_addrmap.PRBS_Error_Mask, - po_reg => po_addrmap.PRBS_Error_Mask - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Bit_Count reg type: stat_32_bits - -- --------------------------------------------------------------------------- - blk_PRBS_Bit_Count : block - begin -- - inst_PRBS_Bit_Count: entity work.msk_top_regs_stat_32_bits - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(20), - pi_decoder_wr_stb => reg_wr_stb(20), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(20), - - pi_reg => pi_addrmap.PRBS_Bit_Count, - po_reg => po_addrmap.PRBS_Bit_Count - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: PRBS_Error_Count reg type: stat_32_errs - -- --------------------------------------------------------------------------- - blk_PRBS_Error_Count : block - begin -- - inst_PRBS_Error_Count: entity work.msk_top_regs_stat_32_errs - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(21), - pi_decoder_wr_stb => reg_wr_stb(21), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(21), - - pi_reg => pi_addrmap.PRBS_Error_Count, - po_reg => po_addrmap.PRBS_Error_Count - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: LPF_Accum_F1 reg type: stat_32_lpf_acc - -- --------------------------------------------------------------------------- - blk_LPF_Accum_F1 : block - begin -- - inst_LPF_Accum_F1: entity work.msk_top_regs_stat_32_lpf_acc - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(22), - pi_decoder_wr_stb => reg_wr_stb(22), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(22), - - pi_reg => pi_addrmap.LPF_Accum_F1, - po_reg => po_addrmap.LPF_Accum_F1 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: LPF_Accum_F2 reg type: stat_32_lpf_acc - -- --------------------------------------------------------------------------- - blk_LPF_Accum_F2 : block - begin -- - inst_LPF_Accum_F2: entity work.msk_top_regs_stat_32_lpf_acc - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(23), - pi_decoder_wr_stb => reg_wr_stb(23), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(23), - - pi_reg => pi_addrmap.LPF_Accum_F2, - po_reg => po_addrmap.LPF_Accum_F2 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: axis_xfer_count reg type: msk_stat_3 - -- --------------------------------------------------------------------------- - blk_axis_xfer_count : block - begin -- - inst_axis_xfer_count: entity work.msk_top_regs_msk_stat_3 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(24), - pi_decoder_wr_stb => reg_wr_stb(24), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(24), - - pi_reg => pi_addrmap.axis_xfer_count, - po_reg => po_addrmap.axis_xfer_count - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Rx_Sample_Discard reg type: rx_sample_discard - -- --------------------------------------------------------------------------- - blk_Rx_Sample_Discard : block - begin -- - inst_Rx_Sample_Discard: entity work.msk_top_regs_rx_sample_discard - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(25), - pi_decoder_wr_stb => reg_wr_stb(25), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(25), - - pi_reg => pi_addrmap.Rx_Sample_Discard, - po_reg => po_addrmap.Rx_Sample_Discard - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: LPF_Config_2 reg type: lpf_config_2 - -- --------------------------------------------------------------------------- - blk_LPF_Config_2 : block - begin -- - inst_LPF_Config_2: entity work.msk_top_regs_lpf_config_2 - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(26), - pi_decoder_wr_stb => reg_wr_stb(26), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(26), - - pi_reg => pi_addrmap.LPF_Config_2, - po_reg => po_addrmap.LPF_Config_2 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: f1_nco_adjust reg type: observation_data - -- --------------------------------------------------------------------------- - blk_f1_nco_adjust : block - begin -- - inst_f1_nco_adjust: entity work.msk_top_regs_observation_data - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(27), - pi_decoder_wr_stb => reg_wr_stb(27), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(27), - - pi_reg => pi_addrmap.f1_nco_adjust, - po_reg => po_addrmap.f1_nco_adjust - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: f2_nco_adjust reg type: observation_data - -- --------------------------------------------------------------------------- - blk_f2_nco_adjust : block - begin -- - inst_f2_nco_adjust: entity work.msk_top_regs_observation_data - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(28), - pi_decoder_wr_stb => reg_wr_stb(28), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(28), - - pi_reg => pi_addrmap.f2_nco_adjust, - po_reg => po_addrmap.f2_nco_adjust - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: f1_error reg type: observation_data - -- --------------------------------------------------------------------------- - blk_f1_error : block - begin -- - inst_f1_error: entity work.msk_top_regs_observation_data - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(29), - pi_decoder_wr_stb => reg_wr_stb(29), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(29), - - pi_reg => pi_addrmap.f1_error, - po_reg => po_addrmap.f1_error - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: f2_error reg type: observation_data - -- --------------------------------------------------------------------------- - blk_f2_error : block - begin -- - inst_f2_error: entity work.msk_top_regs_observation_data - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(30), - pi_decoder_wr_stb => reg_wr_stb(30), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(30), - - pi_reg => pi_addrmap.f2_error, - po_reg => po_addrmap.f2_error - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Tx_Sync_Ctrl reg type: tx_sync_ctrl - -- --------------------------------------------------------------------------- - blk_Tx_Sync_Ctrl : block - begin -- - inst_Tx_Sync_Ctrl: entity work.msk_top_regs_tx_sync_ctrl - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(31), - pi_decoder_wr_stb => reg_wr_stb(31), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(31), - - pi_reg => pi_addrmap.Tx_Sync_Ctrl, - po_reg => po_addrmap.Tx_Sync_Ctrl - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: Tx_Sync_Cnt reg type: tx_sync_cnt - -- --------------------------------------------------------------------------- - blk_Tx_Sync_Cnt : block - begin -- - inst_Tx_Sync_Cnt: entity work.msk_top_regs_tx_sync_cnt - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(32), - pi_decoder_wr_stb => reg_wr_stb(32), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(32), - - pi_reg => pi_addrmap.Tx_Sync_Cnt, - po_reg => po_addrmap.Tx_Sync_Cnt - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: lowpass_ema_alpha1 reg type: lowpass_ema_alpha - -- --------------------------------------------------------------------------- - blk_lowpass_ema_alpha1 : block - begin -- - inst_lowpass_ema_alpha1: entity work.msk_top_regs_lowpass_ema_alpha - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(33), - pi_decoder_wr_stb => reg_wr_stb(33), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(33), - - pi_reg => pi_addrmap.lowpass_ema_alpha1, - po_reg => po_addrmap.lowpass_ema_alpha1 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: lowpass_ema_alpha2 reg type: lowpass_ema_alpha - -- --------------------------------------------------------------------------- - blk_lowpass_ema_alpha2 : block - begin -- - inst_lowpass_ema_alpha2: entity work.msk_top_regs_lowpass_ema_alpha - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(34), - pi_decoder_wr_stb => reg_wr_stb(34), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(34), - - pi_reg => pi_addrmap.lowpass_ema_alpha2, - po_reg => po_addrmap.lowpass_ema_alpha2 - ); -- - end block; -- - -- --------------------------------------------------------------------------- - -- reg name: rx_power reg type: rx_power - -- --------------------------------------------------------------------------- - blk_rx_power : block - begin -- - inst_rx_power: entity work.msk_top_regs_rx_power - port map( - pi_clock => pi_clock, - pi_reset => pi_reset, - -- to/from adapter - pi_decoder_rd_stb => reg_rd_stb(35), - pi_decoder_wr_stb => reg_wr_stb(35), - pi_decoder_data => reg_data_in, - po_decoder_data => reg_data_out_vect(35), - - pi_reg => pi_addrmap.rx_power, - po_reg => po_addrmap.rx_power - ); -- - end block; -- - - -- =========================================================================== - -- generated registers instances in regfiles - - -- =========================================================================== - -- Generated Mem Instances - -- - -- --------------------------------------------------------------------------- - - -- =========================================================================== - -- External Busses - -end architecture; diff --git a/rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd b/rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd deleted file mode 100644 index 6a4f008..0000000 --- a/rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd +++ /dev/null @@ -1,536 +0,0 @@ ------------------------------------------------------------------------------- --- ____ _____________ __ -- --- / __ \/ ____/ ___/\ \/ / _ _ _ -- --- / / / / __/ \__ \ \ / / \ / \ / \ -- --- / /_/ / /___ ___/ / / / = ( M | S | K )= -- --- /_____/_____//____/ /_/ \_/ \_/ \_/ -- --- -- ------------------------------------------------------------------------------- ---! @copyright Copyright 2020-2022 DESY ---! SPDX-License-Identifier: Apache-2.0 ------------------------------------------------------------------------------- ---! @date 2020-05-25/2021-10-12 ---! @author Lukasz Butkowski ---! @author Michael Büchler ------------------------------------------------------------------------------- ---! @brief ---! ax4-lite address decoder for DesyRdl ------------------------------------------------------------------------------- - - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -entity msk_top_regs_decoder_axi4l is - generic ( - G_ADDR_WIDTH : integer := 32; - G_DATA_WIDTH : integer := 32 - ); - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- - po_reg_rd_stb : out std_logic_vector(36-1 downto 0); - po_reg_wr_stb : out std_logic_vector(36-1 downto 0); - po_reg_data : out std_logic_vector(G_DATA_WIDTH-1 downto 0); - pi_reg_data : in std_logic_vector(G_DATA_WIDTH-1 downto 0); - -- - -- - -- - -- - pi_s_reset : in std_logic; - pi_s_top : in t_axi4l_m2s ; - po_s_top : out t_axi4l_s2m -); -end entity msk_top_regs_decoder_axi4l; - -architecture arch of msk_top_regs_decoder_axi4l is - - type t_target is (REG, NONE ); - - signal rtarget, wtarget : t_target := NONE; - - -- Standard statements - --- INLINE statement with -- # - ---------------------------------------------------------- - -- read - type t_state_read is ( - ST_READ_IDLE, - ST_READ_SELECT, - ST_READ_VALID, - ST_READ_REG_BUSY, -- when no address hit, dummy reg - ST_READ_DONE - ); - signal state_read : t_state_read; - - signal rdata_reg : std_logic_vector(G_DATA_WIDTH-1 downto 0); - signal rdata_rgf : std_logic_vector(G_DATA_WIDTH-1 downto 0); - signal rdata_mem : std_logic_vector(G_DATA_WIDTH-1 downto 0); - signal rdata_ext : std_logic_vector(G_DATA_WIDTH-1 downto 0); - - signal rdata : std_logic_vector(G_DATA_WIDTH-1 downto 0) := (others => '0'); - signal raddr : std_logic_vector(G_ADDR_WIDTH-1 downto 0) := (others => '0'); - signal raddr_int : integer; - - ---------------------------------------------------------- - -- write - type t_state_write is ( - ST_WRITE_IDLE, - ST_WRITE_WAIT_DATA, - ST_WRITE_WAIT_ADDR, - ST_WRITE_SELECT, - ST_WRITE_RESP - ); - signal state_write : t_state_write; - - signal wdata : std_logic_vector(G_DATA_WIDTH-1 downto 0) := (others => '0'); - signal wstrb : std_logic_vector(G_DATA_WIDTH/8-1 downto 0) := (others => '0'); - signal waddr : std_logic_vector(G_ADDR_WIDTH-1 downto 0) := (others => '0'); - signal waddr_int : integer; - signal wvalid : std_logic; - - ----------------------------------------------------------- - signal reg_rd_stb : std_logic_vector(36-1 downto 0) := (others => '0'); - signal reg_wr_stb : std_logic_vector(36-1 downto 0) := (others => '0'); - - -- external bus - - constant read_timeout : natural := 8191; - constant write_timeout : natural := 8191; - signal read_time_cnt : natural := 0; - signal write_time_cnt : natural := 0; - signal invalid_rdata : std_logic ; - - signal reset : std_logic; -begin - - -- main reset - global or bus reset - reset <= pi_reset or pi_s_reset; - - -- =========================================================================== - -- ### read logic - ------------------------------------------------------------------------------ - -- read channel state machine - ------------------------------------------------------------------------------ - prs_state_read: process (pi_clock) - begin - if rising_edge(pi_clock) then - if reset = '1' then - state_read <= ST_READ_IDLE; - invalid_rdata <= '0'; - else - case state_read is - when ST_READ_IDLE => - - if pi_s_top.arvalid = '1' then - state_read <= ST_READ_SELECT; - end if; - invalid_rdata <= '0'; - when ST_READ_SELECT => - case rtarget is - when REG => - state_read <= ST_READ_VALID; - when others => - state_read <= ST_READ_REG_BUSY; - end case; - - when ST_READ_REG_BUSY => - state_read <= ST_READ_VALID; - - when ST_READ_VALID => - if pi_s_top.rready = '1' then - state_read <= ST_READ_DONE; - end if; - - when ST_READ_DONE => - state_read <= ST_READ_IDLE; - - when others => - state_read <= ST_READ_IDLE; - - end case; - - end if; - end if; - end process; - po_s_top.rresp <= "00"; - ------------------------------------------------------------------------------ - -- read data mux - prs_rdata_mux: process(rtarget,rdata_reg,invalid_rdata) - begin - if invalid_rdata = '1' then - po_s_top.rdata <= (others => '0' ) ; - elsif rtarget = REG then - po_s_top.rdata <= rdata_reg ; - else - po_s_top.rdata <= (others => '0' ) ; - end if; - end process prs_rdata_mux; - - ------------------------------------------------------------------------------ - -- ARREADY flag handling - prs_axi_arready: process (state_read) - begin - case state_read is - when ST_READ_IDLE => - po_s_top.arready <= '1'; - when others => - po_s_top.arready <= '0'; - end case; - end process; - - -- RVALID flag handling - prs_axi_rvalid: process ( - state_read) - begin - case state_read is - when ST_READ_VALID => - po_s_top.rvalid <= '1'; - when others => - po_s_top.rvalid <= '0'; - end case; - end process; - - ------------------------------------------------------------------------------ - -- Address decoder - ------------------------------------------------------------------------------ - raddr_int <= to_integer(unsigned(pi_s_top.araddr(G_ADDR_WIDTH-1 downto 0))); - - prs_raddr_decoder: process(pi_clock) - begin - if rising_edge(pi_clock) then - if state_read = ST_READ_IDLE and pi_s_top.arvalid = '1' then - reg_rd_stb <= (others => '0'); - case raddr_int is - when 0 => - rtarget <= REG; - reg_rd_stb(0) <= '1'; - when 4 => - rtarget <= REG; - reg_rd_stb(1) <= '1'; - when 8 => - rtarget <= REG; - reg_rd_stb(2) <= '1'; - when 12 => - rtarget <= REG; - reg_rd_stb(3) <= '1'; - when 16 => - rtarget <= REG; - reg_rd_stb(4) <= '1'; - when 20 => - rtarget <= REG; - reg_rd_stb(5) <= '1'; - when 24 => - rtarget <= REG; - reg_rd_stb(6) <= '1'; - when 28 => - rtarget <= REG; - reg_rd_stb(7) <= '1'; - when 32 => - rtarget <= REG; - reg_rd_stb(8) <= '1'; - when 36 => - rtarget <= REG; - reg_rd_stb(9) <= '1'; - when 40 => - rtarget <= REG; - reg_rd_stb(10) <= '1'; - when 44 => - rtarget <= REG; - reg_rd_stb(11) <= '1'; - when 48 => - rtarget <= REG; - reg_rd_stb(12) <= '1'; - when 52 => - rtarget <= REG; - reg_rd_stb(13) <= '1'; - when 56 => - rtarget <= REG; - reg_rd_stb(14) <= '1'; - when 60 => - rtarget <= REG; - reg_rd_stb(15) <= '1'; - when 64 => - rtarget <= REG; - reg_rd_stb(16) <= '1'; - when 68 => - rtarget <= REG; - reg_rd_stb(17) <= '1'; - when 72 => - rtarget <= REG; - reg_rd_stb(18) <= '1'; - when 76 => - rtarget <= REG; - reg_rd_stb(19) <= '1'; - when 80 => - rtarget <= REG; - reg_rd_stb(20) <= '1'; - when 84 => - rtarget <= REG; - reg_rd_stb(21) <= '1'; - when 88 => - rtarget <= REG; - reg_rd_stb(22) <= '1'; - when 92 => - rtarget <= REG; - reg_rd_stb(23) <= '1'; - when 96 => - rtarget <= REG; - reg_rd_stb(24) <= '1'; - when 100 => - rtarget <= REG; - reg_rd_stb(25) <= '1'; - when 104 => - rtarget <= REG; - reg_rd_stb(26) <= '1'; - when 108 => - rtarget <= REG; - reg_rd_stb(27) <= '1'; - when 112 => - rtarget <= REG; - reg_rd_stb(28) <= '1'; - when 116 => - rtarget <= REG; - reg_rd_stb(29) <= '1'; - when 120 => - rtarget <= REG; - reg_rd_stb(30) <= '1'; - when 124 => - rtarget <= REG; - reg_rd_stb(31) <= '1'; - when 128 => - rtarget <= REG; - reg_rd_stb(32) <= '1'; - when 132 => - rtarget <= REG; - reg_rd_stb(33) <= '1'; - when 136 => - rtarget <= REG; - reg_rd_stb(34) <= '1'; - when 140 => - rtarget <= REG; - reg_rd_stb(35) <= '1'; - when others => - rtarget <= NONE; - end case; - - elsif state_read = ST_READ_DONE then - reg_rd_stb <= (others => '0'); - - end if; - end if; - end process prs_raddr_decoder; - ---------------------------------------------------------- - -- - - -- =========================================================================== - -- ### write logic - ------------------------------------------------------------------------------ - -- Write channel state machine - ------------------------------------------------------------------------------ - prs_state_write: process (pi_clock) - begin - if rising_edge (pi_clock) then - if reset = '1' then - state_write <= ST_WRITE_IDLE; - else - case state_write is - when ST_WRITE_IDLE => - - if pi_s_top.awvalid = '1' and pi_s_top.wvalid = '1' then - state_write <= ST_WRITE_SELECT; - elsif pi_s_top.awvalid = '1' and pi_s_top.wvalid = '0' then - state_write <= ST_WRITE_WAIT_DATA; - elsif pi_s_top.awvalid = '0' and pi_s_top.wvalid = '1' then - state_write <= ST_WRITE_WAIT_ADDR; - end if; - - when ST_WRITE_WAIT_DATA => - if pi_s_top.wvalid = '1' then - state_write <= ST_WRITE_SELECT; - end if; - - when ST_WRITE_WAIT_ADDR => - if pi_s_top.awvalid = '1' then - state_write <= ST_WRITE_SELECT; - end if; - - when ST_WRITE_SELECT => - case wtarget is - when REG => - state_write <= ST_WRITE_RESP; - when others => - state_write <= ST_WRITE_RESP; -- every write transaction must end with response - end case; - - when ST_WRITE_RESP => - if pi_s_top.bready = '1' then - state_write <= ST_WRITE_IDLE; - end if; - - when others => - state_write <= ST_WRITE_IDLE; - - end case; - end if; - end if; - end process; - - ------------------------------------------------------------------------------ - -- WRITE AXI handshaking - po_s_top.bresp <= "00"; - - prs_axi_bvalid: process (state_write) - begin - case state_write is - when ST_WRITE_RESP => - po_s_top.bvalid <= '1'; - when others => - po_s_top.bvalid <= '0'; - end case; - end process; - - prs_axi_awready: process (state_write) - begin - case state_write is - when ST_WRITE_IDLE | ST_WRITE_WAIT_ADDR => - po_s_top.awready <= '1'; - when others => - po_s_top.awready <= '0'; - end case; - end process; - - prs_axi_wready: process (state_write) - begin - case state_write is - when ST_WRITE_IDLE | ST_WRITE_WAIT_DATA => - po_s_top.wready <= '1'; - when others => - po_s_top.wready <= '0'; - end case; - end process; - - ------------------------------------------------------------------------------ - -- write Address decoder - ------------------------------------------------------------------------------ - waddr_int <= to_integer(unsigned(pi_s_top.awaddr(G_ADDR_WIDTH-1 downto 0))); - - prs_waddr_decoder: process(pi_clock) - begin - if rising_edge(pi_clock) then - if (state_write = ST_WRITE_IDLE or state_write = ST_WRITE_WAIT_ADDR ) and pi_s_top.awvalid = '1' then - reg_wr_stb <= (others => '0'); - case waddr_int is - when 8 => - wtarget <= REG; - reg_wr_stb(2) <= '1'; - when 12 => - wtarget <= REG; - reg_wr_stb(3) <= '1'; - when 28 => - wtarget <= REG; - reg_wr_stb(7) <= '1'; - when 32 => - wtarget <= REG; - reg_wr_stb(8) <= '1'; - when 36 => - wtarget <= REG; - reg_wr_stb(9) <= '1'; - when 40 => - wtarget <= REG; - reg_wr_stb(10) <= '1'; - when 44 => - wtarget <= REG; - reg_wr_stb(11) <= '1'; - when 48 => - wtarget <= REG; - reg_wr_stb(12) <= '1'; - when 52 => - wtarget <= REG; - reg_wr_stb(13) <= '1'; - when 56 => - wtarget <= REG; - reg_wr_stb(14) <= '1'; - when 60 => - wtarget <= REG; - reg_wr_stb(15) <= '1'; - when 64 => - wtarget <= REG; - reg_wr_stb(16) <= '1'; - when 68 => - wtarget <= REG; - reg_wr_stb(17) <= '1'; - when 72 => - wtarget <= REG; - reg_wr_stb(18) <= '1'; - when 76 => - wtarget <= REG; - reg_wr_stb(19) <= '1'; - when 100 => - wtarget <= REG; - reg_wr_stb(25) <= '1'; - when 104 => - wtarget <= REG; - reg_wr_stb(26) <= '1'; - when 124 => - wtarget <= REG; - reg_wr_stb(31) <= '1'; - when 128 => - wtarget <= REG; - reg_wr_stb(32) <= '1'; - when 132 => - wtarget <= REG; - reg_wr_stb(33) <= '1'; - when 136 => - wtarget <= REG; - reg_wr_stb(34) <= '1'; - when others => - wtarget <= NONE; - end case; - - elsif state_write = ST_WRITE_RESP then - reg_wr_stb <= (others => '0'); - end if; - end if; - end process prs_waddr_decoder; - ---------------------------------------------------------- - -- - - prs_wvalid_reg : process(pi_clock) - begin - if rising_edge(pi_clock) then - if state_write = ST_WRITE_IDLE or state_write = ST_WRITE_WAIT_DATA then - wvalid <= pi_s_top.wvalid; - elsif state_write = ST_WRITE_RESP then - wvalid <= '0'; - end if; - end if; - end process; - - prs_wdata_reg : process(pi_clock) - begin - if rising_edge(pi_clock) then - if state_write = ST_WRITE_IDLE or state_write = ST_WRITE_WAIT_DATA then - wdata <= pi_s_top.wdata; - end if; - end if; - end process prs_wdata_reg ; - - -- =========================================================================== - -- OUTPUT - -- =========================================================================== - -- registers - ------------------------------------------------------------------------------ - gen_reg_wr_str: for ridx in 0 to 36-1 generate - po_reg_wr_stb(ridx) <= reg_wr_stb(ridx) and wvalid; - end generate; - po_reg_data <= wdata; - po_reg_rd_stb <= reg_rd_stb; - rdata_reg <= pi_reg_data ; - -end architecture arch; diff --git a/rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd b/rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd deleted file mode 100644 index 42ebf24..0000000 --- a/rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd +++ /dev/null @@ -1,3394 +0,0 @@ ------------------------------------------------------------------------------- --- ____ _____________ __ -- --- / __ \/ ____/ ___/\ \/ / _ _ _ -- --- / / / / __/ \__ \ \ / / \ / \ / \ -- --- / /_/ / /___ ___/ / / / = ( M | S | K )= -- --- /_____/_____//____/ /_/ \_/ \_/ \_/ -- --- -- ------------------------------------------------------------------------------- ---! @copyright Copyright 2021-2022 DESY ---! SPDX-License-Identifier: Apache-2.0 ------------------------------------------------------------------------------- ---! @date 2021-10-01 ---! @author Michael Büchler ---! @author Lukasz Butkowski ------------------------------------------------------------------------------- ---! @brief ---! VHDL package of DesyRDL for address space decoder for msk_top_regs ------------------------------------------------------------------------------- - -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - --- library desy; --- use desy.common_axi.all; - -package pkg_msk_top_regs is - - ----------------------------------------------- - -- per addrmap / module - ----------------------------------------------- - constant C_ADDR_WIDTH : integer := 8; - constant C_DATA_WIDTH : integer := 32; - - -- =========================================================================== - -- --------------------------------------------------------------------------- - -- registers - -- --------------------------------------------------------------------------- - - -- =========================================================================== - -- REGISTERS interface - -- --------------------------------------------------------------------------- - -- register type: msk_hash_lo - ----------------------------------------------- - type t_field_signals_msk_hash_lo_hash_id_lo_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_hash_lo_hash_id_lo_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_hash_lo_in is record-- - hash_id_lo : t_field_signals_msk_hash_lo_hash_id_lo_in; -- - end record; - type t_reg_msk_hash_lo_out is record-- - hash_id_lo : t_field_signals_msk_hash_lo_hash_id_lo_out; -- - end record; - type t_reg_msk_hash_lo_2d_in is array (integer range <>) of t_reg_msk_hash_lo_in; - type t_reg_msk_hash_lo_2d_out is array (integer range <>) of t_reg_msk_hash_lo_out; - type t_reg_msk_hash_lo_3d_in is array (integer range <>, integer range <>) of t_reg_msk_hash_lo_in; - type t_reg_msk_hash_lo_3d_out is array (integer range <>, integer range <>) of t_reg_msk_hash_lo_out; - ----------------------------------------------- - -- register type: msk_hash_hi - ----------------------------------------------- - type t_field_signals_msk_hash_hi_hash_id_hi_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_hash_hi_hash_id_hi_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_hash_hi_in is record-- - hash_id_hi : t_field_signals_msk_hash_hi_hash_id_hi_in; -- - end record; - type t_reg_msk_hash_hi_out is record-- - hash_id_hi : t_field_signals_msk_hash_hi_hash_id_hi_out; -- - end record; - type t_reg_msk_hash_hi_2d_in is array (integer range <>) of t_reg_msk_hash_hi_in; - type t_reg_msk_hash_hi_2d_out is array (integer range <>) of t_reg_msk_hash_hi_out; - type t_reg_msk_hash_hi_3d_in is array (integer range <>, integer range <>) of t_reg_msk_hash_hi_in; - type t_reg_msk_hash_hi_3d_out is array (integer range <>, integer range <>) of t_reg_msk_hash_hi_out; - ----------------------------------------------- - -- register type: msk_init - ----------------------------------------------- - type t_field_signals_msk_init_txrxinit_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_init_txrxinit_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_init_txinit_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_init_txinit_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_init_rxinit_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_init_rxinit_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_msk_init_in is record-- - txrxinit : t_field_signals_msk_init_txrxinit_in; -- - txinit : t_field_signals_msk_init_txinit_in; -- - rxinit : t_field_signals_msk_init_rxinit_in; -- - end record; - type t_reg_msk_init_out is record-- - txrxinit : t_field_signals_msk_init_txrxinit_out; -- - txinit : t_field_signals_msk_init_txinit_out; -- - rxinit : t_field_signals_msk_init_rxinit_out; -- - end record; - type t_reg_msk_init_2d_in is array (integer range <>) of t_reg_msk_init_in; - type t_reg_msk_init_2d_out is array (integer range <>) of t_reg_msk_init_out; - type t_reg_msk_init_3d_in is array (integer range <>, integer range <>) of t_reg_msk_init_in; - type t_reg_msk_init_3d_out is array (integer range <>, integer range <>) of t_reg_msk_init_out; - ----------------------------------------------- - -- register type: msk_ctrl - ----------------------------------------------- - type t_field_signals_msk_ctrl_ptt_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_ctrl_ptt_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_ctrl_loopback_ena_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_ctrl_loopback_ena_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_ctrl_rx_invert_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_ctrl_rx_invert_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_ctrl_clear_counts_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_ctrl_clear_counts_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_msk_ctrl_diff_encoder_loopback_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_msk_ctrl_diff_encoder_loopback_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_msk_ctrl_in is record-- - ptt : t_field_signals_msk_ctrl_ptt_in; -- - loopback_ena : t_field_signals_msk_ctrl_loopback_ena_in; -- - rx_invert : t_field_signals_msk_ctrl_rx_invert_in; -- - clear_counts : t_field_signals_msk_ctrl_clear_counts_in; -- - diff_encoder_loopback : t_field_signals_msk_ctrl_diff_encoder_loopback_in; -- - end record; - type t_reg_msk_ctrl_out is record-- - ptt : t_field_signals_msk_ctrl_ptt_out; -- - loopback_ena : t_field_signals_msk_ctrl_loopback_ena_out; -- - rx_invert : t_field_signals_msk_ctrl_rx_invert_out; -- - clear_counts : t_field_signals_msk_ctrl_clear_counts_out; -- - diff_encoder_loopback : t_field_signals_msk_ctrl_diff_encoder_loopback_out; -- - end record; - type t_reg_msk_ctrl_2d_in is array (integer range <>) of t_reg_msk_ctrl_in; - type t_reg_msk_ctrl_2d_out is array (integer range <>) of t_reg_msk_ctrl_out; - type t_reg_msk_ctrl_3d_in is array (integer range <>, integer range <>) of t_reg_msk_ctrl_in; - type t_reg_msk_ctrl_3d_out is array (integer range <>, integer range <>) of t_reg_msk_ctrl_out; - ----------------------------------------------- - -- register type: msk_stat_0 - ----------------------------------------------- - type t_field_signals_msk_stat_0_demod_sync_lock_in is record - data : std_logic_vector(1-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_0_demod_sync_lock_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - type t_field_signals_msk_stat_0_tx_enable_in is record - data : std_logic_vector(1-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_0_tx_enable_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - type t_field_signals_msk_stat_0_rx_enable_in is record - data : std_logic_vector(1-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_0_rx_enable_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - type t_field_signals_msk_stat_0_tx_axis_valid_in is record - data : std_logic_vector(1-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_0_tx_axis_valid_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_stat_0_in is record-- - demod_sync_lock : t_field_signals_msk_stat_0_demod_sync_lock_in; -- - tx_enable : t_field_signals_msk_stat_0_tx_enable_in; -- - rx_enable : t_field_signals_msk_stat_0_rx_enable_in; -- - tx_axis_valid : t_field_signals_msk_stat_0_tx_axis_valid_in; -- - end record; - type t_reg_msk_stat_0_out is record-- - demod_sync_lock : t_field_signals_msk_stat_0_demod_sync_lock_out; -- - tx_enable : t_field_signals_msk_stat_0_tx_enable_out; -- - rx_enable : t_field_signals_msk_stat_0_rx_enable_out; -- - tx_axis_valid : t_field_signals_msk_stat_0_tx_axis_valid_out; -- - end record; - type t_reg_msk_stat_0_2d_in is array (integer range <>) of t_reg_msk_stat_0_in; - type t_reg_msk_stat_0_2d_out is array (integer range <>) of t_reg_msk_stat_0_out; - type t_reg_msk_stat_0_3d_in is array (integer range <>, integer range <>) of t_reg_msk_stat_0_in; - type t_reg_msk_stat_0_3d_out is array (integer range <>, integer range <>) of t_reg_msk_stat_0_out; - ----------------------------------------------- - -- register type: msk_stat_1 - ----------------------------------------------- - type t_field_signals_msk_stat_1_tx_bit_counter_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_1_tx_bit_counter_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_stat_1_in is record-- - tx_bit_counter : t_field_signals_msk_stat_1_tx_bit_counter_in; -- - end record; - type t_reg_msk_stat_1_out is record-- - tx_bit_counter : t_field_signals_msk_stat_1_tx_bit_counter_out; -- - end record; - type t_reg_msk_stat_1_2d_in is array (integer range <>) of t_reg_msk_stat_1_in; - type t_reg_msk_stat_1_2d_out is array (integer range <>) of t_reg_msk_stat_1_out; - type t_reg_msk_stat_1_3d_in is array (integer range <>, integer range <>) of t_reg_msk_stat_1_in; - type t_reg_msk_stat_1_3d_out is array (integer range <>, integer range <>) of t_reg_msk_stat_1_out; - ----------------------------------------------- - -- register type: msk_stat_2 - ----------------------------------------------- - type t_field_signals_msk_stat_2_tx_ena_counter_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_2_tx_ena_counter_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_stat_2_in is record-- - tx_ena_counter : t_field_signals_msk_stat_2_tx_ena_counter_in; -- - end record; - type t_reg_msk_stat_2_out is record-- - tx_ena_counter : t_field_signals_msk_stat_2_tx_ena_counter_out; -- - end record; - type t_reg_msk_stat_2_2d_in is array (integer range <>) of t_reg_msk_stat_2_in; - type t_reg_msk_stat_2_2d_out is array (integer range <>) of t_reg_msk_stat_2_out; - type t_reg_msk_stat_2_3d_in is array (integer range <>, integer range <>) of t_reg_msk_stat_2_in; - type t_reg_msk_stat_2_3d_out is array (integer range <>, integer range <>) of t_reg_msk_stat_2_out; - ----------------------------------------------- - -- register type: config_nco_fw - ----------------------------------------------- - type t_field_signals_config_nco_fw_config_data_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_config_nco_fw_config_data_out is record - data : std_logic_vector(32-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_config_nco_fw_in is record-- - config_data : t_field_signals_config_nco_fw_config_data_in; -- - end record; - type t_reg_config_nco_fw_out is record-- - config_data : t_field_signals_config_nco_fw_config_data_out; -- - end record; - type t_reg_config_nco_fw_2d_in is array (integer range <>) of t_reg_config_nco_fw_in; - type t_reg_config_nco_fw_2d_out is array (integer range <>) of t_reg_config_nco_fw_out; - type t_reg_config_nco_fw_3d_in is array (integer range <>, integer range <>) of t_reg_config_nco_fw_in; - type t_reg_config_nco_fw_3d_out is array (integer range <>, integer range <>) of t_reg_config_nco_fw_out; - ----------------------------------------------- - -- register type: lpf_config_0 - ----------------------------------------------- - type t_field_signals_lpf_config_0_lpf_freeze_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_0_lpf_freeze_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_lpf_config_0_lpf_zero_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_0_lpf_zero_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_lpf_config_0_prbs_reserved_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_0_prbs_reserved_out is record - data : std_logic_vector(6-1 downto 0); -- - end record; -- - type t_field_signals_lpf_config_0_lpf_alpha_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_0_lpf_alpha_out is record - data : std_logic_vector(24-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_lpf_config_0_in is record-- - lpf_freeze : t_field_signals_lpf_config_0_lpf_freeze_in; -- - lpf_zero : t_field_signals_lpf_config_0_lpf_zero_in; -- - prbs_reserved : t_field_signals_lpf_config_0_prbs_reserved_in; -- - lpf_alpha : t_field_signals_lpf_config_0_lpf_alpha_in; -- - end record; - type t_reg_lpf_config_0_out is record-- - lpf_freeze : t_field_signals_lpf_config_0_lpf_freeze_out; -- - lpf_zero : t_field_signals_lpf_config_0_lpf_zero_out; -- - prbs_reserved : t_field_signals_lpf_config_0_prbs_reserved_out; -- - lpf_alpha : t_field_signals_lpf_config_0_lpf_alpha_out; -- - end record; - type t_reg_lpf_config_0_2d_in is array (integer range <>) of t_reg_lpf_config_0_in; - type t_reg_lpf_config_0_2d_out is array (integer range <>) of t_reg_lpf_config_0_out; - type t_reg_lpf_config_0_3d_in is array (integer range <>, integer range <>) of t_reg_lpf_config_0_in; - type t_reg_lpf_config_0_3d_out is array (integer range <>, integer range <>) of t_reg_lpf_config_0_out; - ----------------------------------------------- - -- register type: lpf_config_1 - ----------------------------------------------- - type t_field_signals_lpf_config_1_i_gain_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_1_i_gain_out is record - data : std_logic_vector(24-1 downto 0); -- - end record; -- - type t_field_signals_lpf_config_1_i_shift_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_1_i_shift_out is record - data : std_logic_vector(8-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_lpf_config_1_in is record-- - i_gain : t_field_signals_lpf_config_1_i_gain_in; -- - i_shift : t_field_signals_lpf_config_1_i_shift_in; -- - end record; - type t_reg_lpf_config_1_out is record-- - i_gain : t_field_signals_lpf_config_1_i_gain_out; -- - i_shift : t_field_signals_lpf_config_1_i_shift_out; -- - end record; - type t_reg_lpf_config_1_2d_in is array (integer range <>) of t_reg_lpf_config_1_in; - type t_reg_lpf_config_1_2d_out is array (integer range <>) of t_reg_lpf_config_1_out; - type t_reg_lpf_config_1_3d_in is array (integer range <>, integer range <>) of t_reg_lpf_config_1_in; - type t_reg_lpf_config_1_3d_out is array (integer range <>, integer range <>) of t_reg_lpf_config_1_out; - ----------------------------------------------- - -- register type: data_width - ----------------------------------------------- - type t_field_signals_data_width_data_width_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_data_width_data_width_out is record - data : std_logic_vector(8-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_data_width_in is record-- - data_width : t_field_signals_data_width_data_width_in; -- - end record; - type t_reg_data_width_out is record-- - data_width : t_field_signals_data_width_data_width_out; -- - end record; - type t_reg_data_width_2d_in is array (integer range <>) of t_reg_data_width_in; - type t_reg_data_width_2d_out is array (integer range <>) of t_reg_data_width_out; - type t_reg_data_width_3d_in is array (integer range <>, integer range <>) of t_reg_data_width_in; - type t_reg_data_width_3d_out is array (integer range <>, integer range <>) of t_reg_data_width_out; - ----------------------------------------------- - -- register type: prbs_ctrl - ----------------------------------------------- - type t_field_signals_prbs_ctrl_prbs_sel_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_sel_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_prbs_ctrl_prbs_error_insert_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_error_insert_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_prbs_ctrl_prbs_clear_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_clear_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_prbs_ctrl_prbs_manual_sync_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_manual_sync_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_prbs_ctrl_prbs_reserved_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_reserved_out is record - data : std_logic_vector(12-1 downto 0); -- - end record; -- - type t_field_signals_prbs_ctrl_prbs_sync_threshold_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_prbs_ctrl_prbs_sync_threshold_out is record - data : std_logic_vector(16-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_prbs_ctrl_in is record-- - prbs_sel : t_field_signals_prbs_ctrl_prbs_sel_in; -- - prbs_error_insert : t_field_signals_prbs_ctrl_prbs_error_insert_in; -- - prbs_clear : t_field_signals_prbs_ctrl_prbs_clear_in; -- - prbs_manual_sync : t_field_signals_prbs_ctrl_prbs_manual_sync_in; -- - prbs_reserved : t_field_signals_prbs_ctrl_prbs_reserved_in; -- - prbs_sync_threshold : t_field_signals_prbs_ctrl_prbs_sync_threshold_in; -- - end record; - type t_reg_prbs_ctrl_out is record-- - prbs_sel : t_field_signals_prbs_ctrl_prbs_sel_out; -- - prbs_error_insert : t_field_signals_prbs_ctrl_prbs_error_insert_out; -- - prbs_clear : t_field_signals_prbs_ctrl_prbs_clear_out; -- - prbs_manual_sync : t_field_signals_prbs_ctrl_prbs_manual_sync_out; -- - prbs_reserved : t_field_signals_prbs_ctrl_prbs_reserved_out; -- - prbs_sync_threshold : t_field_signals_prbs_ctrl_prbs_sync_threshold_out; -- - end record; - type t_reg_prbs_ctrl_2d_in is array (integer range <>) of t_reg_prbs_ctrl_in; - type t_reg_prbs_ctrl_2d_out is array (integer range <>) of t_reg_prbs_ctrl_out; - type t_reg_prbs_ctrl_3d_in is array (integer range <>, integer range <>) of t_reg_prbs_ctrl_in; - type t_reg_prbs_ctrl_3d_out is array (integer range <>, integer range <>) of t_reg_prbs_ctrl_out; - ----------------------------------------------- - -- register type: config_prbs_seed - ----------------------------------------------- - type t_field_signals_config_prbs_seed_config_data_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_config_prbs_seed_config_data_out is record - data : std_logic_vector(32-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_config_prbs_seed_in is record-- - config_data : t_field_signals_config_prbs_seed_config_data_in; -- - end record; - type t_reg_config_prbs_seed_out is record-- - config_data : t_field_signals_config_prbs_seed_config_data_out; -- - end record; - type t_reg_config_prbs_seed_2d_in is array (integer range <>) of t_reg_config_prbs_seed_in; - type t_reg_config_prbs_seed_2d_out is array (integer range <>) of t_reg_config_prbs_seed_out; - type t_reg_config_prbs_seed_3d_in is array (integer range <>, integer range <>) of t_reg_config_prbs_seed_in; - type t_reg_config_prbs_seed_3d_out is array (integer range <>, integer range <>) of t_reg_config_prbs_seed_out; - ----------------------------------------------- - -- register type: config_prbs_poly - ----------------------------------------------- - type t_field_signals_config_prbs_poly_config_data_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_config_prbs_poly_config_data_out is record - data : std_logic_vector(32-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_config_prbs_poly_in is record-- - config_data : t_field_signals_config_prbs_poly_config_data_in; -- - end record; - type t_reg_config_prbs_poly_out is record-- - config_data : t_field_signals_config_prbs_poly_config_data_out; -- - end record; - type t_reg_config_prbs_poly_2d_in is array (integer range <>) of t_reg_config_prbs_poly_in; - type t_reg_config_prbs_poly_2d_out is array (integer range <>) of t_reg_config_prbs_poly_out; - type t_reg_config_prbs_poly_3d_in is array (integer range <>, integer range <>) of t_reg_config_prbs_poly_in; - type t_reg_config_prbs_poly_3d_out is array (integer range <>, integer range <>) of t_reg_config_prbs_poly_out; - ----------------------------------------------- - -- register type: config_prbs_errmask - ----------------------------------------------- - type t_field_signals_config_prbs_errmask_config_data_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_config_prbs_errmask_config_data_out is record - data : std_logic_vector(32-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_config_prbs_errmask_in is record-- - config_data : t_field_signals_config_prbs_errmask_config_data_in; -- - end record; - type t_reg_config_prbs_errmask_out is record-- - config_data : t_field_signals_config_prbs_errmask_config_data_out; -- - end record; - type t_reg_config_prbs_errmask_2d_in is array (integer range <>) of t_reg_config_prbs_errmask_in; - type t_reg_config_prbs_errmask_2d_out is array (integer range <>) of t_reg_config_prbs_errmask_out; - type t_reg_config_prbs_errmask_3d_in is array (integer range <>, integer range <>) of t_reg_config_prbs_errmask_in; - type t_reg_config_prbs_errmask_3d_out is array (integer range <>, integer range <>) of t_reg_config_prbs_errmask_out; - ----------------------------------------------- - -- register type: stat_32_bits - ----------------------------------------------- - type t_field_signals_stat_32_bits_status_data_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_stat_32_bits_status_data_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_stat_32_bits_in is record-- - status_data : t_field_signals_stat_32_bits_status_data_in; -- - end record; - type t_reg_stat_32_bits_out is record-- - status_data : t_field_signals_stat_32_bits_status_data_out; -- - end record; - type t_reg_stat_32_bits_2d_in is array (integer range <>) of t_reg_stat_32_bits_in; - type t_reg_stat_32_bits_2d_out is array (integer range <>) of t_reg_stat_32_bits_out; - type t_reg_stat_32_bits_3d_in is array (integer range <>, integer range <>) of t_reg_stat_32_bits_in; - type t_reg_stat_32_bits_3d_out is array (integer range <>, integer range <>) of t_reg_stat_32_bits_out; - ----------------------------------------------- - -- register type: stat_32_errs - ----------------------------------------------- - type t_field_signals_stat_32_errs_status_data_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_stat_32_errs_status_data_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_stat_32_errs_in is record-- - status_data : t_field_signals_stat_32_errs_status_data_in; -- - end record; - type t_reg_stat_32_errs_out is record-- - status_data : t_field_signals_stat_32_errs_status_data_out; -- - end record; - type t_reg_stat_32_errs_2d_in is array (integer range <>) of t_reg_stat_32_errs_in; - type t_reg_stat_32_errs_2d_out is array (integer range <>) of t_reg_stat_32_errs_out; - type t_reg_stat_32_errs_3d_in is array (integer range <>, integer range <>) of t_reg_stat_32_errs_in; - type t_reg_stat_32_errs_3d_out is array (integer range <>, integer range <>) of t_reg_stat_32_errs_out; - ----------------------------------------------- - -- register type: stat_32_lpf_acc - ----------------------------------------------- - type t_field_signals_stat_32_lpf_acc_status_data_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_stat_32_lpf_acc_status_data_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_stat_32_lpf_acc_in is record-- - status_data : t_field_signals_stat_32_lpf_acc_status_data_in; -- - end record; - type t_reg_stat_32_lpf_acc_out is record-- - status_data : t_field_signals_stat_32_lpf_acc_status_data_out; -- - end record; - type t_reg_stat_32_lpf_acc_2d_in is array (integer range <>) of t_reg_stat_32_lpf_acc_in; - type t_reg_stat_32_lpf_acc_2d_out is array (integer range <>) of t_reg_stat_32_lpf_acc_out; - type t_reg_stat_32_lpf_acc_3d_in is array (integer range <>, integer range <>) of t_reg_stat_32_lpf_acc_in; - type t_reg_stat_32_lpf_acc_3d_out is array (integer range <>, integer range <>) of t_reg_stat_32_lpf_acc_out; - ----------------------------------------------- - -- register type: msk_stat_3 - ----------------------------------------------- - type t_field_signals_msk_stat_3_xfer_count_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_msk_stat_3_xfer_count_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_msk_stat_3_in is record-- - xfer_count : t_field_signals_msk_stat_3_xfer_count_in; -- - end record; - type t_reg_msk_stat_3_out is record-- - xfer_count : t_field_signals_msk_stat_3_xfer_count_out; -- - end record; - type t_reg_msk_stat_3_2d_in is array (integer range <>) of t_reg_msk_stat_3_in; - type t_reg_msk_stat_3_2d_out is array (integer range <>) of t_reg_msk_stat_3_out; - type t_reg_msk_stat_3_3d_in is array (integer range <>, integer range <>) of t_reg_msk_stat_3_in; - type t_reg_msk_stat_3_3d_out is array (integer range <>, integer range <>) of t_reg_msk_stat_3_out; - ----------------------------------------------- - -- register type: rx_sample_discard - ----------------------------------------------- - type t_field_signals_rx_sample_discard_rx_sample_discard_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_rx_sample_discard_rx_sample_discard_out is record - data : std_logic_vector(8-1 downto 0); -- - end record; -- - type t_field_signals_rx_sample_discard_rx_nco_discard_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_rx_sample_discard_rx_nco_discard_out is record - data : std_logic_vector(8-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_rx_sample_discard_in is record-- - rx_sample_discard : t_field_signals_rx_sample_discard_rx_sample_discard_in; -- - rx_nco_discard : t_field_signals_rx_sample_discard_rx_nco_discard_in; -- - end record; - type t_reg_rx_sample_discard_out is record-- - rx_sample_discard : t_field_signals_rx_sample_discard_rx_sample_discard_out; -- - rx_nco_discard : t_field_signals_rx_sample_discard_rx_nco_discard_out; -- - end record; - type t_reg_rx_sample_discard_2d_in is array (integer range <>) of t_reg_rx_sample_discard_in; - type t_reg_rx_sample_discard_2d_out is array (integer range <>) of t_reg_rx_sample_discard_out; - type t_reg_rx_sample_discard_3d_in is array (integer range <>, integer range <>) of t_reg_rx_sample_discard_in; - type t_reg_rx_sample_discard_3d_out is array (integer range <>, integer range <>) of t_reg_rx_sample_discard_out; - ----------------------------------------------- - -- register type: lpf_config_2 - ----------------------------------------------- - type t_field_signals_lpf_config_2_p_gain_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_2_p_gain_out is record - data : std_logic_vector(24-1 downto 0); -- - end record; -- - type t_field_signals_lpf_config_2_p_shift_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lpf_config_2_p_shift_out is record - data : std_logic_vector(8-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_lpf_config_2_in is record-- - p_gain : t_field_signals_lpf_config_2_p_gain_in; -- - p_shift : t_field_signals_lpf_config_2_p_shift_in; -- - end record; - type t_reg_lpf_config_2_out is record-- - p_gain : t_field_signals_lpf_config_2_p_gain_out; -- - p_shift : t_field_signals_lpf_config_2_p_shift_out; -- - end record; - type t_reg_lpf_config_2_2d_in is array (integer range <>) of t_reg_lpf_config_2_in; - type t_reg_lpf_config_2_2d_out is array (integer range <>) of t_reg_lpf_config_2_out; - type t_reg_lpf_config_2_3d_in is array (integer range <>, integer range <>) of t_reg_lpf_config_2_in; - type t_reg_lpf_config_2_3d_out is array (integer range <>, integer range <>) of t_reg_lpf_config_2_out; - ----------------------------------------------- - -- register type: observation_data - ----------------------------------------------- - type t_field_signals_observation_data_data32_in is record - data : std_logic_vector(32-1 downto 0); -- - end record; - - type t_field_signals_observation_data_data32_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_observation_data_in is record-- - data : t_field_signals_observation_data_data32_in; -- - end record; - type t_reg_observation_data_out is record-- - data : t_field_signals_observation_data_data32_out; -- - end record; - type t_reg_observation_data_2d_in is array (integer range <>) of t_reg_observation_data_in; - type t_reg_observation_data_2d_out is array (integer range <>) of t_reg_observation_data_out; - type t_reg_observation_data_3d_in is array (integer range <>, integer range <>) of t_reg_observation_data_in; - type t_reg_observation_data_3d_out is array (integer range <>, integer range <>) of t_reg_observation_data_out; - ----------------------------------------------- - -- register type: tx_sync_ctrl - ----------------------------------------------- - type t_field_signals_tx_sync_ctrl_tx_sync_ena_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_tx_sync_ctrl_tx_sync_ena_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_tx_sync_ctrl_tx_sync_force_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_tx_sync_ctrl_tx_sync_force_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_tx_sync_ctrl_tx_sync_f1_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_tx_sync_ctrl_tx_sync_f1_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - type t_field_signals_tx_sync_ctrl_tx_sync_f2_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_tx_sync_ctrl_tx_sync_f2_out is record - data : std_logic_vector(1-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_tx_sync_ctrl_in is record-- - tx_sync_ena : t_field_signals_tx_sync_ctrl_tx_sync_ena_in; -- - tx_sync_force : t_field_signals_tx_sync_ctrl_tx_sync_force_in; -- - tx_sync_f1 : t_field_signals_tx_sync_ctrl_tx_sync_f1_in; -- - tx_sync_f2 : t_field_signals_tx_sync_ctrl_tx_sync_f2_in; -- - end record; - type t_reg_tx_sync_ctrl_out is record-- - tx_sync_ena : t_field_signals_tx_sync_ctrl_tx_sync_ena_out; -- - tx_sync_force : t_field_signals_tx_sync_ctrl_tx_sync_force_out; -- - tx_sync_f1 : t_field_signals_tx_sync_ctrl_tx_sync_f1_out; -- - tx_sync_f2 : t_field_signals_tx_sync_ctrl_tx_sync_f2_out; -- - end record; - type t_reg_tx_sync_ctrl_2d_in is array (integer range <>) of t_reg_tx_sync_ctrl_in; - type t_reg_tx_sync_ctrl_2d_out is array (integer range <>) of t_reg_tx_sync_ctrl_out; - type t_reg_tx_sync_ctrl_3d_in is array (integer range <>, integer range <>) of t_reg_tx_sync_ctrl_in; - type t_reg_tx_sync_ctrl_3d_out is array (integer range <>, integer range <>) of t_reg_tx_sync_ctrl_out; - ----------------------------------------------- - -- register type: tx_sync_cnt - ----------------------------------------------- - type t_field_signals_tx_sync_cnt_tx_sync_cnt_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_tx_sync_cnt_tx_sync_cnt_out is record - data : std_logic_vector(24-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_tx_sync_cnt_in is record-- - tx_sync_cnt : t_field_signals_tx_sync_cnt_tx_sync_cnt_in; -- - end record; - type t_reg_tx_sync_cnt_out is record-- - tx_sync_cnt : t_field_signals_tx_sync_cnt_tx_sync_cnt_out; -- - end record; - type t_reg_tx_sync_cnt_2d_in is array (integer range <>) of t_reg_tx_sync_cnt_in; - type t_reg_tx_sync_cnt_2d_out is array (integer range <>) of t_reg_tx_sync_cnt_out; - type t_reg_tx_sync_cnt_3d_in is array (integer range <>, integer range <>) of t_reg_tx_sync_cnt_in; - type t_reg_tx_sync_cnt_3d_out is array (integer range <>, integer range <>) of t_reg_tx_sync_cnt_out; - ----------------------------------------------- - -- register type: lowpass_ema_alpha - ----------------------------------------------- - type t_field_signals_lowpass_ema_alpha_alpha_in is record - -- no data if field cannot be written from hw - data : std_logic_vector(-1 downto 0); -- - end record; - - type t_field_signals_lowpass_ema_alpha_alpha_out is record - data : std_logic_vector(18-1 downto 0); -- - end record; -- - - -- The actual register types - type t_reg_lowpass_ema_alpha_in is record-- - alpha : t_field_signals_lowpass_ema_alpha_alpha_in; -- - end record; - type t_reg_lowpass_ema_alpha_out is record-- - alpha : t_field_signals_lowpass_ema_alpha_alpha_out; -- - end record; - type t_reg_lowpass_ema_alpha_2d_in is array (integer range <>) of t_reg_lowpass_ema_alpha_in; - type t_reg_lowpass_ema_alpha_2d_out is array (integer range <>) of t_reg_lowpass_ema_alpha_out; - type t_reg_lowpass_ema_alpha_3d_in is array (integer range <>, integer range <>) of t_reg_lowpass_ema_alpha_in; - type t_reg_lowpass_ema_alpha_3d_out is array (integer range <>, integer range <>) of t_reg_lowpass_ema_alpha_out; - ----------------------------------------------- - -- register type: rx_power - ----------------------------------------------- - type t_field_signals_rx_power_rx_power_in is record - data : std_logic_vector(23-1 downto 0); -- - end record; - - type t_field_signals_rx_power_rx_power_out is record - -- no data if field cannot be written from hw - dummy : std_logic; -- - end record; -- - - -- The actual register types - type t_reg_rx_power_in is record-- - rx_power : t_field_signals_rx_power_rx_power_in; -- - end record; - type t_reg_rx_power_out is record-- - rx_power : t_field_signals_rx_power_rx_power_out; -- - end record; - type t_reg_rx_power_2d_in is array (integer range <>) of t_reg_rx_power_in; - type t_reg_rx_power_2d_out is array (integer range <>) of t_reg_rx_power_out; - type t_reg_rx_power_3d_in is array (integer range <>, integer range <>) of t_reg_rx_power_in; - type t_reg_rx_power_3d_out is array (integer range <>, integer range <>) of t_reg_rx_power_out; - ----------------------------------------------- - - ------------------------------------------------------------------------------ - -- Register types in regfiles -- - - -- =========================================================================== - -- REGFILE interface - -- ----------------------------------------------------------------------------- - - -- =========================================================================== - -- MEMORIES interface - -- --------------------------------------------------------------------------- - - -- =========================================================================== - -- msk_top_regs : Top module address map interface - -- --------------------------------------------------------------------------- - type t_addrmap_msk_top_regs_in is record - -- - Hash_ID_Low : t_reg_msk_hash_lo_in; -- - Hash_ID_High : t_reg_msk_hash_hi_in; -- - MSK_Init : t_reg_msk_init_in; -- - MSK_Control : t_reg_msk_ctrl_in; -- - MSK_Status : t_reg_msk_stat_0_in; -- - Tx_Bit_Count : t_reg_msk_stat_1_in; -- - Tx_Enable_Count : t_reg_msk_stat_2_in; -- - Fb_FreqWord : t_reg_config_nco_fw_in; -- - TX_F1_FreqWord : t_reg_config_nco_fw_in; -- - TX_F2_FreqWord : t_reg_config_nco_fw_in; -- - RX_F1_FreqWord : t_reg_config_nco_fw_in; -- - RX_F2_FreqWord : t_reg_config_nco_fw_in; -- - LPF_Config_0 : t_reg_lpf_config_0_in; -- - LPF_Config_1 : t_reg_lpf_config_1_in; -- - Tx_Data_Width : t_reg_data_width_in; -- - Rx_Data_Width : t_reg_data_width_in; -- - PRBS_Control : t_reg_prbs_ctrl_in; -- - PRBS_Initial_State : t_reg_config_prbs_seed_in; -- - PRBS_Polynomial : t_reg_config_prbs_poly_in; -- - PRBS_Error_Mask : t_reg_config_prbs_errmask_in; -- - PRBS_Bit_Count : t_reg_stat_32_bits_in; -- - PRBS_Error_Count : t_reg_stat_32_errs_in; -- - LPF_Accum_F1 : t_reg_stat_32_lpf_acc_in; -- - LPF_Accum_F2 : t_reg_stat_32_lpf_acc_in; -- - axis_xfer_count : t_reg_msk_stat_3_in; -- - Rx_Sample_Discard : t_reg_rx_sample_discard_in; -- - LPF_Config_2 : t_reg_lpf_config_2_in; -- - f1_nco_adjust : t_reg_observation_data_in; -- - f2_nco_adjust : t_reg_observation_data_in; -- - f1_error : t_reg_observation_data_in; -- - f2_error : t_reg_observation_data_in; -- - Tx_Sync_Ctrl : t_reg_tx_sync_ctrl_in; -- - Tx_Sync_Cnt : t_reg_tx_sync_cnt_in; -- - lowpass_ema_alpha1 : t_reg_lowpass_ema_alpha_in; -- - lowpass_ema_alpha2 : t_reg_lowpass_ema_alpha_in; -- - rx_power : t_reg_rx_power_in; -- - -- - -- - -- - end record; - - type t_addrmap_msk_top_regs_out is record - -- - Hash_ID_Low : t_reg_msk_hash_lo_out; -- - Hash_ID_High : t_reg_msk_hash_hi_out; -- - MSK_Init : t_reg_msk_init_out; -- - MSK_Control : t_reg_msk_ctrl_out; -- - MSK_Status : t_reg_msk_stat_0_out; -- - Tx_Bit_Count : t_reg_msk_stat_1_out; -- - Tx_Enable_Count : t_reg_msk_stat_2_out; -- - Fb_FreqWord : t_reg_config_nco_fw_out; -- - TX_F1_FreqWord : t_reg_config_nco_fw_out; -- - TX_F2_FreqWord : t_reg_config_nco_fw_out; -- - RX_F1_FreqWord : t_reg_config_nco_fw_out; -- - RX_F2_FreqWord : t_reg_config_nco_fw_out; -- - LPF_Config_0 : t_reg_lpf_config_0_out; -- - LPF_Config_1 : t_reg_lpf_config_1_out; -- - Tx_Data_Width : t_reg_data_width_out; -- - Rx_Data_Width : t_reg_data_width_out; -- - PRBS_Control : t_reg_prbs_ctrl_out; -- - PRBS_Initial_State : t_reg_config_prbs_seed_out; -- - PRBS_Polynomial : t_reg_config_prbs_poly_out; -- - PRBS_Error_Mask : t_reg_config_prbs_errmask_out; -- - PRBS_Bit_Count : t_reg_stat_32_bits_out; -- - PRBS_Error_Count : t_reg_stat_32_errs_out; -- - LPF_Accum_F1 : t_reg_stat_32_lpf_acc_out; -- - LPF_Accum_F2 : t_reg_stat_32_lpf_acc_out; -- - axis_xfer_count : t_reg_msk_stat_3_out; -- - Rx_Sample_Discard : t_reg_rx_sample_discard_out; -- - LPF_Config_2 : t_reg_lpf_config_2_out; -- - f1_nco_adjust : t_reg_observation_data_out; -- - f2_nco_adjust : t_reg_observation_data_out; -- - f1_error : t_reg_observation_data_out; -- - f2_error : t_reg_observation_data_out; -- - Tx_Sync_Ctrl : t_reg_tx_sync_ctrl_out; -- - Tx_Sync_Cnt : t_reg_tx_sync_cnt_out; -- - lowpass_ema_alpha1 : t_reg_lowpass_ema_alpha_out; -- - lowpass_ema_alpha2 : t_reg_lowpass_ema_alpha_out; -- - rx_power : t_reg_rx_power_out; -- - -- - -- - -- - end record; - - -- =========================================================================== - -- top level component declaration - -- must come after defining the interfaces - -- --------------------------------------------------------------------------- - subtype t_msk_top_regs_m2s is t_axi4l_m2s; - subtype t_msk_top_regs_s2m is t_axi4l_s2m; - - component msk_top_regs is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- TOP subordinate memory mapped interface - pi_s_top : in t_msk_top_regs_m2s; - po_s_top : out t_msk_top_regs_s2m; - -- to logic interface - pi_addrmap : in t_addrmap_msk_top_regs_in; - po_addrmap : out t_addrmap_msk_top_regs_out - ); - end component msk_top_regs; - -end package pkg_msk_top_regs; --------------------------------------------------------------------------------- -package body pkg_msk_top_regs is -end package body; - ---============================================================================== - - --------------------------------------------------------------------------------- --- Register types directly in addmap --------------------------------------------------------------------------------- --- --- register type: msk_hash_lo ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_hash_lo is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_hash_lo_in ; - po_reg : out t_reg_msk_hash_lo_out - ); -end entity msk_top_regs_msk_hash_lo; - -architecture rtl of msk_top_regs_msk_hash_lo is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_hash_id_lo : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_hash_id_lo; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_hash_id_lo : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(-1431677611,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_hash_id_lo -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - hash_id_lo_wire : block -- - begin - -- - field_reg_hash_id_lo <= std_logic_vector(to_signed(-1431677611,32)); -- - --no signal to read by HW - po_reg.hash_id_lo.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: msk_hash_hi ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_hash_hi is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_hash_hi_in ; - po_reg : out t_reg_msk_hash_hi_out - ); -end entity msk_top_regs_msk_hash_hi; - -architecture rtl of msk_top_regs_msk_hash_hi is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_hash_id_hi : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_hash_id_hi; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_hash_id_hi : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(1431677610,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_hash_id_hi -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - hash_id_hi_wire : block -- - begin - -- - field_reg_hash_id_hi <= std_logic_vector(to_signed(1431677610,32)); -- - --no signal to read by HW - po_reg.hash_id_hi.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: msk_init ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_init is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_init_in ; - po_reg : out t_reg_msk_init_out - ); -end entity msk_top_regs_msk_init; - -architecture rtl of msk_top_regs_msk_init is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_txrxinit : std_logic_vector(1-1 downto 0); -- - field_reg_txinit : std_logic_vector(1-1 downto 0); -- - field_reg_rxinit : std_logic_vector(1-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_txrxinit; -- - v_data_out(1 downto 1) := field_reg_txinit; -- - v_data_out(2 downto 2) := field_reg_rxinit; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_txrxinit : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(1,1)); -- - signal field_reg_txinit : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(1,1)); -- - signal field_reg_rxinit : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(1,1)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_txrxinit, -- - field_reg_txinit, -- - field_reg_rxinit -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - txrxinit_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_txrxinit <= std_logic_vector(to_signed(1,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_txrxinit <= pi_decoder_data(0 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.txrxinit.data <= field_reg_txrxinit; -- - end block txrxinit_storage; - ------------------------------------------------------------STORAGE - txinit_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_txinit <= std_logic_vector(to_signed(1,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_txinit <= pi_decoder_data(1 downto 1); - end if; - end if; - end if; - end process; - -- - po_reg.txinit.data <= field_reg_txinit; -- - end block txinit_storage; - ------------------------------------------------------------STORAGE - rxinit_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_rxinit <= std_logic_vector(to_signed(1,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_rxinit <= pi_decoder_data(2 downto 2); - end if; - end if; - end if; - end process; - -- - po_reg.rxinit.data <= field_reg_rxinit; -- - end block rxinit_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: msk_ctrl ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_ctrl is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_ctrl_in ; - po_reg : out t_reg_msk_ctrl_out - ); -end entity msk_top_regs_msk_ctrl; - -architecture rtl of msk_top_regs_msk_ctrl is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_ptt : std_logic_vector(1-1 downto 0); -- - field_reg_loopback_ena : std_logic_vector(1-1 downto 0); -- - field_reg_rx_invert : std_logic_vector(1-1 downto 0); -- - field_reg_clear_counts : std_logic_vector(1-1 downto 0); -- - field_reg_diff_encoder_loopback : std_logic_vector(1-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_ptt; -- - v_data_out(1 downto 1) := field_reg_loopback_ena; -- - v_data_out(2 downto 2) := field_reg_rx_invert; -- - v_data_out(3 downto 3) := field_reg_clear_counts; -- - v_data_out(4 downto 4) := field_reg_diff_encoder_loopback; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_ptt : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_loopback_ena : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_rx_invert : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_clear_counts : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_diff_encoder_loopback : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_ptt, -- - field_reg_loopback_ena, -- - field_reg_rx_invert, -- - field_reg_clear_counts, -- - field_reg_diff_encoder_loopback -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - ptt_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_ptt <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_ptt <= pi_decoder_data(0 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.ptt.data <= field_reg_ptt; -- - end block ptt_storage; - ------------------------------------------------------------STORAGE - loopback_ena_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_loopback_ena <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_loopback_ena <= pi_decoder_data(1 downto 1); - end if; - end if; - end if; - end process; - -- - po_reg.loopback_ena.data <= field_reg_loopback_ena; -- - end block loopback_ena_storage; - ------------------------------------------------------------STORAGE - rx_invert_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_rx_invert <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_rx_invert <= pi_decoder_data(2 downto 2); - end if; - end if; - end if; - end process; - -- - po_reg.rx_invert.data <= field_reg_rx_invert; -- - end block rx_invert_storage; - ------------------------------------------------------------STORAGE - clear_counts_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_clear_counts <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- This is a "singlepulse" register - clear on each clock, - -- unless it is written to with a 1 (see below) - field_reg_clear_counts <= (others => '0'); - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_clear_counts <= pi_decoder_data(3 downto 3); - end if; - end if; - end if; - end process; - -- - po_reg.clear_counts.data <= field_reg_clear_counts; -- - end block clear_counts_storage; - ------------------------------------------------------------STORAGE - diff_encoder_loopback_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_diff_encoder_loopback <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_diff_encoder_loopback <= pi_decoder_data(4 downto 4); - end if; - end if; - end if; - end process; - -- - po_reg.diff_encoder_loopback.data <= field_reg_diff_encoder_loopback; -- - end block diff_encoder_loopback_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: msk_stat_0 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_stat_0 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_stat_0_in ; - po_reg : out t_reg_msk_stat_0_out - ); -end entity msk_top_regs_msk_stat_0; - -architecture rtl of msk_top_regs_msk_stat_0 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_demod_sync_lock : std_logic_vector(1-1 downto 0); -- - field_reg_tx_enable : std_logic_vector(1-1 downto 0); -- - field_reg_rx_enable : std_logic_vector(1-1 downto 0); -- - field_reg_tx_axis_valid : std_logic_vector(1-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_demod_sync_lock; -- - v_data_out(1 downto 1) := field_reg_tx_enable; -- - v_data_out(2 downto 2) := field_reg_rx_enable; -- - v_data_out(3 downto 3) := field_reg_tx_axis_valid; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_demod_sync_lock : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_tx_enable : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_rx_enable : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_tx_axis_valid : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_demod_sync_lock, -- - field_reg_tx_enable, -- - field_reg_rx_enable, -- - field_reg_tx_axis_valid -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - demod_sync_lock_wire : block -- - begin - -- - field_reg_demod_sync_lock <= pi_reg.demod_sync_lock.data(1-1 downto 0); -- - --no signal to read by HW - po_reg.demod_sync_lock.dummy <= '0'; -- - end block; ----WIRE - tx_enable_wire : block -- - begin - -- - field_reg_tx_enable <= pi_reg.tx_enable.data(1-1 downto 0); -- - --no signal to read by HW - po_reg.tx_enable.dummy <= '0'; -- - end block; ----WIRE - rx_enable_wire : block -- - begin - -- - field_reg_rx_enable <= pi_reg.rx_enable.data(1-1 downto 0); -- - --no signal to read by HW - po_reg.rx_enable.dummy <= '0'; -- - end block; ----WIRE - tx_axis_valid_wire : block -- - begin - -- - field_reg_tx_axis_valid <= pi_reg.tx_axis_valid.data(1-1 downto 0); -- - --no signal to read by HW - po_reg.tx_axis_valid.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: msk_stat_1 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_stat_1 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_stat_1_in ; - po_reg : out t_reg_msk_stat_1_out - ); -end entity msk_top_regs_msk_stat_1; - -architecture rtl of msk_top_regs_msk_stat_1 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_tx_bit_counter : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_tx_bit_counter; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_tx_bit_counter : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_tx_bit_counter -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - tx_bit_counter_wire : block -- - begin - -- - field_reg_tx_bit_counter <= pi_reg.tx_bit_counter.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.tx_bit_counter.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: msk_stat_2 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_stat_2 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_stat_2_in ; - po_reg : out t_reg_msk_stat_2_out - ); -end entity msk_top_regs_msk_stat_2; - -architecture rtl of msk_top_regs_msk_stat_2 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_tx_ena_counter : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_tx_ena_counter; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_tx_ena_counter : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_tx_ena_counter -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - tx_ena_counter_wire : block -- - begin - -- - field_reg_tx_ena_counter <= pi_reg.tx_ena_counter.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.tx_ena_counter.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: config_nco_fw ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_config_nco_fw is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_config_nco_fw_in ; - po_reg : out t_reg_config_nco_fw_out - ); -end entity msk_top_regs_config_nco_fw; - -architecture rtl of msk_top_regs_config_nco_fw is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_config_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_config_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_config_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_config_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - config_data_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_config_data <= std_logic_vector(to_signed(0,32)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_config_data <= pi_decoder_data(31 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.config_data.data <= field_reg_config_data; -- - end block config_data_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: lpf_config_0 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_lpf_config_0 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_lpf_config_0_in ; - po_reg : out t_reg_lpf_config_0_out - ); -end entity msk_top_regs_lpf_config_0; - -architecture rtl of msk_top_regs_lpf_config_0 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_lpf_freeze : std_logic_vector(1-1 downto 0); -- - field_reg_lpf_zero : std_logic_vector(1-1 downto 0); -- - field_reg_prbs_reserved : std_logic_vector(6-1 downto 0); -- - field_reg_lpf_alpha : std_logic_vector(24-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_lpf_freeze; -- - v_data_out(1 downto 1) := field_reg_lpf_zero; -- - v_data_out(7 downto 2) := field_reg_prbs_reserved; -- - v_data_out(31 downto 8) := field_reg_lpf_alpha; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_lpf_freeze : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_lpf_zero : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_prbs_reserved : std_logic_vector(6-1 downto 0) - := std_logic_vector(to_signed(0,6)); -- - signal field_reg_lpf_alpha : std_logic_vector(24-1 downto 0) - := std_logic_vector(to_signed(0,24)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_lpf_freeze, -- - field_reg_lpf_zero, -- - field_reg_prbs_reserved, -- - field_reg_lpf_alpha -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - lpf_freeze_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_lpf_freeze <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_lpf_freeze <= pi_decoder_data(0 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.lpf_freeze.data <= field_reg_lpf_freeze; -- - end block lpf_freeze_storage; - ------------------------------------------------------------STORAGE - lpf_zero_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_lpf_zero <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_lpf_zero <= pi_decoder_data(1 downto 1); - end if; - end if; - end if; - end process; - -- - po_reg.lpf_zero.data <= field_reg_lpf_zero; -- - end block lpf_zero_storage; - ------------------------------------------------------------STORAGE - prbs_reserved_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_reserved <= std_logic_vector(to_signed(0,6)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_reserved <= pi_decoder_data(7 downto 2); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_reserved.data <= field_reg_prbs_reserved; -- - end block prbs_reserved_storage; - ------------------------------------------------------------STORAGE - lpf_alpha_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_lpf_alpha <= std_logic_vector(to_signed(0,24)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_lpf_alpha <= pi_decoder_data(31 downto 8); - end if; - end if; - end if; - end process; - -- - po_reg.lpf_alpha.data <= field_reg_lpf_alpha; -- - end block lpf_alpha_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: lpf_config_1 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_lpf_config_1 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_lpf_config_1_in ; - po_reg : out t_reg_lpf_config_1_out - ); -end entity msk_top_regs_lpf_config_1; - -architecture rtl of msk_top_regs_lpf_config_1 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_i_gain : std_logic_vector(24-1 downto 0); -- - field_reg_i_shift : std_logic_vector(8-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(23 downto 0) := field_reg_i_gain; -- - v_data_out(31 downto 24) := field_reg_i_shift; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_i_gain : std_logic_vector(24-1 downto 0) - := std_logic_vector(to_signed(0,24)); -- - signal field_reg_i_shift : std_logic_vector(8-1 downto 0) - := std_logic_vector(to_signed(0,8)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_i_gain, -- - field_reg_i_shift -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - i_gain_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_i_gain <= std_logic_vector(to_signed(0,24)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_i_gain <= pi_decoder_data(23 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.i_gain.data <= field_reg_i_gain; -- - end block i_gain_storage; - ------------------------------------------------------------STORAGE - i_shift_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_i_shift <= std_logic_vector(to_signed(0,8)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_i_shift <= pi_decoder_data(31 downto 24); - end if; - end if; - end if; - end process; - -- - po_reg.i_shift.data <= field_reg_i_shift; -- - end block i_shift_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: data_width ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_data_width is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_data_width_in ; - po_reg : out t_reg_data_width_out - ); -end entity msk_top_regs_data_width; - -architecture rtl of msk_top_regs_data_width is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_data_width : std_logic_vector(8-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(7 downto 0) := field_reg_data_width; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_data_width : std_logic_vector(8-1 downto 0) - := std_logic_vector(to_signed(8,8)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_data_width -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - data_width_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_data_width <= std_logic_vector(to_signed(8,8)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_data_width <= pi_decoder_data(7 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.data_width.data <= field_reg_data_width; -- - end block data_width_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: prbs_ctrl ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_prbs_ctrl is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_prbs_ctrl_in ; - po_reg : out t_reg_prbs_ctrl_out - ); -end entity msk_top_regs_prbs_ctrl; - -architecture rtl of msk_top_regs_prbs_ctrl is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_prbs_sel : std_logic_vector(1-1 downto 0); -- - field_reg_prbs_error_insert : std_logic_vector(1-1 downto 0); -- - field_reg_prbs_clear : std_logic_vector(1-1 downto 0); -- - field_reg_prbs_manual_sync : std_logic_vector(1-1 downto 0); -- - field_reg_prbs_reserved : std_logic_vector(12-1 downto 0); -- - field_reg_prbs_sync_threshold : std_logic_vector(16-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_prbs_sel; -- - v_data_out(1 downto 1) := field_reg_prbs_error_insert; -- - v_data_out(2 downto 2) := field_reg_prbs_clear; -- - v_data_out(3 downto 3) := field_reg_prbs_manual_sync; -- - v_data_out(15 downto 4) := field_reg_prbs_reserved; -- - v_data_out(31 downto 16) := field_reg_prbs_sync_threshold; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_prbs_sel : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_prbs_error_insert : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_prbs_clear : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_prbs_manual_sync : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_prbs_reserved : std_logic_vector(12-1 downto 0) - := std_logic_vector(to_signed(0,12)); -- - signal field_reg_prbs_sync_threshold : std_logic_vector(16-1 downto 0) - := std_logic_vector(to_signed(0,16)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_prbs_sel, -- - field_reg_prbs_error_insert, -- - field_reg_prbs_clear, -- - field_reg_prbs_manual_sync, -- - field_reg_prbs_reserved, -- - field_reg_prbs_sync_threshold -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - prbs_sel_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_sel <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_sel <= pi_decoder_data(0 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_sel.data <= field_reg_prbs_sel; -- - end block prbs_sel_storage; - ------------------------------------------------------------STORAGE - prbs_error_insert_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_error_insert <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- This is a "singlepulse" register - clear on each clock, - -- unless it is written to with a 1 (see below) - field_reg_prbs_error_insert <= (others => '0'); - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_error_insert <= pi_decoder_data(1 downto 1); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_error_insert.data <= field_reg_prbs_error_insert; -- - end block prbs_error_insert_storage; - ------------------------------------------------------------STORAGE - prbs_clear_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_clear <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- This is a "singlepulse" register - clear on each clock, - -- unless it is written to with a 1 (see below) - field_reg_prbs_clear <= (others => '0'); - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_clear <= pi_decoder_data(2 downto 2); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_clear.data <= field_reg_prbs_clear; -- - end block prbs_clear_storage; - ------------------------------------------------------------STORAGE - prbs_manual_sync_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_manual_sync <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- This is a "singlepulse" register - clear on each clock, - -- unless it is written to with a 1 (see below) - field_reg_prbs_manual_sync <= (others => '0'); - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_manual_sync <= pi_decoder_data(3 downto 3); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_manual_sync.data <= field_reg_prbs_manual_sync; -- - end block prbs_manual_sync_storage; - ------------------------------------------------------------STORAGE - prbs_reserved_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_reserved <= std_logic_vector(to_signed(0,12)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_reserved <= pi_decoder_data(15 downto 4); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_reserved.data <= field_reg_prbs_reserved; -- - end block prbs_reserved_storage; - ------------------------------------------------------------STORAGE - prbs_sync_threshold_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_prbs_sync_threshold <= std_logic_vector(to_signed(0,16)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_prbs_sync_threshold <= pi_decoder_data(31 downto 16); - end if; - end if; - end if; - end process; - -- - po_reg.prbs_sync_threshold.data <= field_reg_prbs_sync_threshold; -- - end block prbs_sync_threshold_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: config_prbs_seed ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_config_prbs_seed is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_config_prbs_seed_in ; - po_reg : out t_reg_config_prbs_seed_out - ); -end entity msk_top_regs_config_prbs_seed; - -architecture rtl of msk_top_regs_config_prbs_seed is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_config_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_config_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_config_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_config_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - config_data_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_config_data <= std_logic_vector(to_signed(0,32)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_config_data <= pi_decoder_data(31 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.config_data.data <= field_reg_config_data; -- - end block config_data_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: config_prbs_poly ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_config_prbs_poly is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_config_prbs_poly_in ; - po_reg : out t_reg_config_prbs_poly_out - ); -end entity msk_top_regs_config_prbs_poly; - -architecture rtl of msk_top_regs_config_prbs_poly is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_config_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_config_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_config_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_config_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - config_data_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_config_data <= std_logic_vector(to_signed(0,32)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_config_data <= pi_decoder_data(31 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.config_data.data <= field_reg_config_data; -- - end block config_data_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: config_prbs_errmask ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_config_prbs_errmask is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_config_prbs_errmask_in ; - po_reg : out t_reg_config_prbs_errmask_out - ); -end entity msk_top_regs_config_prbs_errmask; - -architecture rtl of msk_top_regs_config_prbs_errmask is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_config_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_config_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_config_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_config_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - config_data_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_config_data <= std_logic_vector(to_signed(0,32)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_config_data <= pi_decoder_data(31 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.config_data.data <= field_reg_config_data; -- - end block config_data_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: stat_32_bits ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_stat_32_bits is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_stat_32_bits_in ; - po_reg : out t_reg_stat_32_bits_out - ); -end entity msk_top_regs_stat_32_bits; - -architecture rtl of msk_top_regs_stat_32_bits is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_status_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_status_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_status_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_status_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - status_data_wire : block -- - begin - -- - field_reg_status_data <= pi_reg.status_data.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.status_data.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: stat_32_errs ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_stat_32_errs is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_stat_32_errs_in ; - po_reg : out t_reg_stat_32_errs_out - ); -end entity msk_top_regs_stat_32_errs; - -architecture rtl of msk_top_regs_stat_32_errs is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_status_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_status_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_status_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_status_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - status_data_wire : block -- - begin - -- - field_reg_status_data <= pi_reg.status_data.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.status_data.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: stat_32_lpf_acc ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_stat_32_lpf_acc is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_stat_32_lpf_acc_in ; - po_reg : out t_reg_stat_32_lpf_acc_out - ); -end entity msk_top_regs_stat_32_lpf_acc; - -architecture rtl of msk_top_regs_stat_32_lpf_acc is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_status_data : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_status_data; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_status_data : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_status_data -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - status_data_wire : block -- - begin - -- - field_reg_status_data <= pi_reg.status_data.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.status_data.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: msk_stat_3 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_msk_stat_3 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_msk_stat_3_in ; - po_reg : out t_reg_msk_stat_3_out - ); -end entity msk_top_regs_msk_stat_3; - -architecture rtl of msk_top_regs_msk_stat_3 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_xfer_count : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_xfer_count; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_xfer_count : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_xfer_count -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - xfer_count_wire : block -- - begin - -- - field_reg_xfer_count <= pi_reg.xfer_count.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.xfer_count.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: rx_sample_discard ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_rx_sample_discard is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_rx_sample_discard_in ; - po_reg : out t_reg_rx_sample_discard_out - ); -end entity msk_top_regs_rx_sample_discard; - -architecture rtl of msk_top_regs_rx_sample_discard is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_rx_sample_discard : std_logic_vector(8-1 downto 0); -- - field_reg_rx_nco_discard : std_logic_vector(8-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(7 downto 0) := field_reg_rx_sample_discard; -- - v_data_out(15 downto 8) := field_reg_rx_nco_discard; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_rx_sample_discard : std_logic_vector(8-1 downto 0) - := std_logic_vector(to_signed(0,8)); -- - signal field_reg_rx_nco_discard : std_logic_vector(8-1 downto 0) - := std_logic_vector(to_signed(0,8)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_rx_sample_discard, -- - field_reg_rx_nco_discard -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - rx_sample_discard_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_rx_sample_discard <= std_logic_vector(to_signed(0,8)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_rx_sample_discard <= pi_decoder_data(7 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.rx_sample_discard.data <= field_reg_rx_sample_discard; -- - end block rx_sample_discard_storage; - ------------------------------------------------------------STORAGE - rx_nco_discard_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_rx_nco_discard <= std_logic_vector(to_signed(0,8)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_rx_nco_discard <= pi_decoder_data(15 downto 8); - end if; - end if; - end if; - end process; - -- - po_reg.rx_nco_discard.data <= field_reg_rx_nco_discard; -- - end block rx_nco_discard_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: lpf_config_2 ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_lpf_config_2 is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_lpf_config_2_in ; - po_reg : out t_reg_lpf_config_2_out - ); -end entity msk_top_regs_lpf_config_2; - -architecture rtl of msk_top_regs_lpf_config_2 is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_p_gain : std_logic_vector(24-1 downto 0); -- - field_reg_p_shift : std_logic_vector(8-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(23 downto 0) := field_reg_p_gain; -- - v_data_out(31 downto 24) := field_reg_p_shift; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_p_gain : std_logic_vector(24-1 downto 0) - := std_logic_vector(to_signed(0,24)); -- - signal field_reg_p_shift : std_logic_vector(8-1 downto 0) - := std_logic_vector(to_signed(0,8)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_p_gain, -- - field_reg_p_shift -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - p_gain_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_p_gain <= std_logic_vector(to_signed(0,24)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_p_gain <= pi_decoder_data(23 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.p_gain.data <= field_reg_p_gain; -- - end block p_gain_storage; - ------------------------------------------------------------STORAGE - p_shift_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_p_shift <= std_logic_vector(to_signed(0,8)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_p_shift <= pi_decoder_data(31 downto 24); - end if; - end if; - end if; - end process; - -- - po_reg.p_shift.data <= field_reg_p_shift; -- - end block p_shift_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: observation_data ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_observation_data is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_observation_data_in ; - po_reg : out t_reg_observation_data_out - ); -end entity msk_top_regs_observation_data; - -architecture rtl of msk_top_regs_observation_data is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_data32 : std_logic_vector(32-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(31 downto 0) := field_reg_data32; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_data32 : std_logic_vector(32-1 downto 0) - := std_logic_vector(to_signed(0,32)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_data32 -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - data32_wire : block -- - begin - -- - field_reg_data32 <= pi_reg.data.data(32-1 downto 0); -- - --no signal to read by HW - po_reg.data.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ --- register type: tx_sync_ctrl ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_tx_sync_ctrl is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_tx_sync_ctrl_in ; - po_reg : out t_reg_tx_sync_ctrl_out - ); -end entity msk_top_regs_tx_sync_ctrl; - -architecture rtl of msk_top_regs_tx_sync_ctrl is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_tx_sync_ena : std_logic_vector(1-1 downto 0); -- - field_reg_tx_sync_force : std_logic_vector(1-1 downto 0); -- - field_reg_tx_sync_f1 : std_logic_vector(1-1 downto 0); -- - field_reg_tx_sync_f2 : std_logic_vector(1-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(0 downto 0) := field_reg_tx_sync_ena; -- - v_data_out(1 downto 1) := field_reg_tx_sync_force; -- - v_data_out(2 downto 2) := field_reg_tx_sync_f1; -- - v_data_out(3 downto 3) := field_reg_tx_sync_f2; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_tx_sync_ena : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_tx_sync_force : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_tx_sync_f1 : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- - signal field_reg_tx_sync_f2 : std_logic_vector(1-1 downto 0) - := std_logic_vector(to_signed(0,1)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_tx_sync_ena, -- - field_reg_tx_sync_force, -- - field_reg_tx_sync_f1, -- - field_reg_tx_sync_f2 -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - tx_sync_ena_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_tx_sync_ena <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_tx_sync_ena <= pi_decoder_data(0 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.tx_sync_ena.data <= field_reg_tx_sync_ena; -- - end block tx_sync_ena_storage; - ------------------------------------------------------------STORAGE - tx_sync_force_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_tx_sync_force <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_tx_sync_force <= pi_decoder_data(1 downto 1); - end if; - end if; - end if; - end process; - -- - po_reg.tx_sync_force.data <= field_reg_tx_sync_force; -- - end block tx_sync_force_storage; - ------------------------------------------------------------STORAGE - tx_sync_f1_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_tx_sync_f1 <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_tx_sync_f1 <= pi_decoder_data(2 downto 2); - end if; - end if; - end if; - end process; - -- - po_reg.tx_sync_f1.data <= field_reg_tx_sync_f1; -- - end block tx_sync_f1_storage; - ------------------------------------------------------------STORAGE - tx_sync_f2_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_tx_sync_f2 <= std_logic_vector(to_signed(0,1)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_tx_sync_f2 <= pi_decoder_data(3 downto 3); - end if; - end if; - end if; - end process; - -- - po_reg.tx_sync_f2.data <= field_reg_tx_sync_f2; -- - end block tx_sync_f2_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: tx_sync_cnt ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_tx_sync_cnt is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_tx_sync_cnt_in ; - po_reg : out t_reg_tx_sync_cnt_out - ); -end entity msk_top_regs_tx_sync_cnt; - -architecture rtl of msk_top_regs_tx_sync_cnt is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_tx_sync_cnt : std_logic_vector(24-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(23 downto 0) := field_reg_tx_sync_cnt; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_tx_sync_cnt : std_logic_vector(24-1 downto 0) - := std_logic_vector(to_signed(0,24)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_tx_sync_cnt -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - tx_sync_cnt_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_tx_sync_cnt <= std_logic_vector(to_signed(0,24)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_tx_sync_cnt <= pi_decoder_data(23 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.tx_sync_cnt.data <= field_reg_tx_sync_cnt; -- - end block tx_sync_cnt_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: lowpass_ema_alpha ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_lowpass_ema_alpha is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_lowpass_ema_alpha_in ; - po_reg : out t_reg_lowpass_ema_alpha_out - ); -end entity msk_top_regs_lowpass_ema_alpha; - -architecture rtl of msk_top_regs_lowpass_ema_alpha is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_alpha : std_logic_vector(18-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(17 downto 0) := field_reg_alpha; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_alpha : std_logic_vector(18-1 downto 0) - := std_logic_vector(to_signed(0,18)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_alpha -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------STORAGE - alpha_storage: block - begin - prs_write : process(pi_clock) - begin - if rising_edge(pi_clock) then - if pi_reset = '1' then - field_reg_alpha <= std_logic_vector(to_signed(0,18)); - else - -- HW -- - -- SW -- - if pi_decoder_wr_stb = '1' then - field_reg_alpha <= pi_decoder_data(17 downto 0); - end if; - end if; - end if; - end process; - -- - po_reg.alpha.data <= field_reg_alpha; -- - end block alpha_storage; - ---------------------------------------------------------- -end rtl; ------------------------------------------------ --- register type: rx_power ------------------------------------------------ -library ieee; -use ieee.std_logic_1164.all; -use ieee.numeric_std.all; - -library desyrdl; -use desyrdl.common.all; - -use work.pkg_msk_top_regs.all; - -entity msk_top_regs_rx_power is - port ( - pi_clock : in std_logic; - pi_reset : in std_logic; - -- to/from adapter - pi_decoder_rd_stb : in std_logic; - pi_decoder_wr_stb : in std_logic; - pi_decoder_data : in std_logic_vector(C_DATA_WIDTH-1 downto 0); - po_decoder_data : out std_logic_vector(C_DATA_WIDTH-1 downto 0); - - pi_reg : in t_reg_rx_power_in ; - po_reg : out t_reg_rx_power_out - ); -end entity msk_top_regs_rx_power; - -architecture rtl of msk_top_regs_rx_power is - - -- assign slices of data_out for each field, but force the rest to constant zeros - function fun_set_data_out ( -- - field_reg_rx_power : std_logic_vector(23-1 downto 0)) -- - return std_logic_vector is - variable v_data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0); - begin - v_data_out := (others => '0'); - -- - v_data_out(22 downto 0) := field_reg_rx_power; -- - return v_data_out; - end function fun_set_data_out; - - signal data_out : std_logic_vector(C_DATA_WIDTH-1 downto 0) := (others => '0'); - -- - signal field_reg_rx_power : std_logic_vector(23-1 downto 0) - := std_logic_vector(to_signed(0,23)); -- -begin - - data_out <= fun_set_data_out( -- - field_reg_rx_power -- - ); - - -- resize field data out to the register bus width - -- do only if 1 field and signed-- - po_decoder_data <= data_out; -- - ------------------------------------------------------------WIRE - rx_power_wire : block -- - begin - -- - field_reg_rx_power <= pi_reg.rx_power.data(23-1 downto 0); -- - --no signal to read by HW - po_reg.rx_power.dummy <= '0'; -- - end block; -- -end rtl; ------------------------------------------------ - --------------------------------------------------------------------------------- --- Register types in regfiles --------------------------------------------------------------------------------- --- \ No newline at end of file diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index ba71d22..ee86e51 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -62,8 +62,7 @@ USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; USE work.axi4lite_intf_pkg.ALL; ---USE work.msk_top_regs_pkg.ALL; -USE work.pkg_msk_top_regs.ALL; +USE work.msk_top_regs_pkg.ALL; ------------------------------------------------------------------------------------------------------ -- ╔═╗┌┐┌┌┬┐┬┌┬┐┬ ┬ From a56c29b6566ff1f01bfe377743d730c3b8a7b56a Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:22:41 -0700 Subject: [PATCH 12/60] added reg_utils.vhd to /library/msk_top_ip.tcl build script --- library/msk_top_ip.tcl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 3b4c90f..fb9e4c3 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -8,11 +8,11 @@ adi_ip_create msk_top read_vhdl -library "desyrdl" "../rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd" read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" -read_vhdl "../rdl/vhdl/msk_top_regs/pkg_msk_top_regs.vhd" +read_vhdl "../rdl/src/reg_utils.vhd" +read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ - "../rdl/vhdl/msk_top_regs/msk_top_regs_decoder_axi4l.vhd" \ "../rdl/vhdl/msk_top_regs/msk_top_regs.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ From 0550e64185b44b913042acd569c1fe24a8992791 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:23:37 -0700 Subject: [PATCH 13/60] removed desyrdl package from /library/msk_top_ip.tcl build script --- library/msk_top_ip.tcl | 1 - 1 file changed, 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index fb9e4c3..1e0804a 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -6,7 +6,6 @@ source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl adi_ip_create msk_top -read_vhdl -library "desyrdl" "../rdl/vhdl/desyrdl/pkg_desyrdl_common.vhd" read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" read_vhdl "../rdl/src/reg_utils.vhd" read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" From 5266d125f202be36fe753917490f50b46ceeea5d Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:30:08 -0700 Subject: [PATCH 14/60] changed path from rdl/vhdl/msk_top_regs/ to rdl/outputs/rtl --- library/msk_top_ip.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 1e0804a..cf83f3f 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -12,7 +12,7 @@ read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ - "../rdl/vhdl/msk_top_regs/msk_top_regs.vhd" \ + "../rdl/outputs/msk_top_regs/msk_top_regs.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ "../lowpass_ema/src/lowpass_ema.vhd" \ From e3c30b9a36e583b6cf386faec4cc24e7de73a85e Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:38:30 -0700 Subject: [PATCH 15/60] cast the wrong spell but fixed it to /rdl/outputs/rtl/msk_top_regs.vhd --- library/msk_top_ip.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index cf83f3f..356db58 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -12,7 +12,7 @@ read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ - "../rdl/outputs/msk_top_regs/msk_top_regs.vhd" \ + "../rdl/outputs/rtl/msk_top_regs.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ "../lowpass_ema/src/lowpass_ema.vhd" \ From cfe0a8010a03679138a23e0884658007236a00c9 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:45:26 -0700 Subject: [PATCH 16/60] vhdl2008 added to reg_utils.vhd to resolve errors --- library/msk_top_ip.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 356db58..d249204 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -7,7 +7,7 @@ source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl adi_ip_create msk_top read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" -read_vhdl "../rdl/src/reg_utils.vhd" +read_vhdl -vhdl2008 "../rdl/src/reg_utils.vhd" read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] From d821407a6950d658a36196e52729e0848c46ea41 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 18:54:16 -0700 Subject: [PATCH 17/60] vhdl2008 added to msk_top_regs.vhd. Should be the last one? --- library/msk_top_ip.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index d249204..055ac37 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -9,10 +9,10 @@ adi_ip_create msk_top read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" read_vhdl -vhdl2008 "../rdl/src/reg_utils.vhd" read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" +read_vhdl -vhdl2008 "../rdl/outputs/rtl/msk_top_regs.vhd" #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ - "../rdl/outputs/rtl/msk_top_regs.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ "../lowpass_ema/src/lowpass_ema.vhd" \ From 86943dddab281fc975662a4ad98ff8863a2f8748 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 27 Oct 2025 19:10:56 -0700 Subject: [PATCH 18/60] added cdc_resync.vhd pulse_detect.vhd and data_capture.vhd to add ip files list in librar/msk_top_ip.tcl --- library/msk_top_ip.tcl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 055ac37..d2a85db 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -19,6 +19,9 @@ adi_ip_files msk_top [list \ "../power_detector/src/power_detector.vhd" \ "../msk_demodulator/src/msk_demodulator.vhd" \ "../msk_modulator/src/msk_modulator.vhd" \ + "../src/cdc_resync.vhd" \ + "../src/pulse_detect.vhd" \ + "../src/data_capture.vhd" \ "../src/msk_top.vhd" \ "../src/msk_top_csr.vhd" \ "../src/axis_dma_adapter.vhd" \ From dc22efddbbbc1d1a3c5b3c0c5c450ebb235a3514 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Wed, 29 Oct 2025 00:55:10 -0600 Subject: [PATCH 19/60] Update regmap in README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d941e89..4fd5ff4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The following ORI library components are used as submodules to this repository: 7. [Exponential Moving Average Filter](https://github.com/OpenResearchInstitute/lowpass_ema) ## Building -In oder to build the FPGA bitstream, you first need to install Vivado. Recommended version is 2022.2. In this documentation and in the `Makefile`, the Vivado installation path is assumed to be `/opt/Xilinx/Vivado`. If it is in another directory, change the path in the steps below (for example, to `/tools/Xilinx/Vivado`) or create a symbolic link in `/opt` pointing to the actual installation directory. For example, +In order to build the FPGA bitstream, you first need to install Vivado. Recommended version is 2022.2. In this documentation and in the `Makefile`, the Vivado installation path is assumed to be `/opt/Xilinx/Vivado`. If it is in another directory, change the path in the steps below (for example, to `/tools/Xilinx/Vivado`) or create a symbolic link in `/opt` pointing to the actual installation directory. For example, ``` sudo ln -s /tools/Xilinx /opt/Xilinx ``` @@ -130,6 +130,8 @@ sys 39m46.236s | 0x84 |lowpass_ema_alpha1| Exponential Moving Average Alpha | | 0x88 |lowpass_ema_alpha2| Exponential Moving Average Alpha | | 0x8C | rx_power | Receive Power | +| 0x90 |tx_async_fifo_rd_wr_ptr| Tx async FIFO read and write pointers | +| 0x94 |rx_async_fifo_rd_wr_ptr| Rx async FIFO read and write pointers | See [MSK Top Regs](rdl/msk_top_regs.pdf) for detailed register definitions. From e0dd8892a62e68b2a2bf4aff97987d6659e25def Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Tue, 4 Nov 2025 11:47:28 -0700 Subject: [PATCH 20/60] rdl: move away from external registers to a write to capture model --- rdl/outputs/c-header/msk_top_regs.h | 63 +- rdl/outputs/docs/msk_top_regs.md | 92 +- rdl/outputs/docs/msk_top_regs.pdf | Bin 114122 -> 113978 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 310 +-- .../python/msk_top_regs/sim/msk_top_regs.py | 44 +- .../msk_top_regs/tests/test_msk_top_regs.py | 1830 ++++++++++++++--- .../tests/test_sim_msk_top_regs.py | 1162 ++++++++++- rdl/outputs/rtl/msk_top_regs.vhd | 845 ++++++-- rdl/outputs/rtl/msk_top_regs_pkg.vhd | 313 ++- rdl/src/msk_top_regs.rdl | 207 +- sim/msk_test.py | 8 + src/msk_top_csr.vhd | 92 +- 12 files changed, 3902 insertions(+), 1064 deletions(-) diff --git a/rdl/outputs/c-header/msk_top_regs.h b/rdl/outputs/c-header/msk_top_regs.h index accc8fb..58f9611 100644 --- a/rdl/outputs/c-header/msk_top_regs.h +++ b/rdl/outputs/c-header/msk_top_regs.h @@ -78,15 +78,16 @@ extern "C" { #define MSK_TOP_REGS__MSK_STAT_0__TX_AXIS_VALID_reset 0x0 // Reg - msk_top_regs::msk_stat_1 -#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bm 0xffffffff -#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bp 0 -#define MSK_TOP_REGS__MSK_STAT_1__TX_BIT_COUNTER_bw 32 +#define MSK_TOP_REGS__MSK_STAT_1__DATA_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_1__DATA_bp 0 +#define MSK_TOP_REGS__MSK_STAT_1__DATA_bw 32 +#define MSK_TOP_REGS__MSK_STAT_1__DATA_reset 0x0 // Reg - msk_top_regs::msk_stat_2 -#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bm 0xffffffff -#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bp 0 -#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_bw 32 -#define MSK_TOP_REGS__MSK_STAT_2__TX_ENA_COUNTER_reset 0x0 +#define MSK_TOP_REGS__MSK_STAT_2__DATA_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_2__DATA_bp 0 +#define MSK_TOP_REGS__MSK_STAT_2__DATA_bw 32 +#define MSK_TOP_REGS__MSK_STAT_2__DATA_reset 0x0 // Reg - msk_top_regs::config_nco_fw_desc_c4924cc6_name_0c494469 #define MSK_TOP_REGS__CONFIG_NCO_FW_DESC_C4924CC6_NAME_0C494469__CONFIG_DATA_bm 0xffffffff @@ -203,34 +204,34 @@ extern "C" { #define MSK_TOP_REGS__CONFIG_PRBS_ERRMASK__CONFIG_DATA_reset 0x0 // Reg - msk_top_regs::stat_32_bits -#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bm 0xffffffff -#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bp 0 -#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_bw 32 -#define MSK_TOP_REGS__STAT_32_BITS__STATUS_DATA_reset 0x0 +#define MSK_TOP_REGS__STAT_32_BITS__DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_BITS__DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_BITS__DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_BITS__DATA_reset 0x0 // Reg - msk_top_regs::stat_32_errs -#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bm 0xffffffff -#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bp 0 -#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_bw 32 -#define MSK_TOP_REGS__STAT_32_ERRS__STATUS_DATA_reset 0x0 +#define MSK_TOP_REGS__STAT_32_ERRS__DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_ERRS__DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_ERRS__DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_ERRS__DATA_reset 0x0 // Reg - msk_top_regs::stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670 -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bm 0xffffffff -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bp 0 -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_bw 32 -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__STATUS_DATA_reset 0x0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_8CEBC7DC_NAME_F20C6670__DATA_reset 0x0 // Reg - msk_top_regs::stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bm 0xffffffff -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bp 0 -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_bw 32 -#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__STATUS_DATA_reset 0x0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__DATA_bm 0xffffffff +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__DATA_bp 0 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__DATA_bw 32 +#define MSK_TOP_REGS__STAT_32_LPF_ACC_DESC_DEA6BD99_NAME_758FD0CE__DATA_reset 0x0 // Reg - msk_top_regs::msk_stat_3 -#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bm 0xffffffff -#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bp 0 -#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_bw 32 -#define MSK_TOP_REGS__MSK_STAT_3__XFER_COUNT_reset 0x0 +#define MSK_TOP_REGS__MSK_STAT_3__DATA_bm 0xffffffff +#define MSK_TOP_REGS__MSK_STAT_3__DATA_bp 0 +#define MSK_TOP_REGS__MSK_STAT_3__DATA_bw 32 +#define MSK_TOP_REGS__MSK_STAT_3__DATA_reset 0x0 // Reg - msk_top_regs::rx_sample_discard #define MSK_TOP_REGS__RX_SAMPLE_DISCARD__RX_SAMPLE_DISCARD_bm 0xff @@ -307,10 +308,10 @@ extern "C" { #define MSK_TOP_REGS__LOWPASS_EMA_ALPHA__ALPHA_reset 0x0 // Reg - msk_top_regs::rx_power -#define MSK_TOP_REGS__RX_POWER__RX_POWER_bm 0x7fffff -#define MSK_TOP_REGS__RX_POWER__RX_POWER_bp 0 -#define MSK_TOP_REGS__RX_POWER__RX_POWER_bw 23 -#define MSK_TOP_REGS__RX_POWER__RX_POWER_reset 0x0 +#define MSK_TOP_REGS__RX_POWER__DATA_bm 0x7fffff +#define MSK_TOP_REGS__RX_POWER__DATA_bp 0 +#define MSK_TOP_REGS__RX_POWER__DATA_bw 23 +#define MSK_TOP_REGS__RX_POWER__DATA_reset 0x0 // Reg - msk_top_regs::observation_data_data_cf6acbd7_name_aa4ec676 #define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bm 0xffffffff diff --git a/rdl/outputs/docs/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md index e724aaf..b1db448 100644 --- a/rdl/outputs/docs/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -194,11 +194,11 @@ Don't override. Generated from: msk_top_regs

Modem status data

-|Bits| Identifier | Access |Reset| Name | -|----|--------------|--------|-----|------------| -|31:0|tx_bit_counter|r, ruser| — |Tx Bit Count| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|------------| +|31:0| data | rw | 0x0 |Tx Bit Count| -#### tx_bit_counter field +#### data field

Count of data requests made by modem

@@ -210,11 +210,11 @@ Don't override. Generated from: msk_top_regs

Modem status data

-|Bits| Identifier | Access |Reset| Name | -|----|--------------|--------|-----|---------------| -|31:0|tx_ena_counter|r, ruser| 0x0 |Tx Enable Count| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|---------------| +|31:0| data | rw | 0x0 |Tx Enable Count| -#### tx_ena_counter field +#### data field

Number of clocks on which Tx Enable is active

@@ -483,11 +483,11 @@ N > 0 : Auto sync after N errors

PRBS Bits Received

-|Bits| Identifier|Access|Reset| Name | -|----|-----------|------|-----|------------------| -|31:0|status_data| r | 0x0 |PRBS Bits Received| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|------------------| +|31:0| data | rw | 0x0 |PRBS Bits Received| -#### status_data field +#### data field

Number of bits received by the PRBS monitor since last BER can be calculated as the ratio of received bits to errored-bits

@@ -500,11 +500,11 @@ BER can be calculated as the ratio of received bits to errored-bits

PRBS Bit Errors

-|Bits| Identifier|Access|Reset| Name | -|----|-----------|------|-----|---------------| -|31:0|status_data| r | 0x0 |PRBS Bit Errors| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|---------------| +|31:0| data | rw | 0x0 |PRBS Bit Errors| -#### status_data field +#### data field

Number of errored-bits received by the PRBS monitor since last sync BER can be calculated as the ratio of received bits to errored-bits

@@ -517,11 +517,11 @@ BER can be calculated as the ratio of received bits to errored-bits

Value of the F1 PI Controller Accumulator

-|Bits| Identifier|Access|Reset| Name | -|----|-----------|------|-----|-------------------------------| -|31:0|status_data| r | 0x0 |PI Controller Accumulator Value| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|-------------------------------| +|31:0| data | rw | 0x0 |PI Controller Accumulator Value| -#### status_data field +#### data field

PI Controller Accumulator Value

@@ -533,11 +533,11 @@ BER can be calculated as the ratio of received bits to errored-bits

Value of the F2 PI Controller Accumulator

-|Bits| Identifier|Access|Reset| Name | -|----|-----------|------|-----|-------------------------------| -|31:0|status_data| r | 0x0 |PI Controller Accumulator Value| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|-------------------------------| +|31:0| data | rw | 0x0 |PI Controller Accumulator Value| -#### status_data field +#### data field

PI Controller Accumulator Value

@@ -551,9 +551,9 @@ BER can be calculated as the ratio of received bits to errored-bits

|Bits|Identifier|Access|Reset| Name | |----|----------|------|-----|----------------| -|31:0|xfer_count| r | 0x0 |S_AXIS Transfers| +|31:0| data | rw | 0x0 |S_AXIS Transfers| -#### xfer_count field +#### data field

Number completed S_AXIS transfers

@@ -607,9 +607,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Frequency offet applied to the F1 NCO

-|Bits|Identifier| Access |Reset| Name | -|----|----------|--------|-----|-----------------------| -|31:0| data |r, ruser| 0x0 |F1 NCO Frequency Adjust| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|-----------------------| +|31:0| data | rw | 0x0 |F1 NCO Frequency Adjust| #### data field @@ -623,9 +623,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Frequency offet applied to the F2 NCO

-|Bits|Identifier| Access |Reset| Name | -|----|----------|--------|-----|-----------------------| -|31:0| data |r, ruser| 0x0 |F2 NCO Frequency Adjust| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|-----------------------| +|31:0| data | rw | 0x0 |F2 NCO Frequency Adjust| #### data field @@ -639,9 +639,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Error value of the F1 Costas loop after each active bit period

-|Bits|Identifier| Access |Reset| Name | -|----|----------|--------|-----|--------------| -|31:0| data |r, ruser| 0x0 |F1 Error Value| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|--------------| +|31:0| data | rw | 0x0 |F1 Error Value| #### data field @@ -655,9 +655,9 @@ BER can be calculated as the ratio of received bits to errored-bits

Error value of the F2 Costas loop after each active bit period

-|Bits|Identifier| Access |Reset| Name | -|----|----------|--------|-----|--------------| -|31:0| data |r, ruser| 0x0 |F2 Error Value| +|Bits|Identifier|Access|Reset| Name | +|----|----------|------|-----|--------------| +|31:0| data | rw | 0x0 |F2 Error Value| #### data field @@ -762,9 +762,9 @@ signal should be sent after PTT is asserted.

|Bits|Identifier|Access|Reset| Name | |----|----------|------|-----|-------------| -|22:0| rx_power | r | 0x0 |Receive Power| +|22:0| data | rw | 0x0 |Receive Power| -#### rx_power field +#### data field

Value that represent the RMS power of the incoming I;

@@ -774,9 +774,9 @@ signal should be sent after PTT is asserted.

- Base Offset: 0x90 - Size: 0x4 -|Bits|Identifier| Access |Reset|Name| -|----|----------|--------|-----|----| -|31:0| data |r, ruser| 0x0 | — | +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field @@ -789,9 +789,9 @@ Bits 15:00 -> read pointer (12-bits)

- Base Offset: 0x94 - Size: 0x4 -|Bits|Identifier| Access |Reset|Name| -|----|----------|--------|-----|----| -|31:0| data |r, ruser| 0x0 | — | +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index 6f013ede1561600e1f281f435ff699f1ec3f4a95..5319bc354e7c0dd86cb4e25489c4debd10c0b6a7 100644 GIT binary patch delta 14609 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

c?V1$i^|xeuwt+KhSV+K>XCESmX7+bLaEsyXrOX zD@lH=Qi8Vpv`c3Y^s)NeVlO63vu^rWU&j@IYk{l#C$?#AX%aK)k zr`=BO#&u_u$elnBqVC1sNPLh(E8z1Z6~%h;NhgnOQvZLqy-)_h41?T=4Z^_BVi`Dq zY3*Xyh4r@ z8?Yz`G`E1A$7M8zR!lXyok=y*>ILv7j%|#{s9sUG(umJhbeA|GX+82ffYOYX-54h& zW>Q?~sL8vK_G=PVjc~v|&uIm7fj_f~54jGrN~G^w;XW|~)lj$+7R`H)@tWnp6Efcf)BOhFvx{{bM~MGgP} diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py index e9597a8..0ec486a 100644 --- a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -76,7 +76,7 @@ -class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -108,7 +108,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -130,7 +130,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -229,7 +229,7 @@ def rdl_name(self) -> str: -class msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -261,7 +261,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -283,7 +283,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -294,7 +294,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls = msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls( + self.__data:msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls = msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -325,7 +325,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls: + def data(self) -> msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls: """ Property to access data field of the register @@ -361,7 +361,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_0x0x1075e913_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls: return super().get_child_by_system_rdl_name(name) @@ -382,7 +382,7 @@ def rdl_name(self) -> str: -class msk_top_regs_rx_power_rx_power_cls(FieldAsyncReadOnly): +class msk_top_regs_rx_power_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -420,7 +420,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_rx_power_cls(RegAsyncReadOnly): +class msk_top_regs_rx_power_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -438,7 +438,7 @@ class msk_top_regs_rx_power_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__rx_power'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -446,7 +446,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -457,7 +457,7 @@ def __init__(self, # build the field attributes - self.__rx_power:msk_top_regs_rx_power_rx_power_cls = msk_top_regs_rx_power_rx_power_cls( + self.__data:msk_top_regs_rx_power_data_cls = msk_top_regs_rx_power_data_cls( parent_register=self, size_props=FieldSizeProps( width=23, @@ -468,8 +468,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.rx_power', - inst_name='rx_power', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -477,7 +477,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.rx_power + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -488,9 +488,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def rx_power(self) -> msk_top_regs_rx_power_rx_power_cls: + def data(self) -> msk_top_regs_rx_power_data_cls: """ - Property to access rx_power field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -505,7 +505,7 @@ def rx_power(self) -> msk_top_regs_rx_power_rx_power_cls: | |

Value that represent the RMS power of the incoming I;

| +--------------+-------------------------------------------------------------------------+ """ - return self.__rx_power + return self.__data @property @@ -517,7 +517,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'rx_power':'rx_power', + return {'data':'data', } @@ -527,7 +527,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_rx_power_rx_power_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_rx_power_data_cls: return super().get_child_by_system_rdl_name(name) @@ -720,7 +720,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -758,7 +758,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -795,7 +795,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -826,7 +826,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls: """ Property to access alpha field of the register @@ -865,7 +865,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1075e9a9_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls: return super().get_child_by_system_rdl_name(name) @@ -1484,7 +1484,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1523,7 +1523,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1550,7 +1550,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -1656,7 +1656,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1695,7 +1695,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1722,7 +1722,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -1828,7 +1828,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1866,7 +1866,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1892,7 +1892,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -1997,7 +1997,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadOnly): +class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -2035,7 +2035,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls(RegAsyncReadOnly): +class msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -2061,7 +2061,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -2672,7 +2672,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_3_xfer_count_cls(FieldAsyncReadOnly): +class msk_top_regs_msk_stat_3_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -2710,7 +2710,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_3_cls(RegAsyncReadOnly): +class msk_top_regs_msk_stat_3_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -2728,7 +2728,7 @@ class msk_top_regs_msk_stat_3_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__xfer_count'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -2736,7 +2736,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -2747,7 +2747,7 @@ def __init__(self, # build the field attributes - self.__xfer_count:msk_top_regs_msk_stat_3_xfer_count_cls = msk_top_regs_msk_stat_3_xfer_count_cls( + self.__data:msk_top_regs_msk_stat_3_data_cls = msk_top_regs_msk_stat_3_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2758,8 +2758,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.xfer_count', - inst_name='xfer_count', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -2767,7 +2767,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.xfer_count + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -2778,9 +2778,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def xfer_count(self) -> msk_top_regs_msk_stat_3_xfer_count_cls: + def data(self) -> msk_top_regs_msk_stat_3_data_cls: """ - Property to access xfer_count field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -2795,7 +2795,7 @@ def xfer_count(self) -> msk_top_regs_msk_stat_3_xfer_count_cls: | |

Number completed S_AXIS transfers

| +--------------+-------------------------------------------------------------------------+ """ - return self.__xfer_count + return self.__data @property @@ -2807,7 +2807,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'xfer_count':'xfer_count', + return {'data':'data', } @@ -2817,7 +2817,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_3_xfer_count_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_3_data_cls: return super().get_child_by_system_rdl_name(name) @@ -2841,7 +2841,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_status_data_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -2879,7 +2879,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls(RegAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -2897,7 +2897,7 @@ class msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls(RegAsyncReadO +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__status_data'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -2905,7 +2905,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -2916,7 +2916,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_cls = msk_top_regs_stat_32_lpf_acc_status_data_cls( + self.__data:msk_top_regs_stat_32_lpf_acc_data_cls = msk_top_regs_stat_32_lpf_acc_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2927,8 +2927,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.status_data', - inst_name='status_data', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -2936,7 +2936,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.status_data + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -2947,9 +2947,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_cls: + def data(self) -> msk_top_regs_stat_32_lpf_acc_data_cls: """ - Property to access status_data field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -2964,7 +2964,7 @@ def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_cls: | |

PI Controller Accumulator Value

| +--------------+-------------------------------------------------------------------------+ """ - return self.__status_data + return self.__data @property @@ -2976,7 +2976,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'status_data':'status_data', + return {'data':'data', } @@ -2986,7 +2986,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_cls: return super().get_child_by_system_rdl_name(name) @@ -3010,7 +3010,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -3048,7 +3048,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls(RegAsyncReadOnly): +class msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -3066,7 +3066,7 @@ class msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls(RegAsyncReadO +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__status_data'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -3074,7 +3074,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -3085,7 +3085,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls = msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls( + self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -3096,8 +3096,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.status_data', - inst_name='status_data', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -3105,7 +3105,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.status_data + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -3116,9 +3116,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls: + def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls: """ - Property to access status_data field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -3133,7 +3133,7 @@ def status_data(self) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_c | |

PI Controller Accumulator Value

| +--------------+-------------------------------------------------------------------------+ """ - return self.__status_data + return self.__data @property @@ -3145,7 +3145,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'status_data':'status_data', + return {'data':'data', } @@ -3155,7 +3155,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_status_data_0x0x1073cd31_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls: return super().get_child_by_system_rdl_name(name) @@ -3179,7 +3179,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_errs_status_data_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_errs_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -3219,7 +3219,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_errs_cls(RegAsyncReadOnly): +class msk_top_regs_stat_32_errs_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -3237,7 +3237,7 @@ class msk_top_regs_stat_32_errs_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__status_data'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -3245,7 +3245,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -3256,7 +3256,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_errs_status_data_cls = msk_top_regs_stat_32_errs_status_data_cls( + self.__data:msk_top_regs_stat_32_errs_data_cls = msk_top_regs_stat_32_errs_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -3267,8 +3267,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.status_data', - inst_name='status_data', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -3276,7 +3276,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.status_data + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -3287,9 +3287,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_errs_status_data_cls: + def data(self) -> msk_top_regs_stat_32_errs_data_cls: """ - Property to access status_data field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -3306,7 +3306,7 @@ def status_data(self) -> msk_top_regs_stat_32_errs_status_data_cls: | | errored-bits

| +--------------+-------------------------------------------------------------------------+ """ - return self.__status_data + return self.__data @property @@ -3318,7 +3318,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'status_data':'status_data', + return {'data':'data', } @@ -3328,7 +3328,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_errs_status_data_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_errs_data_cls: return super().get_child_by_system_rdl_name(name) @@ -3352,7 +3352,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_bits_status_data_cls(FieldAsyncReadOnly): +class msk_top_regs_stat_32_bits_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -3391,7 +3391,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_bits_cls(RegAsyncReadOnly): +class msk_top_regs_stat_32_bits_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -3409,7 +3409,7 @@ class msk_top_regs_stat_32_bits_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__status_data'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -3417,7 +3417,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -3428,7 +3428,7 @@ def __init__(self, # build the field attributes - self.__status_data:msk_top_regs_stat_32_bits_status_data_cls = msk_top_regs_stat_32_bits_status_data_cls( + self.__data:msk_top_regs_stat_32_bits_data_cls = msk_top_regs_stat_32_bits_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -3439,8 +3439,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.status_data', - inst_name='status_data', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -3448,7 +3448,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.status_data + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -3459,9 +3459,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def status_data(self) -> msk_top_regs_stat_32_bits_status_data_cls: + def data(self) -> msk_top_regs_stat_32_bits_data_cls: """ - Property to access status_data field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -3477,7 +3477,7 @@ def status_data(self) -> msk_top_regs_stat_32_bits_status_data_cls: | | be calculated as the ratio of received bits to errored-bits

| +--------------+-------------------------------------------------------------------------+ """ - return self.__status_data + return self.__data @property @@ -3489,7 +3489,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'status_data':'status_data', + return {'data':'data', } @@ -3499,7 +3499,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_bits_status_data_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_bits_data_cls: return super().get_child_by_system_rdl_name(name) @@ -4760,7 +4760,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x107468c8_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x105dda63_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -4836,7 +4836,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x107468c8_cls = msk_top_regs_data_width_data_width_0x0x107468c8_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x105dda63_cls = msk_top_regs_data_width_data_width_0x0x105dda63_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -4867,7 +4867,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x107468c8_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x105dda63_cls: """ Property to access data_width field of the register @@ -4906,7 +4906,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x107468c8_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x105dda63_cls: return super().get_child_by_system_rdl_name(name) @@ -5752,7 +5752,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5829,7 +5829,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls = msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5860,7 +5860,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls: """ Property to access config_data field of the register @@ -5901,7 +5901,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1074bb14_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls: return super().get_child_by_system_rdl_name(name) @@ -5925,7 +5925,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6002,7 +6002,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls = msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6033,7 +6033,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls: """ Property to access config_data field of the register @@ -6074,7 +6074,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x107566c9_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls: return super().get_child_by_system_rdl_name(name) @@ -6098,7 +6098,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6175,7 +6175,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls = msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6206,7 +6206,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls: """ Property to access config_data field of the register @@ -6247,7 +6247,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10756468_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls: return super().get_child_by_system_rdl_name(name) @@ -6271,7 +6271,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6348,7 +6348,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls = msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6379,7 +6379,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls: """ Property to access config_data field of the register @@ -6420,7 +6420,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1075c880_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls: return super().get_child_by_system_rdl_name(name) @@ -6444,7 +6444,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_2_tx_ena_counter_cls(FieldAsyncReadOnly): +class msk_top_regs_msk_stat_2_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6482,7 +6482,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_2_cls(RegAsyncReadOnly): +class msk_top_regs_msk_stat_2_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -6500,7 +6500,7 @@ class msk_top_regs_msk_stat_2_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__tx_ena_counter'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -6508,7 +6508,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -6519,7 +6519,7 @@ def __init__(self, # build the field attributes - self.__tx_ena_counter:msk_top_regs_msk_stat_2_tx_ena_counter_cls = msk_top_regs_msk_stat_2_tx_ena_counter_cls( + self.__data:msk_top_regs_msk_stat_2_data_cls = msk_top_regs_msk_stat_2_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6530,8 +6530,8 @@ def __init__(self, misc_props=FieldMiscProps( default=0, is_volatile=True), - logger_handle=logger_handle+'.tx_ena_counter', - inst_name='tx_ena_counter', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -6539,7 +6539,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.tx_ena_counter + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -6550,9 +6550,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def tx_ena_counter(self) -> msk_top_regs_msk_stat_2_tx_ena_counter_cls: + def data(self) -> msk_top_regs_msk_stat_2_data_cls: """ - Property to access tx_ena_counter field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -6567,7 +6567,7 @@ def tx_ena_counter(self) -> msk_top_regs_msk_stat_2_tx_ena_counter_cls: | |

Number of clocks on which Tx Enable is active

| +--------------+-------------------------------------------------------------------------+ """ - return self.__tx_ena_counter + return self.__data @property @@ -6579,7 +6579,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'tx_ena_counter':'tx_ena_counter', + return {'data':'data', } @@ -6589,7 +6589,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_2_tx_ena_counter_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_2_data_cls: return super().get_child_by_system_rdl_name(name) @@ -6613,7 +6613,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_1_tx_bit_counter_cls(FieldAsyncReadOnly): +class msk_top_regs_msk_stat_1_data_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6651,7 +6651,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_msk_stat_1_cls(RegAsyncReadOnly): +class msk_top_regs_msk_stat_1_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -6669,7 +6669,7 @@ class msk_top_regs_msk_stat_1_cls(RegAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__tx_bit_counter'] + __slots__ : list[str] = ['__data'] def __init__(self, address: int, @@ -6677,7 +6677,7 @@ def __init__(self, accesswidth: int, logger_handle: str, inst_name: str, - parent: Union[AsyncAddressMap,AsyncRegFile,ReadableAsyncMemory]): + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): super().__init__(address=address, width=width, @@ -6688,7 +6688,7 @@ def __init__(self, # build the field attributes - self.__tx_bit_counter:msk_top_regs_msk_stat_1_tx_bit_counter_cls = msk_top_regs_msk_stat_1_tx_bit_counter_cls( + self.__data:msk_top_regs_msk_stat_1_data_cls = msk_top_regs_msk_stat_1_data_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6697,10 +6697,10 @@ def __init__(self, low=0, high=31), misc_props=FieldMiscProps( - default=None, + default=0, is_volatile=True), - logger_handle=logger_handle+'.tx_bit_counter', - inst_name='tx_bit_counter', + logger_handle=logger_handle+'.data', + inst_name='data', field_type=int) @property @@ -6708,7 +6708,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field """ generator that produces has all the fields within the register """ - yield self.tx_bit_counter + yield self.data # Empty generator in case there are no children of this type if False: yield @@ -6719,9 +6719,9 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def tx_bit_counter(self) -> msk_top_regs_msk_stat_1_tx_bit_counter_cls: + def data(self) -> msk_top_regs_msk_stat_1_data_cls: """ - Property to access tx_bit_counter field of the register + Property to access data field of the register +--------------+-------------------------------------------------------------------------+ | SystemRDL | Value | @@ -6736,7 +6736,7 @@ def tx_bit_counter(self) -> msk_top_regs_msk_stat_1_tx_bit_counter_cls: | |

Count of data requests made by modem

| +--------------+-------------------------------------------------------------------------+ """ - return self.__tx_bit_counter + return self.__data @property @@ -6748,7 +6748,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'tx_bit_counter':'tx_bit_counter', + return {'data':'data', } @@ -6758,7 +6758,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_1_tx_bit_counter_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_msk_stat_1_data_cls: return super().get_child_by_system_rdl_name(name) @@ -8638,7 +8638,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls = msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls = msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls( address=self.address+132, accesswidth=32, width=32, @@ -9340,7 +9340,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls: """ Property to access lowpass_ema_alpha1 @@ -9586,7 +9586,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls: ... @overload @@ -9606,7 +9606,7 @@ def get_child_by_system_rdl_name(self, name: Literal["rx_async_fifo_rd_wr_ptr"]) @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1075e9f4_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls, msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls, msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) diff --git a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py index 0b442a7..f7af222 100644 --- a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py @@ -42,12 +42,12 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='demod_sync_lock'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='tx_enable'),FieldDefinition(high=2, low=2, msb=2, lsb=2, inst_name='rx_enable'),FieldDefinition(high=3, low=3, msb=3, lsb=3, inst_name='tx_axis_valid'), ]), 20 : - Register(width=32, full_inst_name='msk_top_regs.Tx_Bit_Count', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='tx_bit_counter'), + Register(width=32, full_inst_name='msk_top_regs.Tx_Bit_Count', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 24 : - Register(width=32, full_inst_name='msk_top_regs.Tx_Enable_Count', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='tx_ena_counter'), + Register(width=32, full_inst_name='msk_top_regs.Tx_Enable_Count', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 28 : Register(width=32, full_inst_name='msk_top_regs.Fb_FreqWord', readable=True, writable=True, @@ -102,24 +102,24 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='config_data'), ]), 80 : - Register(width=32, full_inst_name='msk_top_regs.PRBS_Bit_Count', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + Register(width=32, full_inst_name='msk_top_regs.PRBS_Bit_Count', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 84 : - Register(width=32, full_inst_name='msk_top_regs.PRBS_Error_Count', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + Register(width=32, full_inst_name='msk_top_regs.PRBS_Error_Count', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 88 : - Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F1', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F1', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 92 : - Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F2', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='status_data'), + Register(width=32, full_inst_name='msk_top_regs.LPF_Accum_F2', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 96 : - Register(width=32, full_inst_name='msk_top_regs.axis_xfer_count', readable=True, writable=False, - fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='xfer_count'), + Register(width=32, full_inst_name='msk_top_regs.axis_xfer_count', readable=True, writable=True, + fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 100 : Register(width=32, full_inst_name='msk_top_regs.Rx_Sample_Discard', readable=True, writable=True, @@ -130,19 +130,19 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe fields=[FieldDefinition(high=23, low=0, msb=23, lsb=0, inst_name='p_gain'),FieldDefinition(high=31, low=24, msb=31, lsb=24, inst_name='p_shift'), ]), 108 : - Register(width=32, full_inst_name='msk_top_regs.f1_nco_adjust', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.f1_nco_adjust', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 112 : - Register(width=32, full_inst_name='msk_top_regs.f2_nco_adjust', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.f2_nco_adjust', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 116 : - Register(width=32, full_inst_name='msk_top_regs.f1_error', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.f1_error', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 120 : - Register(width=32, full_inst_name='msk_top_regs.f2_error', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.f2_error', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 124 : @@ -162,15 +162,15 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe fields=[FieldDefinition(high=17, low=0, msb=17, lsb=0, inst_name='alpha'), ]), 140 : - Register(width=32, full_inst_name='msk_top_regs.rx_power', readable=True, writable=False, - fields=[FieldDefinition(high=22, low=0, msb=22, lsb=0, inst_name='rx_power'), + Register(width=32, full_inst_name='msk_top_regs.rx_power', readable=True, writable=True, + fields=[FieldDefinition(high=22, low=0, msb=22, lsb=0, inst_name='data'), ]), 144 : - Register(width=32, full_inst_name='msk_top_regs.tx_async_fifo_rd_wr_ptr', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.tx_async_fifo_rd_wr_ptr', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), 148 : - Register(width=32, full_inst_name='msk_top_regs.rx_async_fifo_rd_wr_ptr', readable=True, writable=False, + Register(width=32, full_inst_name='msk_top_regs.rx_async_fifo_rd_wr_ptr', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), } diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py index 2b9468e..c76701a 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -212,12 +212,12 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): self.assertEqual(self.dut.MSK_Status.tx_axis_valid.inst_name, 'tx_axis_valid') # type: ignore[union-attr] self.assertEqual(self.dut.MSK_Status.tx_axis_valid.full_inst_name, 'msk_top_regs.MSK_Status.tx_axis_valid') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): - self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.inst_name, 'tx_bit_counter') # type: ignore[union-attr] - self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.full_inst_name, 'msk_top_regs.Tx_Bit_Count.tx_bit_counter') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): - self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.inst_name, 'tx_ena_counter') # type: ignore[union-attr] - self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.full_inst_name, 'msk_top_regs.Tx_Enable_Count.tx_ena_counter') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.data'): + self.assertEqual(self.dut.Tx_Bit_Count.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.data.full_inst_name, 'msk_top_regs.Tx_Bit_Count.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.data'): + self.assertEqual(self.dut.Tx_Enable_Count.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.data.full_inst_name, 'msk_top_regs.Tx_Enable_Count.data') # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): self.assertEqual(self.dut.Fb_FreqWord.config_data.inst_name, 'config_data') # type: ignore[union-attr] self.assertEqual(self.dut.Fb_FreqWord.config_data.full_inst_name, 'msk_top_regs.Fb_FreqWord.config_data') # type: ignore[union-attr] @@ -284,21 +284,21 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.PRBS_Error_Mask.config_data'): self.assertEqual(self.dut.PRBS_Error_Mask.config_data.inst_name, 'config_data') # type: ignore[union-attr] self.assertEqual(self.dut.PRBS_Error_Mask.config_data.full_inst_name, 'msk_top_regs.PRBS_Error_Mask.config_data') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): - self.assertEqual(self.dut.PRBS_Bit_Count.status_data.inst_name, 'status_data') # type: ignore[union-attr] - self.assertEqual(self.dut.PRBS_Bit_Count.status_data.full_inst_name, 'msk_top_regs.PRBS_Bit_Count.status_data') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): - self.assertEqual(self.dut.PRBS_Error_Count.status_data.inst_name, 'status_data') # type: ignore[union-attr] - self.assertEqual(self.dut.PRBS_Error_Count.status_data.full_inst_name, 'msk_top_regs.PRBS_Error_Count.status_data') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): - self.assertEqual(self.dut.LPF_Accum_F1.status_data.inst_name, 'status_data') # type: ignore[union-attr] - self.assertEqual(self.dut.LPF_Accum_F1.status_data.full_inst_name, 'msk_top_regs.LPF_Accum_F1.status_data') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): - self.assertEqual(self.dut.LPF_Accum_F2.status_data.inst_name, 'status_data') # type: ignore[union-attr] - self.assertEqual(self.dut.LPF_Accum_F2.status_data.full_inst_name, 'msk_top_regs.LPF_Accum_F2.status_data') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): - self.assertEqual(self.dut.axis_xfer_count.xfer_count.inst_name, 'xfer_count') # type: ignore[union-attr] - self.assertEqual(self.dut.axis_xfer_count.xfer_count.full_inst_name, 'msk_top_regs.axis_xfer_count.xfer_count') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.data'): + self.assertEqual(self.dut.PRBS_Bit_Count.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.data.full_inst_name, 'msk_top_regs.PRBS_Bit_Count.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.data'): + self.assertEqual(self.dut.PRBS_Error_Count.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.data.full_inst_name, 'msk_top_regs.PRBS_Error_Count.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.data'): + self.assertEqual(self.dut.LPF_Accum_F1.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.data.full_inst_name, 'msk_top_regs.LPF_Accum_F1.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.data'): + self.assertEqual(self.dut.LPF_Accum_F2.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.data.full_inst_name, 'msk_top_regs.LPF_Accum_F2.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.data'): + self.assertEqual(self.dut.axis_xfer_count.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.data.full_inst_name, 'msk_top_regs.axis_xfer_count.data') # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.inst_name, 'rx_sample_discard') # type: ignore[union-attr] self.assertEqual(self.dut.Rx_Sample_Discard.rx_sample_discard.full_inst_name, 'msk_top_regs.Rx_Sample_Discard.rx_sample_discard') # type: ignore[union-attr] @@ -344,9 +344,9 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.lowpass_ema_alpha2.alpha'): self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.inst_name, 'alpha') # type: ignore[union-attr] self.assertEqual(self.dut.lowpass_ema_alpha2.alpha.full_inst_name, 'msk_top_regs.lowpass_ema_alpha2.alpha') # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): - self.assertEqual(self.dut.rx_power.rx_power.inst_name, 'rx_power') # type: ignore[union-attr] - self.assertEqual(self.dut.rx_power.rx_power.full_inst_name, 'msk_top_regs.rx_power.rx_power') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_power.data'): + self.assertEqual(self.dut.rx_power.data.inst_name, 'data') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.data.full_inst_name, 'msk_top_regs.rx_power.data') # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.inst_name, 'data') # type: ignore[union-attr] self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.full_inst_name, 'msk_top_regs.tx_async_fifo_rd_wr_ptr.data') # type: ignore[union-attr] @@ -723,17 +723,17 @@ def test_name_property(self) -> None: - with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.data'): - self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.rdl_name, "Tx Bit Count") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.data.rdl_name, "Tx Bit Count") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.data'): - self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.rdl_name, "Tx Enable Count") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.data.rdl_name, "Tx Enable Count") # type: ignore[union-attr] @@ -891,38 +891,38 @@ def test_name_property(self) -> None: - with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.data'): - self.assertEqual(self.dut.PRBS_Bit_Count.status_data.rdl_name, "PRBS Bits Received") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.data.rdl_name, "PRBS Bits Received") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.data'): - self.assertEqual(self.dut.PRBS_Error_Count.status_data.rdl_name, "PRBS Bit Errors") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.data.rdl_name, "PRBS Bit Errors") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.data'): - self.assertEqual(self.dut.LPF_Accum_F1.status_data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.data'): - self.assertEqual(self.dut.LPF_Accum_F2.status_data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.data.rdl_name, "PI Controller Accumulator Value") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.data'): - self.assertEqual(self.dut.axis_xfer_count.xfer_count.rdl_name, "S_AXIS Transfers") # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.data.rdl_name, "S_AXIS Transfers") # type: ignore[union-attr] @@ -1031,10 +1031,10 @@ def test_name_property(self) -> None: - with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + with self.subTest(msg='node: msk_top_regs.rx_power.data'): - self.assertEqual(self.dut.rx_power.rx_power.rdl_name, "Receive Power") # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.data.rdl_name, "Receive Power") # type: ignore[union-attr] @@ -1422,17 +1422,17 @@ def test_desc(self) -> None: - with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.data'): - self.assertEqual(self.dut.Tx_Bit_Count.tx_bit_counter.rdl_desc, "Count of data requests made by modem") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.data.rdl_desc, "Count of data requests made by modem") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.data'): - self.assertEqual(self.dut.Tx_Enable_Count.tx_ena_counter.rdl_desc, "Number of clocks on which Tx Enable is active") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.data.rdl_desc, "Number of clocks on which Tx Enable is active") # type: ignore[union-attr] @@ -1590,38 +1590,38 @@ def test_desc(self) -> None: - with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.data'): - self.assertEqual(self.dut.PRBS_Bit_Count.status_data.rdl_desc, "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.data.rdl_desc, "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.data'): - self.assertEqual(self.dut.PRBS_Error_Count.status_data.rdl_desc, "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.data.rdl_desc, "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.data'): - self.assertEqual(self.dut.LPF_Accum_F1.status_data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.data'): - self.assertEqual(self.dut.LPF_Accum_F2.status_data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] - with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.data'): - self.assertEqual(self.dut.axis_xfer_count.xfer_count.rdl_desc, "Number completed S_AXIS transfers") # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.data.rdl_desc, "Number completed S_AXIS transfers") # type: ignore[union-attr] @@ -1730,10 +1730,10 @@ def test_desc(self) -> None: - with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + with self.subTest(msg='node: msk_top_regs.rx_power.data'): - self.assertEqual(self.dut.rx_power.rx_power.rdl_desc, "Value that represent the RMS power of the incoming I;") # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.data.rdl_desc, "Value that represent the RMS power of the incoming I;") # type: ignore[union-attr] @@ -2278,9 +2278,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): - # test properties of field: msk_top_regs.Tx_Bit_Count.tx_bit_counter - fut = self.dut.Tx_Bit_Count.tx_bit_counter # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.data'): + # test properties of field: msk_top_regs.Tx_Bit_Count.data + fut = self.dut.Tx_Bit_Count.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2291,12 +2291,12 @@ def test_field_properties(self) -> None: self.assertEqual(fut.inverse_bitmask,0x0) self.assertEqual(fut.max_value,0xFFFFFFFF) - self.assertEqual(fut.default,None) + self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): - # test properties of field: msk_top_regs.Tx_Enable_Count.tx_ena_counter - fut = self.dut.Tx_Enable_Count.tx_ena_counter # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.data'): + # test properties of field: msk_top_regs.Tx_Enable_Count.data + fut = self.dut.Tx_Enable_Count.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2662,9 +2662,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,False) - with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): - # test properties of field: msk_top_regs.PRBS_Bit_Count.status_data - fut = self.dut.PRBS_Bit_Count.status_data # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.data'): + # test properties of field: msk_top_regs.PRBS_Bit_Count.data + fut = self.dut.PRBS_Bit_Count.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2678,9 +2678,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): - # test properties of field: msk_top_regs.PRBS_Error_Count.status_data - fut = self.dut.PRBS_Error_Count.status_data # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.data'): + # test properties of field: msk_top_regs.PRBS_Error_Count.data + fut = self.dut.PRBS_Error_Count.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2694,9 +2694,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): - # test properties of field: msk_top_regs.LPF_Accum_F1.status_data - fut = self.dut.LPF_Accum_F1.status_data # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.data'): + # test properties of field: msk_top_regs.LPF_Accum_F1.data + fut = self.dut.LPF_Accum_F1.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2710,9 +2710,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): - # test properties of field: msk_top_regs.LPF_Accum_F2.status_data - fut = self.dut.LPF_Accum_F2.status_data # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.data'): + # test properties of field: msk_top_regs.LPF_Accum_F2.data + fut = self.dut.LPF_Accum_F2.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2726,9 +2726,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) - with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): - # test properties of field: msk_top_regs.axis_xfer_count.xfer_count - fut = self.dut.axis_xfer_count.xfer_count # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.data'): + # test properties of field: msk_top_regs.axis_xfer_count.data + fut = self.dut.axis_xfer_count.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -2982,9 +2982,9 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,False) - with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): - # test properties of field: msk_top_regs.rx_power.rx_power - fut = self.dut.rx_power.rx_power # type: ignore[union-attr] + with self.subTest(msg='field: msk_top_regs.rx_power.data'): + # test properties of field: msk_top_regs.rx_power.data + fut = self.dut.rx_power.data # type: ignore[union-attr] if not isinstance(fut, Field): raise TypeError('This test relies on node being of type Field') self.assertEqual(fut.lsb,0) @@ -3311,13 +3311,13 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.MSK_Status.tx_axis_valid.udp,{}) - with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count.data'): - self.assertDictEqual(self.dut.Tx_Bit_Count.tx_bit_counter.udp,{}) + self.assertDictEqual(self.dut.Tx_Bit_Count.data.udp,{}) - with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count.data'): - self.assertDictEqual(self.dut.Tx_Enable_Count.tx_ena_counter.udp,{}) + self.assertDictEqual(self.dut.Tx_Enable_Count.data.udp,{}) with self.subTest(msg='register: msk_top_regs.Fb_FreqWord.config_data'): @@ -3407,25 +3407,25 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.PRBS_Error_Mask.config_data.udp,{}) - with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count.status_data'): + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count.data'): - self.assertDictEqual(self.dut.PRBS_Bit_Count.status_data.udp,{}) + self.assertDictEqual(self.dut.PRBS_Bit_Count.data.udp,{}) - with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count.status_data'): + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count.data'): - self.assertDictEqual(self.dut.PRBS_Error_Count.status_data.udp,{}) + self.assertDictEqual(self.dut.PRBS_Error_Count.data.udp,{}) - with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1.status_data'): + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1.data'): - self.assertDictEqual(self.dut.LPF_Accum_F1.status_data.udp,{}) + self.assertDictEqual(self.dut.LPF_Accum_F1.data.udp,{}) - with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2.status_data'): + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2.data'): - self.assertDictEqual(self.dut.LPF_Accum_F2.status_data.udp,{}) + self.assertDictEqual(self.dut.LPF_Accum_F2.data.udp,{}) - with self.subTest(msg='register: msk_top_regs.axis_xfer_count.xfer_count'): + with self.subTest(msg='register: msk_top_regs.axis_xfer_count.data'): - self.assertDictEqual(self.dut.axis_xfer_count.xfer_count.udp,{}) + self.assertDictEqual(self.dut.axis_xfer_count.data.udp,{}) with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): @@ -3487,9 +3487,9 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.lowpass_ema_alpha2.alpha.udp,{}) - with self.subTest(msg='register: msk_top_regs.rx_power.rx_power'): + with self.subTest(msg='register: msk_top_regs.rx_power.data'): - self.assertDictEqual(self.dut.rx_power.rx_power.udp,{}) + self.assertDictEqual(self.dut.rx_power.data.udp,{}) with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): @@ -3916,9 +3916,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -3974,9 +4008,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5228,9 +5296,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5286,9 +5388,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5344,9 +5480,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5402,9 +5572,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5460,19 +5664,53 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] - - # check the read has not been called in the write test - read_callback_mock.assert_not_called() - # test access operations (read and/or write) to register: - # msk_top_regs.Rx_Sample_Discard - with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): - rut=self.dut.Rx_Sample_Discard # type: ignore[union-attr,assignment] - with patch(base_name + '.write_addr_space') as write_callback_mock, \ - patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: - + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): + rut=self.dut.Rx_Sample_Discard # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): raise TypeError('Register is not a Readable Async Type') @@ -5702,9 +5940,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5760,9 +6032,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5818,9 +6124,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -5876,9 +6216,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -6302,9 +6676,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -6352,17 +6760,51 @@ async def test_register_read_and_write(self) -> None: read_callback_mock.assert_called_once_with( addr=144, width=32, - accesswidth=rut.accesswidth) + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() - # at the end of the read tests the write should not have been called - read_callback_mock.reset_mock() - write_callback_mock.assert_not_called() - + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) - - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -6418,9 +6860,43 @@ async def test_register_read_and_write(self) -> None: - # test that a non-writable register has no write method and attempting one generates and error - with self.assertRaises(AttributeError): - await rut.write(0) # type: ignore[attr-defined] + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) # check the read has not been called in the write test read_callback_mock.assert_not_called() @@ -7394,9 +7870,9 @@ async def test_int_field_read_and_write(self) -> None: write_callback_mock.assert_not_called() # test access operations (read and/or write) to field: - # msk_top_regs.Tx_Bit_Count.tx_bit_counter - with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): - fut = self.dut.Tx_Bit_Count.tx_bit_counter # type: ignore[union-attr] + # msk_top_regs.Tx_Bit_Count.data + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.data'): + fut = self.dut.Tx_Bit_Count.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -7440,11 +7916,43 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Bit_Count.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=20, + width=32, + accesswidth=self.dut.Tx_Bit_Count.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.Tx_Enable_Count.tx_ena_counter - with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): - fut = self.dut.Tx_Enable_Count.tx_ena_counter # type: ignore[union-attr] + # msk_top_regs.Tx_Enable_Count.data + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.data'): + fut = self.dut.Tx_Enable_Count.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -7488,6 +7996,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.Tx_Enable_Count.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=24, + width=32, + accesswidth=self.dut.Tx_Enable_Count.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.Fb_FreqWord.config_data @@ -9189,9 +9729,9 @@ async def test_int_field_read_and_write(self) -> None: await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.PRBS_Bit_Count.status_data - with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): - fut = self.dut.PRBS_Bit_Count.status_data # type: ignore[union-attr] + # msk_top_regs.PRBS_Bit_Count.data + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.data'): + fut = self.dut.PRBS_Bit_Count.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -9235,11 +9775,43 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Bit_Count.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=80, + width=32, + accesswidth=self.dut.PRBS_Bit_Count.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.PRBS_Error_Count.status_data - with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): - fut = self.dut.PRBS_Error_Count.status_data # type: ignore[union-attr] + # msk_top_regs.PRBS_Error_Count.data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.data'): + fut = self.dut.PRBS_Error_Count.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -9283,11 +9855,43 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.PRBS_Error_Count.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=84, + width=32, + accesswidth=self.dut.PRBS_Error_Count.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.LPF_Accum_F1.status_data - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): - fut = self.dut.LPF_Accum_F1.status_data # type: ignore[union-attr] + # msk_top_regs.LPF_Accum_F1.data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.data'): + fut = self.dut.LPF_Accum_F1.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -9331,11 +9935,43 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Accum_F1.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=88, + width=32, + accesswidth=self.dut.LPF_Accum_F1.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.LPF_Accum_F2.status_data - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): - fut = self.dut.LPF_Accum_F2.status_data # type: ignore[union-attr] + # msk_top_regs.LPF_Accum_F2.data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.data'): + fut = self.dut.LPF_Accum_F2.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -9379,11 +10015,43 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.LPF_Accum_F2.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=92, + width=32, + accesswidth=self.dut.LPF_Accum_F2.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.axis_xfer_count.xfer_count - with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): - fut = self.dut.axis_xfer_count.xfer_count # type: ignore[union-attr] + # msk_top_regs.axis_xfer_count.data + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.data'): + fut = self.dut.axis_xfer_count.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -9422,11 +10090,43 @@ async def test_int_field_read_and_write(self) -> None: read_callback_mock.assert_called_once_with( addr=96, width=32, - accesswidth=fut.parent_register.accesswidth) + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.axis_xfer_count.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=96, + width=32, + accesswidth=self.dut.axis_xfer_count.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + - # at the end of the read tests the write should not have been called - read_callback_mock.reset_mock() - write_callback_mock.assert_not_called() + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.Rx_Sample_Discard.rx_sample_discard @@ -9811,6 +10511,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.f1_nco_adjust.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=108, + width=32, + accesswidth=self.dut.f1_nco_adjust.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.f2_nco_adjust.data @@ -9859,6 +10591,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.f2_nco_adjust.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=112, + width=32, + accesswidth=self.dut.f2_nco_adjust.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.f1_error.data @@ -9907,6 +10671,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.f1_error.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=116, + width=32, + accesswidth=self.dut.f1_error.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.f2_error.data @@ -9955,6 +10751,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.f2_error.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=120, + width=32, + accesswidth=self.dut.f2_error.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena @@ -10545,9 +11373,9 @@ async def test_int_field_read_and_write(self) -> None: await fut.write(-1) # test access operations (read and/or write) to field: - # msk_top_regs.rx_power.rx_power - with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): - fut = self.dut.rx_power.rx_power # type: ignore[union-attr] + # msk_top_regs.rx_power.data + with self.subTest(msg='field: msk_top_regs.rx_power.data'): + fut = self.dut.rx_power.data # type: ignore[union-attr] with patch(base_name + '.write_addr_space') as write_callback_mock,\ patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: @@ -10591,6 +11419,42 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x7FFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x7FFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_power.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=140, + width=32, + accesswidth=self.dut.rx_power.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFF800000) | \ + (0x7FFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x7FFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.tx_async_fifo_rd_wr_ptr.data @@ -10639,6 +11503,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.tx_async_fifo_rd_wr_ptr.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=144, + width=32, + accesswidth=self.dut.tx_async_fifo_rd_wr_ptr.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.rx_async_fifo_rd_wr_ptr.data @@ -10687,6 +11583,38 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_async_fifo_rd_wr_ptr.data.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_not_called() + write_callback_mock.assert_called_once_with( + addr=148, + width=32, + accesswidth=self.dut.rx_async_fifo_rd_wr_ptr.data.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x0) | \ + (0xFFFFFFFF & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) @@ -10987,7 +11915,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'tx_bit_counter' : await self.dut.Tx_Bit_Count.tx_bit_counter.read() + 'data' : await self.dut.Tx_Bit_Count.data.read() } read_callback_mock.reset_mock() @@ -11019,7 +11947,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'tx_ena_counter' : await self.dut.Tx_Enable_Count.tx_ena_counter.read() + 'data' : await self.dut.Tx_Enable_Count.data.read() } read_callback_mock.reset_mock() @@ -11551,7 +12479,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'status_data' : await self.dut.PRBS_Bit_Count.status_data.read() + 'data' : await self.dut.PRBS_Bit_Count.data.read() } read_callback_mock.reset_mock() @@ -11583,7 +12511,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'status_data' : await self.dut.PRBS_Error_Count.status_data.read() + 'data' : await self.dut.PRBS_Error_Count.data.read() } read_callback_mock.reset_mock() @@ -11615,7 +12543,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'status_data' : await self.dut.LPF_Accum_F1.status_data.read() + 'data' : await self.dut.LPF_Accum_F1.data.read() } read_callback_mock.reset_mock() @@ -11647,7 +12575,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'status_data' : await self.dut.LPF_Accum_F2.status_data.read() + 'data' : await self.dut.LPF_Accum_F2.data.read() } read_callback_mock.reset_mock() @@ -11679,7 +12607,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'xfer_count' : await self.dut.axis_xfer_count.xfer_count.read() + 'data' : await self.dut.axis_xfer_count.data.read() } read_callback_mock.reset_mock() @@ -12091,7 +13019,7 @@ async def test_register_read_fields(self) -> None: # from the object with all the read back field # values reference_read_fields = { - 'rx_power' : await self.dut.rx_power.rx_power.read() + 'data' : await self.dut.rx_power.data.read() } read_callback_mock.reset_mock() @@ -12511,14 +13439,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'tx_bit_counter' : await self.dut.Tx_Bit_Count.tx_bit_counter.read() # type: ignore[union-attr] + 'data' : await self.dut.Tx_Bit_Count.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.Tx_Bit_Count.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['tx_bit_counter'], - await reg_context.get_child_by_system_rdl_name('tx_bit_counter').read() + async with self.dut.Tx_Bit_Count.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -12547,14 +13476,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'tx_ena_counter' : await self.dut.Tx_Enable_Count.tx_ena_counter.read() # type: ignore[union-attr] + 'data' : await self.dut.Tx_Enable_Count.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.Tx_Enable_Count.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['tx_ena_counter'], - await reg_context.get_child_by_system_rdl_name('tx_ena_counter').read() + async with self.dut.Tx_Enable_Count.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13166,14 +14096,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'status_data' : await self.dut.PRBS_Bit_Count.status_data.read() # type: ignore[union-attr] + 'data' : await self.dut.PRBS_Bit_Count.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.PRBS_Bit_Count.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['status_data'], - await reg_context.get_child_by_system_rdl_name('status_data').read() + async with self.dut.PRBS_Bit_Count.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13202,14 +14133,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'status_data' : await self.dut.PRBS_Error_Count.status_data.read() # type: ignore[union-attr] + 'data' : await self.dut.PRBS_Error_Count.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.PRBS_Error_Count.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['status_data'], - await reg_context.get_child_by_system_rdl_name('status_data').read() + async with self.dut.PRBS_Error_Count.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13238,14 +14170,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'status_data' : await self.dut.LPF_Accum_F1.status_data.read() # type: ignore[union-attr] + 'data' : await self.dut.LPF_Accum_F1.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.LPF_Accum_F1.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['status_data'], - await reg_context.get_child_by_system_rdl_name('status_data').read() + async with self.dut.LPF_Accum_F1.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13274,14 +14207,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'status_data' : await self.dut.LPF_Accum_F2.status_data.read() # type: ignore[union-attr] + 'data' : await self.dut.LPF_Accum_F2.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.LPF_Accum_F2.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['status_data'], - await reg_context.get_child_by_system_rdl_name('status_data').read() + async with self.dut.LPF_Accum_F2.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13310,14 +14244,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'xfer_count' : await self.dut.axis_xfer_count.xfer_count.read() # type: ignore[union-attr] + 'data' : await self.dut.axis_xfer_count.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.axis_xfer_count.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['xfer_count'], - await reg_context.get_child_by_system_rdl_name('xfer_count').read() + async with self.dut.axis_xfer_count.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13455,7 +14390,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.f1_nco_adjust.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.f1_nco_adjust.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13491,7 +14427,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.f2_nco_adjust.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.f2_nco_adjust.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13527,7 +14464,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.f1_error.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.f1_error.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13563,7 +14501,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.f2_error.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.f2_error.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13787,14 +14726,15 @@ async def test_register_read_context_manager(self) -> None: # first read the fields using the "normal" method, then compare the result to reading # via the context manager reference_read_fields = { - 'rx_power' : await self.dut.rx_power.rx_power.read() # type: ignore[union-attr] + 'data' : await self.dut.rx_power.data.read() # type: ignore[union-attr] } read_callback_mock.reset_mock() - async with self.dut.rx_power.single_read() as reg_context: # type: ignore[union-attr] - self.assertEqual(reference_read_fields['rx_power'], - await reg_context.get_child_by_system_rdl_name('rx_power').read() + async with self.dut.rx_power.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['data'], + await reg_context.get_child_by_system_rdl_name('data').read() ) pass @@ -13828,7 +14768,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.tx_async_fifo_rd_wr_ptr.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.tx_async_fifo_rd_wr_ptr.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13864,7 +14805,8 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.reset_mock() - async with self.dut.rx_async_fifo_rd_wr_ptr.single_read() as reg_context: # type: ignore[union-attr] + async with self.dut.rx_async_fifo_rd_wr_ptr.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + self.assertEqual(reference_read_fields['data'], await reg_context.get_child_by_system_rdl_name('data').read() ) @@ -13965,6 +14907,14 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ 'clear_counts', 'diff_encoder_loopback' ]) + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + await write_field_combinations(reg=self.dut.Tx_Bit_Count, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + await write_field_combinations(reg=self.dut.Tx_Enable_Count, + writable_fields = [ 'data' + ]) with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): await write_field_combinations(reg=self.dut.Fb_FreqWord, writable_fields = [ 'config_data' @@ -14026,6 +14976,26 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ await write_field_combinations(reg=self.dut.PRBS_Error_Mask, writable_fields = [ 'config_data' ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + await write_field_combinations(reg=self.dut.PRBS_Bit_Count, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + await write_field_combinations(reg=self.dut.PRBS_Error_Count, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + await write_field_combinations(reg=self.dut.LPF_Accum_F1, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + await write_field_combinations(reg=self.dut.LPF_Accum_F2, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + await write_field_combinations(reg=self.dut.axis_xfer_count, + writable_fields = [ 'data' + ]) with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): await write_field_combinations(reg=self.dut.Rx_Sample_Discard, writable_fields = [ 'rx_sample_discard', @@ -14036,6 +15006,22 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ writable_fields = [ 'p_gain', 'p_shift' ]) + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + await write_field_combinations(reg=self.dut.f1_nco_adjust, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + await write_field_combinations(reg=self.dut.f2_nco_adjust, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.f1_error'): + await write_field_combinations(reg=self.dut.f1_error, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.f2_error'): + await write_field_combinations(reg=self.dut.f2_error, + writable_fields = [ 'data' + ]) with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): await write_field_combinations(reg=self.dut.Tx_Sync_Ctrl, writable_fields = [ 'tx_sync_ena', @@ -14055,6 +15041,18 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ await write_field_combinations(reg=self.dut.lowpass_ema_alpha2, writable_fields = [ 'alpha' ]) + with self.subTest(msg='register: msk_top_regs.rx_power'): + await write_field_combinations(reg=self.dut.rx_power, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + await write_field_combinations(reg=self.dut.tx_async_fifo_rd_wr_ptr, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + await write_field_combinations(reg=self.dut.rx_async_fifo_rd_wr_ptr, + writable_fields = [ 'data' + ]) async def test_register_write_fields(self) -> None: """ @@ -14124,6 +15122,20 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ 'diff_encoder_loopback' ]) + with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): + # test read_fields to register: + # msk_top_regs.Tx_Bit_Count + await write_field_combinations(reg=self.dut.Tx_Bit_Count, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): + # test read_fields to register: + # msk_top_regs.Tx_Enable_Count + await write_field_combinations(reg=self.dut.Tx_Enable_Count, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.Fb_FreqWord'): # test read_fields to register: # msk_top_regs.Fb_FreqWord @@ -14224,6 +15236,41 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ writable_fields = [ 'config_data' ]) + with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): + # test read_fields to register: + # msk_top_regs.PRBS_Bit_Count + await write_field_combinations(reg=self.dut.PRBS_Bit_Count, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): + # test read_fields to register: + # msk_top_regs.PRBS_Error_Count + await write_field_combinations(reg=self.dut.PRBS_Error_Count, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): + # test read_fields to register: + # msk_top_regs.LPF_Accum_F1 + await write_field_combinations(reg=self.dut.LPF_Accum_F1, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): + # test read_fields to register: + # msk_top_regs.LPF_Accum_F2 + await write_field_combinations(reg=self.dut.LPF_Accum_F2, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): + # test read_fields to register: + # msk_top_regs.axis_xfer_count + await write_field_combinations(reg=self.dut.axis_xfer_count, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.Rx_Sample_Discard'): # test read_fields to register: # msk_top_regs.Rx_Sample_Discard @@ -14240,6 +15287,34 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ 'p_shift' ]) + with self.subTest(msg='register: msk_top_regs.f1_nco_adjust'): + # test read_fields to register: + # msk_top_regs.f1_nco_adjust + await write_field_combinations(reg=self.dut.f1_nco_adjust, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.f2_nco_adjust'): + # test read_fields to register: + # msk_top_regs.f2_nco_adjust + await write_field_combinations(reg=self.dut.f2_nco_adjust, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.f1_error'): + # test read_fields to register: + # msk_top_regs.f1_error + await write_field_combinations(reg=self.dut.f1_error, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.f2_error'): + # test read_fields to register: + # msk_top_regs.f2_error + await write_field_combinations(reg=self.dut.f2_error, + writable_fields = [ 'data' + ]) + with self.subTest(msg='register: msk_top_regs.Tx_Sync_Ctrl'): # test read_fields to register: # msk_top_regs.Tx_Sync_Ctrl @@ -14271,6 +15346,27 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ writable_fields = [ 'alpha' ]) + with self.subTest(msg='register: msk_top_regs.rx_power'): + # test read_fields to register: + # msk_top_regs.rx_power + await write_field_combinations(reg=self.dut.rx_power, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.tx_async_fifo_rd_wr_ptr'): + # test read_fields to register: + # msk_top_regs.tx_async_fifo_rd_wr_ptr + await write_field_combinations(reg=self.dut.tx_async_fifo_rd_wr_ptr, + writable_fields = [ 'data' + ]) + + with self.subTest(msg='register: msk_top_regs.rx_async_fifo_rd_wr_ptr'): + # test read_fields to register: + # msk_top_regs.rx_async_fifo_rd_wr_ptr + await write_field_combinations(reg=self.dut.rx_async_fifo_rd_wr_ptr, + writable_fields = [ 'data' + ]) + @@ -14542,16 +15638,16 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.MSK_Status.tx_axis_valid.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.Tx_Bit_Count.tx_bit_counter.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): + self.dut.Tx_Bit_Count.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.Tx_Enable_Count.tx_ena_counter.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + self.dut.Tx_Enable_Count.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] with self.subTest(msg='node: msk_top_regs.Fb_FreqWord.config_data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type @@ -14662,31 +15758,31 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.PRBS_Error_Mask.config_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.status_data'): + with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.PRBS_Bit_Count.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.status_data'): + self.dut.PRBS_Bit_Count.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.PRBS_Error_Count.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.status_data'): + self.dut.PRBS_Error_Count.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.LPF_Accum_F1.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.status_data'): + self.dut.LPF_Accum_F1.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.LPF_Accum_F2.status_data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.axis_xfer_count.xfer_count'): + self.dut.LPF_Accum_F2.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.axis_xfer_count.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.axis_xfer_count.xfer_count.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + self.dut.axis_xfer_count.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] with self.subTest(msg='node: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type @@ -14762,11 +15858,11 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.lowpass_ema_alpha2.alpha.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] - with self.subTest(msg='node: msk_top_regs.rx_power.rx_power'): + with self.subTest(msg='node: msk_top_regs.rx_power.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type # checks - self.dut.rx_power.rx_power.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + self.dut.rx_power.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type @@ -14966,9 +16062,9 @@ def test_top_traversal_iterators(self) -> None: - + self.dut.Tx_Bit_Count, # type: ignore[union-attr,list-item] - + self.dut.Tx_Enable_Count, # type: ignore[union-attr,list-item] self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] @@ -14996,27 +16092,27 @@ def test_top_traversal_iterators(self) -> None: self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] - + self.dut.PRBS_Bit_Count, # type: ignore[union-attr,list-item] - + self.dut.PRBS_Error_Count, # type: ignore[union-attr,list-item] - + self.dut.LPF_Accum_F1, # type: ignore[union-attr,list-item] - + self.dut.LPF_Accum_F2, # type: ignore[union-attr,list-item] - + self.dut.axis_xfer_count, # type: ignore[union-attr,list-item] self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] - + self.dut.f1_nco_adjust, # type: ignore[union-attr,list-item] - + self.dut.f2_nco_adjust, # type: ignore[union-attr,list-item] - + self.dut.f1_error, # type: ignore[union-attr,list-item] - + self.dut.f2_error, # type: ignore[union-attr,list-item] self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] @@ -15026,11 +16122,11 @@ def test_top_traversal_iterators(self) -> None: self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] - + self.dut.rx_power, # type: ignore[union-attr,list-item] - + self.dut.tx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] - + self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] ] writable_regs = [] @@ -15049,9 +16145,9 @@ def test_top_traversal_iterators(self) -> None: - + self.dut.Tx_Bit_Count, # type: ignore[union-attr,list-item] - + self.dut.Tx_Enable_Count, # type: ignore[union-attr,list-item] self.dut.Fb_FreqWord, # type: ignore[union-attr,list-item] @@ -15079,27 +16175,27 @@ def test_top_traversal_iterators(self) -> None: self.dut.PRBS_Error_Mask, # type: ignore[union-attr,list-item] - + self.dut.PRBS_Bit_Count, # type: ignore[union-attr,list-item] - + self.dut.PRBS_Error_Count, # type: ignore[union-attr,list-item] - + self.dut.LPF_Accum_F1, # type: ignore[union-attr,list-item] - + self.dut.LPF_Accum_F2, # type: ignore[union-attr,list-item] - + self.dut.axis_xfer_count, # type: ignore[union-attr,list-item] self.dut.Rx_Sample_Discard, # type: ignore[union-attr,list-item] self.dut.LPF_Config_2, # type: ignore[union-attr,list-item] - + self.dut.f1_nco_adjust, # type: ignore[union-attr,list-item] - + self.dut.f2_nco_adjust, # type: ignore[union-attr,list-item] - + self.dut.f1_error, # type: ignore[union-attr,list-item] - + self.dut.f2_error, # type: ignore[union-attr,list-item] self.dut.Tx_Sync_Ctrl, # type: ignore[union-attr,list-item] @@ -15109,11 +16205,11 @@ def test_top_traversal_iterators(self) -> None: self.dut.lowpass_ema_alpha2, # type: ignore[union-attr,list-item] - + self.dut.rx_power, # type: ignore[union-attr,list-item] - + self.dut.tx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] - + self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] ] writable_regs = [] @@ -15676,7 +16772,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.Tx_Bit_Count'): - expected_fields = [self.dut.Tx_Bit_Count.tx_bit_counter, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.Tx_Bit_Count.data, # type: ignore[union-attr,list-item] @@ -15686,11 +16782,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.Tx_Bit_Count, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.Tx_Bit_Count.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Tx_Bit_Count.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.Tx_Bit_Count.tx_bit_counter, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.Tx_Bit_Count.data, # type: ignore[union-attr,list-item] ] @@ -15701,7 +16803,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.Tx_Enable_Count'): - expected_fields = [self.dut.Tx_Enable_Count.tx_ena_counter, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.Tx_Enable_Count.data, # type: ignore[union-attr,list-item] @@ -15711,11 +16813,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.Tx_Enable_Count, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.Tx_Enable_Count.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.Tx_Enable_Count.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.Tx_Enable_Count.tx_ena_counter, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.Tx_Enable_Count.data, # type: ignore[union-attr,list-item] ] @@ -16192,7 +17300,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.PRBS_Bit_Count'): - expected_fields = [self.dut.PRBS_Bit_Count.status_data, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.PRBS_Bit_Count.data, # type: ignore[union-attr,list-item] @@ -16202,11 +17310,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.PRBS_Bit_Count, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.PRBS_Bit_Count.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Bit_Count.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.PRBS_Bit_Count.status_data, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.PRBS_Bit_Count.data, # type: ignore[union-attr,list-item] ] @@ -16217,7 +17331,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.PRBS_Error_Count'): - expected_fields = [self.dut.PRBS_Error_Count.status_data, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.PRBS_Error_Count.data, # type: ignore[union-attr,list-item] @@ -16227,11 +17341,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.PRBS_Error_Count, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.PRBS_Error_Count.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.PRBS_Error_Count.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.PRBS_Error_Count.status_data, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.PRBS_Error_Count.data, # type: ignore[union-attr,list-item] ] @@ -16242,7 +17362,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.LPF_Accum_F1'): - expected_fields = [self.dut.LPF_Accum_F1.status_data, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.LPF_Accum_F1.data, # type: ignore[union-attr,list-item] @@ -16252,11 +17372,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.LPF_Accum_F1, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.LPF_Accum_F1.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.LPF_Accum_F1.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.LPF_Accum_F1.status_data, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.LPF_Accum_F1.data, # type: ignore[union-attr,list-item] ] @@ -16267,7 +17393,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.LPF_Accum_F2'): - expected_fields = [self.dut.LPF_Accum_F2.status_data, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.LPF_Accum_F2.data, # type: ignore[union-attr,list-item] @@ -16277,11 +17403,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.LPF_Accum_F2, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.LPF_Accum_F2.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.LPF_Accum_F2.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.LPF_Accum_F2.status_data, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.LPF_Accum_F2.data, # type: ignore[union-attr,list-item] ] @@ -16292,7 +17424,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.axis_xfer_count'): - expected_fields = [self.dut.axis_xfer_count.xfer_count, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.axis_xfer_count.data, # type: ignore[union-attr,list-item] @@ -16302,11 +17434,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.axis_xfer_count, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.axis_xfer_count.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.axis_xfer_count.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.axis_xfer_count.xfer_count, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.axis_xfer_count.data, # type: ignore[union-attr,list-item] ] @@ -16403,8 +17541,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.f1_nco_adjust, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.f1_nco_adjust.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.f1_nco_adjust.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.f1_nco_adjust.data, # type: ignore[union-attr,list-item] @@ -16428,8 +17572,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.f2_nco_adjust, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.f2_nco_adjust.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.f2_nco_adjust.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.f2_nco_adjust.data, # type: ignore[union-attr,list-item] @@ -16453,8 +17603,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.f1_error, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.f1_error.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.f1_error.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.f1_error.data, # type: ignore[union-attr,list-item] @@ -16478,8 +17634,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.f2_error, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.f2_error.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.f2_error.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.f2_error.data, # type: ignore[union-attr,list-item] @@ -16638,7 +17800,7 @@ def test_traversal_iterators(self) -> None: with self.subTest(msg='register: msk_top_regs.rx_power'): - expected_fields = [self.dut.rx_power.rx_power, # type: ignore[union-attr,list-item] + expected_fields = [self.dut.rx_power.data, # type: ignore[union-attr,list-item] @@ -16648,11 +17810,17 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.rx_power, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.rx_power.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.rx_power.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) - expected_readable_fields = [self.dut.rx_power.rx_power, # type: ignore[union-attr,list-item] + expected_readable_fields = [self.dut.rx_power.data, # type: ignore[union-attr,list-item] ] @@ -16673,8 +17841,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.tx_async_fifo_rd_wr_ptr, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.tx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.tx_async_fifo_rd_wr_ptr.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.tx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] @@ -16698,8 +17872,14 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - # register should not have writable_fields attribute - self.assertFalse(hasattr(self.dut.rx_async_fifo_rd_wr_ptr, 'writable_fields')) # type: ignore[union-attr] + expected_writable_fields = [self.dut.rx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.rx_async_fifo_rd_wr_ptr.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) expected_readable_fields = [self.dut.rx_async_fifo_rd_wr_ptr.data, # type: ignore[union-attr,list-item] @@ -16800,13 +17980,13 @@ def test_name_map(self) -> None: - self.assertEqual(self.dut.Tx_Bit_Count.get_child_by_system_rdl_name('tx_bit_counter').inst_name, 'tx_bit_counter') + self.assertEqual(self.dut.Tx_Bit_Count.get_child_by_system_rdl_name('data').inst_name, 'data') - self.assertEqual(self.dut.Tx_Enable_Count.get_child_by_system_rdl_name('tx_ena_counter').inst_name, 'tx_ena_counter') + self.assertEqual(self.dut.Tx_Enable_Count.get_child_by_system_rdl_name('data').inst_name, 'data') @@ -16935,31 +18115,31 @@ def test_name_map(self) -> None: - self.assertEqual(self.dut.PRBS_Bit_Count.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + self.assertEqual(self.dut.PRBS_Bit_Count.get_child_by_system_rdl_name('data').inst_name, 'data') - self.assertEqual(self.dut.PRBS_Error_Count.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + self.assertEqual(self.dut.PRBS_Error_Count.get_child_by_system_rdl_name('data').inst_name, 'data') - self.assertEqual(self.dut.LPF_Accum_F1.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + self.assertEqual(self.dut.LPF_Accum_F1.get_child_by_system_rdl_name('data').inst_name, 'data') - self.assertEqual(self.dut.LPF_Accum_F2.get_child_by_system_rdl_name('status_data').inst_name, 'status_data') + self.assertEqual(self.dut.LPF_Accum_F2.get_child_by_system_rdl_name('data').inst_name, 'data') - self.assertEqual(self.dut.axis_xfer_count.get_child_by_system_rdl_name('xfer_count').inst_name, 'xfer_count') + self.assertEqual(self.dut.axis_xfer_count.get_child_by_system_rdl_name('data').inst_name, 'data') @@ -17050,7 +18230,7 @@ def test_name_map(self) -> None: - self.assertEqual(self.dut.rx_power.get_child_by_system_rdl_name('rx_power').inst_name, 'rx_power') + self.assertEqual(self.dut.rx_power.get_child_by_system_rdl_name('data').inst_name, 'data') diff --git a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py index f4578fd..f95ff7a 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py @@ -279,6 +279,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Tx_Bit_Count.read(), random_value) + # test access operations (read and/or write) to register: @@ -313,6 +334,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Enable_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Enable_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.Tx_Enable_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.Tx_Enable_Count.read(), random_value) + # test access operations (read and/or write) to register: @@ -1062,6 +1104,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Bit_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Bit_Count.read(), random_value) + # test access operations (read and/or write) to register: @@ -1096,6 +1159,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.PRBS_Error_Count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.PRBS_Error_Count.read(), random_value) + # test access operations (read and/or write) to register: @@ -1130,6 +1214,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F1.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.LPF_Accum_F1.read(), random_value) + # test access operations (read and/or write) to register: @@ -1164,6 +1269,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.LPF_Accum_F2.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.LPF_Accum_F2.read(), random_value) + # test access operations (read and/or write) to register: @@ -1198,6 +1324,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.axis_xfer_count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.axis_xfer_count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.axis_xfer_count.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.axis_xfer_count.read(), random_value) + # test access operations (read and/or write) to register: @@ -1342,6 +1489,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.f1_nco_adjust.read(), random_value) + # test access operations (read and/or write) to register: @@ -1376,6 +1544,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_nco_adjust.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.f2_nco_adjust.read(), random_value) + # test access operations (read and/or write) to register: @@ -1410,6 +1599,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f1_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.f1_error.read(), random_value) + # test access operations (read and/or write) to register: @@ -1444,6 +1654,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.f2_error.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.f2_error.read(), random_value) + # test access operations (read and/or write) to register: @@ -1698,6 +1929,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_power.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_power.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_power.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.rx_power.read(), random_value) + # test access operations (read and/or write) to register: @@ -1732,6 +1984,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.tx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.tx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.tx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.tx_async_fifo_rd_wr_ptr.read(), random_value) + # test access operations (read and/or write) to register: @@ -1766,6 +2039,27 @@ async def test_register_read_and_write(self) -> None: + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_async_fifo_rd_wr_ptr.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.rx_async_fifo_rd_wr_ptr.read(), random_value) + @@ -3148,11 +3442,11 @@ async def test_field_read_and_write(self) -> None: # test access operations (read and/or write) to register: - # msk_top_regs.Tx_Bit_Count.tx_bit_counter - with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.tx_bit_counter'): + # msk_top_regs.Tx_Bit_Count.data + with self.subTest(msg='field: msk_top_regs.Tx_Bit_Count.data'): sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Bit_Count') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Bit_Count.tx_bit_counter') + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Bit_Count.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -3166,14 +3460,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Bit_Count.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Bit_Count.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -3184,7 +3478,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Bit_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -3204,21 +3498,68 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.Tx_Bit_Count.tx_bit_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Bit_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() - - - # test access operations (read and/or write) to register: - # msk_top_regs.Tx_Enable_Count.tx_ena_counter - with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.tx_ena_counter'): - sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Enable_Count') + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Tx_Enable_Count.data + with self.subTest(msg='field: msk_top_regs.Tx_Enable_Count.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.Tx_Enable_Count') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Enable_Count.tx_ena_counter') + sim_field = self.sim.field_by_full_name('msk_top_regs.Tx_Enable_Count.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -3232,14 +3573,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Enable_Count.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Enable_Count.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -3250,7 +3591,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Enable_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -3270,13 +3611,60 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.Tx_Enable_Count.tx_ena_counter.read(), random_field_value) + self.assertEqual(await self.dut.Tx_Enable_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Enable_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Enable_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.Tx_Enable_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -5634,11 +6022,11 @@ async def test_field_read_and_write(self) -> None: # test access operations (read and/or write) to register: - # msk_top_regs.PRBS_Bit_Count.status_data - with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.status_data'): + # msk_top_regs.PRBS_Bit_Count.data + with self.subTest(msg='field: msk_top_regs.PRBS_Bit_Count.data'): sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Bit_Count') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Bit_Count.status_data') + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Bit_Count.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -5652,14 +6040,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Bit_Count.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Bit_Count.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -5670,7 +6058,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Bit_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -5690,21 +6078,68 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.PRBS_Bit_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Bit_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Bit_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: - # msk_top_regs.PRBS_Error_Count.status_data - with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.status_data'): + # msk_top_regs.PRBS_Error_Count.data + with self.subTest(msg='field: msk_top_regs.PRBS_Error_Count.data'): sim_register = self.sim.register_by_full_name('msk_top_regs.PRBS_Error_Count') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Error_Count.status_data') + sim_field = self.sim.field_by_full_name('msk_top_regs.PRBS_Error_Count.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -5718,14 +6153,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Error_Count.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Error_Count.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -5736,7 +6171,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Error_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -5756,21 +6191,68 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.PRBS_Error_Count.status_data.read(), random_field_value) + self.assertEqual(await self.dut.PRBS_Error_Count.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.PRBS_Error_Count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: - # msk_top_regs.LPF_Accum_F1.status_data - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.status_data'): + # msk_top_regs.LPF_Accum_F1.data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F1.data'): sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F1') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F1.status_data') + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F1.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -5784,14 +6266,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F1.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F1.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -5802,7 +6284,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F1.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -5822,87 +6304,68 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.LPF_Accum_F1.status_data.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F1.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value - - # test access operations (read and/or write) to register: - # msk_top_regs.LPF_Accum_F2.status_data - with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.status_data'): - sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F2') - self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F2.status_data') - self.assertIsInstance(sim_field, Field) - register_read_callback = Mock() - register_write_callback = Mock() - field_read_callback = Mock() - field_write_callback = Mock() - - # register read checks - # update the register value via the backdoor in the simulator - random_value = random.randrange(0, 0xFFFFFFFF+1) - random_field_value = (random_value & 0xFFFFFFFF) >> 0 - - - sim_register.value = random_value - self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) - # update the field value via the backdoor in the simulator - previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) - sim_field.value = random_field_value - self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) - # hook up the call backs to check they work correctly - random_value = random.randrange(0, 0xFFFFFFFF+1) - random_field_value = (random_value & 0xFFFFFFFF) >> 0 - + await self.dut.LPF_Accum_F1.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) - sim_register.value = random_value - sim_register.read_callback = register_read_callback - sim_register.write_callback = register_write_callback - sim_field.read_callback = field_read_callback - sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) register_write_callback.assert_not_called() - register_read_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() field_write_callback.assert_not_called() - field_read_callback.assert_called_once_with(value=random_field_value) + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.LPF_Accum_F1.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value # revert the callbacks and check again register_write_callback.reset_mock() register_read_callback.reset_mock() field_write_callback.reset_mock() field_read_callback.reset_mock() - sim_register.read_callback = None sim_register.write_callback = None - sim_field.read_callback = None sim_field.write_callback = None - random_value = random.randrange(0, 0xFFFFFFFF+1) - random_field_value = (random_value & 0xFFFFFFFF) >> 0 - + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.LPF_Accum_F1.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) - sim_register.value = random_value - self.assertEqual(await self.dut.LPF_Accum_F2.status_data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() - - # test access operations (read and/or write) to register: - # msk_top_regs.axis_xfer_count.xfer_count - with self.subTest(msg='field: msk_top_regs.axis_xfer_count.xfer_count'): - sim_register = self.sim.register_by_full_name('msk_top_regs.axis_xfer_count') + # msk_top_regs.LPF_Accum_F2.data + with self.subTest(msg='field: msk_top_regs.LPF_Accum_F2.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.LPF_Accum_F2') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.axis_xfer_count.xfer_count') + sim_field = self.sim.field_by_full_name('msk_top_regs.LPF_Accum_F2.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -5916,14 +6379,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F2.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0xFFFFFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) - self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F2.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0xFFFFFFFF) >> 0 @@ -5934,7 +6397,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F2.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -5954,18 +6417,178 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.axis_xfer_count.xfer_count.read(), random_field_value) + self.assertEqual(await self.dut.LPF_Accum_F2.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value - - # test access operations (read and/or write) to register: - # msk_top_regs.Rx_Sample_Discard.rx_sample_discard - with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.LPF_Accum_F2.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.LPF_Accum_F2.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.LPF_Accum_F2.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.axis_xfer_count.data + with self.subTest(msg='field: msk_top_regs.axis_xfer_count.data'): + sim_register = self.sim.register_by_full_name('msk_top_regs.axis_xfer_count') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.axis_xfer_count.data') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.data.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x0) | (random_field_value << 0)) + + self.assertEqual(await self.dut.axis_xfer_count.data.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.axis_xfer_count.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFFFFFFFF) >> 0 + + + sim_register.value = random_value + self.assertEqual(await self.dut.axis_xfer_count.data.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.axis_xfer_count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.axis_xfer_count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.axis_xfer_count.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.Rx_Sample_Discard.rx_sample_discard + with self.subTest(msg='field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard'): sim_register = self.sim.register_by_full_name('msk_top_regs.Rx_Sample_Discard') self.assertIsInstance(sim_register, (Register,MemoryRegister)) sim_field = self.sim.field_by_full_name('msk_top_regs.Rx_Sample_Discard.rx_sample_discard') @@ -6479,6 +7102,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -6545,6 +7215,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_nco_adjust.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -6611,6 +7328,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f1_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -6677,6 +7441,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.f2_error.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -7495,11 +8306,11 @@ async def test_field_read_and_write(self) -> None: # test access operations (read and/or write) to register: - # msk_top_regs.rx_power.rx_power - with self.subTest(msg='field: msk_top_regs.rx_power.rx_power'): + # msk_top_regs.rx_power.data + with self.subTest(msg='field: msk_top_regs.rx_power.data'): sim_register = self.sim.register_by_full_name('msk_top_regs.rx_power') self.assertIsInstance(sim_register, (Register,MemoryRegister)) - sim_field = self.sim.field_by_full_name('msk_top_regs.rx_power.rx_power') + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_power.data') self.assertIsInstance(sim_field, Field) register_read_callback = Mock() register_write_callback = Mock() @@ -7513,14 +8324,14 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + self.assertEqual(await self.dut.rx_power.data.read(), random_field_value) # update the field value via the backdoor in the simulator previous_register_value = random_value random_field_value = random.randrange(0, 0x7FFFFF+1) sim_field.value = random_field_value self.assertEqual(sim_register.value, (previous_register_value & 0xFF800000) | (random_field_value << 0)) - self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + self.assertEqual(await self.dut.rx_power.data.read(), random_field_value) # hook up the call backs to check they work correctly random_value = random.randrange(0, 0xFFFFFFFF+1) random_field_value = (random_value & 0x7FFFFF) >> 0 @@ -7531,7 +8342,7 @@ async def test_field_read_and_write(self) -> None: sim_register.write_callback = register_write_callback sim_field.read_callback = field_read_callback sim_field.write_callback = field_write_callback - self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + self.assertEqual(await self.dut.rx_power.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_called_once_with(value=random_value) field_write_callback.assert_not_called() @@ -7551,13 +8362,60 @@ async def test_field_read_and_write(self) -> None: sim_register.value = random_value - self.assertEqual(await self.dut.rx_power.rx_power.read(), random_field_value) + self.assertEqual(await self.dut.rx_power.data.read(), random_field_value) register_write_callback.assert_not_called() register_read_callback.assert_not_called() field_write_callback.assert_not_called() field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x7FFFFF+1) + + await self.dut.rx_power.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF800000) | (0x7FFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x7FFFFF+1) + + await self.dut.rx_power.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF800000) | (0x7FFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFF800000) | (0x7FFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x7FFFFF+1) + + await self.dut.rx_power.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFF800000) | (0x7FFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -7624,6 +8482,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.tx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.tx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.tx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -7690,6 +8595,53 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.rx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.rx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFFFF+1) + + await self.dut.rx_async_fifo_rd_wr_ptr.data.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x0) | (0xFFFFFFFF & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd index dc0d5cb..12e679f 100644 --- a/rdl/outputs/rtl/msk_top_regs.vhd +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -70,10 +70,6 @@ architecture rtl of msk_top_regs is signal axil_resp_buffer : axil_resp_buffer_array_t(1 downto 0); signal axil_resp_wptr : unsigned(1 downto 0); signal axil_resp_rptr : unsigned(1 downto 0); - signal external_req : std_logic; - signal external_pending : std_logic; - signal external_wr_ack : std_logic; - signal external_rd_ack : std_logic; ---------------------------------------------------------------------------- -- Address Decode Signals @@ -119,8 +115,6 @@ architecture rtl of msk_top_regs is rx_async_fifo_rd_wr_ptr : std_logic; end record; signal decoded_reg_strb : decoded_reg_strb_t; - signal decoded_strb_is_external : std_logic; - signal decoded_req : std_logic; signal decoded_req_is_wr : std_logic; signal decoded_wr_data : std_logic_vector(31 downto 0); @@ -184,6 +178,24 @@ architecture rtl of msk_top_regs is diff_encoder_loopback : \msk_top_regs.MSK_Control.diff_encoder_loopback_combo_t\; end record; + type \msk_top_regs.Tx_Bit_Count.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Bit_Count_combo_t\ is record + data : \msk_top_regs.Tx_Bit_Count.data_combo_t\; + end record; + + type \msk_top_regs.Tx_Enable_Count.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.Tx_Enable_Count_combo_t\ is record + data : \msk_top_regs.Tx_Enable_Count.data_combo_t\; + end record; + type \msk_top_regs.Fb_FreqWord.config_data_combo_t\ is record next_q : std_logic_vector(31 downto 0); load_next : std_logic; @@ -355,6 +367,51 @@ architecture rtl of msk_top_regs is config_data : \msk_top_regs.PRBS_Error_Mask.config_data_combo_t\; end record; + type \msk_top_regs.PRBS_Bit_Count.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Bit_Count_combo_t\ is record + data : \msk_top_regs.PRBS_Bit_Count.data_combo_t\; + end record; + + type \msk_top_regs.PRBS_Error_Count.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.PRBS_Error_Count_combo_t\ is record + data : \msk_top_regs.PRBS_Error_Count.data_combo_t\; + end record; + + type \msk_top_regs.LPF_Accum_F1.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Accum_F1_combo_t\ is record + data : \msk_top_regs.LPF_Accum_F1.data_combo_t\; + end record; + + type \msk_top_regs.LPF_Accum_F2.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.LPF_Accum_F2_combo_t\ is record + data : \msk_top_regs.LPF_Accum_F2.data_combo_t\; + end record; + + type \msk_top_regs.axis_xfer_count.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.axis_xfer_count_combo_t\ is record + data : \msk_top_regs.axis_xfer_count.data_combo_t\; + end record; + type \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_combo_t\ is record next_q : std_logic_vector(7 downto 0); load_next : std_logic; @@ -385,6 +442,42 @@ architecture rtl of msk_top_regs is p_shift : \msk_top_regs.LPF_Config_2.p_shift_combo_t\; end record; + type \msk_top_regs.f1_nco_adjust.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.f1_nco_adjust_combo_t\ is record + data : \msk_top_regs.f1_nco_adjust.data_combo_t\; + end record; + + type \msk_top_regs.f2_nco_adjust.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.f2_nco_adjust_combo_t\ is record + data : \msk_top_regs.f2_nco_adjust.data_combo_t\; + end record; + + type \msk_top_regs.f1_error.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.f1_error_combo_t\ is record + data : \msk_top_regs.f1_error.data_combo_t\; + end record; + + type \msk_top_regs.f2_error.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.f2_error_combo_t\ is record + data : \msk_top_regs.f2_error.data_combo_t\; + end record; + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_combo_t\ is record next_q : std_logic; load_next : std_logic; @@ -439,9 +532,38 @@ architecture rtl of msk_top_regs is alpha : \msk_top_regs.lowpass_ema_alpha2.alpha_combo_t\; end record; + type \msk_top_regs.rx_power.data_combo_t\ is record + next_q : std_logic_vector(22 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.rx_power_combo_t\ is record + data : \msk_top_regs.rx_power.data_combo_t\; + end record; + + type \msk_top_regs.tx_async_fifo_rd_wr_ptr.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.tx_async_fifo_rd_wr_ptr_combo_t\ is record + data : \msk_top_regs.tx_async_fifo_rd_wr_ptr.data_combo_t\; + end record; + + type \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_combo_t\ is record + next_q : std_logic_vector(31 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.rx_async_fifo_rd_wr_ptr_combo_t\ is record + data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_combo_t\; + end record; + type field_combo_t is record MSK_Init : \msk_top_regs.MSK_Init_combo_t\; MSK_Control : \msk_top_regs.MSK_Control_combo_t\; + Tx_Bit_Count : \msk_top_regs.Tx_Bit_Count_combo_t\; + Tx_Enable_Count : \msk_top_regs.Tx_Enable_Count_combo_t\; Fb_FreqWord : \msk_top_regs.Fb_FreqWord_combo_t\; TX_F1_FreqWord : \msk_top_regs.TX_F1_FreqWord_combo_t\; TX_F2_FreqWord : \msk_top_regs.TX_F2_FreqWord_combo_t\; @@ -455,12 +577,24 @@ architecture rtl of msk_top_regs is PRBS_Initial_State : \msk_top_regs.PRBS_Initial_State_combo_t\; PRBS_Polynomial : \msk_top_regs.PRBS_Polynomial_combo_t\; PRBS_Error_Mask : \msk_top_regs.PRBS_Error_Mask_combo_t\; + PRBS_Bit_Count : \msk_top_regs.PRBS_Bit_Count_combo_t\; + PRBS_Error_Count : \msk_top_regs.PRBS_Error_Count_combo_t\; + LPF_Accum_F1 : \msk_top_regs.LPF_Accum_F1_combo_t\; + LPF_Accum_F2 : \msk_top_regs.LPF_Accum_F2_combo_t\; + axis_xfer_count : \msk_top_regs.axis_xfer_count_combo_t\; Rx_Sample_Discard : \msk_top_regs.Rx_Sample_Discard_combo_t\; LPF_Config_2 : \msk_top_regs.LPF_Config_2_combo_t\; + f1_nco_adjust : \msk_top_regs.f1_nco_adjust_combo_t\; + f2_nco_adjust : \msk_top_regs.f2_nco_adjust_combo_t\; + f1_error : \msk_top_regs.f1_error_combo_t\; + f2_error : \msk_top_regs.f2_error_combo_t\; Tx_Sync_Ctrl : \msk_top_regs.Tx_Sync_Ctrl_combo_t\; Tx_Sync_Cnt : \msk_top_regs.Tx_Sync_Cnt_combo_t\; lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha1_combo_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha2_combo_t\; + rx_power : \msk_top_regs.rx_power_combo_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.tx_async_fifo_rd_wr_ptr_combo_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.rx_async_fifo_rd_wr_ptr_combo_t\; end record; signal field_combo : field_combo_t; @@ -511,6 +645,22 @@ architecture rtl of msk_top_regs is diff_encoder_loopback : \msk_top_regs.MSK_Control.diff_encoder_loopback_storage_t\; end record; + type \msk_top_regs.Tx_Bit_Count.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.Tx_Bit_Count_storage_t\ is record + data : \msk_top_regs.Tx_Bit_Count.data_storage_t\; + end record; + + type \msk_top_regs.Tx_Enable_Count.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.Tx_Enable_Count_storage_t\ is record + data : \msk_top_regs.Tx_Enable_Count.data_storage_t\; + end record; + type \msk_top_regs.Fb_FreqWord.config_data_storage_t\ is record value : std_logic_vector(31 downto 0); end record; @@ -660,6 +810,46 @@ architecture rtl of msk_top_regs is config_data : \msk_top_regs.PRBS_Error_Mask.config_data_storage_t\; end record; + type \msk_top_regs.PRBS_Bit_Count.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.PRBS_Bit_Count_storage_t\ is record + data : \msk_top_regs.PRBS_Bit_Count.data_storage_t\; + end record; + + type \msk_top_regs.PRBS_Error_Count.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.PRBS_Error_Count_storage_t\ is record + data : \msk_top_regs.PRBS_Error_Count.data_storage_t\; + end record; + + type \msk_top_regs.LPF_Accum_F1.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.LPF_Accum_F1_storage_t\ is record + data : \msk_top_regs.LPF_Accum_F1.data_storage_t\; + end record; + + type \msk_top_regs.LPF_Accum_F2.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.LPF_Accum_F2_storage_t\ is record + data : \msk_top_regs.LPF_Accum_F2.data_storage_t\; + end record; + + type \msk_top_regs.axis_xfer_count.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.axis_xfer_count_storage_t\ is record + data : \msk_top_regs.axis_xfer_count.data_storage_t\; + end record; + type \msk_top_regs.Rx_Sample_Discard.rx_sample_discard_storage_t\ is record value : std_logic_vector(7 downto 0); end record; @@ -686,6 +876,38 @@ architecture rtl of msk_top_regs is p_shift : \msk_top_regs.LPF_Config_2.p_shift_storage_t\; end record; + type \msk_top_regs.f1_nco_adjust.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.f1_nco_adjust_storage_t\ is record + data : \msk_top_regs.f1_nco_adjust.data_storage_t\; + end record; + + type \msk_top_regs.f2_nco_adjust.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.f2_nco_adjust_storage_t\ is record + data : \msk_top_regs.f2_nco_adjust.data_storage_t\; + end record; + + type \msk_top_regs.f1_error.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.f1_error_storage_t\ is record + data : \msk_top_regs.f1_error.data_storage_t\; + end record; + + type \msk_top_regs.f2_error.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.f2_error_storage_t\ is record + data : \msk_top_regs.f2_error.data_storage_t\; + end record; + type \msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena_storage_t\ is record value : std_logic; end record; @@ -733,9 +955,35 @@ architecture rtl of msk_top_regs is alpha : \msk_top_regs.lowpass_ema_alpha2.alpha_storage_t\; end record; + type \msk_top_regs.rx_power.data_storage_t\ is record + value : std_logic_vector(22 downto 0); + end record; + + type \msk_top_regs.rx_power_storage_t\ is record + data : \msk_top_regs.rx_power.data_storage_t\; + end record; + + type \msk_top_regs.tx_async_fifo_rd_wr_ptr.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.tx_async_fifo_rd_wr_ptr_storage_t\ is record + data : \msk_top_regs.tx_async_fifo_rd_wr_ptr.data_storage_t\; + end record; + + type \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_storage_t\ is record + value : std_logic_vector(31 downto 0); + end record; + + type \msk_top_regs.rx_async_fifo_rd_wr_ptr_storage_t\ is record + data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_storage_t\; + end record; + type field_storage_t is record MSK_Init : \msk_top_regs.MSK_Init_storage_t\; MSK_Control : \msk_top_regs.MSK_Control_storage_t\; + Tx_Bit_Count : \msk_top_regs.Tx_Bit_Count_storage_t\; + Tx_Enable_Count : \msk_top_regs.Tx_Enable_Count_storage_t\; Fb_FreqWord : \msk_top_regs.Fb_FreqWord_storage_t\; TX_F1_FreqWord : \msk_top_regs.TX_F1_FreqWord_storage_t\; TX_F2_FreqWord : \msk_top_regs.TX_F2_FreqWord_storage_t\; @@ -749,20 +997,30 @@ architecture rtl of msk_top_regs is PRBS_Initial_State : \msk_top_regs.PRBS_Initial_State_storage_t\; PRBS_Polynomial : \msk_top_regs.PRBS_Polynomial_storage_t\; PRBS_Error_Mask : \msk_top_regs.PRBS_Error_Mask_storage_t\; + PRBS_Bit_Count : \msk_top_regs.PRBS_Bit_Count_storage_t\; + PRBS_Error_Count : \msk_top_regs.PRBS_Error_Count_storage_t\; + LPF_Accum_F1 : \msk_top_regs.LPF_Accum_F1_storage_t\; + LPF_Accum_F2 : \msk_top_regs.LPF_Accum_F2_storage_t\; + axis_xfer_count : \msk_top_regs.axis_xfer_count_storage_t\; Rx_Sample_Discard : \msk_top_regs.Rx_Sample_Discard_storage_t\; LPF_Config_2 : \msk_top_regs.LPF_Config_2_storage_t\; + f1_nco_adjust : \msk_top_regs.f1_nco_adjust_storage_t\; + f2_nco_adjust : \msk_top_regs.f2_nco_adjust_storage_t\; + f1_error : \msk_top_regs.f1_error_storage_t\; + f2_error : \msk_top_regs.f2_error_storage_t\; Tx_Sync_Ctrl : \msk_top_regs.Tx_Sync_Ctrl_storage_t\; Tx_Sync_Cnt : \msk_top_regs.Tx_Sync_Cnt_storage_t\; lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha1_storage_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha2_storage_t\; + rx_power : \msk_top_regs.rx_power_storage_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.tx_async_fifo_rd_wr_ptr_storage_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.rx_async_fifo_rd_wr_ptr_storage_t\; end record; signal field_storage : field_storage_t; ---------------------------------------------------------------------------- -- Readback Signals ---------------------------------------------------------------------------- - signal readback_external_rd_ack_c : std_logic; - signal readback_external_rd_ack : std_logic; signal readback_err : std_logic; signal readback_done : std_logic; signal readback_data : std_logic_vector(31 downto 0); @@ -960,32 +1218,10 @@ begin s_axil_o.RRESP <= "00"; end if; end process; - process(clk) begin - if false then -- async reset - external_pending <= '0'; - elsif rising_edge(clk) then - if rst then -- sync reset - external_pending <= '0'; - else - if external_req and not external_wr_ack and not external_rd_ack then - external_pending <= '1'; - elsif external_wr_ack or external_rd_ack then - external_pending <= '0'; - end if; - --pragma translate_off - assert_bad_ext_wr_ack: assert not external_wr_ack or (external_pending or external_req) - report "An external wr_ack strobe was asserted when no external request was active"; - assert_bad_ext_rd_ack: assert not external_rd_ack or (external_pending or external_req) - report "An external rd_ack strobe was asserted when no external request was active"; - --pragma translate_on - end if; - end if; - end process; -- Read & write latencies are balanced. Stalls not required - -- except if external - cpuif_req_stall_rd <= external_pending; - cpuif_req_stall_wr <= external_pending; + cpuif_req_stall_rd <= '0'; + cpuif_req_stall_wr <= '0'; cpuif_req_masked <= cpuif_req and not (not cpuif_req_is_wr and cpuif_req_stall_rd) and not (cpuif_req_is_wr and cpuif_req_stall_wr); @@ -1001,18 +1237,14 @@ begin result := '1' when unsigned(L) = R else '0'; return result; end; - variable is_external: std_logic; begin - is_external := '0'; decoded_reg_strb.Hash_ID_Low <= cpuif_req_masked and (cpuif_addr = 16#0#); decoded_reg_strb.Hash_ID_High <= cpuif_req_masked and (cpuif_addr = 16#4#); decoded_reg_strb.MSK_Init <= cpuif_req_masked and (cpuif_addr = 16#8#); decoded_reg_strb.MSK_Control <= cpuif_req_masked and (cpuif_addr = 16#C#); decoded_reg_strb.MSK_Status <= cpuif_req_masked and (cpuif_addr = 16#10#); decoded_reg_strb.Tx_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#14#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#14#)) and not cpuif_req_is_wr); decoded_reg_strb.Tx_Enable_Count <= cpuif_req_masked and (cpuif_addr = 16#18#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#18#)) and not cpuif_req_is_wr); decoded_reg_strb.Fb_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#1C#); decoded_reg_strb.TX_F1_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#20#); decoded_reg_strb.TX_F2_FreqWord <= cpuif_req_masked and (cpuif_addr = 16#24#); @@ -1027,37 +1259,23 @@ begin decoded_reg_strb.PRBS_Polynomial <= cpuif_req_masked and (cpuif_addr = 16#48#); decoded_reg_strb.PRBS_Error_Mask <= cpuif_req_masked and (cpuif_addr = 16#4C#); decoded_reg_strb.PRBS_Bit_Count <= cpuif_req_masked and (cpuif_addr = 16#50#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#50#)) and not cpuif_req_is_wr); decoded_reg_strb.PRBS_Error_Count <= cpuif_req_masked and (cpuif_addr = 16#54#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#54#)) and not cpuif_req_is_wr); decoded_reg_strb.LPF_Accum_F1 <= cpuif_req_masked and (cpuif_addr = 16#58#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#58#)) and not cpuif_req_is_wr); decoded_reg_strb.LPF_Accum_F2 <= cpuif_req_masked and (cpuif_addr = 16#5C#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#5C#)) and not cpuif_req_is_wr); decoded_reg_strb.axis_xfer_count <= cpuif_req_masked and (cpuif_addr = 16#60#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#60#)) and not cpuif_req_is_wr); decoded_reg_strb.Rx_Sample_Discard <= cpuif_req_masked and (cpuif_addr = 16#64#); decoded_reg_strb.LPF_Config_2 <= cpuif_req_masked and (cpuif_addr = 16#68#); decoded_reg_strb.f1_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#6C#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#6C#)) and not cpuif_req_is_wr); decoded_reg_strb.f2_nco_adjust <= cpuif_req_masked and (cpuif_addr = 16#70#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#70#)) and not cpuif_req_is_wr); decoded_reg_strb.f1_error <= cpuif_req_masked and (cpuif_addr = 16#74#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#74#)) and not cpuif_req_is_wr); decoded_reg_strb.f2_error <= cpuif_req_masked and (cpuif_addr = 16#78#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#78#)) and not cpuif_req_is_wr); decoded_reg_strb.Tx_Sync_Ctrl <= cpuif_req_masked and (cpuif_addr = 16#7C#); decoded_reg_strb.Tx_Sync_Cnt <= cpuif_req_masked and (cpuif_addr = 16#80#); decoded_reg_strb.lowpass_ema_alpha1 <= cpuif_req_masked and (cpuif_addr = 16#84#); decoded_reg_strb.lowpass_ema_alpha2 <= cpuif_req_masked and (cpuif_addr = 16#88#); decoded_reg_strb.rx_power <= cpuif_req_masked and (cpuif_addr = 16#8C#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#8C#)) and not cpuif_req_is_wr); decoded_reg_strb.tx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#90#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#90#)) and not cpuif_req_is_wr); decoded_reg_strb.rx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#94#); - is_external := is_external or ((cpuif_req_masked and (cpuif_addr = 16#94#)) and not cpuif_req_is_wr); - decoded_strb_is_external <= is_external; - external_req <= is_external; end process; -- Pass down signals to next stage @@ -1307,11 +1525,69 @@ begin end process; hwif_out.MSK_Control.diff_encoder_loopback.value <= field_storage.MSK_Control.diff_encoder_loopback.value; - hwif_out.Tx_Bit_Count.req <= decoded_reg_strb.Tx_Bit_Count when not decoded_req_is_wr else '0'; - hwif_out.Tx_Bit_Count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.Tx_Bit_Count.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Bit_Count.data.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Bit_Count and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Bit_Count.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.Tx_Bit_Count.data.we then -- HW Write - we + next_c := hwif_in.Tx_Bit_Count.data.next_q; + load_next_c := '1'; + end if; + field_combo.Tx_Bit_Count.data.next_q <= next_c; + field_combo.Tx_Bit_Count.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Bit_Count.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Bit_Count.data.value <= 32x"0"; + else + if field_combo.Tx_Bit_Count.data.load_next then + field_storage.Tx_Bit_Count.data.value <= field_combo.Tx_Bit_Count.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Bit_Count.data.swmod <= decoded_reg_strb.Tx_Bit_Count and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.Tx_Enable_Count.req <= decoded_reg_strb.Tx_Enable_Count when not decoded_req_is_wr else '0'; - hwif_out.Tx_Enable_Count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.Tx_Enable_Count.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.Tx_Enable_Count.data.value; + load_next_c := '0'; + if decoded_reg_strb.Tx_Enable_Count and decoded_req_is_wr then -- SW write + next_c := (field_storage.Tx_Enable_Count.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.Tx_Enable_Count.data.we then -- HW Write - we + next_c := hwif_in.Tx_Enable_Count.data.next_q; + load_next_c := '1'; + end if; + field_combo.Tx_Enable_Count.data.next_q <= next_c; + field_combo.Tx_Enable_Count.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.Tx_Enable_Count.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.Tx_Enable_Count.data.value <= 32x"0"; + else + if field_combo.Tx_Enable_Count.data.load_next then + field_storage.Tx_Enable_Count.data.value <= field_combo.Tx_Enable_Count.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.Tx_Enable_Count.data.swmod <= decoded_reg_strb.Tx_Enable_Count and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); -- Field: msk_top_regs.Fb_FreqWord.config_data process(all) @@ -1960,20 +2236,165 @@ begin end process; hwif_out.PRBS_Error_Mask.config_data.value <= field_storage.PRBS_Error_Mask.config_data.value; - hwif_out.PRBS_Bit_Count.req <= decoded_reg_strb.PRBS_Bit_Count when not decoded_req_is_wr else '0'; - hwif_out.PRBS_Bit_Count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.PRBS_Bit_Count.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Bit_Count.data.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Bit_Count and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Bit_Count.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.PRBS_Bit_Count.data.we then -- HW Write - we + next_c := hwif_in.PRBS_Bit_Count.data.next_q; + load_next_c := '1'; + end if; + field_combo.PRBS_Bit_Count.data.next_q <= next_c; + field_combo.PRBS_Bit_Count.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Bit_Count.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Bit_Count.data.value <= 32x"0"; + else + if field_combo.PRBS_Bit_Count.data.load_next then + field_storage.PRBS_Bit_Count.data.value <= field_combo.PRBS_Bit_Count.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Bit_Count.data.swmod <= decoded_reg_strb.PRBS_Bit_Count and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.PRBS_Error_Count.req <= decoded_reg_strb.PRBS_Error_Count when not decoded_req_is_wr else '0'; - hwif_out.PRBS_Error_Count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.PRBS_Error_Count.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.PRBS_Error_Count.data.value; + load_next_c := '0'; + if decoded_reg_strb.PRBS_Error_Count and decoded_req_is_wr then -- SW write + next_c := (field_storage.PRBS_Error_Count.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.PRBS_Error_Count.data.we then -- HW Write - we + next_c := hwif_in.PRBS_Error_Count.data.next_q; + load_next_c := '1'; + end if; + field_combo.PRBS_Error_Count.data.next_q <= next_c; + field_combo.PRBS_Error_Count.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.PRBS_Error_Count.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.PRBS_Error_Count.data.value <= 32x"0"; + else + if field_combo.PRBS_Error_Count.data.load_next then + field_storage.PRBS_Error_Count.data.value <= field_combo.PRBS_Error_Count.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.PRBS_Error_Count.data.swmod <= decoded_reg_strb.PRBS_Error_Count and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.LPF_Accum_F1.req <= decoded_reg_strb.LPF_Accum_F1 when not decoded_req_is_wr else '0'; - hwif_out.LPF_Accum_F1.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.LPF_Accum_F1.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Accum_F1.data.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Accum_F1 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Accum_F1.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.LPF_Accum_F1.data.we then -- HW Write - we + next_c := hwif_in.LPF_Accum_F1.data.next_q; + load_next_c := '1'; + end if; + field_combo.LPF_Accum_F1.data.next_q <= next_c; + field_combo.LPF_Accum_F1.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Accum_F1.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Accum_F1.data.value <= 32x"0"; + else + if field_combo.LPF_Accum_F1.data.load_next then + field_storage.LPF_Accum_F1.data.value <= field_combo.LPF_Accum_F1.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Accum_F1.data.swmod <= decoded_reg_strb.LPF_Accum_F1 and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.LPF_Accum_F2.req <= decoded_reg_strb.LPF_Accum_F2 when not decoded_req_is_wr else '0'; - hwif_out.LPF_Accum_F2.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.LPF_Accum_F2.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.LPF_Accum_F2.data.value; + load_next_c := '0'; + if decoded_reg_strb.LPF_Accum_F2 and decoded_req_is_wr then -- SW write + next_c := (field_storage.LPF_Accum_F2.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.LPF_Accum_F2.data.we then -- HW Write - we + next_c := hwif_in.LPF_Accum_F2.data.next_q; + load_next_c := '1'; + end if; + field_combo.LPF_Accum_F2.data.next_q <= next_c; + field_combo.LPF_Accum_F2.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.LPF_Accum_F2.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.LPF_Accum_F2.data.value <= 32x"0"; + else + if field_combo.LPF_Accum_F2.data.load_next then + field_storage.LPF_Accum_F2.data.value <= field_combo.LPF_Accum_F2.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.LPF_Accum_F2.data.swmod <= decoded_reg_strb.LPF_Accum_F2 and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.axis_xfer_count.req <= decoded_reg_strb.axis_xfer_count when not decoded_req_is_wr else '0'; - hwif_out.axis_xfer_count.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.axis_xfer_count.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.axis_xfer_count.data.value; + load_next_c := '0'; + if decoded_reg_strb.axis_xfer_count and decoded_req_is_wr then -- SW write + next_c := (field_storage.axis_xfer_count.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.axis_xfer_count.data.we then -- HW Write - we + next_c := hwif_in.axis_xfer_count.data.next_q; + load_next_c := '1'; + end if; + field_combo.axis_xfer_count.data.next_q <= next_c; + field_combo.axis_xfer_count.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.axis_xfer_count.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.axis_xfer_count.data.value <= 32x"0"; + else + if field_combo.axis_xfer_count.data.load_next then + field_storage.axis_xfer_count.data.value <= field_combo.axis_xfer_count.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.axis_xfer_count.data.swmod <= decoded_reg_strb.axis_xfer_count and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); -- Field: msk_top_regs.Rx_Sample_Discard.rx_sample_discard process(all) @@ -2091,17 +2512,133 @@ begin end process; hwif_out.LPF_Config_2.p_shift.value <= field_storage.LPF_Config_2.p_shift.value; - hwif_out.f1_nco_adjust.req <= decoded_reg_strb.f1_nco_adjust when not decoded_req_is_wr else '0'; - hwif_out.f1_nco_adjust.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.f1_nco_adjust.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.f1_nco_adjust.data.value; + load_next_c := '0'; + if decoded_reg_strb.f1_nco_adjust and decoded_req_is_wr then -- SW write + next_c := (field_storage.f1_nco_adjust.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.f1_nco_adjust.data.we then -- HW Write - we + next_c := hwif_in.f1_nco_adjust.data.next_q; + load_next_c := '1'; + end if; + field_combo.f1_nco_adjust.data.next_q <= next_c; + field_combo.f1_nco_adjust.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.f1_nco_adjust.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.f1_nco_adjust.data.value <= 32x"0"; + else + if field_combo.f1_nco_adjust.data.load_next then + field_storage.f1_nco_adjust.data.value <= field_combo.f1_nco_adjust.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.f1_nco_adjust.data.swmod <= decoded_reg_strb.f1_nco_adjust and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.f2_nco_adjust.req <= decoded_reg_strb.f2_nco_adjust when not decoded_req_is_wr else '0'; - hwif_out.f2_nco_adjust.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.f2_nco_adjust.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.f2_nco_adjust.data.value; + load_next_c := '0'; + if decoded_reg_strb.f2_nco_adjust and decoded_req_is_wr then -- SW write + next_c := (field_storage.f2_nco_adjust.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.f2_nco_adjust.data.we then -- HW Write - we + next_c := hwif_in.f2_nco_adjust.data.next_q; + load_next_c := '1'; + end if; + field_combo.f2_nco_adjust.data.next_q <= next_c; + field_combo.f2_nco_adjust.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.f2_nco_adjust.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.f2_nco_adjust.data.value <= 32x"0"; + else + if field_combo.f2_nco_adjust.data.load_next then + field_storage.f2_nco_adjust.data.value <= field_combo.f2_nco_adjust.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.f2_nco_adjust.data.swmod <= decoded_reg_strb.f2_nco_adjust and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.f1_error.req <= decoded_reg_strb.f1_error when not decoded_req_is_wr else '0'; - hwif_out.f1_error.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.f1_error.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.f1_error.data.value; + load_next_c := '0'; + if decoded_reg_strb.f1_error and decoded_req_is_wr then -- SW write + next_c := (field_storage.f1_error.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.f1_error.data.we then -- HW Write - we + next_c := hwif_in.f1_error.data.next_q; + load_next_c := '1'; + end if; + field_combo.f1_error.data.next_q <= next_c; + field_combo.f1_error.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.f1_error.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.f1_error.data.value <= 32x"0"; + else + if field_combo.f1_error.data.load_next then + field_storage.f1_error.data.value <= field_combo.f1_error.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.f1_error.data.swmod <= decoded_reg_strb.f1_error and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.f2_error.req <= decoded_reg_strb.f2_error when not decoded_req_is_wr else '0'; - hwif_out.f2_error.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.f2_error.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.f2_error.data.value; + load_next_c := '0'; + if decoded_reg_strb.f2_error and decoded_req_is_wr then -- SW write + next_c := (field_storage.f2_error.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.f2_error.data.we then -- HW Write - we + next_c := hwif_in.f2_error.data.next_q; + load_next_c := '1'; + end if; + field_combo.f2_error.data.next_q <= next_c; + field_combo.f2_error.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.f2_error.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.f2_error.data.value <= 32x"0"; + else + if field_combo.f2_error.data.load_next then + field_storage.f2_error.data.value <= field_combo.f2_error.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.f2_error.data.swmod <= decoded_reg_strb.f2_error and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); -- Field: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena process(all) @@ -2306,54 +2843,112 @@ begin end process; hwif_out.lowpass_ema_alpha2.alpha.value <= field_storage.lowpass_ema_alpha2.alpha.value; - hwif_out.rx_power.req <= decoded_reg_strb.rx_power when not decoded_req_is_wr else '0'; - hwif_out.rx_power.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.rx_power.data + process(all) + variable next_c: std_logic_vector(22 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_power.data.value; + load_next_c := '0'; + if decoded_reg_strb.rx_power and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_power.data.value and not decoded_wr_biten(22 downto 0)) or (decoded_wr_data(22 downto 0) and decoded_wr_biten(22 downto 0)); + load_next_c := '1'; + elsif hwif_in.rx_power.data.we then -- HW Write - we + next_c := hwif_in.rx_power.data.next_q; + load_next_c := '1'; + end if; + field_combo.rx_power.data.next_q <= next_c; + field_combo.rx_power.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_power.data.value <= 23x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_power.data.value <= 23x"0"; + else + if field_combo.rx_power.data.load_next then + field_storage.rx_power.data.value <= field_combo.rx_power.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.rx_power.data.swmod <= decoded_reg_strb.rx_power and decoded_req_is_wr and or_reduce(decoded_wr_biten(22 downto 0)); - hwif_out.tx_async_fifo_rd_wr_ptr.req <= decoded_reg_strb.tx_async_fifo_rd_wr_ptr when not decoded_req_is_wr else '0'; - hwif_out.tx_async_fifo_rd_wr_ptr.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.tx_async_fifo_rd_wr_ptr.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.tx_async_fifo_rd_wr_ptr.data.value; + load_next_c := '0'; + if decoded_reg_strb.tx_async_fifo_rd_wr_ptr and decoded_req_is_wr then -- SW write + next_c := (field_storage.tx_async_fifo_rd_wr_ptr.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.tx_async_fifo_rd_wr_ptr.data.we then -- HW Write - we + next_c := hwif_in.tx_async_fifo_rd_wr_ptr.data.next_q; + load_next_c := '1'; + end if; + field_combo.tx_async_fifo_rd_wr_ptr.data.next_q <= next_c; + field_combo.tx_async_fifo_rd_wr_ptr.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.tx_async_fifo_rd_wr_ptr.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.tx_async_fifo_rd_wr_ptr.data.value <= 32x"0"; + else + if field_combo.tx_async_fifo_rd_wr_ptr.data.load_next then + field_storage.tx_async_fifo_rd_wr_ptr.data.value <= field_combo.tx_async_fifo_rd_wr_ptr.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.tx_async_fifo_rd_wr_ptr.data.swmod <= decoded_reg_strb.tx_async_fifo_rd_wr_ptr and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - hwif_out.rx_async_fifo_rd_wr_ptr.req <= decoded_reg_strb.rx_async_fifo_rd_wr_ptr when not decoded_req_is_wr else '0'; - hwif_out.rx_async_fifo_rd_wr_ptr.req_is_wr <= decoded_req_is_wr; + -- Field: msk_top_regs.rx_async_fifo_rd_wr_ptr.data + process(all) + variable next_c: std_logic_vector(31 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_async_fifo_rd_wr_ptr.data.value; + load_next_c := '0'; + if decoded_reg_strb.rx_async_fifo_rd_wr_ptr and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_async_fifo_rd_wr_ptr.data.value and not decoded_wr_biten(31 downto 0)) or (decoded_wr_data(31 downto 0) and decoded_wr_biten(31 downto 0)); + load_next_c := '1'; + elsif hwif_in.rx_async_fifo_rd_wr_ptr.data.we then -- HW Write - we + next_c := hwif_in.rx_async_fifo_rd_wr_ptr.data.next_q; + load_next_c := '1'; + end if; + field_combo.rx_async_fifo_rd_wr_ptr.data.next_q <= next_c; + field_combo.rx_async_fifo_rd_wr_ptr.data.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_async_fifo_rd_wr_ptr.data.value <= 32x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_async_fifo_rd_wr_ptr.data.value <= 32x"0"; + else + if field_combo.rx_async_fifo_rd_wr_ptr.data.load_next then + field_storage.rx_async_fifo_rd_wr_ptr.data.value <= field_combo.rx_async_fifo_rd_wr_ptr.data.next_q; + end if; + end if; + end if; + end process; + hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod <= decoded_reg_strb.rx_async_fifo_rd_wr_ptr and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); ---------------------------------------------------------------------------- -- Write response ---------------------------------------------------------------------------- - process(all) - variable wr_ack: std_logic; - begin - wr_ack := '0'; - - external_wr_ack <= wr_ack; - end process; - cpuif_wr_ack <= external_wr_ack or (decoded_req and decoded_req_is_wr and not decoded_strb_is_external); + cpuif_wr_ack <= decoded_req and decoded_req_is_wr; -- Writes are always granted with no error response cpuif_wr_err <= '0'; ---------------------------------------------------------------------------- -- Readback ---------------------------------------------------------------------------- - process(all) - variable rd_ack: std_logic; - begin - rd_ack := '0'; - rd_ack := rd_ack or hwif_in.Tx_Bit_Count.rd_ack; - rd_ack := rd_ack or hwif_in.Tx_Enable_Count.rd_ack; - rd_ack := rd_ack or hwif_in.PRBS_Bit_Count.rd_ack; - rd_ack := rd_ack or hwif_in.PRBS_Error_Count.rd_ack; - rd_ack := rd_ack or hwif_in.LPF_Accum_F1.rd_ack; - rd_ack := rd_ack or hwif_in.LPF_Accum_F2.rd_ack; - rd_ack := rd_ack or hwif_in.axis_xfer_count.rd_ack; - rd_ack := rd_ack or hwif_in.f1_nco_adjust.rd_ack; - rd_ack := rd_ack or hwif_in.f2_nco_adjust.rd_ack; - rd_ack := rd_ack or hwif_in.f1_error.rd_ack; - rd_ack := rd_ack or hwif_in.f2_error.rd_ack; - rd_ack := rd_ack or hwif_in.rx_power.rd_ack; - rd_ack := rd_ack or hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack; - rd_ack := rd_ack or hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack; - readback_external_rd_ack_c <= rd_ack; - end process; - - readback_external_rd_ack <= readback_external_rd_ack_c; -- Assign readback values to a flattened array readback_array(0)(31 downto 0) <= 32x"AAAA5555" when (decoded_reg_strb.Hash_ID_Low and not decoded_req_is_wr) else (others => '0'); @@ -2373,8 +2968,8 @@ begin readback_array(4)(2 downto 2) <= to_std_logic_vector(hwif_in.MSK_Status.rx_enable.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); readback_array(4)(3 downto 3) <= to_std_logic_vector(hwif_in.MSK_Status.tx_axis_valid.next_q) when (decoded_reg_strb.MSK_Status and not decoded_req_is_wr) else (others => '0'); readback_array(4)(31 downto 4) <= (others => '0'); - readback_array(5) <= hwif_in.Tx_Bit_Count.rd_data when hwif_in.Tx_Bit_Count.rd_ack else (others => '0'); - readback_array(6) <= hwif_in.Tx_Enable_Count.rd_data when hwif_in.Tx_Enable_Count.rd_ack else (others => '0'); + readback_array(5)(31 downto 0) <= field_storage.Tx_Bit_Count.data.value when (decoded_reg_strb.Tx_Bit_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(6)(31 downto 0) <= field_storage.Tx_Enable_Count.data.value when (decoded_reg_strb.Tx_Enable_Count and not decoded_req_is_wr) else (others => '0'); readback_array(7)(31 downto 0) <= field_storage.Fb_FreqWord.config_data.value when (decoded_reg_strb.Fb_FreqWord and not decoded_req_is_wr) else (others => '0'); readback_array(8)(31 downto 0) <= field_storage.TX_F1_FreqWord.config_data.value when (decoded_reg_strb.TX_F1_FreqWord and not decoded_req_is_wr) else (others => '0'); readback_array(9)(31 downto 0) <= field_storage.TX_F2_FreqWord.config_data.value when (decoded_reg_strb.TX_F2_FreqWord and not decoded_req_is_wr) else (others => '0'); @@ -2397,20 +2992,20 @@ begin readback_array(17)(31 downto 0) <= field_storage.PRBS_Initial_State.config_data.value when (decoded_reg_strb.PRBS_Initial_State and not decoded_req_is_wr) else (others => '0'); readback_array(18)(31 downto 0) <= field_storage.PRBS_Polynomial.config_data.value when (decoded_reg_strb.PRBS_Polynomial and not decoded_req_is_wr) else (others => '0'); readback_array(19)(31 downto 0) <= field_storage.PRBS_Error_Mask.config_data.value when (decoded_reg_strb.PRBS_Error_Mask and not decoded_req_is_wr) else (others => '0'); - readback_array(20) <= hwif_in.PRBS_Bit_Count.rd_data when hwif_in.PRBS_Bit_Count.rd_ack else (others => '0'); - readback_array(21) <= hwif_in.PRBS_Error_Count.rd_data when hwif_in.PRBS_Error_Count.rd_ack else (others => '0'); - readback_array(22) <= hwif_in.LPF_Accum_F1.rd_data when hwif_in.LPF_Accum_F1.rd_ack else (others => '0'); - readback_array(23) <= hwif_in.LPF_Accum_F2.rd_data when hwif_in.LPF_Accum_F2.rd_ack else (others => '0'); - readback_array(24) <= hwif_in.axis_xfer_count.rd_data when hwif_in.axis_xfer_count.rd_ack else (others => '0'); + readback_array(20)(31 downto 0) <= field_storage.PRBS_Bit_Count.data.value when (decoded_reg_strb.PRBS_Bit_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(21)(31 downto 0) <= field_storage.PRBS_Error_Count.data.value when (decoded_reg_strb.PRBS_Error_Count and not decoded_req_is_wr) else (others => '0'); + readback_array(22)(31 downto 0) <= field_storage.LPF_Accum_F1.data.value when (decoded_reg_strb.LPF_Accum_F1 and not decoded_req_is_wr) else (others => '0'); + readback_array(23)(31 downto 0) <= field_storage.LPF_Accum_F2.data.value when (decoded_reg_strb.LPF_Accum_F2 and not decoded_req_is_wr) else (others => '0'); + readback_array(24)(31 downto 0) <= field_storage.axis_xfer_count.data.value when (decoded_reg_strb.axis_xfer_count and not decoded_req_is_wr) else (others => '0'); readback_array(25)(7 downto 0) <= field_storage.Rx_Sample_Discard.rx_sample_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); readback_array(25)(15 downto 8) <= field_storage.Rx_Sample_Discard.rx_nco_discard.value when (decoded_reg_strb.Rx_Sample_Discard and not decoded_req_is_wr) else (others => '0'); readback_array(25)(31 downto 16) <= (others => '0'); readback_array(26)(23 downto 0) <= field_storage.LPF_Config_2.p_gain.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); readback_array(26)(31 downto 24) <= field_storage.LPF_Config_2.p_shift.value when (decoded_reg_strb.LPF_Config_2 and not decoded_req_is_wr) else (others => '0'); - readback_array(27) <= hwif_in.f1_nco_adjust.rd_data when hwif_in.f1_nco_adjust.rd_ack else (others => '0'); - readback_array(28) <= hwif_in.f2_nco_adjust.rd_data when hwif_in.f2_nco_adjust.rd_ack else (others => '0'); - readback_array(29) <= hwif_in.f1_error.rd_data when hwif_in.f1_error.rd_ack else (others => '0'); - readback_array(30) <= hwif_in.f2_error.rd_data when hwif_in.f2_error.rd_ack else (others => '0'); + readback_array(27)(31 downto 0) <= field_storage.f1_nco_adjust.data.value when (decoded_reg_strb.f1_nco_adjust and not decoded_req_is_wr) else (others => '0'); + readback_array(28)(31 downto 0) <= field_storage.f2_nco_adjust.data.value when (decoded_reg_strb.f2_nco_adjust and not decoded_req_is_wr) else (others => '0'); + readback_array(29)(31 downto 0) <= field_storage.f1_error.data.value when (decoded_reg_strb.f1_error and not decoded_req_is_wr) else (others => '0'); + readback_array(30)(31 downto 0) <= field_storage.f2_error.data.value when (decoded_reg_strb.f2_error and not decoded_req_is_wr) else (others => '0'); readback_array(31)(0 downto 0) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_ena.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); readback_array(31)(1 downto 1) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_force.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); readback_array(31)(2 downto 2) <= to_std_logic_vector(field_storage.Tx_Sync_Ctrl.tx_sync_f1.value) when (decoded_reg_strb.Tx_Sync_Ctrl and not decoded_req_is_wr) else (others => '0'); @@ -2422,15 +3017,16 @@ begin readback_array(33)(31 downto 18) <= (others => '0'); readback_array(34)(17 downto 0) <= field_storage.lowpass_ema_alpha2.alpha.value when (decoded_reg_strb.lowpass_ema_alpha2 and not decoded_req_is_wr) else (others => '0'); readback_array(34)(31 downto 18) <= (others => '0'); - readback_array(35) <= hwif_in.rx_power.rd_data when hwif_in.rx_power.rd_ack else (others => '0'); - readback_array(36) <= hwif_in.tx_async_fifo_rd_wr_ptr.rd_data when hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack else (others => '0'); - readback_array(37) <= hwif_in.rx_async_fifo_rd_wr_ptr.rd_data when hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack else (others => '0'); + readback_array(35)(22 downto 0) <= field_storage.rx_power.data.value when (decoded_reg_strb.rx_power and not decoded_req_is_wr) else (others => '0'); + readback_array(35)(31 downto 23) <= (others => '0'); + readback_array(36)(31 downto 0) <= field_storage.tx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.tx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); + readback_array(37)(31 downto 0) <= field_storage.rx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.rx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); -- Reduce the array process(all) variable readback_data_var : std_logic_vector(31 downto 0) := (others => '0'); begin - readback_done <= decoded_req and not decoded_req_is_wr and not decoded_strb_is_external; + readback_done <= decoded_req and not decoded_req_is_wr; readback_err <= '0'; readback_data_var := (others => '0'); for i in readback_array'RANGE loop @@ -2439,8 +3035,7 @@ begin readback_data <= readback_data_var; end process; - external_rd_ack <= readback_external_rd_ack; - cpuif_rd_ack <= readback_done or readback_external_rd_ack; + cpuif_rd_ack <= readback_done; cpuif_rd_data <= readback_data; cpuif_rd_err <= readback_err; end architecture rtl; diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd index 394906e..c7439ad 100644 --- a/rdl/outputs/rtl/msk_top_regs_pkg.vhd +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -34,92 +34,143 @@ package msk_top_regs_pkg is tx_axis_valid : \msk_top_regs.msk_stat_0.tx_axis_valid_in_t\; end record; - type \msk_top_regs.msk_stat_1__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_1.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.msk_stat_2__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_1_in_t\ is record + data : \msk_top_regs.msk_stat_1.data_in_t\; end record; - type \msk_top_regs.stat_32_bits__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_2.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.stat_32_errs__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_2_in_t\ is record + data : \msk_top_regs.msk_stat_2.data_in_t\; end record; - type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_bits.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_bits_in_t\ is record + data : \msk_top_regs.stat_32_bits.data_in_t\; end record; - type \msk_top_regs.msk_stat_3__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_errs.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_errs_in_t\ is record + data : \msk_top_regs.stat_32_errs.data_in_t\; end record; - type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\ is record + data : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.data_in_t\; end record; - type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.rx_power__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\ is record + data : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.data_in_t\; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_3.data_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_in_t\ is record - rd_ack : std_logic; - rd_data : std_logic_vector(31 downto 0); + type \msk_top_regs.msk_stat_3_in_t\ is record + data : \msk_top_regs.msk_stat_3.data_in_t\; + end record; + + type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\ is record + data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\; + end record; + + type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\ is record + data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\; + end record; + + type \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\ is record + data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\; + end record; + + type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\ is record + data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\; + end record; + + type \msk_top_regs.rx_power.data_in_t\ is record + next_q : std_logic_vector(22 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.rx_power_in_t\ is record + data : \msk_top_regs.rx_power.data_in_t\; + end record; + + type \msk_top_regs.data32_desc_7b98a70e_in_t\ is record + next_q : std_logic_vector(31 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_in_t\ is record + data : \msk_top_regs.data32_desc_7b98a70e_in_t\; + end record; + + type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_in_t\ is record + data : \msk_top_regs.data32_desc_7b98a70e_in_t\; end record; type msk_top_regs_in_t is record MSK_Status : \msk_top_regs.msk_stat_0_in_t\; - Tx_Bit_Count : \msk_top_regs.msk_stat_1__external_in_t\; - Tx_Enable_Count : \msk_top_regs.msk_stat_2__external_in_t\; - PRBS_Bit_Count : \msk_top_regs.stat_32_bits__external_in_t\; - PRBS_Error_Count : \msk_top_regs.stat_32_errs__external_in_t\; - LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_in_t\; - LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_in_t\; - axis_xfer_count : \msk_top_regs.msk_stat_3__external_in_t\; - f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_in_t\; - f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_in_t\; - f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_in_t\; - f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_in_t\; - rx_power : \msk_top_regs.rx_power__external_in_t\; - tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_in_t\; - rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_in_t\; + Tx_Bit_Count : \msk_top_regs.msk_stat_1_in_t\; + Tx_Enable_Count : \msk_top_regs.msk_stat_2_in_t\; + PRBS_Bit_Count : \msk_top_regs.stat_32_bits_in_t\; + PRBS_Error_Count : \msk_top_regs.stat_32_errs_in_t\; + LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\; + LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\; + axis_xfer_count : \msk_top_regs.msk_stat_3_in_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\; + f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\; + f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\; + rx_power : \msk_top_regs.rx_power_in_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_in_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_in_t\; end record; type \msk_top_regs.msk_init.txrxinit_out_t\ is record @@ -168,14 +219,20 @@ package msk_top_regs_pkg is diff_encoder_loopback : \msk_top_regs.msk_ctrl.diff_encoder_loopback_out_t\; end record; - type \msk_top_regs.msk_stat_1__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.msk_stat_1.data_out_t\ is record + swmod : std_logic; end record; - type \msk_top_regs.msk_stat_2__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.msk_stat_1_out_t\ is record + data : \msk_top_regs.msk_stat_1.data_out_t\; + end record; + + type \msk_top_regs.msk_stat_2.data_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.msk_stat_2_out_t\ is record + data : \msk_top_regs.msk_stat_2.data_out_t\; end record; type \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469.config_data_out_t\ is record @@ -327,29 +384,44 @@ package msk_top_regs_pkg is config_data : \msk_top_regs.config_prbs_errmask.config_data_out_t\; end record; - type \msk_top_regs.stat_32_bits__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.stat_32_bits.data_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.stat_32_bits_out_t\ is record + data : \msk_top_regs.stat_32_bits.data_out_t\; + end record; + + type \msk_top_regs.stat_32_errs.data_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.stat_32_errs_out_t\ is record + data : \msk_top_regs.stat_32_errs.data_out_t\; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.data_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_out_t\ is record + data : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670.data_out_t\; end record; - type \msk_top_regs.stat_32_errs__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.data_out_t\ is record + swmod : std_logic; end record; - type \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_out_t\ is record + data : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce.data_out_t\; end record; - type \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.msk_stat_3.data_out_t\ is record + swmod : std_logic; end record; - type \msk_top_regs.msk_stat_3__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.msk_stat_3_out_t\ is record + data : \msk_top_regs.msk_stat_3.data_out_t\; end record; type \msk_top_regs.rx_sample_discard.rx_sample_discard_out_t\ is record @@ -378,24 +450,36 @@ package msk_top_regs_pkg is p_shift : \msk_top_regs.lpf_config_2.p_shift_out_t\; end record; - type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_out_t\ is record + data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_out_t\; + end record; + + type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_out_t\ is record + data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_out_t\; end record; - type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.data32_desc_417e1c96_name_3b640507_out_t\ is record + swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_out_t\ is record + data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_out_t\; end record; - type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_out_t\ is record + data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_out_t\; end record; type \msk_top_regs.tx_sync_ctrl.tx_sync_ena_out_t\ is record @@ -437,26 +521,31 @@ package msk_top_regs_pkg is alpha : \msk_top_regs.lowpass_ema_alpha.alpha_out_t\; end record; - type \msk_top_regs.rx_power__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.rx_power.data_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.rx_power_out_t\ is record + data : \msk_top_regs.rx_power.data_out_t\; + end record; + + type \msk_top_regs.data32_desc_7b98a70e_out_t\ is record + swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_out_t\ is record + data : \msk_top_regs.data32_desc_7b98a70e_out_t\; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_out_t\ is record - req : std_logic; - req_is_wr : std_logic; + type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_out_t\ is record + data : \msk_top_regs.data32_desc_7b98a70e_out_t\; end record; type msk_top_regs_out_t is record MSK_Init : \msk_top_regs.msk_init_out_t\; MSK_Control : \msk_top_regs.msk_ctrl_out_t\; - Tx_Bit_Count : \msk_top_regs.msk_stat_1__external_out_t\; - Tx_Enable_Count : \msk_top_regs.msk_stat_2__external_out_t\; + Tx_Bit_Count : \msk_top_regs.msk_stat_1_out_t\; + Tx_Enable_Count : \msk_top_regs.msk_stat_2_out_t\; Fb_FreqWord : \msk_top_regs.config_nco_fw_desc_c4924cc6_name_0c494469_out_t\; TX_F1_FreqWord : \msk_top_regs.config_nco_fw_desc_94d7aaf5_name_84dd0c1c_out_t\; TX_F2_FreqWord : \msk_top_regs.config_nco_fw_desc_42134a4f_name_d97dbd51_out_t\; @@ -470,23 +559,23 @@ package msk_top_regs_pkg is PRBS_Initial_State : \msk_top_regs.config_prbs_seed_out_t\; PRBS_Polynomial : \msk_top_regs.config_prbs_poly_out_t\; PRBS_Error_Mask : \msk_top_regs.config_prbs_errmask_out_t\; - PRBS_Bit_Count : \msk_top_regs.stat_32_bits__external_out_t\; - PRBS_Error_Count : \msk_top_regs.stat_32_errs__external_out_t\; - LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670__external_out_t\; - LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce__external_out_t\; - axis_xfer_count : \msk_top_regs.msk_stat_3__external_out_t\; + PRBS_Bit_Count : \msk_top_regs.stat_32_bits_out_t\; + PRBS_Error_Count : \msk_top_regs.stat_32_errs_out_t\; + LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_out_t\; + LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_out_t\; + axis_xfer_count : \msk_top_regs.msk_stat_3_out_t\; Rx_Sample_Discard : \msk_top_regs.rx_sample_discard_out_t\; LPF_Config_2 : \msk_top_regs.lpf_config_2_out_t\; - f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25__external_out_t\; - f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788__external_out_t\; - f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507__external_out_t\; - f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3__external_out_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_out_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_out_t\; + f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_out_t\; + f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_out_t\; Tx_Sync_Ctrl : \msk_top_regs.tx_sync_ctrl_out_t\; Tx_Sync_Cnt : \msk_top_regs.tx_sync_cnt_out_t\; lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha_out_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha_out_t\; - rx_power : \msk_top_regs.rx_power__external_out_t\; - tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676__external_out_t\; - rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1__external_out_t\; + rx_power : \msk_top_regs.rx_power_out_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_out_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_out_t\; end record; end package; diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index 852fc5f..f8a2598 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -180,10 +180,11 @@ addrmap msk_top_regs { field { name = "Tx Bit Count"; desc = "Count of data requests made by modem"; - sw = r; + sw = rw; hw = w; - onread = ruser; - } tx_bit_counter[31:0]; + we = true; + swmod = true; + } data[31:0] = 0; }; reg msk_stat_2 { @@ -193,10 +194,11 @@ addrmap msk_top_regs { field { desc = "Number of clocks on which Tx Enable is active"; name = "Tx Enable Count"; - sw = r; + sw = rw; hw = w; - onread = ruser; - } tx_ena_counter[31:0] = 0; + we = true; + swmod = true; + } data[31:0] = 0; }; reg config_nco_fw { @@ -362,9 +364,11 @@ addrmap msk_top_regs { name = "PRBS Bits Received"; desc = "Number of bits received by the PRBS monitor since last BER can be calculated as the ratio of received bits to errored-bits"; - sw = r; + sw = rw; hw = w; - } status_data[31:0] = 0; + we = true; + swmod = true; + } data[31:0] = 0; }; reg stat_32_errs { @@ -375,9 +379,11 @@ addrmap msk_top_regs { name = "PRBS Bit Errors"; desc = "Number of errored-bits received by the PRBS monitor since last sync BER can be calculated as the ratio of received bits to errored-bits"; - sw = r; + sw = rw; hw = w; - } status_data[31:0] = 0; + we = true; + swmod = true; + } data[31:0] = 0; }; reg stat_32_lpf_acc { @@ -385,9 +391,11 @@ addrmap msk_top_regs { field { name = "PI Controller Accumulator Value"; desc = "PI Controller Accumulator Value"; - sw = r; + sw = rw; hw = w; - } status_data[31:0] = 0; + we = true; + swmod = true; + } data[31:0] = 0; }; reg msk_stat_3 { @@ -397,9 +405,11 @@ addrmap msk_top_regs { field { desc = "Number completed S_AXIS transfers"; name = "S_AXIS Transfers"; - sw = r; + sw = rw; hw = w; - } xfer_count[31:0] = 0; + we = true; + swmod = true; + } data[31:0] = 0; }; reg tx_sync_ctrl { @@ -463,16 +473,19 @@ addrmap msk_top_regs { field { name = "Receive Power"; desc = "Value that represent the RMS power of the incoming I;"; - sw = r; + sw = rw; hw = w; - } rx_power[22:0] = 0; + we = true; + swmod = true; + } data[22:0] = 0; }; field data32 { fieldwidth = 32; - sw = r; - hw = w; - onread = ruser; + sw = rw; + hw = w; + we = true; + swmod = true; }; reg observation_data { @@ -481,82 +494,82 @@ addrmap msk_top_regs { }; - msk_hash_lo Hash_ID_Low; - msk_hash_hi Hash_ID_High; - msk_init MSK_Init; - msk_ctrl MSK_Control; - msk_stat_0 MSK_Status; - external msk_stat_1 Tx_Bit_Count; - external msk_stat_2 Tx_Enable_Count; - config_nco_fw Fb_FreqWord; - Fb_FreqWord->desc = "Set Modem Data Rate"; - Fb_FreqWord->name = "Bitrate NCO Frequency Control Word"; - config_nco_fw TX_F1_FreqWord; - TX_F1_FreqWord->desc = "Set Modulator F1 Frequency"; - TX_F1_FreqWord->name = "Tx F1 NCO Frequency Control Word"; - config_nco_fw TX_F2_FreqWord; - TX_F2_FreqWord->desc = "Set Modulator F2 Frequency"; - TX_F2_FreqWord->name = "Tx F2 NCO Frequency Control Word"; - config_nco_fw RX_F1_FreqWord; - RX_F1_FreqWord->desc = "Set Demodulator F1 Frequency"; - RX_F1_FreqWord->name = "Rx F1 NCO Frequency Control Word"; - config_nco_fw RX_F2_FreqWord; - RX_F2_FreqWord->desc = "Set Demodulator F2 Frequency"; - RX_F2_FreqWord->name = "Rx F2 NCO Frequency Control Word"; - lpf_config_0 LPF_Config_0; - lpf_config_1 LPF_Config_1; - data_width Tx_Data_Width; - Tx_Data_Width->desc = "Set the parallel data width of the parallel-to-serial converter"; - Tx_Data_Width->name = "Modem Tx Input Data Width"; - data_width Rx_Data_Width; - Rx_Data_Width->desc = "Set the parallel data width of the serial-to-parallel converter"; - Rx_Data_Width->name = "Modem Rx Output Data Width"; - prbs_ctrl PRBS_Control; - config_prbs_seed PRBS_Initial_State; - config_prbs_poly PRBS_Polynomial; - config_prbs_errmask PRBS_Error_Mask; - external stat_32_bits PRBS_Bit_Count; - external stat_32_errs PRBS_Error_Count; - external stat_32_lpf_acc LPF_Accum_F1; - LPF_Accum_F1->name = "F1 PI Controller Accumulator"; - LPF_Accum_F1->desc = "Value of the F1 PI Controller Accumulator"; - external stat_32_lpf_acc LPF_Accum_F2; - LPF_Accum_F2->name = "F2 PI Controller Accumulator"; - LPF_Accum_F2->desc = "Value of the F2 PI Controller Accumulator"; - external msk_stat_3 axis_xfer_count; - rx_sample_discard Rx_Sample_Discard; - lpf_config_2 LPF_Config_2; - external observation_data f1_nco_adjust; - f1_nco_adjust->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; - f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; - external observation_data f2_nco_adjust; - f2_nco_adjust->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; - f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; - external observation_data f1_error; - f1_error->name = "F1 Error Value"; - f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; - f1_error.data->name = "F1 Error Value"; - f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; - external observation_data f2_error; - f2_error->name = "F2 Error Value"; - f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; - f2_error.data->name = "F2 Error Value"; - f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period"; - tx_sync_ctrl Tx_Sync_Ctrl; - tx_sync_cnt Tx_Sync_Cnt; - lowpass_ema_alpha lowpass_ema_alpha1; - lowpass_ema_alpha lowpass_ema_alpha2; - external rx_power rx_power; - external observation_data tx_async_fifo_rd_wr_ptr; - tx_async_fifo_rd_wr_ptr->name = "Tx async FIFO read and write pointers"; - tx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) - Bits 15:00 -> read pointer (12-bits)"; - external observation_data rx_async_fifo_rd_wr_ptr; - rx_async_fifo_rd_wr_ptr->name = "Rx async FIFO read and write pointers"; - rx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) - Bits 15:00 -> read pointer (12-bits)"; + msk_hash_lo Hash_ID_Low; + msk_hash_hi Hash_ID_High; + msk_init MSK_Init; + msk_ctrl MSK_Control; + msk_stat_0 MSK_Status; + msk_stat_1 Tx_Bit_Count; + msk_stat_2 Tx_Enable_Count; + config_nco_fw Fb_FreqWord; + Fb_FreqWord->desc = "Set Modem Data Rate"; + Fb_FreqWord->name = "Bitrate NCO Frequency Control Word"; + config_nco_fw TX_F1_FreqWord; + TX_F1_FreqWord->desc = "Set Modulator F1 Frequency"; + TX_F1_FreqWord->name = "Tx F1 NCO Frequency Control Word"; + config_nco_fw TX_F2_FreqWord; + TX_F2_FreqWord->desc = "Set Modulator F2 Frequency"; + TX_F2_FreqWord->name = "Tx F2 NCO Frequency Control Word"; + config_nco_fw RX_F1_FreqWord; + RX_F1_FreqWord->desc = "Set Demodulator F1 Frequency"; + RX_F1_FreqWord->name = "Rx F1 NCO Frequency Control Word"; + config_nco_fw RX_F2_FreqWord; + RX_F2_FreqWord->desc = "Set Demodulator F2 Frequency"; + RX_F2_FreqWord->name = "Rx F2 NCO Frequency Control Word"; + lpf_config_0 LPF_Config_0; + lpf_config_1 LPF_Config_1; + data_width Tx_Data_Width; + Tx_Data_Width->desc = "Set the parallel data width of the parallel-to-serial converter"; + Tx_Data_Width->name = "Modem Tx Input Data Width"; + data_width Rx_Data_Width; + Rx_Data_Width->desc = "Set the parallel data width of the serial-to-parallel converter"; + Rx_Data_Width->name = "Modem Rx Output Data Width"; + prbs_ctrl PRBS_Control; + config_prbs_seed PRBS_Initial_State; + config_prbs_poly PRBS_Polynomial; + config_prbs_errmask PRBS_Error_Mask; + stat_32_bits PRBS_Bit_Count; + stat_32_errs PRBS_Error_Count; + stat_32_lpf_acc LPF_Accum_F1; + LPF_Accum_F1->name = "F1 PI Controller Accumulator"; + LPF_Accum_F1->desc = "Value of the F1 PI Controller Accumulator"; + stat_32_lpf_acc LPF_Accum_F2; + LPF_Accum_F2->name = "F2 PI Controller Accumulator"; + LPF_Accum_F2->desc = "Value of the F2 PI Controller Accumulator"; + msk_stat_3 axis_xfer_count; + rx_sample_discard Rx_Sample_Discard; + lpf_config_2 LPF_Config_2; + observation_data f1_nco_adjust; + f1_nco_adjust->name = "F1 NCO Frequency Adjust"; + f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; + f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; + f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; + observation_data f2_nco_adjust; + f2_nco_adjust->name = "F2 NCO Frequency Adjust"; + f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; + f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; + f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; + observation_data f1_error; + f1_error->name = "F1 Error Value"; + f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; + f1_error.data->name = "F1 Error Value"; + f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; + observation_data f2_error; + f2_error->name = "F2 Error Value"; + f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; + f2_error.data->name = "F2 Error Value"; + f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period"; + tx_sync_ctrl Tx_Sync_Ctrl; + tx_sync_cnt Tx_Sync_Cnt; + lowpass_ema_alpha lowpass_ema_alpha1; + lowpass_ema_alpha lowpass_ema_alpha2; + rx_power rx_power; + observation_data tx_async_fifo_rd_wr_ptr; + tx_async_fifo_rd_wr_ptr->name = "Tx async FIFO read and write pointers"; + tx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) + Bits 15:00 -> read pointer (12-bits)"; + observation_data rx_async_fifo_rd_wr_ptr; + rx_async_fifo_rd_wr_ptr->name = "Rx async FIFO read and write pointers"; + rx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) + Bits 15:00 -> read pointer (12-bits)"; }; diff --git a/sim/msk_test.py b/sim/msk_test.py index d063eba..c19b048 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -265,6 +265,8 @@ async def write_dwords(self,addr, data): async def read(self, addr, width, accesswidth): await RisingEdge(self.aclk) + await RisingEdge(self.aclk) + await RisingEdge(self.aclk) self.arvalid.value = 1 self.araddr.value = addr @@ -826,16 +828,22 @@ async def msk_test_1(dut): sim_time_d = sim_time sim_time = get_sim_time("us") + await regs.f1_nco_adjust.write(0) data = await regs.f1_nco_adjust.read() print("F1 NCO Adjust: ", hex(data)) + await regs.f2_nco_adjust.write(0) data = await regs.f2_nco_adjust.read() print("F2 NCO Adjust: ", hex(data)) + await regs.f1_error.write(0) data = await regs.f1_error.read() print("F1 Error: ", hex(data)) + await regs.f2_error.write(0) data = await regs.f2_error.read() print("F2 Error: ", hex(data)) + await regs.tx_async_fifo_rd_wr_ptr.write(0) data = await regs.tx_async_fifo_rd_wr_ptr.read() print("Tx FIFO Pointers", hex(data)) + await regs.rx_async_fifo_rd_wr_ptr.write(0) data = await regs.rx_async_fifo_rd_wr_ptr.read() print("Rx FIFO Pointers", hex(data)) #data = await regs.read("msk_top_regs", "LPF_Accum_F1") diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index ee86e51..830c1c8 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -301,58 +301,58 @@ BEGIN hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; -- Status Request from AXI to MDM - utbc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Bit_Count.req, tx_bit_counter_req ); - utbe_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Enable_Count.req, tx_ena_counter_req ); - utatc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.axis_xfer_count.req, axis_xfer_count_req ); - utf1e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_error.req, f1_error_req ); - utf2e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_error.req, f2_error_req ); - utf1a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_nco_adjust.req, f1_nco_adjust_req ); - utf2a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_nco_adjust.req, f2_nco_adjust_req ); - utprb_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Bit_Count.req, prbs_bits_req ); - utpre_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Error_Count.req, prbs_errs_req ); - utlp1_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F1.req, lpf_accum_f1_req ); - utlp2_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F2.req, lpf_accum_f2_req ); - utpwr_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_power.req, pd_power_req ); + utbc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Bit_Count.data.swmod, tx_bit_counter_req ); + utbe_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.Tx_Enable_Count.data.swmod, tx_ena_counter_req ); + utatc_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.axis_xfer_count.data.swmod, axis_xfer_count_req ); + utf1e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_error.data.swmod, f1_error_req ); + utf2e_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_error.data.swmod, f2_error_req ); + utf1a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f1_nco_adjust.data.swmod, f1_nco_adjust_req ); + utf2a_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.f2_nco_adjust.data.swmod, f2_nco_adjust_req ); + utprb_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Bit_Count.data.swmod, prbs_bits_req ); + utpre_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.PRBS_Error_Count.data.swmod, prbs_errs_req ); + utlp1_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F1.data.swmod, lpf_accum_f1_req ); + utlp2_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F2.data.swmod, lpf_accum_f2_req ); + utpwr_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_power.data.swmod, pd_power_req ); -- Status acknowledge from MDM to AXI - utbc_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_bit_counter_req, hwif_in.Tx_Bit_Count.rd_ack ); - utbe_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_ena_counter_req, hwif_in.Tx_Enable_Count.rd_ack ); - utatc_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, axis_xfer_count_req, hwif_in.axis_xfer_count.rd_ack ); - utf1e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_error_req, hwif_in.f1_error.rd_ack ); - utf2e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_error_req, hwif_in.f2_error.rd_ack ); - utf1a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_nco_adjust_req, hwif_in.f1_nco_adjust.rd_ack ); - utf2a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_nco_adjust_req, hwif_in.f2_nco_adjust.rd_ack ); - utprb_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_bits_req, hwif_in.PRBS_Bit_Count.rd_ack ); - utpre_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_errs_req, hwif_in.PRBS_Error_Count.rd_ack ); - utlp1_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f1_req, hwif_in.LPF_Accum_F1.rd_ack ); - utlp2_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f2_req, hwif_in.LPF_Accum_F2.rd_ack ); - utpwr_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, pd_power_req, hwif_in.rx_power.rd_ack ); + utbc_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_bit_counter_req, hwif_in.Tx_Bit_Count.data.we ); + utbe_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_ena_counter_req, hwif_in.Tx_Enable_Count.data.we ); + utatc_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, axis_xfer_count_req, hwif_in.axis_xfer_count.data.we ); + utf1e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_error_req, hwif_in.f1_error.data.we ); + utf2e_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_error_req, hwif_in.f2_error.data.we ); + utf1a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f1_nco_adjust_req, hwif_in.f1_nco_adjust.data.we ); + utf2a_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, f2_nco_adjust_req, hwif_in.f2_nco_adjust.data.we ); + utprb_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_bits_req, hwif_in.PRBS_Bit_Count.data.we ); + utpre_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, prbs_errs_req, hwif_in.PRBS_Error_Count.data.we ); + utlp1_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f1_req, hwif_in.LPF_Accum_F1.data.we ); + utlp2_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f2_req, hwif_in.LPF_Accum_F2.data.we ); + utpwr_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, pd_power_req, hwif_in.rx_power.data.we ); -- Status capture from MDM to AXI - utbc_c : data_capture PORT MAP (clk, csr_init, tx_bit_counter_req, tx_bit_counter, hwif_in.Tx_Bit_Count.rd_data ); - utbe_c : data_capture PORT MAP (clk, csr_init, tx_ena_counter_req, tx_ena_counter, hwif_in.Tx_Enable_Count.rd_data ); - utatc_c: data_capture PORT MAP (clk, csr_init, axis_xfer_count_req, xfer_count, hwif_in.axis_xfer_count.rd_data ); - utf1e_c: data_capture PORT MAP (clk, csr_init, f1_error_req, f1_error, hwif_in.f1_error.rd_data ); - utf2e_c: data_capture PORT MAP (clk, csr_init, f2_error_req, f2_error, hwif_in.f2_error.rd_data ); - utf1a_c: data_capture PORT MAP (clk, csr_init, f1_nco_adjust_req, f1_nco_adjust, hwif_in.f1_nco_adjust.rd_data ); - utf2a_c: data_capture PORT MAP (clk, csr_init, f2_nco_adjust_req, f2_nco_adjust, hwif_in.f2_nco_adjust.rd_data ); - utprb_c: data_capture PORT MAP (clk, csr_init, prbs_bits_req, prbs_bits, hwif_in.PRBS_Bit_Count.rd_data ); - utpre_c: data_capture PORT MAP (clk, csr_init, prbs_errs_req, prbs_errs, hwif_in.PRBS_Error_Count.rd_data); - utlp1_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f1_req, lpf_accum_f1, hwif_in.LPF_Accum_F1.rd_data ); - utlp2_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f2_req, lpf_accum_f2, hwif_in.LPF_Accum_F2.rd_data ); - utpwr_c: data_capture PORT MAP (clk, csr_init, pd_power_req, std_logic_vector(resize(unsigned(pd_power),32)), - hwif_in.rx_power.rd_data); + utbc_c : data_capture PORT MAP (clk, csr_init, tx_bit_counter_req, tx_bit_counter, hwif_in.Tx_Bit_Count.data.next_q ); + utbe_c : data_capture PORT MAP (clk, csr_init, tx_ena_counter_req, tx_ena_counter, hwif_in.Tx_Enable_Count.data.next_q ); + utatc_c: data_capture PORT MAP (clk, csr_init, axis_xfer_count_req, xfer_count, hwif_in.axis_xfer_count.data.next_q ); + utf1e_c: data_capture PORT MAP (clk, csr_init, f1_error_req, f1_error, hwif_in.f1_error.data.next_q ); + utf2e_c: data_capture PORT MAP (clk, csr_init, f2_error_req, f2_error, hwif_in.f2_error.data.next_q ); + utf1a_c: data_capture PORT MAP (clk, csr_init, f1_nco_adjust_req, f1_nco_adjust, hwif_in.f1_nco_adjust.data.next_q ); + utf2a_c: data_capture PORT MAP (clk, csr_init, f2_nco_adjust_req, f2_nco_adjust, hwif_in.f2_nco_adjust.data.next_q ); + utprb_c: data_capture PORT MAP (clk, csr_init, prbs_bits_req, prbs_bits, hwif_in.PRBS_Bit_Count.data.next_q ); + utpre_c: data_capture PORT MAP (clk, csr_init, prbs_errs_req, prbs_errs, hwif_in.PRBS_Error_Count.data.next_q); + utlp1_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f1_req, lpf_accum_f1, hwif_in.LPF_Accum_F1.data.next_q ); + utlp2_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f2_req, lpf_accum_f2, hwif_in.LPF_Accum_F2.data.next_q ); + utpwr_c: data_capture GENERIC MAP (23) + PORT MAP (clk, csr_init, pd_power_req, pd_power, hwif_in.rx_power.data.next_q ); -- FIFO status reads - rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.req; - hwif_in.rx_async_fifo_rd_wr_ptr.rd_ack <= rx_async_fifo_status_ack; - hwif_in.rx_async_fifo_rd_wr_ptr.rd_data <= std_logic_vector(resize(unsigned(rx_async_fifo_wr_ptr), 16) & - resize(unsigned(rx_async_fifo_rd_ptr), 16)); - - tx_async_fifo_status_req <= hwif_out.tx_async_fifo_rd_wr_ptr.req; - hwif_in.tx_async_fifo_rd_wr_ptr.rd_ack <= tx_async_fifo_status_ack; - hwif_in.tx_async_fifo_rd_wr_ptr.rd_data <= std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 16) & - resize(unsigned(tx_async_fifo_rd_ptr), 16)); + rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod; + hwif_in.rx_async_fifo_rd_wr_ptr.data.we <= rx_async_fifo_status_ack; + hwif_in.rx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(rx_async_fifo_wr_ptr), 16) & + resize(unsigned(rx_async_fifo_rd_ptr), 16)); + + tx_async_fifo_status_req <= hwif_out.tx_async_fifo_rd_wr_ptr.data.swmod; + hwif_in.tx_async_fifo_rd_wr_ptr.data.we <= tx_async_fifo_status_ack; + hwif_in.tx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 16) & + resize(unsigned(tx_async_fifo_rd_ptr), 16)); -- Control from AXI to MDM u01s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txrxinit.value, txrxinit ); From fce224f8ff99c6d64876f33ed0e48fa44bc77cd9 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Tue, 4 Nov 2025 12:22:17 -0700 Subject: [PATCH 21/60] rdl: update descriptions for write-to-capture registers --- rdl/outputs/c-header/msk_top_regs.h | 68 +- rdl/outputs/docs/msk_top_regs.md | 182 ++++-- rdl/outputs/docs/msk_top_regs.pdf | Bin 113978 -> 115808 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 596 +++++++++--------- .../msk_top_regs/tests/test_msk_top_regs.py | 82 +-- rdl/outputs/rtl/msk_top_regs_pkg.vhd | 92 +-- rdl/src/msk_top_regs.rdl | 181 +++++- 7 files changed, 693 insertions(+), 508 deletions(-) diff --git a/rdl/outputs/c-header/msk_top_regs.h b/rdl/outputs/c-header/msk_top_regs.h index 58f9611..d5b3d65 100644 --- a/rdl/outputs/c-header/msk_top_regs.h +++ b/rdl/outputs/c-header/msk_top_regs.h @@ -253,29 +253,29 @@ extern "C" { #define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_bw 8 #define MSK_TOP_REGS__LPF_CONFIG_2__P_SHIFT_reset 0x0 -// Reg - msk_top_regs::observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0C017EF4_DESC_64FF3689_NAME_D8AD3B25__DATA_reset 0x0 - -// Reg - msk_top_regs::observation_data_data_0515efaa_desc_ebde6d39_name_2c154788 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0515EFAA_DESC_EBDE6D39_NAME_2C154788__DATA_reset 0x0 - -// Reg - msk_top_regs::observation_data_data_25a21249_desc_417e1c96_name_3b640507 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_25A21249_DESC_417E1C96_NAME_3B640507__DATA_reset 0x0 - -// Reg - msk_top_regs::observation_data_data_272a00b6_desc_70869502_name_3de9a0d3 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_272A00B6_DESC_70869502_NAME_3DE9A0D3__DATA_reset 0x0 +// Reg - msk_top_regs::observation_data_data_521c7d53_name_d8ad3b25 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_521C7D53_NAME_D8AD3B25__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_521C7D53_NAME_D8AD3B25__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_521C7D53_NAME_D8AD3B25__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_521C7D53_NAME_D8AD3B25__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_5802c5b1_name_2c154788 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_5802C5B1_NAME_2C154788__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_5802C5B1_NAME_2C154788__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_5802C5B1_NAME_2C154788__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_5802C5B1_NAME_2C154788__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_f83682dd_name_3b640507 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_F83682DD_NAME_3B640507__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_F83682DD_NAME_3B640507__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_F83682DD_NAME_3B640507__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_F83682DD_NAME_3B640507__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_0a9850a4_name_3de9a0d3 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0A9850A4_NAME_3DE9A0D3__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0A9850A4_NAME_3DE9A0D3__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0A9850A4_NAME_3DE9A0D3__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_0A9850A4_NAME_3DE9A0D3__DATA_reset 0x0 // Reg - msk_top_regs::tx_sync_ctrl #define MSK_TOP_REGS__TX_SYNC_CTRL__TX_SYNC_ENA_bm 0x1 @@ -313,17 +313,17 @@ extern "C" { #define MSK_TOP_REGS__RX_POWER__DATA_bw 23 #define MSK_TOP_REGS__RX_POWER__DATA_reset 0x0 -// Reg - msk_top_regs::observation_data_data_cf6acbd7_name_aa4ec676 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_AA4EC676__DATA_reset 0x0 - -// Reg - msk_top_regs::observation_data_data_cf6acbd7_name_8a90eed1 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_CF6ACBD7_NAME_8A90EED1__DATA_reset 0x0 +// Reg - msk_top_regs::observation_data_data_dbd8270c_name_aa4ec676 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_reset 0x0 + +// Reg - msk_top_regs::observation_data_data_dbd8270c_name_8a90eed1 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_reset 0x0 // Addrmap - msk_top_regs typedef struct __attribute__ ((__packed__)) { diff --git a/rdl/outputs/docs/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md index b1db448..b657208 100644 --- a/rdl/outputs/docs/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -99,18 +99,18 @@ Don't override. Generated from: msk_top_regs #### txrxinit field -

0 -> Normal modem operation -1 -> Initialize Tx and Rx

+

0 -> Normal modem operation

+

1 -> Initialize Tx and Rx

#### txinit field -

0 -> Normal Tx operation -1 -> Initialize Tx

+

0 -> Normal Tx operation

+

1 -> Initialize Tx

#### rxinit field -

0 -> Normal Rx operation -1 -> Initialize Rx

+

0 -> Normal Rx operation

+

1 -> Initialize Rx

### MSK_Control register @@ -135,8 +135,8 @@ Don't override. Generated from: msk_top_regs #### loopback_ena field -

0 -> Modem loopback disabled -1 -> Modem loopback enabled

+

0 -> Modem loopback disabled

+

1 -> Modem loopback enabled

#### rx_invert field @@ -149,8 +149,8 @@ Don't override. Generated from: msk_top_regs #### diff_encoder_loopback field -

0 -> Differential Encoder -> Decoder loopback disabled -1 -> Differential Encoder -> Decoder loopback enabled

+

0 -> Differential Encoder -> Decoder loopback disabled

+

1 -> Differential Encoder -> Decoder loopback enabled

### MSK_Status register @@ -173,18 +173,18 @@ Don't override. Generated from: msk_top_regs #### tx_enable field -

1 -> Data to DAC Enabled -0 -> Data to DAC Disabled

+

1 -> Data to DAC Enabled

+

0 -> Data to DAC Disabled

#### rx_enable field -

1 -> Data from ADC Enabled -0 -> Data from ADC Disabled

+

1 -> Data from ADC Enabled

+

0 -> Data from ADC Disabled

#### tx_axis_valid field -

1 -> S_AXIS_VALID Enabled -0 -> S_AXIS_VALID Disabled

+

1 -> S_AXIS_VALID Enabled

+

0 -> S_AXIS_VALID Disabled

### Tx_Bit_Count register @@ -201,6 +201,10 @@ Don't override. Generated from: msk_top_regs #### data field

Count of data requests made by modem

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### Tx_Enable_Count register @@ -217,6 +221,10 @@ Don't override. Generated from: msk_top_regs #### data field

Number of clocks on which Tx Enable is active

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### Fb_FreqWord register @@ -320,13 +328,13 @@ where Fn is the desired NCO frequency, and Fs is the NCO sample rate

#### lpf_freeze field -

0 -> Normal operation -1 -> Freeze current value

+

0 -> Normal operation

+

1 -> Freeze current value

#### lpf_zero field -

0 -> Normal operation -1 -> Zero and hold accumulator

+

0 -> Normal operation

+

1 -> Zero and hold accumulator

#### lpf_alpha field @@ -409,23 +417,23 @@ where Fn is the desired NCO frequency, and Fs is the NCO sample rate

#### prbs_error_insert field -

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) -1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

+

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS)

+

1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

#### prbs_clear field -

0 -> 1 : Clear PRBS Counters -1 -> 0 : Clear PRBS Counters

+

0 -> 1 : Clear PRBS Counters

+

1 -> 0 : Clear PRBS Counters

#### prbs_manual_sync field -

0 -> 1 : Synchronize PRBS monitor -1 -> 0 : Synchronize PRBS monitor

+

0 -> 1 : Synchronize PRBS monitor

+

1 -> 0 : Synchronize PRBS monitor

#### prbs_sync_threshold field -

0 : Auto Sync Disabled -N > 0 : Auto sync after N errors

+

0 : Auto Sync Disabled

+

N > 0 : Auto sync after N errors

### PRBS_Initial_State register @@ -491,6 +499,10 @@ N > 0 : Auto sync after N errors

Number of bits received by the PRBS monitor since last BER can be calculated as the ratio of received bits to errored-bits

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### PRBS_Error_Count register @@ -508,6 +520,10 @@ BER can be calculated as the ratio of received bits to errored-bits

Number of errored-bits received by the PRBS monitor since last sync BER can be calculated as the ratio of received bits to errored-bits

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### LPF_Accum_F1 register @@ -524,6 +540,10 @@ BER can be calculated as the ratio of received bits to errored-bits

#### data field

PI Controller Accumulator Value

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### LPF_Accum_F2 register @@ -540,6 +560,10 @@ BER can be calculated as the ratio of received bits to errored-bits

#### data field

PI Controller Accumulator Value

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### axis_xfer_count register @@ -556,6 +580,10 @@ BER can be calculated as the ratio of received bits to errored-bits

#### data field

Number completed S_AXIS transfers

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### Rx_Sample_Discard register @@ -605,15 +633,17 @@ BER can be calculated as the ratio of received bits to errored-bits

- Base Offset: 0x6C - Size: 0x4 -

Frequency offet applied to the F1 NCO

- -|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|-----------------------| -|31:0| data | rw | 0x0 |F1 NCO Frequency Adjust| +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field

Frequency offet applied to the F1 NCO

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### f2_nco_adjust register @@ -621,15 +651,17 @@ BER can be calculated as the ratio of received bits to errored-bits

- Base Offset: 0x70 - Size: 0x4 -

Frequency offet applied to the F2 NCO

- -|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|-----------------------| -|31:0| data | rw | 0x0 |F2 NCO Frequency Adjust| +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field

Frequency offet applied to the F2 NCO

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### f1_error register @@ -637,15 +669,17 @@ BER can be calculated as the ratio of received bits to errored-bits

- Base Offset: 0x74 - Size: 0x4 -

Error value of the F1 Costas loop after each active bit period

- -|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|--------------| -|31:0| data | rw | 0x0 |F1 Error Value| +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field

Error value of the F1 Costas loop after each active bit period

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### f2_error register @@ -653,15 +687,17 @@ BER can be calculated as the ratio of received bits to errored-bits

- Base Offset: 0x78 - Size: 0x4 -

Error value of the F2 Costas loop after each active bit period

- -|Bits|Identifier|Access|Reset| Name | -|----|----------|------|-----|--------------| -|31:0| data | rw | 0x0 |F2 Error Value| +|Bits|Identifier|Access|Reset|Name| +|----|----------|------|-----|----| +|31:0| data | rw | 0x0 | — | #### data field

Error value of the F2 Costas loop after each active bit period

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### Tx_Sync_Ctrl register @@ -680,27 +716,27 @@ BER can be calculated as the ratio of received bits to errored-bits

#### tx_sync_ena field -

0 -> Disable sync transmission -1 -> Enable sync transmission when PTT is asserted

+

0 -> Disable sync transmission

+

1 -> Enable sync transmission when PTT is asserted

#### tx_sync_force field -

0 : Normal operation) -1 : Transmit synchronization pattern)

+

0 : Normal operation

+

1 : Transmit synchronization pattern

#### tx_sync_f1 field

Enables/Disables transmission of F1 tone for receiver synchronization -0 : F1 tone transmission disabled -1 : F1 tone transmission enabled -Both F1 and F2 can be enabled at the same time

+0 : F1 tone transmission disabled

+

1 : F1 tone transmission enabled

+

Both F1 and F2 can be enabled at the same time

#### tx_sync_f2 field

Enables/Disables transmission of F2 tone for receiver synchronization -0 : F2 tone transmission disabled -1 : F2 tone transmission enabled -Both F1 and F2 can be enabled at the same time

+0 : F2 tone transmission disabled

+

1 : F2 tone transmission enabled

+

Both F1 and F2 can be enabled at the same time

### Tx_Sync_Cnt register @@ -716,9 +752,9 @@ Both F1 and F2 can be enabled at the same time

#### tx_sync_cnt field -

Value from 0x00_0000 to 0xFF_FFFF. -This value represents the number bit-times the synchronization -signal should be sent after PTT is asserted.

+

Value from 0x00_0000 to 0xFF_FFFF.

+

This value represents the number bit-times the synchronization

+

signal should be sent after PTT is asserted.

### lowpass_ema_alpha1 register @@ -766,7 +802,11 @@ signal should be sent after PTT is asserted.

#### data field -

Value that represent the RMS power of the incoming I;

+

Value that represent the RMS power of the incoming I

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### tx_async_fifo_rd_wr_ptr register @@ -780,8 +820,13 @@ signal should be sent after PTT is asserted.

#### data field -

Bits 31:16 -> write pointer (12-bits) -Bits 15:00 -> read pointer (12-bits)

+

Read and Write Pointers

+

Bits 31:16 - write pointer (12-bits)

+

Bits 15:00 - read pointer (12-bits)

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

### rx_async_fifo_rd_wr_ptr register @@ -795,5 +840,10 @@ Bits 15:00 -> read pointer (12-bits)

#### data field -

Bits 31:16 -> write pointer (12-bits) -Bits 15:00 -> read pointer (12-bits)

+

Read and Write Pointers

+

Bits 31:16 - write pointer (12-bits)

+

Bits 15:00 - read pointer (12-bits)

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index 5319bc354e7c0dd86cb4e25489c4debd10c0b6a7..76457c20de05d81162c6da199d185a4ab9d09e49 100644 GIT binary patch delta 43745 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

dMulEX}mFF-R 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�RDyAq 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 diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py index 0ec486a..718508e 100644 --- a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -76,7 +76,7 @@ -class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_52ad9f96_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -87,8 +87,11 @@ class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadWrite): +==============+=========================================================================+ | Description | .. raw:: html | | | | - | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | - | | pointer (12-bits)

| + | |

Read and Write Pointers

Bits 31:16 - write pointer | + | | (12-bits)

Bits 15:00 - read pointer (12-bits)

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -101,14 +104,14 @@ class msk_top_regs_data32_desc_7b98a70e_cls(FieldAsyncReadWrite): @property def rdl_desc(self) -> str: - return "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)" + return "Read and Write Pointers\n\nBits 31:16 - write pointer (12-bits)\n\nBits 15:00 - read pointer (12-bits)\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -141,7 +144,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_7b98a70e_cls = msk_top_regs_data32_desc_7b98a70e_cls( + self.__data:msk_top_regs_data32_desc_52ad9f96_cls = msk_top_regs_data32_desc_52ad9f96_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -172,7 +175,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_7b98a70e_cls: + def data(self) -> msk_top_regs_data32_desc_52ad9f96_cls: """ Property to access data field of the register @@ -182,8 +185,11 @@ def data(self) -> msk_top_regs_data32_desc_7b98a70e_cls: +==============+=========================================================================+ | Description | .. raw:: html | | | | - | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | - | | pointer (12-bits)

| + | |

Read and Write Pointers

Bits 31:16 - write pointer | + | | (12-bits)

Bits 15:00 - read pointer (12-bits)

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -208,7 +214,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_52ad9f96_cls: return super().get_child_by_system_rdl_name(name) @@ -229,7 +235,7 @@ def rdl_name(self) -> str: -class msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_52ad9f96_0x0x105270e0_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -240,8 +246,11 @@ class msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls(FieldAsyncReadWrite): +==============+=========================================================================+ | Description | .. raw:: html | | | | - | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | - | | pointer (12-bits)

| + | |

Read and Write Pointers

Bits 31:16 - write pointer | + | | (12-bits)

Bits 15:00 - read pointer (12-bits)

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -254,14 +263,14 @@ class msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls(FieldAsyncReadWrite): @property def rdl_desc(self) -> str: - return "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)" + return "Read and Write Pointers\n\nBits 31:16 - write pointer (12-bits)\n\nBits 15:00 - read pointer (12-bits)\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -294,7 +303,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls = msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls( + self.__data:msk_top_regs_data32_desc_52ad9f96_0x0x105270e0_cls = msk_top_regs_data32_desc_52ad9f96_0x0x105270e0_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -325,7 +334,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls: + def data(self) -> msk_top_regs_data32_desc_52ad9f96_0x0x105270e0_cls: """ Property to access data field of the register @@ -335,8 +344,11 @@ def data(self) -> msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls: +==============+=========================================================================+ | Description | .. raw:: html | | | | - | |

Bits 31:16 -> write pointer (12-bits) Bits 15:00 -> read | - | | pointer (12-bits)

| + | |

Read and Write Pointers

Bits 31:16 - write pointer | + | | (12-bits)

Bits 15:00 - read pointer (12-bits)

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -361,7 +373,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_7b98a70e_0x0x105c7600_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_52ad9f96_0x0x105270e0_cls: return super().get_child_by_system_rdl_name(name) @@ -397,7 +409,10 @@ class msk_top_regs_rx_power_data_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Value that represent the RMS power of the incoming I;

| + | |

Value that represent the RMS power of the incoming I

| + | |

This register is write-to-capture.

To read data the | + | | following steps are required:

1 - Write any value to this | + | | register to capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -413,7 +428,7 @@ def rdl_name(self) -> str: return "Receive Power" @property def rdl_desc(self) -> str: - return "Value that represent the RMS power of the incoming I;" + return "Value that represent the RMS power of the incoming I\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -502,7 +517,10 @@ def data(self) -> msk_top_regs_rx_power_data_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Value that represent the RMS power of the incoming I;

| + | |

Value that represent the RMS power of the incoming I

| + | |

This register is write-to-capture.

To read data the | + | | following steps are required:

1 - Write any value to this | + | | register to capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -720,7 +738,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x10527152_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -758,7 +776,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -795,7 +813,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x10527152_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x10527152_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -826,7 +844,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x10527152_cls: """ Property to access alpha field of the register @@ -865,7 +883,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105c7501_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x10527152_cls: return super().get_child_by_system_rdl_name(name) @@ -904,9 +922,9 @@ class msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Value from 0x00_0000 to 0xFF_FFFF. This value represents the | - | | number bit-times the synchronization signal should be sent after | - | | PTT is asserted.

| + | |

Value from 0x00_0000 to 0xFF_FFFF.

This value | + | | represents the number bit-times the synchronization

signal | + | | should be sent after PTT is asserted.

| +--------------+-------------------------------------------------------------------------+ """ @@ -922,7 +940,7 @@ def rdl_name(self) -> str: return "Tx sync duration" @property def rdl_desc(self) -> str: - return "Value from 0x00_0000 to 0xFF_FFFF. \nThis value represents the number bit-times the synchronization \nsignal should be sent after PTT is asserted." + return "Value from 0x00_0000 to 0xFF_FFFF. \n\nThis value represents the number bit-times the synchronization \n\nsignal should be sent after PTT is asserted." @@ -1011,9 +1029,9 @@ def tx_sync_cnt(self) -> msk_top_regs_tx_sync_cnt_tx_sync_cnt_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Value from 0x00_0000 to 0xFF_FFFF. This value represents the | - | | number bit-times the synchronization signal should be sent after | - | | PTT is asserted.

| + | |

Value from 0x00_0000 to 0xFF_FFFF.

This value | + | | represents the number bit-times the synchronization

signal | + | | should be sent after PTT is asserted.

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_sync_cnt @@ -1078,9 +1096,9 @@ class msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls(FieldAsyncReadWrite): | Description | .. raw:: html | | | | | |

Enables/Disables transmission of F2 tone for receiver | - | | synchronization 0 : F2 tone transmission disabled 1 : F2 tone | - | | transmission enabled Both F1 and F2 can be enabled at the same | - | | time

| + | | synchronization 0 : F2 tone transmission disabled

1 : F2 | + | | tone transmission enabled

Both F1 and F2 can be enabled at | + | | the same time

| +--------------+-------------------------------------------------------------------------+ """ @@ -1096,7 +1114,7 @@ def rdl_name(self) -> str: return "Tx F2 Sync Enable" @property def rdl_desc(self) -> str: - return "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n1 : F2 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time" + return "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n\n1 : F2 tone transmission enabled\n\nBoth F1 and F2 can be enabled at the same time" @@ -1120,9 +1138,9 @@ class msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls(FieldAsyncReadWrite): | Description | .. raw:: html | | | | | |

Enables/Disables transmission of F1 tone for receiver | - | | synchronization 0 : F1 tone transmission disabled 1 : F1 tone | - | | transmission enabled Both F1 and F2 can be enabled at the same | - | | time

| + | | synchronization 0 : F1 tone transmission disabled

1 : F1 | + | | tone transmission enabled

Both F1 and F2 can be enabled at | + | | the same time

| +--------------+-------------------------------------------------------------------------+ """ @@ -1138,7 +1156,7 @@ def rdl_name(self) -> str: return "Tx F1 Sync Enable" @property def rdl_desc(self) -> str: - return "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n1 : F1 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time" + return "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n\n1 : F1 tone transmission enabled\n\nBoth F1 and F2 can be enabled at the same time" @@ -1161,7 +1179,8 @@ class msk_top_regs_tx_sync_ctrl_tx_sync_force_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 : Normal operation) 1 : Transmit synchronization pattern)

| + | |

0 : Normal operation

1 : Transmit synchronization | + | | pattern

| +--------------+-------------------------------------------------------------------------+ """ @@ -1177,7 +1196,7 @@ def rdl_name(self) -> str: return "Tx Sync Force" @property def rdl_desc(self) -> str: - return "0 : Normal operation)\n1 : Transmit synchronization pattern)" + return "0 : Normal operation\n\n1 : Transmit synchronization pattern" @@ -1200,7 +1219,7 @@ class msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Disable sync transmission 1 -> Enable sync | + | |

0 -> Disable sync transmission

1 -> Enable sync | | | transmission when PTT is asserted

| +--------------+-------------------------------------------------------------------------+ """ @@ -1217,7 +1236,7 @@ def rdl_name(self) -> str: return "Tx Sync Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Disable sync transmission\n1 -\u003e Enable sync transmission when PTT is asserted" + return "0 -\u003e Disable sync transmission\n\n1 -\u003e Enable sync transmission when PTT is asserted" @@ -1352,7 +1371,7 @@ def tx_sync_ena(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_ena_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Disable sync transmission 1 -> Enable sync | + | |

0 -> Disable sync transmission

1 -> Enable sync | | | transmission when PTT is asserted

| +--------------+-------------------------------------------------------------------------+ """ @@ -1372,7 +1391,8 @@ def tx_sync_force(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_force_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 : Normal operation) 1 : Transmit synchronization pattern)

| + | |

0 : Normal operation

1 : Transmit synchronization | + | | pattern

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_sync_force @@ -1392,9 +1412,9 @@ def tx_sync_f1(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_f1_cls: | Description | .. raw:: html | | | | | |

Enables/Disables transmission of F1 tone for receiver | - | | synchronization 0 : F1 tone transmission disabled 1 : F1 tone | - | | transmission enabled Both F1 and F2 can be enabled at the same | - | | time

| + | | synchronization 0 : F1 tone transmission disabled

1 : F1 | + | | tone transmission enabled

Both F1 and F2 can be enabled at | + | | the same time

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_sync_f1 @@ -1414,9 +1434,9 @@ def tx_sync_f2(self) -> msk_top_regs_tx_sync_ctrl_tx_sync_f2_cls: | Description | .. raw:: html | | | | | |

Enables/Disables transmission of F2 tone for receiver | - | | synchronization 0 : F2 tone transmission disabled 1 : F2 tone | - | | transmission enabled Both F1 and F2 can be enabled at the same | - | | time

| + | | synchronization 0 : F2 tone transmission disabled

1 : F2 | + | | tone transmission enabled

Both F1 and F2 can be enabled at | + | | the same time

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_sync_f2 @@ -1484,7 +1504,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_c8bf066a_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1493,14 +1513,13 @@ class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadWrite): | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F2 Error Value | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | | |

Error value of the F2 Costas loop after each active bit | - | | period

| + | | period

This register is write-to-capture.

To read | + | | data the following steps are required:

1 - Write any value | + | | to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ @@ -1511,19 +1530,16 @@ class msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls(FieldAsyncReadWrite): - @property - def rdl_name(self) -> str: - return "F2 Error Value" @property def rdl_desc(self) -> str: - return "Error value of the F2 Costas loop after each active bit period" + return "Error value of the F2 Costas loop after each active bit period\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1535,11 +1551,6 @@ class msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cl | | | | | F2 Error Value | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Error value of the F2 Costas loop after each active bit | - | | period

| - +--------------+-------------------------------------------------------------------------+ """ __slots__ : list[str] = ['__data'] @@ -1561,7 +1572,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls = msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls( + self.__data:msk_top_regs_data32_desc_c8bf066a_cls = msk_top_regs_data32_desc_c8bf066a_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -1592,7 +1603,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls: + def data(self) -> msk_top_regs_data32_desc_c8bf066a_cls: """ Property to access data field of the register @@ -1600,14 +1611,13 @@ def data(self) -> msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls: | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F2 Error Value | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | | |

Error value of the F2 Costas loop after each active bit | - | | period

| + | | period

This register is write-to-capture.

To read | + | | data the following steps are required:

1 - Write any value | + | | to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -1632,7 +1642,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_70869502_name_3de9a0d3_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_c8bf066a_cls: return super().get_child_by_system_rdl_name(name) @@ -1646,9 +1656,6 @@ def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_70 @property def rdl_name(self) -> str: return "F2 Error Value" - @property - def rdl_desc(self) -> str: - return "Error value of the F2 Costas loop after each active bit period" @@ -1656,7 +1663,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_83db1b72_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1665,14 +1672,13 @@ class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadWrite): | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F1 Error Value | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | | |

Error value of the F1 Costas loop after each active bit | - | | period

| + | | period

This register is write-to-capture.

To read | + | | data the following steps are required:

1 - Write any value | + | | to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ @@ -1683,19 +1689,16 @@ class msk_top_regs_data32_desc_417e1c96_name_3b640507_cls(FieldAsyncReadWrite): - @property - def rdl_name(self) -> str: - return "F1 Error Value" @property def rdl_desc(self) -> str: - return "Error value of the F1 Costas loop after each active bit period" + return "Error value of the F1 Costas loop after each active bit period\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1707,11 +1710,6 @@ class msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cl | | | | | F1 Error Value | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Error value of the F1 Costas loop after each active bit | - | | period

| - +--------------+-------------------------------------------------------------------------+ """ __slots__ : list[str] = ['__data'] @@ -1733,7 +1731,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_417e1c96_name_3b640507_cls = msk_top_regs_data32_desc_417e1c96_name_3b640507_cls( + self.__data:msk_top_regs_data32_desc_83db1b72_cls = msk_top_regs_data32_desc_83db1b72_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -1764,7 +1762,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_417e1c96_name_3b640507_cls: + def data(self) -> msk_top_regs_data32_desc_83db1b72_cls: """ Property to access data field of the register @@ -1772,14 +1770,13 @@ def data(self) -> msk_top_regs_data32_desc_417e1c96_name_3b640507_cls: | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F1 Error Value | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | | |

Error value of the F1 Costas loop after each active bit | - | | period

| + | | period

This register is write-to-capture.

To read | + | | data the following steps are required:

1 - Write any value | + | | to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -1804,7 +1801,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_417e1c96_name_3b640507_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_83db1b72_cls: return super().get_child_by_system_rdl_name(name) @@ -1818,9 +1815,6 @@ def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_41 @property def rdl_name(self) -> str: return "F1 Error Value" - @property - def rdl_desc(self) -> str: - return "Error value of the F1 Costas loop after each active bit period" @@ -1828,7 +1822,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_13897f4c_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1837,13 +1831,12 @@ class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadWrite): | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F2 NCO Frequency Adjust | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Frequency offet applied to the F2 NCO

| + | |

Frequency offet applied to the F2 NCO

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -1854,19 +1847,16 @@ class msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls(FieldAsyncReadWrite): - @property - def rdl_name(self) -> str: - return "F2 NCO Frequency Adjust" @property def rdl_desc(self) -> str: - return "Frequency offet applied to the F2 NCO" + return "Frequency offet applied to the F2 NCO\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1878,10 +1868,6 @@ class msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cl | | | | | F2 NCO Frequency Adjust | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Frequency offet applied to the F2 NCO

| - +--------------+-------------------------------------------------------------------------+ """ __slots__ : list[str] = ['__data'] @@ -1903,7 +1889,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls = msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls( + self.__data:msk_top_regs_data32_desc_13897f4c_cls = msk_top_regs_data32_desc_13897f4c_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -1934,7 +1920,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls: + def data(self) -> msk_top_regs_data32_desc_13897f4c_cls: """ Property to access data field of the register @@ -1942,13 +1928,12 @@ def data(self) -> msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls: | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F2 NCO Frequency Adjust | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Frequency offet applied to the F2 NCO

| + | |

Frequency offet applied to the F2 NCO

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -1973,7 +1958,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_ebde6d39_name_2c154788_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_13897f4c_cls: return super().get_child_by_system_rdl_name(name) @@ -1987,9 +1972,6 @@ def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_eb @property def rdl_name(self) -> str: return "F2 NCO Frequency Adjust" - @property - def rdl_desc(self) -> str: - return "Frequency offet applied to the F2 NCO" @@ -1997,7 +1979,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadWrite): +class msk_top_regs_data32_desc_0ed96915_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -2006,13 +1988,12 @@ class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadWrite): | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F1 NCO Frequency Adjust | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Frequency offet applied to the F1 NCO

| + | |

Frequency offet applied to the F1 NCO

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -2023,19 +2004,16 @@ class msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls(FieldAsyncReadWrite): - @property - def rdl_name(self) -> str: - return "F1 NCO Frequency Adjust" @property def rdl_desc(self) -> str: - return "Frequency offet applied to the F1 NCO" + return "Frequency offet applied to the F1 NCO\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" -class msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls(RegAsyncReadWrite): +class msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -2047,10 +2025,6 @@ class msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cl | | | | | F1 NCO Frequency Adjust | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Frequency offet applied to the F1 NCO

| - +--------------+-------------------------------------------------------------------------+ """ __slots__ : list[str] = ['__data'] @@ -2072,7 +2046,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls = msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls( + self.__data:msk_top_regs_data32_desc_0ed96915_cls = msk_top_regs_data32_desc_0ed96915_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2103,7 +2077,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls: + def data(self) -> msk_top_regs_data32_desc_0ed96915_cls: """ Property to access data field of the register @@ -2111,13 +2085,12 @@ def data(self) -> msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls: | SystemRDL | Value | | Field | | +==============+=========================================================================+ - | Name | .. raw:: html | - | | | - | | F1 NCO Frequency Adjust | - +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Frequency offet applied to the F1 NCO

| + | |

Frequency offet applied to the F1 NCO

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -2142,7 +2115,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_64ff3689_name_d8ad3b25_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_0ed96915_cls: return super().get_child_by_system_rdl_name(name) @@ -2156,9 +2129,6 @@ def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data32_desc_64 @property def rdl_name(self) -> str: return "F1 NCO Frequency Adjust" - @property - def rdl_desc(self) -> str: - return "Frequency offet applied to the F1 NCO" @@ -2687,7 +2657,10 @@ class msk_top_regs_msk_stat_3_data_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Number completed S_AXIS transfers

| + | |

Number completed S_AXIS transfers

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -2703,7 +2676,7 @@ def rdl_name(self) -> str: return "S_AXIS Transfers" @property def rdl_desc(self) -> str: - return "Number completed S_AXIS transfers" + return "Number completed S_AXIS transfers\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -2792,7 +2765,10 @@ def data(self) -> msk_top_regs_msk_stat_3_data_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Number completed S_AXIS transfers

| + | |

Number completed S_AXIS transfers

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -2856,7 +2832,10 @@ class msk_top_regs_stat_32_lpf_acc_data_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

PI Controller Accumulator Value

| + | |

PI Controller Accumulator Value

This register is write- | + | | to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -2872,7 +2851,7 @@ def rdl_name(self) -> str: return "PI Controller Accumulator Value" @property def rdl_desc(self) -> str: - return "PI Controller Accumulator Value" + return "PI Controller Accumulator Value\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -2961,7 +2940,10 @@ def data(self) -> msk_top_regs_stat_32_lpf_acc_data_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

PI Controller Accumulator Value

| + | |

PI Controller Accumulator Value

This register is write- | + | | to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -3010,7 +2992,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls(FieldAsyncReadWrite): +class msk_top_regs_stat_32_lpf_acc_data_0x0x10527359_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -3025,7 +3007,10 @@ class msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

PI Controller Accumulator Value

| + | |

PI Controller Accumulator Value

This register is write- | + | | to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -3041,7 +3026,7 @@ def rdl_name(self) -> str: return "PI Controller Accumulator Value" @property def rdl_desc(self) -> str: - return "PI Controller Accumulator Value" + return "PI Controller Accumulator Value\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -3085,7 +3070,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls( + self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x10527359_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x10527359_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -3116,7 +3101,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls: + def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10527359_cls: """ Property to access data field of the register @@ -3130,7 +3115,10 @@ def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

PI Controller Accumulator Value

| + | |

PI Controller Accumulator Value

This register is write- | + | | to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -3155,7 +3143,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x105c2672_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10527359_cls: return super().get_child_by_system_rdl_name(name) @@ -3196,7 +3184,10 @@ class msk_top_regs_stat_32_errs_data_cls(FieldAsyncReadWrite): | | | | |

Number of errored-bits received by the PRBS monitor since last | | | sync BER can be calculated as the ratio of received bits to | - | | errored-bits

| + | | errored-bits

This register is write-to-capture.

To | + | | read data the following steps are required:

1 - Write any | + | | value to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ @@ -3212,7 +3203,7 @@ def rdl_name(self) -> str: return "PRBS Bit Errors" @property def rdl_desc(self) -> str: - return "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits" + return "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -3303,7 +3294,10 @@ def data(self) -> msk_top_regs_stat_32_errs_data_cls: | | | | |

Number of errored-bits received by the PRBS monitor since last | | | sync BER can be calculated as the ratio of received bits to | - | | errored-bits

| + | | errored-bits

This register is write-to-capture.

To | + | | read data the following steps are required:

1 - Write any | + | | value to this register to capture read data

2 - Read the | + | | register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -3369,6 +3363,9 @@ class msk_top_regs_stat_32_bits_data_cls(FieldAsyncReadWrite): | | | | |

Number of bits received by the PRBS monitor since last BER can | | | be calculated as the ratio of received bits to errored-bits

| + | |

This register is write-to-capture.

To read data the | + | | following steps are required:

1 - Write any value to this | + | | register to capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -3384,7 +3381,7 @@ def rdl_name(self) -> str: return "PRBS Bits Received" @property def rdl_desc(self) -> str: - return "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits" + return "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -3475,6 +3472,9 @@ def data(self) -> msk_top_regs_stat_32_bits_data_cls: | | | | |

Number of bits received by the PRBS monitor since last BER can | | | be calculated as the ratio of received bits to errored-bits

| + | |

This register is write-to-capture.

To read data the | + | | following steps are required:

1 - Write any value to this | + | | register to capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -4049,7 +4049,8 @@ class msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 : Auto Sync Disabled N > 0 : Auto sync after N errors

| + | |

0 : Auto Sync Disabled

N > 0 : Auto sync after N | + | | errors

| +--------------+-------------------------------------------------------------------------+ """ @@ -4065,7 +4066,7 @@ def rdl_name(self) -> str: return "PRBS Auto Sync Threshold" @property def rdl_desc(self) -> str: - return "0 : Auto Sync Disabled\nN \u003e 0 : Auto sync after N errors" + return "0 : Auto Sync Disabled\n\nN \u003e 0 : Auto sync after N errors" @@ -4120,8 +4121,8 @@ class msk_top_regs_prbs_ctrl_prbs_manual_sync_cls(FieldAsyncWriteOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Synchronize PRBS monitor 1 -> 0 : Synchronize | - | | PRBS monitor

| + | |

0 -> 1 : Synchronize PRBS monitor

1 -> 0 : | + | | Synchronize PRBS monitor

| +--------------+-------------------------------------------------------------------------+ """ @@ -4137,7 +4138,7 @@ def rdl_name(self) -> str: return "PRBS Manual Sync" @property def rdl_desc(self) -> str: - return "0 -\u003e 1 : Synchronize PRBS monitor\n1 -\u003e 0 : Synchronize PRBS monitor" + return "0 -\u003e 1 : Synchronize PRBS monitor\n\n1 -\u003e 0 : Synchronize PRBS monitor" @@ -4160,7 +4161,7 @@ class msk_top_regs_prbs_ctrl_prbs_clear_cls(FieldAsyncWriteOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Clear PRBS Counters 1 -> 0 : Clear PRBS | + | |

0 -> 1 : Clear PRBS Counters

1 -> 0 : Clear PRBS | | | Counters

| +--------------+-------------------------------------------------------------------------+ """ @@ -4177,7 +4178,7 @@ def rdl_name(self) -> str: return "PRBS Clear Counters" @property def rdl_desc(self) -> str: - return "0 -\u003e 1 : Clear PRBS Counters\n1 -\u003e 0 : Clear PRBS Counters" + return "0 -\u003e 1 : Clear PRBS Counters\n\n1 -\u003e 0 : Clear PRBS Counters" @@ -4200,8 +4201,9 @@ class msk_top_regs_prbs_ctrl_prbs_error_insert_cls(FieldAsyncWriteOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) | - | | 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

| + | |

0 -> 1 : Insert bit error in Tx data (both Normal and | + | | PRBS)

1 -> 0 : Insert bit error in Tx data (both Normal | + | | and PRBS)

| +--------------+-------------------------------------------------------------------------+ """ @@ -4217,7 +4219,7 @@ def rdl_name(self) -> str: return "PRBS Error Insert" @property def rdl_desc(self) -> str: - return "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)" + return "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)" @@ -4439,8 +4441,9 @@ def prbs_error_insert(self) -> msk_top_regs_prbs_ctrl_prbs_error_insert_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) | - | | 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

| + | |

0 -> 1 : Insert bit error in Tx data (both Normal and | + | | PRBS)

1 -> 0 : Insert bit error in Tx data (both Normal | + | | and PRBS)

| +--------------+-------------------------------------------------------------------------+ """ return self.__prbs_error_insert @@ -4459,7 +4462,7 @@ def prbs_clear(self) -> msk_top_regs_prbs_ctrl_prbs_clear_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Clear PRBS Counters 1 -> 0 : Clear PRBS | + | |

0 -> 1 : Clear PRBS Counters

1 -> 0 : Clear PRBS | | | Counters

| +--------------+-------------------------------------------------------------------------+ """ @@ -4479,8 +4482,8 @@ def prbs_manual_sync(self) -> msk_top_regs_prbs_ctrl_prbs_manual_sync_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> 1 : Synchronize PRBS monitor 1 -> 0 : Synchronize | - | | PRBS monitor

| + | |

0 -> 1 : Synchronize PRBS monitor

1 -> 0 : | + | | Synchronize PRBS monitor

| +--------------+-------------------------------------------------------------------------+ """ return self.__prbs_manual_sync @@ -4514,7 +4517,8 @@ def prbs_sync_threshold(self) -> msk_top_regs_prbs_ctrl_prbs_sync_threshold_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 : Auto Sync Disabled N > 0 : Auto sync after N errors

| + | |

0 : Auto Sync Disabled

N > 0 : Auto sync after N | + | | errors

| +--------------+-------------------------------------------------------------------------+ """ return self.__prbs_sync_threshold @@ -4760,7 +4764,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x105dda63_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x1050d0ec_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -4836,7 +4840,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x105dda63_cls = msk_top_regs_data_width_data_width_0x0x105dda63_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x1050d0ec_cls = msk_top_regs_data_width_data_width_0x0x1050d0ec_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -4867,7 +4871,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x105dda63_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x1050d0ec_cls: """ Property to access data_width field of the register @@ -4906,7 +4910,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x105dda63_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x1050d0ec_cls: return super().get_child_by_system_rdl_name(name) @@ -5269,7 +5273,8 @@ class msk_top_regs_lpf_config_0_lpf_zero_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal operation 1 -> Zero and hold accumulator

| + | |

0 -> Normal operation

1 -> Zero and hold | + | | accumulator

| +--------------+-------------------------------------------------------------------------+ """ @@ -5285,7 +5290,7 @@ def rdl_name(self) -> str: return "Hold the PI Accumulator at zero" @property def rdl_desc(self) -> str: - return "0 -\u003e Normal operation\n1 -\u003e Zero and hold accumulator" + return "0 -\u003e Normal operation\n\n1 -\u003e Zero and hold accumulator" @@ -5308,7 +5313,8 @@ class msk_top_regs_lpf_config_0_lpf_freeze_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal operation 1 -> Freeze current value

| + | |

0 -> Normal operation

1 -> Freeze current | + | | value

| +--------------+-------------------------------------------------------------------------+ """ @@ -5324,7 +5330,7 @@ def rdl_name(self) -> str: return "Freeze the accumulator\u0027s current value" @property def rdl_desc(self) -> str: - return "0 -\u003e Normal operation\n1 -\u003e Freeze current value" + return "0 -\u003e Normal operation\n\n1 -\u003e Freeze current value" @@ -5458,7 +5464,8 @@ def lpf_freeze(self) -> msk_top_regs_lpf_config_0_lpf_freeze_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal operation 1 -> Freeze current value

| + | |

0 -> Normal operation

1 -> Freeze current | + | | value

| +--------------+-------------------------------------------------------------------------+ """ return self.__lpf_freeze @@ -5477,7 +5484,8 @@ def lpf_zero(self) -> msk_top_regs_lpf_config_0_lpf_zero_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal operation 1 -> Zero and hold accumulator

| + | |

0 -> Normal operation

1 -> Zero and hold | + | | accumulator

| +--------------+-------------------------------------------------------------------------+ """ return self.__lpf_zero @@ -5752,7 +5760,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1050efce_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5829,7 +5837,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1050efce_cls = msk_top_regs_config_nco_fw_config_data_0x0x1050efce_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5860,7 +5868,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1050efce_cls: """ Property to access config_data field of the register @@ -5901,7 +5909,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea0f_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1050efce_cls: return super().get_child_by_system_rdl_name(name) @@ -5925,7 +5933,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1050ed7f_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6002,7 +6010,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1050ed7f_cls = msk_top_regs_config_nco_fw_config_data_0x0x1050ed7f_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6033,7 +6041,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1050ed7f_cls: """ Property to access config_data field of the register @@ -6074,7 +6082,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea21_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1050ed7f_cls: return super().get_child_by_system_rdl_name(name) @@ -6098,7 +6106,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10511cc5_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6175,7 +6183,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10511cc5_cls = msk_top_regs_config_nco_fw_config_data_0x0x10511cc5_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6206,7 +6214,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10511cc5_cls: """ Property to access config_data field of the register @@ -6247,7 +6255,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea63_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10511cc5_cls: return super().get_child_by_system_rdl_name(name) @@ -6271,7 +6279,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10511c86_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6348,7 +6356,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls = msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10511c86_cls = msk_top_regs_config_nco_fw_config_data_0x0x10511c86_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6379,7 +6387,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10511c86_cls: """ Property to access config_data field of the register @@ -6420,7 +6428,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105dea75_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10511c86_cls: return super().get_child_by_system_rdl_name(name) @@ -6459,7 +6467,10 @@ class msk_top_regs_msk_stat_2_data_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Number of clocks on which Tx Enable is active

| + | |

Number of clocks on which Tx Enable is active

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -6475,7 +6486,7 @@ def rdl_name(self) -> str: return "Tx Enable Count" @property def rdl_desc(self) -> str: - return "Number of clocks on which Tx Enable is active" + return "Number of clocks on which Tx Enable is active\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -6564,7 +6575,10 @@ def data(self) -> msk_top_regs_msk_stat_2_data_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Number of clocks on which Tx Enable is active

| + | |

Number of clocks on which Tx Enable is active

This | + | | register is write-to-capture.

To read data the following | + | | steps are required:

1 - Write any value to this register to | + | | capture read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -6628,7 +6642,10 @@ class msk_top_regs_msk_stat_1_data_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Count of data requests made by modem

| + | |

Count of data requests made by modem

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ @@ -6644,7 +6661,7 @@ def rdl_name(self) -> str: return "Tx Bit Count" @property def rdl_desc(self) -> str: - return "Count of data requests made by modem" + return "Count of data requests made by modem\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register" @@ -6733,7 +6750,10 @@ def data(self) -> msk_top_regs_msk_stat_1_data_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

Count of data requests made by modem

| + | |

Count of data requests made by modem

This register is | + | | write-to-capture.

To read data the following steps are | + | | required:

1 - Write any value to this register to capture | + | | read data

2 - Read the register

| +--------------+-------------------------------------------------------------------------+ """ return self.__data @@ -6797,7 +6817,8 @@ class msk_top_regs_msk_stat_0_tx_axis_valid_cls(FieldAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> S_AXIS_VALID Enabled 0 -> S_AXIS_VALID Disabled

| + | |

1 -> S_AXIS_VALID Enabled

0 -> S_AXIS_VALID | + | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -6813,7 +6834,7 @@ def rdl_name(self) -> str: return "Tx S_AXIS_VALID" @property def rdl_desc(self) -> str: - return "1 -\u003e S_AXIS_VALID Enabled\n0 -\u003e S_AXIS_VALID Disabled" + return "1 -\u003e S_AXIS_VALID Enabled\n\n0 -\u003e S_AXIS_VALID Disabled" @@ -6836,7 +6857,7 @@ class msk_top_regs_msk_stat_0_rx_enable_cls(FieldAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> Data from ADC Enabled 0 -> Data from ADC | + | |

1 -> Data from ADC Enabled

0 -> Data from ADC | | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -6853,7 +6874,7 @@ def rdl_name(self) -> str: return "AD9363 ADC Interface Rx Enable Input Active" @property def rdl_desc(self) -> str: - return "1 -\u003e Data from ADC Enabled\n0 -\u003e Data from ADC Disabled" + return "1 -\u003e Data from ADC Enabled\n\n0 -\u003e Data from ADC Disabled" @@ -6876,7 +6897,8 @@ class msk_top_regs_msk_stat_0_tx_enable_cls(FieldAsyncReadOnly): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> Data to DAC Enabled 0 -> Data to DAC Disabled

| + | |

1 -> Data to DAC Enabled

0 -> Data to DAC | + | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -6892,7 +6914,7 @@ def rdl_name(self) -> str: return "AD9363 DAC Interface Tx Enable Input Active" @property def rdl_desc(self) -> str: - return "1 -\u003e Data to DAC Enabled\n0 -\u003e Data to DAC Disabled" + return "1 -\u003e Data to DAC Enabled\n\n0 -\u003e Data to DAC Disabled" @@ -7084,7 +7106,8 @@ def tx_enable(self) -> msk_top_regs_msk_stat_0_tx_enable_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> Data to DAC Enabled 0 -> Data to DAC Disabled

| + | |

1 -> Data to DAC Enabled

0 -> Data to DAC | + | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_enable @@ -7103,7 +7126,7 @@ def rx_enable(self) -> msk_top_regs_msk_stat_0_rx_enable_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> Data from ADC Enabled 0 -> Data from ADC | + | |

1 -> Data from ADC Enabled

0 -> Data from ADC | | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -7123,7 +7146,8 @@ def tx_axis_valid(self) -> msk_top_regs_msk_stat_0_tx_axis_valid_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

1 -> S_AXIS_VALID Enabled 0 -> S_AXIS_VALID Disabled

| + | |

1 -> S_AXIS_VALID Enabled

0 -> S_AXIS_VALID | + | | Disabled

| +--------------+-------------------------------------------------------------------------+ """ return self.__tx_axis_valid @@ -7206,8 +7230,9 @@ class msk_top_regs_msk_ctrl_diff_encoder_loopback_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Differential Encoder -> Decoder loopback disabled 1 | - | | -> Differential Encoder -> Decoder loopback enabled

| + | |

0 -> Differential Encoder -> Decoder loopback | + | | disabled

1 -> Differential Encoder -> Decoder | + | | loopback enabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -7223,7 +7248,7 @@ def rdl_name(self) -> str: return "Differential Encoder -\u003e Decoder Loopback Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled" + return "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled" @@ -7324,7 +7349,7 @@ class msk_top_regs_msk_ctrl_loopback_ena_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Modem loopback disabled 1 -> Modem loopback | + | |

0 -> Modem loopback disabled

1 -> Modem loopback | | | enabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -7341,7 +7366,7 @@ def rdl_name(self) -> str: return "Modem Digital Tx -\u003e Rx Loopback Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Modem loopback disabled\n1 -\u003e Modem loopback enabled" + return "0 -\u003e Modem loopback disabled\n\n1 -\u003e Modem loopback enabled" @@ -7548,7 +7573,7 @@ def loopback_ena(self) -> msk_top_regs_msk_ctrl_loopback_ena_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Modem loopback disabled 1 -> Modem loopback | + | |

0 -> Modem loopback disabled

1 -> Modem loopback | | | enabled

| +--------------+-------------------------------------------------------------------------+ """ @@ -7606,8 +7631,9 @@ def diff_encoder_loopback(self) -> msk_top_regs_msk_ctrl_diff_encoder_loopback_c +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Differential Encoder -> Decoder loopback disabled 1 | - | | -> Differential Encoder -> Decoder loopback enabled

| + | |

0 -> Differential Encoder -> Decoder loopback | + | | disabled

1 -> Differential Encoder -> Decoder | + | | loopback enabled

| +--------------+-------------------------------------------------------------------------+ """ return self.__diff_encoder_loopback @@ -7694,7 +7720,7 @@ class msk_top_regs_msk_init_rxinit_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal Rx operation 1 -> Initialize Rx

| + | |

0 -> Normal Rx operation

1 -> Initialize Rx

| +--------------+-------------------------------------------------------------------------+ """ @@ -7710,7 +7736,7 @@ def rdl_name(self) -> str: return "Rx Init Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Normal Rx operation \n1 -\u003e Initialize Rx" + return "0 -\u003e Normal Rx operation \n\n1 -\u003e Initialize Rx" @@ -7733,7 +7759,7 @@ class msk_top_regs_msk_init_txinit_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal Tx operation 1 -> Initialize Tx

| + | |

0 -> Normal Tx operation

1 -> Initialize Tx

| +--------------+-------------------------------------------------------------------------+ """ @@ -7749,7 +7775,7 @@ def rdl_name(self) -> str: return "Tx Init Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Normal Tx operation \n1 -\u003e Initialize Tx" + return "0 -\u003e Normal Tx operation\n\n1 -\u003e Initialize Tx" @@ -7772,8 +7798,8 @@ class msk_top_regs_msk_init_txrxinit_cls(FieldAsyncReadWrite): +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal modem operation 1 -> Initialize Tx and | - | | Rx

| + | |

0 -> Normal modem operation

1 -> Initialize Tx | + | | and Rx

| +--------------+-------------------------------------------------------------------------+ """ @@ -7789,7 +7815,7 @@ def rdl_name(self) -> str: return "Tx/Rx Init Enable" @property def rdl_desc(self) -> str: - return "0 -\u003e Normal modem operation \n1 -\u003e Initialize Tx and Rx" + return "0 -\u003e Normal modem operation \n\n1 -\u003e Initialize Tx and Rx" @@ -7909,8 +7935,8 @@ def txrxinit(self) -> msk_top_regs_msk_init_txrxinit_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal modem operation 1 -> Initialize Tx and | - | | Rx

| + | |

0 -> Normal modem operation

1 -> Initialize Tx | + | | and Rx

| +--------------+-------------------------------------------------------------------------+ """ return self.__txrxinit @@ -7929,7 +7955,7 @@ def txinit(self) -> msk_top_regs_msk_init_txinit_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal Tx operation 1 -> Initialize Tx

| + | |

0 -> Normal Tx operation

1 -> Initialize Tx

| +--------------+-------------------------------------------------------------------------+ """ return self.__txinit @@ -7948,7 +7974,7 @@ def rxinit(self) -> msk_top_regs_msk_init_rxinit_cls: +--------------+-------------------------------------------------------------------------+ | Description | .. raw:: html | | | | - | |

0 -> Normal Rx operation 1 -> Initialize Rx

| + | |

0 -> Normal Rx operation

1 -> Initialize Rx

| +--------------+-------------------------------------------------------------------------+ """ return self.__rxinit @@ -8590,7 +8616,7 @@ def __init__(self, *, inst_name='LPF_Config_2', parent=self) - self.__f1_nco_adjust:msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls = msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls( + self.__f1_nco_adjust:msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls = msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls( address=self.address+108, accesswidth=32, width=32, @@ -8598,7 +8624,7 @@ def __init__(self, *, inst_name='f1_nco_adjust', parent=self) - self.__f2_nco_adjust:msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls = msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls( + self.__f2_nco_adjust:msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls = msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls( address=self.address+112, accesswidth=32, width=32, @@ -8606,7 +8632,7 @@ def __init__(self, *, inst_name='f2_nco_adjust', parent=self) - self.__f1_error:msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls = msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls( + self.__f1_error:msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls = msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls( address=self.address+116, accesswidth=32, width=32, @@ -8614,7 +8640,7 @@ def __init__(self, *, inst_name='f1_error', parent=self) - self.__f2_error:msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls = msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls( + self.__f2_error:msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls = msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls( address=self.address+120, accesswidth=32, width=32, @@ -8638,7 +8664,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls = msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls = msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls( address=self.address+132, accesswidth=32, width=32, @@ -8662,7 +8688,7 @@ def __init__(self, *, inst_name='rx_power', parent=self) - self.__tx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls = msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls( + self.__tx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls = msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls( address=self.address+144, accesswidth=32, width=32, @@ -8670,7 +8696,7 @@ def __init__(self, *, inst_name='tx_async_fifo_rd_wr_ptr', parent=self) - self.__rx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls = msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls( + self.__rx_async_fifo_rd_wr_ptr:msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls = msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls( address=self.address+148, accesswidth=32, width=32, @@ -9217,7 +9243,7 @@ def LPF_Config_2(self) -> msk_top_regs_lpf_config_2_cls: return self.__LPF_Config_2 @property - def f1_nco_adjust(self) -> msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls: + def f1_nco_adjust(self) -> msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls: """ Property to access f1_nco_adjust @@ -9229,15 +9255,11 @@ def f1_nco_adjust(self) -> msk_top_regs_observation_data_data_0c017ef4_desc_64ff | | | | | F1 NCO Frequency Adjust | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Frequency offet applied to the F1 NCO

| - +--------------+-------------------------------------------------------------------------+ """ return self.__f1_nco_adjust @property - def f2_nco_adjust(self) -> msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls: + def f2_nco_adjust(self) -> msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls: """ Property to access f2_nco_adjust @@ -9249,15 +9271,11 @@ def f2_nco_adjust(self) -> msk_top_regs_observation_data_data_0515efaa_desc_ebde | | | | | F2 NCO Frequency Adjust | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Frequency offet applied to the F2 NCO

| - +--------------+-------------------------------------------------------------------------+ """ return self.__f2_nco_adjust @property - def f1_error(self) -> msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls: + def f1_error(self) -> msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls: """ Property to access f1_error @@ -9269,16 +9287,11 @@ def f1_error(self) -> msk_top_regs_observation_data_data_25a21249_desc_417e1c96_ | | | | | F1 Error Value | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Error value of the F1 Costas loop after each active bit | - | | period

| - +--------------+-------------------------------------------------------------------------+ """ return self.__f1_error @property - def f2_error(self) -> msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls: + def f2_error(self) -> msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls: """ Property to access f2_error @@ -9290,11 +9303,6 @@ def f2_error(self) -> msk_top_regs_observation_data_data_272a00b6_desc_70869502_ | | | | | F2 Error Value | +--------------+-------------------------------------------------------------------------+ - | Description | .. raw:: html | - | | | - | |

Error value of the F2 Costas loop after each active bit | - | | period

| - +--------------+-------------------------------------------------------------------------+ """ return self.__f2_error @@ -9340,7 +9348,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls: """ Property to access lowpass_ema_alpha1 @@ -9400,7 +9408,7 @@ def rx_power(self) -> msk_top_regs_rx_power_cls: return self.__rx_power @property - def tx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls: + def tx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls: """ Property to access tx_async_fifo_rd_wr_ptr @@ -9416,7 +9424,7 @@ def tx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_cf6acbd7 return self.__tx_async_fifo_rd_wr_ptr @property - def rx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls: + def rx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls: """ Property to access rx_async_fifo_rd_wr_ptr @@ -9562,19 +9570,19 @@ def get_child_by_system_rdl_name(self, name: Literal["LPF_Config_2"]) -> msk_top @overload - def get_child_by_system_rdl_name(self, name: Literal["f1_nco_adjust"]) -> msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["f1_nco_adjust"]) -> msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls: ... @overload - def get_child_by_system_rdl_name(self, name: Literal["f2_nco_adjust"]) -> msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["f2_nco_adjust"]) -> msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls: ... @overload - def get_child_by_system_rdl_name(self, name: Literal["f1_error"]) -> msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["f1_error"]) -> msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls: ... @overload - def get_child_by_system_rdl_name(self, name: Literal["f2_error"]) -> msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["f2_error"]) -> msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls: ... @overload @@ -9586,7 +9594,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls: ... @overload @@ -9598,15 +9606,15 @@ def get_child_by_system_rdl_name(self, name: Literal["rx_power"]) -> msk_top_reg @overload - def get_child_by_system_rdl_name(self, name: Literal["tx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["tx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls: ... @overload - def get_child_by_system_rdl_name(self, name: Literal["rx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["rx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls: ... @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_cls, msk_top_regs_observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_cls, msk_top_regs_observation_data_data_25a21249_desc_417e1c96_name_3b640507_cls, msk_top_regs_observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x105c0c74_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_observation_data_data_cf6acbd7_name_aa4ec676_cls, msk_top_regs_observation_data_data_cf6acbd7_name_8a90eed1_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_observation_data_data_521c7d53_name_d8ad3b25_cls, msk_top_regs_observation_data_data_5802c5b1_name_2c154788_cls, msk_top_regs_observation_data_data_f83682dd_name_3b640507_cls, msk_top_regs_observation_data_data_0a9850a4_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1052719d_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_observation_data_data_dbd8270c_name_aa4ec676_cls, msk_top_regs_observation_data_data_dbd8270c_name_8a90eed1_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py index c76701a..e6344e7 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -957,28 +957,28 @@ def test_name_property(self) -> None: with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): - self.assertEqual(self.dut.f1_nco_adjust.data.rdl_name, "F1 NCO Frequency Adjust") # type: ignore[union-attr] + self.assertIsNone(self.dut.f1_nco_adjust.data.rdl_name) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): - self.assertEqual(self.dut.f2_nco_adjust.data.rdl_name, "F2 NCO Frequency Adjust") # type: ignore[union-attr] + self.assertIsNone(self.dut.f2_nco_adjust.data.rdl_name) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f1_error.data'): - self.assertEqual(self.dut.f1_error.data.rdl_name, "F1 Error Value") # type: ignore[union-attr] + self.assertIsNone(self.dut.f1_error.data.rdl_name) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_error.data'): - self.assertEqual(self.dut.f2_error.data.rdl_name, "F2 Error Value") # type: ignore[union-attr] + self.assertIsNone(self.dut.f2_error.data.rdl_name) # type: ignore[union-attr] @@ -1250,28 +1250,28 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.f1_nco_adjust'): - self.assertEqual(self.dut.f1_nco_adjust.rdl_desc, "Frequency offet applied to the F1 NCO") # type: ignore[union-attr] + self.assertIsNone(self.dut.f1_nco_adjust.rdl_desc) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_nco_adjust'): - self.assertEqual(self.dut.f2_nco_adjust.rdl_desc, "Frequency offet applied to the F2 NCO") # type: ignore[union-attr] + self.assertIsNone(self.dut.f2_nco_adjust.rdl_desc) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f1_error'): - self.assertEqual(self.dut.f1_error.rdl_desc, "Error value of the F1 Costas loop after each active bit period") # type: ignore[union-attr] + self.assertIsNone(self.dut.f1_error.rdl_desc) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_error'): - self.assertEqual(self.dut.f2_error.rdl_desc, "Error value of the F2 Costas loop after each active bit period") # type: ignore[union-attr] + self.assertIsNone(self.dut.f2_error.rdl_desc) # type: ignore[union-attr] @@ -1341,21 +1341,21 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.MSK_Init.txrxinit'): - self.assertEqual(self.dut.MSK_Init.txrxinit.rdl_desc, "0 -\u003e Normal modem operation \n1 -\u003e Initialize Tx and Rx") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.txrxinit.rdl_desc, "0 -\u003e Normal modem operation \n\n1 -\u003e Initialize Tx and Rx") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.MSK_Init.txinit'): - self.assertEqual(self.dut.MSK_Init.txinit.rdl_desc, "0 -\u003e Normal Tx operation \n1 -\u003e Initialize Tx") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.txinit.rdl_desc, "0 -\u003e Normal Tx operation\n\n1 -\u003e Initialize Tx") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.MSK_Init.rxinit'): - self.assertEqual(self.dut.MSK_Init.rxinit.rdl_desc, "0 -\u003e Normal Rx operation \n1 -\u003e Initialize Rx") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Init.rxinit.rdl_desc, "0 -\u003e Normal Rx operation \n\n1 -\u003e Initialize Rx") # type: ignore[union-attr] @@ -1369,7 +1369,7 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.MSK_Control.loopback_ena'): - self.assertEqual(self.dut.MSK_Control.loopback_ena.rdl_desc, "0 -\u003e Modem loopback disabled\n1 -\u003e Modem loopback enabled") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.loopback_ena.rdl_desc, "0 -\u003e Modem loopback disabled\n\n1 -\u003e Modem loopback enabled") # type: ignore[union-attr] @@ -1390,7 +1390,7 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.MSK_Control.diff_encoder_loopback'): - self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.rdl_desc, "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Control.diff_encoder_loopback.rdl_desc, "0 -\u003e Differential Encoder -\u003e Decoder loopback disabled\n\n1 -\u003e Differential Encoder -\u003e Decoder loopback enabled") # type: ignore[union-attr] @@ -1404,35 +1404,35 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_enable'): - self.assertEqual(self.dut.MSK_Status.tx_enable.rdl_desc, "1 -\u003e Data to DAC Enabled\n0 -\u003e Data to DAC Disabled") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.tx_enable.rdl_desc, "1 -\u003e Data to DAC Enabled\n\n0 -\u003e Data to DAC Disabled") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.MSK_Status.rx_enable'): - self.assertEqual(self.dut.MSK_Status.rx_enable.rdl_desc, "1 -\u003e Data from ADC Enabled\n0 -\u003e Data from ADC Disabled") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.rx_enable.rdl_desc, "1 -\u003e Data from ADC Enabled\n\n0 -\u003e Data from ADC Disabled") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.MSK_Status.tx_axis_valid'): - self.assertEqual(self.dut.MSK_Status.tx_axis_valid.rdl_desc, "1 -\u003e S_AXIS_VALID Enabled\n0 -\u003e S_AXIS_VALID Disabled") # type: ignore[union-attr] + self.assertEqual(self.dut.MSK_Status.tx_axis_valid.rdl_desc, "1 -\u003e S_AXIS_VALID Enabled\n\n0 -\u003e S_AXIS_VALID Disabled") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Bit_Count.data'): - self.assertEqual(self.dut.Tx_Bit_Count.data.rdl_desc, "Count of data requests made by modem") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Bit_Count.data.rdl_desc, "Count of data requests made by modem\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Enable_Count.data'): - self.assertEqual(self.dut.Tx_Enable_Count.data.rdl_desc, "Number of clocks on which Tx Enable is active") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Enable_Count.data.rdl_desc, "Number of clocks on which Tx Enable is active\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] @@ -1474,14 +1474,14 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_freeze'): - self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.rdl_desc, "0 -\u003e Normal operation\n1 -\u003e Freeze current value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.lpf_freeze.rdl_desc, "0 -\u003e Normal operation\n\n1 -\u003e Freeze current value") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.LPF_Config_0.lpf_zero'): - self.assertEqual(self.dut.LPF_Config_0.lpf_zero.rdl_desc, "0 -\u003e Normal operation\n1 -\u003e Zero and hold accumulator") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Config_0.lpf_zero.rdl_desc, "0 -\u003e Normal operation\n\n1 -\u003e Zero and hold accumulator") # type: ignore[union-attr] @@ -1537,21 +1537,21 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_error_insert'): - self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.rdl_desc, "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_error_insert.rdl_desc, "0 -\u003e 1 : Insert bit error in Tx data (both Normal and PRBS)\n\n1 -\u003e 0 : Insert bit error in Tx data (both Normal and PRBS)") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_clear'): - self.assertEqual(self.dut.PRBS_Control.prbs_clear.rdl_desc, "0 -\u003e 1 : Clear PRBS Counters\n1 -\u003e 0 : Clear PRBS Counters") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_clear.rdl_desc, "0 -\u003e 1 : Clear PRBS Counters\n\n1 -\u003e 0 : Clear PRBS Counters") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_manual_sync'): - self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.rdl_desc, "0 -\u003e 1 : Synchronize PRBS monitor\n1 -\u003e 0 : Synchronize PRBS monitor") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_manual_sync.rdl_desc, "0 -\u003e 1 : Synchronize PRBS monitor\n\n1 -\u003e 0 : Synchronize PRBS monitor") # type: ignore[union-attr] @@ -1565,7 +1565,7 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.PRBS_Control.prbs_sync_threshold'): - self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.rdl_desc, "0 : Auto Sync Disabled\nN \u003e 0 : Auto sync after N errors") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Control.prbs_sync_threshold.rdl_desc, "0 : Auto Sync Disabled\n\nN \u003e 0 : Auto sync after N errors") # type: ignore[union-attr] @@ -1593,35 +1593,35 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.PRBS_Bit_Count.data'): - self.assertEqual(self.dut.PRBS_Bit_Count.data.rdl_desc, "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Bit_Count.data.rdl_desc, "Number of bits received by the PRBS monitor since last\nBER can be calculated as the ratio of received bits to errored-bits\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.PRBS_Error_Count.data'): - self.assertEqual(self.dut.PRBS_Error_Count.data.rdl_desc, "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits") # type: ignore[union-attr] + self.assertEqual(self.dut.PRBS_Error_Count.data.rdl_desc, "Number of errored-bits received by the PRBS monitor since last sync\nBER can be calculated as the ratio of received bits to errored-bits\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.LPF_Accum_F1.data'): - self.assertEqual(self.dut.LPF_Accum_F1.data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F1.data.rdl_desc, "PI Controller Accumulator Value\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.LPF_Accum_F2.data'): - self.assertEqual(self.dut.LPF_Accum_F2.data.rdl_desc, "PI Controller Accumulator Value") # type: ignore[union-attr] + self.assertEqual(self.dut.LPF_Accum_F2.data.rdl_desc, "PI Controller Accumulator Value\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.axis_xfer_count.data'): - self.assertEqual(self.dut.axis_xfer_count.data.rdl_desc, "Number completed S_AXIS transfers") # type: ignore[union-attr] + self.assertEqual(self.dut.axis_xfer_count.data.rdl_desc, "Number completed S_AXIS transfers\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] @@ -1656,63 +1656,63 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.f1_nco_adjust.data'): - self.assertEqual(self.dut.f1_nco_adjust.data.rdl_desc, "Frequency offet applied to the F1 NCO") # type: ignore[union-attr] + self.assertEqual(self.dut.f1_nco_adjust.data.rdl_desc, "Frequency offet applied to the F1 NCO\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_nco_adjust.data'): - self.assertEqual(self.dut.f2_nco_adjust.data.rdl_desc, "Frequency offet applied to the F2 NCO") # type: ignore[union-attr] + self.assertEqual(self.dut.f2_nco_adjust.data.rdl_desc, "Frequency offet applied to the F2 NCO\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f1_error.data'): - self.assertEqual(self.dut.f1_error.data.rdl_desc, "Error value of the F1 Costas loop after each active bit period") # type: ignore[union-attr] + self.assertEqual(self.dut.f1_error.data.rdl_desc, "Error value of the F1 Costas loop after each active bit period\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.f2_error.data'): - self.assertEqual(self.dut.f2_error.data.rdl_desc, "Error value of the F2 Costas loop after each active bit period") # type: ignore[union-attr] + self.assertEqual(self.dut.f2_error.data.rdl_desc, "Error value of the F2 Costas loop after each active bit period\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_ena'): - self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.rdl_desc, "0 -\u003e Disable sync transmission\n1 -\u003e Enable sync transmission when PTT is asserted") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_ena.rdl_desc, "0 -\u003e Disable sync transmission\n\n1 -\u003e Enable sync transmission when PTT is asserted") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_force'): - self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.rdl_desc, "0 : Normal operation)\n1 : Transmit synchronization pattern)") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_force.rdl_desc, "0 : Normal operation\n\n1 : Transmit synchronization pattern") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f1'): - self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.rdl_desc, "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n1 : F1 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f1.rdl_desc, "Enables/Disables transmission of F1 tone for receiver synchronization\n0 : F1 tone transmission disabled\n\n1 : F1 tone transmission enabled\n\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Sync_Ctrl.tx_sync_f2'): - self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.rdl_desc, "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n1 : F2 tone transmission enabled\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Ctrl.tx_sync_f2.rdl_desc, "Enables/Disables transmission of F2 tone for receiver synchronization\n0 : F2 tone transmission disabled\n\n1 : F2 tone transmission enabled\n\nBoth F1 and F2 can be enabled at the same time") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Tx_Sync_Cnt.tx_sync_cnt'): - self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.rdl_desc, "Value from 0x00_0000 to 0xFF_FFFF. \nThis value represents the number bit-times the synchronization \nsignal should be sent after PTT is asserted.") # type: ignore[union-attr] + self.assertEqual(self.dut.Tx_Sync_Cnt.tx_sync_cnt.rdl_desc, "Value from 0x00_0000 to 0xFF_FFFF. \n\nThis value represents the number bit-times the synchronization \n\nsignal should be sent after PTT is asserted.") # type: ignore[union-attr] @@ -1733,21 +1733,21 @@ def test_desc(self) -> None: with self.subTest(msg='node: msk_top_regs.rx_power.data'): - self.assertEqual(self.dut.rx_power.data.rdl_desc, "Value that represent the RMS power of the incoming I;") # type: ignore[union-attr] + self.assertEqual(self.dut.rx_power.data.rdl_desc, "Value that represent the RMS power of the incoming I\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.tx_async_fifo_rd_wr_ptr.data'): - self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.rdl_desc, "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)") # type: ignore[union-attr] + self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.data.rdl_desc, "Read and Write Pointers\n\nBits 31:16 - write pointer (12-bits)\n\nBits 15:00 - read pointer (12-bits)\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): - self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.rdl_desc, "Bits 31:16 -\u003e write pointer (12-bits)\nBits 15:00 -\u003e read pointer (12-bits)") # type: ignore[union-attr] + self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.rdl_desc, "Read and Write Pointers\n\nBits 31:16 - write pointer (12-bits)\n\nBits 15:00 - read pointer (12-bits)\n\nThis register is write-to-capture.\n\nTo read data the following steps are required:\n\n1 - Write any value to this register to capture read data\n\n2 - Read the register") # type: ignore[union-attr] diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd index c7439ad..e646abe 100644 --- a/rdl/outputs/rtl/msk_top_regs_pkg.vhd +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -97,40 +97,40 @@ package msk_top_regs_pkg is data : \msk_top_regs.msk_stat_3.data_in_t\; end record; - type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\ is record + type \msk_top_regs.data32_desc_0ed96915_in_t\ is record next_q : std_logic_vector(31 downto 0); we : std_logic; end record; - type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\ is record - data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_in_t\; + type \msk_top_regs.observation_data_data_521c7d53_name_d8ad3b25_in_t\ is record + data : \msk_top_regs.data32_desc_0ed96915_in_t\; end record; - type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\ is record + type \msk_top_regs.data32_desc_13897f4c_in_t\ is record next_q : std_logic_vector(31 downto 0); we : std_logic; end record; - type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\ is record - data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_in_t\; + type \msk_top_regs.observation_data_data_5802c5b1_name_2c154788_in_t\ is record + data : \msk_top_regs.data32_desc_13897f4c_in_t\; end record; - type \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\ is record + type \msk_top_regs.data32_desc_83db1b72_in_t\ is record next_q : std_logic_vector(31 downto 0); we : std_logic; end record; - type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\ is record - data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_in_t\; + type \msk_top_regs.observation_data_data_f83682dd_name_3b640507_in_t\ is record + data : \msk_top_regs.data32_desc_83db1b72_in_t\; end record; - type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\ is record + type \msk_top_regs.data32_desc_c8bf066a_in_t\ is record next_q : std_logic_vector(31 downto 0); we : std_logic; end record; - type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\ is record - data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_in_t\; + type \msk_top_regs.observation_data_data_0a9850a4_name_3de9a0d3_in_t\ is record + data : \msk_top_regs.data32_desc_c8bf066a_in_t\; end record; type \msk_top_regs.rx_power.data_in_t\ is record @@ -142,17 +142,17 @@ package msk_top_regs_pkg is data : \msk_top_regs.rx_power.data_in_t\; end record; - type \msk_top_regs.data32_desc_7b98a70e_in_t\ is record + type \msk_top_regs.data32_desc_52ad9f96_in_t\ is record next_q : std_logic_vector(31 downto 0); we : std_logic; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_in_t\ is record - data : \msk_top_regs.data32_desc_7b98a70e_in_t\; + type \msk_top_regs.observation_data_data_dbd8270c_name_aa4ec676_in_t\ is record + data : \msk_top_regs.data32_desc_52ad9f96_in_t\; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_in_t\ is record - data : \msk_top_regs.data32_desc_7b98a70e_in_t\; + type \msk_top_regs.observation_data_data_dbd8270c_name_8a90eed1_in_t\ is record + data : \msk_top_regs.data32_desc_52ad9f96_in_t\; end record; type msk_top_regs_in_t is record @@ -164,13 +164,13 @@ package msk_top_regs_pkg is LPF_Accum_F1 : \msk_top_regs.stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_in_t\; LPF_Accum_F2 : \msk_top_regs.stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_in_t\; axis_xfer_count : \msk_top_regs.msk_stat_3_in_t\; - f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_in_t\; - f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_in_t\; - f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_in_t\; - f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_in_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_521c7d53_name_d8ad3b25_in_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_5802c5b1_name_2c154788_in_t\; + f1_error : \msk_top_regs.observation_data_data_f83682dd_name_3b640507_in_t\; + f2_error : \msk_top_regs.observation_data_data_0a9850a4_name_3de9a0d3_in_t\; rx_power : \msk_top_regs.rx_power_in_t\; - tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_in_t\; - rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_in_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_dbd8270c_name_aa4ec676_in_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_dbd8270c_name_8a90eed1_in_t\; end record; type \msk_top_regs.msk_init.txrxinit_out_t\ is record @@ -450,36 +450,36 @@ package msk_top_regs_pkg is p_shift : \msk_top_regs.lpf_config_2.p_shift_out_t\; end record; - type \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_out_t\ is record + type \msk_top_regs.data32_desc_0ed96915_out_t\ is record swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_out_t\ is record - data : \msk_top_regs.data32_desc_64ff3689_name_d8ad3b25_out_t\; + type \msk_top_regs.observation_data_data_521c7d53_name_d8ad3b25_out_t\ is record + data : \msk_top_regs.data32_desc_0ed96915_out_t\; end record; - type \msk_top_regs.data32_desc_ebde6d39_name_2c154788_out_t\ is record + type \msk_top_regs.data32_desc_13897f4c_out_t\ is record swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_out_t\ is record - data : \msk_top_regs.data32_desc_ebde6d39_name_2c154788_out_t\; + type \msk_top_regs.observation_data_data_5802c5b1_name_2c154788_out_t\ is record + data : \msk_top_regs.data32_desc_13897f4c_out_t\; end record; - type \msk_top_regs.data32_desc_417e1c96_name_3b640507_out_t\ is record + type \msk_top_regs.data32_desc_83db1b72_out_t\ is record swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_out_t\ is record - data : \msk_top_regs.data32_desc_417e1c96_name_3b640507_out_t\; + type \msk_top_regs.observation_data_data_f83682dd_name_3b640507_out_t\ is record + data : \msk_top_regs.data32_desc_83db1b72_out_t\; end record; - type \msk_top_regs.data32_desc_70869502_name_3de9a0d3_out_t\ is record + type \msk_top_regs.data32_desc_c8bf066a_out_t\ is record swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_out_t\ is record - data : \msk_top_regs.data32_desc_70869502_name_3de9a0d3_out_t\; + type \msk_top_regs.observation_data_data_0a9850a4_name_3de9a0d3_out_t\ is record + data : \msk_top_regs.data32_desc_c8bf066a_out_t\; end record; type \msk_top_regs.tx_sync_ctrl.tx_sync_ena_out_t\ is record @@ -529,16 +529,16 @@ package msk_top_regs_pkg is data : \msk_top_regs.rx_power.data_out_t\; end record; - type \msk_top_regs.data32_desc_7b98a70e_out_t\ is record + type \msk_top_regs.data32_desc_52ad9f96_out_t\ is record swmod : std_logic; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_out_t\ is record - data : \msk_top_regs.data32_desc_7b98a70e_out_t\; + type \msk_top_regs.observation_data_data_dbd8270c_name_aa4ec676_out_t\ is record + data : \msk_top_regs.data32_desc_52ad9f96_out_t\; end record; - type \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_out_t\ is record - data : \msk_top_regs.data32_desc_7b98a70e_out_t\; + type \msk_top_regs.observation_data_data_dbd8270c_name_8a90eed1_out_t\ is record + data : \msk_top_regs.data32_desc_52ad9f96_out_t\; end record; type msk_top_regs_out_t is record @@ -566,16 +566,16 @@ package msk_top_regs_pkg is axis_xfer_count : \msk_top_regs.msk_stat_3_out_t\; Rx_Sample_Discard : \msk_top_regs.rx_sample_discard_out_t\; LPF_Config_2 : \msk_top_regs.lpf_config_2_out_t\; - f1_nco_adjust : \msk_top_regs.observation_data_data_0c017ef4_desc_64ff3689_name_d8ad3b25_out_t\; - f2_nco_adjust : \msk_top_regs.observation_data_data_0515efaa_desc_ebde6d39_name_2c154788_out_t\; - f1_error : \msk_top_regs.observation_data_data_25a21249_desc_417e1c96_name_3b640507_out_t\; - f2_error : \msk_top_regs.observation_data_data_272a00b6_desc_70869502_name_3de9a0d3_out_t\; + f1_nco_adjust : \msk_top_regs.observation_data_data_521c7d53_name_d8ad3b25_out_t\; + f2_nco_adjust : \msk_top_regs.observation_data_data_5802c5b1_name_2c154788_out_t\; + f1_error : \msk_top_regs.observation_data_data_f83682dd_name_3b640507_out_t\; + f2_error : \msk_top_regs.observation_data_data_0a9850a4_name_3de9a0d3_out_t\; Tx_Sync_Ctrl : \msk_top_regs.tx_sync_ctrl_out_t\; Tx_Sync_Cnt : \msk_top_regs.tx_sync_cnt_out_t\; lowpass_ema_alpha1 : \msk_top_regs.lowpass_ema_alpha_out_t\; lowpass_ema_alpha2 : \msk_top_regs.lowpass_ema_alpha_out_t\; rx_power : \msk_top_regs.rx_power_out_t\; - tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_aa4ec676_out_t\; - rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_cf6acbd7_name_8a90eed1_out_t\; + tx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_dbd8270c_name_aa4ec676_out_t\; + rx_async_fifo_rd_wr_ptr : \msk_top_regs.observation_data_data_dbd8270c_name_8a90eed1_out_t\; end record; end package; diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index f8a2598..6c22529 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -92,18 +92,21 @@ addrmap msk_top_regs { field { name = "Tx/Rx Init Enable"; desc = "0 -> Normal modem operation + 1 -> Initialize Tx and Rx"; } txrxinit = 1; field { name = "Tx Init Enable"; - desc = "0 -> Normal Tx operation + desc = "0 -> Normal Tx operation + 1 -> Initialize Tx"; } txinit = 1; field { name = "Rx Init Enable"; - desc = "0 -> Normal Rx operation + desc = "0 -> Normal Rx operation + 1 -> Initialize Rx"; } rxinit = 1; }; @@ -121,6 +124,7 @@ addrmap msk_top_regs { field { name = "Modem Digital Tx -> Rx Loopback Enable"; desc = "0 -> Modem loopback disabled + 1 -> Modem loopback enabled"; } loopback_ena = 0; field { @@ -136,6 +140,7 @@ addrmap msk_top_regs { field { name = "Differential Encoder -> Decoder Loopback Enable"; desc = "0 -> Differential Encoder -> Decoder loopback disabled + 1 -> Differential Encoder -> Decoder loopback enabled"; } diff_encoder_loopback = 0; }; @@ -153,6 +158,7 @@ addrmap msk_top_regs { field { name = "AD9363 DAC Interface Tx Enable Input Active"; desc = "1 -> Data to DAC Enabled + 0 -> Data to DAC Disabled"; sw = r; hw = w; @@ -160,6 +166,7 @@ addrmap msk_top_regs { field { name = "AD9363 ADC Interface Rx Enable Input Active"; desc = "1 -> Data from ADC Enabled + 0 -> Data from ADC Disabled"; sw = r; hw = w; @@ -167,6 +174,7 @@ addrmap msk_top_regs { field { name = "Tx S_AXIS_VALID"; desc = "1 -> S_AXIS_VALID Enabled + 0 -> S_AXIS_VALID Disabled"; sw = r; hw = w; @@ -179,7 +187,15 @@ addrmap msk_top_regs { regwidth = 32; field { name = "Tx Bit Count"; - desc = "Count of data requests made by modem"; + desc = "Count of data requests made by modem + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -192,7 +208,15 @@ addrmap msk_top_regs { desc = "Modem status data"; regwidth = 32; field { - desc = "Number of clocks on which Tx Enable is active"; + desc = "Number of clocks on which Tx Enable is active + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; name = "Tx Enable Count"; sw = rw; hw = w; @@ -231,11 +255,13 @@ addrmap msk_top_regs { field { name = "Freeze the accumulator's current value"; desc = "0 -> Normal operation + 1 -> Freeze current value"; } lpf_freeze = 0; field { name = "Hold the PI Accumulator at zero"; desc = "0 -> Normal operation + 1 -> Zero and hold accumulator"; } lpf_zero = 0; field { @@ -295,6 +321,7 @@ addrmap msk_top_regs { field { name = "PRBS Error Insert"; desc = "0 -> 1 : Insert bit error in Tx data (both Normal and PRBS) + 1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)"; sw = w; hw = r; @@ -303,6 +330,7 @@ addrmap msk_top_regs { field { name = "PRBS Clear Counters"; desc = "0 -> 1 : Clear PRBS Counters + 1 -> 0 : Clear PRBS Counters"; sw = w; hw = r; @@ -311,6 +339,7 @@ addrmap msk_top_regs { field { name = "PRBS Manual Sync"; desc = "0 -> 1 : Synchronize PRBS monitor + 1 -> 0 : Synchronize PRBS monitor"; sw = w; hw = r; @@ -322,6 +351,7 @@ addrmap msk_top_regs { field { name = "PRBS Auto Sync Threshold"; desc = "0 : Auto Sync Disabled + N > 0 : Auto sync after N errors"; } prbs_sync_threshold[31:16] = 0; }; @@ -332,6 +362,7 @@ addrmap msk_top_regs { regwidth = 32; field { name = "PRBS Seed"; + desc = "Sets the starting value of the PRBS generator"; } config_data[31:0] = 0; }; @@ -342,6 +373,7 @@ addrmap msk_top_regs { regwidth = 32; field { name = "PRBS Polynomial"; + desc = "Bit positions set to '1' indicate polynomial feedback positions"; } config_data[31:0] = 0; }; @@ -352,6 +384,7 @@ addrmap msk_top_regs { regwidth = 32; field { name = "PRBS Error Mask"; + desc = "Bit positions set to '1' indicate bits that are inverted when a bit error is inserted"; } config_data[31:0] = 0; }; @@ -363,7 +396,15 @@ addrmap msk_top_regs { field { name = "PRBS Bits Received"; desc = "Number of bits received by the PRBS monitor since last - BER can be calculated as the ratio of received bits to errored-bits"; + BER can be calculated as the ratio of received bits to errored-bits + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -378,7 +419,15 @@ addrmap msk_top_regs { field { name = "PRBS Bit Errors"; desc = "Number of errored-bits received by the PRBS monitor since last sync - BER can be calculated as the ratio of received bits to errored-bits"; + BER can be calculated as the ratio of received bits to errored-bits + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -390,7 +439,15 @@ addrmap msk_top_regs { regwidth = 32; field { name = "PI Controller Accumulator Value"; - desc = "PI Controller Accumulator Value"; + desc = "PI Controller Accumulator Value + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -403,8 +460,16 @@ addrmap msk_top_regs { desc = "Modem status data"; regwidth = 32; field { - desc = "Number completed S_AXIS transfers"; name = "S_AXIS Transfers"; + desc = "Number completed S_AXIS transfers + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -419,25 +484,31 @@ addrmap msk_top_regs { field { name = "Tx Sync Enable"; desc = "0 -> Disable sync transmission + 1 -> Enable sync transmission when PTT is asserted"; } tx_sync_ena = 0; field { name = "Tx Sync Force"; - desc = "0 : Normal operation) - 1 : Transmit synchronization pattern)"; + desc = "0 : Normal operation + + 1 : Transmit synchronization pattern"; } tx_sync_force = 0; field { name = "Tx F1 Sync Enable"; desc = "Enables/Disables transmission of F1 tone for receiver synchronization 0 : F1 tone transmission disabled + 1 : F1 tone transmission enabled + Both F1 and F2 can be enabled at the same time"; } tx_sync_f1 = 0; field { name = "Tx F2 Sync Enable"; desc = "Enables/Disables transmission of F2 tone for receiver synchronization 0 : F2 tone transmission disabled + 1 : F2 tone transmission enabled + Both F1 and F2 can be enabled at the same time"; } tx_sync_f2 = 0; }; @@ -449,7 +520,9 @@ addrmap msk_top_regs { field { name = "Tx sync duration"; desc = "Value from 0x00_0000 to 0xFF_FFFF. + This value represents the number bit-times the synchronization + signal should be sent after PTT is asserted."; sw = rw; hw = r; @@ -472,7 +545,15 @@ addrmap msk_top_regs { regwidth = 32; field { name = "Receive Power"; - desc = "Value that represent the RMS power of the incoming I;"; + desc = "Value that represent the RMS power of the incoming I + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; sw = rw; hw = w; we = true; @@ -541,24 +622,48 @@ addrmap msk_top_regs { lpf_config_2 LPF_Config_2; observation_data f1_nco_adjust; f1_nco_adjust->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust->desc = "Frequency offet applied to the F1 NCO"; - f1_nco_adjust.data->name = "F1 NCO Frequency Adjust"; - f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO"; + f1_nco_adjust.data->desc = "Frequency offet applied to the F1 NCO + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; observation_data f2_nco_adjust; f2_nco_adjust->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust->desc = "Frequency offet applied to the F2 NCO"; - f2_nco_adjust.data->name = "F2 NCO Frequency Adjust"; - f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO"; + f2_nco_adjust.data->desc = "Frequency offet applied to the F2 NCO + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; observation_data f1_error; f1_error->name = "F1 Error Value"; - f1_error->desc = "Error value of the F1 Costas loop after each active bit period"; - f1_error.data->name = "F1 Error Value"; - f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period"; + f1_error.data->desc = "Error value of the F1 Costas loop after each active bit period + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; observation_data f2_error; f2_error->name = "F2 Error Value"; - f2_error->desc = "Error value of the F2 Costas loop after each active bit period"; - f2_error.data->name = "F2 Error Value"; - f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period"; + f2_error.data->desc = "Error value of the F2 Costas loop after each active bit period + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; tx_sync_ctrl Tx_Sync_Ctrl; tx_sync_cnt Tx_Sync_Cnt; lowpass_ema_alpha lowpass_ema_alpha1; @@ -566,10 +671,32 @@ addrmap msk_top_regs { rx_power rx_power; observation_data tx_async_fifo_rd_wr_ptr; tx_async_fifo_rd_wr_ptr->name = "Tx async FIFO read and write pointers"; - tx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) - Bits 15:00 -> read pointer (12-bits)"; + tx_async_fifo_rd_wr_ptr.data->desc = "Read and Write Pointers + + Bits 31:16 - write pointer (12-bits) + + Bits 15:00 - read pointer (12-bits) + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; observation_data rx_async_fifo_rd_wr_ptr; rx_async_fifo_rd_wr_ptr->name = "Rx async FIFO read and write pointers"; - rx_async_fifo_rd_wr_ptr.data->desc = "Bits 31:16 -> write pointer (12-bits) - Bits 15:00 -> read pointer (12-bits)"; + rx_async_fifo_rd_wr_ptr.data->desc = "Read and Write Pointers + + Bits 31:16 - write pointer (12-bits) + + Bits 15:00 - read pointer (12-bits) + + This register is write-to-capture. + + To read data the following steps are required: + + 1 - Write any value to this register to capture read data + + 2 - Read the register"; }; From eadbfcb4a0a50be28ff0fe59a2951cce752b8c5c Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Thu, 6 Nov 2025 11:07:54 -0700 Subject: [PATCH 22/60] rdl: update register descriptions, add HTML output --- rdl/Makefile | 12 +- rdl/outputs/c-header/msk_top_regs.h | 10 +- .../docs/html/.launcher_data/firefox/user.js | 4 + ...1d8a8c3c9175e1c33719680affb67165e68d7.html | 70 + ...4c2cce678b196818b4f08e31bc15b1b3e6e8e.html | 95 + ...48ccc7797ab5a2e0a9ce250fc373fb5d1b044.html | 72 + ...914803428de754127f501a151f8d9f2f6346f.html | 77 + ...385a5df67ff7f5d1fbfe621945563573fbb22.html | 69 + ...eb9d33100e7486423224eec5450a659e2203c.html | 68 + ...360864d8b656cfa1ebcc20f12a51ba4f4f9cc.html | 201 ++ ...d902a6f30dcb8d14e261e3eb867f29ae8aa29.html | 95 + ...fac861ad2452f8ace4d5f4459d66b2ead24dc.html | 68 + ...b7862ddb3fa504d82685711c9a66bce7f577d.html | 72 + ...508e257881c5e4a5502062b7c9aa9a792dc12.html | 68 + ...38d6efca727bb9bf39e13e872f922349ff15e.html | 68 + ...2c31237c70d2c50e8a1e8a25d3a13f9cec6a2.html | 77 + ...16507967fd003316096871c9cb43cb2983373.html | 161 ++ ...ea48e8d9edee01f284df7c443e2add40252d9.html | 189 ++ ...b0a3a62ae385442fa3b250263026f7cfdd441.html | 72 + ...d75d5fc9168e025083358f26a5e06ca7b3007.html | 144 + ...cea7d8db3cfd91d0b598d43abc73b85b237e5.html | 64 + ...520c9b6891107c7d1b147a3b1bed28bebe71c.html | 73 + ...1423b7e011932aacabd59a183a4c2d7c81b46.html | 69 + ...99b88ab61eb3569764525c3aef19596c2a4e8.html | 72 + ...8d61e4e2c8cc1adaabca728671903515e6053.html | 69 + ...18df4e6a7993047f37ec6f74d05dae744e911.html | 335 +++ ...cac1ec3dda403a0b7a1db5c224b03a74f9f9d.html | 81 + ...627ebae54f7207a648572a54cbd7f918c0ae7.html | 68 + ...3348faf8a0f9a3da26ea0fc3d9e8d47d5d737.html | 69 + ...0e44e2c6ffcbb57715d4fc6fd621eca17bbe9.html | 166 ++ ...ab06a84343db43279a768a29160c012ea8fcc.html | 134 + ...6e4ec8a024a37ce1f65c5c90a495b4b9555cf.html | 68 + ...b92fc9fcd9a12ab08ab5d411dbc399e12cb62.html | 68 + ...d99c8aadce2aee57600cd3b0212da9c9972cf.html | 64 + ...506c578ba1e4bb6eaf4767617cd58beb4a3ae.html | 79 + ...786425f5920f3a1e885e740599831cfd792bc.html | 72 + ...b7c226a4ebc36be166e4a2b523cb2a8959870.html | 104 + ...580c1f1dcded555681dfd8a6e15e379cf5f0f.html | 72 + ...7807489e9b5f5b719044911537b66b3a06bdf.html | 77 + ...9a6888cc769d718b5d38d555e7aed6b422371.html | 77 + ...aaf8ea45f55844cf66da35a46142d55a5253a.html | 69 + ...b9e9189271b3cac659475d0b7621c0ffe0c3f.html | 73 + rdl/outputs/docs/html/css/layout.css | 209 ++ rdl/outputs/docs/html/css/normalize.css | 341 +++ rdl/outputs/docs/html/css/theme.css | 903 ++++++ rdl/outputs/docs/html/data/data_index.js | 4 + rdl/outputs/docs/html/data/ral-data-0.json | 1 + rdl/outputs/docs/html/favicon.png | Bin 0 -> 1367 bytes .../html/fonts/FontAwesome/fa-regular-400.eot | Bin 0 -> 40576 bytes .../html/fonts/FontAwesome/fa-regular-400.svg | 467 ++++ .../html/fonts/FontAwesome/fa-regular-400.ttf | Bin 0 -> 40348 bytes .../fonts/FontAwesome/fa-regular-400.woff | Bin 0 -> 18168 bytes .../fonts/FontAwesome/fa-regular-400.woff2 | Bin 0 -> 14868 bytes .../html/fonts/FontAwesome/fa-solid-900.eot | Bin 0 -> 180720 bytes .../html/fonts/FontAwesome/fa-solid-900.svg | 2444 +++++++++++++++++ .../html/fonts/FontAwesome/fa-solid-900.ttf | Bin 0 -> 180500 bytes .../html/fonts/FontAwesome/fa-solid-900.woff | Bin 0 -> 86876 bytes .../html/fonts/FontAwesome/fa-solid-900.woff2 | Bin 0 -> 67400 bytes .../docs/html/fonts/Lato/lato-bold.eot | Bin 0 -> 256056 bytes .../docs/html/fonts/Lato/lato-bold.ttf | Bin 0 -> 600856 bytes .../docs/html/fonts/Lato/lato-bold.woff | Bin 0 -> 309728 bytes .../docs/html/fonts/Lato/lato-bold.woff2 | Bin 0 -> 184912 bytes .../docs/html/fonts/Lato/lato-bolditalic.eot | Bin 0 -> 266158 bytes .../docs/html/fonts/Lato/lato-bolditalic.ttf | Bin 0 -> 622572 bytes .../docs/html/fonts/Lato/lato-bolditalic.woff | Bin 0 -> 323344 bytes .../html/fonts/Lato/lato-bolditalic.woff2 | Bin 0 -> 193308 bytes .../docs/html/fonts/Lato/lato-italic.eot | Bin 0 -> 268604 bytes .../docs/html/fonts/Lato/lato-italic.ttf | Bin 0 -> 639388 bytes .../docs/html/fonts/Lato/lato-italic.woff | Bin 0 -> 328412 bytes .../docs/html/fonts/Lato/lato-italic.woff2 | Bin 0 -> 195704 bytes .../docs/html/fonts/Lato/lato-regular.eot | Bin 0 -> 253461 bytes .../docs/html/fonts/Lato/lato-regular.ttf | Bin 0 -> 607720 bytes .../docs/html/fonts/Lato/lato-regular.woff | Bin 0 -> 309192 bytes .../docs/html/fonts/Lato/lato-regular.woff2 | Bin 0 -> 182708 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.eot | Bin 0 -> 79520 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.ttf | Bin 0 -> 170616 bytes .../fonts/RobotoSlab/roboto-slab-v7-bold.woff | Bin 0 -> 87624 bytes .../RobotoSlab/roboto-slab-v7-bold.woff2 | Bin 0 -> 67312 bytes .../RobotoSlab/roboto-slab-v7-regular.eot | Bin 0 -> 78331 bytes .../RobotoSlab/roboto-slab-v7-regular.ttf | Bin 0 -> 169064 bytes .../RobotoSlab/roboto-slab-v7-regular.woff | Bin 0 -> 86288 bytes .../RobotoSlab/roboto-slab-v7-regular.woff2 | Bin 0 -> 66444 bytes rdl/outputs/docs/html/index.html | 123 + rdl/outputs/docs/html/js/address_search.js | 33 + rdl/outputs/docs/html/js/content_search.js | 370 +++ rdl/outputs/docs/html/js/field_testers.js | 213 ++ rdl/outputs/docs/html/js/index_edit.js | 162 ++ rdl/outputs/docs/html/js/main.js | 451 +++ rdl/outputs/docs/html/js/nav.js | 209 ++ rdl/outputs/docs/html/js/path_search.js | 84 + rdl/outputs/docs/html/js/progressbar.min.js | 1 + rdl/outputs/docs/html/js/ral.js | 447 +++ rdl/outputs/docs/html/js/search.js | 252 ++ rdl/outputs/docs/html/js/sha1.js | 173 ++ rdl/outputs/docs/html/js/sidebar.js | 287 ++ .../docs/html/launcher-windows-chrome.bat | 17 + .../docs/html/launcher-windows-edge.bat | 19 + .../docs/html/launcher-windows-firefox.bat | 14 + rdl/outputs/docs/html/search/bkt-0.json | 1 + rdl/outputs/docs/html/search/bkt_index.js | 1 + rdl/outputs/docs/msk_top_regs.md | 14 +- rdl/outputs/docs/msk_top_regs.pdf | Bin 115808 -> 14190 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 114 +- .../msk_top_regs/tests/test_msk_top_regs.py | 2 +- rdl/outputs/rtl/msk_top_regs_pkg.vhd | 21 +- rdl/src/msk_top_regs.rdl | 15 +- 106 files changed, 11022 insertions(+), 85 deletions(-) create mode 100644 rdl/outputs/docs/html/.launcher_data/firefox/user.js create mode 100644 rdl/outputs/docs/html/content/1211d8a8c3c9175e1c33719680affb67165e68d7.html create mode 100644 rdl/outputs/docs/html/content/1254c2cce678b196818b4f08e31bc15b1b3e6e8e.html create mode 100644 rdl/outputs/docs/html/content/14648ccc7797ab5a2e0a9ce250fc373fb5d1b044.html create mode 100644 rdl/outputs/docs/html/content/181914803428de754127f501a151f8d9f2f6346f.html create mode 100644 rdl/outputs/docs/html/content/1e2385a5df67ff7f5d1fbfe621945563573fbb22.html create mode 100644 rdl/outputs/docs/html/content/1e5eb9d33100e7486423224eec5450a659e2203c.html create mode 100644 rdl/outputs/docs/html/content/1fc360864d8b656cfa1ebcc20f12a51ba4f4f9cc.html create mode 100644 rdl/outputs/docs/html/content/263d902a6f30dcb8d14e261e3eb867f29ae8aa29.html create mode 100644 rdl/outputs/docs/html/content/26afac861ad2452f8ace4d5f4459d66b2ead24dc.html create mode 100644 rdl/outputs/docs/html/content/2b5b7862ddb3fa504d82685711c9a66bce7f577d.html create mode 100644 rdl/outputs/docs/html/content/373508e257881c5e4a5502062b7c9aa9a792dc12.html create mode 100644 rdl/outputs/docs/html/content/38738d6efca727bb9bf39e13e872f922349ff15e.html create mode 100644 rdl/outputs/docs/html/content/4092c31237c70d2c50e8a1e8a25d3a13f9cec6a2.html create mode 100644 rdl/outputs/docs/html/content/4f916507967fd003316096871c9cb43cb2983373.html create mode 100644 rdl/outputs/docs/html/content/54cea48e8d9edee01f284df7c443e2add40252d9.html create mode 100644 rdl/outputs/docs/html/content/611b0a3a62ae385442fa3b250263026f7cfdd441.html create mode 100644 rdl/outputs/docs/html/content/611d75d5fc9168e025083358f26a5e06ca7b3007.html create mode 100644 rdl/outputs/docs/html/content/6a1cea7d8db3cfd91d0b598d43abc73b85b237e5.html create mode 100644 rdl/outputs/docs/html/content/766520c9b6891107c7d1b147a3b1bed28bebe71c.html create mode 100644 rdl/outputs/docs/html/content/8341423b7e011932aacabd59a183a4c2d7c81b46.html create mode 100644 rdl/outputs/docs/html/content/aaa99b88ab61eb3569764525c3aef19596c2a4e8.html create mode 100644 rdl/outputs/docs/html/content/aab8d61e4e2c8cc1adaabca728671903515e6053.html create mode 100644 rdl/outputs/docs/html/content/b4c18df4e6a7993047f37ec6f74d05dae744e911.html create mode 100644 rdl/outputs/docs/html/content/b54cac1ec3dda403a0b7a1db5c224b03a74f9f9d.html create mode 100644 rdl/outputs/docs/html/content/b60627ebae54f7207a648572a54cbd7f918c0ae7.html create mode 100644 rdl/outputs/docs/html/content/b883348faf8a0f9a3da26ea0fc3d9e8d47d5d737.html create mode 100644 rdl/outputs/docs/html/content/c3a0e44e2c6ffcbb57715d4fc6fd621eca17bbe9.html create mode 100644 rdl/outputs/docs/html/content/cc5ab06a84343db43279a768a29160c012ea8fcc.html create mode 100644 rdl/outputs/docs/html/content/ce06e4ec8a024a37ce1f65c5c90a495b4b9555cf.html create mode 100644 rdl/outputs/docs/html/content/d4cb92fc9fcd9a12ab08ab5d411dbc399e12cb62.html create mode 100644 rdl/outputs/docs/html/content/db8d99c8aadce2aee57600cd3b0212da9c9972cf.html create mode 100644 rdl/outputs/docs/html/content/dbb506c578ba1e4bb6eaf4767617cd58beb4a3ae.html create mode 100644 rdl/outputs/docs/html/content/e3c786425f5920f3a1e885e740599831cfd792bc.html create mode 100644 rdl/outputs/docs/html/content/e41b7c226a4ebc36be166e4a2b523cb2a8959870.html create mode 100644 rdl/outputs/docs/html/content/eca580c1f1dcded555681dfd8a6e15e379cf5f0f.html create mode 100644 rdl/outputs/docs/html/content/ee57807489e9b5f5b719044911537b66b3a06bdf.html create mode 100644 rdl/outputs/docs/html/content/f439a6888cc769d718b5d38d555e7aed6b422371.html create mode 100644 rdl/outputs/docs/html/content/f7daaf8ea45f55844cf66da35a46142d55a5253a.html create mode 100644 rdl/outputs/docs/html/content/fd9b9e9189271b3cac659475d0b7621c0ffe0c3f.html create mode 100644 rdl/outputs/docs/html/css/layout.css create mode 100644 rdl/outputs/docs/html/css/normalize.css create mode 100644 rdl/outputs/docs/html/css/theme.css create mode 100644 rdl/outputs/docs/html/data/data_index.js create mode 100644 rdl/outputs/docs/html/data/ral-data-0.json create mode 100644 rdl/outputs/docs/html/favicon.png create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.eot create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.svg create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.ttf create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff2 create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.eot create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.svg create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.ttf create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.woff create mode 100644 rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.woff2 create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bold.eot create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bold.ttf create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bold.woff create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bold.woff2 create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bolditalic.eot create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bolditalic.ttf create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bolditalic.woff create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-bolditalic.woff2 create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-italic.eot create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-italic.ttf create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-italic.woff create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-italic.woff2 create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-regular.eot create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-regular.ttf create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-regular.woff create mode 100644 rdl/outputs/docs/html/fonts/Lato/lato-regular.woff2 create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-bold.eot create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-bold.ttf create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-bold.woff create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-regular.eot create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-regular.ttf create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-regular.woff create mode 100644 rdl/outputs/docs/html/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 create mode 100644 rdl/outputs/docs/html/index.html create mode 100644 rdl/outputs/docs/html/js/address_search.js create mode 100644 rdl/outputs/docs/html/js/content_search.js create mode 100644 rdl/outputs/docs/html/js/field_testers.js create mode 100644 rdl/outputs/docs/html/js/index_edit.js create mode 100644 rdl/outputs/docs/html/js/main.js create mode 100644 rdl/outputs/docs/html/js/nav.js create mode 100644 rdl/outputs/docs/html/js/path_search.js create mode 100644 rdl/outputs/docs/html/js/progressbar.min.js create mode 100644 rdl/outputs/docs/html/js/ral.js create mode 100644 rdl/outputs/docs/html/js/search.js create mode 100644 rdl/outputs/docs/html/js/sha1.js create mode 100644 rdl/outputs/docs/html/js/sidebar.js create mode 100644 rdl/outputs/docs/html/launcher-windows-chrome.bat create mode 100644 rdl/outputs/docs/html/launcher-windows-edge.bat create mode 100644 rdl/outputs/docs/html/launcher-windows-firefox.bat create mode 100644 rdl/outputs/docs/html/search/bkt-0.json create mode 100644 rdl/outputs/docs/html/search/bkt_index.js diff --git a/rdl/Makefile b/rdl/Makefile index 901e45d..3d7be10 100644 --- a/rdl/Makefile +++ b/rdl/Makefile @@ -10,6 +10,7 @@ OUTCHEADER = outputs/c-header all: $(OUTDOCS)/msk_top_regs.pdf \ $(OUTDOCS)/msk_top_regs.md \ + $(OUTDOCS)/html/index.html \ $(OUTRTL)/msk_top_regs.vhd \ $(OUTPYTHON)/__init__.py \ $(OUTCHEADER)/msk_top_regs.h @@ -17,20 +18,23 @@ all: $(OUTDOCS)/msk_top_regs.pdf \ $(OUTDOCS)/msk_top_regs.md: $(SRCS) peakrdl markdown $(SRCS) -o $(OUTDOCS)/msk_top_regs.md +$(OUTDOCS)/html/index.html: $(SRCS) + peakrdl html $(SRCS) -o $(OUTDOCS)/html + $(OUTCHEADER)/msk_top_regs.h: $(SRCS) peakrdl c-header $(SRCS) -o outputs/c-header/msk_top_regs.h $(OUTRTL)/msk_top_regs.vhd: $(SRCS) peakrdl regblock-vhdl $(SRCS) -o $(OUTRTL) --cpuif axi4-lite -$(OUTDOCS)/msk_top_regs.pdf: $(OUTDOCS)/msk_top_regs.md - pandoc -o $(OUTDOCS)/msk_top_regs.pdf $(OUTDOCS)/msk_top_regs.md +$(OUTDOCS)/msk_top_regs.pdf: $(OUTDOCS)/html/index.html + pandoc -o $(OUTDOCS)/msk_top_regs.pdf $(OUTDOCS)/html/index.html --pdf-engine=weasyprint --css=$(OUTDOCS)/html/css/theme.css $(OUTPYTHON)/__init__.py: $(SRCS) peakrdl python $(SRCS) --async -o $(OUTPYTHON) clean: - rm outputs/docs/* + rm -r outputs/docs/* rm outputs/c-header/* rm -r outputs/python/* - rm outputs/rtl/* \ No newline at end of file + rm outputs/rtl/* diff --git a/rdl/outputs/c-header/msk_top_regs.h b/rdl/outputs/c-header/msk_top_regs.h index d5b3d65..a290f98 100644 --- a/rdl/outputs/c-header/msk_top_regs.h +++ b/rdl/outputs/c-header/msk_top_regs.h @@ -319,11 +319,11 @@ extern "C" { #define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_bw 32 #define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_AA4EC676__DATA_reset 0x0 -// Reg - msk_top_regs::observation_data_data_dbd8270c_name_8a90eed1 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bm 0xffffffff -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bp 0 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_bw 32 -#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_DBD8270C_NAME_8A90EED1__DATA_reset 0x0 +// Reg - msk_top_regs::observation_data_data_91b9abca_name_8a90eed1 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_91B9ABCA_NAME_8A90EED1__DATA_bm 0xffffffff +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_91B9ABCA_NAME_8A90EED1__DATA_bp 0 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_91B9ABCA_NAME_8A90EED1__DATA_bw 32 +#define MSK_TOP_REGS__OBSERVATION_DATA_DATA_91B9ABCA_NAME_8A90EED1__DATA_reset 0x0 // Addrmap - msk_top_regs typedef struct __attribute__ ((__packed__)) { diff --git a/rdl/outputs/docs/html/.launcher_data/firefox/user.js b/rdl/outputs/docs/html/.launcher_data/firefox/user.js new file mode 100644 index 0000000..34b966f --- /dev/null +++ b/rdl/outputs/docs/html/.launcher_data/firefox/user.js @@ -0,0 +1,4 @@ +user_pref("app.normandy.first_run", false); +user_pref("toolkit.telemetry.reportingpolicy.firstRun", false); + +user_pref("security.fileuri.strict_origin_policy", false); \ No newline at end of file diff --git a/rdl/outputs/docs/html/content/1211d8a8c3c9175e1c33719680affb67165e68d7.html b/rdl/outputs/docs/html/content/1211d8a8c3c9175e1c33719680affb67165e68d7.html new file mode 100644 index 0000000..74cafaa --- /dev/null +++ b/rdl/outputs/docs/html/content/1211d8a8c3c9175e1c33719680affb67165e68d7.html @@ -0,0 +1,70 @@ + + +
+

Tx async FIFO read and write pointers

+ + +
+
Absolute Address:
+
+
Base Offset:
0x90
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Read and Write Pointers

+

Bits 31:16 - write pointer (12-bits)

+

Bits 15:00 - read pointer (12-bits)

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/1254c2cce678b196818b4f08e31bc15b1b3e6e8e.html b/rdl/outputs/docs/html/content/1254c2cce678b196818b4f08e31bc15b1b3e6e8e.html new file mode 100644 index 0000000..25659e1 --- /dev/null +++ b/rdl/outputs/docs/html/content/1254c2cce678b196818b4f08e31bc15b1b3e6e8e.html @@ -0,0 +1,95 @@ + + +
+

PI Controller Configuration Configuration Register 1

+ + +
+
Absolute Address:
+
+
Base Offset:
0x34
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Configures PI Controller I-gain and divisor

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:24]i_shift + rw0x0 + + + Integral Gain Bit Shift + + +
[23:0]i_gain + rw0x0 + + + Integral Gain Value + + +
+

+ +

+

Field Descriptions

+ +

i_shift - Integral Gain Bit Shift + +

+
+

Value n of 0-32 sets the integral divisor as 2^-n

+
+ +

i_gain - Integral Gain Value + +

+
+

Value m of 0-16,777,215 sets the integral multiplier

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/14648ccc7797ab5a2e0a9ce250fc373fb5d1b044.html b/rdl/outputs/docs/html/content/14648ccc7797ab5a2e0a9ce250fc373fb5d1b044.html new file mode 100644 index 0000000..77b6e21 --- /dev/null +++ b/rdl/outputs/docs/html/content/14648ccc7797ab5a2e0a9ce250fc373fb5d1b044.html @@ -0,0 +1,72 @@ + + +
+

F2 PI Controller Accumulator

+ + +
+
Absolute Address:
+
+
Base Offset:
0x5c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Value of the F2 PI Controller Accumulator

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + PI Controller Accumulator Value + + +
+

+ +

+

Field Descriptions

+ +

data - PI Controller Accumulator Value + +

+
+

PI Controller Accumulator Value

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/181914803428de754127f501a151f8d9f2f6346f.html b/rdl/outputs/docs/html/content/181914803428de754127f501a151f8d9f2f6346f.html new file mode 100644 index 0000000..f88fad0 --- /dev/null +++ b/rdl/outputs/docs/html/content/181914803428de754127f501a151f8d9f2f6346f.html @@ -0,0 +1,77 @@ + + +
+

Modem Tx Input Data Width

+ + +
+
Absolute Address:
+
+
Base Offset:
0x38
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set the parallel data width of the parallel-to-serial converter

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:8]----
[7:0]data_width + rw0x8 + + + Modem input/output data width + + +
+

+ +

+

Field Descriptions

+ +

data_width - Modem input/output data width + +

+
+

Set the data width of the modem input/output

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/1e2385a5df67ff7f5d1fbfe621945563573fbb22.html b/rdl/outputs/docs/html/content/1e2385a5df67ff7f5d1fbfe621945563573fbb22.html new file mode 100644 index 0000000..1d7492d --- /dev/null +++ b/rdl/outputs/docs/html/content/1e2385a5df67ff7f5d1fbfe621945563573fbb22.html @@ -0,0 +1,69 @@ + + +
+

Bitrate NCO Frequency Control Word

+ + +
+
Absolute Address:
+
+
Base Offset:
0x1c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set Modem Data Rate

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + Frequency Control Word + + +
+

+ +

+

Field Descriptions

+ +

config_data - Frequency Control Word + +

+
+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/1e5eb9d33100e7486423224eec5450a659e2203c.html b/rdl/outputs/docs/html/content/1e5eb9d33100e7486423224eec5450a659e2203c.html new file mode 100644 index 0000000..c5617b5 --- /dev/null +++ b/rdl/outputs/docs/html/content/1e5eb9d33100e7486423224eec5450a659e2203c.html @@ -0,0 +1,68 @@ + + +
+

F1 Error Value

+ + +
+
Absolute Address:
+
+
Base Offset:
0x74
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Error value of the F1 Costas loop after each active bit period

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/1fc360864d8b656cfa1ebcc20f12a51ba4f4f9cc.html b/rdl/outputs/docs/html/content/1fc360864d8b656cfa1ebcc20f12a51ba4f4f9cc.html new file mode 100644 index 0000000..6167fcd --- /dev/null +++ b/rdl/outputs/docs/html/content/1fc360864d8b656cfa1ebcc20f12a51ba4f4f9cc.html @@ -0,0 +1,201 @@ + + +
+

PRBS Control 0

+ + +
+
Absolute Address:
+
+
Base Offset:
0x40
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Configures operation of the PRBS Generator and Monitor

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:16]prbs_sync_threshold + rw0x0 + + + PRBS Auto Sync Threshold + + +
[15:4]prbs_reserved + rw0x0 + + + Reserved + + +
[3]prbs_manual_sync + w0x0 + + + PRBS Manual Sync + + +
[2]prbs_clear + w0x0 + + + PRBS Clear Counters + + +
[1]prbs_error_insert + w0x0 + + + PRBS Error Insert + + +
[0]prbs_sel + rw0x0 + + + PRBS Data Select + + +
+

+ +

+

Field Descriptions

+ +

prbs_sync_threshold - PRBS Auto Sync Threshold + +

+
+

0 : Auto Sync Disabled

+

N > 0 : Auto sync after N errors

+
+ +

prbs_manual_sync - PRBS Manual Sync + +

+
+

0 -> 1 : Synchronize PRBS monitor

+

1 -> 0 : Synchronize PRBS monitor

+
+ +

prbs_clear - PRBS Clear Counters + +

+
+

0 -> 1 : Clear PRBS Counters

+

1 -> 0 : Clear PRBS Counters

+
+ +

prbs_error_insert - PRBS Error Insert + +

+
+

0 -> 1 : Insert bit error in Tx data (both Normal and PRBS)

+

1 -> 0 : Insert bit error in Tx data (both Normal and PRBS)

+
+ +

prbs_sel - PRBS Data Select + +

+
+

0 -> Select Normal Tx Data +1 -> Select PRBS Tx Data

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/263d902a6f30dcb8d14e261e3eb867f29ae8aa29.html b/rdl/outputs/docs/html/content/263d902a6f30dcb8d14e261e3eb867f29ae8aa29.html new file mode 100644 index 0000000..ac7d09d --- /dev/null +++ b/rdl/outputs/docs/html/content/263d902a6f30dcb8d14e261e3eb867f29ae8aa29.html @@ -0,0 +1,95 @@ + + +
+

PI Controller Configuration Configuration Register 2

+ + +
+
Absolute Address:
+
+
Base Offset:
0x68
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Configures PI Controller I-gain and divisor

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:24]p_shift + rw0x0 + + + Proportional Gain Bit Shift + + +
[23:0]p_gain + rw0x0 + + + Proportional Gain Value + + +
+

+ +

+

Field Descriptions

+ +

p_shift - Proportional Gain Bit Shift + +

+
+

Value n of 0-32 sets the proportional divisor as 2^-n

+
+ +

p_gain - Proportional Gain Value + +

+
+

Value m of 0-16,777,215 sets the proportional multiplier

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/26afac861ad2452f8ace4d5f4459d66b2ead24dc.html b/rdl/outputs/docs/html/content/26afac861ad2452f8ace4d5f4459d66b2ead24dc.html new file mode 100644 index 0000000..0654293 --- /dev/null +++ b/rdl/outputs/docs/html/content/26afac861ad2452f8ace4d5f4459d66b2ead24dc.html @@ -0,0 +1,68 @@ + + +
+

F1 NCO Frequency Adjust

+ + +
+
Absolute Address:
+
+
Base Offset:
0x6c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Frequency offet applied to the F1 NCO

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/2b5b7862ddb3fa504d82685711c9a66bce7f577d.html b/rdl/outputs/docs/html/content/2b5b7862ddb3fa504d82685711c9a66bce7f577d.html new file mode 100644 index 0000000..85a5bfe --- /dev/null +++ b/rdl/outputs/docs/html/content/2b5b7862ddb3fa504d82685711c9a66bce7f577d.html @@ -0,0 +1,72 @@ + + +
+

MSK Modem Status 1

+ + +
+
Absolute Address:
+
+
Base Offset:
0x14
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Modem status data

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + Tx Bit Count + + +
+

+ +

+

Field Descriptions

+ +

data - Tx Bit Count + +

+
+

Count of data requests made by modem

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/373508e257881c5e4a5502062b7c9aa9a792dc12.html b/rdl/outputs/docs/html/content/373508e257881c5e4a5502062b7c9aa9a792dc12.html new file mode 100644 index 0000000..872c0ab --- /dev/null +++ b/rdl/outputs/docs/html/content/373508e257881c5e4a5502062b7c9aa9a792dc12.html @@ -0,0 +1,68 @@ + + +
+

PRBS Control 3

+ + +
+
Absolute Address:
+
+
Base Offset:
0x4c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

PRBS Error Mask

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + PRBS Error Mask + + +
+

+ +

+

Field Descriptions

+ +

config_data - PRBS Error Mask + +

+
+

Bit positions set to '1' indicate bits that are inverted when a bit error is inserted

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/38738d6efca727bb9bf39e13e872f922349ff15e.html b/rdl/outputs/docs/html/content/38738d6efca727bb9bf39e13e872f922349ff15e.html new file mode 100644 index 0000000..8813da8 --- /dev/null +++ b/rdl/outputs/docs/html/content/38738d6efca727bb9bf39e13e872f922349ff15e.html @@ -0,0 +1,68 @@ + + +
+

PRBS Control 1

+ + +
+
Absolute Address:
+
+
Base Offset:
0x44
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

PRBS Initial State

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + PRBS Seed + + +
+

+ +

+

Field Descriptions

+ +

config_data - PRBS Seed + +

+
+

Sets the starting value of the PRBS generator

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/4092c31237c70d2c50e8a1e8a25d3a13f9cec6a2.html b/rdl/outputs/docs/html/content/4092c31237c70d2c50e8a1e8a25d3a13f9cec6a2.html new file mode 100644 index 0000000..96a4a32 --- /dev/null +++ b/rdl/outputs/docs/html/content/4092c31237c70d2c50e8a1e8a25d3a13f9cec6a2.html @@ -0,0 +1,77 @@ + + +
+

Modem Rx Output Data Width

+ + +
+
Absolute Address:
+
+
Base Offset:
0x3c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set the parallel data width of the serial-to-parallel converter

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:8]----
[7:0]data_width + rw0x8 + + + Modem input/output data width + + +
+

+ +

+

Field Descriptions

+ +

data_width - Modem input/output data width + +

+
+

Set the data width of the modem input/output

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/4f916507967fd003316096871c9cb43cb2983373.html b/rdl/outputs/docs/html/content/4f916507967fd003316096871c9cb43cb2983373.html new file mode 100644 index 0000000..6b97b33 --- /dev/null +++ b/rdl/outputs/docs/html/content/4f916507967fd003316096871c9cb43cb2983373.html @@ -0,0 +1,161 @@ + + +
+

MSK Modem Status 0

+ + +
+
Absolute Address:
+
+
Base Offset:
0x10
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Modem status bits

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:4]----
[3]tx_axis_valid + r0x0 + + + Tx S_AXIS_VALID + + +
[2]rx_enable + r0x0 + + + AD9363 ADC Interface Rx Enable Input Active + + +
[1]tx_enable + r0x0 + + + AD9363 DAC Interface Tx Enable Input Active + + +
[0]demod_sync_lock + r0x0 + + + Demodulator Sync Status + + +
+

+ +

+

Field Descriptions

+ +

tx_axis_valid - Tx S_AXIS_VALID + +

+
+

1 -> S_AXIS_VALID Enabled

+

0 -> S_AXIS_VALID Disabled

+
+ +

rx_enable - AD9363 ADC Interface Rx Enable Input Active + +

+
+

1 -> Data from ADC Enabled

+

0 -> Data from ADC Disabled

+
+ +

tx_enable - AD9363 DAC Interface Tx Enable Input Active + +

+
+

1 -> Data to DAC Enabled

+

0 -> Data to DAC Disabled

+
+ +

demod_sync_lock - Demodulator Sync Status + +

+
+

Demodulator Sync Status - not currently implemented

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/54cea48e8d9edee01f284df7c443e2add40252d9.html b/rdl/outputs/docs/html/content/54cea48e8d9edee01f284df7c443e2add40252d9.html new file mode 100644 index 0000000..7120ffb --- /dev/null +++ b/rdl/outputs/docs/html/content/54cea48e8d9edee01f284df7c443e2add40252d9.html @@ -0,0 +1,189 @@ + + +
+

MSK Modem Control

+ + +
+
Absolute Address:
+
+
Base Offset:
0xc
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

MSK Modem Configuration and Control

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:5]----
[4]diff_encoder_loopback + rw0x0 + + + Differential Encoder -> Decoder Loopback Enable + + +
[3]clear_counts + rw0x0 + + + Clear Status Counters + + +
[2]rx_invert + rw0x0 + + + Rx Data Invert Enable + + +
[1]loopback_ena + rw0x0 + + + Modem Digital Tx -> Rx Loopback Enable + + +
[0]ptt + rw0x0 + + + Push-to-Talk Enable + + +
+

+ +

+

Field Descriptions

+ +

diff_encoder_loopback - Differential Encoder -> Decoder Loopback Enable + +

+
+

0 -> Differential Encoder -> Decoder loopback disabled

+

1 -> Differential Encoder -> Decoder loopback enabled

+
+ +

clear_counts - Clear Status Counters + +

+
+

Clear Tx Bit Counter and Tx Enable Counter

+
+ +

rx_invert - Rx Data Invert Enable + +

+
+

0 -> Rx data normal +1 -> Rx data inverted

+
+ +

loopback_ena - Modem Digital Tx -> Rx Loopback Enable + +

+
+

0 -> Modem loopback disabled

+

1 -> Modem loopback enabled

+
+ +

ptt - Push-to-Talk Enable + +

+
+

0 -> PTT Disabled +1 -> PTT Enabled

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/611b0a3a62ae385442fa3b250263026f7cfdd441.html b/rdl/outputs/docs/html/content/611b0a3a62ae385442fa3b250263026f7cfdd441.html new file mode 100644 index 0000000..019e6eb --- /dev/null +++ b/rdl/outputs/docs/html/content/611b0a3a62ae385442fa3b250263026f7cfdd441.html @@ -0,0 +1,72 @@ + + +
+

MSK Modem Status 2

+ + +
+
Absolute Address:
+
+
Base Offset:
0x18
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Modem status data

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + Tx Enable Count + + +
+

+ +

+

Field Descriptions

+ +

data - Tx Enable Count + +

+
+

Number of clocks on which Tx Enable is active

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/611d75d5fc9168e025083358f26a5e06ca7b3007.html b/rdl/outputs/docs/html/content/611d75d5fc9168e025083358f26a5e06ca7b3007.html new file mode 100644 index 0000000..7fc73be --- /dev/null +++ b/rdl/outputs/docs/html/content/611d75d5fc9168e025083358f26a5e06ca7b3007.html @@ -0,0 +1,144 @@ + + +
+

PI Controller Configuration and Low-pass Filter Configuration

+ + +
+
Absolute Address:
+
+
Base Offset:
0x30
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Configure PI controller and low-pass filter

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:8]lpf_alpha + rw0x0 + + + Lowpass IIR filter alpha + + +
[7:2]prbs_reserved + rw0x0 + + + Reserved + + +
[1]lpf_zero + rw0x0 + + + Hold the PI Accumulator at zero + + +
[0]lpf_freeze + rw0x0 + + + Freeze the accumulator's current value + + +
+

+ +

+

Field Descriptions

+ +

lpf_alpha - Lowpass IIR filter alpha + +

+
+

Value controls the filter rolloff

+
+ +

lpf_zero - Hold the PI Accumulator at zero + +

+
+

0 -> Normal operation

+

1 -> Zero and hold accumulator

+
+ +

lpf_freeze - Freeze the accumulator's current value + +

+
+

0 -> Normal operation

+

1 -> Freeze current value

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/6a1cea7d8db3cfd91d0b598d43abc73b85b237e5.html b/rdl/outputs/docs/html/content/6a1cea7d8db3cfd91d0b598d43abc73b85b237e5.html new file mode 100644 index 0000000..c45c2e1 --- /dev/null +++ b/rdl/outputs/docs/html/content/6a1cea7d8db3cfd91d0b598d43abc73b85b237e5.html @@ -0,0 +1,64 @@ + + +
+

Pluto MSK FPGA Hash ID - Lower 32-bits

+ + +
+
Absolute Address:
+
+
Base Offset:
0x0
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]hash_id_lo + r0xaaaa5555 + + + Hash ID Lower 32-bits + + +
+

+ +

+

Field Descriptions

+ +

hash_id_lo - Hash ID Lower 32-bits + +

+
+

Lower 32-bits of Pluto MSK FPGA Hash ID

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/766520c9b6891107c7d1b147a3b1bed28bebe71c.html b/rdl/outputs/docs/html/content/766520c9b6891107c7d1b147a3b1bed28bebe71c.html new file mode 100644 index 0000000..fb34eaf --- /dev/null +++ b/rdl/outputs/docs/html/content/766520c9b6891107c7d1b147a3b1bed28bebe71c.html @@ -0,0 +1,73 @@ + + +
+

PRBS Status 0

+ + +
+
Absolute Address:
+
+
Base Offset:
0x50
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

PRBS Bits Received

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + PRBS Bits Received + + +
+

+ +

+

Field Descriptions

+ +

data - PRBS Bits Received + +

+
+

Number of bits received by the PRBS monitor since last +BER can be calculated as the ratio of received bits to errored-bits

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/8341423b7e011932aacabd59a183a4c2d7c81b46.html b/rdl/outputs/docs/html/content/8341423b7e011932aacabd59a183a4c2d7c81b46.html new file mode 100644 index 0000000..87df749 --- /dev/null +++ b/rdl/outputs/docs/html/content/8341423b7e011932aacabd59a183a4c2d7c81b46.html @@ -0,0 +1,69 @@ + + +
+

Rx F1 NCO Frequency Control Word

+ + +
+
Absolute Address:
+
+
Base Offset:
0x28
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set Demodulator F1 Frequency

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + Frequency Control Word + + +
+

+ +

+

Field Descriptions

+ +

config_data - Frequency Control Word + +

+
+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/aaa99b88ab61eb3569764525c3aef19596c2a4e8.html b/rdl/outputs/docs/html/content/aaa99b88ab61eb3569764525c3aef19596c2a4e8.html new file mode 100644 index 0000000..fbe5ace --- /dev/null +++ b/rdl/outputs/docs/html/content/aaa99b88ab61eb3569764525c3aef19596c2a4e8.html @@ -0,0 +1,72 @@ + + +
+

MSK Modem Status 3

+ + +
+
Absolute Address:
+
+
Base Offset:
0x60
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Modem status data

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + S_AXIS Transfers + + +
+

+ +

+

Field Descriptions

+ +

data - S_AXIS Transfers + +

+
+

Number completed S_AXIS transfers

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/aab8d61e4e2c8cc1adaabca728671903515e6053.html b/rdl/outputs/docs/html/content/aab8d61e4e2c8cc1adaabca728671903515e6053.html new file mode 100644 index 0000000..77463d4 --- /dev/null +++ b/rdl/outputs/docs/html/content/aab8d61e4e2c8cc1adaabca728671903515e6053.html @@ -0,0 +1,69 @@ + + +
+

Tx F1 NCO Frequency Control Word

+ + +
+
Absolute Address:
+
+
Base Offset:
0x20
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set Modulator F1 Frequency

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + Frequency Control Word + + +
+

+ +

+

Field Descriptions

+ +

config_data - Frequency Control Word + +

+
+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/b4c18df4e6a7993047f37ec6f74d05dae744e911.html b/rdl/outputs/docs/html/content/b4c18df4e6a7993047f37ec6f74d05dae744e911.html new file mode 100644 index 0000000..c615bf7 --- /dev/null +++ b/rdl/outputs/docs/html/content/b4c18df4e6a7993047f37ec6f74d05dae744e911.html @@ -0,0 +1,335 @@ + + +
+

Pluto MSK Registers

+ + +
+
Absolute Address:
+
+
Base Offset:
0x0
+
Size:
0x98
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

MSK Modem Configuration and Status Registers

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OffsetIdentifierName
0x00Hash_ID_LowPluto MSK FPGA Hash ID - Lower 32-bits + +
0x04Hash_ID_HighPluto MSK FPGA Hash ID - Upper 32-bits + +
0x08MSK_InitMSK Modem Initialization Control + +
0x0CMSK_ControlMSK Modem Control + +
0x10MSK_StatusMSK Modem Status 0 + +
0x14Tx_Bit_CountMSK Modem Status 1 + +
0x18Tx_Enable_CountMSK Modem Status 2 + +
0x1CFb_FreqWordBitrate NCO Frequency Control Word + +
0x20TX_F1_FreqWordTx F1 NCO Frequency Control Word + +
0x24TX_F2_FreqWordTx F2 NCO Frequency Control Word + +
0x28RX_F1_FreqWordRx F1 NCO Frequency Control Word + +
0x2CRX_F2_FreqWordRx F2 NCO Frequency Control Word + +
0x30LPF_Config_0PI Controller Configuration and Low-pass Filter Configuration + +
0x34LPF_Config_1PI Controller Configuration Configuration Register 1 + +
0x38Tx_Data_WidthModem Tx Input Data Width + +
0x3CRx_Data_WidthModem Rx Output Data Width + +
0x40PRBS_ControlPRBS Control 0 + +
0x44PRBS_Initial_StatePRBS Control 1 + +
0x48PRBS_PolynomialPRBS Control 2 + +
0x4CPRBS_Error_MaskPRBS Control 3 + +
0x50PRBS_Bit_CountPRBS Status 0 + +
0x54PRBS_Error_CountPRBS Status 1 + +
0x58LPF_Accum_F1F1 PI Controller Accumulator + +
0x5CLPF_Accum_F2F2 PI Controller Accumulator + +
0x60axis_xfer_countMSK Modem Status 3 + +
0x64Rx_Sample_DiscardRx Sample Discard + +
0x68LPF_Config_2PI Controller Configuration Configuration Register 2 + +
0x6Cf1_nco_adjustF1 NCO Frequency Adjust + +
0x70f2_nco_adjustF2 NCO Frequency Adjust + +
0x74f1_errorF1 Error Value + +
0x78f2_errorF2 Error Value + +
0x7CTx_Sync_CtrlTransmitter Sync Control + +
0x80Tx_Sync_CntTransmitter Sync Duration + +
0x84lowpass_ema_alpha1Exponential Moving Average Alpha + +
0x88lowpass_ema_alpha2Exponential Moving Average Alpha + +
0x8Crx_powerReceive Power + +
0x90tx_async_fifo_rd_wr_ptrTx async FIFO read and write pointers + +
0x94rx_async_fifo_rd_wr_ptrRx async FIFO read and write pointers + +
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/b54cac1ec3dda403a0b7a1db5c224b03a74f9f9d.html b/rdl/outputs/docs/html/content/b54cac1ec3dda403a0b7a1db5c224b03a74f9f9d.html new file mode 100644 index 0000000..403a6e7 --- /dev/null +++ b/rdl/outputs/docs/html/content/b54cac1ec3dda403a0b7a1db5c224b03a74f9f9d.html @@ -0,0 +1,81 @@ + + +
+

Receive Power

+ + +
+
Absolute Address:
+
+
Base Offset:
0x8c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Receive power computed from I/Q ssamples

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:23]----
[22:0]data + rw0x0 + + + Receive Power + + +
+

+ +

+

Field Descriptions

+ +

data - Receive Power + +

+
+

Value that represent the RMS power of the incoming I

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/b60627ebae54f7207a648572a54cbd7f918c0ae7.html b/rdl/outputs/docs/html/content/b60627ebae54f7207a648572a54cbd7f918c0ae7.html new file mode 100644 index 0000000..ae7e2a5 --- /dev/null +++ b/rdl/outputs/docs/html/content/b60627ebae54f7207a648572a54cbd7f918c0ae7.html @@ -0,0 +1,68 @@ + + +
+

F2 Error Value

+ + +
+
Absolute Address:
+
+
Base Offset:
0x78
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Error value of the F2 Costas loop after each active bit period

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/b883348faf8a0f9a3da26ea0fc3d9e8d47d5d737.html b/rdl/outputs/docs/html/content/b883348faf8a0f9a3da26ea0fc3d9e8d47d5d737.html new file mode 100644 index 0000000..421d85f --- /dev/null +++ b/rdl/outputs/docs/html/content/b883348faf8a0f9a3da26ea0fc3d9e8d47d5d737.html @@ -0,0 +1,69 @@ + + +
+

Tx F2 NCO Frequency Control Word

+ + +
+
Absolute Address:
+
+
Base Offset:
0x24
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set Modulator F2 Frequency

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + Frequency Control Word + + +
+

+ +

+

Field Descriptions

+ +

config_data - Frequency Control Word + +

+
+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/c3a0e44e2c6ffcbb57715d4fc6fd621eca17bbe9.html b/rdl/outputs/docs/html/content/c3a0e44e2c6ffcbb57715d4fc6fd621eca17bbe9.html new file mode 100644 index 0000000..c5a4feb --- /dev/null +++ b/rdl/outputs/docs/html/content/c3a0e44e2c6ffcbb57715d4fc6fd621eca17bbe9.html @@ -0,0 +1,166 @@ + + +
+

Transmitter Sync Control

+ + +
+
Absolute Address:
+
+
Base Offset:
0x7c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Provides control bits for generation of transmitter synchronization patterns

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:4]----
[3]tx_sync_f2 + rw0x0 + + + Tx F2 Sync Enable + + +
[2]tx_sync_f1 + rw0x0 + + + Tx F1 Sync Enable + + +
[1]tx_sync_force + rw0x0 + + + Tx Sync Force + + +
[0]tx_sync_ena + rw0x0 + + + Tx Sync Enable + + +
+

+ +

+

Field Descriptions

+ +

tx_sync_f2 - Tx F2 Sync Enable + +

+
+

Enables/Disables transmission of F2 tone for receiver synchronization +0 : F2 tone transmission disabled

+

1 : F2 tone transmission enabled

+

Both F1 and F2 can be enabled at the same time

+
+ +

tx_sync_f1 - Tx F1 Sync Enable + +

+
+

Enables/Disables transmission of F1 tone for receiver synchronization +0 : F1 tone transmission disabled

+

1 : F1 tone transmission enabled

+

Both F1 and F2 can be enabled at the same time

+
+ +

tx_sync_force - Tx Sync Force + +

+
+

0 : Normal operation

+

1 : Transmit synchronization pattern

+
+ +

tx_sync_ena - Tx Sync Enable + +

+
+

0 -> Disable sync transmission

+

1 -> Enable sync transmission when PTT is asserted

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/cc5ab06a84343db43279a768a29160c012ea8fcc.html b/rdl/outputs/docs/html/content/cc5ab06a84343db43279a768a29160c012ea8fcc.html new file mode 100644 index 0000000..8ad2a8b --- /dev/null +++ b/rdl/outputs/docs/html/content/cc5ab06a84343db43279a768a29160c012ea8fcc.html @@ -0,0 +1,134 @@ + + +
+

MSK Modem Initialization Control

+ + +
+
Absolute Address:
+
+
Base Offset:
0x8
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Synchronous initialization of MSK Modem functions, does not affect configuration registers.

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:3]----
[2]rxinit + rw0x1 + + + Rx Init Enable + + +
[1]txinit + rw0x1 + + + Tx Init Enable + + +
[0]txrxinit + rw0x1 + + + Tx/Rx Init Enable + + +
+

+ +

+

Field Descriptions

+ +

rxinit - Rx Init Enable + +

+
+

0 -> Normal Rx operation

+

1 -> Initialize Rx

+
+ +

txinit - Tx Init Enable + +

+
+

0 -> Normal Tx operation

+

1 -> Initialize Tx

+
+ +

txrxinit - Tx/Rx Init Enable + +

+
+

0 -> Normal modem operation

+

1 -> Initialize Tx and Rx

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/ce06e4ec8a024a37ce1f65c5c90a495b4b9555cf.html b/rdl/outputs/docs/html/content/ce06e4ec8a024a37ce1f65c5c90a495b4b9555cf.html new file mode 100644 index 0000000..4392053 --- /dev/null +++ b/rdl/outputs/docs/html/content/ce06e4ec8a024a37ce1f65c5c90a495b4b9555cf.html @@ -0,0 +1,68 @@ + + +
+

F2 NCO Frequency Adjust

+ + +
+
Absolute Address:
+
+
Base Offset:
0x70
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Frequency offet applied to the F2 NCO

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/d4cb92fc9fcd9a12ab08ab5d411dbc399e12cb62.html b/rdl/outputs/docs/html/content/d4cb92fc9fcd9a12ab08ab5d411dbc399e12cb62.html new file mode 100644 index 0000000..6712c3d --- /dev/null +++ b/rdl/outputs/docs/html/content/d4cb92fc9fcd9a12ab08ab5d411dbc399e12cb62.html @@ -0,0 +1,68 @@ + + +
+

PRBS Control 2

+ + +
+
Absolute Address:
+
+
Base Offset:
0x48
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

PRBS Polynomial

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + PRBS Polynomial + + +
+

+ +

+

Field Descriptions

+ +

config_data - PRBS Polynomial + +

+
+

Bit positions set to '1' indicate polynomial feedback positions

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/db8d99c8aadce2aee57600cd3b0212da9c9972cf.html b/rdl/outputs/docs/html/content/db8d99c8aadce2aee57600cd3b0212da9c9972cf.html new file mode 100644 index 0000000..5fdcba9 --- /dev/null +++ b/rdl/outputs/docs/html/content/db8d99c8aadce2aee57600cd3b0212da9c9972cf.html @@ -0,0 +1,64 @@ + + +
+

Pluto MSK FPGA Hash ID - Upper 32-bits

+ + +
+
Absolute Address:
+
+
Base Offset:
0x4
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]hash_id_hi + r0x5555aaaa + + + Hash ID Upper 32-bits + + +
+

+ +

+

Field Descriptions

+ +

hash_id_hi - Hash ID Upper 32-bits + +

+
+

Upper 32-bits of Pluto MSK FPGA Hash ID

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/dbb506c578ba1e4bb6eaf4767617cd58beb4a3ae.html b/rdl/outputs/docs/html/content/dbb506c578ba1e4bb6eaf4767617cd58beb4a3ae.html new file mode 100644 index 0000000..950a4f9 --- /dev/null +++ b/rdl/outputs/docs/html/content/dbb506c578ba1e4bb6eaf4767617cd58beb4a3ae.html @@ -0,0 +1,79 @@ + + +
+

Transmitter Sync Duration

+ + +
+
Absolute Address:
+
+
Base Offset:
0x80
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Sets the duration of the synchronization tones when enabled

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:24]----
[23:0]tx_sync_cnt + rw0x0 + + + Tx sync duration + + +
+

+ +

+

Field Descriptions

+ +

tx_sync_cnt - Tx sync duration + +

+
+

Value from 0x00_0000 to 0xFF_FFFF.

+

This value represents the number bit-times the synchronization

+

signal should be sent after PTT is asserted.

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/e3c786425f5920f3a1e885e740599831cfd792bc.html b/rdl/outputs/docs/html/content/e3c786425f5920f3a1e885e740599831cfd792bc.html new file mode 100644 index 0000000..39c2ab1 --- /dev/null +++ b/rdl/outputs/docs/html/content/e3c786425f5920f3a1e885e740599831cfd792bc.html @@ -0,0 +1,72 @@ + + +
+

Rx async FIFO read and write pointers

+ + +
+
Absolute Address:
+
+
Base Offset:
0x94
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + - + + +
+

+ +

+

Field Descriptions

+ +

data + +

+
+

Read and Write Pointers

+

+Bits 31:16 - write pointer (12-bits)

+

Bits 15:00 - read pointer (12-bits)

+

This register is write-to-capture. To read data the following steps are required:

+
    +
  • Write any value to this register to capture read data
    +
  • Read the register +
+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/e41b7c226a4ebc36be166e4a2b523cb2a8959870.html b/rdl/outputs/docs/html/content/e41b7c226a4ebc36be166e4a2b523cb2a8959870.html new file mode 100644 index 0000000..bb4822e --- /dev/null +++ b/rdl/outputs/docs/html/content/e41b7c226a4ebc36be166e4a2b523cb2a8959870.html @@ -0,0 +1,104 @@ + + +
+

Rx Sample Discard

+ + +
+
Absolute Address:
+
+
Base Offset:
0x64
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Configure samples discard operation for demodulator

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:16]----
[15:8]rx_nco_discard + rw0x0 + + + Rx NCO Sample Discard Value + + +
[7:0]rx_sample_discard + rw0x0 + + + Rx Sample Discard Value + + +
+

+ +

+

Field Descriptions

+ +

rx_nco_discard - Rx NCO Sample Discard Value + +

+
+

Number of NCO samples to discard

+
+ +

rx_sample_discard - Rx Sample Discard Value + +

+
+

Number of Rx samples to discard

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/eca580c1f1dcded555681dfd8a6e15e379cf5f0f.html b/rdl/outputs/docs/html/content/eca580c1f1dcded555681dfd8a6e15e379cf5f0f.html new file mode 100644 index 0000000..2688b8b --- /dev/null +++ b/rdl/outputs/docs/html/content/eca580c1f1dcded555681dfd8a6e15e379cf5f0f.html @@ -0,0 +1,72 @@ + + +
+

F1 PI Controller Accumulator

+ + +
+
Absolute Address:
+
+
Base Offset:
0x58
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Value of the F1 PI Controller Accumulator

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + PI Controller Accumulator Value + + +
+

+ +

+

Field Descriptions

+ +

data - PI Controller Accumulator Value + +

+
+

PI Controller Accumulator Value

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/ee57807489e9b5f5b719044911537b66b3a06bdf.html b/rdl/outputs/docs/html/content/ee57807489e9b5f5b719044911537b66b3a06bdf.html new file mode 100644 index 0000000..bb881fd --- /dev/null +++ b/rdl/outputs/docs/html/content/ee57807489e9b5f5b719044911537b66b3a06bdf.html @@ -0,0 +1,77 @@ + + +
+

Exponential Moving Average Alpha

+ + +
+
Absolute Address:
+
+
Base Offset:
0x88
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Sets the alpha for the EMA

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:18]----
[17:0]alpha + rw0x0 + + + EMA alpha + + +
+

+ +

+

Field Descriptions

+ +

alpha - EMA alpha + +

+
+

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/f439a6888cc769d718b5d38d555e7aed6b422371.html b/rdl/outputs/docs/html/content/f439a6888cc769d718b5d38d555e7aed6b422371.html new file mode 100644 index 0000000..1512d5a --- /dev/null +++ b/rdl/outputs/docs/html/content/f439a6888cc769d718b5d38d555e7aed6b422371.html @@ -0,0 +1,77 @@ + + +
+

Exponential Moving Average Alpha

+ + +
+
Absolute Address:
+
+
Base Offset:
0x84
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Sets the alpha for the EMA

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:18]----
[17:0]alpha + rw0x0 + + + EMA alpha + + +
+

+ +

+

Field Descriptions

+ +

alpha - EMA alpha + +

+
+

Value from 0x0_0000 to 0x3_FFFF represent the EMA alpha

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/f7daaf8ea45f55844cf66da35a46142d55a5253a.html b/rdl/outputs/docs/html/content/f7daaf8ea45f55844cf66da35a46142d55a5253a.html new file mode 100644 index 0000000..d3e7289 --- /dev/null +++ b/rdl/outputs/docs/html/content/f7daaf8ea45f55844cf66da35a46142d55a5253a.html @@ -0,0 +1,69 @@ + + +
+

Rx F2 NCO Frequency Control Word

+ + +
+
Absolute Address:
+
+
Base Offset:
0x2c
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

Set Demodulator F2 Frequency

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]config_data + rw0x0 + + + Frequency Control Word + + +
+

+ +

+

Field Descriptions

+ +

config_data - Frequency Control Word + +

+
+

Sets the center frequency of the NCO as FW = Fn * 2^32/Fs, +where Fn is the desired NCO frequency, and Fs is the NCO sample rate

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/content/fd9b9e9189271b3cac659475d0b7621c0ffe0c3f.html b/rdl/outputs/docs/html/content/fd9b9e9189271b3cac659475d0b7621c0ffe0c3f.html new file mode 100644 index 0000000..c4eddb0 --- /dev/null +++ b/rdl/outputs/docs/html/content/fd9b9e9189271b3cac659475d0b7621c0ffe0c3f.html @@ -0,0 +1,73 @@ + + +
+

PRBS Status 1

+ + +
+
Absolute Address:
+
+
Base Offset:
0x54
+
Size:
0x4
+ +
Source:
msk_top_regs.rdl
+ +
+

Description

+
+

PRBS Bit Errors

+
+ +

Contents

+ + + + + + + + + + + + + + + + + + + +
BitsIdentifierAccessResetDecodedName
[31:0]data + rw0x0 + + + PRBS Bit Errors + + +
+

+ +

+

Field Descriptions

+ +

data - PRBS Bit Errors + +

+
+

Number of errored-bits received by the PRBS monitor since last sync +BER can be calculated as the ratio of received bits to errored-bits

+

This register is write-to-capture.

+

To read data the following steps are required:

+

1 - Write any value to this register to capture read data

+

2 - Read the register

+
+
\ No newline at end of file diff --git a/rdl/outputs/docs/html/css/layout.css b/rdl/outputs/docs/html/css/layout.css new file mode 100644 index 0000000..59ab518 --- /dev/null +++ b/rdl/outputs/docs/html/css/layout.css @@ -0,0 +1,209 @@ +/* This file is part of PeakRDL-html . + * and can be redistributed under the terms of GNU GPL v3 . + */ + +/* Base layout */ +html, body { + height: 100%; +} + +button { + cursor: pointer; +} + +img { + max-width: 100%; +} + +#_Sidebar { + height: 100%; +} + +#_SBContents { + width: 19em; + min-width: 19em !important; +} + +#_SBResizer { + width: 6px; + margin-left: -3px; + margin-right: -3px; + cursor: col-resize; +} + +#MainPane { + height: 100%; +} + +#_SBTreeContainer { + display: flex; + flex-direction: column; +} +#_SBTree { + display: inline-flex; + flex-direction: column; + min-width: max-content; +} + +.node { + flex-direction: row; + display: flex; + flex-shrink: 0; +} +.node-link { + flex-grow: 1; +} + +.node-icon { + flex-grow: 0; + flex-shrink: 0; +} + +.node-children { + padding-left: 1em; + display: inline-flex; + flex-direction: column; + min-width: max-content; +} + +.pack-v { + display: flex; + flex-direction: column; +} + +.pack-h { + display: flex; + flex-direction: row; +} + +.scroll-v { + overflow-y: auto; +} + +.scroll-h { + overflow-x: auto; +} + +.stretchy { + flex-grow: 1; + flex-shrink: 1; +} + +.no-stretchy { + flex-grow: 0; + flex-shrink: 0; +} + +#_Overlay { + width: 100%; + height: 100%; + position:absolute; + display:none; + z-index: 2; + cursor:pointer; +} + +#_IdxEditModal { + display: none; /* Hidden by default */ + position: fixed; + z-index: 1; + left: 18.75em; + top: 18.75em; + + padding: 0.625em; +} + +/* arrow thingy on top of modal */ +#_IdxEditModal::before { + content: ""; + width: 0em; + height: 0em; + position: absolute; + left: 2.188em; /* = ([input with] + [modal padding]*2)/2 - [this border_width] */ + top: -1.25em; + border: 0.625em solid transparent; + border-bottom: 0.625em solid; +} + +#_IdxEditInput { + width: 4.375em; +} + +.crumb-idx { + cursor:pointer; +} + +#_AbsAddr div { + cursor: pointer; +} + +#_SearchResults{ + margin: 0em; +} + +#_SearchResults li{ + cursor:pointer; + overflow: hidden; +} + +#_Search, #_SearchBar{ + display: none; +} + +#_SearchInput { + width: 100%; +} + +#_Search { + overflow-wrap: anywhere; +} + +.generic-modal-overlay { + width: 100%; + height: 100%; + position:absolute; + display:none; + z-index: 3; + cursor:pointer; + align-items: center; + justify-content: center; +} + +.generic-modal { + cursor: default; +} + +/* Mobile mode */ +#_Sidebar { + display: none; + position: absolute; + z-index: 3; +} + +#_SBSearchButton, #_SBSearchButtonSpan { + display: none; +} + +/* Desktop mode */ +@media (min-width:950px){ + #_Sidebar { + position: static; + display: flex!important; + z-index: 0; + } + #_SBSearchButton, #_SBSearchButtonSpan { + display: block; + } + + #_MobiTitlebar { + display:none; + } + + #_Overlay { + display: none!important; + } + + .limit-h { + max-width: 900px; + } +} diff --git a/rdl/outputs/docs/html/css/normalize.css b/rdl/outputs/docs/html/css/normalize.css new file mode 100644 index 0000000..47b010e --- /dev/null +++ b/rdl/outputs/docs/html/css/normalize.css @@ -0,0 +1,341 @@ +/*! normalize.css v8.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/rdl/outputs/docs/html/css/theme.css b/rdl/outputs/docs/html/css/theme.css new file mode 100644 index 0000000..303c3b7 --- /dev/null +++ b/rdl/outputs/docs/html/css/theme.css @@ -0,0 +1,903 @@ +/* This file is part of PeakRDL-html . + * and can be redistributed under the terms of GNU GPL v3 . + */ + +/* ------------------------------ Color Scheme ------------------------------ */ +:root { + --main-text-color:#404040; + --title-text-color: #fff; + --title-text-color-hover: #fff; + --footer-text-color: #808080; + --url-color: #2980b9; + --url-color-hover: #3091d1; + --overlay-bg-rgba: 0,0,0,0.5; + --reserved-text-color:#808080; + --content-preview-text-color:#ccc; + + --offpage-bg-color:#eee; + --main-bg-color:#fcfcfc; + --title-bg-color: #2980b9; + --title-bg-color-hover: #2e8ece; + --alt-row-bg-color:#f3f6f6; + --inline-code-block-bg-color: #fff; + --code-block-bg-color: #efc; + --input-bg-color: #fff; + --input-invalid-bg-color: #f99; + --highlight-color: #f1c40f; + --progressbar-color: #f1c40f; + + --content-border-color: #e1e4e5; + --strong-content-border-color: #aaa; + --blockquote-bar-color: #ccc; + + --button-border-color: #949494; + --button-text-color: #4c4c4c; + --button-gradient-top-color: #f5f5f5; + --button-gradient-bottom-color: #dddddd; + + --button-disabled-border-color: #ccc; + --button-disabled-text-color: #999; + --button-disabled-bg-color: #e8e8e8; + + --admonition-title-text-color: #fff; + --admonition-title-bg-color: #6ab0de; + --admonition-bg-color: #e7f2fa; + --admonition-error-title-bg-color: #f29f97; + --admonition-error-bg-color: #fdf3f2; + --admonition-warning-title-bg-color: #f0b37e; + --admonition-warning-bg-color: #ffedcc; + --admonition-note-title-bg-color: #6ab0de; + --admonition-note-bg-color: #e7f2fa; + --admonition-hint-title-bg-color: #1abc9c; + --admonition-hint-bg-color: #dbfaf4; + + --idx-edit-text-color: #fff; + --idx-edit-bg-color: #2e8ece; + --idx-edit-input-border-color: #2472a4; + + --crumb-idx-hover-text-color: #fff; + --crumb-idx-hover-bg-color: #2e8ece; + + --tree-text-color: #d9d9d9; + --tree-bg-color: #303030; + --tree-border-color: #303030; + --tree-hover-text-color: #d9d9d9; + --tree-hover-bg-color: #4e4a4a; + --tree-hover-border-color: #303030; + --tree-selected-text-color: #444; + --tree-selected-border-color: #c9c9c9; + +} + +@media (prefers-color-scheme: dark) { + :root { + --main-text-color: #C0C0C0; + --title-text-color: #ccc; + --title-text-color-hover: #eee; + --footer-text-color: #444; + --url-color: #2e8fcf; + --url-color-hover: #35a0e6; + --overlay-bg-rgba: 0,0,0,0.65; + --reserved-text-color:#444; + --content-preview-text-color:#888; + + --offpage-bg-color: #111; + --main-bg-color: #000; + --title-bg-color: #005e9a; + --title-bg-color-hover: #2e8ece; + --alt-row-bg-color:#222; + --inline-code-block-bg-color: #111; + --code-block-bg-color: #2a301f; + --input-bg-color: #000; + --input-invalid-bg-color: #A33; + --highlight-color: #7e6500; + --progressbar-color: #7e6500; + + --content-border-color: #444; + --strong-content-border-color: #555; + --blockquote-bar-color: #444; + + --button-border-color: #6c6c6c; + --button-text-color: #999; + --button-gradient-top-color: #444; + --button-gradient-bottom-color: #222; + + --button-disabled-border-color: #555; + --button-disabled-text-color: #555; + --button-disabled-bg-color: #222; + + --admonition-title-text-color: #ccc; + --admonition-title-bg-color: #12806a; + --admonition-bg-color: #263330; + --admonition-error-title-bg-color: #730000; + --admonition-error-bg-color: #300; + --admonition-warning-title-bg-color: #8b6b00; + --admonition-warning-bg-color: #342800; + --admonition-note-title-bg-color: #3d6580; + --admonition-note-bg-color: #262e33; + --admonition-hint-title-bg-color: #12806a; + --admonition-hint-bg-color: #263330; + + --idx-edit-text-color: #ccc; + --idx-edit-bg-color: #005e9a; + --idx-edit-input-border-color: #004e80; + + --crumb-idx-hover-text-color: #000; + --crumb-idx-hover-bg-color: #54abe6; + + --tree-text-color: #d9d9d9; + --tree-bg-color: #303030; + --tree-border-color: #303030; + --tree-hover-text-color: #d9d9d9; + --tree-hover-bg-color: #4e4a4a; + --tree-hover-border-color: #303030; + --tree-selected-text-color: #ccc; + --tree-selected-border-color: #222; + } +} + +/* --------------------------------- General -------------------------------- */ + +html{ + background-color: var(--offpage-bg-color); + font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif; + font-weight: normal; + color: var(--main-text-color); +} + +a { + text-decoration: none; + color: var(--url-color); +} + +a:hover { + color: var(--url-color-hover); +} + +:not(html) { + line-height: inherit; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 700; + font-family: "Roboto Slab","ff-tisa-web-pro","Georgia",Arial,sans-serif; + color: var(--main-text-color); +} + +table { + border: solid 1px var(--content-border-color); + border-collapse: collapse; + empty-cells: show; + margin-top: 1em; +} + +th { + border-bottom: solid 2px var(--content-border-color); + font-weight: bold; +} + +td, th { + border-color: var(--content-border-color); + padding: 0.5em; +} + +td:first-child, th:first-child { + border-left-width: 0; +} + +tr:nth-child(2n) td { + background-color: var(--alt-row-bg-color); +} + +tr.reserved-field, tr.reserved-addr { + color: var(--reserved-text-color); +} + +td > p:first-child { + margin-top: 0px; +} + +td > p:last-child { + margin-bottom: 0px; +} + +hr { + border: 0; + border-top: solid 1px var(--content-border-color); + margin: 1em 0em; +} + +dt { + font-weight: bold; +} + +blockquote { + margin-left: 0px; + padding-left: 0.25em; + border-left: solid 0.313em var(--blockquote-bar-color); +} + +pre { + background-color: var(--code-block-bg-color); + border: solid 1px var(--content-border-color); + padding: 0.75em; +} + +code { + font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",Courier,monospace; + font-size: 0.75em; + line-height: 1.4; + + /* inline code format */ + background-color: var(--inline-code-block-bg-color); + border: solid 1px var(--content-border-color); + padding: 0.17em 0.41em;; + font-weight: bold; +} + +pre code { + /* undo inline formatting for code block */ + background-color: inherit; + border: none; + padding: 0em; + font-weight: normal; +} + +input { + background-color: var(--input-bg-color); + color: var(--main-text-color); +} + +input.invalid { + background-color: var(--input-invalid-bg-color); +} + +button { + border-style: solid; + border-width: 1px; + border-color: var(--button-border-color); + color: var(--button-text-color); + border-radius: 2px; + background-image: linear-gradient(var(--button-gradient-top-color), var(--button-gradient-bottom-color)); + padding: 0.25em 0.9em; +} + +button:disabled { + border-color: var(--button-disabled-border-color); + color: var(--button-disabled-text-color); + background-color: var(--button-disabled-bg-color); + background-image: none; +} + + +/*:target, :target td {*/ +.target-highlight, .target-highlight td { + background-color: var(--highlight-color)!important; +} + +mark { + background-color: var(--highlight-color); +} + +#_ProgressBar { + width: 15em; + margin: auto; +} + +#_ProgressBar path { + stroke: var(--strong-content-border-color); + stroke-width: 3; +} + +#_ProgressBar path + path { + stroke: var(--progressbar-color); + stroke-width: 8; +} + +.progressbar-text { + color: var(--main-text-color)!important; +} + +/* ------------------------------- Admonitions ------------------------------ */ +.admonition-title:before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f06a"; + margin-right:4px; +} + +.admonition { + padding:12px; + line-height:24px; + margin-bottom:24px; + background: var(--admonition-bg-color); +} + +.admonition-title { + font-weight:bold; + display:block; + color: var(--admonition-title-text-color); + background: var(--admonition-title-bg-color); + margin:-12px; + padding:6px 12px; + margin-bottom:12px; +} + +.admonition p:last-child { + margin-bottom:0; +} + +.admonition.danger, +.admonition.error{ + background: var(--admonition-error-bg-color); +} + +.admonition.danger .admonition-title, +.admonition.error .admonition-title{ + background: var(--admonition-error-title-bg-color); +} + +.admonition.attention, +.admonition.caution, +.admonition.warning { + background: var(--admonition-warning-bg-color); +} + +.admonition.attention .admonition-title, +.admonition.caution .admonition-title, +.admonition.warning .admonition-title { + background: var(--admonition-warning-title-bg-color); +} + +.admonition.note, +.admonition.seealso { + background: var(--admonition-note-bg-color); +} + +.admonition.note .admonition-title, +.admonition.seealso .admonition-title { + background: var(--admonition-note-title-bg-color); +} + +.admonition.hint, +.admonition.important, +.admonition.tip { + background: var(--admonition-hint-bg-color); +} + +.admonition.hint .admonition-title, +.admonition.important .admonition-title, +.admonition.tip .admonition-title { + background: var(--admonition-hint-title-bg-color); +} + +/* ------------------------------- Button Icons ----------------------------- */ + +.collapse-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f146"; +} + +.search-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f002"; +} + +.close-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f00d"; +} + +.menu-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f0c9"; +} + +.home-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f015"; +} + +.help-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f059"; +} + +.copy-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: normal; + content: "\f0c5"; +} + +.reset-button::before { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f2ea"; +} + +/* --------------------------------- Sidebar -------------------------------- */ +#_SBTitlebar { + background-color: var(--title-bg-color); +} + +#_SBTitlebox { + font-size: 1.125em; + font-weight: bold; + text-align: center; + vertical-align: middle; + line-height: 2.2em; + + color: var(--title-text-color); +} + +#_Overlay { + background-color: rgba(var(--overlay-bg-rgba)); +} + +#_SBResizer:hover { + background-color: rgba(128, 128, 128, 0.5); +} + +.sb-button-strip { + padding: 0em 0.3em 0.3em 0.3em; +} + +.sb-button-strip button, .sb-button-strip a.button-link{ + background-color: inherit; + background-image: none; + border: none; + width: 1.25em; + height: 1.25em; + font-size: 1.5em; + text-align: center; + vertical-align: middle; + color: var(--title-text-color); + padding: 0em; + border-radius: 3px; +} + +.sb-button-strip button:hover, .sb-button-strip a.button-link:hover{ + color: var(--title-text-color-hover); + background-color: var(--title-bg-color-hover); + border: none; +} + +#_SBTreeContainer { + background-color: var(--tree-bg-color); + color: var(--tree-text-color); +} + +#_SBTree { + padding-top: 0.5em; +} + +#_SBTree a { + color: inherit; +} + +.node { + line-height: 1.3em; + border-color: var(--tree-border-color); + border-top-style: solid; + border-top-width: 1px; + border-bottom-style: solid; + border-bottom-width: 1px; + border-left-style: solid; + border-left-width: 1px; +} + +.node-icon { + width: 1.25em; + text-align: center; +} + +.node:hover{ + color: var(--tree-hover-text-color); + border-color: var(--tree-hover-border-color); + background-color: var(--tree-hover-bg-color); +} + +.node.open .node-icon::before { + font-family: "Font Awesome 5 Free"; + font-weight: normal; + content: "\f146"; +} + +.node.closed .node-icon::before { + font-family: "Font Awesome 5 Free"; + font-weight: normal; + content: "\f0fe"; +} + +.node.leaf .node-icon::before { + font-weight: normal; + content: "\2022"; +} + +.node.selected { + background-color: var(--main-bg-color); + color: var(--tree-selected-text-color); + font-weight: bold; + border-color: var(--tree-selected-border-color); +} + +.node.selected a:focus { + outline: none; +} + +/* ----------------------------- Mobile Titlebar ---------------------------- */ +#_MobiTitlebar { + background-color: var(--title-bg-color); + color: var(--title-text-color); +} + +#_MobiTitlebox { + vertical-align: middle; + font-size: 1.125em; + font-weight: bold; + text-align: center; + line-height: 2em; +} + +#_MobiTitlebar button{ + background-color: inherit; + background-image: none; + border: none; + font-size: 1.5em; + width: 1.5em; + height: 1.5em; + line-height: 1.5em; + text-align: center; + vertical-align: middle; + color: var(--title-text-color); + padding: 0em; +} + +#_MobiTitlebar button:hover{ + color: var(--title-text-color-hover); + background-color: var(--title-bg-color-hover); + border: none; +} +/* ------------------------------- Main Window ------------------------------ */ + +.main { + background-color: var(--main-bg-color); + padding-left: 1.875em; + padding-right: 1.875em; +} + +#_Crumbtrail { + padding-top: 0.875em; +} + +.crumb-separator { + padding: 0em 0.25em; +} + +.crumb-idx { + font-weight: bold; + padding: 0.07em; +} + +.crumb-idx:hover{ + background-color: var(--crumb-idx-hover-bg-color); + color: var(--crumb-idx-hover-text-color); +} + +dl.node-info { + display: grid; + justify-content: start; +} + +.node-info dt{ + grid-column: 1; +} + +.node-info dd { + grid-column: 2; + margin-left: 0.5em; +} + +#_AbsAddr div { + display: inline; + visibility: hidden; + color: var(--url-color); + margin-left: 1em; +} +#_AbsAddr div:hover { + color: var(--url-color-hover); +} + +#_AbsAddr:hover div { + visibility: visible; +} + +#_AbsAddr div::after { + font-family: "Font Awesome 5 Free"; + font-weight: bold; + content: "\f05a"; +} + +div#_AbsAddrDetails { + display: none; + grid-column: 2; + margin-left: 0.5em; + border-left: solid 0.313em var(--blockquote-bar-color); + padding-left: 0.5em; +} + +div#_AbsAddrDetails.open { + display: grid; +} + +#_AbsAddrDetails dt{ + grid-column: 1; +} + +#_AbsAddrDetails dd { + grid-column: 2; + margin-left: 0.5em; +} + + +input.field-value-tester { + border: solid 1px var(--strong-content-border-color); + padding: 0.25em 0.5em; + width: 9em; +} + +select.field-value-enum-tester { + padding: 0.0em 0.25em; + width: 12em; + height: 2.3em; + font-size: 0.75em; +} + +input#_RegValueTester { + border: solid 1px var(--strong-content-border-color); + padding: 0.25em 0.5em; + width: 8em; +} + +footer { + padding-bottom: 0.875em; + color: var(--footer-text-color); +} + +.headerlink { + visibility: hidden; +} + +.headerlink::after { + font-family: "Font Awesome 5 Free"; + font-size: 0.75em; + font-weight: bold; + content: "\f0c1"; +} + +.radix-button { + font-size: 0.79em; + font-weight: bold; + padding: 0.25em 0.48em; + border-style: solid; + border-width: 1px; + border-color: var(--button-border-color); + color: var(--button-text-color); + border-radius: 2px; + background-image: linear-gradient(var(--button-gradient-top-color), var(--button-gradient-bottom-color)); +} + +.reset-button { + font-size: 0.90em; + padding: 0.30em 0.50em; + border-style: solid; + border-width: 1px; + border-color: var(--button-border-color); + color: var(--button-text-color); + border-radius: 2px; + background-image: linear-gradient(var(--button-gradient-top-color), var(--button-gradient-bottom-color)); +} + +h1:hover .headerlink::after, +h2:hover .headerlink::after, +h3:hover .headerlink::after, +h4:hover .headerlink::after, +tr:hover .headerlink::after { + visibility: visible; +} + +/* --------------------------------- Search --------------------------------- */ +#_SearchBar { + padding-top: 0.875em; + padding-bottom: 0.875em; +} + +#_SearchBar input { + border: solid 1px var(--strong-content-border-color); + padding: 0.5em 1em; + font-size: 1.125em; +} + +#_SearchResults { + padding: 0em; + width: 100%; +} + +#_SearchResults li:first-child { + border-top: solid 1px var(--content-border-color); +} + +#_SearchResults li { + display: block; + width: 100%; + padding: 0.5em 0em; + border-bottom: solid 1px var(--content-border-color); +} + +#_SearchResults .selected { + background-color: var(--alt-row-bg-color); +} + +#_SearchResults a { + color: var(--main-text-color); +} + +.search-content-preview { + color: var(--content-preview-text-color); + padding-left: 2em; + padding-top: 0.5em; + } + +/* --------------------------- Index Editor Modal --------------------------- */ +#_IdxEditModal { + background-color: var(--idx-edit-bg-color); + box-shadow: rgba(0, 0, 0, 0.25) 1px 3px 6px 1px; +} + +#_IdxEditModal::before { + border-bottom-color: var(--idx-edit-bg-color); +} + +#_IdxEditInput { + border: solid 1px var(--idx-edit-input-border-color); + padding: 0.25em 0.5em; +} + +#_IdxEditRange { + color: var(--idx-edit-text-color); +} + +/* ------------------------------ Generic Modal ----------------------------- */ +.generic-modal-overlay { + background-color: rgba(var(--overlay-bg-rgba)); +} + +.generic-modal { + background-color: var(--main-bg-color); + border: 1px solid var(--strong-content-border-color); + padding: 0em 1em 1em 1em; +} + +.generic-modal h1 { + font-size: 1.5em; +} + +.generic-modal h2 { + font-size: 1.3em; +} + +.generic-modal h3 { + font-size: 1.1em; +} + +/* ------------------------------- Help Modal ------------------------------- */ +.kb-shortcut-key { + border: solid 1px var(--strong-content-border-color); + background-color: var(--alt-row-bg-color); + padding: 0.125em 0.25em; + margin-left: 0.125em; + margin-right: 0.125em; + border-radius: 0.25em; +} + +.generic-modal dt { + margin-top: 1em; + margin-bottom: 0.1em; +} + +/* ---------------------------------- Fonts --------------------------------- */ +@font-face { + font-family:"Lato"; + font-weight:400; + font-style:normal; + src:url("../fonts/Lato/lato-regular.eot"); + src:url("../fonts/Lato/lato-regular.eot?#iefix") format("embedded-opentype"), + url("../fonts/Lato/lato-regular.woff2") format("woff2"), + url("../fonts/Lato/lato-regular.woff") format("woff"), + url("../fonts/Lato/lato-regular.ttf") format("truetype"); +} +@font-face { + font-family:"Lato"; + font-weight:700; + font-style:normal; + src:url("../fonts/Lato/lato-bold.eot"); + src:url("../fonts/Lato/lato-bold.eot?#iefix") format("embedded-opentype"), + url("../fonts/Lato/lato-bold.woff2") format("woff2"), + url("../fonts/Lato/lato-bold.woff") format("woff"), + url("../fonts/Lato/lato-bold.ttf") format("truetype"); +} +@font-face { + font-family:"Lato"; + font-weight:700; + font-style:italic; + src:url("../fonts/Lato/lato-bolditalic.eot"); + src:url("../fonts/Lato/lato-bolditalic.eot?#iefix") format("embedded-opentype"), + url("../fonts/Lato/lato-bolditalic.woff2") format("woff2"), + url("../fonts/Lato/lato-bolditalic.woff") format("woff"), + url("../fonts/Lato/lato-bolditalic.ttf") format("truetype"); +} +@font-face { + font-family:"Lato"; + font-weight:400; + font-style:italic; + src:url("../fonts/Lato/lato-italic.eot"); + src:url("../fonts/Lato/lato-italic.eot?#iefix") format("embedded-opentype"), + url("../fonts/Lato/lato-italic.woff2") format("woff2"), + url("../fonts/Lato/lato-italic.woff") format("woff"), + url("../fonts/Lato/lato-italic.ttf") format("truetype"); +} +@font-face { + font-family:"Roboto Slab"; + font-weight:400; + font-style:normal; + src:url("../fonts/RobotoSlab/roboto-slab.eot"); + src:url("../fonts/RobotoSlab/roboto-slab-v7-regular.eot?#iefix") format("embedded-opentype"), + url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff2") format("woff2"), + url("../fonts/RobotoSlab/roboto-slab-v7-regular.woff") format("woff"), + url("../fonts/RobotoSlab/roboto-slab-v7-regular.ttf") format("truetype") +} +@font-face { + font-family:"Roboto Slab"; + font-weight:700; + font-style:normal; + src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot"); + src:url("../fonts/RobotoSlab/roboto-slab-v7-bold.eot?#iefix") format("embedded-opentype"), + url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff2") format("woff2"), + url("../fonts/RobotoSlab/roboto-slab-v7-bold.woff") format("woff"), + url("../fonts/RobotoSlab/roboto-slab-v7-bold.ttf") format("truetype") +} + + +/*! + * Font Awesome Free 5.3.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +@font-face { + font-family: 'Font Awesome 5 Free'; + font-weight: 900; + font-style: normal; + src:url("../fonts/FontAwesome/fa-solid-900.eot"); + src:url("../fonts/FontAwesome/fa-solid-900.eot?#iefix") format("embedded-opentype"), + url("../fonts/FontAwesome/fa-solid-900.woff2") format("woff2"), + url("../fonts/FontAwesome/fa-solid-900.woff") format("woff"), + url("../fonts/FontAwesome/fa-solid-900.ttf") format("truetype"), + url("../fonts/FontAwesome/fa-solid-900.svg#fontawesome") format("svg"); +} + +@font-face { + font-family: 'Font Awesome 5 Free'; + font-weight: 400; + font-style: normal; + src:url("../fonts/FontAwesome/fa-regular-400.eot"); + src:url("../fonts/FontAwesome/fa-regular-400.eot?#iefix") format("embedded-opentype"), + url("../fonts/FontAwesome/fa-regular-400.woff2") format("woff2"), + url("../fonts/FontAwesome/fa-regular-400.woff") format("woff"), + url("../fonts/FontAwesome/fa-regular-400.ttf") format("truetype"), + url("../fonts/FontAwesome/fa-regular-400.svg#fontawesome") format("svg"); +} diff --git a/rdl/outputs/docs/html/data/data_index.js b/rdl/outputs/docs/html/data/data_index.js new file mode 100644 index 0000000..b121232 --- /dev/null +++ b/rdl/outputs/docs/html/data/data_index.js @@ -0,0 +1,4 @@ +var N_RAL_FILES = 1; +var N_RAL_NODES_PER_FILE = 16384; +var RootNodeIds = [0]; +var PageInfo = {"title":null}; diff --git a/rdl/outputs/docs/html/data/ral-data-0.json b/rdl/outputs/docs/html/data/ral-data-0.json new file mode 100644 index 0000000..b6a21d8 --- /dev/null +++ b/rdl/outputs/docs/html/data/ral-data-0.json @@ -0,0 +1 @@ +[{"parent":null,"children":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"name":"msk_top_regs","offset":"0","size":"98"},{"parent":0,"children":[],"name":"Hash_ID_Low","offset":"0","size":"4","fields":[{"name":"hash_id_lo","lsb":0,"msb":31,"reset":"aaaa5555","disp":"H"}]},{"parent":0,"children":[],"name":"Hash_ID_High","offset":"4","size":"4","fields":[{"name":"hash_id_hi","lsb":0,"msb":31,"reset":"5555aaaa","disp":"H"}]},{"parent":0,"children":[],"name":"MSK_Init","offset":"8","size":"4","fields":[{"name":"txrxinit","lsb":0,"msb":0,"reset":"1","disp":"H"},{"name":"txinit","lsb":1,"msb":1,"reset":"1","disp":"H"},{"name":"rxinit","lsb":2,"msb":2,"reset":"1","disp":"H"}]},{"parent":0,"children":[],"name":"MSK_Control","offset":"c","size":"4","fields":[{"name":"ptt","lsb":0,"msb":0,"reset":"0","disp":"H"},{"name":"loopback_ena","lsb":1,"msb":1,"reset":"0","disp":"H"},{"name":"rx_invert","lsb":2,"msb":2,"reset":"0","disp":"H"},{"name":"clear_counts","lsb":3,"msb":3,"reset":"0","disp":"H"},{"name":"diff_encoder_loopback","lsb":4,"msb":4,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"MSK_Status","offset":"10","size":"4","fields":[{"name":"demod_sync_lock","lsb":0,"msb":0,"reset":"0","disp":"H"},{"name":"tx_enable","lsb":1,"msb":1,"reset":"0","disp":"H"},{"name":"rx_enable","lsb":2,"msb":2,"reset":"0","disp":"H"},{"name":"tx_axis_valid","lsb":3,"msb":3,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Tx_Bit_Count","offset":"14","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Tx_Enable_Count","offset":"18","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Fb_FreqWord","offset":"1c","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"TX_F1_FreqWord","offset":"20","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"TX_F2_FreqWord","offset":"24","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"RX_F1_FreqWord","offset":"28","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"RX_F2_FreqWord","offset":"2c","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"LPF_Config_0","offset":"30","size":"4","fields":[{"name":"lpf_freeze","lsb":0,"msb":0,"reset":"0","disp":"H"},{"name":"lpf_zero","lsb":1,"msb":1,"reset":"0","disp":"H"},{"name":"prbs_reserved","lsb":2,"msb":7,"reset":"0","disp":"H"},{"name":"lpf_alpha","lsb":8,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"LPF_Config_1","offset":"34","size":"4","fields":[{"name":"i_gain","lsb":0,"msb":23,"reset":"0","disp":"H"},{"name":"i_shift","lsb":24,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Tx_Data_Width","offset":"38","size":"4","fields":[{"name":"data_width","lsb":0,"msb":7,"reset":"8","disp":"H"}]},{"parent":0,"children":[],"name":"Rx_Data_Width","offset":"3c","size":"4","fields":[{"name":"data_width","lsb":0,"msb":7,"reset":"8","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Control","offset":"40","size":"4","fields":[{"name":"prbs_sel","lsb":0,"msb":0,"reset":"0","disp":"H"},{"name":"prbs_error_insert","lsb":1,"msb":1,"reset":"0","disp":"H"},{"name":"prbs_clear","lsb":2,"msb":2,"reset":"0","disp":"H"},{"name":"prbs_manual_sync","lsb":3,"msb":3,"reset":"0","disp":"H"},{"name":"prbs_reserved","lsb":4,"msb":15,"reset":"0","disp":"H"},{"name":"prbs_sync_threshold","lsb":16,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Initial_State","offset":"44","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Polynomial","offset":"48","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Error_Mask","offset":"4c","size":"4","fields":[{"name":"config_data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Bit_Count","offset":"50","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"PRBS_Error_Count","offset":"54","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"LPF_Accum_F1","offset":"58","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"LPF_Accum_F2","offset":"5c","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"axis_xfer_count","offset":"60","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Rx_Sample_Discard","offset":"64","size":"4","fields":[{"name":"rx_sample_discard","lsb":0,"msb":7,"reset":"0","disp":"H"},{"name":"rx_nco_discard","lsb":8,"msb":15,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"LPF_Config_2","offset":"68","size":"4","fields":[{"name":"p_gain","lsb":0,"msb":23,"reset":"0","disp":"H"},{"name":"p_shift","lsb":24,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"f1_nco_adjust","offset":"6c","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"f2_nco_adjust","offset":"70","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"f1_error","offset":"74","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"f2_error","offset":"78","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Tx_Sync_Ctrl","offset":"7c","size":"4","fields":[{"name":"tx_sync_ena","lsb":0,"msb":0,"reset":"0","disp":"H"},{"name":"tx_sync_force","lsb":1,"msb":1,"reset":"0","disp":"H"},{"name":"tx_sync_f1","lsb":2,"msb":2,"reset":"0","disp":"H"},{"name":"tx_sync_f2","lsb":3,"msb":3,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"Tx_Sync_Cnt","offset":"80","size":"4","fields":[{"name":"tx_sync_cnt","lsb":0,"msb":23,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"lowpass_ema_alpha1","offset":"84","size":"4","fields":[{"name":"alpha","lsb":0,"msb":17,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"lowpass_ema_alpha2","offset":"88","size":"4","fields":[{"name":"alpha","lsb":0,"msb":17,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"rx_power","offset":"8c","size":"4","fields":[{"name":"data","lsb":0,"msb":22,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"tx_async_fifo_rd_wr_ptr","offset":"90","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]},{"parent":0,"children":[],"name":"rx_async_fifo_rd_wr_ptr","offset":"94","size":"4","fields":[{"name":"data","lsb":0,"msb":31,"reset":"0","disp":"H"}]}] \ No newline at end of file diff --git a/rdl/outputs/docs/html/favicon.png b/rdl/outputs/docs/html/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..d2a8088029f5db0470b3e73f91c6608a68e83806 GIT binary patch literal 1367 zcmV-d1*rOoP)Hrdy5U}i%uk^Q&Vl7Xb`0t z)rv4|{}B-_wMeM79m+sO5jGJ9W2K|5V*>|k#mWXM+ib>|DYb|+9bG%B9gA*lx+Z;p zPtqj*BXzeVm)y)Yh+CjuFxNVR}eBYOi>oKZLg<+7Jr z@~~Eqh*Cq8g9!zoSec=u2nc250t)5km}7u)*^AthRn&^j?mrHH{?kM`G~+HjaMn&q z5#X);5h0ynb1eH7ki7vazF=fWCW1M;MJErZ=|s=HJ4e815j|h+8w2BCiW}!OAegfo zGu002mzT>>uWCxNz;{ zLDBOUtxZs@FK&**T0JMuF(9JU2)c)--Bk$IQXyJgG6=F}-Z)VUgg1gD)3*gg2HZT~ zfvLeuw6vrIA_IcU^Kc%lK>wi{1eRuLX-X8l^T5GWPqi?ZeXEtYhV0jJ$ z$Li7h@k?0s-XanxHN-7ov{u8`F&y*y{LXI|&{JQ6v2(`|iG)c@NdlE)Kw1`yvJX$= z+0TDKdbW`h3$8BWYWw@Ra=?nE+oLqfQHAPSz))TVTgMOzY;OS!!--9g^ub}b;P>y2 zAQBGIEK3CS#gHZ=3r`(51?%CTpk)gWurbr}j$}Rn|ov7`Fo)1DH^N^DI4_ zrc1b<{_E0dTy1ZPxfn8(SE2O1cBE(LQIZRU7Q9%y@$2SzW6s0-d-c?H&JB@((ZYFg zi(`OdWrp)YQov~8eL3OQ7zRa^b$INZBT%Jh zQjo+?US1w-w)iF+42HO|SP&VY$;iSppPog|p65x@2%@;S7!3^#)bbHsjTF6HpVXa~ z0wMz#rKC^SlLFBm_=bMQ@YkQv(h`$cXBwIi88AKEi|OHBT3S-V_E?dm5ZN0bs0GT( z%Fxo%B9)dcQCL_=HJ=~@OePadCKFWwsYdoKAbSINTR`m_gTA{?bn-=OQ^NZRiBL~n zht7Fa{CwXSZ=BZv#=pe-u|Xp4z7au^gG58Z{E}t9o`Tyf-nIn4x Z{sxeXX!`Ig&XxcG002ovPDHLkV1keAbBh1~ literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.eot b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.eot new file mode 100644 index 0000000000000000000000000000000000000000..656e9a028a2cda2f16b4ae4a37e79b80466eb686 GIT binary patch literal 40576 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 S5$9g}KG@6L)XW4J_Wuj+;BXoM literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.svg b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.svg new file mode 100644 index 0000000..0085843 --- /dev/null +++ b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.ttf b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.ttf new file mode 100644 index 0000000000000000000000000000000000000000..36a7de36cc8eaf102da5b60290d3cce885268fe2 GIT binary patch literal 40348 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 z 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 WQ9M6=R-Ak7`(Q6~Q!^7_*#9qET~%5D literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff new file mode 100644 index 0000000000000000000000000000000000000000..f7fab8586e1b289547ad2779507faa082d3998a8 GIT binary patch literal 18168 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 ay~m{ve7)oRk5U^;OH2O&+MtMS0001JG(o=r literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff2 b/rdl/outputs/docs/html/fonts/FontAwesome/fa-regular-400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..719a712a39cc413d9fbf49b9248e4c1d9e27fda9 GIT binary patch literal 14868 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 G_#gmsS;$ZT literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.eot b/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.eot new file mode 100644 index 0000000000000000000000000000000000000000..4e4cbb2c60f8986d600b9e48e9d2b6d036dad16b GIT binary patch literal 180720 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 QMBzRFrN73w@F~9k1F6}aHvj+t literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.svg b/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.svg new file mode 100644 index 0000000..4f5aa88 --- /dev/null +++ b/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.svg @@ -0,0 +1,2444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.ttf b/rdl/outputs/docs/html/fonts/FontAwesome/fa-solid-900.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2a05512698c686d42e010ac9988efa86d10cdd22 GIT binary patch literal 180500 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�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%0DX`?L?5P)&`0TG^l|zGeUd&!pQg{yXX$hFdHMo< zk-kJ1*_L`UZWIzD3`r@6dPYd-Q$!0sWAEL_emV&`;@S^mF2LIR`Um}!{zd<$|ImMV9}_bRd)(kAx46w6?sAX&Jm3x9 z5Alp+o^!$}XM8^ATyV)1Z}Wl=^OBG7J^5aIZ@v%Tm+!~-=Lhfu`9b_(eh5F5 zAI1;oNAM&0QT%9r3_q41$B*YH@Duq-{A7L#Kb4=xPv>XwGx=HkY<>rdyTe+RwUhW`wlsn0tCJW?Jd zkCw;CW94!3czJ?6QJy4EmZ!*5ILd-;R>QT`-d z{w4pG|Hyy6eI9x2iRXC@uj#eCw%75xUeD`$18>9I^tQbH-U08Rca(RucZ_$ecbs>; zcY=4KcOmb>-bK8Vypz3Cyi>i?ywkliyfeMCytBP?ymP(t_OT!I{UFFqQ4B|EI@=** zKM$IIaHuNEfgk0=39O+>Oy2k7XqpViCMiuma73?)Cd;m4v6+-T2lHqemK{HiO+JlG z(edY_D)y7HInAG&JR1ASu&}rI$+YsPW*F&Hv)q(XGHv3*FwOVlTx^CxT8(V8NcLLv zbqDrX>{~bYn5wM1;)|q)uAdg#JK7FcSpy(ndVVqsJARhI=Er5r&&Of3ZEU;nmq+_~ zo-Xvva2)01`qBSu)wdk;KUVv~ga2c$vi;7s_Q<^!_qFSm`fJxs`n8t3ueH#9t%dd1 zT3ls)3kutfaGh*-cgcx2!t={?zTdBc zC>;i-80S$|MrqRU7x1di$RE#&%paS!A~g+0zV(V>G4^94BR|2ZBpCWp&>CU9)4+IW z3tU$iTpJJdun9IZIF`r zj#UxLsG7D%RTKw!6+j$gJth_uW{KWbdD0qH)7$#RCyQe2h(*r%gw2GD-YVq*rA{6=M{} z?u|Wd>j~~C9_N_HwxS{mi~yjsc$Ql*4%!9dpj|Ng9WK;0>Xo_2VprxKi(8p{OjXu) zyvp=MIow^R9n1Bjdt;L$o?@O#b6^Z_osCkgl3{6lj2ODQW7+~lWYx7;`ntsQoPDbC zI}VQgyf(sLOl`~})3<|PM~s@dU|AE_Xr?rUQG_1#I<<>@^~mtt|SS9ik5ytVq74-Ou%H`%bjxsk3wbSl!jfb5b+8D>_c&5k1?8mV%xWl*M z4`XxymMXBli?Qm|H@BRr%2tMkHMGZgOo=tz)95$EGDb4=6gS7|WMbg7=@figG{$L^ zz}3^ZnkVp`bUsIJb_=b>K^n)pW_DMFG4o%jf!#0lA_SF znW_c6C>bLfB7tjcL?6;w1RRyxTgB*UhNXvt9e?z>8i&1cj%ZX`tFMZ7mUSRx53+ZN7rddCLpU<&e{8{dIg2Jkq!C0%jw~fe{GJ;`D{%&jk%tftky09#HG?$4631mJLX!2Bj>Q_wyO^cgvArPO zMo(&|*$Q%hqWWl9PeUJu#V||bIUAFo)3JE@+e? zr4PehxP8DR+a|`_Z4VG{4wr*Hrp+DZqCs3}J8Ioj=8=_Py*1;0b2zh7U`L8HodqWl&J#=q;@V749Jkj}M_dj6$W_At zZk1`*fUVC9&|so@ZzV(emQB)JiA?;%y@`ROFgAy@YTTTdIg(IsqJE51hfLX?L{202 z9dJUi>xhb=j)l5-2Q^B{9IMH()x^3R@a-n<)i6u*(wU<<D7 zwq;43?{|Aw8(g2WV6y3erv40pq}=a#zAM`{tVL(jFRQ%ngo{_MZ|e2+H!jjV@DwSH zG3ZgIG}gnsi35fV4}e2J<-51#`l0I26|xI-j#_Ycj;VnD11-W0ESsqdyapk|Q`*3x zn6)Ozm!ZMbK}?xiLiB24B~*HYZ<43e?nJ|ky}M!IU{WQC ziR(dbPO1{Btu=+{$o!x^^^xbQdDfWvSPL>W^X}BjJP44&n?{pz{}f#!#K;hf_g?qfN9^n-+|WkNB~`b)6mFvnVv^Zn58DEH2ERDw4eDty#Jb zmoPhMuQ=c!v~6YT3%Axy3#`}Pn!&wUt)3$7ST=<8jE-RD{CHsbwu&V6+{wgQ&j~0bwkgRI69(o#^TIJpr|1vm)UesSBG7!>s+tHg=gU!*;1U4Z61C?MQ1Y z3{5)<;N}6MUldrWV54!38#XRB?XhS?35uU4YAZ;VHkzs^^CbWR4m4a3AYG+Y#ZB#O zH1-Z5BsLD|{A?V;>otQcAPVE6G4mlU1VhlqpVfEGna+gYnMEpru{Jg>QeSn><|)VN zMFjl=U4z0l(2A|S+T-ZOkb}@VR?9iujs0pG+Q;=BtXGpG`tXK@xOa)=JI&K7^J3_o zMr`J3vKiZ&YiFHzcKAkYwr%8E*d^X~w6aR86GszO(x^D?yrZled73&wQCexhZ>zYq z<81+=o^7kx({=+=*M%FKoja<0ZP@e_9fSm)4tKXWthB#?%}VZ5TJ$HbJKITZ5{A2RbaNpH;kOoQyqSf}ak(%m!p-ZObiAr@Xo zTOET!fST@P4^2^*Ndt@FVd=~a!#!-fx5hlh4WwN^ZsItL&`X2KhCj@<6y-=O8knF* z@GcYLsyP;43&K0i{Sa-Am9Xs0Bj{g9i|i%-W97`oUgOppwdcFL1_ukQd(*cG zb5#X8Qb$uuy7P2Yi<_o{8}K)TgpsCqSP!nz1rneQ3>UCQRZgaRoO)em zwT6#M+hVN?2bmAC7oumVnGbiA+0p?w=UOO{A!TV>I7ifM*lH!=;MTNnr}ttKi9i%>^GM@E-*wC%^6js;Lr zxeCjMseZV zLZJ1t>c|ll*O3{U=J|GCa}!=&tQAD<74IMe1gO`>VfXwBzU%g*9CS7G`4D|c6Mq3b z6-B5)H?-B&(S}S;Z8@!=o13Zb+5&fSlc5fUyEZJs4dud^vYAJtQJQ$V8Q92Ed|p#U z3M2#8L}|Ktu^Ms#?B;e?UB`06`jOV6qbM=KmZQ63tvj8;~)3g4{RDh2gx?h1gKSkdoryD%ouFbkgJX-$YJ zgqAHdc^yUV*L8LbeTV93Xh{#H#tivW``v{@o7m`n z<~D1mn`=aOuLnC^lNoxYo{76F>vr3I(z8F1IE6mg^J7WhGR%(a14z>rX>n(#R%;be ziE=e-6tgOZJw~OLYt3KGHL9!NsG-#u7WRsHI&&Sw;7G*&~>e$yjSl9=&t~qtIb)|e>SbHCb;zH*?twFLsjBqUD$|$ z18Y&KYUAtTiM@TCw-6&g`xhu%CfnDJ`l;!_i7;V-v}3L!;* z2&h#@du5QK!Z=}B=I#cZ&=S2c-NN=me|cyXi)cRArKqj?2qG+AvP}GGin^^0GLm^IE)!0zHpl;pbD+Qh;d4WjH89R}atix%+i{XI{VC{(Q8x zZc*piV^B9ZxNfL_G&*73w)f|x-r6bPYCbC5-hYj;9xTEj%)06sZjAc&$B&f;umopU zo41}qSP|X3WjfX0Fp=3hE10xOOp^XGgtiQEgs8-Yc@zz&`1%gAV_;O@4uB>TEHzsW zG&E}_n>Z$g+t9FrZH?=lMQB~qB2QhiS*prh;#nvfhq_4wAE+4wo@Sx`if!x9299L- z*eYvS(ku~6vBJx8$>sJ2#v?a~`5LYe$XB#e*-aKCoi>n5b_%wtMAJo~Me2BrLa19C zPy#lqL<<~PY^|d1=U~(AXKg@T<-3}?y`r^US61RzW!F+GT6+%KnW@eCJa^|fopvnH zjn}?KlRU!M6$4A^4IASw()(H#%>(x+C&4XDqU4b8uCqT8SyUK=sj|j49l49wI*+we zgQ)JGbstZmeO#fvY*;ivqE8A)L#WX-Y1gb6Y(vAO`AYb08!ZxC4b*kSRyY=V+YxfS z9*Umb7Ib}SSlrx>kVXB?ZPm`poz1tN6Orz>w;HPh*AQ`k;m4YVnhUG4I|!mCRQ12H zu&Z2k+ti+Si+&Lr6OZ+G18)&cqCRq4pg)f54*OKmj0S5K}0RR9100000000000000000000 z0000SR0dW6>3#}{j0A_FD*-kFBm4dI!&2TS-2025Yxnj#r}Ys^a!* z-S6O1!E~GP+${x1k(}ZKc+=5V!SrAb$VtcS|NsAAlQd#%y9qn~4*&oaRMe!b3SwS) zf-B`fZ5z00jl*pRhua?Bcf&YLbB*?BPG|Is$f8kXg_s~FhzVlCFbQLBOcZn}#WimA zHs5KDZDQTv9b7_9QiijDP}v8Z3E35$*CuG{hz^mcL?xR97rTm8qgz+f8G+&HG9i+B z96$6j2|JlTjgM(RW#pV1o${Ker@98MmH9g7(amvt-E)t)1l3OEv=Ohk=!_RjJeT-x z-&TiAOgswvwr~3b7m>|YT=uyY8faMX7S4oUH-CkwxV*0GdNcp!jfjXaOZno$CSS+| zFQdp}=0j)fC3(UaTn_+AjY$^C)^oMoM?T@D-;d8EZ%Y7*HG>3V6t1dMMJIb_3-k#f zy3pCZ|G;n?)MV@c7=&xBi?E-F!}D|N!TPU)u>mW_Mvra4$o&D_rJP}vw%cki)=2jK}lFlZJA)F(ii<*5fC z2TWa)Jpcc3z&iJRDa$a36N!>$5)LS_9Fta;qPYDYsK%Hf36(^&?EQk?ok$iMf!~cN^1)|sCmFar_x$&M`*KBoKVzB9zg-NPx=tT^WPt_ zckkDTmfhNE1q!5Hpsa{$Jn_goAz$?N_So8Emx!4M4~76CA|h(^qkpM(-Imj-w{s7- zPOLNMCp_r-{^F)3w;;f`Z z>Xz{T)ikTh+^WV|`XJb4f$at4TY;p$bgMM3B~RzA50~z%`YJHYuw_f~5GHYQTExxN z{>?nARC~)$KjzHq0U}|N5d?Ao$X+dcuajwmFgS%02#wJgLP$^op|`aw?ftu#0RaC) zsjh!%-%Wblq#2hKirrIyO(TWS+LnN%;Vl_A&n0a&s8$eiyy)^UatKg%(N+g(sB~cxk6vnO@oDp?W*2#`U@vQ@&u5?Hn@6<7%97A1r+#vSOCY`S|wtdcAvfrA7NV7J?WP7~uP zBu~#|dqc{H%N&k#-Ro@+hx^XIsah>a$=aB7Id87Lx)7`C%B%R(eEt6?Xl4)u41x#{ zk^qpB5l9&%CCz*Q)Zl}VL0aA?(cbqcZIZQ#(xxPWqGgIsl)aa8eYNZhA$3<(cb)4i zsw=wkOiZUvCK$Gygf$F=F?QQu-|7G$QfY4gQjBiBzSZjw5eY#;7(x&~zE)+Zg~*Nn zjfCyG)TC<}n_Z8x^1_cYQV{e<=Bl4ZndZ#iazR6s7HUASbfg6WGG6=t3OAcjc@^Nl zLE{j$)7_JH7;F9ytzDP((B*|!y0Y$NO$`+kQ2u$1Y5(JuS8MX`c`cf9(X=y06I8$j zc3GHjPVJv^6wQJQ75SG5A$W~3LI^Po!n~qg_K;2c14`FWd4WMff=U%U=>8EI(EOm5 z7NX4SRVIha`{Ol5q=1YXXm#7=vvy>%1&|t&c26mQ44ww4Q+0!M(3zJV+OGEUIiRq0 z1f-$KUAupbSG4*CXIjsR|E$p!9cEXRq;#7mKpU=3ap6DS`a<85G}0T^vRQnMDb%;| zLFQ|j2YmngLuc}dBvRAcd&{V>qUN+9XJ|xBLP~mWL2bjn3Ay=2Rn2|w&c3O1wp^t% z+r1K`%21$4xg~HCg~s4$^+r}6SUQs{Ra=QXOl&{DKEV-D$r&?dHP2hYh>GdP`E;?` z9M`r^Ztp*QmS1u)Sx*@7?HXhJ7jE2tGiF`M7BAUuhan@zOqer&$(o&e_b)Ytlp;in zrKSNvU??n}MCb5?QjO8<@brP9uw)unV`OP-?~-5Dxatm0={3aP-yEULz}Vcz#j-V9 z_8mEK?$V8WAAJGl%fF}eo_PgjBgfW+W64~hQtu9@tIh6weY}1CC918#Z1kHyz%dwh z)#VDu*o|zSSZQQxY3F9u2F0GmzJM)W7&(|> zEn7(~=TqyLMc@BCVw|DA?{Po%d+(j_Cu$svn0EQpu$6Ka^2QgfWL@jq)^6`9t$V&V z`*@I~&~eV|d}+M&VlV!*mvkwYP5Vrjdlfh5T5jGsFNP@YQvA~{=jyJ()^Y&{nSe|RPeJA*rz4A0E3!nbK+ZAOAe+#V z`aCR1Wf7cMOe>L{-s_M($W6$8-i{nX?l&Jm9>S4lzeA28&mbpJw^1)qZ%}`t-O)%i z7EMBP&_c8?T1v42u|bf<%Mk&UH5Lt%7OkfgbcV@<4kY)_VGfJ;`|@g7*TIF-JGHTm z+P3B8&OFIxd#oV$Ov=A4pU8%4uQ$f(j&;oQSXfg*gB@D8KKd@$%w)ROxuFfq1Tuik zAS2Y1{Vw^iay2al`NW}h2T^C-A>x*}Ld4w;yU|S}?a?mTJg!!IPd(+7S3%hoxddJw zdE=@&2PN9BXmbnv4+zU(F!p8Tmx?zvHx87P})ka&L zO{JArqLk9gD4G8Jb~GwORX%KZ#Dg*U*z0|s#+GZ?!8%s5hkez^u6kmj6&6|S$we(} ztxiHd6s_B;_hN40;k_(pmD+l=P+6fq4Xbt2<|8M_CASD%bMreNCcL()?iDuDQh%R!UoXZ9$fpw9 z8jMkH8H^8ov}g-#5GDrvII|=_}N|$UW6@UcEUV z6SdhRZ>Z*KlTOy#WaHL%T?gacH*>43T=9YMVVmRxqQTx1bNXP>o-ELCQ!cy|`JXQrBBn#rwfrtdrN zsX^kt*{rlXDT~*)Y;y8#Pft;>Oi{IqV?aa<@Y<5k?KmG|$*qt>W zF3A%2@8R|?f6l91%tUnzIcA9&!n5@^(4dRpZWUEhR58Vsa2Z?yXTkj*NVvT<)zeh> z`YBwQ9A)CEXWiH9+~VFJxkei6XOHc6*lCw*Tx++3g=J{&lyj}+aAX1X4KUCUW6gG_ zyL{mnzxyp#%>0_)g4+7l|KToh0Sj5lnznBpn>})p>p16i68$~nS#SEoKNU5-8O^M! z|Ard#O*6ytH*57fva?Md^?dioe(u-)?C<{V|DN`|*S#H75|boJB^h~+F%Z++CD-WQ+!)2Kb%7Kt?% zHQmydyp*LbYuPJZ%^KIcf)%ZFn|pHX^He|))zwm4J3Wms&MaFz6?1=UtxbBl7+ zT~P%UR$WDvRW;mXV_oQK*Sg;GUiPVGW`;#JUEHL2&lg@vU%b95{>sZRt*Rbu~KKl7%I3#Lc5Rle>Xlt9807TdY zivtw?1Q4PRFxUrRNhZKE!2trM1Vl0dNMsC<$ta+pYXFrj0~*l-45AB|gdVVnD`2DN z0T%}WK6(@gh!hZ_pMV4>0T~eiO40;WGmmLU4crSfm=S2P7tk@`0X-8gFfic*BjE%l zv>7myE?^4++HnbP8FQYhsjt9>98W+$`z>PD2hYSHP83sNyF91K98$bZf2Ox;% z0T9AnAdG(pA~+dDnXo_%Cx9fL1}QWPK$@(A4Eh-qNERq!2q>YAK$#GO3V{Yyk_2k= zY#PAOph>bp3;hDx=q}JfcY`h=1wDKW`eX?V(3N0FxWEXffie0V%+Mxafz|{|v=&&Q zwZR�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

LiF6s4qCmqR)As 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℞{!~>f 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 literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/Lato/lato-bold.ttf b/rdl/outputs/docs/html/fonts/Lato/lato-bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..29f691d5ed0c2d3d224423bb0288e6bd59292511 GIT binary patch literal 600856 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

8(RS%1n6kJInt)@EwW0s*7{=S!BxlrK2Yv$^ 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%0DlAp?9S$v1aS+zA8SL`rj9s3ipCNfYQ`8n;ahbfV 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 zBEc*Y%p$=o63imOEE3Ej!7LKYBEc*Y%p$=o63imOEE3Ej!7LKYBEc*Y%p$=o63iyS zY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH z%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S z!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX z63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%D zCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iyS zY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH z%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S z!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX z63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!E6%D zCc$hH%qGEX63iySY!b{S!E6%DCc$hH%qGEX63iySY!b{S!5k9IA;BCH%pt)X63ijN z91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH z%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS z!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X z63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9I zA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN z91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH z%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS!5k9IA;BCH%pt)X63ijN91_eS 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ͻgzEstkwjq)Y z1gzEstkwjq)ͻgzEstkwjq)ͻgzEstkwjq)ͻgzEstkwjq)!16XYb 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 PZr+dgQO8;Dp|bx6Kf>?& literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/Lato/lato-bold.woff b/rdl/outputs/docs/html/fonts/Lato/lato-bold.woff new file mode 100644 index 0000000000000000000000000000000000000000..c6dff51f063cc732fdb5fe786a8966de85f4ebec GIT binary patch literal 309728 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

F}woT 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"bt0}@AlIHaMn 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 literal 0 HcmV?d00001 diff --git a/rdl/outputs/docs/html/fonts/Lato/lato-bold.woff2 b/rdl/outputs/docs/html/fonts/Lato/lato-bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..bb195043cfc07fa52741c6144d7378b5ba8be4c5 GIT binary patch literal 184912 zcmbrlV{|0Z8U-4g6Wg{k$;7tpOzdRhOl;e>ZQHhO+vu0M_dc!n^L?xObl2*xbJkbu z!`}OJxyXq!0|5g80fEfP10jFEL(^aafy^EQfq*W5pZ$LfC-Tz^cg6%lAE=xZ%GU%s z83P##Ch}7_e3%!Q9fTBg>laFZ4+!iQKM)upcoi0;?}9Cy?@z6Ky%%>tw~NKKJ987+ zBV~BtSYfP`gDMdo{o&nFop4 z$oXL1NPsIf!3NQIe%V|P5t^GcXU(bIn+oI0I-(Pi^QdP;c44Z{(p8IrT9|(o@c+{e zgFiYyCq`u`THS?5MRLK*ACtv@7{O^c1iE!ygQLbBi~POQITE#|&AQRahOEN*6Bviu z#%`Bd5HLp>&z67^M|l0_dyNq$5JR2#J5fad3AW7A!t?I8)8oR9TY~KYyU3s)D_i@a z11yTUQ)MCg5_;oAoKd9dC}wRJky=DZ3=JvjJxLW!MJ5+ov)_-j=o48=R@V7<8*chuFk$gZVlS)hW+XSPcQ*yv+ z=dQ`KU~~{yCXCLFHNap)&|4zIBLxaPG_@r27@b>6$c;ER39AK`c+&{~)fCy+)Ig^PvF=n>)aNXs*}#Ju zC`&4U5IMy(qO#`8Y_#Ys?CTE^s`)AFmSH$sYFB_CNIC+A8b(OuA5gYTnteGD*Dim| zm`< zP-qKPZA-Z>wQx%4dq;`5MrqV1Adlz@(6rq4=p0eJHO(2$x)v2Xv>#SI=tgjq_mNM9 zSeMolu4dJTrum0spvic0|>+0s3Ne%cRrmsLmeIV24Ar2*cj6sSplOh!8 zG?K8l$+r+eJ3e#MsuF?ogYl|3*}@g6HCUr`vfyTs(`T%XWXiE)ciE_NXF^HEffX2? zI$||g1S7@f6e1;ke?#WV+Y?yfl`LJDJ^rTN`JFgSy+`z^1NpRMKtVR^P4P(gusxb< zBNolQ6$;!~r*uw}$^R~|`5ehLYe9|kOv$!e;!ly~cxQk%%-d3`>u)YOc~*SF*S!~6 zW)&%G9L!Y@BK^~0?R1zbEB7)rzc@PjTKxASy0iaM{fLMlNCXk6Do2sS+v>!#gUz|3 zru)rL)JLA&2MA~f9rT#M+j{u8Kk&>TA~~dg1NUKq=e4(HYcC>L>6Ce+_fGzr3!%8` zgw16sXLJy)>yov~W|G(|%lM_$=E6pSw_9#H?uyuLhjRp_`*G5STTn6z_|X$ZAB9uA zD?!>G)@d3rSBLjjf?2zi3M2`V8pT}v3`}~&@zRK+@AlIhWmu0GR0$^)KM{AN)D5p{ z(*(mCsm?v1wWC960!6B;-z5$swmZDRzj_256s6!zjU zKe^e=IL+RdZ9Q*kxKk;H!%=tziX$o0|hyWToE*?^U z#qZ5^`)PPeKeI+GpJpWz{$eb?OjW1cv0bvE0AEaWH)?UQ$in?tCw#irr)k1UPC0CUjx3q$d#}W_Qwj#)I`PN>ta=2vj+$Z7=E@r?z94qmL%Th^&Z}Rrs zEJQ=}m_OoZe>7$ztW)M6q=-5DWNp*UOhoZLngnSoX`K>k~HciGo)FP1fR z@m2nMjWP{ikro4YY_MZd&4={`p+u2}$j(dD$rV?U$avGHlCbAOYKcX(q)PC6 zOGH+&(_`3gxfAb%CsFTnpL44XUlp}PSJije9yXeu!IC$A$2$=JCUHz{=bXC%lC=ev zV=nBxe(@Pxt|Yg-SL+wrLlm|)E#uO@qNxd$%>1WM^;|3%7R6Iv_4IJ?j$Gj zXgOgvNu34|YteFA{4}KcU)EAdQE15(x%&aHOEG8;qijYzBu4O92IC%8WZMrs{aMD# zS!&g;4|EnHixxi|ao8_VolB35+rlsirm=WC1aqbPmKu{4Po})->pS##s;e*PvJw2) zEp!16e1E(nBC~cBG#mSj=b95%y5Qwz_v@m-xBj2nY{dkPZii*OvbGot3Y z6rX9(KwkC+*QwcaIUl*O^v-%J)13B6iV6Nwt4H8h%`!UlCAMXcn$&b9h?oQgReeRD zW*b3f7rJDBsRA_9g%GVPtaD{mZ`~L=2MC79GA6lnT{s>C?AhC5W#Hi69s;5mXmJ0a zbsr|GEjv%QB#Ds7gQ7t)TKcD{0(!3_GyF z%O&UZVGPG5wK?kAAnVvIYZ&1s2MX1bMm#$$@S z!*`2Ezhg#xH!A_eWEKb&bg=a=4Rx9!6D|7av*-4+=aVj!$oC}n7oUjebT2i&Zdn{B zZWT}Bl;4FZM9Jnx0SQ{@$Sv#Itzy%kSRO2l^O?!&wIDyA{-BGuyj+zIaH{V78Uy(j zQ5Ix?8Dua5s>5!{l}UaJs){W}uentCSLl}BQY`EZXvAUQ z6=y$NaKB@`4S3c%c0y_fZ?Fjde%KFv65<|}sYc$OFe@_<{5^kaNiE8iGO+dhGM#%n zollJY*0;_uolCuCz(~jw!6~5jYxt!5fJVV=Gu~k#0PLFNg;ZsirpB`emkXxBvJ>Xz zjvOmt9yQ6rEn`S4r&>V|Jq%rp#yc`%%tCy`sX^uz=d*he!2Q`>4dg{x4#8DX_>up` zcM7Qg0{`S&e1&oR;l%k6AliKbDF4bn1EhapoB`Uuyjibc$<1$2bn|#i0NHQP=YWVW zhI2s37snZ(>FfF2yZmeV6d)bX!a*hN;EMRL98~?Q;Gx2u1pOFc79jqad;$pn3V+Zm z`o1Lngiq@jZDyObXj5UV{ghzVTjUck<4u++v>>P2KEBYs0KoqQ%&v+p&siWWa=*mA zxww0LY!|0gt7-7emwV=ab-n?LodN)I(blMqG!|%oY}A{z#8=ub5NM~W_j)3#YunM(wy476!s+e2E#TWTr9oYk~bot zT~9|Ce-KLWULX$(*HB(CNAxc)TzLa!SNG#M4hYcr=vdBEo8wXoFGRk5zFNcZ-RT}r zE$&!tz>9P(8L|7t*gtpEX^DUV383e(&--e&PvjaztTt5C5y*MwH#*ZxOwg;NKfOv0 z$Ur>b#mMc6G&FzqV{Sebeo+G0`cQTkz9uiKNV%!vm4|RY48MQ{!oa9z4}EIvdQyg- zzWCSAw)ts9=`qE}_{&R#rx+Q9!$J&6MRP4Trm!#$pF~=pf727Y+hs)gzZ3y$9>2OSR|Wp4hF3i! zaZ!OvlmB_cSU4&_EPet^=zlbF*B&~wpDwDsEz=-D$A(DwiTNygcMfwaCI6ct92((D@~+`GwfPTw`fCxYPsQafqzQ%%AH@2@-|Ta z{L!Fh16HU_9kic;^qi5T4r2n3VhOgJB6betC@m~4G&k#|U_=h?lpDxmG9|xm>l{^H zmAhQ!^GNlP3qu=EECXC^?LrwoM#zwZ${CA@V(QCP040kJR^<7x<}&W2biGx~2{AU? z`0I+WVA7!Xh(?K*qM`^xE65`&Fv5bO)PUyedVYHEUwV7e5Lkyf{8*}+iZua+lHmcq zsNH=BeCqZ;T?2I@Wu_u+GNP%gD*~%I_Jr{htxC?T7{I{DN-nQ1D~3Vg?P37g*zMqp zD4>eWv*JB{2vvfwTwiToJXk@g*M~_K{yODM5|*t&zR25^ZHec+1}vL*&P!gB`ePAO zb12&=T)m>{&ymxO_JB0)rx+Vb483oC0?h!yARw*ngOY+7HB!#Ys+Bz*VKRL&_Finx z4SeBCWt3y4-jm$qwm&9z-9-Bl9J>eidFFP@10q(*7XnsEb8ar=quK0O{Mb7q+YwVN zt6Lw~;BRF9+B_+ThU0I6pR+NXz_Zwg#P_L8YADi1qUphN-D|dMb(V_e`%LXS!tnf;I5KgpwtDDa8QK1Yh?&%S-X z%vi(nD8uqjO8D>>ur26O5B8qB$$ok?;LxdScL39i_*UH9@GT$f@T*!j4}((KU1(`& z>?Q|RmC3`!OQ-WOh$F_A{77g0XkOFjTfe8EZ4-_upe9=pkU0T&R^qd^rO~@=_i7w7 z*n!Ew{X>P`=ZkQPvR9GWq7XXd7s$9`*Ao~16#S&VwryD$sLdd}YQ(0C>TBkzC<3iR zegk3u1;%(*v-7Zipb1@x-q@u{@LQj$2Zufa5SZ`my?w8UD)P?-?0?>TdqK(dA7}o3 z3Jdd2i7#9_0ENDLrmrXyMM@B$l(MVbP*}7%lJxX$H07gBzWj8o>e(6E)A zlpQr5h8TUA2k7Z5qeKxEW*8e*R^<>DVKY$ZZJ8cp**7djKEo1tz!AN&QDPsk zgDrv-$J+>c)Z_XZidYf&Yk6B<8#O%@5{oJU(Gg)WZys2?PywasRtyivz^=cB>)vWx zv%Er6VlW6t^RdHN6|7cn5slCUBQ_oX8bxb7k-h9g9SB-set@fZ(IwhAt>aWm^2pj4v zw?N+4U6tUdkmx&gZvfC9+@44#D($xyd}R*cBPA3B)lWX2f5qVY_-|B1iRS1odfA`*v$Se5O1;{)Qp73QF2i zyd3Yod&m&>0lynj$?z2cLsI%w$~V32)44cLU3?gh7ybZ$e&c>tBZwI|H^= z?YWn-hJX$Z+LZ?bzvXFs;*&=A7+@fODXm&1NtN)6kfU&c;U`43==iW3{g#zB80wxT zDI`IyE6;N9T`ljuF=Qo0sDBXh1KIQ}@lX!=C}CO;)9pkLDNt<%s&B(aE;9^31o6Y$ zqL4Jt?a%$qaSb95i+}9nV0(lVPt2;Jx6l3QiRr5Q{G}O5nuR21^DCL@eaQw(%lA`> zXAc=WH(G&`rD%8#9fO!8&%lhn&Rys7)|_Po7+12+TXZp0EaVI#$5%MvMu@l^b~1_r z68lC7v6wO=ld+1Z;4rYgGJkOKRLQ8A6J3|j9Kk3j5&UNhFpg!oWNTL5&r!2_<)YTO z+$Kq$kLXY3Li|Tjq+ndaKfPbT#HZyxW_a}d=T+c@7&0RBF1Vhh{OioXJz%}oWQWNQ z#7%#UWZc*eIGWJVadLUNG53UobuZI2yR0R$9p=Akr0CIlh*b1g#P|9l5FCBwM6}w> zw5um-detMc5CbW?<6eX$0|kB&ym6BT$mcw) ziZ`&-6E(9o8mRY$Qr^KlrT|_Y&jI8m8jHM8b zVaTAuoR3Z)qUydfi<*YW=f__`c}EAw+x^6$_4c+2asw$!K(~Q;%&@OeXS4@J*ZxHG z0UJ|vIz3#6yd}p697+h#ER0*x^R@LeHRSX4gjR2_z~leb_v|raG-q}aDpeH5QCG^P z=n=&P=yoC9$-jFPK=Vqz;=on>x&fIK{cu?}!oYSNh4sxaQM73s#WPb{0BLLjPMmGA$g>T-s*$FMm(F4PS z_XPmBdhs1=dSrWHx{~BDK&n6Gi}noqijlp65%A`_$YBQTE*Otp3H!TOHdW&V=#pkB zOKP537^&5+?8z1SF!t?Q7I3&n8c&h~&{%SyHZb@YJZIPy4cdSbBS ziJwDb$H(RDKx<+bGQ%W_77r6?9`_cr;CtCLa2kI-Bm1jY8b$<>Ug!@Wy4El`M`gZL z5}L8I48O+1)rY9vz!2|wB9rI}2!9-*b@XK!izkr*Oy2stLPM52Q0IjwxRI;%)69!P zExopn5Gz}cYl0Fpf-~@fY9GL*keEHT7st5*{~W!FVjtuMV4K2Uk9Q?w+CoVJZdCmGgT@f15ni zUz0)5q>$(RoFM+lbuD&9`t5UI0AC029KZdWNm2>wh|-x+O1$4(K{&-(?MElT(omZb z_~P5YdaUh|h7JXQeQ|JGM86lGXO)?6YgI%Qo@K>9uybQfeeg-=D@;(7^zBfmI@D@{ zmu2GYfnRYtIe?(>s&jN;mYK)5yD$I#0Tlv=l>Ws931-SD>7Y>^6*H^qOEX5B0R`SE zgotG77F|(y&hb52W*-P9D(uaS9_-c^Og|o??KY^dSx-Op34t}BJ`YUpPapWURWL)6 z>CU#q%z>7I(!#n*{NOn>OsZWDXG^knXM|rIOnD1T#Yk8eQbaEy+<ciatH!D%$#@mh07a$-mRg<)SS0wP z+lX>B2;URdY`n;sP6=2D5{KHBSS19Hc@f1h2>Mjn<2-F1|9NG26Gvt9b>PXV|Mb_c z!|HyG^Tg!8<*{GZpQJsK&kQ_Mv50cSQ_4cfXh4$ES^$F8g zg!lZuO+$t85HK+pNXhjJZuTA7HZy`bPy#eP6a@s8aEu@jaW7w&twzyxjY3M5RY)ZH z{&Z1&CE+=dDP=mf1X?%XOpVQ!uk)(3aN}6)GH1EF)Ovy!4LiRY!q-O6%0YbePb>4* zgqW{-BBk0nl^mr5xp;<*e-W)IyaUymJiRiKaM%F=FlXE@l6T(k3wEyX%2W86`z5cb zbU3NbH(NS3nGYl*8IUm+KQVY~PGB)c#!8s2+`Rxs0 zT)B;di($ww2xP{`Gm?}W=}Tql&~)n0@82$*rydb=YE}7-+%RzLa4>Xekb!mlnq?~W zl2vznNGY-rPSfKNDY4Y!dgh-IQ38BAXGzNQXS1hQ$K)YqA5&P^NNONHJ@KmPd_Y4!Rq?FTPJSnFQiMUW}4g!Gy!Mk zrf1CTFtLS>E|?jB?X~jFQTR)muAQfa6dy(rXX^S_p4Hdt2N#fcm%bHhW$~&ZWivv> zlCh?$A+@wOKxL;Uh=G*8qasQELiW2pvsCWt+!tXfYZ+_(YDRsxcwel7d7~xm&2y1v zA$;7N{E>~*P#R%^TN`2L*zNZF<|M$|n|~7?2~oMQUdMd~?3mUck=uWdh~S_$GaH zhLZAe&1D3uDEzn7ux^e{eRZsb1Y#`(#A7rSVJy%DDhq@Klp|u?26Xj+V-JkSu)^>T zA<>x`A4ZkN%ZRsJD;96m7r7W<*rHw{%2WaB<(}@wYBhTBP6R`u0W>2JKcC;5YO4+s~aF6G2j)ThX(O=f8NEsY9FP&21;aS8#=MR*k7Lw-ZI_CLPpjR z4-gIs2@&oH7ch!ZPr4F1pj^mQdDRLDmyn^%UHbUD8QW8d=YWDpbg;DC@5LR8v`3sF z72Fm0G|lbwMiK1#v5{heW(>B32h)HMW5aoJ$U`i=5PUv$GZ z+Lr@CkA`Bo7EfF8VPtLBdGDW_=(N4{FZ}%HG%|E@Ka<+gvqn$r0Md8Fvj4^=5heZk!jKp3ana@R%@W8BZtNg;pFk&MCPhY_V1Ow zAXUrU7&f(njp6?WgL73)lNUJ*D#P-mEiR$r)+bd#R&gacfuXL$J5{4!i1zX5?7^jk zI&|jYucUNf)XD7!+kkDkPu&aLDB299UNmXa-$}oa|Gd4U3%8n#u8_(RIzrpF!2%4q z+$2wGB7bg}4cJe3Y1QnSA7PxTHD+&bIOho!tHUTj5d{!O>~Th6r4^-WO-T)`g($7i z;ir@l;rq?r^qPJ!r+aoTO~}f2YiEK7auT8rV(!Cth$p!)2k%E?fW#DKFB?35(#8d~ zO(!4zNsvR<9@HEB zg#)4I^t4k=fE9#m?{OEHO}>5Se)ow%&i8I|R~}5-?c(zqA5EtPwy1;U|M&j*W7@}N znWr@@zv6`!hop<8c!`a$|$5N;u_T^H87cwNqg%CGJXo!g9b%1UjePWgQG{SvMA!mZ9O z(`J@9oS{p+_lXP*HZO9WCC7>_p4|NQ7uhcd6WMYPPm4csHN@;80U^?ei}WlC zsp!~v9}`H%C1k0Jb#>?A=N+tY z3j*g_i~qP4yL&UTD(TpUN&x-2U#wJBzotk})k$ngeQG5_7#^)!o`RtR!uLPOB$9|9PmSfSZ|<+u0b=}Lf_}%A^?-eaXIdPkEbjG(jl{QA z&5e5I@EGVlyP`|p@NC z^GEm%1QRGl2|E!wL-KRYce~<^SQfojoyu;S!$Sd`ZJtbTj7Qrk3|e(C>Wl*ydJZOk zGarQnZE|n47eX?$ZpRC&uH~K!!IFqGPI5z1N)c*oR*+zEy{Oe+MRb6krp*MzkLd-3yz`eXA821en>_z z<-VI)2T1xXqWG(#Vxe`BcS;0gt${F!bjIo1CFM^L`qNWm^dU3Vy<_bz5i&v?qndj-}JyxbRAV?nQ74bH;5Y$e|UuyO-d9AJ9AK7(j;+U`CMgzDGN*iCT*b@g}2#=Eq&Hn zT!xhIi#B)TEOnBgL4}M2iC}Up-V#=yc`GB4FNh6Oc z7Fe6|*F6q6gbZ4M@K*8GtLqp)H;|2qD3N1rf<(;`$2bGO6Qc@sq|7L@L%FVugTpPNs&KtAWCGvC{vGXsH1iJ3q+kjP3bhqSujQ!ghE=FpDN8ce%qH) zZPy1yvPy}Em+sJ^-$YASuW9g`BUt@>yV_R{5^2}cm>C2GA|TY~7T{D z&-hd_vQ|xg1CBcTuM%h^DO`W9Ciz(Z;(>-pgw$PmwQckpc<+Vql@e8~V_bC>?9p){ zFV*0npWS*K@_rr=3UY?r^{ccwVY11!iclO0b6YHvk`Z$)U zzzB6VdSebj)3qb%&s;K&>)J!Ec2B^=;#s_LR)zG`C_Nxz-p_0e?NvPvx$&bMjdZt+ zfBIK)K|MnlbERRUPiQxKczP^mc8EJQxK=d=>WnOHpn-1KrNi+Ddj@+NsaWFi!}4ep zc}A5O%s_Y4sB?G}Bq`*TIJF&g@r{z`GR(>kxI%c(um?$dx6?U=>{4&S5Ji!0Pkuqe zl~Nh4#Y*Mq%ZDSZti479UinxZIwX*4yE92OW=}+lMX}2>M;{#L>QmY_O&)fT_mR{> zU`EA-j7FGQHoi{PjrExO7rPwDh^ccH8V1B691f|ZSGCI$-xlI^le)s=8$HO3M%p&y zMcb)u>RkW!f4oN2vRA=(qm_J&Hjk91%wP?-Y4$AgdrpY|tg)_k{49 zK>iu>m4NS4(+e6i*BmjE5auddC|?j!i4t)nb(uR1_7R{U z;nbE&>+pkXwO{L$g*Z>15*5a{C_?FiCop=(-@7<8bXRfY7U_w1Zu!7uDbWU@H=|Qf zj@xcEnj`*dYKebVC3~x-I90e%p;+`>d%plVEwX74L^l78wvT2{*=prw5_;SGp);OB z^QhVBoQkmP^Q5z4SN9fGGq1`;^>M3?SAA0q*5kB#w*rpfw#PKY%B!}F*ph@OzrgkA zRKXLs9~9oL#h&jnTtr55Bf&${(L)OTN$2A;_e0t1@-Yjqvv>XZt29@SG) zEHhf(8Y2U&yJN_01D3ttE3=TeJQ)HDaSK1Gv~(jH#*%=C}OBpGW-<&teshW}a59S|g=bu;7<^Hx_ zo(s(;ip4&l9Gurv?+O|tqf#=P` zxUP~NeWJSpihREflZ@HRt(-L!*gg--Mvg>gVKrBke|ECc+h}!o2z*Sg>!J>B-R^B9 zR&U&QXUEAu0XjL~L&8EyNaeeKo_3_L7hAg)7#m61c{$v{gh`H3GgNcY_0T=7Nv^=! z8)3C7a%_b=APCRhKG$L#|1JGnnB64qBBhOk$KweqMDiO&iDgH3#nymn51;iJgdhV+ zG;fBFY}QsH0xnQ8pCyHsy;$2G-@6(enk9B1uG5`V4W_fhQBq=V;fiM84t8vl=hytz zFf`huhL2pOrral5J1%UexR#JYCYvP14#h_dTRa9cS%kvoBEFVHxj3$O#LBT|}W32_( z08#(o2=7yD1s#&k_s^}&+Wor&gLsdXLO9cU(Vvl2n9m)CqyC0tF64iw(=-Q-+!%VQ zSO^Zbi3Ay#Y!98dXJNFojI}xk@kFW`$W|n?-^37|`AsRTufw9_R%2oVU;HaVE=@Zl z>WMivD=_C1HvOe+e|bE_xW75z#}tchPt=*?L(5`7?lL_f zm!YsCU7OUU+C!tA@~euP=L*N7=T)t&j;$2G2=q96aSzyB1XYvp+V?1nGtovs(xb?a zJ`uFuQrJC1xDZ@$Z2BKN6lXq`IOWn=6;@;0jft$oJjn&?7OmvqnvX$^oo?Z69O$N* zw2QoTJ*PVvv`q+&n}jH`8iR?}&xf#+4`zn_9430~gPmACGs+NDJ^02Z_4jx~Ar$eC z`Z1beq`#20=Zkr!uc$6WOMMTJltUcZx+lV;6wfq@;@7ry@9B0QI zEz@)^j0l(z>Wp@Yx+4|5nyL`5{)kPxj=>2KF9_X+=dGK+eDwQ>&5QM$S;L#N>GolJ z8=9%u6p;#OOy?Fq**@GRaNW79RV*my5#-1s3!TFkY!l4l=rr^hWLh>Ecen$JaH#uC zv6^iz-wKRY4_yyMP+7?3n^K*(nL=bAoe#~y&acb6q$lKFfdyZ)qM=;u1z4*3H4m_)5mrY)j!reNKo8F^36iRWk%b8h95O(mUd+}2pUoYdRahdXH{i@sjp z$3B#jF?_9Izcxg$+8WmxdAO?N<)K%odz4!nRt|QC^?POpHXyPv)>s*FNqydOcZjPl z>p_)WKVN42h(<0mE0m#gbN(i3xaP>d+PtWV0@YevhrA8f7f}L3l~JB?m=FDmg#8%nx-Ee zfxg$1T}0PIR3y!&&kTAON9hVk zc?DIcdBFf^<8SN|dB`S1-qDUn%5|73p^vV?VZ3Q<($drxXe10NAY&l1m=LQ}y&@p4 zHw0_}5o#|K6uDx&ka8>2!Mj^fUZqjjaXvj2k%!gUYi9UUmr<*Nz5REx(pZv8|859V z*e;mFsaese@lRbO_zAxRA1r@#l;#tX4jS`6%uM@Z0|pq}VR?hDgixubPlmq{|E7vL zHSBZ0BR#P88#){=7y9(t8x@^r&P)uDlO-#J-7&vl^WE3}t{?rQM0)zI37D75-Mr-1 z)%Ic`(+#>Vv`?nAP-t?=2rbFBl`yeC!S8q2mW7_`vk24eaM1ONs`KQFWV?;r@7~Q` z!OF7EGE|0bMN{VG)t@v1Nh+{PSRHI`5OD(*b*uiu+`rfQeE2ODo~LZyW@}2NHzZ1H zaGjLIPqm$trC+(@HlN)v9-E%i;W0umqBBm>457&6Q25EnD&fn5!$A1hLP2~#)8zxv zt~8(p2?XQsE^iCeSjiuKs0Mw zdt}P?@^Iu>){76drYwi;l*@=6m5hO{oUU#S2+0rmJ02Zg*v>aS2E2iKirLr9KxY_;L?b`aTI5v(7SX5RuxuS0(yUR95BqDmgdfD%D7 zB~wi82&bo3O2m#t{|`a`hZ*Q|^IUhNZ2swU5<6k*ulC&ar zotBuZPRyZiIljGBx0dIu1-5R}bsC6J1iHww58)SqEz)0u%Mc>f)>k9kO;H=`vdnE% zoZ&Tc8Tn1}r?6jhLDp4Y;!yB5N6moEw0ypHkH5ShX7$`};!A-4BTW1cD-zQ4T;Qbs z(;=?x+Kj%blFRy#;+%BSFOYxrrZ8$R26xcTufUP@cdm=gE53E;3=vsdAhMJ9mR2*% zo4T=vGzZOe<;c~Ck1z1|gEHbf{ScJM1myz`6^XUB2bggz6GT7cT`dF{D}RHeGP9=U zd~YgJ#%j(zVTPbaoJvYvFs&7u8^UJQ!T-b(2aZbYMDff`;K!FsQ~nY_41iL_2y+lm zL2!}W10SW9@{IANwL3#POZ`t7bK)IHkm5OnBbKJz7o@hfva@lH-LK=XXiDGQs#+&R z!2A|n{0dGGFAlWLICg5g#H22)pO;IWEp;p7*xzR3Ua|ke^&%MvrrH=;Xp~oUOY;P1 z1Jfkmu73{xQhVO4iL z#t_woN!E*bR`goy5Xiq*pAmDxbMj$Lmx}(etN82Wcwr;!+}BS!7fpq!{72!KiZWTV zMgO8j$Gfy$TfrGRS~!z`2Itw2TXNMTu(@{gz{A>0s%FPDm0(3={6t~c*G0Y*e ztJxXH4s%Qc+8%owo2yDgs_ctLx}{g9q3fx954|BYwPOx&v1NWmv#a>E0*UQPJX!L@ zNq5SUljTH@*u@hIzeF}wb&Y@4J>>2f+z(@gs|_MZyjMx5$m|d{No9U4b(7%jpe(Ho zLKZqiTZ(k)K4E*RU+wXgI_PC!$;l~2Ni{cxpF>Hn90vnsvuRa z*vWU}FWFGX8cnjT1a7jHBBy-}+lc;JwcexC=y`a|CJyu;##O9@O&fv7* zevJK*cgvOe%P&8#U~1MA3$~tMTE|}o-})&yX*R6G2iZQCZO##{}&gB8U0DZ1JMhP_$n_Md)<6Iq$v=;p#IF7i`m)b83He`LY&f*VrEbla_U%K_Rlr_^HLXfSXxn6QM=8~ zu1@sxyIDD}kqKl)kz81fTUC5EC(|wRp0d)iB5%vU=o_iWF35{>^cWu{6@|&1gNky_U zKFP9!;aQ(>;D4Rwf5PLp>fx*_#_n;VuAM~!C3q~MAA$5EOZx58o{=N3h1YwFN)s^V zOd}Mqw63BvIkcg1WDVUkC@%PqQ(Cy!fz-5 z3d@4FVKeye19>=)npfSdJhGKSD$cco*GHgZ$(bLn)Gxo0Fhj4AJNn10>J zVgDzurpsiqat=;!4=zq_o*yJbEIxl?F(pD6`;W|2gi{3my}4t8gSz`)77ow<4aV9G zG@JI*o&`J)HBvuy5RrMP2EmEwCGXQYmus|(?aI;XZ^mWn#NqkdcN!6)J2Sm5AN4dT9qKD=~_EcnW##PoV2X8l5RLKWQwxK zyKwh@=QghH7b?Pyom6nHO+X|i#h4~ns7x4823`}Fn8%lPhv3wJ8ob4ML|34t{<}YV z9Neonvd5MS2dkE=VyJ!6w&MqD;6X4oG^E-A7W$_2jsWuwlJtRqb^<3s5&i=Je13w0 z0#W_@&)I*5Qna1_;sP&w^@Fa93sFl=Un`=bkmeP~P*eeV6o+KF1v|pY_Rv+9&6hN8eP=DPUTAZ_Y;}^ED%WQ-0KH6`>iWMqw`)#&{GaZ zl{>oy@G!R`VS_V2PMKd}LK%$9$Sf3`Lfl&+T-#_#Ip|GKz$rmS%%)4Z>|h{W4O)t; z^$l3Ed=g*=PBaP}Q*s4>`E+uSgl9!E)WafK6v7I$myej^R@0_^(_<$8((UQ`&><0X zVt|viK|=8RF^t+t#tl$uiEyv)vu37;7Y3QCE3NmteP>R}S=pDD5% z`uK-n2%Ep|p#NX-2mXJ@Uzg7YHvT0gTaRzg=W8w5p(#Q= zM`3K6(X?#fEn|6EYN2JtHC}26uLjd8zXp z|Cd&?bg9QmTQrYparfanm4Rx9x9OA1ofEj;!03^NFSwAYB)>7UmTJfk1f7Q>nVfAA zU!v#xVF4lCXSaQhzm9n7tEbcS7fr*u?-wpTy=@oUX#WzBOv9GZVYL6$!DH;iWPbH{@85$NYS`oRLue=i&6P* zU(U$s>Adc`EgatmuFHo#v4XbnpU@lgU%6nNKZxQM#GNVE^k z58{0UNns$-beINyKxX?;j{YBXeFan;UAAuH?jAI_1}C_?yM^HH?ry=|-AQnFcXtRb z!6kTb$ZO!Axijy+SF6#6Ue#5n&e{93qVo75D>NA*&7)2Zao&ff{$o`A*ExeQ5Mw4G z)Y!(>CQcU*GY(|eJ_9yIOu&w)>+~ISd!IJCGu}_z^k8<`&tp`SLG^$eRcwX+hqS_x z)Z4-CzL0&+`)?L&_2!vd6w*;16n z_4D05+06ad=0;7%FS9Ge6t+Q$BK&sJQ-wUKu%1*F&{aRQ!%K0Kd4d(CixP}PYc3IO zc_~c0JqWlo=>BH>at!-P*6k~7E%8A5C87K~wkFcH8qRJM7k^bJ_fnN|-`c(=(S}^s zQK4Jm&-QisYzDvDmKYHa_7LFQp5zH3_EB6iSNVq-WDMTFi|5@t*y}Lh5R*-QG(pbo zG@Exe%a1P1Ao#C=*kD7v2qcGw!%9G2S&dgPG9-OPW%l<=NpJrFEK{p~cqO57T0xwP zkUSE?j2(t`8o^eHA4fpcCm8Jz>3Vco-+o21bmQ}Y7et}rLdrfmc3F{M5eL-{lc@Nm zo{8q=$ken#0pO-uzM@$o*r__roXDFOiJB{ZU;`K0B)UU9S^A@f^_}NKMb(jE5`_sE zMRUrQTNlu!2*}n8#_3awV-5PMSOW3NZK@KMaVUktyHD`rB5l4Yip3DLP$={vGumBg zUr30kf)opjaQMyNTcEf+oTP0U-Os?Y#`*Qsy}ZfhNM~+l4DcV62JrHmMrUD0S|?1> zbWKVZww7xp8Q@_+ip4B@87qTUaWV3iR2BIwT|~e9d^%hMj__kh?T3QnT2Uj*|?^@ zuY-fpaCpqTBN2UQQa($4E5Xh>-+kTEe0Zymc?}oue$S%<0ARqG8WP}JAM;oM=J!9; z&D%6%vSV)UyIH~*P|`14QKCGKm8iV`lC`NbT}Z7$({c;1H}RGWcF3<3MAwgrgB*!`&lsQoKP4UUv#IXe_Bj-1`D^m*mSB^Y*Q8 z4u!F@L@P*qiTs~7`_C6ik1Pa~SJ)%-Dp{pRugXf4g?-Em%;QfQK5u zP=34qGg;jui9cy58Fd7`G}F#4?M_q}H4${>WK#=`HFvlmmaZ0;*&Msvrv=<(muBVA zuWCL(5#)-+$6_5#{(ImFsl+mb&nW5(s=>o<%Wilwkq{uzRbj_sWlKtVU(da=3bgz>6`)N`BIKiHD{9W+EpT z{O$3%srKNP{Y6SfkZQd;#QG=pKUsbBYX@}fFd$)6@PHh{JNm(FVpmyI%E`-c=YIsL@4Y4IP&>Be$9Trkz=!mRpu%4XAgiHEP(e`TG2|hE z*Cwk36mpt{5ESrE!e2OT2vI-kFAa>hIs!KTqEd7N7$7zQfUbi|j^voi+GvO|Ba49Z z+>)Q^H#Gp_&0yU=W-iw86%UdH5jpyapbA(T4W%hwz?^^SmaqFWyFX(F10pI$R*b+l z653`STOy|<*~konYlK>aIrDODb9`m8 zsOj^h2Xk@OAh%gun}@Mn!4r4RSuCKEFeC&Z54GF?08D|>)sdry*-AB@uul7Y0tccv zAOK%bmS3S83EhI@3tUCbV(I!OC^tvKiGP$>bwiS0EKsz@HeEZk@`cZ}L8bxxs357A z#;SoogEP2gTS~`}vWG49GgCI80<=8BC-)rHcN%tZePN7YY2?(<=L=X2>&{zLdB}tY zU_q_@L+#yrg8epAz_}%8)ISu_T1Rcb8wyLCWeqF%thnC?G8z`IQZGx!1b*jfyAkQ< z{6q$7h|1DmM0&vB7)Is1lF{VKNmnYpp-~3T=HR;fgStTdtD+)@(#QGsLbmE5^J?`4 zRFP$|y`e+S42%`fgfcv+ErMRxHh00*ctdl`786p-6u5&cV;nZ7^dz(3`|FU;8?=_* zI;IoMd;S;}3*ATz-?~xIwTDI_2G}0V&sP$sV{^mI&}(bNlh~~U$^)ueYotPGm#UhA zvJG*vzx3rSr6`}&DUnx%;1aOgJXT%Acda*panM{Ld)>4!V9@Oa)Rb{1K)M3_M$}k1 zq8~>1kG&n$$i$e$D(AU(ak3ghO)PioFfhLy2uShRd2uTdoJWLbIZ1^c3lKc_=eM!u z&!3APS)WDGHr31L^epTZt+jg7{cJd^;vPK>RkHA0m*~nmftIP&EX(RJ^sJ;8OX?Rw z`~?D{JYa?@e9Y3`f*q?TEBuo|aFyJ6H9(?KV~h9G9J7nrhTJOVQGx8YS!>Qwa{KJc z0{vkPRYvMHmQ=EyRZ7#GpJre43HIda8Xk$b-HhM~0sYhaHDwfBabe>3`pP1*VxdAo zd7*)6NOT|YD+57@AV_3>QbNTg6ZB}{N#RcixFW@SrES4{lI!Lnan?_Ao#p(KgB<-; zC;W-CN@D<>uO^ITI7d}5oIknAWtvzNKTci)!;l7O$pWEUDG#M=8OxbZE`;hZK~k@gy6({?ZjjK6^wzbP$fr+ntN-z-1uF6&`8)fK^&FE zSQ;fUnEIQ3GM+MrlHL!VZsO8q)V#vxx)Txm1(9mHE&-Zv0<{Et*Y#=y2JRVIwtex< zCI&?~CIH+J$aWLsh@;6MFFWstLfzSO!Xm zg1ds(+I6$-$>#>}P*xxmvagRhR3l7z@m<(dFn2`Zo9CmOcV~G6nD%HXxk@b}srU{e z-YI0OSp;qvZ8uu{u%RI17#)dYfM2MaB{}-=Hf+FvVS&vv5@P)AARGf~5xfn=eMw)_ zxY6~`oJoe~!<|u4X`0?J4xS9$ahXqW#AdzLxz=2=Q3o;w8H=*E>B#kia~;4VnM=$s zd7^zKFbq#8z1T5}I`X|19;O0MNyI2odAkTwPP(YC;j<)xbt+4{TkP_n)1Oe*NH_OO zE>UYY{??6B*2WKeM~;krd4=O&L&?~a`hH=)NUBOSYsEx$mBrjcGEp*Pv)nWs_Vx8g zq(e=t@QOaAcC9zxYM3jI@5OY*t_TH;vruR33!ACsBQ37(u8r;vK4=*{qu~0MfLxSo9j_4#ZmZ>>7GZik?pQT{$JMjZlupk)6zT6^}f!O#Gm>l3IbRbNg~* zm4H`+trv(QIupyk2Z~E0UJqh31(H@nH0iP7N`_PqI-XaTWBP42cS06gPCU=4#``mV zl(v~H%~z_tRZ{9t)Ud>=T+*N&unI69X}-Ij6+$=%8|^S|auRN$4Q6xUqhpL!17ax* zdOc?BDW)eKzl4V)gxW@pdQ|4&Rm&Hn@`V1#Dw%3XfxYdq3yrd)(5}2u%+J;{w*=Zy zB%@WJB;kdJ#(~H!LmV=_CD}8Kx zSRVB3?<#)j9la>EN2AFO6Mgin&Dh=XtO&~K$U$2`*#2aO=m~H=b8Qb^cb^X5>&HaR z31Y$D>VcPrp3oeoKm-s;)yA0JAPM#Nq#yUh*Lf%nCB>%B-b)V?9QN!aJFj&Bt4ODa^_$r7Acs{#8I`e1yZ)n{E~R1}B>@OGQlwhW z+k$pKN%8C!s+XqY;ev6rS z6&qJTkL})}{>%RQ@>v*WU=1+kg2K0g-(8{;pKfR8N-*)1{1&!ZwYOHYZ+AXETcJF0 zV%!=hHX!zc%ei=%o%fH)7xA$MB+f&|KR8U2YQOewt(ypsAv6iUp4OICDSMHXeprPK zVW{Q*tp9m%U@!AHAOSq~Kqj7h&GWZvf%trb-H$a&w~*ur#qtkjqcy@`U^NVuKc zOAxk~bw8$9K~hK3Eh+q>yw4XIvS$+H-Me;UIe27|;=c#V5{h~Bn0 zt8l=h(k!Z1PcHH*F2ZUGgy#B_`bQ9agyq>2oUu8hg(Br)Fgf^yf+vV&7q4Y-_?P2N zWwLHbrTlV*Z4-U5B#W0?1UnN+%?>){O}CD{{WWd!Zi~moArmijxK5$9Fz4uly}OCi z6VEBEE5T@!duw5TJI{3)f-@pS#wvH4=dJ582;dF?I6klvoTOv>6*zm01Z5G;{qmUX z;sT(gLLX2mJmUpL(o8bHwQm3Tk!I<{=#04S5npxjspDxD?BW+bZ=DayHOfO6Q6te2 zvP0_FnDibYF0Psyu7}5$FCO1=Ku$0KClG+AY`phw8Ia?7D?1N3{lrJW@%Ec0sW?Mp zOx;Ezy`A-TWI^Z)pD-|BKgr|)K!*(yL>XV(xg2_yi{1d2+xia174+w@j7O`g9Le~R zEv5M3u1cjYOkQJ`(($-8oAAuswjFop#qz?%U@VZNFE&g-R9O%+8GUAmC>+lfG*(!3 zNl65uMbu0(oG%Sa&i(jhToYo_?Qp+jaw2<9iFXoTc-z`ScMcKlly|6!;wov9aG2Q4 zePBlxYhsRz@uL!YLbpz`-7zUElKG8v1htnj?B8i_=uQ%7a$eYQ7S!47FV-?&j9g$; zTYk#1IQ4v@U-1lbdvSv1`8D=nIr1zjaHnCiS~VF7~e*> z;R1=Pg{k9d5~%A%;r=Z|JX&EsJ7PKD76c@f{9v6Q`FS`9GFs3jO)pu#c#=**)Ay!w zAQeg8(m(Tl*7a@ez{}#^WYgnD)yr?!zdxr|?U_&Z4rpV+NCnEmiZawZ zbIA+z6vHb#c$s3V{e9DIAq&YFGC~S4sDS;Y2(Z7D4$X*t5n%>I!YKDQr(Gy{@U8LzFnOZ?Ub5aWgweiSmwaN&mGBz@w)MQiq0RQSFd z7It77;Bdev`{DaQ_(#ZL)dOx3fZgoWeVF>mv^JeTel$Xtv{C3&5(B&J-DV~YrWls`}>4i<= ze`!$<+ItPl*n!Mq1k_riPIv|U>zM|_#N<)_X&)70Rf5@AuqG_%^MGF@^m|yRlxGYQ@eX367gP1Gy zq}js+?zJ5(=nrPNtr=VRIBnhrLLDBDN0|v5_428O>DkW=EKF>StYDa=gus8c1)m9T zhJcMUYv5^uNAeRVR{GAu8DM5+WMyDsa<(~Sj@z3nr~ZlC<_VEf5cOk{_-?ugSm6xN z^YLc-D2tZXB=|=I^iOfYl=dH5lE%R=8}KBz>RrK6jh%!j!SB8gOWJj5!^~;(rXo_H z&4Y=L3=>yn!PVHEW%L`$Xc&%7!bY6l7lw=>8tXQV+_bAd1b&T!8L1K}B;>K;0~fgE z6&{6);o<25KfVQ8za^~T*_5-{c189%3^R6 zDxhKTDYlQcF_AJFy%aB)ky0c>lE7)v<4mQEG9;3SD0Cny&=V7qNAS-aW^d1|dH-@f zW|cbpa&xQWt-L;HW^>Q_c?8O&jzIWp%&YOKBb*U!6*Jd8e`&|`2|+Z(dB>BW327W# zk;*MkX^}Q+X++t>nBv;!o4G5&hsv(i7z}+a@!1nDwBK6=(BM_hF56s))04Xw5Q1+* z2m|Pn%Ksnkkmn>8IhyBUj(M{Ee1@j7eD5dCUs;W>g3h(Wza?GaLk^H1{WDO41m_}5 zO>ZKYCJ?N`pyV_^oY#Hi76r%M7TVsv8HNY9A?Wq~rV~?{UTk=bVVz$?!h3pfLTc0s zqk%A5gPf#B|2IOfJi=PlR2Whe*sv$HPQA!WXX86A8(hFQ?-w>LJw>@LMc|Cg@Ny}q z@hSRIfx{tkgNJzLiWekG88XreJ+AR2=X-##%B3DO7Vjj z2E|bLNgOp*5aN}vw>*~_kK43$BNY*PvoJ|x|B$X=P$`-FP@X!mDrjR>RZG!LmOKsy z^kbosV$eNzT-Muo(xAT^O5Pbct0gbKL9jf~((+G#pXlRABVUr{En9uVuN3)^YP^O} zmZ^*WLpel}d03LYYzg3p)|P0Y#O8(gFPGQamLre}JG74e>~mCIShM2|>kC^53wvRN z-pi`_D!a=69B~n$rW$ky`rk|vkTyY0FS!j?CYk^??{>YzcM%kfh(V+ul&B7?*q`FO zTX7q%h|Uz1U@hdXntzG~I0Y$xK3kVURz64X^{E#6E|Wv1Pku$?;5l;hrz4D^Tt%4r z(ME;Ii(JZ7q6u}Qx({3Z8}gI{)(ukvbdEmORdU5!c;D5Xx2o@w0}i=MfXV3 znoQ0##T|&JJbpmm+^v*8XO)!$_Ru>P%18{LZ>|ba9vO{Vk)67|Sw;Wgo7~|e-CU_M zCPTGt1+HI&cWxUTh4e*0(6F5d;|!wl!(dRa7xJ?iQ`s%>aq`^sh}x*I#W2Qy&JDZh zF2#95HIuMIZK8*a5&L@wHukWwpkse15pUAz;(0rE@zJizRdtMWkz-+$JXLmy@8D?I zy@C6$39d(~vA|!Q7kYAc`l*6*4a3`Sm=ryP<)4n_ev7xq2A4jXT^5No8ts;i2knO0 zH+BS$@gy~pMQ02S*_=M*5H;JFs`=`DVXWOjAUG2R;SBGf7n7GP1YdYI~a(rxjRwSJ6zv$yMf_JdqyC|vOmBlEE)9<{*W|LGsx|_B~uzmtZ z3m@<8a69~54IXVp>_^%Z%tf>y!~i*}d3=V(*d&Mt%xtt^`e;>X{UJTexEk?~mG0_8 z0nD9AliPTyM7t2{?wJKm*7NVKQW{zqS8@NxRD$VnhsEB0)KmOi|1NFQx!a9{O2%!* z4H{eK!9at01EG_U)M^p~q`}Y8@q?Lz)7u3X*B6%;zqgAA&!Rii7TLQqx@68N;wUa% zKFh+GC>1q0u<6K8SMGSn5*QdvIuNckgA zPee*=l89DRwns!OWype*##leL5Ha^3_tzUOBWsWNZyxNA$AsKW3|5^`QbHqW8+Cn= zCT*rSo~w-O-bv7U*m#GVx!-racfB7|4{fqVIRT&S@FTyUseik;q3iyirpEe8t?z$$UPLC6Rq2C(m2&s# zh?67JEEAuxIg-2^L)4+xPf;|?^<@i?qDGSb?KQMB{aARJRKByHp-UTieEnAt(JLT( z7S;bzBAO4&}krZl=0w`0F; z)b={<3xC1>;O0_s$W)Z8JkZcjJ*uy$E?qdv>RkU(iIg_>C|Dks4$#PgVFx{+-)F_&Ap6!o(^4n=9b-6Qg#W)qHr)xO z?Cnm@3Ls`ukvh{JHw`Eu^u*cNbEw(Q*I$KwUmJyxV$7P+^k!6*FELbRmHh2}RM$5N zZ69zU^x&=NU-jE8gVMh~rm>2+cED9}9VJjWeh8iVt%kUBlWl~nnX^3o!r^Sa@ASP& z;MHg~eTgJE*!5~Md|wk9w%t!c#Zyk1W5qA)l3j4dQYrw%Cvzs*pJFJbXP*y>$FpM{ z4SfOss#hAR`g;0FfPw(S26d}#?RueAiBCJ9E|lvWR}=NrKyW#El|7-2wym`N4U5DL z7DL5pV@GxX-{n;kP30#FAc45gPt#BZNl}hyw*M>(X_IMa@%5gm#H(Tu>qYgU@u0=O zyYz1M9R+dt2tG3i~moPoLlXmdyFqje?mSZ<>|w zpVKuxUd6FAX5=5@{oWgce|ek#XVufe89RRUW1USXGl`U>jFuXvGI>AWn^39Ou8ka_ z|A8d&*PrI@w~b69qQW0PKrm?QkyyR;*g0uuWdSxH)ysfZuz&C3?j88{yLEG-w{A-7 zzY9|!>Xn`u5$y2Q&62}~d5r4I8OTTPxzVfg`{mj52m_q z7u|x~OFSKlgT(W&p;x>ez1VDp&`sNNjFj2H*>_2XU?lW>@Ra=?n?;FuAawTGzz?6*Bs3a2tZ7-X-&uN; zCunhhdD@n`;<-sI|6wrRl=(L+Z{r5c37PmYbsZ{6kU`wZLB`lnz4yhS)T(!RM}$tR zffMa>!o7&|-i|BnkPhD0oXT)(>(;5APfpplT|&_nOSB4^{hf%9BuklVljz< z@~A;jmhovJM>-#tJCVJl;cGz2n%vjttG<2#aD%{W3uPs25q4*Ay^r6kSR8U(*T@dH z^$p(bu9y}!u+Wemi2s^RftW*hqIlCj`VadNvPSN^p+Vk@ACs5&^`0MfE>$|#FJ&(2 zHtyGJ<3%(-WRAm;`w6^44R77~`Bi4tekyE)2s)WOE7Z{p%MJ9OkMI#b2KzUvR3QGZ z!3}w20SDNx!3_Vx3M#~;+BgU@ulM02Qq3C@3K8F*tA#hFeVg_7-S@=uQi>j@<l0znYo4E$sKR}f#eX>u!qo&Jj^{z6s1!f}%^?#u(ZRHjyVd<3> z(GOK7hvE;aDGf&6pL^Yt$fOjhd&<8ugVDT$Q$Wi+(478eZ%rD-FcwwsghQn*5Gv2Y z_6zV0eCT2)$vcW6=fYesW=l(fz&WgW7_25_diYkPAOm-ZFs(Un#xoer`Bbnx8RQLC zUsk^D@^2$9po++e0US1fBu0CTPTo|y*2$p_mvflc@%2ZvQ&kJKbu&hiY)<<9=NRWYVJjw^06ZQ@k&G&fjLqfapsr&-#P0_>VzQ zHpjN-c4+B5hF4?m;YLG#zhfR{xnTrFXTl=|a*p5+|DzLSgpDVk8YrezOR0P^aY->| z_kauIG*`RuZHTLyJ_^Q*Cm(v#XJc>{B^y69LuhVqe=9ssP`fAc*}P-z%8ze$V6YR! z|J3YZqXT8KnV(#EB4D2({zJC;uDq&tz_BY)Wo|fO|L-M(gZu6If8@1}S1PTH!cDJP z0T?P^Z=RBrq~A?fx8@$ZtDA5MXMwmh1y*&d1nqbb)vL}`gFo#3el_%i?U!?TE?E

%B(P!1;3@XzqXU{_LB)TXZF4iD`l?3CZEtLuvNHIQ2hi|&y5k8&`(n}qnxXZ0S!L03&J1g*ZL~eOVj{& z_o{a=Qng^nx*y{b2)ZC zJ`JL|;3Nhe@P_kl!etFnDkznZ#XHX)3!6;)XHz`z_&r4eR-ItJFA-0?CN-(WLHW6P ztymg4D=5AsNax%DP{|neCjbQajPEQ}o2N1=eRD`uuUPNR<+>2_ZUDCV^!M)X7pFlN zmU{)U#G%rH;FJZ!e+xnd6O4ztQh3Cq%^H4EWk%k#1p64gMynabSVxo)!F*>g?^wmJEyq7WJLe61j9nT{;I^mr2R*c zWO?(fp_d0TRHLjgA_RP!EVQ_dG7DG^M+E#z_^3b8rk$&MF#1h!zA;y$)<}DyMrWNjA5VC!wNZ==VB|S5M@8>>dX~FhdX1bv}y;&C?etHCd z#WS&LVh_@S;!ZcN(oCLtMPyreR-7zS)5rwvs61y76d3?W0PaT;00$oa6&0&e=kpS7 zw!*?l6!{XBRbw^@=izpO>~6a-whJSSihEzi6g{LsLjR+Av*>cl_5Kb5{7?{HuLvAv z+9C8RvQPQIAW5a7oG2sU5{6d(Z#d@%0rl?2R%FH4cEEIEN)8UWKQ?k6B^hXZE+f1B6_H10>=KvR#3{0u+q` zs^DI~dEMsl0d2r91fCUe2|7QWzW)4k@5wuP#r^&WL=FVfSBWLS4fgHN0Xc7D?EO^% z#ycplMg`x0)RM0k5&+IvVPhHds)Mec{jPxAe6)!H#;iLe|0#v`|D zdczT^WgD{5e5VxE*)WfgsPH473!PvZcC|45?^8STZ0h4fyWg5rfe*!WbLRn8j9xCQm_vORFSu+dT4XjRe=! zU9%IDb7x;TZ>`qo+Ls1+?~l~3a%Q3KMsao_Ogv``w5dR7qMjt!9x?^JA1Hjf@zYfv zz9zJ<@^wGbHI1JFkB1FV5$KNv`0h^)$bnS}tH-YOdAT=#+2(a)>|Cf0A-qs4h4n_| z5#_Kz!2X{K9avQV6Up$F3dF@{hzOI?G?UdoLLtGRYIx)Z{`LDmRWT>oL{k*gwo$C7_%Z?oEXztDT2oNWGI zle^*Ps}Up>XA!qfTN{`BZ`vD;B=YRrr$j}FPZ=xT0$@JWcDPhWM;g4AXqA&H(HmJj zM%{HhBYTS{PKzAH8Wdx5R(->v*IdmVCxSh2pM_|y1Vn|2!h_;I;S3W)c}GJU7k%6S zx>Fq^XA&^y`=$07i=G`%d)FJ*yo#NWWG&nWALa*74rXw_GWt(T!%*lmRAC;5TovDy zz_-(6Wm+wCxXe(i;OorgbFnZIuHsrBa(~Za_&c!q5bK8BrVa<1jB?Dc|G{jb?&hQ1 zB91brlCy6f;XsM=r#=%`32{$Uz(eXJg$8qujkOUq)xpW*KAp@#)>cNVM;y> zlKwxlM=JdZU!-srp5ZlL#kH&7^Vw3_fQ|@{=rtaQn^y(9Of;7R31Rc4?v~?$;`z*T zkNKpcNuqm#J^kOnKR0}doR5dm4g~hF-r&pVLa{hsh4GW@jW+jzBWLGBuDLEbH1IX7 z4sn(HBA#?FvZ0#7EO~G!>msAF1k`bips}XOp<@|vjp`T;G9wVFW4_|&Rj0Hf9peo@ zW0iz6>F^zWvRzlOn0h0x;Qxz2@K~S$dA2><{mxgRye$Q_h>T%@IU-ybH4_{Jg6#j+ zir$@8e2bleA59G;>sSze=7>muJ!mjC?n4(77GWscm3dSMh6jHger9j!Bd>ni-a5{& z-ob^LPm=C^SJ?Gy*Hab`mo~X>%-|6)EDk5t0%K@e6k>SnCE8n6^pnr8#5=aQidhSHk$7zqDuAz`8*GJ8lhX{OQ4WCt?;lzKK}XmjBtciCOxC?5 zSqgI5brI|!KZ4s5*5-8rkRH8uN1&brU<>OAH5S_kM_5YLix}ZYevh*vpUd0F=4`nS z1Jk*3YMG!!^ori)bT<8SFF>+zj;LW;K*jQGV{l*K+_81*r8&}-ptIJC)4S_v);MUk zPaCsmB2ps{54NG_#2$o{R!`1j&by|@zfDZ6u&XUwz17aPbhms z202cD76XEBs;9Y9<_RRrN^Nqzb#-^9ud0S-2Ap>9C)D3mG8*HsF!%nu>}>6)wNR4o z;*a0^C_D6O(L*B$A$(DlGtKcn_;OT^GXt7qB*EZp*te!Am;>Ozf^mpo&?Y!sn6N?Q zH3kK6Dh6!xxjEdYb8m0lp7~0b4$J0hiEz{vsU#q|sM1dL zTP*t$;m~wk{&Wzs7)+^whh+u&^noCZX_{%)+<6M2al z4fx}RiW*T^1D-)>z0O+O5DrP}=C#oV_YzmKx8lthgjUXFM8PD}4G~}vh-C8(X;F}V zNv~IBgm{k#DXO0azVK_n+`s*j6dVEn_Kc{xR8w(92iV9@y($UF)c`q)g$o6{Q-`dT zkO2c(b?LQOYe3lIUT&3S2O!!~v8R`tl%$o{efL2VIs*{~C) zn=rt(fTqCd9RLT~Vh!KVKipmD2Ap>yZ0BEbx*Gu0D;0P+{owmgT;8iI6xav6^>Zgc zB+#9p<>zN#Ea2P`R1arFJgl(nOAtz?_^O49sr~SZ+93n!ANPRiK47F>N64gB^%DN4 z=A?U;KqlJcuH;~1s@(*&j~H^mms-@X=W^y(q+DyT@@SK9uv+=&@m4zl0IxspAp&R< z-hK{{2LP~(orkKe6Pa|0LX#UMk%jf&`d7^8bNngdVnT`ImF)g zTsI0Z*!RBdze1fxfxOx6-QN{00swy|CGaKa08=;TO5@TZiJ*1!55_T7oH-rFeCQ3a z??zL=T>}Sg(%a$Md8^{iJ?ly3<4hxzC8+;u&n>kALpwa@nCe_oJtAQ?Fty{fm0$}c zy`qn7f`;{5G8I0Q)9OnDguHz0Fn6 z+)P<{C13&on(lWx%bKN9R;s|#6giIc^?9OynSMxNUJp9}0JK2GkV?3BLtDG-=HX`X z$Fab@{>cnfIc1r%Mg=_hclnZ>Id7P6cU1q3D5cb0SG_Scc7?J%;DFj^N~2+WWVcom z;sf4~>Bqczy=M8e>704*YaQ;p$ME4R08rqa@`+qYy02$uW(Jie7|VB?J!)H?Jjk3G zx>qBC4R!m<_F?-HT8a#B5+ucRW5c4)lvF{7Uc`gLx&!ua%fc`LJ2nHm6b4EzIFUL7 zHd&y}KUc#rbB1bp)ru91uyCDLHm&`s&vX0lZ>4W<4EU*`Tp95Fy{Om41_hiO6S#(0 z`a{3&SY;kko#cBl-}NQ*)%(K#+EKi3Q|mx85^&?De-X}Mzw0qE25yi5*Jy(2u`yB! zQtKx~X)PXVd{i*`o-OeKok6z-UDlK>3L@ zB86r@%s!z@$l~ol$BS)BhN28b&p!a~)?`YeMU;UF9;*nF7QjGV z&W3_wXMf_c*LtJ-HT8&GmMwpyBM2)*9-Cm^3+O(joE81cr$>Dmt9q?O>qT$qYqv7z zQ12*HzMN8j+%(viY9X^>m44`~wy6U-7<47U3}|meGl?VZ?X|Av^5-gdxqkGV?_7Km zFaJhwiB+aMLTlK@FpWR6W^rQw;AHegI=S43MTb3)&g=>A=^BmhLHTEpo{@+0L`Qml zFfRG%;xzp+!EBlz%zGR0UpkXdK>TQ9H^1s7hi=@W?P6gND&+~3k}q5l0{{p@S5f&x zUwk%@`K`GH!uN~>6aLlj#`1pBU&sBwwl26Huf=d1$Cje!mThbx!Z297GInw?{Wee+eBnDNE^Hj zrKjV7Jn@Ykdvb~rX$NDM4V7$oYP$`Gl&%;vojC`2!WwfMWOS#xcb9w>Rvs_j7T@W3 zba$|V%n!5rh=;P+k862J>NYvDzXKB(Yg=&8S?hPL9#Rt~|MXjWtF?S*n<$BNFyC%l zZpvZ%R7$ob7I#e|aUTorP0GO+*G4GO9c`%e5~Nt!-|*zwv(dP1$prCHwsNz9$Y~HeCK}uNL}5j7MtpeDcQd0I+bsrI zVHLrWmmG{zgH4a(N?odseN;M&0t>L&mKB*eytd}Q{#6EN^a~?f1d|m&%N>B7eiz= zVLioMY0_ayTwuf&^ulXS3oyfqnYOX5^bscHUYm&m8s4vG^J7`6IJ$2y8nG->Xr#1W zv;%7M4;F1+ZxDeN2BpA!R?T+C+H##TwtpmF5e=8Y7_VuI#iIy%49GaIF9A&o8`=Hq z92^L6<<1buS26~UNM)pYoX`UyVlE`T?gh)t1C1Z&X7B{3yiio@38So z?mW2C;Wa3dY9wgqH1=WEe?n>by7^l)TH9+rdKDxfIB9F`^8gg$CSQxfb z3?c7J3DGD2k2ZG37UrfHEeut57qU|4;?+YilAa!f?HL# zO=0q4!Rr%$T~rihns5A@VN&4mzlNt;Q4a&}PEXS(syDSMW4a=DZ3@Q-=uF=1>qzf> z7hAF7&c#68K9gC?wX;!g_sG^(h<~;rBeh=JizIPip)+dJu9m7jjRM5w3*n-g5*7^uFgCzt!NB?q2Z_ zKM-d@c&v%uE8ISpnVtOO{t{3^h8{{^y`BifH8klUCv>n7~lR>Nw zjE2)-DjnyI!p*_DLaG`4+qY@MN!rD^AC)N|SYSk>TCOqqaT$@z{v*NyOmU~iS|}sWYgNweh}W*e(FOtc_}9K ztBI%`F@8NaaEqw$9(w3wF=0V4M*8&eE#RMT3l)h5>#?LHnECxE6FipCg(s?8uRsEF zusb{=p+J^KSeE}YQ~TmPu7dLs$p!*=Uyh~A(~hT+H_So$9ADiK9Pg;#Cmu)c%y*<*J=Cziu|km+}+ z3Uqh3!|!!cO09BRws0;;lamGxh7-*wV5>tzbbur{F0JWL)X_j9=q>**@wJHp5+B>w z9ygC#10=LprJ0_j64|x%VKZQaFnSfcQl;Y^czLY#n00qawPU?@?w-5KUq$|sfbMVVH*UgDgkSIJ>VEYnuXi;5eo9!q z&3E&;yFA<48?wJ-GOrw#T$2ZJS9+H#*v~Byk^pI|uI>B;Gk!UJ-s%8J|9fZ=S zAVdh^Cqjk>2lW&0|MYw~G$ILYuhMD%asI*7i0ECm5&xP?4aBtGG#jruxjZWhC#Isn z{9RzO?wjg$aW_HHXjkyf`chAsVU*_$y8c6?JO%Xv@?e-}OrmQ(ZjOa);@)B zeYfS>9FN>k2I`+=s1IXKl5=P)5$RJmdQ8h4QQJ*6ty~p;DZ}o!B_7TjU~=4lP6nhA z{wkjuj(-IO#gN26*AIKm73Tc#AthV|7Oh;J<*5>){4NLz874xgSveu$8iuNaoUkDUsqEBRu4>wKLYLKMN8-$Q1_(x=wVS)1j3H ziCX12fLRd&I5LpDJ~T<;kAxntFi)fhpE(H@yrk43VI_r-g+q@LA*FW6h5Kb}N|Ey{ z4Yiq>6nOyN73V8dW^X8qmFh|xf1m}3lU+k*F%_Kg%ae-c1q+U_js(MOA@7=F2KjvLk>>t!;?(X`#XkxH2};WO`_SdHh*RBaR~WznRNf2}&( zgJ8wg(T^~oKMD&Am-{!QVZAH_b$0uxnYk48uI<{+8L!Qu9I8z*AI46_y0X%JUd()7 zh~9yt9($|bxQuVA@_$K5Z-qeHVLeC*e=|2{PPHUXHIE=Jnkw{fN6q~8`8!SbSY^Hw zVm5GBI{YR5_u|QMKCjm=?v08D&`j+;<$mz(=zUWvu*ijjDFdRDAPDgTYV1$Z4Yz9% z)XbVIgS1G&Mr(!4FjHD~Nq79M=F2tO#uD@t8BQxcGHx8FkJULzadf2BxIhZ0=Ks+3 zj^UYhTh?}L+qPY?ZQHhO+qP|1#kTEKtg2M(q>}HhdiL(_-Cw`!&T-^V{v^4swdR_0 zjB{|A9ibYk3icBfdi1<`$NpXj2m3#IqqhYIC&!&Vb+1tHc{010vvc&kMEiR0&-c0^$5 z7Y4H(zlTTVunsG}>aqKloin zWg`j4sb(V*b!pG~W49f%-tA}lPjFVN1iqS$4-ay zLNkhhV;MVID$=YB941`fn5wn zu(TK#6b7w`llzN#%?!?$8pJtOH(a%(`w!&qI{`vnb6HXpxpBp$DG_2$={czQo7Z@p zhWX8D5?1ku=csTgP21x2_WY3AI(LE2pz<0Wm$i9rE@EVYM2N6xDqST}R1rF-KM@T8 zE>vleg=#qgU5)!!8WtLihqU4kZCY=vP-yjaJ_H5=e=sBzvF zGj#8NI|%-fabzVpAYc41IUGbL&yvGg3-1TWYN$$B4%Rt+y@!AiExXdJ%7C(!MA{1u zm@igB!Xg-sSV}yAkG9F`-NL-Ju>{6uW4FJdxjOtvg)Uly6r-(BAXS`>fg(im`bQT;lZ`>1guI&3>pZTNnyBW z6^M_w$JEX%qsK1(+VZ1jx1Q-?#=S0x$m9E{WePFn*5>(Pe(oc&bSx(rS(KzuDi}_= z^i2v@4O{deR!cC7a7R=0aB}fv6->3bT1{4Fqtc**l@vzuQ?*F69R!s&_MD+FhB!Nc zlkjTFc|Jys)dAdMxK@z=PHnJFkB)&b6j`KHZW5u!+p5jL^DhEs*Y`zNMtNpC|qnBOgJCc z=rQ#6V_-aod+5=*PjoOcgh9MP#DX6E`d_+(SA%&_TD4GlrBKjiESZ{3xUQKUQ#chmRqR7yrWeXh5O$o7f)0;NAE`AmjCEtm zuY`>p&huONV%i8x@|9xgE{Tyzh>@wEXre3)vsE%oHRq!4s-MeUsYTM;M1|8^G)FXH zMrcIDR+6fEzLUh1!%9d+*0yF$XKlOGrx@n|?=MVpT2_rM@i}Owv{NG3WOE)C!?S|m zTkIH@=zrLC{jSgRpHm9hi?H3KpV37Ld+tc9;T#U8#n4p_g&d%{&?C6vL@G`#XG-Ek z(CRM#NZv5Sl#!tsA9nF??aJ2~tdV*3)pDReZSf0cC~J?`#+w#t>e{GcXSf>q_2HR) z-PA2w;Bhd=|7~639>*gw=2TCgwVZA$1S~-}9zqL;PqoUqgqf*!eXx{$1p@I7DgmS0 zGS)F4BQ6LyK1hgCoJn&*4q~q4T%}ZiOKUm^Sh)~ht0*3;0xvqplWSsId2`WygfATM z9KnGki^J(ZgsbSz;K)+MXa(m!&SN=`rCt%z8@f+!v=7%uhD5=nj%3FqjP2ws%gh8= z{miR0WM@;hpmv_&?$h+hVtC1C9NzX39_M-zOu?0$xM!l0YPz6xes5UOI zlB<@Viawh!$IYj3EO@UNap;x^F}(m~gZ(7R4rg-DSa28NBQF0b`ypih!A{P&w=pJDvs7$?!8*~PwQjIl``%dfFyK06ZP9RUc}vbV z=*eJd4_2RVd2FZUKwa090x?i*h+?Rt43zqXmlxOzI;|PGf7o>Y^5Cc8La0e-fKTc; z*=E$zunHMtRaR@xbVf%;ce-zQ@;e>X6jep#@JdGzR9U&w?xkSKSOn#~eqqn?L;Yp> zTnV9t=Wi_@6F!qZ-I~wl@1%?$EeE;#dV9YI5QjrgRbCjGxwRF1g8F)lRajkIF}(*a z;uQxInXhn)*K^AGT`e5-5&9gsf;UPMRj$#|R*(T7^yrl%cD3wI*`;y>l?JPRHtS83 zO$TmMZaFTA4t$gg7?%(|Q@n)ftAtrhj1tVy4za@#ni2XDgA>T-_1I)mX47f3yRk_d z8k?`n-O|Tvy^3#S52sWLm=%{Htrb?ExOjrt+>WhG8igzIWPc!kHp9b~v{07qOU_t~RK$Kz8jBvFAJ-@NV<+ zCUkkkw&U*WUXUV05walXcP3x~f=q8=y*W2{kROz*7>m3%?$B{6^cZgYzJ#opdj=vS zsT!Gmaom)RKn@l;5m`aixgjB0iH2vB)p~S(XQ$MDQYWk)8^#;z{Q_g|Tf9|!OWKx# z58;}y8Dedq3Kx`WIjK$#4PUO(IbxsFqQN_%YGIcscw7jG+AhVBu`^C`8${Vjr(qET zHY+fC(26zho+B$aS%-x(>6tn8*uBpu4(K=aLs^Tx#L(Q0VW?PX(iWP{c5^i9gv9&{ z&?2z5T(+pR-?sYS=Y=A=8jS(m0MO-!nyS1Jr*wZ0YeRf_jHJtN$ioNlxGug$j4 z!C$f$b)NQLC|!0Ran${6o#t?Ytj%esnumDo3keDbFu&Z7$e|JQ^M@Cz2t+uq+M(4E zdn0|(3MkqNR6KCByPfoM9kOq68#Zxp{h8KBDgYw(dQ)yd9l9<%n#N93bZbkKTaVK= z9<4QP4m}vHZUI!ljuQgXjK!GKK?!s5B_p?USP6-mfs~6Qb*Ja=l z5->?M~GI^~W0ArYXk^D~(@pUsh z2ONUSrf*DkKw`5|o)Q(-(5AI&>24q*hJ@-4oJlTYBlfP-0m_XloQ3SSZpfzG6`P1k z+7eC2m75hEUfpMhspd(=QC*Q^6uFb^T&=i!YgDv8?kHGHp0H9$bU8WB@6(p=l-O)+ zY>ca7HD%!&`C#Am+sZq22vC;;SX<0R0-gAcxTYj1^5`yH8&>R{I_2_V?;V5kC#Ieq z85YDar+$gamf&^35?xl!Pii)9DV4v<-d9gHc5eFX`V}Y&5T&zrtMq0Wg=3p%8buO^ zV}XoaANo!v#p{~+s>hcX$LRLFv8vj~wKvn@KC}ntH=_YlQ_E^K5VHZ< zRfQmf#e?CH=d1&wo1&tjaU4E~8P2KM)4(K=wUwt`Ipn|1$bYRU^(!7W#v=xiB#%tZ zlLny=&lHZ?8D%S!9j%3iR<^GtNv*2vWN*u88uzw^-du#ED@g{OwxJGX$sc&B#ai)f zkjhLqQXm@5WP@i*aX@yw68mL!tocS8ft6Bn8n(`zb4f*1LUG^jYpA{ zZbXJ;lDohr!Fp5?(feYKfpfy^qORDostGyEbh`%zjoaMQFB!64^c7}fk;K2M$GX^E zV;6-^1_opHnl=O44GnqP@j{eRLbqpo4|ojMPw@Ty0=T{f1%Y_2!uV{{3wZVM2LZ;V z__#=Pp>4gk$czcj<#IT8bMFcq4lp#T)KkearT(x_AeB_{ffV3(_DUZb>;HAYd;YjR zqz6N5MWe8u`Zf30ox5V}tqw34l2B~|^l14S&8}imrCC!JTgR7|(fug=MgVO4nPYJwTow}A;V8~keCI-bInAEs7rsVWHpEI`vZ=+=GD>P9c?x>g>>?jf*q^Zyd3V0RXghshB=G#%HIUc z*U{wCZsz#ipQ@ZUv8raxFG`{)uo$zflR5PnF`0fJ&KqoOJ8bV{ibEeWk08DTSAV%_ zMwW(9LDahhdvu)ds$SAu@4B%EwUmSGonp*oqMB=zDA63XX`i3UxYnjj`e9Djou`@V zl+I2hROW;Z_byB;bZO1}tRDPo%e0B;ma*H6dvU4naQK^H_KNxiv`o;$4fs_*RKA8w z-Dn$l|8;*Cj!RSUw}3QLnD)<4r$@UA-A0;%AOThE0py2}!iL9;Lk9cOIx(9s+<26w z^LNY#%Ch+$Mbo*AeoCDQK0OMad|yZ%Xg)#K!Y+Ex5>r1^LXQL>assUeib$5Ir95KR zQV&9Ty`Az6qWz@rEs8`{-Iy>xqlC4Q$f;McDT(#7qP57OO}&uO8Px1FW4kHNA6)l- z<_**vpcN=DR0HW_j!=iLaw~|N0aIjA(p&U-iJoKq9!6ps!&11*1dE_RSOg1shkNTl zPL!20kg>{4wq%(KMGpd=$HL69LWGb{Y$V=-H5|OauV6^U{g#t-jlu~&3OZJZ)2K&C z1CqCjik*vPQD7+H5PDiyJcsj|k}?ZX!R-iXvx}{Q3+pHz? zp|d-yw3OyrHEA`GU_jf-Aeu@g-2}gU2=0)bm^sf`GPt-gXyJU2^`;3(D z)HM_fB)Ylt>PnNqjX;4hW_&jXv0M}Z>vLeY3G%q-;YDp0GLlP7b3QTrwC4))+Y`5u>MT@m1myl2VWzS?}9zsBg+q&9cxOE9B`&wf#Vru`x5Pkf4;3>xsX> znT%$kMw1&I^ZVMxH8rP%TLE|90@O0m%BKfgBi*dC?FXhG!Gf-BA1&*VJJFY-8$37MJiD&T0#;I(~Yfl73K_+lJ zXZqmGmRHpmh0kU{Z>F1{SDdHE0q%rG30;8DqgsehCxxZ~^SMAJS06y0b*8hP6a_RNR@y7vKpH zn}eY7-;j*CL_DUXxW7>f@}bY^Mih2vtE^;JX&3%DOE_3jED<+n*Xt|&6J!3UbjC|0&WBo9e^fZ2!^UErEXK#`v9tU=R#XF6FQwjNCoY@~dRDVT@IL&TYs$J~ zjRR|#{nlkJUUZD7@h$-V;4I<0ku{-rOiRw0f%Jyqd-;=q@NOFdfgo80ahCI$PCNp- zf*1B@#dAIeuc7Pt=Hp3(2B*YbPsWSj$HDG9$U$VzBs-!D?dzmVE=UjiX`T)&%_q2i zd3jy0F@=ras?!Sl8tfuLCVFztmW!P+B(qH(R<-q+T0#xy)ee<*I=EB6$#P6F*rbpE z)Cn<{C!b?+43@RX8ZdlW5HQR(pn-}yJi{g3&~3G+w!WvseO>$ zrV-(SxxG;=v5{5+s2HMKWL%Y{M66Zxl)(i02jDFU-yKJPooeH?)(MK&7eDxMj6vYo zy#N_iz(VxSLG>#2*3yi*&hVAYwR0kb+sv{JZCkGhrs;(PC?vi$OSIz0B^^G#no}~B zS`&l#uFZ;)yF(}(0s;cVyS$_UN7Zxk-eOBe1VfoFPDd+tst0jm%l0AfFH7zpbFP6H zQ$`@%w|H))KurvEvNVOtQH;4VyiCG~-73&+&VVIgul@|6uNGa1)J>W=B52K($5)|k zqrgDy8FyQrI5V{uUh_i%m5+4$XnpY%9WdZGZg^#->wS%YHCtCUI;Ao0El!kn&gS>A z<$*s`G+AI?KbQu{e%CDZ>!6MQ2u(pMkO8?wU+*=V;`xvLloqa+g(<;D@d|t*y@GQI z73qmM&bdOeDAyg?1O$*GIZ2w@-WSl;r*2-jIt~!5z4$TXzVP2r5)Hh?UEMK#>HPv5 zU|{C&4t+C0f~TG!N~?^=Lij8I1r1$C&Svf;IU<8S2KyvPy6RBreCY9Siql`eV@mFS zxgys03=3rb2n7NprIzV^*&I@WVS!Yum$O@e^7uhBoFvlw#pLDnukh-K6Znwu{}rSP zC(z}BmqDaL@1T1T;4hXS9|%cYwV@Z&sjg?YVvjEeqVjIjTpRZNWKrJ1px&)-<#>N0 zb^S&$@-DYAlIwDqO2{C3FsMEGEaNbPfq^91)QJ;F9Tb|wLW<=J7MVwGepMvbLo@QDdtPhm9%rlF z{${NSK>q~wWJ8TH42UGgSG7)Y z>2%yW2)f&JTGI#?9=s$@5$roEl`?Yjw8}CKD(ZtIQviqe%m9Il1V6@@wGL z{bowt{yb>B2i`Exe?@-xknib~_Ju;|K!Hubs-#boAc61;e7lGbmpzLANai?!Fj)NH z#Q#ctu+v$g4|vX9U^X~wimUrUIL)=ssKbC^Ark^ao0U5jXH$StVR0cd0uwWH4@zic z&7n@1?l>^jasQ~;Uh{!_ZR#RQN|lfj$NutOzERMx>e*eHixoyVM%gUYxM^ z8?h5${T@XBeq{<8ks&{7+YH9_g7ysXVVaw$ShXAFT&WEDtv3HWa#7edu7eKKtGbg^ zlL?R#HPx>(hDhY0k&O`c^gsR?-5q&-FQ#a!uU*p%7hOx%XIK>yVj*GxFXmAe`07pN zoQw%BNT4s4+VIg-Cxvp{^HAdeva7O)mwAwI!F)1~tu{!h=}@izKo$VJ%lUvA44vO< z?i05i6*Iil^Il}Q<;4F5IU)U|u=VzKV6Lk8N`i`9OAL7u zba<+yTu9pd7s^x+F!)WPsXsA9N4BY|tN?2rAZ&Z){{86NTDSEwn{uLkW7bXqECCuIJr+yJlEhUMlcSzOrH1zX{&-mvPbOu3pOh|Kl~>(FwM zpy45;dK*@sla}+a==vsK5>||OC!sZiMQ*8yNYw1+(fWiwI;MdvZts) zVE#UIe!jFwL$_4oc=R5-Pc8{;{(V6zeItSqfW1x_hvBoqPUgpCojo1cbRH)nS)|nT z^~Vqi5mC(Un`@<|uoO{@pya{DoGStt;h-4_SvMOw=rLC-nAH3h8>}|1DqI6+ViHYa zY=0475Etq($;q zur*C#B(EcfN(XR|pvK)0OCDNRrFk81IzJI2<;%E#cC7y$L8A|d<8tfVCJ?p<{_p+# zd>GaSlAWoJBO+%u_?P?h=(pax9zyr5N~6papYjjKq7BcssS@lV5u)VvakNK0@xK!I zTu#JiXCycE0O1a({{YHbPuUkP(*#2C*cJG-laZxbaj(1vDfs?i#i(J$yCQBdV!W)v@w8+aw2y_h6lAgo42` zz%kQYbhVJ@pjTg}8DQ1qR;V;FV}!+-z+yCMBgK=wz*J6i?O$0{z!j$~?aZbE8XUFm z+8S(breAye@rDVPfz2J2NP+DtykZULT%!rbDEJ)Xb!n_Em(m$;5bvGf_^^?O*i&9( zIvQrA9MCd%Z1zCFRbdV@3D(wD5m|{k1iGnOaL(Jza{a8zLVm?U+5Ss>4g@6I=8y_h zC|U*FX!oiPn7cU+jex4yV?vk|Yk&d#pno)`Kv?GeH%6+!qU%;ax8H@SmhQJ&^H-V| zYc}TY7&B((o-{u9z=;A+Oyq{W2-DOt?TAZI0t4PVf03`s&&$&U+Esq(JLxbG= zI#G3`ySFP%>_ccwJQpwDAVsotNi%0a4$Z2i5CCrWkGlqu?{*zkf$we`ma%70H=qu@ z>_9l|l3UP&aM@{!3ox>FV-*tU{*V$BwPAr-i(x2^$Zyr4s*jQUjoZ}BrO{=Y#*((I zvqDz>@UK{mj5NBw0*gM266FL}*{QO?w5jIKA{YYa<1GO#I2454a1ekz=xQwJbmLmO|FY}{#tI+9}J>DUgLYi8vn}o?4#cECT zT&4poN^7&kz1sWMd62C0JKwp`ZG>uzHZ z5$6)+4u>Y_^=}-)*7CGD9)M{ip0WX`Qu6+WrpvA6PZqB7K!R@;0;Mt(O?gqdDQpGk8;WVIgL{BV@i*xKh9PT)sb@^c4^?-WTtQ z*B^5GKO(0Ibp1A=(!K?K1wIS}g+##PblmIjAdF`izIVhfggulD%?)FfGE8wl;*)np zQ#^r%PBbR)Fe*?y;L0IGvWN|WNY6HlQPA@_VC7pg_27rU92(n*;4+T?iiiWJ>G*Q7 zhqO*zW#pLIb1&V39m>oSWom9@W`fD?@-8=X{u}h<`flpk1=|CDv{lJjtaN4SdZ$tI zf+g%&-U$9rP;;*CcJWB$aS{G(#Kj0loC!RtCCLceJ}JOB!+6p0<55a{PHv;|6aw6B9`k+ zy*t`Ae|%jwndks4^o_hxP2TU>Zl(jfYp|_T*nJli;ckFC$#(xR%Uyuv`w&-xCEgAh z;Jlfd=I7ZRmYF?O_us{6ADCjS+OJc>ibGGeqz0T^AI$6~qhdVVcEDAx69^+uM z7On-fOHk#uRNmthWX^tl@n%XbJ=ebx=8u4`*FB)ZeyYG+2HIxAfl?4c_h}YLI;OEZ z@E!*Sa)whzXpJ)1!UdG5Ktsf*QepK^h+(F<3@EgoCXfGBHp2H(kNop+{!bUR?bt*7 z0HV4hV0*e{uVY98<1$?CA;q0}9#It84`n?Fh%o-g9FPuu73S?ULw}!$z6V*! z#)3W2qFDekt~n5|Gax*GVVg3p)ST~nQp8NIo3BCj#GcNvREH_vjl}- z1J5f#Hw{x+kPoW7h>UEXRoE-qVL*d8aZtuM31rgQq1;e2MG3%pgG_XJvlako5efyq zQJi|-5QQFh0_syjOnYg)C(<>#1Utet=oqIW)K_PJQ+RUSoI*`U)TaQQEOt*|!(UTC zpdYF<$iLNHC_x~?A%8$Hyj3#>w-?PoRnyTr5FE_9P&6-GPX(B1(VSQCU4hZa5IouR{-DCyF3>7Yf(!z7;5ke}Q&sUVM3e>pOh-!AsYXG+1 zHKYfG{IHF4{O}hPB!Z1ebe40TX=%`dYSeP^PUie|@E~27AxROB4Qe5Rr8Y zD@_FILHbB|oeY@86w4Zo>UmL#jhV4d_}Q4&b!-UWZWgX6VJ}Pm)|vsw2#G~4Mf)|3 zF`OMw^yrpm)}%g;`WoyT<&uKeijGtGRJd2rV@ogg&v)3eEDSq{&-=44j2PQ8ha_US zOn4H9_qP9iXmXeSyp+8*Z6UKm5MOw9Sr$a zS@>|Lzh;Gt3@Y6q2wJj+fMA*=p5OdkK=O+?&U(^Beg3je!D8;Ag%h$$HpBp0xotg` zYRX#T{NoSBzLmgHAZS!*>{QNy!?46s&fEn>Q6eC)K^U9FYkt=VkhUhoo77!4=H1Q% z+nA0S1Ty(Xx9T7(+X!VgPz)Y2Ta&q|D3OXY54>^dVwHPDhcMMr&d33Dqgo*%SJ&E` zMl$QLu@SN*mRK;9SebLHhB>yo`%1unk4BnUJ;k4lq8~X0TleqOS5OaB2j4zIxm@4e zs;PC@J?5Dk&3$bKaUl5b^jnkZ1u*@V9$uM(2XwthgrIHRf7D7xj62e*wlX~uJ-6#; zeh0rP5-U;eh{rRgA2p!B+D0K-Xk$;r{}y@EemLe1rE}+Xhs%prwH5=jv{sr^_9lU+g;{AccFtdY`qq%JczUKok?;6~vFOp&59XrQ=r!7v_ob3xqR#5cBw+{mU zr@II^*Tr=_hhY98fpXY+K0_!aS65q$brt;S8~)+w{rgCb{f}$v%?YhO#DDlMHOaO| zFiX8|%H3m^HA$t+v{MESpyZRK6RFGnXS5T?4}tDWfUYZ1KHjIEL zPsu5y$)`+%gUcg8(UoiVA^7tYaHPE|?GT}}i5ZYf1RjLpZ3ifVU6hE5afho>DnxzF zMZJ_oN9NPX;2AUd2Nl`M!_V-n&qfhXDBq!@imt)&KpBEerHsnm@i8DzY(jX!NG6VC z=n#tA$7%k_q22uVB@U27i%Ryd99oAb(p>#WIHy=5(2Z6>qz!?PL?ZRw@(M-o9r?^Z zRr|kI%d5isN!}cgvQ8Y@k!F*Mn2q2JwKdS=QHj}zSm+fWOV9TF96eEN4es~K=am;< z{MP*?`@~`UKJnB_xI`SyGKwdm01C^ZP&O*jB1bV~Ik=|b0l)yE;-V}$JYOlxyYV6) zB}fV)gqgKGoa62~Eyrl5>)ZOaRUshfK`VX_Bc}mPQMs)|I*g*J0-jOS*x$|&<0Yr9 z2^w~d*Xato-Fmx3r@B%^c z?eeWUuq*Bxj0R>WSp2kK$*S@<^E5)+%M=(38a|!lDC-WKgw^VrwWYm%@y{GrHEFkB zE3soOY91dA6Ff654t>|rADaDG_MkSTTV!c75A^XZD`F(cl9>B9RM?_ZKnr<@lnUKh zP=jQfv=gfTI*d)NnnS8AJX2-wP0J=2ma)Eqi)U3>-W4MeQ|R|(XL>$Z8!N|i{>VH$ zUa5(S(rB2=5xmZ~-S9U1$xq6G>At|o4=?6XGkfym3D02BG2 zP5{W5O>5_UC*0qb3h;k0f1u69{u;#nW}0foj>1~@3GQqbeG{2QWy9Zk@SU7T6J$uN zw*F}R0bi2;`cBq~)?g5x028^N6)M^Wk?5&MRLR4AS19{XdX4t1{8?J=#$8KtY?CBv zGI~#yST-wzZ!kS?&vU8l3Eg&>F(UaGp{MV?nKT{+mPh`a3=zhJR!>zNMV!w02e6ge zqq;cHN~409Zqc}0Af{|^e9b!VuZSkj4K}lE0@zrESev#upTQ0|<;ul8z9l6^rKQEk zu}cCQgWQdca*EyE4GXCo1PpLCQM{d6MOEBsg+~KU$nq27=SYSHp4NL^&GGjvaeeuE zPOW#5i9u=H<=nO2+a%q;&2j-H@+$` zEsfOM-U{S!U#((-KP8hxFG{(oDLJJOu$1*l((_@m*HH0mH~(t5UtzLmy$>>U68DuL zx3GY)wCD73>!j;_Qv}ycRdp|BtSQ4IzDc-~I%R6SJLvOQsMMFE?|xwAC)#}_2DgND zs+bK3xIr4YA8d#PLav(+l5VAk{7UUe#o}KB(DTh=o)kamglA<+ZUedt1YHHpF&>fm z@%rFC^BQ0147a3;j&PhQU*OSF-qVE3S+3|_QXv;weV%yA56`3SwO$RV0)(C${S^teuyIn!|YM;D!@wey_ z+!M#V@x&=p6{+J`MpH6bcySR`2M)zGh&#+-{WQw*IT_+>T)y+g<)@0J~@ z#su+#&&&|(f;&-iO6Bw+0YBEGG&=Lma4LDS1)P-DphF`FuOaENG&w!N{?H_2Wl6HM zG&k18v|5~MORvd((7|{5-9hA2zAlKQGJY*rPM7Bpfl7A+4Ia@(%e2YxgYimzXOh`y z4_yaBuemzvD2Yio=KfwS?`yTq$j1q+0RQ}%(udV{($cNkCH;kn=XWa6c%Cx<_}&=8 zVX$YjL@_rfuWw98qo?fa%G1S)ba30P0w_8MEl zGZ)BboH2WjC#kl1knzA&_WIXRNomFy-*|BUOPGZC_T#tNvRGQbj8E|!;mxHGP!Go~ z=fn-|_59&Mb*{g>`tUtM6p=a4n9~X(b#?V+}Hso1ZLt~N1g(Cr^&gqd8UR*F7>am!Ix^>GfrRh(=t?w5u%v4u7wsjxa0e?zgK%Ew&{f z;B&j4&1+@pzyE1-pAJ=Q{jWCnkOy=gcq5=8OV9ncF$?(V4J*6FS+t=SESx)@eTJ7` z^b^ifDWaIc_GL|$9EF(Ti5rc>J+)D;SRu(%anme~Az%yl(2#3o!qoG5tPjl;TgxMs zS(o`FJANr=m*m85j8i*u-0W!Jk5Mq_WmrN{%EvUy&|+=-*6iQUN#^s=ycy`UYpdYn z4~Jn&PbL#Osi#V41wML|Cq`OEPp5G@4JOKFrzg2G(u>)l)Q6z}!_sL`DU?M2tA3s(W^ZN7phrc&HY}7y8 z0qE;ONMH-Ei^)V##pIj*{7#>>C}RDh$yT^Q%aY;5(5yh5uohvMP6%YqOX2J4rNMNL zTBth2v+&@X6mr<6$HZw@-)PI^C%0O;U)a`vZ@N~9fP`f-NnR6!e=H#J*qb;U5(!?T z^!7$WjGkE+&GeCufsV>; zW0@VnYaB)mPzkTe*zHJ`aC~A$L%)kyWg?Wyw%8k^7)Znzs|#F#1F|dvca$l#>J^99 zS_Xp&7LIN<7AH@AEWwLU1FJUTY-9Ug7o-2hfR3zeTi#DfT&Ni>5U~>vWr3oco{|1| zKMTE2($kp_2m~lY1_eL`WRY8%roQ2?$STKXEw>s3wEX+IQzQFC>BfFyWCb-cF)=Th z$<1hxlIca7CORBuSkZ=TPQq=$8$g!e60??S`sGlD*&=q}fvI9W>EUgrmsH-Mg#unt zHQajj!-k*1#XA0Up>UA^{!@Aq7QapMBXdK418G{2c7Eodw-mHG;++7?tU;^YC|rKq zZ-3ZWW}wQG7MHpqBd|a3a3IJ5KukQ7PyV9+CG9F(aHoHbKEE@stOKW7SbHbU21u#c zEuaRnyuBl|Zjv1P$h6%pew>MB){~K8{M|t;3{v^hfe#$SI+z<02a?M02MIWiTIm=OBg=A-GlsiYb;hEW%#gqK;_F1Kk8)sllean$fd4^Q zZ2;*IUolT_wF|7nIzWl_82Kv`=cIro^*H6MrN&Z;UQ0%+M>L=Y+nHcmoeK_@3+F5; z_C6|9GjzIVN}eQ6eP7=$-654jvJxK7dfwNUNvC__a%0EOwpmR};nloiO&A$vh2duf zK_HqYlg*5aT!e<8JQR;KSaebjSz-^LcKZ4;`n(7BS$UBJN2k2)dSCUzGnGR^z`3=O z?N0e`H$*M|ZRM7Hd0hhEmtGTUIn+;o-3;29cS@;{uk)d;!XS0b@N^5n1bb^@Mhc|& zVe_iEgZ*QLSN^*MMT+C?P07@T&U_;VT42r|c3E!OoLuwjm*?mSQY0Vs`t)a6W4V?3 zOsd_+SHwTmrS>qZ-{eYm$y=PxH`ve+qEGNS-10X`+BcF0?M1e-_fmoOk$Qvm-HOwx zl!}Kx(<^17?Zp6h!xb7;8mV)Ol*Q!ZeIG!a@1*6+?I(Xx=5q`N_Ey(x`tS?etw^$` zb56HFklQn=bgCxOt;~T>l+(0yZj_`irPJ*d zcC01=V3HtRw-Eea7)u-)ZDl&0Kl>d=4ih_RPUQ$$N}Dz7i0TptkLHZwve#2qu`BeN zosf6_y7U2+w5dA=vs5y@_II_p6g~C8Le8Jb!r3sasg*S4&bc?h0;D@b5} zo+|N^_mE@h)$hqM;)pB}#IJTwLRlc1R=k*@pR9J4xT}``6F-zRo7q^pt(3qIuS32Y^NAl z!}gr*>jUpa!kgzN(@8EjbKVRM7&5GI1skjrU)muiELKqr{_4SXeagBQaLFPmLE-cT(6ru~$zLsdlmJW--EM0pZW%4Q2`&Iy8HEC;D zRfTxXz=Z%n_{ux&onV{w%FS@NjJ?mEl$w~EYK{A!-A7Q3x`BUl)K-t}AxQ=A5_d&! z$3ADmWr4Mwv&TLi&NlTjLXC_D-)=K24Bm7X3}y#9Ot?r`FbwQ(4bjBVT>i52m?R;! ztLM4gQ2v+LC=3N0#=&-bUn5m;MciEJ9N$<I^=MOjzNu@*khGbrNjTTd^b;@8885dOTvyvf<~ z)Z6zlsVP3P$`?O-F4&N=_N&Cll>e#q?wtR}PA@H{e~$;o&*H#KVZTKIk~DpKH2!B= zTj?m3ugCk}PG*I3?ZCtfy1Onq6VaB19To)2&oN^F)yMrrXbrrOM`lZ(HQl_knZ-qt_)J}xP6el zPTiS+P?pb1W)}Uy7pl0;a#HC}!hE43Q#LeQX?dcR?W?*!6(BJD-2dkdQH3!wm?D&` zm|B~)**|L4Ow({M<)^^Pe2dGm-LFWgF&uRJygtAgb}XVELp>fyxQT_;(~zvo;_|c( zEcCH~Y{A_Y%f_V%HFu_8CkVf;S z;s|1Jj!?QhB+qc{HJ@Xl5v@|n*`HD{E9!~_OJ0>MRj5EF%r9iB0EhIy4Ht+bH?_4I~tRYcZuyB{Nvq8uy3Q6M1` zXBilWi*Trrq*E)SsnWHKAmd6TLQzrxQ?)7_(@nHO69l4foEFGa6FqbF7P3ZZXfjay zHH~pO2HnB_U7)}e^A7jxZwi}^Rx?pmiVm98XmK?{&gI|LM^RsXeW2H2*A6*C&+xRt zSwErG-VZ!u6&n@5Z5;PiSg5dmQzF&;#izH%nr}f1c(MPbi$EOq|K!meiKJ|YpZm$$zp5Ha+ ze%~d)j{kAkFj*V7m^F~7&}UzdOqk`pofN=O5yZz}Fn_t*1~o)#$;?^-99J$k`6iVq?}YrBR`*_o&uw4Bpa(+8Sb>i#s#X!N}{^Hn(*hd{U!BoNVTVJSrB*J z646OYKIu`I19w^M@dG}<8DYTn7Jp*yjDA_#YmI(wY@@ETirBOCK^_zo^>g_(xfY~s z8?^5z_wzDJKetW&lk^k0WiKjCJpcCVV`f3$z4LujsfsT+#VzdXra z+s?eORFuPdU4(VkOh<9wnW_&D1}w1X#JU}8TI^|G4rs2|28A7asC$;HyMEeM7+sNv zp0)yt{99`%W@D(CLsYi40$(*)s2pkCklbpy!IjexiE$LiuSds+glJAI0S=7;456=r za}9cxg-|O%iV;o6pof`%^Bn*AORz1%H{;^M7LVkI z49Rm?pz6;}Z2x7YbQL&Q6}yOHw%xx>cyIpesIAU`zc@)@0mf{C3JZ+XH~ZtkK@Gv? zm5UvmC33HvweHm;_pQ@bdvwlg>?NL1ByczM~@IWg!C;cRrvOl(*BnkF1^(q)nsyA41}dBTT`KiBvQ0u z;UqDx_k99?ja{BA9Pi&mU@yJbeZk->V5ASv@&xj$c$H4a9`nt{1xf=9r<#5JtA!C3-5#1q`Z*G!G1iuWIt3`)n+mhy2f#R-a%b5*M&-ml55DwsRa-sVp6=Xi?Xoh6|dWCKj1}MafBlNEA6?i zEbueqKR*NiCrZsfjijCsikl=kqPTb-toqw`_YdSSJB|Aa{2RKZfkE&wh59_M}5o4SnQ7P&d%a6U^ z9Kqyzgks;bzW@SK9a)EKGV!7W=C{m9Oex`gWPi>~uz@&l-y-uS`5Uk@FsQWCLmREq z&;Ce}GEtxGv0g-`bHfU5B!Jb!>RHbT>~*K#`-^_06M=JLf@Bo5C9pHZ-ELtz!t^PX4eXpGb4864gpVq z2vwW6OwPaaO8-EVzd5VltnzPKHj>6aul#%S+}imP^`%sW`WG_~P=6}AAsZJ;twF|a zLS*mwAXyfDF-46zArix_o3T8b#562k>*g;gDp~DLd2m8YD1g(+y>r63gA1 zxNMYyPL3vVXlPs(whU}b(z?7*9q!?#iv?W-RYd~|p@?2!%fsVfxHhduol=AI{DLE_*PEw_n)jrD>Mqy_FHoP zw-7o_%*hn(_7Es0%-O7APKCL}hZ%g&uvXt+XZ*vk8*y%oB3lGw)P=pn<(nuFHambc z1&ZlPq_eY$;dZ~pOdW3Ll?BGCwHiBquGTj=9R<=Tu}7`$4i@Rs=&Hv*r!P_`vk!yN z3EXlR6>%_!n{g@xx&z-zEu6$c+16vVpO6r!ZIB{0qNd4IYE&n>O+{1ROOMfN=*i>kv?i#Goyg9 z)FUtIL}J>S2jj7R>s9&YBOE>;6_%)R*NBm9V)NB+Tp)nc>UsX=`xT6&sM_B05nM0W z0WSJ`cx(XBEhL@U|IZs5sq^*$!!%)`V17$DNl{c$sto$mO??#~WR1J1B! ze9sp#3hKD1a52fydMq|UCTe#Bi^WZVU)wH5f(D`x zTMY-qDlD>_b5|if*6tFjvi8ZbJ8{44;LbdNv!%~L)pBtAwR;-(^6Pht{}0hG*>sQD zVB}$UM`>8kjER_+TlIu0wYKifMqBFf9oRZPVz!=Cna!7oMjQ4g$Dj0_Q!VBbZp#_A z8~T1~mp~BBs8*2yZi6C}6#?Lu5aryAgKEf#i4X3#%XC6av}}C>Xz#LeXupd|(1()V z1ZclU{-@kh+CgnZ~dLtq(R1 zu>`Vcvd@GAo#QsJj5B`c#M~7qG&FCKw2tgrjoNNXm1>Jc#)fOi44`3V=9ZFTWtps~ zrC5SE#>J?z8(jic>^cc^2RZ@Cp~K^2&^a3TJl?1}R9UB1t&WIpr>`4$J^Bk$a#lf- zG$eA`AmswsJ-o*bZ)3Z7F!WHwMgqgqT!tA1u@GiFA7;Sa{6{)oS^!VF#cyg1s5v4E zDjf6L(3&&EBfI20b-a;MeJM=JLh{UxJ3-pW62J96ex(m@xS~%sGrOV#o3Nu*O8B+} z1QPv-Y$|T5$*t;*WTF_l-+eJO!epwck0`jVg{SAJ(TW3lMerjrjIlP}%pPVnf_iLI z+|&1;FY0-gY|}V*<%dC>&>F4rs8LqVdMTs!kQ1p}F%6Skg)HH23;ibuWLfWpq{^pPhH_FR(SVJoO?bdFMi!P(}X((a-bX91$)32_pR%NdgvJv-WCfS z^IxZx30!D`wT;=qvVspN2$Q4(2vV$LnKm*TzY7~rvZoD)!z7@$ESm4$N}cBoZ>-aM zq&JyjbdfS4G3`SyxyGCN^uO8QP^dmmu3>|I-LWBig#~Hx>F^Qp=Hx(XV$D&K7BE0Sb*>HEpvT^&R(3k5-G2oc4$k{dYjuS|sBNnahpLD}! z7VKvUJ#$i@)&zm9${1}dUrbZp4+KDU=uhCBkcXoM(nSi9$rRjzCKzl&EiJ48R%i|N zV(@aBqQ@(39Zth28)S#RZsJ;Q3uet-)YY?je1$@|J#5#Jm0kPhG1-j1k;UM;m{4EA zJWjHy@}g{46*-~JHhLjE1^HT6Q=nw(HbKpp@t{dzDRw>(LKJaSYm_&N8l>v#Q!3Z( zYtRO*?aznMxB&+olBPa#a(7sD?uWK>`z$3gi(mhnEfIx|`kn8Xf6+fa`s`s(w1bW< zpc6h&5q3gIm7FZu3%%`-hRHCzCEktJnGU*lcSM3_+$xD-p2n(+EyYs*R>H2XU0XBR zM%XJw|JN2nDe{lKU`k&r%+Q@{@-KG=ZhMMXje9Kas4g9q&5$$(ng$ECgTfr^_O6SG z9i+}~TnrqBVVcW2FjC+@O))L|YNsIzJb!B25uh9q;Iqw5Y1tq~a5gHKhZMz^^GOV^ z4WM^*$~&i{20z;6<>>6l7Bh5?cTrIE#p6}Fqp-e3hU^r5zu-9}x9v=H-cX8aBSmA7 zQY}*9+kLe8%%9|9^r%~o2f1Fp=q-tn)?u98vXCj|OQP za<&Im{Sh=0KLon~q8)Isoy3;QZ(lo$=|pI*MAkWXoQZsFI9Z*x{Gq}q5@{$Lb%&-A zCCM0v)uYtXIM&C7$gXOQ#*R}FvsN=To&dZ9qx4p{3kXs$fvR^Kh}77QMxE_&R4rvZ zfD5w>p?1trB*o&G^i>XNI}nZ|oizqNJ+GOjMK=JPi8`dsNU8UMi_iYU%W^uy@)oAO+KvqH-r z{V^0%A*d)gPNeS)0?YtG3a;;XU%)z`#+pDqzaM}ij*#Oxf=nq5;XW2v#RG&0f)HYL zpl%96ih2QYQ9s7u?PoNofWOjpRa}@sAecmE%e@&=74A=ynm|iq66Hr2gG$T8ZC;eV zQPCt4>LpH@@J7N+u}}sz)C}pVVy$>%$7JiDr)VQ8Whfk20MR&9<8(7v&P|m-@ghMw zSfwI~B%F}99^ELNo!LTb&wj(e$rem`rJCR6wEv_Ea2D+jN9>M=VQ^jqV@nabi!#dJ zcZu}0H2>7SSn;UiS_ll8FD%V0tF-jfDX#fC$qYeiU6eJa1bthL~#hfdisXYE|eJzN-3Ju z-&?&N46ParBktkGwO^yQwzgS-f862SJ*%6#F9QWjP9k-+5-1Pp<7qKC4ke=qTh935 z%pbopKJ076J*~TkMB-Nlk*Cm33qB0jGlr#GNgMLp!iqpu1AYR}e8{obu;?Fe^2~3D z?ow&lU$r#r11}-HA(u*r*5T`qEe%x9)1v=gb+4~Mwdtxj_AqV3%!U+-3Hdp^CiqNt zo&fYMtIr)`*pnBk{D|G*p7~K_dwm*oVnc{Q02At(wFsNCXRhWz2c{pDRkUxHD`t=;n?HVa}<{TTmWjB@*t(Z2$ z&;*t7cvzju)|AD?X@ycbDO@8rjObAhevesZ|TyD2$#P5M+jaD;oK!P~ObZ3o8D~u!3%f6xPV+9^171Ct4Zdyu5 z>+)WR_Vp|8%IL;p-sl`@25AXhDOX!nR3>mNu6yA7D@J&Kfm%Nr60z<1%)0Nsv|_HW z5mRf`$r2XpMz5E#f&T&swYN-K-R7oR+PXj+@-pxfL=jAppO72mSprxo4naWJB-{W} z!WK9+0`Ne)5?D_h=QCA zL5TS#!Cm|CS(KB~Lf>M|b*_EUTHD1ye%kwG3;(eC)q>RXc&An|zU_m#y+u@NyjDW1C8iMM< zpprX`0aU;hZv|As2H+Z?)(1Vry2ApR&&i-=X9yf9DA-K}74VY*3l0GtgaCnLjf{@&Uf+tG z$psd;YL_*>!rL9@F_(rogKKjvAPuC~8|5C#q9t3Qio%Ot*NyqgCf!LdI7A#!2?wGC zhiGQ6U5TEKK#?>JbEb|G8j!+iAyabyNG@!fvx18xVUgsl!8MI}{@`!D`~2BmY=kua zq6&o`5*l1*LX^;unvhgX$m4o$;j;)5L!roaCA4FSiER9mb1pF=4We{jC1e4AgnR`z z3XKg#f^~VAN9X}JBCbcNS3a%q%cP&J%F${7L~ks`7yRkovl(t`r+nLV5_=4wtJD>5 zum0BCItCj#k4L6QAs2ME=!P#TZx@J}0+6{W1==0QEl|Jl*pVHpdh=SJyt%=mb*D`9 z7CzC}U2$Bh?Df;T2r*?X9j;1++R$jSKmlqH^2hl}go)bP=BZ;5<8O!=8L@I{)Tg6xb=eSxE2IW6^ahUb z2Z_Bas71)6MC;AM1a4;%)QK>EfgsqT;<$z!Jg3eCk4QW$4fn{zr+E{pb%T+{RH)tIyEyN2}?)=4aa>{lRxZ*P79H8Re>dCcusrx4yBdRf@&BigTNgzK-mp zl;%?So`Ua4vqdguS`&C%PkCQ52Y9Jm>mJ5)%83V~m5Yx!Y}@VZn71H}tx=?RW~yv< zP(e~?1sK{y6Ft6K@r_MBna-ebhIX`u@Zra3;XP$ZYO+o?2F{wZzB51#NTqDDu3Ozf zfes<>lb%%A5lJ!vUOg*;n*m?KJbKy2T6KKn4yK)FeqZ^pr7GfPzspwTf<1+Gx{s@H zGP>)auuEgCl}UBeIIM6y4tvbBAjG=#hGl8P4rfZFdeJ-q5S>f_$t@ed8vHhtIA2-kxQ{iOcuw^V!5qit5`Ea%WvQQ$O+)j9UBkxS@Gaad+zK zML09dR)V!W!d-g%ajpz_#sp`hb(&-lW@{@Arld|)= z7izK2fzIkycsBen)|>5VqJFNg{+X2T=Y15vnL4uciy5?bDEhS|fxXf1E5y?<=e3QN zDPL$+D77;F0fY4~@kdN0q6G*0K0F&Z1vNBdv)4ZJ3NHS@B?|1Pk2R(AsnP34IPe|g1!00ascC}3gawIdQL2s~x{fI-8% z*QG(~s$<;0fer*APEX>PCX+D$LIAJr2E#=>ZU>XBd&v3qdS|_yvYz(w^kceLxoj65 z&eMB(vrT$TkFf$#Vd)zHJ42y+Mk=J7W5H7=!2;LF>Gwx11|qfO?$y^!lBgmCb?m2$pXGsw z*bP3^l#t=>X90rI<`mRS68Tng}<(XYur21K~ID*WZgCKzu`jiql z;>?>PAVm=wDB%R!!jSZf3~``I|1_Wrj0s6HU>hzHZCgo`JrX;qwjG{%|o%L22>#Q1C*FT+c5ss4bYEVJiITc9?f@-1oGc zgzxE%?XC8}4AgPpJqn!Vh|oa$#y^^uYmIw_xvF}40g{*vc+#6LrXJYTpCC?MRwqnY z+4q&uRQWNjzIytSaMKp`H1UPY2Y&=&>-+}|yTr(nq^vT{D994Lk@$Jj1zG_5`fWrDN4?PNvSR_l=_TVp&@-D zJdxb@jHx`Sx+^9nL+4P{<-)4_VRW<1=(E)YL%c(BwTD;eM6rh4P`r}9;bg*GdZ zx5AT&hY4(IXQCuqYuLN@mOMY;FIq0&%BF9qS!j5O$mj?eDLZ7ZX6vuR$Lzn}0-D62 z(N7o`@JZPx;X7-h~$j0Oav$D()?{2kJ+FX&`h*BM$~NYP3)R z%SpnHI&GsUvcx%e(Gu_J*`lPEDUcxCNH7v11IUf=r}PK(UNr(h0@z{nA7AQHzta27 zHK=v83##|2Qx-qHGY|_8BCLS15R7Bjegf=hi4X>MFo3RK^JDSs;Sl6jm@tZwP{GCl zg>g+J6qpB?4*+JuzaFFC1%SHJ+Unl%MWoN@y?4R$RRU;V# zQ?+E}v{@2JK-MH`3xXCUW|}_B$%7Y0zT=i~k-idZc#*!y;3YOOi%B+Uiit3xuu8?I z1T;<>YY7apVE!zf7f|Ql4b=K7rpljinqI~N=jO(hQ`EEIk%|Jx+KNPusR^7L0U!W$ z-KGL6?>-)~edQ-QmzYjtWJGDHohoq|{_(|wpzy3p;}RiUfpW24{OOe_5AB zSQU63&n=MmosBJuh(ZKokK*A+{|+*<=cPY|HQu||`P=MJ;5L>jOAp+d4U`t)Y*M}7 zd{K-wUi0_`*hyE2yckqg4N$9z)+I@GqtiDPogL6o!D-vE_vx=Sd(=i1&hc)HO1>w# z$@=@(BpoaE{%@BazmM8dJ5I98h8Pcrs3%u&0?gx0AT@&u;zc z%s*@g7<8Dd0vRUVN&%*l;)`e;PqjkyTTO%~D?&BX38T?V<@13Mupa}u&G@3;qPTm* zbfl_5C_!#|yx(hdjWMM30I+*`Rd;-NzTU~#Opz{>5<%(cw>(#1_l@RS7B@}Dg9ca` z05!RS1A9Q23sOMN!}D1*WI*)2#4fyqWKY}JP2b)DG;bnNiO(NIt@BT5?j@*o%inR@ zGE-ja{0XdJBx>Ziys{0BpElcojK_&AGu4AAN55Ri{8g7_JRYJNpF@an zzo9I1gt!XsPRer(B2Qny9QD3|z2)y4Fxvv;6M)=d^y`R#+>Mz$QIKb=V)RdV!^|ls z4HTVgWY0pA-T;I?@NJ{v_ulvOs0 zva*^bHdd)3VkkKn4zdV^=RaRG6 zSz23M-zOj=EN@XMtybIFY6dc7Wxr`?4#dw$=KhrU$7 zKW4NW&GcHkl+6UZ_i}tdP?=b;0s=;g&S<U*bg4mb%KYg!Q` zqka0fMKc$EJfnxNFdDjkIt*g`6VJ^!ct~%4rNGM22rycbn!w&WaZ)}t*DN;Xl*{}e zLWE|jpaBFiNz80i|T9PRFZ10rBi!Z!c}|5#zam9GDog>Xh@gW@$; zIomxjz26BizW;9lNJN3Z!6X);2kw6(;f}?1(j<`~LEp*YsX^-h#(DmR&Qyz*PX4tH zrSx7I2m}vef*4U0grVkMg9i{gfM5lYBM2&B-~bvpx&tAGjO-W?g~VncMft0<$TW-~ z{_uvDp)JWxanr(=vomrQpH8vjZp-b?%I0lO>^E^;^>T5FU_Q8Wk$qrIX<1Rd`ng{* z=oB-KkfxrBLrBT|i;0R%__1Rjb1ah@17A{ZLSB05UNOcE#u)F6V}!R?beQx2b&2%> zHb%6>^Z+$vz4JA6r1CVg)5%!c>-UAN1p z+Ipv(D=p^4(13xZsjV?~@IOyUR{i@(vo5~TcuA|?g=H1v^wZVu$-%{+GxP7m$i16y z<=d$EKS@29g+|hJx#nk`fdM;QR&Q)rD>h_)V{F%Qs6+6FJ^ubVnm4lBIFZ z%B6sJWr?k%hp4MX3LdNV)B`|85&4(A}#=) zXsLUyE6t`WXiszTx$q7|4=QK;B8i7(8r$)hn+^7wlO;N$#=tnQ_d8$jG+M>^Ai}&; z3Zui#x;)+7+l=$FX`W9gJJVca8nVrMp0ta)NshA$-(6@veO(tH76yq#Qnn1U03Tiu-5Sdcc%4g z@5ahHgAi8@TQGDXbsW2_KT=3QJSM5F@6A4lH7ja3N0TdTht5({p{8)YFVw*|;K|~Q zr7^S8Y(l-yz@33mUWswXnI?jl&ohZK1om-an=Bz(!bI2CzB(x4G&?4n83WhSmh^is zHW0Ab5S(~Obd&IgtK7k-87x{G5HpBA@7o{`ws^dC_ljBcGDBGB=%}1(2hu4E@%6gj z@4&4jxz?>w^R0GsFFR3tVF(ggPi(-H(JqrIteEf_lvRSD+wJ=4d!s%{7QUf0O$P6V zMeMb+Hd2R!l@L7bMv-)I? zp<;f(&_pCx7rLRmkR}E$0{wWTU;4T*qd_b&pv`?*tw6SK&fd^{a+u9b;Y<9(BY!%w zq++m}euYCOphpZ^2DqeEdPr5YunZ(*iR*(0LKkR=@V8{*@AA#!g+36F6%^ ze0KeW6_1QZmzY5VzGpggQh26RZZo8O6B$r*>q_PRQ(1GfF?E!OF{WK{Cr;I?HyZPy zOR{UJV{ajqgPsEW%5-U&@^P1;rz~4OolaL+I>ymIwJ*kVEp^6ViR#P@>=Vs<&)7-< zn7VEA%Jj;$m2$b(`3AQ==ap}diUz-dJ7jNe+D8pfhu$7!Uc-cqw=G{>!GSj)9h}vY znfONMWq8;?9`Dn_yoj9#HvKD^*fQ?0!)n1`rT>FHEbGjF+Jqxx2_bi`L84KQ>I+*6 z*mjBAczb4>+1FxLyl^fy>ohz~8`b|~;|kcGpm5hzN34GwPT-Y6jN9k2#jyZKt-OG$2R(*n za2)HD`hl{Co__%`<&KG_RyHfQ%HRS}Jah(+3-YAHiN*#nvLH~ZPCuFtj^qTcP7{8` z{u&SF_O)$)lVLO0%_YM;6sPte(Mp?mhx#)Tb@+EdA69Bw*mcpdw332wJQ3kleB%9H zAG!N^FFL;CNj#nRTRZpqRq{Oa{ga=N2jNA0R=?H$+Tkxc0Kl9EiswWSwUqetE}qer z!Axbwat*~LM9*Dpc@tgo?Do*2A;JV>+qf`Eg&3RWHr-WK=q-vrO#v>m09LePKsP~; zBr*9+X0$~6A?pV8;>Al_g)E0s@+>;TP#%C!EV6bZ58@QyaFO*Qz%Rjy>924-`o0yL?fyzX7nAsAvMi_(rB#4m{!Z<4dwjVk&=N-CB$^tw4#C&vvW=~ z%|Q4yBtlgZb5>X^#vU<2XF+4Drfe~=el(Kcpv)_v{ z<+U=S`E^e$fM(8oEC>^|vYxwU@|j}ie0$RSbh5c*9$P>6F=!1g0{7fEZ90wh;2bfc z$=wn0>7~POw8HO3>;l`|vq-Kk-EIK!6A#a-nBOIah2&}7wdx+_-mKc8Sp|VdXLi^d z8LeCFltVwpTJfHc+kRlf{5YI>>e1%TVQnhnMz3_nt9+W!8Qgp?nad*>q2XjSm^bs7 zl+4pNo*MZT&FmpKK>4aDsLYrWQEFwCD6_yqo@cv|;N%8UVV0KU>6@ibm7U9hDtq4rT;F)F_@0CG36Dd$eJ%2KTRM+&OYbp4p4#%Y} zDtA=nw~M7`EZK%>pP2dny5R4VXC=!`8lM&pkI&*=O1Hk-02kEQM#T!`e&<^ z;tS_a>BE#D%RrzrFu%7Pbdcpo2-Lb4N0{}(HosrH-WE`v;+&VoG|lIT%i%SB>m9KC z2@k((*Bc58h1MnFgt|M?k)CbrgMzcoDGdMR+DDc!oFKW4EFVq9yj*Y*l9z{P<`CkG?)r%}T3 zs|D}A(rP!W>=)1Um4T_-Lc%C2?v>0FWzO_Acm&7SS054XyZP0I{uB1XkXQdGnJX{OYm|juJ3r>QFAiK2gJ%Y{8+~;ZFpZd0Dwh;GQb`~ z#>;TYb0|BmPcb}lQ`AJ@h`I4gBEAqsK?xZwU=TxO63c|?+?>}%`Kd16=-tD2dRC@m zad}iHVX5h;7hjXttIunFT;uICW~$~Q=Qppy^!Wp#sgA!ZpNN9okGjnUBfU{?`LP&H zz25f%2NJ9(@<0LjUSs8%ss1}Ku>u-yE=(dQJcqNEtK zu1A5Hbe2w%eU!!K@0Ilbwoxnu4HUN3cmCf^i-!IRKzMMVfTXCbF!X;`ll--J*5knc zO~A{YpHLA-AIJ-^A({bhJ!XjSC)4 z3=12b43$Xz+1ZMc?_ZK$q&CZ1eCmTLaQVQ>)LQ52^!y7)5vx*u_&y6rlQ6#jy)F@f z^xIIbiXffkxcpKNO6AI!eZaSV9vx&O@(+o9Ac3|6BWW zeu|ZSw6}YGfBSd?`mI*QL{|btio!bMA!sP?IR8oq72(K{q$o}F)H;#$L%;wM&u9GZ zc0fY<5dr>ks=gEaaAZoy>68sH-ll(&|9-1&KNpowH7&~?cK6BHe(dX1d=npjb^Tfs zrpElnNS}<$0ue%zrm2~AOt5R{;htq$jXhYMgsZSwW{k5mU(GXHTtMAPb}ZL5O|LXX zj%ZocRq;LWW62*zJ(&4%#FjR_7_DADhW)YXS(_T2@agjrFD(aiYdODPw8FM+`+xKS zuTROV3*s+ZGr;8Vyid#KeQ*EoRzO}@SfX#I+8B+PnVOrNogSiyL}-IQ$c7cs!HclC1Cg&qIjjSai|7Fwi} zv526gGPyiXY>3c-1Phv6iPFHoBQ$C1;NOv|+}lMRJdY~%Jq(skz6UCct@;~5^d8C7 zZDF<0-*M|q{e!|a&i#UM`{n)p?}7Ax9yb>@IZ`CDjg?|CR%xvHjI!UT;|?oE-4d3u zlM>Oea4Fg5Exw*RpOfYc)RJ%bGaw?v0qJkY)ov7ZS}1UKO9(? zSee@xR@c|KIkYr4Rx@yQH*M|hXV&pC^U`y1C#SLwO@BWcXRq)ct{-*gJ-v$babVZ{IZa$(b_Q6J=(n&@1+eEjGB!upEWU1s94as$uvvL&wfjhlssiI0(& zxv!psg^P`kF+C?sUn4s+Hv^l#wt8mcq}`13Y;DSs&N=JI8?XI-yyyp?$L}?-O_z<` z3452jq_VoMi=0c}lSA%lJl%GehY`h%%ctJ==jWHRr@X$fKmWF9M`s*$Zyx;H+h2e0 z`@TNBu%s+~zGA0qFLSqg3#(5{7cN>p=tzFT6*`q@Rk3H*{M~o)+6m6Kstpbo@)Oa5 zMyM#S!q@%(+QR?fQ^)n${CfNHL3=Ul&zx-{$L!L;Js;}cU6Yg6n`_--c#1u4BSxMUeQ52SWwx5q{aiI-jKSmzIy!5Zh4U z7uK?elbXM-sAyH;NImq0*M$G18!ft)k;^4<87%Z>c&xvHaYdb}B53x<+>TnIZYaNa zBGo2xpO-^A*c>E`D*J z*HtTZ6rtc?f2@P8dFvhCPO;W&0((&5$?`k{Tb$jNKYHgqzi!%1KqCO0K<}>J4 zSwO-Dnca(2pDpR+nfNMq5DnJs6KpmiHP!<#&r0@B%yQL@=2@TI_U?I=r!V0d=_X>GX`a$KY zD^PKW_f#w-zQVA2a*G~J?3LQSE8uby>iF1_*hPTD-)tCgiorj)`hfOnE7qh~kLP*z zMDE@tQD`tsUW+Q%Sqp}h;M3zxKDf}En-$!=HY++V`Ap$4_*i=WqOvyGiUpOE$I+FW zSvMc)>wvT3O(1f#&eDXjMSPhANUXBSvn)F(roAh|26!<_?}hF!7i#bB0fCO;6NRUi)o|sk@MA^ z&|TAxjvEKk_zolZDBq$VTnrVjv9+m^0%K@dxSV+`Efu5`!oAc;x;A*+7(#X=d05^} zv_&ay?hjP3HoVw6-(1)4wrym$Fk&4-Z#go#kc4yK;XG*H-dfTA?Qia)4ilL=(`jOn z2-#6Su^FY;$E`GGxyt&umtQhxFueNJ!@P_iA|@y}PdkyrSQ&yW+sAtDjnCxsc&>s% zC7SkFJ>2n0J<1|H<0Ow#R{*DzvO&`Qv)S^8gZ$jj_;k6#;u9^cPdcT_`3D{gD)1jY zDS^yFIZV*Cc2dSmz3{ZGk>wV(TVwL?XBvK}3MK8{>vpG@O{dx}q8!52i3>&-_#bMt z(-O4xi%2}p6v#!r742Wz39aMx)Vjahz2;UMU7qTHEa(6X%?W&6HWNxF3-0f@07*eh)V_RAs zO}vn`EkDcQ{4xn;stWX(%|Dk?!p8Jtc+(_E;hWgaWeFQ(MT-^mZB?Ep2eOoFx1Gt( zf>X^0s*i6=pC5FLg6#~!l=Z)y8zt25AN+J5tB_98qVJVUJjKN#dj}q(%&=+B-Vs-- zMQ)Y&gA!X?i~72Jb>Vo0*C6b=4yrokoRMC$I7tU>%VLi9g#C_w7WxLYq`8@rZaB@7ftP&BQcV$o z)zcE|a@#ixTyZd4+k9B-3f{AbpIcIhWJT{gasbz`5Jg|EK_ph%-S;${V3p5hkbkey zY$uO_AptU}J!XcV`KYLIP*hWLj+P|HY_D0>viOZ4kVcgwPV~#2GMiR+FnQGP8_7!V zkvmOaz#nfjPJS~|rh?LkrZjBWKgLW;WZHRQ-z7ofC%%Be>|(v*!Xi@-&;5$XMlJ#! z5fQONIPjXDv@g0Nyub#_(3FC77t7(%yz?{?+>VKUA$Ym{foTrBCG1(iYt7wMlT}a4dR^=e#Mvb+y44@nFyaBtBsACD%vCLp=jn@h}?IY$WUhV@8bLQ$v z7DG)l7&+cVO^>hyF&MIN+egGgjfL&+=qWbUQo+y!QhNbPTDr{@TWnm|rGR}QWo1Ju z9$T+^=8O(R`zA9tV$JLkw&Z8xhDi1#V=DE;fMgDHyMtxu;qmdri7CN9u`-Nu8xobep7&vNN&Se2)Tw1dbebm)%JHVyG-N^?7zQIDCMX z&|9f25a%QP*yWjTgaq3&Jl1B zZoQheJ0MWFFXk16=7d!jjKeH>d%l(!iVhe8gC7yTRJ!_B+CDruE6KD-e9^E1@;zRt z%4QX2;4?BG2USAsA?i?m5flq$C|I~+k;yzZBZ~k4n?bSg2y6D{>V7=}uT%W&ubE#y z@5lHl{=wCBZ)>8-E%WTK{qkjg+Sr_%v&?F`BA4og$NVXYxq8Cx{EW&eT3a6`Q(^xuKK zDxeaZF9rBiyBIB#&(7azp&6xK^tB`^7!WC~d2QpGD=Ke;v=5(d`b}Y|1*Uaujx4J)XUnRTVxmWLl zzu24%TxRvsp;LO*Vd?Ohyy{1nj`;nfBR~E}=6$KaPkw8E>zw%8n9j+Uy-wBtDC8&N zYXZ?T<6j`axlIS;55NK-4SVUd{7|_o4qy>r1z;Uu3t$&uKj0|f9>7C@Cjid@UICm0yaV_M@CD#Iz%PKm0-OmbKq>&B z@&TyIK-C1QK2VK;YKc^F<<-_)XKQM2R`XiYs@Auq?d|PwCwtde(|zk_YaqF!!XJxr zczgJ-V7plRPLvqzFj)Rr@7!ZmM)CG!KT&}vUO4k-Fz$F1-1G^j^dXk@*os9q5!+Yw zI3!{iS~xn+V(Z1}-*JfDhp>|mR|P_yIVi#N^#UgAfn@v&N*Ig07I&up`FY>LFNx}V z=KGcg1QI`BpuoHyo_*eX_2@!#0Wf^mKDx8c65=+5rGA z%aj1)-G9b*2OW2xM?B>PuQ}~KpZLlTe)CV6fQgEfw?}ViYH91}>X}%!V%3^;8}{rw zaOfOBgb8I_Nae}17q8yD`!M&}f7yZ`zedI;re@|AmR1N8%D4cjw6%?`oxOvjle3Gf zo4bdnm-hnw&pZI|+3<-E-PrEf?5OJ;!M?g&n?}P*!$vt+%>ip}Pd4Dw5!pDLS(3SJ z)_CuV37d5N&$a)*k+eAR{uZ9P5;Hiwqtx!euK#2S**KR}>sFt_ezBW_S1-T9fn z^%lDG>g+$x;(ADpJqNJKL$KkQ&ee544?UY&X%PC|$5RL%qk%KPPx&?~#P@oH+nd&F zjSzGD80N}8S-V_4Ou@P;F3(bi75hvGYu+!&PMg1t7Iv7guQ_!^4!ifU`C;0Qd(G@x z1{u=bO%$`JFm+}PTVQ%oK6M$v(yZ66!n5&TP9W=8`2^8MEt$J2i(JRfq};n>@mT`h zfpde&sia_BYum>8`!xuKl}R~7_lywiG!9CV&OUydk+wzuP57umJa+b!aHH8&(t9+( z`@fX3)@~mAcj4jk^e@JDjOd6a@qA&eZE=XWM&FFLWo{#-ZZbLmlHf1&2H6D|Jk#2w zG~i$7%C-e)a5s731DeElgR?asNwu#R2+YsCHyw~S9rRwClRK5^_e%eXF?&XK$?Q(5 zBky?!6Y*oyr(E6FRJPWvKI0|dWRVljkhOk?JjaTS)kpo!hVq7Afg^oF2D;#!;3;$N z>>-mA$z~rMYRB-~Ogn{G@j1EP?q%cGd=g??*L}rS{M$l2Q}H_2j-fT1ba0P?zG;oJ zfe3j@{uirhlk+5nXMWzepQ-)}Ajfv4tn0+tPXmz`6r0m8xSGiT5QOHs&*vgfgF7~2 zvhCW!E%h>|6oK5J+Nij}Z2}L%Czw!5-0oNpIe#f-&;%p4 zNiDZIzSy{YxK-KA)^?^Q;`nKH;0H12;%1m#{!0@XOsH7Jq6T$C)AZ9Y|;Q>uk~zcCVR z5gIR|cUC$r*<(8_#;&ZO0yVKzSv^M;@`>}Su?PwnjmTOcHNr&+87EciY^aT4At-HUA700cU&k~B{D-J`B>Rn%bVZ znKG0*iN?VcKtI7EvIub)<|Ug`u`}3ih)n4H8sKEGwerbwR+es_7F z(zuLJKegWl0lIssIAK?C5Wi^YK) z(9+Mskzdy8U?CzhDmo@MEMy?^dz^8{8-IccCz^PYmCB@`X2WV1rw2SD0RBEP@9~-_zo?{gf(cf0L5HNnvB({D zB35DPWN#-*=jxO|m+Nu`U8!GEb+v&BbiKiWZZs^=N+a%}n|+c(-Rg_9YJPy!Qc*@n zK>{a99q$?>VEnNfI7W($nVAzian7H3Adx(hnDkfT7@0Q71}VrAtdU)#qh4L_X1FJb znB?1J3K?}D?Co|NF<8oXwzt3qBFK=3d=#Lp09QKOy-!*h)E?0#eI(OqR|bm@>= z95RiejFHA1@Ev{5(q1mej^uHF?MboE0RoVg33tRN-wzR7Uh?wS-~f44P=yEy&1f-W z2O~s;EIIN_v%qm|Py}-2SD1v>BVU5RMnE+UsL|05PLL!i1{h_EB`CJ{7|yq`S{gw= zrGBsDg&9oo)DjCjsk0(Ksk&nK95RpefA)1 z`<(k`SX#v6(;9T5P&%3p$?R1vT*MN z^TwYMtlj3soo@#II5$1X3>PUbF+VOW&fkjYW*vGB7_}$&|L5*pA9A~Y8HuL06O`Rt z{(r8|7pW#!ahAVV-V`;OwCXZobbb1hw<{*iyzf?Rp`71+?{|h#g3w~di7(-OcZ{VZ zd8$Y2gI~{>xWWX>q-ORw0bRi zKZ>7w-@lF$s8HCV&d(AqDJ>HRZ>7wyk{pG~)fj6+wv62Gs|2aC;XGH~YTB$xt1bgZ zecF>>ZZ&VdTeXGaccxz1XY6)BD3$h0NB)eYn@*q=%KwSW!Qcoa3P5A9I6RT`pr_#J zz%P;9TjOYr+#36IysdHeg7abBLa3N@t+BO2f8Tuqch1sEg*98e8L? z_$0Q2K}fuCzj-lTX8*DDLx6D0AMKU)e)XR!5hphI@-yfm21bS z>eN;3>}sR_tGBTx*LA;MvRC(iNiOOEb6@`tvGt&9${RkfgZKU8+a7Xd6+x+}HFejK zHv{$yewM%M*w?I%{jce9m*Ps?fqU>6o|4=<$GZ@MhmHQ(J%;D4e~!9_ij|o7!rtzo z5)eY70%{BmE7fcCTC-L}9lG=w@C@z1Kq~hL2ul%rOR3I5fid1RRE0R&M zOj)w!$dxC*Fxv{(S!P-L|67LQV;}jF?&`TZ4VnHXi6)gLn@o;edGZw~RHRsmQqRPRmmpD65tXdVzyH-8ZX4B?a6dci9AViPw;`_5 zhPphL@5Nwh~~cu4<;r#j;b4m@u@=-6tq$H9+AZ^5$s5xDy&nr{IrjFmgSIN6sRJqcbyXJf@qnk;UTc<~b?jDet9jaqf; zHG17p%)p>TiBU8ii844WEq8zN4=h{Zz+X>|{RjiBA0?Z--obUW=o)E_=dQTM`}kMp zx$5>hXPt1W+7F4+L5Cf+?X^Nhij{corBY?eRdn1*zrFB^2-m7N3@T32N%vI~Dca7z zcNn#)YFGHG1vD~5XXOvjU$g{CwbomI169@@v5vaysk5&7s;Ra*@e(~&&}0oY*3|1b z+R>X@1|%JW#19bHNgk>gu`sCvi7{;qG#0`Qb=<3exEy0Akv8Hq!4r~fX%!<)T`@i0 ztmEDGUi7k89@clrC|_Dx<$`@tna?;Xh(WkO+$3$FE7t0v5$36@UA}(ns~cg5CbzB@ zRm!8emmD`dL5gL_^m_B!5Vh;jsY|yWz54XelvmlsF42>Es)hqH-D0}xp^cTW3)t~# zrbSsyVtV;=jmI9Z9GI%vqH!Zf>Wx*ohlT_cOUB0`;e$CT& z)G}hf{P&XEkF0Xu9vA5Sal=0P~8;p+#Qpyj3^aWV0={X0*c)Mm-q5t0SJ(2GALJ-E!MK6j3o~) zy>CfJm+8uyH*AZBJ$bFJuHlue@v{;X+%nt|=w7f~AYtYTLxj_qh(%x-N{FjpKjzx~ zMOUenNY>R_8cVdB$g=VaiH&X`iP?R%Vp#@^=K=3b<$J-eK+21Km4GwCMnoV!Nm@UR zmCJdAVaP+i6cQmwCM{rsgh^YEo?%)hWzV4W6MFH{^B2= zx=Z_a5Q2dc2$FbySQK-D_HzgjEdMhDpoFTK&14a?FKsMO-F^pFpkn!kL*;_L-@)L9DH@g-*ka-E zz}@c=j5P@NM?_;i;{6H9{(x+(Lq67`n7^UfKQYZKM9!QsJftKKE6*cQVI>3#EuS48Srt3vtJUeUXG?TU_S&iJw-KTI zobn6GFDbWEent5;bX$2&2Hf^-ziq#7JGWii z?k7RzB?$~h0RnJ<2Ld#ygnO`za$TW+6hG@91rx1B2Y>(wKmi7D-~=P$2KY?71_%vf zsTcw|(WMZBZjs&86cV#A%k)b2tsU3S1sMIych&&|M!8ts85OGh0oug%!IYPl(Sw!J z{^zs^NGNC+SU7kDMC3jZauhO&NT6$ujuWLQbS*ZX6v><6SyC#k^fJoq{(GzV@-Rv# z0b6F_BxweLIH>aAxz@b> zn|B$585$+^n%hS)YH9P$*Thttclnf4B%-A(b!kgq#xnQHoBHv7)KB&QdZ~m;SZG9m zz=LSoT?;!GzmTY6r7Bdb)2Ky$gVD=NSGnzV$qxy2ImsO+?`TK<;wFwdcuXUvstljgXzMjaYU20SzezFkP`WhX7MI ztt(;NfsrmIE|-OSv`Wj~>Tq3wKbvZU}|>frDaF z5HUrfPTggp$z{o+Yy}s)_mBb1_-i+9Xv5{mQxf^~P)IS)DdAN*auqRBYc&{2D8+uo8Xtv|j-9PG+g%G4k#0R&N{iFp@6aFOACR zr}t^^TBk>N7bPmp2N!~dvZdT;3}cG)9g$?qoTa^;JL@~96IGV+wNjFuH3V8cVWB<#$g5};0_Sf%S6H55TJWtuf$?3(Vy=W^cbQECP$caO=WatT~2m&KKEW!zY9AveZb%tP}y{967~0T6%$Z~)>c_~!2R z|9qafiY0mXM_A4Oj$LOCuNv!p6W#*(4StbR7tnu^Z<*ZhT#m)6f6POf;RTF8G%x+X z6lIB9-i61MUJu&6KOzwde|Yk3j(^iQ3(tl0&94J6Wp9Bh2VWDw?w|V5k<~c%;6B73 z^1+@@KO7#k%@p?iAAQytS^o1yZB@sIem&n}@`0|Vtmty7n(4|U8t7@k&OCL|tf!G%s_5&LL!{sD6Z5B@ zjolKmE|2vTnO)XT(4Cw}a_YC#YpeI#yiQzO)=6E~ zlY2@}Jv%WjXI|DP_Le@mpE-G)&;zBo(`OV)98&C|(PxlQ{+P&b$z3u&JZ166k_4v# zz9JD|4JcrB0GuXq26JS^UUNZrOy2JDp#}Zd)5oVhV|)gadS;B{edajPXOF=?Yn<#0 zv^z_*Kl$TkUp;R1HRCo`r?YZg>)VG#QeU&^X~z3vr*N2lA)x>82ZII_45*t_voAJZ960kCH3z7< zXLnTi*^0hX(6bFw8!)qxBxWVpL=^j+63awIBGK^v-f+y*9Cwiup5dftlaORW{fE0g z;~s4uk>?4y9%pLPi@DPcYG5;qEw0iPG^qGyHM_wjlvq+_C705iQvZ-mY@WVtEWM1& zY{>KMY3qR&l-a_DHM~Vvw+kCxR!ho$oo+IualLwPN4d~tPZWeXZ{|GE0U zxicUC6MlmA@4rSUQ!L0Hmc5%b7?$OTy~tTFan8$}_X=@dEoLT656#T(bEM9#UX5V# zu`B9F?zH@F#n<#l`eW|;^0>AlA;{Rquo(=V3q5n=FzPlA&-~1oTMpZM#@19W+)YE_ z*nqJUKwFQYb@+OVi{2#Z-7CM$ChxVZEpBb^x32E3-xc;Pk7WX^#Pt1wgjJYZO|`qt zZF(~@u+7cd)unTGZtU9HoG-t*^Q!pjYym5Cy13=tS}!Z>-HtZ2u}ytlLYu$AbGK`2 z+e&Qv9c@iJ{{(ta2INqC+S|VNci``rJ3{MM&=Up9ELc|A<&;}q`4v=nU-olF6<1Pe zWtD%qCsDXV-?PqFQ*CwC*HB}d+wvu!0cxqWw%XhJMW005clrhDZ0D7{(k+J5NK*jF&oH&dfZq=h@5t!almz!FTS}ob;1)5>N8M zyc@6MWS>-$;Y~hiy2E?+fs7do*7NXWaPBTl=E*wQC+EU($9eP?J#cc-Jb5o|x_r9I zZ{x{7*n>L-r|=Y=VsldYeghAlYHFzUK7#?pZ7|^KsHcHOns^Q2vhPr`+IuNVb*!>< z7yfz*S9CTktvjWa*sTu)c2N!r+RbyA5EeELF5be%>O1c~BUp}rkXV`|%MSiu{FdkB3>~Cb)n3Zp~a*mbaaqbn@4bmq)y=oFCTP zGy(U)DCcAtWyW%Pui({o#|4OOhHPtoO-E_-scl@c)U$ytQBKQ2$EB=FR zd*Hr@9w}C;O!<4S*5s&atM`vlNseOOnsV`BPl+e54f<%j^~O^vJZ%x_GNmsvL*~M= zWXyVPy6T?McgZ<$RbBW8b?v%?uEC3N)oiO zw$p_w>^i@#=Nu3>X^zR1zjaP&dww@P+>?14_o#iVb zg@11FLqs~~eUE~M{^m1$o1Qa%f1mpEeIS6~31&&el!%9d^11nFEIxxm-`OwE%YT)q z7%%Z$KK$1qkZoTwRcT*TlmerMjTSC?K{3J?a`euk`9DIF8||8>4Gd+=Vqv-j#fdY>D@ z^+4>8#TC}>;&3CdUGj7vXj|WSH-otCnK0cOJru_hZz92@fLlTB3G8+-F2T8m;I^0C z4ap-E&j4Pbd57T>mTx$I;rU0f=U%|z2}BYZ1{Mw;0TBrq1r-e)0}~4y2Nw_jw|M`Q zkcgOsl#HB$l8Ty!mX4l57^83zOd^?C?(2Spjs1RQR*Mt}TREyKSVP?{G=dSTVw250 zNYxOBf{KQY@f4(%Mq25lrxp4j^z(Ac9y9<9Pfj8W##6XV&+ zV@)~ii@DG%x!R7Oqs8w2#i#!qeBC|V;q~nAPz&Z)fm`tk-u>Qh6Nv5x=E}1m5=%@X zPP_z(k|ax!Dowf!nWVC0lgW`QuP}`Y6e=Oz`XxTPI+k~-8IfKx-Z=9)OrI-<=FPGB zaD2WjESU34;=+=-xD+ncf&ORRyT;|cWOc6~?=@?C!}{K`F)TYH2_=7%Z98P&PB~t# z`0aYdcgr7l+j)B{V(--0do}mJx*Jk&pVi+N4faQq{apf(DntPcK@ki^2@GQk7>y-$j3T=M}peZ(#QBhx)z`Wu|56!=HjEA+nIUxc00 zWbL$AH*MArN$+&nFccf7%ckkEdHQUb0h2Ri&y1K_3g4E)!g5*MLzec4@5|%I9`kcg z_%($=`_msFTY#R0=v#z=#lS5AVJS$k_Ox{yn{)JwVaOTM)A z?!}(()k^mA+Fs6OUG5FP5tn@H9jz?I&Nn|;%7*3G=K{j=s7W}1F2 zGtTT)GtDr|bfws!M1dMPCqIYLsYo~)hC*PDW^h!pW)g6v$U7Z^8V9MU^O0s!&X^vaaANUAuJKpE>8YrCYl;T{?Q4Eo+u- znQU^iWE>U%B;k)g?$~4Q$9z*x=sK}Rq`U9eLP_D)I~1;IBQ|a+OI^~^mcEP)+0bQf z*gCIzHCwRJNb4dF<*aS@euH9RUsqN(QR^lX2W?|2{j2?}+e1dM`-R4SShp2*_l&n6 zq)VTHE=1FT5W#5S*-kgaFJ#s$NmCO8@4W*DNN?$?*Ya4u?if+1oZi^9BQ|{(#dGJ= zj}|>f%viDG#N9K?S+01(Onz4Gl(L;h+qu=Oavug(Q*XOpx z*h6g3u=n7HYdu-;Ka1)xFlm$O+|^=afj`*iK!2OY(sVMOm9?!;4|aWP{K+tJ z*^2n&5KYt^HIl-6>8ZbRpcBxY7Fl}pkJ98Dg2Sgo=K<)koNDY&sMr5diU(sycIdnZ zdI7ij1Oj-80fb1-rvV0aEFO$aK26Qj1YaC2c0MO>-i=w2*h(HxcEU2AZ8>JOz7)Y; zk7>TE-m(bO(u4^MJcuQL+x{wwwyEstB*nU-cS#56FqW(s2ZEdpNTidT1564+1k3BO zU~4PkED~50-901c0E;G*vyPj)Mir_Uqi1*Ad2xgZUz8_};oi88X39rY6538>%hjEn zELT`OyXj2l6jF0-Ex;yR-I;)47QoSR>9`4y$BJH0ksETxMSx2QSgBY?|7>bh#6|Qh zx!hdl`Hk^7ajSqY;%#r}Meu2OeGz~KffZH8deLG`E>57WWP*B2T4*>BP_rtBajSFs z4Joe6(wJZY>eZ@t0R%{yUYhbMOd@$_KHv6%5;jJLps3CRr35)k2=uxx^;TjrQ*H~U zV2Nv>jH28eSlZ(;o;MriRWuHZQi~QS=bOFM?0ufEQu44LfeOCaPH%P(u+E=Lt1?!y zK^eZUtuURDOQZq<)Cu+2@}FQi2huj_VBJd1a1N};(Y1)BCA`(qeCk~lLN}{l;j9H- z$&ObAUfkr1^FlNLHb(@m36b{GnfO2z*IF3FUZR3UEy%M-+F+lf3Uc{fv9*p$0gK~p zt#Tp3>K%6_2ddei>Q11B4SA)u80;w~!eSvRHg(0JzPL0LkH+G^sHq<0BcNIFeQ5c4 zw3us*A)lHgmZYK0kJN!4S&zI&(WC5X?osuiee3RkmN5IH|6Qnf*37=%nJc!XRXNi- z*8bcWh#u%8V5GE?7phhtSQ{3+l7!K0z~q{}q>V8eJ6*F#Z4fBe(P9;!vbk33uB>lB z8`rR8uss6CP?Uk%|5)pvpZC-rwAM7c9WYaaRlP{Kqng` zReMdnRv?e+Gq1)aD@(pAwdo&cMl4QU)41mB?SO?qEi8Y)@;yoE&dJ!;q+x^!S<7to znqa5=tZCS8Nqq9XIXzBN0s2m$i)#I{? zs=7~Jx*t#c=4ukG#FqYJ23}dB{(>Ba7A+0y=<+O;*9vT}kDdqw473q00C_gHIyeWP zY7W@+pOQ1MldQpp2Lbz`3OtL&Q%ismcuF|T1;VS=Y$lz04d&gRcFrY-W^Oa^t&Ud% zFLjb{^r~JV^34RC+*5K3FMYG8dYT)TTr~9-`)JFZq#^gskfwJ6?nB3HMR+j%t8ee^ zuz+F>)?vlS6as}v>XW|+EcF-=z@tmEECkk~X;7aal-8TKuWP)VGKS%QidE!+=+L#8 zgS8({UuS)mj}wN_bRY9)y{%LobafK}qb4y=?S7&O-sMb>IRa$SBG@%Ro|?2ThoO$n z7lbdNc46wZ93{xDeWVM;CKq09M7s$|Gn4{he$4Nc}^oP?I zSe)na=$80{<3>{bWM5xE0N4MgxBM&bUxcE@Um*Pf%4&jq{S5#61T=d;$3 zG_&XE(+aqLB}eTwjnTqlH5)nnU!=@C>QoGy@2Wtl_M3PiSz2d_P$x!w1vJU_OQA)J zUIW>KaIJ|q0hXw(4WViqa-^bfHIyD`xrwO8cLV?+Uux$zYC6cNkqIPN`VA0gI z$VrYf+v|@$_!Mh80^#8pxc`SJ+r(jVC)PVHc;wK79oE9gcpTn`76Vg(lzbHlSq|B; z7oxd%k86tV7N7a{xS-&bfSlAM{1pBoUQAX}#+&d4PzfWT9w%6t^~5;{$qVy zewYHaL0llUHw`aFB}_wA=|G}vh}<2QnTP8b6`G(o1q0<{^ErpgNzy>LH>^Bgx{O2h z3K$bA#Ycqak!uF)Y)ceX6j&f(?KTi+WpW7swYV)1RktPQ-s`PF>!)^n^i{onUv{NB zWg@+KScB-~IrG-D;!%{ts@Pm41DQ_y7eXok<&5GIyR6CmnW(UD!5G($R$MRpJ)J;o zzU%k#6JXfIPFohX$5I|eeN%XJ>JaDQ(i3UIBiPlTS%oyB@oh`dz2P3%RP_1=JsY^` z3>l_j}stx)8?}T79?yZ+m)O zwAZbd|J$Y6zcgwW1i>S(;*)SxP}MJoz0ynMl~dAXlU;PBn^q1cT47-4rJ*=gDIU6~ zsR)`BjPQzrdaa}dx^F^ktJ62SQ)775S{jkWC=ib2a?Qt1!yV&#;P8TsGH#479VxCH zEJ1vY?!pjkdr5v0Any{gM-syTSTrIQ&^RsCyA?pWv=q$1iUNgAb|{?!$Grxk9^gw|oDN=3kErB!oGvv$SBi{Vs%*(ArxdNU}Jy zR2#Mda;PyCu8^4X{eXe-@BLNucuWm z5%c@}a*ufW-D&vt_{ZYz_FE6HVi#ltv13~tcrtI5^azYL@UV;4r;U4Q|FTE_cg~Pi z{SBX*r$6D}UW9{Qo6v&=0(GF3(OibCGT14afrq2GovC`f1n-broH)nW<1B#INa_k&XM1#%{==0YSF%v9L)@R z&Xddb+jxv9g|sM*t`EgD5se732Xs2A>W1qgXd#8W-Qz@l3C~*|8bjFFA@(^cl+q>*J$9BL8sj*hKesGiz3-?DhX?Ps zy-9?d7!kB7G&^U=&Z)n>@%eSUzP43kcL)(6AtywE=nbDndWo6uVWA2{7f}r_Be~LB zZa0_18K!6|;f<+PhcrK%$336q&sGR*A;D{A$F2(wrD1`*xe$Brz zSFQI;-}NMRqUPo?jc=P-I1GDf>ky|J2p8qX{&p3#N@PRyK9IyIeJP9w6S~e{)hd z`xKmP#HYW(Tu$;{>Q``-t?by0HSlu#bDoH&t=BoXV0ICqf9Si%zKcDbXWOo_s=>W|nM6w{!UkM)DG!*bSU7-*F+OvkP-Z znmKQhhs!RZ!&icFst|jG6{Rh(0dGn%mx-MQNmAHLdhQOdJ4@3xVveN+*OG;T0jz-p zsZ|C60$$PYE;Lv`Cu0f^tU6x^c5|hoYGIPXS-^ZNeRe12fAjDj)Q-ha9iL>(HqPQ~ z0t7|Ca8$8%n0B2%8sV5FUz$CeY=eWU=)C0&o2X?G2-KG=OQ{Gg0b-o_+fK49+JqQ7 zv;BFq*;X?>=(K~-S?UpJ|!TaH+m7W;&#|^}5$Z~J8;O)S9AgZAh zuIxV#$JtPQ-IxUroy|+z&Zl+k@Wu64Aa-YGcE2~37rTyf5L(2hhtI>g-!!WoA3uMo zd?6OG78VV7awY6u{CMX$bunlkkIbSKKNFVyf^Y3Rn;H|M^Jrv60U@!z-F{bZzI<%d zW%9H2o?n=$+)a%6dSQwsVkw4y76nFMhv(x?+Cpsq8`+ZYn?_(%cnRBK==%qk81%6C ziXO}zzKw!NScGWxOnD)vN{uZ1K~9XF#{FL1QHtaQgcyTBH~|4ctU^R`fYca4I*^Xp zdAuAdb+IhNirUr$vAhI zWSp3sMSK8eJrfdmNt8@bEei8AGYDt-l7yU)altuez)(+Zxn^bVjU`QQz!=TLVjwTH zxW?U(1Kg)s(ltE>M3Z(avAe?VDtBc>4~Mp`l(C_(iA{hUrdt;y0kk^yjAU?SvJn+q zcP51A5^4dG`!beoZ@yq3X+ufVg&bT3DXg&LL)?QL{_r^y#B74^C7bQnx7~7SYZ(|L z147!&7FjCw1PD>j69TA|p0h_~R!+r>s*)}yk-DUM$d{vz$QO16Nj?SfOs%MzUW!@a zP#{6&)H4Nu)`hmA6n@VuYvTyVF@`y@eYE3I1$ACVvSjcl|88<6?zmiMpqRiunjyA#K9_O>?N3pwi z`?k#pVhm3@bZ}cIz}4%XY!DC#^y8DaTrPDoT|fTew*H8#6@LG&@5~TZ(2gb;y3w3V zGPKbL8MP9ty7pG7q=SAdB%izSW

x{o9f|7gEmo2*wv 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 z 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≶M9Zv|5`G?V+t`dH%WEMXqpk;_3Hk#c)5bow}^>GHdOg=@5pYx=49b13Ly zrJynzDRebu8rnRSaDCBo@|9g53n?-Toj%;)7@=UY|Noy}Ma{<^CTZW`I9PGat{6t2 zaDw4J3oUfqrNwG{*q4kXjQO#)d%E?I`6unq0@g?R`EPa45Y|xpiRX?D^@^QqfPjrp z`1!tA9;wNGs_VH%HtUBo8*1_;v~g)avtfdTTKYQ+w|_T@R1|@!z4MWbhw@XQ#{r8n zFBZwGL~*S&Epds65DN=S9LDmC%OD``N?Ja3mq@-KYHmwkg<5GJXlu`C1U~hF;}GUt zEV_svDDRB0pxY;h0iVB6!+t9MoPjoUN2{tnNvmp71!_;3|F6OefCDX3EgVYSHa&Y~ zU}M_~aPglu-?Am;VW9ar%IVbGkq@`{Tq5wAt!;iU^4x0?c1udN{X&%ux4V&|KJ4W8 z^-G%6%-Mk6r|NGgPt?6Gz6|&!zRxhaV4(F`GZ8rK4j__!PX?Q7^;*CQ1mh5%DvR6C z?e!IxGMT8~xw^^9NiPO6=pQ@SRODn~Fsq8jD|VmScW#=CFmzog>dWa9ISWyD>bX6* zxnZ#2TwN0;af`pj^X|5h-UR+^#wtJ!B@tKiK!pf5VjK5!fZLt zzX!?qwZ#;g@k9fI%Zc#zkaZg@VAO57d!5O3Ue&0UhOx8iALeb!OI zRvYFgz{G^aMMxIXA9Q8%Ks(ns{Ng8LwsDMRXV9_!HbeTZg#-D*^A&&kWc>8s7s|rI z=ynSoO>Z_is~m>%blt}gX#It_>e2=$ntV|mjceXzzfgYM^uWLH4|qn@T1Vx$y+(mB zr_oTl_0pJ8ZR}4L)pN;gX0*r7gHMr7oprWF%6?*dA?da-61JtJNHWwP^#36TIN#Kl zHX65H`VqI9GB?_ee-?H!Yb?FpyYadu!+UaImNKBnpF_sZf6ay)B7}^R1hodXNP?eK z4UhCNG=>^Ra(w)t-DekO(;#W^pCZ0-I00f84I3?O?7O zB%x)J$UIIl{lRxlFHDbkes}4Xh27aeZ@lufb-e26$_f|NxU&YtVUJG#2x>BxrM_VU z1LCx!(BL?8gDF{Vq$J)xNc>yL)$=)7I*g|%)(&0-;j8CsUSvGa_^S6DVMpH zb8v0T>G{!ohHICj*>1fftNM+zZtws0KCZLv(IK>C_QT1EH@fD(8$2iPv~!>Y4cV!P zSZxtr!>L43HPE+4<>ftO;-5eywKK$aj&E__@NZF$Ub2O545&GURXRcHZf+@4Q*sxY zWp376swn?@b?YH5czxG41HZOjt)n5ymnfWVn}~l0v!W9f09Qb$zl@4>j!2BD$PIWy zG%tHq1co&qIS~ddbB3;u@9Dn~xdsYnr5s8^`W*i3m@VDEnOB&F?o#)Rs5v1eUah$w>#9 z(>0sd(bH1S1!0KMO_Fm9-(30B*tAvEi!I8bj@kN6Z10~`=5`eh*Oh@TSgc~GARo=W z<9@k$y19A1xpq3jbDRG4LD38!4XW&4?>FThiiaoIiVSTRo?|YzPPb-muv!>myEIOW zt#-bt4&U((ZdDWewL`sy(~|m2`BN@QF+Q{|G9ZCrd6ta$KC*E*TQ_G)_3NXw*H*CY zbEL^@$wN>XGaLNe4bu&0*GJMUg5zS=CN)LQyqHShcMq=mcw_4h9+%ozHC=V~`$%?N z`DWW#&TppMgR}4%!g!nK9J8-_y1Mk=F&oUrC@E68`W@5@I(HpHbiw(p1ld9~Keub^ z`qq-^lE(GMES@?`16xSt_yAA?b$A0;omip zd;&xiYAZP+=TTDO@|)ZHN*1!_{_wQ@i@zy5-UG{`HCbB7dqN5AgmRL@R~5 z-KAmZe7J3gow^U;9@e_R+QBj&j{H=={FCM3!&hwmwI9#NDh>OjBmRdo%0A!wRKaXY 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
+ +### rx_frame_sync_status register + +- Absolute Address: 0x98 +- Base Offset: 0x98 +- Size: 0x4 + +| Bits| Identifier | Access |Reset| Name | +|-----|---------------------|--------|-----|---------------------| +| 0 | frame_sync_locked | rw | 0x0 | Frame Sync Lock | +| 1 |frame_buffer_overflow|rw, rclr| 0x0 |Frame Buffer Overflow| +| 25:2| frames_received | rw | 0x0 | Frames Received | +|31:26| frame_sync_errors | rw | 0x0 | Frames Sync Errors | + +#### frame_sync_locked field + +

0 - Frame sync not locked +1 - Frame sync locked

+ +#### frame_buffer_overflow field + +

0 - Normal operation +1 - Buffer overflow

+ +#### frames_received field + +

Count of frames received since last read. Value is 0x00_0000 to 0xFF_FFFF

+ +#### frame_sync_errors field + +

Count of frame sync errors since last read. Value is 0 to 63. This field will saturate at 63 if more than 63 occur.

diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index a9485c2443085004fe447958ed226b3a089d7563..60c703c84fe3af9c951733d32e82e46113b1bf36 100644 GIT binary patch delta 90185 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

}!yX~Z@f*fyfOvI6Ax>P875 z=yqY0-A%}mHelol4X03|1`bITd9dm@bD-LAN#?-KFf=>ko(o;E$bz?pP6p`;Cl{Nq zX)?CO=lQQZ`~I%{B5K8n~#NVSi2Ol~*1Cc>3$f?m(8G~Nes~fIc!seIVjhO~^E-qELNOzVI z88b~ap3ixn#37?@JUVDb4br%mHXC+|b-dCtBx+|fAMs^}$!g&NdLUdX>)GAzsqVvC z(|7ySXvVZulyq@Q!*IxfBda;{JET23($n|ZjBWreI^0X{4SAC^HKsU;T5J?9hBFgL z6|Uq&(TXyHN<-baMIO92-~LK9PdmQ^y^Zjq!&=~QOQ zuxNmVb!`e58?@APgz0D*yy{-G7k%0atbDqTEp0xePU@W`9Nb3YM7~*~TT+6}Nr-e; z2%LWFdI%kEUqfv7;nQ108-KBHhEn8!m-y>&)}2q!YU?`dXcu8^QK*LM6-^b;1?^zdifr^Fp!Qm7mmNg}^LwGB zDOJzPP35AU{)4%VozbrCLGAiQs_Y!IMdv$qdquC0fBm}6VqPw5)~9>wp{tvLkXc)P zz%(iSUh70w=S<^H%bZM6hJVolmFb^C$>-YYk!h21nfKq|G8rH1&4KInaXGsBSF(Ej}$JilSPEk`zS5 z1q+Sj@+&s}022)_x+fbDQ2}%Q)9=(x4MdK>0HuL?RSc<$`U0Hk^rFXju;aTs`v2|M z_TKa42eL-ebXPKL*gc4#jcS3h%*4zpbY$MDo>VGwvJVs&_n zcG7&F=bl*v*x4K{&LI_{z<$Hg4M&WKZ~pud9yBI_FI+J!5QD;%jL@=6x;#+<@Y?X# z(TZFr1g)?=_q;J4M!;n3eRE{Ig0{h8^RQiKmD-!%J&Sz#foQRci5>JvPQG}19kUO< z$Sq%9-4BEboRm!d62YmtZSloBdbjI|A~cojniU}2FfjMi(a_?y=~H*{6iw+_T|5^j zU4dPA%@R?#$0&MGe0n1uz?KcuvKbtKS;Nr1wwqX2v^MyBN~om5)rPyV*aoR)v<9S} z3hr=sSw#eFscD24Q~2HZbH=(qbS27g4`CR-M|f?%yY31zQQ{3P2gi))j=;6`eG!EL zfFW*o{ga)@C_%W`{+%=$fQH=vGP#~hjXm`{A}k`HpebTjcWsZY;7ifYb?j6Wqezt~ zSE)*;hs<VHEPo+RsE;h2dZQH$D!Sh)9$!gX6cLH+>d|1LGYCQiDlUF@N6Dpr|t= zjZv(Ige%6mNLQa~^Ei@6F$NSzlXe^{Y!kur#{fAwlkIJPy{WhWrzt}`6=!!nAJROH zp}8$wz10_H+IyaOzv_MPezIDrZ&0}I9h(X@@@K@eYhc=Fwl<8`i3i7-mgwZ)(QNfJ zp2-+-b-EIe4!v~wc*J(WMM~IuG$n#6tZpFnQ1DKU1ysbE;1_Xg|FU6)G1qL2#PJ1; z?qdd#^9X-hW$vQ@C_%2!whM_ZXd;bDj3VKjj^hGgpe04C5s1@th97{8y?`3DNY#14 z`6HbA=%CtZ<(6ottLv@48oyEa!?OJE0{P(Z{L0nMfP~vx?FnEgam?q@L?I{Rv?X5HM$vXWEgYdfUn4 zFHuEXShP|BpjWN52~n!11+K)Nj^Czw(>!kYJT*wMtDe%?`3?#eBsDhF+)fiF*@4-$ zn+3=AAXjVL*d@QyyxEk{hE6_gdfv_c`b8oShD>A1BOSpORH2!;?(F!LnGEM2B5q8< zd?eH6DrJhrJb;RYY0CB%p>d8dC&vWuLNKGX!vPEgIAZSkLzgA7!!GcYo;YaOV$Mp1 zQN8FSDyWr!GD=+EE1RxRuo5Med{yL5dFQ!A9G}S%Bng#;6wh+N@+lQ1Ao=^90ay{4Tmp40a*Q(QZEgG2 z{XVVu3`gndGG_GDm)qxF+sQOy+%qgqBLZ6JLAFTt_@C*MM$R(^U^ubBEVJ8e#_Zd? z$tOeC-doYr(7W9@`g)jN*^6Ff*=-qxo^(lJkqhA%SmT{J+rcjIn8_()Iea@dTdn5k z0W}Z??4?7mw$tgXx=~8elng&5`?^iBf|tc$mGmxG6r#=AVd8(^$HB~Z?D(h%j%{i^ z=YIs5uOX_74>}u%ybbzCOq3D9`4K>1mQAjYVS_TFF%Oeb(y&TeNwHWdHss~@m6eB# za7H9;9i7cM=#dVv4weVr!{knX!;~;ZI@{0zFhjDS?DU`YK=zel0knGjM{AZUWfu!o))M_36y99zQ7z1HL8fvMZ_@~jM^R1mn7muFmC&Vl5mn( zpG{n4u&5ei_yg^shoHH9sTUHR=&koR&p1sjYpa!bXtup#m$zG0o|%sWoV=6ZzlS zo8TDZp|oMBa!!HM9RLNc6($SC8I4XB(5mzu)Zvp0pP$$0?8GQ{pm*W}r@qzJycfVM z^hy<&Is%*cY&vL5bj#sP-&-;OfX8jcgE>YqSlgq|E46B}h`+lkdl78*J~>8FHim%k zw>sjpVH|T}urhLl4fkbn(mO0Ros6X=2! z_6V2KGK}YN8YwMh;Eq-$pa1lN(Vc_^14+Me0AzJG{$>e?v#*LyhAZ;_&CDHUpbFh3 z3TzHs!I`wG%ODE-0hTFA%>1vu_vtYH)%QQq2)I_4Q#fQo>Uq_8%fK`K#OB?iDx_7X zO$)Vt1%fJ(3Xrq{m6{m)e#ak^-*g2IRMjj#M(ZM&?dD|7(+FZf7BYYs_6t88SdnBw z+ov)m#xWp@f(|APqAJWWLAOSe4#iHl+?hM9R5(%XTw8AnKwo#N zX;~LrG5+-Tq?s|a;6&v#usO+vi7~&dL^SVYqkH0pz-J9_1@;Xe0=TZJG?rqQV#Dd1SEnAiwU5XMrTeM! z@1pB-qeG`hJC(T(Qu*V4@Ahq)-6}geo7bu=ulXL?$=?j%QohGC8J*6a`#tk|EGiJ7 z5M&gZ!I&_rOa%EEDCzw<*Q_YCP8+$hh$bWzl!4A)W5I;(S1*4HV`hR|6?U-PTJ#fB6ZJdJYhPnD30adeLE>yQJdoG7OP00=V&x_xLBk=Fo~Lb4LVa?(K)=O#4(yT_!39}3lZ8=5 z-vu!7Xn<+J4aL}^)o?0{AfR(e*o1-2xyOW`!qmIR45q?4;RRzIwEs0{-Hw}bQ!fgs z#iRd&R7Pwel7k^0X6(N}4Sfn}dI~n9$ zK2BZ8K(!bODFP%g7sP3cg4fc=7E2rC5Dai2$_g`Vm8{IP2!t?vPE|=f^D7tLN!;ZQ zdcso?R1AG!POYOAzAhz^One# z*a80wB=}hh9+F*hQE};44#Gk~i+mo$0UQ~qQOzJW)&|X}kma8Pu&5Y2+u!}a=->g8 zB*|AW@Wl$tLV5DhvJIs@7pgWFK{qGvOb`qS#4w?bkpE&q&mc6ly}qBGf3cJi|3s)` zrC9uqg&l&2F883%$ayWmq{^Yt!ptx}Oe+rdZd-K;d)UX}cV`sT>jU)k6|@0}Zbrbb zcdq(&<^%`QVubS`QywC78q1`55PNC_3$ePh2L}7ayisU%T^(Vn)FyNtSTyO#z>~k2 zdwQXpy82nh#tw3+GVq`&C}AkP28J~j4GnP|5oq=6A4=+XI=I|R(bRQ>Ca9~WQ}#RB z*TAKp^9G}aVzPp1x-;nHeun_808<7Y{BEl@KkEiO1n;oP56xn&ryA>dud6W8dX=tM z>eSUFp}LyYxC!bmn$=P#9ShCYk!doRkX6dr=Dv4*_Hg>~FB|?@h_=Okj)d=DEheEO ziN$|{*3i`@=>L85K%39m$tj5bvEJ(@b|9XjHlNFhU(m^q-Dy3F4g)ZYzS0n_ZAVQf z4=Lt@P-S9>I(|&66y0=MPeML8!(fjWiOcPz10b?L8i}Qhz*Ru<2pxHqbJ|B!Z#W#C z!%J&+?Zcn~Ewz zUfTM?_jvSs$x zJGDkmPK9}(lMEBHpJ{J0xO&TEQq$naaldPttpUhxz`1$tq5?HSIgSan>|2$(nB?3H zsA<`_*{o-1S@tV6z-UrnJxDV81pwMdi==}Tc1pR&qibubdc{h)IhF}XoFZ>OZ?gw3 z!Y1MJxP;G`{f4T{2*3}P3Uef&<*TX|`9-FFSIEY@OQ6F&)4nJ|gPmAlHd%6+u}P^4 z!T1jzs;Qv;O5MrwF|F@@!jdCew0u^r0rL&GtM8zY1nhG^@0ia^GwLBT{JJ2`kS0axaC=#ITnDj*>U7jP!^`BB0TiF_Reu)Rk-w`(G9I4Gl$?K%!hiJzi~;QIP9oO#6ERsrZLrW>wI5mo!&{^H(Nxw2`K!Vtj+ebOZV>8 z^H|hDAU5|hjV0@C8|hPC=flYv+p5+B`%`m4arXPkdPlr(*P*#4y9++tDU_)+{_rNo zEW+g(>}Ceby)#wti5a)y8=`vIhqK#f_)QUjbT` zKM-j0v7;Me@Hz@WSs(RN^z?~U_erdEL;upa4a4nv*KK)j#?}fj#a31hQ0-KRju{>( zOO~_e`T-89;9vN!PCdCX{%?4zF6Xexh1B!$kC+EWpS+FV$}(25MZC5*ZVo4dQk9W! zSEN%*%612Q#feI{z*9;plTy8qWl>n{_^>{bMb#pU-I}ur^vz)LQ5#1{$)~tW+Q`vq zZ_UgwQcvvHy+)uM!gb;z?2rtw8!ZiVidr=FS&TidU!oc%lFGZpo&YBE3sOjQY1n4x zxdmSIvWuq_qkpEN)duNrKEcr&Et8g@%GNqZNXyWH zEtG4YV-5=aQSxQYTdAWkQW3p!915}A9&06ez@y>`%dOFsrGFj^jITcpYd|l&Yo*zn zluD@qwu!z|=^(WQVzrPT*f(9beTws5aUJb^wTG~&OJ!x!d z`->gsn!@AHJJ>~wl9YS~^IS$+gcAq@R}rs=yJ$kzA*aDcrLKokkWtEGcc7Mlv@*3& z=Ole-y_0*4!tnCrg&^cKKv3vy5b@gPY z8{OJ@>6s6uqO}yzhY_9zjeKzf<6gV6^*`OmJ{Fn|>Ub&%BZhXGj2y?2ZlUMi2d%GI zO9=D_zX9oyXoez(RC;&^uAJZ)j&hvI(_nSP`kr({7_eI*=6YIPD`Rjpk5;9m;CtCq4?@aD+yR^eFFCgx4Q3ITpMq3%&GSy0uZYC#Ss^a*gv6&~s zagTS-_ESF|_I&VIlGae+%@s_dRd2up!z;v8SKxqR5=)DJHAw}+!t#Gs?6lo~GzHQ> znnL4k-mAP}R&WSc)^&q`!%lSr^fxsdgD4Fc3g+7PyPk2IHBFe|#T?lS8l}Ll->vVf z5?2RNPB-EG6JJi;3&lcW&M^dB=1gQlQXsjw4uo>Dm6Uw>pHXFLo*RNF|H+&}IdorN z`dU`UCkeKW$>!1#+~NW*Zd3@u3k42`v+T_;*7WQ%dxqYR(h6QZdrx=0s-DQk>`)Mj zYB8lasdNd(GNQMYOd%(Q(Fq`aE{Dqz7P4GOy}uKU_jX{6hX~rRns^j@W~c0 zd&OyPe!2~`yGQEu#^-|g(tLcmKC%s`=f%3F^X;N^wSi8Zl=)33szH{P(beffLOF>x z(m-G?WKk-^jU!Q+u^bgscXl4`!{XuTT25R0aX$xdF)}O)&$vr)ZUR5A>H&?JeirES z1B9vonvml-e=0w~?tH-@PerXt4H}33qHS1Pi2DY1N;La0yJ2U36zxxlEz*>B8@DZV-70iS;(TAGcsVnx!!gdiQ6oQQV^%=?(nK{ z9#K*GEEv5xwx)OHi+MrkWi9Jp!8+mQ;U>%DY?^l(lU?JU7TnhBCr-X-1N5HTd#W?8 zB`7K(i`)H)`ZcP;kbErVmC zC8iS{L!M7H6FLl&Z7W99CuFH@Eq2|J@gC&c~;^P`wRq(d1&)8S;#{y zoU5>NPob&Gz9`qX_$SWzCw4#tQyO&tXSI=d$qeeykE-p5fj9$N+$8J&K(ZeU!!CV+XSZR`B9b3va#K$VMDIq>SkDvF?mdk?~NovZjrS|9n z*U6!@pq@-xu58hJ<;aC0MscoVl-Hs#Ofe=sc8Qf1PI~N)h5&p>a^2eA){Os*Zm8Wa z-^@c%B5H>PSlMzRZU{8T2LE(ut}}SH*;=?DRdTu!*7uWHY{CF#b}2!2UD;#)6c9Qe9AkO_+BR1MpVs#UpmG_*~gO%)H#3{ zi0B8sYPgpRXwqb;U=jeynbP0&2`rkd5jP**jg(vJD71y~+ZYrd1Z}YcC|RP?f!Ia^ zb|}}cudtXap*1eyAl?5AXygvUkP~XQ1;2c{K_UVyIVlO(sPkJaJM;f0tY zBf`>bj#4|6m?Mp_t`YT;2jzfaU zy=Esrjlrtgyj!iOA7iL%oOUF{`r0z{Oc~nW+^*QzD#S;xyON0OG>=?6AKY9*qxh4| z;Y{uzg2fla{yv8d8b%Wdhec|({<&jBrlv6_1JMhrPm9&7&WA}T4*(KkX)?U(cm}$t zDL7YoKBNzu-~}M1X&5_j!Iczj=`&x2jI@qhEYCu&=L{{<%+V|ydETMWr%KN!VVQ{t zAuc}$#!m$?+0qg|acxePO^bh;S{F*TF+CGKXDEGKBLjVgvS_3)7ad5CX}ID^x@R+{ zkDmZ@a_>`0em6eGp}0lic#$e%0Nd9fWHvKwJpG=ziXPC{^1|wQtq@Mi=+UsYVy6;{ z{)-$oA!2xybLhpkHDdrVd>}$@6e40T^>+ky6grydF_pz3wsyji3(d131V{21coMfJ$ZY>ut5LX;01ib@#4mR6PIaelw-BKoyzY#XmaYkwIG9S}X@ z(-qx@CbSyyJKvm4Kya3d5Bk5;-zZ5P3a?#lp^*G zYh~b%f}X63LHYHeW6igKi^;^eX^t=ciwY9-z=GsF+bQ+b;ttciX0tURJ7L(eJu0sk zeh7?52s?T0{~_y~qBDuQb{pHaZQC|Gww-jWPTttIZQHhO+vwQI>F+z||8GuRRn-{# zcCT7{&1cq{CZ=nmQ_59~`0BB}-q9cjhGx@E$AuRa65&+6Y3vM<ceV&7!=@- z=2&*S&-P}b&{_5E;%*z%3dv~F#nzGq>5w|JD<6Bo5N$#)Y@I64>v`_{Y3U;?QqO$A zghE2spS7+Lhhzk{vVkWd5_FPg^Ib?LMiq_TCKwh3fU05UeE*>$rt!0Pc%Zj6l#WCB znbjB)R7P^Pg!X*MlC4G{CwBN|hi?B3tKoBp9JWV9%4GF9!C=N?3bukd?FCCrTPp7C z`$(K5oVrk?`7b!n?+eVOp*aU?1!n<*`vikBSRQO{XF$cQRFYve1TB^u29#OP8%`bh z4ITUjppfq^A(q{+7$>_c;e#XWVaM_;zc75&4)-ktVun|f7WP}|BkRMIk@)gA_RtKd z%GdYT{6!?(<%i~jCBH=86{U`O%Q)DlQMPj`P{lbp9%BtEu47j-SXEiWDSkbwPfE@` z8=@mzT6N^dQK#+kQ)%4j$Zngzk0Wf6X#Rr%nAT9^yf8tlF~U$6Z?K_N!p$)CNfego zXWUA*1N)UmG=_9A0y-Sy&ooH0rBI}rKDv#OrJ}K(Jv@lOWLZLDqCwcS#bfq_ z3Gj9oe@Zi@0GXKEtJ5SeuC2EBEmQ7xJ=Z^^(L)KVwq&!s*TK<8GX%=id#AW$zp$#t zUe}ABql6N^K`zz*C?z^dQGziuG5sf4O$E5t_}@N}>R+Gepwh!G)NNV6cEbbV^5iL0#kN-@s=4wJG- zC%7@t{#&-`X*$%TP#Xqhq;3n5QwI<~5`vt>?)(ave0W}B4hZi#;$F3Ru z^Cdm^7}>6N?^bud_ioH@Ect#xL=k0%niY7|uQTwH$HzxUsKV%7e`29l+9fi-&;E-t zIce6;-5uqAEMR3hMu4*t#};sP# z;;^dvPgO5z)(QBVSfs22$x(p~g@*mfe3&(oA?s7ur6r(+vLsW&bW;Av!Pil;h?4l0ciSW54>5!vjWI3CgojP*T?Wu97G~ulgx% z{dKXlq;Zg}Hf`H@oeAI{`$CkmwH4?~);12Nq&6iY9xs9OX&(T9G ze+6)Fyc%6ySbXf#>acEioV=U?zwe-zJPi87kLs2A1E*?vAB8g|Pq3B4BJ*tfT*ind zyOY&CZOxBXPspZrY`7rz)eK{KsLO}3-U>9_o&*rY`6beck8TI|3hZ>kG+E*=_Mb-J zYddB=OsKTpP$wwk)+T&y9>rHfc8IlE3<>=3he>6?**{u^k%+vHZYm!Zk%U}V^!Qvj zImjji8%!`P;Wsd!>SJrdXInzuuFSnI`MzNJKfEo$8Ir&2>bU4S!hTyoQ4FD)_(Yt2 z2+-vhvLzTuH6=CuXe7ZKY|!}Y0Tb&QO`_EJ>Qv(6Oip>qvWQF$C&ebw_7261Bd~;? ze+%IAp-sfEs-!J=->z6p_!fngF!jFkxcAX1K=5<&wf-1L!}kryYXVQsIzoBjl3jmcXz5*RAz{#PiZZ+2NBZ z)-oo!NHPCs@aK)2SQ9$ta~6SJw_@j94d{+A&-=peKgArAi|Ie0|3BiNj}L}X&dlDz z#gd4f`Tq`rgMaG;-gTl2@gEmgC7h%Ve#Xsg<5wEsP(ysb}CZ? zq+J=lPl3T?FmVXQdut{@iymxkfZ7pc4+%kh&XcfKsEbs+LER$-}_MN974v5y`>jN zOlU-BXtso_IvhsNG&h98`s~!+Y`f8hY7X$P6s@#~yS+M=srde7_;VE&GufrST`q?{ zgP0vUg6KmBwdG%bJB?(s-e~1infkgjJTU_Rh{_4LR)#kFsO6C|Mhes>mrHO0ij($y}U&9SK_Ns zqTO$x-&9mi|NZKlljQ*6_Ahzb}bq+|QmX!@upE7@^3=ZptQA`5}-9}>RdxL6Mf(fPx4 zx!>oLR*W{!v4IjvUH{jA7CU&mwH$s5#?B1-F3pqrBVUqbT<^ zs-oK+w5Qp+{UO(!;nyA`kB9a=P^|tQi{nfeu-?3>_Lm^e;xQPsHDr8@KPhmyAUe#i zGqC!`3-LuZ&+quzWu#2;-7$t%?T`n>WvX;BcI?=tJpo!v_r#+0h_FYR8E$tT9bccCXC>d2h%2EZ2M9cz$E0g2vj}M=w>2b>apUMLVY|*A!V2*O1ELr?@xzqW9uhC!{v|hK5H-5E(<} zgy0-ABZzzSqSUT5+*X+DUTv-DdQ1!@8bY&h`hmeCU`0@|TG46q(eZ{Z(tq}JZ15)V zI8(T5h@J5g*BguLUt|2i&DgZ_{w=|d#yF!&3jmneA61pwDMY6@t~LeHP6lc?<4k06 zq;OXgJL9O*-F__%?jk&-`(T0{Fico1AWW z+X3vGJWHpUzk4p7^QYx9FOT=zIaKXtF1t)d6>=#zvX)O^AI*V$4DMEAZ!Kg+TNp2f zc6N3rw|wW#-93+5JHh~|-Md;t;_R(ugeO0uk-f<)krz*&uwJ}d2XULSb_mUHu0od; z@0zypLGIIZIcmW*6o|Sciypmha*waW{;xjP%|3ETPQZD&1>s_ z-4jDooVUKui{pEv42O?W4a-r7#@iqB`qqncLOXpm^M?)_yU1T1lzz34MV~K4S{YUg z?nT%V*2jCJk>*g-Y`r#Yk}xHL)GxH@-YuuS>WDS7RITz(W|K#s9E!fy>lp4Digq!H z#}2g>n~gAQCvUTV6k)!(;3Q}EzhoY)_yL69Aw*3CjrF)o;?bwatM+J%b}FY&Ww*5u ze@*npt9E8?YfNRuR)76?K5-jtBME})*X(rdR?j{Oo?)B<|NlWe*2H}}R0d`u7FJg7 z|0&QcL@bd-`v;_Q|oUp;^2tAJqWCg_0B>oCPEA@e{3fiQ%0 zoF#35)^PH`mq0CTWNa)!Oxb@mF9X=lwTS%L`LnY7Yko$>Ra9klQlN>*YYNEWfi9SU zO`F-9eS2+yg^|8F3!I(+*Wqkf!2U?gfuuicddRxap8lo z_Ym2`Dw}E7&U3+lcy!#|Er8Y485tQda1lA(G3qMeBO4C|Kbvf?w}A8wH2{!6M~moZ zP@kpD1Vpq_yxVsEKQMp2rGaGJQiS4g|F$N=y&A|+O3@N4Ahmx0!h~`5zj;dzd#8Zy zh4ui&_3Z8+qZ-ok^3Z#x_K;4H0aL;$NTTk}?ueXz>w+v}gmV$k24Ma`(uf+XyWB}X z)lOfE835H(AW<4tr$<<(7r^^2IxD1S+uQeY<`2Ur3Y=4;v$Ok$h8R)b#tianX7}bT zdn4!d}{p4lCgRK96^{CHrzQv*zoq|7vbgZ-B5877|zeB-Rs1Lz{hd?tBb*RLDg#@5O4p_Zw+fZ$cBdRZC6@E3xK*^Ty`X+lK#by zEiuWFAPa6DuOB>+3ouYOy`2`I^xZVCzWl>8^M-t!R4p1uQLiFqCbp$Zyb1BuYJz9H)y zg%@7uV2pWwtnc0U1eIiJUH+=`mlKLJQH z2moQI^IlR>7Tz!atGJ=Oe@oe41><0iVIjWMz=M9mr?iR`>6 z+Qmur2(1E`UvKS-oPde}!0nZ4#(*qn@dM@LUiq7r0?l8sN3?_elm!ajFsLG@7An62 z@P2yXb2e~8a&F+mz9K`Vc!DQh-OuO1Eh=|ZBn^NR zS$;;S=^2(c2&zt^JbpjgVDujm*%v@!r{T!S*Mj=~E^7J5Z4G1nOt4R=y7kyhkD>uRe)6K*LUhp% zBi86Tm%4XIt%Fk}yq1~erM5JE)q-o}1E5*N58Ika-epznl=j04+1hu46R z7|lusLR1<0ZnlaOGp0_+f@~6>z#cfC5H*gjn7Y|{bvt~2m z1i9?m8p9)D6LJ6Z2xqfTgCgbNRkiO=IkabcI7Lk4;F@D9Z1Vd8+{T?DXCBnh4T zz(rBLZ_wH@`4qhP%K*=qb?HX*p)l0yN!m~Sv3UICx@sYC7tir0Z*ZbE@<3Tm=MxBE zJbU&a+okvJoMSN#HxCPWcR`PF=;<)a@SCcF$Yywxo{v#V=Q|<{XHiypc-$nr6>qEebP_52QW@zaG?-hO3a=3%EW%7_JF%)d@U)9!A zgN=`#4d&w8Qz}ex7qUbD++!wn?|;HDXR%oO72^f_vrB^Tmt6PViOAbyA}JUzMQ}@= z!G7#$)vab8a8L?2rOe120S0BVslR5jM`o27sZ$uCM-hV;&Wba&OzMDhY|Cg#kwtF7 z5?etvlycF2Y}XEs#vn91?)vA2v#Y9dWf)g?I1C!|O^+b01ujas_Ye(%-x=X6sU8SC zi1}k!miqcL;Jv;ZayIlrQzFr@tSY4w<^@PLJj5(UqCS)VthlF@F2-9k*HSv9AJCl; z;l;!V47l1Y_ec zeT-pz?Ty#JE~am^l2bRntCXgh8Fd&znn5d*W@a<8=Gin!Q=u)BQba7-;<02k7=rhr zQ;j@6cvpCZ=|LrAHE-1x3CE1LFv#dnT!uW?o7P>K7Tma^b{2qNk5DInZ-*1ojbA z+~dT`V=sz`E|>y9ZzzO5bA0c`AK^H_DO#jtMHa$MFdphTZH|!)ha$~jzK)CU*6vUw zVe~u?SR4=G?R}q@QiH2usOD*#O9p~Z4uilZD41=qQOlf`k7`&-Ugnh>Y1G=mL*ywP zvHopzJ}^xmH5#7#cg0te$634$>>^;ddgaZ6&Btk$iSn|sv3?$+qP6T z6!Ca{2T}kvCse5nv+5+J5KZw)d;G9Kl{FBOm zoyoT?rWWBFx7DmBpR8k(lPsDUd%{*Mm`Wbng4Y;G{{fl;seXKdqm*h;rKFE?MEs3; zgAtn&h5ABkyy!ld8kov+@NF&w3T{Fjra9rij0?nvv2~)^#y`K zYr)6m5~;0)%c1)Sv(}FVOP<0u{U!@OiQ!7WHS?WEV}?P)Ig^C8s|wx(T$-)Q;*OUi z3Cck{Opmll=IglW1kZ2|Te54fqkqXh5CyRO{EI~4vwpx*D`Ig2Gl+a`sV8>T87+$h zfN7G7@en+e--Qa0cb}QEjmH9#I)Lr7+ZF7y$qz4@I`ul{+#4f#U!h!2;V0qxC%AU& zr$-Z-)HO}5r`=mp5pWcZ#%BIzaA6kU&XsxukM!Tv9YNI2l}N=!Pm5rhb0Kc$;%$jA|a9uB{#N5O@sl5zX}W_!8e_i zQNew>98Mzf1ccThH(-r<$XJSe6xOq3H)6S(mISAZ@U~oLL{s80NK)4uE^K0~8hl=# z>HpmMY~yy)A=D^M1urYZRb25Rp>mkZdl=jrX@MsF^MgmU{74T)Fa(MXy7Ks8;ClHJ zMygYodvU4bjjWI}xvu~e4+ASyq^34;+0L&@jIP|GPb&-7{pincn-0n_(auEDbl_$F zE#_Q=pK=BW6MFIryxMvS5;SKyWB+17)%IF17p!h@*^zNH$3z>#nU zxw?3M=6*?QEq~`jT#H8h1u{uur)#D2X5g}dS zPD>fhk9rz96N>{dX>Jr+FY8u%DAtrEwG*Y~B&t5OTYK0ryXSOc^kTH-v<-+$Jxv_6 zfVW$7z2Ff<6X-v7B42XSKG;cIVO)6Op6lWNBW4^nG$Hw5&|iU%Wn-bVG_z!D{Tn53 zRM+XQ!u1uo9;481k8Bsn07|~uQqoTTI2hQ)=2JDS?}8Xmi;=m&DBeCXgvdD}1(LeS zQ?rBLK3$S}pg2T&Rx(*Wrs-KhX|o<2i2hBA^nzb4Wg}NDeWY>!qYdA@KKB%82}!LJ&&H z$k836cqA!c;98|D%tiljl1#RaH&dpK$g%zRkAM=7sm~_DvfV$Ae1|d@T;3?Vq1=RlB240uZ@pzLH#Izu(-nkH=!0JFmJ{FEI6+ak0~-m z&&f_L`&m76Hf&^hh67M#GCp{aad4#A>3zqoX|f1Tuk)1exH`a4=Z#>Ou}&JNP3plO zxjVqrihXV+8w6eEN4b&EB8{zz!9mDYfQvw3?qu^d0-c_iST|2l)N~Pg8_F}u9Hj7B zSKtgl3SE={FR0YRc~Ou<-sinj&?wlxhG-Dmry zS~fs(4{ayJnuN10V(sp`n0)M2lps!|4?RNK52d^ppYuqS3%RbEn|c~Phz$!UJRoqh zdlA#AQjhS#YaJd$Im{8FKWwu(%q4Xa7QX>98|*+KezPquqpej2cb8h8;eQl4rbOwQ zMvocmJh@)+4^%nG6oY->k4QyNI2!B_1#WR2h7FV>Hv27tuBmD@3pQ%m3b3led|*=- zUM!OVP-*`DNx(?DxW)E;Wlpvop|}fUD}HRJ@~)E6tea9kYOg*x*}m^%P|VF-dUycn z!(T*%XBD@D_dmvgWh!D3O3wIzzR_48I744}4&G5pD=UmXpZ0)_#G$kYUu}))pRE^$ zCqjl4JD8H52nupqZJQKv8g{moRPpDMcBK^e>GFK`kG>`0%Z>PEd9mX7AQh&iG4C^= zQhEu2VXPnLDkKET&pS1NKapL69qj_7w2RIDXyLYST;XhddbHKX?x3T~xBeZ^+?HK# z`7I8;X^mXdLY(ff#Z^^{``SDJI-Nny9iiiK!ribUjs8t=X@0!xP z?@U?G*#*~wKRC9(s%X0EQQJ6!S$QWlH_xH7u?qyw`Yd}@UEK;d8I6mF2}CvAi_}O> zrZ!?<-M-@T%zbP#TP3r5u8-;;i5(OYQkA)@lC~r@671vQXf7(eLVD4Mf;3tM|7eEr z>vb*RJ}0DZQ5IU`+{ ziH8D<0rxS-n9pc}`41mrY1zRrI)FGTP|VQVgu|u=aADi~u%}QNoevouI4{C?>(6fC zNhP$pj;i1W*RRI-MF|5iW-+!^E_CDNvb#Fv6csw2^1BzH=E-gClzl`&+=Fn2cT>J3 zBE4f77|)5y!6lfNQo=K@YUUP{RP{`E@Hs|NaH70b$zU%eer@jCduGy)#f6`L5M$ zh6>l2M;D9si8uN;r6DL1pYy$0+m6g5a2;UAKYN2IbtbP0tS)Ze8NZLvvPrXJoPJ-{ zUznsgXT>SQQR?jmNOztd~> zrx~RMy?Wf(3DbOJ@QWA`lQGaK>(aaO4-*Qu8d!;%L{tDydPSJL2Yn$!Y!vv51Fz)j31rG1-4E*ok@i*2(L#^9g)sK zgEmEu39$N>wkd=K!tqno93V6Jw=Q-bc&l?BvYPouhh3b1-mZ1!-Vcqy->4|P90v-! zCey}2+&BP>#b?EM@d1~^S(F{RFu7}chXB*RYvf%0z3Q=Ps)c%KEYj=m^ST7QDS&Dh>S#}ie+Q5)cm&41;pby9K-0u*1Al71PwjIVOOb;70^z^^6@RtCdg}zs7{nj zVJ!l;;B_lyx)8B1#W2zS8i*qLY_0Xf?iOZet7MOo#2DVnpi8!e3At5+`b${6s|7av z0c?N?MP=uYO_RmK3^=i&{>c@_&OWeW3NTeZaQN`fL`IjU+Lt&^B!o*=?GFJmvO&7< zsh{uxz&;I@4Zid-lYO3Vw`rUW0S;TMbvDd>#cQ2FLt4^3sbt1?999dlJg66_jlzW+ zPzYbT-Fim(Z44I~Y~Xa-dbUR3Q|H>I!4n{jj3KyQVAdlhpTr>|BaRk+XYNSlVh=Ko zQ*S0(KZ?2IZLka5hSwr5qQxg=pIHmV_vgDA*lyEP}xN)$3h%hfFC^miXS2}-Q^J2rpTn%nFk>A zw-V3v)rW@fDccd34B8I67BKs1h)wi@QoqE5Tl8bRL=EpCus|){QPP&|SlV`E+sF zthc>h^I~f&{taB0JIFvU=Y*4~?t=f<=lTe2T<_senwb5#uJQ}OE7XUf(<}bX{BKgE zwH)d`;iHqE=M8sw*gE85owpJ-hoDsDS`u>eHn-yTO)sfPq^rHQBL(AYMGwH3l9bfF z%Np*`UpnqMYquViOkRj9;vPoal@YyuFsb#n8Zxt&9%Nl$NyN!^ylz(ie$7wuNRIWX zr1@J~Fg1cQ-=I);O{2Z3p5`C3t6C3jV)1;CPCePeEf|dPST|H7+15YF$};ezK!26b zUkBqrf`vXxtV;h|(76uFT?ByLCIa76zLI2{k&!~lz8fg2y=IpqKWu0`a%BX=v`ggX z+nOCH8PK@;D6N@Nz5|joGO@lMGyIKpV;SF2Ww}>8c#bE%#Zw2?qxbvn^eYv8OE}vy zXCF1t8!rCu%nP`AY=;&jv_A^FNxC=Era8m$SNQ+`vch%!6 z^sJBS+U0`NJVs)wm)FMiM|c9b^6IoVJ0$z9&HBF_(_S}nzz5G+UR;2fp9I4Is=BTk zb*pbBGNfjTH=#PZ;7v|v7`ncb2J$hWd%??_IuM9#Inv`>=z)50J?wOQLpDqgB1G(q z&gfXHgMIL~2-Ev;gDHSGRZLse(ETT)i+__hGu`sUVyyckS=Z=Tb0LEd{U6kPY2F~k z{}gN40i62FUQ~;AU4^E2vZ-ebU)J7jso;C_rX=*GLXVMDXTg&sUo1A?@zzMkDNA(T z`JG43_@*WyN96WJrRM%fG=dD_c=$Es-7!ljDBoO4?Af^uSpe`VP+an%-jR-L;+3=; z&vXD)_=Szw-w6nTnnoF}3L9xK5 z6FpT58WLGU2Uk_Ye$-c$RJ(HO=jxBe1SnJtbUjmHpi~O9RzG40@UkZN zzDyZf|0XCDa~E>(x75l7J>0Txt@iDFB)1SIbpuAbbe;LqdhryL{dY zFvACFojh5altB91!p)zk3fe|i$mI#B&aQUXFku5*iWYV?32}OTGX{u8DS!81<6Z<* z9C`ji0s$v&a~6x~#nk+NJC-gcFw*lNnJta2&e`D7SH z$t>p2)km+{rAG~9wM9)*JEU_|^THe&lmlD>_qM8SwQZ#9fqtbbF`uMQJ9i5^CBEGu zh9Gcx9O{2>fG4=-+0e?mU|j3Nu{YfXj%#^fIp~5YGu`wxGk3US%I;z)R*r9z)Qgjp zx+mrdU1ek1ITzb2BIsfDR0mp5^Lr2TGiD{>wOY-6B*UL~J19Vx6KKDB8Zfh!%K&=t ztS5OVuV;X3U}W@cKIO9R$(N)o>Aofqz@RuNZa2g0b`2FNH`pFe?kBBb)uS)<2^lfl z)e0h~zP13zmc}@9EYh?^o&?d$_s{gJ9s7Lbq!FyqjoPBvp21?(enh#=1BEBi43=-2 zCfZ*MEMDj0AB$O*Q_pn&Y@V7P`haSbqr`12z%GG6nJus`b-xc zsKU6%3Mq!aCPXUe&UxC8k2OK9j1?Q8Ir!x7Re0{OQ^v+K(;HtXX1Zo=ftrn~jD;!Y z%aY3OAFW(2pe9B8t;Cwf%pSR!_i z_z&05#F$0g`RM&aQXBQjfq;^y-6tm|c!@C_VnF1i(m3Rnj8ZQitP#4g!&0q`xBg_HpX0CFlhIU_Lp8Ji7 zO&mEzS^~-Kl>cIyg2cVLb(=2Rl1<}go7%CWedbGlum#QH1GjoqkNN95(C~|ZScrCK zs4U^hg{WZ!k}|8Q;&_%sH&?3w`{@0+E8)_rO^)V=Ylo;J1hQ{NL5Fv zJm#nSxGCw#+MGLx{^1((;x4oY72~5SW^902z%mQHUb}+0yv94fi*E94m6O0@H)SFcvnW!=&7@+f7np`)R!Hz!KiQY`#$VXT%Tca z|CnzMht%(24?ht?tG2ZZ7Sq6;qC}AJ$mlo} zXSJ&HskOMyT>x4nIk?OntsapyvbtY0)T;d*PGesb`i&JOn4wamZ3Z2PSGKNYfF0|!k4r#e0#&cEOafn;-{ zr=$M#)Qd;^%wKwCxpxS2LaiJnpgUM84#J9aIp%aWY*Ty6tiM*8In?9`$xd`DVvmfD zDc+j;;Q^KzXeT*_NVDC9APijE9U~pKTLu=y+{f?aINI9FXE$Bu>VP%~(WB z9Yq;Y`9)@}jbyB8TA+^GNq7Ij`x~iTseX!Tgx-Z#*P~-S5w4d+p?8`LG!ei7vT&^8 z+^!E_IlXVG7&I3Q2~%3Oyc%CSLJWp+(&Ir(5$^7{VmmiBeYw~m?7myJy9!l>p+7kB06xJQ^)RJ$!lLr(4S@GpeKkhpWOD`W;;CXc>F}E>dke1l2 zz~p;|5n4g@C}{B1C6nHv_NCiCLgjU8$sJLz=uM+I8}pH^W@UG=YoEtZI2TWv`nYaN z2Dj6^x5SXqmBNI5iMd+$5Qor?=RB0OHE;ZF7So-X)#`syB8`sM^M0Dqx!C!1P6OD= zOD~s}Ymwz9VKf53`QX?f70z9AyNyrYksCYAyW`IOlrv9nh@bggEayVV5^1$fz~w$r zRFf|EA{6dJr2_(J#nHq9 zy$G?drD5Tuho}GCm_7uMAvVhFBES|DK ztR^TP45jCN4IVx@oxRBA5CxcO!!9y}dOvDnogLJhS<4SDE96CFA0*{|BCofFi7RQY zHJh5KlX1kT0%anm2y^~3?-B=lpx8AHCcv9Rk)UWiO@r}+WH88X94TYY-`C@yKt=U!o)ikIvpb6;fncCv9B!h@9N+occtoM9@V5Guu$v?aGI@M ziHj$}X((mhJxrfmCw~|(uGhCpm$I46TOMqfg)$1A)6T9rrEKx6tDF~ZoXQxCHFp#M zeJ4S+JFuoO-l@XXcmNQ~z+P@14MScE&?##h>=Z{0uVj=N20q|t1y!36-Q)Spez4sj3ToH)SY zX(eqM7Dj`VAxC*_dk0aFYoI6231{!&Zd2ga6~qFGveKX9gKUwT6;9kw)kA>WLf zA^=|n7>$8HweT`8oAKNstkS^gGO$S=cGZ~jBti@P+345cySFws9fJ+!7w(xn^A2gv zs;LH}n-6uQZU>}ZxHW$_nWW6dGgNIvU@*pedo1nVtKU7%o2*7cdUtQ!whUUxCDI9R z55ykkgjx_pKC2jCzZ=WEHosz5MH?+`tRMl&=fFEv%-_CT{8 zuIlR0T6q}kFug@atnk6EoBWA+uQ-0@7I9!(V&!uiTxqW3?A^lNw11_w0|;QNK$S-1 zT90+8&t3)_Dr=;QXi@hZFbjy?IFCexhocU^K&={7+qqrW&0&b6PY~Xl^(^s7mWC z>%_H*)Jj+>j0eAB&k1hOgTutd}cY41kN9MyN0}F z2uYoMpyXZhc913P@*+ zg#zv?IS}#P@EvLW_Oeqa)oy%?Dknnl@bgIz62fhRm~t z@KRTE)$DSe^5k;-W-zLYR3Yv{Qpl*JW{5wwq^7aT)ZHTN^#oDbHt}AiKK`6VXM%jC zMFyG7w<4+{(iz)6t7VP@Ez#z?3eV%W&H!3g3Cv9ojSh?pHuo>l(HgR)VB#}y0;z^5 zQw4XuxFw%Rz{zmV2-~*zP;2&_c}JH`Q}R@N6RxKB9UJ5$+05WPDi6r-$c(qmF|Jsb z#9y>h3QdUi7DMyrQhZn?YZ@4N*B-sQOn(q(NoUD_Q)c-IBLF;hZ256-met9<5AR5!ud1S zj5=L&YwFg}i(`WAzru7~6M9kk>d{~Qocvb&6vh-(0_q;pbKT0sp?MjOI}MiOs|LS z9GY7zln^f0sM*YUKB)Yo%kKk$fMq-E!ttfbq~7TgGZaf|DT}`}ZNF30BQWLf&Hw#< zgD{cRo&&|7k3X;HK>Of&?^A;rm*I7Mj_SR?8;|x=8uE!}*Wx-PB2_vEm zR_mh+x+a2(T7n75rbs@DtL;0s3T`a_KH2C^Rl`2umQ{}K+C!ZY{_LzOBJ11Z&4L(U zkWNTzAO90?Sw3;kKjYJ;X>c@sYNgZo9E3bcGeQk7GWwF~AI{H1u z^)ISwF=Aclyf^Gr z)#BMPPpv+Kc%KCaIo*RV9Qyjz$o#8d21o|tWqBqaIKs0Ey_vbw%d6@PMzt25jfvo& z)-K%R;vqj3Ij0&LopKR=W7{jw3QPAd`Mah#d{{YPCY3JT!Tv85H@a1FxazbgecS2& zti;=b;epB9T#8ikV-o;98 zaEY7~nJ_m9Z@K2TI(s`;6-~QxH!7Jgie@7l!Lc`!`EtLm^qQ|svoRC+up9nh6mJQc zgWttoviBvaTNJ2y+a6cYJx}9t=Lh4|jrHKREtzu+ooiLZ1R6Y+vX?FD6+g;{ z`V1oPijO#OX$Y(*7@}r>SFk$hlKy#+U$s_1)!8-#Z5$~1$xG+rA&zLVBD8ktUC^HO ze9kne1YP&`J)>XH(IN2=W``p7oc`yIfEl+HjN|nIn+3c^qSn==I1IiloSAzvcS~oU zF412x*153n{PhYIFLM4N<42T2zFhkmmnU*dAg|UU^pNBcUUQy$C5WTVBY&ZBy|_+= zg~*?5)m3(v`Dk0(`sk0gq#1+l%DJIETsNBnrfjMB{9aytefX-Cow0$5AKZ07iJNoa z^9fNUz6W%_oY1guo5Ie~#WzX7k(eBWVWCb1bl&TntFUXHHtus#A^>_Q%*XT69NI0g zQV_x_((kJgZqi{DGid;rT36SC!CN^ahr1YGf%Odt;cQtf%LneWp%Gt$H|sSDF?u<2LmEl=P5krpOHpY37Ko;R%x$EECSm+ z8X_bLjB#3?k|YnZbID7 z`Zy`xZLxmC>Ip)C*KIH!HrLkfFe-dbwcory;1i<>2q1K(ixz5QeOxD$v^5h3Vakyu z&nR2>e?HGU{*r2lYvk1-0Me)8QwDP~UCjI3bVRb?9x>wsIyCeo_z90+UA-h1e8NT_ zo%ngR8?)W<&AT(cI}8<?3Zf8QaNzhELAAHdWvknAiZiTZ7`lsi+X#}?I|)#ou_?Y ze9b>zzBH#&fW0Q~XF1pAwPhsWy{8k%f6c5qaURve6ZmzGkuU?_QTAtrCW=@_Ui;na zl?Lre%c$?)Xun&!`^>ycyNC@z(R_c4kh@!JERQC4^SEe6R%l+cREy=2y!W!MLXJY( z7sInMOj}#oM<_6CXOgP&Eoa+zV`1mkqKwhX_XXaSC324gS%S%#daAuxEr9#{f788Q zU4+-$A7%S$wTNSb-59fc_}HZ)rZBrEH?gi+2yNmTY~6+n=gzbuGkdL zA!R}&UO(QCZO?|bsw&;0%aUF*Lk-RRS_dV5PCGsRWIXq8j0R^k)q8>7gM#|^393s1*m*Q5DzMHIIc&wH6XpG-Q%Y{Md~Juojz*saNs~Q0 z+Mq3PQb$!-?Neu8ZTQ<#e{<+J21{Ess}dmygM!p-7*A|+`&W5Tc{9Kukj7o@SG0s7$lTLm= zBC>bcRlkWpW6m{yJ083=yDUy(H7PUZsH`Y6IC$bj-Kc3wpsCUrfA8Y#?2V z7#=xOoiUpwg#XB)HsYDK39T~SwY!^4@+91~CogMbtNFtaPF(C@QIB}Ask`o3V78s} z^fdzo_nC!M$_-5Ye}1&o@(n9vtu>;p;|EVo%dA!DNxl5p8X{FXgz;gmmL#Zd^tRX` z*KNOmojN{xOv$Ymj{~p3@4WBn^xR63x2jba$5{K=7gk<=tZ>RC1bcV2Y}J(B)=S~U z5KA?ri&&;^!jq7Nna2*Cx--OoLg#P;yz_G;sY`bKfOm`ue}c5+^7rFuzwxTy~(SU6H4pmH9c7f_e z6YCf}s}4&W8-{(vFM~j-5ja8A!!LTYG9Hi5+(Og`TNpQEWvwV$ttsI9pLyX$4ZpS_FLYSGlp454e-BxSQ8; zkh$C6PZFC9p8w=u`^w7J0Ty!g(ugXrpBDYDIU-{1f9YesT5Sa?74@E@)|Na$PSqvm zd{%oER6UDiVY8>~Ql(oLqwjEBW2iHfFeUTDKfQ+c`lb}D zs9~2Fn%#Gg&l0m}*2yU#Ai&c3k##Q9~gO_L_A<&v!ZjyjY@`a_8NrBTPXmDb5=$J*>ZO>^cU z{pT)xDSoDR(TP8M8(le~gMAW5eUf0%r@W4%uDSsJBnX`%6Rv?Z=&L3{b)p*L1zofJ zLWa#c3QVR=Cxw~xmw9GE9o@nVq`i}7f4WuyDm?Wz3(`%r16L?WCBg~Iow7f8nF(sI zqZ*Q7O7>@KDL>Wb4nMY!n8r6A99~ZgHSM(%2L*YL>0NRUMe+iDn z9`qvM6O7Im`4S~Sb_ka2IGP!Z?$k-ngY|X_lRv#_gb@kzn}b7T?U2UQGntYeNT_Na z`kLLLcj#*f{jKsqkvaEf?9H%dJN`%dBbpA%0y~^df%a+fRHfUEV@JFdfN{k+%C`gz zDNCUcB+Uq+pV(E+=a{4U9f_Ar zS#xt*ip{PwQg-59*Ob1R0ydaYyUZU~mYGco^dVfeR62g}l%1+WX7Kw$e^+oE(;I|N zdi}Fjp24Q6L$wG`GjDqf#VLv^)&_&i?Zwu4dsbfR z7|@(JQ|IxFOyx>=Ixn)|e|($TJDJhv()EbG&yfbD;?bb3%|u;P6_h(nktHyVMk4jvx6H{LxYG^ z1WoLs36bw`vHE(NIg*bPDg10-nW)S*GRvN2@0iurG7o!sP}(*^@b}ncW_A1L`q}bN zb7*ZE8<~S|b_teze?I1Lm9`G!0xvQ6kGAHGQqvTYQmxb+I5g!2KJrSCgd?O1_rhCp zXNS?Zj07bltA=8*u_s@PQvziHGtnExohJSbytUc*z=uw@_ak7Q2lP2g)9>~L5vFjg z)i!35fNi~FW%eZy{*!5nTnys5&QH~2#7J2wR`r^~{S*-re=S^P8{%u`8*-pTRgjPT zIwP!{##gtK{+b)Q$1Z4^M;zmyF?X5St6^35Rs8K;@pw{OaV(eEg^3TbAcH9J878T6 zWvHX`s-xjT1+>DB4Femw z^v3rdV@!0Pe>*k_kKgp5w_6~gv98FC@0klQe&vMjDSV1J(uZ*uBpf_5 z2DpWan`Vkxaz$=HRe4MoeEDF+rQSHlQku!o$00}Jv@QwCWyAnqXY>yB(@^60`*}Hc zjY#7vVArx}I%+PLBI(E;N+xm2!CQ zn*WEOJ(h(h2O$bPM8r^rgBB)+WX#Zz*|i|Ig3!FLCIS^}aaPHw?~Du>gHIX@DM#sX zOQ~ytrh^i(;A({TnI8)W`V`rvoym6ja>#l)72nrOuetNTs?<51P(l)&V*2u?+0*40 z9ZqY2f43BQ&(E*Sn`8WkHDMnTd(UC&FKUyQKktiP%<>?@b5sKk*lmT5f-j8nL6&lOY@$KQK7d2=$MoTsRpg6^!( z6WFc|O$Lv3?~EwoCOwf+DS$66w_rr*Xouk{f9=4+9aQ^X%vQ4XUUuX|ejHzj42Z9F z1swXU?b48$=)gykk;()n56?yBRkgQ)UoxnzLz2<{vix1J@Q07rUaiY_55-3I9$o~? zr0)bJ@zL}>L^Akjp!hZ|Xc$8k{ReYLFT9$FqYLC;5rimC=IL?9p}wA4-c0NjHmmRE zf9|tE#RfOiEr^1MP*)S$Q6)-HQ8woMt%l~#xnY(zr=soc9M~@tM}l9+v9OY1PqFii zQ;BS02KPh)EnuHw6?PYXWL1{Ddd=@;9Mv-w3U(ZQysy%+?i5^+TVo$6cbF)i(Zkyf znKHWM{<3OHm6&lHRr>FHd6&iQcJdLCe}43LM(MQR+B78OJd+qGHdT`NAgta1v3<-q z&yW8vr!ZL0W!2_wu~H!GypS646^s~8JX2ZWhe_45K z*r`1eK-gXz4?~W+2nS&4T>rzwfdvkx99739Duo0~yqrkK9Xo)DuXxDMl8a8up_STF z4t6kMuaKV1tofjt)gbI$Q#1WrVEL+?EK|`^ zpjPM0yPN_u<@1*~CbNoiHTKuuX@IRpHdBPM6J)0Ow%7Dm%VFFq;^aUoWF&L;{pEBvHqg*JaqJ`m8%9PK?kb_D+$Uyh{m4?_^g zMLPNeEw>7i@pEgW9SZrby0g4hTc!*)2?V519UjJ`JQ6mD4Z}-8f0B>F^*BIsS1y%P z9Aj$sM9&bA+dEJDaWjKtv0f{l#X;o2iI0&ADtjH-2NS>W##L2bzrPmC zjxuVmkVR3jpTn;3T2rfxX{Wyb(3P4e2qIzm`3Jh6BygwEl9UOs$x8tK zbIu^bOxbic*H2M1f3R;vq9}CHmN4V_HIyRlCiv3NwiR9XzyOit5WG#2iP7I5<;pr0 z#%mTH0%Wi?8v>NuP8`+paGLWJCy*?VHz5UE35OS0bET;ct~9R%etmnscjv7e!osi| zrRoD2Ml9!(BZ@G2*rTfL`$bHA)tJ1+{uf^ht0+XQ(2Muye}MIjKV)l4hkr~ofBJ(F z=~ZJLwnz-(%&p+@GL$;*Rs2}0KCI78m5%Ot7P$7FToK7KNJ1MwM65^5Ep5{qoKx~s z%g`zL3KRCP`)4}5gb=T5B71EBP#2#HmyPTYN*+8zKh<3gQ90A*?*1o~a*c~Xo-XhH=JYW_J?4PK*zg!*k`a^}Zx^0j?J-_hk zr8v@HK>(?}M#Ug{8ILy>?!#N%x$!P!0oZMbe?BiFk;6PZR)^P(V*jV-wgt)GyrqZN z+uISm-1bo^n0XV^ytLQ=>?JB)-SL-lR ze^P?CApV*~N4E;)OWx(z-eV^vwTr!ZLDT-;+PP)i6vzx!4Bo(--&kZ9pN#z~;tCJ2 z7fs4`=1PjtlJ_~gKa5$GYe8e8uOg@`BrfcAC++o^%CVzP>K{e~L*$wz&`gia>qb#7BX+Im5OYivJ4`p zw9}XtACm;H0E@HiLGM~`ejc%aSj&v+RmL^FX6Vw{EyL)P(9W=Z6ym=Zel|?eL*^!l ztSRJON#tDv*H)b{o#U(B+VQ;=q(fq%4;Pi-cnm=*U~MzNbDzM@S|sShDa{V$fBhM_ zu;K*Ih}O7$o7)b&1XBB%#2E`hm*2^>qR$zmtZvh=0mQYZfphSFKi8pj#1A88sF`8^W~G~&`wgEv^A=TG8^cB!v|`1Mzbj3#IX)331+X9UMxZN=_Ck;2eAjc51( z9qe>^d3`^AGV=8S@l4^Y5&GcOf3i4pMale3^1ML8poz*@%ZG>Gn=8BDP1nCAz8GX9kWX%XSEFr4=bxO-I;u_&znrczk4ZP zxZ{zG)^prD7+JZokHuTIw3J4Z;JML?6dB<1WWQ|?60m*PQ|kj}#lur!e}6V!Gf5P< zc{PKx1Cx`fn%(IeUal|?;uQCPsVnf}Vb&nXDf>AoX_d_bn8RLDuxLKGFQtD`Ttal1 z4v&omivo_(S4-~t3qa8%IpX2W)Sa-~rLWYq70u}bQxu{XT|~q!d63LSqo+qGgVLZI z3=5Y4VhL(Ia$s_+u%*pjQ@hSHmfs(~WTP0CANb!y8!9nZ0yGL( z;`?vNr4KtTYG8ooejkxkPkL*=&~qcfJ~t6dBUfFir&P-Y>DFQ)e{{X$t2q|qOP;S? z@5fWG;UE*MNGb1F)-CqL%~n|0-sM=;ZWFOQ=lw^JvQJz@AQ#@R$H!bQG;7GUyt*I7 zG;SNPpSu|v0s!h7sC^N)iFUU_lHV&q0-*;U^g4u8mDMGW!i1T*G7fMh+%4ql)uJ^u z?|3rVEtMU|EuNRIe+T6~dnlkn1yE7y_Nt$v@|zaRDT)-*Pe}M*h*J3~J=gp|YRvg{dAWcCvS7W4bRqBZCfoC0 zjuI&B2EJ0p_c@HTAl}AB1YFi>j?3dA4K+^S$w5j<2Zq2ve{<13xWHXAg*DB05F*j$ zhn`!IoU5A4hqIwF;T?~ewMx}gszA8yRp?pcKa<6umcfRPVpLR2gz3&yd#lEK)F4PSo5$|forGuW*P$YE||6U|l!`f5>xe}!EXCUJ&L#cjs2qJ0m2;sMooh~D z=_9C7<9}+5XDgH7;y-NqOUj`a8|2EI%?l-S+Z8m8VL3+{6f=Pj+wTmC59a>v=NqJ zCR>|$Ko-~c+$`#rkyL$73E7b(15+oS>R@8@0JOfd`fIx&@ZTjguX>vMe<|3KUPR|( zgWch@jM}hMFcEX?T9dK4?-|8RK5J=U)0pV{=@Tm;n!dlvTz-O!=4a{0A|kjuGc7y4yrq^++@+RgKUae`-7}X~n<`+33{?blXsX?w=fOvTeKEiqnU@gR0)ID(pX( zqajL1i8Eq@`c>&GcVhYEUfq_=aw_02m1N*=0cr1e2jEXp0Xm}MAzTBk$`@blL4`_V z^jj&L0WHek>yPP>2dsV!d1Y0ZN^goMGYgozLb}--No4keFDXW_fBzQ%-A59U`vF_9 zR5>QE^X`~JvM&qT&AaMNTG{;Di&j(IzAcykPuw#6>{7m)J}Mo{S^6|8EAMp}t4gV@ zJm`UjCE6PpiN0%4)G)nB%!(0pttX#sA9=KXnBwWVPgMa>XQdKyPrGllh6>Ldi*9Bq zJ4FvAXWndfC4t1ce+~dyN^P6H-5Bw;bnT_#NGCqI(bKYofjNkKk?JXmXbE*>txSq$ zf-CLbsy-KdQ9-GMQv&xE-p}{HF7f0Xl-ZJqh5FrEep$;xhc0TTg1a$7Zki-jc3c10 zBb}CL59v3LcWH?Zw2<6^SEgEJt1a9#$e^$sxLK(PN`jK_f6+Z~Y304aOJQ9{QGe!# z?(|VORy1MQZf{WJau0GAfARu9^40z@HJ*DpN<1OJ(3Sa5GZm4DQ~I4F#vj$^jKAlm z@Rdjd6la?|8E4%@5#N!<^U@!?s?ZPJ+P~SEe>s~`9SnB*$U7l3Guq}@v;!c0C?xjj zevUi5LKt&^e@In^_-k$6RnwPpplSojB%wAE9?b*wP9oy5LDkQ|VCJ?uuq7){ed@K~ zRJpNI9VGDfFKV#L!g;cXYvthHH=)8wQ}Ka?VHGRYVhfwd9LL@0QA#OREY02S70nhNFyN1bgU%`rkCB<<{p|w5^r_ zC^yPL?Yb≮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 delta 88574 zcmY(qLttfV*R~tmwr$(CZQHC=u)>OM+qP|2oQiE$oE7}_?yqxB@9E9fnB&GZ3R0oR zBcKxu0kmqp*VB__J`QV6OPLhK3mbaUv5dS)IaeoZ*cg(vd2vfhKa&*D2cY-JLE!lD zq50>jIvxa!l>#!|Z%~5$NGqCqykX2`eoozoN~FMAcY5t~c7Ld=lmJPhx!yd+N?eAY z_@e(_j5BR13o{rm+liKY_#OE!(`%|plz3Q407%RHithy}JIIGM#80+ke3u2grb2A&?t;uE+&PsLZ)R=dD+y^{s*kL^haQ=dNASEYLEWU7MyTS_i|Q_aS*NpkfOI z2{3dsxqx^!!M8FEqK+sq;jB%vXy)wq z@v_=!iJ6>yD%H)*4A&wPg|%5^x}cP@_I6c0sg$P|8RVzQ8^`~x(0MB;x+e^=AOG1$ zv10qIX-Uigu_kK(;*UwWN&+xDOX=vIB65fxcKoOvR3&lB++x_q69?~Ezzp&E1wb@; zGs|F~HN?|Ue~2-Sm}Ye_Bxs1JKr?KIb?PuArmsKkXpwIAf4y^IiBvpstI7bP3M9vBzq{faeqq#AG)wAI=x}tN$ zKwjqd-j&UkIw5cYeEBG8b6N~E%zq($f~zu7-SyVQ)x*;I_x3EA}g0$;>1UwbTEB^eO?bK;Riir<>4D8T?XiT`5g@%wgy3NaH{6>ieA4F^OO^%8ONovT1`OW|VprpxdyoyfR! zY2Nbs78jfhr<{(@r(rEpw+J^inZJ=Tobo8bm&+x=GGr~*%KR`F!=ghBrUuN2%`6@GXb2GGZ(1yKsBs0-cy&5JY+!^A3x#UiXb` zLd_zH!MFc}=SIqHKF33zE%F*lv)YY}cw!pWi^l+(;EI|f0Lt5k=Gq3dPNEA%!CH*X zz}MAs_3<*l%QSpboI`=PGOwVGW8u~oPX;nwX7QbmQd(_cOEZ=*dfWoj03-9JL(Z)i zffP2`4;z~k^0AD#i;aGZ$SDTXR}YtJCxNsM@jOH|H;GEscVE4jI!)zQN-w9=Y=Q1v z<_KbuAx`L~_~&>6Lf%%|*-FS8R}$5;xkg7VJi^Bp8a2NDG)&7lj;En-05%OqO1b%p)jjKQqe#630y(pArY+4%3ic@{g(N= zkDwrVR1^vq1R0P4Gi9o@tmtU5Cugg`_gEJrs?=})N7&je`q;>$?bKnONk6L|x-dpE z+K)aAHD7?#!-&(3VT>0l3aD1ldI<^0ay4y@gKJ18>~9(<4hvg_Sf5-I_-;cR(|I@e zpZ6%KrOLf5nbM{lz8O+A!x^*@)i7Q9%xTC0#9XJk(*jw5H~+cLmr}0x6f1OJ=AIyB z+J`*9vfh#isz`m#hJZGaHiwL%h7}($uKwG(f%hsiT&_Snx#xN%aLgd@+?eFY$~?D( zx{ukgRUrYe0JJCC(V!GZ2Jj~CG!2uw>_Cla7P{}*vBKIwpa8>xi)tvcW+Q*vrM`6E z{?6iPY1=;FSNgDg^iB1!0fp)o!(`TAkxVsJ4&ux5F&VAgc!XF4n0Px)WN!-0aIoO` zBaYmqem(bj1QKDNqI8dpwKw*pi0SNWqZrAbIHn{L+F*O^vUpWq#PHkU`ObM<47q%K zc;BS7RQilmu3SU7UZ+^oD$bEDlbyCBZmG$!JSAel?sJ&g&R*S&b-W`ARGJ?FwybX7 z15gZRf`IoZ!{gzjNm(|+n@Q52digh}iJy>}gUD_3^p4Q&*1#GKZT6azFt# zu%9vjaSaz(dQS(s9`0WY9Cd$rxW2*WB5_$26ayKM;+a{zShERm{~I9i`{U$Du6Y~q z(LMJaL#IINEj@|v8yqU4KI5 zjr-sH8OinZ4_3f7sJ?T^NportS~>#?JT%z%~8r=*4L*}OXVzG6Gh#+2XHm|6&{vbnN}%KKt=ECC~z;`=)ZsJb}U~|Rt1Aj zT=1|iGTv>nUHJFz^afQbVeI0nF(04CAQ8Sn=_IjK;4Gai+&$bZO&$ODN=AXl1LNRH zR%N6C)M`(=WwT&x1L<2rA)|~)&WhM)tCRb(f24Z}j8xF7JE#rRmK*O@L*vkRUbSRH zgx*|kxyM@s-=K;zTaSDS=guoJiT^^&kzf#eV2*H$v&1N-Ny)fJnPvC5#@pbxEoh(oE65|Xm2XhZ|b+`o&_z3(tfBn$iq*of|ZS_W z@YXCvzpv9XzdC@zN~3 zS&_yiS1{hK{|%M5(7~e^bVQ3!AC0HIETF6U));LKSvd9sAGy&JVf)~x7V^t zt-7=hAPK#jcy=&00b`|A8an%(LAn=^waT>Pdxl!CX&xLF4h0_%>jiFjW{27qLTDg} z2KLNV-d_AC^p_3Qwle|rOc6eFVZYrBK%v`%3H#yC3vQSPOi^x9M1t8EgS&3kC+Fw$?u%=7@R%)-2*yga_>WS_`-Sb2TE|M>KpUYi?0)D|O z;1YrtLm#@B@L9*0$`YcRw&5O~3vv`dC5?AV!m5`C`ge!h>+Dr}5DCqe$ zGxq9~dxtd*AmB>pE){W9sR(VA$|KIUhv}6!V4$*MTFq2EdR0{*iL%=xCHODgixLDrT`9xEzWb9aiwCl*6ZCzn#VY)yZxk?B_I-zA2Zd z3lg&8wxCIdBn;6OixB1LeF4_ep0y(=w2_To`#`{@?v=oBmMfF~>BX(5vZ41Qi}-@@ zBQg7oa%J~Q_6%az-D+<)3LqD&yhc6DuLjO{^CaRLLv+5S?`9d=YR5JN$G}^8w$zyh ztvI=>{}ZgK1^o!=K6e4*20+lm5md~1f}T_q-oS)Y3PjtAN9dT0yosQp8 zEV8t>+EfW=Dc^`>UQ=?h9)g%H|5PvpSNMu$4$tBN|ymnJI#7H5rvGj8=R4F z8X`u`p;Ta{f`Xz`X4>X%UODt(QL~lv?N%q-0?>^Wd-ozLkIoXyc*=VB=5n;(?Ri)0 zkOcBqQ7g5zlzVBg9Td_WVu1^=2;&eV`T%&^duJDgf4wIp)6tK;xvaJyp#<;8ouKEy z?LoFU0;VI(BcQ)BeQHZ}E*B~8X5 zJfvw|s9a(KeRI5M<@Y(Q`6|8G+hv`#=IoQ(%&SDHvIo%PDqj>~7;xfw@%8IE+U=4W z$JMFt*$50kp&h^!%`@i=d9sjV6#!nM0qBh3)!v&%d9cI3NGD0Rr>@vbruu-&*!Q&2 zuog^v>Y&8YuTe-sPZWJZ0#XenHPG?03Ctlbm=)VY!NthkcYnmH>II=AaTrR4Fx3=r zoe8l7>tL%J$QH~eY`UhW{=5_}%XUp+DgUj0I7%>1pd@O7Fv!aN_T{CfMkPyELH$g)fg#(MQlUahajjSI zPKj-9TJa*#xo-|+jP@f8fDd~MNxRS1ud^7*m*a-lyyb*FTO#_HAZGe&I)PIjQE=T?W+nqWwS*W z(ofx*C@p-6l)(H_p$3o-1GafuV$!xKVKZ&@+}9HwoRgp1nW4>;M)t%IWCTo3Nts?j zJhi*fB>~B*{l*D2eYO`*NXore+FV{M$27+UoH5Fx`_@*{&raBk2Lqu`Z<=Qv)zNO4 z-jlHI^*~QRY_vK?b<1%QcS|`Os>!V`0daN@+wZ@wzQA$el0iL^g)nG9S&~t>=mDEf zn>;A~FWPsBdNsH^w2)`whqc(<18p|sB=8hrg)$0cH4c#$U+|-cV@6n(b^&HvucAy|nrXc)o^hxsG1_@;TP++f9wx^tzyGiJrQT zLZA4mLzcl~GYJwd10&EGJC3^^++OoZ>Mk6be&gc>ar9`^c*~`#MfX3S?Gg>OytpdU zqh(yScs1`;R=7N*)or~F$6(pVOk*M=&{cj8;%@u0M?Agh*u@zewRyH)fdQ`4g|Z|U z*4qT*#?<5#))<5=GWm*QDCC5fD~d4kEgV^1PlDkVHtO2Th#V9J$2M%=CY^c{{pH3t z1K&#Eem}=oL*Mr0g15CzcUkf?{935?@ZdI^!;wUArHb^xN-d!{K{$R`c=L^dds#@2 zl||5d(mstC&4C%tH7HzK*aR>ye`(<=!>p0!QCps(uqc^-Xqy7fZsoAq&!g7~)n#<^ zx?{pZyjMrrC+eF!1wpdm%`$ev8IxaC8+a4d$d9!KL0V15IY`dHq0O4%zzm)H$`a}C zI74x&h>!Xpd+MPF)D<5O#f5AnmAR$HW$+Xs(m{w&fOD6J2AIExeF0&k709=4M6Mys zhTAwjg{kj!zvVPvPCNVm8dntm1iic{o9PYVcHw@iX@mMRPHNTxhtR%X$8bA^{1q7n zS0+*MLucSzI|50G(&(vY@~)$r(493r#&k~zOrpJfj=KDdjPWKZcSPIs*w6E~*73p5 zCH`kG@E+JTJnOj~#%aJ9);K7m^bzcfgp zfX%i7I8)}sZ^e*KcgK0+QKa}Vin6{QJ>xJuoFRB0nbP^9UE}TUoAv+;gq!}no*<#g z;Iebv8s;IcC|;w$5B)vH^if}740#l9VKhC;J?Q>|6!?H6Bf71x8?u?oY_Ya-u~mBw zqhb@d6G(WM4^e=r{``i^hWSJJi&96qsCgTW*JG>k0=919RXM2@iTf$KH-Hn zs8Q+nT-g-IP9 zahDn4|KGDXo7ur}@{+KS{O=(k0GFJA1NTpvs4&t3wzc$?H(4+OZtL%g*=xsy`k-u) zf7dQiA#&(N$_A>e;#4eik;9s8*6+IJ)Tw~tscA7OdnsMr8uYpMg(kZXO^y>euTAF- zq@s(8(3F*skKvq5SnTlg?Nf|v=fhfawH|fx@=ylNax-?c8*cc)K; zcyR$Y{y4jsEpnN%D?iuiJmX>Xbs$hjWX1=AN|j9<|J zf^rKa7lAZkWlMA$SuVk(FDosNJ}q30ke76@JsV_J(H~Gop2$YX<9l43hG@KPc6NolF66)+^|h zHouC-$`TedMa8A8crw;H6)#@o8R_i;-wY4vh$!pOveWE0V>{%SGEUsU58x`t-o>a7 z;FMSi10wU(3_$zkmHy0)Vy2jH^!#vyw9VLmPqn4L0BaU7jHDOPb|rMsFo2%dGPwP8 zH~dLGRHA^V`2IRg1tFp1eu)4LH$a?Iv@)MOg--*<`G2myS6knClk2~Par2DS>IXHZ z33!&txdDc4Iu3n935!Ow62wFr{p4htald$CpG<3Pi|hl%MFgKf`mJBSMA2r1gtIS& zLH{$2fvg0%6eQM`gdD9y(PWMHXQl+Lz)x({8goKH4t#4=P6YQ^lU!---u|EE#XI-B zJvfIttN_f|GJI_{Gb#%Xxng^dtQAdw2rjEl#)eNmu7)*tD7-$GRqzhariEEG9S)PD zDhBwSX70mPWTtE94b#V zhhuS_1c3JD98juYF~D%+?Wq4N&^>4lF5gM_2rxIWP~Nv+L9+x7>-vil;=b2E!GWJt zLFZ1McU&*X7>qf{lOyDa4_9_dbt$0-wnjboQq%#atEnzpj7DQuw?8A)s!ON~cuwWx zt*^ijWS$f12$PV#^Z1%H2Ee!b5C7h(2Y3dF?ED^ABuW}fjDbB70}8AolEyTf|4=Ww z0KnMI!2IlJrp%eJJyhk3&yh>f+*u7hM5wH7S}fby7&)oQrr2BAW6dnr|Ed!F3Wg7> zvS^zKX;iSgwBK-2Dd$%ceX%^71IC{oHfx517!t6kZ*11MrFsqM&feYgVwg?S4r^T6 zh#;PTj&jE&&C%!Xz>WUSX4Xt(w!dWE04SJerLn|O*WrS(%uN=Cz~;!hG90TTr?N1W z%VHvZfMmMiyrRd)<-2WYKHIGQiGVT)@$BV@<9*rD@-$8(?T8l#mD$UFUe3k|;cj<`HR5&0db^2PAC1v6BKoLXZ8(&BehB$b3NFgEs- zu>2AoYKQZOaf)#jD?$n5Z7#aB9ssCu=H|PGR9;|D<>0AH`F6nMsxi94bzi;n^=-2{8$OaHx)}*p*$ZM0ec!Fdd4r)ulP5=RJat_vV z->=PtO4ckt#`Xiv<7e6OO6*kq=h!VR$6mqB+VQ4uxi54IL5;BRL7%{qz}wXVL5m z{TTx%SOH~zWix9;Yp^lF381euy8zcYz%i%6!rWL1?pv_?6@b%s=RA#>*<+XvV9(xU zD_&(AmT*amt?qWvyIrdhFBb{(Kdr|j21Y~n=j24Dt75}Ji2k5itCA8H(`g!B1QKU4 zEN&;4kUFprWf9%gWZ0-VxiX5N^$p|p{WkDtRXy8 zX2tA;gZ`-+7|Te=pv6KHq!UP?C8zR9?iMPjJA*DgkCz=7^h08afVQrCS~-8YZ7S`i zc5rGe^Wb(coh2VClQS`+NJ6+%(16h=PQnRt9%k?=5VmnT__dYQ0pPD4uY_*auM2%vHUQP(CM;R{I;S=5DJtTM zo9DQ4RQ~Ak3{+jZZ&q8n&sSEgeK0tRtfZ!8X=1&Du{*$GqkOcjh{O->RGAl1G=Ps# z6++~69p(PdG8kLw(u+`K$aU4z-=)~s(HhsJ-;NM`~^v~B5I z`|Fx;+5SWqkidB@1oX23WIj0>S{~PY>do$>sy-Vjm*dCkFw5-PBMFY`$4rTXzT-Xm zTC?ER!D7>!Xz07Nw$oaRSNh*CiB}al*sylwd%`#LReWmZeg8PUDkBAR(>5eb%6jYs zZgXr*-byhYBj^X7lb<+VF8RX`=C~keBeP+-W3q33J%`|YK`Q>(IZp1Spa$hmM&_bV zMxjIih~SWb1RN#c^4Id;40?)fU&Y8pHjL0pc2TVGygli9Q3wF zLq{a@?jOCNdiPr&E=+bJ$qXg2z)ZfT!O-erj8QD3!k17T<`^t>TWu)mssHSYq3qpP z%Vc{IivQ-}O}{s}Z)N5=O&J!btoYvflFP~hEY9!|7_ZK<(Yp#fll&2k1I%_IXu~21 z7}T7tls9`cYwW9q$@?{pK{#hG!xG zlxzc;{9tqxB&dyip*l{e)8G-upd$--jT^LQqA@^A(E)$kAyHea(#fp!r*s^a<;M{D zBa^)|@!l!{lrDBfpbC#qs7rRsMP!S#o1s-IHF($5lq|3{s~7Te`2>_Ax~wkB*((1V zt%z{>RZ=jdlYHVDwoA4isa#kMY}yyF$cVSZbioG514CM^Jnp`*LnsSGY;8$XY5CK_ z@peLjSmhU)fXpV?%3&xcYv|};zAF~C4NFMy_ZfE6)uL7^8D6D4(5&2W758W(!)IZm zB*FA>jQW%gPtSEg0t56tW0Ggkk2`43*Zw(0%~V9W+|jU(Zw;zf#Ro~RJ&qdCuYFOO zyS7stzpWweIoGu6_)4vz)>h`;`zG!sUx?W5(9p;oj5yWnsHP3+UHe$t(EY(h^vRCa zfJz+XJt@P2NzbMqS10VAG%RgHfklb>wy11~h6=491sWrt6eo0`*#+*AtROx! z$V=a~3SJ;khTSRpK=VH4{LTUxx0|(6VZeU15Rv2Vn@LkHT!kZ{1Xf(b`a#(du@l0Q zX$~aGkUG%rxI&w1X=B~`1+R(y3w1g``;C=1FY@pNBH~Tb?&c!$>K_NCqmM}C4`5ht zK?SEw)y${Ok$JY9gZYZ>yKBy)?Be{so;+ll-HwG;+i`BNkPW<@=#~H$@i>P!4<#>= z^uF}V$7@waX2pF2G&>vA2l*H1_um85bu|c^bOIZlpd8sq$?f+ri8f=5gsTLcNHk8R0_YcUg1WTz~D2kWvSD|LN|s22AI+7Ty@*(E|rore!AW!Y?18uN1d%PT@>xg(Ocj%+TC4av)RQF+6k;BsfbU}{-JJKfU& z@M4Mzjz&+0U@Vnm{V8=s7mL~=X`xa$GaSoRGzA(94K5-U2K}w}-pE%B)N)he>x*a5 z16EQfu(M?vQW+77)a$UZC{blZcSgo3ZS4!IPKUt(c*a1iRZJ61WNUvnP}(4ekllMG zIwjbU^fdd4Baprc+ULjmDbRJ*V%90Z9~F)t=veKtQ;1GoRrOh2@La|OgSnK9uvRUu2{&cV8QkLq_|vs z&qd*2k-Yr04gFRPT`tvg{)Va5MR5Je(-7^$uFq1;g_*eUsYoqSuGA7H*%)2{(8-Ld zEQHD9Fd0C8CLXGcb~`7O{5n$bC*DSb%3?5AF3=xx0Sh9c)X$+K8;JZJGw?3c)~8h~ zwF$^aFIIqC0%b5x9hYj&dMZO%i(1NkKt7J z%bM!~MQ0Cgo*>j87V zzOvimEc>Ek@rt~U%v=-fl%ZXcpq8Koyv_51Opsx~8EzuTf78v&hy}{=Pae_(44s!) zF#P}JIOcy*=KI>vt(`9=P+3*!EOrbePr*I{dAiO>qj4O4gAUdjXQw^$LulK#= z06nKBC{2%!L*I7K{hGMdMbxs!P?Fyu_ftTLSchP-gQ*&+8s%tUBv0Vo@Gx}K!xDd! z@tBKcRlx|)8sE-__L&}X$Z;YAcIvQ5&-MgjNMIF0;zJQG;DPimyUVe#J}MHYmTO(Z zU*b+v&V~M}9oeT|55u+H^oLl|<4fr6ddt&I)%fkU)0Q{R8oHahHWTL2u^JdHFTkL26!5Uw5BoRNAu zQPg#iq1ch+rAe1}xY z1*S6+#xbk+$qvD+5OFA2uz)e6(0qq|YBtwuZ##GLZQ%6$v`XMsdwo zJ^t{z z|3K0Jm;bfei<4q0@0+yU8fQ}2o02^!LMFuWl$+7ac zAK@cCXjh77|Ft|8{BKB#U9F(7P**7BJG@B9WI*yJi!>NF*MI0oua2UAAsEg9D5Z&uYCEtD0V;pVyIdR6(y$esh(#4tXRwWDORV5_~ zq6`YLJSlv#x!=j_B;>eaS0$_w__{2v)b(w$l-z-t1SqI*h-jr}sp}Q{u{=+DvUpFh z=N!wX2~zkaBAN>T#A^3gsVK`k=_(vTc)T&toMCKqp1?+P$R2Hl)i_N%>JY+lGAMqh zu0I~_!|J&UEVy?IF$i9G2Hfkmq!tlvDFOK>@z~8QE)Jlp?F}eM!OwB`GY(GU|vN*oa?p(M~LK9&{rN1 zYbMqtb5Q)nw674BDj@NCrUaz4+PioaW<0wnaL9X9sW2C5i*qO-DenbwZ&2U+RU0f9 z8Miv+=6#3c6)OqrBDqjlw}i_IgruV4F6L@Ts3awE`n0S=yctbV5TKM=jYwi#b#Sq) zdYe!*r=SFYiX_^TWjT{n`jMdO3B(u|?>V+?KFxKvTofGl9|DjKlX%Lb#ph#~&1HEr z4Qpm*BzE-=vwk812rrH^9-#mu>l1~dO9e}o^9TNU2djK%C=O|({-2WFFD=0HzmG{? z&Swg$6t_0sf6q^HjQYn;9lhVz@_jdYKkvo^Ha~v=d|aFRJ36WII~-q}0RC^s7l&VX zt?s~s)6d&{p%0h0)HymMh#Y(IIc|miApwd9#;du%?N0%3PuzaVi)JUm*eb5~#}B6u zF^}__~XAFMY1zzmKmcsYX0Ss0k&hKXX(f7kb~f8znr_*1XZU_sf~GRvr6^B#Qqb z(Bk{>m#cMdx>9PGyf5^So}z?yn@n_*HDbEgM2%r<&%w~@G1-+j?R9s}k*BR`14~!e zNu?Qf_i}|wxeyG)be80R)?~^;P%H?w1<>^aZcdj!4S@4+rH8Ho`x*RB(bsQ+ZKn_R zVXai9hc$Ahm`q1A7bY^*yfv+6dGLzWX*Rsx3tFig9Ldn%myLT*dnMQ7$3d|kL;|4! zfLk5Yg#-*;l85nQ!(ww$8i z%NwH5xqqEB)RcyoHZ1DnCPv3%ZjbzUd#-;tl(0GMkT~Pag+VUd70yf7St1)&*Qu9j zNE_bhVP$9oVrqG&_=qc;CURiCAM~#MqdD4%X>TT?`SVC`{(XbKrg$jF-HXu6+|}L4 z6miqv`0-i3M!GWTP_#4Ml$Y4TrgBwH$14Q+dK5jTn$Y06njqcmA-v?#v)@i=GR@4;K`!{zc4*ekL^S<29#H%v$SLPGs|7g3N=!>2Z`2XK4nTE+^ztCq?xHEA zTyIJ1vbj$)8J&oZwT4Zjvpnm){&rqy*D6R3QpQMr=fwQ4?_~rm^Pu$3*Z*D+(m7j7 za+eQODf9}ORT$I?OOapC8q{PzG_jBPV;pZWX_b>(A~RvdtGg=wa(T0+EM@|U@`F=+ z-?u44kpCFMf<;~y4og0eHjFHlo%=xGWutGEN!Ghj*4utRDIRz z8C9P_4^gZTzoi*qmn=vJCcy-@a;9f69-kQAgZaG2WnMCX0{$_l{qE_|}{o*xSq{X0+W1l_G5>U+bj>#RyGU8P#eO=gK{3g(FX2 z-=?A>d$+(PC)0+<7EyJsTirNY{A`kSuo7lUAd%@rxPqU<&aWP5ZQKV63r`namNgkh z6^|@ODjI35H+HdgOAYT(WhHegTM6Q5923O~7R&=SHVs!VJ+FB@3>~$>@1HaWin1DN z8*d)d4Ohui{(!a`{%?>GlcuVp;Q)Ow3TDhLMh<$(9k6%9fA zu~Z2`C#*B&n2@0>oE~PPd}|mvCs1UN6HFBn&v*OP8Kgd7YwA~&`DI86w@EZpr`kOC z%RT}geqQRib0!sBN3%ve>YxGDji2o5@GYx;UY@3T9{Q;8aXAO?+^$Y7&t3?YM*Khths(!o3KpX(t`7IW*Pn~ZM-_k6|5GXO@-Oo{i_EFY@ z5WYSjDS+@Yao8%o2yAPFXK|ty(8ADr%NCk6Z3?-wGNoHrX>v)X;ISBV!l1^ROO^FLX4q4oHx za<{@5bN#^_oDyw_6?EWMeb!0haKu<(3j4a0qBY~kyDB>22iCo@v;dr%gw!TQRsSNF z)HGMJ(3l;>^iY(A^7SYh#x-zMh$I()QZC#(OaKI%L{o!$O}Al zj2&sdfiqdl=;AsIe z<=q)&5w?r4oy78$WG?1zRGZyLBga+<{1}O@pooYsn0!F1o`$yV^L!T~N7hG|4gY*V z*7v`Infh2cu;Vckb3M8-*bb06ubZm~5>5%{z81~Sn_!4x8f)EmRZaa(+}fDtm-W$y_<8BwmHAmyg+y|Ykb;xGbrvdJ$#QoojFrt8&0lk)7M z+gy=KO3ABmSA)txIdkIy*V5(Xpf}F((R6S(XtJ;(I1{#^g_EWh`CINmc&K;Kz`csm z3}{!beF9Cg$1>?B8f%`&@IheLoOU$vAlAFmYzTk3ry-UPmO|m*VWJs;s08(vuyD`k zSvTUf=AUb;>|Kn)m9jUYfHymnP1JM$inl=y6YFF^|zy^Knv022Q644CsJEcZYkug)orw-|eE^ z&W&pLQk$CO6`y!9!At^x{oWcV#5?*?NQFXJQ~0HG59_Mgvg{kZM&x$O@w?4Gji$`D z(~2Ow$3<=Kn`U zjNg9J`*|R7K0nO6ghVQBnl2SAA_bQH?m($Tkug|*Uc06AsxC8wDML~;E9bd?@HOry zCJsxMADRTBD$fs}+c=XEPU<=hB%J5K(BkTtwOEpHW~LpbL^&{&mK@#`o~_N$ZfFdS zuN_c@gIHp&vM}15 z$gu?j!!)IYBFk@&9wGF)4=oCh2JVFh*YP7H4)@N;o0EfV=d7-!<6qWmog3LS-I+8d zLwXp;86G~5ZcxF_xwsTB9yJKRL!#S^7{nKSewWrW;P18p|LD+4z5%?e^P*;0D@;1M z<`JuS%fltJ!2*O1)!Kv}7ap67&(kIND+Au29Dlx?S*AABMX~+lhn3VRTjkkNcwhL( zLZRUV{>Ou`M5V>?mQP&$^!Pa^8<}nByuOtbzVny`1FfJp@D!XA(g;FB0e3ulD z5$1{3`ZsI}DxWl;zp(Sy;Cra$d@G!o4vC=p74@R1GC6VPb{VV3(t*|dFq|=OSQ$v) z7)#sLY}>s`LQDI~8BDx;@xQhamq<@%cz!^Zg)Aw^G~$Tmh?~)3-$df!{cnYrk^Z4wxRj8@^9TU zBkOsAF0H!}wfNiEA%DB~xj5cA8EFTU+uP;CGbLsBL`zS1!A9!?v^%LT-B7OkFD+57 zvufFclhhp)2Mv^@zhh|jNF&Jp5gZ_Lc)vI;ZH)d^ z8mKLS!`=}lj+|YWlJXLwq4rRhV1}_@2%6jx<3^cf8FJ_*`7aqX&W3F2?EsWRXJwWvDi(wBuze)3MOUKKsImuJ#^hJR+3j|o_xQc);-?@XRb(RuoLpMMmOR$V}Dt6kI6Z(hZ0P<@xlzDW9Of95@3YW4=nfJ7Cn{%VXq3j+G9gpE!~ zfz)oQVu}e{r2*UZ2t+@2V1|$r?-L@TH>}T`5Vfu9W~_7@jVvG6e$3(D7fCP#P?Fs| zpe%L+`frh$0mAq=(i*f5EfVJbcUL8DBoG*P%z9pyiT`QIX9-L&4(|Vez7=gn=YMc- z@BeNM2uJR+HJoG@7}N^7H%Hcq7R6K;`LIazt4fw_0si4+sj;cZC9&Bz?_abf%OtuX>%iy~BmAh~5|!w~gqtg(q<>Gl@zB^s1CH;{hWOCSy#u;XZ- z`8_*%3FH&z42)rvN6~TsjK41B5GG#w~Y8VJ$}_%EPutW+eRIf?P~DO*18= zog5n*46(819ISyXU+l)4uZJJAS5F^8zsW}FFxA(|IEBHoSsB8lqVQ)FE=<+^Wxzsv z?6iDv+BaE9)(#KXoZ}Bd-HEP<#-{dhT)vA*)2^_zrg&H3a!?xp6f@?CAf5XQDC<=& zG*k@CXmTLe!i}yn^)=%?4wtROpoIts5!sOy_2Zg(xdY?#dYdf?`1vCy9dLO!zf8e$ z3qoZb7FDn{3Ei46N>c{O)~6a(d<}|d4U5o znGTtuA~aZp{udX3iz?)X@B@0df)&ECNE9#{{D<|yfe^JExwmEU{|9wIioYd<{W$N! zfqy}YIMnxWn*24VotNM24IAO?!OIvgjZ@COw{z?6rbBg;#<7+lwadDlJajpJu)Zas z*ch=N2@xs5oTV=yA;Ji(wb_q^2+hHg|0)R)N@E4?_aY&JYs`)QKYvPy@}S%6tbq+I z@>1fyTt)nhf|z|v$g8JZYPBy3dG*^Q7kX964b0usY%3e7rwro=#*YNin<5Pc#%Y{qUR zrpWt86y{Ev{*HZ?w13NziNZ~}A3nTmF!Eg0!Gs0BqX01tRY^gB*1*KW7fJ^GfnvB{ zf>J}B0ob&fcE;fvZrx%Y9g{my;dk28y=aT>4p8UT*Trjh#kH za+(acf=*e<0j+1XaQ;{MW@9VZLj5&@&L++7Et;>&Zq&yhTz|vNuZn2fmY_B?O8Pp1 zjDladD@}jZTI@Ao9vdLwja!?CTjqnh)54c^Re9#QxZZJRayf25J51g zD>A+|sU0Jbr0)!sd$*IpKogS#NfZM&HZzk@Eh>LiO;g)25WV|X=x84-^l8bt!A#SE zLusjJI1nadVgsHDagdz``s=&0~hla2zom9@~E+G-Y1+BMWb= zP1S#v&Rj+@9IdN`z0sDYiO#d5;8Pad1{9DGL=mF`3&4^HhEpNY>?SxnC#ZmrM~GmR zDzxs7-XN+O=8AzmN8f{QzbRuAj8n{0SH?lrHc?C&(cxiHIwaMEa8a7hO~QTao6X9m z@s5+SDO+!U$#2SMP&0`&WE!9rseTJ;Au)g93?*Gq;b3z*A|67Kx4AdX+8gAq|2iQo zc?KZSSV7FUwpFqLJ5-{PR2mDR9YBYQ14p`M&I=1-P}x~bN!L$D67fKi(?|n(JW)jW zHG0ew02EV&Q_i;^(q4w%(8OJgU*w$gPKYFw#TO6*OzJK_M5J;=h%@7!*bxnT*nNLY za6wr0bXW^JCYVdTi#@xpd?r&~Rn6wU^9qljhH+a%ej3hf@@2a+C5~btq#Z^P*29_e zZva+%?aRNc=kwZPTvv-L=Yn)gpFKBa594-KnX(x5kg427d}^ovp{se<&U^RgM4!T*7l0JShp*JW$wD6vEPFQOUp0nX6!S*-PUkH;{+*9oyrX<2f_7mxzot#B5^1#~X@_ zuNbC)Z!jDP-)NlGelkw9pN-4tJ8Qhx-B`XVQ5HK}TRBk&a+%sZ&HJt5a-_Ep|`ALx?aRG*pD8Sc#aq z238HT)sX~2ApjF|))8xf9V3wpdvyvEEPop62!n!oiZB?gC>96`A!1d?2ycYts7|qM zP8N6)rn2r7QRJ)?CI_n2R}$ltD8jZKYXB11V+?B?ol97i$v98BA&}w(EK&9l0Gu+G z2biY}?js?FFzS>wwibf!$%1xkRd5hI_5@5`1Ifr17`6?9WW3XSf}VE>Hj^d|9Dg#5 zdI51vSRN2{CV>D@ntVQK_93#!EEps#&)6IzYGO$mM$U?64#R|K+9KFSoK+!00AGxR z6|Y<&Q^g}?87U?KR@pfS(h*`LA>fSt3pUs=HYr&NL4F2{tuWjK%|Va`0dZ!qh&%!w zWM^<_7}LRL7(`|U0Xjxzh5&ZJFn@%Yo3*uOv^lw$nYA@D+7t~cs&5A}Dx#}Im6cE1 z$**2DqwVSBcy~NA`)0Jgv1vwo!P{Zbq+Rd3-Uu(gM-t&1h$Q zHMyQ1kFUBC?S{6-Cuc|NlN+$*-igxqSPRVfP`5K^W}**o9*RB4%$YXvOVDNAfatzk!PB)_QK zPx2kH^MpT^WVcMRt0S2_-DlaYz_ROO*>bC;SEVd5w7!q!US+YZ5Y;JrqSoh1Wt4B5 zg0EA?0o^A5AkFjj+fVspX@7>#`!sugEY054)4Ztrg=Uu41+G)}DYVX4D!Y_WMpCDY zleNW-`1E85FOebkv1ACqY&^~26!}<%fSD9VweSalpy=_yhw2aqh z%XqRpc{Rsnn&YEsjw{d{`0q_^G9ry7I+=ivhoQV6FYA&6PGEv^l^(LjBIPnP_u4KRnfDtj%dzcVNBM?~yhq zrMXkRT2lR3^emVdEs7Cg5oHWxkptIfND zY+6pOp+Ln40{DIj6g?-*Tn&?-5vJ>@m7O0in$A_jeAa086ijzhZWk~Q9M69*UR<|Y zc1Un}U~n|#&CfN*;>P05aWp^ouDCrZ3Paxi-an9nKMum4dw9FRTrcLGdGifRTcv< zF)@?TASZvcx@AxuO4>Dw6Ck)tVB_viAh^2+*9~l(jk^aA4nczihu{$0-QC^YU2@5p zcjla#`u^UckoD;5)lYX*1(c*ps*J*>cE&&nJ6k74RwfocfSkOFosE$#D+{BDowX@| zjfsVY1Cf$a6bv+S0@>M$894#@0NhR%07Vn0w?uz1fQ^NP7m*Sm3A6=*-<+lZV|Rc& z(8);6-5$sapfUOjDA_qWF&Y~=zPW+6<{(=j?OTedoxM94WNzW~rv^JCD>TGXs2mU`UqN-}@k_-SbVFfjD08oPgAgQjZ_UEe_(DseLIRijJ?alwE z&s*T1ba`<#VKpr!aaQI(YXGnUT!3Il(4V&d!;R{V8Q^bfZ>eTrJDa~60B9_nob36S znO$97narIXotW&v=1lh1fALeZ0679&?ZAIlfVb~ppf&I>VVrGE-{f?%0RF4MpDh8% zflPq5j=(=j5_bP`+Pq2mmh@(K`VX-;A)NlywEkB(z!3=iuQnD&j(_FKDJjVTY>Ys* zPC#2DTa&jyCnG0kM}Xm9wzp59DfPby0s*4VVDO(F^8a>$|I_B*)J5#xR;Fw1>1}`H z`oBA7Wb5qc@eghOd)X#-wvHf2C&zzP1Om)J*1$jP9sleZ$o4Orys(0_gt)32qukrz z*)q!8y{Ti%K|%bhy0opC9f0>=<~Jt)cKzS>)BJTvY2Qw$shzF0JHQlZhRA=cVCVEU z3^f1$oU#AuCE;vstzcvWr1@__|2N9W24wC2-*NvFq6z#%mFEAE404nJxdBa;Ku#tW z|5Ei|c4;T0x1krdHMa)7?Z{sy^*`sx`fXs}E*;RHI}5Nsq{B` ztEuugdaJ4WH{t*=tNo4Ms%ZX=-dKPB58{3E8U2mke8zvHw-uTE2eGoewKx3-WCbt- z{{i3VnEege-g3=A|8T$YGyeyCBWUpt_@==>gWp83{0DsFX!Q^HM$-Bp@U4^0-;ni< zrR_i98%w+YK#sRqJKKMMux5Q@ZT}DW#?s**@Qo$-AMlN(<3HdVOQ-)p&bPi!u6F-$ zzp-}yTg$iHzg`nZ6Fcxf3A`=FHSv&%D=DSe`Je@*tvN!a`12g7}?&I&&u_-k8cXId;eFi$-myTzwXhu1OIRQ=RpAg zfo?z(#D!TqlaE1`$#q|fe8h9di(x5wnT|_wK7E#ng;_`)ZzjYO%i1IZ3jXl_<(EeF z!%j|$PtPaO-!^~$Gi4CA_3LUwLfP20sj|?Pk&nC&A&R*0(02_c^?)?_dB5UTGTH-~ z?>Slp9Fu8{v5mw4^`S#i-sZN4D7Mkx=$A=ky2Xvl*|4s8)2#JaU~3Gwc{G9+!ujzQ zNT=TqSkaM2ox%%rQ-(QTaE4^y>^s`fwCR&`)C_8V&hCGk!bO&M5E0s_(%8ONck?g5 z#ZH@tE|Vtahy!u*`qk5uhMNC~r`4Dw0C#U(-2hslbeMPP8tLVGF1R8(82~vOq<~3>b0r%A=9oEs z&_wwDLtlRs_kFSL9hC4!0ic78E)QrlI1qUNZx-g!ZiHou6Okv{VK6qO1pLl&mO^T)=Iya+3%M839@>ALE&vzKF#ddp*ll9yKuLE^LUPV` zCZ{N`XbtX#fw^FS!h691GrwVqDLZ2YH}q6f@P^p&yEMC3A}i2%5{JlKib^OmNrUJygt zUY2}*NOKa7-K!MpN=MoK8e8PhMkN~cx|ZglaQAupt+eoN7M$ouw+U}mdl(qq5weE{ z8-Kvq_WSz$m*@qu_$i+6B01j`jS8m=02XP4-Ie%4kS35BGwe@@G13vS8Ot7vp#diiWp}J#2eU|sWJV9{Vz2XTm+qZ*_wXDaiDj!UAu&{r5 zF5;$$DGnw>ulbV05JWRPur2$qyr9W6no^S7l6SbKeR9p7ni*nY>qUix;9ZRin$^^C zVQENmmkt@7Jg<*QHdLXF3D6157K@AR7Yth!$QchT77=VoH0GTXIevMP9-y67X<=bz z=}yJhC34JezJ6G23Ce?){mcf{YT18S;Z{G*UK?mJrSKVV2KP}o$#_9qlVGL>KQ<=K z6WWF35*~@_8nKxC81gXXX1I%yq;LZb6Aj=krST$n{X!{Pzw7i8yve`*LWWuy!vTAG zcz&RN>G~-t56&a$W4`*zua6%~LS^gVxM(C>>2Sk|^%{VXh-+ekEnN#HyDfhhI4tsL z#ww!v>o7Oo!jH7$zXi{rlcB!mtBHu(uuY>qcV;df0Cc(04Io>7*B)74Vu_*1k6k9L z<74N3pJzn!0R@@SJt=M5}CA>Gmtl}@UqhVPq7eNc31N+85z+j?m$@UDNF4rI6pxMVob;zRu&;#hQ9ozckNb4ep6TrsjNHfz%{S3C7OK-urA zJLtCSZ~noNN2Op2-Lx0Tg_Nj56|~$^AE=*vWEK}Ke&{cOBPLAcqecu{RZ%#SRih%5 z9_ga5DA#_eChz0g55a$qB?7;!VnkW1e6xoQ$7M=*J$H zgeD&bF8eMuguM*qdVUNi!=ua3NMc0u%g9jB)Z(d3FZwY_z=?lJmf8?tk9{EEP9EDg zsMXOZg@I~~M!&m6|79EC^Ff*SBpid`7toVB_yXojpNT3$jm5mPoF=oo-p-P*s=WEw zgS6yf2Acq+P1r}}Z-J$Yusl|W!)!F{I(2U7+;HMExnTelTbpceYLkr(7944jMFV^J zExm67B&*>c^~irxg>&G@Y;p*#Q1D=@HA5Co83QBV$3Grgf$w5Gd5fWL^6vddT(+y& zxNa1vibI3#$_eTi=(`S)tEHt-zCI!BPI9b4c^UPcA;JfJ;vVZF-zn)w9GHv8{*=;P z^C02zt%;5hDtwY+djG{PVv153dY=53l>@^}bl-3OJ;s0XPWXFCA*AYi9_X`;&FQhw;lZnhNUVutd*?Kp##49s#Yl=SQMz|NNQV%8HKf4?|g1P ztfJ%sFBmLo@5Lz3YJYM*hhs0rVV9ycO_;~9JyoUBjfO^jaoXx+;fe;-)DC7E$) z8_|zJjP8HHkWsY)OAriaD;FM!8!Uy$XTD5kTh(An?XFlkiJYORzdL$8G~%M_#;1($ zNAsIO;v1?+00Gj#B(K(d130w971Mue@upJh{M+bewx*TpCj??CKnL@-538D6Ce$kz zKWpqK3jG~5y}6p+a6xy8&d=sodBdSigj2c~3-Rwhb*W#9W}H_&5l(vK#bsf(I1y@ZzC$;c2*x zCPsgry5v4bCLxPPlWTfAwr1Nnwib>kQ}48CLOx8-Z{xyMo!2bV`O9N1V;T)7sx2`| zR2pq>E$r8xLXn)|)UnTn)t04TWG$*&*n|Z>EK3s4N`>bKkBf-5NkAwsYRwoPvkli7 z97qS?Bq1W?hFIBrS^_qdhOv-_a(vWy_CSAzhzAk3cX1h0*%WG3Q9yTGRD?ku?HPI? ze(53avfcG#I3U!aeofw(N!$xLFwr{AAn)6-&p{Ls=O>leH0`R7s`!6$p#Qzb%CE+ESH23h=j-2i5j%Ij7BwD+d?GPUsg3o;abw9Ohh*m6s2@5Y~) zf{SYwP@RP8MoS&6s2p~(p2vIfph)ND#f+NYHDmTFZI!2N&(*YvJkAfgd11&k=s(9k zQ1|#Aj`oVnQ=gLAk)~3Cu=jPxDNcV|^;@05I@3~!k=h>>u1K#tPDJz5KBnc+$QV-!-YNOEsoCs+i>R429 z(&u=V>Zqk|8QoStv&U(|2uI=RyJ5eFC@MO{#gA8gpK;r9CB!5{!uLb2h2)&o$UV zpG-vmFd|s@kE|cJLU1|hx)t$yc~Ij||K$c>+<=Fm!&>yH7C=PC;z)l zJ&)9jm2U{Vn&@MwQtyA7x_|x%#g%H$xp>IpAMrzbQd~}`4S82itUpdDe;LWhq4@&i z@kl%MNf;-~+2U{o9#84%R{+`3c|AmRv8xst-FNjvSBxg;T8L(tp3>0iM&y&wn=~0u z-^6_gx$P{l=(n&i>5-ZW@++i8(vryVxr@77aecWKxzkx%vxa{%YGMm?_S|H)K4!Ub zlmIJ+Ld4^U!vsV9TN*a9AFtxu=s*usEKYUPNN_yTv^1Ic`<6lHxc5@y@8n#?IAp4( z>f~Q25LLjYxM8tJP4PS~cCgB+4pEAYXOgYl5RDo<`&-wazcLe0PVoqmh!W9(7amwM zmTmbiFleonBMg5$2W7BsCLhmrGX^;XyGAs<{DAH6urv9i9Q3Dtl`HHvLy_tYVB(W< zj=POXQi?Y5%`VHG!%oGU)7=^%L+XAxa9%X}h=kp;J0psRaN*pi;Y#z=mz@8K2qO(w zslVmjbFIovF&Es)VEP%Mx4NboZfgn-BJqwI8^cfapi+MZR`0t-1c`hpxA1#UQuONz z3%ruGt}tu&$Fc^+KEs< zD!n-y8g}uAw->fI>v%IX5LxiI^HrLNt0jTT%SU-qQ~EMm8B2BY8s5I!d^nMkNf;gD z{b6lM9zB2Ay9mW`pl%n#-Irbo?X@(MVXLI~u{qOEYx}6yA)_ z0TocS8FNf6{zo!e;-#b8nb^zEsvfQi(a^TJEhK-{I>K1dH_V^x>&2tnGihUq_SR){ zHXqkUKHdHnUCWB62X_2+b$O-M}thg)AHQm-K6iK)BY?(eUbRf{r2cbdyt+p_K$Tt}WQ z%1YcHH_?=+HYG0U4^kJEE*LnQct`C;Xsv(d%Ta^C1m(39D{>F7En`-$wK(fHD=qHH zHxs;^U?fJ!ylf11fzT;GS&gbN?pccWJc8Twj&?t(`9?F4DjY{j73YUc!qN^H|Y%!o7LOjg>^`dM3aMPLTKP;uVkYsmGcif*R(TSP|KB z;$M^yj^6ax_rP<%5C4Jg?Pq#&rN4hmZh5}OvS6qwwM(ugk{5a9VDqzvnSbVb1Ba&2 zLgQj;?z2te-rC+X7e>f#avVwDHqK-k{uTc875fwp-btJx_LwJL5~=f-C0tv?D0z3T z{!*o2Z342~NYaF}77>FIgyst2a1;g2%8%F?RXa&NgT~0%WV!!-^;_foO!t2>LxuO= zA-!&!WiNP{IK#jk>vK&y?f$w@+3qr4`yjJhAn?^)q^rIb30Kx5mP1ea!-Ki$2l<41C++-nU<;vcNULfh~oZw3|(f(MQIQUf#jhykLr ze|u#8@s#=5T^xA)g1{$%QSG-j2N~U;*SEkmfqb9ovgtZnCuBO}JV2%`QMPHog zV(g?nQT>l%MKRDj!R*sQ;hhutram^-Mc7|eS(7=}Yzi4a(Ovq$a;FUTS2@t!zTU(U zo3DFzXi~rDu5bbtp;i!)P&93VdW*7o?BtG%rupd0e~7TUmXscj@^TR+4^Zx4AMu(n zlA(4q$G3YPUM~%Kq=$KO2m5*}dv(a3vWW(s!G9jSvgo-Cz@M*ZM%S?Kg)&CkImhz0 z=qk5@Sc03c)dGLYn_Db24_ir0vW2RPV>kXng4Q^e__60K|FNM;r=f_JhKm$h`;!$q zycf$dicsf#{+WC*r@odgRh{#$;f%AYT@lSfKZUd}2G;}Ex}!>eW&XAcUl_Zywo4ZMxOeeUy%Y9YMj?A%C(@kqtC)z2|MmcdCAv`3;l z&~;A!3bcQKC9)M$a-`9gtJLVbdM8dYB?>zC*@GlUo8$A$iFE^Tgs@di(Fkx~rj`{uHW35YemWADL7Nmb9dj?jpjX>V zOxb}rahN=h)-^S!UbyfavuAviq$Z*5@a)*;^wEEGY>K{y6Jow19Y-e1v9UP_j2q^L zNO7E~GtSWpeBeufZkWAoDt#U>12Re{@aQ1dqOYZ|qRxHmL-oa$LnX_vO+m8%`ZW+6 zg8cOInsCs}fxE!mXej6D_h|XnL6myTfF}5hXsKj0!HGzULjhdKO#adjA-v*Nau7z4dLP?>{Jp!0OYCsj%kOZse_Wtn176 z_l~CFD|UntIu-sbT6i7<^L49FaflWDOnmo@#G1$2sMow}2V9)}tq!V!e>>t=dT>KU zl{uQQlLwN;{LZw+D6<*`C-d6pv8I2p_sM-z+VP`f3(9RalSG2{jQ0$A>3P~jA)e&# z*R6A6^eD*&_X+Z#*e;Rt9TRr&%0T?b$pnOw7#T?_w-(^p$*&4>;-Afe0?x5>|uTrU%kZrn`qqddJQ@kIU4%2^p_U(Lc zc_ZQOZ`^9WMOz5voJWCubACRz%JegqpWfTnfs0`k-S;mfTb4fb!iVZ(JUu#!rXXVX zIY9op?O-1WEI6Kro}dRu87h#uEP5Nd2Kt7&lqCwCc$c$lAhbkM4icxsQxN;I^m~5# z-R!Zuf1#7i)pu$RzeqzY_6vVrr^U**K;t~s1*XYDme$0H)=(Y~X5Fg(I7HyFt+)X5 z;cgP-Cbs@;RxNdVo)r-9{5cbTP46Yy(Ni#m;FQL%0@&~b*NaJG1V^8TkRA>j zsxvO;ZtP89PZP=C$o#xUAZlSKVBvlDHLw5qxG#c23`?Js%Gebp=;3vc@k`aqc}UJ|2==C!DnsH{sN6s=d1a zEXi-3gr0bq5WAn3H{YbtidC{N`8l?yioZZn846g=1fAmSt3&-vtCc&!UDe&sFb=_K zBWAHIiKXslG(N+dGf`%qw_@64=nG!ZJR7_Uf#eTw88m*hW%hqt<;-D^oS*5=;T_2C zG@yUn6FPIqAfmn_RATw~#NMj3iO&b{YZWA^KCnVCENr-1-hk{!EZ)*tC)A@zW0di9 z!VEO}_}UfeGlCx5WM`O2wCB(c@z{{u4@%9!AJU9c4bm1e=h+)D0$!{XzdGjKe5`s> z;Zpn-=?|xE0a}0Yz#GP|vfKcMtK)3bKg(o3qdLUvo#?@N6cP|wHrMEDf0N3Q((jkY zID=*jOr48XnU>VoWqEUMns&Rd^kq0-&-j9+N1Y)T$mKu{&JIDG|-(5s&f?NfqN z8GILVku#$oGY~TnkiO(J5C(J(siUNmHanyvkA^)}eWZW<)ne>Y_A^EEi&@TS#Q9g9 zE)Q$0FK-oYvnc=&WXLU9y@qYH=bos?fVE3tEG<u*-k;Mw^O}kV~%5FV$X1ENrr$k8;oO zK~MBXuB0pt@x+j2_5h3uaX)fi@B%5mT6(K$MVOiSu^Y2D1QQuCkDIX!q`{slSpizb zzNRX@kfDwJ3d+uoiO~o(G?gr7}t} z`8rPS1WBI}JG|mcO-~Siy2kJC+(ZGdpWb%QsXovN3U@Bfa)erNmk;OloBYi0n|pyN zv}F&%uQ9sDv#JP{ZW3!}G^^@8kj78O3-^By>cma^RU6jB`Y*UbntlFjllG_LM;0Jt zH<(o#ga8AFnH2&8n)CruTcz-LP7OubxiLH`TlU^EED1UbuWg)b!Qua?HHxXs{17k%qG!uU? z_Dr%-bL#?WMdH}j0d0tURT7P0MbK;IF{x+XuK*%Uf0IOK$C`|pnif1pPR_1}L^E4a zHwjYP;uzdf#sg?LLU61F#{_QN`u8AYZ`fl;yx!YX-f-5Dtljls0xd1%AXE2GJ0=nK zHe*jidJj+Yj+g<%`4Us!3`2?QsR)1c73_<-MvqoTC&U5RyZcOT@En6sA zOi&p&Ms3-XO4!mL{c~SLBXwDu?;?@SIXwztn?BCpJ+>@i_i03O4IFDfq6!T3IuSmu0vdek{o!lwlvJrAU2uj!S%Ccywy*@VGW7E!(G?3PJDE~QmcQF#3GvW znkci1!YyA}3$)S64WGDzDIaTTkt*Md6*^*{Mze{*LP@he-eYu+TlVa}8Hc=QYHR&G zwrV~=Pr%tfQ#p+O6047p2H%BaFbJ~HO+rQz%o;Sz+40CF!gRRrbf2C?zLkWV&q(zaQ1%g%xFBSd9lXV|L0+}AUoG*Cn1hecB zU3q*8kA;I&8dqPspQkH9PNGHMAH`xXf9bJ4;`7cMeLA$l(ZO;t#c&4;N?Jp4UX3ue zy9`}IF4qK4M7J=Z?l`m%SBk%SEvetNJgYCu3i*-4it@*WW35UD&=Quk=80#@l(S8Ee{D5AG(B$zF?uG%4VJ97#Jsh$Y zMVzX9{yjLf2MK@qWh;M;1FgN^S|l~Y&zj-B*v#s^-QMoVQXUQ=5I{oYwbM3__&$5t z21+^C{kup1A-b74+jzDTc$b*hOyJ_4?|4p3+(Od|*8?Q=k<@mPqB`6LWY?NdVYU)Vu*5b*f+=ayj=?c zwSiAl@+8kKY)=}*E_^o)N$``AzCL-W7oWt>e~{3e;l|F}_k^&nCIa%foynbjBYiPR zJ5*FRc~Bu*b%?z!wR+^Ti4?cFZAmavpKUeTze8jXo*GjLw>nju;3?0zIH5fcN~@@> zWnA_52B15B?csk#8oapf*%D*jMKrlKfm*__fWBxI{8T7j3HQVGdkIzih(X;~$8bX_ zzsSpPqh`BWfrsM-&njD6RJNO}(WRr7cf-jRcYqQFq)t`!o3ZhZxf~^dJ{inT*@T^w zhn0D|!?KE_!EAvt(Ek zN^My$=@*>&CsNnT^U%5ClGe=yFx==sq)6pEV!4iB;@E~B+W3=EL9mjc-{-TK(jJ)@ zV8&cIsOtCiG#&+W%i*P$#Jxwql~@KFSFbxm99hqY+?Kc(>qEe}X^evyJuS}BsDWa_ z5QjDzIeUMvFTpC(ecW9d3kOPBFgHj!mm2w1iJ;}Mfz5~3TZdW{ zOPpX#h=}Tu(XV^(kiJ^QUz8-TUSkm4;(c|KDVdJ*2DxQTdk~+CQblx&C3FR*gGACx z31az#!e`$=ZKbE|+DawC?;*r1l_gs&%qP+fSAK z4B@m2XsHZED#v3gY-Y>viwdzmf6o%Zp{xR%uhiocg;0Az#y@<>2#ciC;D$DTzbWY# zK$7hY1RXyGmM&Aqc+L^DE5TIhaIi0dNasK{4Ir2p)`|fJcwEX#4J4M?A#M>T>N6qt zImmyeHZD9T{vnnvJ?uo%S;{zLPfEpXEq1+EL=e5tyjc?ax=vWh6gv(2Rz`!mt&jW1 zbpw~`Woq5TQ-g9on-CyZttR}P-06orfvFIe>UEuPEcIA|(i^WTBCVc*^^XLlkuD;O z@Mp|4-~2Iz4E!z|jAW@x9WSB0Q=lx(NdkY3<>hHB0tOH%yFO`^Ldq-Fs`>ro#!%ym zT&WFx-{|Gjq=WaXXcC!3RZgSbdB8hP8qRnktX~XX?xP!Q2&Jow*{Un_VHb};2V6?& z*Mo!BRM}*`QWYSn7#Hc-I{)utvxfJfbA7&*2wqlPv(j2PFQ7`7y$8~`Qc4%WV$6SM z49j6qR|-gvs)gN4cd89*a!r6W<}@zXn}1pDb~<<4LlvOd!X@OSjl`r}S?`BZSw*K- zCCd@K>$vfe3?>aoc0^22ea$ndnKPYSi$q4Yv&6RMbXw0jLi7zl5~kfC!qKDMjlM}f zO3XIpSoO$Doz)a@$7h)Wm8tb~$=83wr`#RH1N9Ck$xY`%&*etk&9sEk>r*R?Br>Kc zJ2!JR%K#-h^p3fxzn0?VF6J@c!|BLPYoU)<9GXEtYrqVF#V6o~;oZ+MQp`lx+6YHo z60x2|7lxiW#q6giB3zFXCFbw2@)kp}tEMDmSs7Omg1xA2h zifB1H_G0XNQVZ0D%LHEV!ie8S9P2#67@ ztW7A1cZmn4p6BGi_t*(&-mkgcjJ0V@ryr0y(P2!GyyLUEKcP)4v9Y@vhf`?l^BgtELibwbH&x*??rj(jcVMi-ry1H+ zE2XS_y;|aAWSBuh+vjd>-YYkvSQ^n zPy;G9Q$vhkAm>5kh`aZZNR5&~%J9;nnyBYkYPfvTj$34muMoo>juSfQjS~Xv1fXX? zg{Ht)2|`TYW-Zh!Xc3m>N;UdzoSw(ajQ4Uw)Tmf~Gr@Ar{=R>+0kSM&EHF{dlAIrJ z&);8I6A{;FIkK^t@{b%cZN=bnWy@X;IpCy=%s%N;-$*z*NtZ?={fa_DDa<{OQ$^xp z(D`dhM@oc`55B+PTF ztt0+tS;50pJDh(Ir19i;NSC%Fiuqx~DF@^c#Jr7iia!a5)}1EMf1dO;&RlxiN?t!D zL6zB}e^wKK$nU4n5zhYv5VVCZLK!DsA&_t*)f!PZfuq#_oQdFfdg*(`H>7r+UluC; z5c!Y|^dWNcu+pQIyPo#wVEzynFu98A7rFtdp~{5c0R?{vMhuJSm}YR_Rl)jgh7P-! z3i_ELqW5&}}ljM-3-5-?pF;vI9*uHF`O3g7JNp-r$rh7E) z`$d0&6sq5`3~oe^Ja0r`Do9;d>ft4A!qBKFswO|q#L2<&xKtkJ1*#)m_0ZyFms;&- z<%agFRJFAf@`(2~+|-YO%!;swb&$@~DZ>T?ZjTaR8fV!APr6#qCh!Y+qgDvh*VI-C$Ay)wa@F z{Trc=_mwc+d?D{pxF_aV^c~+#=6(}N>?-gcLS6VVmDvwiulr0uafBJ$B+x?}K3IQF zRdE}X6xy9T&p)TFC8}60?ah`}#o2X{$HTsQDB7w{K!uU|m~jyv>PYHc*ME75(0vBq z@p6fXU%W)dxaBN_hFeqv>78nZV*ImXvEi@^2gK_uG9dtlx|pxwS#6x^oK_XCqEXd& zy`M+UmZSIqKmE=XQ`kSUB@Uxhi*aTsI?V2Hg+RshJJ@1tbIQQ)EmDnWWon6?q=Anj*k_cXoOG<_dqu-ypM= zceGnAI6j}=T6V^YrQ56*($ z>)( zdb%tUjgd_o(GrLXh4^Zbnq%3?I8V0CvD-RjTh&9K{q=@*6`_{iK7KCvng@xUoSK?4 ztoQaqY(YAs5p+aBPECL8j0o=MlFOvNBD~b^IGBbOyk8NZzfGZrEH`V#=ce-QDfh?< za;#H*5p+l0s$T5^kJyu`w~Dk+gAj7(#$OuJvAb1QDpEZ06A?WpDVevcXowa|$t zMbm2JgS-6UN_4OGN&!vNopa@x?)Yf8MSdaia7@RaH4d|-?UH}n=xIm`jF#9e+mz6Y zdXzZaE!j7jD{pB)$Z9AOH+gqR(lP1P`y+eTd)8+r#t{2^+qF&7$l41WaHWrVpIbNf zX#x7PunYKe>y(q;z3AR5Qrp*SAB4LN@PJ3Hg(Bzkz{9xX&d8@%Gux-UhIcb5OZ#mZ z*LT0=11Iteb8mk?ooP}Hk0QT-$G;0Plqfq+<5cI5=6#mvdJ(dA8pWpDf5F2al+cS{ zV!p%>z6zH%!xjnd&P0=F!N>`}$f|C2K8Ut;pv7(VmLL9V;HAVJx@5jz+UNpZx`tFI z-{)Hp9Wv#P^h90#{=){l!w=OK{U|tobUA;#sFFbE1^$0FV=FZcu-PHA82aJ4M~Sr2 z2T$6DVSSuEZx$bwc$o2`Me>ix7;%A80aKZff#@D{CA?YhA>uzqk+;(I7(6lX|Aw!n z77i_eL^!Y+EL*J-W$uT5rz4W9+W{({P4^E%%RbQg_~VpmMrcUhEd@3*;_Fk?4i$v|=}Sl$4{`@} zM;0b8Q3dOH`sLbnCSNM0v^mcq3ZFlz(~s4>n4KfkDGrXSu#N)qXCt1m>%r5Y41Pi$ zlA>CK>=V)e}+ERg4WH6Mi0qCCvA!Y9*(6oyAlmJzX|Y z7=smBZlbRUa|SD~ zy~D#1t?FnIE6FgH=cH$7)#}7J(whw1n(#xq=O~ zpO%DkAsrP<#E6$rVHIgKjZzP!fb~Ql ztO`7b-+kZ1Iqs?edq9N0$+g?&dbc|tr9i!N@-*5(H3Ft9%U=p%bCDJ_!FO-DCTk9? zsr^8JxHXCaD|Aq&zAHUx{t=TFZu&mrf{sJnU2$MZkg%!;4cUP`2idzhJM#)utBifJQ)~;AWX8UF+q+p&nvKh{?k_w#FrlLFe)erqKU=@= z_wB_GTXqjr-U;>kmPyI11g&MZ$6h3*kX?sxTSWOiPLfHK8Y2ZVA-~OxH}sPf;bE;1 z`N=|4!k!!QX`X9YId0L?JLh$3shAFTE4no~%2kAW z%CdQ!G0xhOGv(GTBcdf}odCbLuq`v-kVRE5M9Eh};<;{z)07lQeh-t^O~nW{`p;q& zD&q|#Vbx~2V*hZe*z^);^WuL1TbVn$mpbrXKwn?(!! zpx)b7JJE{*?jyv~&$l}fh&?93_n0+*1`b{=37Xj5E}JrnRbQj%Ga6~Cc!-QPe-W&P zJCIGjMA&Sck^LIx+fOLxTKtJU|C&Z^sZb>)-Smrq)d7qjh4!TbGTsv

45Iw}g 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 diff --git a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py index 4781613..ef38b6e 100644 --- a/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/reg_model/msk_top_regs.py @@ -76,6 +76,410 @@ +class msk_top_regs_frame_sync_status_frame_sync_errors_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frames Sync Errors | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of frame sync errors since last read. Value is 0 to 63. | + | | This field will saturate at 63 if more than 63 occur.

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frames Sync Errors" + @property + def rdl_desc(self) -> str: + return "Count of frame sync errors since last read. Value is 0 to 63. This field will saturate at 63 if more than 63 occur." + + + + + + + +class msk_top_regs_frame_sync_status_frames_received_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frames Received | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of frames received since last read. Value is 0x00_0000 to | + | | 0xFF_FFFF

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frames Received" + @property + def rdl_desc(self) -> str: + return "Count of frames received since last read. Value is 0x00_0000 to 0xFF_FFFF" + + + + + + + +class msk_top_regs_frame_sync_status_frame_buffer_overflow_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Buffer Overflow | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 - Normal operation 1 - Buffer overflow

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frame Buffer Overflow" + @property + def rdl_desc(self) -> str: + return "0 - Normal operation\n1 - Buffer overflow" + + + + + + + +class msk_top_regs_frame_sync_status_frame_sync_locked_cls(FieldAsyncReadWrite): + + """ + Class to represent a register field in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Sync Lock | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 - Frame sync not locked 1 - Frame sync locked

| + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = [] + + + + + + + @property + def rdl_name(self) -> str: + return "Frame Sync Lock" + @property + def rdl_desc(self) -> str: + return "0 - Frame sync not locked\n1 - Frame sync locked" + + + + + + +class msk_top_regs_frame_sync_status_cls(RegAsyncReadWrite): + """ + Class to represent a register in the register model + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Sync Status | + +--------------+-------------------------------------------------------------------------+ + """ + + __slots__ : list[str] = ['__frame_sync_locked', '__frame_buffer_overflow', '__frames_received', '__frame_sync_errors'] + + def __init__(self, + address: int, + width: int, + accesswidth: int, + logger_handle: str, + inst_name: str, + parent: Union[AsyncAddressMap,AsyncRegFile,MemoryAsyncReadWrite]): + + super().__init__(address=address, + width=width, + accesswidth=accesswidth, + logger_handle=logger_handle, + inst_name=inst_name, + parent=parent) + + # build the field attributes + + self.__frame_sync_locked:msk_top_regs_frame_sync_status_frame_sync_locked_cls = msk_top_regs_frame_sync_status_frame_sync_locked_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=0, + msb=0, + low=0, + high=0), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.frame_sync_locked', + inst_name='frame_sync_locked', + field_type=int) + self.__frame_buffer_overflow:msk_top_regs_frame_sync_status_frame_buffer_overflow_cls = msk_top_regs_frame_sync_status_frame_buffer_overflow_cls( + parent_register=self, + size_props=FieldSizeProps( + width=1, + lsb=1, + msb=1, + low=1, + high=1), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.frame_buffer_overflow', + inst_name='frame_buffer_overflow', + field_type=int) + self.__frames_received:msk_top_regs_frame_sync_status_frames_received_cls = msk_top_regs_frame_sync_status_frames_received_cls( + parent_register=self, + size_props=FieldSizeProps( + width=24, + lsb=2, + msb=25, + low=2, + high=25), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.frames_received', + inst_name='frames_received', + field_type=int) + self.__frame_sync_errors:msk_top_regs_frame_sync_status_frame_sync_errors_cls = msk_top_regs_frame_sync_status_frame_sync_errors_cls( + parent_register=self, + size_props=FieldSizeProps( + width=6, + lsb=26, + msb=31, + low=26, + high=31), + misc_props=FieldMiscProps( + default=0, + is_volatile=True), + logger_handle=logger_handle+'.frame_sync_errors', + inst_name='frame_sync_errors', + field_type=int) + + @property + def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,FieldAsyncReadWrite]]: + """ + generator that produces has all the fields within the register + """ + yield self.frame_sync_locked + yield self.frame_buffer_overflow + yield self.frames_received + yield self.frame_sync_errors + + # Empty generator in case there are no children of this type + if False: yield + + + + + # build the properties for the fields + + @property + def frame_sync_locked(self) -> msk_top_regs_frame_sync_status_frame_sync_locked_cls: + """ + Property to access frame_sync_locked field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Sync Lock | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 - Frame sync not locked 1 - Frame sync locked

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__frame_sync_locked + @property + def frame_buffer_overflow(self) -> msk_top_regs_frame_sync_status_frame_buffer_overflow_cls: + """ + Property to access frame_buffer_overflow field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Buffer Overflow | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

0 - Normal operation 1 - Buffer overflow

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__frame_buffer_overflow + @property + def frames_received(self) -> msk_top_regs_frame_sync_status_frames_received_cls: + """ + Property to access frames_received field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frames Received | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of frames received since last read. Value is 0x00_0000 to | + | | 0xFF_FFFF

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__frames_received + @property + def frame_sync_errors(self) -> msk_top_regs_frame_sync_status_frame_sync_errors_cls: + """ + Property to access frame_sync_errors field of the register + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frames Sync Errors | + +--------------+-------------------------------------------------------------------------+ + | Description | .. raw:: html | + | | | + | |

Count of frame sync errors since last read. Value is 0 to 63. | + | | This field will saturate at 63 if more than 63 occur.

| + +--------------+-------------------------------------------------------------------------+ + """ + return self.__frame_sync_errors + + + @property + def systemrdl_python_child_name_map(self) -> dict[str, str]: + """ + In some cases systemRDL names need to be converted make them python safe, this dictionary + is used to map the original systemRDL names to the names of the python attributes of this + class + + Returns: dictionary whose key is the systemRDL names and value it the property name + """ + return {'frame_sync_locked':'frame_sync_locked','frame_buffer_overflow':'frame_buffer_overflow','frames_received':'frames_received','frame_sync_errors':'frame_sync_errors', + } + + + + + + + + # nodes:4 + + @overload + def get_child_by_system_rdl_name(self, name: Literal["frame_sync_locked"]) -> msk_top_regs_frame_sync_status_frame_sync_locked_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["frame_buffer_overflow"]) -> msk_top_regs_frame_sync_status_frame_buffer_overflow_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["frames_received"]) -> msk_top_regs_frame_sync_status_frames_received_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: Literal["frame_sync_errors"]) -> msk_top_regs_frame_sync_status_frame_sync_errors_cls: ... + + + @overload + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_frame_sync_status_frame_sync_locked_cls, msk_top_regs_frame_sync_status_frame_buffer_overflow_cls, msk_top_regs_frame_sync_status_frames_received_cls, msk_top_regs_frame_sync_status_frame_sync_errors_cls, ]: ... + + def get_child_by_system_rdl_name(self, name: Any) -> Any: + return super().get_child_by_system_rdl_name(name) + + + + + + + + + @property + def rdl_name(self) -> str: + return "Frame Sync Status" + + + + + + + class msk_top_regs_status_reg_data_desc_a6882ec4_cls(FieldAsyncReadWrite): """ @@ -244,7 +648,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1059601d_cls(FieldAsyncReadWrite): +class msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -317,7 +721,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1059601d_cls = msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1059601d_cls( + self.__data:msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls = msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -348,7 +752,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1059601d_cls: + def data(self) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls: """ Property to access data field of the register @@ -388,7 +792,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1059601d_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls: return super().get_child_by_system_rdl_name(name) @@ -758,7 +1162,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x105960a4_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -796,7 +1200,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -833,7 +1237,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x105960a4_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x105960a4_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -864,7 +1268,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105960a4_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls: """ Property to access alpha field of the register @@ -903,7 +1307,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x105960a4_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls: return super().get_child_by_system_rdl_name(name) @@ -2874,7 +3278,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_data_0x0x10526299_cls(FieldAsyncReadWrite): +class msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -2952,7 +3356,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x10526299_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x10526299_cls( + self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -2983,7 +3387,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10526299_cls: + def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls: """ Property to access data field of the register @@ -3025,7 +3429,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10526299_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls: return super().get_child_by_system_rdl_name(name) @@ -4646,7 +5050,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x1059408f_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x10443038_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -4722,7 +5126,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x1059408f_cls = msk_top_regs_data_width_data_width_0x0x1059408f_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x10443038_cls = msk_top_regs_data_width_data_width_0x0x10443038_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -4753,7 +5157,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x1059408f_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x10443038_cls: """ Property to access data_width field of the register @@ -4792,7 +5196,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x1059408f_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x10443038_cls: return super().get_child_by_system_rdl_name(name) @@ -5642,7 +6046,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1059568d_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5719,7 +6123,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1059568d_cls = msk_top_regs_config_nco_fw_config_data_0x0x1059568d_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls = msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5750,7 +6154,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1059568d_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls: """ Property to access config_data field of the register @@ -5791,7 +6195,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1059568d_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls: return super().get_child_by_system_rdl_name(name) @@ -5815,7 +6219,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x105956cc_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5892,7 +6296,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x105956cc_cls = msk_top_regs_config_nco_fw_config_data_0x0x105956cc_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -5923,7 +6327,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x105956cc_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls: """ Property to access config_data field of the register @@ -5964,7 +6368,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x105956cc_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls: return super().get_child_by_system_rdl_name(name) @@ -5988,7 +6392,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1059570e_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6065,7 +6469,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1059570e_cls = msk_top_regs_config_nco_fw_config_data_0x0x1059570e_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6096,7 +6500,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1059570e_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls: """ Property to access config_data field of the register @@ -6137,7 +6541,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1059570e_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls: return super().get_child_by_system_rdl_name(name) @@ -6161,7 +6565,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x10595720_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6238,7 +6642,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10595720_cls = msk_top_regs_config_nco_fw_config_data_0x0x10595720_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6269,7 +6673,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10595720_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls: """ Property to access config_data field of the register @@ -6310,7 +6714,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10595720_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls: return super().get_child_by_system_rdl_name(name) @@ -8261,7 +8665,7 @@ class msk_top_regs_cls(AsyncAddressMap): +--------------+-------------------------------------------------------------------------+ """ - __slots__ : list[str] = ['__Hash_ID_Low', '__Hash_ID_High', '__MSK_Init', '__MSK_Control', '__MSK_Status', '__Tx_Bit_Count', '__Tx_Enable_Count', '__Fb_FreqWord', '__TX_F1_FreqWord', '__TX_F2_FreqWord', '__RX_F1_FreqWord', '__RX_F2_FreqWord', '__LPF_Config_0', '__LPF_Config_1', '__Tx_Data_Width', '__Rx_Data_Width', '__PRBS_Control', '__PRBS_Initial_State', '__PRBS_Polynomial', '__PRBS_Error_Mask', '__PRBS_Bit_Count', '__PRBS_Error_Count', '__LPF_Accum_F1', '__LPF_Accum_F2', '__axis_xfer_count', '__Rx_Sample_Discard', '__LPF_Config_2', '__f1_nco_adjust', '__f2_nco_adjust', '__f1_error', '__f2_error', '__Tx_Sync_Ctrl', '__Tx_Sync_Cnt', '__lowpass_ema_alpha1', '__lowpass_ema_alpha2', '__rx_power', '__tx_async_fifo_rd_wr_ptr', '__rx_async_fifo_rd_wr_ptr'] + __slots__ : list[str] = ['__Hash_ID_Low', '__Hash_ID_High', '__MSK_Init', '__MSK_Control', '__MSK_Status', '__Tx_Bit_Count', '__Tx_Enable_Count', '__Fb_FreqWord', '__TX_F1_FreqWord', '__TX_F2_FreqWord', '__RX_F1_FreqWord', '__RX_F2_FreqWord', '__LPF_Config_0', '__LPF_Config_1', '__Tx_Data_Width', '__Rx_Data_Width', '__PRBS_Control', '__PRBS_Initial_State', '__PRBS_Polynomial', '__PRBS_Error_Mask', '__PRBS_Bit_Count', '__PRBS_Error_Count', '__LPF_Accum_F1', '__LPF_Accum_F2', '__axis_xfer_count', '__Rx_Sample_Discard', '__LPF_Config_2', '__f1_nco_adjust', '__f2_nco_adjust', '__f1_error', '__f2_error', '__Tx_Sync_Ctrl', '__Tx_Sync_Cnt', '__lowpass_ema_alpha1', '__lowpass_ema_alpha2', '__rx_power', '__tx_async_fifo_rd_wr_ptr', '__rx_async_fifo_rd_wr_ptr', '__rx_frame_sync_status'] def __init__(self, *, address:int=0, @@ -8546,7 +8950,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls = msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls = msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls( address=self.address+132, accesswidth=32, width=32, @@ -8585,10 +8989,18 @@ def __init__(self, *, logger_handle=logger_handle+'.rx_async_fifo_rd_wr_ptr', inst_name='rx_async_fifo_rd_wr_ptr', parent=self) + + self.__rx_frame_sync_status:msk_top_regs_frame_sync_status_cls = msk_top_regs_frame_sync_status_cls( + address=self.address+152, + accesswidth=32, + width=32, + logger_handle=logger_handle+'.rx_frame_sync_status', + inst_name='rx_frame_sync_status', parent=self) + @property def size(self) -> int: - return 152 + return 156 @property def Hash_ID_Low(self) -> msk_top_regs_msk_hash_lo_cls: """ @@ -9246,7 +9658,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls: """ Property to access lowpass_ema_alpha1 @@ -9345,6 +9757,22 @@ def rx_async_fifo_rd_wr_ptr(self) -> msk_top_regs_status_reg_data_8a67e1fe_desc_ """ return self.__rx_async_fifo_rd_wr_ptr + @property + def rx_frame_sync_status(self) -> msk_top_regs_frame_sync_status_cls: + """ + Property to access rx_frame_sync_status + + +--------------+-------------------------------------------------------------------------+ + | SystemRDL | Value | + | Field | | + +==============+=========================================================================+ + | Name | .. raw:: html | + | | | + | | Frame Sync Status | + +--------------+-------------------------------------------------------------------------+ + """ + return self.__rx_frame_sync_status + @property @@ -9356,7 +9784,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: Returns: dictionary whose key is the systemRDL names and value it the property name """ - return {'Hash_ID_Low':'Hash_ID_Low','Hash_ID_High':'Hash_ID_High','MSK_Init':'MSK_Init','MSK_Control':'MSK_Control','MSK_Status':'MSK_Status','Tx_Bit_Count':'Tx_Bit_Count','Tx_Enable_Count':'Tx_Enable_Count','Fb_FreqWord':'Fb_FreqWord','TX_F1_FreqWord':'TX_F1_FreqWord','TX_F2_FreqWord':'TX_F2_FreqWord','RX_F1_FreqWord':'RX_F1_FreqWord','RX_F2_FreqWord':'RX_F2_FreqWord','LPF_Config_0':'LPF_Config_0','LPF_Config_1':'LPF_Config_1','Tx_Data_Width':'Tx_Data_Width','Rx_Data_Width':'Rx_Data_Width','PRBS_Control':'PRBS_Control','PRBS_Initial_State':'PRBS_Initial_State','PRBS_Polynomial':'PRBS_Polynomial','PRBS_Error_Mask':'PRBS_Error_Mask','PRBS_Bit_Count':'PRBS_Bit_Count','PRBS_Error_Count':'PRBS_Error_Count','LPF_Accum_F1':'LPF_Accum_F1','LPF_Accum_F2':'LPF_Accum_F2','axis_xfer_count':'axis_xfer_count','Rx_Sample_Discard':'Rx_Sample_Discard','LPF_Config_2':'LPF_Config_2','f1_nco_adjust':'f1_nco_adjust','f2_nco_adjust':'f2_nco_adjust','f1_error':'f1_error','f2_error':'f2_error','Tx_Sync_Ctrl':'Tx_Sync_Ctrl','Tx_Sync_Cnt':'Tx_Sync_Cnt','lowpass_ema_alpha1':'lowpass_ema_alpha1','lowpass_ema_alpha2':'lowpass_ema_alpha2','rx_power':'rx_power','tx_async_fifo_rd_wr_ptr':'tx_async_fifo_rd_wr_ptr','rx_async_fifo_rd_wr_ptr':'rx_async_fifo_rd_wr_ptr', + return {'Hash_ID_Low':'Hash_ID_Low','Hash_ID_High':'Hash_ID_High','MSK_Init':'MSK_Init','MSK_Control':'MSK_Control','MSK_Status':'MSK_Status','Tx_Bit_Count':'Tx_Bit_Count','Tx_Enable_Count':'Tx_Enable_Count','Fb_FreqWord':'Fb_FreqWord','TX_F1_FreqWord':'TX_F1_FreqWord','TX_F2_FreqWord':'TX_F2_FreqWord','RX_F1_FreqWord':'RX_F1_FreqWord','RX_F2_FreqWord':'RX_F2_FreqWord','LPF_Config_0':'LPF_Config_0','LPF_Config_1':'LPF_Config_1','Tx_Data_Width':'Tx_Data_Width','Rx_Data_Width':'Rx_Data_Width','PRBS_Control':'PRBS_Control','PRBS_Initial_State':'PRBS_Initial_State','PRBS_Polynomial':'PRBS_Polynomial','PRBS_Error_Mask':'PRBS_Error_Mask','PRBS_Bit_Count':'PRBS_Bit_Count','PRBS_Error_Count':'PRBS_Error_Count','LPF_Accum_F1':'LPF_Accum_F1','LPF_Accum_F2':'LPF_Accum_F2','axis_xfer_count':'axis_xfer_count','Rx_Sample_Discard':'Rx_Sample_Discard','LPF_Config_2':'LPF_Config_2','f1_nco_adjust':'f1_nco_adjust','f2_nco_adjust':'f2_nco_adjust','f1_error':'f1_error','f2_error':'f2_error','Tx_Sync_Ctrl':'Tx_Sync_Ctrl','Tx_Sync_Cnt':'Tx_Sync_Cnt','lowpass_ema_alpha1':'lowpass_ema_alpha1','lowpass_ema_alpha2':'lowpass_ema_alpha2','rx_power':'rx_power','tx_async_fifo_rd_wr_ptr':'tx_async_fifo_rd_wr_ptr','rx_async_fifo_rd_wr_ptr':'rx_async_fifo_rd_wr_ptr','rx_frame_sync_status':'rx_frame_sync_status', } @@ -9365,7 +9793,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - # nodes:38 + # nodes:39 @overload def get_child_by_system_rdl_name(self, name: Literal["Hash_ID_Low"]) -> msk_top_regs_msk_hash_lo_cls: ... @@ -9500,7 +9928,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls: ... @overload @@ -9518,9 +9946,13 @@ def get_child_by_system_rdl_name(self, name: Literal["tx_async_fifo_rd_wr_ptr"]) @overload def get_child_by_system_rdl_name(self, name: Literal["rx_async_fifo_rd_wr_ptr"]) -> msk_top_regs_status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_cls: ... + + @overload + def get_child_by_system_rdl_name(self, name: Literal["rx_frame_sync_status"]) -> msk_top_regs_frame_sync_status_cls: ... + @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_status_reg_data_f53978c8_name_d8ad3b25_cls, msk_top_regs_status_reg_data_05243a4e_name_2c154788_cls, msk_top_regs_status_reg_data_10a2e5b5_name_3b640507_cls, msk_top_regs_status_reg_data_642692cf_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x105960e6_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_status_reg_data_f53978c8_name_d8ad3b25_cls, msk_top_regs_status_reg_data_05243a4e_name_2c154788_cls, msk_top_regs_status_reg_data_10a2e5b5_name_3b640507_cls, msk_top_regs_status_reg_data_642692cf_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_cls, msk_top_regs_frame_sync_status_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) @@ -9661,6 +10093,9 @@ def get_registers(self, unroll:bool=False) -> Iterator[Union[AsyncReg, AsyncRegA yield self.rx_async_fifo_rd_wr_ptr + + yield self.rx_frame_sync_status + # Empty generator in case there are no children of this type if False: yield diff --git a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py index 8a49d28..5dc9718 100644 --- a/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/sim/msk_top_regs.py @@ -173,6 +173,10 @@ def _build_registers(self) -> dict[int, Union[list[Union[MemoryRegister, Registe Register(width=32, full_inst_name='msk_top_regs.rx_async_fifo_rd_wr_ptr', readable=True, writable=True, fields=[FieldDefinition(high=31, low=0, msb=31, lsb=0, inst_name='data'), ]), + 152 : + Register(width=32, full_inst_name='msk_top_regs.rx_frame_sync_status', readable=True, writable=True, + fields=[FieldDefinition(high=0, low=0, msb=0, lsb=0, inst_name='frame_sync_locked'),FieldDefinition(high=1, low=1, msb=1, lsb=1, inst_name='frame_buffer_overflow'),FieldDefinition(high=25, low=2, msb=25, lsb=2, inst_name='frames_received'),FieldDefinition(high=31, low=26, msb=31, lsb=26, inst_name='frame_sync_errors'), + ]), } def _build_memories(self) -> list[MemoryEntry]: diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py index 5371434..414ee3a 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -170,6 +170,9 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.inst_name, 'rx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.full_inst_name, 'msk_top_regs.rx_async_fifo_rd_wr_ptr') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status'): + self.assertEqual(self.dut.rx_frame_sync_status.inst_name, 'rx_frame_sync_status') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.full_inst_name, 'msk_top_regs.rx_frame_sync_status') # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.inst_name, 'hash_id_lo') # type: ignore[union-attr] self.assertEqual(self.dut.Hash_ID_Low.hash_id_lo.full_inst_name, 'msk_top_regs.Hash_ID_Low.hash_id_lo') # type: ignore[union-attr] @@ -347,6 +350,18 @@ def test_inst_name(self) -> None: with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr.data'): self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.inst_name, 'data') # type: ignore[union-attr] self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.full_inst_name, 'msk_top_regs.rx_async_fifo_rd_wr_ptr.data') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_locked.inst_name, 'frame_sync_locked') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_locked.full_inst_name, 'msk_top_regs.rx_frame_sync_status.frame_sync_locked') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + self.assertEqual(self.dut.rx_frame_sync_status.frame_buffer_overflow.inst_name, 'frame_buffer_overflow') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.frame_buffer_overflow.full_inst_name, 'msk_top_regs.rx_frame_sync_status.frame_buffer_overflow') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frames_received'): + self.assertEqual(self.dut.rx_frame_sync_status.frames_received.inst_name, 'frames_received') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.frames_received.full_inst_name, 'msk_top_regs.rx_frame_sync_status.frames_received') # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_errors.inst_name, 'frame_sync_errors') # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_errors.full_inst_name, 'msk_top_regs.rx_frame_sync_status.frame_sync_errors') # type: ignore[union-attr] def test_name_property(self) -> None: @@ -619,6 +634,13 @@ def test_name_property(self) -> None: + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status'): + + + self.assertEqual(self.dut.rx_frame_sync_status.rdl_name, "Frame Sync Status") # type: ignore[union-attr] + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): @@ -1032,6 +1054,34 @@ def test_name_property(self) -> None: + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_locked.rdl_name, "Frame Sync Lock") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_buffer_overflow.rdl_name, "Frame Buffer Overflow") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frames_received'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frames_received.rdl_name, "Frames Received") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_errors.rdl_name, "Frames Sync Errors") # type: ignore[union-attr] + + + def test_desc(self) -> None: @@ -1304,6 +1354,13 @@ def test_desc(self) -> None: + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status'): + + + self.assertIsNone(self.dut.rx_frame_sync_status.rdl_desc) # type: ignore[union-attr] + + + with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): @@ -1717,6 +1774,34 @@ def test_desc(self) -> None: + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_locked.rdl_desc, "0 - Frame sync not locked\n1 - Frame sync locked") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_buffer_overflow.rdl_desc, "0 - Normal operation\n1 - Buffer overflow") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frames_received'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frames_received.rdl_desc, "Count of frames received since last read. Value is 0x00_0000 to 0xFF_FFFF") # type: ignore[union-attr] + + + + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + + + self.assertEqual(self.dut.rx_frame_sync_status.frame_sync_errors.rdl_desc, "Count of frame sync errors since last read. Value is 0 to 63. This field will saturate at 63 if more than 63 occur.") # type: ignore[union-attr] + + + def test_sizes(self) -> None: @@ -1799,12 +1884,14 @@ def test_sizes(self) -> None: self.assertEqual(self.dut.tx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] with self.subTest(msg='node: msk_top_regs.rx_async_fifo_rd_wr_ptr'): self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status'): + self.assertEqual(self.dut.rx_frame_sync_status.size, 4) # type: ignore[union-attr] # check the size of the address map itself with self.subTest(msg='node: msk_top_regs'): - self.assertEqual(self.dut.size, 152) # type: ignore[union-attr] + self.assertEqual(self.dut.size, 156) # type: ignore[union-attr] @@ -2003,6 +2090,11 @@ def test_register_properties(self) -> None: self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.width, 32) # type: ignore[union-attr] self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.size, 4) # type: ignore[union-attr] self.assertEqual(self.dut.rx_async_fifo_rd_wr_ptr.accesswidth, 32) # type: ignore[union-attr] + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + self.assertEqual(self.dut.rx_frame_sync_status.address, 152) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.width, 32) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.size, 4) # type: ignore[union-attr] + self.assertEqual(self.dut.rx_frame_sync_status.accesswidth, 32) # type: ignore[union-attr] def test_memory_properties(self) -> None: @@ -2964,6 +3056,70 @@ def test_field_properties(self) -> None: self.assertEqual(fut.default,0) self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + # test properties of field: msk_top_regs.rx_frame_sync_status.frame_sync_locked + fut = self.dut.rx_frame_sync_status.frame_sync_locked # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,0) + self.assertEqual(fut.msb,0) + self.assertEqual(fut.low,0) + self.assertEqual(fut.high,0) + self.assertEqual(fut.bitmask,0x1) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFE) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + # test properties of field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow + fut = self.dut.rx_frame_sync_status.frame_buffer_overflow # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,1) + self.assertEqual(fut.msb,1) + self.assertEqual(fut.low,1) + self.assertEqual(fut.high,1) + self.assertEqual(fut.bitmask,0x2) + self.assertEqual(fut.inverse_bitmask,0xFFFFFFFD) + self.assertEqual(fut.max_value,0x1) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frames_received'): + # test properties of field: msk_top_regs.rx_frame_sync_status.frames_received + fut = self.dut.rx_frame_sync_status.frames_received # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,2) + self.assertEqual(fut.msb,25) + self.assertEqual(fut.low,2) + self.assertEqual(fut.high,25) + self.assertEqual(fut.bitmask,0x3FFFFFC) + self.assertEqual(fut.inverse_bitmask,0xFC000003) + self.assertEqual(fut.max_value,0xFFFFFF) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + # test properties of field: msk_top_regs.rx_frame_sync_status.frame_sync_errors + fut = self.dut.rx_frame_sync_status.frame_sync_errors # type: ignore[union-attr] + if not isinstance(fut, Field): + raise TypeError('This test relies on node being of type Field') + self.assertEqual(fut.lsb,26) + self.assertEqual(fut.msb,31) + self.assertEqual(fut.low,26) + self.assertEqual(fut.high,31) + self.assertEqual(fut.bitmask,0xFC000000) + self.assertEqual(fut.inverse_bitmask,0x3FFFFFF) + self.assertEqual(fut.max_value,0x3F) + + self.assertEqual(fut.default,0) + + self.assertEqual(fut.is_volatile,True) def test_field_encoding_properties(self) -> None: @@ -3025,6 +3181,10 @@ def test_field_encoding_properties(self) -> None: + + + + @@ -3187,6 +3347,10 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.rx_async_fifo_rd_wr_ptr.udp,{}) + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + + self.assertDictEqual(self.dut.rx_frame_sync_status.udp,{}) + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low.hash_id_lo'): self.assertDictEqual(self.dut.Hash_ID_Low.hash_id_lo.udp,{}) @@ -3423,6 +3587,22 @@ def test_user_defined_properties(self) -> None: self.assertDictEqual(self.dut.rx_async_fifo_rd_wr_ptr.data.udp,{}) + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + + self.assertDictEqual(self.dut.rx_frame_sync_status.frame_sync_locked.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + + self.assertDictEqual(self.dut.rx_frame_sync_status.frame_buffer_overflow.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status.frames_received'): + + self.assertDictEqual(self.dut.rx_frame_sync_status.frames_received.udp,{}) + + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + + self.assertDictEqual(self.dut.rx_frame_sync_status.frame_sync_errors.udp,{}) + async def test_register_read_and_write(self) -> None: @@ -6824,6 +7004,98 @@ async def test_register_read_and_write(self) -> None: # check the read has not been called in the write test read_callback_mock.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + rut=self.dut.rx_frame_sync_status # type: ignore[union-attr,assignment] + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=1) as read_callback_mock: + + + if not isinstance(rut, (RegAsyncReadOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Readable Async Type') + + # test reading back 1 (the unpatched version returns 0 so this confirms the patch works) + self.assertEqual(await rut.read(), 1) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth) + + # test the read check with high value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFFFFFFFF + self.assertEqual(await rut.read(), 0xFFFFFFFF) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth) + + # test the read of the low value + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0 + self.assertEqual(await rut.read(), 0x0) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth) + + # test the read of a random value + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.reset_mock() + read_callback_mock.return_value = random_value + self.assertEqual(await rut.read(), random_value) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + + + + if not isinstance(rut, (RegAsyncWriteOnly, RegAsyncReadWrite)): + raise TypeError('Register is not a Writeable Async Type') + + # test the write with high value + await rut.write(0xFFFFFFFF) + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth, + data=0xFFFFFFFF) + write_callback_mock.reset_mock() + + # test the write of a low value + await rut.write(0) + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth, + data=0) + write_callback_mock.reset_mock() + + # test the write of a random + random_value = random.randrange(0, 0xFFFFFFFF+1) + await rut.write(random_value) # type: ignore[union-attr] + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=rut.accesswidth, + data=random_value) + write_callback_mock.reset_mock() + + # test writing a value beyond the register range is blocked with an exception being raised + with self.assertRaises(ValueError): + await rut.write(-1) + + with self.assertRaises(ValueError): + await rut.write(0xFFFFFFFF+1) + + # check the read has not been called in the write test + read_callback_mock.assert_not_called() async def test_int_field_read_and_write(self) -> None: @@ -11372,57 +11644,393 @@ async def test_int_field_read_and_write(self) -> None: with self.assertRaises(ValueError): await fut.write(-1) - + # test access operations (read and/or write) to field: + # msk_top_regs.rx_frame_sync_status.frame_sync_locked + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + fut = self.dut.rx_frame_sync_status.frame_sync_locked # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: - async def test_register_read_fields(self) -> None: - """ - Walk the register map and check every register read_fields method - """ - reference_read_fields: dict[str, Union[bool, SystemRDLEnum, int]] - - with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): - # test read_fields to register: - # msk_top_regs.Hash_ID_Low - # build up the register value with a random base value, overlaid with - # a random value for each field - rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) - - - rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) - - - rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) - - - - with patch(base_name + '.write_addr_space') as write_callback_mock, \ - patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: - # the read_fields method gets a dictionary back - # from the object with all the read back field - # values - reference_read_fields = { - 'hash_id_lo' : await self.dut.Hash_ID_Low.hash_id_lo.read() - } + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFE + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + # read back - max_value, this is achieved by setting the register to bitmask read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x1 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) - self.assertDictEqual(await self.dut.Hash_ID_Low.read_fields(), - reference_read_fields) - read_callback_mock.assert_called_once() - write_callback_mock.assert_not_called() - with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): - # test read_fields to register: - # msk_top_regs.Hash_ID_High - # build up the register value with a random base value, overlaid with - # a random value for each field - rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) - - - - rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) - + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x1) >> 0 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_frame_sync_status.frame_sync_locked.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=self.dut.rx_frame_sync_status.frame_sync_locked.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFE) | \ + (0x1 & (field_value << 0))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.rx_frame_sync_status.frame_buffer_overflow + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + fut = self.dut.rx_frame_sync_status.frame_buffer_overflow # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFFFFFFFD + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x2 + self.assertEqual(await fut.read(), + 0x1) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x2) >> 1 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x1 + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x1, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=self.dut.rx_frame_sync_status.frame_buffer_overflow.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFFFFFFFD) | \ + (0x2 & (field_value << 1))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x1 + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.rx_frame_sync_status.frames_received + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frames_received'): + fut = self.dut.rx_frame_sync_status.frames_received # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0xFC000003 + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0x3FFFFFC + self.assertEqual(await fut.read(), + 0xFFFFFF) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0x3FFFFFC) >> 2 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0xFFFFFF + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0xFFFFFF, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_frame_sync_status.frames_received.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=self.dut.rx_frame_sync_status.frames_received.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0xFC000003) | \ + (0x3FFFFFC & (field_value << 2))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0xFFFFFF + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + # test access operations (read and/or write) to field: + # msk_top_regs.rx_frame_sync_status.frame_sync_errors + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + fut = self.dut.rx_frame_sync_status.frame_sync_errors # type: ignore[union-attr] + with patch(base_name + '.write_addr_space') as write_callback_mock,\ + patch(base_name + '.read_addr_space', return_value=0) as read_callback_mock: + + + + if not isinstance(fut, (FieldAsyncReadOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a readable async field') + + + # read back - zero, this is achieved by setting the register to inverse bitmask + read_callback_mock.return_value = 0x3FFFFFF + self.assertEqual(await fut.read(), + 0) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - max_value, this is achieved by setting the register to bitmask + read_callback_mock.reset_mock() + read_callback_mock.return_value = 0xFC000000 + self.assertEqual(await fut.read(), + 0x3F) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # read back - random value + read_callback_mock.reset_mock() + random_value = random.randrange(0, 0xFFFFFFFF+1) + read_callback_mock.return_value = random_value + random_field_value = (random_value & 0xFC000000) >> 26 + self.assertEqual(await fut.read(), + random_field_value) + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + # at the end of the read tests the write should not have been called + read_callback_mock.reset_mock() + write_callback_mock.assert_not_called() + # check the write + + if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): + raise TypeError('Test can not proceed as the fut is not a writable async field') + + + random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + random_field_value = random.randrange(0, 0x3F + 1) + for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: + for field_value in [0, 0x3F, random_field_value]: + read_callback_mock.reset_mock() + write_callback_mock.reset_mock() + read_callback_mock.return_value = reg_base_value + + await self.dut.rx_frame_sync_status.frame_sync_errors.write(field_value) # type: ignore[union-attr] + + + read_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=fut.parent_register.accesswidth) + + write_callback_mock.assert_called_once_with( + addr=152, + width=32, + accesswidth=self.dut.rx_frame_sync_status.frame_sync_errors.parent_register.accesswidth, # type: ignore[union-attr] + data=(reg_base_value & 0x3FFFFFF) | \ + (0xFC000000 & (field_value << 26))) + + + # check invalid write values bounce + with self.assertRaises(ValueError): + await fut.write(0x3F + 1) + + with self.assertRaises(ValueError): + await fut.write(-1) + + + + async def test_register_read_fields(self) -> None: + """ + Walk the register map and check every register read_fields method + """ + reference_read_fields: dict[str, Union[bool, SystemRDLEnum, int]] + + with self.subTest(msg='register: msk_top_regs.Hash_ID_Low'): + # test read_fields to register: + # msk_top_regs.Hash_ID_Low + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'hash_id_lo' : await self.dut.Hash_ID_Low.hash_id_lo.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.Hash_ID_Low.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.Hash_ID_High'): + # test read_fields to register: + # msk_top_regs.Hash_ID_High + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0xFFFFFFFF + 1) + rand_reg_value = (rand_reg_value & 0x0) | (rand_field_value << 0) @@ -12824,6 +13432,74 @@ async def test_register_read_fields(self) -> None: reference_read_fields) read_callback_mock.assert_called_once() write_callback_mock.assert_not_called() + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + # test read_fields to register: + # msk_top_regs.rx_frame_sync_status + # build up the register value with a random base value, overlaid with + # a random value for each field + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFC000003) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x3F + 1) + + + rand_reg_value = (rand_reg_value & 0x3FFFFFF) | (rand_field_value << 26) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + # the read_fields method gets a dictionary back + # from the object with all the read back field + # values + reference_read_fields = { + 'frame_sync_locked' : await self.dut.rx_frame_sync_status.frame_sync_locked.read(), + 'frame_buffer_overflow' : await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), + 'frames_received' : await self.dut.rx_frame_sync_status.frames_received.read(), + 'frame_sync_errors' : await self.dut.rx_frame_sync_status.frame_sync_errors.read() + } + + read_callback_mock.reset_mock() + + self.assertDictEqual(await self.dut.rx_frame_sync_status.read_fields(), + reference_read_fields) + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() async def test_register_read_context_manager(self) -> None: """ @@ -14516,6 +15192,88 @@ async def test_register_read_context_manager(self) -> None: read_callback_mock.assert_called_once() write_callback_mock.assert_not_called() + # test context manager to register: + # msk_top_regs.rx_frame_sync_status + # build up the register value with a random base value, overlaid with + # a random value for each field + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + rand_reg_value = random.randrange(0, 0xFFFFFFFF + 1) + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFE) | (rand_field_value << 0) + + + + + + + + rand_field_value = random.randrange(0, 0x1 + 1) + + + rand_reg_value = (rand_reg_value & 0xFFFFFFFD) | (rand_field_value << 1) + + + + + + + + rand_field_value = random.randrange(0, 0xFFFFFF + 1) + + + rand_reg_value = (rand_reg_value & 0xFC000003) | (rand_field_value << 2) + + + + + + + + rand_field_value = random.randrange(0, 0x3F + 1) + + + rand_reg_value = (rand_reg_value & 0x3FFFFFF) | (rand_field_value << 26) + + + + + with patch(base_name + '.write_addr_space') as write_callback_mock, \ + patch(base_name + '.read_addr_space', return_value=rand_reg_value) as read_callback_mock: + + # first read the fields using the "normal" method, then compare the result to reading + # via the context manager + reference_read_fields = { + 'frame_sync_locked' : await self.dut.rx_frame_sync_status.frame_sync_locked.read(), # type: ignore[union-attr] + 'frame_buffer_overflow' : await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), # type: ignore[union-attr] + 'frames_received' : await self.dut.rx_frame_sync_status.frames_received.read(), # type: ignore[union-attr] + 'frame_sync_errors' : await self.dut.rx_frame_sync_status.frame_sync_errors.read() # type: ignore[union-attr] + } + read_callback_mock.reset_mock() + + + async with self.dut.rx_frame_sync_status.single_read_modify_write(skip_write=True) as reg_context: # type: ignore[union-attr] + + self.assertEqual(reference_read_fields['frame_sync_locked'], + await reg_context.get_child_by_system_rdl_name('frame_sync_locked').read() + ) + self.assertEqual(reference_read_fields['frame_buffer_overflow'], + await reg_context.get_child_by_system_rdl_name('frame_buffer_overflow').read() + ) + self.assertEqual(reference_read_fields['frames_received'], + await reg_context.get_child_by_system_rdl_name('frames_received').read() + ) + self.assertEqual(reference_read_fields['frame_sync_errors'], + await reg_context.get_child_by_system_rdl_name('frame_sync_errors').read() + ) + pass + + read_callback_mock.assert_called_once() + write_callback_mock.assert_not_called() async def test_register_write_context_manager(self) -> None: """ @@ -14753,6 +15511,13 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ await write_field_combinations(reg=self.dut.rx_async_fifo_rd_wr_ptr, writable_fields = [ 'data' ]) + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + await write_field_combinations(reg=self.dut.rx_frame_sync_status, + writable_fields = [ 'frame_sync_locked', + 'frame_buffer_overflow', + 'frames_received', + 'frame_sync_errors' + ]) async def test_register_write_fields(self) -> None: """ @@ -15065,6 +15830,16 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ writable_fields = [ 'data' ]) + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + # test read_fields to register: + # msk_top_regs.rx_frame_sync_status + await write_field_combinations(reg=self.dut.rx_frame_sync_status, + writable_fields = [ 'frame_sync_locked', + 'frame_buffer_overflow', + 'frames_received', + 'frame_sync_errors' + ]) + @@ -15266,6 +16041,11 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.rx_async_fifo_rd_wr_ptr.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_frame_sync_status.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] with self.subTest(msg='node: msk_top_regs.Hash_ID_Low.hash_id_lo'): with self.assertRaises(AttributeError): # this line is trying to set an illegal value so by definition should fail the type @@ -15561,6 +16341,26 @@ def test_adding_attributes(self) -> None: # this line is trying to set an illegal value so by definition should fail the type # checks self.dut.rx_async_fifo_rd_wr_ptr.data.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_frame_sync_status.frame_sync_locked.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_frame_sync_status.frame_buffer_overflow.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frames_received'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_frame_sync_status.frames_received.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] + with self.subTest(msg='node: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + with self.assertRaises(AttributeError): + # this line is trying to set an illegal value so by definition should fail the type + # checks + self.dut.rx_frame_sync_status.frame_sync_errors.cppkbrgmgeloagvfgjjeiiushygirh = 1 # type: ignore[attr-defined,union-attr] @@ -15650,6 +16450,8 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + self.dut.rx_frame_sync_status, # type: ignore[union-attr,list-item] + ] readable_regs = [] for readable_reg in self.dut.get_readable_registers(unroll=True): # type: ignore[union-attr] @@ -15733,6 +16535,8 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + self.dut.rx_frame_sync_status, # type: ignore[union-attr,list-item] + ] readable_regs = [] for readable_reg in self.dut.get_readable_registers(unroll=False): # type: ignore[union-attr] @@ -15816,6 +16620,8 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + self.dut.rx_frame_sync_status, # type: ignore[union-attr,list-item] + ] writable_regs = [] for writable_reg in self.dut.get_writable_registers(unroll=True): # type: ignore[union-attr] @@ -15899,6 +16705,8 @@ def test_top_traversal_iterators(self) -> None: self.dut.rx_async_fifo_rd_wr_ptr, # type: ignore[union-attr,list-item] + self.dut.rx_frame_sync_status, # type: ignore[union-attr,list-item] + ] writable_regs = [] for writable_reg in self.dut.get_writable_registers(unroll=False): # type: ignore[union-attr] @@ -15979,6 +16787,8 @@ def test_top_traversal_iterators(self) -> None: + + @@ -16062,6 +16872,8 @@ def test_top_traversal_iterators(self) -> None: + + @@ -16145,6 +16957,8 @@ def test_top_traversal_iterators(self) -> None: + + @@ -16228,6 +17042,8 @@ def test_top_traversal_iterators(self) -> None: + + @@ -17565,6 +18381,58 @@ def test_traversal_iterators(self) -> None: readable_fields.append(readable_field) self.assertCountEqual(expected_readable_fields, readable_fields) + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + + expected_fields = [self.dut.rx_frame_sync_status.frame_sync_locked, # type: ignore[union-attr,list-item] + + + self.dut.rx_frame_sync_status.frame_buffer_overflow, # type: ignore[union-attr,list-item] + + + self.dut.rx_frame_sync_status.frames_received, # type: ignore[union-attr,list-item] + + + self.dut.rx_frame_sync_status.frame_sync_errors, # type: ignore[union-attr,list-item] + + + + ] + fields = [] + for field in self.dut.rx_frame_sync_status.fields: # type: ignore[union-attr] + fields.append(field) + self.assertCountEqual(expected_fields, fields) + + expected_writable_fields = [self.dut.rx_frame_sync_status.frame_sync_locked, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frame_buffer_overflow, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frames_received, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frame_sync_errors, # type: ignore[union-attr,list-item] + + + ] + writable_fields = [] + for writable_field in self.dut.rx_frame_sync_status.writable_fields: # type: ignore[union-attr] + writable_fields.append(writable_field) + self.assertCountEqual(expected_writable_fields, writable_fields) + + + expected_readable_fields = [self.dut.rx_frame_sync_status.frame_sync_locked, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frame_buffer_overflow, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frames_received, # type: ignore[union-attr,list-item] + + self.dut.rx_frame_sync_status.frame_sync_errors, # type: ignore[union-attr,list-item] + + + ] + readable_fields = [] + for readable_field in self.dut.rx_frame_sync_status.readable_fields: # type: ignore[union-attr] + readable_fields.append(readable_field) + self.assertCountEqual(expected_readable_fields, readable_fields) + # test all the memories @@ -17912,6 +18780,31 @@ def test_name_map(self) -> None: + self.assertEqual(self.dut.rx_frame_sync_status.get_child_by_system_rdl_name('frame_sync_locked').inst_name, 'frame_sync_locked') + + + + + self.assertEqual(self.dut.rx_frame_sync_status.get_child_by_system_rdl_name('frame_buffer_overflow').inst_name, 'frame_buffer_overflow') + + + + + self.assertEqual(self.dut.rx_frame_sync_status.get_child_by_system_rdl_name('frames_received').inst_name, 'frames_received') + + + + + self.assertEqual(self.dut.rx_frame_sync_status.get_child_by_system_rdl_name('frame_sync_errors').inst_name, 'frame_sync_errors') + + + + + + + + + diff --git a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py index b0b98ad..c0ee28a 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py @@ -2062,6 +2062,61 @@ async def test_register_read_and_write(self) -> None: + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status + with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_frame_sync_status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + register_read_callback = Mock() + register_write_callback = Mock() + + # register read checks + # update the value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.read(), random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.value = random_value + sim_register.read_callback = None + sim_register.write_callback = None + self.assertEqual(await self.dut.rx_frame_sync_status.read(), random_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + + + + # register write checks + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_frame_sync_status.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + # up to now the callback should not have been called + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_frame_sync_status.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + register_write_callback.assert_called_once_with(value=random_value) + register_read_callback.assert_not_called() + register_write_callback.reset_mock() + register_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + await self.dut.rx_frame_sync_status.write(random_value) # type: ignore[union-attr] + self.assertEqual(sim_register.value, random_value) + self.assertEqual(await self.dut.rx_frame_sync_status.read(), random_value) + + + async def test_field_read_and_write(self) -> None: @@ -8406,6 +8461,470 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status.frame_sync_locked + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_locked'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_frame_sync_status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_frame_sync_status.frame_sync_locked') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_locked.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFE) | (random_field_value << 0)) + + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_locked.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_locked.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x1) >> 0 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_locked.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status.frame_buffer_overflow + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_frame_sync_status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_frame_sync_status.frame_buffer_overflow') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x1+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFFFFFFFD) | (random_field_value << 1)) + + self.assertEqual(await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x2) >> 1 + + random_field_value = self._reverse_bits(value=random_field_value, number_bits=1) + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_buffer_overflow.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x1+1) + + await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status.frames_received + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frames_received'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_frame_sync_status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_frame_sync_status.frames_received') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFFFC) >> 2 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frames_received.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0xFFFFFF+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0xFC000003) | (random_field_value << 2)) + + self.assertEqual(await self.dut.rx_frame_sync_status.frames_received.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFFFC) >> 2 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_frame_sync_status.frames_received.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0x3FFFFFC) >> 2 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frames_received.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.rx_frame_sync_status.frames_received.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFC000003) | (0x3FFFFFC & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.rx_frame_sync_status.frames_received.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFC000003) | (0x3FFFFFC & (random_field_value << 2))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFC000003) | (0x3FFFFFC & (random_field_value << 2))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0xFFFFFF+1) + + await self.dut.rx_frame_sync_status.frames_received.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFC000003) | (0x3FFFFFC & (random_field_value << 2))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # test access operations (read and/or write) to register: + # msk_top_regs.rx_frame_sync_status.frame_sync_errors + with self.subTest(msg='field: msk_top_regs.rx_frame_sync_status.frame_sync_errors'): + sim_register = self.sim.register_by_full_name('msk_top_regs.rx_frame_sync_status') + self.assertIsInstance(sim_register, (Register,MemoryRegister)) + sim_field = self.sim.field_by_full_name('msk_top_regs.rx_frame_sync_status.frame_sync_errors') + self.assertIsInstance(sim_field, Field) + register_read_callback = Mock() + register_write_callback = Mock() + field_read_callback = Mock() + field_write_callback = Mock() + + # register read checks + # update the register value via the backdoor in the simulator + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC000000) >> 26 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_errors.read(), random_field_value) + # update the field value via the backdoor in the simulator + previous_register_value = random_value + random_field_value = random.randrange(0, 0x3F+1) + sim_field.value = random_field_value + self.assertEqual(sim_register.value, (previous_register_value & 0x3FFFFFF) | (random_field_value << 26)) + + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_errors.read(), random_field_value) + # hook up the call backs to check they work correctly + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC000000) >> 26 + + + sim_register.value = random_value + sim_register.read_callback = register_read_callback + sim_register.write_callback = register_write_callback + sim_field.read_callback = field_read_callback + sim_field.write_callback = field_write_callback + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_errors.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_called_once_with(value=random_value) + field_write_callback.assert_not_called() + field_read_callback.assert_called_once_with(value=random_field_value) + + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.read_callback = None + sim_register.write_callback = None + sim_field.read_callback = None + sim_field.write_callback = None + random_value = random.randrange(0, 0xFFFFFFFF+1) + random_field_value = (random_value & 0xFC000000) >> 26 + + + sim_register.value = random_value + self.assertEqual(await self.dut.rx_frame_sync_status.frame_sync_errors.read(), random_field_value) + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + + # register write checks + # update the register value via the backdoor in the simulator, then perform a field + # write and make sure it is updated + inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) + sim_register.value = inital_reg_random_value + + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.rx_frame_sync_status.frame_sync_errors.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x3FFFFFF) | (0xFC000000 & (random_field_value << 26))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # hook up the call backs + sim_register.read_callback = None + sim_register.write_callback = register_write_callback + sim_field.read_callback = None + sim_field.write_callback = field_write_callback + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.rx_frame_sync_status.frame_sync_errors.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x3FFFFFF) | (0xFC000000 & (random_field_value << 26))) + register_write_callback.assert_called_once_with(value=(reg_random_value & 0x3FFFFFF) | (0xFC000000 & (random_field_value << 26))) + field_write_callback.assert_called_once_with(value=random_field_value) + + register_read_callback.assert_not_called() + field_read_callback.assert_not_called() + reg_random_value = sim_register.value + # revert the callbacks and check again + register_write_callback.reset_mock() + register_read_callback.reset_mock() + field_write_callback.reset_mock() + field_read_callback.reset_mock() + sim_register.write_callback = None + sim_field.write_callback = None + random_field_value = random.randrange(0, 0x3F+1) + + await self.dut.rx_frame_sync_status.frame_sync_errors.write(random_field_value) # type: ignore[arg-type] + self.assertEqual(sim_register.value, (inital_reg_random_value & 0x3FFFFFF) | (0xFC000000 & (random_field_value << 26))) + + register_write_callback.assert_not_called() + register_read_callback.assert_not_called() + field_write_callback.assert_not_called() + field_read_callback.assert_not_called() + + diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd index c61b38d..4bda2d8 100644 --- a/rdl/outputs/rtl/msk_top_regs.vhd +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -114,6 +114,7 @@ architecture rtl of msk_top_regs is rx_power : std_logic; tx_async_fifo_rd_wr_ptr : std_logic; rx_async_fifo_rd_wr_ptr : std_logic; + rx_frame_sync_status : std_logic; end record; signal decoded_reg_strb : decoded_reg_strb_t; signal decoded_req : std_logic; @@ -548,6 +549,33 @@ architecture rtl of msk_top_regs is data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_combo_t\; end record; + type \msk_top_regs.rx_frame_sync_status.frame_sync_locked_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_combo_t\ is record + next_q : std_logic; + load_next : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status.frames_received_combo_t\ is record + next_q : std_logic_vector(23 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status.frame_sync_errors_combo_t\ is record + next_q : std_logic_vector(5 downto 0); + load_next : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status_combo_t\ is record + frame_sync_locked : \msk_top_regs.rx_frame_sync_status.frame_sync_locked_combo_t\; + frame_buffer_overflow : \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_combo_t\; + frames_received : \msk_top_regs.rx_frame_sync_status.frames_received_combo_t\; + frame_sync_errors : \msk_top_regs.rx_frame_sync_status.frame_sync_errors_combo_t\; + end record; + type field_combo_t is record MSK_Init : \msk_top_regs.MSK_Init_combo_t\; MSK_Control : \msk_top_regs.MSK_Control_combo_t\; @@ -584,6 +612,7 @@ architecture rtl of msk_top_regs is rx_power : \msk_top_regs.rx_power_combo_t\; tx_async_fifo_rd_wr_ptr : \msk_top_regs.tx_async_fifo_rd_wr_ptr_combo_t\; rx_async_fifo_rd_wr_ptr : \msk_top_regs.rx_async_fifo_rd_wr_ptr_combo_t\; + rx_frame_sync_status : \msk_top_regs.rx_frame_sync_status_combo_t\; end record; signal field_combo : field_combo_t; @@ -958,6 +987,29 @@ architecture rtl of msk_top_regs is data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_storage_t\; end record; + type \msk_top_regs.rx_frame_sync_status.frame_sync_locked_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_storage_t\ is record + value : std_logic; + end record; + + type \msk_top_regs.rx_frame_sync_status.frames_received_storage_t\ is record + value : std_logic_vector(23 downto 0); + end record; + + type \msk_top_regs.rx_frame_sync_status.frame_sync_errors_storage_t\ is record + value : std_logic_vector(5 downto 0); + end record; + + type \msk_top_regs.rx_frame_sync_status_storage_t\ is record + frame_sync_locked : \msk_top_regs.rx_frame_sync_status.frame_sync_locked_storage_t\; + frame_buffer_overflow : \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_storage_t\; + frames_received : \msk_top_regs.rx_frame_sync_status.frames_received_storage_t\; + frame_sync_errors : \msk_top_regs.rx_frame_sync_status.frame_sync_errors_storage_t\; + end record; + type field_storage_t is record MSK_Init : \msk_top_regs.MSK_Init_storage_t\; MSK_Control : \msk_top_regs.MSK_Control_storage_t\; @@ -994,6 +1046,7 @@ architecture rtl of msk_top_regs is rx_power : \msk_top_regs.rx_power_storage_t\; tx_async_fifo_rd_wr_ptr : \msk_top_regs.tx_async_fifo_rd_wr_ptr_storage_t\; rx_async_fifo_rd_wr_ptr : \msk_top_regs.rx_async_fifo_rd_wr_ptr_storage_t\; + rx_frame_sync_status : \msk_top_regs.rx_frame_sync_status_storage_t\; end record; signal field_storage : field_storage_t; @@ -1003,7 +1056,7 @@ architecture rtl of msk_top_regs is signal readback_err : std_logic; signal readback_done : std_logic; signal readback_data : std_logic_vector(31 downto 0); - signal readback_array : std_logic_vector_array1(0 to 37)(31 downto 0); + signal readback_array : std_logic_vector_array1(0 to 38)(31 downto 0); begin @@ -1255,6 +1308,7 @@ begin decoded_reg_strb.rx_power <= cpuif_req_masked and (cpuif_addr = 16#8C#); decoded_reg_strb.tx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#90#); decoded_reg_strb.rx_async_fifo_rd_wr_ptr <= cpuif_req_masked and (cpuif_addr = 16#94#); + decoded_reg_strb.rx_frame_sync_status <= cpuif_req_masked and (cpuif_addr = 16#98#); end process; -- Pass down signals to next stage @@ -2860,6 +2914,135 @@ begin end process; hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod <= decoded_reg_strb.rx_async_fifo_rd_wr_ptr and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); + -- Field: msk_top_regs.rx_frame_sync_status.frame_sync_locked + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_frame_sync_status.frame_sync_locked.value; + load_next_c := '0'; + if decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_frame_sync_status.frame_sync_locked.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); + load_next_c := '1'; + else -- HW Write + next_c := hwif_in.rx_frame_sync_status.frame_sync_locked.next_q; + load_next_c := '1'; + end if; + field_combo.rx_frame_sync_status.frame_sync_locked.next_q <= next_c; + field_combo.rx_frame_sync_status.frame_sync_locked.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_frame_sync_status.frame_sync_locked.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_frame_sync_status.frame_sync_locked.value <= '0'; + else + if field_combo.rx_frame_sync_status.frame_sync_locked.load_next then + field_storage.rx_frame_sync_status.frame_sync_locked.value <= field_combo.rx_frame_sync_status.frame_sync_locked.next_q; + end if; + end if; + end if; + end process; + + -- Field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow + process(all) + variable next_c: std_logic; + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_frame_sync_status.frame_buffer_overflow.value; + load_next_c := '0'; + if decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr then -- SW clear on read + next_c := '0'; + load_next_c := '1'; + elsif decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_frame_sync_status.frame_buffer_overflow.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); + load_next_c := '1'; + elsif hwif_in.rx_frame_sync_status.frame_buffer_overflow.we then -- HW Write - we + next_c := hwif_in.rx_frame_sync_status.frame_buffer_overflow.next_q; + load_next_c := '1'; + end if; + field_combo.rx_frame_sync_status.frame_buffer_overflow.next_q <= next_c; + field_combo.rx_frame_sync_status.frame_buffer_overflow.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_frame_sync_status.frame_buffer_overflow.value <= '0'; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_frame_sync_status.frame_buffer_overflow.value <= '0'; + else + if field_combo.rx_frame_sync_status.frame_buffer_overflow.load_next then + field_storage.rx_frame_sync_status.frame_buffer_overflow.value <= field_combo.rx_frame_sync_status.frame_buffer_overflow.next_q; + end if; + end if; + end if; + end process; + + -- Field: msk_top_regs.rx_frame_sync_status.frames_received + process(all) + variable next_c: std_logic_vector(23 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_frame_sync_status.frames_received.value; + load_next_c := '0'; + if decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_frame_sync_status.frames_received.value and not decoded_wr_biten(25 downto 2)) or (decoded_wr_data(25 downto 2) and decoded_wr_biten(25 downto 2)); + load_next_c := '1'; + elsif hwif_in.rx_frame_sync_status.frames_received.we then -- HW Write - we + next_c := hwif_in.rx_frame_sync_status.frames_received.next_q; + load_next_c := '1'; + end if; + field_combo.rx_frame_sync_status.frames_received.next_q <= next_c; + field_combo.rx_frame_sync_status.frames_received.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_frame_sync_status.frames_received.value <= 24x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_frame_sync_status.frames_received.value <= 24x"0"; + else + if field_combo.rx_frame_sync_status.frames_received.load_next then + field_storage.rx_frame_sync_status.frames_received.value <= field_combo.rx_frame_sync_status.frames_received.next_q; + end if; + end if; + end if; + end process; + hwif_out.rx_frame_sync_status.frames_received.swmod <= decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr and or_reduce(decoded_wr_biten(25 downto 2)); + + -- Field: msk_top_regs.rx_frame_sync_status.frame_sync_errors + process(all) + variable next_c: std_logic_vector(5 downto 0); + variable load_next_c: std_logic; + begin + next_c := field_storage.rx_frame_sync_status.frame_sync_errors.value; + load_next_c := '0'; + if decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write + next_c := (field_storage.rx_frame_sync_status.frame_sync_errors.value and not decoded_wr_biten(31 downto 26)) or (decoded_wr_data(31 downto 26) and decoded_wr_biten(31 downto 26)); + load_next_c := '1'; + elsif hwif_in.rx_frame_sync_status.frame_sync_errors.we then -- HW Write - we + next_c := hwif_in.rx_frame_sync_status.frame_sync_errors.next_q; + load_next_c := '1'; + end if; + field_combo.rx_frame_sync_status.frame_sync_errors.next_q <= next_c; + field_combo.rx_frame_sync_status.frame_sync_errors.load_next <= load_next_c; + end process; + process(clk) begin + if false then -- async reset + field_storage.rx_frame_sync_status.frame_sync_errors.value <= 6x"0"; + elsif rising_edge(clk) then + if rst then -- sync reset + field_storage.rx_frame_sync_status.frame_sync_errors.value <= 6x"0"; + else + if field_combo.rx_frame_sync_status.frame_sync_errors.load_next then + field_storage.rx_frame_sync_status.frame_sync_errors.value <= field_combo.rx_frame_sync_status.frame_sync_errors.next_q; + end if; + end if; + end if; + end process; + hwif_out.rx_frame_sync_status.frame_sync_errors.swmod <= decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 26)); + ---------------------------------------------------------------------------- -- Write response ---------------------------------------------------------------------------- @@ -2940,6 +3123,10 @@ begin readback_array(35)(31 downto 23) <= (others => '0'); readback_array(36)(31 downto 0) <= field_storage.tx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.tx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); readback_array(37)(31 downto 0) <= field_storage.rx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.rx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); + readback_array(38)(0 downto 0) <= to_std_logic_vector(field_storage.rx_frame_sync_status.frame_sync_locked.value) when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); + readback_array(38)(1 downto 1) <= to_std_logic_vector(field_storage.rx_frame_sync_status.frame_buffer_overflow.value) when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); + readback_array(38)(25 downto 2) <= field_storage.rx_frame_sync_status.frames_received.value when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); + readback_array(38)(31 downto 26) <= field_storage.rx_frame_sync_status.frame_sync_errors.value when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); -- Reduce the array process(all) diff --git a/rdl/outputs/rtl/msk_top_regs_pkg.vhd b/rdl/outputs/rtl/msk_top_regs_pkg.vhd index 8634115..a4ca55e 100644 --- a/rdl/outputs/rtl/msk_top_regs_pkg.vhd +++ b/rdl/outputs/rtl/msk_top_regs_pkg.vhd @@ -9,7 +9,7 @@ package msk_top_regs_pkg is constant MSK_TOP_REGS_DATA_WIDTH : positive := 32; constant MSK_TOP_REGS_MIN_ADDR_WIDTH : positive := 8; - constant MSK_TOP_REGS_SIZE : positive := 152; + constant MSK_TOP_REGS_SIZE : positive := 156; type \msk_top_regs.msk_stat_0.demod_sync_lock_in_t\ is record next_q : std_logic; @@ -160,6 +160,32 @@ package msk_top_regs_pkg is data : \msk_top_regs.status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1.data_desc_a6882ec4_in_t\; end record; + type \msk_top_regs.frame_sync_status.frame_sync_locked_in_t\ is record + next_q : std_logic; + end record; + + type \msk_top_regs.frame_sync_status.frame_buffer_overflow_in_t\ is record + next_q : std_logic; + we : std_logic; + end record; + + type \msk_top_regs.frame_sync_status.frames_received_in_t\ is record + next_q : std_logic_vector(23 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.frame_sync_status.frame_sync_errors_in_t\ is record + next_q : std_logic_vector(5 downto 0); + we : std_logic; + end record; + + type \msk_top_regs.frame_sync_status_in_t\ is record + frame_sync_locked : \msk_top_regs.frame_sync_status.frame_sync_locked_in_t\; + frame_buffer_overflow : \msk_top_regs.frame_sync_status.frame_buffer_overflow_in_t\; + frames_received : \msk_top_regs.frame_sync_status.frames_received_in_t\; + frame_sync_errors : \msk_top_regs.frame_sync_status.frame_sync_errors_in_t\; + end record; + type msk_top_regs_in_t is record MSK_Status : \msk_top_regs.msk_stat_0_in_t\; Tx_Bit_Count : \msk_top_regs.msk_stat_1_in_t\; @@ -176,6 +202,7 @@ package msk_top_regs_pkg is rx_power : \msk_top_regs.rx_power_in_t\; tx_async_fifo_rd_wr_ptr : \msk_top_regs.status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_in_t\; rx_async_fifo_rd_wr_ptr : \msk_top_regs.status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_in_t\; + rx_frame_sync_status : \msk_top_regs.frame_sync_status_in_t\; end record; type \msk_top_regs.msk_init.txrxinit_out_t\ is record @@ -540,6 +567,19 @@ package msk_top_regs_pkg is data : \msk_top_regs.status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1.data_desc_a6882ec4_out_t\; end record; + type \msk_top_regs.frame_sync_status.frames_received_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.frame_sync_status.frame_sync_errors_out_t\ is record + swmod : std_logic; + end record; + + type \msk_top_regs.frame_sync_status_out_t\ is record + frames_received : \msk_top_regs.frame_sync_status.frames_received_out_t\; + frame_sync_errors : \msk_top_regs.frame_sync_status.frame_sync_errors_out_t\; + end record; + type msk_top_regs_out_t is record MSK_Init : \msk_top_regs.msk_init_out_t\; MSK_Control : \msk_top_regs.msk_ctrl_out_t\; @@ -576,5 +616,6 @@ package msk_top_regs_pkg is rx_power : \msk_top_regs.rx_power_out_t\; tx_async_fifo_rd_wr_ptr : \msk_top_regs.status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_out_t\; rx_async_fifo_rd_wr_ptr : \msk_top_regs.status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_out_t\; + rx_frame_sync_status : \msk_top_regs.frame_sync_status_out_t\; end record; end package; diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index 6437efd..b1ec87d 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -552,6 +552,48 @@ addrmap msk_top_regs { } data[31:0] = 0; }; + reg frame_sync_status { + name = "Frame Sync Status"; + //desc = "Frame Sync Status"; + regwidth = 32; + field { + name = "Frame Sync Lock"; + desc = "0 - Frame sync not locked + 1 - Frame sync locked"; + fieldwidth = 1; + sw = r; + hw = w; + } frame_sync_locked = 0; + field { + name = "Frame Buffer Overflow"; + desc = "0 - Normal operation + 1 - Buffer overflow"; + fieldwidth = 1; + sw = r; + hw = w; + we = true; + rclr = true; + } frame_buffer_overflow = 0; + field { + name = "Frames Received"; + desc = "Count of frames received since last read. Value is 0x00_0000 to 0xFF_FFFF"; + fieldwidth = 24; + sw = rw; + hw = w; + swmod = true; + we = true; + } frames_received = 0; + field { + name = "Frames Sync Errors"; + desc = "Count of frame sync errors since last read. Value is 0 to 63. This field will saturate at 63 if more than 63 occur."; + fieldwidth = 6; + sw = rw; + hw = w; + swmod = true; + we = true; + } frame_sync_errors = 0; + }; + msk_hash_lo Hash_ID_Low; msk_hash_hi Hash_ID_High; @@ -685,4 +727,6 @@ addrmap msk_top_regs { [*] Read the register [/list]"; + frame_sync_status rx_frame_sync_status; + }; diff --git a/sim/msk_test.py b/sim/msk_test.py index 0b45ed9..7792c44 100755 --- a/sim/msk_test.py +++ b/sim/msk_test.py @@ -849,6 +849,9 @@ async def msk_test_1(dut): await regs.rx_power.write(0) data = await regs.rx_power.read() print("Rx Power", hex(data)) + await regs.rx_frame_sync_status.write(0xFFFF_0000) + data = await regs.rx_frame_sync_status.read() + print("Frame Sync Status", hex(data)) #data = await regs.read("msk_top_regs", "LPF_Accum_F1") # print("F1 Acc: ", hex(data)) # data = await regs.read("msk_top_regs", "LPF_Accum_F2") diff --git a/src/msk_top.vhd b/src/msk_top.vhd index d030c48..47506cd 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -496,7 +496,7 @@ BEGIN m_axis_tlast => sync_det_tlast, -- Frame synchronization signals - frame_sync_locked => rx_frame_sync_locked, + frame_sync_locked => rx_frame_sync_locked, frames_received => rx_frames_count, frame_sync_errors => rx_frame_sync_errors, frame_buffer_overflow => rx_frame_buffer_overflow, @@ -780,6 +780,11 @@ BEGIN f2_nco_adjust => f2_nco_adjust, f1_error => f1_error, f2_error => f2_error, + pd_power => pd_power, + rx_frame_sync => rx_frame_sync_locked, + rx_frame_buffer_ovf => rx_frame_buffer_overflow, + rx_frame_count => rx_frames_count(23 DOWNTO 0), + rx_frame_sync_err => rx_frame_sync_errors(5 DOWNTO 0), tx_async_fifo_wr_ptr => tx_async_fifo_wr_ptr, tx_async_fifo_rd_ptr => tx_async_fifo_rd_ptr, tx_async_fifo_status_req => tx_async_fifo_status_req, @@ -825,8 +830,7 @@ BEGIN tx_sync_f1 => tx_sync_f1, tx_sync_f2 => tx_sync_f2, pd_alpha1 => pd_alpha1, - pd_alpha2 => pd_alpha2, - pd_power => pd_power + pd_alpha2 => pd_alpha2 ); END ARCHITECTURE struct; diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index 830c1c8..e91a01e 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -128,6 +128,11 @@ ENTITY msk_top_csr IS f2_nco_adjust : IN std_logic_vector(31 DOWNTO 0); f1_error : IN std_logic_vector(31 DOWNTO 0); f2_error : IN std_logic_vector(31 DOWNTO 0); + pd_power : IN std_logic_vector(22 DOWNTO 0); + rx_frame_sync : IN std_logic; + rx_frame_buffer_ovf : IN std_logic; + rx_frame_count : IN std_logic_vector(23 DOWNTO 0); + rx_frame_sync_err : IN std_logic_vector( 5 DOWNTO 0); tx_async_fifo_wr_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); tx_async_fifo_rd_ptr : IN std_logic_vector(FIFO_ADDR_WIDTH DOWNTO 0); @@ -175,8 +180,7 @@ ENTITY msk_top_csr IS tx_sync_f1 : out std_logic; tx_sync_f2 : out std_logic; pd_alpha1 : out std_logic_vector(17 DOWNTO 0); - pd_alpha2 : out std_logic_vector(17 DOWNTO 0); - pd_power : in std_logic_vector(22 DOWNTO 0) + pd_alpha2 : out std_logic_vector(17 DOWNTO 0) ); END ENTITY msk_top_csr; @@ -249,6 +253,9 @@ ARCHITECTURE rtl OF msk_top_csr IS SIGNAL pd_power_req : std_logic; SIGNAL axis_xfer_count_req : std_logic; + SIGNAL frames_received_req : std_logic; + SIGNAL frame_sync_errors_req: std_logic; + BEGIN s_axil_i.AWVALID <= s_axi_awvalid; @@ -294,10 +301,14 @@ BEGIN END IF; END PROCESS csr_init_proc; - ulck_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, '0', hwif_in.MSK_Status.demod_sync_lock.next_q); - utxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_enable, hwif_in.MSK_Status.tx_enable.next_q); - urxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_enable, hwif_in.MSK_Status.rx_enable.next_q); + ulck_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, '0', hwif_in.MSK_Status.demod_sync_lock.next_q); + utxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_enable, hwif_in.MSK_Status.tx_enable.next_q); + urxe_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_enable, hwif_in.MSK_Status.rx_enable.next_q); + urfl_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_frame_sync, hwif_in.rx_frame_sync_status.frame_sync_locked.next_q); + + urfo_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_frame_buffer_ovf, hwif_in.rx_frame_sync_status.frame_buffer_overflow.we); + hwif_in.MSK_Status.rx_enable.next_q <= '1'; hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; -- Status Request from AXI to MDM @@ -313,6 +324,8 @@ BEGIN utlp1_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F1.data.swmod, lpf_accum_f1_req ); utlp2_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.LPF_Accum_F2.data.swmod, lpf_accum_f2_req ); utpwr_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_power.data.swmod, pd_power_req ); + utfss_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_frame_sync_status.frames_received.swmod, frames_received_req ); + utfsr_r: pulse_detect PORT MAP (clk, csr_init, hwif_out.rx_frame_sync_status.frame_sync_errors.swmod, frame_sync_errors_req ); -- Status acknowledge from MDM to AXI utbc_a : pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, tx_bit_counter_req, hwif_in.Tx_Bit_Count.data.we ); @@ -327,6 +340,8 @@ BEGIN utlp1_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f1_req, hwif_in.LPF_Accum_F1.data.we ); utlp2_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, lpf_accum_f2_req, hwif_in.LPF_Accum_F2.data.we ); utpwr_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, pd_power_req, hwif_in.rx_power.data.we ); + utfss_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, frames_received_req, hwif_in.rx_frame_sync_status.frames_received.we ); + utfsr_a: pulse_detect PORT MAP (s_axi_aclk, NOT s_axi_aresetn, frame_sync_errors_req, hwif_in.rx_frame_sync_status.frame_sync_errors.we ); -- Status capture from MDM to AXI utbc_c : data_capture PORT MAP (clk, csr_init, tx_bit_counter_req, tx_bit_counter, hwif_in.Tx_Bit_Count.data.next_q ); @@ -342,6 +357,10 @@ BEGIN utlp2_c: data_capture PORT MAP (clk, csr_init, lpf_accum_f2_req, lpf_accum_f2, hwif_in.LPF_Accum_F2.data.next_q ); utpwr_c: data_capture GENERIC MAP (23) PORT MAP (clk, csr_init, pd_power_req, pd_power, hwif_in.rx_power.data.next_q ); + utfsc_c: data_capture GENERIC MAP (24) + PORT MAP (clk, csr_init, frames_received_req, rx_frame_count, hwif_in.rx_frame_sync_status.frames_received.next_q ); + utfse_c: data_capture GENERIC MAP (6) + PORT MAP (clk, csr_init, frame_sync_errors_req, rx_frame_sync_err, hwif_in.rx_frame_sync_status.frame_sync_errors.next_q ); -- FIFO status reads rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod; From 19c15f17577f893c29ef51d990434172324d3d49 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Wed, 12 Nov 2025 22:38:44 -0700 Subject: [PATCH 34/60] rdl: update outputs --- ...d5d50d18610dbbfe8e1803c2e8d1c73b5a100.html | 4 +- rdl/outputs/docs/html/index.html | 6 +- rdl/outputs/docs/msk_top_regs.docx | Bin 41861 -> 41860 bytes rdl/outputs/docs/msk_top_regs.md | 12 +-- rdl/outputs/docs/msk_top_regs.pdf | Bin 117408 -> 117366 bytes .../msk_top_regs/reg_model/msk_top_regs.py | 78 +++++++-------- .../msk_top_regs/tests/test_msk_top_regs.py | 84 +--------------- .../tests/test_sim_msk_top_regs.py | 94 ------------------ rdl/outputs/rtl/msk_top_regs.vhd | 47 +-------- 9 files changed, 55 insertions(+), 270 deletions(-) diff --git a/rdl/outputs/docs/html/content/9d2d5d50d18610dbbfe8e1803c2e8d1c73b5a100.html b/rdl/outputs/docs/html/content/9d2d5d50d18610dbbfe8e1803c2e8d1c73b5a100.html index 52f0bd5..e1c4393 100644 --- a/rdl/outputs/docs/html/content/9d2d5d50d18610dbbfe8e1803c2e8d1c73b5a100.html +++ b/rdl/outputs/docs/html/content/9d2d5d50d18610dbbfe8e1803c2e8d1c73b5a100.html @@ -69,7 +69,7 @@

Contents

[1]
frame_buffer_overflow - rw, rclr + r, rclr 0x0 @@ -89,7 +89,7 @@

Contents

[0] frame_sync_locked - rw + r 0x0 diff --git a/rdl/outputs/docs/html/index.html b/rdl/outputs/docs/html/index.html index b7fb4d4..8fdb151 100644 --- a/rdl/outputs/docs/html/index.html +++ b/rdl/outputs/docs/html/index.html @@ -14,7 +14,7 @@ - - + + diff --git a/rdl/outputs/docs/msk_top_regs.docx b/rdl/outputs/docs/msk_top_regs.docx index 5559d204a8f9e4eb0773419b179f5c1a3f98da56..ac6b82d76b9237cebc39d6873715a18c399a53a7 100644 GIT binary patch delta 948 zcmZoY&eU?8i6_9DnMH(wfq{cz>6VQ=M;MuwZrOZ^Q65ZxW|{`3yII7Uc$aR;iS|-B zv|@!A14IAj^=x{g^&jh&+}iB^aND*Sv2s5=BXyP-|AUB-_&Q%8 zllNSbICU3}8*_nZ0`)Bk?+D}CAYy1RGrv5WsAOFstvJrQ%)-Xcrx z?TmM^vHvvWe}=t2&=bo3>iyxz%|$LTF}25b$)4mY{d=IU_4UE6Rn>P4@_+kyna!!4 zGjYqemkyH68oBqjow+^5FtWPZbkeijn=xmM7OtC?S@l=8*fMdW+{~<-ChFoL$GlGe zU96bJkh?bV-jl^YlS6+u@gQ3Zj2DzhMT^ z&)W^a@{*ksnLzwC-QU@O^yHO9M8(cG z2T{}J+k&X8^KDSm%4E3(M)IK4lh+_EWW>n8aGHgIK?a!QV4#69e{%i;ZII?U3uG8? zPu{se4#c^+K!&N>Z}JR38NL8-MkWzvSUR1oxKM`i&1AcU3Ls?(K+dhnwF{NOmi)F{ zP@K%f!0?-kfk6mn1CVZD?4oQl(TR>6@TCR@xt|`$BN&}u01?CjDuZJaJzA!fR5aAk*ehNscgmX`F=4hUR>}Y z(X8t;???UP%5U75y>r5>TI+6R1eEhX4Uapxw>zi8m~;Oe&yZ7@_x{#Dapc>$@Rhye zC8<~c_b}Yeh+})r>al(1z0Dpw7adE_nc{65o_BP?N(sl$GZbtSj3lp{e~U43Im+Dq z>dyVHTZi`rE?;waN|RWLclq;-|GckwGj1wKUDk1C^4|MuqJqxV=N-#3PVCUMJMpzz z?6|UBz2`!Oje8!fIvsOi$?9X1d%xA+yr}>C?c7(FSg(sqyZ0{syZP0lrN1Wb+*Mz2 z#pagb-QBzX1loOCd#zD&E#H;0qY+!+tv$Ijw`(SE`t~hLY>4T!S-7nu1ME_`h z!wjOIwHtutB|0ZEf%vPtzq0}9$x9|(15q`Tzk@_er-*`8^-P@!)}=o46DvqsdcHk~ zikWW?qNdKb1yNV#+n^?v$+8QKKoWrqWEcx3=Pl3%ab^QKcP8&xAP3^y0CH+3e_fyn z;wUVXVSGE;cA)}@6A$Fvo?Np~8N^u#{iaaP~&TFu`z8sj0 z*%%oZgn={+G%(Jb?6^ot0i?$6)YGebffDLKHF7WoK)QjkaPs7y$qIY{-i%Bl%&^=r zdE+7(#;nQb7O8`6m~f%JGn<)#p;MHBK?p^6<7AP=ieNR1PFzdh%gVseqQJl)j-p0p Na>!yWHoo~FK>%&$dHDbU diff --git a/rdl/outputs/docs/msk_top_regs.md b/rdl/outputs/docs/msk_top_regs.md index c020bbc..c3a221c 100644 --- a/rdl/outputs/docs/msk_top_regs.md +++ b/rdl/outputs/docs/msk_top_regs.md @@ -855,12 +855,12 @@ Bits 15:00 - read pointer (12-bits)

- Base Offset: 0x98 - Size: 0x4 -| Bits| Identifier | Access |Reset| Name | -|-----|---------------------|--------|-----|---------------------| -| 0 | frame_sync_locked | rw | 0x0 | Frame Sync Lock | -| 1 |frame_buffer_overflow|rw, rclr| 0x0 |Frame Buffer Overflow| -| 25:2| frames_received | rw | 0x0 | Frames Received | -|31:26| frame_sync_errors | rw | 0x0 | Frames Sync Errors | +| Bits| Identifier | Access|Reset| Name | +|-----|---------------------|-------|-----|---------------------| +| 0 | frame_sync_locked | r | 0x0 | Frame Sync Lock | +| 1 |frame_buffer_overflow|r, rclr| 0x0 |Frame Buffer Overflow| +| 25:2| frames_received | rw | 0x0 | Frames Received | +|31:26| frame_sync_errors | rw | 0x0 | Frames Sync Errors | #### frame_sync_locked field diff --git a/rdl/outputs/docs/msk_top_regs.pdf b/rdl/outputs/docs/msk_top_regs.pdf index 60c703c84fe3af9c951733d32e82e46113b1bf36..9821309b7b3651ac953d1596086f3c0b93c34422 100644 GIT binary patch delta 15913 zcmajGQ*fry5-uFuwmoq&v27a@n-lws?Jt>lV%xTD+qQjX?_Gb@f3D8Os(M#d_j}jf z4|?S!Lq8=!*YHDuadHDuIcNczx~lse7=F{$Gx_}UF#2{@+alO*t5e za>lCbLT%k$l7DQC(Ta1Gbco_Bq>g=#p9mvzxXDiX!&`3SP(u<(B597f5HR2ZL4L67 z##D8oC-o?1qx9w?&5G9l4r%d^0V|Sq;eNAo;Ugr>atdKz0)?M>fNBERJgSu>rNTxO z{ct(-{gmLUo?H7C_zdQG6b_F#_{_49PJfs4bcK=>(|I$YH9h&nt5$LLaADmv^Pl0G z*(-$w6C$(~p^o}7kt8t>F%#dYf_NkkuDfz60q(7hGlSgxTm5w*YEGSCaC}{S!V9Y& zP0(c*>k+^m zw95E%0i8n4W=b9w6Za>Fx~tx{IxoX%7SGRKmSOt3aYnwBEdR|zhGfej3)Uo4-Z5R7 zfDq%Qow(nP;Zs`x$!z#+wvincPMCR5jYSS1?;IZw=57&ts1;7&GsY2vrjJPyANM?Y zYI!Y8Draj|496UFTXL(w4Dujuoes=GZb(-^?2x|RHlEr`Z=sQk$ zoS31Yc_5ex?(zI^YBy)?iI!iXk<-#oZS+-)$j44y%ak`h|8hDh4b>r;&=1vbQ}bx)BGIfVdTw-;xVd8|3<(yNtZv{4oqLv$bA409#znN<^I<)h|b!`pb`WXD8^h)f#dJBfE# zVi0~%d1cJfSfU$D}l^JMIDmBNQGNdpz&wqGDU^To$0!`uR0H_b)FmEOjAK&+b z7Z*InQbw5dI1F86W84bH5qmVf(UO)4x$ilv>g_&2ⅈ-A|EQf6S53|b_aj^QJsYk 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 MaFmqdiV|@D2Xg0>Qvd(} delta 16000 zcmajGQ*!t&bvoE_c5HOmvD2~5j&0jEIywD)|2hA`&AF?pF-Kk0 zsJYfV-{)OVDX_m%VQYn8Ab8o*U2DMUfRow^?(5uW-RIgjvQrv>T&RSsjg`pxB3JXn z0}I|pNrmi0+4LeuuAXj0h$5+Ije|AM^AK?H-m8H37o6U${(-Fybg%t9N(jm)kPMy# zyM_^7xU5gZQwls<{)BV5X5dcbC=0jvTr?#!csEYcP1;&iSSq^Txs|3Q4S?|L zC&UbHM2ltRB6*w%IS8)4`;iBz_&{AIzV9&XIOaeBd(_pT!IFS zm=O$^%Bo(8pR#&PowQ}y6zF#G_OV!tz99&5^0iwsYq0?6P=s6H?@PgNmF#$!k($ap zi7~S0Ppe3sDDR;NLCcEn!4+U&kkuuNl8HqQ&Xuoit1~XHe}q`z%_Maj@O?sZ;1!b7 zPX&W(%y1ES_9me|p+4H6ll!_KUe<$$>}cwqQnBBZX4&^x_3OgZ%Cqfq%Yco&4F-1vlE9PifqvTLjV%e@R|v4a+jj;(WLB*`Q@- zLQXPai98-RD^2m#z+U{)7^;q#)k^qS9wu53LG`{)!$k|9tt}txPgOk~>2&h2H1Mbr z>Nt|itH(;D3d*K3Q{%JFqwk~4LWeV$xtWwO#91GveY0}X`Kj4n12mqbobmyA<3>Q3 zgX9vThU(bNd;bbn`*(`u%Tz7JBIA$}G6_?!5PRfThIOELxjf3kt#o7y$5>$!m}NY) zJ`&YN2XwZ++5s9a+1m`5t$@>TMIn%L^ziZU1)T6&=c|8li7akznIA+{r zu`t1>rCfO4$4BRW0f}M)StxrH$rHg~msNUwwicQ@S=tjoA>(~DS&AK@?gAufn*Pfg zW|H8$L5amfcE#s>@b(Ffp`aTriEWtMjKCy1;>-ZWlX}sGF4STKStQrF0mh#!OqQm^Cu3Mr3E$(kh!}f&B$>sLR`QkJce@1 zR#i`vE{|j`HR$MF%~?$cBSSe1pW}=jIFUu)~Oz zbN}r%zQMjTvLVmW3;B>e(ShAJ-Y91%&Qo2SC`l%9Ph>VBV~EXPoyG{DZy_{CF^I*} zGBntV_BG`Ob_9AWtvQ@~p|!-dw^zW{`HjD3j8nlR$$}3S$-0h=Ox)y(^=LV&S6H$k zy9=NjkVUTcjzj6BFV)qo-MandTB#z^C!4$JY+HCIa**spBlm;b`HfZE>^oQr8-0tX zil0}-n~X~?&8s#>%INjW$gML#k4f)snZ^ewLf*3qJY<+CL7Cdkw{3?-a);{+AstRH z;w4!yBlxId-uZ*5bdIxfEqLE$tHIcC`wMH8 zsy;B;7L^{H^kg4_j%}&yO<2F3 zGESAie&9V0-DK)C&bF_p-yjQ(X^vJJn+j%GxwO+0Z5(gG_O&%r35dJ9K5_qdj(nuG zcWmwI5h8e+DyWfsi&2ug5XYtAPlYFXy*bi~Dgqy-TTGx&wwHQZzvGmLnq#R`>LydR zOmcH!g((f;2xeS)ixM0YUOXG2ZcXd5T~gw)I_xcbXKOG~Ej(xJy2DX_<><^G3&H~) zRd?PWJ*PuI0S;sn*+A3$38!$4SDr7A#Ju_pQ4z!sjhzvSo`L~oq4D3!@#swS=diK+a-{LlezdCGNk?s( z?Rm6h@P?QL$Ft5D!z-NSHkAFmZZfl%RTutI>KE!bHlm<34$X%gzu1n@@1TxV*TPIP zQ0eE><6_%F&z*)Cg8b6a?1z8dW}_RyJ%L42hfX2sTMGF5AT$hzko^)IZk18=TVh69 zHx;^EFT(i8&?wNnBK(1D6J4@D5{%}lw-t7txK`Du*=8gXTO?}5vCb%bTii5&wiqUy z2T(u`seaNZI`l)GVqqQeyK9~ir;mTxoY9{%u-?F%%0ziSOTAhh{*WGKM$UGHxKYzrj;XPxai+rrzJbH4BHwG!zmcR@P$qDr9m&5KskuH40#r>4pb zfw`d#krwFuQ9bhVM1OiVNR^?0dCz{-d*E)w9ax9Cu-&hpD2U~AC}5>meV)b*$=C6l zJ8WQ@t7h%^90ri}TwNn9!{NM)h<9VMA<^A#FW8??Ey~HE=?5ul}9Eo7*WZ~}NW@+k(V3{n5MFh^BY>FiSyvV;jD}Y=wiw;DR zMUY6$kj!wPPBQ3te-ywfAH36J6`OBV7A*SX-tGP#N7pWm)%A0xHn%9bunnXtjxot4 z{~HZ6*d?TqJrpr)4kE`KM=1>L`x#E;bb-!Z$wk$+RV8TTCAsI0O%1_%aqZ1fJL0j# zp=)8~y#CUm;oWc#DA;ki6iZxV5tbfRHC}*v>I}kQ!Q`|IrwaB}^b0+me&^YY-E4qD zh&zh9e!*LCmD-c^^|Vc~=``##vP@4koH%=Az##Je#XwToj=DK(kh$6F+8+ZR!-np< zmulo9{k#=p<}aL@xv!n>Xjt6=_MRGTrOMgt7++YPf-%nwj7HThF-b|3JRKp>Oxa7W zLWbEkRw370e_UE9tS&Fr5n%qRd*1pZTs;3C*j9w_`_j7%_PE>dhl69f=ed^wQu6ZY zfm44ko)i+>XyhEcT2fL5M+z(LF)1CxP9Y;BhU--m>F zz1i8=S+*o;%)VmSYxIt(^L+#C?uciEXjR;;NA^7!pt1NSp5TnUKekPA#ryq+;j6%c zYS-QQQOQJ32+ya}nU3SRC2j<0mjSTRYpA=GO1g=8&X|Fbzvl{GYD~rtWVkIkRthgQ zM4lJ|!ym|f2hp|*d9v_5THCs&Ur=>dFy3JQavWQHoDq2P0^16;N6u*QKCiDEy4`_H zHaGhV%>QHLhgqLz%yJZWP3Y@=wAAkUmR-1=bz(jJtt$c)@N{8*2#gfQS}os~fwjxK z1tK>g>rS;p4$=qu;`!2aA4gKj|HR$#C7}(S`+eYRg)!2xfmd(}d=>t!jdJz42e_Sn zpMv48t^7zveXV-B;`Tgja9z4rRwr`#BO2=mJcJ`lLDd`J+(`+P|Ehww~p1I47q+-V|1(*+v*yzp%a|*1zmT zn4uBBB+fA02HYUZx9!N>sO>&kg8-#~FbCzZs^zk5>AsXaT&7-E*f2+8`}cX0ECGLQ z7l>S#*wu=a+2sH+W0ic@EN16QmzB`8b>*1=uQL6xXNJG_Y}O)lIc{%B9&fz%tP-W? z4CiM6@8b#Y=hj_sN6HdRibipDYIwo`zr_<2kFOq-1hbH2J3PAob~t@kiXQZ%zQ$MVz;i%3{ z#QT_~EU@m{$@bUkiZ6&fLee`))v=qJ{Q_{ZCTp3kD$L*f-H83(_ylzMdm5UuxWkXD z)tq~DMH)poQ2o{}wy9<4oGSJ`iKL;eg0adBF=2`1;oK41B$fg>en-j*9xP`)fC;!#&5kP0^p{5UTTAGYH7y@u#r z4x0!A>^e>Qa?=Ms&>Bgpk0*~&7=MErl&;QuNzQ)bA8)5e#ohN4W+c={&Ajavx_ypo zd^&)xf~#Ir)yxTiXtaavhpd6BUSr5l1sXNl{b1xf)Q;0ambTIOO;W9wKQqz>E zAnq8vMp<8how)cLNKpMLH+z;xT1~otz|vYF(}!JdTkKjH#3)Z4Ge{fA2qp0vmfDNm zi9_R$Aw+8sw54Fwkvf3gNc&fNT1%9%iqko!dJuZItU%i(EFEFFnl|iwDLU-D%eW?b z{b#+{FRm(uJO_C(N_*!Vazf=X<}$xjDL;y8Heo8?%ZhLr6fqY$4bvD(G|m`BgC?MgvH;N zkVrF?z~ota2_L}lymDdBX${cfFbz9ztXY`ZwLULtyT3hVDPQt$>hWh5DFB@OT^8d6tQuNeT8xq4FJ}NJh=8p-hB5b+MiM4=1x}3PpQZ$ln z@WuEsV&$$A=a>Yv#FJ@nk!HYgLT-8fr0GyR??a$j`6_U)Xw>*!=5Wz+lCXOWbCt9zuVf1-V(Yel7^ zAT)1{39v^7=J9THDYVGB&jzgVnvafjXCrm{dYyjhejn&5*D|~FGW?u$a9WQsT1QGJ zmldvYzPD}IZXgkWX1EXlt`4slGrb&O8Fa^V0MOtV#M`vE-q8Cpp`mksAaR<#k;Uyp zPNjU6I*C;B%cntZ3O%K2P`l%iW8Hy{?O4@{>Q{;oz)l&lKL9Xg(`!+vFonq!?yS+|97#V^+pm6LqYhFn_!W)u-%) zHa0dCBeEt^GIkdE{7Yofa;~VtoTniG?Pg_WdwGV1Q7or!G27c& z;}_ZULb_a)^=8NaCRmUFE{3JrSE~WUkt?swCzwnxypM-Eyt!ef(9w@|`Y}trr)VnA zbfLhB--QZUuNf4}M$V?rMD;`CJDs|c;vJ2*zo_9XDgv3ddj%xQk$WKcAGyLLj^(#A z6_`iAbmmPVQ}<}D;to?pdlJlMj10U;Do8<0?Ea+)D(RhdKs50QYGzg|c?%8j>f5>N zS>Hw4xoMY?C+uTI2sO(2H;(IXk!)3DQ6pYvteWuSfKpfKh)6+DHH9>EAhOG0K$QG# zPIcOOaNr)h;CjWV^6BZtb79H8b#ckQNM5GiaoZnEb!9aZ3-cZHg+XQu`IC7SOdcrr z{M?|-RvffKKLWeGDCe7x9yUy1#50LbZfFMYybjtYEXMq{wM_CVTW@+pk^R|S%MOiL zZgN&YP)mdxCe~Krz8&=G2#WDDvZvA#wx=g7=4(k<;d0GgLDupS18UZMJHy9m&WUxP zqy54B3|b)u;wKW*AZSQ>{p*i-zZnH`!IDY76da)}NY^px{77BEUg$TFQQ|Toc!~3| z>xFe6gpjfG$(`{G*@B4A&v}_y;$(I6DDl@HLYG5IYOhOn{OO0!Ay@yC(&G8WZC|+X zQSrE_1VQz6lONH+n`2iLsfALMkNUoxy zOE$q`1Zpe&2jg^|Ywu{?kl~Sm1y7K3cgq%yZui~d-m`18cdB|0`-kmq>h+|NX z*L)-@Di4bGUimuXqN35d_m5sfUiDb-_l>rp$n_`D#r%0mgQNc$X@+4tAYMMoOS$|| zlgphvjMJwwoV4Xq?vMzbHv-Jg9&c@V{XxeIJWd(lFF(2IdY9*~56fxd?XEhr)Z6(^ zBwFiB^p)96e}%z&>(Wr5oi`<&RgKWXu(4*kO5Q&TSYZ10hUH+W{Yb@1sNa!*w(nyg z$S<`GEm6$br6UtuZhHl5h(UC8D6B5kfILrF^U8@A&Q`rP6ek!syo(!5%`g68`*Rlq zNDFa+wOK%J%@Ao?Y#NE=dKedo052<9g+iXDKX?ab<^xuzOQ|IQEd+AyVS;OAR9ax1 ztg5yBTmOk66rLGy6C{X4_mb<8;|CMsU?K|BwI7yh-4wFZOdlcoz~D| zBIM=@Hd;_K_K~%D+!MNrWA{;z+qVJ(G=mLx>aQHwjZf*l&25Zc-i% zg*L)0eyy?TPgC=Kr>huw|8T7GRO+d|>z`1zKw&HPZ-6Z&x|gk7p<)fJxp`Z4Aa>g!3;Bu6O6R?CpsF7ztxE63zF zh8O!{#<20b_3t;+qM{VvpwJmC_~k*I!R0!Mt8OlTe52U&O;#LqI92nmk|MeZ7{lbX z-HPeT`Abo9$rpuQv^U=u$m4%<2g|}`;)T@~e;*MF)z#$hyoWbJ+%)(*g!=OL$EwzI z;!wy7oE7{v(!F0Xs<0kaybcE8U?=PYT?D?aHi>udZUE*2q2YXqXI8rV0r1}W7iA_6 zC0ehvZ;QU zi~vulmHRf&EnK3_aM&9>4f$SZxor0om1IE%8aXKzl`{X_EenJ-J?d;>-Tf_`G*Q^Hoqih6fUB|>W&=D1s*{8Qt-^v9l1ro7#8 zu#)Q=|4n!Bj816OoRUq%>+3G2ftu1GVdBwzQS>=6vcHAmk|_XuTXqeyTpXQV3v1+) zFJk*{OQz&GItFmw{}G?m^r*l*svZ3lSN=)Gd95Wy)NjKegEaqa=D7T3({D8Cmnvdl}UfulU9zQc<>?F&vSwUx-)!%U4}wWL@_$?>*RR1yxJB-_0!ar9S{PR!WBCPXdEmI=(uB56OzfHb_Owz#(fZ z$8M`qmz&d5S{6FQ0|F*(9Gpx!8&dXh^p^$QBIHbdA`}B6-RzlgLo?wVjUEjlc2#46 zjD|u7#lHiY;KLG*f)B~HrNGOB{pGE{?*_`^x%Yl7)odo#He}P$KM$lyi%>aGfB6$)eZ6Vd z717h}h*m;_^gv^}!zi2NOIhrluJ4NuXOdtQ$N5@O!o_-jp`1~*E6K1Wq;XkHTV1dh zWa1=nu6x9i2$DD+%{>(G=;~vHf}G$7;CX+fIJj1Tz$nEzAod|w-?W+tbaBzX(%gQ1 z!JSiROR7HFY_gkOXCjuvS@Rp*muZV$xONrr1$5}5jsjbun&wt~m{nTa2y$1;Bmnc$ zfdsyN_)FpG)22;5uBL7W(z~AO+Ws?XNZy);t$?0-LsFXK(rAF@%6lpzh*}U6Tnz~@ zW4NMOr@KlPaN}f7U`B+|f}_DR0nM}r7PL~3EEZ=vJf6>}-m~|cm|Fbwv|4{FMy(CI zoftgz1z1!4mX9#kEthZM0&ecR?yM)%sYEb&Yr_IQ>L4A$J&eQA8hu)!Tb)V%*-_Dr zV!!jjJ&dt707ksg7N3RSk{yGWku7ert4Q$eBgckU>v1-)y5%SKj8#g%S5xF*yyT0>lIcz!j$G|v7IZOV zm_h%D{k|nxcC1}G3vvQuvMBfv%3!*JY;$ZoEcr0}bQ?h_S|b9UI#QR(F7 zm-8jiIW{S+SP`(?8<6*==!+?0GB(c8IvA#Hl))O|uc`G@xr;O7K*xig|NpDc^T=%3sEkD ztY)UAI|XQDFwwARfUgpN{A=9O3|?fcViMen;>_GkNKqzQV7%TdaZUKT3;Q@uPEo>c z(_ern=lUhvM~*!&H@?iDp;8#f+1Z|I;cUP>g8_Pn^N7EG>l;3`z4sDHCfv^!j`DG{ zE#6K6npj&sOV6%LSaG=c4TZl37W4R6GHTtNWmLdH!r>;w7h)Lj-wh?PG}|<5uAc(> zwdl<~WTqIM4;8QT9*_0T?cS|)R{CgV_q*Mj*J+N+T-cmG%ZdV4J5)!n8Q>*?_a_Sa z?OnG!R<(F^5MZI`7!3U};dDPyzD>c&@6LE+Mq#zvE0uy8(9|*d+C@h~NWCteY*@0x z5F&tv9LVdYV%W1=0hzi*J_26g6?+=1X0-4N1Q$gp`9b*@wN?p@A>T8FAO%9h3(w1> zii|__=&R@@#379L7{*SyUEwZxZPOQX^b_8%9!@DhaT%#-+CfX-b$3gD_Jz_09yLLq zp8rZl1iw!7lDN10m(~f+{$4RaLP?9nS4ReXE@9~X3PPy;(u7`tRSnwo)(paxLgcA{ zxCmqD<^Bz!$gXH&jr|9FDXN;hK5VAp^d3-;jz$mupN@}{g|nF*0y`Oi%(-C$Kn(rgR%Ar@ zUzrV;%*ss)gn;@3s=0{7T%MHs1$WWy|Naz&R|O8!Gv)Fjq(70HgNWdkV$BH|jZGFq z{*yidK9Ua8L^YVPtfPXtJ=HeKvTK_Zzb5U=e>Kd1I3X4Mf~J$KMSnqnNrgxT~g%bkt$tOr&%tzE6x zvNSFFml)$TD0A#3nTmq#Vns5+io2%V5;3(jR6gUSTpcO|CQeYdp0+rF7vfX!dY>a_ zOn<@wD>4F!L*&9;NEihxt0Y9Jv~CJG1-41_`KDUuB^dA%^DW1V&okC(HDFl(;ojHFToP+`GX=4$pdtwW-V65bL_fr+Q8I=`un4Z57YJZ`DMZ<_? zMp9Ylaf%}*^%A+10k~Z(g!xLKPgetT#%@fVgNqiPhu zp~la{K#bL4f0ggPv0A=~HJ;diwXeeoJKhYM9vgK7E%4RU0yWx|qhkj9N|TkGc)!3y z%Z29tzYUr^z=!`okOH`=rR2QMi`Mo2FUSavJ$@a(k!hyxfO_d<))+wrr=jqzRfS12 zDa#A^H%?N%37J+_jgsz(DwD=~%a`MxDyjxu>e`A^xMvDaklqX=_btUs)?SH8Z)0kT zm40mZ_cI7%AE})XWs9PZ%XFcyUDCRt$9m*`^&HbQk@A~+>=AH0FF%FCfPr&*mQVP} zFso=nCHiY3TC<<|>H`|P-X>`Q&gv#Bz`2fY?K8WcAP>iJwl7mXO2nc?%8d^w@^0RZ z+UOxE(1xhb|BkhS1L}{%Npm@eaA1i$0n6HZJLA8vB#HNIZHw+b@g~p)a%tuiZR}K> z`ZbM>QDKYkc>@Qi$)P?|bb=b(gwVjr=*LB42ESNHGTKfDIbrEAesjD9N;{9 zT(U8k50cNTUrJoW(F&Q>;xNdSb~q}i1MgLi*so15YyxuG5&QxeI0CzoJt{0;L6$aj_!KNwqok6<7@@n*AVb^b$ z5Wfm5ms@^2ut%c}8qPo|aA zk`rHA6+1bwcT*y5hHpi6tUIl0c6+U_Tq9xWkS@ov2vS(b$>?$1>DGo`J@7^~1O7#DUx8QXa=uH44TDvse{?i&-KlVbk5$ z-OG^~N0Z-UPCV-$!y{T*N4_uEUew+8f=JW@w%WzN2#tFAD?2>Z6Hb{M@oQiWV!<0g zOzc~nHI|xbn%lzO0iMK{)r@B#YWuyqt(2f{=co^xgWdzLsXy$dP0`)c{C=qm96&H-Hz?Hsc_|6NDF1R3Fc|=|%>hLX|44r}+_-hBWbT?9ZdYxceJ7 zr-?6bCqZO9Sv$Ch#&UpUt&TWPni7V~vE{QDY7A7d*bsmO$+AZlrS7`0?uxo>5EhSlWxuSlW-#Jg)YdBmU zWH{T#8%u`FPWOTKW%Kv-cKa2#xSE814Q;ihs zHxOTdf>bhIw(c+9jtWJ2q9NdRQ@j%8NY6TPV(ES_DHkww`tD^|*%euz6$U|5C8ZiC zmoCFvO7^n!Q_NL)cnnO4*ZF*iohk>`@O7;I*0CcmHdPInBBJxCVG$<=J>KNwq%z4T z#I%NWb5EaM|Ck?Nl1Hr6L$&7mIRCrhbh9vBv#(u0Wp>?_uAjYWczLpbR7s|VG6hR4Ba)Zh7s6crxL_qcOtJ`#VQsy^+hUUvA?J(S8o zhS0;f06Kr*_H2GXe|e31H5RwgyhC_PsMi{PN;KCXmq~kG6ysN@1KNaM3$y;=6?DCr z?Qq>|(~jbrhA{n;Ptwe^yaD&KZ6B#tM=8++CPbSVjDL4yO-TM(uW2mh7y}U;A+)sS zrtIU8L5eFu3%|5W%J-CE)KYwUGj2MyY1qQ*6Dn}vso`cgh37PcYA}z+_TaKvE?HsO zG!(NHzRr)IPgeQu=QSL!BEQ8O2ODe-vl!kO%(u%bFI}$g4dX+y1;CNM z3I7MWx}x{*F^}gr#Rw78_JcqXf@C96QtIzw6BRvC9xw3^Jn;`)KoB4ezW1ZbRJwQy zbKpzE;oVr81uHJOP?Y{3`!K~~OnwnX1|n1NtT+9~ZE0M3*t6hlgwoC4m7p$P8U1~| zCnlBR7(3tYO zOPu>}c+Eu^N@~ceq4(~B*3YK3rXNpQtY|WP=FUMN$8h`2`c0R{B*l#K&^=aOJn6nO z8V2|-%X{r`T|N3Wyry}(cr^=0i>enMXzRd>x+dHh8}ikrv&!e+vVAtUQUA=b#>uEQ%Fc=Hs zH*sj*Nm^q2Fft|OgYZrJ95F7RpAm7F!m8aPAUglqH0W)lp-1$bbN-+v``@+gRrgtQ z0zdQR+NS5Y}HmcDHjHD15^41Z`vnS{zOUBmVH1B#6D>7xY2-5 zo8$qW8bw7E&G)dh;C>f)tJ5yTV7#n3>sj;NpEb-QPA?K>b!Cxlsub%rrz1AD67}Ba zrWkaY=AGl{OPE7y8h`Y2@F!m|$@~*)Z;$gD1FN}=^E^Fg@5~`8pkV}HEO|!vVZD6O zem4&14MamNNk-Nf&A^tlfaWdBgZ1SUIZJ66#1ESDpoCiZ$WsSWQU2zW%C%PNI>Cyx zbg_&;pLH(qtu*vaSOk!v#N}lp_^YEP+t?r{uFNQM>IzNL8^9^nr~kyx9!MY6&cL3c zEgb5}!3Hw~43Ua#Rn)7Ntf^01Ynl3_LkBXY`>)^nsLyVL&^nzd-a+*jSQ>bk_U$ zdI<;a438$TpUqx~f3M{Ssr<3vu~DOYBU1%BA~y(7cKo?6qsK^$;h4?h^ahEsTAGe+ zTedg_Kv2Kn?3Df;As}hJ4q-sjqJcQMP=O1WsCss8;tiI02|*7frQByjPmdj+*~F<~ za!6&pbL$vAjla#F9<0Qudr1VX9FrG$e+6ul8h!rYW{)dVD`X* zwR}zQ=nr9KvVH-*sHv^Q3w$DLlIAO}=VI*4lJ4gm)vS`b z-(*`|95ZdddAjW_;~*~k2-s@4?eZ@VWS}Q~7*rX)*?u}bd3~bUnAX*sA?WMe6W8KH zT8mQ-AzKZ@tZ0xX!{wK?R8qvP8xkd~-#)HC)7lR6#e2n@AKpMcZxfo0UPWZMSET~Q zq5u={h&q&_PT$#~npuRR;KwUtFht+=?F8otaRIFBR>abxbg+&*#S34=DRQMuj715o^8_{l3PI=G(6ZfO_IQp<-ARtL*SWDojAW*FyWVEa85VsNYOMTHe`K;&8tlCe&deQRVAW z@7f~d;ofa$haiDLSgvK)yPU7)-#V&3J-i)4TVPquJO4vtozthbmEzA>V$GSw?9!D4 zd`{gzZ2T3(>)7@H7!*u>*{j+KXr@q0YedrGp+_0^pM_MCbg|g2BA`&X8Xz0b+ZP=< zL!guMJ+p&}Tmr_|wDzEgDw?|uyw82MLNy9Cx$`F%e47iRw*M_UXorjvVEZw~V##j- zwS+tQ1CgAuRLVWzfjmVleXdBy*?w6l0GwA_X9m(1$r^(25dmYMJj}|`n2t@QB-3^f zUNR2^mQ^PZNgw?QANES41nemxS6H(irMfKcy3p{u^ZWT_?CI-zZ2&gG{V55X&D=X@R;kMho|vb)Z+fZ0lIKif4Q@&JI#a-?3(( zsT<-0lA3QiTwkoT>L8H2R`2^)rCEb3mqY$8ftYo&)fdjBHc*r2%p9x66h}*{ z-kwo~Fw??6SxmZ*btBagIL}YSX_8Aoh8Cl*J*bZp+`inOu4D*%2Fca~HR8B`Ds?W6 zm*-rulsZCb!SIa!b(Pf{$lyRE{>i1-U8J^Uk7iDJqD`42iy_XRNM{;k;wM^S80|kFbj8cd6MGUv&G@AdBWSV`|^u2b}(t#fofXdGA#CB zibR!u=a`U61F!1O%WBb6jA+s)#JQHAO7fH}EfgC7@P8g*yVU;Q$&c>ecbZSwTeh$g)e2-@8Sk_0AHh`^mSm#Nn$sUPNL$eMkCcjLLRO?3)*%T@fBKx$;*a0^L!HU>u8 zYVSn~4dg{1twWIh-&%cC0m=-8hG_rWwz$OXuCn!6;fp9x9*yp@s9$D^@QY`Q7f$I< zv^noW+04Hs(cWN{SMG{mox0To@viE|hM~-G-o%BtQz(G$Dtqh7Q?Q?7hJ&R3@7r2U zC*!Zof__THicyRF-RGG=@PUMHiWo^QrslkA;YBb=0zMDgan$(oxP+#{xlw$!4o_wO0wi16O_O#)SaqbFnujKHihr9BZ1xQVaaLQvhT2kqA_N-Z9mLpxfFVjRm zA}R&7fyCjdSZb(!I6jmJD9Hs}Q2n7L>7zBNc3b|=fO=P?{9hs@$sJax^Ww1RGRkRF zSXmOKn*2zLYY^BO7``DALN_5h`Cuw75N6z~M?mgFB>zS!e_3|E@byF*yqfFnuuukQe|ig)oKw?MscqUH+c9D7lZUtUQuK5`xSxQ}TRE`y4#Q%$g2(qF!3|FY-*cMAQ#9&HG= zQVX^cc(MmHfP;&TJH5IOoaBElTW0#ekD*lg*x9+bd3gbBeA1HK03Kd|l(Zx-FON7E zfJ=&tn@dudOz{7=#1Mg1(bCD!-$}1I}oQT@}t%i?h`C11~fdUnrT&5z`?Y zd<8<^lrW}OMf$p-{kyp8Oy^=SZ{7cOE4KonHypgt)C zTZnJJwY;(K0`aY%o)_7AhshwME(RHBY&XoC9f9bA&e8{^*l*bip}otZXo>VuLue2| z=z{6g=h!+g?m5~OlmC~i9TjzlTrhY9ki&MHtsn_87LzFQn3yT4R6vs$zm^XPlFsht z=Ro-=!FSLdmaUJbcp9UPB7}&)pdM zA;?XVuK==on)k8NN+pLI;(s3er&>G&-#j*x4eI|YLnoMO{oYzb3BG9d^xra0t30WH zFK&3IAk`Fp#!JkVe*IG(`iJ str: -class msk_top_regs_frame_sync_status_frame_buffer_overflow_cls(FieldAsyncReadWrite): +class msk_top_regs_frame_sync_status_frame_buffer_overflow_cls(FieldAsyncReadOnly): """ Class to represent a register field in the register model @@ -195,7 +195,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_frame_sync_status_frame_sync_locked_cls(FieldAsyncReadWrite): +class msk_top_regs_frame_sync_status_frame_sync_locked_cls(FieldAsyncReadOnly): """ Class to represent a register field in the register model @@ -648,7 +648,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls(FieldAsyncReadWrite): +class msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1101989e_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -721,7 +721,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls = msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls( + self.__data:msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1101989e_cls = msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1101989e_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -752,7 +752,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls: + def data(self) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1101989e_cls: """ Property to access data field of the register @@ -792,7 +792,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x10447444_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_status_reg_data_desc_a6882ec4_0x0x1101989e_cls: return super().get_child_by_system_rdl_name(name) @@ -1162,7 +1162,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls(FieldAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_alpha_0x0x110198d4_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -1200,7 +1200,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls(RegAsyncReadWrite): +class msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls(RegAsyncReadWrite): """ Class to represent a register in the register model @@ -1237,7 +1237,7 @@ def __init__(self, # build the field attributes - self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls( + self.__alpha:msk_top_regs_lowpass_ema_alpha_alpha_0x0x110198d4_cls = msk_top_regs_lowpass_ema_alpha_alpha_0x0x110198d4_cls( parent_register=self, size_props=FieldSizeProps( width=18, @@ -1268,7 +1268,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls: + def alpha(self) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x110198d4_cls: """ Property to access alpha field of the register @@ -1307,7 +1307,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x1042fd22_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_lowpass_ema_alpha_alpha_0x0x110198d4_cls: return super().get_child_by_system_rdl_name(name) @@ -3278,7 +3278,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls(FieldAsyncReadWrite): +class msk_top_regs_stat_32_lpf_acc_data_0x0x10797426_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -3356,7 +3356,7 @@ def __init__(self, # build the field attributes - self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls( + self.__data:msk_top_regs_stat_32_lpf_acc_data_0x0x10797426_cls = msk_top_regs_stat_32_lpf_acc_data_0x0x10797426_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -3387,7 +3387,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls: + def data(self) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10797426_cls: """ Property to access data field of the register @@ -3429,7 +3429,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10427b77_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_stat_32_lpf_acc_data_0x0x10797426_cls: return super().get_child_by_system_rdl_name(name) @@ -5050,7 +5050,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_data_width_data_width_0x0x10443038_cls(FieldAsyncReadWrite): +class msk_top_regs_data_width_data_width_0x0x1079ec62_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -5126,7 +5126,7 @@ def __init__(self, # build the field attributes - self.__data_width:msk_top_regs_data_width_data_width_0x0x10443038_cls = msk_top_regs_data_width_data_width_0x0x10443038_cls( + self.__data_width:msk_top_regs_data_width_data_width_0x0x1079ec62_cls = msk_top_regs_data_width_data_width_0x0x1079ec62_cls( parent_register=self, size_props=FieldSizeProps( width=8, @@ -5157,7 +5157,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def data_width(self) -> msk_top_regs_data_width_data_width_0x0x10443038_cls: + def data_width(self) -> msk_top_regs_data_width_data_width_0x0x1079ec62_cls: """ Property to access data_width field of the register @@ -5196,7 +5196,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x10443038_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_data_width_data_width_0x0x1079ec62_cls: return super().get_child_by_system_rdl_name(name) @@ -6046,7 +6046,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1079c844_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6123,7 +6123,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls = msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1079c844_cls = msk_top_regs_config_nco_fw_config_data_0x0x1079c844_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6154,7 +6154,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1079c844_cls: """ Property to access config_data field of the register @@ -6195,7 +6195,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1044472f_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1079c844_cls: return super().get_child_by_system_rdl_name(name) @@ -6219,7 +6219,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1079621e_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6296,7 +6296,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1079621e_cls = msk_top_regs_config_nco_fw_config_data_0x0x1079621e_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6327,7 +6327,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1079621e_cls: """ Property to access config_data field of the register @@ -6368,7 +6368,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a0c_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1079621e_cls: return super().get_child_by_system_rdl_name(name) @@ -6392,7 +6392,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x1079636b_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6469,7 +6469,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x1079636b_cls = msk_top_regs_config_nco_fw_config_data_0x0x1079636b_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6500,7 +6500,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x1079636b_cls: """ Property to access config_data field of the register @@ -6541,7 +6541,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a24_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x1079636b_cls: return super().get_child_by_system_rdl_name(name) @@ -6565,7 +6565,7 @@ def rdl_desc(self) -> str: -class msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls(FieldAsyncReadWrite): +class msk_top_regs_config_nco_fw_config_data_0x0x11011ef6_cls(FieldAsyncReadWrite): """ Class to represent a register field in the register model @@ -6642,7 +6642,7 @@ def __init__(self, # build the field attributes - self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls = msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls( + self.__config_data:msk_top_regs_config_nco_fw_config_data_0x0x11011ef6_cls = msk_top_regs_config_nco_fw_config_data_0x0x11011ef6_cls( parent_register=self, size_props=FieldSizeProps( width=32, @@ -6673,7 +6673,7 @@ def fields(self) -> Iterator[Union[FieldAsyncReadOnly, FieldAsyncWriteOnly,Field # build the properties for the fields @property - def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls: + def config_data(self) -> msk_top_regs_config_nco_fw_config_data_0x0x11011ef6_cls: """ Property to access config_data field of the register @@ -6714,7 +6714,7 @@ def systemrdl_python_child_name_map(self) -> dict[str, str]: - def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x10445a66_cls: + def get_child_by_system_rdl_name(self, name: Any) -> msk_top_regs_config_nco_fw_config_data_0x0x11011ef6_cls: return super().get_child_by_system_rdl_name(name) @@ -8950,7 +8950,7 @@ def __init__(self, *, inst_name='Tx_Sync_Cnt', parent=self) - self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls = msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls( + self.__lowpass_ema_alpha1:msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls = msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls( address=self.address+132, accesswidth=32, width=32, @@ -9658,7 +9658,7 @@ def Tx_Sync_Cnt(self) -> msk_top_regs_tx_sync_cnt_cls: return self.__Tx_Sync_Cnt @property - def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls: + def lowpass_ema_alpha1(self) -> msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls: """ Property to access lowpass_ema_alpha1 @@ -9928,7 +9928,7 @@ def get_child_by_system_rdl_name(self, name: Literal["Tx_Sync_Cnt"]) -> msk_top_ @overload - def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls: ... + def get_child_by_system_rdl_name(self, name: Literal["lowpass_ema_alpha1"]) -> msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls: ... @overload @@ -9952,7 +9952,7 @@ def get_child_by_system_rdl_name(self, name: Literal["rx_frame_sync_status"]) -> @overload - def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_status_reg_data_f53978c8_name_d8ad3b25_cls, msk_top_regs_status_reg_data_05243a4e_name_2c154788_cls, msk_top_regs_status_reg_data_10a2e5b5_name_3b640507_cls, msk_top_regs_status_reg_data_642692cf_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1042fd73_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_cls, msk_top_regs_frame_sync_status_cls, ]: ... + def get_child_by_system_rdl_name(self, name: str) -> Union[msk_top_regs_msk_hash_lo_cls, msk_top_regs_msk_hash_hi_cls, msk_top_regs_msk_init_cls, msk_top_regs_msk_ctrl_cls, msk_top_regs_msk_stat_0_cls, msk_top_regs_msk_stat_1_cls, msk_top_regs_msk_stat_2_cls, msk_top_regs_config_nco_fw_desc_c4924cc6_name_0c494469_cls, msk_top_regs_config_nco_fw_desc_94d7aaf5_name_84dd0c1c_cls, msk_top_regs_config_nco_fw_desc_42134a4f_name_d97dbd51_cls, msk_top_regs_config_nco_fw_desc_16fb48c8_name_8d01a20d_cls, msk_top_regs_config_nco_fw_desc_43c0828f_name_bdc60ecf_cls, msk_top_regs_lpf_config_0_cls, msk_top_regs_lpf_config_1_cls, msk_top_regs_data_width_desc_58c848dd_name_2fbd8eba_cls, msk_top_regs_data_width_desc_6097df38_name_4609588b_cls, msk_top_regs_prbs_ctrl_cls, msk_top_regs_config_prbs_seed_cls, msk_top_regs_config_prbs_poly_cls, msk_top_regs_config_prbs_errmask_cls, msk_top_regs_stat_32_bits_cls, msk_top_regs_stat_32_errs_cls, msk_top_regs_stat_32_lpf_acc_desc_8cebc7dc_name_f20c6670_cls, msk_top_regs_stat_32_lpf_acc_desc_dea6bd99_name_758fd0ce_cls, msk_top_regs_msk_stat_3_cls, msk_top_regs_rx_sample_discard_cls, msk_top_regs_lpf_config_2_cls, msk_top_regs_status_reg_data_f53978c8_name_d8ad3b25_cls, msk_top_regs_status_reg_data_05243a4e_name_2c154788_cls, msk_top_regs_status_reg_data_10a2e5b5_name_3b640507_cls, msk_top_regs_status_reg_data_642692cf_name_3de9a0d3_cls, msk_top_regs_tx_sync_ctrl_cls, msk_top_regs_tx_sync_cnt_cls, msk_top_regs_lowpass_ema_alpha_0x0x1101991f_cls, msk_top_regs_lowpass_ema_alpha_cls, msk_top_regs_rx_power_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_aa4ec676_name_aa4ec676_cls, msk_top_regs_status_reg_data_8a67e1fe_desc_8a90eed1_name_8a90eed1_cls, msk_top_regs_frame_sync_status_cls, ]: ... def get_child_by_system_rdl_name(self, name: Any) -> Any: return super().get_child_by_system_rdl_name(name) diff --git a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py index 414ee3a..f3025d6 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_msk_top_regs.py @@ -11691,42 +11691,6 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() - # check the write - - if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): - raise TypeError('Test can not proceed as the fut is not a writable async field') - - - random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) - random_field_value = random.randrange(0, 0x1 + 1) - for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: - for field_value in [0, 0x1, random_field_value]: - read_callback_mock.reset_mock() - write_callback_mock.reset_mock() - read_callback_mock.return_value = reg_base_value - - await self.dut.rx_frame_sync_status.frame_sync_locked.write(field_value) # type: ignore[union-attr] - - - read_callback_mock.assert_called_once_with( - addr=152, - width=32, - accesswidth=fut.parent_register.accesswidth) - - write_callback_mock.assert_called_once_with( - addr=152, - width=32, - accesswidth=self.dut.rx_frame_sync_status.frame_sync_locked.parent_register.accesswidth, # type: ignore[union-attr] - data=(reg_base_value & 0xFFFFFFFE) | \ - (0x1 & (field_value << 0))) - - - # check invalid write values bounce - with self.assertRaises(ValueError): - await fut.write(0x1 + 1) - - with self.assertRaises(ValueError): - await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.rx_frame_sync_status.frame_buffer_overflow @@ -11775,42 +11739,6 @@ async def test_int_field_read_and_write(self) -> None: # at the end of the read tests the write should not have been called read_callback_mock.reset_mock() write_callback_mock.assert_not_called() - # check the write - - if not isinstance(fut, (FieldAsyncWriteOnly, FieldAsyncReadWrite)): - raise TypeError('Test can not proceed as the fut is not a writable async field') - - - random_reg_value = random.randrange(0, 0xFFFFFFFF + 1) - random_field_value = random.randrange(0, 0x1 + 1) - for reg_base_value in [0, 0xFFFFFFFF, random_reg_value]: - for field_value in [0, 0x1, random_field_value]: - read_callback_mock.reset_mock() - write_callback_mock.reset_mock() - read_callback_mock.return_value = reg_base_value - - await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(field_value) # type: ignore[union-attr] - - - read_callback_mock.assert_called_once_with( - addr=152, - width=32, - accesswidth=fut.parent_register.accesswidth) - - write_callback_mock.assert_called_once_with( - addr=152, - width=32, - accesswidth=self.dut.rx_frame_sync_status.frame_buffer_overflow.parent_register.accesswidth, # type: ignore[union-attr] - data=(reg_base_value & 0xFFFFFFFD) | \ - (0x2 & (field_value << 1))) - - - # check invalid write values bounce - with self.assertRaises(ValueError): - await fut.write(0x1 + 1) - - with self.assertRaises(ValueError): - await fut.write(-1) # test access operations (read and/or write) to field: # msk_top_regs.rx_frame_sync_status.frames_received @@ -15513,9 +15441,7 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ ]) with self.subTest(msg='register: msk_top_regs.rx_frame_sync_status'): await write_field_combinations(reg=self.dut.rx_frame_sync_status, - writable_fields = [ 'frame_sync_locked', - 'frame_buffer_overflow', - 'frames_received', + writable_fields = [ 'frames_received', 'frame_sync_errors' ]) @@ -15834,9 +15760,7 @@ async def write_field_combinations(reg: RegAsyncReadWrite, writable_fields:list[ # test read_fields to register: # msk_top_regs.rx_frame_sync_status await write_field_combinations(reg=self.dut.rx_frame_sync_status, - writable_fields = [ 'frame_sync_locked', - 'frame_buffer_overflow', - 'frames_received', + writable_fields = [ 'frames_received', 'frame_sync_errors' ]) @@ -18402,9 +18326,9 @@ def test_traversal_iterators(self) -> None: fields.append(field) self.assertCountEqual(expected_fields, fields) - expected_writable_fields = [self.dut.rx_frame_sync_status.frame_sync_locked, # type: ignore[union-attr,list-item] + expected_writable_fields = [ - self.dut.rx_frame_sync_status.frame_buffer_overflow, # type: ignore[union-attr,list-item] + self.dut.rx_frame_sync_status.frames_received, # type: ignore[union-attr,list-item] diff --git a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py index c0ee28a..3cf4d4b 100644 --- a/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py +++ b/rdl/outputs/python/msk_top_regs/tests/test_sim_msk_top_regs.py @@ -8531,53 +8531,6 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() - # register write checks - # update the register value via the backdoor in the simulator, then perform a field - # write and make sure it is updated - inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) - sim_register.value = inital_reg_random_value - - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) - - register_write_callback.assert_not_called() - register_read_callback.assert_not_called() - field_write_callback.assert_not_called() - field_read_callback.assert_not_called() - reg_random_value = sim_register.value - # hook up the call backs - sim_register.read_callback = None - sim_register.write_callback = register_write_callback - sim_field.read_callback = None - sim_field.write_callback = field_write_callback - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) - register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) - field_write_callback.assert_called_once_with(value=random_field_value) - - register_read_callback.assert_not_called() - field_read_callback.assert_not_called() - reg_random_value = sim_register.value - # revert the callbacks and check again - register_write_callback.reset_mock() - register_read_callback.reset_mock() - field_write_callback.reset_mock() - field_read_callback.reset_mock() - sim_register.write_callback = None - sim_field.write_callback = None - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_sync_locked.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFE) | (0x1 & (random_field_value << 0))) - - register_write_callback.assert_not_called() - register_read_callback.assert_not_called() - field_write_callback.assert_not_called() - field_read_callback.assert_not_called() # test access operations (read and/or write) to register: @@ -8650,53 +8603,6 @@ async def test_field_read_and_write(self) -> None: field_read_callback.assert_not_called() - # register write checks - # update the register value via the backdoor in the simulator, then perform a field - # write and make sure it is updated - inital_reg_random_value = random.randrange(0, 0xFFFFFFFF+1) - sim_register.value = inital_reg_random_value - - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) - - register_write_callback.assert_not_called() - register_read_callback.assert_not_called() - field_write_callback.assert_not_called() - field_read_callback.assert_not_called() - reg_random_value = sim_register.value - # hook up the call backs - sim_register.read_callback = None - sim_register.write_callback = register_write_callback - sim_field.read_callback = None - sim_field.write_callback = field_write_callback - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) - register_write_callback.assert_called_once_with(value=(reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) - field_write_callback.assert_called_once_with(value=random_field_value) - - register_read_callback.assert_not_called() - field_read_callback.assert_not_called() - reg_random_value = sim_register.value - # revert the callbacks and check again - register_write_callback.reset_mock() - register_read_callback.reset_mock() - field_write_callback.reset_mock() - field_read_callback.reset_mock() - sim_register.write_callback = None - sim_field.write_callback = None - random_field_value = random.randrange(0, 0x1+1) - - await self.dut.rx_frame_sync_status.frame_buffer_overflow.write(random_field_value) # type: ignore[arg-type] - self.assertEqual(sim_register.value, (inital_reg_random_value & 0xFFFFFFFD) | (0x2 & (random_field_value << 1))) - - register_write_callback.assert_not_called() - register_read_callback.assert_not_called() - field_write_callback.assert_not_called() - field_read_callback.assert_not_called() # test access operations (read and/or write) to register: diff --git a/rdl/outputs/rtl/msk_top_regs.vhd b/rdl/outputs/rtl/msk_top_regs.vhd index 4bda2d8..952a997 100644 --- a/rdl/outputs/rtl/msk_top_regs.vhd +++ b/rdl/outputs/rtl/msk_top_regs.vhd @@ -549,11 +549,6 @@ architecture rtl of msk_top_regs is data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_combo_t\; end record; - type \msk_top_regs.rx_frame_sync_status.frame_sync_locked_combo_t\ is record - next_q : std_logic; - load_next : std_logic; - end record; - type \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_combo_t\ is record next_q : std_logic; load_next : std_logic; @@ -570,7 +565,6 @@ architecture rtl of msk_top_regs is end record; type \msk_top_regs.rx_frame_sync_status_combo_t\ is record - frame_sync_locked : \msk_top_regs.rx_frame_sync_status.frame_sync_locked_combo_t\; frame_buffer_overflow : \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_combo_t\; frames_received : \msk_top_regs.rx_frame_sync_status.frames_received_combo_t\; frame_sync_errors : \msk_top_regs.rx_frame_sync_status.frame_sync_errors_combo_t\; @@ -987,10 +981,6 @@ architecture rtl of msk_top_regs is data : \msk_top_regs.rx_async_fifo_rd_wr_ptr.data_storage_t\; end record; - type \msk_top_regs.rx_frame_sync_status.frame_sync_locked_storage_t\ is record - value : std_logic; - end record; - type \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_storage_t\ is record value : std_logic; end record; @@ -1004,7 +994,6 @@ architecture rtl of msk_top_regs is end record; type \msk_top_regs.rx_frame_sync_status_storage_t\ is record - frame_sync_locked : \msk_top_regs.rx_frame_sync_status.frame_sync_locked_storage_t\; frame_buffer_overflow : \msk_top_regs.rx_frame_sync_status.frame_buffer_overflow_storage_t\; frames_received : \msk_top_regs.rx_frame_sync_status.frames_received_storage_t\; frame_sync_errors : \msk_top_regs.rx_frame_sync_status.frame_sync_errors_storage_t\; @@ -2914,37 +2903,6 @@ begin end process; hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod <= decoded_reg_strb.rx_async_fifo_rd_wr_ptr and decoded_req_is_wr and or_reduce(decoded_wr_biten(31 downto 0)); - -- Field: msk_top_regs.rx_frame_sync_status.frame_sync_locked - process(all) - variable next_c: std_logic; - variable load_next_c: std_logic; - begin - next_c := field_storage.rx_frame_sync_status.frame_sync_locked.value; - load_next_c := '0'; - if decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write - next_c := (field_storage.rx_frame_sync_status.frame_sync_locked.value and not decoded_wr_biten(0)) or (decoded_wr_data(0) and decoded_wr_biten(0)); - load_next_c := '1'; - else -- HW Write - next_c := hwif_in.rx_frame_sync_status.frame_sync_locked.next_q; - load_next_c := '1'; - end if; - field_combo.rx_frame_sync_status.frame_sync_locked.next_q <= next_c; - field_combo.rx_frame_sync_status.frame_sync_locked.load_next <= load_next_c; - end process; - process(clk) begin - if false then -- async reset - field_storage.rx_frame_sync_status.frame_sync_locked.value <= '0'; - elsif rising_edge(clk) then - if rst then -- sync reset - field_storage.rx_frame_sync_status.frame_sync_locked.value <= '0'; - else - if field_combo.rx_frame_sync_status.frame_sync_locked.load_next then - field_storage.rx_frame_sync_status.frame_sync_locked.value <= field_combo.rx_frame_sync_status.frame_sync_locked.next_q; - end if; - end if; - end if; - end process; - -- Field: msk_top_regs.rx_frame_sync_status.frame_buffer_overflow process(all) variable next_c: std_logic; @@ -2955,9 +2913,6 @@ begin if decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr then -- SW clear on read next_c := '0'; load_next_c := '1'; - elsif decoded_reg_strb.rx_frame_sync_status and decoded_req_is_wr then -- SW write - next_c := (field_storage.rx_frame_sync_status.frame_buffer_overflow.value and not decoded_wr_biten(1)) or (decoded_wr_data(1) and decoded_wr_biten(1)); - load_next_c := '1'; elsif hwif_in.rx_frame_sync_status.frame_buffer_overflow.we then -- HW Write - we next_c := hwif_in.rx_frame_sync_status.frame_buffer_overflow.next_q; load_next_c := '1'; @@ -3123,7 +3078,7 @@ begin readback_array(35)(31 downto 23) <= (others => '0'); readback_array(36)(31 downto 0) <= field_storage.tx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.tx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); readback_array(37)(31 downto 0) <= field_storage.rx_async_fifo_rd_wr_ptr.data.value when (decoded_reg_strb.rx_async_fifo_rd_wr_ptr and not decoded_req_is_wr) else (others => '0'); - readback_array(38)(0 downto 0) <= to_std_logic_vector(field_storage.rx_frame_sync_status.frame_sync_locked.value) when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); + readback_array(38)(0 downto 0) <= to_std_logic_vector(hwif_in.rx_frame_sync_status.frame_sync_locked.next_q) when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); readback_array(38)(1 downto 1) <= to_std_logic_vector(field_storage.rx_frame_sync_status.frame_buffer_overflow.value) when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); readback_array(38)(25 downto 2) <= field_storage.rx_frame_sync_status.frames_received.value when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); readback_array(38)(31 downto 26) <= field_storage.rx_frame_sync_status.frame_sync_errors.value when (decoded_reg_strb.rx_frame_sync_status and not decoded_req_is_wr) else (others => '0'); From 6174fd30cc7fda73d1206414f5cdbe1c06a14a69 Mon Sep 17 00:00:00 2001 From: Matthew Wishek Date: Fri, 14 Nov 2025 14:05:07 -0700 Subject: [PATCH 35/60] rdl: update frame sync status register descriptions. --- rdl/src/msk_top_regs.rdl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rdl/src/msk_top_regs.rdl b/rdl/src/msk_top_regs.rdl index b1ec87d..4ca52f3 100644 --- a/rdl/src/msk_top_regs.rdl +++ b/rdl/src/msk_top_regs.rdl @@ -576,7 +576,7 @@ addrmap msk_top_regs { } frame_buffer_overflow = 0; field { name = "Frames Received"; - desc = "Count of frames received since last read. Value is 0x00_0000 to 0xFF_FFFF"; + desc = "Count of frames received. Value is 0x00_0000 to 0xFF_FFFF. Counter rolls over when max count is reached."; fieldwidth = 24; sw = rw; hw = w; @@ -585,7 +585,7 @@ addrmap msk_top_regs { } frames_received = 0; field { name = "Frames Sync Errors"; - desc = "Count of frame sync errors since last read. Value is 0 to 63. This field will saturate at 63 if more than 63 occur."; + desc = "Count of frame sync errors. Value is 0 to 63. Counter rolls over when max count is reached."; fieldwidth = 6; sw = rw; hw = w; From 628ca20c35ba02dd359bb071b62055e3397dc50b Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Fri, 14 Nov 2025 18:00:14 -0800 Subject: [PATCH 36/60] Improved reset of FIFO read and write pointers. Works in sim and hardware. --- src/msk_top.vhd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 47506cd..ac0e43c 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -328,7 +328,7 @@ BEGIN ) PORT MAP ( wr_aclk => s_axis_aclk, - wr_aresetn => s_axis_aresetn, + wr_aresetn => s_axis_aresetn AND NOT txinit, -- add software control s_axis_tdata => adapter_tdata, s_axis_tvalid => adapter_tvalid, @@ -528,7 +528,7 @@ BEGIN -- Read side (AXI clock domain) rd_aclk => s_axis_aclk, -- Use system AXI clock - rd_aresetn => s_axis_aresetn, + rd_aresetn => s_axis_aresetn AND NOT rxinit, -- add software control m_axis_tdata => m_axis_tdata(7 DOWNTO 0), m_axis_tvalid => m_axis_tvalid, From 7708fd88a972cf7aaa802365c8f23491109b4591 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 17 Nov 2025 20:03:41 -0800 Subject: [PATCH 37/60] encoder and decoder tested in loopback and pass. encoder and decoder then installed in msk_top.vhd. Compiles clean. --- src/msk_top.vhd | 120 ++++++++++++- src/ov_frame_decoder.vhd | 351 +++++++++++++++++++++++++++++++++++++ src/ov_frame_encoder.vhd | 362 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 824 insertions(+), 9 deletions(-) create mode 100644 src/ov_frame_decoder.vhd create mode 100644 src/ov_frame_encoder.vhd diff --git a/src/msk_top.vhd b/src/msk_top.vhd index ac0e43c..e14168c 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -59,6 +59,20 @@ -- MODIFIED FOR MSB-FIRST: Updated sync word from 0xACFA47/0xE25F35 to 0xE25F35/0xE25F35 -- Both TX and RX now use the same sync word pattern (no bit reversal) ------------------------------------------------------------------------------------------------------ +-- PHASE 1: OV ENCODER/DECODER INTEGRATION (Issue #24) +------------------------------------------------------------------------------------------------------ +-- Integrated OV frame encoder (TX) and decoder (RX) into datapath: +-- TX: FIFO → Encoder (134→268 bytes) → Deserializer → Modulator +-- RX: Demodulator → Frame Sync → Decoder (268→134 bytes) → FIFO +-- +-- KNOWN LIMITATION: Frame size mismatch - PS currently sends/expects 268 bytes +-- - Encoder expects 134-byte input but receives 268 bytes +-- - Decoder outputs 134 bytes but PS expects 268 bytes +-- - This will be resolved in Phase 2 by updating PS frame size to 134 bytes +-- +-- Modified: TX Stage 3 (encoder insertion), TX Stage 4 (deserializer rewire) +-- RX Stage 3 (decoder insertion), RX Stage 4 (FIFO rewire) +------------------------------------------------------------------------------------------------------ LIBRARY ieee; USE ieee.std_logic_1164.ALL; @@ -168,6 +182,14 @@ ARCHITECTURE struct OF msk_top IS SIGNAL fifo_tlast : std_logic; SIGNAL frame_complete : std_logic; + + -- TX Encoder signals (OV Frame Encoder - Phase 1) + SIGNAL encoder_tdata : std_logic_vector(7 DOWNTO 0); + SIGNAL encoder_tvalid : std_logic; + SIGNAL encoder_tready : std_logic; + SIGNAL encoder_tlast : std_logic; + SIGNAL tx_frames_encoded : std_logic_vector(31 DOWNTO 0); + SIGNAL tx_encoder_active : std_logic; SIGNAL tx_async_fifo_prog_full : std_logic; SIGNAL tx_async_fifo_prog_empty : std_logic; @@ -205,6 +227,14 @@ ARCHITECTURE struct OF msk_top IS SIGNAL rx_debug_state : std_logic_vector(2 DOWNTO 0); SIGNAL rx_debug_missed_syncs : std_logic_vector(3 DOWNTO 0); SIGNAL rx_debug_consecutive_good: std_logic_vector(3 DOWNTO 0); + + -- RX Decoder signals (OV Frame Decoder - Phase 1) + SIGNAL decoder_tdata : std_logic_vector(7 DOWNTO 0); + SIGNAL decoder_tvalid : std_logic; + SIGNAL decoder_tready : std_logic; + SIGNAL decoder_tlast : std_logic; + SIGNAL rx_frames_decoded : std_logic_vector(31 DOWNTO 0); + SIGNAL rx_decoder_active : std_logic; SIGNAL rx_bit : std_logic; SIGNAL rx_bit_corr : std_logic; @@ -356,20 +386,56 @@ BEGIN fifo_rd_ptr => tx_async_fifo_rd_ptr ); - -- Stage 3: Byte-to-Bit De-serializer (MSB-FIRST VERSION) - u_deserializer : ENTITY work.byte_to_bit_deserializer + ------------------------------------------------------------------------------------------------------ + -- TX Stage 3: OV Frame Encoder (Randomize + FEC + Interleave) - PHASE 1 + ------------------------------------------------------------------------------------------------------ + -- NOTE: Phase 1 limitation - encoder expects 134-byte frames but currently receives 268 bytes + -- This will be corrected in Phase 2 when PS side is updated to send 134-byte frames + ------------------------------------------------------------------------------------------------------ + + u_ov_encoder : ENTITY work.ov_frame_encoder GENERIC MAP ( - BYTE_WIDTH => 8 + PAYLOAD_BYTES => 134, + ENCODED_BYTES => 268, + ENCODED_BITS => 2144, + BYTE_WIDTH => 8 ) PORT MAP ( clk => clk, - init => txinit, + aresetn => NOT txinit, + -- Input from FIFO s_axis_tdata => fifo_tdata, s_axis_tvalid => fifo_tvalid, s_axis_tready => fifo_tready, s_axis_tlast => fifo_tlast, + -- Output to deserializer + m_axis_tdata => encoder_tdata, + m_axis_tvalid => encoder_tvalid, + m_axis_tready => encoder_tready, + m_axis_tlast => encoder_tlast, + + -- Status + frames_encoded => tx_frames_encoded, + encoder_active => tx_encoder_active + ); + + -- Stage 4: Byte-to-Bit De-serializer (MSB-FIRST VERSION) + u_deserializer : ENTITY work.byte_to_bit_deserializer + GENERIC MAP ( + BYTE_WIDTH => 8 + ) + PORT MAP ( + clk => clk, + init => txinit, + + -- Input from encoder (was: from FIFO) + s_axis_tdata => encoder_tdata, + s_axis_tvalid => encoder_tvalid, + s_axis_tready => encoder_tready, + s_axis_tlast => encoder_tlast, + tx_data => tx_data_bit, tx_req => tx_req, @@ -508,7 +574,42 @@ BEGIN ); ------------------------------------------------------------------------------ - -- RX Stage 3: Async FIFO (Clock Domain Crossing) + -- RX Stage 3: OV Frame Decoder (Deinterleave + FEC Decode + Derandomize) - PHASE 1 + ------------------------------------------------------------------------------ + -- NOTE: Phase 1 limitation - decoder outputs 134 bytes but RX FIFO/DMA expects 268 bytes + -- This will be corrected in Phase 2 when PS side is updated to receive 134-byte frames + ------------------------------------------------------------------------------ + + u_ov_decoder : ENTITY work.ov_frame_decoder + GENERIC MAP ( + PAYLOAD_BYTES => 134, + ENCODED_BYTES => 268, + ENCODED_BITS => 2144, + BYTE_WIDTH => 8 + ) + PORT MAP ( + clk => clk, + aresetn => NOT rxinit, + + -- Input from frame sync detector + s_axis_tdata => sync_det_tdata, + s_axis_tvalid => sync_det_tvalid, + s_axis_tready => sync_det_tready, + s_axis_tlast => sync_det_tlast, + + -- Output to RX FIFO + m_axis_tdata => decoder_tdata, + m_axis_tvalid => decoder_tvalid, + m_axis_tready => decoder_tready, + m_axis_tlast => decoder_tlast, + + -- Status + frames_decoded => rx_frames_decoded, + decoder_active => rx_decoder_active + ); + + ------------------------------------------------------------------------------ + -- RX Stage 4: Async FIFO (Clock Domain Crossing) -- Reuses existing axis_async_fifo component! ------------------------------------------------------------------------------ u_rx_async_fifo : ENTITY work.axis_async_fifo @@ -521,10 +622,11 @@ BEGIN wr_aclk => clk, wr_aresetn => NOT rxinit, - s_axis_tdata => sync_det_tdata, - s_axis_tvalid => sync_det_tvalid, - s_axis_tready => sync_det_tready, - s_axis_tlast => sync_det_tlast, + -- Input from decoder (was: from frame sync detector) + s_axis_tdata => decoder_tdata, + s_axis_tvalid => decoder_tvalid, + s_axis_tready => decoder_tready, + s_axis_tlast => decoder_tlast, -- Read side (AXI clock domain) rd_aclk => s_axis_aclk, -- Use system AXI clock diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd new file mode 100644 index 0000000..6c792a2 --- /dev/null +++ b/src/ov_frame_decoder.vhd @@ -0,0 +1,351 @@ +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- _______ ________ ______ +-- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +-- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +-- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +-- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +-- /_/ +-- ________ _____ _____ _____ _____ +-- ____ _/_______ __________ /____(_)__ /_____ ____ /______ +-- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +-- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +-- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- Copyright +------------------------------------------------------------------------------------------------------ +-- +-- Copyright 2025 by Open Research Institute +-- +------------------------------------------------------------------------------------------------------ +-- License +------------------------------------------------------------------------------------------------------ +-- +-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +-- +-- You may redistribute and modify this source and make products using it under +-- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +-- +-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +-- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- Please see the CERN-OHL-W v2 for applicable conditions. +-- +------------------------------------------------------------------------------------------------------ +-- Block name and description +------------------------------------------------------------------------------------------------------ +-- +-- Opulent Voice Protocol Frame Decoder +-- +-- This module implements the RX path processing for OVP frames (reverse of encoder): +-- 1. Collects 268 bytes of encoded data from AXI-Stream input +-- 2. Deinterleaves bits (reverse 67x32 row-column interleaver) +-- 3. Applies FEC decoding (majority vote on bit pairs) +-- 4. Derandomizes (XOR with same fixed sequence) +-- 5. Outputs 134 bytes of payload via AXI-Stream +-- +-- BUGFIX (2025-11-16): Fixed first-byte-lost issue in IDLE→COLLECT transition +-- Now stores first byte immediately when transitioning states +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY ov_frame_decoder IS + GENERIC ( + PAYLOAD_BYTES : NATURAL := 134; -- Output frame size + ENCODED_BYTES : NATURAL := 268; -- Input frame size + ENCODED_BITS : NATURAL := 2144; -- Encoded bits (268 * 8) + BYTE_WIDTH : NATURAL := 8 + ); + PORT ( + clk : IN std_logic; + aresetn : IN std_logic; + + -- Input AXI-Stream (268-byte encoded frames) + s_axis_tdata : IN std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + s_axis_tvalid : IN std_logic; + s_axis_tready : OUT std_logic; + s_axis_tlast : IN std_logic; + + -- Output AXI-Stream (134-byte payload frames) + m_axis_tdata : OUT std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + m_axis_tvalid : OUT std_logic; + m_axis_tready : IN std_logic; + m_axis_tlast : OUT std_logic; + + -- Status outputs + frames_decoded : OUT std_logic_vector(31 DOWNTO 0); + decoder_active : OUT std_logic + ); +END ENTITY ov_frame_decoder; + +ARCHITECTURE rtl OF ov_frame_decoder IS + + -- State machine + TYPE state_t IS (IDLE, COLLECT, DEINTERLEAVE, FEC_DECODE, DERANDOMIZE, OUTPUT); + SIGNAL state : state_t := IDLE; + + -- Buffer types + TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; + + -- Processing buffers + SIGNAL input_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + SIGNAL deinterleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + SIGNAL fec_decoded_buffer : byte_buffer_t; + SIGNAL output_buffer : byte_buffer_t; + + -- Index counters + SIGNAL byte_idx : NATURAL RANGE 0 TO ENCODED_BYTES; + SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; + SIGNAL out_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; + + -- Frame counter + SIGNAL frame_count : UNSIGNED(31 DOWNTO 0) := (OTHERS => '0'); + + -- Output holding registers + SIGNAL m_tdata_reg : std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + SIGNAL m_tvalid_reg : std_logic; + SIGNAL m_tlast_reg : std_logic; + + -- OVP Randomizer sequence (same as encoder) + TYPE randomizer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + CONSTANT RANDOMIZER_SEQUENCE : randomizer_t := ( + x"A3", x"81", x"5C", x"C4", x"C9", x"08", x"0E", x"53", + x"CC", x"A1", x"FB", x"29", x"9E", x"4F", x"16", x"E0", + x"97", x"4E", x"2B", x"57", x"12", x"A7", x"3F", x"C2", + x"4D", x"6B", x"0F", x"08", x"30", x"46", x"11", x"56", + x"0D", x"1A", x"13", x"E7", x"50", x"97", x"61", x"F3", + x"BE", x"E3", x"99", x"B0", x"64", x"39", x"22", x"2C", + x"F0", x"09", x"E1", x"86", x"CF", x"73", x"59", x"C2", + x"5C", x"8E", x"E3", x"D7", x"3F", x"70", x"D4", x"27", + x"C2", x"E0", x"81", x"92", x"DA", x"FC", x"CA", x"5A", + x"80", x"42", x"83", x"15", x"0F", x"A2", x"9E", x"15", + x"9C", x"8B", x"DB", x"A4", x"46", x"1C", x"10", x"9F", + x"B3", x"47", x"6C", x"5E", x"15", x"12", x"1F", x"AD", + x"38", x"3D", x"03", x"BA", x"90", x"8D", x"BE", x"D3", + x"65", x"23", x"32", x"B8", x"AB", x"10", x"62", x"7E", + x"C6", x"26", x"7C", x"13", x"C9", x"65", x"3D", x"15", + x"15", x"ED", x"35", x"F4", x"57", x"F5", x"58", x"11", + x"9D", x"8E", x"E8", x"34", x"C9", x"59" + ); + + -- Deinterleaver address calculation (reverse of interleaver) + FUNCTION deinterleave_address(addr : NATURAL) RETURN NATURAL IS + CONSTANT ROWS : NATURAL := 67; + CONSTANT COLS : NATURAL := 32; + VARIABLE row : NATURAL; + VARIABLE col : NATURAL; + BEGIN + row := addr MOD ROWS; + col := addr / ROWS; + RETURN row * COLS + col; + END FUNCTION; + +BEGIN + + -- Output assignments + m_axis_tdata <= m_tdata_reg; + m_axis_tvalid <= m_tvalid_reg; + m_axis_tlast <= m_tlast_reg; + + frames_decoded <= std_logic_vector(frame_count); + + -- Main FSM + decoder_fsm : PROCESS(clk) + VARIABLE bit_0, bit_1 : std_logic; + BEGIN + IF rising_edge(clk) THEN + IF aresetn = '0' THEN + state <= IDLE; + byte_idx <= 0; + bit_idx <= 0; + out_idx <= 0; + frame_count <= (OTHERS => '0'); + s_axis_tready <= '0'; + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + decoder_active <= '0'; + + ELSE + CASE state IS + + -- IDLE: Wait for incoming data and capture first byte + WHEN IDLE => + decoder_active <= '0'; + s_axis_tready <= '1'; -- Ready to accept data + m_tvalid_reg <= '0'; -- Not outputting yet + + IF s_axis_tvalid = '1' THEN + -- *** FIX: Store the FIRST byte immediately! *** + input_buffer(0) <= s_axis_tdata(0); + input_buffer(1) <= s_axis_tdata(1); + input_buffer(2) <= s_axis_tdata(2); + input_buffer(3) <= s_axis_tdata(3); + input_buffer(4) <= s_axis_tdata(4); + input_buffer(5) <= s_axis_tdata(5); + input_buffer(6) <= s_axis_tdata(6); + input_buffer(7) <= s_axis_tdata(7); + + REPORT "DECODER: Stored FIRST byte at index 0, data=" & + INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & + " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); + + -- Check for edge case: single-byte frame (unlikely with ENCODED_BYTES=268) + IF s_axis_tlast = '1' AND ENCODED_BYTES = 1 THEN + REPORT "DECODER: Single-byte frame received"; + byte_idx <= 0; + bit_idx <= 0; + state <= DEINTERLEAVE; + s_axis_tready <= '0'; + ELSE + -- Normal case: transition to COLLECT for remaining bytes + byte_idx <= 1; -- Next byte will go to index 1 + bit_idx <= 0; + state <= COLLECT; + decoder_active <= '1'; + END IF; + END IF; + + -- COLLECT: Gather remaining bytes (1 through 267) + WHEN COLLECT => + IF s_axis_tvalid = '1' THEN + -- Store incoming byte as 8 bits + input_buffer(byte_idx * 8 + 0) <= s_axis_tdata(0); + input_buffer(byte_idx * 8 + 1) <= s_axis_tdata(1); + input_buffer(byte_idx * 8 + 2) <= s_axis_tdata(2); + input_buffer(byte_idx * 8 + 3) <= s_axis_tdata(3); + input_buffer(byte_idx * 8 + 4) <= s_axis_tdata(4); + input_buffer(byte_idx * 8 + 5) <= s_axis_tdata(5); + input_buffer(byte_idx * 8 + 6) <= s_axis_tdata(6); + input_buffer(byte_idx * 8 + 7) <= s_axis_tdata(7); + + -- Debug: Report first 5 received bytes + IF byte_idx < 5 THEN + REPORT "DECODER: Stored byte at byte_idx=" & INTEGER'IMAGE(byte_idx) & + " data=" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & + " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); + END IF; + + byte_idx <= byte_idx + 1; + + -- Check for frame completion + IF s_axis_tlast = '1' THEN + REPORT "DECODER: Received tlast. Total bytes stored = " & + INTEGER'IMAGE(byte_idx + 1); + + -- Verify we got the expected number of bytes + IF byte_idx + 1 /= ENCODED_BYTES THEN + REPORT "DECODER: WARNING! Expected " & INTEGER'IMAGE(ENCODED_BYTES) & + " bytes but got " & INTEGER'IMAGE(byte_idx + 1) severity warning; + END IF; + + byte_idx <= 0; + bit_idx <= 0; + state <= DEINTERLEAVE; + s_axis_tready <= '0'; + + ELSIF byte_idx + 1 >= ENCODED_BYTES THEN + -- Stored all bytes but no tlast! This is an error condition + REPORT "DECODER: ERROR! Stored " & INTEGER'IMAGE(ENCODED_BYTES) & + " bytes but no tlast received" severity error; + byte_idx <= 0; + state <= IDLE; + s_axis_tready <= '1'; + END IF; + END IF; + + -- DEINTERLEAVE: Reverse the row-column shuffle + WHEN DEINTERLEAVE => + IF bit_idx < ENCODED_BITS THEN + deinterleaved_buffer(deinterleave_address(bit_idx)) <= input_buffer(bit_idx); + bit_idx <= bit_idx + 1; + ELSE + REPORT "DEINTERLEAVE complete"; + byte_idx <= 0; + bit_idx <= 0; + state <= FEC_DECODE; + END IF; + + -- FEC_DECODE: Majority vote on bit pairs + WHEN FEC_DECODE => + IF byte_idx < PAYLOAD_BYTES THEN + -- Process one bit position at a time + IF bit_idx < 8 THEN + bit_0 := deinterleaved_buffer(byte_idx * 16 + bit_idx * 2); + bit_1 := deinterleaved_buffer(byte_idx * 16 + bit_idx * 2 + 1); + fec_decoded_buffer(byte_idx)(bit_idx) <= bit_0 OR bit_1; + bit_idx <= bit_idx + 1; + ELSE + -- Done with this byte, move to next + bit_idx <= 0; + byte_idx <= byte_idx + 1; + END IF; + ELSE + REPORT "FEC_DECODE complete"; + byte_idx <= 0; + state <= DERANDOMIZE; + END IF; + + -- DERANDOMIZE: XOR with same sequence (inverse operation) + WHEN DERANDOMIZE => + IF byte_idx < PAYLOAD_BYTES THEN + output_buffer(byte_idx) <= + fec_decoded_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); + + -- Debug: Report first 5 derandomized bytes + IF byte_idx < 5 THEN + REPORT "DERANDOMIZE[" & INTEGER'IMAGE(byte_idx) & + "] fec=" & INTEGER'IMAGE(to_integer(unsigned(fec_decoded_buffer(byte_idx)))) & + " rand=" & INTEGER'IMAGE(to_integer(unsigned(RANDOMIZER_SEQUENCE(byte_idx)))) & + " out=" & INTEGER'IMAGE(to_integer(unsigned(fec_decoded_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx)))); + END IF; + + byte_idx <= byte_idx + 1; + ELSE + REPORT "DERANDOMIZE complete"; + out_idx <= 0; + state <= OUTPUT; + END IF; + + -- OUTPUT: Send bytes to next stage + WHEN OUTPUT => + IF m_axis_tready = '1' OR m_tvalid_reg = '0' THEN + IF out_idx < PAYLOAD_BYTES THEN + m_tdata_reg <= output_buffer(out_idx); + m_tvalid_reg <= '1'; + + -- Debug: Report first 5 output bytes + IF out_idx < 5 THEN + REPORT "DECODER OUTPUT byte " & INTEGER'IMAGE(out_idx) & " = " & + INTEGER'IMAGE(to_integer(unsigned(output_buffer(out_idx)))); + END IF; + + -- Set tlast on final byte + IF out_idx = PAYLOAD_BYTES - 1 THEN + m_tlast_reg <= '1'; + ELSE + m_tlast_reg <= '0'; + END IF; + + out_idx <= out_idx + 1; + ELSE + -- Frame complete + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + frame_count <= frame_count + 1; + state <= IDLE; + END IF; + END IF; + + END CASE; + END IF; + END IF; + END PROCESS decoder_fsm; + +END ARCHITECTURE rtl; diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd new file mode 100644 index 0000000..1772603 --- /dev/null +++ b/src/ov_frame_encoder.vhd @@ -0,0 +1,362 @@ +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- _______ ________ ______ +-- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ +-- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ +-- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / +-- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ +-- /_/ +-- ________ _____ _____ _____ _____ +-- ____ _/_______ __________ /____(_)__ /_____ ____ /______ +-- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ +-- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ +-- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ +-- Copyright +------------------------------------------------------------------------------------------------------ +-- +-- Copyright 2025 by Open Research Institute +-- +------------------------------------------------------------------------------------------------------ +-- License +------------------------------------------------------------------------------------------------------ +-- +-- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. +-- +-- You may redistribute and modify this source and make products using it under +-- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). +-- +-- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING +-- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. +-- Please see the CERN-OHL-W v2 for applicable conditions. +-- +------------------------------------------------------------------------------------------------------ +-- Block name and description +------------------------------------------------------------------------------------------------------ +-- +-- Opulent Voice Protocol Frame Encoder +-- +-- This module implements the TX path processing for OVP frames: +-- 1. Collects 134 bytes of payload from AXI-Stream input +-- 2. Applies randomization (XOR with fixed sequence) +-- 3. Applies FEC (rate 1/2 convolutional - currently simple bit duplication) +-- 4. Applies interleaving (67x32 row-column interleaver) +-- 5. Outputs 268 bytes (2144 bits) via AXI-Stream +-- +-- The module is designed to maintain timing for 40ms frame periods. +-- +-- BUGFIX (2025-11-16): Fixed first-byte-lost issue in IDLE?COLLECT transition +-- Now stores first byte immediately when transitioning states +-- +------------------------------------------------------------------------------------------------------ +------------------------------------------------------------------------------------------------------ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY ov_frame_encoder IS + GENERIC ( + PAYLOAD_BYTES : NATURAL := 134; -- Input frame size + ENCODED_BYTES : NATURAL := 268; -- Output frame size (after FEC) + ENCODED_BITS : NATURAL := 2144; -- Encoded bits (268 * 8) + BYTE_WIDTH : NATURAL := 8 + ); + PORT ( + clk : IN std_logic; + aresetn : IN std_logic; + + -- Input AXI-Stream (134-byte frames from async FIFO) + s_axis_tdata : IN std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + s_axis_tvalid : IN std_logic; + s_axis_tready : OUT std_logic; + s_axis_tlast : IN std_logic; + + -- Output AXI-Stream (268-byte frames to deserializer) + m_axis_tdata : OUT std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + m_axis_tvalid : OUT std_logic; + m_axis_tready : IN std_logic; + m_axis_tlast : OUT std_logic; + + -- Status outputs + frames_encoded : OUT std_logic_vector(31 DOWNTO 0); + encoder_active : OUT std_logic + ); +END ENTITY ov_frame_encoder; + +ARCHITECTURE rtl OF ov_frame_encoder IS + + -- State machine + TYPE state_t IS (IDLE, COLLECT, RANDOMIZE, FEC_ENCODE, INTERLEAVE, OUTPUT); + SIGNAL state : state_t := IDLE; + + -- Buffer types + TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; + + -- Processing buffers + SIGNAL input_buffer : byte_buffer_t; + SIGNAL randomized_buffer : byte_buffer_t; + SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + + -- Index counters + SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; + SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; + SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; + + -- Frame counter + SIGNAL frame_count : UNSIGNED(31 DOWNTO 0) := (OTHERS => '0'); + + -- Output holding registers + SIGNAL m_tdata_reg : std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + SIGNAL m_tvalid_reg : std_logic; + SIGNAL m_tlast_reg : std_logic; + + -- OVP Randomizer sequence (from OVP spec) + TYPE randomizer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + CONSTANT RANDOMIZER_SEQUENCE : randomizer_t := ( + x"A3", x"81", x"5C", x"C4", x"C9", x"08", x"0E", x"53", + x"CC", x"A1", x"FB", x"29", x"9E", x"4F", x"16", x"E0", + x"97", x"4E", x"2B", x"57", x"12", x"A7", x"3F", x"C2", + x"4D", x"6B", x"0F", x"08", x"30", x"46", x"11", x"56", + x"0D", x"1A", x"13", x"E7", x"50", x"97", x"61", x"F3", + x"BE", x"E3", x"99", x"B0", x"64", x"39", x"22", x"2C", + x"F0", x"09", x"E1", x"86", x"CF", x"73", x"59", x"C2", + x"5C", x"8E", x"E3", x"D7", x"3F", x"70", x"D4", x"27", + x"C2", x"E0", x"81", x"92", x"DA", x"FC", x"CA", x"5A", + x"80", x"42", x"83", x"15", x"0F", x"A2", x"9E", x"15", + x"9C", x"8B", x"DB", x"A4", x"46", x"1C", x"10", x"9F", + x"B3", x"47", x"6C", x"5E", x"15", x"12", x"1F", x"AD", + x"38", x"3D", x"03", x"BA", x"90", x"8D", x"BE", x"D3", + x"65", x"23", x"32", x"B8", x"AB", x"10", x"62", x"7E", + x"C6", x"26", x"7C", x"13", x"C9", x"65", x"3D", x"15", + x"15", x"ED", x"35", x"F4", x"57", x"F5", x"58", x"11", + x"9D", x"8E", x"E8", x"34", x"C9", x"59" + ); + + -- Interleaver address calculation (67 rows x 32 cols) + FUNCTION interleave_address(addr : NATURAL) RETURN NATURAL IS + CONSTANT ROWS : NATURAL := 67; + CONSTANT COLS : NATURAL := 32; + VARIABLE row : NATURAL; + VARIABLE col : NATURAL; + BEGIN + row := addr / COLS; + col := addr MOD COLS; + RETURN col * ROWS + row; + END FUNCTION; + +BEGIN + + -- Connect output registers to ports + m_axis_tdata <= m_tdata_reg; + m_axis_tvalid <= m_tvalid_reg; + m_axis_tlast <= m_tlast_reg; + + frames_encoded <= std_logic_vector(frame_count); + + -- Main FSM + encoder_fsm: PROCESS(clk, aresetn) + BEGIN + IF aresetn = '0' THEN + state <= IDLE; + byte_idx <= 0; + bit_idx <= 0; + out_idx <= 0; + s_axis_tready <= '0'; + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + frame_count <= (OTHERS => '0'); + + ELSIF rising_edge(clk) THEN + IF aresetn = '1' THEN + CASE state IS + + -- IDLE: Wait for incoming data + WHEN IDLE => + encoder_active <= '0'; + s_axis_tready <= '0'; -- Keep tready LOW to prevent premature handshakes + m_tvalid_reg <= '0'; + byte_idx <= 0; + + IF s_axis_tvalid = '1' THEN + -- Data is waiting, transition to COLLECT and assert tready + state <= COLLECT; + encoder_active <= '1'; + s_axis_tready <= '1'; -- Assert tready ONLY when transitioning + END IF; + + -- COLLECT: Gather ALL bytes (0 through 133) + WHEN COLLECT => + -- DON'T touch tready - it was set to '1' during IDLE transition + -- Leave it alone to prevent FIFO synchronization issues + + IF s_axis_tvalid = '1' AND s_axis_tready = '1' THEN + -- Store the incoming byte + input_buffer(byte_idx) <= s_axis_tdata; + REPORT "ENCODER: Stored byte at byte_idx=" & INTEGER'IMAGE(byte_idx) & + " data=" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & + " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); + + -- Check tlast FIRST + IF s_axis_tlast = '1' THEN + REPORT "ENCODER: Received tlast. Total bytes stored = " & + INTEGER'IMAGE(byte_idx + 1); + + IF byte_idx + 1 /= PAYLOAD_BYTES THEN + REPORT "ENCODER: WARNING! Expected " & INTEGER'IMAGE(PAYLOAD_BYTES) & + " bytes but got " & INTEGER'IMAGE(byte_idx + 1) severity warning; + END IF; + + byte_idx <= 0; + state <= RANDOMIZE; + s_axis_tready <= '0'; -- Deassert when done + + ELSIF byte_idx >= PAYLOAD_BYTES - 1 THEN + -- Just stored the last expected byte but no tlast + REPORT "ENCODER: ERROR! Stored " & INTEGER'IMAGE(byte_idx + 1) & + " bytes but no tlast received" severity error; + byte_idx <= 0; + state <= IDLE; + s_axis_tready <= '0'; -- Deassert on error + ELSE + -- Continue to next byte + byte_idx <= byte_idx + 1; + -- DON'T touch tready! + END IF; + END IF; + + -- RANDOMIZE: XOR with sequence + WHEN RANDOMIZE => + IF byte_idx < PAYLOAD_BYTES THEN + randomized_buffer(byte_idx) <= + input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); + + -- Debug: Report first 5 bytes + IF byte_idx < 5 THEN + REPORT "RANDOMIZE[" & INTEGER'IMAGE(byte_idx) & + "] input=" & INTEGER'IMAGE(to_integer(unsigned(input_buffer(byte_idx)))) & + " rand=" & INTEGER'IMAGE(to_integer(unsigned(RANDOMIZER_SEQUENCE(byte_idx)))) & + " out=" & INTEGER'IMAGE(to_integer(unsigned(input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx)))); + END IF; + + byte_idx <= byte_idx + 1; + ELSE + REPORT "RANDOMIZE complete, " & INTEGER'IMAGE(PAYLOAD_BYTES) & " bytes processed"; + byte_idx <= 0; + bit_idx <= 0; + state <= FEC_ENCODE; + END IF; + + -- FEC_ENCODE: Duplicate each bit (rate 1/2) + WHEN FEC_ENCODE => + IF byte_idx < PAYLOAD_BYTES THEN + -- Process one source bit at a time (produces 2 output bits) + IF bit_idx < 8 THEN + -- Duplicate bit (bit_idx) from current byte + fec_buffer(byte_idx * 16 + bit_idx * 2) <= randomized_buffer(byte_idx)(bit_idx); + fec_buffer(byte_idx * 16 + bit_idx * 2 + 1) <= randomized_buffer(byte_idx)(bit_idx); + bit_idx <= bit_idx + 1; + ELSE + -- Done with this byte, move to next + -- Debug: Report first byte's FEC output + IF byte_idx = 0 THEN + REPORT "FEC_ENCODE byte 0 produces 16 bits: " & + std_logic'IMAGE(fec_buffer(0)) & std_logic'IMAGE(fec_buffer(1)) & " " & + std_logic'IMAGE(fec_buffer(2)) & std_logic'IMAGE(fec_buffer(3)) & " " & + std_logic'IMAGE(fec_buffer(4)) & std_logic'IMAGE(fec_buffer(5)) & " " & + std_logic'IMAGE(fec_buffer(6)) & std_logic'IMAGE(fec_buffer(7)) & " " & + std_logic'IMAGE(fec_buffer(8)) & std_logic'IMAGE(fec_buffer(9)) & " " & + std_logic'IMAGE(fec_buffer(10)) & std_logic'IMAGE(fec_buffer(11)) & " " & + std_logic'IMAGE(fec_buffer(12)) & std_logic'IMAGE(fec_buffer(13)) & " " & + std_logic'IMAGE(fec_buffer(14)) & std_logic'IMAGE(fec_buffer(15)); + END IF; + bit_idx <= 0; + byte_idx <= byte_idx + 1; + END IF; + ELSE + REPORT "FEC_ENCODE complete, " & INTEGER'IMAGE(ENCODED_BITS) & " bits produced"; + byte_idx <= 0; + bit_idx <= 0; + state <= INTERLEAVE; + END IF; + + -- INTERLEAVE: Shuffle bits via row-column interleaver + WHEN INTERLEAVE => + IF bit_idx < ENCODED_BITS THEN + interleaved_buffer(interleave_address(bit_idx)) <= fec_buffer(bit_idx); + bit_idx <= bit_idx + 1; + ELSE + REPORT "INTERLEAVE complete"; + bit_idx <= 0; + out_idx <= 0; + state <= OUTPUT; + END IF; + + -- OUTPUT: Send bytes to deserializer + + + + + WHEN OUTPUT => + IF m_axis_tready = '1' OR m_tvalid_reg = '0' THEN + IF out_idx < ENCODED_BYTES THEN + -- Pack 8 bits into a byte + m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); + m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); + m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); + m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); + m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); + m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); + m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); + m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); + + m_tvalid_reg <= '1'; + + -- Debug reports... + IF out_idx < 5 THEN + REPORT "OUTPUT[" & INTEGER'IMAGE(out_idx) & "] bits: " & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 7)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 6)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 5)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 4)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 3)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 2)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 1)) & + std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 0)); + END IF; + + -- Set tlast on final byte + IF out_idx = ENCODED_BYTES - 1 THEN + m_tlast_reg <= '1'; + ELSE + m_tlast_reg <= '0'; + END IF; + + out_idx <= out_idx + 1; + ELSE + -- Frame complete + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + frame_count <= frame_count + 1; + state <= IDLE; + END IF; + END IF; + + + + + + + + + + END CASE; + END IF; + END IF; + END PROCESS encoder_fsm; + +END ARCHITECTURE rtl; From e0ddf298189d6e5e720c1e21405c80c3a05467d5 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Tue, 18 Nov 2025 22:21:07 -0800 Subject: [PATCH 38/60] data now good in loopback - defeated tricky FIFO to encoder timing bug --- src/msk_top.vhd | 4 +- src/ov_frame_encoder.vhd | 228 ++++++++++++++++----------------------- 2 files changed, 93 insertions(+), 139 deletions(-) diff --git a/src/msk_top.vhd b/src/msk_top.vhd index e14168c..2c02f60 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -62,8 +62,8 @@ -- PHASE 1: OV ENCODER/DECODER INTEGRATION (Issue #24) ------------------------------------------------------------------------------------------------------ -- Integrated OV frame encoder (TX) and decoder (RX) into datapath: --- TX: FIFO → Encoder (134→268 bytes) → Deserializer → Modulator --- RX: Demodulator → Frame Sync → Decoder (268→134 bytes) → FIFO +-- TX: FIFO ? Encoder (134?268 bytes) ? Deserializer ? Modulator +-- RX: Demodulator ? Frame Sync ? Decoder (268?134 bytes) ? FIFO -- -- KNOWN LIMITATION: Frame size mismatch - PS currently sends/expects 268 bytes -- - Encoder expects 134-byte input but receives 268 bytes diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 1772603..8e1d646 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -45,10 +45,10 @@ -- 4. Applies interleaving (67x32 row-column interleaver) -- 5. Outputs 268 bytes (2144 bits) via AXI-Stream -- --- The module is designed to maintain timing for 40ms frame periods. --- --- BUGFIX (2025-11-16): Fixed first-byte-lost issue in IDLE?COLLECT transition --- Now stores first byte immediately when transitioning states +-- BUGFIX (2025-11-18): Completely redesigned collection strategy +-- - Collect ALL bytes into circular buffer +-- - When tlast arrives, count back 134 bytes +-- - This handles any FIFO latency/alignment naturally -- ------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------ @@ -89,23 +89,29 @@ END ENTITY ov_frame_encoder; ARCHITECTURE rtl OF ov_frame_encoder IS -- State machine - TYPE state_t IS (IDLE, COLLECT, RANDOMIZE, FEC_ENCODE, INTERLEAVE, OUTPUT); + TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, FEC_ENCODE, INTERLEAVE, OUTPUT); SIGNAL state : state_t := IDLE; -- Buffer types TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; + -- Circular collection buffer (larger than needed to handle any transients) + CONSTANT COLLECT_SIZE : NATURAL := 256; + TYPE collect_buffer_t IS ARRAY(0 TO COLLECT_SIZE-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + SIGNAL collect_buffer : collect_buffer_t; + -- Processing buffers SIGNAL input_buffer : byte_buffer_t; SIGNAL randomized_buffer : byte_buffer_t; - SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' - SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); + SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- Index counters - SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; - SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; - SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; + SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; -- Where we're writing in collect_buffer + SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; + SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; + SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; -- Frame counter SIGNAL frame_count : UNSIGNED(31 DOWNTO 0) := (OTHERS => '0'); @@ -160,9 +166,12 @@ BEGIN -- Main FSM encoder_fsm: PROCESS(clk, aresetn) + VARIABLE extract_start : NATURAL; + VARIABLE extract_end : NATURAL; BEGIN IF aresetn = '0' THEN state <= IDLE; + collect_idx <= 0; byte_idx <= 0; bit_idx <= 0; out_idx <= 0; @@ -178,182 +187,127 @@ BEGIN -- IDLE: Wait for incoming data WHEN IDLE => encoder_active <= '0'; - s_axis_tready <= '0'; -- Keep tready LOW to prevent premature handshakes + s_axis_tready <= '0'; m_tvalid_reg <= '0'; - byte_idx <= 0; + collect_idx <= 0; IF s_axis_tvalid = '1' THEN - -- Data is waiting, transition to COLLECT and assert tready state <= COLLECT; encoder_active <= '1'; - s_axis_tready <= '1'; -- Assert tready ONLY when transitioning + s_axis_tready <= '1'; END IF; - -- COLLECT: Gather ALL bytes (0 through 133) + -- COLLECT: Gather ALL bytes into circular buffer until tlast + -- Don't worry about alignment - just collect everything WHEN COLLECT => - -- DON'T touch tready - it was set to '1' during IDLE transition - -- Leave it alone to prevent FIFO synchronization issues + s_axis_tready <= '1'; - IF s_axis_tvalid = '1' AND s_axis_tready = '1' THEN - -- Store the incoming byte - input_buffer(byte_idx) <= s_axis_tdata; - REPORT "ENCODER: Stored byte at byte_idx=" & INTEGER'IMAGE(byte_idx) & - " data=" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & + IF s_axis_tvalid = '1' THEN + -- Store byte in circular buffer + collect_buffer(collect_idx MOD COLLECT_SIZE) <= s_axis_tdata; + + REPORT "COLLECT: collect_idx=" & INTEGER'IMAGE(collect_idx) & + " data=0x" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); - -- Check tlast FIRST IF s_axis_tlast = '1' THEN - REPORT "ENCODER: Received tlast. Total bytes stored = " & - INTEGER'IMAGE(byte_idx + 1); - - IF byte_idx + 1 /= PAYLOAD_BYTES THEN - REPORT "ENCODER: WARNING! Expected " & INTEGER'IMAGE(PAYLOAD_BYTES) & - " bytes but got " & INTEGER'IMAGE(byte_idx + 1) severity warning; - END IF; - - byte_idx <= 0; - state <= RANDOMIZE; - s_axis_tready <= '0'; -- Deassert when done - - ELSIF byte_idx >= PAYLOAD_BYTES - 1 THEN - -- Just stored the last expected byte but no tlast - REPORT "ENCODER: ERROR! Stored " & INTEGER'IMAGE(byte_idx + 1) & - " bytes but no tlast received" severity error; + -- Frame boundary! Now extract the last 134 bytes + REPORT "COLLECT: tlast at collect_idx=" & INTEGER'IMAGE(collect_idx); + s_axis_tready <= '0'; + state <= EXTRACT; byte_idx <= 0; - state <= IDLE; - s_axis_tready <= '0'; -- Deassert on error ELSE - -- Continue to next byte - byte_idx <= byte_idx + 1; - -- DON'T touch tready! + collect_idx <= collect_idx + 1; END IF; END IF; - -- RANDOMIZE: XOR with sequence - WHEN RANDOMIZE => + -- EXTRACT: Copy the last 134 bytes from collect_buffer to input_buffer + -- The frame ends at collect_idx, so we want bytes [collect_idx-133 : collect_idx] + WHEN EXTRACT => IF byte_idx < PAYLOAD_BYTES THEN - randomized_buffer(byte_idx) <= - input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); + -- Calculate which byte in collect_buffer to read + -- If collect_idx = 133, we want bytes [0:133] + -- If collect_idx = 150, we want bytes [17:150] + extract_start := (collect_idx + 1) - PAYLOAD_BYTES; + extract_end := collect_idx; + + -- Copy byte from circular buffer + input_buffer(byte_idx) <= collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE); - -- Debug: Report first 5 bytes IF byte_idx < 5 THEN - REPORT "RANDOMIZE[" & INTEGER'IMAGE(byte_idx) & - "] input=" & INTEGER'IMAGE(to_integer(unsigned(input_buffer(byte_idx)))) & - " rand=" & INTEGER'IMAGE(to_integer(unsigned(RANDOMIZER_SEQUENCE(byte_idx)))) & - " out=" & INTEGER'IMAGE(to_integer(unsigned(input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx)))); + REPORT "EXTRACT[" & INTEGER'IMAGE(byte_idx) & + "] from collect_buffer[" & + INTEGER'IMAGE((extract_start + byte_idx) MOD COLLECT_SIZE) & + "] = 0x" & + INTEGER'IMAGE(to_integer(unsigned(collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE)))); END IF; byte_idx <= byte_idx + 1; ELSE - REPORT "RANDOMIZE complete, " & INTEGER'IMAGE(PAYLOAD_BYTES) & " bytes processed"; + REPORT "EXTRACT complete, " & INTEGER'IMAGE(PAYLOAD_BYTES) & " bytes copied"; + byte_idx <= 0; + state <= RANDOMIZE; + END IF; + + -- RANDOMIZE: XOR with sequence + WHEN RANDOMIZE => + IF byte_idx < PAYLOAD_BYTES THEN + randomized_buffer(byte_idx) <= + input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); + byte_idx <= byte_idx + 1; + ELSE byte_idx <= 0; bit_idx <= 0; state <= FEC_ENCODE; END IF; - -- FEC_ENCODE: Duplicate each bit (rate 1/2) + -- FEC_ENCODE: Simple rate-1/2 code (bit duplication) WHEN FEC_ENCODE => - IF byte_idx < PAYLOAD_BYTES THEN - -- Process one source bit at a time (produces 2 output bits) - IF bit_idx < 8 THEN - -- Duplicate bit (bit_idx) from current byte - fec_buffer(byte_idx * 16 + bit_idx * 2) <= randomized_buffer(byte_idx)(bit_idx); - fec_buffer(byte_idx * 16 + bit_idx * 2 + 1) <= randomized_buffer(byte_idx)(bit_idx); - bit_idx <= bit_idx + 1; - ELSE - -- Done with this byte, move to next - -- Debug: Report first byte's FEC output - IF byte_idx = 0 THEN - REPORT "FEC_ENCODE byte 0 produces 16 bits: " & - std_logic'IMAGE(fec_buffer(0)) & std_logic'IMAGE(fec_buffer(1)) & " " & - std_logic'IMAGE(fec_buffer(2)) & std_logic'IMAGE(fec_buffer(3)) & " " & - std_logic'IMAGE(fec_buffer(4)) & std_logic'IMAGE(fec_buffer(5)) & " " & - std_logic'IMAGE(fec_buffer(6)) & std_logic'IMAGE(fec_buffer(7)) & " " & - std_logic'IMAGE(fec_buffer(8)) & std_logic'IMAGE(fec_buffer(9)) & " " & - std_logic'IMAGE(fec_buffer(10)) & std_logic'IMAGE(fec_buffer(11)) & " " & - std_logic'IMAGE(fec_buffer(12)) & std_logic'IMAGE(fec_buffer(13)) & " " & - std_logic'IMAGE(fec_buffer(14)) & std_logic'IMAGE(fec_buffer(15)); - END IF; - bit_idx <= 0; - byte_idx <= byte_idx + 1; - END IF; + IF bit_idx < ENCODED_BITS THEN + fec_buffer(bit_idx) <= randomized_buffer(bit_idx / 16)((bit_idx / 2) MOD 8); + bit_idx <= bit_idx + 1; ELSE - REPORT "FEC_ENCODE complete, " & INTEGER'IMAGE(ENCODED_BITS) & " bits produced"; - byte_idx <= 0; bit_idx <= 0; state <= INTERLEAVE; END IF; - -- INTERLEAVE: Shuffle bits via row-column interleaver + -- INTERLEAVE: Row-column interleaving WHEN INTERLEAVE => IF bit_idx < ENCODED_BITS THEN interleaved_buffer(interleave_address(bit_idx)) <= fec_buffer(bit_idx); bit_idx <= bit_idx + 1; ELSE - REPORT "INTERLEAVE complete"; - bit_idx <= 0; out_idx <= 0; state <= OUTPUT; + m_tvalid_reg <= '0'; END IF; - -- OUTPUT: Send bytes to deserializer - - - - + -- OUTPUT: Send 268 bytes via AXI-Stream WHEN OUTPUT => - IF m_axis_tready = '1' OR m_tvalid_reg = '0' THEN - IF out_idx < ENCODED_BYTES THEN - -- Pack 8 bits into a byte - m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); - m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); - m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); - m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); - m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); - m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); - m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); - m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); - - m_tvalid_reg <= '1'; - - -- Debug reports... - IF out_idx < 5 THEN - REPORT "OUTPUT[" & INTEGER'IMAGE(out_idx) & "] bits: " & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 7)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 6)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 5)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 4)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 3)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 2)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 1)) & - std_logic'IMAGE(interleaved_buffer(out_idx * 8 + 0)); - END IF; - - -- Set tlast on final byte - IF out_idx = ENCODED_BYTES - 1 THEN - m_tlast_reg <= '1'; + IF out_idx < ENCODED_BYTES THEN + m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); + m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); + m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); + m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); + m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); + m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); + m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); + m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); + + m_tvalid_reg <= '1'; + m_tlast_reg <= '1' WHEN out_idx = (ENCODED_BYTES - 1) ELSE '0'; + + IF m_axis_tready = '1' THEN + IF out_idx = (ENCODED_BYTES - 1) THEN + frame_count <= frame_count + 1; + state <= IDLE; + m_tvalid_reg <= '0'; ELSE - m_tlast_reg <= '0'; + out_idx <= out_idx + 1; END IF; - - out_idx <= out_idx + 1; - ELSE - -- Frame complete - m_tvalid_reg <= '0'; - m_tlast_reg <= '0'; - frame_count <= frame_count + 1; - state <= IDLE; END IF; END IF; - - - - - - - - - + END CASE; END IF; END IF; From f9b7ab04526f7827e85a2bf3dc8cc610b4525be7 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Wed, 19 Nov 2025 08:04:14 -0800 Subject: [PATCH 39/60] new encoder and decoder files added to the list in msk_top_ip.tcl --- library/msk_top_ip.tcl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index d2a85db..7ac6586 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -11,6 +11,10 @@ read_vhdl -vhdl2008 "../rdl/src/reg_utils.vhd" read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" read_vhdl -vhdl2008 "../rdl/outputs/rtl/msk_top_regs.vhd" +# OV frame encoder/decoder require VHDL-2008 for division/modulo operators +read_vhdl -vhdl2008 "../src/ov_frame_encoder.vhd" +read_vhdl -vhdl2008 "../src/ov_frame_decoder.vhd" + #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ "../msk_demodulator/src/costas_loop.vhd" \ @@ -75,4 +79,3 @@ adi_add_bus_clock "s_axis_aclk" "m_axis" "s_axis_aresetn" ipx::save_core [ipx::current_core] ipx::save_core [ipx::current_core] - From eae5b6046ee3c4ac9ace9782a40ae4437c5a7585 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Wed, 19 Nov 2025 23:45:26 -0800 Subject: [PATCH 40/60] added hard decision convolutional encoder and decoder --- library/msk_top_ip.tcl | 8 +- msk_demodulator | 2 +- src/conv_encoder_k7.vhd | 162 ++++++++++++++ src/frame_sync_detector.vhd | 4 + src/msk_top.vhd | 7 +- src/ov_frame_decoder.vhd | 79 +++++-- src/ov_frame_encoder.vhd | 53 ++++- src/viterbi_decoder_k7.vhd | 358 ++++++++++++++++++++++++++++++ src/viterbi_decoder_k7_simple.vhd | 251 +++++++++++++++++++++ 9 files changed, 892 insertions(+), 32 deletions(-) create mode 100644 src/conv_encoder_k7.vhd create mode 100644 src/viterbi_decoder_k7.vhd create mode 100644 src/viterbi_decoder_k7_simple.vhd diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 7ac6586..774faa7 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -15,8 +15,11 @@ read_vhdl -vhdl2008 "../rdl/outputs/rtl/msk_top_regs.vhd" read_vhdl -vhdl2008 "../src/ov_frame_encoder.vhd" read_vhdl -vhdl2008 "../src/ov_frame_decoder.vhd" + #set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] adi_ip_files msk_top [list \ + "../src/conv_encoder_k7.vhd" \ + "../src/viterbi_decoder_k7_simple.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ "../lowpass_ema/src/lowpass_ema.vhd" \ @@ -31,13 +34,16 @@ adi_ip_files msk_top [list \ "../src/axis_dma_adapter.vhd" \ "../src/axis_async_fifo.vhd" \ "../src/byte_to_bit_deserializer.vhd" \ - "../src/bit_to_byte_serializer.vhd" \ "../src/frame_sync_detector.vhd" \ "../nco/src/nco.vhd" \ "../prbs/src/prbs_gen.vhd" \ "../prbs/src/prbs_mon.vhd" \ "../nco/src/sin_cos_lut.vhd" ] +# Set VHDL-2008 for FEC files +set_property FILE_TYPE {VHDL 2008} [get_files "../src/conv_encoder_k7.vhd"] +set_property FILE_TYPE {VHDL 2008} [get_files "../src/viterbi_decoder_k7_simple.vhd"] + # use this command if we have AXI lite interface for register control adi_ip_properties msk_top diff --git a/msk_demodulator b/msk_demodulator index e837e29..f62469a 160000 --- a/msk_demodulator +++ b/msk_demodulator @@ -1 +1 @@ -Subproject commit e837e291cc2ad3c503b54203de741e27dbe4a6eb +Subproject commit f62469ac3af2481f4f79027ef0eafbec06782c71 diff --git a/src/conv_encoder_k7.vhd b/src/conv_encoder_k7.vhd new file mode 100644 index 0000000..6f3fbe4 --- /dev/null +++ b/src/conv_encoder_k7.vhd @@ -0,0 +1,162 @@ +------------------------------------------------------------------------------------------------------ +-- K=7 Convolutional Encoder (FIXED - No Signal Timing Bugs) +------------------------------------------------------------------------------------------------------ +-- Rate 1/2, constraint length K=7 +-- Generator polynomials: G1 = 171 octal = 1111001 binary +-- G2 = 133 octal = 1011011 binary +------------------------------------------------------------------------------------------------------ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY conv_encoder_k7 IS + GENERIC ( + PAYLOAD_BYTES : NATURAL := 134; -- Input size in bytes + ENCODED_BYTES : NATURAL := 268 -- Output size in bytes (2x for rate 1/2) + ); + PORT ( + clk : IN std_logic; + aresetn : IN std_logic; + + start : IN std_logic; + busy : OUT std_logic; + done : OUT std_logic; + + input_buffer : IN std_logic_vector(PAYLOAD_BYTES*8-1 DOWNTO 0); + output_buffer : OUT std_logic_vector(ENCODED_BYTES*8-1 DOWNTO 0) + ); +END ENTITY conv_encoder_k7; + +ARCHITECTURE rtl OF conv_encoder_k7 IS + + TYPE state_t IS (IDLE, ENCODE_DATA, FLUSH_TRELLIS, COMPLETE); + SIGNAL state : state_t := IDLE; + + SIGNAL input_bit_count : NATURAL RANGE 0 TO PAYLOAD_BYTES*8; + SIGNAL output_bit_count : NATURAL RANGE 0 TO ENCODED_BYTES*8; + + CONSTANT G1_POLY : std_logic_vector(6 DOWNTO 0) := "1111001"; + CONSTANT G2_POLY : std_logic_vector(6 DOWNTO 0) := "1011011"; + + SIGNAL out_buf : std_logic_vector(ENCODED_BYTES*8-1 DOWNTO 0); + + ATTRIBUTE ram_style : STRING; + ATTRIBUTE ram_style OF out_buf : SIGNAL IS "block"; + + -- Function to compute encoder outputs + FUNCTION compute_outputs( + current_bit : std_logic; + shift_reg : std_logic_vector(5 DOWNTO 0) + ) RETURN std_logic_vector IS + VARIABLE full_state : std_logic_vector(6 DOWNTO 0); + VARIABLE g1, g2 : std_logic; + BEGIN + full_state := current_bit & shift_reg; + + -- G1 output + g1 := '0'; + FOR i IN 0 TO 6 LOOP + IF G1_POLY(i) = '1' THEN + g1 := g1 XOR full_state(6-i); + END IF; + END LOOP; + + -- G2 output + g2 := '0'; + FOR i IN 0 TO 6 LOOP + IF G2_POLY(i) = '1' THEN + g2 := g2 XOR full_state(6-i); + END IF; + END LOOP; + + RETURN g1 & g2; -- Return as 2-bit vector + END FUNCTION; + +BEGIN + + PROCESS(clk, aresetn) + VARIABLE shift_reg : std_logic_vector(5 DOWNTO 0); + VARIABLE current_bit : std_logic; + VARIABLE outputs : std_logic_vector(1 DOWNTO 0); + BEGIN + IF aresetn = '0' THEN + state <= IDLE; + shift_reg := (OTHERS => '0'); + input_bit_count <= 0; + output_bit_count <= 0; + busy <= '0'; + done <= '0'; + out_buf <= (OTHERS => '0'); + + ELSIF rising_edge(clk) THEN + done <= '0'; + + CASE state IS + + WHEN IDLE => + busy <= '0'; + IF start = '1' THEN + state <= ENCODE_DATA; + busy <= '1'; + shift_reg := (OTHERS => '0'); + input_bit_count <= 0; + output_bit_count <= 0; + END IF; + + WHEN ENCODE_DATA => + -- Process 1,070 bits (stop 2 bits early for tail) + IF input_bit_count < PAYLOAD_BYTES*8 - 2 THEN + -- Read input bit (MSB first) + current_bit := input_buffer(PAYLOAD_BYTES*8 - 1 - input_bit_count); + + -- Compute outputs using current state + outputs := compute_outputs(current_bit, shift_reg); + + -- Store outputs (g1 first, then g2) + out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); -- g1 + out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); -- g2 + + -- Update shift register + shift_reg := shift_reg(4 DOWNTO 0) & current_bit; + + input_bit_count <= input_bit_count + 1; + output_bit_count <= output_bit_count + 2; + ELSE + state <= FLUSH_TRELLIS; + input_bit_count <= 0; + END IF; + + WHEN FLUSH_TRELLIS => + -- Add 2 tail bits (produces 4 encoded bits) + IF input_bit_count < 2 THEN + current_bit := '0'; + + -- Compute outputs + outputs := compute_outputs(current_bit, shift_reg); + + -- Store outputs + out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); + out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); + + -- Update shift register + shift_reg := shift_reg(4 DOWNTO 0) & '0'; + + input_bit_count <= input_bit_count + 1; + output_bit_count <= output_bit_count + 2; + ELSE + state <= COMPLETE; + END IF; + + WHEN COMPLETE => + done <= '1'; + busy <= '0'; + state <= IDLE; + + END CASE; + END IF; + END PROCESS; + + output_buffer <= out_buf; + +END ARCHITECTURE rtl; diff --git a/src/frame_sync_detector.vhd b/src/frame_sync_detector.vhd index bce92a3..4fbc9ef 100644 --- a/src/frame_sync_detector.vhd +++ b/src/frame_sync_detector.vhd @@ -50,6 +50,10 @@ ENTITY frame_sync_detector IS -- BIT Input Interface rx_bit : IN std_logic; rx_bit_valid : IN std_logic; + + -- soft decision signals + s_axis_soft_tdata : IN signed(15 DOWNTO 0); -- Soft decision input + m_axis_soft_tdata : OUT signed(15 DOWNTO 0); -- Soft decision output -- AXIS Master Interface (to FIFO) m_axis_tdata : OUT std_logic_vector(7 DOWNTO 0); diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 2c02f60..40c3d25 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -244,6 +244,9 @@ ARCHITECTURE struct OF msk_top IS SIGNAL rx_data_int : std_logic_vector(S_AXIS_DATA_W -1 DOWNTO 0); SIGNAL rx_invert : std_logic; + SIGNAL rx_data_soft : signed(15 downto 0); + SIGNAL rx_data_soft_valid : std_logic; + SIGNAL rx_sample_clk : std_logic; SIGNAL discard_rxsamples: std_logic_vector(7 DOWNTO 0); SIGNAL discard_rxnco : std_logic_vector(7 DOWNTO 0); @@ -555,6 +558,7 @@ BEGIN rx_bit => rx_bit_corr, rx_bit_valid => rx_bit_valid, + s_axis_soft_tdata => (OTHERS => '0'), -- tied to zero for hard decisions m_axis_tdata => sync_det_tdata, m_axis_tvalid => sync_det_tvalid, @@ -745,7 +749,8 @@ BEGIN rx_svalid => rx_sample_clk, rx_samples => rx_samples_dec(11 DOWNTO 0), - rx_data => rx_bit, + rx_data => rx_bit, -- hard decision + rx_data_soft => rx_data_soft, -- soft decision rx_dvalid => rx_bit_valid ); diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd index 6c792a2..875e67f 100644 --- a/src/ov_frame_decoder.vhd +++ b/src/ov_frame_decoder.vhd @@ -87,7 +87,7 @@ END ENTITY ov_frame_decoder; ARCHITECTURE rtl OF ov_frame_decoder IS -- State machine - TYPE state_t IS (IDLE, COLLECT, DEINTERLEAVE, FEC_DECODE, DERANDOMIZE, OUTPUT); + TYPE state_t IS (IDLE, COLLECT, DEINTERLEAVE, PREP_FEC_DECODE, FEC_DECODE, DERANDOMIZE, OUTPUT); SIGNAL state : state_t := IDLE; -- Buffer types @@ -135,6 +135,14 @@ ARCHITECTURE rtl OF ov_frame_decoder IS x"9D", x"8E", x"E8", x"34", x"C9", x"59" ); + -- Viterbi decoder signals + SIGNAL decoder_start : std_logic := '0'; + SIGNAL decoder_busy : std_logic; + SIGNAL decoder_done : std_logic; + SIGNAL decoder_input_g1 : std_logic_vector(2143 DOWNTO 0); -- 268*8 bits + SIGNAL decoder_input_g2 : std_logic_vector(2143 DOWNTO 0); + SIGNAL decoder_output_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 bits + -- Deinterleaver address calculation (reverse of interleaver) FUNCTION deinterleave_address(addr : NATURAL) RETURN NATURAL IS CONSTANT ROWS : NATURAL := 67; @@ -149,6 +157,24 @@ ARCHITECTURE rtl OF ov_frame_decoder IS BEGIN + -- Viterbi Decoder Instantiation (Hard Decision) + U_DECODER : ENTITY work.viterbi_decoder_k7_simple + GENERIC MAP ( + PAYLOAD_BITS => PAYLOAD_BYTES * 8, -- 1072 bits + ENCODED_BITS => ENCODED_BYTES * 8, -- 2144 bits + TRACEBACK_DEPTH => 35 + ) + PORT MAP ( + clk => clk, + aresetn => aresetn, + start => decoder_start, + busy => decoder_busy, + done => decoder_done, + input_bits_g1 => decoder_input_g1, + input_bits_g2 => decoder_input_g2, + output_bits => decoder_output_buf + ); + -- Output assignments m_axis_tdata <= m_tdata_reg; m_axis_tvalid <= m_tvalid_reg; @@ -171,6 +197,7 @@ BEGIN m_tvalid_reg <= '0'; m_tlast_reg <= '0'; decoder_active <= '0'; + decoder_start <= '0'; -- Initialize FEC decoder control ELSE CASE state IS @@ -269,29 +296,37 @@ BEGIN REPORT "DEINTERLEAVE complete"; byte_idx <= 0; bit_idx <= 0; - state <= FEC_DECODE; - END IF; - - -- FEC_DECODE: Majority vote on bit pairs - WHEN FEC_DECODE => - IF byte_idx < PAYLOAD_BYTES THEN - -- Process one bit position at a time - IF bit_idx < 8 THEN - bit_0 := deinterleaved_buffer(byte_idx * 16 + bit_idx * 2); - bit_1 := deinterleaved_buffer(byte_idx * 16 + bit_idx * 2 + 1); - fec_decoded_buffer(byte_idx)(bit_idx) <= bit_0 OR bit_1; - bit_idx <= bit_idx + 1; - ELSE - -- Done with this byte, move to next - bit_idx <= 0; - byte_idx <= byte_idx + 1; - END IF; - ELSE - REPORT "FEC_DECODE complete"; - byte_idx <= 0; - state <= DERANDOMIZE; + state <= PREP_FEC_DECODE; -- Changed to go to prep state first END IF; + -- PREP_FEC_DECODE: Separate deinterleaved bits into G1 and G2 streams +WHEN PREP_FEC_DECODE => + -- **FIX: Pack bits in FORWARD order, not reversed!** + -- deinterleaved_buffer[0] = first g1, [1] = first g2, etc. + FOR i IN 0 TO ENCODED_BITS/2 - 1 LOOP + decoder_input_g1(i) <= deinterleaved_buffer(i*2); -- G1 bits: 0, 2, 4, ... + decoder_input_g2(i) <= deinterleaved_buffer(i*2 + 1); -- G2 bits: 1, 3, 5, ... + END LOOP; + decoder_start <= '1'; + state <= FEC_DECODE; + +WHEN FEC_DECODE => + decoder_start <= '0'; -- Clear start pulse + IF decoder_done = '1' THEN + -- Unpack decoded bits in FORWARD order + -- decoder_output_buf[0] = first bit, goes to byte 0 bit 7 + FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP + FOR j IN 0 TO 7 LOOP + fec_decoded_buffer(i)(7-j) <= decoder_output_buf(i*8 + j); + END LOOP; + END LOOP; + byte_idx <= 0; + state <= DERANDOMIZE; + END IF; + + + + -- DERANDOMIZE: XOR with same sequence (inverse operation) WHEN DERANDOMIZE => IF byte_idx < PAYLOAD_BYTES THEN diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 8e1d646..cfe24fc 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -89,7 +89,7 @@ END ENTITY ov_frame_encoder; ARCHITECTURE rtl OF ov_frame_encoder IS -- State machine - TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, FEC_ENCODE, INTERLEAVE, OUTPUT); + TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); SIGNAL state : state_t := IDLE; -- Buffer types @@ -142,6 +142,13 @@ ARCHITECTURE rtl OF ov_frame_encoder IS x"15", x"ED", x"35", x"F4", x"57", x"F5", x"58", x"11", x"9D", x"8E", x"E8", x"34", x"C9", x"59" ); + + -- Viterbi encoder signals + SIGNAL encoder_start : std_logic := '0'; + SIGNAL encoder_busy : std_logic; + SIGNAL encoder_done : std_logic; + SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 + SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); -- 268*8 -- Interleaver address calculation (67 rows x 32 cols) FUNCTION interleave_address(addr : NATURAL) RETURN NATURAL IS @@ -157,6 +164,22 @@ ARCHITECTURE rtl OF ov_frame_encoder IS BEGIN + -- Convolutional Encoder Instantiation + U_ENCODER : ENTITY work.conv_encoder_k7 + GENERIC MAP ( + PAYLOAD_BYTES => PAYLOAD_BYTES, + ENCODED_BYTES => ENCODED_BYTES + ) + PORT MAP ( + clk => clk, + aresetn => aresetn, + start => encoder_start, + busy => encoder_busy, + done => encoder_done, + input_buffer => encoder_input_buf, + output_buffer => encoder_output_buf + ); + -- Connect output registers to ports m_axis_tdata <= m_tdata_reg; m_axis_tvalid <= m_tvalid_reg; @@ -179,6 +202,7 @@ BEGIN m_tvalid_reg <= '0'; m_tlast_reg <= '0'; frame_count <= (OTHERS => '0'); + encoder_start <= '0'; -- Initialize FEC encoder control; ELSIF rising_edge(clk) THEN IF aresetn = '1' THEN @@ -258,18 +282,33 @@ BEGIN ELSE byte_idx <= 0; bit_idx <= 0; - state <= FEC_ENCODE; + state <= PREP_FEC; -- Changed from FEC_ENCODE END IF; - -- FEC_ENCODE: Simple rate-1/2 code (bit duplication) +WHEN PREP_FEC => + -- Pack randomized_buffer MSB-first to match encoder's MSB-first reading + FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP + FOR j IN 0 TO 7 LOOP + -- Put byte 0 at top of buffer, MSB of each byte first + encoder_input_buf(PAYLOAD_BYTES*8 - 1 - (i*8 + j)) <= randomized_buffer(i)(7-j); + END LOOP; + END LOOP; + encoder_start <= '1'; + state <= FEC_ENCODE; + + -- FEC_ENCODE: Wait for convolution encoder to complete WHEN FEC_ENCODE => - IF bit_idx < ENCODED_BITS THEN - fec_buffer(bit_idx) <= randomized_buffer(bit_idx / 16)((bit_idx / 2) MOD 8); - bit_idx <= bit_idx + 1; - ELSE + encoder_start <= '0'; -- Clear start pulse + IF encoder_done = '1' THEN + -- Unpack encoded bits into fec_buffer + FOR i IN 0 TO ENCODED_BITS-1 LOOP + fec_buffer(i) <= encoder_output_buf(ENCODED_BITS - 1 - i); -- MSB-first + --fec_buffer(i) <= encoder_output_buf(i); + END LOOP; bit_idx <= 0; state <= INTERLEAVE; END IF; + -- INTERLEAVE: Row-column interleaving WHEN INTERLEAVE => diff --git a/src/viterbi_decoder_k7.vhd b/src/viterbi_decoder_k7.vhd new file mode 100644 index 0000000..3539c94 --- /dev/null +++ b/src/viterbi_decoder_k7.vhd @@ -0,0 +1,358 @@ +------------------------------------------------------------------------------------------------------ +-- Soft-Decision Viterbi Decoder for K=7 Convolutional Code +------------------------------------------------------------------------------------------------------ +-- Rate 1/2, constraint length K=7, 64 states +-- Generator polynomials: G1 = 171 octal, G2 = 133 octal (NASA Voyager code) +-- +-- Supports both hard-decision (1-bit) and soft-decision (3-4 bit) inputs +-- Uses register-exchange for survivor path management (simpler than traceback memory) +-- +-- Performance: +-- Hard decisions: ~5 dB coding gain at BER=10^-5 +-- 3-bit soft: ~7 dB coding gain (2 dB improvement over hard) +-- 4-bit soft: ~7.3 dB coding gain (marginal improvement over 3-bit) +-- +-- Think of this like a maze solver that tracks 64 parallel adventurer parties, +-- keeping only the most efficient path to each destination +------------------------------------------------------------------------------------------------------ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY viterbi_decoder_k7 IS + GENERIC ( + PAYLOAD_BYTES : NATURAL := 134; -- Output size in bytes + ENCODED_BYTES : NATURAL := 268; -- Input size in bytes + SOFT_DECISION_WIDTH : NATURAL := 3; -- Bits per soft input (1=hard, 3-4=soft) + TRACEBACK_DEPTH : NATURAL := 35; -- Path memory depth (5*K is typical) + METRIC_WIDTH : NATURAL := 12 -- Path metric width (avoid overflow) + ); + PORT ( + clk : IN std_logic; + aresetn : IN std_logic; + + -- Control + start : IN std_logic; + busy : OUT std_logic; + done : OUT std_logic; + + -- Input buffer (soft decisions, MSB first) + -- For hard decisions: use only MSB of each symbol + -- For soft decisions: full SOFT_DECISION_WIDTH bits represent confidence + -- Most positive value = strong '1', most negative = strong '0' + input_buffer_g1 : IN std_logic_vector(ENCODED_BYTES*4-1 DOWNTO 0); + input_buffer_g2 : IN std_logic_vector(ENCODED_BYTES*4-1 DOWNTO 0); + + -- Output buffer (decoded bits, MSB first) + output_buffer : OUT std_logic_vector(PAYLOAD_BYTES*8-1 DOWNTO 0); + + -- Debug/monitoring + path_metric_min : OUT std_logic_vector(METRIC_WIDTH-1 DOWNTO 0); + path_metric_max : OUT std_logic_vector(METRIC_WIDTH-1 DOWNTO 0) + ); +END ENTITY viterbi_decoder_k7; + +ARCHITECTURE rtl OF viterbi_decoder_k7 IS + + CONSTANT NUM_STATES : NATURAL := 64; -- 2^(K-1) states + CONSTANT TRACEBACK_LENGTH : NATURAL := TRACEBACK_DEPTH; + + -- State machine + TYPE state_t IS (IDLE, INIT_METRICS, DECODE_BITS, TRACEBACK, COMPLETE); + SIGNAL state : state_t := IDLE; + + -- Path metrics: one metric per state (track cumulative "cost" to reach each state) + TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF signed(METRIC_WIDTH-1 DOWNTO 0); + SIGNAL path_metrics_curr : metric_array_t := (OTHERS => (OTHERS => '0')); + SIGNAL path_metrics_next : metric_array_t := (OTHERS => (OTHERS => '0')); + + -- Survivor path memory: register-exchange method + -- Each state stores its best path history + TYPE path_history_t IS ARRAY(0 TO TRACEBACK_LENGTH-1) OF std_logic; + TYPE survivor_memory_t IS ARRAY(0 TO NUM_STATES-1) OF path_history_t; + SIGNAL survivor_paths_curr : survivor_memory_t; + SIGNAL survivor_paths_next : survivor_memory_t; + + -- Branch metrics: cost to take each transition + SIGNAL branch_metric_00 : signed(METRIC_WIDTH-1 DOWNTO 0); -- Output = 00 + SIGNAL branch_metric_01 : signed(METRIC_WIDTH-1 DOWNTO 0); -- Output = 01 + SIGNAL branch_metric_10 : signed(METRIC_WIDTH-1 DOWNTO 0); -- Output = 10 + SIGNAL branch_metric_11 : signed(METRIC_WIDTH-1 DOWNTO 0); -- Output = 11 + + -- Bit processing + SIGNAL bit_index : NATURAL RANGE 0 TO ENCODED_BYTES*4; + SIGNAL output_bit_index : NATURAL RANGE 0 TO PAYLOAD_BYTES*8; + + -- Current received symbols (soft decisions) + SIGNAL rx_g1 : signed(SOFT_DECISION_WIDTH-1 DOWNTO 0); + SIGNAL rx_g2 : signed(SOFT_DECISION_WIDTH-1 DOWNTO 0); + + -- Trellis butterfly outputs (expected G1, G2 for each input bit) + TYPE output_lut_t IS ARRAY(0 TO NUM_STATES-1, 0 TO 1) OF std_logic_vector(1 DOWNTO 0); + SIGNAL expected_outputs : output_lut_t; + + -- Output buffer working copy + SIGNAL out_buf : std_logic_vector(PAYLOAD_BYTES*8-1 DOWNTO 0); + + -- Best path tracking for traceback + SIGNAL best_state : NATURAL RANGE 0 TO NUM_STATES-1; + SIGNAL traceback_bit : NATURAL RANGE 0 TO TRACEBACK_LENGTH-1; + + -------------------------------------------------------------------------------------------- + -- Precompute expected outputs for each state transition + -- This is the trellis structure for K=7, rate 1/2 code + -------------------------------------------------------------------------------------------- + FUNCTION compute_expected_output( + current_state : NATURAL; + input_bit : std_logic + ) RETURN std_logic_vector IS + VARIABLE full_state : std_logic_vector(6 DOWNTO 0); + VARIABLE g1, g2 : std_logic; + CONSTANT G1_POLY : std_logic_vector(6 DOWNTO 0) := "1111001"; + CONSTANT G2_POLY : std_logic_vector(6 DOWNTO 0) := "1011011"; + BEGIN + -- Construct full state (input bit + 6 state bits) + full_state := input_bit & std_logic_vector(to_unsigned(current_state, 6)); + + -- Compute G1 output + g1 := '0'; + FOR i IN 0 TO 6 LOOP + IF G1_POLY(i) = '1' THEN + g1 := g1 XOR full_state(6-i); + END IF; + END LOOP; + + -- Compute G2 output + g2 := '0'; + FOR i IN 0 TO 6 LOOP + IF G2_POLY(i) = '1' THEN + g2 := g2 XOR full_state(6-i); + END IF; + END LOOP; + + RETURN g1 & g2; + END FUNCTION; + +BEGIN + + -------------------------------------------------------------------------------------------- + -- Initialize expected output LUT (done once at elaboration time) + -------------------------------------------------------------------------------------------- + gen_lut: PROCESS + BEGIN + FOR s IN 0 TO NUM_STATES-1 LOOP + expected_outputs(s, 0) <= compute_expected_output(s, '0'); + expected_outputs(s, 1) <= compute_expected_output(s, '1'); + END LOOP; + WAIT; -- Static initialization + END PROCESS; + + -------------------------------------------------------------------------------------------- + -- Branch Metric Computation + -- For soft decisions: Euclidean distance between received and expected + -- For hard decisions: Hamming distance + -------------------------------------------------------------------------------------------- + PROCESS(rx_g1, rx_g2) + VARIABLE diff_g1, diff_g2 : signed(SOFT_DECISION_WIDTH DOWNTO 0); + VARIABLE metric : signed(METRIC_WIDTH-1 DOWNTO 0); + BEGIN + -- Expected output 00 (both symbols are '0' = most negative value) + diff_g1 := resize(rx_g1, SOFT_DECISION_WIDTH+1) + + to_signed(2**(SOFT_DECISION_WIDTH-1), SOFT_DECISION_WIDTH+1); + diff_g2 := resize(rx_g2, SOFT_DECISION_WIDTH+1) + + to_signed(2**(SOFT_DECISION_WIDTH-1), SOFT_DECISION_WIDTH+1); + branch_metric_00 <= resize(diff_g1*diff_g1 + diff_g2*diff_g2, METRIC_WIDTH); + + -- Expected output 01 (g1='0', g2='1') + diff_g1 := resize(rx_g1, SOFT_DECISION_WIDTH+1) + + to_signed(2**(SOFT_DECISION_WIDTH-1), SOFT_DECISION_WIDTH+1); + diff_g2 := resize(rx_g2, SOFT_DECISION_WIDTH+1) - + to_signed(2**(SOFT_DECISION_WIDTH-1)-1, SOFT_DECISION_WIDTH+1); + branch_metric_01 <= resize(diff_g1*diff_g1 + diff_g2*diff_g2, METRIC_WIDTH); + + -- Expected output 10 + diff_g1 := resize(rx_g1, SOFT_DECISION_WIDTH+1) - + to_signed(2**(SOFT_DECISION_WIDTH-1)-1, SOFT_DECISION_WIDTH+1); + diff_g2 := resize(rx_g2, SOFT_DECISION_WIDTH+1) + + to_signed(2**(SOFT_DECISION_WIDTH-1), SOFT_DECISION_WIDTH+1); + branch_metric_10 <= resize(diff_g1*diff_g1 + diff_g2*diff_g2, METRIC_WIDTH); + + -- Expected output 11 + diff_g1 := resize(rx_g1, SOFT_DECISION_WIDTH+1) - + to_signed(2**(SOFT_DECISION_WIDTH-1)-1, SOFT_DECISION_WIDTH+1); + diff_g2 := resize(rx_g2, SOFT_DECISION_WIDTH+1) - + to_signed(2**(SOFT_DECISION_WIDTH-1)-1, SOFT_DECISION_WIDTH+1); + branch_metric_11 <= resize(diff_g1*diff_g1 + diff_g2*diff_g2, METRIC_WIDTH); + END PROCESS; + + -------------------------------------------------------------------------------------------- + -- Main Viterbi Decoder State Machine + -------------------------------------------------------------------------------------------- + PROCESS(clk, aresetn) + VARIABLE prev_state_0, prev_state_1 : NATURAL RANGE 0 TO NUM_STATES-1; + VARIABLE metric_0, metric_1 : signed(METRIC_WIDTH-1 DOWNTO 0); + VARIABLE input_bit_0, input_bit_1 : std_logic; + VARIABLE expected_out_0, expected_out_1 : std_logic_vector(1 DOWNTO 0); + VARIABLE branch_met_0, branch_met_1 : signed(METRIC_WIDTH-1 DOWNTO 0); + VARIABLE min_metric, max_metric : signed(METRIC_WIDTH-1 DOWNTO 0); + BEGIN + IF aresetn = '0' THEN + state <= IDLE; + busy <= '0'; + done <= '0'; + bit_index <= 0; + output_bit_index <= 0; + path_metrics_curr <= (OTHERS => (OTHERS => '0')); + + ELSIF rising_edge(clk) THEN + done <= '0'; -- Pulse signal + + CASE state IS + + WHEN IDLE => + busy <= '0'; + IF start = '1' THEN + state <= INIT_METRICS; + busy <= '1'; + bit_index <= 0; + output_bit_index <= 0; + END IF; + + WHEN INIT_METRICS => + -- Initialize: state 0 has metric 0, all others have large metric + FOR i IN 0 TO NUM_STATES-1 LOOP + IF i = 0 THEN + path_metrics_curr(i) <= (OTHERS => '0'); + ELSE + path_metrics_curr(i) <= to_signed(2**(METRIC_WIDTH-2), METRIC_WIDTH); + END IF; + -- Clear survivor paths + FOR j IN 0 TO TRACEBACK_LENGTH-1 LOOP + survivor_paths_curr(i)(j) <= '0'; + END LOOP; + END LOOP; + state <= DECODE_BITS; + + WHEN DECODE_BITS => + IF bit_index < (PAYLOAD_BYTES*8 + 6)*2 THEN -- Include 6 flush bits + -- Get received soft symbols + rx_g1 <= signed(input_buffer_g1( + ENCODED_BYTES*4-1 - bit_index*SOFT_DECISION_WIDTH DOWNTO + ENCODED_BYTES*4 - (bit_index+1)*SOFT_DECISION_WIDTH)); + rx_g2 <= signed(input_buffer_g2( + ENCODED_BYTES*4-1 - bit_index*SOFT_DECISION_WIDTH DOWNTO + ENCODED_BYTES*4 - (bit_index+1)*SOFT_DECISION_WIDTH)); + + -- ACS (Add-Compare-Select) for all states + FOR s IN 0 TO NUM_STATES-1 LOOP + -- Each state can be reached from two previous states + -- Previous state that led here with input bit = 0 + prev_state_0 := (s * 2) MOD NUM_STATES; + -- Previous state that led here with input bit = 1 + prev_state_1 := ((s * 2) + 1) MOD NUM_STATES; + + -- Get expected outputs for these transitions + expected_out_0 := expected_outputs(prev_state_0, 0); + expected_out_1 := expected_outputs(prev_state_1, 1); + + -- Branch metrics + CASE expected_out_0 IS + WHEN "00" => branch_met_0 := branch_metric_00; + WHEN "01" => branch_met_0 := branch_metric_01; + WHEN "10" => branch_met_0 := branch_metric_10; + WHEN "11" => branch_met_0 := branch_metric_11; + WHEN OTHERS => branch_met_0 := (OTHERS => '0'); + END CASE; + + CASE expected_out_1 IS + WHEN "00" => branch_met_1 := branch_metric_00; + WHEN "01" => branch_met_1 := branch_metric_01; + WHEN "10" => branch_met_1 := branch_metric_10; + WHEN "11" => branch_met_1 := branch_metric_11; + WHEN OTHERS => branch_met_1 := (OTHERS => '0'); + END CASE; + + -- Add-Compare-Select + metric_0 := path_metrics_curr(prev_state_0) + branch_met_0; + metric_1 := path_metrics_curr(prev_state_1) + branch_met_1; + + IF metric_0 < metric_1 THEN + path_metrics_next(s) <= metric_0; + input_bit_0 := '0'; + -- Shift survivor path and prepend decision + FOR j IN TRACEBACK_LENGTH-1 DOWNTO 1 LOOP + survivor_paths_next(s)(j) <= survivor_paths_curr(prev_state_0)(j-1); + END LOOP; + survivor_paths_next(s)(0) <= input_bit_0; + ELSE + path_metrics_next(s) <= metric_1; + input_bit_1 := '1'; + FOR j IN TRACEBACK_LENGTH-1 DOWNTO 1 LOOP + survivor_paths_next(s)(j) <= survivor_paths_curr(prev_state_1)(j-1); + END LOOP; + survivor_paths_next(s)(0) <= input_bit_1; + END IF; + END LOOP; + + -- Update current metrics + path_metrics_curr <= path_metrics_next; + survivor_paths_curr <= survivor_paths_next; + + bit_index <= bit_index + 2; -- Processed 2 symbols + ELSE + state <= TRACEBACK; + traceback_bit <= 0; + + -- Find best ending state (should be state 0 due to flush bits) + min_metric := path_metrics_curr(0); + best_state <= 0; + FOR i IN 1 TO NUM_STATES-1 LOOP + IF path_metrics_curr(i) < min_metric THEN + min_metric := path_metrics_curr(i); + best_state <= i; + END IF; + END LOOP; + END IF; + + WHEN TRACEBACK => + -- Extract decoded bits from survivor path of best state + IF traceback_bit < PAYLOAD_BYTES*8 THEN + out_buf(PAYLOAD_BYTES*8 - 1 - traceback_bit) <= + survivor_paths_curr(best_state)(TRACEBACK_LENGTH - 1 - traceback_bit); + traceback_bit <= traceback_bit + 1; + ELSE + state <= COMPLETE; + END IF; + + WHEN COMPLETE => + done <= '1'; + busy <= '0'; + state <= IDLE; + + END CASE; + END IF; + END PROCESS; + + -- Output assignment + output_buffer <= out_buf; + + -- Debug outputs + PROCESS(path_metrics_curr) + VARIABLE min_val, max_val : signed(METRIC_WIDTH-1 DOWNTO 0); + BEGIN + min_val := path_metrics_curr(0); + max_val := path_metrics_curr(0); + FOR i IN 1 TO NUM_STATES-1 LOOP + IF path_metrics_curr(i) < min_val THEN + min_val := path_metrics_curr(i); + END IF; + IF path_metrics_curr(i) > max_val THEN + max_val := path_metrics_curr(i); + END IF; + END LOOP; + path_metric_min <= std_logic_vector(min_val); + path_metric_max <= std_logic_vector(max_val); + END PROCESS; + +END ARCHITECTURE rtl; diff --git a/src/viterbi_decoder_k7_simple.vhd b/src/viterbi_decoder_k7_simple.vhd new file mode 100644 index 0000000..533e7db --- /dev/null +++ b/src/viterbi_decoder_k7_simple.vhd @@ -0,0 +1,251 @@ +------------------------------------------------------------------------------------------------------ +-- FIXED Viterbi Decoder for K=7 Code (NASA Voyager) +------------------------------------------------------------------------------------------------------ +-- Corrected Issues: +-- 1. MSB-first bit indexing to match encoder output format +-- 2. Traceback now correctly outputs input bits (LSB of state) not decision bits +------------------------------------------------------------------------------------------------------ + +LIBRARY ieee; +USE ieee.std_logic_1164.ALL; +USE ieee.numeric_std.ALL; + +ENTITY viterbi_decoder_k7_simple IS + GENERIC ( + PAYLOAD_BITS : NATURAL := 134*8; -- 1072 bits + ENCODED_BITS : NATURAL := 268*8; -- 2144 bits + TRACEBACK_DEPTH : NATURAL := 35 -- 5*K recommended + ); + PORT ( + clk : IN std_logic; + aresetn : IN std_logic; + + start : IN std_logic; + busy : OUT std_logic; + done : OUT std_logic; + + -- Hard decision inputs (g1 and g2 bits) + input_bits_g1 : IN std_logic_vector(ENCODED_BITS-1 DOWNTO 0); + input_bits_g2 : IN std_logic_vector(ENCODED_BITS-1 DOWNTO 0); + + output_bits : OUT std_logic_vector(PAYLOAD_BITS-1 DOWNTO 0) + ); +END ENTITY viterbi_decoder_k7_simple; + +ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS + + CONSTANT NUM_STATES : INTEGER := 64; + CONSTANT METRIC_WIDTH : INTEGER := 12; + CONSTANT INF_METRIC : INTEGER := 4095; + + TYPE state_t IS (IDLE, INITIALIZE, ACS_COMPUTE, TRACEBACK, COMPLETE); + SIGNAL state : state_t := IDLE; + + -- Path metrics arrays are now VARIABLES in the process + TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF INTEGER RANGE 0 TO INF_METRIC; + + -- Decision memory: stores which previous state was selected (MSB bit) + TYPE decision_array_t IS ARRAY(0 TO ENCODED_BITS/2) OF std_logic_vector(NUM_STATES-1 DOWNTO 0); + SIGNAL decisions : decision_array_t; + + -- Force synthesis to use BRAM + ATTRIBUTE ram_style : STRING; + ATTRIBUTE ram_style OF decisions : SIGNAL IS "block"; + + -- Counters + SIGNAL time_step : INTEGER RANGE 0 TO ENCODED_BITS/2 + 1; + SIGNAL tb_step : INTEGER RANGE -1 TO ENCODED_BITS/2; + SIGNAL output_idx : INTEGER RANGE 0 TO PAYLOAD_BITS; + + -- Current state during traceback + SIGNAL tb_state : INTEGER RANGE 0 TO NUM_STATES-1; + + -- Output buffer + SIGNAL out_buf : std_logic_vector(PAYLOAD_BITS-1 DOWNTO 0); + + -------------------------------------------------------------------------------------------- + -- Trellis functions + -------------------------------------------------------------------------------------------- + FUNCTION next_state(curr_state : INTEGER; input_bit : std_logic) RETURN INTEGER IS + VARIABLE shift_reg : std_logic_vector(5 DOWNTO 0); + BEGIN + shift_reg := std_logic_vector(to_unsigned(curr_state, 6)); + RETURN to_integer(unsigned(input_bit & shift_reg(5 DOWNTO 1))); + END FUNCTION; + + FUNCTION compute_output(curr_state : INTEGER; input_bit : std_logic) RETURN std_logic_vector IS + CONSTANT G1_POLY : std_logic_vector(6 DOWNTO 0) := "1111001"; + CONSTANT G2_POLY : std_logic_vector(6 DOWNTO 0) := "1011011"; + VARIABLE full_state : std_logic_vector(6 DOWNTO 0); + VARIABLE g1, g2 : std_logic; + BEGIN + full_state := input_bit & std_logic_vector(to_unsigned(curr_state, 6)); + + g1 := '0'; + FOR i IN 0 TO 6 LOOP + IF G1_POLY(i) = '1' THEN + g1 := g1 XOR full_state(6-i); + END IF; + END LOOP; + + g2 := '0'; + FOR i IN 0 TO 6 LOOP + IF G2_POLY(i) = '1' THEN + g2 := g2 XOR full_state(6-i); + END IF; + END LOOP; + + RETURN g1 & g2; + END FUNCTION; + + FUNCTION hamming_distance(a : std_logic_vector; b : std_logic_vector) RETURN INTEGER IS + VARIABLE dist : INTEGER := 0; + BEGIN + FOR i IN a'RANGE LOOP + IF a(i) /= b(i) THEN + dist := dist + 1; + END IF; + END LOOP; + RETURN dist; + END FUNCTION; + +BEGIN + + PROCESS(clk, aresetn) + VARIABLE received_symbol : std_logic_vector(1 DOWNTO 0); + VARIABLE expected_symbol : std_logic_vector(1 DOWNTO 0); + VARIABLE branch_metric : INTEGER; + VARIABLE new_metric : INTEGER; + VARIABLE prev_state_for_0 : INTEGER; + VARIABLE prev_state_for_1 : INTEGER; + VARIABLE metric_via_0 : INTEGER; + VARIABLE metric_via_1 : INTEGER; + VARIABLE min_metric : INTEGER; + VARIABLE best_state : INTEGER; + VARIABLE input_bit_used : INTEGER; + + -- **FIX: Use VARIABLES for metrics, not SIGNALS!** + VARIABLE metrics_old : metric_array_t; + VARIABLE metrics_new : metric_array_t; + BEGIN + IF aresetn = '0' THEN + state <= IDLE; + busy <= '0'; + done <= '0'; + time_step <= 0; + + ELSIF rising_edge(clk) THEN + done <= '0'; + + CASE state IS + + WHEN IDLE => + busy <= '0'; + IF start = '1' THEN + state <= INITIALIZE; + busy <= '1'; + time_step <= 0; + END IF; + + WHEN INITIALIZE => + -- Start with state 0 having metric 0, all others infinity + FOR i IN 0 TO NUM_STATES-1 LOOP + IF i = 0 THEN + metrics_old(i) := 0; + ELSE + metrics_old(i) := INF_METRIC; + END IF; + END LOOP; + state <= ACS_COMPUTE; + + +WHEN ACS_COMPUTE => + IF time_step < ENCODED_BITS/2 THEN + -- **FIX #1: Read bits in order starting from index 0** + -- Frame decoder packs: input_bits_g1(0)=first_g1, input_bits_g2(0)=first_g2 + -- So we read sequentially from index 0 up + received_symbol := input_bits_g1(time_step) & input_bits_g2(time_step); + + -- For each current state, find best path from two possible previous states + FOR curr_st IN 0 TO NUM_STATES-1 LOOP + -- Two prev states can lead here + prev_state_for_0 := curr_st / 2; -- Previous state with MSB=0 + prev_state_for_1 := (curr_st / 2) + 32; -- Previous state with MSB=1 + + -- The input bit that created curr_st is its LSB + input_bit_used := curr_st MOD 2; + + -- Metric via path with previous MSB=0 + expected_symbol := compute_output(prev_state_for_0, std_logic(to_unsigned(input_bit_used, 1)(0))); + branch_metric := hamming_distance(received_symbol, expected_symbol); + metric_via_0 := metrics_old(prev_state_for_0) + branch_metric; + + -- Metric via path with previous MSB=1 + expected_symbol := compute_output(prev_state_for_1, std_logic(to_unsigned(input_bit_used, 1)(0))); + branch_metric := hamming_distance(received_symbol, expected_symbol); + metric_via_1 := metrics_old(prev_state_for_1) + branch_metric; + + -- Select better path and store decision + IF metric_via_0 <= metric_via_1 THEN + metrics_new(curr_st) := metric_via_0; -- Changed to := + decisions(time_step)(curr_st) <= '0'; -- Came from prev_state_for_0 + ELSE + metrics_new(curr_st) := metric_via_1; -- Changed to := + decisions(time_step)(curr_st) <= '1'; -- Came from prev_state_for_1 + END IF; + END LOOP; + + -- Swap buffers (now happens immediately with variables!) + metrics_old := metrics_new; + time_step <= time_step + 1; + + ELSE + -- ACS complete, prepare for traceback + -- Find best final state (should be state 0 after tail bits) + min_metric := metrics_old(0); + best_state := 0; + FOR i IN 1 TO NUM_STATES-1 LOOP + IF metrics_old(i) < min_metric THEN + min_metric := metrics_old(i); + best_state := i; + END IF; + END LOOP; + + tb_state <= best_state; + tb_step <= time_step - 1; + output_idx <= 0; + state <= TRACEBACK; + END IF; + + +WHEN TRACEBACK => + IF tb_step >= 0 THEN + -- Output the decoded input bit (LSB of current state) + -- tb_step counts DOWN from last to first, giving us the natural index + out_buf(tb_step) <= std_logic(to_unsigned(tb_state MOD 2, 1)(0)); + + -- Move to previous state based on decision + IF decisions(tb_step)(tb_state) = '0' THEN + tb_state <= tb_state / 2; -- Previous state had MSB=0 + ELSE + tb_state <= (tb_state / 2) + 32; -- Previous state had MSB=1 + END IF; + + tb_step <= tb_step - 1; + ELSE + state <= COMPLETE; + END IF; + + + WHEN COMPLETE => + done <= '1'; + busy <= '0'; + state <= IDLE; + + END CASE; + END IF; + END PROCESS; + + output_bits <= out_buf; + +END ARCHITECTURE rtl; From 8ba0705263e0ce9b458b2cb911dcfe618edfba41 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 20 Nov 2025 14:29:21 -0800 Subject: [PATCH 41/60] hard decision Viterbit decoder installed and input data equals output data to modem. Randomization, FEC, Interleaving all working as intended. --- src/axis_async_fifo.vhd | 76 +++++--- src/ov_frame_decoder.vhd | 259 +++++++++++++------------ src/ov_frame_encoder.vhd | 4 +- src/viterbi_decoder_k7_simple.vhd | 302 ++++++++++++++++-------------- 4 files changed, 339 insertions(+), 302 deletions(-) diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 99fbdb3..215a0cf 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -1,8 +1,10 @@ ------------------------------------------------------------------------------------------------------ -- AXIS-Compliant Asynchronous FIFO ------------------------------------------------------------------------------------------------------ --- FIX: Added safety margin to empty detection to account for 2-cycle synchronization lag --- This prevents reading past actual data and hitting stale tlast markers +-- FIX v3: Proper three-state handling +-- State A: Becoming valid (empty→non-empty): Present first byte, assert tvalid +-- State B: Handshake completes (tvalid='1', tready='1'): Advance pointer, present next byte +-- State C: Valid but not consumed (tvalid='1', tready='0'): HOLD STABLE ------------------------------------------------------------------------------------------------------ -- SIGNAL INITIALIZATION PRACTICES: -- Per FPGA best practices, signals are initialized via reset blocks in their respective clock @@ -41,9 +43,6 @@ ENTITY axis_async_fifo IS m_axis_tready : IN std_logic; m_axis_tlast : OUT std_logic; - -- Control signals - --prog_packet_size: IN std_logic_vector... - -- Status signals prog_full : OUT std_logic; prog_empty : OUT std_logic; @@ -193,12 +192,16 @@ BEGIN END PROCESS write_proc; ------------------------------------------------------------------------------ - -- Read Clock Domain - WITH SYNC LAG FIX + -- Read Clock Domain - CORRECTED THREE-STATE LOGIC + ------------------------------------------------------------------------------ + -- State A: Becoming valid (tvalid_int='0' → '1'): Present first byte + -- State B: Handshake completes (tvalid='1', tready='1'): Advance, present next + -- State C: Valid but stalled (tvalid='1', tready='0'): HOLD STABLE ------------------------------------------------------------------------------ read_proc: PROCESS(rd_aclk) VARIABLE rd_ptr_bin_next : std_logic_vector(ADDR_WIDTH DOWNTO 0); VARIABLE wr_ptr_bin_sync : std_logic_vector(ADDR_WIDTH DOWNTO 0); - VARIABLE empty_next : std_logic; + VARIABLE empty_current : std_logic; BEGIN IF rising_edge(rd_aclk) THEN IF rd_aresetn = '0' THEN @@ -216,44 +219,61 @@ BEGIN wr_ptr_gray_sync2 <= wr_ptr_gray_sync1; wr_ptr_bin_sync := gray_to_bin(wr_ptr_gray_sync2); - -- Calculate next empty status based on CURRENT pointers + -- Check if FIFO is currently empty IF wr_ptr_bin_sync = rd_ptr_bin THEN - empty_next := '1'; + empty_current := '1'; ELSE - empty_next := '0'; + empty_current := '0'; END IF; - -- Present data when not empty - -- This sets up tdata, tlast, and tvalid for the CURRENT cycle - IF empty_next = '0' THEN + ---------------------------------------------------------------------- + -- THREE STATE LOGIC + ---------------------------------------------------------------------- + + -- STATE A: Becoming valid (was invalid, now have data) + -- Action: Present first byte, assert tvalid, DO NOT advance pointer + IF tvalid_int = '0' AND empty_current = '0' THEN m_axis_tdata <= ram_data(to_integer(unsigned(rd_ptr_bin(ADDR_WIDTH-1 DOWNTO 0)))); m_axis_tlast <= ram_last(to_integer(unsigned(rd_ptr_bin(ADDR_WIDTH-1 DOWNTO 0)))); tvalid_int <= '1'; - ELSE - -- When empty, deassert tvalid and clear tlast - -- (tdata is don't care per AXI-Stream spec, but we clear it for cleanliness) - tvalid_int <= '0'; - m_axis_tlast <= '0'; - m_axis_tdata <= (OTHERS => '0'); - END IF; + empty_int <= '0'; + -- rd_ptr_bin stays same! This is the first presentation - -- AXIS read handshake - advance pointer only when: - -- 1. We're presenting valid data (empty_next = '0') - -- 2. Downstream is ready (m_axis_tready = '1') - IF empty_next = '0' AND m_axis_tready = '1' THEN + -- STATE B: Handshake completes (valid and ready) + -- Action: Advance pointer, present next byte OR deassert tvalid + ELSIF tvalid_int = '1' AND m_axis_tready = '1' THEN rd_ptr_bin_next := std_logic_vector(unsigned(rd_ptr_bin) + 1); rd_ptr_bin <= rd_ptr_bin_next; rd_ptr_gray <= bin_to_gray(rd_ptr_bin_next); - -- Update empty status based on where we'll be AFTER this read + -- Check if we'll be empty after this read IF wr_ptr_bin_sync = rd_ptr_bin_next THEN + -- Going empty empty_int <= '1'; + tvalid_int <= '0'; + m_axis_tlast <= '0'; + m_axis_tdata <= (OTHERS => '0'); ELSE + -- More data available - present next byte empty_int <= '0'; + tvalid_int <= '1'; + m_axis_tdata <= ram_data(to_integer(unsigned(rd_ptr_bin_next(ADDR_WIDTH-1 DOWNTO 0)))); + m_axis_tlast <= ram_last(to_integer(unsigned(rd_ptr_bin_next(ADDR_WIDTH-1 DOWNTO 0)))); END IF; + + -- STATE C: Valid but NOT ready (tvalid='1', tready='0') + -- Action: HOLD EVERYTHING STABLE - no changes to tdata, tlast, tvalid, rd_ptr + ELSIF tvalid_int = '1' AND m_axis_tready = '0' THEN + -- Explicitly do nothing - all signals hold their values + -- This is the critical fix: maintain protocol compliance + empty_int <= '0'; -- We know we're not empty if tvalid='1' + + -- All other cases: remain invalid ELSE - -- No advancement - empty_int <= empty_next; + empty_int <= '1'; + tvalid_int <= '0'; + m_axis_tlast <= '0'; + m_axis_tdata <= (OTHERS => '0'); END IF; -- Programmable empty @@ -274,8 +294,6 @@ BEGIN BEGIN IF rising_edge(status_aclk) THEN IF status_aresetn = '0' THEN - --prog_empty <= '0'; - --prog_full <= '0'; fifo_overflow <= '0'; fifo_underflow <= '0'; status_ack <= '0'; diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd index 875e67f..9d60f86 100644 --- a/src/ov_frame_decoder.vhd +++ b/src/ov_frame_decoder.vhd @@ -45,8 +45,11 @@ -- 4. Derandomizes (XOR with same fixed sequence) -- 5. Outputs 134 bytes of payload via AXI-Stream -- --- BUGFIX (2025-11-16): Fixed first-byte-lost issue in IDLE→COLLECT transition --- Now stores first byte immediately when transitioning states +-- CIRCULAR BUFFER FIX (2025-11-20): Matching encoder's proven strategy +-- - Collect ALL incoming bytes into circular buffer +-- - When tlast arrives, count back 268 bytes +-- - This handles FIFO timing issues naturally +-- - Never try to time the "first" byte arrival -- ------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------ @@ -86,17 +89,24 @@ END ENTITY ov_frame_decoder; ARCHITECTURE rtl OF ov_frame_decoder IS - -- State machine - TYPE state_t IS (IDLE, COLLECT, DEINTERLEAVE, PREP_FEC_DECODE, FEC_DECODE, DERANDOMIZE, OUTPUT); + -- State machine - ADDED EXTRACT STATE + TYPE state_t IS (IDLE, COLLECT, EXTRACT, DEINTERLEAVE, PREP_FEC_DECODE, FEC_DECODE, DERANDOMIZE, OUTPUT); SIGNAL state : state_t := IDLE; + -- Circular collection buffer (2x encoded size for safety) + CONSTANT COLLECT_SIZE : NATURAL := 512; + TYPE collect_buffer_t IS ARRAY(0 TO COLLECT_SIZE-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + SIGNAL collect_buffer : collect_buffer_t; + SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE-1; + -- Buffer types TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + TYPE encoded_byte_buffer_t IS ARRAY(0 TO ENCODED_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; -- Processing buffers - SIGNAL input_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' - SIGNAL deinterleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- Initialize to prevent 'U' + SIGNAL input_buffer : encoded_byte_buffer_t; -- 268 bytes extracted from circular buffer + SIGNAL deinterleaved_buffer : bit_buffer_t := (OTHERS => '0'); SIGNAL fec_decoded_buffer : byte_buffer_t; SIGNAL output_buffer : byte_buffer_t; @@ -139,9 +149,9 @@ ARCHITECTURE rtl OF ov_frame_decoder IS SIGNAL decoder_start : std_logic := '0'; SIGNAL decoder_busy : std_logic; SIGNAL decoder_done : std_logic; - SIGNAL decoder_input_g1 : std_logic_vector(2143 DOWNTO 0); -- 268*8 bits + SIGNAL decoder_input_g1 : std_logic_vector(2143 DOWNTO 0); SIGNAL decoder_input_g2 : std_logic_vector(2143 DOWNTO 0); - SIGNAL decoder_output_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 bits + SIGNAL decoder_output_buf : std_logic_vector(1071 DOWNTO 0); -- Deinterleaver address calculation (reverse of interleaver) FUNCTION deinterleave_address(addr : NATURAL) RETURN NATURAL IS @@ -160,8 +170,8 @@ BEGIN -- Viterbi Decoder Instantiation (Hard Decision) U_DECODER : ENTITY work.viterbi_decoder_k7_simple GENERIC MAP ( - PAYLOAD_BITS => PAYLOAD_BYTES * 8, -- 1072 bits - ENCODED_BITS => ENCODED_BYTES * 8, -- 2144 bits + PAYLOAD_BITS => PAYLOAD_BYTES * 8, + ENCODED_BITS => ENCODED_BYTES * 8, TRACEBACK_DEPTH => 35 ) PORT MAP ( @@ -182,9 +192,10 @@ BEGIN frames_decoded <= std_logic_vector(frame_count); - -- Main FSM + -- Main FSM with Circular Buffer Collection decoder_fsm : PROCESS(clk) - VARIABLE bit_0, bit_1 : std_logic; + VARIABLE extract_start : INTEGER; + VARIABLE extract_end : INTEGER; BEGIN IF rising_edge(clk) THEN IF aresetn = '0' THEN @@ -192,140 +203,126 @@ BEGIN byte_idx <= 0; bit_idx <= 0; out_idx <= 0; + collect_idx <= 0; frame_count <= (OTHERS => '0'); s_axis_tready <= '0'; m_tvalid_reg <= '0'; m_tlast_reg <= '0'; decoder_active <= '0'; - decoder_start <= '0'; -- Initialize FEC decoder control + decoder_start <= '0'; ELSE CASE state IS - -- IDLE: Wait for incoming data and capture first byte + -- IDLE: Ready to start collecting WHEN IDLE => decoder_active <= '0'; - s_axis_tready <= '1'; -- Ready to accept data - m_tvalid_reg <= '0'; -- Not outputting yet + s_axis_tready <= '0'; -- Keep tready LOW in IDLE + m_tvalid_reg <= '0'; + collect_idx <= 0; IF s_axis_tvalid = '1' THEN - -- *** FIX: Store the FIRST byte immediately! *** - input_buffer(0) <= s_axis_tdata(0); - input_buffer(1) <= s_axis_tdata(1); - input_buffer(2) <= s_axis_tdata(2); - input_buffer(3) <= s_axis_tdata(3); - input_buffer(4) <= s_axis_tdata(4); - input_buffer(5) <= s_axis_tdata(5); - input_buffer(6) <= s_axis_tdata(6); - input_buffer(7) <= s_axis_tdata(7); - - REPORT "DECODER: Stored FIRST byte at index 0, data=" & - INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & - " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); - - -- Check for edge case: single-byte frame (unlikely with ENCODED_BYTES=268) - IF s_axis_tlast = '1' AND ENCODED_BYTES = 1 THEN - REPORT "DECODER: Single-byte frame received"; - byte_idx <= 0; - bit_idx <= 0; - state <= DEINTERLEAVE; - s_axis_tready <= '0'; - ELSE - -- Normal case: transition to COLLECT for remaining bytes - byte_idx <= 1; -- Next byte will go to index 1 - bit_idx <= 0; - state <= COLLECT; - decoder_active <= '1'; - END IF; + state <= COLLECT; + s_axis_tready <= '1'; -- Set tready HIGH when entering COLLECT END IF; - -- COLLECT: Gather remaining bytes (1 through 267) + -- COLLECT: Continuously store ALL incoming bytes into circular buffer WHEN COLLECT => + s_axis_tready <= '1'; -- Maintain tready HIGH during collection + IF s_axis_tvalid = '1' THEN - -- Store incoming byte as 8 bits - input_buffer(byte_idx * 8 + 0) <= s_axis_tdata(0); - input_buffer(byte_idx * 8 + 1) <= s_axis_tdata(1); - input_buffer(byte_idx * 8 + 2) <= s_axis_tdata(2); - input_buffer(byte_idx * 8 + 3) <= s_axis_tdata(3); - input_buffer(byte_idx * 8 + 4) <= s_axis_tdata(4); - input_buffer(byte_idx * 8 + 5) <= s_axis_tdata(5); - input_buffer(byte_idx * 8 + 6) <= s_axis_tdata(6); - input_buffer(byte_idx * 8 + 7) <= s_axis_tdata(7); + -- Store byte at current circular buffer position + collect_buffer(collect_idx) <= s_axis_tdata; - -- Debug: Report first 5 received bytes - IF byte_idx < 5 THEN - REPORT "DECODER: Stored byte at byte_idx=" & INTEGER'IMAGE(byte_idx) & - " data=" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & + -- Debug: Report first few bytes + IF collect_idx < 5 THEN + REPORT "COLLECT: collect_idx=" & INTEGER'IMAGE(collect_idx) & + " data=0x" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); END IF; - byte_idx <= byte_idx + 1; - - -- Check for frame completion + -- Check for tlast IF s_axis_tlast = '1' THEN - REPORT "DECODER: Received tlast. Total bytes stored = " & - INTEGER'IMAGE(byte_idx + 1); - - -- Verify we got the expected number of bytes - IF byte_idx + 1 /= ENCODED_BYTES THEN - REPORT "DECODER: WARNING! Expected " & INTEGER'IMAGE(ENCODED_BYTES) & - " bytes but got " & INTEGER'IMAGE(byte_idx + 1) severity warning; - END IF; + REPORT "COLLECT: tlast at collect_idx=" & INTEGER'IMAGE(collect_idx); - byte_idx <= 0; - bit_idx <= 0; - state <= DEINTERLEAVE; + -- Move to EXTRACT state to count back 268 bytes s_axis_tready <= '0'; - - ELSIF byte_idx + 1 >= ENCODED_BYTES THEN - -- Stored all bytes but no tlast! This is an error condition - REPORT "DECODER: ERROR! Stored " & INTEGER'IMAGE(ENCODED_BYTES) & - " bytes but no tlast received" severity error; byte_idx <= 0; - state <= IDLE; - s_axis_tready <= '1'; + state <= EXTRACT; + ELSE + -- Advance circular buffer pointer (wrap around) + IF collect_idx = COLLECT_SIZE - 1 THEN + collect_idx <= 0; + ELSE + collect_idx <= collect_idx + 1; + END IF; + END IF; + END IF; + + -- EXTRACT: Count back ENCODED_BYTES from where tlast arrived + WHEN EXTRACT => + IF byte_idx < ENCODED_BYTES THEN + -- Calculate which byte in collect_buffer to read + -- If collect_idx = 267, we want bytes [0:267] + -- If collect_idx = 300, we want bytes [33:300] + extract_start := (collect_idx + 1) - ENCODED_BYTES; + extract_end := collect_idx; + + -- Copy byte from circular buffer (with modulo wraparound) + input_buffer(byte_idx) <= collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE); + + IF byte_idx < 5 THEN + REPORT "EXTRACT[" & INTEGER'IMAGE(byte_idx) & + "] from collect_buffer[" & + INTEGER'IMAGE((extract_start + byte_idx) MOD COLLECT_SIZE) & + "] = 0x" & + INTEGER'IMAGE(to_integer(unsigned(collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE)))); END IF; + + byte_idx <= byte_idx + 1; + ELSE + REPORT "EXTRACT complete, " & INTEGER'IMAGE(ENCODED_BYTES) & " bytes copied"; + byte_idx <= 0; + bit_idx <= 0; + state <= DEINTERLEAVE; + decoder_active <= '1'; END IF; -- DEINTERLEAVE: Reverse the row-column shuffle WHEN DEINTERLEAVE => IF bit_idx < ENCODED_BITS THEN - deinterleaved_buffer(deinterleave_address(bit_idx)) <= input_buffer(bit_idx); + -- Unpack input_buffer bytes to bits + deinterleaved_buffer(deinterleave_address(bit_idx)) <= + input_buffer(bit_idx / 8)(bit_idx MOD 8); bit_idx <= bit_idx + 1; ELSE REPORT "DEINTERLEAVE complete"; byte_idx <= 0; bit_idx <= 0; - state <= PREP_FEC_DECODE; -- Changed to go to prep state first + state <= PREP_FEC_DECODE; END IF; -- PREP_FEC_DECODE: Separate deinterleaved bits into G1 and G2 streams -WHEN PREP_FEC_DECODE => - -- **FIX: Pack bits in FORWARD order, not reversed!** - -- deinterleaved_buffer[0] = first g1, [1] = first g2, etc. - FOR i IN 0 TO ENCODED_BITS/2 - 1 LOOP - decoder_input_g1(i) <= deinterleaved_buffer(i*2); -- G1 bits: 0, 2, 4, ... - decoder_input_g2(i) <= deinterleaved_buffer(i*2 + 1); -- G2 bits: 1, 3, 5, ... - END LOOP; - decoder_start <= '1'; - state <= FEC_DECODE; - -WHEN FEC_DECODE => - decoder_start <= '0'; -- Clear start pulse - IF decoder_done = '1' THEN - -- Unpack decoded bits in FORWARD order - -- decoder_output_buf[0] = first bit, goes to byte 0 bit 7 - FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP - FOR j IN 0 TO 7 LOOP - fec_decoded_buffer(i)(7-j) <= decoder_output_buf(i*8 + j); - END LOOP; - END LOOP; - byte_idx <= 0; - state <= DERANDOMIZE; - END IF; - - + WHEN PREP_FEC_DECODE => + FOR i IN 0 TO ENCODED_BITS/2 - 1 LOOP + decoder_input_g1(i) <= deinterleaved_buffer(i*2); + decoder_input_g2(i) <= deinterleaved_buffer(i*2 + 1); + END LOOP; + decoder_start <= '1'; + state <= FEC_DECODE; + WHEN FEC_DECODE => + decoder_start <= '0'; + IF decoder_done = '1' THEN + -- Unpack decoded bits in FORWARD order + FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP + FOR j IN 0 TO 7 LOOP + fec_decoded_buffer(i)(7-j) <= decoder_output_buf(i*8 + j); + END LOOP; + END LOOP; + byte_idx <= 0; + state <= DERANDOMIZE; + END IF; -- DERANDOMIZE: XOR with same sequence (inverse operation) WHEN DERANDOMIZE => @@ -333,7 +330,6 @@ WHEN FEC_DECODE => output_buffer(byte_idx) <= fec_decoded_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); - -- Debug: Report first 5 derandomized bytes IF byte_idx < 5 THEN REPORT "DERANDOMIZE[" & INTEGER'IMAGE(byte_idx) & "] fec=" & INTEGER'IMAGE(to_integer(unsigned(fec_decoded_buffer(byte_idx)))) & @@ -348,34 +344,35 @@ WHEN FEC_DECODE => state <= OUTPUT; END IF; - -- OUTPUT: Send bytes to next stage + -- OUTPUT: Send bytes to next stage (FIXED AXI-Stream handshaking) WHEN OUTPUT => - IF m_axis_tready = '1' OR m_tvalid_reg = '0' THEN - IF out_idx < PAYLOAD_BYTES THEN - m_tdata_reg <= output_buffer(out_idx); - m_tvalid_reg <= '1'; - - -- Debug: Report first 5 output bytes - IF out_idx < 5 THEN - REPORT "DECODER OUTPUT byte " & INTEGER'IMAGE(out_idx) & " = " & - INTEGER'IMAGE(to_integer(unsigned(output_buffer(out_idx)))); - END IF; - - -- Set tlast on final byte - IF out_idx = PAYLOAD_BYTES - 1 THEN - m_tlast_reg <= '1'; - ELSE - m_tlast_reg <= '0'; - END IF; - - out_idx <= out_idx + 1; + IF out_idx < PAYLOAD_BYTES THEN + -- Present current data + m_tdata_reg <= output_buffer(out_idx); + m_tvalid_reg <= '1'; + + IF out_idx < 5 THEN + REPORT "DECODER OUTPUT byte " & INTEGER'IMAGE(out_idx) & " = " & + INTEGER'IMAGE(to_integer(unsigned(output_buffer(out_idx)))); + END IF; + + -- Set tlast on final byte + IF out_idx = PAYLOAD_BYTES - 1 THEN + m_tlast_reg <= '1'; ELSE - -- Frame complete - m_tvalid_reg <= '0'; m_tlast_reg <= '0'; - frame_count <= frame_count + 1; - state <= IDLE; END IF; + + -- Advance on handshake OR on first presentation (tvalid was 0) + IF m_axis_tready = '1' OR m_tvalid_reg = '0' THEN + out_idx <= out_idx + 1; + END IF; + ELSE + -- Frame complete + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + frame_count <= frame_count + 1; + state <= IDLE; END IF; END CASE; diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index cfe24fc..0870c0b 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -211,14 +211,14 @@ BEGIN -- IDLE: Wait for incoming data WHEN IDLE => encoder_active <= '0'; - s_axis_tready <= '0'; + s_axis_tready <= '0'; -- Keep LOW in IDLE m_tvalid_reg <= '0'; collect_idx <= 0; IF s_axis_tvalid = '1' THEN state <= COLLECT; encoder_active <= '1'; - s_axis_tready <= '1'; + -- tready set HIGH in COLLECT state, not here END IF; -- COLLECT: Gather ALL bytes into circular buffer until tlast diff --git a/src/viterbi_decoder_k7_simple.vhd b/src/viterbi_decoder_k7_simple.vhd index 533e7db..0a1c988 100644 --- a/src/viterbi_decoder_k7_simple.vhd +++ b/src/viterbi_decoder_k7_simple.vhd @@ -1,9 +1,11 @@ ------------------------------------------------------------------------------------------------------ --- FIXED Viterbi Decoder for K=7 Code (NASA Voyager) +-- BRAM-Optimized Viterbi Decoder - SIMPLIFIED TRACEBACK (2 cycles per step) ------------------------------------------------------------------------------------------------------ --- Corrected Issues: --- 1. MSB-first bit indexing to match encoder output format --- 2. Traceback now correctly outputs input bits (LSB of state) not decision bits +-- This version uses 2 clock cycles per traceback step for clarity and correctness: +-- Cycle 1: Fetch decision from BRAM +-- Cycle 2: Use decision, output bit, move to previous state +-- +-- This is slower but eliminates pipeline complexity bugs. ------------------------------------------------------------------------------------------------------ LIBRARY ieee; @@ -12,22 +14,18 @@ USE ieee.numeric_std.ALL; ENTITY viterbi_decoder_k7_simple IS GENERIC ( - PAYLOAD_BITS : NATURAL := 134*8; -- 1072 bits - ENCODED_BITS : NATURAL := 268*8; -- 2144 bits - TRACEBACK_DEPTH : NATURAL := 35 -- 5*K recommended + PAYLOAD_BITS : NATURAL := 134*8; + ENCODED_BITS : NATURAL := 268*8; + TRACEBACK_DEPTH : NATURAL := 35 ); PORT ( clk : IN std_logic; aresetn : IN std_logic; - start : IN std_logic; busy : OUT std_logic; done : OUT std_logic; - - -- Hard decision inputs (g1 and g2 bits) input_bits_g1 : IN std_logic_vector(ENCODED_BITS-1 DOWNTO 0); input_bits_g2 : IN std_logic_vector(ENCODED_BITS-1 DOWNTO 0); - output_bits : OUT std_logic_vector(PAYLOAD_BITS-1 DOWNTO 0) ); END ENTITY viterbi_decoder_k7_simple; @@ -37,43 +35,39 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS CONSTANT NUM_STATES : INTEGER := 64; CONSTANT METRIC_WIDTH : INTEGER := 12; CONSTANT INF_METRIC : INTEGER := 4095; + CONSTANT NUM_SYMBOLS : INTEGER := ENCODED_BITS/2; - TYPE state_t IS (IDLE, INITIALIZE, ACS_COMPUTE, TRACEBACK, COMPLETE); + TYPE state_t IS (IDLE, INITIALIZE, ACS_COMPUTE, FIND_BEST, + TB_FETCH, TB_USE, COMPLETE); SIGNAL state : state_t := IDLE; - -- Path metrics arrays are now VARIABLES in the process - TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF INTEGER RANGE 0 TO INF_METRIC; + TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF unsigned(METRIC_WIDTH-1 DOWNTO 0); + SIGNAL metrics_current : metric_array_t; + SIGNAL metrics_next : metric_array_t; + + CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; + TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; + SIGNAL decision_mem : decision_mem_t; - -- Decision memory: stores which previous state was selected (MSB bit) - TYPE decision_array_t IS ARRAY(0 TO ENCODED_BITS/2) OF std_logic_vector(NUM_STATES-1 DOWNTO 0); - SIGNAL decisions : decision_array_t; - - -- Force synthesis to use BRAM ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF decisions : SIGNAL IS "block"; + ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; - -- Counters - SIGNAL time_step : INTEGER RANGE 0 TO ENCODED_BITS/2 + 1; - SIGNAL tb_step : INTEGER RANGE -1 TO ENCODED_BITS/2; - SIGNAL output_idx : INTEGER RANGE 0 TO PAYLOAD_BITS; + SIGNAL dec_wr_en : std_logic; + SIGNAL dec_wr_addr : INTEGER RANGE 0 TO DECISION_DEPTH-1; + SIGNAL dec_wr_data : std_logic; + SIGNAL dec_rd_addr : INTEGER RANGE 0 TO DECISION_DEPTH-1; + SIGNAL dec_rd_data : std_logic; - -- Current state during traceback + SIGNAL time_step : INTEGER RANGE 0 TO NUM_SYMBOLS; + SIGNAL state_idx : INTEGER RANGE 0 TO NUM_STATES-1; + SIGNAL tb_time : INTEGER RANGE -1 TO NUM_SYMBOLS; SIGNAL tb_state : INTEGER RANGE 0 TO NUM_STATES-1; - -- Output buffer SIGNAL out_buf : std_logic_vector(PAYLOAD_BITS-1 DOWNTO 0); + SIGNAL rx_symbol : std_logic_vector(1 DOWNTO 0); - -------------------------------------------------------------------------------------------- - -- Trellis functions - -------------------------------------------------------------------------------------------- - FUNCTION next_state(curr_state : INTEGER; input_bit : std_logic) RETURN INTEGER IS - VARIABLE shift_reg : std_logic_vector(5 DOWNTO 0); - BEGIN - shift_reg := std_logic_vector(to_unsigned(curr_state, 6)); - RETURN to_integer(unsigned(input_bit & shift_reg(5 DOWNTO 1))); - END FUNCTION; - - FUNCTION compute_output(curr_state : INTEGER; input_bit : std_logic) RETURN std_logic_vector IS + FUNCTION compute_output(curr_state : INTEGER; input_bit : std_logic) + RETURN std_logic_vector IS CONSTANT G1_POLY : std_logic_vector(6 DOWNTO 0) := "1111001"; CONSTANT G2_POLY : std_logic_vector(6 DOWNTO 0) := "1011011"; VARIABLE full_state : std_logic_vector(6 DOWNTO 0); @@ -98,7 +92,7 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS RETURN g1 & g2; END FUNCTION; - FUNCTION hamming_distance(a : std_logic_vector; b : std_logic_vector) RETURN INTEGER IS + FUNCTION hamming_distance(a, b : std_logic_vector) RETURN INTEGER IS VARIABLE dist : INTEGER := 0; BEGIN FOR i IN a'RANGE LOOP @@ -111,31 +105,39 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS BEGIN + PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF dec_wr_en = '1' THEN + decision_mem(dec_wr_addr) <= dec_wr_data; + END IF; + END IF; + END PROCESS; + + PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + dec_rd_data <= decision_mem(dec_rd_addr); + END IF; + END PROCESS; + PROCESS(clk, aresetn) - VARIABLE received_symbol : std_logic_vector(1 DOWNTO 0); - VARIABLE expected_symbol : std_logic_vector(1 DOWNTO 0); - VARIABLE branch_metric : INTEGER; - VARIABLE new_metric : INTEGER; - VARIABLE prev_state_for_0 : INTEGER; - VARIABLE prev_state_for_1 : INTEGER; - VARIABLE metric_via_0 : INTEGER; - VARIABLE metric_via_1 : INTEGER; - VARIABLE min_metric : INTEGER; - VARIABLE best_state : INTEGER; - VARIABLE input_bit_used : INTEGER; - - -- **FIX: Use VARIABLES for metrics, not SIGNALS!** - VARIABLE metrics_old : metric_array_t; - VARIABLE metrics_new : metric_array_t; + VARIABLE prev_state_0, prev_state_1 : INTEGER RANGE 0 TO NUM_STATES-1; + VARIABLE input_bit : std_logic; + VARIABLE expected_0, expected_1 : std_logic_vector(1 DOWNTO 0); + VARIABLE metric_0, metric_1 : unsigned(METRIC_WIDTH-1 DOWNTO 0); + VARIABLE min_metric : unsigned(METRIC_WIDTH-1 DOWNTO 0); + VARIABLE best_state_var : INTEGER RANGE 0 TO NUM_STATES-1; BEGIN IF aresetn = '0' THEN state <= IDLE; busy <= '0'; done <= '0'; - time_step <= 0; + dec_wr_en <= '0'; ELSIF rising_edge(clk) THEN done <= '0'; + dec_wr_en <= '0'; CASE state IS @@ -144,98 +146,118 @@ BEGIN IF start = '1' THEN state <= INITIALIZE; busy <= '1'; - time_step <= 0; + state_idx <= 0; END IF; WHEN INITIALIZE => - -- Start with state 0 having metric 0, all others infinity - FOR i IN 0 TO NUM_STATES-1 LOOP - IF i = 0 THEN - metrics_old(i) := 0; + IF state_idx < NUM_STATES THEN + IF state_idx = 0 THEN + metrics_current(state_idx) <= (OTHERS => '0'); ELSE - metrics_old(i) := INF_METRIC; + metrics_current(state_idx) <= to_unsigned(INF_METRIC, METRIC_WIDTH); END IF; - END LOOP; - state <= ACS_COMPUTE; + state_idx <= state_idx + 1; + ELSE + state <= ACS_COMPUTE; + state_idx <= 0; + time_step <= 0; + END IF; - -WHEN ACS_COMPUTE => - IF time_step < ENCODED_BITS/2 THEN - -- **FIX #1: Read bits in order starting from index 0** - -- Frame decoder packs: input_bits_g1(0)=first_g1, input_bits_g2(0)=first_g2 - -- So we read sequentially from index 0 up - received_symbol := input_bits_g1(time_step) & input_bits_g2(time_step); - - -- For each current state, find best path from two possible previous states - FOR curr_st IN 0 TO NUM_STATES-1 LOOP - -- Two prev states can lead here - prev_state_for_0 := curr_st / 2; -- Previous state with MSB=0 - prev_state_for_1 := (curr_st / 2) + 32; -- Previous state with MSB=1 - - -- The input bit that created curr_st is its LSB - input_bit_used := curr_st MOD 2; - - -- Metric via path with previous MSB=0 - expected_symbol := compute_output(prev_state_for_0, std_logic(to_unsigned(input_bit_used, 1)(0))); - branch_metric := hamming_distance(received_symbol, expected_symbol); - metric_via_0 := metrics_old(prev_state_for_0) + branch_metric; - - -- Metric via path with previous MSB=1 - expected_symbol := compute_output(prev_state_for_1, std_logic(to_unsigned(input_bit_used, 1)(0))); - branch_metric := hamming_distance(received_symbol, expected_symbol); - metric_via_1 := metrics_old(prev_state_for_1) + branch_metric; - - -- Select better path and store decision - IF metric_via_0 <= metric_via_1 THEN - metrics_new(curr_st) := metric_via_0; -- Changed to := - decisions(time_step)(curr_st) <= '0'; -- Came from prev_state_for_0 - ELSE - metrics_new(curr_st) := metric_via_1; -- Changed to := - decisions(time_step)(curr_st) <= '1'; -- Came from prev_state_for_1 - END IF; - END LOOP; - - -- Swap buffers (now happens immediately with variables!) - metrics_old := metrics_new; - time_step <= time_step + 1; - - ELSE - -- ACS complete, prepare for traceback - -- Find best final state (should be state 0 after tail bits) - min_metric := metrics_old(0); - best_state := 0; - FOR i IN 1 TO NUM_STATES-1 LOOP - IF metrics_old(i) < min_metric THEN - min_metric := metrics_old(i); - best_state := i; - END IF; - END LOOP; - - tb_state <= best_state; - tb_step <= time_step - 1; - output_idx <= 0; - state <= TRACEBACK; - END IF; - - -WHEN TRACEBACK => - IF tb_step >= 0 THEN - -- Output the decoded input bit (LSB of current state) - -- tb_step counts DOWN from last to first, giving us the natural index - out_buf(tb_step) <= std_logic(to_unsigned(tb_state MOD 2, 1)(0)); - - -- Move to previous state based on decision - IF decisions(tb_step)(tb_state) = '0' THEN - tb_state <= tb_state / 2; -- Previous state had MSB=0 - ELSE - tb_state <= (tb_state / 2) + 32; -- Previous state had MSB=1 - END IF; - - tb_step <= tb_step - 1; - ELSE - state <= COMPLETE; - END IF; - + WHEN ACS_COMPUTE => + IF time_step < NUM_SYMBOLS THEN + IF state_idx = 0 THEN + rx_symbol <= input_bits_g1(time_step) & input_bits_g2(time_step); + END IF; + + IF state_idx < NUM_STATES THEN + prev_state_0 := state_idx / 2; + prev_state_1 := (state_idx / 2) + 32; + input_bit := std_logic(to_unsigned(state_idx MOD 2, 1)(0)); + + expected_0 := compute_output(prev_state_0, input_bit); + metric_0 := metrics_current(prev_state_0) + + to_unsigned(hamming_distance(rx_symbol, expected_0), METRIC_WIDTH); + + expected_1 := compute_output(prev_state_1, input_bit); + metric_1 := metrics_current(prev_state_1) + + to_unsigned(hamming_distance(rx_symbol, expected_1), METRIC_WIDTH); + + IF metric_0 <= metric_1 THEN + metrics_next(state_idx) <= metric_0; + dec_wr_data <= '0'; + ELSE + metrics_next(state_idx) <= metric_1; + dec_wr_data <= '1'; + END IF; + + dec_wr_addr <= time_step * NUM_STATES + state_idx; + dec_wr_en <= '1'; + state_idx <= state_idx + 1; + ELSE + metrics_current <= metrics_next; + state_idx <= 0; + time_step <= time_step + 1; + END IF; + ELSE + state <= FIND_BEST; + state_idx <= 0; + END IF; + + WHEN FIND_BEST => + IF state_idx = 0 THEN + min_metric := metrics_current(0); + best_state_var := 0; + state_idx <= 1; + ELSIF state_idx < NUM_STATES THEN + IF metrics_current(state_idx) < min_metric THEN + min_metric := metrics_current(state_idx); + best_state_var := state_idx; + END IF; + state_idx <= state_idx + 1; + ELSE + tb_state <= best_state_var; + tb_time <= NUM_SYMBOLS - 1; + dec_rd_addr <= (NUM_SYMBOLS-1) * NUM_STATES + best_state_var; + state <= TB_FETCH; + END IF; + + ------------------------------------------------------------------------------------ + -- SIMPLIFIED 2-CYCLE TRACEBACK + ------------------------------------------------------------------------------------ + WHEN TB_FETCH => + -- Cycle 1: Issue BRAM read for current (tb_time, tb_state) + -- Next cycle, dec_rd_data will be valid + state <= TB_USE; + + WHEN TB_USE => + -- Cycle 2: Use the decision that was fetched + IF tb_time >= 0 THEN + -- Output decoded bit + out_buf(tb_time) <= std_logic(to_unsigned(tb_state MOD 2, 1)(0)); + + -- Move to previous state based on decision + IF dec_rd_data = '0' THEN + tb_state <= tb_state / 2; + ELSE + tb_state <= (tb_state / 2) + 32; + END IF; + + tb_time <= tb_time - 1; + + -- Fetch next decision (if not done) + IF tb_time > 0 THEN + IF dec_rd_data = '0' THEN + dec_rd_addr <= (tb_time-1) * NUM_STATES + (tb_state / 2); + ELSE + dec_rd_addr <= (tb_time-1) * NUM_STATES + ((tb_state / 2) + 32); + END IF; + state <= TB_FETCH; + ELSE + state <= COMPLETE; + END IF; + ELSE + state <= COMPLETE; + END IF; WHEN COMPLETE => done <= '1'; From e4ce3c250d184855f1c429a6fb3c2b46906e8464 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 20 Nov 2025 22:36:48 -0800 Subject: [PATCH 42/60] input matches output but firmware build seg faults. Please send help. --- library/msk_top_ip.tcl | 25 +++++++------------------ src/axis_async_fifo.vhd | 6 +++--- src/msk_top.vhd | 9 ++++++--- src/msk_top_csr.vhd | 2 +- src/ov_frame_encoder.vhd | 6 ++++++ 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/library/msk_top_ip.tcl b/library/msk_top_ip.tcl index 774faa7..c2a01e8 100644 --- a/library/msk_top_ip.tcl +++ b/library/msk_top_ip.tcl @@ -1,25 +1,22 @@ # ip -# "src/axi_ctrlif.vhd" - source ../hdl/scripts/adi_env.tcl source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl adi_ip_create msk_top +# Register ALL VHDL-2008 files first with read_vhdl -vhdl2008 +# Order matters: dependencies before modules that use them read_vhdl -vhdl2008 "../rdl/src/axi4lite_intf_pkg.vhd" read_vhdl -vhdl2008 "../rdl/src/reg_utils.vhd" read_vhdl "../rdl/outputs/rtl/msk_top_regs_pkg.vhd" read_vhdl -vhdl2008 "../rdl/outputs/rtl/msk_top_regs.vhd" - -# OV frame encoder/decoder require VHDL-2008 for division/modulo operators +read_vhdl -vhdl2008 "../src/conv_encoder_k7.vhd" +read_vhdl -vhdl2008 "../src/viterbi_decoder_k7_simple.vhd" read_vhdl -vhdl2008 "../src/ov_frame_encoder.vhd" read_vhdl -vhdl2008 "../src/ov_frame_decoder.vhd" - -#set_property FILE_TYPE {VHDL 2008} [get_files $ad_hdl_dir/library/msk_top/src/*.vhd] +# Register all non-VHDL-2008 files adi_ip_files msk_top [list \ - "../src/conv_encoder_k7.vhd" \ - "../src/viterbi_decoder_k7_simple.vhd" \ "../msk_demodulator/src/costas_loop.vhd" \ "../pi_controller/src/pi_controller.vhd" \ "../lowpass_ema/src/lowpass_ema.vhd" \ @@ -40,14 +37,9 @@ adi_ip_files msk_top [list \ "../prbs/src/prbs_mon.vhd" \ "../nco/src/sin_cos_lut.vhd" ] -# Set VHDL-2008 for FEC files -set_property FILE_TYPE {VHDL 2008} [get_files "../src/conv_encoder_k7.vhd"] -set_property FILE_TYPE {VHDL 2008} [get_files "../src/viterbi_decoder_k7_simple.vhd"] - -# use this command if we have AXI lite interface for register control +# Configure IP properties adi_ip_properties msk_top - # Remove auto-inferred ADI custom bus interfaces before defining proper AXI-Stream set core [ipx::current_core] foreach intf {rx s_axis tx} { @@ -56,7 +48,7 @@ foreach intf {rx s_axis tx} { } } - +# TX AXIS slave interface (from DMA to MSK) adi_add_bus "s_axis" "slave" \ "xilinx.com:interface:axis_rtl:1.0" \ "xilinx.com:interface:axis:1.0" \ @@ -79,9 +71,6 @@ adi_add_bus "m_axis" "master" \ {"m_axis_tdata" "TDATA"} \ {"m_axis_tlast" "TLAST"}] -# m_axis shares the same clock as the demodulator adi_add_bus_clock "s_axis_aclk" "m_axis" "s_axis_aresetn" ipx::save_core [ipx::current_core] - -ipx::save_core [ipx::current_core] diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 215a0cf..c454491 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -68,9 +68,9 @@ ARCHITECTURE rtl OF axis_async_fifo IS SIGNAL ram_data : ram_data_type; SIGNAL ram_last : ram_last_type; - ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF ram_data : SIGNAL IS "block"; - ATTRIBUTE ram_style OF ram_last : SIGNAL IS "block"; + --ATTRIBUTE ram_style : STRING; + --ATTRIBUTE ram_style OF ram_data : SIGNAL IS "auto"; + --ATTRIBUTE ram_style OF ram_last : SIGNAL IS "auto"; -- Gray code pointers (reset-initialized in respective clock domains) SIGNAL wr_ptr_gray : std_logic_vector(ADDR_WIDTH DOWNTO 0); diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 40c3d25..e11fbd9 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -97,7 +97,7 @@ ENTITY msk_top IS C_S_AXI_DATA_WIDTH : NATURAL := 32; C_S_AXI_ADDR_WIDTH : NATURAL := 32; SYNC_CNT_W : NATURAL := 24; - FIFO_ADDR_WIDTH : NATURAL := 11 -- 2048 byte FIFO (used in both tx and rx) + FIFO_ADDR_WIDTH : NATURAL := 9 -- 512 byte FIFO (used in both tx and rx) ); PORT ( clk : IN std_logic; @@ -325,6 +325,9 @@ ARCHITECTURE struct OF msk_top IS SIGNAL pd_alpha2 : std_logic_vector(17 DOWNTO 0); SIGNAL pd_power : std_logic_vector(22 DOWNTO 0); + ATTRIBUTE dont_touch : STRING; + ATTRIBUTE dont_touch OF u_async_fifo : LABEL IS "true"; + ATTRIBUTE dont_touch OF u_rx_async_fifo : LABEL IS "true"; BEGIN ------------------------------------------------------------------------------------------------------ @@ -357,7 +360,7 @@ BEGIN u_async_fifo : ENTITY work.axis_async_fifo GENERIC MAP ( DATA_WIDTH => 8, - ADDR_WIDTH => FIFO_ADDR_WIDTH + ADDR_WIDTH => FIFO_ADDR_WIDTH --9 which is 512 bytes ) PORT MAP ( wr_aclk => s_axis_aclk, @@ -619,7 +622,7 @@ BEGIN u_rx_async_fifo : ENTITY work.axis_async_fifo GENERIC MAP ( DATA_WIDTH => 8, - ADDR_WIDTH => FIFO_ADDR_WIDTH -- Reuse generic (11 = 2048 bytes) + ADDR_WIDTH => FIFO_ADDR_WIDTH -- Reuse generic (9 = 512 bytes) ) PORT MAP ( -- Write side (symbol clock domain) diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index e91a01e..e5135d5 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -85,7 +85,7 @@ ENTITY msk_top_csr IS C_S_AXI_DATA_WIDTH : NATURAL := 32; C_S_AXI_ADDR_WIDTH : NATURAL := 32; SYNC_CNT_W : NATURAL := 24; - FIFO_ADDR_WIDTH : NATURAL := 11 + FIFO_ADDR_WIDTH : NATURAL := 9 ); PORT ( clk : IN std_logic; diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 0870c0b..90d6a3e 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -106,6 +106,12 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL randomized_buffer : byte_buffer_t; SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); + + ATTRIBUTE ram_style : STRING; + --ATTRIBUTE ram_style OF collect_buffer : SIGNAL IS "block"; + --ATTRIBUTE ram_style OF input_buffer : SIGNAL IS "block"; + --ATTRIBUTE ram_style OF randomized_buffer : SIGNAL IS "block"; + ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "register"; -- Index counters SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; -- Where we're writing in collect_buffer From af474e73c71b941081d275f62cb20b3a3f50d186 Mon Sep 17 00:00:00 2001 From: abraxas3d Date: Sun, 23 Nov 2025 12:46:56 -0800 Subject: [PATCH 43/60] seg fault resolved. needs testing on full test bench on mymelody. --- src/msk_top_csr.vhd | 2 +- src/ov_frame_encoder.vhd | 66 ++++++++++++++++++++++--------- src/viterbi_decoder_k7_simple.vhd | 42 +++++++++++++++++--- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index e5135d5..c35f891 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -308,7 +308,7 @@ BEGIN urfo_s: cdc_resync PORT MAP (s_axi_aclk, NOT s_axi_aresetn, rx_frame_buffer_ovf, hwif_in.rx_frame_sync_status.frame_buffer_overflow.we); - hwif_in.MSK_Status.rx_enable.next_q <= '1'; + -- hwif_in.MSK_Status.rx_enable.next_q <= '1'; -- Commented out becuase handled by urxe_s CDC, by Abraxas3d hwif_in.MSK_Status.tx_axis_valid.next_q <= tx_axis_valid; -- Status Request from AXI to MDM diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 90d6a3e..545c350 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -89,12 +89,15 @@ END ENTITY ov_frame_encoder; ARCHITECTURE rtl OF ov_frame_encoder IS -- State machine - TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); + TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, PACK_FEC, INTERLEAVE, OUTPUT); + --TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); SIGNAL state : state_t := IDLE; -- Buffer types TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; + TYPE byte_interleave_buffer_t IS ARRAY(0 TO ENCODED_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + -- Circular collection buffer (larger than needed to handle any transients) CONSTANT COLLECT_SIZE : NATURAL := 256; @@ -105,7 +108,12 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL input_buffer : byte_buffer_t; SIGNAL randomized_buffer : byte_buffer_t; SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); - SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); + --SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); + SIGNAL interleaved_buffer : byte_interleave_buffer_t := (OTHERS => (OTHERS => '0')); + + TYPE fec_byte_buffer_t IS ARRAY(0 TO ENCODED_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + SIGNAL fec_buffer_bytes : fec_byte_buffer_t; + ATTRIBUTE ram_style : STRING; --ATTRIBUTE ram_style OF collect_buffer : SIGNAL IS "block"; @@ -156,15 +164,17 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); -- 268*8 - -- Interleaver address calculation (67 rows x 32 cols) - FUNCTION interleave_address(addr : NATURAL) RETURN NATURAL IS + -- Interleaver address calculation (67 rows x 32 bit cols) + FUNCTION interleave_address_byte(byte_addr : NATURAL) RETURN NATURAL IS CONSTANT ROWS : NATURAL := 67; - CONSTANT COLS : NATURAL := 32; + CONSTANT COLS : NATURAL := 4; --was 32 with bit level. 32/8 = 4 VARIABLE row : NATURAL; VARIABLE col : NATURAL; BEGIN - row := addr / COLS; - col := addr MOD COLS; + --row := addr / COLS; -- bit level + --col := addr MOD COLS; -- bit level + row := byte_addr / COLS; -- byte version + col := byte_addr MOD COLS; -- byte version RETURN col * ROWS + row; END FUNCTION; @@ -315,12 +325,31 @@ WHEN PREP_FEC => state <= INTERLEAVE; END IF; + + + +WHEN PACK_FEC => + IF byte_idx < ENCODED_BYTES THEN + FOR i IN 0 TO 7 LOOP + fec_buffer_bytes(byte_idx)(i) <= fec_buffer(byte_idx * 8 + i); + END LOOP; + byte_idx <= byte_idx + 1; + ELSE + byte_idx <= 0; + state <= INTERLEAVE; + END IF; + + + -- INTERLEAVE: Row-column interleaving WHEN INTERLEAVE => - IF bit_idx < ENCODED_BITS THEN - interleaved_buffer(interleave_address(bit_idx)) <= fec_buffer(bit_idx); - bit_idx <= bit_idx + 1; + IF byte_idx < ENCODED_BYTES THEN + --IF bit_idx < ENCODED_BITS THEN + --interleaved_buffer(interleave_address(bit_idx)) <= fec_buffer(bit_idx); + interleaved_buffer(interleave_address_byte(byte_idx)) <= fec_buffer_bytes(byte_idx); + --bit_idx <= bit_idx + 1; + byte_idx <= byte_idx + 1; ELSE out_idx <= 0; state <= OUTPUT; @@ -330,14 +359,15 @@ WHEN PREP_FEC => -- OUTPUT: Send 268 bytes via AXI-Stream WHEN OUTPUT => IF out_idx < ENCODED_BYTES THEN - m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); - m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); - m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); - m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); - m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); - m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); - m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); - m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); + m_tdata_reg <= interleaved_buffer(out_idx); -- Direct byte assignment! + --m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); + --m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); + --m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); + --m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); + --m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); + --m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); + --m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); + --m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); m_tvalid_reg <= '1'; m_tlast_reg <= '1' WHEN out_idx = (ENCODED_BYTES - 1) ELSE '0'; diff --git a/src/viterbi_decoder_k7_simple.vhd b/src/viterbi_decoder_k7_simple.vhd index 0a1c988..9a52bbb 100644 --- a/src/viterbi_decoder_k7_simple.vhd +++ b/src/viterbi_decoder_k7_simple.vhd @@ -32,26 +32,54 @@ END ENTITY viterbi_decoder_k7_simple; ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS + CONSTANT NUM_STATES : INTEGER := 64; CONSTANT METRIC_WIDTH : INTEGER := 12; CONSTANT INF_METRIC : INTEGER := 4095; CONSTANT NUM_SYMBOLS : INTEGER := ENCODED_BITS/2; - + TYPE state_t IS (IDLE, INITIALIZE, ACS_COMPUTE, FIND_BEST, - TB_FETCH, TB_USE, COMPLETE); + TB_FETCH, TB_USE, COMPLETE); SIGNAL state : state_t := IDLE; TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF unsigned(METRIC_WIDTH-1 DOWNTO 0); SIGNAL metrics_current : metric_array_t; SIGNAL metrics_next : metric_array_t; + --CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; + --TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; + --SIGNAL decision_mem : decision_mem_t; + + -- ATTRIBUTE ram_style : STRING; + -- ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "ultra"; + -- was block, worked with distributed but was too large of a design, tried ultra + -- still too big. removed entirely tried, was still too big. Then... + + --ATTRIBUTE ram_style : STRING; + --ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; + --ATTRIBUTE ram_extract : STRING; + --ATTRIBUTE ram_extract OF decision_mem : SIGNAL IS "yes"; + --ATTRIBUTE keep : STRING; + --ATTRIBUTE keep OF decision_mem : SIGNAL IS "true"; + -- crashed in a different place + + --CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; + --CONSTANT CHUNK_SIZE : INTEGER := 4096; + --CONSTANT NUM_CHUNKS : INTEGER := (DECISION_DEPTH + CHUNK_SIZE - 1) / CHUNK_SIZE; + + --TYPE decision_chunk_t IS ARRAY(0 TO CHUNK_SIZE-1) OF std_logic; + --TYPE decision_mem_array_t IS ARRAY(0 TO NUM_CHUNKS-1) OF decision_chunk_t; + --SIGNAL decision_mem : decision_mem_array_t; + + --ATTRIBUTE ram_style : STRING; + --ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; + CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; SIGNAL decision_mem : decision_mem_t; - - ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; - + + + SIGNAL dec_wr_en : std_logic; SIGNAL dec_wr_addr : INTEGER RANGE 0 TO DECISION_DEPTH-1; SIGNAL dec_wr_data : std_logic; @@ -110,6 +138,7 @@ BEGIN IF rising_edge(clk) THEN IF dec_wr_en = '1' THEN decision_mem(dec_wr_addr) <= dec_wr_data; + --decision_mem(dec_wr_addr / CHUNK_SIZE)(dec_wr_addr MOD CHUNK_SIZE) <= dec_wr_data; END IF; END IF; END PROCESS; @@ -118,6 +147,7 @@ BEGIN BEGIN IF rising_edge(clk) THEN dec_rd_data <= decision_mem(dec_rd_addr); + --dec_rd_data <= decision_mem(dec_rd_addr / CHUNK_SIZE)(dec_rd_addr MOD CHUNK_SIZE); END IF; END PROCESS; From dbc5a1ff82ac3d2f2781f622be3c1345e5b2f4e2 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 24 Nov 2025 17:31:36 -0800 Subject: [PATCH 44/60] end to end data corruption resolved. input equals output. --- src/axis_async_fifo.vhd | 17 ++- src/conv_encoder_k7.vhd | 50 ++++----- src/ov_frame_decoder.vhd | 7 +- src/ov_frame_encoder.vhd | 227 +++++++++++++++------------------------ 4 files changed, 131 insertions(+), 170 deletions(-) diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index c454491..311a24d 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -2,7 +2,7 @@ -- AXIS-Compliant Asynchronous FIFO ------------------------------------------------------------------------------------------------------ -- FIX v3: Proper three-state handling --- State A: Becoming valid (empty→non-empty): Present first byte, assert tvalid +-- State A: Becoming valid (empty?non-empty): Present first byte, assert tvalid -- State B: Handshake completes (tvalid='1', tready='1'): Advance pointer, present next byte -- State C: Valid but not consumed (tvalid='1', tready='0'): HOLD STABLE ------------------------------------------------------------------------------------------------------ @@ -61,6 +61,14 @@ ARCHITECTURE rtl OF axis_async_fifo IS CONSTANT DEPTH : NATURAL := 2**ADDR_WIDTH; + -- Frame-aware programmable full threshold + -- Alert when only fractional frame space remains, allowing N complete frames + -- to buffer without backpressure while maintaining elasticity for system response + CONSTANT FRAME_SIZE : NATURAL := 134; -- OV frame payload size (bytes) + CONSTANT ALERT_THRESHOLD : NATURAL := DEPTH MOD FRAME_SIZE; -- Remainder space + -- Example: 512-byte FIFO holds 3 full frames (402 bytes) + 110 bytes remainder + -- Alerts when ?110 bytes free, giving elasticity while protecting overflow + -- Separate arrays for Block RAM inference TYPE ram_data_type IS ARRAY (0 TO DEPTH-1) OF std_logic_vector(DATA_WIDTH-1 DOWNTO 0); TYPE ram_last_type IS ARRAY (0 TO DEPTH-1) OF std_logic; @@ -174,8 +182,9 @@ BEGIN full_int <= '0'; END IF; - -- Programmable full - IF DEPTH - (unsigned(wr_ptr_bin) - unsigned(rd_ptr_bin_sync)) <= 512 THEN + -- Programmable full - frame-aware threshold + -- Alerts when free space drops below one fractional frame + IF DEPTH - (unsigned(wr_ptr_bin) - unsigned(rd_ptr_bin_sync)) <= ALERT_THRESHOLD THEN prog_full_int <= '1'; ELSE prog_full_int <= '0'; @@ -194,7 +203,7 @@ BEGIN ------------------------------------------------------------------------------ -- Read Clock Domain - CORRECTED THREE-STATE LOGIC ------------------------------------------------------------------------------ - -- State A: Becoming valid (tvalid_int='0' → '1'): Present first byte + -- State A: Becoming valid (tvalid_int='0' ? '1'): Present first byte -- State B: Handshake completes (tvalid='1', tready='1'): Advance, present next -- State C: Valid but stalled (tvalid='1', tready='0'): HOLD STABLE ------------------------------------------------------------------------------ diff --git a/src/conv_encoder_k7.vhd b/src/conv_encoder_k7.vhd index 6f3fbe4..1cc624a 100644 --- a/src/conv_encoder_k7.vhd +++ b/src/conv_encoder_k7.vhd @@ -30,7 +30,8 @@ END ENTITY conv_encoder_k7; ARCHITECTURE rtl OF conv_encoder_k7 IS - TYPE state_t IS (IDLE, ENCODE_DATA, FLUSH_TRELLIS, COMPLETE); + -- TYPE state_t IS (IDLE, ENCODE_DATA, FLUSH_TRELLIS, COMPLETE); + TYPE state_t IS (IDLE, ENCODE_DATA, COMPLETE); SIGNAL state : state_t := IDLE; SIGNAL input_bit_count : NATURAL RANGE 0 TO PAYLOAD_BYTES*8; @@ -106,7 +107,7 @@ BEGIN WHEN ENCODE_DATA => -- Process 1,070 bits (stop 2 bits early for tail) - IF input_bit_count < PAYLOAD_BYTES*8 - 2 THEN + IF input_bit_count < PAYLOAD_BYTES*8 THEN -- Read input bit (MSB first) current_bit := input_buffer(PAYLOAD_BYTES*8 - 1 - input_bit_count); @@ -123,30 +124,31 @@ BEGIN input_bit_count <= input_bit_count + 1; output_bit_count <= output_bit_count + 2; ELSE - state <= FLUSH_TRELLIS; - input_bit_count <= 0; - END IF; - - WHEN FLUSH_TRELLIS => - -- Add 2 tail bits (produces 4 encoded bits) - IF input_bit_count < 2 THEN - current_bit := '0'; - - -- Compute outputs - outputs := compute_outputs(current_bit, shift_reg); - - -- Store outputs - out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); - out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); - - -- Update shift register - shift_reg := shift_reg(4 DOWNTO 0) & '0'; - - input_bit_count <= input_bit_count + 1; - output_bit_count <= output_bit_count + 2; - ELSE + -- state <= FLUSH_TRELLIS; + -- input_bit_count <= 0; state <= COMPLETE; END IF; + +-- WHEN FLUSH_TRELLIS => +-- -- Add 2 tail bits (produces 4 encoded bits) +-- IF input_bit_count < 2 THEN +-- current_bit := '0'; +-- +-- -- Compute outputs +-- outputs := compute_outputs(current_bit, shift_reg); +-- +-- -- Store outputs +-- out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); +-- out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); +-- +-- -- Update shift register +-- shift_reg := shift_reg(4 DOWNTO 0) & '0'; +-- +-- input_bit_count <= input_bit_count + 1; +-- output_bit_count <= output_bit_count + 2; +-- ELSE +-- state <= COMPLETE; +-- END IF; WHEN COMPLETE => done <= '1'; diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd index 9d60f86..0cf98fe 100644 --- a/src/ov_frame_decoder.vhd +++ b/src/ov_frame_decoder.vhd @@ -314,10 +314,13 @@ BEGIN WHEN FEC_DECODE => decoder_start <= '0'; IF decoder_done = '1' THEN - -- Unpack decoded bits in FORWARD order + -- Unpack decoded bits in REVERSE order to match encoder's bit reversal + -- Viterbi traceback produces bits in reverse order, compensating for + -- conv encoder's MSB-first processing, but we need to reverse again + -- to match how encoder packed the input FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP FOR j IN 0 TO 7 LOOP - fec_decoded_buffer(i)(7-j) <= decoder_output_buf(i*8 + j); + fec_decoded_buffer(i)(j) <= decoder_output_buf(PAYLOAD_BYTES*8 - 1 - i*8 - j); END LOOP; END LOOP; byte_idx <= 0; diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 545c350..5d192df 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -41,14 +41,13 @@ -- This module implements the TX path processing for OVP frames: -- 1. Collects 134 bytes of payload from AXI-Stream input -- 2. Applies randomization (XOR with fixed sequence) --- 3. Applies FEC (rate 1/2 convolutional - currently simple bit duplication) --- 4. Applies interleaving (67x32 row-column interleaver) +-- 3. Applies FEC (rate 1/2 convolutional encoding via conv_encoder_k7) +-- 4. Applies interleaving (67x32 row-column BIT interleaver) -- 5. Outputs 268 bytes (2144 bits) via AXI-Stream -- --- BUGFIX (2025-11-18): Completely redesigned collection strategy --- - Collect ALL bytes into circular buffer --- - When tlast arrives, count back 134 bytes --- - This handles any FIFO latency/alignment naturally +-- FIX (2025-11-24): Restored bit-level 67x32 interleaving +-- Byte-level interleaving broke protocol compatibility +-- Now processes 8 bits/clock for throughput (not 1 bit/clock) -- ------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------ @@ -88,17 +87,14 @@ END ENTITY ov_frame_encoder; ARCHITECTURE rtl OF ov_frame_encoder IS - -- State machine - TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, PACK_FEC, INTERLEAVE, OUTPUT); - --TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); + -- State machine (no PACK_FEC needed with bit-level interleaving) + TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); SIGNAL state : state_t := IDLE; -- Buffer types TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; - TYPE byte_interleave_buffer_t IS ARRAY(0 TO ENCODED_BYTES-1) OF std_logic_vector(7 DOWNTO 0); - -- Circular collection buffer (larger than needed to handle any transients) CONSTANT COLLECT_SIZE : NATURAL := 256; TYPE collect_buffer_t IS ARRAY(0 TO COLLECT_SIZE-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); @@ -108,21 +104,13 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL input_buffer : byte_buffer_t; SIGNAL randomized_buffer : byte_buffer_t; SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); - --SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); - SIGNAL interleaved_buffer : byte_interleave_buffer_t := (OTHERS => (OTHERS => '0')); - - TYPE fec_byte_buffer_t IS ARRAY(0 TO ENCODED_BYTES-1) OF std_logic_vector(7 DOWNTO 0); - SIGNAL fec_buffer_bytes : fec_byte_buffer_t; - + SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- BIT-level buffer! ATTRIBUTE ram_style : STRING; - --ATTRIBUTE ram_style OF collect_buffer : SIGNAL IS "block"; - --ATTRIBUTE ram_style OF input_buffer : SIGNAL IS "block"; - --ATTRIBUTE ram_style OF randomized_buffer : SIGNAL IS "block"; - ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "register"; + ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "distributed"; -- Index counters - SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; -- Where we're writing in collect_buffer + SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; @@ -137,6 +125,7 @@ ARCHITECTURE rtl OF ov_frame_encoder IS -- OVP Randomizer sequence (from OVP spec) TYPE randomizer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + -- OVP Randomizer sequence (from protocol spec - must match decoder!) CONSTANT RANDOMIZER_SEQUENCE : randomizer_t := ( x"A3", x"81", x"5C", x"C4", x"C9", x"08", x"0E", x"53", x"CC", x"A1", x"FB", x"29", x"9E", x"4F", x"16", x"E0", @@ -157,30 +146,29 @@ ARCHITECTURE rtl OF ov_frame_encoder IS x"9D", x"8E", x"E8", x"34", x"C9", x"59" ); - -- Viterbi encoder signals + -- Convolutional encoder signals (matches conv_encoder_k7 interface) SIGNAL encoder_start : std_logic := '0'; SIGNAL encoder_busy : std_logic; SIGNAL encoder_done : std_logic; SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); -- 268*8 - -- Interleaver address calculation (67 rows x 32 bit cols) - FUNCTION interleave_address_byte(byte_addr : NATURAL) RETURN NATURAL IS + -- BIT-LEVEL interleaver address calculation (67 rows x 32 cols) + -- This is the CORRECT algorithm - scatters bits across byte boundaries + FUNCTION interleave_address(addr : NATURAL) RETURN NATURAL IS CONSTANT ROWS : NATURAL := 67; - CONSTANT COLS : NATURAL := 4; --was 32 with bit level. 32/8 = 4 + CONSTANT COLS : NATURAL := 32; VARIABLE row : NATURAL; VARIABLE col : NATURAL; BEGIN - --row := addr / COLS; -- bit level - --col := addr MOD COLS; -- bit level - row := byte_addr / COLS; -- byte version - col := byte_addr MOD COLS; -- byte version + row := addr / COLS; + col := addr MOD COLS; RETURN col * ROWS + row; END FUNCTION; BEGIN - -- Convolutional Encoder Instantiation + -- Convolutional Encoder Instantiation (using YOUR actual component) U_ENCODER : ENTITY work.conv_encoder_k7 GENERIC MAP ( PAYLOAD_BYTES => PAYLOAD_BYTES, @@ -202,94 +190,63 @@ BEGIN m_axis_tlast <= m_tlast_reg; frames_encoded <= std_logic_vector(frame_count); + encoder_active <= '1' WHEN state /= IDLE ELSE '0'; + + -- Ready to accept data when IDLE or COLLECT + s_axis_tready <= '1' WHEN (state = IDLE OR state = COLLECT) AND aresetn = '1' ELSE '0'; -- Main FSM - encoder_fsm: PROCESS(clk, aresetn) - VARIABLE extract_start : NATURAL; - VARIABLE extract_end : NATURAL; + encoder_fsm: PROCESS(clk) BEGIN - IF aresetn = '0' THEN - state <= IDLE; - collect_idx <= 0; - byte_idx <= 0; - bit_idx <= 0; - out_idx <= 0; - s_axis_tready <= '0'; - m_tvalid_reg <= '0'; - m_tlast_reg <= '0'; - frame_count <= (OTHERS => '0'); - encoder_start <= '0'; -- Initialize FEC encoder control; - - ELSIF rising_edge(clk) THEN - IF aresetn = '1' THEN + IF rising_edge(clk) THEN + IF aresetn = '0' THEN + state <= IDLE; + collect_idx <= 0; + byte_idx <= 0; + bit_idx <= 0; + out_idx <= 0; + m_tvalid_reg <= '0'; + m_tlast_reg <= '0'; + encoder_start <= '0'; + frame_count <= (OTHERS => '0'); + ELSE CASE state IS - - -- IDLE: Wait for incoming data + -- IDLE: Wait for start of frame WHEN IDLE => - encoder_active <= '0'; - s_axis_tready <= '0'; -- Keep LOW in IDLE m_tvalid_reg <= '0'; - collect_idx <= 0; + m_tlast_reg <= '0'; + encoder_start <= '0'; IF s_axis_tvalid = '1' THEN + collect_buffer(0) <= s_axis_tdata; + collect_idx <= 1; state <= COLLECT; - encoder_active <= '1'; - -- tready set HIGH in COLLECT state, not here END IF; - -- COLLECT: Gather ALL bytes into circular buffer until tlast - -- Don't worry about alignment - just collect everything + -- COLLECT: Gather bytes until tlast WHEN COLLECT => - s_axis_tready <= '1'; - IF s_axis_tvalid = '1' THEN - -- Store byte in circular buffer collect_buffer(collect_idx MOD COLLECT_SIZE) <= s_axis_tdata; - - REPORT "COLLECT: collect_idx=" & INTEGER'IMAGE(collect_idx) & - " data=0x" & INTEGER'IMAGE(to_integer(unsigned(s_axis_tdata))) & - " tlast=" & STD_LOGIC'IMAGE(s_axis_tlast)(2); + collect_idx <= collect_idx + 1; IF s_axis_tlast = '1' THEN - -- Frame boundary! Now extract the last 134 bytes - REPORT "COLLECT: tlast at collect_idx=" & INTEGER'IMAGE(collect_idx); - s_axis_tready <= '0'; - state <= EXTRACT; byte_idx <= 0; - ELSE - collect_idx <= collect_idx + 1; + state <= EXTRACT; END IF; END IF; - -- EXTRACT: Copy the last 134 bytes from collect_buffer to input_buffer - -- The frame ends at collect_idx, so we want bytes [collect_idx-133 : collect_idx] + -- EXTRACT: Pull last 134 bytes from circular buffer WHEN EXTRACT => IF byte_idx < PAYLOAD_BYTES THEN - -- Calculate which byte in collect_buffer to read - -- If collect_idx = 133, we want bytes [0:133] - -- If collect_idx = 150, we want bytes [17:150] - extract_start := (collect_idx + 1) - PAYLOAD_BYTES; - extract_end := collect_idx; - - -- Copy byte from circular buffer - input_buffer(byte_idx) <= collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE); - - IF byte_idx < 5 THEN - REPORT "EXTRACT[" & INTEGER'IMAGE(byte_idx) & - "] from collect_buffer[" & - INTEGER'IMAGE((extract_start + byte_idx) MOD COLLECT_SIZE) & - "] = 0x" & - INTEGER'IMAGE(to_integer(unsigned(collect_buffer((extract_start + byte_idx) MOD COLLECT_SIZE)))); - END IF; - + input_buffer(byte_idx) <= + collect_buffer((collect_idx - PAYLOAD_BYTES + byte_idx) MOD COLLECT_SIZE); byte_idx <= byte_idx + 1; ELSE - REPORT "EXTRACT complete, " & INTEGER'IMAGE(PAYLOAD_BYTES) & " bytes copied"; byte_idx <= 0; state <= RANDOMIZE; END IF; - -- RANDOMIZE: XOR with sequence + -- RANDOMIZE: XOR with randomizer sequence WHEN RANDOMIZE => IF byte_idx < PAYLOAD_BYTES THEN randomized_buffer(byte_idx) <= @@ -297,59 +254,45 @@ BEGIN byte_idx <= byte_idx + 1; ELSE byte_idx <= 0; - bit_idx <= 0; - state <= PREP_FEC; -- Changed from FEC_ENCODE + state <= PREP_FEC; END IF; -WHEN PREP_FEC => - -- Pack randomized_buffer MSB-first to match encoder's MSB-first reading - FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP - FOR j IN 0 TO 7 LOOP - -- Put byte 0 at top of buffer, MSB of each byte first - encoder_input_buf(PAYLOAD_BYTES*8 - 1 - (i*8 + j)) <= randomized_buffer(i)(7-j); - END LOOP; - END LOOP; - encoder_start <= '1'; - state <= FEC_ENCODE; + -- PREP_FEC: Pack bytes into encoder input vector + WHEN PREP_FEC => + FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP + FOR j IN 0 TO 7 LOOP + encoder_input_buf(i*8 + j) <= randomized_buffer(i)(j); + END LOOP; + END LOOP; + encoder_start <= '1'; + state <= FEC_ENCODE; - -- FEC_ENCODE: Wait for convolution encoder to complete + -- FEC_ENCODE: Wait for convolutional encoder to complete WHEN FEC_ENCODE => - encoder_start <= '0'; -- Clear start pulse + encoder_start <= '0'; IF encoder_done = '1' THEN -- Unpack encoded bits into fec_buffer FOR i IN 0 TO ENCODED_BITS-1 LOOP fec_buffer(i) <= encoder_output_buf(ENCODED_BITS - 1 - i); -- MSB-first - --fec_buffer(i) <= encoder_output_buf(i); END LOOP; bit_idx <= 0; state <= INTERLEAVE; END IF; - - - - -WHEN PACK_FEC => - IF byte_idx < ENCODED_BYTES THEN - FOR i IN 0 TO 7 LOOP - fec_buffer_bytes(byte_idx)(i) <= fec_buffer(byte_idx * 8 + i); - END LOOP; - byte_idx <= byte_idx + 1; - ELSE - byte_idx <= 0; - state <= INTERLEAVE; - END IF; - - - - -- INTERLEAVE: Row-column interleaving + -- INTERLEAVE: Bit-level 67x32 interleaving + -- Process 8 bits per clock for throughput (268 clocks total) WHEN INTERLEAVE => - IF byte_idx < ENCODED_BYTES THEN - --IF bit_idx < ENCODED_BITS THEN - --interleaved_buffer(interleave_address(bit_idx)) <= fec_buffer(bit_idx); - interleaved_buffer(interleave_address_byte(byte_idx)) <= fec_buffer_bytes(byte_idx); - --bit_idx <= bit_idx + 1; - byte_idx <= byte_idx + 1; + IF bit_idx < ENCODED_BITS THEN + -- Write 8 bits in parallel to their interleaved positions + interleaved_buffer(interleave_address(bit_idx + 0)) <= fec_buffer(bit_idx + 0); + interleaved_buffer(interleave_address(bit_idx + 1)) <= fec_buffer(bit_idx + 1); + interleaved_buffer(interleave_address(bit_idx + 2)) <= fec_buffer(bit_idx + 2); + interleaved_buffer(interleave_address(bit_idx + 3)) <= fec_buffer(bit_idx + 3); + interleaved_buffer(interleave_address(bit_idx + 4)) <= fec_buffer(bit_idx + 4); + interleaved_buffer(interleave_address(bit_idx + 5)) <= fec_buffer(bit_idx + 5); + interleaved_buffer(interleave_address(bit_idx + 6)) <= fec_buffer(bit_idx + 6); + interleaved_buffer(interleave_address(bit_idx + 7)) <= fec_buffer(bit_idx + 7); + bit_idx <= bit_idx + 8; ELSE out_idx <= 0; state <= OUTPUT; @@ -357,20 +300,24 @@ WHEN PACK_FEC => END IF; -- OUTPUT: Send 268 bytes via AXI-Stream + -- Pack 8 bits from interleaved buffer into each output byte WHEN OUTPUT => IF out_idx < ENCODED_BYTES THEN - m_tdata_reg <= interleaved_buffer(out_idx); -- Direct byte assignment! - --m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); - --m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); - --m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); - --m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); - --m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); - --m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); - --m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); - --m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); + m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); + m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); + m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); + m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); + m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); + m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); + m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); + m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); m_tvalid_reg <= '1'; - m_tlast_reg <= '1' WHEN out_idx = (ENCODED_BYTES - 1) ELSE '0'; + IF out_idx = (ENCODED_BYTES - 1) THEN + m_tlast_reg <= '1'; + ELSE + m_tlast_reg <= '0'; + END IF; IF m_axis_tready = '1' THEN IF out_idx = (ENCODED_BYTES - 1) THEN From 184aa7dc902f636975fcf089e6e74a41f1223474 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 24 Nov 2025 18:49:17 -0800 Subject: [PATCH 45/60] works in simulation, comes under LUT limit for PLUTO, but doesn't route. Right before generate byte vs bit interleaver option installed. --- src/ov_frame_encoder.vhd | 171 +++++++++++++++++++++++++++++++++------ 1 file changed, 146 insertions(+), 25 deletions(-) diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 5d192df..b08d8ea 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -107,7 +107,7 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- BIT-level buffer! ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "distributed"; + ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "block"; -- Index counters SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; @@ -153,18 +153,146 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); -- 268*8 - -- BIT-LEVEL interleaver address calculation (67 rows x 32 cols) - -- This is the CORRECT algorithm - scatters bits across byte boundaries - FUNCTION interleave_address(addr : NATURAL) RETURN NATURAL IS - CONSTANT ROWS : NATURAL := 67; - CONSTANT COLS : NATURAL := 32; - VARIABLE row : NATURAL; - VARIABLE col : NATURAL; - BEGIN - row := addr / COLS; - col := addr MOD COLS; - RETURN col * ROWS + row; - END FUNCTION; + -- BIT-LEVEL interleaver address LUT (67 rows x 32 cols) + -- Pre-computed to avoid expensive division/multiply in hardware + -- Formula: row = addr/32, col = addr%32, result = col*67 + row + TYPE address_lut_t IS ARRAY(0 TO 2143) OF NATURAL RANGE 0 TO 2143; + CONSTANT INTERLEAVE_LUT : address_lut_t := ( + 0, 67, 134, 201, 268, 335, 402, 469, 536, 603, 670, 737, 804, 871, 938, 1005, + 1072, 1139, 1206, 1273, 1340, 1407, 1474, 1541, 1608, 1675, 1742, 1809, 1876, 1943, 2010, 2077, + 1, 68, 135, 202, 269, 336, 403, 470, 537, 604, 671, 738, 805, 872, 939, 1006, + 1073, 1140, 1207, 1274, 1341, 1408, 1475, 1542, 1609, 1676, 1743, 1810, 1877, 1944, 2011, 2078, + 2, 69, 136, 203, 270, 337, 404, 471, 538, 605, 672, 739, 806, 873, 940, 1007, + 1074, 1141, 1208, 1275, 1342, 1409, 1476, 1543, 1610, 1677, 1744, 1811, 1878, 1945, 2012, 2079, + 3, 70, 137, 204, 271, 338, 405, 472, 539, 606, 673, 740, 807, 874, 941, 1008, + 1075, 1142, 1209, 1276, 1343, 1410, 1477, 1544, 1611, 1678, 1745, 1812, 1879, 1946, 2013, 2080, + 4, 71, 138, 205, 272, 339, 406, 473, 540, 607, 674, 741, 808, 875, 942, 1009, + 1076, 1143, 1210, 1277, 1344, 1411, 1478, 1545, 1612, 1679, 1746, 1813, 1880, 1947, 2014, 2081, + 5, 72, 139, 206, 273, 340, 407, 474, 541, 608, 675, 742, 809, 876, 943, 1010, + 1077, 1144, 1211, 1278, 1345, 1412, 1479, 1546, 1613, 1680, 1747, 1814, 1881, 1948, 2015, 2082, + 6, 73, 140, 207, 274, 341, 408, 475, 542, 609, 676, 743, 810, 877, 944, 1011, + 1078, 1145, 1212, 1279, 1346, 1413, 1480, 1547, 1614, 1681, 1748, 1815, 1882, 1949, 2016, 2083, + 7, 74, 141, 208, 275, 342, 409, 476, 543, 610, 677, 744, 811, 878, 945, 1012, + 1079, 1146, 1213, 1280, 1347, 1414, 1481, 1548, 1615, 1682, 1749, 1816, 1883, 1950, 2017, 2084, + 8, 75, 142, 209, 276, 343, 410, 477, 544, 611, 678, 745, 812, 879, 946, 1013, + 1080, 1147, 1214, 1281, 1348, 1415, 1482, 1549, 1616, 1683, 1750, 1817, 1884, 1951, 2018, 2085, + 9, 76, 143, 210, 277, 344, 411, 478, 545, 612, 679, 746, 813, 880, 947, 1014, + 1081, 1148, 1215, 1282, 1349, 1416, 1483, 1550, 1617, 1684, 1751, 1818, 1885, 1952, 2019, 2086, + 10, 77, 144, 211, 278, 345, 412, 479, 546, 613, 680, 747, 814, 881, 948, 1015, + 1082, 1149, 1216, 1283, 1350, 1417, 1484, 1551, 1618, 1685, 1752, 1819, 1886, 1953, 2020, 2087, + 11, 78, 145, 212, 279, 346, 413, 480, 547, 614, 681, 748, 815, 882, 949, 1016, + 1083, 1150, 1217, 1284, 1351, 1418, 1485, 1552, 1619, 1686, 1753, 1820, 1887, 1954, 2021, 2088, + 12, 79, 146, 213, 280, 347, 414, 481, 548, 615, 682, 749, 816, 883, 950, 1017, + 1084, 1151, 1218, 1285, 1352, 1419, 1486, 1553, 1620, 1687, 1754, 1821, 1888, 1955, 2022, 2089, + 13, 80, 147, 214, 281, 348, 415, 482, 549, 616, 683, 750, 817, 884, 951, 1018, + 1085, 1152, 1219, 1286, 1353, 1420, 1487, 1554, 1621, 1688, 1755, 1822, 1889, 1956, 2023, 2090, + 14, 81, 148, 215, 282, 349, 416, 483, 550, 617, 684, 751, 818, 885, 952, 1019, + 1086, 1153, 1220, 1287, 1354, 1421, 1488, 1555, 1622, 1689, 1756, 1823, 1890, 1957, 2024, 2091, + 15, 82, 149, 216, 283, 350, 417, 484, 551, 618, 685, 752, 819, 886, 953, 1020, + 1087, 1154, 1221, 1288, 1355, 1422, 1489, 1556, 1623, 1690, 1757, 1824, 1891, 1958, 2025, 2092, + 16, 83, 150, 217, 284, 351, 418, 485, 552, 619, 686, 753, 820, 887, 954, 1021, + 1088, 1155, 1222, 1289, 1356, 1423, 1490, 1557, 1624, 1691, 1758, 1825, 1892, 1959, 2026, 2093, + 17, 84, 151, 218, 285, 352, 419, 486, 553, 620, 687, 754, 821, 888, 955, 1022, + 1089, 1156, 1223, 1290, 1357, 1424, 1491, 1558, 1625, 1692, 1759, 1826, 1893, 1960, 2027, 2094, + 18, 85, 152, 219, 286, 353, 420, 487, 554, 621, 688, 755, 822, 889, 956, 1023, + 1090, 1157, 1224, 1291, 1358, 1425, 1492, 1559, 1626, 1693, 1760, 1827, 1894, 1961, 2028, 2095, + 19, 86, 153, 220, 287, 354, 421, 488, 555, 622, 689, 756, 823, 890, 957, 1024, + 1091, 1158, 1225, 1292, 1359, 1426, 1493, 1560, 1627, 1694, 1761, 1828, 1895, 1962, 2029, 2096, + 20, 87, 154, 221, 288, 355, 422, 489, 556, 623, 690, 757, 824, 891, 958, 1025, + 1092, 1159, 1226, 1293, 1360, 1427, 1494, 1561, 1628, 1695, 1762, 1829, 1896, 1963, 2030, 2097, + 21, 88, 155, 222, 289, 356, 423, 490, 557, 624, 691, 758, 825, 892, 959, 1026, + 1093, 1160, 1227, 1294, 1361, 1428, 1495, 1562, 1629, 1696, 1763, 1830, 1897, 1964, 2031, 2098, + 22, 89, 156, 223, 290, 357, 424, 491, 558, 625, 692, 759, 826, 893, 960, 1027, + 1094, 1161, 1228, 1295, 1362, 1429, 1496, 1563, 1630, 1697, 1764, 1831, 1898, 1965, 2032, 2099, + 23, 90, 157, 224, 291, 358, 425, 492, 559, 626, 693, 760, 827, 894, 961, 1028, + 1095, 1162, 1229, 1296, 1363, 1430, 1497, 1564, 1631, 1698, 1765, 1832, 1899, 1966, 2033, 2100, + 24, 91, 158, 225, 292, 359, 426, 493, 560, 627, 694, 761, 828, 895, 962, 1029, + 1096, 1163, 1230, 1297, 1364, 1431, 1498, 1565, 1632, 1699, 1766, 1833, 1900, 1967, 2034, 2101, + 25, 92, 159, 226, 293, 360, 427, 494, 561, 628, 695, 762, 829, 896, 963, 1030, + 1097, 1164, 1231, 1298, 1365, 1432, 1499, 1566, 1633, 1700, 1767, 1834, 1901, 1968, 2035, 2102, + 26, 93, 160, 227, 294, 361, 428, 495, 562, 629, 696, 763, 830, 897, 964, 1031, + 1098, 1165, 1232, 1299, 1366, 1433, 1500, 1567, 1634, 1701, 1768, 1835, 1902, 1969, 2036, 2103, + 27, 94, 161, 228, 295, 362, 429, 496, 563, 630, 697, 764, 831, 898, 965, 1032, + 1099, 1166, 1233, 1300, 1367, 1434, 1501, 1568, 1635, 1702, 1769, 1836, 1903, 1970, 2037, 2104, + 28, 95, 162, 229, 296, 363, 430, 497, 564, 631, 698, 765, 832, 899, 966, 1033, + 1100, 1167, 1234, 1301, 1368, 1435, 1502, 1569, 1636, 1703, 1770, 1837, 1904, 1971, 2038, 2105, + 29, 96, 163, 230, 297, 364, 431, 498, 565, 632, 699, 766, 833, 900, 967, 1034, + 1101, 1168, 1235, 1302, 1369, 1436, 1503, 1570, 1637, 1704, 1771, 1838, 1905, 1972, 2039, 2106, + 30, 97, 164, 231, 298, 365, 432, 499, 566, 633, 700, 767, 834, 901, 968, 1035, + 1102, 1169, 1236, 1303, 1370, 1437, 1504, 1571, 1638, 1705, 1772, 1839, 1906, 1973, 2040, 2107, + 31, 98, 165, 232, 299, 366, 433, 500, 567, 634, 701, 768, 835, 902, 969, 1036, + 1103, 1170, 1237, 1304, 1371, 1438, 1505, 1572, 1639, 1706, 1773, 1840, 1907, 1974, 2041, 2108, + 32, 99, 166, 233, 300, 367, 434, 501, 568, 635, 702, 769, 836, 903, 970, 1037, + 1104, 1171, 1238, 1305, 1372, 1439, 1506, 1573, 1640, 1707, 1774, 1841, 1908, 1975, 2042, 2109, + 33, 100, 167, 234, 301, 368, 435, 502, 569, 636, 703, 770, 837, 904, 971, 1038, + 1105, 1172, 1239, 1306, 1373, 1440, 1507, 1574, 1641, 1708, 1775, 1842, 1909, 1976, 2043, 2110, + 34, 101, 168, 235, 302, 369, 436, 503, 570, 637, 704, 771, 838, 905, 972, 1039, + 1106, 1173, 1240, 1307, 1374, 1441, 1508, 1575, 1642, 1709, 1776, 1843, 1910, 1977, 2044, 2111, + 35, 102, 169, 236, 303, 370, 437, 504, 571, 638, 705, 772, 839, 906, 973, 1040, + 1107, 1174, 1241, 1308, 1375, 1442, 1509, 1576, 1643, 1710, 1777, 1844, 1911, 1978, 2045, 2112, + 36, 103, 170, 237, 304, 371, 438, 505, 572, 639, 706, 773, 840, 907, 974, 1041, + 1108, 1175, 1242, 1309, 1376, 1443, 1510, 1577, 1644, 1711, 1778, 1845, 1912, 1979, 2046, 2113, + 37, 104, 171, 238, 305, 372, 439, 506, 573, 640, 707, 774, 841, 908, 975, 1042, + 1109, 1176, 1243, 1310, 1377, 1444, 1511, 1578, 1645, 1712, 1779, 1846, 1913, 1980, 2047, 2114, + 38, 105, 172, 239, 306, 373, 440, 507, 574, 641, 708, 775, 842, 909, 976, 1043, + 1110, 1177, 1244, 1311, 1378, 1445, 1512, 1579, 1646, 1713, 1780, 1847, 1914, 1981, 2048, 2115, + 39, 106, 173, 240, 307, 374, 441, 508, 575, 642, 709, 776, 843, 910, 977, 1044, + 1111, 1178, 1245, 1312, 1379, 1446, 1513, 1580, 1647, 1714, 1781, 1848, 1915, 1982, 2049, 2116, + 40, 107, 174, 241, 308, 375, 442, 509, 576, 643, 710, 777, 844, 911, 978, 1045, + 1112, 1179, 1246, 1313, 1380, 1447, 1514, 1581, 1648, 1715, 1782, 1849, 1916, 1983, 2050, 2117, + 41, 108, 175, 242, 309, 376, 443, 510, 577, 644, 711, 778, 845, 912, 979, 1046, + 1113, 1180, 1247, 1314, 1381, 1448, 1515, 1582, 1649, 1716, 1783, 1850, 1917, 1984, 2051, 2118, + 42, 109, 176, 243, 310, 377, 444, 511, 578, 645, 712, 779, 846, 913, 980, 1047, + 1114, 1181, 1248, 1315, 1382, 1449, 1516, 1583, 1650, 1717, 1784, 1851, 1918, 1985, 2052, 2119, + 43, 110, 177, 244, 311, 378, 445, 512, 579, 646, 713, 780, 847, 914, 981, 1048, + 1115, 1182, 1249, 1316, 1383, 1450, 1517, 1584, 1651, 1718, 1785, 1852, 1919, 1986, 2053, 2120, + 44, 111, 178, 245, 312, 379, 446, 513, 580, 647, 714, 781, 848, 915, 982, 1049, + 1116, 1183, 1250, 1317, 1384, 1451, 1518, 1585, 1652, 1719, 1786, 1853, 1920, 1987, 2054, 2121, + 45, 112, 179, 246, 313, 380, 447, 514, 581, 648, 715, 782, 849, 916, 983, 1050, + 1117, 1184, 1251, 1318, 1385, 1452, 1519, 1586, 1653, 1720, 1787, 1854, 1921, 1988, 2055, 2122, + 46, 113, 180, 247, 314, 381, 448, 515, 582, 649, 716, 783, 850, 917, 984, 1051, + 1118, 1185, 1252, 1319, 1386, 1453, 1520, 1587, 1654, 1721, 1788, 1855, 1922, 1989, 2056, 2123, + 47, 114, 181, 248, 315, 382, 449, 516, 583, 650, 717, 784, 851, 918, 985, 1052, + 1119, 1186, 1253, 1320, 1387, 1454, 1521, 1588, 1655, 1722, 1789, 1856, 1923, 1990, 2057, 2124, + 48, 115, 182, 249, 316, 383, 450, 517, 584, 651, 718, 785, 852, 919, 986, 1053, + 1120, 1187, 1254, 1321, 1388, 1455, 1522, 1589, 1656, 1723, 1790, 1857, 1924, 1991, 2058, 2125, + 49, 116, 183, 250, 317, 384, 451, 518, 585, 652, 719, 786, 853, 920, 987, 1054, + 1121, 1188, 1255, 1322, 1389, 1456, 1523, 1590, 1657, 1724, 1791, 1858, 1925, 1992, 2059, 2126, + 50, 117, 184, 251, 318, 385, 452, 519, 586, 653, 720, 787, 854, 921, 988, 1055, + 1122, 1189, 1256, 1323, 1390, 1457, 1524, 1591, 1658, 1725, 1792, 1859, 1926, 1993, 2060, 2127, + 51, 118, 185, 252, 319, 386, 453, 520, 587, 654, 721, 788, 855, 922, 989, 1056, + 1123, 1190, 1257, 1324, 1391, 1458, 1525, 1592, 1659, 1726, 1793, 1860, 1927, 1994, 2061, 2128, + 52, 119, 186, 253, 320, 387, 454, 521, 588, 655, 722, 789, 856, 923, 990, 1057, + 1124, 1191, 1258, 1325, 1392, 1459, 1526, 1593, 1660, 1727, 1794, 1861, 1928, 1995, 2062, 2129, + 53, 120, 187, 254, 321, 388, 455, 522, 589, 656, 723, 790, 857, 924, 991, 1058, + 1125, 1192, 1259, 1326, 1393, 1460, 1527, 1594, 1661, 1728, 1795, 1862, 1929, 1996, 2063, 2130, + 54, 121, 188, 255, 322, 389, 456, 523, 590, 657, 724, 791, 858, 925, 992, 1059, + 1126, 1193, 1260, 1327, 1394, 1461, 1528, 1595, 1662, 1729, 1796, 1863, 1930, 1997, 2064, 2131, + 55, 122, 189, 256, 323, 390, 457, 524, 591, 658, 725, 792, 859, 926, 993, 1060, + 1127, 1194, 1261, 1328, 1395, 1462, 1529, 1596, 1663, 1730, 1797, 1864, 1931, 1998, 2065, 2132, + 56, 123, 190, 257, 324, 391, 458, 525, 592, 659, 726, 793, 860, 927, 994, 1061, + 1128, 1195, 1262, 1329, 1396, 1463, 1530, 1597, 1664, 1731, 1798, 1865, 1932, 1999, 2066, 2133, + 57, 124, 191, 258, 325, 392, 459, 526, 593, 660, 727, 794, 861, 928, 995, 1062, + 1129, 1196, 1263, 1330, 1397, 1464, 1531, 1598, 1665, 1732, 1799, 1866, 1933, 2000, 2067, 2134, + 58, 125, 192, 259, 326, 393, 460, 527, 594, 661, 728, 795, 862, 929, 996, 1063, + 1130, 1197, 1264, 1331, 1398, 1465, 1532, 1599, 1666, 1733, 1800, 1867, 1934, 2001, 2068, 2135, + 59, 126, 193, 260, 327, 394, 461, 528, 595, 662, 729, 796, 863, 930, 997, 1064, + 1131, 1198, 1265, 1332, 1399, 1466, 1533, 1600, 1667, 1734, 1801, 1868, 1935, 2002, 2069, 2136, + 60, 127, 194, 261, 328, 395, 462, 529, 596, 663, 730, 797, 864, 931, 998, 1065, + 1132, 1199, 1266, 1333, 1400, 1467, 1534, 1601, 1668, 1735, 1802, 1869, 1936, 2003, 2070, 2137, + 61, 128, 195, 262, 329, 396, 463, 530, 597, 664, 731, 798, 865, 932, 999, 1066, + 1133, 1200, 1267, 1334, 1401, 1468, 1535, 1602, 1669, 1736, 1803, 1870, 1937, 2004, 2071, 2138, + 62, 129, 196, 263, 330, 397, 464, 531, 598, 665, 732, 799, 866, 933, 1000, 1067, + 1134, 1201, 1268, 1335, 1402, 1469, 1536, 1603, 1670, 1737, 1804, 1871, 1938, 2005, 2072, 2139, + 63, 130, 197, 264, 331, 398, 465, 532, 599, 666, 733, 800, 867, 934, 1001, 1068, + 1135, 1202, 1269, 1336, 1403, 1470, 1537, 1604, 1671, 1738, 1805, 1872, 1939, 2006, 2073, 2140, + 64, 131, 198, 265, 332, 399, 466, 533, 600, 667, 734, 801, 868, 935, 1002, 1069, + 1136, 1203, 1270, 1337, 1404, 1471, 1538, 1605, 1672, 1739, 1806, 1873, 1940, 2007, 2074, 2141, + 65, 132, 199, 266, 333, 400, 467, 534, 601, 668, 735, 802, 869, 936, 1003, 1070, + 1137, 1204, 1271, 1338, 1405, 1472, 1539, 1606, 1673, 1740, 1807, 1874, 1941, 2008, 2075, 2142, + 66, 133, 200, 267, 334, 401, 468, 535, 602, 669, 736, 803, 870, 937, 1004, 1071, + 1138, 1205, 1272, 1339, 1406, 1473, 1540, 1607, 1674, 1741, 1808, 1875, 1942, 2009, 2076, 2143 + ); BEGIN @@ -279,20 +407,13 @@ BEGIN state <= INTERLEAVE; END IF; - -- INTERLEAVE: Bit-level 67x32 interleaving - -- Process 8 bits per clock for throughput (268 clocks total) + -- INTERLEAVE: Bit-level 67x32 interleaving using pre-computed LUT + -- Process 1 bit per clock - slow but minimal LUTs (2144 clocks = 35us) WHEN INTERLEAVE => IF bit_idx < ENCODED_BITS THEN - -- Write 8 bits in parallel to their interleaved positions - interleaved_buffer(interleave_address(bit_idx + 0)) <= fec_buffer(bit_idx + 0); - interleaved_buffer(interleave_address(bit_idx + 1)) <= fec_buffer(bit_idx + 1); - interleaved_buffer(interleave_address(bit_idx + 2)) <= fec_buffer(bit_idx + 2); - interleaved_buffer(interleave_address(bit_idx + 3)) <= fec_buffer(bit_idx + 3); - interleaved_buffer(interleave_address(bit_idx + 4)) <= fec_buffer(bit_idx + 4); - interleaved_buffer(interleave_address(bit_idx + 5)) <= fec_buffer(bit_idx + 5); - interleaved_buffer(interleave_address(bit_idx + 6)) <= fec_buffer(bit_idx + 6); - interleaved_buffer(interleave_address(bit_idx + 7)) <= fec_buffer(bit_idx + 7); - bit_idx <= bit_idx + 8; + -- Write one bit using LUT for address lookup + interleaved_buffer(INTERLEAVE_LUT(bit_idx)) <= fec_buffer(bit_idx); + bit_idx <= bit_idx + 1; ELSE out_idx <= 0; state <= OUTPUT; From a563e0ad147c11b31fdbeac8bdebd695847597f1 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 24 Nov 2025 19:41:21 -0800 Subject: [PATCH 46/60] simulation looks good for byte level interleaver. byte vs bit now optional. --- src/msk_top.vhd | 6 +- src/ov_frame_decoder.vhd | 58 +++-- src/ov_frame_encoder.vhd | 478 ++++++++++++++++++++------------------- 3 files changed, 289 insertions(+), 253 deletions(-) diff --git a/src/msk_top.vhd b/src/msk_top.vhd index e11fbd9..cb6a1dc 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -404,7 +404,8 @@ BEGIN PAYLOAD_BYTES => 134, ENCODED_BYTES => 268, ENCODED_BITS => 2144, - BYTE_WIDTH => 8 + BYTE_WIDTH => 8, + USE_BIT_INTERLEAVER => FALSE ) PORT MAP ( clk => clk, @@ -592,7 +593,8 @@ BEGIN PAYLOAD_BYTES => 134, ENCODED_BYTES => 268, ENCODED_BITS => 2144, - BYTE_WIDTH => 8 + BYTE_WIDTH => 8, + USE_BIT_INTERLEAVER => FALSE ) PORT MAP ( clk => clk, diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd index 0cf98fe..933e2f6 100644 --- a/src/ov_frame_decoder.vhd +++ b/src/ov_frame_decoder.vhd @@ -60,10 +60,11 @@ USE ieee.numeric_std.ALL; ENTITY ov_frame_decoder IS GENERIC ( - PAYLOAD_BYTES : NATURAL := 134; -- Output frame size - ENCODED_BYTES : NATURAL := 268; -- Input frame size - ENCODED_BITS : NATURAL := 2144; -- Encoded bits (268 * 8) - BYTE_WIDTH : NATURAL := 8 + PAYLOAD_BYTES : NATURAL := 134; -- Output frame size + ENCODED_BYTES : NATURAL := 268; -- Input frame size + ENCODED_BITS : NATURAL := 2144; -- Encoded bits (268 * 8) + BYTE_WIDTH : NATURAL := 8; + USE_BIT_INTERLEAVER : BOOLEAN := TRUE -- Must match encoder setting ); PORT ( clk : IN std_logic; @@ -153,7 +154,7 @@ ARCHITECTURE rtl OF ov_frame_decoder IS SIGNAL decoder_input_g2 : std_logic_vector(2143 DOWNTO 0); SIGNAL decoder_output_buf : std_logic_vector(1071 DOWNTO 0); - -- Deinterleaver address calculation (reverse of interleaver) + -- Bit-level deinterleaver address calculation (67x32 - reverse of interleaver) FUNCTION deinterleave_address(addr : NATURAL) RETURN NATURAL IS CONSTANT ROWS : NATURAL := 67; CONSTANT COLS : NATURAL := 32; @@ -164,6 +165,18 @@ ARCHITECTURE rtl OF ov_frame_decoder IS col := addr / ROWS; RETURN row * COLS + col; END FUNCTION; + + -- Byte-level deinterleaver address calculation (67x4 - reverse of byte interleaver) + FUNCTION deinterleave_address_byte(addr : NATURAL) RETURN NATURAL IS + CONSTANT ROWS : NATURAL := 67; + CONSTANT COLS : NATURAL := 4; + VARIABLE row : NATURAL; + VARIABLE col : NATURAL; + BEGIN + row := addr MOD ROWS; + col := addr / ROWS; + RETURN row * COLS + col; + END FUNCTION; BEGIN @@ -290,16 +303,33 @@ BEGIN -- DEINTERLEAVE: Reverse the row-column shuffle WHEN DEINTERLEAVE => - IF bit_idx < ENCODED_BITS THEN - -- Unpack input_buffer bytes to bits - deinterleaved_buffer(deinterleave_address(bit_idx)) <= - input_buffer(bit_idx / 8)(bit_idx MOD 8); - bit_idx <= bit_idx + 1; + IF USE_BIT_INTERLEAVER THEN + -- BIT-LEVEL mode: Process 1 bit per clock (2144 clocks) + IF bit_idx < ENCODED_BITS THEN + -- Unpack input_buffer bytes to bits + deinterleaved_buffer(deinterleave_address(bit_idx)) <= + input_buffer(bit_idx / 8)(bit_idx MOD 8); + bit_idx <= bit_idx + 1; + ELSE + REPORT "DEINTERLEAVE complete (bit-level)"; + byte_idx <= 0; + bit_idx <= 0; + state <= PREP_FEC_DECODE; + END IF; ELSE - REPORT "DEINTERLEAVE complete"; - byte_idx <= 0; - bit_idx <= 0; - state <= PREP_FEC_DECODE; + -- BYTE-LEVEL mode: Process 1 byte per clock (268 clocks) + IF byte_idx < ENCODED_BYTES THEN + FOR j IN 0 TO 7 LOOP + deinterleaved_buffer(deinterleave_address_byte(byte_idx)*8 + j) <= + input_buffer(byte_idx)(j); + END LOOP; + byte_idx <= byte_idx + 1; + ELSE + REPORT "DEINTERLEAVE complete (byte-level)"; + byte_idx <= 0; + bit_idx <= 0; + state <= PREP_FEC_DECODE; + END IF; END IF; -- PREP_FEC_DECODE: Separate deinterleaved bits into G1 and G2 streams diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index b08d8ea..3c7de28 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -1,131 +1,50 @@ ------------------------------------------------------------------------------------------------------ +-- Opulent Voice Protocol Frame Encoder - DUAL MODE (Bit-level or Byte-level Interleaver) ------------------------------------------------------------------------------------------------------ --- _______ ________ ______ --- __ __ \________ _____ _______ ___ __ \_____ _____________ ______ ___________________ /_ --- _ / / /___ __ \_ _ \__ __ \ __ /_/ /_ _ \__ ___/_ _ \_ __ `/__ ___/_ ___/__ __ \ --- / /_/ / __ /_/ // __/_ / / / _ _, _/ / __/_(__ ) / __// /_/ / _ / / /__ _ / / / --- \____/ _ .___/ \___/ /_/ /_/ /_/ |_| \___/ /____/ \___/ \__,_/ /_/ \___/ /_/ /_/ --- /_/ --- ________ _____ _____ _____ _____ --- ____ _/_______ __________ /____(_)__ /_____ ____ /______ --- __ / __ __ \__ ___/_ __/__ / _ __/_ / / /_ __/_ _ \ --- __/ / _ / / /_(__ ) / /_ _ / / /_ / /_/ / / /_ / __/ --- /___/ /_/ /_/ /____/ \__/ /_/ \__/ \__,_/ \__/ \___/ --- ------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------- --- Copyright ------------------------------------------------------------------------------------------------------- --- --- Copyright 2025 by Open Research Institute --- ------------------------------------------------------------------------------------------------------- --- License ------------------------------------------------------------------------------------------------------- --- --- This source describes Open Hardware and is licensed under the CERN-OHL-W v2. --- --- You may redistribute and modify this source and make products using it under --- the terms of the CERN-OHL-W v2 (https://ohwr.org/cern_ohl_w_v2.txt). --- --- This source is distributed WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING --- OF MERCHANTABILITY, SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE. --- Please see the CERN-OHL-W v2 for applicable conditions. --- ------------------------------------------------------------------------------------------------------- --- Block name and description ------------------------------------------------------------------------------------------------------- --- --- Opulent Voice Protocol Frame Encoder --- --- This module implements the TX path processing for OVP frames: --- 1. Collects 134 bytes of payload from AXI-Stream input --- 2. Applies randomization (XOR with fixed sequence) --- 3. Applies FEC (rate 1/2 convolutional encoding via conv_encoder_k7) --- 4. Applies interleaving (67x32 row-column BIT interleaver) --- 5. Outputs 268 bytes (2144 bits) via AXI-Stream --- --- FIX (2025-11-24): Restored bit-level 67x32 interleaving --- Byte-level interleaving broke protocol compatibility --- Now processes 8 bits/clock for throughput (not 1 bit/clock) --- ------------------------------------------------------------------------------------------------------- +-- Supports both interleaver modes via generic parameter: +-- USE_BIT_INTERLEAVER = TRUE : 67x32 bit-level (correct protocol, requires large FPGA) +-- USE_BIT_INTERLEAVER = FALSE : 67x4 byte-level (fits PlutoSDR, breaks protocol compatibility) ------------------------------------------------------------------------------------------------------ LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.numeric_std.ALL; -ENTITY ov_frame_encoder IS +ENTITY ov_frame_encoder IS GENERIC ( - PAYLOAD_BYTES : NATURAL := 134; -- Input frame size - ENCODED_BYTES : NATURAL := 268; -- Output frame size (after FEC) - ENCODED_BITS : NATURAL := 2144; -- Encoded bits (268 * 8) - BYTE_WIDTH : NATURAL := 8 + PAYLOAD_BYTES : NATURAL := 134; + ENCODED_BYTES : NATURAL := 268; + COLLECT_SIZE : NATURAL := 4; + ENCODED_BITS : NATURAL := 2144; -- Kept for compatibility + BYTE_WIDTH : NATURAL := 8; -- Kept for compatibility + USE_BIT_INTERLEAVER : BOOLEAN := TRUE -- TRUE=bit-level(67x32), FALSE=byte-level(67x4) ); PORT ( - clk : IN std_logic; - aresetn : IN std_logic; + clk : IN std_logic; + aresetn : IN std_logic; - -- Input AXI-Stream (134-byte frames from async FIFO) - s_axis_tdata : IN std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); - s_axis_tvalid : IN std_logic; - s_axis_tready : OUT std_logic; - s_axis_tlast : IN std_logic; + -- AXI-Stream Input (from application) + s_axis_tdata : IN std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + s_axis_tvalid : IN std_logic; + s_axis_tready : OUT std_logic; + s_axis_tlast : IN std_logic; - -- Output AXI-Stream (268-byte frames to deserializer) - m_axis_tdata : OUT std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); - m_axis_tvalid : OUT std_logic; - m_axis_tready : IN std_logic; - m_axis_tlast : OUT std_logic; + -- AXI-Stream Output (to modulator) + m_axis_tdata : OUT std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); + m_axis_tvalid : OUT std_logic; + m_axis_tready : IN std_logic; + m_axis_tlast : OUT std_logic; -- Status outputs - frames_encoded : OUT std_logic_vector(31 DOWNTO 0); - encoder_active : OUT std_logic + frames_encoded : OUT std_logic_vector(31 DOWNTO 0); + encoder_active : OUT std_logic ); END ENTITY ov_frame_encoder; ARCHITECTURE rtl OF ov_frame_encoder IS - -- State machine (no PACK_FEC needed with bit-level interleaving) - TYPE state_t IS (IDLE, COLLECT, EXTRACT, RANDOMIZE, PREP_FEC, FEC_ENCODE, INTERLEAVE, OUTPUT); - SIGNAL state : state_t := IDLE; - - -- Buffer types - TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); - TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; - - -- Circular collection buffer (larger than needed to handle any transients) - CONSTANT COLLECT_SIZE : NATURAL := 256; - TYPE collect_buffer_t IS ARRAY(0 TO COLLECT_SIZE-1) OF std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); - SIGNAL collect_buffer : collect_buffer_t; - - -- Processing buffers - SIGNAL input_buffer : byte_buffer_t; - SIGNAL randomized_buffer : byte_buffer_t; - SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); - SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); -- BIT-level buffer! - - ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "block"; - - -- Index counters - SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; - SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; - SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; - SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; - - -- Frame counter - SIGNAL frame_count : UNSIGNED(31 DOWNTO 0) := (OTHERS => '0'); - - -- Output holding registers - SIGNAL m_tdata_reg : std_logic_vector(BYTE_WIDTH-1 DOWNTO 0); - SIGNAL m_tvalid_reg : std_logic; - SIGNAL m_tlast_reg : std_logic; - - -- OVP Randomizer sequence (from OVP spec) + -- Randomizer sequence from protocol specification TYPE randomizer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(7 DOWNTO 0); - -- OVP Randomizer sequence (from protocol spec - must match decoder!) CONSTANT RANDOMIZER_SEQUENCE : randomizer_t := ( x"A3", x"81", x"5C", x"C4", x"C9", x"08", x"0E", x"53", x"CC", x"A1", x"FB", x"29", x"9E", x"4F", x"16", x"E0", @@ -146,18 +65,57 @@ ARCHITECTURE rtl OF ov_frame_encoder IS x"9D", x"8E", x"E8", x"34", x"C9", x"59" ); - -- Convolutional encoder signals (matches conv_encoder_k7 interface) + TYPE state_t IS ( + IDLE, + COLLECT, + EXTRACT, + RANDOMIZE, + PREP_FEC, + FEC_ENCODE, + INTERLEAVE, + OUTPUT + ); + SIGNAL state : state_t := IDLE; + + TYPE byte_buffer_t IS ARRAY(0 TO PAYLOAD_BYTES-1) OF std_logic_vector(7 DOWNTO 0); + TYPE bit_buffer_t IS ARRAY(0 TO ENCODED_BITS-1) OF std_logic; + + SIGNAL input_buffer : byte_buffer_t; + SIGNAL randomized_buffer : byte_buffer_t; + SIGNAL fec_buffer : bit_buffer_t := (OTHERS => '0'); + SIGNAL interleaved_buffer : bit_buffer_t := (OTHERS => '0'); + + ATTRIBUTE ram_style : STRING; + ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "block"; + + -- Index counters + SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; + SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; + SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; + SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; + + -- AXI-Stream control + SIGNAL s_axis_tready_reg : std_logic := '0'; + SIGNAL m_axis_tdata_reg : std_logic_vector(BYTE_WIDTH-1 DOWNTO 0) := (OTHERS => '0'); + SIGNAL m_axis_tvalid_reg : std_logic := '0'; + SIGNAL m_axis_tlast_reg : std_logic := '0'; + + -- Status counters + SIGNAL frames_encoded_reg : unsigned(31 DOWNTO 0) := (OTHERS => '0'); + SIGNAL encoder_active_reg : std_logic := '0'; + + -- Convolutional encoder signals SIGNAL encoder_start : std_logic := '0'; SIGNAL encoder_busy : std_logic; SIGNAL encoder_done : std_logic; - SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); -- 134*8 - SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); -- 268*8 + SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); + SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); - -- BIT-LEVEL interleaver address LUT (67 rows x 32 cols) - -- Pre-computed to avoid expensive division/multiply in hardware - -- Formula: row = addr/32, col = addr%32, result = col*67 + row + ---------------------------------------------------------------------------- + -- BIT-LEVEL INTERLEAVER (67x32) - For large FPGAs, correct protocol + ---------------------------------------------------------------------------- TYPE address_lut_t IS ARRAY(0 TO 2143) OF NATURAL RANGE 0 TO 2143; - CONSTANT INTERLEAVE_LUT : address_lut_t := ( + CONSTANT INTERLEAVE_LUT_BIT : address_lut_t := ( 0, 67, 134, 201, 268, 335, 402, 469, 536, 603, 670, 737, 804, 871, 938, 1005, 1072, 1139, 1206, 1273, 1340, 1407, 1474, 1541, 1608, 1675, 1742, 1809, 1876, 1943, 2010, 2077, 1, 68, 135, 202, 269, 336, 403, 470, 537, 604, 671, 738, 805, 872, 939, 1006, @@ -293,10 +251,24 @@ ARCHITECTURE rtl OF ov_frame_encoder IS 66, 133, 200, 267, 334, 401, 468, 535, 602, 669, 736, 803, 870, 937, 1004, 1071, 1138, 1205, 1272, 1339, 1406, 1473, 1540, 1607, 1674, 1741, 1808, 1875, 1942, 2009, 2076, 2143 ); - + + ---------------------------------------------------------------------------- + -- BYTE-LEVEL INTERLEAVER (67x4) - For PlutoSDR, fits in xc7z010 + ---------------------------------------------------------------------------- + FUNCTION interleave_address_byte(addr : NATURAL) RETURN NATURAL IS + CONSTANT ROWS : NATURAL := 67; + CONSTANT COLS : NATURAL := 4; + VARIABLE row : NATURAL; + VARIABLE col : NATURAL; + BEGIN + row := addr / COLS; + col := addr MOD COLS; + RETURN col * ROWS + row; + END FUNCTION; + BEGIN - -- Convolutional Encoder Instantiation (using YOUR actual component) + -- Convolutional Encoder Instantiation U_ENCODER : ENTITY work.conv_encoder_k7 GENERIC MAP ( PAYLOAD_BYTES => PAYLOAD_BYTES, @@ -312,148 +284,180 @@ BEGIN output_buffer => encoder_output_buf ); - -- Connect output registers to ports - m_axis_tdata <= m_tdata_reg; - m_axis_tvalid <= m_tvalid_reg; - m_axis_tlast <= m_tlast_reg; - - frames_encoded <= std_logic_vector(frame_count); - encoder_active <= '1' WHEN state /= IDLE ELSE '0'; + -- AXI-Stream output assignments + s_axis_tready <= s_axis_tready_reg; + m_axis_tdata <= m_axis_tdata_reg; + m_axis_tvalid <= m_axis_tvalid_reg; + m_axis_tlast <= m_axis_tlast_reg; - -- Ready to accept data when IDLE or COLLECT - s_axis_tready <= '1' WHEN (state = IDLE OR state = COLLECT) AND aresetn = '1' ELSE '0'; - - -- Main FSM - encoder_fsm: PROCESS(clk) + -- Status outputs + frames_encoded <= std_logic_vector(frames_encoded_reg); + encoder_active <= encoder_active_reg; + + -- Main State Machine + PROCESS(clk, aresetn) + VARIABLE out_bit_idx : NATURAL RANGE 0 TO 7; BEGIN - IF rising_edge(clk) THEN - IF aresetn = '0' THEN - state <= IDLE; - collect_idx <= 0; - byte_idx <= 0; - bit_idx <= 0; - out_idx <= 0; - m_tvalid_reg <= '0'; - m_tlast_reg <= '0'; - encoder_start <= '0'; - frame_count <= (OTHERS => '0'); - ELSE - CASE state IS - -- IDLE: Wait for start of frame - WHEN IDLE => - m_tvalid_reg <= '0'; - m_tlast_reg <= '0'; - encoder_start <= '0'; - - IF s_axis_tvalid = '1' THEN - collect_buffer(0) <= s_axis_tdata; - collect_idx <= 1; - state <= COLLECT; - END IF; - - -- COLLECT: Gather bytes until tlast - WHEN COLLECT => - IF s_axis_tvalid = '1' THEN - collect_buffer(collect_idx MOD COLLECT_SIZE) <= s_axis_tdata; - collect_idx <= collect_idx + 1; - - IF s_axis_tlast = '1' THEN - byte_idx <= 0; - state <= EXTRACT; - END IF; - END IF; - - -- EXTRACT: Pull last 134 bytes from circular buffer - WHEN EXTRACT => - IF byte_idx < PAYLOAD_BYTES THEN - input_buffer(byte_idx) <= - collect_buffer((collect_idx - PAYLOAD_BYTES + byte_idx) MOD COLLECT_SIZE); - byte_idx <= byte_idx + 1; + IF aresetn = '0' THEN + state <= IDLE; + collect_idx <= 0; + byte_idx <= 0; + bit_idx <= 0; + out_idx <= 0; + s_axis_tready_reg <= '0'; + m_axis_tdata_reg <= (OTHERS => '0'); + m_axis_tvalid_reg <= '0'; + m_axis_tlast_reg <= '0'; + encoder_start <= '0'; + frames_encoded_reg <= (OTHERS => '0'); + encoder_active_reg <= '0'; + + ELSIF rising_edge(clk) THEN + encoder_start <= '0'; + + CASE state IS + + -- IDLE: Wait for input + WHEN IDLE => + s_axis_tready_reg <= '1'; + m_axis_tvalid_reg <= '0'; + m_axis_tlast_reg <= '0'; + encoder_active_reg <= '0'; + IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN + input_buffer(0) <= s_axis_tdata; + collect_idx <= 1; + encoder_active_reg <= '1'; + state <= COLLECT; + END IF; + + -- COLLECT: Gather 4 bytes before proceeding + WHEN COLLECT => + IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN + input_buffer(collect_idx) <= s_axis_tdata; + IF collect_idx = COLLECT_SIZE - 1 THEN + collect_idx <= COLLECT_SIZE; -- Continue from position 4, not 0 + s_axis_tready_reg <= '0'; + state <= EXTRACT; ELSE - byte_idx <= 0; - state <= RANDOMIZE; + collect_idx <= collect_idx + 1; END IF; - - -- RANDOMIZE: XOR with randomizer sequence - WHEN RANDOMIZE => - IF byte_idx < PAYLOAD_BYTES THEN - randomized_buffer(byte_idx) <= - input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); - byte_idx <= byte_idx + 1; - ELSE - byte_idx <= 0; - state <= PREP_FEC; + END IF; + + -- EXTRACT: Continue collecting remaining bytes + WHEN EXTRACT => + IF collect_idx < PAYLOAD_BYTES THEN + s_axis_tready_reg <= '1'; + IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN + input_buffer(collect_idx) <= s_axis_tdata; + collect_idx <= collect_idx + 1; END IF; - - -- PREP_FEC: Pack bytes into encoder input vector - WHEN PREP_FEC => - FOR i IN 0 TO PAYLOAD_BYTES-1 LOOP - FOR j IN 0 TO 7 LOOP - encoder_input_buf(i*8 + j) <= randomized_buffer(i)(j); - END LOOP; + ELSE + s_axis_tready_reg <= '0'; + byte_idx <= 0; + state <= RANDOMIZE; + END IF; + + -- RANDOMIZE: XOR with randomizer sequence + WHEN RANDOMIZE => + IF byte_idx < PAYLOAD_BYTES THEN + randomized_buffer(byte_idx) <= + input_buffer(byte_idx) XOR RANDOMIZER_SEQUENCE(byte_idx); + byte_idx <= byte_idx + 1; + ELSE + byte_idx <= 0; + state <= PREP_FEC; + END IF; + + -- PREP_FEC: Pack randomized bytes into encoder input buffer + WHEN PREP_FEC => + IF byte_idx < PAYLOAD_BYTES THEN + FOR j IN 0 TO 7 LOOP + encoder_input_buf(byte_idx*8 + j) <= randomized_buffer(byte_idx)(j); END LOOP; + byte_idx <= byte_idx + 1; + ELSE encoder_start <= '1'; state <= FEC_ENCODE; - - -- FEC_ENCODE: Wait for convolutional encoder to complete - WHEN FEC_ENCODE => - encoder_start <= '0'; - IF encoder_done = '1' THEN - -- Unpack encoded bits into fec_buffer - FOR i IN 0 TO ENCODED_BITS-1 LOOP - fec_buffer(i) <= encoder_output_buf(ENCODED_BITS - 1 - i); -- MSB-first - END LOOP; + END IF; + + -- FEC_ENCODE: Wait for convolutional encoder to complete + WHEN FEC_ENCODE => + encoder_start <= '0'; + IF encoder_done = '1' THEN + -- Copy encoder output to fec_buffer (MSB-first to bit-buffer) + FOR i IN 0 TO ENCODED_BITS-1 LOOP + fec_buffer(i) <= encoder_output_buf(ENCODED_BITS - 1 - i); + END LOOP; + + IF USE_BIT_INTERLEAVER THEN bit_idx <= 0; - state <= INTERLEAVE; + ELSE + byte_idx <= 0; END IF; - - -- INTERLEAVE: Bit-level 67x32 interleaving using pre-computed LUT - -- Process 1 bit per clock - slow but minimal LUTs (2144 clocks = 35us) - WHEN INTERLEAVE => + state <= INTERLEAVE; + END IF; + + ------------------------------------------------------------------------ + -- INTERLEAVE: Dual-mode implementation + ------------------------------------------------------------------------ + WHEN INTERLEAVE => + IF USE_BIT_INTERLEAVER THEN + -- BIT-LEVEL mode: Process 1 bit per clock (2144 clocks) IF bit_idx < ENCODED_BITS THEN - -- Write one bit using LUT for address lookup - interleaved_buffer(INTERLEAVE_LUT(bit_idx)) <= fec_buffer(bit_idx); + interleaved_buffer(INTERLEAVE_LUT_BIT(bit_idx)) <= fec_buffer(bit_idx); bit_idx <= bit_idx + 1; ELSE out_idx <= 0; state <= OUTPUT; - m_tvalid_reg <= '0'; + m_axis_tvalid_reg <= '0'; END IF; - - -- OUTPUT: Send 268 bytes via AXI-Stream - -- Pack 8 bits from interleaved buffer into each output byte - WHEN OUTPUT => - IF out_idx < ENCODED_BYTES THEN - m_tdata_reg(0) <= interleaved_buffer(out_idx * 8 + 0); - m_tdata_reg(1) <= interleaved_buffer(out_idx * 8 + 1); - m_tdata_reg(2) <= interleaved_buffer(out_idx * 8 + 2); - m_tdata_reg(3) <= interleaved_buffer(out_idx * 8 + 3); - m_tdata_reg(4) <= interleaved_buffer(out_idx * 8 + 4); - m_tdata_reg(5) <= interleaved_buffer(out_idx * 8 + 5); - m_tdata_reg(6) <= interleaved_buffer(out_idx * 8 + 6); - m_tdata_reg(7) <= interleaved_buffer(out_idx * 8 + 7); + ELSE + -- BYTE-LEVEL mode: Process 1 byte per clock (268 clocks) + IF byte_idx < ENCODED_BYTES THEN + FOR j IN 0 TO 7 LOOP + interleaved_buffer(interleave_address_byte(byte_idx)*8 + j) <= + fec_buffer(byte_idx*8 + j); + END LOOP; + byte_idx <= byte_idx + 1; + ELSE + out_idx <= 0; + state <= OUTPUT; + m_axis_tvalid_reg <= '0'; + END IF; + END IF; + + -- OUTPUT: Stream interleaved bytes to modulator + WHEN OUTPUT => + IF out_idx < ENCODED_BYTES THEN + IF m_axis_tready = '1' OR m_axis_tvalid_reg = '0' THEN + -- Pack 8 bits from interleaved_buffer into output byte + FOR j IN 0 TO 7 LOOP + out_bit_idx := out_idx*8 + j; + m_axis_tdata_reg(j) <= interleaved_buffer(out_bit_idx); + END LOOP; + m_axis_tvalid_reg <= '1'; - m_tvalid_reg <= '1'; - IF out_idx = (ENCODED_BYTES - 1) THEN - m_tlast_reg <= '1'; + -- Assert tlast on final byte + IF out_idx = ENCODED_BYTES - 1 THEN + m_axis_tlast_reg <= '1'; ELSE - m_tlast_reg <= '0'; + m_axis_tlast_reg <= '0'; END IF; - IF m_axis_tready = '1' THEN - IF out_idx = (ENCODED_BYTES - 1) THEN - frame_count <= frame_count + 1; - state <= IDLE; - m_tvalid_reg <= '0'; - ELSE - out_idx <= out_idx + 1; - END IF; - END IF; + out_idx <= out_idx + 1; END IF; - - END CASE; - END IF; + ELSE + IF m_axis_tready = '1' THEN + m_axis_tvalid_reg <= '0'; + m_axis_tlast_reg <= '0'; + frames_encoded_reg <= frames_encoded_reg + 1; + collect_idx <= 0; + state <= IDLE; + END IF; + END IF; + + END CASE; END IF; - END PROCESS encoder_fsm; + END PROCESS; END ARCHITECTURE rtl; From 2cc8fa595d9fd89c6ee4958504bb042c87a7d0b9 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Tue, 25 Nov 2025 09:56:43 -0800 Subject: [PATCH 47/60] simulation now working with yet again the count back from tlast method working for us. added a lot of comments about this to the source code. --- src/ov_frame_encoder.vhd | 176 ++++++++++++++++++++++++++++++++------- 1 file changed, 144 insertions(+), 32 deletions(-) diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 3c7de28..b26f49c 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -5,6 +5,35 @@ -- USE_BIT_INTERLEAVER = TRUE : 67x32 bit-level (correct protocol, requires large FPGA) -- USE_BIT_INTERLEAVER = FALSE : 67x4 byte-level (fits PlutoSDR, breaks protocol compatibility) ------------------------------------------------------------------------------------------------------ +-- CRITICAL DESIGN PRINCIPLE: TLAST-DRIVEN FRAME COLLECTION +------------------------------------------------------------------------------------------------------ +-- This encoder uses AXI-Stream TLAST signal to detect frame boundaries, NOT fixed byte counting! +-- +-- WHY THIS MATTERS: +-- When data flows continuously (e.g., FIFO buffering multiple frames), counting to a fixed +-- number of bytes and ignoring tlast causes the encoder to "steal" bytes from the next frame. +-- This creates cascading byte loss: +-- Frame 3: Missing byte 0 (stolen during Frame 2 collection) +-- Frame 4: Missing bytes 0-1 (stolen during Frame 3 collection) +-- Frame 5: Missing bytes 0-2 (stolen during Frame 4 collection) +-- ... continues until no more data available +-- +-- CORRECT APPROACH (implemented here): +-- 1. IDLE state: Wait for first byte +-- 2. COLLECT state: Accept bytes until s_axis_tlast = '1' (frame boundary marker) +-- 3. Validate we got exactly PAYLOAD_BYTES (134) +-- 4. Process the complete frame through randomization, FEC, interleaving +-- 5. Pre-set s_axis_tready = '1' before returning to IDLE for next frame +-- +-- This approach: +-- ? Respects AXI-Stream protocol (tlast marks frame boundaries) +-- ? Works with continuous data streams (FIFO buffering) +-- ? Prevents byte stealing across frame boundaries +-- ? Validates frame size for error detection +-- ? Works for BOTH bit-level and byte-level interleaving modes +-- +-- NEVER count to a fixed byte number and ignore tlast - this violates AXI-Stream protocol! +------------------------------------------------------------------------------------------------------ LIBRARY ieee; USE ieee.std_logic_1164.ALL; @@ -14,7 +43,7 @@ ENTITY ov_frame_encoder IS GENERIC ( PAYLOAD_BYTES : NATURAL := 134; ENCODED_BYTES : NATURAL := 268; - COLLECT_SIZE : NATURAL := 4; + COLLECT_SIZE : NATURAL := 4; -- DEPRECATED: No longer used (kept for compatibility) ENCODED_BITS : NATURAL := 2144; -- Kept for compatibility BYTE_WIDTH : NATURAL := 8; -- Kept for compatibility USE_BIT_INTERLEAVER : BOOLEAN := TRUE -- TRUE=bit-level(67x32), FALSE=byte-level(67x4) @@ -65,15 +94,37 @@ ARCHITECTURE rtl OF ov_frame_encoder IS x"9D", x"8E", x"E8", x"34", x"C9", x"59" ); + ------------------------------------------------------------------------------ + -- STATE MACHINE DESIGN PHILOSOPHY + ------------------------------------------------------------------------------ + -- CRITICAL: This encoder uses TLAST-DRIVEN frame detection, NOT fixed byte counting! + -- + -- WHY: AXI-Stream protocol uses tlast to mark frame boundaries. Ignoring tlast + -- causes the encoder to "steal" bytes from the next frame when data is + -- continuously available (e.g., from a buffering FIFO). This creates + -- cascading byte loss errors across multiple frames. + -- + -- COLLECT state strategy: + -- 1. Accept bytes one at a time + -- 2. Store each byte in input_buffer[collect_idx] + -- 3. Watch for s_axis_tlast = '1' (frame boundary) + -- 4. When tlast seen, validate we got PAYLOAD_BYTES (134), then process + -- + -- This works for BOTH byte-level and bit-level interleaving modes because: + -- - Collection only fills input_buffer + -- - Interleaving happens later (INTERLEAVE state) on FEC-encoded bits + -- - Interleaver type doesn't affect how we collect input bytes + -- + -- NEVER count to a fixed number and ignore tlast - this violates AXI protocol! + ------------------------------------------------------------------------------ TYPE state_t IS ( - IDLE, - COLLECT, - EXTRACT, - RANDOMIZE, - PREP_FEC, - FEC_ENCODE, - INTERLEAVE, - OUTPUT + IDLE, -- Wait for first byte of frame + COLLECT, -- Gather bytes until tlast (AXI-Stream frame boundary marker) + RANDOMIZE, -- XOR with randomizer sequence + PREP_FEC, -- Prepare for convolutional encoding + FEC_ENCODE, -- Apply K=7 convolutional code + INTERLEAVE, -- Shuffle bits (bit-level) or bytes (byte-level) per generic + OUTPUT -- Stream encoded frame to modulator ); SIGNAL state : state_t := IDLE; @@ -89,7 +140,7 @@ ARCHITECTURE rtl OF ov_frame_encoder IS ATTRIBUTE ram_style OF interleaved_buffer : SIGNAL IS "block"; -- Index counters - SIGNAL collect_idx : NATURAL RANGE 0 TO COLLECT_SIZE; + SIGNAL collect_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; -- Now collects all bytes until tlast SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; @@ -317,46 +368,95 @@ BEGIN CASE state IS - -- IDLE: Wait for input + ---------------------------------------------------------------------- + -- IDLE: Wait for first byte of frame + ---------------------------------------------------------------------- + -- Ready to accept data. When valid data arrives, capture first byte + -- and check for tlast (single-byte frame, unlikely but possible). + ---------------------------------------------------------------------- WHEN IDLE => - s_axis_tready_reg <= '1'; + s_axis_tready_reg <= '1'; -- Always ready in IDLE m_axis_tvalid_reg <= '0'; m_axis_tlast_reg <= '0'; encoder_active_reg <= '0'; + IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN + -- Capture first byte input_buffer(0) <= s_axis_tdata; collect_idx <= 1; encoder_active_reg <= '1'; - state <= COLLECT; + + -- Check for single-byte frame (shouldn't happen for 134-byte frames) + IF s_axis_tlast = '1' THEN + s_axis_tready_reg <= '0'; + REPORT "Single-byte frame detected (unexpected)" SEVERITY WARNING; + byte_idx <= 0; + state <= RANDOMIZE; + ELSE + state <= COLLECT; + END IF; END IF; - -- COLLECT: Gather 4 bytes before proceeding + + ---------------------------------------------------------------------- + -- COLLECT: Gather bytes until tlast (AXI-Stream frame boundary) + ---------------------------------------------------------------------- + -- This is the CRITICAL state that prevents byte loss! + -- + -- Strategy: + -- - Keep s_axis_tready = 1 (accept data) + -- - Capture each byte to input_buffer[collect_idx] + -- - Increment collect_idx + -- - WATCH FOR TLAST (frame boundary marker) + -- - When tlast seen, validate frame size and proceed to encoding + -- + -- Why not count to 134 and ignore tlast? + -- Because when FIFO has next frame buffered, we'd keep accepting + -- bytes past the frame boundary, "stealing" from the next frame. + -- This causes cascading byte loss (Frame 3 missing byte 0, + -- Frame 4 missing bytes 0-1, etc.) + -- + -- TLAST is the ONLY reliable frame boundary in AXI-Stream protocol! + ---------------------------------------------------------------------- WHEN COLLECT => + s_axis_tready_reg <= '1'; -- Keep accepting data + IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN + -- Capture byte input_buffer(collect_idx) <= s_axis_tdata; - IF collect_idx = COLLECT_SIZE - 1 THEN - collect_idx <= COLLECT_SIZE; -- Continue from position 4, not 0 + + -- Check for frame boundary (tlast = end of frame) + IF s_axis_tlast = '1' THEN + -- Frame complete! Stop accepting data s_axis_tready_reg <= '0'; - state <= EXTRACT; + + -- Validate frame size (collect_idx is 0-indexed, so +1 for count) + IF collect_idx + 1 /= PAYLOAD_BYTES THEN + REPORT "Frame size mismatch: expected " & + INTEGER'IMAGE(PAYLOAD_BYTES) & " bytes, got " & + INTEGER'IMAGE(collect_idx + 1) & " bytes" + SEVERITY WARNING; + END IF; + + -- Proceed to randomization (even if size is wrong, try to process) + byte_idx <= 0; + state <= RANDOMIZE; ELSE + -- Not end of frame yet, continue collecting collect_idx <= collect_idx + 1; + + -- Safety check: prevent buffer overflow + IF collect_idx >= PAYLOAD_BYTES - 1 THEN + REPORT "Collected " & INTEGER'IMAGE(PAYLOAD_BYTES) & + " bytes but tlast not seen yet! Frame too large!" + SEVERITY ERROR; + s_axis_tready_reg <= '0'; + byte_idx <= 0; + state <= RANDOMIZE; -- Try to process what we have + END IF; END IF; END IF; - -- EXTRACT: Continue collecting remaining bytes - WHEN EXTRACT => - IF collect_idx < PAYLOAD_BYTES THEN - s_axis_tready_reg <= '1'; - IF s_axis_tvalid = '1' AND s_axis_tready_reg = '1' THEN - input_buffer(collect_idx) <= s_axis_tdata; - collect_idx <= collect_idx + 1; - END IF; - ELSE - s_axis_tready_reg <= '0'; - byte_idx <= 0; - state <= RANDOMIZE; - END IF; - -- RANDOMIZE: XOR with randomizer sequence WHEN RANDOMIZE => IF byte_idx < PAYLOAD_BYTES THEN @@ -426,7 +526,12 @@ BEGIN END IF; END IF; + ---------------------------------------------------------------------- -- OUTPUT: Stream interleaved bytes to modulator + ---------------------------------------------------------------------- + -- Send encoded frame one byte at a time via AXI-Stream. + -- Assert tlast on final byte to mark frame boundary. + ---------------------------------------------------------------------- WHEN OUTPUT => IF out_idx < ENCODED_BYTES THEN IF m_axis_tready = '1' OR m_axis_tvalid_reg = '0' THEN @@ -437,7 +542,7 @@ BEGIN END LOOP; m_axis_tvalid_reg <= '1'; - -- Assert tlast on final byte + -- Assert tlast on final byte (AXI-Stream frame boundary) IF out_idx = ENCODED_BYTES - 1 THEN m_axis_tlast_reg <= '1'; ELSE @@ -447,9 +552,16 @@ BEGIN out_idx <= out_idx + 1; END IF; ELSE + -- Frame output complete IF m_axis_tready = '1' THEN m_axis_tvalid_reg <= '0'; m_axis_tlast_reg <= '0'; + + -- Pre-set ready for next frame BEFORE going to IDLE + -- This ensures s_axis_tready is already high when we + -- enter IDLE, preventing one-clock delay in handshake + s_axis_tready_reg <= '1'; + frames_encoded_reg <= frames_encoded_reg + 1; collect_idx <= 0; state <= IDLE; From 247beadb3597de6dc21dd9ceb8022247a0fba546 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Wed, 26 Nov 2025 08:40:30 -0800 Subject: [PATCH 48/60] experiment to isolate encoder as source of lab hardware transmitter stall --- src/axis_async_fifo.vhd | 4 +++ src/msk_top.vhd | 70 ++++++++++++++++++++++------------------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/axis_async_fifo.vhd b/src/axis_async_fifo.vhd index 311a24d..28ccfbb 100644 --- a/src/axis_async_fifo.vhd +++ b/src/axis_async_fifo.vhd @@ -157,6 +157,8 @@ BEGIN full_int <= '0'; tready_int <= '0'; prog_full_int <= '0'; + rd_ptr_gray_sync1 <= (OTHERS => '0'); + rd_ptr_gray_sync2 <= (OTHERS => '0'); ELSE -- Synchronize read pointer @@ -221,6 +223,8 @@ BEGIN prog_empty_int <= '1'; m_axis_tdata <= (OTHERS => '0'); m_axis_tlast <= '0'; + wr_ptr_gray_sync1 <= (OTHERS => '0'); + wr_ptr_gray_sync2 <= (OTHERS => '0'); ELSE -- Synchronize write pointer diff --git a/src/msk_top.vhd b/src/msk_top.vhd index cb6a1dc..99edfed 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -399,34 +399,34 @@ BEGIN -- This will be corrected in Phase 2 when PS side is updated to send 134-byte frames ------------------------------------------------------------------------------------------------------ - u_ov_encoder : ENTITY work.ov_frame_encoder - GENERIC MAP ( - PAYLOAD_BYTES => 134, - ENCODED_BYTES => 268, - ENCODED_BITS => 2144, - BYTE_WIDTH => 8, - USE_BIT_INTERLEAVER => FALSE - ) - PORT MAP ( - clk => clk, - aresetn => NOT txinit, - - -- Input from FIFO - s_axis_tdata => fifo_tdata, - s_axis_tvalid => fifo_tvalid, - s_axis_tready => fifo_tready, - s_axis_tlast => fifo_tlast, - - -- Output to deserializer - m_axis_tdata => encoder_tdata, - m_axis_tvalid => encoder_tvalid, - m_axis_tready => encoder_tready, - m_axis_tlast => encoder_tlast, - - -- Status - frames_encoded => tx_frames_encoded, - encoder_active => tx_encoder_active - ); +-- u_ov_encoder : ENTITY work.ov_frame_encoder +-- GENERIC MAP ( +-- PAYLOAD_BYTES => 134, +-- ENCODED_BYTES => 268, +-- ENCODED_BITS => 2144, +-- BYTE_WIDTH => 8, +-- USE_BIT_INTERLEAVER => FALSE +-- ) +-- PORT MAP ( +-- clk => clk, +-- aresetn => NOT txinit, +-- +-- -- Input from FIFO +-- s_axis_tdata => fifo_tdata, +-- s_axis_tvalid => fifo_tvalid, +-- s_axis_tready => fifo_tready, +-- s_axis_tlast => fifo_tlast, +-- +-- -- Output to deserializer +-- m_axis_tdata => encoder_tdata, +-- m_axis_tvalid => encoder_tvalid, +-- m_axis_tready => encoder_tready, +-- m_axis_tlast => encoder_tlast, +-- +-- -- Status +-- frames_encoded => tx_frames_encoded, +-- encoder_active => tx_encoder_active +-- ); -- Stage 4: Byte-to-Bit De-serializer (MSB-FIRST VERSION) u_deserializer : ENTITY work.byte_to_bit_deserializer @@ -438,10 +438,16 @@ BEGIN init => txinit, -- Input from encoder (was: from FIFO) - s_axis_tdata => encoder_tdata, - s_axis_tvalid => encoder_tvalid, - s_axis_tready => encoder_tready, - s_axis_tlast => encoder_tlast, + --s_axis_tdata => encoder_tdata, + --s_axis_tvalid => encoder_tvalid, + --s_axis_tready => encoder_tready, + --s_axis_tlast => encoder_tlast, + + s_axis_tdata => fifo_tdata, + s_axis_tvalid => fifo_tvalid, + s_axis_tready => fifo_tready, + s_axis_tlast => fifo_tlast, + tx_data => tx_data_bit, tx_req => tx_req, From cd5f27cdc9adc550c9c1c01bef4b0187273522b4 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 27 Nov 2025 11:03:52 -0800 Subject: [PATCH 49/60] decoder created a stall with no gaps between frames. this is a fix for that. works in encoder-decoder testbench and end-to-end testbench. --- src/msk_top.vhd | 75 ++++++++++++++++--------------- src/ov_frame_decoder.vhd | 21 ++++++++- src/viterbi_decoder_k7_simple.vhd | 12 +++-- 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 99edfed..cabc9ee 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -399,34 +399,34 @@ BEGIN -- This will be corrected in Phase 2 when PS side is updated to send 134-byte frames ------------------------------------------------------------------------------------------------------ --- u_ov_encoder : ENTITY work.ov_frame_encoder --- GENERIC MAP ( --- PAYLOAD_BYTES => 134, --- ENCODED_BYTES => 268, --- ENCODED_BITS => 2144, --- BYTE_WIDTH => 8, --- USE_BIT_INTERLEAVER => FALSE --- ) --- PORT MAP ( --- clk => clk, --- aresetn => NOT txinit, --- --- -- Input from FIFO --- s_axis_tdata => fifo_tdata, --- s_axis_tvalid => fifo_tvalid, --- s_axis_tready => fifo_tready, --- s_axis_tlast => fifo_tlast, --- --- -- Output to deserializer --- m_axis_tdata => encoder_tdata, --- m_axis_tvalid => encoder_tvalid, --- m_axis_tready => encoder_tready, --- m_axis_tlast => encoder_tlast, --- --- -- Status --- frames_encoded => tx_frames_encoded, --- encoder_active => tx_encoder_active --- ); + u_ov_encoder : ENTITY work.ov_frame_encoder + GENERIC MAP ( + PAYLOAD_BYTES => 134, + ENCODED_BYTES => 268, + ENCODED_BITS => 2144, + BYTE_WIDTH => 8, + USE_BIT_INTERLEAVER => FALSE + ) + PORT MAP ( + clk => clk, + aresetn => NOT txinit, + + -- Input from FIFO + s_axis_tdata => fifo_tdata, + s_axis_tvalid => fifo_tvalid, + s_axis_tready => fifo_tready, + s_axis_tlast => fifo_tlast, + + -- Output to deserializer + m_axis_tdata => encoder_tdata, + m_axis_tvalid => encoder_tvalid, + m_axis_tready => encoder_tready, + m_axis_tlast => encoder_tlast, + + -- Status + frames_encoded => tx_frames_encoded, + encoder_active => tx_encoder_active + ); -- Stage 4: Byte-to-Bit De-serializer (MSB-FIRST VERSION) u_deserializer : ENTITY work.byte_to_bit_deserializer @@ -438,15 +438,16 @@ BEGIN init => txinit, -- Input from encoder (was: from FIFO) - --s_axis_tdata => encoder_tdata, - --s_axis_tvalid => encoder_tvalid, - --s_axis_tready => encoder_tready, - --s_axis_tlast => encoder_tlast, - - s_axis_tdata => fifo_tdata, - s_axis_tvalid => fifo_tvalid, - s_axis_tready => fifo_tready, - s_axis_tlast => fifo_tlast, + s_axis_tdata => encoder_tdata, + s_axis_tvalid => encoder_tvalid, + s_axis_tready => encoder_tready, + s_axis_tlast => encoder_tlast, + + -- if you want to bypass the encoder, then comment out encoder above and use this: + --s_axis_tdata => fifo_tdata, + --s_axis_tvalid => fifo_tvalid, + --s_axis_tready => fifo_tready, + --s_axis_tlast => fifo_tlast, tx_data => tx_data_bit, diff --git a/src/ov_frame_decoder.vhd b/src/ov_frame_decoder.vhd index 933e2f6..5e2e8eb 100644 --- a/src/ov_frame_decoder.vhd +++ b/src/ov_frame_decoder.vhd @@ -51,6 +51,13 @@ -- - This handles FIFO timing issues naturally -- - Never try to time the "first" byte arrival -- +-- VITERBI HANDSHAKE FIX (2025-11-26): Fixed race condition in PREP_FEC_DECODE +-- - decoder_start was only HIGH for 1 clock cycle +-- - If Viterbi was still in COMPLETE state, it missed the pulse +-- - Now holds decoder_start HIGH until decoder_busy='1' +-- - This ensures proper handshake regardless of Viterbi state +-- - Bug only appeared with back-to-back frames (no inter-frame gap) +-- ------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------ @@ -333,13 +340,25 @@ BEGIN END IF; -- PREP_FEC_DECODE: Separate deinterleaved bits into G1 and G2 streams + -- and start the Viterbi decoder with proper handshaking WHEN PREP_FEC_DECODE => + -- Setup G1/G2 streams for Viterbi decoder FOR i IN 0 TO ENCODED_BITS/2 - 1 LOOP decoder_input_g1(i) <= deinterleaved_buffer(i*2); decoder_input_g2(i) <= deinterleaved_buffer(i*2 + 1); END LOOP; + + -- Assert start and WAIT for Viterbi to acknowledge via busy signal + -- FIX: Previously decoder_start was only high for 1 clock cycle. + -- If the Viterbi decoder was still in COMPLETE state (transitioning + -- to IDLE), it would miss the start pulse entirely, causing the + -- frame decoder to wait forever for decoder_done. + -- Now we hold decoder_start high until decoder_busy confirms + -- the Viterbi has accepted the request. decoder_start <= '1'; - state <= FEC_DECODE; + IF decoder_busy = '1' THEN + state <= FEC_DECODE; + END IF; WHEN FEC_DECODE => decoder_start <= '0'; diff --git a/src/viterbi_decoder_k7_simple.vhd b/src/viterbi_decoder_k7_simple.vhd index 9a52bbb..d1a8a82 100644 --- a/src/viterbi_decoder_k7_simple.vhd +++ b/src/viterbi_decoder_k7_simple.vhd @@ -43,8 +43,11 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS SIGNAL state : state_t := IDLE; TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF unsigned(METRIC_WIDTH-1 DOWNTO 0); - SIGNAL metrics_current : metric_array_t; - SIGNAL metrics_next : metric_array_t; + -- added initialization to try to get simulation to stop stalling on second frame + SIGNAL metrics_current : metric_array_t := (OTHERS => (OTHERS => '0')); + SIGNAL metrics_next : metric_array_t := (OTHERS => (OTHERS => '0')); + --SIGNAL metrics_current : metric_array_t; + --SIGNAL metrics_next : metric_array_t; --CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; --TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; @@ -164,13 +167,16 @@ BEGIN busy <= '0'; done <= '0'; dec_wr_en <= '0'; + time_step <= 0; + state_idx <= 0; + metrics_next <= (OTHERS => (OTHERS => '0')); ELSIF rising_edge(clk) THEN done <= '0'; dec_wr_en <= '0'; CASE state IS - + WHEN IDLE => busy <= '0'; IF start = '1' THEN From 44356f26425e3033648d7e03e42ba19e0fdb7a3c Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 27 Nov 2025 16:26:25 -0800 Subject: [PATCH 50/60] Change the encoder to deassert tvalid unconditionally after frame completion. Don't wait for tready. --- src/ov_frame_encoder.vhd | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index b26f49c..0bb4865 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -553,19 +553,20 @@ BEGIN END IF; ELSE -- Frame output complete - IF m_axis_tready = '1' THEN - m_axis_tvalid_reg <= '0'; - m_axis_tlast_reg <= '0'; - - -- Pre-set ready for next frame BEFORE going to IDLE - -- This ensures s_axis_tready is already high when we - -- enter IDLE, preventing one-clock delay in handshake - s_axis_tready_reg <= '1'; - - frames_encoded_reg <= frames_encoded_reg + 1; - collect_idx <= 0; - state <= IDLE; - END IF; + -- FIX: Deassert tvalid immediately, don't wait for tready! + -- The last byte's handshake already completed (that's how we got here). + -- Waiting for tready creates a race with the deserializer. + m_axis_tvalid_reg <= '0'; + m_axis_tlast_reg <= '0'; + + -- Pre-set ready for next frame BEFORE going to IDLE + -- This ensures s_axis_tready is already high when we + -- enter IDLE, preventing one-clock delay in handshake + s_axis_tready_reg <= '1'; + + frames_encoded_reg <= frames_encoded_reg + 1; + collect_idx <= 0; + state <= IDLE; END IF; END CASE; From 501c991882773ea04009136b87486f998852cad1 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 27 Nov 2025 16:30:10 -0800 Subject: [PATCH 51/60] Revert "Change the encoder to deassert tvalid unconditionally after frame completion. Don't wait for tready." because it did not work in simulation. This reverts commit 44356f26425e3033648d7e03e42ba19e0fdb7a3c. --- src/ov_frame_encoder.vhd | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index 0bb4865..b26f49c 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -553,20 +553,19 @@ BEGIN END IF; ELSE -- Frame output complete - -- FIX: Deassert tvalid immediately, don't wait for tready! - -- The last byte's handshake already completed (that's how we got here). - -- Waiting for tready creates a race with the deserializer. - m_axis_tvalid_reg <= '0'; - m_axis_tlast_reg <= '0'; - - -- Pre-set ready for next frame BEFORE going to IDLE - -- This ensures s_axis_tready is already high when we - -- enter IDLE, preventing one-clock delay in handshake - s_axis_tready_reg <= '1'; - - frames_encoded_reg <= frames_encoded_reg + 1; - collect_idx <= 0; - state <= IDLE; + IF m_axis_tready = '1' THEN + m_axis_tvalid_reg <= '0'; + m_axis_tlast_reg <= '0'; + + -- Pre-set ready for next frame BEFORE going to IDLE + -- This ensures s_axis_tready is already high when we + -- enter IDLE, preventing one-clock delay in handshake + s_axis_tready_reg <= '1'; + + frames_encoded_reg <= frames_encoded_reg + 1; + collect_idx <= 0; + state <= IDLE; + END IF; END IF; END CASE; From 77336cb046f8b4959c6bcd6eb940a221386f3dd8 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Thu, 27 Nov 2025 18:35:05 -0800 Subject: [PATCH 52/60] Prevent Vivado from optimizing away data paths. I think synthesis was tracing through the PRBS mux and determining that the entire TX data path was unused, and then removed the deserializer, the encoder_tdata buses, fifo_tadatoutputs (which gave a no routable loads warning that tipped me off) and tx_data_bit signal. Added do not touch attributes to preserve evertyhing. This may have been the reason we were stalling. --- src/msk_top.vhd | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/msk_top.vhd b/src/msk_top.vhd index cabc9ee..6ffd5cb 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -328,6 +328,17 @@ ARCHITECTURE struct OF msk_top IS ATTRIBUTE dont_touch : STRING; ATTRIBUTE dont_touch OF u_async_fifo : LABEL IS "true"; ATTRIBUTE dont_touch OF u_rx_async_fifo : LABEL IS "true"; + ATTRIBUTE dont_touch OF u_ov_encoder : LABEL IS "true"; + ATTRIBUTE dont_touch OF u_deserializer : LABEL IS "true"; + ATTRIBUTE dont_touch OF tx_data_bit : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF fifo_tdata : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF fifo_tvalid : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF fifo_tready : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF fifo_tlast : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF encoder_tdata : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF encoder_tvalid : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF encoder_tready : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF encoder_tlast : SIGNAL IS "true"; BEGIN ------------------------------------------------------------------------------------------------------ From e2a45a7f8ec891974f9748323f97a63ca821886f Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Sun, 30 Nov 2025 23:20:46 -0800 Subject: [PATCH 53/60] transmitter stall resolved. had 134 as loop limit when needed 268. --- src/byte_to_bit_deserializer.vhd | 8 + src/conv_encoder_k7.vhd | 189 ++++++++------- src/msk_top.vhd | 53 ++++- src/msk_top_csr.vhd | 44 +++- src/ov_frame_encoder.vhd | 369 ++++++++++++++++-------------- src/viterbi_decoder_k7_simple.vhd | 82 +++---- 6 files changed, 409 insertions(+), 336 deletions(-) diff --git a/src/byte_to_bit_deserializer.vhd b/src/byte_to_bit_deserializer.vhd index 74cc3f6..a77c208 100644 --- a/src/byte_to_bit_deserializer.vhd +++ b/src/byte_to_bit_deserializer.vhd @@ -48,6 +48,14 @@ ARCHITECTURE rtl OF byte_to_bit_deserializer IS TYPE state_t IS (IDLE, SENDING_SYNC, SHIFTING_DATA); SIGNAL state : state_t; +-- ATTRIBUTE dont_touch : STRING; +-- ATTRIBUTE dont_touch OF state : SIGNAL IS "true"; +-- ATTRIBUTE dont_touch OF ready_int : SIGNAL IS "true"; +-- ATTRIBUTE dont_touch OF last_byte : SIGNAL IS "true"; +-- ATTRIBUTE dont_touch OF shift_reg : SIGNAL IS "true"; +-- ATTRIBUTE dont_touch OF bit_counter : SIGNAL IS "true"; + + BEGIN s_axis_tready <= ready_int; diff --git a/src/conv_encoder_k7.vhd b/src/conv_encoder_k7.vhd index 1cc624a..9c052cf 100644 --- a/src/conv_encoder_k7.vhd +++ b/src/conv_encoder_k7.vhd @@ -1,9 +1,18 @@ ------------------------------------------------------------------------------------------------------ --- K=7 Convolutional Encoder (FIXED - No Signal Timing Bugs) +-- K=7 Convolutional Encoder - Shift Register Version (Corrected Polynomials) ------------------------------------------------------------------------------------------------------ -- Rate 1/2, constraint length K=7 --- Generator polynomials: G1 = 171 octal = 1111001 binary --- G2 = 133 octal = 1011011 binary +-- Generator polynomials: G1 = 171 octal, G2 = 133 octal +-- +-- CRITICAL: The polynomial tap interpretation must match the original! +-- G1_POLY = "1111001" with loop using full_state(6-i) means: +-- G1 = curr_bit XOR sr(3) XOR sr(2) XOR sr(1) XOR sr(0) +-- G2_POLY = "1011011" means: +-- G2 = curr_bit XOR sr(5) XOR sr(3) XOR sr(2) XOR sr(0) +-- +-- RESOURCE OPTIMIZATION: +-- Original version: ~3000 LUTs (variable bit indexing creates massive mux/demux) +-- This version: ~200-400 LUTs (shift registers, fixed-position access only) ------------------------------------------------------------------------------------------------------ LIBRARY ieee; @@ -12,8 +21,8 @@ USE ieee.numeric_std.ALL; ENTITY conv_encoder_k7 IS GENERIC ( - PAYLOAD_BYTES : NATURAL := 134; -- Input size in bytes - ENCODED_BYTES : NATURAL := 268 -- Output size in bytes (2x for rate 1/2) + PAYLOAD_BYTES : NATURAL := 134; + ENCODED_BYTES : NATURAL := 268 ); PORT ( clk : IN std_logic; @@ -30,67 +39,46 @@ END ENTITY conv_encoder_k7; ARCHITECTURE rtl OF conv_encoder_k7 IS - -- TYPE state_t IS (IDLE, ENCODE_DATA, FLUSH_TRELLIS, COMPLETE); - TYPE state_t IS (IDLE, ENCODE_DATA, COMPLETE); + CONSTANT INPUT_BITS : NATURAL := PAYLOAD_BYTES * 8; -- 1072 + CONSTANT OUTPUT_BITS : NATURAL := ENCODED_BYTES * 8; -- 2144 + + TYPE state_t IS (IDLE, ENCODE, COMPLETE); SIGNAL state : state_t := IDLE; - SIGNAL input_bit_count : NATURAL RANGE 0 TO PAYLOAD_BYTES*8; - SIGNAL output_bit_count : NATURAL RANGE 0 TO ENCODED_BYTES*8; + -- Input shift register - shifts MSB out first + SIGNAL in_sr : std_logic_vector(INPUT_BITS-1 DOWNTO 0); - CONSTANT G1_POLY : std_logic_vector(6 DOWNTO 0) := "1111001"; - CONSTANT G2_POLY : std_logic_vector(6 DOWNTO 0) := "1011011"; + -- Output shift register - accumulates encoded bits + SIGNAL out_sr : std_logic_vector(OUTPUT_BITS-1 DOWNTO 0); - SIGNAL out_buf : std_logic_vector(ENCODED_BYTES*8-1 DOWNTO 0); - - ATTRIBUTE ram_style : STRING; - ATTRIBUTE ram_style OF out_buf : SIGNAL IS "block"; + -- Encoder shift register (6 bits of history for K=7) + -- sr(0) = most recent previous bit, sr(5) = oldest + SIGNAL enc_sr : std_logic_vector(5 DOWNTO 0); - -- Function to compute encoder outputs - FUNCTION compute_outputs( - current_bit : std_logic; - shift_reg : std_logic_vector(5 DOWNTO 0) - ) RETURN std_logic_vector IS - VARIABLE full_state : std_logic_vector(6 DOWNTO 0); - VARIABLE g1, g2 : std_logic; - BEGIN - full_state := current_bit & shift_reg; - - -- G1 output - g1 := '0'; - FOR i IN 0 TO 6 LOOP - IF G1_POLY(i) = '1' THEN - g1 := g1 XOR full_state(6-i); - END IF; - END LOOP; - - -- G2 output - g2 := '0'; - FOR i IN 0 TO 6 LOOP - IF G2_POLY(i) = '1' THEN - g2 := g2 XOR full_state(6-i); - END IF; - END LOOP; - - RETURN g1 & g2; -- Return as 2-bit vector - END FUNCTION; + -- Bit counter + SIGNAL bit_count : unsigned(10 DOWNTO 0); -- counts 0 to 1071 + + -- Latched output (stable while not encoding) + SIGNAL out_latched : std_logic_vector(OUTPUT_BITS-1 DOWNTO 0); BEGIN PROCESS(clk, aresetn) - VARIABLE shift_reg : std_logic_vector(5 DOWNTO 0); - VARIABLE current_bit : std_logic; - VARIABLE outputs : std_logic_vector(1 DOWNTO 0); + VARIABLE curr_bit : std_logic; + VARIABLE g1, g2 : std_logic; BEGIN IF aresetn = '0' THEN state <= IDLE; - shift_reg := (OTHERS => '0'); - input_bit_count <= 0; - output_bit_count <= 0; busy <= '0'; done <= '0'; - out_buf <= (OTHERS => '0'); + in_sr <= (OTHERS => '0'); + out_sr <= (OTHERS => '0'); + enc_sr <= (OTHERS => '0'); + bit_count <= (OTHERS => '0'); + out_latched <= (OTHERS => '0'); ELSIF rising_edge(clk) THEN + -- Default: done is single-cycle pulse done <= '0'; CASE state IS @@ -98,57 +86,63 @@ BEGIN WHEN IDLE => busy <= '0'; IF start = '1' THEN - state <= ENCODE_DATA; + -- Parallel load input shift register + in_sr <= input_buffer; + out_sr <= (OTHERS => '0'); + enc_sr <= (OTHERS => '0'); + bit_count <= (OTHERS => '0'); busy <= '1'; - shift_reg := (OTHERS => '0'); - input_bit_count <= 0; - output_bit_count <= 0; + state <= ENCODE; END IF; - WHEN ENCODE_DATA => - -- Process 1,070 bits (stop 2 bits early for tail) - IF input_bit_count < PAYLOAD_BYTES*8 THEN - -- Read input bit (MSB first) - current_bit := input_buffer(PAYLOAD_BYTES*8 - 1 - input_bit_count); - - -- Compute outputs using current state - outputs := compute_outputs(current_bit, shift_reg); - - -- Store outputs (g1 first, then g2) - out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); -- g1 - out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); -- g2 - - -- Update shift register - shift_reg := shift_reg(4 DOWNTO 0) & current_bit; - - input_bit_count <= input_bit_count + 1; - output_bit_count <= output_bit_count + 2; - ELSE - -- state <= FLUSH_TRELLIS; - -- input_bit_count <= 0; + WHEN ENCODE => + -- Get current input bit from MSB of shift register + curr_bit := in_sr(INPUT_BITS - 1); + + ---------------------------------------------------------------- + -- POLYNOMIAL COMPUTATION - Must match original exactly! + ---------------------------------------------------------------- + -- Original uses: full_state = curr_bit & enc_sr + -- With loop: g1 XOR= full_state(6-i) when G1_POLY(i)='1' + -- + -- G1_POLY = "1111001" (bits 6,5,4,3,0 are '1') + -- i=0: full_state(6) = curr_bit + -- i=3: full_state(3) = enc_sr(3) + -- i=4: full_state(2) = enc_sr(2) + -- i=5: full_state(1) = enc_sr(1) + -- i=6: full_state(0) = enc_sr(0) + -- G1 = curr_bit XOR enc_sr(3) XOR enc_sr(2) XOR enc_sr(1) XOR enc_sr(0) + -- + -- G2_POLY = "1011011" (bits 6,4,3,1,0 are '1') + -- i=0: full_state(6) = curr_bit + -- i=1: full_state(5) = enc_sr(5) + -- i=3: full_state(3) = enc_sr(3) + -- i=4: full_state(2) = enc_sr(2) + -- i=6: full_state(0) = enc_sr(0) + -- G2 = curr_bit XOR enc_sr(5) XOR enc_sr(3) XOR enc_sr(2) XOR enc_sr(0) + ---------------------------------------------------------------- + + g1 := curr_bit XOR enc_sr(3) XOR enc_sr(2) XOR enc_sr(1) XOR enc_sr(0); + g2 := curr_bit XOR enc_sr(5) XOR enc_sr(3) XOR enc_sr(2) XOR enc_sr(0); + + -- Update encoder shift register (shift in current bit at LSB) + enc_sr <= enc_sr(4 DOWNTO 0) & curr_bit; + + -- Shift input register left (next bit moves to MSB position) + in_sr <= in_sr(INPUT_BITS-2 DOWNTO 0) & '0'; + + -- Shift output register left by 2, insert g1 and g2 at LSB + -- g1 goes to higher bit position (matches original out_buf indexing) + out_sr <= out_sr(OUTPUT_BITS-3 DOWNTO 0) & g1 & g2; + + -- Count bits processed + IF bit_count = INPUT_BITS - 1 THEN + -- All bits encoded, latch output + out_latched <= out_sr(OUTPUT_BITS-3 DOWNTO 0) & g1 & g2; state <= COMPLETE; + ELSE + bit_count <= bit_count + 1; END IF; - --- WHEN FLUSH_TRELLIS => --- -- Add 2 tail bits (produces 4 encoded bits) --- IF input_bit_count < 2 THEN --- current_bit := '0'; --- --- -- Compute outputs --- outputs := compute_outputs(current_bit, shift_reg); --- --- -- Store outputs --- out_buf(ENCODED_BYTES*8 - 1 - output_bit_count) <= outputs(1); --- out_buf(ENCODED_BYTES*8 - 2 - output_bit_count) <= outputs(0); --- --- -- Update shift register --- shift_reg := shift_reg(4 DOWNTO 0) & '0'; --- --- input_bit_count <= input_bit_count + 1; --- output_bit_count <= output_bit_count + 2; --- ELSE --- state <= COMPLETE; --- END IF; WHEN COMPLETE => done <= '1'; @@ -159,6 +153,7 @@ BEGIN END IF; END PROCESS; - output_buffer <= out_buf; + -- Output is latched value (stable during next encoding) + output_buffer <= out_latched; END ARCHITECTURE rtl; diff --git a/src/msk_top.vhd b/src/msk_top.vhd index 6ffd5cb..7489f06 100644 --- a/src/msk_top.vhd +++ b/src/msk_top.vhd @@ -190,6 +190,7 @@ ARCHITECTURE struct OF msk_top IS SIGNAL encoder_tlast : std_logic; SIGNAL tx_frames_encoded : std_logic_vector(31 DOWNTO 0); SIGNAL tx_encoder_active : std_logic; + SIGNAL encoder_debug_state : std_logic_vector(2 DOWNTO 0); SIGNAL tx_async_fifo_prog_full : std_logic; SIGNAL tx_async_fifo_prog_empty : std_logic; @@ -330,17 +331,36 @@ ARCHITECTURE struct OF msk_top IS ATTRIBUTE dont_touch OF u_rx_async_fifo : LABEL IS "true"; ATTRIBUTE dont_touch OF u_ov_encoder : LABEL IS "true"; ATTRIBUTE dont_touch OF u_deserializer : LABEL IS "true"; - ATTRIBUTE dont_touch OF tx_data_bit : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF fifo_tdata : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF fifo_tvalid : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF fifo_tready : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF fifo_tlast : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF encoder_tdata : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF encoder_tvalid : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF encoder_tready : SIGNAL IS "true"; - ATTRIBUTE dont_touch OF encoder_tlast : SIGNAL IS "true"; + + --ATTRIBUTE dont_touch OF tx_data_bit : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF fifo_tdata : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF fifo_tvalid : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF fifo_tready : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF fifo_tlast : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF encoder_tdata : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF encoder_tvalid : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF encoder_tready : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF encoder_tlast : SIGNAL IS "true"; + + -- RX path protection (add after existing TX dont_touch attributes) + ATTRIBUTE dont_touch OF u_ov_decoder : LABEL IS "true"; + ATTRIBUTE dont_touch OF u_rx_frame_sync : LABEL IS "true"; + + --ATTRIBUTE dont_touch OF decoder_tdata : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF decoder_tvalid : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF decoder_tready : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF decoder_tlast : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF sync_det_tdata : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF sync_det_tvalid : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF sync_det_tready : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF sync_det_tlast : SIGNAL IS "true"; + + + BEGIN + + ------------------------------------------------------------------------------------------------------ -- OPULENT VOICE TX FIFO CHAIN ------------------------------------------------------------------------------------------------------ @@ -436,7 +456,8 @@ BEGIN -- Status frames_encoded => tx_frames_encoded, - encoder_active => tx_encoder_active + encoder_active => tx_encoder_active, + debug_state => encoder_debug_state ); -- Stage 4: Byte-to-Bit De-serializer (MSB-FIRST VERSION) @@ -960,7 +981,17 @@ BEGIN tx_sync_f1 => tx_sync_f1, tx_sync_f2 => tx_sync_f2, pd_alpha1 => pd_alpha1, - pd_alpha2 => pd_alpha2 + pd_alpha2 => pd_alpha2, + + -- Abraxas3d added these experimental signals for transmitter stall investigation + tx_debug_encoder_tvalid => encoder_tvalid, + tx_debug_encoder_tready => encoder_tready, + tx_debug_fifo_tvalid => fifo_tvalid, + tx_debug_fifo_tready => fifo_tready, + tx_debug_tx_req => tx_req, + tx_debug_encoder_tlast => encoder_tlast, + tx_debug_encoder_state => encoder_debug_state + ); END ARCHITECTURE struct; diff --git a/src/msk_top_csr.vhd b/src/msk_top_csr.vhd index c35f891..b694d23 100644 --- a/src/msk_top_csr.vhd +++ b/src/msk_top_csr.vhd @@ -180,7 +180,18 @@ ENTITY msk_top_csr IS tx_sync_f1 : out std_logic; tx_sync_f2 : out std_logic; pd_alpha1 : out std_logic_vector(17 DOWNTO 0); - pd_alpha2 : out std_logic_vector(17 DOWNTO 0) + pd_alpha2 : out std_logic_vector(17 DOWNTO 0); + + -- Debug signals for TX path + tx_debug_encoder_tvalid : IN std_logic; + tx_debug_encoder_tready : IN std_logic; + tx_debug_fifo_tvalid : IN std_logic; + tx_debug_fifo_tready : IN std_logic; + tx_debug_tx_req : IN std_logic; + tx_debug_encoder_tlast : IN std_logic; + tx_debug_encoder_state : IN std_logic_vector(2 DOWNTO 0) + + ); END ENTITY msk_top_csr; @@ -363,15 +374,28 @@ BEGIN PORT MAP (clk, csr_init, frame_sync_errors_req, rx_frame_sync_err, hwif_in.rx_frame_sync_status.frame_sync_errors.next_q ); -- FIFO status reads - rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod; - hwif_in.rx_async_fifo_rd_wr_ptr.data.we <= rx_async_fifo_status_ack; - hwif_in.rx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(rx_async_fifo_wr_ptr), 16) & - resize(unsigned(rx_async_fifo_rd_ptr), 16)); - - tx_async_fifo_status_req <= hwif_out.tx_async_fifo_rd_wr_ptr.data.swmod; - hwif_in.tx_async_fifo_rd_wr_ptr.data.we <= tx_async_fifo_status_ack; - hwif_in.tx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 16) & - resize(unsigned(tx_async_fifo_rd_ptr), 16)); + rx_async_fifo_status_req <= hwif_out.rx_async_fifo_rd_wr_ptr.data.swmod; + hwif_in.rx_async_fifo_rd_wr_ptr.data.we <= rx_async_fifo_status_ack; + hwif_in.rx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(rx_async_fifo_wr_ptr), 16) & resize(unsigned(rx_async_fifo_rd_ptr), 16)); + + tx_async_fifo_status_req <= hwif_out.tx_async_fifo_rd_wr_ptr.data.swmod; + hwif_in.tx_async_fifo_rd_wr_ptr.data.we <= tx_async_fifo_status_ack; + -- commented out by Abraxas3d to add more bits to the register in order to investigate transmitter stall + --hwif_in.tx_async_fifo_rd_wr_ptr.data.next_q <= std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 16) & resize(unsigned(tx_async_fifo_rd_ptr), 16)); + +-- experimental register setup by Abraxas3d +hwif_in.tx_async_fifo_rd_wr_ptr.data.next_q <= + tx_debug_encoder_tvalid & -- bit 31 + tx_debug_encoder_tready & -- bit 30 + tx_debug_fifo_tvalid & -- bit 29 + tx_debug_fifo_tready & -- bit 28 + tx_debug_tx_req & -- bit 27 + tx_debug_encoder_tlast & -- bit 26 + tx_debug_encoder_state & -- bits 25:23 + std_logic_vector(resize(unsigned(tx_async_fifo_wr_ptr), 10)) & -- bits 22:13 + "000" & -- bits 12:10 spare + std_logic_vector(resize(unsigned(tx_async_fifo_rd_ptr), 10)); -- bits 9:0 + -- Control from AXI to MDM u01s: cdc_resync PORT MAP (clk, csr_init, hwif_out.MSK_Init.txrxinit.value, txrxinit ); diff --git a/src/ov_frame_encoder.vhd b/src/ov_frame_encoder.vhd index b26f49c..7fa6b28 100644 --- a/src/ov_frame_encoder.vhd +++ b/src/ov_frame_encoder.vhd @@ -26,11 +26,11 @@ -- 5. Pre-set s_axis_tready = '1' before returning to IDLE for next frame -- -- This approach: --- ? Respects AXI-Stream protocol (tlast marks frame boundaries) --- ? Works with continuous data streams (FIFO buffering) --- ? Prevents byte stealing across frame boundaries --- ? Validates frame size for error detection --- ? Works for BOTH bit-level and byte-level interleaving modes +-- Respects AXI-Stream protocol (tlast marks frame boundaries) +-- Works with continuous data streams (FIFO buffering) +-- Prevents byte stealing across frame boundaries +-- Validates frame size for error detection +-- Works for BOTH bit-level and byte-level interleaving modes -- -- NEVER count to a fixed byte number and ignore tlast - this violates AXI-Stream protocol! ------------------------------------------------------------------------------------------------------ @@ -46,7 +46,7 @@ ENTITY ov_frame_encoder IS COLLECT_SIZE : NATURAL := 4; -- DEPRECATED: No longer used (kept for compatibility) ENCODED_BITS : NATURAL := 2144; -- Kept for compatibility BYTE_WIDTH : NATURAL := 8; -- Kept for compatibility - USE_BIT_INTERLEAVER : BOOLEAN := TRUE -- TRUE=bit-level(67x32), FALSE=byte-level(67x4) + USE_BIT_INTERLEAVER : BOOLEAN := FALSE -- TRUE=bit-level(67x32), FALSE=byte-level(67x4) ); PORT ( clk : IN std_logic; @@ -66,7 +66,8 @@ ENTITY ov_frame_encoder IS -- Status outputs frames_encoded : OUT std_logic_vector(31 DOWNTO 0); - encoder_active : OUT std_logic + encoder_active : OUT std_logic; + debug_state : OUT std_logic_vector(2 DOWNTO 0) ); END ENTITY ov_frame_encoder; @@ -141,7 +142,7 @@ ARCHITECTURE rtl OF ov_frame_encoder IS -- Index counters SIGNAL collect_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; -- Now collects all bytes until tlast - SIGNAL byte_idx : NATURAL RANGE 0 TO PAYLOAD_BYTES; + SIGNAL byte_idx : NATURAL RANGE 0 TO ENCODED_BYTES; SIGNAL bit_idx : NATURAL RANGE 0 TO ENCODED_BITS; SIGNAL out_idx : NATURAL RANGE 0 TO ENCODED_BYTES; @@ -161,147 +162,157 @@ ARCHITECTURE rtl OF ov_frame_encoder IS SIGNAL encoder_done : std_logic; SIGNAL encoder_input_buf : std_logic_vector(1071 DOWNTO 0); SIGNAL encoder_output_buf : std_logic_vector(2143 DOWNTO 0); + + -- preserve the output registers from synthesis optimization + ATTRIBUTE dont_touch : STRING; + ATTRIBUTE dont_touch OF m_axis_tvalid_reg : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF m_axis_tdata_reg : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF m_axis_tlast_reg : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF interleaved_buffer : SIGNAL IS "true"; + --ATTRIBUTE dont_touch OF out_idx : SIGNAL IS "true"; + ATTRIBUTE dont_touch OF s_axis_tready_reg : SIGNAL IS "true"; + ---------------------------------------------------------------------------- -- BIT-LEVEL INTERLEAVER (67x32) - For large FPGAs, correct protocol ---------------------------------------------------------------------------- - TYPE address_lut_t IS ARRAY(0 TO 2143) OF NATURAL RANGE 0 TO 2143; - CONSTANT INTERLEAVE_LUT_BIT : address_lut_t := ( - 0, 67, 134, 201, 268, 335, 402, 469, 536, 603, 670, 737, 804, 871, 938, 1005, - 1072, 1139, 1206, 1273, 1340, 1407, 1474, 1541, 1608, 1675, 1742, 1809, 1876, 1943, 2010, 2077, - 1, 68, 135, 202, 269, 336, 403, 470, 537, 604, 671, 738, 805, 872, 939, 1006, - 1073, 1140, 1207, 1274, 1341, 1408, 1475, 1542, 1609, 1676, 1743, 1810, 1877, 1944, 2011, 2078, - 2, 69, 136, 203, 270, 337, 404, 471, 538, 605, 672, 739, 806, 873, 940, 1007, - 1074, 1141, 1208, 1275, 1342, 1409, 1476, 1543, 1610, 1677, 1744, 1811, 1878, 1945, 2012, 2079, - 3, 70, 137, 204, 271, 338, 405, 472, 539, 606, 673, 740, 807, 874, 941, 1008, - 1075, 1142, 1209, 1276, 1343, 1410, 1477, 1544, 1611, 1678, 1745, 1812, 1879, 1946, 2013, 2080, - 4, 71, 138, 205, 272, 339, 406, 473, 540, 607, 674, 741, 808, 875, 942, 1009, - 1076, 1143, 1210, 1277, 1344, 1411, 1478, 1545, 1612, 1679, 1746, 1813, 1880, 1947, 2014, 2081, - 5, 72, 139, 206, 273, 340, 407, 474, 541, 608, 675, 742, 809, 876, 943, 1010, - 1077, 1144, 1211, 1278, 1345, 1412, 1479, 1546, 1613, 1680, 1747, 1814, 1881, 1948, 2015, 2082, - 6, 73, 140, 207, 274, 341, 408, 475, 542, 609, 676, 743, 810, 877, 944, 1011, - 1078, 1145, 1212, 1279, 1346, 1413, 1480, 1547, 1614, 1681, 1748, 1815, 1882, 1949, 2016, 2083, - 7, 74, 141, 208, 275, 342, 409, 476, 543, 610, 677, 744, 811, 878, 945, 1012, - 1079, 1146, 1213, 1280, 1347, 1414, 1481, 1548, 1615, 1682, 1749, 1816, 1883, 1950, 2017, 2084, - 8, 75, 142, 209, 276, 343, 410, 477, 544, 611, 678, 745, 812, 879, 946, 1013, - 1080, 1147, 1214, 1281, 1348, 1415, 1482, 1549, 1616, 1683, 1750, 1817, 1884, 1951, 2018, 2085, - 9, 76, 143, 210, 277, 344, 411, 478, 545, 612, 679, 746, 813, 880, 947, 1014, - 1081, 1148, 1215, 1282, 1349, 1416, 1483, 1550, 1617, 1684, 1751, 1818, 1885, 1952, 2019, 2086, - 10, 77, 144, 211, 278, 345, 412, 479, 546, 613, 680, 747, 814, 881, 948, 1015, - 1082, 1149, 1216, 1283, 1350, 1417, 1484, 1551, 1618, 1685, 1752, 1819, 1886, 1953, 2020, 2087, - 11, 78, 145, 212, 279, 346, 413, 480, 547, 614, 681, 748, 815, 882, 949, 1016, - 1083, 1150, 1217, 1284, 1351, 1418, 1485, 1552, 1619, 1686, 1753, 1820, 1887, 1954, 2021, 2088, - 12, 79, 146, 213, 280, 347, 414, 481, 548, 615, 682, 749, 816, 883, 950, 1017, - 1084, 1151, 1218, 1285, 1352, 1419, 1486, 1553, 1620, 1687, 1754, 1821, 1888, 1955, 2022, 2089, - 13, 80, 147, 214, 281, 348, 415, 482, 549, 616, 683, 750, 817, 884, 951, 1018, - 1085, 1152, 1219, 1286, 1353, 1420, 1487, 1554, 1621, 1688, 1755, 1822, 1889, 1956, 2023, 2090, - 14, 81, 148, 215, 282, 349, 416, 483, 550, 617, 684, 751, 818, 885, 952, 1019, - 1086, 1153, 1220, 1287, 1354, 1421, 1488, 1555, 1622, 1689, 1756, 1823, 1890, 1957, 2024, 2091, - 15, 82, 149, 216, 283, 350, 417, 484, 551, 618, 685, 752, 819, 886, 953, 1020, - 1087, 1154, 1221, 1288, 1355, 1422, 1489, 1556, 1623, 1690, 1757, 1824, 1891, 1958, 2025, 2092, - 16, 83, 150, 217, 284, 351, 418, 485, 552, 619, 686, 753, 820, 887, 954, 1021, - 1088, 1155, 1222, 1289, 1356, 1423, 1490, 1557, 1624, 1691, 1758, 1825, 1892, 1959, 2026, 2093, - 17, 84, 151, 218, 285, 352, 419, 486, 553, 620, 687, 754, 821, 888, 955, 1022, - 1089, 1156, 1223, 1290, 1357, 1424, 1491, 1558, 1625, 1692, 1759, 1826, 1893, 1960, 2027, 2094, - 18, 85, 152, 219, 286, 353, 420, 487, 554, 621, 688, 755, 822, 889, 956, 1023, - 1090, 1157, 1224, 1291, 1358, 1425, 1492, 1559, 1626, 1693, 1760, 1827, 1894, 1961, 2028, 2095, - 19, 86, 153, 220, 287, 354, 421, 488, 555, 622, 689, 756, 823, 890, 957, 1024, - 1091, 1158, 1225, 1292, 1359, 1426, 1493, 1560, 1627, 1694, 1761, 1828, 1895, 1962, 2029, 2096, - 20, 87, 154, 221, 288, 355, 422, 489, 556, 623, 690, 757, 824, 891, 958, 1025, - 1092, 1159, 1226, 1293, 1360, 1427, 1494, 1561, 1628, 1695, 1762, 1829, 1896, 1963, 2030, 2097, - 21, 88, 155, 222, 289, 356, 423, 490, 557, 624, 691, 758, 825, 892, 959, 1026, - 1093, 1160, 1227, 1294, 1361, 1428, 1495, 1562, 1629, 1696, 1763, 1830, 1897, 1964, 2031, 2098, - 22, 89, 156, 223, 290, 357, 424, 491, 558, 625, 692, 759, 826, 893, 960, 1027, - 1094, 1161, 1228, 1295, 1362, 1429, 1496, 1563, 1630, 1697, 1764, 1831, 1898, 1965, 2032, 2099, - 23, 90, 157, 224, 291, 358, 425, 492, 559, 626, 693, 760, 827, 894, 961, 1028, - 1095, 1162, 1229, 1296, 1363, 1430, 1497, 1564, 1631, 1698, 1765, 1832, 1899, 1966, 2033, 2100, - 24, 91, 158, 225, 292, 359, 426, 493, 560, 627, 694, 761, 828, 895, 962, 1029, - 1096, 1163, 1230, 1297, 1364, 1431, 1498, 1565, 1632, 1699, 1766, 1833, 1900, 1967, 2034, 2101, - 25, 92, 159, 226, 293, 360, 427, 494, 561, 628, 695, 762, 829, 896, 963, 1030, - 1097, 1164, 1231, 1298, 1365, 1432, 1499, 1566, 1633, 1700, 1767, 1834, 1901, 1968, 2035, 2102, - 26, 93, 160, 227, 294, 361, 428, 495, 562, 629, 696, 763, 830, 897, 964, 1031, - 1098, 1165, 1232, 1299, 1366, 1433, 1500, 1567, 1634, 1701, 1768, 1835, 1902, 1969, 2036, 2103, - 27, 94, 161, 228, 295, 362, 429, 496, 563, 630, 697, 764, 831, 898, 965, 1032, - 1099, 1166, 1233, 1300, 1367, 1434, 1501, 1568, 1635, 1702, 1769, 1836, 1903, 1970, 2037, 2104, - 28, 95, 162, 229, 296, 363, 430, 497, 564, 631, 698, 765, 832, 899, 966, 1033, - 1100, 1167, 1234, 1301, 1368, 1435, 1502, 1569, 1636, 1703, 1770, 1837, 1904, 1971, 2038, 2105, - 29, 96, 163, 230, 297, 364, 431, 498, 565, 632, 699, 766, 833, 900, 967, 1034, - 1101, 1168, 1235, 1302, 1369, 1436, 1503, 1570, 1637, 1704, 1771, 1838, 1905, 1972, 2039, 2106, - 30, 97, 164, 231, 298, 365, 432, 499, 566, 633, 700, 767, 834, 901, 968, 1035, - 1102, 1169, 1236, 1303, 1370, 1437, 1504, 1571, 1638, 1705, 1772, 1839, 1906, 1973, 2040, 2107, - 31, 98, 165, 232, 299, 366, 433, 500, 567, 634, 701, 768, 835, 902, 969, 1036, - 1103, 1170, 1237, 1304, 1371, 1438, 1505, 1572, 1639, 1706, 1773, 1840, 1907, 1974, 2041, 2108, - 32, 99, 166, 233, 300, 367, 434, 501, 568, 635, 702, 769, 836, 903, 970, 1037, - 1104, 1171, 1238, 1305, 1372, 1439, 1506, 1573, 1640, 1707, 1774, 1841, 1908, 1975, 2042, 2109, - 33, 100, 167, 234, 301, 368, 435, 502, 569, 636, 703, 770, 837, 904, 971, 1038, - 1105, 1172, 1239, 1306, 1373, 1440, 1507, 1574, 1641, 1708, 1775, 1842, 1909, 1976, 2043, 2110, - 34, 101, 168, 235, 302, 369, 436, 503, 570, 637, 704, 771, 838, 905, 972, 1039, - 1106, 1173, 1240, 1307, 1374, 1441, 1508, 1575, 1642, 1709, 1776, 1843, 1910, 1977, 2044, 2111, - 35, 102, 169, 236, 303, 370, 437, 504, 571, 638, 705, 772, 839, 906, 973, 1040, - 1107, 1174, 1241, 1308, 1375, 1442, 1509, 1576, 1643, 1710, 1777, 1844, 1911, 1978, 2045, 2112, - 36, 103, 170, 237, 304, 371, 438, 505, 572, 639, 706, 773, 840, 907, 974, 1041, - 1108, 1175, 1242, 1309, 1376, 1443, 1510, 1577, 1644, 1711, 1778, 1845, 1912, 1979, 2046, 2113, - 37, 104, 171, 238, 305, 372, 439, 506, 573, 640, 707, 774, 841, 908, 975, 1042, - 1109, 1176, 1243, 1310, 1377, 1444, 1511, 1578, 1645, 1712, 1779, 1846, 1913, 1980, 2047, 2114, - 38, 105, 172, 239, 306, 373, 440, 507, 574, 641, 708, 775, 842, 909, 976, 1043, - 1110, 1177, 1244, 1311, 1378, 1445, 1512, 1579, 1646, 1713, 1780, 1847, 1914, 1981, 2048, 2115, - 39, 106, 173, 240, 307, 374, 441, 508, 575, 642, 709, 776, 843, 910, 977, 1044, - 1111, 1178, 1245, 1312, 1379, 1446, 1513, 1580, 1647, 1714, 1781, 1848, 1915, 1982, 2049, 2116, - 40, 107, 174, 241, 308, 375, 442, 509, 576, 643, 710, 777, 844, 911, 978, 1045, - 1112, 1179, 1246, 1313, 1380, 1447, 1514, 1581, 1648, 1715, 1782, 1849, 1916, 1983, 2050, 2117, - 41, 108, 175, 242, 309, 376, 443, 510, 577, 644, 711, 778, 845, 912, 979, 1046, - 1113, 1180, 1247, 1314, 1381, 1448, 1515, 1582, 1649, 1716, 1783, 1850, 1917, 1984, 2051, 2118, - 42, 109, 176, 243, 310, 377, 444, 511, 578, 645, 712, 779, 846, 913, 980, 1047, - 1114, 1181, 1248, 1315, 1382, 1449, 1516, 1583, 1650, 1717, 1784, 1851, 1918, 1985, 2052, 2119, - 43, 110, 177, 244, 311, 378, 445, 512, 579, 646, 713, 780, 847, 914, 981, 1048, - 1115, 1182, 1249, 1316, 1383, 1450, 1517, 1584, 1651, 1718, 1785, 1852, 1919, 1986, 2053, 2120, - 44, 111, 178, 245, 312, 379, 446, 513, 580, 647, 714, 781, 848, 915, 982, 1049, - 1116, 1183, 1250, 1317, 1384, 1451, 1518, 1585, 1652, 1719, 1786, 1853, 1920, 1987, 2054, 2121, - 45, 112, 179, 246, 313, 380, 447, 514, 581, 648, 715, 782, 849, 916, 983, 1050, - 1117, 1184, 1251, 1318, 1385, 1452, 1519, 1586, 1653, 1720, 1787, 1854, 1921, 1988, 2055, 2122, - 46, 113, 180, 247, 314, 381, 448, 515, 582, 649, 716, 783, 850, 917, 984, 1051, - 1118, 1185, 1252, 1319, 1386, 1453, 1520, 1587, 1654, 1721, 1788, 1855, 1922, 1989, 2056, 2123, - 47, 114, 181, 248, 315, 382, 449, 516, 583, 650, 717, 784, 851, 918, 985, 1052, - 1119, 1186, 1253, 1320, 1387, 1454, 1521, 1588, 1655, 1722, 1789, 1856, 1923, 1990, 2057, 2124, - 48, 115, 182, 249, 316, 383, 450, 517, 584, 651, 718, 785, 852, 919, 986, 1053, - 1120, 1187, 1254, 1321, 1388, 1455, 1522, 1589, 1656, 1723, 1790, 1857, 1924, 1991, 2058, 2125, - 49, 116, 183, 250, 317, 384, 451, 518, 585, 652, 719, 786, 853, 920, 987, 1054, - 1121, 1188, 1255, 1322, 1389, 1456, 1523, 1590, 1657, 1724, 1791, 1858, 1925, 1992, 2059, 2126, - 50, 117, 184, 251, 318, 385, 452, 519, 586, 653, 720, 787, 854, 921, 988, 1055, - 1122, 1189, 1256, 1323, 1390, 1457, 1524, 1591, 1658, 1725, 1792, 1859, 1926, 1993, 2060, 2127, - 51, 118, 185, 252, 319, 386, 453, 520, 587, 654, 721, 788, 855, 922, 989, 1056, - 1123, 1190, 1257, 1324, 1391, 1458, 1525, 1592, 1659, 1726, 1793, 1860, 1927, 1994, 2061, 2128, - 52, 119, 186, 253, 320, 387, 454, 521, 588, 655, 722, 789, 856, 923, 990, 1057, - 1124, 1191, 1258, 1325, 1392, 1459, 1526, 1593, 1660, 1727, 1794, 1861, 1928, 1995, 2062, 2129, - 53, 120, 187, 254, 321, 388, 455, 522, 589, 656, 723, 790, 857, 924, 991, 1058, - 1125, 1192, 1259, 1326, 1393, 1460, 1527, 1594, 1661, 1728, 1795, 1862, 1929, 1996, 2063, 2130, - 54, 121, 188, 255, 322, 389, 456, 523, 590, 657, 724, 791, 858, 925, 992, 1059, - 1126, 1193, 1260, 1327, 1394, 1461, 1528, 1595, 1662, 1729, 1796, 1863, 1930, 1997, 2064, 2131, - 55, 122, 189, 256, 323, 390, 457, 524, 591, 658, 725, 792, 859, 926, 993, 1060, - 1127, 1194, 1261, 1328, 1395, 1462, 1529, 1596, 1663, 1730, 1797, 1864, 1931, 1998, 2065, 2132, - 56, 123, 190, 257, 324, 391, 458, 525, 592, 659, 726, 793, 860, 927, 994, 1061, - 1128, 1195, 1262, 1329, 1396, 1463, 1530, 1597, 1664, 1731, 1798, 1865, 1932, 1999, 2066, 2133, - 57, 124, 191, 258, 325, 392, 459, 526, 593, 660, 727, 794, 861, 928, 995, 1062, - 1129, 1196, 1263, 1330, 1397, 1464, 1531, 1598, 1665, 1732, 1799, 1866, 1933, 2000, 2067, 2134, - 58, 125, 192, 259, 326, 393, 460, 527, 594, 661, 728, 795, 862, 929, 996, 1063, - 1130, 1197, 1264, 1331, 1398, 1465, 1532, 1599, 1666, 1733, 1800, 1867, 1934, 2001, 2068, 2135, - 59, 126, 193, 260, 327, 394, 461, 528, 595, 662, 729, 796, 863, 930, 997, 1064, - 1131, 1198, 1265, 1332, 1399, 1466, 1533, 1600, 1667, 1734, 1801, 1868, 1935, 2002, 2069, 2136, - 60, 127, 194, 261, 328, 395, 462, 529, 596, 663, 730, 797, 864, 931, 998, 1065, - 1132, 1199, 1266, 1333, 1400, 1467, 1534, 1601, 1668, 1735, 1802, 1869, 1936, 2003, 2070, 2137, - 61, 128, 195, 262, 329, 396, 463, 530, 597, 664, 731, 798, 865, 932, 999, 1066, - 1133, 1200, 1267, 1334, 1401, 1468, 1535, 1602, 1669, 1736, 1803, 1870, 1937, 2004, 2071, 2138, - 62, 129, 196, 263, 330, 397, 464, 531, 598, 665, 732, 799, 866, 933, 1000, 1067, - 1134, 1201, 1268, 1335, 1402, 1469, 1536, 1603, 1670, 1737, 1804, 1871, 1938, 2005, 2072, 2139, - 63, 130, 197, 264, 331, 398, 465, 532, 599, 666, 733, 800, 867, 934, 1001, 1068, - 1135, 1202, 1269, 1336, 1403, 1470, 1537, 1604, 1671, 1738, 1805, 1872, 1939, 2006, 2073, 2140, - 64, 131, 198, 265, 332, 399, 466, 533, 600, 667, 734, 801, 868, 935, 1002, 1069, - 1136, 1203, 1270, 1337, 1404, 1471, 1538, 1605, 1672, 1739, 1806, 1873, 1940, 2007, 2074, 2141, - 65, 132, 199, 266, 333, 400, 467, 534, 601, 668, 735, 802, 869, 936, 1003, 1070, - 1137, 1204, 1271, 1338, 1405, 1472, 1539, 1606, 1673, 1740, 1807, 1874, 1941, 2008, 2075, 2142, - 66, 133, 200, 267, 334, 401, 468, 535, 602, 669, 736, 803, 870, 937, 1004, 1071, - 1138, 1205, 1272, 1339, 1406, 1473, 1540, 1607, 1674, 1741, 1808, 1875, 1942, 2009, 2076, 2143 - ); +-- TYPE address_lut_t IS ARRAY(0 TO 2143) OF NATURAL RANGE 0 TO 2143; +-- CONSTANT INTERLEAVE_LUT_BIT : address_lut_t := ( +-- 0, 67, 134, 201, 268, 335, 402, 469, 536, 603, 670, 737, 804, 871, 938, 1005, +-- 1072, 1139, 1206, 1273, 1340, 1407, 1474, 1541, 1608, 1675, 1742, 1809, 1876, 1943, 2010, 2077, +-- 1, 68, 135, 202, 269, 336, 403, 470, 537, 604, 671, 738, 805, 872, 939, 1006, +-- 1073, 1140, 1207, 1274, 1341, 1408, 1475, 1542, 1609, 1676, 1743, 1810, 1877, 1944, 2011, 2078, +-- 2, 69, 136, 203, 270, 337, 404, 471, 538, 605, 672, 739, 806, 873, 940, 1007, +-- 1074, 1141, 1208, 1275, 1342, 1409, 1476, 1543, 1610, 1677, 1744, 1811, 1878, 1945, 2012, 2079, +-- 3, 70, 137, 204, 271, 338, 405, 472, 539, 606, 673, 740, 807, 874, 941, 1008, +-- 1075, 1142, 1209, 1276, 1343, 1410, 1477, 1544, 1611, 1678, 1745, 1812, 1879, 1946, 2013, 2080, +-- 4, 71, 138, 205, 272, 339, 406, 473, 540, 607, 674, 741, 808, 875, 942, 1009, +-- 1076, 1143, 1210, 1277, 1344, 1411, 1478, 1545, 1612, 1679, 1746, 1813, 1880, 1947, 2014, 2081, +-- 5, 72, 139, 206, 273, 340, 407, 474, 541, 608, 675, 742, 809, 876, 943, 1010, +-- 1077, 1144, 1211, 1278, 1345, 1412, 1479, 1546, 1613, 1680, 1747, 1814, 1881, 1948, 2015, 2082, +-- 6, 73, 140, 207, 274, 341, 408, 475, 542, 609, 676, 743, 810, 877, 944, 1011, +-- 1078, 1145, 1212, 1279, 1346, 1413, 1480, 1547, 1614, 1681, 1748, 1815, 1882, 1949, 2016, 2083, +-- 7, 74, 141, 208, 275, 342, 409, 476, 543, 610, 677, 744, 811, 878, 945, 1012, +-- 1079, 1146, 1213, 1280, 1347, 1414, 1481, 1548, 1615, 1682, 1749, 1816, 1883, 1950, 2017, 2084, +-- 8, 75, 142, 209, 276, 343, 410, 477, 544, 611, 678, 745, 812, 879, 946, 1013, +-- 1080, 1147, 1214, 1281, 1348, 1415, 1482, 1549, 1616, 1683, 1750, 1817, 1884, 1951, 2018, 2085, +-- 9, 76, 143, 210, 277, 344, 411, 478, 545, 612, 679, 746, 813, 880, 947, 1014, +-- 1081, 1148, 1215, 1282, 1349, 1416, 1483, 1550, 1617, 1684, 1751, 1818, 1885, 1952, 2019, 2086, +-- 10, 77, 144, 211, 278, 345, 412, 479, 546, 613, 680, 747, 814, 881, 948, 1015, +-- 1082, 1149, 1216, 1283, 1350, 1417, 1484, 1551, 1618, 1685, 1752, 1819, 1886, 1953, 2020, 2087, +-- 11, 78, 145, 212, 279, 346, 413, 480, 547, 614, 681, 748, 815, 882, 949, 1016, +-- 1083, 1150, 1217, 1284, 1351, 1418, 1485, 1552, 1619, 1686, 1753, 1820, 1887, 1954, 2021, 2088, +-- 12, 79, 146, 213, 280, 347, 414, 481, 548, 615, 682, 749, 816, 883, 950, 1017, +-- 1084, 1151, 1218, 1285, 1352, 1419, 1486, 1553, 1620, 1687, 1754, 1821, 1888, 1955, 2022, 2089, +-- 13, 80, 147, 214, 281, 348, 415, 482, 549, 616, 683, 750, 817, 884, 951, 1018, +-- 1085, 1152, 1219, 1286, 1353, 1420, 1487, 1554, 1621, 1688, 1755, 1822, 1889, 1956, 2023, 2090, +-- 14, 81, 148, 215, 282, 349, 416, 483, 550, 617, 684, 751, 818, 885, 952, 1019, +-- 1086, 1153, 1220, 1287, 1354, 1421, 1488, 1555, 1622, 1689, 1756, 1823, 1890, 1957, 2024, 2091, +-- 15, 82, 149, 216, 283, 350, 417, 484, 551, 618, 685, 752, 819, 886, 953, 1020, +-- 1087, 1154, 1221, 1288, 1355, 1422, 1489, 1556, 1623, 1690, 1757, 1824, 1891, 1958, 2025, 2092, +-- 16, 83, 150, 217, 284, 351, 418, 485, 552, 619, 686, 753, 820, 887, 954, 1021, +-- 1088, 1155, 1222, 1289, 1356, 1423, 1490, 1557, 1624, 1691, 1758, 1825, 1892, 1959, 2026, 2093, +-- 17, 84, 151, 218, 285, 352, 419, 486, 553, 620, 687, 754, 821, 888, 955, 1022, +-- 1089, 1156, 1223, 1290, 1357, 1424, 1491, 1558, 1625, 1692, 1759, 1826, 1893, 1960, 2027, 2094, +-- 18, 85, 152, 219, 286, 353, 420, 487, 554, 621, 688, 755, 822, 889, 956, 1023, +-- 1090, 1157, 1224, 1291, 1358, 1425, 1492, 1559, 1626, 1693, 1760, 1827, 1894, 1961, 2028, 2095, +-- 19, 86, 153, 220, 287, 354, 421, 488, 555, 622, 689, 756, 823, 890, 957, 1024, +-- 1091, 1158, 1225, 1292, 1359, 1426, 1493, 1560, 1627, 1694, 1761, 1828, 1895, 1962, 2029, 2096, +-- 20, 87, 154, 221, 288, 355, 422, 489, 556, 623, 690, 757, 824, 891, 958, 1025, +-- 1092, 1159, 1226, 1293, 1360, 1427, 1494, 1561, 1628, 1695, 1762, 1829, 1896, 1963, 2030, 2097, +-- 21, 88, 155, 222, 289, 356, 423, 490, 557, 624, 691, 758, 825, 892, 959, 1026, +-- 1093, 1160, 1227, 1294, 1361, 1428, 1495, 1562, 1629, 1696, 1763, 1830, 1897, 1964, 2031, 2098, +-- 22, 89, 156, 223, 290, 357, 424, 491, 558, 625, 692, 759, 826, 893, 960, 1027, +-- 1094, 1161, 1228, 1295, 1362, 1429, 1496, 1563, 1630, 1697, 1764, 1831, 1898, 1965, 2032, 2099, +-- 23, 90, 157, 224, 291, 358, 425, 492, 559, 626, 693, 760, 827, 894, 961, 1028, +-- 1095, 1162, 1229, 1296, 1363, 1430, 1497, 1564, 1631, 1698, 1765, 1832, 1899, 1966, 2033, 2100, +-- 24, 91, 158, 225, 292, 359, 426, 493, 560, 627, 694, 761, 828, 895, 962, 1029, +-- 1096, 1163, 1230, 1297, 1364, 1431, 1498, 1565, 1632, 1699, 1766, 1833, 1900, 1967, 2034, 2101, +-- 25, 92, 159, 226, 293, 360, 427, 494, 561, 628, 695, 762, 829, 896, 963, 1030, +-- 1097, 1164, 1231, 1298, 1365, 1432, 1499, 1566, 1633, 1700, 1767, 1834, 1901, 1968, 2035, 2102, +-- 26, 93, 160, 227, 294, 361, 428, 495, 562, 629, 696, 763, 830, 897, 964, 1031, +-- 1098, 1165, 1232, 1299, 1366, 1433, 1500, 1567, 1634, 1701, 1768, 1835, 1902, 1969, 2036, 2103, +-- 27, 94, 161, 228, 295, 362, 429, 496, 563, 630, 697, 764, 831, 898, 965, 1032, +-- 1099, 1166, 1233, 1300, 1367, 1434, 1501, 1568, 1635, 1702, 1769, 1836, 1903, 1970, 2037, 2104, +-- 28, 95, 162, 229, 296, 363, 430, 497, 564, 631, 698, 765, 832, 899, 966, 1033, +-- 1100, 1167, 1234, 1301, 1368, 1435, 1502, 1569, 1636, 1703, 1770, 1837, 1904, 1971, 2038, 2105, +-- 29, 96, 163, 230, 297, 364, 431, 498, 565, 632, 699, 766, 833, 900, 967, 1034, +-- 1101, 1168, 1235, 1302, 1369, 1436, 1503, 1570, 1637, 1704, 1771, 1838, 1905, 1972, 2039, 2106, +-- 30, 97, 164, 231, 298, 365, 432, 499, 566, 633, 700, 767, 834, 901, 968, 1035, +-- 1102, 1169, 1236, 1303, 1370, 1437, 1504, 1571, 1638, 1705, 1772, 1839, 1906, 1973, 2040, 2107, +-- 31, 98, 165, 232, 299, 366, 433, 500, 567, 634, 701, 768, 835, 902, 969, 1036, +-- 1103, 1170, 1237, 1304, 1371, 1438, 1505, 1572, 1639, 1706, 1773, 1840, 1907, 1974, 2041, 2108, +-- 32, 99, 166, 233, 300, 367, 434, 501, 568, 635, 702, 769, 836, 903, 970, 1037, +-- 1104, 1171, 1238, 1305, 1372, 1439, 1506, 1573, 1640, 1707, 1774, 1841, 1908, 1975, 2042, 2109, +-- 33, 100, 167, 234, 301, 368, 435, 502, 569, 636, 703, 770, 837, 904, 971, 1038, +-- 1105, 1172, 1239, 1306, 1373, 1440, 1507, 1574, 1641, 1708, 1775, 1842, 1909, 1976, 2043, 2110, +-- 34, 101, 168, 235, 302, 369, 436, 503, 570, 637, 704, 771, 838, 905, 972, 1039, +-- 1106, 1173, 1240, 1307, 1374, 1441, 1508, 1575, 1642, 1709, 1776, 1843, 1910, 1977, 2044, 2111, +-- 35, 102, 169, 236, 303, 370, 437, 504, 571, 638, 705, 772, 839, 906, 973, 1040, +-- 1107, 1174, 1241, 1308, 1375, 1442, 1509, 1576, 1643, 1710, 1777, 1844, 1911, 1978, 2045, 2112, +-- 36, 103, 170, 237, 304, 371, 438, 505, 572, 639, 706, 773, 840, 907, 974, 1041, +-- 1108, 1175, 1242, 1309, 1376, 1443, 1510, 1577, 1644, 1711, 1778, 1845, 1912, 1979, 2046, 2113, +-- 37, 104, 171, 238, 305, 372, 439, 506, 573, 640, 707, 774, 841, 908, 975, 1042, +-- 1109, 1176, 1243, 1310, 1377, 1444, 1511, 1578, 1645, 1712, 1779, 1846, 1913, 1980, 2047, 2114, +-- 38, 105, 172, 239, 306, 373, 440, 507, 574, 641, 708, 775, 842, 909, 976, 1043, +-- 1110, 1177, 1244, 1311, 1378, 1445, 1512, 1579, 1646, 1713, 1780, 1847, 1914, 1981, 2048, 2115, +-- 39, 106, 173, 240, 307, 374, 441, 508, 575, 642, 709, 776, 843, 910, 977, 1044, +-- 1111, 1178, 1245, 1312, 1379, 1446, 1513, 1580, 1647, 1714, 1781, 1848, 1915, 1982, 2049, 2116, +-- 40, 107, 174, 241, 308, 375, 442, 509, 576, 643, 710, 777, 844, 911, 978, 1045, +-- 1112, 1179, 1246, 1313, 1380, 1447, 1514, 1581, 1648, 1715, 1782, 1849, 1916, 1983, 2050, 2117, +-- 41, 108, 175, 242, 309, 376, 443, 510, 577, 644, 711, 778, 845, 912, 979, 1046, +-- 1113, 1180, 1247, 1314, 1381, 1448, 1515, 1582, 1649, 1716, 1783, 1850, 1917, 1984, 2051, 2118, +-- 42, 109, 176, 243, 310, 377, 444, 511, 578, 645, 712, 779, 846, 913, 980, 1047, +-- 1114, 1181, 1248, 1315, 1382, 1449, 1516, 1583, 1650, 1717, 1784, 1851, 1918, 1985, 2052, 2119, +-- 43, 110, 177, 244, 311, 378, 445, 512, 579, 646, 713, 780, 847, 914, 981, 1048, +-- 1115, 1182, 1249, 1316, 1383, 1450, 1517, 1584, 1651, 1718, 1785, 1852, 1919, 1986, 2053, 2120, +-- 44, 111, 178, 245, 312, 379, 446, 513, 580, 647, 714, 781, 848, 915, 982, 1049, +-- 1116, 1183, 1250, 1317, 1384, 1451, 1518, 1585, 1652, 1719, 1786, 1853, 1920, 1987, 2054, 2121, +-- 45, 112, 179, 246, 313, 380, 447, 514, 581, 648, 715, 782, 849, 916, 983, 1050, +-- 1117, 1184, 1251, 1318, 1385, 1452, 1519, 1586, 1653, 1720, 1787, 1854, 1921, 1988, 2055, 2122, +-- 46, 113, 180, 247, 314, 381, 448, 515, 582, 649, 716, 783, 850, 917, 984, 1051, +-- 1118, 1185, 1252, 1319, 1386, 1453, 1520, 1587, 1654, 1721, 1788, 1855, 1922, 1989, 2056, 2123, +-- 47, 114, 181, 248, 315, 382, 449, 516, 583, 650, 717, 784, 851, 918, 985, 1052, +-- 1119, 1186, 1253, 1320, 1387, 1454, 1521, 1588, 1655, 1722, 1789, 1856, 1923, 1990, 2057, 2124, +-- 48, 115, 182, 249, 316, 383, 450, 517, 584, 651, 718, 785, 852, 919, 986, 1053, +-- 1120, 1187, 1254, 1321, 1388, 1455, 1522, 1589, 1656, 1723, 1790, 1857, 1924, 1991, 2058, 2125, +-- 49, 116, 183, 250, 317, 384, 451, 518, 585, 652, 719, 786, 853, 920, 987, 1054, +-- 1121, 1188, 1255, 1322, 1389, 1456, 1523, 1590, 1657, 1724, 1791, 1858, 1925, 1992, 2059, 2126, +-- 50, 117, 184, 251, 318, 385, 452, 519, 586, 653, 720, 787, 854, 921, 988, 1055, +-- 1122, 1189, 1256, 1323, 1390, 1457, 1524, 1591, 1658, 1725, 1792, 1859, 1926, 1993, 2060, 2127, +-- 51, 118, 185, 252, 319, 386, 453, 520, 587, 654, 721, 788, 855, 922, 989, 1056, +-- 1123, 1190, 1257, 1324, 1391, 1458, 1525, 1592, 1659, 1726, 1793, 1860, 1927, 1994, 2061, 2128, +-- 52, 119, 186, 253, 320, 387, 454, 521, 588, 655, 722, 789, 856, 923, 990, 1057, +-- 1124, 1191, 1258, 1325, 1392, 1459, 1526, 1593, 1660, 1727, 1794, 1861, 1928, 1995, 2062, 2129, +-- 53, 120, 187, 254, 321, 388, 455, 522, 589, 656, 723, 790, 857, 924, 991, 1058, +-- 1125, 1192, 1259, 1326, 1393, 1460, 1527, 1594, 1661, 1728, 1795, 1862, 1929, 1996, 2063, 2130, +-- 54, 121, 188, 255, 322, 389, 456, 523, 590, 657, 724, 791, 858, 925, 992, 1059, +-- 1126, 1193, 1260, 1327, 1394, 1461, 1528, 1595, 1662, 1729, 1796, 1863, 1930, 1997, 2064, 2131, +-- 55, 122, 189, 256, 323, 390, 457, 524, 591, 658, 725, 792, 859, 926, 993, 1060, +-- 1127, 1194, 1261, 1328, 1395, 1462, 1529, 1596, 1663, 1730, 1797, 1864, 1931, 1998, 2065, 2132, +-- 56, 123, 190, 257, 324, 391, 458, 525, 592, 659, 726, 793, 860, 927, 994, 1061, +-- 1128, 1195, 1262, 1329, 1396, 1463, 1530, 1597, 1664, 1731, 1798, 1865, 1932, 1999, 2066, 2133, +-- 57, 124, 191, 258, 325, 392, 459, 526, 593, 660, 727, 794, 861, 928, 995, 1062, +-- 1129, 1196, 1263, 1330, 1397, 1464, 1531, 1598, 1665, 1732, 1799, 1866, 1933, 2000, 2067, 2134, +-- 58, 125, 192, 259, 326, 393, 460, 527, 594, 661, 728, 795, 862, 929, 996, 1063, +-- 1130, 1197, 1264, 1331, 1398, 1465, 1532, 1599, 1666, 1733, 1800, 1867, 1934, 2001, 2068, 2135, +-- 59, 126, 193, 260, 327, 394, 461, 528, 595, 662, 729, 796, 863, 930, 997, 1064, +-- 1131, 1198, 1265, 1332, 1399, 1466, 1533, 1600, 1667, 1734, 1801, 1868, 1935, 2002, 2069, 2136, +-- 60, 127, 194, 261, 328, 395, 462, 529, 596, 663, 730, 797, 864, 931, 998, 1065, +-- 1132, 1199, 1266, 1333, 1400, 1467, 1534, 1601, 1668, 1735, 1802, 1869, 1936, 2003, 2070, 2137, +-- 61, 128, 195, 262, 329, 396, 463, 530, 597, 664, 731, 798, 865, 932, 999, 1066, +-- 1133, 1200, 1267, 1334, 1401, 1468, 1535, 1602, 1669, 1736, 1803, 1870, 1937, 2004, 2071, 2138, +-- 62, 129, 196, 263, 330, 397, 464, 531, 598, 665, 732, 799, 866, 933, 1000, 1067, +-- 1134, 1201, 1268, 1335, 1402, 1469, 1536, 1603, 1670, 1737, 1804, 1871, 1938, 2005, 2072, 2139, +-- 63, 130, 197, 264, 331, 398, 465, 532, 599, 666, 733, 800, 867, 934, 1001, 1068, +-- 1135, 1202, 1269, 1336, 1403, 1470, 1537, 1604, 1671, 1738, 1805, 1872, 1939, 2006, 2073, 2140, +-- 64, 131, 198, 265, 332, 399, 466, 533, 600, 667, 734, 801, 868, 935, 1002, 1069, +-- 1136, 1203, 1270, 1337, 1404, 1471, 1538, 1605, 1672, 1739, 1806, 1873, 1940, 2007, 2074, 2141, +-- 65, 132, 199, 266, 333, 400, 467, 534, 601, 668, 735, 802, 869, 936, 1003, 1070, +-- 1137, 1204, 1271, 1338, 1405, 1472, 1539, 1606, 1673, 1740, 1807, 1874, 1941, 2008, 2075, 2142, +-- 66, 133, 200, 267, 334, 401, 468, 535, 602, 669, 736, 803, 870, 937, 1004, 1071, +-- 1138, 1205, 1272, 1339, 1406, 1473, 1540, 1607, 1674, 1741, 1808, 1875, 1942, 2009, 2076, 2143 +-- ); ---------------------------------------------------------------------------- -- BYTE-LEVEL INTERLEAVER (67x4) - For PlutoSDR, fits in xc7z010 @@ -317,7 +328,17 @@ ARCHITECTURE rtl OF ov_frame_encoder IS RETURN col * ROWS + row; END FUNCTION; -BEGIN +BEGIN + + -- to find the state of the state machine for debug + debug_state <= "000" WHEN state = IDLE ELSE + "001" WHEN state = COLLECT ELSE + "010" WHEN state = RANDOMIZE ELSE + "011" WHEN state = PREP_FEC ELSE + "100" WHEN state = FEC_ENCODE ELSE + "101" WHEN state = INTERLEAVE ELSE + "110" WHEN state = OUTPUT ELSE + "111"; -- Convolutional Encoder Instantiation U_ENCODER : ENTITY work.conv_encoder_k7 @@ -500,31 +521,35 @@ BEGIN ------------------------------------------------------------------------ -- INTERLEAVE: Dual-mode implementation ------------------------------------------------------------------------ - WHEN INTERLEAVE => - IF USE_BIT_INTERLEAVER THEN - -- BIT-LEVEL mode: Process 1 bit per clock (2144 clocks) - IF bit_idx < ENCODED_BITS THEN - interleaved_buffer(INTERLEAVE_LUT_BIT(bit_idx)) <= fec_buffer(bit_idx); - bit_idx <= bit_idx + 1; - ELSE - out_idx <= 0; - state <= OUTPUT; - m_axis_tvalid_reg <= '0'; - END IF; - ELSE - -- BYTE-LEVEL mode: Process 1 byte per clock (268 clocks) - IF byte_idx < ENCODED_BYTES THEN - FOR j IN 0 TO 7 LOOP - interleaved_buffer(interleave_address_byte(byte_idx)*8 + j) <= - fec_buffer(byte_idx*8 + j); - END LOOP; - byte_idx <= byte_idx + 1; - ELSE - out_idx <= 0; - state <= OUTPUT; - m_axis_tvalid_reg <= '0'; - END IF; - END IF; + +WHEN INTERLEAVE => +-- IF USE_BIT_INTERLEAVER THEN +-- -- BIT-LEVEL mode: Process 1 bit per clock (2144 clocks) +-- IF bit_idx < ENCODED_BITS THEN +-- interleaved_buffer(INTERLEAVE_LUT_BIT(bit_idx)) <= fec_buffer(bit_idx); +-- bit_idx <= bit_idx + 1; +-- ELSE +-- out_idx <= 0; +-- state <= OUTPUT; +-- m_axis_tvalid_reg <= '0'; +-- END IF; +-- ELSE + -- BYTE-LEVEL mode: Process 1 byte per clock (268 clocks) + IF byte_idx < ENCODED_BYTES THEN + FOR j IN 0 TO 7 LOOP + interleaved_buffer(interleave_address_byte(byte_idx)*8 + j) <= + fec_buffer(byte_idx*8 + j); + END LOOP; + byte_idx <= byte_idx + 1; + ELSE + out_idx <= 0; + state <= OUTPUT; + m_axis_tvalid_reg <= '0'; + END IF; +-- END IF; + + + ---------------------------------------------------------------------- -- OUTPUT: Stream interleaved bytes to modulator @@ -552,6 +577,7 @@ BEGIN out_idx <= out_idx + 1; END IF; ELSE + -- Frame output complete IF m_axis_tready = '1' THEN m_axis_tvalid_reg <= '0'; @@ -569,6 +595,7 @@ BEGIN END IF; END CASE; + END IF; END PROCESS; diff --git a/src/viterbi_decoder_k7_simple.vhd b/src/viterbi_decoder_k7_simple.vhd index d1a8a82..d70da79 100644 --- a/src/viterbi_decoder_k7_simple.vhd +++ b/src/viterbi_decoder_k7_simple.vhd @@ -1,11 +1,14 @@ ------------------------------------------------------------------------------------------------------ --- BRAM-Optimized Viterbi Decoder - SIMPLIFIED TRACEBACK (2 cycles per step) +-- BRAM-Optimized Viterbi Decoder - SHIFT REGISTER INPUTS ------------------------------------------------------------------------------------------------------ --- This version uses 2 clock cycles per traceback step for clarity and correctness: --- Cycle 1: Fetch decision from BRAM --- Cycle 2: Use decision, output bit, move to previous state +-- This version uses shift registers for the input data to avoid massive muxes. +-- Instead of input_bits_g1(time_step) creating a 1072:1 mux, we: +-- 1. Load the parallel input into a shift register +-- 2. Shift out one bit per time step -- --- This is slower but eliminates pipeline complexity bugs. +-- This saves ~2000 LUTs (2 x 1072:1 mux elimination) +-- +-- Interface is IDENTICAL to original - parallel load happens internally. ------------------------------------------------------------------------------------------------------ LIBRARY ieee; @@ -32,56 +35,26 @@ END ENTITY viterbi_decoder_k7_simple; ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS - CONSTANT NUM_STATES : INTEGER := 64; CONSTANT METRIC_WIDTH : INTEGER := 12; CONSTANT INF_METRIC : INTEGER := 4095; - CONSTANT NUM_SYMBOLS : INTEGER := ENCODED_BITS/2; + CONSTANT NUM_SYMBOLS : INTEGER := ENCODED_BITS/2; -- 1072 TYPE state_t IS (IDLE, INITIALIZE, ACS_COMPUTE, FIND_BEST, - TB_FETCH, TB_USE, COMPLETE); + TB_FETCH, TB_USE, COMPLETE); SIGNAL state : state_t := IDLE; TYPE metric_array_t IS ARRAY(0 TO NUM_STATES-1) OF unsigned(METRIC_WIDTH-1 DOWNTO 0); - -- added initialization to try to get simulation to stop stalling on second frame SIGNAL metrics_current : metric_array_t := (OTHERS => (OTHERS => '0')); SIGNAL metrics_next : metric_array_t := (OTHERS => (OTHERS => '0')); - --SIGNAL metrics_current : metric_array_t; - --SIGNAL metrics_next : metric_array_t; - - --CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; - --TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; - --SIGNAL decision_mem : decision_mem_t; - - -- ATTRIBUTE ram_style : STRING; - -- ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "ultra"; - -- was block, worked with distributed but was too large of a design, tried ultra - -- still too big. removed entirely tried, was still too big. Then... - - --ATTRIBUTE ram_style : STRING; - --ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; - --ATTRIBUTE ram_extract : STRING; - --ATTRIBUTE ram_extract OF decision_mem : SIGNAL IS "yes"; - --ATTRIBUTE keep : STRING; - --ATTRIBUTE keep OF decision_mem : SIGNAL IS "true"; - -- crashed in a different place - --CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; - --CONSTANT CHUNK_SIZE : INTEGER := 4096; - --CONSTANT NUM_CHUNKS : INTEGER := (DECISION_DEPTH + CHUNK_SIZE - 1) / CHUNK_SIZE; - - --TYPE decision_chunk_t IS ARRAY(0 TO CHUNK_SIZE-1) OF std_logic; - --TYPE decision_mem_array_t IS ARRAY(0 TO NUM_CHUNKS-1) OF decision_chunk_t; - --SIGNAL decision_mem : decision_mem_array_t; - - --ATTRIBUTE ram_style : STRING; - --ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; - + -- Decision memory in BRAM CONSTANT DECISION_DEPTH : INTEGER := NUM_SYMBOLS * NUM_STATES; TYPE decision_mem_t IS ARRAY(0 TO DECISION_DEPTH-1) OF std_logic; SIGNAL decision_mem : decision_mem_t; - + ATTRIBUTE ram_style : STRING; + ATTRIBUTE ram_style OF decision_mem : SIGNAL IS "block"; SIGNAL dec_wr_en : std_logic; SIGNAL dec_wr_addr : INTEGER RANGE 0 TO DECISION_DEPTH-1; @@ -96,6 +69,11 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS SIGNAL out_buf : std_logic_vector(PAYLOAD_BITS-1 DOWNTO 0); SIGNAL rx_symbol : std_logic_vector(1 DOWNTO 0); + + -- SHIFT REGISTERS for input data (replaces massive mux) + -- These shift left, MSB contains current symbol + SIGNAL g1_sr : std_logic_vector(NUM_SYMBOLS-1 DOWNTO 0); + SIGNAL g2_sr : std_logic_vector(NUM_SYMBOLS-1 DOWNTO 0); FUNCTION compute_output(curr_state : INTEGER; input_bit : std_logic) RETURN std_logic_vector IS @@ -136,24 +114,25 @@ ARCHITECTURE rtl OF viterbi_decoder_k7_simple IS BEGIN + -- BRAM write process PROCESS(clk) BEGIN IF rising_edge(clk) THEN IF dec_wr_en = '1' THEN decision_mem(dec_wr_addr) <= dec_wr_data; - --decision_mem(dec_wr_addr / CHUNK_SIZE)(dec_wr_addr MOD CHUNK_SIZE) <= dec_wr_data; END IF; END IF; END PROCESS; + -- BRAM read process PROCESS(clk) BEGIN IF rising_edge(clk) THEN dec_rd_data <= decision_mem(dec_rd_addr); - --dec_rd_data <= decision_mem(dec_rd_addr / CHUNK_SIZE)(dec_rd_addr MOD CHUNK_SIZE); END IF; END PROCESS; + -- Main FSM PROCESS(clk, aresetn) VARIABLE prev_state_0, prev_state_1 : INTEGER RANGE 0 TO NUM_STATES-1; VARIABLE input_bit : std_logic; @@ -169,7 +148,9 @@ BEGIN dec_wr_en <= '0'; time_step <= 0; state_idx <= 0; - metrics_next <= (OTHERS => (OTHERS => '0')); + metrics_next <= (OTHERS => (OTHERS => '0')); + g1_sr <= (OTHERS => '0'); + g2_sr <= (OTHERS => '0'); ELSIF rising_edge(clk) THEN done <= '0'; @@ -183,6 +164,11 @@ BEGIN state <= INITIALIZE; busy <= '1'; state_idx <= 0; + -- PARALLEL LOAD shift registers from input vectors + -- Load bits 0..1071 directly - simple slice, no mux needed + -- We'll read from bit 0 and shift right each time step + g1_sr <= input_bits_g1(NUM_SYMBOLS-1 DOWNTO 0); + g2_sr <= input_bits_g2(NUM_SYMBOLS-1 DOWNTO 0); END IF; WHEN INITIALIZE => @@ -202,7 +188,8 @@ BEGIN WHEN ACS_COMPUTE => IF time_step < NUM_SYMBOLS THEN IF state_idx = 0 THEN - rx_symbol <= input_bits_g1(time_step) & input_bits_g2(time_step); + -- Get current symbol from LSB of shift registers + rx_symbol <= g1_sr(0) & g2_sr(0); END IF; IF state_idx < NUM_STATES THEN @@ -230,9 +217,13 @@ BEGIN dec_wr_en <= '1'; state_idx <= state_idx + 1; ELSE + -- Done with all states for this time step metrics_current <= metrics_next; state_idx <= 0; time_step <= time_step + 1; + -- SHIFT RIGHT: next symbol moves to bit 0 + g1_sr <= '0' & g1_sr(NUM_SYMBOLS-1 DOWNTO 1); + g2_sr <= '0' & g2_sr(NUM_SYMBOLS-1 DOWNTO 1); END IF; ELSE state <= FIND_BEST; @@ -257,12 +248,9 @@ BEGIN state <= TB_FETCH; END IF; - ------------------------------------------------------------------------------------ -- SIMPLIFIED 2-CYCLE TRACEBACK - ------------------------------------------------------------------------------------ WHEN TB_FETCH => -- Cycle 1: Issue BRAM read for current (tb_time, tb_state) - -- Next cycle, dec_rd_data will be valid state <= TB_USE; WHEN TB_USE => From edc5a7b4686c8dd361a64367ef93cd3d570516de Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 14:43:15 -0800 Subject: [PATCH 54/60] Add LibreSDR (XC7Z020/AD9363) support - Add projects/libre/ with HDL project files (LVDS interface, XC7Z020-CLG400) - Add firmware/scripts/libre.mk and libre.its for firmware build - Add firmware/ori/libre/ with device tree and config files for submodules - Add setup_libre.sh script to install files into submodules after clone - Update firmware/Makefile to support TARGET=libre Pin constraint fixes from hz12opensource patch: - gpio_status[5]: Moved from T20 to G14 to avoid conflict Build instructions: cd firmware/ori/libre && ./setup_libre.sh cd ~/pluto_msk/firmware make TARGET=libre XSA_FILE=/path/to/system_top.xsa LibreSDR provides 53,200 LUTs vs PlutoSDR's 17,600 (3x capacity) --- firmware/Makefile | 11 +- .../buildroot-configs/zynq_libre_defconfig | 68 +++ .../linux-configs/zynq_libre_linux_defconfig | 286 +++++++++++ firmware/ori/libre/linux-dts/zynq-libre.dts | 60 +++ firmware/ori/libre/linux-dts/zynq-libre.dtsi | 449 ++++++++++++++++++ firmware/ori/libre/setup_libre.sh | 29 ++ .../libre/uboot-configs/zynq_libre_defconfig | 62 +++ .../ori/libre/uboot-dts/zynq-libre-sdr.dts | 111 +++++ firmware/scripts/libre.its | 70 +++ firmware/scripts/libre.mk | 7 + projects/libre/Makefile | 24 + projects/libre/Readme.md | 10 + projects/libre/system_bd.tcl | 395 +++++++++++++++ projects/libre/system_constr.xdc | 133 ++++++ projects/libre/system_project.tcl | 14 + projects/libre/system_top.v | 183 +++++++ 16 files changed, 1908 insertions(+), 4 deletions(-) create mode 100644 firmware/ori/libre/buildroot-configs/zynq_libre_defconfig create mode 100644 firmware/ori/libre/linux-configs/zynq_libre_linux_defconfig create mode 100644 firmware/ori/libre/linux-dts/zynq-libre.dts create mode 100644 firmware/ori/libre/linux-dts/zynq-libre.dtsi create mode 100755 firmware/ori/libre/setup_libre.sh create mode 100644 firmware/ori/libre/uboot-configs/zynq_libre_defconfig create mode 100644 firmware/ori/libre/uboot-dts/zynq-libre-sdr.dts create mode 100644 firmware/scripts/libre.its create mode 100644 firmware/scripts/libre.mk create mode 100644 projects/libre/Makefile create mode 100755 projects/libre/Readme.md create mode 100644 projects/libre/system_bd.tcl create mode 100644 projects/libre/system_constr.xdc create mode 100644 projects/libre/system_project.tcl create mode 100644 projects/libre/system_top.v diff --git a/firmware/Makefile b/firmware/Makefile index 82c136f..4b82183 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -44,7 +44,7 @@ ifneq (1, ${PATCH}) endif TARGET ?= pluto -SUPPORTED_TARGETS:=pluto plutoplus e200 +SUPPORTED_TARGETS:=pluto plutoplus e200 libre #XSA_FILE ?= ori/bitstream/${TARGET}/system_top.xsa $(warning *** Building target $(TARGET),) @@ -54,9 +54,9 @@ include scripts/$(TARGET).mk ifeq (, $(shell which dfu-suffix)) $(warning "No dfu-utils in PATH consider doing: sudo apt-get install dfu-util") -TARGETS = build/pluto.frm build/boot.frm +TARGETS = build/$(TARGET).frm build/boot.frm else -TARGETS = build/$(TARGET).dfu build/uboot-env.dfu build/pluto.frm build/boot.dfu build/boot.frm +TARGETS = build/$(TARGET).dfu build/uboot-env.dfu build/$(TARGET).frm build/boot.dfu build/boot.frm endif ifeq ($(findstring $(TARGET),$(SUPPORTED_TARGETS)),) @@ -199,7 +199,7 @@ else endif ### MSD update firmware file ### -build/pluto.frm: build/$(TARGET).itb +build/$(TARGET).frm: build/$(TARGET).itb md5sum $< | cut -d ' ' -f 1 > $@.md5 cat $< $@.md5 > $@ @@ -235,6 +235,9 @@ endif ifeq ($(TARGET),e200) cp build/zynq-e200.dtb $(SDIMGDIR)/devicetree.dtb endif +ifeq ($(TARGET),libre) + cp build/zynq-libre.dtb $(SDIMGDIR)/devicetree.dtb +endif cp build/uboot-env.txt $(SDIMGDIR)/uEnv.txt cp build/rootfs.cpio.gz $(SDIMGDIR)/ramdisk.image.gz mkimage -A arm -T ramdisk -C gzip -d $(SDIMGDIR)/ramdisk.image.gz $(SDIMGDIR)/uramdisk.image.gz diff --git a/firmware/ori/libre/buildroot-configs/zynq_libre_defconfig b/firmware/ori/libre/buildroot-configs/zynq_libre_defconfig new file mode 100644 index 0000000..0692d2d --- /dev/null +++ b/firmware/ori/libre/buildroot-configs/zynq_libre_defconfig @@ -0,0 +1,68 @@ +BR2_arm=y +BR2_cortex_a9=y +BR2_ARM_ENABLE_NEON=y +BR2_ARM_ENABLE_VFP=y +BR2_ARM_FPU_NEON=y +BR2_TOOLCHAIN_EXTERNAL=y +BR2_TOOLCHAIN_EXTERNAL_LINARO_ARM=y +BR2_OPTIMIZE_3=y +BR2_PACKAGE_ETHTOOL=y +BR2_PACKAGE_ETHTOOL_PRETTY_PRINT=y +BR2_PACKAGE_IPERF3=y +BR2_PACKAGE_HTOP=y +BR2_TARGET_GENERIC_HOSTNAME="libre" +BR2_TARGET_GENERIC_ISSUE="Welcome to LibreSDR" +BR2_ROOTFS_DEVICE_CREATION_DYNAMIC_MDEV=y +BR2_TARGET_GENERIC_ROOT_PASSWD="analog" +BR2_TARGET_GENERIC_GETTY_PORT="ttyPS0" +BR2_ROOTFS_POST_BUILD_SCRIPT="board/libre/post-build.sh" +BR2_PACKAGE_ZSTD=y +BR2_PACKAGE_MTD=y +# BR2_PACKAGE_MTD_NANDDUMP is not set +# BR2_PACKAGE_MTD_NANDTEST is not set +# BR2_PACKAGE_MTD_NANDWRITE is not set +# BR2_PACKAGE_MTD_UBIATTACH is not set +# BR2_PACKAGE_MTD_UBICRC32 is not set +# BR2_PACKAGE_MTD_UBIDETACH is not set +# BR2_PACKAGE_MTD_UBIFORMAT is not set +# BR2_PACKAGE_MTD_UBIMKVOL is not set +# BR2_PACKAGE_MTD_UBINFO is not set +# BR2_PACKAGE_MTD_UBINIZE is not set +# BR2_PACKAGE_MTD_UBIRENAME is not set +# BR2_PACKAGE_MTD_UBIRMVOL is not set +# BR2_PACKAGE_MTD_UBIRSVOL is not set +# BR2_PACKAGE_MTD_UBIUPDATEVOL is not set +# BR2_PACKAGE_MTD_UBIBLOCK is not set +BR2_PACKAGE_LINUX_FIRMWARE=y +BR2_PACKAGE_LINUX_FIRMWARE_RALINK_RT61=y +BR2_PACKAGE_LINUX_FIRMWARE_RALINK_RT73=y +BR2_PACKAGE_LINUX_FIRMWARE_RALINK_RT2XX=y +BR2_PACKAGE_LINUX_FIRMWARE_RTL_81XX=y +BR2_PACKAGE_LINUX_FIRMWARE_RTL_87XX=y +BR2_PACKAGE_LINUX_FIRMWARE_RTL_88XX=y +BR2_PACKAGE_INPUT_EVENT_DAEMON=y +BR2_PACKAGE_UBOOT_TOOLS=y +BR2_PACKAGE_ZLIB=y +BR2_PACKAGE_LIBAD9361_IIO=y +BR2_PACKAGE_LIBGPIOD=y +BR2_PACKAGE_LIBGPIOD_TOOLS=y +BR2_PACKAGE_LIBIIO_IIOD_USBD=y +BR2_PACKAGE_LIBIIO_TESTS=y +BR2_PACKAGE_LIBINI=y +BR2_PACKAGE_AVAHI=y +BR2_PACKAGE_AVAHI_DAEMON=y +BR2_PACKAGE_AVAHI_LIBDNSSD_COMPATIBILITY=y +BR2_PACKAGE_DROPBEAR=y +BR2_PACKAGE_DROPBEAR_LOCALOPTIONS_FILE="board/pluto/dropbrear_localoptions.h" +BR2_PACKAGE_IW=y +BR2_PACKAGE_WPA_SUPPLICANT=y +BR2_PACKAGE_WPA_SUPPLICANT_CLI=y +BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y +BR2_PACKAGE_POLL_SYSFS=y +BR2_PACKAGE_AD936X_REF_CAL=y +BR2_TARGET_ROOTFS_CPIO=y +BR2_TARGET_ROOTFS_CPIO_GZIP=y +BR2_TARGET_ROOTFS_CPIO_UIMAGE=y +BR2_PACKAGE_HOST_DOSFSTOOLS=y +BR2_PACKAGE_HOST_GENIMAGE=y +BR2_PACKAGE_HOST_MTOOLS=y \ No newline at end of file diff --git a/firmware/ori/libre/linux-configs/zynq_libre_linux_defconfig b/firmware/ori/libre/linux-configs/zynq_libre_linux_defconfig new file mode 100644 index 0000000..73790cc --- /dev/null +++ b/firmware/ori/libre/linux-configs/zynq_libre_linux_defconfig @@ -0,0 +1,286 @@ +CONFIG_SYSVIPC=y +CONFIG_USELIB=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=15 +CONFIG_CGROUPS=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3=y +CONFIG_EMBEDDED=y +CONFIG_PERF_EVENTS=y +CONFIG_SLAB=y +CONFIG_ARCH_ZYNQ=y + + +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y + +CONFIG_UEVENT_HELPER=y +CONFIG_MACB=y +CONFIG_MDIO_BITBANG=y +CONFIG_MARVELL_PHY=y +CONFIG_XILINX_GMII2RGMII=y +CONFIG_USB_NET_DM9601=y + +CONFIG_XILINX_RESET_CODE=y +CONFIG_PL310_ERRATA_588369=y +CONFIG_PL310_ERRATA_727915=y +CONFIG_PL310_ERRATA_769419=y +# CONFIG_ARM_ERRATA_643719 is not set +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_754327=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HIGHMEM=y +# CONFIG_HIGHPTE is not set +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw earlyprintk" +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_MENU=y +CONFIG_ARM_ZYNQ_CPUIDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +# CONFIG_IPV6 is not set +CONFIG_VLAN_8021Q=m +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_RFKILL_INPUT=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_DMA_CMA=y +CONFIG_CMA_SIZE_MBYTES=256 +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_M25P80=y +CONFIG_MTD_SPI_NOR=y +# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_ADI_AXI_TDD=y +CONFIG_SRAM=y +# CONFIG_MATHWORKS_IP_CORE is not set +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ALACRITECH is not set +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_VENDOR_AQUANTIA is not set +# CONFIG_NET_VENDOR_ARC is not set +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_HUAWEI is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MELLANOX is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_RENESAS is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SOLARFLARE is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_CDC_NCM is not set +CONFIG_USB_NET_SMSC75XX=y +CONFIG_USB_NET_SMSC95XX=y +# CONFIG_USB_NET_NET1080 is not set +CONFIG_USB_NET_RNDIS_HOST=y +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +CONFIG_RT2X00=y +CONFIG_RT2500USB=y +CONFIG_RT73USB=y +CONFIG_RT2800USB=y +CONFIG_RT2800USB_RT3573=y +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8187=y +CONFIG_RTL8192CU=y +# CONFIG_RTLWIFI_DEBUG is not set +CONFIG_RTL8XXXU=y +CONFIG_RTL8XXXU_UNTESTED=y +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +CONFIG_INPUT_FF_MEMLESS=y +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_CADENCE=y +CONFIG_I2C_GPIO=y +CONFIG_I2C_XILINX=y +CONFIG_SPI=y +CONFIG_SPI_AXI_SPI_ENGINE=y +CONFIG_SPI_CADENCE=y +CONFIG_SPI_XILINX=y +CONFIG_SPI_ZYNQ_QSPI=y +CONFIG_SPI_SPIDEV=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_ZYNQ=y +CONFIG_POWER_SUPPLY=y +CONFIG_THERMAL=y +CONFIG_WATCHDOG=y +CONFIG_XILINX_WATCHDOG=y +CONFIG_CADENCE_WATCHDOG=y +CONFIG_SSB=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_HIDRAW=y +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_OTG=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_XILINX=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_ECM_SUBSET=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_EEM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_DMADEVICES=y +CONFIG_AXI_DMAC=y +CONFIG_UIO=y +CONFIG_UIO_PDRV_GENIRQ=y +CONFIG_UIO_DMEM_GENIRQ=y +CONFIG_UIO_XILINX_APM=y +CONFIG_STAGING=y +CONFIG_R8712U=y +CONFIG_R8188EU=y +CONFIG_COMMON_CLK_AXI_CLKGEN=y +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_MEMORY=y +CONFIG_IIO=y +CONFIG_ADM1177=y +CONFIG_AD9361=y +CONFIG_AD9361_EXT_BAND_CONTROL=y +CONFIG_ADMC=y +CONFIG_XILINX_XADC=y +CONFIG_ONE_BIT_ADC_DAC=y +CONFIG_CF_AXI_DDS=y +CONFIG_ADI_IIO_FAKEDEV=y +CONFIG_FPGA=y +CONFIG_FPGA_MGR_ZYNQ_FPGA=y +CONFIG_EXT4_FS=y +# CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_COMPRESSION_OPTIONS=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_CRYPTO_ECB=y +CONFIG_CRYPTO_MICHAEL_MIC=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_FS=y +CONFIG_DETECT_HUNG_TASK=y +CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_FTRACE is not set +CONFIG_DEBUG_LL=y +CONFIG_DEBUG_ZYNQ_UART0=y +CONFIG_EARLY_PRINTK=y \ No newline at end of file diff --git a/firmware/ori/libre/linux-dts/zynq-libre.dts b/firmware/ori/libre/linux-dts/zynq-libre.dts new file mode 100644 index 0000000..1c43423 --- /dev/null +++ b/firmware/ori/libre/linux-dts/zynq-libre.dts @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * + * hdl_project: + * board_revision: <5> + * + */ +/dts-v1/; +#include "zynq-libre.dtsi" + + +// &axi_i2c0 { +// current_limiter@5a { +// compatible = "adi,adm1177"; +// reg = <0x5a>; +// adi,r-sense-mohm = <50>; /* 50 mOhm */ +// adi,shutdown-threshold-ma = <1059>; /* 1.059 A */ +// adi,vrange-high-enable; +// }; +// }; + + +&adc0_ad9364 { + /* This property is controlled by u-boot environment. */ + adi,2rx-2tx-mode-enable; +}; + +&cf_ad9364_dac_core_0 { + /* This property is controlled by u-boot environment. */ + compatible = "adi,axi-ad9361-dds-6.00.a"; +}; + + +/ { + + leds { + compatible = "gpio-leds"; + led0 { + label = "led0:green"; + gpios = <&gpio0 15 0>; + linux,default-trigger = "heartbeat"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + button { + interrupt-parent = <&gpio0>; + interrupts = <14 IRQ_TYPE_EDGE_FALLING>; + label = "Button"; + linux,code = ; + }; + + }; +}; + + diff --git a/firmware/ori/libre/linux-dts/zynq-libre.dtsi b/firmware/ori/libre/linux-dts/zynq-libre.dtsi new file mode 100644 index 0000000..eca50e7 --- /dev/null +++ b/firmware/ori/libre/linux-dts/zynq-libre.dtsi @@ -0,0 +1,449 @@ +/* + * Libre SDR (Z7020/AD936x) + * + * + * Licensed under the GPL-2. + */ +#include "zynq.dtsi" +#include +#include +#include + +#define AD9361_EXT_BAND_CTL_SHORTHANDS +#include + +/ { + model = "LibreSDR Rev.5 (Z7020/AD9363)"; + memory { + device_type = "memory"; + reg = <0x00000000 0x40000000>; + }; + + chosen { + stdout-path = "/amba@0/uart@E0000000"; + }; + + + clocks { + ad9364_clkin: clock@0 { + #clock-cells = <0>; + compatible = "adjustable-clock"; + clock-frequency = <40000000>; + clock-accuracy = <200000>; /* 200 ppm (ppb) */ + clock-output-names = "ad9364_ext_refclk"; + }; + }; + + usb_phy0: phy0 { + compatible = "ulpi-phy"; + #phy-cells = <0>; + reg = <0xe0002000 0x1000>; + view-port = <0x0170>; + drv-vbus; + }; + +}; + +&clkc { + ps-clk-frequency = <50000000>; +}; + +&sdhci0 { + status = "okay"; + xlnx,has-cd = <0x0>; + xlnx,has-power = <0x0>; + xlnx,has-wp = <0x0>; +}; + +&watchdog0 { + status = "okay"; + reset-on-timeout; +}; + +&gem0 { + status = "okay"; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + + phy0: phy@0 { /* Marvell 88e1512 */ + reg = <0>; + compatible = "ethernet-phy-ieee802.3-c22"; + reset-gpios = <&gpio0 46 1>; + }; +}; + +&usb0 { + xlnx,phy-reset-gpio = <&gpio0 47 0>; + dr_mode = "otg"; + status = "okay"; + usb-phy = <&usb_phy0>; +}; + +&uart0 { + u-boot,dm-pre-reloc; + status = "okay"; +}; + +&qspi { + status = "okay"; + is-dual = <0>; + num-cs = <1>; + primary_flash: ps7-qspi@0 { + #address-cells = <1>; + #size-cells = <1>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + compatible = "n25q256a", "n25q512a", "jedec,spi-nor"; /* same as S25FL256 */ + reg = <0x0>; + spi-max-frequency = <50000000>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; /* 1M */ + }; + partition@qspi-uboot-env { + label = "qspi-uboot-env"; + reg = <0x100000 0x20000>; /* 128k */ + }; + partition@qspi-nvmfs { + label = "qspi-nvmfs"; + reg = <0x120000 0xE0000>; /* 1M */ + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x200000 0x1E00000>; /* 30M */ + }; + }; +}; + +&adc { + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + channel@0 { + reg = <0>; + }; + }; +}; + +/ { + fpga_axi: fpga-axi@0 { + compatible = "simple-bus"; + #address-cells = <0x1>; + #size-cells = <0x1>; + ranges; + + // axi_i2c0: i2c@41600000 { + // compatible = "xlnx,axi-iic-1.02.a", "xlnx,xps-iic-2.00.a"; + // reg = <0x41600000 0x10000>; + // interrupt-parent = <&intc>; + // interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>; + // clocks = <&clkc 15>; + // clock-names = "pclk"; + + // #address-cells = <1>; + // #size-cells = <0>; + + // }; + + rx_dma: dma@7c400000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c400000 0x10000>; + #dma-cells = <1>; + interrupts = <0 57 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <32>; + adi,source-bus-type = <2>; + adi,destination-bus-width = <64>; + adi,destination-bus-type = <0>; + }; + }; + }; + + tx_dma: dma@7c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c420000 0x10000>; + #dma-cells = <1>; + interrupts = <0 56 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clkc 16>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <64>; + adi,source-bus-type = <0>; + adi,destination-bus-width = <32>; + adi,destination-bus-type = <2>; + }; + }; + }; + + cf_ad9364_adc_core_0: cf-ad9361-lpc@79020000 { + compatible = "adi,axi-ad9361-6.00.a"; + reg = <0x79020000 0x6000>; + dmas = <&rx_dma 0>; + dma-names = "rx"; + spibus-connected = <&adc0_ad9364>; + adi,axi-decimation-core-available; + }; + + cf_ad9364_dac_core_0: cf-ad9361-dds-core-lpc@79024000 { + compatible = "adi,axi-ad9364-dds-6.00.a"; + reg = <0x79024000 0x1000>; + clocks = <&adc0_ad9364 13>; + clock-names = "sampl_clk"; + dmas = <&tx_dma 0>; + dma-names = "tx"; + adi,axi-interpolation-core-available; + adi,axi-dds-default-scale = <0>; + }; + + mwipcore@43c00000 { + compatible = "mathworks,mwipcore-axi4lite-v1.00"; + reg = <0x43c00000 0xffff>; + }; + }; +}; + +&spi0 { + status = "okay"; + + adc0_ad9364: ad9361-phy@0 { + #address-cells = <1>; + #size-cells = <0>; + #clock-cells = <1>; + compatible = "adi,ad9361"; + + /* SPI Setup */ + reg = <0>; + spi-cpha; + spi-max-frequency = <10000000>; + + /* Clocks */ + clocks = <&ad9364_clkin 0>; + clock-names = "ad9364_ext_refclk"; + clock-output-names = "rx_sampl_clk", "tx_sampl_clk"; + + /* Digital Interface Control */ + + /* adi,digital-interface-tune-skip-mode: + * 0 = TUNE RX&TX + * 1 = SKIP TX + * 2 = SKIP ALL + */ + adi,digital-interface-tune-skip-mode = <0>; /* TUNE RX & TX */ + + adi,pp-tx-swap-enable; + adi,pp-rx-swap-enable; + adi,rx-frame-pulse-mode-enable; + adi,lvds-mode-enable; + adi,lvds-bias-mV = <150>; + adi,lvds-rx-onchip-termination-enable; + adi,rx-data-delay = <4>; + adi,tx-fb-clock-delay = <7>; + adi,tx-data-delay = <9>; + + adi,xo-disable-use-ext-refclk-enable; + + /* Mode Setup */ + + //adi,split-gain-table-mode-enable; + + /* ENSM Mode */ + adi,frequency-division-duplex-mode-enable; + //adi,ensm-enable-pin-pulse-mode-enable; + //adi,ensm-enable-txnrx-control-enable; + + + /* adi,rx-rf-port-input-select: + * 0 = (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced + * 1 = (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced + * 2 = (RX1C_N & RX1C_P) and (RX2C_N & RX2C_P) enabled; balanced + * + * 3 = RX1A_N and RX2A_N enabled; unbalanced + * 4 = RX1A_P and RX2A_P enabled; unbalanced + * 5 = RX1B_N and RX2B_N enabled; unbalanced + * 6 = RX1B_P and RX2B_P enabled; unbalanced + * 7 = RX1C_N and RX2C_N enabled; unbalanced + * 8 = RX1C_P and RX2C_P enabled; unbalanced + */ + + adi,rx-rf-port-input-select = <0>; /* (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced */ + adi,rx-rf-port-input-select-lock-enable; + + /* adi,tx-rf-port-input-select: + * 0 TX1A, TX2A + * 1 TX1B, TX2B + */ + + adi,tx-rf-port-input-select = <0>; /* TX1A, TX2A */ + adi,tx-rf-port-input-select-lock-enable; + + //adi,update-tx-gain-in-alert-enable; + adi,tx-attenuation-mdB = <10000>; + adi,tx-lo-powerdown-managed-enable; + + adi,rf-rx-bandwidth-hz = <18000000>; + adi,rf-tx-bandwidth-hz = <18000000>; + adi,rx-synthesizer-frequency-hz = /bits/ 64 <2400000000>; + adi,tx-synthesizer-frequency-hz = /bits/ 64 <2450000000>; + + /* BBPLL ADC R2CLK R1CLK CLKRF RSAMPL */ + adi,rx-path-clock-frequencies = <983040000 245760000 122880000 61440000 30720000 30720000>; + /* BBPLL DAC T2CLK T1CLK CLKTF TSAMPL */ + adi,tx-path-clock-frequencies = <983040000 122880000 122880000 61440000 30720000 30720000>; + + /* Gain Control */ + + /* adi,gc-rx[1|2]-mode: + * 0 = RF_GAIN_MGC + * 1 = RF_GAIN_FASTATTACK_AGC + * 2 = RF_GAIN_SLOWATTACK_AGC + * 3 = RF_GAIN_HYBRID_AGC + */ + + adi,gc-rx1-mode = <2>; + adi,gc-rx2-mode = <2>; + adi,gc-adc-ovr-sample-size = <4>; /* sum 4 samples */ + adi,gc-adc-small-overload-thresh = <47>; /* sum of squares */ + adi,gc-adc-large-overload-thresh = <58>; /* sum of squares */ + adi,gc-lmt-overload-high-thresh = <800>; /* mV */ + adi,gc-lmt-overload-low-thresh = <704>; /* mV */ + adi,gc-dec-pow-measurement-duration = <8192>; /* 0..524288 Samples */ + adi,gc-low-power-thresh = <24>; /* 0..-64 dBFS vals are set pos */ + //adi,gc-dig-gain-enable; + //adi,gc-max-dig-gain = <15>; + + /* Manual Gain Control Setup */ + + //adi,mgc-rx1-ctrl-inp-enable; /* uncomment to use ctrl inputs */ + //adi,mgc-rx2-ctrl-inp-enable; /* uncomment to use ctrl inputs */ + adi,mgc-inc-gain-step = <2>; + adi,mgc-dec-gain-step = <2>; + + /* adi,mgc-split-table-ctrl-inp-gain-mode: + * (relevant if adi,split-gain-table-mode-enable is set) + * 0 = AGC determine this + * 1 = only in LPF + * 2 = only in LMT + */ + + adi,mgc-split-table-ctrl-inp-gain-mode = <0>; + + /* Automatic Gain Control Setup */ + + adi,agc-attack-delay-extra-margin-us= <1>; /* us */ + adi,agc-outer-thresh-high = <5>; /* -dBFS */ + adi,agc-outer-thresh-high-dec-steps = <2>; /* 0..15 */ + adi,agc-inner-thresh-high = <10>; /* -dBFS */ + adi,agc-inner-thresh-high-dec-steps = <1>; /* 0..7 */ + adi,agc-inner-thresh-low = <12>; /* -dBFS */ + adi,agc-inner-thresh-low-inc-steps = <1>; /* 0..7 */ + adi,agc-outer-thresh-low = <18>; /* -dBFS */ + adi,agc-outer-thresh-low-inc-steps = <2>; /* 0..15 */ + + adi,agc-adc-small-overload-exceed-counter = <10>; /* 0..15 */ + adi,agc-adc-large-overload-exceed-counter = <10>; /* 0..15 */ + adi,agc-adc-large-overload-inc-steps = <2>; /* 0..15 */ + //adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable; + adi,agc-lmt-overload-large-exceed-counter = <10>; /* 0..15 */ + adi,agc-lmt-overload-small-exceed-counter = <10>; /* 0..15 */ + adi,agc-lmt-overload-large-inc-steps = <2>; /* 0..7 */ + //adi,agc-dig-saturation-exceed-counter = <3>; /* 0..15 */ + //adi,agc-dig-gain-step-size = <4>; /* 1..8 */ + + //adi,agc-sync-for-gain-counter-enable; + adi,agc-gain-update-interval-us = <1000>; /* 1ms */ + //adi,agc-immed-gain-change-if-large-adc-overload-enable; + //adi,agc-immed-gain-change-if-large-lmt-overload-enable; + + /* Fast AGC */ + + adi,fagc-dec-pow-measurement-duration = <64>; /* 64 Samples */ + //adi,fagc-allow-agc-gain-increase-enable; + adi,fagc-lp-thresh-increment-steps = <1>; + adi,fagc-lp-thresh-increment-time = <5>; + + adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt = <8>; + adi,fagc-final-overrange-count = <3>; + //adi,fagc-gain-increase-after-gain-lock-enable; + adi,fagc-gain-index-type-after-exit-rx-mode = <0>; + adi,fagc-lmt-final-settling-steps = <1>; + adi,fagc-lock-level = <10>; + adi,fagc-lock-level-gain-increase-upper-limit = <5>; + adi,fagc-lock-level-lmt-gain-increase-enable; + + adi,fagc-lpf-final-settling-steps = <1>; + adi,fagc-optimized-gain-offset = <5>; + adi,fagc-power-measurement-duration-in-state5 = <64>; + adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable; + adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll = <10>; + adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable; + adi,fagc-rst-gla-if-en-agc-pulled-high-mode = <0>; + adi,fagc-rst-gla-large-adc-overload-enable; + adi,fagc-rst-gla-large-lmt-overload-enable; + adi,fagc-rst-gla-stronger-sig-thresh-above-ll = <10>; + adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable; + adi,fagc-state-wait-time-ns = <260>; + adi,fagc-use-last-lock-level-for-set-gain-enable; + + /* RSSI */ + + /* adi,rssi-restart-mode: + * 0 = AGC_IN_FAST_ATTACK_MODE_LOCKS_THE_GAIN, + * 1 = EN_AGC_PIN_IS_PULLED_HIGH, + * 2 = ENTERS_RX_MODE, + * 3 = GAIN_CHANGE_OCCURS, + * 4 = SPI_WRITE_TO_REGISTER, + * 5 = GAIN_CHANGE_OCCURS_OR_EN_AGC_PIN_PULLED_HIGH, + */ + adi,rssi-restart-mode = <3>; + //adi,rssi-unit-is-rx-samples-enable; + adi,rssi-delay = <1>; /* 1us */ + adi,rssi-wait = <1>; /* 1us */ + adi,rssi-duration = <1000>; /* 1ms */ + + /* Control Outputs */ + adi,ctrl-outs-index = <0>; + adi,ctrl-outs-enable-mask = <0xFF>; + + /* AuxADC Temp Sense Control */ + + adi,temp-sense-measurement-interval-ms = <1000>; + adi,temp-sense-offset-signed = <0xCE>; + adi,temp-sense-periodic-measurement-enable; + + /* AuxDAC Control */ + + adi,aux-dac-manual-mode-enable; + + adi,aux-dac1-default-value-mV = <0>; + //adi,aux-dac1-active-in-rx-enable; + //adi,aux-dac1-active-in-tx-enable; + //adi,aux-dac1-active-in-alert-enable; + adi,aux-dac1-rx-delay-us = <0>; + adi,aux-dac1-tx-delay-us = <0>; + + adi,aux-dac2-default-value-mV = <0>; + //adi,aux-dac2-active-in-rx-enable; + //adi,aux-dac2-active-in-tx-enable; + //adi,aux-dac2-active-in-alert-enable; + adi,aux-dac2-rx-delay-us = <0>; + adi,aux-dac2-tx-delay-us = <0>; + + /* Control GPIOs */ + + en_agc-gpios = <&gpio0 66 0>; + reset-gpios = <&gpio0 67 0>; + + }; +}; diff --git a/firmware/ori/libre/setup_libre.sh b/firmware/ori/libre/setup_libre.sh new file mode 100755 index 0000000..f86596e --- /dev/null +++ b/firmware/ori/libre/setup_libre.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Setup script to install LibreSDR support files into submodules +# Run this after cloning the repo and initializing submodules + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +FIRMWARE_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")" + +echo "Installing LibreSDR files..." + +# Linux device tree and config +cp "$SCRIPT_DIR/linux-dts/zynq-libre.dts" "$FIRMWARE_DIR/linux/arch/arm/boot/dts/" +cp "$SCRIPT_DIR/linux-dts/zynq-libre.dtsi" "$FIRMWARE_DIR/linux/arch/arm/boot/dts/" +cp "$SCRIPT_DIR/linux-configs/zynq_libre_linux_defconfig" "$FIRMWARE_DIR/linux/arch/arm/configs/" + +# U-Boot device tree and config +cp "$SCRIPT_DIR/uboot-dts/zynq-libre-sdr.dts" "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/" +cp "$SCRIPT_DIR/uboot-configs/zynq_libre_defconfig" "$FIRMWARE_DIR/u-boot-xlnx/configs/" + +# Add zynq-libre-sdr.dtb to U-Boot DTS Makefile if not present +if ! grep -q "zynq-libre-sdr.dtb" "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/Makefile"; then + sed -i '/zynq-pluto-sdr.dtb/a\ zynq-libre-sdr.dtb \\' "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/Makefile" + echo "Added zynq-libre-sdr.dtb to U-Boot DTS Makefile" +fi + +# Buildroot config +cp "$SCRIPT_DIR/buildroot-configs/zynq_libre_defconfig" "$FIRMWARE_DIR/buildroot/configs/" + +echo "LibreSDR setup complete!" +echo "Build with: make TARGET=libre" diff --git a/firmware/ori/libre/uboot-configs/zynq_libre_defconfig b/firmware/ori/libre/uboot-configs/zynq_libre_defconfig new file mode 100644 index 0000000..c33cb87 --- /dev/null +++ b/firmware/ori/libre/uboot-configs/zynq_libre_defconfig @@ -0,0 +1,62 @@ +CONFIG_ARM=y +CONFIG_SYS_CONFIG_NAME="zynq_zc70x" +CONFIG_ARCH_ZYNQ=y +CONFIG_SYS_MALLOC_F_LEN=0x800 +CONFIG_DEFAULT_DEVICE_TREE="zynq-libre-sdr" +CONFIG_SPL=y +CONFIG_FIT=y +CONFIG_FIT_VERBOSE=y +CONFIG_FIT_SIGNATURE=y +CONFIG_BOOTDELAY=3 +CONFIG_SYS_NO_FLASH=y +CONFIG_HUSH_PARSER=y +CONFIG_SYS_PROMPT="LIBRESDR> " +# CONFIG_CMD_IMLS is not set +# CONFIG_CMD_XIMG is not set +# CONFIG_CMD_FLASH is not set +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_ZYNQ=y +CONFIG_ZYNQ_SDHCI=y +CONFIG_CMD_MMC=y +CONFIG_SD_BOOT=y + +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +CONFIG_CMD_DFU=y +CONFIG_CMD_GPIO=y +# CONFIG_CMD_SETEXPR is not set +# CONFIG_CMD_NET is not set +# CONFIG_CMD_NFS is not set +CONFIG_CMD_CACHE=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_OF_EMBED=y +CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_SPI_FLASH=y +CONFIG_SPI_FLASH_BAR=y +CONFIG_SPI_FLASH_ISSI=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +CONFIG_ZYNQ_QSPI=y +CONFIG_USB=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ULPI_VIEWPORT=y +CONFIG_USB_ULPI=y +CONFIG_USB_STORAGE=y +CONFIG_USB_GADGET=y +CONFIG_CI_UDC=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_DOWNLOAD=y +CONFIG_G_DNL_MANUFACTURER="Analog Devices Inc." +CONFIG_G_DNL_VENDOR_NUM=0x0456 +CONFIG_G_DNL_PRODUCT_NUM=0xb674 +CONFIG_REGEX=y +CONFIG_LIB_RAND=y \ No newline at end of file diff --git a/firmware/ori/libre/uboot-dts/zynq-libre-sdr.dts b/firmware/ori/libre/uboot-dts/zynq-libre-sdr.dts new file mode 100644 index 0000000..8121518 --- /dev/null +++ b/firmware/ori/libre/uboot-dts/zynq-libre-sdr.dts @@ -0,0 +1,111 @@ +/* + * LIBRE board DTS + * + * SPDX-License-Identifier: GPL-2.0+ + */ +/dts-v1/; +#include "zynq-7000.dtsi" + +/ { + model = "LibreSDR"; + compatible = "xlnx,zynq-7000"; + + aliases { + ethernet0 = &gem0; + serial0 = &uart0; + spi0 = &qspi; + }; + + memory { + device_type = "memory"; + reg = <0x0 0x40000000>; + }; + + chosen { + bootargs = "earlyprintk"; + linux,stdout-path = &uart0; + stdout-path = &uart0; + }; + + usb_phy0: phy0 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + button { + label = "Button"; + gpios = <&gpio0 14 0>; + linux,code = <103>; /* up */ + wakeup-source; + autorepeat; + }; + + }; + + +}; + + + + + + +&qspi { + status = "okay"; + is-dual = <0>; + num-cs = <1>; + flash@0 { + compatible = "n25q512a","micron,m25p80"; + reg = <0x0>; + spi-tx-bus-width = <1>; + spi-rx-bus-width = <4>; + spi-max-frequency = <50000000>; + #address-cells = <1>; + #size-cells = <1>; + partition@qspi-fsbl-uboot { + label = "qspi-fsbl-uboot"; + reg = <0x0 0x100000>; /* 1M */ + }; + partition@qspi-uboot-env { + label = "qspi-uboot-env"; + reg = <0x100000 0x20000>; /* 128k */ + }; + partition@qspi-nvmfs { + label = "qspi-nvmfs"; + reg = <0x120000 0xE0000>; /* 1M */ + }; + partition@qspi-linux { + label = "qspi-linux"; + reg = <0x200000 0x1E00000>; /* 30M */ + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; + usb-phy = <&usb_phy0>; +}; +&sdhci0 { + u-boot,dm-pre-reloc; + status = "okay"; + +}; + +&gem0 { + status = "okay"; + phy-mode = "rgmii-id"; + phy-handle = <ðernet_phy0>; + + ethernet_phy0: ethernet-phy@0 { + reg = <0>; + reset-gpios = <&gpio0 46 0>; + }; +}; \ No newline at end of file diff --git a/firmware/scripts/libre.its b/firmware/scripts/libre.its new file mode 100644 index 0000000..37df960 --- /dev/null +++ b/firmware/scripts/libre.its @@ -0,0 +1,70 @@ +/* + * U-Boot uImage source file for LibreSDR + */ + +/dts-v1/; + +/ { + description = "Configuration to load fpga before Kernel"; + magic = "ITB PlutoSDR (ADALM-PLUTO)"; + #address-cells = <1>; + images { + + fdt@1 { + description = "zynq-libre"; + data = /incbin/("../build/zynq-libre.dtb"); + type = "flat_dt"; + arch = "arm"; + compression = "none"; + }; + + fpga@1 { + description = "FPGA"; + data = /incbin/("../build/system_top.bit"); + type = "fpga"; + arch = "arm"; + compression = "none"; + load = <0xF000000>; + hash@1 { + algo = "md5"; + }; + }; + + linux_kernel@1 { + description = "Linux"; + data = /incbin/("../build/zImage"); + type = "kernel"; + arch = "arm"; + os = "linux"; + compression = "none"; + load = <0x8000>; + entry = <0x8000>; + hash@1 { + algo = "md5"; + }; + }; + + ramdisk@1 { + description = "Ramdisk"; + data = /incbin/("../build/rootfs.cpio.gz"); + type = "ramdisk"; + arch = "arm"; + os = "linux"; + compression = "gzip"; + hash@1 { + algo = "md5"; + }; + }; + }; + + configurations { + default = "config@0"; + config@0 { + description = "Linux with fpga LibreSDR"; + fdt = "fdt@1"; + kernel = "linux_kernel@1"; + ramdisk = "ramdisk@1"; + fpga = "fpga@1"; + }; + }; +}; diff --git a/firmware/scripts/libre.mk b/firmware/scripts/libre.mk new file mode 100644 index 0000000..2fb18e9 --- /dev/null +++ b/firmware/scripts/libre.mk @@ -0,0 +1,7 @@ +# Target specific constants go here + +TARGET_DTS_FILES:= zynq-libre.dtb +COMPLETE_NAME:=LIBRE +ZIP_ARCHIVE_PREFIX:=libresdr +DEVICE_VID:=0x0456 +DEVICE_PID:=0xb673 diff --git a/projects/libre/Makefile b/projects/libre/Makefile new file mode 100644 index 0000000..750d349 --- /dev/null +++ b/projects/libre/Makefile @@ -0,0 +1,24 @@ +#################################################################################### +## Copyright (c) 2018 - 2023 Analog Devices, Inc. +### SPDX short identifier: BSD-1-Clause +## Auto-generated, do not modify! +#################################################################################### + +PROJECT_NAME := libre + +M_DEPS += ../common/xilinx/adi_fir_filter_constr.xdc +M_DEPS += ../common/xilinx/adi_fir_filter_bd.tcl +M_DEPS += ../../library/util_cdc/sync_bits.v +M_DEPS += ../../library/common/util_pulse_gen.v +M_DEPS += ../../library/common/ad_iobuf.v +M_DEPS += ../../library/common/ad_bus_mux.v +M_DEPS += ../../library/axi_tdd/scripts/axi_tdd.tcl +M_DEPS += ../../library/axi_ad9361/axi_ad9361_delay.tcl + +LIB_DEPS += axi_ad9361 +LIB_DEPS += axi_dmac +LIB_DEPS += axi_tdd +LIB_DEPS += util_pack/util_cpack2 +LIB_DEPS += util_pack/util_upack2 + +include ../scripts/project-xilinx.mk diff --git a/projects/libre/Readme.md b/projects/libre/Readme.md new file mode 100755 index 0000000..c42a660 --- /dev/null +++ b/projects/libre/Readme.md @@ -0,0 +1,10 @@ +# PLUTO HDL Project + +Here are some pointers to help you: + * [Board Product Page](https://www.analog.com/adalm-pluto) + * [Board Product Page](https://www.analog.com/cn0566) + * Parts : [RF Agile Transceiver](https://www.analog.com/ad9363) + * Project Doc: https://wiki.analog.com/university/tools/pluto + * Project Doc: https://wiki.analog.com/resources/eval/user-guides/circuits-from-the-lab/cn0566 + * HDL Doc: https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz/reference_hdl + * Linux Drivers: https://wiki.analog.com/resources/tools-software/linux-drivers/iio-transceiver/ad9361 diff --git a/projects/libre/system_bd.tcl b/projects/libre/system_bd.tcl new file mode 100644 index 0000000..21813c3 --- /dev/null +++ b/projects/libre/system_bd.tcl @@ -0,0 +1,395 @@ +# create board design + + +source $ad_hdl_dir/projects/common/xilinx/adi_fir_filter_bd.tcl + +# default ports + +create_bd_intf_port -mode Master -vlnv xilinx.com:interface:ddrx_rtl:1.0 ddr +create_bd_intf_port -mode Master -vlnv xilinx.com:display_processing_system7:fixedio_rtl:1.0 fixed_io + +create_bd_port -dir O spi0_csn_2_o +create_bd_port -dir O spi0_csn_1_o +create_bd_port -dir O spi0_csn_0_o +create_bd_port -dir I spi0_csn_i +create_bd_port -dir I spi0_clk_i +create_bd_port -dir O spi0_clk_o +create_bd_port -dir I spi0_sdo_i +create_bd_port -dir O spi0_sdo_o +create_bd_port -dir I spi0_sdi_i + +create_bd_port -dir I -from 24 -to 0 gpio_i +create_bd_port -dir O -from 24 -to 0 gpio_o +create_bd_port -dir O -from 24 -to 0 gpio_t + +create_bd_port -dir O spi_csn_o +create_bd_port -dir I spi_csn_i +create_bd_port -dir I spi_clk_i +create_bd_port -dir O spi_clk_o +create_bd_port -dir I spi_sdo_i +create_bd_port -dir O spi_sdo_o +create_bd_port -dir I spi_sdi_i + +# instance: sys_ps7 + +ad_ip_instance processing_system7 sys_ps7 + +# ps7 settings + +ad_ip_parameter sys_ps7 CONFIG.PCW_PRESET_BANK0_VOLTAGE {LVCMOS 3.3V} +ad_ip_parameter sys_ps7 CONFIG.PCW_PRESET_BANK1_VOLTAGE {LVCMOS 2.5V} +ad_ip_parameter sys_ps7 CONFIG.PCW_PACKAGE_NAME clg400 +ad_ip_parameter sys_ps7 CONFIG.PCW_GPIO_MIO_GPIO_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_ENET0_IO "MIO 16 .. 27" +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_GRP_MDIO_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_GRP_MDIO_IO "MIO 52 .. 53" +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET_RESET_SELECT "Separate reset pins" +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_RESET_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_ENET0_RESET_IO "MIO 46" +ad_ip_parameter sys_ps7 CONFIG.PCW_USE_S_AXI_HP1 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_USE_S_AXI_HP2 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_EN_CLK1_PORT 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_EN_RST1_PORT 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_FPGA0_PERIPHERAL_FREQMHZ 100.0 +ad_ip_parameter sys_ps7 CONFIG.PCW_FPGA1_PERIPHERAL_FREQMHZ 200.0 +ad_ip_parameter sys_ps7 CONFIG.PCW_CRYSTAL_PERIPHERAL_FREQMHZ 50 +ad_ip_parameter sys_ps7 CONFIG.PCW_GPIO_EMIO_GPIO_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_GPIO_EMIO_GPIO_IO 25 +ad_ip_parameter sys_ps7 CONFIG.PCW_SPI1_PERIPHERAL_ENABLE 0 +ad_ip_parameter sys_ps7 CONFIG.PCW_I2C0_PERIPHERAL_ENABLE 0 +ad_ip_parameter sys_ps7 CONFIG.PCW_SD0_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_SDIO_PERIPHERAL_FREQMHZ 50 +ad_ip_parameter sys_ps7 CONFIG.PCW_UART0_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_UART0_UART0_IO {MIO 14 .. 15} +ad_ip_parameter sys_ps7 CONFIG.PCW_I2C1_PERIPHERAL_ENABLE 0 +ad_ip_parameter sys_ps7 CONFIG.PCW_QSPI_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_QSPI_GRP_SINGLE_SS_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_SPI0_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_SPI0_SPI0_IO EMIO +ad_ip_parameter sys_ps7 CONFIG.PCW_TTC0_PERIPHERAL_ENABLE 0 +ad_ip_parameter sys_ps7 CONFIG.PCW_USE_FABRIC_INTERRUPT 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_USB0_PERIPHERAL_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_GPIO_MIO_GPIO_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_GPIO_MIO_GPIO_IO MIO +ad_ip_parameter sys_ps7 CONFIG.PCW_USB0_RESET_IO {MIO 47} +ad_ip_parameter sys_ps7 CONFIG.PCW_USB0_RESET_ENABLE 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_IRQ_F2P_INTR 1 +ad_ip_parameter sys_ps7 CONFIG.PCW_IRQ_F2P_MODE REVERSE +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_0_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_9_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_10_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_11_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_48_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_49_PULLUP {disabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_MIO_53_PULLUP {enabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_APU_PERIPHERAL_FREQMHZ 750 + +# DDR MT41K256M16 HA-125 (32M, 16bit, 8banks) + +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_ACT_DDR_FREQ_MHZ 525 +# ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_PARTNO {MT41J256M16 RE-125} +# Use Custom memory parameters to allow tuning DDR timings. +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_PARTNO {Custom} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_BANK_ADDR_COUNT {3} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_ROW_ADDR_COUNT {15} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_COL_ADDR_COUNT {10} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_CL {7} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_CWL {5} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RCD {7} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RP {7} +# Increase DDR timing parameters to allow more DDR overclock. +# Tested 7-5-7-7 for 625 MHz, 8-6-8-8 for 700 MHz, 9-7-9-9 for 750 MHz, 10-7-10-10 for 775 MHz. +# ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_CL {9} +# ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_CWL {7} +# ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RCD {9} +# ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RP {9} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RC {48.91} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_RAS_MIN {35.0} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_T_FAW {40.0} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_0 {0.048} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_DQS_TO_CLK_DELAY_1 {0.050} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY0 {0.241} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_BOARD_DELAY1 {0.240} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_ECC {Disabled} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_BUS_WIDTH {32 Bit} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_DRAM_WIDTH {16 Bits} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_DEVICE_CAPACITY {4096 MBits} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_SPEED_BIN {DDR3_1066F} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_TRAIN_WRITE_LEVEL {1} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_TRAIN_READ_GATE {1} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_TRAIN_DATA_EYE {1} +ad_ip_parameter sys_ps7 CONFIG.PCW_UIPARAM_DDR_USE_INTERNAL_VREF {0} + +# ad_ip_parameter sys_ps7 CONFIG.PCW_OVERRIDE_BASIC_CLOCK 1 +# ad_ip_parameter sys_ps7 CONFIG.PCW_CPU_PERIPHERAL_DIVISOR0 3 +# ad_ip_parameter sys_ps7 CONFIG.PCW_ARMPLL_CTRL_FBDIV 52 +# ad_ip_parameter sys_ps7 CONFIG.PCW_DDR_PERIPHERAL_DIVISOR0 3 +# ad_ip_parameter sys_ps7 CONFIG.PCW_DDRPLL_CTRL_FBDIV 32 + +ad_ip_instance xlconcat sys_concat_intc +ad_ip_parameter sys_concat_intc CONFIG.NUM_PORTS 16 + +ad_ip_instance proc_sys_reset sys_rstgen +ad_ip_parameter sys_rstgen CONFIG.C_EXT_RST_WIDTH 1 + +# system reset/clock definitions + +# add external spi + +ad_ip_instance axi_quad_spi axi_spi +ad_ip_parameter axi_spi CONFIG.C_USE_STARTUP 0 +ad_ip_parameter axi_spi CONFIG.C_NUM_SS_BITS 1 +ad_ip_parameter axi_spi CONFIG.C_SCK_RATIO 8 + +ad_connect sys_cpu_clk sys_ps7/FCLK_CLK0 +ad_connect sys_200m_clk sys_ps7/FCLK_CLK1 +ad_connect sys_cpu_reset sys_rstgen/peripheral_reset +ad_connect sys_cpu_resetn sys_rstgen/peripheral_aresetn +ad_connect sys_cpu_clk sys_rstgen/slowest_sync_clk +ad_connect sys_rstgen/ext_reset_in sys_ps7/FCLK_RESET0_N + +# interface connections + +ad_connect ddr sys_ps7/DDR +ad_connect gpio_i sys_ps7/GPIO_I +ad_connect gpio_o sys_ps7/GPIO_O +ad_connect gpio_t sys_ps7/GPIO_T +ad_connect fixed_io sys_ps7/FIXED_IO + +# ps7 spi connections + +ad_connect spi0_csn_2_o sys_ps7/SPI0_SS2_O +ad_connect spi0_csn_1_o sys_ps7/SPI0_SS1_O +ad_connect spi0_csn_0_o sys_ps7/SPI0_SS_O +ad_connect spi0_csn_i sys_ps7/SPI0_SS_I +ad_connect spi0_clk_i sys_ps7/SPI0_SCLK_I +ad_connect spi0_clk_o sys_ps7/SPI0_SCLK_O +ad_connect spi0_sdo_i sys_ps7/SPI0_MOSI_I +ad_connect spi0_sdo_o sys_ps7/SPI0_MOSI_O +ad_connect spi0_sdi_i sys_ps7/SPI0_MISO_I + +# axi spi connections + +ad_connect sys_cpu_clk axi_spi/ext_spi_clk +ad_connect spi_csn_i axi_spi/ss_i +ad_connect spi_csn_o axi_spi/ss_o +ad_connect spi_clk_i axi_spi/sck_i +ad_connect spi_clk_o axi_spi/sck_o +ad_connect spi_sdo_i axi_spi/io0_i +ad_connect spi_sdo_o axi_spi/io0_o +ad_connect spi_sdi_i axi_spi/io1_i + +# interrupts + +ad_connect sys_concat_intc/dout sys_ps7/IRQ_F2P +ad_connect sys_concat_intc/In15 GND +ad_connect sys_concat_intc/In14 GND +ad_connect sys_concat_intc/In13 GND +ad_connect sys_concat_intc/In12 GND +ad_connect sys_concat_intc/In11 GND +ad_connect sys_concat_intc/In10 GND +ad_connect sys_concat_intc/In9 GND +ad_connect sys_concat_intc/In8 GND +ad_connect sys_concat_intc/In7 GND +ad_connect sys_concat_intc/In6 GND +ad_connect sys_concat_intc/In5 GND +ad_connect sys_concat_intc/In4 GND +ad_connect sys_concat_intc/In3 GND +ad_connect sys_concat_intc/In2 GND +ad_connect sys_concat_intc/In1 GND +ad_connect sys_concat_intc/In0 GND + +# iic + +create_bd_intf_port -mode Master -vlnv xilinx.com:interface:iic_rtl:1.0 iic_main + +ad_ip_instance axi_iic axi_iic_main + +ad_connect iic_main axi_iic_main/iic +ad_cpu_interconnect 0x41600000 axi_iic_main +ad_cpu_interrupt ps-15 mb-15 axi_iic_main/iic2intc_irpt + +# ad9361 + +create_bd_port -dir I rx_clk_in_p +create_bd_port -dir I rx_clk_in_n +create_bd_port -dir I rx_frame_in_p +create_bd_port -dir I rx_frame_in_n +create_bd_port -dir I -from 5 -to 0 rx_data_in_p +create_bd_port -dir I -from 5 -to 0 rx_data_in_n + +create_bd_port -dir O tx_clk_out_p +create_bd_port -dir O tx_clk_out_n +create_bd_port -dir O tx_frame_out_p +create_bd_port -dir O tx_frame_out_n +create_bd_port -dir O -from 5 -to 0 tx_data_out_p +create_bd_port -dir O -from 5 -to 0 tx_data_out_n + +create_bd_port -dir O enable +create_bd_port -dir O txnrx +create_bd_port -dir I up_enable +create_bd_port -dir I up_txnrx + +# ad9361 core(s) + +ad_ip_instance axi_ad9361 axi_ad9361 +ad_ip_parameter axi_ad9361 CONFIG.ID 0 +ad_ip_parameter axi_ad9361 CONFIG.CMOS_OR_LVDS_N 0 +ad_ip_parameter axi_ad9361 CONFIG.MODE_1R1T 0 +ad_ip_parameter axi_ad9361 CONFIG.ADC_INIT_DELAY 30 + +ad_ip_instance axi_dmac axi_ad9361_dac_dma +ad_ip_parameter axi_ad9361_dac_dma CONFIG.DMA_TYPE_SRC 0 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.DMA_TYPE_DEST 1 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.CYCLIC 1 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.AXI_SLICE_SRC 0 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.AXI_SLICE_DEST 0 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.DMA_2D_TRANSFER 0 +ad_ip_parameter axi_ad9361_dac_dma CONFIG.DMA_DATA_WIDTH_DEST 64 + +ad_add_interpolation_filter "tx_fir_interpolator" 8 2 1 {61.44} {7.68} \ + "$ad_hdl_dir/library/util_fir_int/coefile_int.coe" +ad_ip_instance xlslice interp_slice +ad_ip_instance util_upack2 tx_upack + +ad_ip_instance axi_dmac axi_ad9361_adc_dma +ad_ip_parameter axi_ad9361_adc_dma CONFIG.DMA_TYPE_SRC 2 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.DMA_TYPE_DEST 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.CYCLIC 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.SYNC_TRANSFER_START 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.AXI_SLICE_SRC 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.AXI_SLICE_DEST 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.DMA_2D_TRANSFER 0 +ad_ip_parameter axi_ad9361_adc_dma CONFIG.DMA_DATA_WIDTH_SRC 64 + +ad_add_decimation_filter "rx_fir_decimator" 8 2 1 {61.44} {61.44} \ + "$ad_hdl_dir/library/util_fir_int/coefile_int.coe" +ad_ip_instance xlslice decim_slice +ad_ip_instance util_cpack2 cpack + +# connections + +ad_connect rx_clk_in_p axi_ad9361/rx_clk_in_p +ad_connect rx_clk_in_n axi_ad9361/rx_clk_in_n +ad_connect rx_frame_in_p axi_ad9361/rx_frame_in_p +ad_connect rx_frame_in_n axi_ad9361/rx_frame_in_n +ad_connect rx_data_in_p axi_ad9361/rx_data_in_p +ad_connect rx_data_in_n axi_ad9361/rx_data_in_n +ad_connect tx_clk_out_p axi_ad9361/tx_clk_out_p +ad_connect tx_clk_out_n axi_ad9361/tx_clk_out_n +ad_connect tx_frame_out_p axi_ad9361/tx_frame_out_p +ad_connect tx_frame_out_n axi_ad9361/tx_frame_out_n +ad_connect tx_data_out_p axi_ad9361/tx_data_out_p +ad_connect tx_data_out_n axi_ad9361/tx_data_out_n +ad_connect enable axi_ad9361/enable +ad_connect txnrx axi_ad9361/txnrx +ad_connect up_enable axi_ad9361/up_enable +ad_connect up_txnrx axi_ad9361/up_txnrx + +ad_connect axi_ad9361/tdd_sync GND +ad_connect sys_200m_clk axi_ad9361/delay_clk +ad_connect axi_ad9361/l_clk axi_ad9361/clk + +ad_connect axi_ad9361/l_clk rx_fir_decimator/aclk + +ad_connect axi_ad9361/adc_valid_i0 rx_fir_decimator/valid_in_0 +ad_connect axi_ad9361/adc_enable_i0 rx_fir_decimator/enable_in_0 +ad_connect axi_ad9361/adc_data_i0 rx_fir_decimator/data_in_0 +ad_connect axi_ad9361/adc_valid_q0 rx_fir_decimator/valid_in_1 +ad_connect axi_ad9361/adc_enable_q0 rx_fir_decimator/enable_in_1 +ad_connect axi_ad9361/adc_data_q0 rx_fir_decimator/data_in_1 + +ad_connect axi_ad9361/l_clk cpack/clk +ad_connect axi_ad9361/rst cpack/reset + +ad_connect axi_ad9361/adc_enable_i1 cpack/enable_2 +ad_connect axi_ad9361/adc_data_i1 cpack/fifo_wr_data_2 +ad_connect axi_ad9361/adc_enable_q1 cpack/enable_3 +ad_connect axi_ad9361/adc_data_q1 cpack/fifo_wr_data_3 + +ad_connect cpack/enable_0 rx_fir_decimator/enable_out_0 +ad_connect cpack/enable_1 rx_fir_decimator/enable_out_1 +ad_connect cpack/fifo_wr_data_0 rx_fir_decimator/data_out_0 +ad_connect cpack/fifo_wr_data_1 rx_fir_decimator/data_out_1 +ad_connect rx_fir_decimator/valid_out_0 cpack/fifo_wr_en + +ad_connect axi_ad9361_adc_dma/fifo_wr cpack/packed_fifo_wr +ad_connect axi_ad9361/up_adc_gpio_out decim_slice/Din +ad_connect rx_fir_decimator/active decim_slice/Dout + +ad_connect axi_ad9361/l_clk tx_fir_interpolator/aclk + +ad_connect axi_ad9361/dac_enable_i0 tx_fir_interpolator/dac_enable_0 +ad_connect axi_ad9361/dac_valid_i0 tx_fir_interpolator/dac_valid_0 +ad_connect axi_ad9361/dac_data_i0 tx_fir_interpolator/data_out_0 +ad_connect axi_ad9361/dac_enable_q0 tx_fir_interpolator/dac_enable_1 +ad_connect axi_ad9361/dac_valid_q0 tx_fir_interpolator/dac_valid_1 +ad_connect axi_ad9361/dac_data_q0 tx_fir_interpolator/data_out_1 + +ad_connect axi_ad9361/l_clk tx_upack/clk +ad_connect axi_ad9361/rst tx_upack/reset + +ad_connect tx_upack/fifo_rd_data_0 tx_fir_interpolator/data_in_0 +ad_connect tx_upack/enable_0 tx_fir_interpolator/enable_out_0 +ad_connect tx_upack/fifo_rd_data_1 tx_fir_interpolator/data_in_1 +ad_connect tx_upack/enable_1 tx_fir_interpolator/enable_out_1 + +ad_connect axi_ad9361/dac_enable_i1 tx_upack/enable_2 +ad_connect axi_ad9361/dac_data_i1 tx_upack/fifo_rd_data_2 +ad_connect axi_ad9361/dac_enable_q1 tx_upack/enable_3 +ad_connect axi_ad9361/dac_data_q1 tx_upack/fifo_rd_data_3 + +ad_connect tx_upack/s_axis axi_ad9361_dac_dma/m_axis + +ad_ip_instance util_vector_logic logic_or [list \ + C_OPERATION {or} \ + C_SIZE 1] + +ad_connect logic_or/Op1 tx_fir_interpolator/valid_out_0 +ad_connect logic_or/Op2 axi_ad9361/dac_valid_i1 +ad_connect logic_or/Res tx_upack/fifo_rd_en +ad_connect tx_upack/fifo_rd_underflow axi_ad9361/dac_dunf + +ad_connect axi_ad9361/up_dac_gpio_out interp_slice/Din +ad_connect tx_fir_interpolator/active interp_slice/Dout + +ad_connect axi_ad9361/l_clk axi_ad9361_adc_dma/fifo_wr_clk +ad_connect axi_ad9361/l_clk axi_ad9361_dac_dma/m_axis_aclk +ad_connect cpack/fifo_wr_overflow axi_ad9361/adc_dovf + +# interconnects + +ad_cpu_interconnect 0x79020000 axi_ad9361 +ad_cpu_interconnect 0x7C400000 axi_ad9361_adc_dma +ad_cpu_interconnect 0x7C420000 axi_ad9361_dac_dma +ad_cpu_interconnect 0x7C430000 axi_spi + +ad_ip_parameter sys_ps7 CONFIG.PCW_USE_S_AXI_HP1 {1} +ad_connect sys_cpu_clk sys_ps7/S_AXI_HP1_ACLK +ad_connect axi_ad9361_adc_dma/m_dest_axi sys_ps7/S_AXI_HP1 + +create_bd_addr_seg -range 0x40000000 -offset 0x00000000 \ + [get_bd_addr_spaces axi_ad9361_adc_dma/m_dest_axi] \ + [get_bd_addr_segs sys_ps7/S_AXI_HP1/HP1_DDR_LOWOCM] \ + SEG_sys_ps7_HP1_DDR_LOWOCM + +ad_ip_parameter sys_ps7 CONFIG.PCW_USE_S_AXI_HP2 {1} +ad_connect sys_cpu_clk sys_ps7/S_AXI_HP2_ACLK +ad_connect axi_ad9361_dac_dma/m_src_axi sys_ps7/S_AXI_HP2 + +create_bd_addr_seg -range 0x40000000 -offset 0x00000000 \ + [get_bd_addr_spaces axi_ad9361_dac_dma/m_src_axi] \ + [get_bd_addr_segs sys_ps7/S_AXI_HP2/HP2_DDR_LOWOCM] \ + SEG_sys_ps7_HP2_DDR_LOWOCM + +ad_connect sys_cpu_clk axi_ad9361_dac_dma/m_src_axi_aclk +ad_connect sys_cpu_clk axi_ad9361_adc_dma/m_dest_axi_aclk +ad_connect sys_cpu_resetn axi_ad9361_adc_dma/m_dest_axi_aresetn +ad_connect sys_cpu_resetn axi_ad9361_dac_dma/m_src_axi_aresetn + +# interrupts + +ad_cpu_interrupt ps-13 mb-13 axi_ad9361_adc_dma/irq +ad_cpu_interrupt ps-12 mb-12 axi_ad9361_dac_dma/irq +ad_cpu_interrupt ps-11 mb-11 axi_spi/ip2intc_irpt diff --git a/projects/libre/system_constr.xdc b/projects/libre/system_constr.xdc new file mode 100644 index 0000000..12547cb --- /dev/null +++ b/projects/libre/system_constr.xdc @@ -0,0 +1,133 @@ +# LibreSDR XC7Z020-CLG400 Pin Constraints +# Extracted from hz12opensource/libresdr hdl.diff patch + +# ============================================================================= +# Clock Constraints +# ============================================================================= + +# AD9363 LVDS RX clock (125 MHz max) +create_clock -name rx_clk -period 8.000 [get_ports rx_clk_in_p] + +# PS7 fabric clocks +create_clock -name clk_fpga_0 -period 10 [get_pins "i_system_wrapper/system_i/sys_ps7/inst/PS7_i/FCLKCLK[0]"] +create_clock -name clk_fpga_1 -period 5 [get_pins "i_system_wrapper/system_i/sys_ps7/inst/PS7_i/FCLKCLK[1]"] + +# SPI clock +create_clock -name spi0_clk -period 40 [get_pins -hier */EMIOSPI0SCLKO] + +# ============================================================================= +# AD9363 LVDS Interface - Bank 34 (2.5V) +# ============================================================================= + +# RX Clock (differential) +set_property -dict {PACKAGE_PIN N20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_clk_in_p] +set_property -dict {PACKAGE_PIN P20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_clk_in_n] + +# RX Frame (differential) +set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_frame_in_p] +set_property -dict {PACKAGE_PIN U19 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports rx_frame_in_n] + +# RX Data (differential) [5:0] +set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[0]}] +set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[0]}] +set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[1]}] +set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[1]}] +set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[2]}] +set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[2]}] +set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[3]}] +set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[3]}] +set_property -dict {PACKAGE_PIN W18 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[4]}] +set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[4]}] +set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_p[5]}] +set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVDS_25 DIFF_TERM 1} [get_ports {rx_data_in_n[5]}] + +# TX Clock (differential) +set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVDS_25} [get_ports tx_clk_out_p] +set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVDS_25} [get_ports tx_clk_out_n] + +# TX Frame (differential) +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVDS_25} [get_ports tx_frame_out_p] +set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVDS_25} [get_ports tx_frame_out_n] + +# TX Data (differential) [5:0] +set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[0]}] +set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[0]}] +set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[1]}] +set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[1]}] +set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[2]}] +set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[2]}] +set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[3]}] +set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[3]}] +set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[4]}] +set_property -dict {PACKAGE_PIN W13 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[4]}] +set_property -dict {PACKAGE_PIN T12 IOSTANDARD LVDS_25} [get_ports {tx_data_out_p[5]}] +set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVDS_25} [get_ports {tx_data_out_n[5]}] + +# ============================================================================= +# AD9363 Control Signals +# ============================================================================= + +# Enable and TxNRx +set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS25} [get_ports enable] +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS25} [get_ports txnrx] + +# GPIO Reset and AGC +set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS25} [get_ports gpio_resetb] +set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS25} [get_ports gpio_en_agc] + +# ============================================================================= +# GPIO Status [7:0] - Bank 34 (2.5V) +# ============================================================================= + +set_property -dict {PACKAGE_PIN T11 IOSTANDARD LVCMOS25} [get_ports {gpio_status[0]}] +set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS25} [get_ports {gpio_status[1]}] +set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS25} [get_ports {gpio_status[2]}] +set_property -dict {PACKAGE_PIN T17 IOSTANDARD LVCMOS25} [get_ports {gpio_status[3]}] +set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS25} [get_ports {gpio_status[4]}] +set_property -dict {PACKAGE_PIN G14 IOSTANDARD LVCMOS33} [get_ports {gpio_status[5]}] +set_property -dict {PACKAGE_PIN U13 IOSTANDARD LVCMOS25} [get_ports {gpio_status[6]}] +set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS25} [get_ports {gpio_status[7]}] + +# ============================================================================= +# GPIO Control [3:0] - Mixed Banks +# ============================================================================= + +set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS25} [get_ports {gpio_ctl[0]}] +set_property -dict {PACKAGE_PIN Y11 IOSTANDARD LVCMOS33} [get_ports {gpio_ctl[1]}] +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {gpio_ctl[2]}] +set_property -dict {PACKAGE_PIN U9 IOSTANDARD LVCMOS33} [get_ports {gpio_ctl[3]}] + +# ============================================================================= +# I2C Interface - Bank 35 (3.3V) +# ============================================================================= + +set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33 PULLUP true} [get_ports iic_scl] +set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33 PULLUP true} [get_ports iic_sda] + +# ============================================================================= +# SPI Interface (AD9363) - Bank 34 (2.5V) +# ============================================================================= + +set_property -dict {PACKAGE_PIN P18 IOSTANDARD LVCMOS25} [get_ports spi_csn] +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS25} [get_ports spi_clk] +set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS25} [get_ports spi_mosi] +set_property -dict {PACKAGE_PIN R19 IOSTANDARD LVCMOS25} [get_ports spi_miso] + +# ============================================================================= +# PL SPI Interface - Bank 35 (3.3V) +# ============================================================================= + +set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports pl_spi_clk_o] +set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports pl_spi_miso] +set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports pl_spi_mosi] + +# ============================================================================= +# Timing Exceptions +# ============================================================================= + +# False paths for GPIO outputs from axi_ad9361 +set_false_path -from [get_pins i_system_wrapper/system_i/axi_ad9361/inst/i_tdd/i_tdd_control/tdd_enable_reg/C] +set_false_path -from [get_pins i_system_wrapper/system_i/axi_ad9361/inst/i_tdd/i_tdd_control/tdd_tx_only_reg/C] +set_false_path -from [get_pins i_system_wrapper/system_i/axi_ad9361/inst/i_tdd/i_tdd_control/tdd_rx_only_reg/C] +set_false_path -from [get_pins i_system_wrapper/system_i/axi_ad9361/inst/i_tdd/i_tdd_control/tdd_gated_tx_dmapath_reg/C] +set_false_path -from [get_pins i_system_wrapper/system_i/axi_ad9361/inst/i_tdd/i_tdd_control/tdd_gated_rx_dmapath_reg/C] diff --git a/projects/libre/system_project.tcl b/projects/libre/system_project.tcl new file mode 100644 index 0000000..43e2e58 --- /dev/null +++ b/projects/libre/system_project.tcl @@ -0,0 +1,14 @@ +source ../../scripts/adi_env.tcl +source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl +source $ad_hdl_dir/projects/scripts/adi_board.tcl + +adi_project_create libre 0 {} "xc7z020clg400-2" + +adi_project_files libre [list \ + "system_top.v" \ + "system_constr.xdc" \ + "$ad_hdl_dir/library/common/ad_iobuf.v"] + +set_property is_enabled false [get_files *system_sys_ps7_0.xdc] +adi_project_run libre +source $ad_hdl_dir/library/axi_ad9361/axi_ad9361_delay.tcl diff --git a/projects/libre/system_top.v b/projects/libre/system_top.v new file mode 100644 index 0000000..63c4413 --- /dev/null +++ b/projects/libre/system_top.v @@ -0,0 +1,183 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. +// +// In this HDL repository, there are many different and unique modules, consisting +// of various HDL (Verilog or VHDL) components. The individual modules are +// developed independently, and may be accompanied by separate and unique license +// terms. +// +// The user should read each of these license terms, and understand the +// freedoms and responsibilities that he or she has by using this source/core. +// +// This core is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. +// +// Redistribution and use of source or resulting binaries, with or without modification +// of this file, are permitted under one of the following two license terms: +// +// 1. The GNU General Public License version 2 as published by the +// Free Software Foundation, which can be found in the top level directory +// of this repository (LICENSE_GPL2), and also online at: +// +// +// OR +// +// 2. An ADI specific BSD license, which can be found in the top level directory +// of this repository (LICENSE_ADIBSD), and also on-line at: +// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD +// This will allow to generate bit files and not release the source code, +// as long as it attaches to an ADI device. +// +// *************************************************************************** +// *************************************************************************** + +`timescale 1ns/100ps + +module system_top ( + + inout [14:0] ddr_addr, + inout [ 2:0] ddr_ba, + inout ddr_cas_n, + inout ddr_ck_n, + inout ddr_ck_p, + inout ddr_cke, + inout ddr_cs_n, + inout [ 3:0] ddr_dm, + inout [31:0] ddr_dq, + inout [ 3:0] ddr_dqs_n, + inout [ 3:0] ddr_dqs_p, + inout ddr_odt, + inout ddr_ras_n, + inout ddr_reset_n, + inout ddr_we_n, + + inout fixed_io_ddr_vrn, + inout fixed_io_ddr_vrp, + inout [53:0] fixed_io_mio, + inout fixed_io_ps_clk, + inout fixed_io_ps_porb, + inout fixed_io_ps_srstb, + + inout iic_scl, + inout iic_sda, + + input rx_clk_in_p, + input rx_clk_in_n, + input rx_frame_in_p, + input rx_frame_in_n, + input [ 5:0] rx_data_in_p, + input [ 5:0] rx_data_in_n, + output tx_clk_out_p, + output tx_clk_out_n, + output tx_frame_out_p, + output tx_frame_out_n, + output [ 5:0] tx_data_out_p, + output [ 5:0] tx_data_out_n, + + output enable, + output txnrx, + + inout gpio_resetb, + inout gpio_en_agc, + inout [ 3:0] gpio_ctl, + inout [ 7:0] gpio_status, + + output spi_csn, + output spi_clk, + output spi_mosi, + input spi_miso, + + output pl_spi_clk_o, + output pl_spi_mosi, + input pl_spi_miso + + ); + + // internal signals + + wire [24:0] gpio_i; + wire [24:0] gpio_o; + wire [24:0] gpio_t; + + // instantiations + + ad_iobuf #(.DATA_WIDTH(14)) i_iobuf ( + .dio_t (gpio_t[13:0]), + .dio_i (gpio_o[13:0]), + .dio_o (gpio_i[13:0]), + .dio_p ({ gpio_resetb, // 13:13 + gpio_en_agc, // 12:12 + gpio_ctl, // 11: 8 + gpio_status})); // 7: 0 + + assign gpio_i[16:14] = gpio_o[16:14]; + + system_wrapper i_system_wrapper ( + .ddr_addr (ddr_addr), + .ddr_ba (ddr_ba), + .ddr_cas_n (ddr_cas_n), + .ddr_ck_n (ddr_ck_n), + .ddr_ck_p (ddr_ck_p), + .ddr_cke (ddr_cke), + .ddr_cs_n (ddr_cs_n), + .ddr_dm (ddr_dm), + .ddr_dq (ddr_dq), + .ddr_dqs_n (ddr_dqs_n), + .ddr_dqs_p (ddr_dqs_p), + .ddr_odt (ddr_odt), + .ddr_ras_n (ddr_ras_n), + .ddr_reset_n (ddr_reset_n), + .ddr_we_n (ddr_we_n), + .enable (enable), + .fixed_io_ddr_vrn (fixed_io_ddr_vrn), + .fixed_io_ddr_vrp (fixed_io_ddr_vrp), + .fixed_io_mio (fixed_io_mio), + .fixed_io_ps_clk (fixed_io_ps_clk), + .fixed_io_ps_porb (fixed_io_ps_porb), + .fixed_io_ps_srstb (fixed_io_ps_srstb), + .gpio_i (gpio_i), + .gpio_o (gpio_o), + .gpio_t (gpio_t), + .iic_main_scl_io (iic_scl), + .iic_main_sda_io (iic_sda), + .rx_clk_in_p (rx_clk_in_p), + .rx_clk_in_n (rx_clk_in_n), + .rx_data_in_p (rx_data_in_p), + .rx_data_in_n (rx_data_in_n), + .rx_frame_in_p (rx_frame_in_p), + .rx_frame_in_n (rx_frame_in_n), + + .spi0_clk_i (1'b0), + .spi0_clk_o (spi_clk), + .spi0_csn_0_o (spi_csn), + .spi0_csn_1_o (), + .spi0_csn_2_o (), + .spi0_csn_i (1'b1), + .spi0_sdi_i (spi_miso), + .spi0_sdo_i (1'b0), + .spi0_sdo_o (spi_mosi), + + .spi_clk_i(1'b0), + .spi_clk_o(pl_spi_clk_o), + .spi_csn_i(1'b1), + .spi_csn_o(), + .spi_sdi_i(pl_spi_miso), + .spi_sdo_i(1'b0), + .spi_sdo_o(pl_spi_mosi), + + .tx_clk_out_p (tx_clk_out_p), + .tx_clk_out_n (tx_clk_out_n), + .tx_data_out_p (tx_data_out_p), + .tx_data_out_n (tx_data_out_n), + .tx_frame_out_p (tx_frame_out_p), + .tx_frame_out_n (tx_frame_out_n), + .txnrx (txnrx), + .up_enable (gpio_o[15]), + .up_txnrx (gpio_o[16])); + +endmodule + +// *************************************************************************** +// *************************************************************************** From 91bd71617708263aca1a306803982524066eb3bd Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 18:24:46 -0800 Subject: [PATCH 55/60] Improve the LibreSDR build documentation and setup script. The .xsa file was not copying over cleanly and the build was failing. --- firmware/ori/libre/setup_libre.sh | 30 +++++++++++++---- projects/libre/README.md | 54 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 projects/libre/README.md diff --git a/firmware/ori/libre/setup_libre.sh b/firmware/ori/libre/setup_libre.sh index f86596e..aea5ed4 100755 --- a/firmware/ori/libre/setup_libre.sh +++ b/firmware/ori/libre/setup_libre.sh @@ -2,28 +2,46 @@ # Setup script to install LibreSDR support files into submodules # Run this after cloning the repo and initializing submodules +set -e + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" FIRMWARE_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")" -echo "Installing LibreSDR files..." +echo "==========================================" +echo "LibreSDR Setup for pluto_msk" +echo "==========================================" -# Linux device tree and config +echo "Installing Linux device tree and config..." cp "$SCRIPT_DIR/linux-dts/zynq-libre.dts" "$FIRMWARE_DIR/linux/arch/arm/boot/dts/" cp "$SCRIPT_DIR/linux-dts/zynq-libre.dtsi" "$FIRMWARE_DIR/linux/arch/arm/boot/dts/" cp "$SCRIPT_DIR/linux-configs/zynq_libre_linux_defconfig" "$FIRMWARE_DIR/linux/arch/arm/configs/" -# U-Boot device tree and config +echo "Installing U-Boot device tree and config..." cp "$SCRIPT_DIR/uboot-dts/zynq-libre-sdr.dts" "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/" cp "$SCRIPT_DIR/uboot-configs/zynq_libre_defconfig" "$FIRMWARE_DIR/u-boot-xlnx/configs/" # Add zynq-libre-sdr.dtb to U-Boot DTS Makefile if not present if ! grep -q "zynq-libre-sdr.dtb" "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/Makefile"; then sed -i '/zynq-pluto-sdr.dtb/a\ zynq-libre-sdr.dtb \\' "$FIRMWARE_DIR/u-boot-xlnx/arch/arm/dts/Makefile" - echo "Added zynq-libre-sdr.dtb to U-Boot DTS Makefile" + echo " Added zynq-libre-sdr.dtb to U-Boot DTS Makefile" fi -# Buildroot config +echo "Installing Buildroot config..." cp "$SCRIPT_DIR/buildroot-configs/zynq_libre_defconfig" "$FIRMWARE_DIR/buildroot/configs/" +echo "" +echo "==========================================" echo "LibreSDR setup complete!" -echo "Build with: make TARGET=libre" +echo "==========================================" +echo "" +echo "To build LibreSDR firmware:" +echo "" +echo " Option 1 - Build HDL first (requires Vivado, ~30 min):" +echo " cd pluto_msk/projects/libre && make" +echo " cd pluto_msk/firmware" +echo " make TARGET=libre" +echo "" +echo " Option 2 - Use pre-built XSA:" +echo " cd pluto_msk/firmware" +echo " make TARGET=libre XSA_FILE=/path/to/system_top.xsa" +echo "" diff --git a/projects/libre/README.md b/projects/libre/README.md new file mode 100644 index 0000000..28a8491 --- /dev/null +++ b/projects/libre/README.md @@ -0,0 +1,54 @@ +# LibreSDR Support + +LibreSDR is a PlutoSDR-compatible board with upgraded hardware: +- **FPGA**: XC7Z020-CLG400 (53,200 LUTs vs PlutoSDR's 17,600) +- **RF**: AD9363 (same as PlutoSDR AD9361 but different frequency range) +- **Memory**: 1GB DDR3 +- **Interface**: LVDS (vs PlutoSDR's CMOS) + +## Building LibreSDR Firmware + +### Prerequisites +- Vivado 2022.2 (for HDL build) +- ARM cross-compiler (arm-none-linux-gnueabihf-) + +### Quick Start +```bash +# 1. Clone and init submodules +git clone --branch encoder-dev https://github.com/OpenResearchInstitute/pluto_msk.git +cd pluto_msk +git submodule update --init --recursive + +# 2. Run LibreSDR setup +cd firmware/ori/libre +./setup_libre.sh + +# 3. Build HDL (requires Vivado) +cd ../../../projects/libre +make + +# 4. Build firmware +cd ../../firmware +make TARGET=libre +``` + +### Using Pre-built XSA + +If you have a pre-built XSA file (from CI or another build): +```bash +cd firmware +make TARGET=libre XSA_FILE=/path/to/system_top.xsa +``` + +### Output + +Firmware files will be in `firmware/build/`: +- `libre.frm` - Main firmware image +- `boot.frm` - Boot image + +### Flashing + +Copy `libre.frm` to the LibreSDR mass storage device, or use DFU: +```bash +dfu-util -D build/libre.dfu -a firmware.dfu +``` From f57ad1570d353bbe4257e8fec416a510282406cd Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 18:36:23 -0800 Subject: [PATCH 56/60] Fix LibreSDR project paths for auto-build - Fix projects/libre/Makefile paths to use ../../hdl/projects/scripts/ - Add libre XSA build block to firmware/Makefile Now 'make TARGET=libre' auto-builds HDL like pluto does. --- firmware/Makefile | 4 ++++ projects/libre/Makefile | 21 +++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 4b82183..67bfefd 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -175,6 +175,10 @@ ifeq ($(TARGET),e200) bash -c "source $(VIVADO_SETTINGS) && make -C ../hdl/projects/pluto-ori-e200 && cp ../hdl/projects/pluto-ori-e200/e200.sdk/system_top.xsa $@" unzip -l $@ | grep -q ps7_init || cp ../hdl/projects/pluto-ori-e200/e200.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif +ifeq ($(TARGET),libre) + bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre && cp ../projects/libre/libre.sdk/system_top.xsa $@" + unzip -l $@ | grep -q ps7_init || cp ../projects/libre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ +endif #bash -c "source $(VIVADO_SETTINGS) && make -C ../hdl/projects/pluto-ori-plus" endif diff --git a/projects/libre/Makefile b/projects/libre/Makefile index 750d349..f965839 100644 --- a/projects/libre/Makefile +++ b/projects/libre/Makefile @@ -3,17 +3,18 @@ ### SPDX short identifier: BSD-1-Clause ## Auto-generated, do not modify! #################################################################################### - +export ADI_IGNORE_VERSION_CHECK = 1 +export ADI_GENERATE_UTILIZATION = 1 PROJECT_NAME := libre -M_DEPS += ../common/xilinx/adi_fir_filter_constr.xdc -M_DEPS += ../common/xilinx/adi_fir_filter_bd.tcl -M_DEPS += ../../library/util_cdc/sync_bits.v -M_DEPS += ../../library/common/util_pulse_gen.v -M_DEPS += ../../library/common/ad_iobuf.v -M_DEPS += ../../library/common/ad_bus_mux.v -M_DEPS += ../../library/axi_tdd/scripts/axi_tdd.tcl -M_DEPS += ../../library/axi_ad9361/axi_ad9361_delay.tcl +M_DEPS += ../../hdl/projects/common/xilinx/adi_fir_filter_constr.xdc +M_DEPS += ../../hdl/projects/common/xilinx/adi_fir_filter_bd.tcl +M_DEPS += ../../hdl/library/util_cdc/sync_bits.v +M_DEPS += ../../hdl/library/common/util_pulse_gen.v +M_DEPS += ../../hdl/library/common/ad_iobuf.v +M_DEPS += ../../hdl/library/common/ad_bus_mux.v +M_DEPS += ../../hdl/library/axi_tdd/scripts/axi_tdd.tcl +M_DEPS += ../../hdl/library/axi_ad9361/axi_ad9361_delay.tcl LIB_DEPS += axi_ad9361 LIB_DEPS += axi_dmac @@ -21,4 +22,4 @@ LIB_DEPS += axi_tdd LIB_DEPS += util_pack/util_cpack2 LIB_DEPS += util_pack/util_upack2 -include ../scripts/project-xilinx.mk +include ../../hdl/projects/scripts/project-xilinx.mk From 391a18a4b274fa2aa7fe56ad38f65a4eec121c83 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 18:49:09 -0800 Subject: [PATCH 57/60] Fix system_project.tcl path to adi_env.tcl --- projects/libre/system_project.tcl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/libre/system_project.tcl b/projects/libre/system_project.tcl index 43e2e58..4739b1b 100644 --- a/projects/libre/system_project.tcl +++ b/projects/libre/system_project.tcl @@ -1,4 +1,4 @@ -source ../../scripts/adi_env.tcl +source ../../hdl/scripts/adi_env.tcl source $ad_hdl_dir/projects/scripts/adi_project_xilinx.tcl source $ad_hdl_dir/projects/scripts/adi_board.tcl @@ -10,5 +10,6 @@ adi_project_files libre [list \ "$ad_hdl_dir/library/common/ad_iobuf.v"] set_property is_enabled false [get_files *system_sys_ps7_0.xdc] + adi_project_run libre source $ad_hdl_dir/library/axi_ad9361/axi_ad9361_delay.tcl From f4a092e7ea58e0c7e8384e8533dc9ecc8caa4904 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 19:12:14 -0800 Subject: [PATCH 58/60] Fix libre XSA path to TARGETlibre/libre.sdk/ --- firmware/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index 67bfefd..fa50f1c 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -176,8 +176,8 @@ ifeq ($(TARGET),e200) unzip -l $@ | grep -q ps7_init || cp ../hdl/projects/pluto-ori-e200/e200.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif ifeq ($(TARGET),libre) - bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre && cp ../projects/libre/libre.sdk/system_top.xsa $@" - unzip -l $@ | grep -q ps7_init || cp ../projects/libre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ + bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre && cp ../projects/libre/TARGETlibre/libre.sdk/system_top.xsa $@" + unzip -l $@ | grep -q ps7_init || cp ../projects/libre/TARGETlibre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif #bash -c "source $(VIVADO_SETTINGS) && make -C ../hdl/projects/pluto-ori-plus" endif From b41d0d101dee5a4c127b1fc200b2561f7a5c38a9 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 20:30:27 -0800 Subject: [PATCH 59/60] Fix HDL build directory: clear TARGET to prevent TARGETlibre/ subdirectory --- firmware/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/Makefile b/firmware/Makefile index fa50f1c..d21245d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -176,8 +176,8 @@ ifeq ($(TARGET),e200) unzip -l $@ | grep -q ps7_init || cp ../hdl/projects/pluto-ori-e200/e200.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif ifeq ($(TARGET),libre) - bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre && cp ../projects/libre/TARGETlibre/libre.sdk/system_top.xsa $@" - unzip -l $@ | grep -q ps7_init || cp ../projects/libre/TARGETlibre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ + bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre TARGET= && cp ../projects/libre/libre.sdk/system_top.xsa $@" + unzip -l $@ | grep -q ps7_init || cp ../projects/libre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif #bash -c "source $(VIVADO_SETTINGS) && make -C ../hdl/projects/pluto-ori-plus" endif From 0a1cafe9128ecc81c43f97d4879be8ae25876696 Mon Sep 17 00:00:00 2001 From: Abraxas3d Date: Mon, 1 Dec 2025 21:03:20 -0800 Subject: [PATCH 60/60] Use env -u TARGET to fully unset TARGET variable for HDL sub-build --- firmware/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/Makefile b/firmware/Makefile index d21245d..540bad4 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -176,7 +176,7 @@ ifeq ($(TARGET),e200) unzip -l $@ | grep -q ps7_init || cp ../hdl/projects/pluto-ori-e200/e200.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif ifeq ($(TARGET),libre) - bash -c "source $(VIVADO_SETTINGS) && make -C ../projects/libre TARGET= && cp ../projects/libre/libre.sdk/system_top.xsa $@" + bash -c "source $(VIVADO_SETTINGS) && env -u TARGET make -C ../projects/libre && cp ../projects/libre/libre.sdk/system_top.xsa $@" unzip -l $@ | grep -q ps7_init || cp ../projects/libre/libre.srcs/sources_1/bd/system/ip/system_sys_ps7_0/ps7_init* build/ endif #bash -c "source $(VIVADO_SETTINGS) && make -C ../hdl/projects/pluto-ori-plus"