예제 #1
0
 public override void Reset()
 {
     RegisteredPeripheral?.Reset();
     RegistersCollection.Reset();
     irqManager.Reset();
     internalBuffer.Clear();
 }
예제 #2
0
        public uint ReadDoubleWord(long offset)
        {
            switch ((Registers)offset)
            {
            case Registers.Control:
                return(controlRegister);

            case Registers.Status:
                return(HandleStatusRegister());

            case Registers.Data:
                IRQ.Unset();
                if (RegisteredPeripheral != null)
                {
                    dataRegister = RegisteredPeripheral.Read();
                }
                return(dataRegister);

            case Registers.ClockDivisor:
                return(clkDivRegister);

            case Registers.InterruptIdentification:
                return(IRQ.IsSet ? 1u : 0u);

            default:
                return(idHelper.Read(offset));
            }
        }
예제 #3
0
 public void Dispose()
 {
     if (RegisteredPeripheral != null)
     {
         RegisteredPeripheral.Dispose();
     }
 }
예제 #4
0
        private void WriteData()
        {
            var data = writerDataBuffer.Take((int)blockSize).ToArray();

            this.Log(LogLevel.Noisy, "Writing data: {0}", Misc.PrettyPrintCollectionHex(data));
            RegisteredPeripheral.WriteData(data);
        }
예제 #5
0
        private void sendCommand(uint command, uint length)
        {
            //TODO: Endianess
            writeOccured          = true;
            transferFIFODataCount = 0;
            this.Log(LogLevel.Warning, "Flash command {0:X}", command);
            switch ((SPIFlashCommand)(command & 0xff))
            {
            case SPIFlashCommand.ReadID:
                //TODO: polarization
                var ID = 0xffffffffu; //return 0xffffffff if there is no flash attached
                if (RegisteredPeripheral != null)
                {
                    ID = RegisteredPeripheral.ReadID();
                }
                registers.ReceiveData = ID;
                receiveFIFODataCount += 1;
                break;

            default:
                receiveFIFODataCount += 1; //XXX: ugly
                this.Log(LogLevel.Warning, "Unimplemented SPI Flash command {0:X}", command);
                break;
            }
        }
예제 #6
0
 private void TryFinishTransmission()
 {
     bytesSent++;
     if (bytesSent == totalBytes)
     {
         RegisteredPeripheral.FinishTransmission();
     }
 }
예제 #7
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();
     }
 }
예제 #8
0
        private void ReadData()
        {
            if (blockCount != 1)
            {
                this.Log(LogLevel.Warning, "This model curently supports only reading a sinlge block at a time, but the block count is set to {0}", blockCount);
                return;
            }

            readerDataBuffer = RegisteredPeripheral.ReadData(blockSize);
            this.Log(LogLevel.Noisy, "Received data is: {0}", Misc.PrettyPrintCollectionHex(readerDataBuffer));
        }
예제 #9
0
        public void WriteChar(byte value)
        {
            if (RegisteredPeripheral != null)
            {
                return;
            }
            var charReceived = CharReceived;
            var read         = RegisteredPeripheral.Transmit(value);

            charReceived(read);
        }
        private void WriteData()
        {
            writerAddress &= 0xffffffff;

            var data = Machine.SystemBus.ReadBytes(writerAddress, (int)writerLength.Value);

#if DEBUG_PACKETS
            this.Log(LogLevel.Noisy, "Writing {0} bytes of data read from 0x{1:X} to the device: {2}", data.Length, writerAddress, Misc.PrettyPrintCollectionHex(data));
#endif

            RegisteredPeripheral.WriteData(data);
        }
        private void ReadData()
        {
            readerAddress &= 0xffffffff;

            var data = RegisteredPeripheral.ReadData(readerLength.Value);

#if DEBUG_PACKETS
            this.Log(LogLevel.Noisy, "Reading {0} bytes of data from device: {1}. Writing it to 0x{2:X}", data.Length, Misc.PrettyPrintCollectionHex(data), readerAddress);
#endif

            Machine.SystemBus.WriteBytes(data, readerAddress);
        }
