From 9053b459e88d6c308bf85736802ee77e13228e23 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 26 Nov 2019 07:45:01 +0800 Subject: [PATCH] current wip of betrusted Signed-off-by: Sean Cross --- fb.cs | 53 +++++++------ kbd_soc.cs | 108 ++++++++++++++++++++++++++ spi_ec.cs | 193 +++++++++++++++++++++++++++++++++++++++++++++++ spi_soc.cs | 184 ++++++++++++++++++++++++++++++++++++++++++++ test.repl | 8 +- test.resc | 10 ++- ticktimer_soc.cs | 82 ++++++++++++++++++++ 7 files changed, 609 insertions(+), 29 deletions(-) create mode 100644 kbd_soc.cs create mode 100644 spi_ec.cs create mode 100644 spi_soc.cs create mode 100644 ticktimer_soc.cs diff --git a/fb.cs b/fb.cs index 69732ae..74009f6 100644 --- a/fb.cs +++ b/fb.cs @@ -25,10 +25,10 @@ namespace Antmicro.Renode.Peripherals.Video RegistersCollection = new DoubleWordRegisterCollection(this); Reconfigure(336, 536, PixelFormat.RGB565, false); - for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; - DoRepaint(); - DefineRegisters(); - Reset(); + for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; + DoRepaint(); + DefineRegisters(); + Reset(); } public void WriteDoubleWord(long address, uint value) @@ -46,40 +46,43 @@ namespace Antmicro.Renode.Peripherals.Video RegistersCollection.Reset(); } - public long Size => 0x800; + public long Size { get{ return 0x800; }} public DoubleWordRegisterCollection RegistersCollection { get; private set; } protected override void Repaint() { - var newbuf = new Byte[44*Height]; + var newbuf = new Byte[44*Height]; machine.SystemBus.ReadBytes(bufferAddress, newbuf.Length, newbuf, 0); - for (int y = 0; y < Height; y++) { - if (!updateDirty || updateAll || ((newbuf[y*44+0x2a] & 0x1) == 0x1)) for (int x = 0; x < Width; x++) { - if (((newbuf[((x+y*44*8))/8] >> (x%8))&1) > 0) { - buffer[2*(x+y*Width)] = 0xFF; - buffer[2*(x+y*Width)+1] = 0xFF; - } else { - buffer[2*(x+y*Width)] = 0x0; - buffer[2*(x+y*Width)+1] = 0x0; - } - } - } + for (int y = 0; y < Height; y++) { + if (!updateDirty || updateAll || ((newbuf[y*44+0x2a] & 0x1) == 0x1)) for (int x = 0; x < Width; x++) { + if (((newbuf[((x+y*44*8))/8] >> (x%8))&1) > 0) { + buffer[2*(x+y*Width)] = 0xFF; + buffer[2*(x+y*Width)+1] = 0xFF; + } else { + buffer[2*(x+y*Width)] = 0x0; + buffer[2*(x+y*Width)+1] = 0x0; + } + } + } } private void DefineRegisters() { Registers.COMMAND.Define(this) .WithValueField(0, 32, writeCallback: (_, val) => - { - updateDirty = (val & 0x1) == 0x1; - updateAll = (val & 0x10) == 0x10; - DoRepaint(); - }) + { + updateDirty = (val & 0x1) == 0x1; + updateAll = (val & 0x2) == 0x2; + DoRepaint(); + }) + ; + Registers.BUSY.Define(this) + .WithValueField(0, 32, valueProviderCallback: _ => { return 0; }) ; } - private bool updateDirty = false; - private bool updateAll = false; + private bool updateDirty = false; + private bool updateAll = false; private uint bufferAddress = 0xB0000000; @@ -88,7 +91,7 @@ namespace Antmicro.Renode.Peripherals.Video private enum Registers { COMMAND = 0x0, - BUSY = 0x04 + BUSY = 0x04 } } } diff --git a/kbd_soc.cs b/kbd_soc.cs new file mode 100644 index 0000000..e53d89c --- /dev/null +++ b/kbd_soc.cs @@ -0,0 +1,108 @@ +// +// Copyright (c) 2010 - 2019 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// + +using System; +using System.Linq; +using Antmicro.Renode.Backends.Display; +using Antmicro.Renode.Core; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Logging; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Peripherals.Memory; +using Antmicro.Renode.Utilities; + +namespace Antmicro.Renode.Peripherals.Input +{ + public class betrusted_kbd : IKeyboard, IDoubleWordPeripheral, IProvidesRegisterCollection, IKnownSize + { + public betrusted_kbd(Machine machine) : base(machine) + { + this.machine = machine; + + RegistersCollection = new DoubleWordRegisterCollection(this); + for (int i = 0; i < buffer.Length; i++) buffer[i] = 0; + // DefineRegisters(); + Reset(); + } + + public void WriteDoubleWord(long address, uint value) + { + RegistersCollection.Write(address, value); + } + + public uint ReadDoubleWord(long offset) + { + return RegistersCollection.Read(offset); + } + + public override void Reset() + { + RegistersCollection.Reset(); + } + + public long Size { get{ return 0x800; }} + public DoubleWordRegisterCollection RegistersCollection { get; private set; } + + // protected override void Repaint() + // { + // var newbuf = new Byte[44*Height]; + // machine.SystemBus.ReadBytes(bufferAddress, newbuf.Length, newbuf, 0); + // for (int y = 0; y < Height; y++) { + // if (!updateDirty || updateAll || ((newbuf[y*44+0x2a] & 0x1) == 0x1)) for (int x = 0; x < Width; x++) { + // if (((newbuf[((x+y*44*8))/8] >> (x%8))&1) > 0) { + // buffer[2*(x+y*Width)] = 0xFF; + // buffer[2*(x+y*Width)+1] = 0xFF; + // } else { + // buffer[2*(x+y*Width)] = 0x0; + // buffer[2*(x+y*Width)+1] = 0x0; + // } + // } + // } + // } + + // private void DefineRegisters() + // { + // Registers.COMMAND.Define(this) + // .WithValueField(0, 32, writeCallback: (_, val) => + // { + // updateDirty = (val & 0x1) == 0x1; + // updateAll = (val & 0x10) == 0x10; + // DoRepaint(); + // }) + // ; + // } + private readonly Machine machine; + + private enum Registers + { + ROW0DAT1 = 0x0, + ROW0DAT0 = 0x4, + ROW1DAT1 = 0x8, + ROW1DAT0 = 0xc, + ROW2DAT1 = 0x10, + ROW2DAT0 = 0x14, + ROW3DAT1 = 0x18, + ROW3DAT0 = 0x1c, + ROW4DAT1 = 0x20, + ROW4DAT0 = 0x24, + ROW5DAT1 = 0x28, + ROW5DAT0 = 0x2c, + ROW6DAT1 = 0x30, + ROW6DAT0 = 0x34, + ROW7DAT1 = 0x38, + ROW7DAT0 = 0x3c, + ROW8DAT1 = 0x40, + ROW8DAT0 = 0x44, + EV_STATUS = 0x48, + EV_PENDING = 0x4c, + EV_ENABLE = 0x50, + ROWCHANGE1 = 0x54, + ROWCHANGE0 = 0x58, + BUSY = 0x04 + } + } +} diff --git a/spi_ec.cs b/spi_ec.cs new file mode 100644 index 0000000..c9c2780 --- /dev/null +++ b/spi_ec.cs @@ -0,0 +1,193 @@ +// +// 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 STM32SPI : NullRegistrationPointPeripheralContainer, IWordPeripheral, IDoubleWordPeripheral, IBytePeripheral, IKnownSize + { + public STM32SPI(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 control2 = new DoubleWordRegister(this); + txBufferEmptyInterruptEnable = control2.DefineFlagField(7); + rxBufferNotEmptyInterruptEnable = control2.DefineFlagField(6); + txDmaEnable = control2.DefineFlagField(1); + rxDmaEnable = control2.DefineFlagField(0, writeCallback: (_,__) => Update()); + + var registerDictionary = new Dictionary + { + { (long)Registers.Control1, new DoubleWordRegister(this).WithValueField(3,3, name:"Baud").WithFlag(2, name:"Master") + .WithFlag(8, name:"SSI").WithFlag(9, name:"SSM").WithFlag(6, changeCallback: (oldValue, newValue) => { + if(!newValue) + { + IRQ.Unset(); + } + }, name:"SpiEnable")}, + {(long)Registers.Status, new DoubleWordRegister(this, 2).WithFlag(1, FieldMode.Read, name:"TXE").WithFlag(0, FieldMode.Read, valueProviderCallback: _ => receiveBuffer.Count != 0 , name:"RXNE")}, + {(long)Registers.CRCPolynomial, new DoubleWordRegister(this, 7).WithValueField(0, 16, name:"CRCPoly") }, + {(long)Registers.I2SConfiguration, new DoubleWordRegister(this, 0).WithFlag(10, FieldMode.Read | FieldMode.WriteOneToClear, writeCallback: (oldValue, newValue) => { + // write one to clear to keep this bit 0 + if(newValue) + { + this.Log(LogLevel.Warning, "Trying to enable not supported I2S mode."); + } + }, name:"I2SE")}, + { (long)Registers.Control2, control2 } + }; + registers = new DoubleWordRegisterCollection(this, registerDictionary); + } + + private DoubleWordRegisterCollection registers; + private IFlagRegisterField txBufferEmptyInterruptEnable, rxBufferNotEmptyInterruptEnable, txDmaEnable, rxDmaEnable; + + private readonly Queue receiveBuffer; + + private enum Registers + { + Control1 = 0x0, // SPI_CR1, + Control2 = 0x4, // SPI_CR2 + Status = 0x8, // SPI_SR + Data = 0xC, // SPI_DR + CRCPolynomial = 0x10, // SPI_CRCPR + I2SConfiguration = 0x1C // SPI_I2SCFGR + } + } +} diff --git a/spi_soc.cs b/spi_soc.cs new file mode 100644 index 0000000..0a1c2e6 --- /dev/null +++ b/spi_soc.cs @@ -0,0 +1,184 @@ +// +// 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, + } + } +} diff --git a/test.repl b/test.repl index 7cd2e3c..17c2a55 100644 --- a/test.repl +++ b/test.repl @@ -2,7 +2,7 @@ cpu: CPU.VexRiscv @ sysbus cpuType: "rv32gc" mem: Memory.MappedMemory @ sysbus 0x20500000 - size: 0x10000 + size: 0x80000 mem2: Memory.MappedMemory @ sysbus 0x00001000 size: 0x40000 @@ -15,3 +15,9 @@ fbmem: Memory.MappedMemory @ sysbus 0xB0000000 fb: Video.fb @ sysbus 0xF0005000 +bsocspi: SPI.BSOCSPI @ sysbus 0xF0005800 + +bsocticktimer: Timers.BSOCTickTimer @ sysbus 0xF0007800 + periodInMs: 1 + +//betrusted_kbd: Input.betrusted_kbd @ 0xF0009000 \ No newline at end of file diff --git a/test.resc b/test.resc index c702548..dc6daeb 100644 --- a/test.resc +++ b/test.resc @@ -1,7 +1,11 @@ mach create i @fb.cs +i @spi_soc.cs +i @ticktimer_soc.cs +#i @kbd.cs using sysbus -machine LoadPlatformDescription "test.repl" -sysbus ApplySVD @soc.svd -sysbus LoadELF @betrusted-soc +machine LoadPlatformDescription $ORIGIN/test.repl +sysbus ApplySVD $ORIGIN/Betrusted\ SoC.svd +sysbus LoadELF "D:/Code/Betrusted/betrusted-soc/sw/target/riscv32imac-unknown-none-elf/debug/betrusted-soc" showAnalyzer sysbus.fb +machine StartGdbServer 3333 true \ No newline at end of file diff --git a/ticktimer_soc.cs b/ticktimer_soc.cs new file mode 100644 index 0000000..a0b9472 --- /dev/null +++ b/ticktimer_soc.cs @@ -0,0 +1,82 @@ +// +// 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.Core; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Time; +using Antmicro.Renode.Logging; +using System.Threading; + +namespace Antmicro.Renode.Peripherals.Timers +{ + public class BSOCTickTimer : IDoubleWordPeripheral, IKnownSize + { + public BSOCTickTimer(ulong periodInMs, Machine machine) + { + running = true; + machine.ClockSource.AddClockEntry(new ClockEntry(periodInMs, ClockEntry.FrequencyToRatio(this, 1000), OnTick, this, String.Empty)); + } + + public long Size + { + get + { + return 0x400; + } + } + + public virtual uint ReadDoubleWord(long offset) + { + if (offset == 0) + return 0; + else if (offset == 4) + offset = 40; + else if (offset == 8) + offset = 32; + else if (offset == 12) + offset = 24; + else if (offset == 16) + offset = 16; + else if (offset == 20) + offset = 8; + else if (offset == 24) + offset = 0; + else { + this.LogUnhandledRead(offset); + return 0; + } + return (uint)(Interlocked.CompareExchange(ref counter, 0, 0) >> (int)offset); + } + + public virtual void WriteDoubleWord(long offset, uint value) + { + if (offset == 0) { + if ((value & 1) == 1) + Interlocked.Exchange(ref counter, 0); + running = ((value & 2) != 2); + return; + } + this.LogUnhandledWrite(offset, value); + } + + public virtual void Reset() + { + Interlocked.Exchange(ref counter, 0); + } + + private void OnTick() + { + if (running) + Interlocked.Increment(ref counter); + } + + private long counter; + private bool running; + } +} +