blob: 0d42cd949768e7caef1877491d8b543e746a25d3 [file] [log] [blame]
//
// Copyright (c) 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Peripherals.Sensor;
namespace Antmicro.Renode.Peripherals.Sensors
{
public class DoubleBufferDMA: NullRegistrationPointPeripheralContainer<ICPIPeripheral>, IDoubleWordPeripheral, IKnownSize, IProvidesRegisterCollection<DoubleWordRegisterCollection>, IGPIOReceiver
{
public DoubleBufferDMA(Machine machine) : base(machine)
{
IRQ = new GPIO();
Trigger = new GPIO();
RegistersCollection = new DoubleWordRegisterCollection(this);
DefineRegisters();
}
public override void Reset()
{
IRQ.Unset();
Trigger.Unset();
RegistersCollection.Reset();
}
public uint ReadDoubleWord(long offset)
{
return RegistersCollection.Read(offset);
}
public void WriteDoubleWord(long offset, uint value)
{
RegistersCollection.Write(offset, value);
}
public void OnGPIO(int number, bool value) {
if (!value) {
return;
}
if(RegisteredPeripheral == null)
{
this.Log(LogLevel.Warning, "Tried to enable the controller, but there is no device connected");
return;
}
var data = RegisteredPeripheral.ReadFrame();
var size = horizontalSize.Value * verticalSize.Value;
// Restore bottom 3 bits of address.
var addr1 = rxBuffer1Address.Value << 3;
if((ulong)data.Length != size)
{
this.Log(LogLevel.Warning, "Received {0} bytes from the device, but RX DMA stream is configured for {1} bytes. This might indicate problems in the driver", data.Length, size);
}
Machine.SystemBus.WriteBytes(data, addr1);
// TODO(jesionowski): re-enable double buffer once sw supports it
// if(use_buffer1) {
// Machine.SystemBus.WriteBytes(data, rxBuffer1Address.Value);
// } else {
// Machine.SystemBus.WriteBytes(data, rxBuffer2Address.Value);
// }
use_buffer1 = !use_buffer1;
IRQ.Blink();
}
public DoubleWordRegisterCollection RegistersCollection { get; }
public GPIO Trigger { get; }
public GPIO IRQ { get; }
public long Size => 0x1000;
private void DefineRegisters()
{
Registers.HorizontalSize.Define(this)
.WithValueField(0, 15, out horizontalSize, name: "HORIZONTAL_SIZE")
;
Registers.VerticalSize.Define(this)
.WithValueField(0, 14, out verticalSize, name: "VERTICAL_SIZE")
;
Registers.RxBufferBaseAddress1.Define(this)
.WithValueField(3, 29, out rxBuffer1Address, name: "ADDR1")
;
Registers.RxBufferBaseAddress2.Define(this)
.WithValueField(3, 29, out rxBuffer2Address, name: "ADDR2")
;
}
private bool use_buffer1 = true;
private IValueRegisterField rxBuffer1Address;
private IValueRegisterField rxBuffer2Address;
private IValueRegisterField horizontalSize;
private IValueRegisterField verticalSize;
private enum Registers
{
HorizontalSize = 0x410,
VerticalSize = 0x414,
RxBufferBaseAddress1 = 0xe08,
RxBufferBaseAddress2 = 0xf30,
}
}
}