예제 #12
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);
                        }
                    }) },
예제 #13
0
        private void HandleByteReception()
        {
            var receivedByte = RegisteredPeripheral.Transmit(0);

            if (bytesToSkip > 0)
            {
                bytesToSkip--;
            }
            else
            {
                TryReceive(receivedByte);
            }
            TryFinishTransmission();
        }
        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);
                        }
                    }) },
예제 #15
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();
 }
예제 #16
0
        private void WriteData(uint unused, uint data)
        {
            if (!ssiEnabled.Value)
            {
                return;
            }
            if (transferMode.Value == TransferMode.ReceiveOnly || transferMode.Value == TransferMode.EEPROMRead)
            {
                // note that number of data frames (NDF field in second control register) is important in this transfer mode
                // see datasheet for details
                this.Log(LogLevel.Error, "Unhandled transfer mode {0}.", transferMode);
            }
            RefreshInterrupt(true); // although we immediately transfer the byte, the interrupt line has to be turned off for the moment
            var result = RegisteredPeripheral.Transmit((byte)data);

            if (transferMode.Value == TransferMode.TransmitAndReceive)
            {
                receiveFifo.Enqueue(result);
            }

            RefreshInterrupt();
        }
예제 #17
0
        private void SendData(byte b)
        {
            if (!enabled)
            {
                this.Log(LogLevel.Warning, "Trying to send data, but the controller is disabled");
                return;
            }

            if (RegisteredPeripheral == null)
            {
                this.Log(LogLevel.Warning, "No device connected");
                return;
            }

            if (receiveFifo.Count == ReceiveBufferSize)
            {
                this.Log(LogLevel.Warning, "Buffers full, ignoring data");
                return;
            }

            // there is no need to queue transmitted bytes - let's send them right away
            var result = RegisteredPeripheral.Transmit(b);

            lock (receiveFifo)
            {
                receiveFifo.Enqueue(result);

                // the READY event is generated
                // only when the head
                // of the queue changes
                if (receiveFifo.Count == 1)
                {
                    readyPending.Value = true;
                    UpdateInterrupts();
                }
            }
        }
예제 #18
0
        public void WriteDoubleWord(long offset, uint value)
        {
            switch ((Registers)offset)
            {
            case Registers.Control:
                controlRegister = value;
                break;

            case Registers.Data:
                if (RegisteredPeripheral != null)
                {
                    RegisteredPeripheral.Write((byte)value);
                }
                break;

            case Registers.ClockDivisor:
                clkDivRegister = value;
                break;

            default:
                this.LogUnhandledWrite(offset, value);
                break;
            }
        }
예제 #19
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();
        }
예제 #20
0
 private void HandleByteReception()
 {
     TryReceive(RegisteredPeripheral.Transmit(0));
     TryFinishTransmission();
 }
예제 #21
0
 private void HandleByteTransmission(uint val)
 {
     RegisteredPeripheral.Transmit((byte)val);
     TryFinishTransmission();
 }
예제 #22
0
 public void Dispose()
 {
     RegisteredPeripheral?.Dispose();
 }
예제 #23
0
 protected override void SendSdConfigurationValue()
 {
     byte[] data = BitConverter.GetBytes(RegisteredPeripheral.SendSdConfigurationValue());
     DmaTransfer(data, 8, DataDirection.ReadFromSD);
 }
