Beispiel #1
0
        private void DataWrite(uint oldValue, uint newValue)
        {
            //moved from WriteByte
            byteTransferFinished.Value = false;
            Update();
            switch (state)
            {
            case State.AwaitingAddress:
                startBit.Value          = false;
                willReadOnSelectedSlave = (newValue & 1) == 1; //LSB is 1 for read and 0 for write
                var address = (int)(newValue >> 1);
                if (ChildCollection.ContainsKey(address))
                {
                    selectedSlave = ChildCollection[address];
                    addressSentOrMatched.Value = true;                    //Note: ADDR is not set after a NACK reception - from documentation

                    transmitterReceiver.Value = !willReadOnSelectedSlave; //true when transmitting

                    if (willReadOnSelectedSlave)
                    {
                        dataToReceive      = new Queue <byte>(selectedSlave.Read());
                        dataRegister.Value = 0u;
                        if (dataToReceive.Any())
                        {
                            dataRegister.Value         = dataToReceive.Dequeue();
                            dataRegisterNotEmpty.Value = true;
                        }
                        state = State.HasDataToRead;
                    }
                    else
                    {
                        state          = State.AwaitingData;
                        dataToTransfer = new List <byte>();
                    }
                }
                else
                {
                    state = State.Idle;
                    acknowledgeFailed.Value = true;
                }
                machine.ExecuteIn(Update);
                break;

            case State.AwaitingData:
                dataToTransfer.Add((byte)newValue);
                dataRegisterEmpty.Value = true;
                machine.ExecuteIn(() =>
                {
                    byteTransferFinished.Value = true;
                    state = State.AwaitingRestartOrStop;
                    Update();
                });
                Update();
                break;

            default:
                this.Log(LogLevel.Warning, "Writing {0} to DataRegister in unsupported state {1}.", newValue, state);
                break;
            }
        }
Beispiel #2
0
 public virtual void Register(T peripheral, NumberRegistrationPoint <int> registrationPoint)
 {
     if (ChildCollection.ContainsKey(registrationPoint.Address))
     {
         throw new RegistrationException("The specified registration point is already in use.");
     }
     ChildCollection.Add(registrationPoint.Address, peripheral);
 }
