public OpenTitan_FlashController(Machine machine, MappedMemory flash) : base(machine) { ProgramEmptyIRQ = new GPIO(); ProgramLevelIRQ = new GPIO(); ReadFullIRQ = new GPIO(); ReadLevelIRQ = new GPIO(); OperationDoneIRQ = new GPIO(); CorrectableErrorIRQ = new GPIO(); mpRegionEnabled = new IFlagRegisterField[NumberOfMpRegions]; mpRegionBase = new IValueRegisterField[NumberOfMpRegions]; mpRegionSize = new IValueRegisterField[NumberOfMpRegions]; mpRegionReadEnabled = new IFlagRegisterField[NumberOfMpRegions]; mpRegionProgEnabled = new IFlagRegisterField[NumberOfMpRegions]; mpRegionEraseEnabled = new IFlagRegisterField[NumberOfMpRegions]; bankInfoPageEnabled = new IFlagRegisterField[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; bankInfoPageReadEnabled = new IFlagRegisterField[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; bankInfoPageProgramEnabled = new IFlagRegisterField[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; bankInfoPageEraseEnabled = new IFlagRegisterField[FlashNumberOfBanks, FlashNumberOfInfoTypes][]; for (var bankNumber = 0; bankNumber < FlashNumberOfBanks; ++bankNumber) { for (var infoType = 0; infoType < FlashNumberOfInfoTypes; ++infoType) { bankInfoPageEnabled[bankNumber, infoType] = new IFlagRegisterField[FlashNumberOfPagesInInfo[infoType]]; bankInfoPageReadEnabled[bankNumber, infoType] = new IFlagRegisterField[FlashNumberOfPagesInInfo[infoType]]; bankInfoPageProgramEnabled[bankNumber, infoType] = new IFlagRegisterField[FlashNumberOfPagesInInfo[infoType]]; bankInfoPageEraseEnabled[bankNumber, infoType] = new IFlagRegisterField[FlashNumberOfPagesInInfo[infoType]]; } } Registers.InterruptState.Define(this) .WithFlag(0, out interruptStatusProgramEmpty, FieldMode.Read | FieldMode.WriteOneToClear, name: "prog_empty") .WithFlag(1, out interruptStatusProgramLevel, FieldMode.Read | FieldMode.WriteOneToClear, name: "prog_lvl") .WithFlag(2, out interruptStatusReadFull, FieldMode.Read | FieldMode.WriteOneToClear, name: "rd_full") .WithFlag(3, out interruptStatusReadLevel, FieldMode.Read | FieldMode.WriteOneToClear, name: "rd_lvl") .WithFlag(4, out interruptStatusOperationDone, FieldMode.Read | FieldMode.WriteOneToClear, name: "op_done") .WithFlag(5, out interruptStatusCorrectableError, FieldMode.Read | FieldMode.WriteOneToClear, name: "corr_err") .WithReservedBits(6, 1 + 31 - 6) .WithWriteCallback((_, __) => UpdateInterrupts()); Registers.InterruptEnable.Define(this) .WithFlag(0, out interruptEnableProgramEmpty, name: "prog_empty") .WithFlag(1, out interruptEnableProgramLevel, name: "prog_lvl") .WithFlag(2, out interruptEnableReadFull, name: "rd_full") .WithFlag(3, out interruptEnableReadLevel, name: "rd_lvl") .WithFlag(4, out interruptEnableOperationDone, name: "op_done") .WithFlag(5, out interruptEnableCorrectableError, name: "corr_err") .WithReservedBits(6, 1 + 31 - 6) .WithWriteCallback((_, __) => UpdateInterrupts()); Registers.InterruptTest.Define(this) .WithFlag(0, FieldMode.Write, writeCallback: (_, val) => { interruptStatusProgramEmpty.Value |= val; }, name: "prog_empty") .WithFlag(1, FieldMode.Write, writeCallback: (_, val) => { interruptStatusProgramLevel.Value |= val; }, name: "prog_lvl") .WithFlag(2, FieldMode.Write, writeCallback: (_, val) => { interruptStatusReadFull.Value |= val; }, name: "rd_full") .WithFlag(3, FieldMode.Write, writeCallback: (_, val) => { interruptStatusReadLevel.Value |= val; }, name: "rd_lvl") .WithFlag(4, FieldMode.Write, writeCallback: (_, val) => { interruptStatusOperationDone.Value |= val; }, name: "op_done") .WithFlag(5, FieldMode.Write, writeCallback: (_, val) => { interruptStatusCorrectableError.Value |= val; }, name: "corr_err") .WithReservedBits(6, 1 + 31 - 6) .WithWriteCallback((_, __) => UpdateInterrupts()); Registers.AlertTest.Define(this) .WithTaggedFlag("recov_err", 0) .WithTaggedFlag("fatal_err", 1) .WithReservedBits(2, 30); Registers.DisableFlashFunctionality.Define(this) .WithTag("VAL", 0, 4) .WithReservedBits(4, 28); Registers.ExecutionFetchesEnabled.Define(this) .WithTag("EN", 0, 4) .WithReservedBits(4, 28); Registers.ControllerInit.Define(this) .WithTaggedFlag("VAL", 0) .WithReservedBits(1, 31); // TODO(julianmb): support register write enable. this isnt tested in the unittests currently Registers.ControlEnable.Define(this, 0x1) .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => true, name: "EN") .WithReservedBits(1, 31); Registers.Control.Define(this) .WithFlag(0, name: "START", writeCallback: (o, n) => { if (n) { StartOperation(); } }) .WithReservedBits(1, 3) .WithEnumField <DoubleWordRegister, ControlOp>(4, 2, out operation, name: "OP") .WithTaggedFlag("PROG_SEL", 6) .WithFlag(7, out flashSelectEraseMode, name: "ERASE_SEL") .WithFlag(8, out flashSelectPartition, name: "PARTITION_SEL") .WithValueField(9, 2, out flashSelectInfo, name: "INFO_SEL") .WithReservedBits(11, 1 + 15 - 11) .WithValueField(16, 1 + 27 - 16, out controlNum, name: "NUM") .WithReservedBits(28, 1 + 31 - 28); Registers.AddressForFlashOperation.Define(this) .WithValueField(0, 32, out address, changeCallback: (_, address) => { flashAddress = null; var addresses = machine.SystemBus.GetRegistrationPoints(dataFlash) .Select(pint => pint.Range) .Where(range => range.Contains(address)) .Select(range => range.StartAddress); if (!addresses.Any()) { this.Log(LogLevel.Warning, "Underlying data flash is not registered on the system bus, so it cannot be accessed"); return; } flashAddress = (long)addresses.First(); }, name: "START"); Registers.EnableDifferentProgramTypes.Define(this) .WithTaggedFlag("NORMAL", 0) .WithTaggedFlag("REPAIR", 1) .WithReservedBits(2, 30); // Erase is performed immediately so write to SuspendErase will never happen during erasing process. // Cleared immediately. Registers.SuspendErase.Define(this) .WithFlag(0, valueProviderCallback: _ => false, name: "REQ") .WithReservedBits(1, 31); for (var i = 0; i < NumberOfMpRegions; i++) { // TODO(julianmb): support register write enable. this isnt tested in the unittests currently RegistersCollection.AddRegister((long)Registers.RegionConfigurationEnable0 + 0x4 * i, new DoubleWordRegister(this, 0x1) .WithTaggedFlag($"REGION_{i}", 0) .WithReservedBits(1, 31)); RegistersCollection.AddRegister((long)(Registers.RegionConfiguration0 + 0x4 * i), new DoubleWordRegister(this) .WithFlag(0, out mpRegionEnabled[i], name: $"EN_{i}") .WithFlag(1, out mpRegionReadEnabled[i], name: $"RD_EN_{i}") .WithFlag(2, out mpRegionProgEnabled[i], name: $"PROG_EN_{i}") .WithFlag(3, out mpRegionEraseEnabled[i], name: $"ERASE_EN_{i}") .WithTaggedFlag($"SCRAMBLE_EN_{i}", 4) .WithTaggedFlag($"ECC_EN_{i}", 5) .WithTaggedFlag($"HE_EN_{i}", 6) .WithReservedBits(7, 1) .WithValueField(8, 1 + 16 - 8, out mpRegionBase[i], name: $"BASE_{i}") .WithValueField(17, 1 + 26 - 17, out mpRegionSize[i], name: $"SIZE_{i}") .WithReservedBits(27, 1 + 31 - 27)); } Registers.DefaultRegionConfiguration.Define(this) .WithFlag(0, out defaultMpRegionReadEnabled, name: "RD_EN") .WithFlag(1, out defaultMpRegionProgEnabled, name: "PROG_EN") .WithFlag(2, out defaultMpRegionEraseEnabled, name: "ERASE_EN") .WithTaggedFlag("SCRAMBLE_EN", 3) .WithTaggedFlag("ECC_EN", 4) .WithTaggedFlag("HE_EN", 5) .WithReservedBits(6, 1 + 31 - 6); var registerOffset = Registers.Bank0Info0Enable0; for (var bankNumber = 0; bankNumber < FlashNumberOfBanks; ++bankNumber) { for (var infoType = 0; infoType < FlashNumberOfInfoTypes; ++infoType) { // For each info type, first are defined configuration enabling registers and then // configuration registers. for (var pageNumber = 0; pageNumber < FlashNumberOfPagesInInfo[infoType]; ++pageNumber) { // TODO(julianmb): support register write enable. this isnt tested in the unittests currently registerOffset.Define(this, 0x1) .WithTaggedFlag($"REGION_{pageNumber}", 0) .WithReservedBits(1, 31); registerOffset += 0x4; } for (var pageNumber = 0; pageNumber < FlashNumberOfPagesInInfo[infoType]; ++pageNumber) { registerOffset.Define(this) .WithFlag(0, out bankInfoPageEnabled[bankNumber, infoType][pageNumber], name: $"EN_{pageNumber}") .WithFlag(1, out bankInfoPageReadEnabled[bankNumber, infoType][pageNumber], name: $"RD_EN_{pageNumber}") .WithFlag(2, out bankInfoPageProgramEnabled[bankNumber, infoType][pageNumber], name: $"PROG_EN_{pageNumber}") .WithFlag(3, out bankInfoPageEraseEnabled[bankNumber, infoType][pageNumber], name: $"ERASE_EN_{pageNumber}") .WithTaggedFlag($"SCRAMBLE_EN_{pageNumber}", 4) .WithTaggedFlag($"ECC_EN_{pageNumber}", 5) .WithTaggedFlag($"HE_EN_{pageNumber}", 6) .WithReservedBits(7, 1 + 31 - 7); registerOffset += 0x4; } } } // TODO(julianmb): support register write enable. this isnt tested in the unittests currently Registers.BankConfigurationEnable.Define(this, 0x1) .WithTaggedFlag("BANK", 0) .WithReservedBits(1, 31); Registers.BankConfiguration.Define(this) .WithFlag(0, out eraseBank0, name: "ERASE_EN_0") .WithFlag(1, out eraseBank1, name: "ERASE_EN_1") .WithReservedBits(2, 1 + 31 - 2); Registers.FlashOperationStatus.Define(this) .WithFlag(0, out opStatusRegisterDoneFlag, name: "done") .WithFlag(1, out opStatusRegisterErrorFlag, name: "err") .WithReservedBits(2, 1 + 31 - 2); Registers.Status.Define(this, 0xa) .WithFlag(0, out statusReadFullFlag, FieldMode.Read, name: "rd_full") .WithFlag(1, out statusReadEmptyFlag, FieldMode.Read, name: "rd_empty") .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => false, name: "prog_full") .WithFlag(3, FieldMode.Read, valueProviderCallback: _ => true, name: "prog_empty") .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => false, name: "init_wip") .WithReservedBits(5, 1 + 31 - 5); Registers.ErrorCode.Define(this) .WithFlag(0, out outOfBoundsError, FieldMode.Read | FieldMode.WriteOneToClear, name: "oob_err") .WithFlag(1, out memoryProtectionError, FieldMode.Read | FieldMode.WriteOneToClear, name: "mp_err") .WithTaggedFlag("rd_err", 2) .WithTaggedFlag("prog_win_err", 3) .WithTaggedFlag("prog_type_err", 4) .WithTaggedFlag("flash_phy_err", 5) .WithTaggedFlag("update_err", 6) .WithReservedBits(7, 1 + 31 - 7); Registers.FaultStatus.Define(this) .WithTaggedFlag("oob_err", 0) .WithTaggedFlag("mp_err", 1) .WithTaggedFlag("rd_err", 2) .WithTaggedFlag("prog_win_err", 3) .WithTaggedFlag("prog_type_err", 4) .WithTaggedFlag("flash_phy_err", 5) .WithTaggedFlag("reg_intg_err", 6) .WithTaggedFlag("phy_intg_err", 7) .WithTaggedFlag("lcmgr_err", 8) .WithTaggedFlag("storage_err", 9) .WithReservedBits(10, 1 + 31 - 10); Registers.ErrorAddress.Define(this) .WithValueField(0, 32, out errorAddress, FieldMode.Read, name: "ERR_ADDR"); Registers.ECCSingleErrorCount.Define(this) .WithTag("ECC_SINGLE_ERR_CNT_0", 0, 8) .WithTag("ECC_SINGLE_ERR_CNT_1", 8, 8) .WithReservedBits(16, 16); Registers.ECCSingleErrorAddress0.Define(this) .WithTag("ECC_SINGLE_ERR_ADDR_0", 0, 20) .WithReservedBits(20, 12); Registers.ECCSingleErrorAddress1.Define(this) .WithTag("ECC_SINGLE_ERR_ADDR_1", 0, 20) .WithReservedBits(20, 12); Registers.PhyErrorConfigurationEnable.Define(this) .WithTaggedFlag("EN", 0) .WithReservedBits(1, 31); Registers.PhyErrorConfiguration.Define(this) .WithTaggedFlag("ECC_MULTI_ERR_DATA_EN", 0) .WithReservedBits(1, 31); Registers.PhyAlertConfiguration.Define(this) .WithTaggedFlag("alert_ack", 0) .WithTaggedFlag("alert_trig", 1) .WithReservedBits(2, 30); Registers.PhyStatus.Define(this, 0x6) .WithTaggedFlag("init_wip", 0) .WithTaggedFlag("prog_normal_avail", 1) .WithTaggedFlag("prog_repair_avail", 2) .WithReservedBits(3, 1 + 31 - 3); Registers.Scratch.Define(this) .WithTag("data", 0, 32); Registers.FifoLevel.Define(this, 0xf0f) .WithValueField(0, 5, out programFifoLevel, name: "PROG") .WithReservedBits(5, 1 + 7 - 5) .WithValueField(8, 1 + 12 - 8, out readFifoLevel, name: "RD") .WithReservedBits(13, 1 + 31 - 13); // TODO(julianmb): implement fifo reset. There isnt any unittest for this currently. Registers.FifoReset.Define(this) .WithTaggedFlag("EN", 0) .WithReservedBits(1, 31); Registers.ProgramFifo.Define(this) .WithValueField(0, 32, mode: FieldMode.Write, writeCallback: (_, data) => { var isInBounds = flashAddress.HasValue && IsOffsetInBounds(programOffset); var isAllowed = isInBounds && IsOperationAllowed(OperationType.ProgramData, programOffset); if (isInBounds && isAllowed) { var oldData = ReadFlashDoubleWord(programOffset); WriteFlashDoubleWord(programOffset, oldData & data); programOffset += 4; } else { opStatusRegisterErrorFlag.Value = true; opStatusRegisterDoneFlag.Value = true; interruptStatusOperationDone.Value = true; if (isInBounds) { memoryProtectionError.Value = true; errorAddress.Value = (uint)(programOffset + flashAddress.Value); } else { outOfBoundsError.Value = true; } return; } if (TryGetOffset(out var offset)) { if (programOffset > (offset + 4 * controlNum.Value)) { opStatusRegisterDoneFlag.Value = true; interruptStatusOperationDone.Value = true; } else { interruptStatusProgramLevel.Value = true; interruptStatusProgramEmpty.Value = true; } }
private void DefineRegisters() { Registers.Control.Define(this) .WithEnumField(0, 2, changeCallback: (Mode _, Mode value) => SetMode(value), name: "MODE") .WithReservedBits(2, 1) .WithTaggedFlag("SYNC", 3) .WithFlag(4, changeCallback: (_, value) => innerTimer.Mode = value ? WorkMode.OneShot : WorkMode.Periodic, name: "OSMEN") .WithTaggedFlag("QDM", 5) .WithTaggedFlag("DEBUGRUN", 6) .WithTaggedFlag("DMACLRACT", 7) .WithTag("RISEA", 8, 2) .WithTag("FALLA", 10, 2) .WithReservedBits(12, 1) .WithTaggedFlag("X2CNT", 13) .WithTaggedFlag("DISSYNCOUT", 14) .WithReservedBits(15, 1) .WithTag("CLKSEL", 16, 2) .WithReservedBits(18, 6) .WithValueField(24, 4, changeCallback: (_, value) => { if (value <= 10) { innerTimer.Divider = 2 << (int)value; } else { this.Log(LogLevel.Warning, "Trying to set the prescaler to an invalid value: {0}, ignoring.", 1 << (int)value); } }, name: "PRESC") .WithTaggedFlag("ATI", 28) .WithTaggedFlag("RSSCOIST", 29) .WithReservedBits(30, 2) ; Registers.Command.Define(this) .WithFlag(0, FieldMode.Set, changeCallback: (_, __) => innerTimer.Enabled = false) .WithFlag(1, FieldMode.Set, changeCallback: (_, __) => innerTimer.Enabled = true) ; Registers.Status.Define(this) .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => innerTimer.Enabled) .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => innerTimer.Direction == Direction.Descending) .WithTaggedFlag("TOPBV", 2) .WithReservedBits(3, 5) .WithTaggedFlag("CCVBV0", 8) .WithTaggedFlag("CCVBV1", 9) .WithTaggedFlag("CCVBV2", 10) .WithTaggedFlag("CCVBV2", 11) .WithReservedBits(12, 4) .WithTaggedFlag("ICV0", 16) .WithTaggedFlag("ICV1", 17) .WithTaggedFlag("ICV2", 18) .WithTaggedFlag("ICV3", 19) .WithReservedBits(20, 4) .WithTaggedFlag("CCPOL0", 24) .WithTaggedFlag("CCPOL1", 25) .WithTaggedFlag("CCPOL2", 26) .WithTaggedFlag("CCPOL3", 27) .WithReservedBits(28, 4) ; RegistersCollection.AddRegister((long)Registers.InterruptFlag, interruptManager.GetMaskedInterruptFlagRegister <DoubleWordRegister>()); RegistersCollection.AddRegister((long)Registers.InterruptFlagSet, interruptManager.GetInterruptSetRegister <DoubleWordRegister>()); RegistersCollection.AddRegister((long)Registers.InterruptFlagClear, interruptManager.GetInterruptClearRegister <DoubleWordRegister>()); RegistersCollection.AddRegister((long)Registers.InterruptEnable, interruptManager.GetInterruptEnableRegister <DoubleWordRegister>()); Registers.CounterTopValue.Define(this) .WithValueField(0, (int)width, writeCallback: (_, value) => innerTimer.Limit = value, valueProviderCallback: _ => (uint)innerTimer.Limit, name: "TOP") ; Registers.CounterValue.Define(this) .WithValueField(0, (int)width, writeCallback: (_, value) => innerTimer.Value = value, valueProviderCallback: _ => (uint)innerTimer.Value, name: "CNT") ; }
private void DefineRegisters() { DefineTask(Registers.TxEnable, TxEnable, "TASKS_TXEN"); DefineTask(Registers.RxEnable, RxEnable, "TASKS_RXEN"); DefineTask(Registers.Start, Start, "TASKS_START"); DefineTask(Registers.Disable, Disable, "TASKS_DISABLE"); DefineEvent(Registers.Ready, () => this.Log(LogLevel.Error, "Trying to trigger READY event, not supported"), Events.Ready, "EVENTS_READY"); DefineEvent(Registers.AddressSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger ADDRESS event, not supported"), Events.Address, "EVENTS_ADDRESS"); DefineEvent(Registers.PayloadSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger PAYLOAD event, not supported"), Events.Payload, "EVENTS_PAYLOAD"); DefineEvent(Registers.PacketSentOrReceived, () => this.Log(LogLevel.Error, "Trying to trigger END event, not supported"), Events.End, "EVENTS_END"); DefineEvent(Registers.BitCounterMatch, () => this.Log(LogLevel.Error, "Trying to trigger BCMATCH event, not supported"), Events.BitCountMatch, "EVENTS_BCMATCH"); DefineEvent(Registers.RSSIEnd, () => this.Log(LogLevel.Error, "Trying to trigger RSSIEnd event, not supported"), Events.RSSIEnd, "EVENTS_RSSIEND"); DefineEvent(Registers.CRCOk, () => this.Log(LogLevel.Error, "Trying to trigger CRCOk event, not supported"), Events.CRCOk, "EVENTS_CRCOK"); DefineEvent(Registers.RadioDisabled, Disable, Events.Disabled, "EVENTS_DISABLED"); DefineEvent(Registers.TxReady, TxEnable, Events.TxReady, "EVENTS_TXREADY"); DefineEvent(Registers.RxReady, RxEnable, Events.RxReady, "EVENTS_RXREADY"); // Notice: while the whole Shorts register is implemented, we don't necessarily // support all the mentioned events and tasks Registers.Shorts.Define(this) .WithFlag(0, out shorts.ReadyStart, name: "READY_START") .WithFlag(1, out shorts.EndDisable, name: "END_DISABLE") .WithFlag(2, out shorts.DisabledTxEnable, name: "DISABLED_TXEN") .WithFlag(3, out shorts.DisabledRxEnable, name: "DISABLED_RXEN") .WithFlag(4, out shorts.AddressRSSIStart, name: "ADDRESS_RSSISTART") .WithFlag(5, out shorts.EndStart, name: "END_START") .WithFlag(6, out shorts.AddressBitCountStart, name: "ADDRESS_BCSTART") .WithFlag(8, out shorts.DisabledRSSIStop, name: "DISABLED_RSSISTOP") .WithFlag(11, out shorts.RxReadyCCAStart, name: "RXREADY_CCASTART") .WithFlag(12, out shorts.CCAIdleTxEnable, name: "CCAIDLE_TXEN") .WithFlag(13, out shorts.CCABusyDisable, name: "CCABUSY_DISABLE") .WithFlag(14, out shorts.FrameStartBitCountStart, name: "FRAMESTART_BCSTART") .WithFlag(15, out shorts.ReadyEnergyDetectStart, name: "READY_EDSTART") .WithFlag(16, out shorts.EnergyDetectEndDisable, name: "EDEND_DISABLE") .WithFlag(17, out shorts.CCAIdleStop, name: "CCAIDLE_STOP") .WithFlag(18, out shorts.TxReadyStart, name: "TXREADY_START") .WithFlag(19, out shorts.RxReadyStart, name: "RXREADY_START") .WithFlag(20, out shorts.PHYEndDisable, name: "PHYEND_DISABLE") .WithFlag(21, out shorts.PHYEndStart, name: "PHYEND_START") .WithReservedBits(22, 10) ; RegistersCollection.AddRegister((long)Registers.InterruptEnable, interruptManager.GetInterruptEnableSetRegister <DoubleWordRegister>()); RegistersCollection.AddRegister((long)Registers.InterruptDisable, interruptManager.GetInterruptEnableClearRegister <DoubleWordRegister>()); Registers.CRCStatus.Define(this) .WithFlag(0, name: "CRCSTATUS", valueProviderCallback: _ => true) // we assume here that CRCs are always ok .WithReservedBits(1, 31) ; Registers.PacketPointer.Define(this) .WithValueField(0, 32, out packetPointer, name: "PACKETPTR") ; Registers.Frequency.Define(this, name: "FREQUENCY") .WithValueField(0, 7, out frequency, name: "FREQUENCY") .WithReservedBits(7, 1) .WithFlag(8, out frequencyMap, name: "MAP") .WithReservedBits(9, 23) ; Registers.TxPower.Define(this, name: "TXPOWER") .WithValueField(0, 8, name: "TXPOWER") // just RW .WithReservedBits(8, 24) ; Registers.Mode.Define(this, name: "MODE") .WithValueField(0, 4, name: "MODE") // just RW .WithReservedBits(4, 24) ; Registers.PacketConfiguration0.Define(this, name: "PCNF0") .WithValueField(0, 4, out lengthFieldLength, name: "LFLEN") .WithReservedBits(4, 4) .WithValueField(8, 1, out s0Length, name: "S0LEN") .WithReservedBits(9, 7) .WithValueField(16, 4, out s1Length, name: "S1LEN") .WithFlag(20, out s1Include, name: "S1INCL") .WithReservedBits(21, 1) .WithValueField(22, 2, out codeIndicatorLength, name: "CILEN") .WithTag("PLEN", 24, 2) .WithFlag(26, out crcIncludedInLength, name: "CRCINC") .WithReservedBits(27, 2) .WithValueField(29, 2, out termLength, name: "TERMLEN") .WithReservedBits(31, 1) ; Registers.PacketConfiguration1.Define(this, name: "PCNF1") .WithValueField(0, 8, out maxPacketLength, name: "MAXLEN") .WithValueField(8, 8, out staticLength, name: "STATLEN") .WithValueField(16, 3, out baseAddressLength, name: "BALEN") .WithReservedBits(19, 5) .WithTaggedFlag("ENDIAN", 24) .WithTaggedFlag("WHITEEN", 25) .WithReservedBits(26, 6) ; Registers.BaseAddress0.Define(this) .WithValueField(0, 32, out baseAddress0, name: "BASE0") ; Registers.BaseAddress1.Define(this) .WithValueField(0, 32, out baseAddress1, name: "BASE1") ; Registers.Prefix0.Define(this, name: "PREFIX0") .WithValueFields(0, 8, 4, writeCallback: (i, _, value) => addressPrefixes[i] = (byte)value, name: "AP") ; Registers.Prefix1.Define(this, name: "PREFIX1") .WithValueFields(0, 8, 4, writeCallback: (i, _, value) => addressPrefixes[4 + i] = (byte)value, name: "AP") ; Registers.TxAddress.Define(this, name: "TXADDRESS") .WithValueField(0, 3, out txAddress, name: "TXADDRESS") .WithReservedBits(3, 29) ; Registers.RxAddresses.Define(this, name: "RXADDRESSES") .WithFlags(0, 8, out rxAddressEnabled, name: "ADDR") ; Registers.CRCConfiguration.Define(this, name: "CRCCNF") .WithValueField(0, 2, out crcLength, name: "LEN") .WithReservedBits(2, 6) .WithEnumField(8, 2, out crcSkipAddress, name: "SKIPADDR") .WithReservedBits(10, 21) ; Registers.CRCPolynomial.Define(this, name: "CRCPOLY") .WithValueField(0, 24, out crcPolynomial, name: "CRCPOLY") .WithReservedBits(24, 8) ; Registers.CRCInitialValue.Define(this, name: "CRCINIT") .WithValueField(0, 24, out crcInitialValue, name: "CRCINIT") .WithReservedBits(24, 8) ; Registers.RSSISample.Define(this, name: "RSSISAMPLE") .WithValueField(0, 32, valueProviderCallback: _ => DefaultRSSISample, name: "RSSISAMPLE"); ; Registers.State.Define(this, name: "STATE") .WithEnumField <DoubleWordRegister, State>(0, 4, FieldMode.Read, valueProviderCallback: _ => radioState, name: "STATE") .WithReservedBits(4, 28) ; Registers.BitCounterCompare.Define(this, name: "BCC") .WithValueField(0, 32, out bitCountCompare) ; Registers.ModeConfiguration0.Define(this, 0x200) .WithTaggedFlag("RU", 0) .WithReservedBits(1, 7) .WithTag("DTX", 8, 2) .WithReservedBits(10, 22) ; Registers.CCAControl.Define(this, 0x052D0000, name: "CCACTRL") .WithEnumField(0, 3, out ccaMode, name: "CCAMODE") .WithReservedBits(3, 5) .WithTag("CCAEDTHRES", 8, 8) .WithTag("CCACORRTHRES", 16, 8) .WithTag("CCACORRCNT", 24, 8) ; Registers.PowerControl.Define(this, 1, name: "POWER") //TODO: radio should be disabled with powerOn == false .WithFlag(0, out powerOn, changeCallback: (_, value) => { if (!value) { Reset(); } }, name: "POWER") .WithReservedBits(1, 31) ; }