private void TryFinishTransmission()
 {
     bytesSent++;
     if (bytesSent == totalBytes)
     {
         RegisteredPeripheral.FinishTransmission();
     }
 }
示例#2
0
 private void DisableSSI(bool oldValue, bool newValue)
 {
     this.Log(LogLevel.Debug, "SSI {0}.", newValue ? "enabled" : "disabled");
     receiveFifo.Clear();
     RefreshInterrupt();
     if (!newValue && oldValue)
     {
         RegisteredPeripheral.FinishTransmission();
     }
 }
示例#3
0
        public PicoRV_SPI(Machine machine) : base(machine)
        {
            bbHelper = new BitBangHelper(8, loggingParent: this, outputMsbFirst: true);

            var registers = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.Config1, new DoubleWordRegister(this)
                  .WithFlag(0, out var data0, FieldMode.Write, name: "data0")
                  .WithFlag(1, FieldMode.Write, name: "data1")   // data 1-3 used in QSPI only
                  .WithFlag(2, FieldMode.Write, name: "data2")
                  .WithFlag(3, FieldMode.Write, name: "data3")
                  .WithFlag(4, out var clock, FieldMode.Write, name: "clk")
                  .WithFlag(5, out var chipSelectNegated, FieldMode.Write, name: "cs_n")
                  .WithReservedBits(6, 2)

                  .WithWriteCallback((_, val) =>
                    {
                        if (memioEnable.Value)
                        {
                            this.Log(LogLevel.Warning, "MEMIO mode not enabled - bit banging not supported in this mode");
                            return;
                        }

                        if (qspiEnable.Value)
                        {
                            this.Log(LogLevel.Warning, "QSPI mode not yet supported");
                            return;
                        }

                        if (RegisteredPeripheral == null)
                        {
                            this.Log(LogLevel.Warning, "Trying to send bytes over SPI, but there is no device attached");
                            return;
                        }

                        if (chipSelectNegated.Value && !previousChipSelectNegated)
                        {
                            this.Log(LogLevel.Noisy, "ChipSelect signal down - finishing the transmission");
                            RegisteredPeripheral.FinishTransmission();
                            bbHelper.ResetOutput();
                        }
                        previousChipSelectNegated = chipSelectNegated.Value;

                        // do not latch bits when MEMIO is enabled or chipSelect is not set
                        if (bbHelper.Update(clock.Value, data0.Value, !memioEnable.Value && !chipSelectNegated.Value))
                        {
                            this.Log(LogLevel.Noisy, "Sending byte 0x{0:X}", bbHelper.DecodedOutput);
                            var input = RegisteredPeripheral.Transmit((byte)bbHelper.DecodedOutput);
                            this.Log(LogLevel.Noisy, "Received byte 0x{0:X}", input);

                            bbHelper.SetInputBuffer(input);
                        }
                    }) },
        public LiteX_SPI_Flash(Machine machine) : base(machine)
        {
            bbHelper = new BitBangHelper(8, loggingParent: this, outputMsbFirst: true);

            var registers = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.BitBang, new DoubleWordRegister(this)
                  .WithFlag(0, out var valueSignal, FieldMode.Write, name: "value")
                  .WithFlag(1, out var clockSignal, FieldMode.Write, name: "clk")
                  .WithFlag(2, out var chipSelectNegatedSignal, FieldMode.Write, name: "cs_n")
                  .WithFlag(3, out var dqInputSignal, FieldMode.Write, name: "dq_input")
                  .WithWriteCallback((_, val) =>
                    {
                        if (!bitBangEnabled.Value)
                        {
                            this.Log(LogLevel.Warning, "Write to not-enabled BitBang register ignored");
                            return;
                        }

                        if (RegisteredPeripheral == null)
                        {
                            this.Log(LogLevel.Warning, "Trying to send bytes over SPI, but there is no device attached");
                            return;
                        }

                        if (chipSelectNegatedSignal.Value && !previousChipSelectNegatedSignal)
                        {
                            this.Log(LogLevel.Noisy, "ChipSelect signal down - finishing the transmission");
                            RegisteredPeripheral.FinishTransmission();
                        }
                        previousChipSelectNegatedSignal = chipSelectNegatedSignal.Value;

                        // do not latch bits when dqInputSignal is set or chipSelect is not set
                        if (bbHelper.Update(clockSignal.Value, valueSignal.Value, !dqInputSignal.Value && !chipSelectNegatedSignal.Value))
                        {
                            this.Log(LogLevel.Noisy, "Sending byte 0x{0:X}", bbHelper.DecodedOutput);
                            var input = RegisteredPeripheral.Transmit((byte)bbHelper.DecodedOutput);
                            this.Log(LogLevel.Noisy, "Received byte 0x{0:X}", input);

                            bbHelper.SetInputBuffer(input);
                        }
                    }) },