Beispiel #3
0
        public void Register(ICFU cfu, NumberRegistrationPoint <int> registrationPoint)
        {
            var isRegistered = ChildCollection.Where(x => x.Value.Equals(cfu)).Select(x => x.Key).ToList();

            if (isRegistered.Count != 0)
            {
                throw new RegistrationException("Can't register the same CFU twice.");
            }
            else if (ChildCollection.ContainsKey(registrationPoint.Address))
            {
                throw new RegistrationException("The specified registration point is already in use.");
            }

            ChildCollection.Add(registrationPoint.Address, cfu);
            machine.RegisterAsAChildOf(this, cfu, registrationPoint);
            cfu.ConnectedCpu = this;
        }
        public HiFive_SPI(Machine machine, bool isFlashEnabled = false, int numberOfSupportedSlaves = 1) : base(machine)
        {
            if (numberOfSupportedSlaves < 1 || numberOfSupportedSlaves > 32)
            {
                throw new ConstructionException($"Wrong number of supported slaves: {numberOfSupportedSlaves}. Provide a value in range from 1 to 32.");
            }

            this.csWidth = numberOfSupportedSlaves;
            receiveQueue = new Queue <byte>();
            IRQ          = new GPIO();

            var registersMap = new Dictionary <long, DoubleWordRegister>()
            {
                { (long)Registers.ChipSelectId, new DoubleWordRegister(this)
                  .WithValueField(0, 32, out selectedSlave, name: "csid", writeCallback: (previousValue, value) =>
                    {
                        if (!ChildCollection.ContainsKey(checked ((int)value)))
                        {
                            this.Log(LogLevel.Warning, "Selected pin {0}, but there is no device connected to it.", value);
                        }

                        if (previousValue != value)
                        {
                            FinishTransmission();
                        }
                        else
                        {
                            ClearReceiveQueue();
                        }
                    }) },

                { (long)Registers.ChipSelectDefault, new DoubleWordRegister(this, (1u << numberOfSupportedSlaves) - 1)
                  // this field's width and reset value depend on a constructor parameter `numberOfSupportedSlaves`
                  .WithValueField(0, numberOfSupportedSlaves, name: "csdef") },

                { (long)Registers.ChipSelectMode, new DoubleWordRegister(this)
                  .WithEnumField <DoubleWordRegister, ChipSelectMode>(0, 2, name: "csmode",
                                                                      writeCallback: (_, val) =>
                    {
                        // means off
                        if (val == ChipSelectMode.Auto)
                        {
                            FinishTransmission();
                        }
                    }) },

                { (long)Registers.TxFifoData, new DoubleWordRegister(this, 0x0)
                  .WithValueField(0, 8, FieldMode.Write, writeCallback: (_, value) => HandleFifoWrite((byte)value), name: "data")
                  .WithReservedBits(8, 23)
                  .WithFlag(31, FieldMode.Read, valueProviderCallback: _ => false, name: "full") },

                { (long)Registers.RxFifoData, new DoubleWordRegister(this, 0x0)
                  // According to the documentation this registers is divided into two fields and a reserved block.
                  // I decided not to split it because the value of both fields must be evaluated IN PROPER ORDER
                  // (flag before dequeuing) and currently the API does not guarantee that.
                  .WithValueField(0, 32, FieldMode.Read, name: "data+empty", valueProviderCallback: _ =>
                    {
                        var result = (receiveQueue.Count == 0)
                            ? FifoEmptyMarker
                            : receiveQueue.Dequeue();

                        UpdateInterrupts();
                        return(result);
                    }) },

                { (long)Registers.TxFifoWatermark, new DoubleWordRegister(this, isFlashEnabled ? 0x1 : 0x0u)
                  .WithValueField(0, 3, out transmitWatermark, writeCallback: (_, __) => UpdateInterrupts(), name: "txmark")
                  .WithReservedBits(3, 29) },

                { (long)Registers.RxFifoWatermark, new DoubleWordRegister(this, 0x0)
                  .WithValueField(0, 3, out receiveWatermark, writeCallback: (_, __) => UpdateInterrupts(), name: "rxmark")
                  .WithReservedBits(3, 29) },

                { (long)Registers.InterruptEnable, new DoubleWordRegister(this, 0x0)
                  .WithFlag(0, out transmitWatermarkInterruptEnable, writeCallback: (_, __) => UpdateInterrupts(), name: "txwm")
                  .WithFlag(1, out receiveWatermarkInterruptEnable, writeCallback: (_, __) => UpdateInterrupts(), name: "rxwm")
                  .WithReservedBits(2, 30) },

                { (long)Registers.InterruptPending, new DoubleWordRegister(this, 0x0)
                  .WithFlag(0, out transmitWatermarkPending, FieldMode.Read, name: "txwm")
                  .WithFlag(1, out receiveWatermarkPending, FieldMode.Read, name: "rxwm")
                  .WithReservedBits(2, 30) }
            };

            registers = new DoubleWordRegisterCollection(this, registersMap);
        }
        private void DataWrite(uint oldValue, uint newValue)
        {
            //moved from WriteByte
            writeLock = true;
            byteTransferFinished.Value = false;
            Update();
            this.Log(LogLevel.Noisy, "Entered DataWrite with oldValue 0x{0:X} and newValue 0x{1:X}. State: {2}", oldValue, newValue, state);
            switch (state)
            {
            case State.AwaitingAddress:
                startBit.Value          = false;
                willReadOnSelectedSlave = (newValue & 1) == 1; //LSB is 1 for read and 0 for write
                var address = (int)(newValue >> 1);
                if (ChildCollection.ContainsKey(address))
                {
                    selectedSlave = ChildCollection[address];
                    addressSentOrMatched.Value = true;                    //Note: ADDR is not set after a NACK reception - from documentation

                    transmitterReceiver.Value = !willReadOnSelectedSlave; //true when transmitting

                    if (willReadOnSelectedSlave)
                    {
                        this.Log(LogLevel.Noisy, "Data will be read from slave {0} at address 0x{1:X}", selectedSlave, address);
                        dataToReceive = new Queue <byte>(selectedSlave.Read());
                        byteTransferFinished.Value = true;
                    }
                    else
                    {
                        this.Log(LogLevel.Noisy, "Data will be written to slave {0} at address 0x{1:X}", selectedSlave, address);
                        state          = State.AwaitingData;
                        dataToTransfer = new List <byte>();

                        dataRegisterEmpty.Value    = true;
                        addressSentOrMatched.Value = true;
                    }
                }
                else
                {
                    this.Log(LogLevel.Warning, "No slave device on address 0x{0:X}", address);
                    state = State.Idle;
                    acknowledgeFailed.Value = true;
                }
                machine.LocalTimeSource.ExecuteInNearestSyncedState(_ => Update());
                break;

            case State.AwaitingData:
                dataToTransfer.Add((byte)newValue);

                machine.LocalTimeSource.ExecuteInNearestSyncedState(_ =>
                {
                    dataRegisterEmpty.Value = true;
                    Update();
                    writeLock = false;
                    machine.LocalTimeSource.ExecuteInNearestSyncedState(__ =>
                    {
                        if (!writeLock)
                        {
                            this.Log(LogLevel.Noisy, "Setting BTF to true!");
                            // Moved setting BTF to inside another "Synced State" since it got set too soon otherwise
                            // Firmware, hardware or emulation problem?
                            byteTransferFinished.Value = true;
                            Update();
                        }
                    });
                });
                break;

            default:
                this.Log(LogLevel.Warning, "Writing {0} to DataRegister in unsupported state {1}.", newValue, state);
                break;
            }
        }