예제 #24
0
        private void DefineRegisters()
        {
            PhyRegisters.CardDetect.Define(this)
            // note: `true` means *no* card
            .WithFlag(0, FieldMode.Read, name: "card_detect", valueProviderCallback: _ => RegisteredPeripheral == null)
            .WithReservedBits(1, 31);

            CoreRegisters.Argument.DefineMany(coreRegistersCollection, 4, (register, idx) =>
            {
                register
                .WithValueField(0, 8, name: $"argument{idx}", writeCallback: (_, val) =>
                {
                    BitHelper.ReplaceBits(ref argumentValue, width: 8, source: val, destinationPosition: 24 - idx * 8);
                })
                .WithIgnoredBits(8, 24);
            });

            CoreRegisters.Command0.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.Command1.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.Command2.Define(coreRegistersCollection)
            .WithValueField(0, 7, out commandIndexField, name: "command_index")
            .WithReservedBits(7, 1)
            .WithIgnoredBits(8, 24);

            CoreRegisters.Command3.Define(coreRegistersCollection)
            .WithEnumField <DoubleWordRegister, ResponseType>(0, 3, out responseTypeField, name: "respone_type")
            .WithReservedBits(3, 2)
            .WithEnumField <DoubleWordRegister, TransferType>(5, 3, out transferTypeField, name: "transfer_type")
            .WithIgnoredBits(8, 24);

            CoreRegisters.IssueCommand.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.WriteOneToClear, name: "issue_command", writeCallback: (_, val) =>
            {
                if (!val)
                {
                    // we are only interested in `true`
                    return;
                }

                if (RegisteredPeripheral == null)
                {
                    this.Log(LogLevel.Warning, "Issued a 0x{0:X} command with 0x{1:X} argument, but there is no SD card attached", commandIndexField.Value, argumentValue);
                    return;
                }

                this.Log(LogLevel.Noisy, "Issuing command #{0}, transfer type is {1}, response type is {2}", commandIndexField.Value, transferTypeField.Value, responseTypeField.Value);

                var resp = RegisteredPeripheral.HandleCommand(commandIndexField.Value, argumentValue).AsByteArray();

                this.Log(LogLevel.Noisy, "Received response of size {0}", resp.Length);
#if DEBUG_PACKETS
                this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(resp));
#endif

                var expectedResponseLength = 0;

                switch (responseTypeField.Value)
                {
                case ResponseType.Short:
                    expectedResponseLength = 4;
                    break;

                case ResponseType.Long:
                    expectedResponseLength = 16;
                    break;
                }

                if (resp.Length != expectedResponseLength)
                {
                    this.Log(LogLevel.Warning, "Expected response of length {0} bytes, but received {1} bytes", expectedResponseLength, resp.Length);
                    return;
                }

                for (var i = 0; i < resp.Length; i++)
                {
                    responseBuffer[ResponseBufferLength - 1 - i] = resp[i];
                }

                switch (transferTypeField.Value)
                {
                case TransferType.Read:
                    if (readerStartFlag.Value)
                    {
                        readerStartFlag.Value = false;
                        ReadData();
                    }
                    break;

                case TransferType.Write:
                    if (writerStartFlag.Value)
                    {
                        writerStartFlag.Value = false;
                        WriteData();
                    }
                    break;
                }
            })
            .WithReservedBits(1, 7)
            .WithReservedBits(8, 24);

            CoreRegisters.Response.DefineMany(coreRegistersCollection, ResponseBufferLength, (register, idx) =>
            {
                register
                .WithValueField(0, 8, FieldMode.Read, name: $"Response{idx}", valueProviderCallback: _ =>
                {
                    return(responseBuffer[idx]);
                })
                .WithIgnoredBits(8, 24);
            });

            CoreRegisters.CommandEvent0.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.CommandEvent1.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.CommandEvent2.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.CommandEvent3.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "cmddone", valueProviderCallback: _ => true)
            .WithReservedBits(1, 1)
            .WithTag("cerrtimeout", 2, 1)
            .WithTag("cerrcrc", 3, 1)
            .WithReservedBits(4, 4)
            .WithIgnoredBits(8, 24);

            CoreRegisters.DataEvent0.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.DataEvent1.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.DataEvent2.Define(coreRegistersCollection)
            .WithIgnoredBits(0, 32);

            CoreRegisters.DataEvent3.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "datadone", valueProviderCallback: _ => true)
            .WithTag("derrwrite", 1, 1)
            .WithTag("derrtimeout", 2, 1)
            .WithTag("derrcrc", 3, 1)
            .WithReservedBits(4, 4)
            .WithIgnoredBits(8, 24);
            ;

            CoreRegisters.BlockSize.DefineMany(coreRegistersCollection, 2, (register, idx) =>
            {
                register
                .WithValueField(0, 8, name: $"BlockSize{idx}", writeCallback: (_, val) =>
                {
                    BitHelper.ReplaceBits(ref blockSize, width: 8, source: val, destinationPosition: 8 - idx * 8);
                })
                .WithIgnoredBits(8, 24);
            });

            CoreRegisters.BlockCount.DefineMany(coreRegistersCollection, 4, (register, idx) =>
            {
                register
                .WithValueField(0, 8, name: $"BlockCount{idx}", writeCallback: (_, val) =>
                {
                    BitHelper.ReplaceBits(ref blockCount, width: 8, source: val, destinationPosition: 24 - idx * 8);
                })
                .WithIgnoredBits(8, 24);
            });

            ReaderRegisters.ReaderReset.Define(readerRegistersCollection)
            .WithIgnoredBits(0, 1)     // reset bit, no need for handling this
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);

            ReaderRegisters.ReaderStart.Define(readerRegistersCollection)
            .WithFlag(0, out readerStartFlag, name: "start")
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);

            ReaderRegisters.ReaderDone.Define(readerRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "done", valueProviderCallback: _ => true)
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);

            WriterRegisters.WriterReset.Define(writerRegistersCollection)
            .WithIgnoredBits(0, 1)     // reset bit, no need for handling this
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);

            WriterRegisters.WriterStart.Define(writerRegistersCollection)
            .WithFlag(0, out writerStartFlag, name: "start")
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);

            WriterRegisters.WriterDone.Define(writerRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "done", valueProviderCallback: _ => true)
            .WithReservedBits(1, 7)
            .WithIgnoredBits(8, 24);
        }
