185 lines
5.8 KiB
C#
185 lines
5.8 KiB
C#
//
|
||
// 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<ISPIPeripheral>, IWordPeripheral, IDoubleWordPeripheral, IBytePeripheral, IKnownSize
|
||
{
|
||
public BSOCSPI(Machine machine) : base(machine)
|
||
{
|
||
// receiveBuffer = new Queue<byte>();
|
||
// 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, DoubleWordRegister>
|
||
{
|
||
{ (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,
|
||
}
|
||
}
|
||
}
|