// // Copyright (c) 2010-2018 Antmicro // Copyright (c) 2011-2015 Realtime Embedded // // This file is licensed under the MIT License. // Full license text is available in 'licenses/MIT.txt'. // using System; using Antmicro.Renode.Peripherals.Bus; using Antmicro.Renode.Logging; using Antmicro.Renode.Core.Structure; using System.Collections.Generic; using Antmicro.Renode.Core; using Antmicro.Renode.Core.Structure.Registers; namespace Antmicro.Renode.Peripherals.SPI { public sealed class BSOCSPI : NullRegistrationPointPeripheralContainer, IWordPeripheral, IDoubleWordPeripheral, IBytePeripheral, IKnownSize { public BSOCSPI(Machine machine) : base(machine) { // receiveBuffer = new Queue(); // IRQ = new GPIO(); SetupRegisters(); Reset(); } public byte ReadByte(long offset) { // byte interface is there for DMA if(offset % 4 == 0) { return (byte)ReadDoubleWord(offset); } this.LogUnhandledRead(offset); return 0; } public void WriteByte(long offset, byte value) { if(offset % 4 == 0) { WriteDoubleWord(offset, (uint)value); } else { this.LogUnhandledWrite(offset, value); } } public ushort ReadWord(long offset) { return (ushort)ReadDoubleWord(offset); } public void WriteWord(long offset, ushort value) { WriteDoubleWord(offset, (uint)value); } public uint ReadDoubleWord(long offset) { // switch((Registers)offset) // { // case Registers.Data: // return HandleDataRead(); // default: return registers.Read(offset); // } } public void WriteDoubleWord(long offset, uint value) { // switch((Registers)offset) // { // case Registers.Data: // HandleDataWrite(value); // break; // default: registers.Write(offset, value); // break; // } } public override void Reset() { // lock(receiveBuffer) // { // receiveBuffer.Clear(); // } registers.Reset(); } public long Size { get { return 0x400; } } // public GPIO IRQ // { // get; // private set; // } // private uint HandleDataRead() // { // IRQ.Unset(); // lock(receiveBuffer) // { // if(receiveBuffer.Count > 0) // { // var value = receiveBuffer.Dequeue(); // return value; // TODO: verify if Update should be called // } // this.Log(LogLevel.Warning, "Trying to read data register while no data has been received."); // return 0; // } // } // private void HandleDataWrite(uint value) // { // IRQ.Unset(); // lock(receiveBuffer) // { // var peripheral = RegisteredPeripheral; // if(peripheral == null) // { // this.Log(LogLevel.Warning, "SPI transmission while no SPI peripheral is connected."); // receiveBuffer.Enqueue(0x0); // return; // } // receiveBuffer.Enqueue(peripheral.Transmit((byte)value)); // currently byte mode is the only one we support // this.NoisyLog("Transmitted 0x{0:X}, received 0x{1:X}.", value, receiveBuffer.Peek()); // } // Update(); // } private void Update() { // TODO: verify this condition // IRQ.Set(txBufferEmptyInterruptEnable.Value || rxBufferNotEmptyInterruptEnable.Value || txDmaEnable.Value || rxDmaEnable.Value); } private void SetupRegisters() { var registerDictionary = new Dictionary { { (long)Registers.TX1, new DoubleWordRegister(this, 0).WithValueField(0, 8, name:"TX1")}, { (long)Registers.TX0, new DoubleWordRegister(this, 0).WithValueField(0, 8, name:"TX0")}, { (long)Registers.RX1, new DoubleWordRegister(this, 0).WithValueField(0, 8, name:"RX1")}, { (long)Registers.RX0, new DoubleWordRegister(this, 0).WithValueField(0, 8, name:"RX0")}, { (long)Registers.CONTROL, new DoubleWordRegister(this) .WithFlag(0, FieldMode.Write, name:"CLR_DONE") .WithFlag(1, FieldMode.Write, name:"GO", changeCallback: (oldValue, newValue) => { // Execute operation here }) .WithFlag(2, FieldMode.Write, name:"INTENA") }, {(long)Registers.STATUS, new DoubleWordRegister(this, 2) .WithFlag(0, FieldMode.Read, name:"TIP") .WithFlag(1, FieldMode.Read, name: "DONE", valueProviderCallback: (_) => {doneBit = !doneBit; return doneBit; }) }, }; registers = new DoubleWordRegisterCollection(this, registerDictionary); } private bool doneBit; private DoubleWordRegisterCollection registers; private enum Registers { TX1 = 0x00, TX0 = 0x04, RX1 = 0x08, RX0 = 0x0c, CONTROL = 0x10, STATUS = 0x14, } } }