public SunxiHighSpeedTimer(Machine machine, long frequency) { irqEnableRegister = new DoubleWordRegister(this); irqStatusRegister = new DoubleWordRegister(this); timers = new SunxiHighSpeedTimerUnit[4]; interruptFlags = new IFlagRegisterField[4]; enableFlags = new IFlagRegisterField[4]; for(var i = 0; i < 4; ++i) { var j = i; timers[i] = new SunxiHighSpeedTimerUnit(machine, frequency); timers[i].LimitReached += () => OnTimerLimitReached(j); interruptFlags[i] = irqStatusRegister.DefineFlagField(i, FieldMode.WriteOneToClear, name: "Tx_IRQ_PEND"); enableFlags[i] = irqEnableRegister.DefineFlagField(i, name: "Tx_INT_EN"); } var innerConnections = new Dictionary<int, IGPIO>(); for(var i = 0; i < 4; ++i) { innerConnections[i] = new GPIO(); } Connections = new ReadOnlyDictionary<int, IGPIO>(innerConnections); }
private void TryHandleInterrupt(IFlagRegisterField field) { if (bytesSent == totalBytes) { field.Value = true; RefreshInterrupt(); } }
private bool AssertFlagEnabled(IFlagRegisterField flag, string errorMessage) { if (!flag.Value) { this.Log(LogLevel.Error, errorMessage); return(false); } return(true); }
public CortexAGenericTimerUnit(Machine machine, GPIO irq, ulong compareValue, bool enabled = false) : base(machine.ClockSource, CortexAGenericTimer.Frequency, compare: compareValue, enabled: enabled) { controlRegister = new DoubleWordRegister(this); controlRegister.DefineFlagField(0, writeCallback: OnEnabled); maskOutput = controlRegister.DefineFlagField(1); outputFlag = controlRegister.DefineFlagField(2, FieldMode.Read); this.irq = irq; compareValueDiff = compareValue; }
public NRF52840_Radio(Machine machine) : base(machine) { IRQ = new GPIO(); interruptManager = new InterruptManager <Events>(this, IRQ, "RadioIrq"); shorts = new Shorts(); events = new IFlagRegisterField[(int)Events.PHYEnd + 1]; rxBuffer = new ConcurrentQueue <byte[]>(); DefineRegisters(); Reset(); }
public NRF52840_Watchdog(Machine machine) : base(machine.ClockSource, InitialFrequency, eventEnabled: true) { IRQ = new GPIO(); this.machine = machine; requestRegisterEnabled = new bool[NumberOfRegisters]; requestRegisterStatus = new IFlagRegisterField[NumberOfRegisters]; LimitReached += TriggerReset; DefineRegisters(); }
public NRF52840_GPIO(Machine machine) : base(machine, NumberOfPins) { Pins = new Pin[NumberOfPins]; for (var i = 0; i < Pins.Length; i++) { Pins[i] = new Pin(this, i); } RegistersCollection = new DoubleWordRegisterCollection(this); physicalPinState = new IFlagRegisterField[NumberOfPins]; DefineRegisters(); }
public SunxiTimer(Machine machine) { timers = new SunxiTimerUnit[NumberOfTimerUnits]; for (int i = 0; i < NumberOfTimerUnits; ++i) { int j = i; timers[i] = new SunxiTimerUnit(machine, this); timers[i].LimitReached += () => OnTimerLimitReached(j); } timerInterruptEnabled = new IFlagRegisterField[NumberOfTimerUnits]; timerInterruptStatus = new IFlagRegisterField[NumberOfTimerUnits]; Timer0Irq = new GPIO(); Timer1Irq = new GPIO(); SetupRegisters(); }
public IMXRT_ADC(Machine machine) : base(machine) { samplesFifos = new SensorSamplesFifo <ScalarSample> [NumberOfChannels]; for (var i = 0; i < samplesFifos.Length; i++) { samplesFifos[i] = new SensorSamplesFifo <ScalarSample>(); } conversionCompleteInterruptEnable = new IFlagRegisterField[NumberOfHardwareTriggers]; inputChannel = new IValueRegisterField[NumberOfHardwareTriggers]; cdata = new IValueRegisterField[NumberOfHardwareTriggers]; IRQ = new GPIO(); DefineRegisters(); }
public SunxiTimer(Machine machine) { timers = new SunxiTimerUnit[NumberOfTimerUnits]; for(int i = 0; i < NumberOfTimerUnits; ++i) { int j = i; timers[i] = new SunxiTimerUnit(machine, this); timers[i].LimitReached += () => OnTimerLimitReached(j); timers[i].EventEnabled = true; } timerInterruptEnabled = new IFlagRegisterField[NumberOfTimerUnits]; timerInterruptStatus = new IFlagRegisterField[NumberOfTimerUnits]; Timer0Irq = new GPIO(); Timer1Irq = new GPIO(); SetupRegisters(); }
/// <summary> /// Fluent API for creation of sets of flag fields. For parameters see the other overload of <see cref="PeripheralRegisterExtensions.WithFlags"/>. /// This overload allows you to retrieve the created array of fields via <c>flagFields</c> parameter. /// </summary> /// <returns>This register with defined flags.</returns> public static T WithFlags <T>(this T register, int position, int count, out IFlagRegisterField[] flagFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action <int, bool, bool> readCallback = null, Action <int, bool, bool> writeCallback = null, Action <int, bool, bool> changeCallback = null, Func <int, bool, bool> valueProviderCallback = null, string name = null) where T : PeripheralRegister { flagFields = new IFlagRegisterField[count]; for (var i = 0; i < count; i++) { var j = i; flagFields[j] = register.DefineFlagField(position + j, mode, readCallback == null ? null : (Action <bool, bool>)((x, y) => readCallback(j, x, y)), writeCallback == null ? null : (Action <bool, bool>)((x, y) => writeCallback(j, x, y)), changeCallback == null ? null : (Action <bool, bool>)((x, y) => changeCallback(j, x, y)), valueProviderCallback == null ? null : (Func <bool, bool>)((x) => valueProviderCallback(j, x)), name == null ? null : $"{name}_{j}"); } return(register); }
public PSE_USB(Machine machine, ControllerMode mode = ControllerMode.Host) : base(machine) { this.mode = mode; addressToDeviceCache = new TwoWayDictionary <byte, IUSBDevice>(); fifoFromDeviceToHost = new Queue <byte> [NumberOfEndpoints]; fifoFromHostToDevice = new Queue <byte> [NumberOfEndpoints]; receiveDeviceAddress = new IValueRegisterField[NumberOfEndpoints]; transmitDeviceAddress = new IValueRegisterField[NumberOfEndpoints]; requestInTransaction = new IFlagRegisterField[NumberOfEndpoints]; transmitTargetEndpointNumber = new IValueRegisterField[NumberOfEndpoints]; receiveTargetEndpointNumber = new IValueRegisterField[NumberOfEndpoints]; for (var i = 0; i < NumberOfEndpoints; i++) { fifoFromDeviceToHost[i] = new Queue <byte>(); fifoFromHostToDevice[i] = new Queue <byte>(); } MainIRQ = new GPIO(); DmaIRQ = new GPIO(); byteRegisters = new ByteRegisterCollection(this); wordRegisters = new WordRegisterCollection(this); doubleWordRegisters = new DoubleWordRegisterCollection(this); var gate = new GPIOGate(MainIRQ); usbInterruptsManager = new InterruptManager <UsbInterrupt>(this, gate.GetGPIO(), "main"); txInterruptsManager = new InterruptManager <TxInterrupt>(this, gate.GetGPIO(), "main"); rxInterruptsManager = new InterruptManager <RxInterrupt>(this, gate.GetGPIO(), "main"); DefineCommonRegisters(); DefineIndexedRegisters(); DefineFifoRegisters(); DefineControlAndStatusRegisters(); DefineNonIndexedEndpointControlAndStatusRegisters(); DefineMultipointControlAndStatusRegisters(); ResetInterrupts(); }
public MPFS_Timer(Machine machine, long frequency = 100000000) { Timer1IRQ = new GPIO(); Timer2IRQ = new GPIO(); timerInterruptEnable = new IFlagRegisterField[NumberOfInternalTimers]; rawInterruptStatus = new IFlagRegisterField[NumberOfInternalTimers]; backgroundLoadValue = new ulong[NumberOfInternalTimers]; backgroundLoadValueIsValid = new bool[NumberOfInternalTimers]; timer = new LimitTimer[NumberOfInternalTimers] { new LimitTimer(machine.ClockSource, frequency, this, "0", uint.MaxValue, autoUpdate: true, eventEnabled: true), new LimitTimer(machine.ClockSource, frequency, this, "1", uint.MaxValue, autoUpdate: true, eventEnabled: true), new LimitTimer(machine.ClockSource, frequency, this, "2", autoUpdate: true, eventEnabled: true) }; for (var i = 0; i < NumberOfInternalTimers; i++) { var j = i; timer[i].LimitReached += delegate { rawInterruptStatus[j].Value = true; lock (timer[j]) { if (backgroundLoadValueIsValid[j]) { backgroundLoadValueIsValid[j] = false; timer[j].Limit = backgroundLoadValue[j]; // TODO: doesn't it reduce the tick count by one (I mean shouldn't we put the new value AFTER this tick is finished?) } } UpdateInterrupt(); }; } var registersMap = new Dictionary <long, DoubleWordRegister> { // the rest of registers is generated using `GenerateRegistersForTimer` method calls located below { (long)Registers.Timer64ValueHigh, new DoubleWordRegister(this) .WithValueField(0, 32, FieldMode.Read, name: "TIM64VALUEU", valueProviderCallback: _ => (uint)(timer[Timer.Timer64].Value >> 32)) },
public NRF52840_Timer(Machine machine) : base(machine) { IRQ = new GPIO(); eventCompareEnabled = new IFlagRegisterField[NumberOfEvents]; eventCompareInterruptEnabled = new IFlagRegisterField[NumberOfEvents]; innerTimers = new ComparingTimer[NumberOfEvents]; for (var i = 0; i < innerTimers.Length; i++) { var j = i; innerTimers[j] = new ComparingTimer(machine.ClockSource, InitialFrequency, this, $"compare{j}", eventEnabled: true); innerTimers[j].CompareReached += () => { eventCompareEnabled[j].Value = true; UpdateInterrupts(); }; } DefineRegisters(); }
public Emios(Machine machine) : base(machine, 2 * NumberOfChannels) { controlRegisters = new DoubleWordRegister[NumberOfChannels]; statusRegisters = new DoubleWordRegister[NumberOfChannels]; channelModes = new IEnumRegisterField<ChannelMode>[NumberOfChannels]; channelFlags = new IFlagRegisterField[NumberOfChannels]; inputState = new IFlagRegisterField[NumberOfChannels]; interruptEnabled = new IFlagRegisterField[NumberOfChannels]; for(var i = 0; i < controlRegisters.Length; i++) { var j = i; controlRegisters[i] = new DoubleWordRegister(this); controlRegisters[i].DefineFlagField(7, writeCallback: (oldValue, newValue) => { if(channelModes[j].Value == ChannelMode.Output) { Connections[j].Set(newValue); } }, name: "Edge polarity"); channelModes[i] = controlRegisters[i].DefineEnumField<ChannelMode>(0, 7); interruptEnabled[i] = controlRegisters[i].DefineFlagField(17); statusRegisters[i] = new DoubleWordRegister(this); channelFlags[i] = statusRegisters[i].DefineFlagField(0, FieldMode.WriteOneToClear, writeCallback: (oldValue, newValue) => { if(newValue) { Connections[NumberOfChannels + j].Unset(); } }); inputState[i] = statusRegisters[i].DefineFlagField(2, FieldMode.Read); } }
public Emios(Machine machine) : base(machine, 2 * NumberOfChannels) { controlRegisters = new DoubleWordRegister[NumberOfChannels]; statusRegisters = new DoubleWordRegister[NumberOfChannels]; channelModes = new IEnumRegisterField <ChannelMode> [NumberOfChannels]; channelFlags = new IFlagRegisterField[NumberOfChannels]; inputState = new IFlagRegisterField[NumberOfChannels]; interruptEnabled = new IFlagRegisterField[NumberOfChannels]; for (var i = 0; i < controlRegisters.Length; i++) { var j = i; controlRegisters[i] = new DoubleWordRegister(this); controlRegisters[i].DefineFlagField(7, writeCallback: (oldValue, newValue) => { if (channelModes[j].Value == ChannelMode.Output) { Connections[j].Set(newValue); } }, name: "Edge polarity"); channelModes[i] = controlRegisters[i].DefineEnumField <ChannelMode>(0, 7); interruptEnabled[i] = controlRegisters[i].DefineFlagField(17); statusRegisters[i] = new DoubleWordRegister(this); channelFlags[i] = statusRegisters[i].DefineFlagField(0, FieldMode.WriteOneToClear, writeCallback: (oldValue, newValue) => { if (newValue) { Connections[NumberOfChannels + j].Unset(); } }); inputState[i] = statusRegisters[i].DefineFlagField(2, FieldMode.Read); } }
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; } }
public HiFive_PWM(Machine machine, uint frequency = 16000000) { connections = new Dictionary <int, IGPIO> { { 0, new GPIO() }, { 1, new GPIO() }, { 2, new GPIO() }, { 3, new GPIO() } }; this.machine = machine; IRQ = new GPIO(); interruptPending = new IFlagRegisterField[NumberOfComparers]; compare = new IValueRegisterField[NumberOfComparers]; rawTimer = new LimitTimer(machine.ClockSource, frequency, this, nameof(rawTimer), TimerLimit + 1, workMode: WorkMode.Periodic, direction: Direction.Ascending, eventEnabled: true); rawTimer.LimitReached += HandleLimitReached; timers = new ComparingTimer[NumberOfComparers]; for (var i = 0; i < timers.Length; i++) { var j = i; timers[i] = new ComparingTimer(machine.ClockSource, frequency, this, (i + 1).ToString(), CompareMask + 1, workMode: WorkMode.Periodic, compare: CompareMask, direction: Direction.Ascending, eventEnabled: true); timers[i].CompareReached += () => { // handle 'pwmzerocmp' flag (defined only for timer0) if (i == 0) { // documentation says that this should be done one cycle after the 'pwms' counter reaches the compare value! if (timers[i].Value == compare[i].Value && resetAfterMatch.Value) { SetValue(0); HandleLimitReached(); } } UpdateCompare(j); }; } var registersMap = new Dictionary <long, DoubleWordRegister> { { (long)Registers.Configuration, new DoubleWordRegister(this) .WithValueField(0, 4, out scale, name: "pwmscale", writeCallback: (_, value) => { Array.ForEach(timers, t => t.Divider = (uint)(1 << (int)value)); Array.ForEach(timers, t => t.Value = (rawTimer.Value >> (int)value) & CompareMask); }) .WithFlag(8, out sticky, name: "pwmsticky") .WithFlag(9, out resetAfterMatch, name: "zerocmp") .WithFlag(12, out enableAlways, name: "pwmenalways", writeCallback: (_, __) => RecalculateEnable()) .WithFlag(13, out enableOneShot, name: "pwmenoneshot", writeCallback: (_, __) => RecalculateEnable()) .WithFlag(28, out interruptPending[0], name: "pwmcmp0ip") .WithFlag(29, out interruptPending[1], name: "pwmcmp1ip") .WithFlag(30, out interruptPending[2], name: "pwmcmp2ip") .WithFlag(31, out interruptPending[3], name: "pwmcmp3ip") // this is a global update .WithWriteCallback((_, __) => UpdateInterrupt()) }, { (long)Registers.Count, new DoubleWordRegister(this) .WithValueField(0, 31, name: "pwmcount", valueProviderCallback: _ => (uint)rawTimer.Value, writeCallback: (_, value) => { SetValue(value); UpdateInterrupt(); }) .WithReservedBits(31, 1) }, { (long)Registers.ScaledCount, new DoubleWordRegister(this) .WithValueField(0, 16, FieldMode.Read, name: "pwms", valueProviderCallback: _ => (uint)timers[0].Value) .WithReservedBits(16, 16) }, { (long)Registers.Compare0, new DoubleWordRegister(this, 0xFFFF) .WithValueField(0, 16, out compare[0], name: "pwmcmp0", writeCallback: (_, value) => UpdateCompare(0)) .WithReservedBits(16, 16) }, { (long)Registers.Compare1, new DoubleWordRegister(this, 0xFFFF) .WithValueField(0, 16, out compare[1], name: "pwmcmp1", writeCallback: (_, value) => UpdateCompare(1)) .WithReservedBits(16, 16) }, { (long)Registers.Compare2, new DoubleWordRegister(this, 0xFFFF) .WithValueField(0, 16, out compare[2], name: "pwmcmp2", writeCallback: (_, value) => UpdateCompare(2)) .WithReservedBits(16, 16) }, { (long)Registers.Compare3, new DoubleWordRegister(this, 0xFFFF) .WithValueField(0, 16, out compare[3], name: "pwmcmp3", writeCallback: (_, value) => UpdateCompare(3)) .WithReservedBits(16, 16) } }; registers = new DoubleWordRegisterCollection(this, registersMap); }
/// <summary> /// Fluent API for flag field creation. For parameters see <see cref="PeripheralRegister.DefineValueField"/>. /// This overload allows you to retrieve the created field via <c>flagFiled</c> parameter. /// </summary> /// <returns>This register with a defined flag.</returns> public static T WithFlag <T>(this T register, int position, out IFlagRegisterField flagField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action <bool, bool> readCallback = null, Action <bool, bool> writeCallback = null, Action <bool, bool> changeCallback = null, Func <bool, bool> valueProviderCallback = null, string name = null) where T : PeripheralRegister { flagField = register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, name); return(register); }
public PULP_Timer(Machine machine, long frequency) : base(machine) { interruptEnable = new IFlagRegisterField[NumberOfTimers]; oneShot = new IFlagRegisterField[NumberOfTimers]; cycleMode = new IFlagRegisterField[NumberOfTimers]; var irqs = new Dictionary <int, IGPIO>(); for (var i = 0; i < NumberOfTimers; i++) { irqs[i] = new GPIO(); } Connections = new ReadOnlyDictionary <int, IGPIO>(irqs); timers = new ComparingTimer[NumberOfTimers]; for (var i = 0; i < NumberOfTimers; i++) { var j = i; timers[j] = new ComparingTimer(machine.ClockSource, frequency, this, $"Timer {j}", limit: uint.MaxValue, direction: Time.Direction.Ascending, workMode: Time.WorkMode.Periodic, enabled: false, eventEnabled: true, compare: uint.MaxValue); timers[j].CompareReached += delegate { this.Log(LogLevel.Noisy, "Timer {0} IRQ compare event", i); if (interruptEnable[j].Value) { Connections[j].Blink(); //verified with RTL } if (oneShot[j].Value) { timers[j].Enabled = false; } if (cycleMode[j].Value) { timers[j].Value = 0; } }; var shift = j * 4; var configReg = ((Registers)(Registers.ConfigLow + shift)).Define(this) .WithFlag(0, writeCallback: (_, val) => { if (val) { timers[j].Enabled = val; } }, valueProviderCallback: _ => timers[j].Enabled, name: $"Timer {j} enable (EN)") .WithFlag(1, writeCallback: (_, val) => { if (val) { timers[j].Value = 0; // this also should affect the prescaller } }, valueProviderCallback: _ => false, name: "RST") .WithFlag(2, out interruptEnable[j], name: "IRQEN") .WithTag("IEM", 3, 1) .WithFlag(4, out cycleMode[j], name: "MODE") .WithFlag(5, out oneShot[j], name: "ONE_S") .WithTag("PEN", 6, 1) .WithTag("CCFG", 7, 1) .WithTag("PVAL", 8, 8) .WithReservedBits(16, 15) ; if (j == 0) { // 64-bit timer mode not yet implemented configReg.Tag("CASC", 31, 1); } else { configReg.Reserved(31, 1); } ((Registers)(Registers.CounterValueLow + shift)).Define(this) .WithValueField(0, 32, writeCallback: (_, val) => timers[j].Value = val, valueProviderCallback: _ => { if (machine.SystemBus.TryGetCurrentCPU(out var cpu)) { // being here means we are on the CPU thread cpu.SyncTime(); } return((uint)timers[j].Value); },
public STM32F4_RTC(Machine machine) { mainTimer = new TimerConfig(this); alarmA = new AlarmConfig(this, mainTimer); alarmB = new AlarmConfig(this, mainTimer); AlarmIRQ = new GPIO(); ticker = new LimitTimer(machine.ClockSource, 1, this, nameof(ticker), 1, direction: Direction.Ascending, eventEnabled: true); ticker.LimitReached += UpdateState; ResetInnerTimers(); IFlagRegisterField syncFlag = null; var registerMap = new Dictionary <long, DoubleWordRegister> { { (long)Registers.TimeRegister, new DoubleWordRegister(this) .WithValueField(0, 4, name: "SU", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Second, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Second, Rank.Units)) .WithValueField(4, 3, name: "ST", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Second, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Second, Rank.Tens)) .WithReservedBits(7, 1) .WithValueField(8, 4, name: "MU", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Minute, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Minute, Rank.Units)) .WithValueField(12, 3, name: "MT", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Minute, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Minute, Rank.Tens)) .WithReservedBits(15, 1) .WithValueField(16, 4, name: "HU", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Hour, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Hour, Rank.Units)) .WithValueField(20, 2, name: "HT", writeCallback: (_, value) => UpdateMainTimer(Registers.TimeRegister, DateTimeSelect.Hour, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Hour, Rank.Tens)) .WithFlag(22, name: "PM", writeCallback: (_, value) => { if (CheckIfInInitMode(Registers.TimeRegister) && CheckIfUnlocked(Registers.TimeRegister)) { mainTimer.PM = value; } }, valueProviderCallback: _ => mainTimer.PM) .WithReservedBits(23, 9) }, { (long)Registers.DateRegister, new DoubleWordRegister(this, 0x2101) .WithValueField(0, 4, name: "DU", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Day, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Day, Rank.Units)) .WithValueField(4, 2, name: "DT", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Day, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Day, Rank.Tens)) .WithReservedBits(6, 2) .WithValueField(8, 4, name: "MU", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Month, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Month, Rank.Units)) .WithValueField(12, 1, name: "MT", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Month, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Month, Rank.Tens)) .WithValueField(13, 3, name: "WDU", writeCallback: (_, value) => { if (CheckIfInInitMode(Registers.DateRegister) && CheckIfUnlocked(Registers.DateRegister)) { if (value == 0) { this.Log(LogLevel.Warning, "Writting value 0 to WeekDay register is forbidden"); return; } mainTimer.WeekDay = (DayOfTheWeek)value; } }, valueProviderCallback: _ => (uint)mainTimer.WeekDay) .WithValueField(16, 4, name: "YU", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Year, Rank.Units, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Year, Rank.Units)) .WithValueField(20, 4, name: "YT", writeCallback: (_, value) => UpdateMainTimer(Registers.DateRegister, DateTimeSelect.Year, Rank.Tens, value), valueProviderCallback: _ => mainTimer.Read(DateTimeSelect.Year, Rank.Tens)) .WithReservedBits(24, 8) }, { (long)Registers.ControlRegister, new DoubleWordRegister(this) .WithTag("WUCKSEL", 0, 3) .WithTag("TSEDGE", 3, 1) .WithTag("REFCKON", 4, 1) .WithTag("BYPSHAD", 5, 1) .WithFlag(6, name: "FMT", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ControlRegister)) { AMPMFormat = value; mainTimer.ConfigureAMPM(); alarmA.ConfigureAMPM(); alarmB.ConfigureAMPM(); } }, valueProviderCallback: _ => AMPMFormat) .WithTag("DCE", 7, 1) .WithFlag(8, name: "ALRAE", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ControlRegister)) { alarmA.Enable = value; } }, valueProviderCallback: _ => alarmA.Enable) .WithFlag(9, name: "ALRBE", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ControlRegister)) { alarmB.Enable = value; } }, valueProviderCallback: _ => alarmB.Enable) .WithTag("WUTE", 10, 1) // Wakeup Timer not supported .WithTag("TSE", 11, 1) // Timestamp not supported .WithFlag(12, name: "ALRAIE", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ControlRegister)) { alarmA.InterruptEnable = value; } }, valueProviderCallback: _ => alarmA.InterruptEnable) .WithFlag(13, name: "ALRBIE", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ControlRegister) && value) { alarmB.InterruptEnable = value; } }, valueProviderCallback: _ => alarmB.InterruptEnable) .WithTag("WUTIE", 14, 1) // Wakeup Timer not supported .WithTag("TSIE", 15, 1) // Timestamp not supported .WithTag("ADD1H", 16, 1) .WithTag("SUB1H", 17, 1) .WithTag("BKP", 18, 1) .WithTag("COSEL", 19, 1) .WithTag("POL", 20, 1) .WithTag("OSEL", 21, 2) .WithTag("COE", 23, 1) .WithReservedBits(24, 8) }, { (long)Registers.ISR, new DoubleWordRegister(this, 0x7) .WithFlag(0, FieldMode.Read, valueProviderCallback: _ => !alarmA.Enable, name: "ALRAWF") .WithFlag(1, FieldMode.Read, valueProviderCallback: _ => !alarmB.Enable, name: "ALRBWF") .WithTag("WUTWF", 2, 1) .WithTag("SHPF", 3, 1) .WithFlag(4, FieldMode.Read, valueProviderCallback: _ => mainTimer.TimeState.Year != 2000, name: "INITS") .WithFlag(5, out syncFlag, FieldMode.Read | FieldMode.WriteZeroToClear, name: "RSF", readCallback: (_, curr) => { // this strange logic is required by the Zephyr driver; // it wants to read 0 before reading 1, otherwise it times-out if (!curr) { syncFlag.Value = true; } }) .WithFlag(6, FieldMode.Read, valueProviderCallback: _ => initMode, name: "INITF") .WithFlag(7, FieldMode.Write, name: "INIT", writeCallback: (_, value) => { if (CheckIfUnlocked(Registers.ISR)) { ticker.Enabled = !value; initMode = value; } }) .WithFlag(8, FieldMode.WriteZeroToClear | FieldMode.Read, name: "ALRAF", changeCallback: (_, __) => { alarmA.Flag = false; }, valueProviderCallback: _ => alarmA.Flag) .WithFlag(9, FieldMode.WriteZeroToClear | FieldMode.Read, name: "ALRBF", changeCallback: (_, __) => { alarmB.Flag = false; }, valueProviderCallback: _ => alarmB.Flag) .WithTag("WUTF", 10, 1) .WithTag("TSF", 11, 1) .WithTag("TSOVF", 12, 1) .WithTag("TAMP1F", 13, 1) .WithTag("TAMP2F", 14, 1) .WithReservedBits(15, 1) .WithTag("RECALPF", 16, 1) .WithReservedBits(17, 15) }, { (long)Registers.PrescalerRegister, new DoubleWordRegister(this) .WithTag("PREDIV_S", 0, 15) .WithReservedBits(15, 1) .WithTag("PREDIV_A", 16, 7) .WithReservedBits(23, 9) }, { (long)Registers.WakeupTimerRegister, new DoubleWordRegister(this, 0x7F00FF) .WithTag("WUT", 0, 16) .WithReservedBits(16, 16) }, { (long)Registers.CalibrationRegister, new DoubleWordRegister(this) .WithTag("DC", 0, 5) .WithReservedBits(5, 2) .WithTag("DCS", 7, 1) .WithReservedBits(8, 24) }, { (long)Registers.AlarmARegister, new DoubleWordRegister(this) .WithValueField(0, 4, name: "SU", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Second, Rank.Units, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Second, Rank.Units)) .WithValueField(4, 3, name: "ST", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Second, Rank.Tens, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Second, Rank.Tens)) .WithFlag(7, name: "MSK1", writeCallback: (_, value) => { if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister)) { alarmA.SecondsMask = value; } }, valueProviderCallback: _ => alarmA.SecondsMask) .WithValueField(8, 4, name: "MU", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Minute, Rank.Units, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Minute, Rank.Units)) .WithValueField(12, 3, name: "MT", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Minute, Rank.Tens, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Minute, Rank.Tens)) .WithFlag(15, name: "MSK2", writeCallback: (_, value) => { if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister)) { alarmA.MinutesMask = value; } }, valueProviderCallback: _ => alarmA.MinutesMask) .WithValueField(16, 4, name: "HU", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Hour, Rank.Units, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Hour, Rank.Units)) .WithValueField(20, 2, name: "HT", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Hour, Rank.Tens, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Hour, Rank.Tens)) .WithFlag(22, name: "PM", writeCallback: (_, value) => { if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister)) { alarmA.PM = value; } }, valueProviderCallback: _ => alarmA.PM) .WithFlag(23, name: "MSK3", writeCallback: (_, value) => { if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister)) { alarmA.HoursMask = value; } }, valueProviderCallback: _ => alarmA.HoursMask) .WithValueField(24, 4, name: "DU", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Day, Rank.Units, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Day, Rank.Units)) .WithValueField(28, 2, name: "DT", writeCallback: (_, value) => UpdateTimerA(DateTimeSelect.Day, Rank.Tens, value), valueProviderCallback: _ => alarmA.Read(DateTimeSelect.Day, Rank.Tens)) .WithTag("WDSEL", 30, 1) // Weekday instead of date units usupported .WithFlag(31, name: "MSK4", writeCallback: (_, value) => { if (CheckIfDisabled(alarmA) && CheckIfUnlocked(Registers.AlarmARegister)) { alarmA.DaysMask = value; } }, valueProviderCallback: _ => alarmA.DaysMask) }, { (long)Registers.AlarmBRegister, new DoubleWordRegister(this) .WithValueField(0, 4, name: "SU", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Second, Rank.Units, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Second, Rank.Units)) .WithValueField(4, 3, name: "ST", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Second, Rank.Tens, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Second, Rank.Tens)) .WithFlag(7, name: "MSK1", writeCallback: (_, value) => { if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister)) { alarmB.SecondsMask = value; } }, valueProviderCallback: _ => alarmB.SecondsMask) .WithValueField(8, 4, name: "MU", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Minute, Rank.Units, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Minute, Rank.Units)) .WithValueField(12, 3, name: "MT", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Minute, Rank.Tens, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Minute, Rank.Tens)) .WithFlag(15, name: "MSK2", writeCallback: (_, value) => { if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister)) { alarmB.MinutesMask = value; } }, valueProviderCallback: _ => alarmB.MinutesMask) .WithValueField(16, 4, name: "HU", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Hour, Rank.Units, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Hour, Rank.Units)) .WithValueField(20, 2, name: "HT", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Hour, Rank.Tens, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Hour, Rank.Tens)) .WithFlag(22, name: "PM", writeCallback: (_, value) => { if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister)) { alarmB.PM = value; } }, valueProviderCallback: _ => alarmB.PM) .WithFlag(23, name: "MSK3", writeCallback: (_, value) => { if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister)) { alarmB.HoursMask = value; } }, valueProviderCallback: _ => alarmB.HoursMask) .WithValueField(24, 4, name: "DU", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Day, Rank.Units, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Day, Rank.Units)) .WithValueField(28, 2, name: "DT", writeCallback: (_, value) => UpdateTimerB(DateTimeSelect.Day, Rank.Tens, value), valueProviderCallback: _ => alarmB.Read(DateTimeSelect.Day, Rank.Tens)) .WithTag("WDSEL", 30, 1) // Weekday instead of date units usupported .WithFlag(31, name: "MSK4", writeCallback: (_, value) => { if (CheckIfDisabled(alarmB) && CheckIfUnlocked(Registers.AlarmBRegister)) { alarmB.DaysMask = value; } }, valueProviderCallback: _ => alarmB.DaysMask) }, { (long)Registers.WriteProtectionRegister, new DoubleWordRegister(this) .WithValueField(0, 8, name: "KEY", writeCallback: (_, value) => { if (value == UnlockKey1 && !firstStageUnlocked) { firstStageUnlocked = true; } else if (value == UnlockKey2 && firstStageUnlocked) { registersUnlocked = true; } else { firstStageUnlocked = false; registersUnlocked = false; } }, valueProviderCallback: _ => 0) .WithReservedBits(8, 24) }, { (long)Registers.SubSecondRegister, new DoubleWordRegister(this) .WithTag("SS", 0, 16) .WithReservedBits(16, 16) }, { (long)Registers.ShiftControlRegister, new DoubleWordRegister(this) .WithTag("SUBFS", 0, 15) .WithReservedBits(15, 16) .WithTag("ADD1S", 31, 1) }, { (long)Registers.TimestampTimeRegister, new DoubleWordRegister(this) .WithTag("Second", 0, 7) .WithReservedBits(7, 1) .WithTag("Minute", 8, 7) .WithReservedBits(15, 1) .WithTag("Hour", 16, 6) .WithTag("PM", 22, 1) .WithReservedBits(23, 9) }, { (long)Registers.TimestampDateRegister, new DoubleWordRegister(this) .WithTag("Day", 0, 6) .WithReservedBits(6, 2) .WithTag("Month", 8, 5) .WithTag("WDU", 13, 3) .WithReservedBits(16, 16) }, { (long)Registers.TimestampSubSecondRegister, new DoubleWordRegister(this) .WithTag("SS", 0, 16) .WithReservedBits(16, 16) }, { (long)Registers.ClockCalibrationRegister, new DoubleWordRegister(this) .WithTag("CALM", 0, 9) .WithReservedBits(9, 4) .WithTag("CALW16", 13, 1) .WithTag("CALW8", 14, 1) .WithTag("CALP", 15, 1) .WithReservedBits(16, 16) }, { (long)Registers.TamperAndAlternateFunctionConfigurationRegister, new DoubleWordRegister(this) .WithTag("TAMP1E", 0, 1) .WithTag("TAMP1TRG", 1, 1) .WithTag("TAMPIE", 2, 1) .WithTag("TAMP2E", 3, 1) .WithTag("TAMP2TRG", 4, 1) .WithReservedBits(5, 2) .WithTag("TAMPTS", 7, 1) .WithTag("TAMPFREQ", 8, 3) .WithTag("TAMPFLT", 11, 2) .WithTag("TAMPPRCH", 13, 2) .WithTag("TAMPPUDIS", 15, 1) .WithTag("TAMP1INSEL", 16, 1) .WithTag("TSINSEL", 17, 1) .WithTag("ALARMOUTTYPE", 18, 1) .WithReservedBits(19, 13) }, { (long)Registers.AlarmASubSecondRegister, new DoubleWordRegister(this) .WithTag("SS", 0, 15) .WithReservedBits(15, 9) .WithTag("MASKSS", 24, 4) .WithReservedBits(28, 4) }, { (long)Registers.AlarmBSubSecondRegister, new DoubleWordRegister(this) .WithTag("SS", 0, 15) .WithReservedBits(15, 9) .WithTag("MASKSS", 24, 4) .WithReservedBits(28, 4) }, }; registers = new DoubleWordRegisterCollection(this, registerMap); }
private void DefineNonIndexedEndpointControlAndStatusRegisters() { Registers.Endpoint0TransmitControlStatus.Define16(this, name: $"EP0_TX_CSR_REG") .WithFlag(0, out var receivedPacketReady, name: "RxPktRdy") .WithFlag(1, out var transmitPacketReady, name: "TxPktRdy") .WithFlag(3, out var setupPacket, name: "SetupPkt") .WithFlag(5, out var requestPacket, name: "ReqPkt") .WithFlag(6, out var statusPacket, name: "StatusPkt") .WithWriteCallback((_, __) => { if (transmitPacketReady.Value) { transmitPacketReady.Value = false; if (!TryGetDeviceForEndpoint(0, Direction.HostToDevice, out var peripheral)) { this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint 0 in host to device direction"); return; } if (setupPacket.Value) { setupPacket.Value = false; var data = fifoFromHostToDevice[0].DequeueAll(); if (data.Length != 8) { this.Log(LogLevel.Warning, "Setup packet must be composed of 8 bytes, but there are currently {0} in the buffer. Refusing to send packet and dropping buffered data.", data.Length); return; } var packet = Packet.Decode <SetupPacket>(data); peripheral.USBCore.HandleSetupPacket(packet, receivedBytes => { fifoFromDeviceToHost[0].EnqueueRange(receivedBytes); txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0); }); } if (statusPacket.Value) { statusPacket.Value = false; // nothing happens here - just setting the interrupt txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0); } } if (requestPacket.Value) { requestPacket.Value = false; // since the communication with the device is instantenous the data should already wait in the buffer receivedPacketReady.Value = true; txInterruptsManager.SetInterrupt(TxInterrupt.Endpoint0); } }) ; ((Registers)Registers.Endpoint0ReceivePacketSize).Define8(this, name: $"EP0_RX_COUNT_REG") .WithValueField(0, 8, FieldMode.Read, name: $"EP0_RX_COUNT_REG", valueProviderCallback: _ => { return(checked ((byte)fifoFromDeviceToHost[0].Count)); }) ; for (var i = 1; i < NumberOfEndpoints; i++) { var endpointId = i; IFlagRegisterField localReceivedPacketReady = null; ((Registers)(Registers.Endpoint0ReceiveControlStatus + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_RX_CSR_REG") .WithFlag(5, out requestInTransaction[endpointId], name: "ReqPkt", writeCallback: (_, val) => { if (!val) { return; } if (!TryGetDeviceForEndpoint(endpointId, Direction.DeviceToHost, out var peripheral)) { this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint {0} in device to host direction", endpointId); return; } var endpoint = peripheral.USBCore.GetEndpoint((int)receiveTargetEndpointNumber[endpointId].Value); if (endpoint == null) { this.Log(LogLevel.Warning, "Trying to read from a non-existing endpoint #{0}", receiveTargetEndpointNumber[endpointId].Value); return; } endpoint.SetDataReadCallbackOneShot((e, bytes) => { fifoFromDeviceToHost[endpointId].EnqueueRange(bytes); requestInTransaction[endpointId].Value = false; localReceivedPacketReady.Value = true; rxInterruptsManager.SetInterrupt((RxInterrupt)endpointId); }); }) .WithFlag(4, FieldMode.WriteOneToClear, name: "FlushFIFO", writeCallback: (_, val) => { if (!val) { return; } fifoFromDeviceToHost[endpointId].Clear(); localReceivedPacketReady.Value = false; }) .WithFlag(0, out localReceivedPacketReady, name: "RxPktRdy") ; ((Registers)(Registers.Endpoint0ReceivePacketSize + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_RX_COUNT_REG") .WithValueField(0, 14, FieldMode.Read, name: $"EP{endpointId}_RX_COUNT_REG", valueProviderCallback: _ => { return(checked ((uint)fifoFromDeviceToHost[endpointId].Count)); }) ; ((Registers)(Registers.Endpoint0TransmitControlStatus + endpointId * 0x10)).Define16(this, name: $"EP{endpointId}_TX_CSR_REG") .WithTag("NAK Timeout/IncompTx", 7, 1) .WithTag("ClrDataTog", 6, 1) .WithTag("RxStall", 5, 1) .WithFlag(4, out var setupPkt, FieldMode.Read | FieldMode.Set, name: "SetupPkt") .WithTag("FlushFIFO", 3, 1) .WithTag("Error", 2, 1) .WithFlag(1, FieldMode.Read, name: "FIFONotEmpty", valueProviderCallback: _ => fifoFromHostToDevice[endpointId].Count > 0) .WithFlag(0, out var txPktRdy, FieldMode.Read | FieldMode.Set, name: "TxPktRdy") .WithWriteCallback((_, val) => { if (!txPktRdy.Value) { return; } if (setupPkt.Value) { throw new ArgumentException("Setup packets on Endpoint 1-4 are not supported"); } else { // standard OUT packet if (!TryGetDeviceForEndpoint(endpointId, Direction.HostToDevice, out var peripheral)) { this.Log(LogLevel.Warning, "There is no peripheral configured for endpoint {0} in host to device direction", endpointId); return; } var mappedEndpointId = (int)transmitTargetEndpointNumber[endpointId].Value; var endpoint = peripheral.USBCore.GetEndpoint(mappedEndpointId); if (endpoint == null) { this.Log(LogLevel.Warning, "Trying to write to a non-existing endpoint #{0}", mappedEndpointId); } var data = fifoFromHostToDevice[endpointId].DequeueAll(); endpoint.WriteData(data); txPktRdy.Value = false; txInterruptsManager.SetInterrupt((TxInterrupt)endpointId); } }) ; ((Registers)Registers.Endpoint0TransmitType + endpointId * 0x10).Define8(this, name: $"EP{endpointId}_TX_TYPE_REG") .WithTag("Speed", 6, 2) .WithTag("Protocol", 4, 2) .WithValueField(0, 4, out transmitTargetEndpointNumber[endpointId], name: "Target Endpoint Number") ; ((Registers)Registers.Endpoint0ReceiveType + endpointId * 0x10).Define8(this, name: $"EP{endpointId}_RX_TYPE_REG") .WithTag("Speed", 6, 2) .WithTag("Protocol", 4, 2) .WithValueField(0, 4, out receiveTargetEndpointNumber[endpointId], name: "Target Endpoint Number") ; } }