private void TryFinishTransmission() { bytesSent++; if (bytesSent == totalBytes) { RegisteredPeripheral.FinishTransmission(); } }
private void DisableSSI(bool oldValue, bool newValue) { this.Log(LogLevel.Debug, "SSI {0}.", newValue ? "enabled" : "disabled"); receiveFifo.Clear(); RefreshInterrupt(); if (!newValue && oldValue) { RegisteredPeripheral.FinishTransmission(); } }
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); } }) },
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(); }
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); }