예제 #25
0
 public uint ReadDoubleWord(long offset)
 {
     return(xipMode.Value
         ? RegisteredPeripheral.ReadDoubleWord(BitHelper.SetBitsFrom((uint)offset, upperAddress.Value, 24, 8))
         : registers.Read(offset));
 }
예제 #26
0
        protected uint[] ExecuteCommand(uint command, uint args, bool sendInitSequence, bool dataTransfer)
        {
            var response = new uint[4];

            if (RegisteredPeripheral == null)
            {
                return(response);
            }

            switch ((Commands)command)
            {
            case Commands.GoIdleState:
                if (sendInitSequence)
                {
                    response[0] = RegisteredPeripheral.GoIdleState();
                }
                break;

            case Commands.SendOpCond:
            case Commands.IoSendOpCond:
                response[0] = RegisteredPeripheral.SendOpCond();
                break;

            case Commands.SendStatus:
                response[0] = RegisteredPeripheral.SendStatus(dataTransfer);
                break;

            case Commands.SendSdConfiguration:
                SendSdConfigurationValue();
                break;

            case Commands.SetRelativeAddress:
                response[0] = RegisteredPeripheral.SetRelativeAddress();
                break;

            case Commands.SelectDeselectCard:
                response[0] = RegisteredPeripheral.SelectDeselectCard();
                break;

            case Commands.SendExtendedCardSpecificData:
                response[0] = RegisteredPeripheral.SendExtendedCardSpecificData();
                break;

            case Commands.SendCardSpecificData:
                response = RegisteredPeripheral.SendCardSpecificData();
                break;

            case Commands.AllSendCid:
                return(RegisteredPeripheral.AllSendCardIdentification());

            case Commands.AppCommand:
                response[0] = RegisteredPeripheral.AppCommand(args);
                break;

            case Commands.Switch:
                response[0] = RegisteredPeripheral.Switch();
                break;

            case Commands.MmcSendAppOpCode:
                response[0] = RegisteredPeripheral.SendAppOpCode(args);
                break;

            case Commands.ReadMultipleBlocks:
                TransferDataFromCard(args, ByteCount);
                break;

            case Commands.ReadSingleBlock:
                TransferDataFromCard(args, BlockSize);
                break;

            case Commands.WriteMultipleBlocks:
                TransferDataToCard(args, ByteCount);
                break;

            default:
                this.Log(LogLevel.Warning, "Unhandled MMC command: 0x{0:X} with args 0x{1:X}", command, args);
                break;
            }
            return(response);
        }