示例#5
0
 private void TryStartTransmission()
 {
     if (!txEnable.Value || command != Commands.TransferData)
     {
         this.Log(LogLevel.Debug, "Tried to issue a transaction without full configuration.");
         return;
     }
     if (RegisteredPeripheral == null)
     {
         this.Log(LogLevel.Warning, "Trying to issue a transaction to a slave peripheral, but nothing is connected");
         return;
     }
     foreach (var b in Machine.SystemBus.ReadBytes(txTransferAddress.Value, (int)txTransferBufferSize.Value))
     {
         RegisteredPeripheral.Transmit(b);
     }
     RegisteredPeripheral.FinishTransmission();
     command = Commands.None;
     TxIRQ.Blink();
 }
示例#6
0
        private void TryStartReception()
        {
            if (!rxEnable.Value || command != Commands.ReceiveData)
            {
                this.Log(LogLevel.Debug, "Tried to issue a transaction without full configuration.");
                return;
            }
            if (RegisteredPeripheral == null)
            {
                this.Log(LogLevel.Warning, "Trying to issue a transaction to a slave peripheral, but nothing is connected");
                return;
            }
            var receiveQueue = new Queue <byte>();

            for (int i = 0; i < (int)rxTransferBufferSize.Value; i++)
            {
                receiveQueue.Enqueue(RegisteredPeripheral.Transmit(0));
            }
            RegisteredPeripheral.FinishTransmission();
            Machine.SystemBus.WriteBytes(receiveQueue.ToArray(), rxTransferAddress.Value);
            receiveQueue.Clear();
            command = Commands.None;
            RxIRQ.Blink();
        }
        public MPFS_SPI(Machine machine) : base(machine)
        {
            locker         = new object();
            receiveBuffer  = new Queue <byte>();
            transmitBuffer = new Queue <byte>();
            IRQ            = new GPIO();

            controlRegister = new DoubleWordRegister(this, 0x80000102)
                              .WithFlag(0, out coreEnabled,
                                        changeCallback: (_, val) =>
            {
                if (!val)
                {
                    frameCounterLimit.Value = 0;
                }
            }, name: "ENABLE")
                              .WithFlag(1, out master, name: "MASTER")
                              .WithTag("MODE", 2, 2)
                              .WithFlag(4, out enableIrqOnReceive, name: "INTRXDATA")
                              .WithFlag(5, out enableIrqOnTransmit, name: "INTTXDATA")
                              .WithFlag(6, out enableIrqOnOverflow, name: "INTRCVOVFLOW")
                              .WithFlag(7, out enableIrqOnUnderrun, name: "INTTXTURUN")
                              .WithValueField(8, 16, out frameCounterLimit,
                                              writeCallback: (_, val) =>
            {
                framesReceived    = 0;
                framesTransmitted = 0;
            }, name: "FRAMECNT")
                              .WithTag("SPO", 24, 1)
                              .WithTag("SPH", 25, 1)
                              .WithTag("SPS", 26, 1)
                              .WithTag("FRAMEURUN", 27, 1)
                              .WithTag("CLKMODE", 28, 1)
                              .WithFlag(29,
                                        changeCallback: (_, val) =>
            {
                if (val)
                {
                    if (frameSize.Value <= 8)
                    {
                        fifoSize = 32;
                    }
                    else if (frameSize.Value >= 9 && frameSize.Value <= 16)
                    {
                        fifoSize = 16;
                    }
                    else if (frameSize.Value >= 17)
                    {
                        fifoSize = 8;
                    }
                }
                else
                {
                    fifoSize = 4;
                }
            }, name: "BIGFIFO")
                              .WithTag("OENOFF", 30, 1)
                              .WithFlag(31,
                                        writeCallback: (_, val) =>
            {
                if (val)
                {
                    Reset();
                }
            }, name: "RESET");

            var registersMap = new Dictionary <long, DoubleWordRegister>
            {
                { (long)Registers.Control, controlRegister },

                { (long)Registers.FrameSize, new DoubleWordRegister(this, 0x4)
                  .WithValueField(0, 6, out frameSize, name: "FRAMESIZE") },

                { (long)Registers.Status, new DoubleWordRegister(this, 0x2440)
                  .WithFlag(0, out dataSent, FieldMode.Read, name: "TXDATASENT")
                  .WithFlag(1, out dataReceived, FieldMode.Read, name: "RXDATARCVD")
                  .WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => receiveOverflow.Value, name: "RXOVERFLOW")
                  .WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => transmitUnderrun.Value, name: "TXUNDERRUN")
                  .WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == fifoSize, name: "RXFIFOFULL")
                  .WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => (receiveBuffer.Count + 1) == fifoSize, name: "RXFIFOFULLNEXT")
                  .WithFlag(6, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 0, name: "RXFIFOEMPTY")
                  .WithFlag(7, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 1, name: "RXFIFOEMPTYNEXT")
                  .WithFlag(8, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == fifoSize, name: "TXFIFOFULL")
                  .WithFlag(9, FieldMode.Read, valueProviderCallback: (_) => (transmitBuffer.Count + 1) == fifoSize, name: "TXFIFOFULLNEXT")
                  .WithFlag(10, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == 0, name: "TXFIFOEMPTY")
                  .WithFlag(11, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == 1, name: "TXFIFOEMPTYNEXT")
                  .WithTag("FRAMESTART", 12, 1)
                  .WithTag("SSEL", 13, 1)
                  .WithTag("ACTIVE", 14, 1) },

                { (long)Registers.InterruptClear, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            transmitDone.Value = false;
                        }
                    }, name: "TXDONE")
                  .WithFlag(1, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            receiveDone.Value = false;
                        }
                    }, name: "RXDONE")
                  .WithFlag(2, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            receiveOverflow.Value = false;
                        }
                    }, name: "RXOVERFLOW")
                  .WithFlag(3, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            transmitUnderrun.Value = false;
                        }
                    }, name: "TXUNDERRUN")
                  .WithFlag(4, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            fullCommandReceived.Value = false;
                        }
                    }, name: "CMDINT")
                  .WithFlag(5, FieldMode.WriteOneToClear,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            slaveSelectGoneInactve.Value = false;
                        }
                    }, name: "SSEND") },

                { (long)Registers.ReceiveData, new DoubleWordRegister(this)
                  .WithValueField(0, 32, FieldMode.Read,
                                  valueProviderCallback: _ =>
                    {
                        dataReceived.Value = false;
                        return(receiveBuffer.Count > 0 ? receiveBuffer.Dequeue() : (byte)0x00);
                    }, name: "RXDATA") },

                { (long)Registers.TransmitData, new DoubleWordRegister(this)
                  .WithValueField(0, 32, FieldMode.Write,
                                  writeCallback: (_, val) =>
                    {
                        if (coreEnabled.Value)
                        {
                            dataSent.Value = false;
                            if (master.Value == true)
                            {
                                this.Log(LogLevel.Noisy, $"Writing 0x{val:X} to slave.");
                                //TODO: should probably enqueue data if frame counter is enabled and the frameTransmitted reached the threshold.
                                // We do not handle TXFIFO as its handling is not clear from the documentation.
                                TryReceive(RegisteredPeripheral.Transmit((byte)val));
                                if (framesReceived + framesTransmitted == frameCounterLimit.Value)
                                {
                                    dataSent.Value     = true;
                                    transmitDone.Value = true;
                                    if (slaveSelect.Value > 0)
                                    {
                                        RegisteredPeripheral.FinishTransmission();
                                    }
                                }
                            }
                            else
                            {
                                this.Log(LogLevel.Noisy, $"Writing 0x{val:X} to transmit buffer in slave mode.");
                                transmitBuffer.Enqueue((byte)val);
                            }
                        }
                    }, name: "TXDATA") },

                { (long)Registers.ClockRate, new DoubleWordRegister(this)
                  .WithValueField(0, 8, name: "CLKRATE") },

                { (long)Registers.SlaveSelect, new DoubleWordRegister(this)
                  .WithValueField(0, 8, out slaveSelect,
                                  writeCallback: (_, val) =>
                    {
                        if (val > 0)
                        {
                            slaveSelect.Value = val;
                            framesReceived    = 0;
                            framesTransmitted = 0;
                        }
                        else if (val == 0 && slaveSelect.Value > 0)
                        {
                            slaveSelect.Value = 0;
                            RegisteredPeripheral.FinishTransmission();
                        }
                    }, name: "SSEL") },

                { (long)Registers.InterruptMasked, new DoubleWordRegister(this)
                  .WithValueField(0, 6, valueProviderCallback: _ => CalculateMaskedInterruptValue()) },

                { (long)Registers.InterruptRaw, new DoubleWordRegister(this)
                  .WithFlag(0, out transmitDone, name: "TXDONE")
                  .WithFlag(1, out receiveDone, name: "RXDONE")
                  .WithFlag(2, out receiveOverflow, name: "RXOVERFLOW")
                  .WithFlag(3, out transmitUnderrun, name: "TXUNDERRUN")
                  .WithFlag(4, out fullCommandReceived, name: "CMDINT")
                  .WithFlag(5, out slaveSelectGoneInactve, name: "SSEND") },

                { (long)Registers.ControlBitsForEnhancedModes, new DoubleWordRegister(this)
                  .WithTag("AUTOSTATUS", 0, 1)
                  .WithTag("AUTOPOLL", 1, 1)
                  .WithFlag(2, out disableFrameCount, name: "DISFRMCNT")
                  // bit 3 reserved
                  .WithFlag(4, out enableIrqOnCmd, name: "INTEN_CMD")
                  .WithFlag(5, out enableIrqOnSsend, name: "INTEN_SSEND") },

                { (long)Registers.CommandRegister, new DoubleWordRegister(this)
                  .WithFlag(0, FieldMode.Read,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            while (transmitBuffer.Count < fifoSize)
                            {
                                transmitBuffer.Enqueue(0);
                            }
                        }
                    }, name: "AUTOFILL")
                  .WithTag("AUTOEMPTY", 1, 1)
                  .WithFlag(2, FieldMode.Read,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            receiveBuffer.Clear();
                        }
                    }, name: "RXFIFORST")
                  .WithFlag(3, FieldMode.Read,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            transmitBuffer.Clear();
                        }
                    }, name: "TXFIFORST")
                  .WithFlag(4, FieldMode.Read,
                            writeCallback: (_, val) =>
                    {
                        if (val)
                        {
                            frameCounterLimit.Value = 0;
                            framesTransmitted       = 0;
                            framesReceived          = 0;
                        }
                    }, name: "CLRFRAMECNT")
                  .WithTag("AUTOSTALL", 5, 1)
                  .WithTag("TXNOW", 6, 1) },

                { (long)Registers.CommandSize, new DoubleWordRegister(this)
                  .WithValueField(0, 6, out commandSize, name: "CMDSIZE") },

                { (long)Registers.SlaveHardwareStatus, new DoubleWordRegister(this)
                  .WithValueField(0, 8, FieldMode.Read, valueProviderCallback: (_) => CalculateSlaveHardwareStatus(), name: "HWSTATUS") },

                { (long)Registers.Status8, new DoubleWordRegister(this)
                  .WithTag("FIRSTFRAME", 0, 1)
                  .WithFlag(1, FieldMode.Read, valueProviderCallback: (_) => dataSent.Value && dataReceived.Value, name: "DONE")
                  .WithFlag(2, FieldMode.Read, valueProviderCallback: (_) => receiveBuffer.Count == 0, name: "RXEMPTY")
                  .WithFlag(3, FieldMode.Read, valueProviderCallback: (_) => transmitBuffer.Count == fifoSize, name: "TXFULL")
                  .WithFlag(4, FieldMode.Read, valueProviderCallback: (_) => receiveOverflow.Value, name: "RXOVFLOW")
                  .WithFlag(5, FieldMode.Read, valueProviderCallback: (_) => transmitUnderrun.Value, name: "TXUNDERRUN")
                  .WithFlag(6, FieldMode.Read, valueProviderCallback: (_) => slaveSelect.Value > 0, name: "SSEL")
                  .WithTag("ACTIVE", 7, 1) },

                { (long)Registers.AliasedControlRegister0, new DoubleWordRegister(this)
                  .WithValueField(0, 8,
                                  writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 0, 8)),
                                  valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 0, 8), name: "CTRL0") },

                { (long)Registers.AliasedControlRegister1, new DoubleWordRegister(this)
                  .WithValueField(0, 8,
                                  writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 8, 8)),
                                  valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 8, 8), name: "CTRL1") },

                { (long)Registers.AliasedControlRegister2, new DoubleWordRegister(this)
                  .WithValueField(0, 8,
                                  writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 16, 8)),
                                  valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 16, 8), name: "CTRL2") },

                { (long)Registers.AliasedControlRegister3, new DoubleWordRegister(this)
                  .WithValueField(0, 8,
                                  writeCallback: (_, newVal) => controlRegister.Write(0, BitHelper.SetBitsFrom(controlRegister.Value, newVal, 24, 8)),
                                  valueProviderCallback: (_) => BitHelper.GetMaskedValue(controlRegister.Value, 24, 8), name: "CTRL3") }
            };

            registers = new DoubleWordRegisterCollection(this, registersMap);
        }