| // |
| // 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, |
| } |
| } |
| } |