예제 #27
0
 protected void WriteToCard(uint cardOffset, byte[] data)
 {
     RegisteredPeripheral.WriteData((long)BlockSize * cardOffset, data.Length, data);
 }
예제 #28
0
 protected byte[] ReadFromCard(uint cardOffset, int bytes)
 {
     return(RegisteredPeripheral.ReadData((long)BlockSize * cardOffset, bytes));
 }
예제 #29
0
 public override void Reset()
 {
     RegisteredPeripheral.Reset();
 }
        private void DefineRegisters()
        {
            PhyRegisters.CardDetect.Define(this)
            // note: `true` means *no* card
            .WithFlag(0, FieldMode.Read, name: "card_detect", valueProviderCallback: _ => RegisteredPeripheral == null)
            .WithReservedBits(1, 31);

            CoreRegisters.Argument.Define(coreRegistersCollection)
            .WithValueField(0, 32, out argumentValue, name: "argument");

            CoreRegisters.Command.Define(coreRegistersCollection)
            .WithEnumField <DoubleWordRegister, ResponseType>(0, 2, out responseTypeField, name: "respone_type")
            .WithReservedBits(2, 3)
            .WithEnumField <DoubleWordRegister, TransferType>(5, 2, out transferTypeField, name: "transfer_type")
            .WithReservedBits(7, 1)
            .WithValueField(8, 6, out commandIndexField, name: "command_index")
            .WithReservedBits(14, 18);

            CoreRegisters.IssueCommand.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.WriteOneToClear, name: "issue_command", writeCallback: (_, val) =>
            {
                if (!val)
                {
                    // we are only interested in `true`
                    return;
                }

                if (RegisteredPeripheral == null)
                {
                    this.Log(LogLevel.Warning, "Issued a 0x{0:X} command with 0x{1:X} argument, but there is no SD card attached", commandIndexField.Value, argumentValue.Value);
                    return;
                }

                this.Log(LogLevel.Noisy, "Issuing command #{0}, transfer type is {1}, response type is {2}", commandIndexField.Value, transferTypeField.Value, responseTypeField.Value);

                var resp = RegisteredPeripheral.HandleCommand(commandIndexField.Value, argumentValue.Value).AsByteArray();

                this.Log(LogLevel.Noisy, "Received response of size {0}", resp.Length);
#if DEBUG_PACKETS
                this.Log(LogLevel.Noisy, Misc.PrettyPrintCollectionHex(resp));
#endif

                var expectedResponseLength = 0;

                switch (responseTypeField.Value)
                {
                case ResponseType.Short:
                    expectedResponseLength = 4;
                    break;

                case ResponseType.Long:
                    expectedResponseLength = 16;
                    break;
                }

                if (resp.Length != expectedResponseLength)
                {
                    this.Log(LogLevel.Warning, "Expected response of length {0} bytes, but received {1} bytes", expectedResponseLength, resp.Length);
                    return;
                }

                for (var i = 0; i < resp.Length; i++)
                {
                    responseBuffer[ResponseBufferLength - 1 - i] = resp[i];
                    //responseBuffer[i] = resp[i];
                }

                switch (transferTypeField.Value)
                {
                case TransferType.Read:
                    if (dmaReaderEnabled.Value)
                    {
                        ReadData();
                    }
                    break;

                case TransferType.Write:
                    if (dmaWriterEnabled.Value)
                    {
                        WriteData();
                    }
                    break;
                }
            })
            .WithReservedBits(1, 7)
            .WithReservedBits(8, 24);

            CoreRegisters.Response.DefineMany(coreRegistersCollection, ResponseBufferLength / 4, (register, idx) =>
            {
                register
                .WithValueField(0, 8, FieldMode.Read, name: $"Response{(4 * idx + 0)}", valueProviderCallback: _ => responseBuffer[4 * idx + 3])
                .WithValueField(8, 8, FieldMode.Read, name: $"Response{(4 * idx + 1)}", valueProviderCallback: _ => responseBuffer[4 * idx + 2])
                .WithValueField(16, 8, FieldMode.Read, name: $"Response{(4 * idx + 2)}", valueProviderCallback: _ => responseBuffer[4 * idx + 1])
                .WithValueField(24, 8, FieldMode.Read, name: $"Response{(4 * idx + 3)}", valueProviderCallback: _ => responseBuffer[4 * idx + 0]);
            });

            CoreRegisters.CommandEvent.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "cmddone", valueProviderCallback: _ => true)
            .WithTag("cerrwrite", 1, 1)
            .WithTag("cerrtimeout", 2, 1)
            .WithTag("cerrcrc", 3, 1)
            .WithReservedBits(4, 28);

            CoreRegisters.DataEvent.Define(coreRegistersCollection)
            .WithFlag(0, FieldMode.Read, name: "datadone", valueProviderCallback: _ => true)
            .WithTag("derrwrite", 1, 1)
            .WithTag("derrtimeout", 2, 1)
            .WithTag("derrcrc", 3, 1)
            .WithReservedBits(4, 28);

            CoreRegisters.BlockSize.Define(coreRegistersCollection)
            .WithValueField(0, 10, out blockSize, name: "BlockSize")
            .WithReservedBits(10, 22);

            CoreRegisters.BlockCount.Define(coreRegistersCollection)
            .WithValueField(0, 32, out blockCount, name: "BlockSize");

            ReaderRegisters.DmaBase.DefineMany(readerRegistersCollection, 2, (register, idx) =>
            {
                register
                .WithValueField(0, 32, name: $"ReaderAddress{idx}",
                                writeCallback: (_, val) => BitHelper.ReplaceBits(ref readerAddress, val, width: 32, destinationPosition: 32 - idx * 32),
                                valueProviderCallback: _ => (uint)BitHelper.GetValue(readerAddress, offset: 32 - idx * 32, size: 32));
            });

            ReaderRegisters.DmaLength.Define(readerRegistersCollection)
            .WithValueField(0, 32, out readerLength, name: "ReaderLength");

            ReaderRegisters.DmaEnable.Define(readerRegistersCollection)
            .WithFlag(0, out dmaReaderEnabled, name: "enable")
            .WithReservedBits(1, 31);

            ReaderRegisters.DmaDone.Define(readerRegistersCollection)
            .WithFlag(0, name: "done", valueProviderCallback: _ => true)
            .WithReservedBits(1, 31);

            ReaderRegisters.DmaLoop.Define(readerRegistersCollection)
            .WithTag("loop", 0, 1)
            .WithReservedBits(1, 31);

            WriterRegisters.DmaBase.DefineMany(writerRegistersCollection, 2, (register, idx) =>
            {
                register
                .WithValueField(0, 32, name: $"WriterAddress{idx}",
                                writeCallback: (_, val) => BitHelper.ReplaceBits(ref writerAddress, val, width: 32, destinationPosition: 32 - idx * 32),
                                valueProviderCallback: _ => (uint)BitHelper.GetValue(writerAddress, offset: 32 - idx * 32, size: 32));
            });

            WriterRegisters.DmaLength.Define(writerRegistersCollection)
            .WithValueField(0, 32, out writerLength, name: "WriterLength");

            WriterRegisters.DmaEnable.Define(writerRegistersCollection)
            .WithFlag(0, out dmaWriterEnabled, name: "enable")
            .WithReservedBits(1, 31);

            WriterRegisters.DmaDone.Define(writerRegistersCollection)
            .WithFlag(0, name: "done", valueProviderCallback: _ => true)
            .WithReservedBits(1, 31);

            WriterRegisters.DmaLoop.Define(writerRegistersCollection)
            .WithTag("loop", 0, 1)
            .WithReservedBits(1, 31);
        }