From ed6199f69f22e99ce14ab9f0fad3e0edf454777c Mon Sep 17 00:00:00 2001 From: guentherweber <38313940+guentherweber@users.noreply.github.com> Date: Sun, 5 Dec 2021 14:06:35 +0100 Subject: [PATCH 1/2] add SAMD20 peripherals: - UART - I2C Master - Timer - GPIO - ADC --- .../Peripherals/Analog/SAMD20_ADC.cs | 337 ++++++++++++++ .../Peripherals/GPIOPort/SAMD20_GPIO.cs | 375 ++++++++++++++++ .../Peripherals/I2C/SAMD20_I2C_Master.cs | 345 +++++++++++++++ .../Peripherals/Timers/SAMD20_Timer.cs | 412 ++++++++++++++++++ .../Peripherals/UART/SAMD20_UART.cs | 351 +++++++++++++++ 5 files changed, 1820 insertions(+) create mode 100644 src/Emulator/Peripherals/Peripherals/Analog/SAMD20_ADC.cs create mode 100644 src/Emulator/Peripherals/Peripherals/GPIOPort/SAMD20_GPIO.cs create mode 100644 src/Emulator/Peripherals/Peripherals/I2C/SAMD20_I2C_Master.cs create mode 100644 src/Emulator/Peripherals/Peripherals/Timers/SAMD20_Timer.cs create mode 100644 src/Emulator/Peripherals/Peripherals/UART/SAMD20_UART.cs diff --git a/src/Emulator/Peripherals/Peripherals/Analog/SAMD20_ADC.cs b/src/Emulator/Peripherals/Peripherals/Analog/SAMD20_ADC.cs new file mode 100644 index 000000000..3a8573065 --- /dev/null +++ b/src/Emulator/Peripherals/Peripherals/Analog/SAMD20_ADC.cs @@ -0,0 +1,337 @@ +// +// Copyright (c) 2010-2018 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System.Collections.Generic; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using System; +using Antmicro.Migrant; + + +namespace Antmicro.Renode.Peripherals.Analog +{ + + [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] + public class SAMD20_ADC : BasicDoubleWordPeripheral, IKnownSize, IWordPeripheral, IBytePeripheral + { + + + public SAMD20_ADC(Machine machine) : base(machine) + { + IRQ = new GPIO(); + + // Create a list of adc values + adc_values = new List(); + + for (int i=0; i < NumberOfADCs; i++) + { + adc_values.Add(0x0000); + } + + DefineRegisters(); + } + + + + + + public long Size => 0x100; + + public GPIO IRQ { get; private set; } + + + public override void Reset() + { + base.Reset(); + UpdateInterrupts(); + } + + public ushort ReadWord(long offset) + { + return (ushort)ReadDoubleWord(offset); + } + + public void WriteWord(long offset, ushort value) + { + WriteDoubleWord(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte)ReadDoubleWord(offset); + } + + public void WriteByte(long offset, byte value) + { + WriteDoubleWord(offset, value); + } + + public void WriteAdcValue(int offset, ushort value) + { + if (offset < NumberOfADCs) + adc_values[offset] = value; + } + + public ushort ReadAdcValue(int offset) + { + if (offset < NumberOfADCs) + return adc_values[offset]; + return 0; + } + + + + + private const int NumberOfADCs = 32; + + private IFlagRegisterField RESRDY; + private IFlagRegisterField RESRDY_Clear; + private IFlagRegisterField RESRDY_Set; + + private IFlagRegisterField OVERRUN; + private IFlagRegisterField OVERRUN_Clear; + private IFlagRegisterField OVERRUN_Set; + + private IFlagRegisterField WINMON; + private IFlagRegisterField WINMON_Clear; + private IFlagRegisterField WINMON_Set; + + private IFlagRegisterField SYNCRDY; + private IFlagRegisterField SYNCRDY_Clear; + private IFlagRegisterField SYNCRDY_Set; + + private IFlagRegisterField START; + private IValueRegisterField ChannelIndex; + + private List adc_values; + + private void DefineRegisters() + { + + Register.ControlA.Define(this, 0x00, "ControlA") + .WithValueField(0, 8, name: "unused"); ; + + Register.RefCtrl.Define(this, 0x00, "RefCtrl") + .WithValueField(0, 8, name: "unused"); ; + + Register.AvgCtrl.Define(this, 0x00, "AvgCtrl") + .WithValueField(0, 8, name: "unused"); ; + + Register.SampCtrl.Define(this, 0x00, "SampCtrl") + .WithValueField(0, 8, name: "unused"); ; + + Register.ControlB.Define(this, 0x00, "ControlB") + .WithTag("Reserved", 0, 16); + + Register.WinCtrl.Define(this, 0x00, "WinCtrl") + .WithValueField(0, 8, name: "unused"); ; + + Register.SWTrig.Define(this, 0x00, "SWTrig") + .WithTaggedFlag("FLUSH", 0) + .WithFlag(1, out START, FieldMode.WriteOneToClear | FieldMode.Read, + writeCallback: (_, value) => + { + if (value == true) + { + RESRDY.Value = true; + UpdateInterrupts(); + } + }, name: "START") + .WithTag("Reserved", 2, 6); + + Register.InputCtrl.Define(this, 0x00, "InputCtrl") + .WithValueField(0, 5, out ChannelIndex) + .WithTag("Reserved", 5, 27); + + Register.EvCtrl.Define(this, 0x00, "EvCtrl") + .WithValueField(0, 8, name: "unused"); ; + + Register.IntenClr.Define(this, 0x00, "IntenClr") + .WithFlag(0, out RESRDY_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + RESRDY_Set.Value = false; + UpdateInterrupts(); + } + }, name: "RESRDY Interrupt Enable") + .WithFlag(1, out OVERRUN_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + OVERRUN_Set.Value = false; + UpdateInterrupts(); + } + }, name: "OVERRUN interrupt is disabled.") + .WithFlag(2, out WINMON_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + WINMON_Set.Value = false; + UpdateInterrupts(); + } + }, name: "WINMON Interrupt is diabled") + .WithFlag(3, out SYNCRDY_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + SYNCRDY_Set.Value = false; + UpdateInterrupts(); + } + }, name: "Int Disable SYNCRDY") + .WithTag("RESERVED", 4, 4); + + Register.IntenSet.Define(this, 0x00, "IntenSet") + .WithFlag(0, out RESRDY_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + RESRDY_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "RESRDY Interrupt Enable") + .WithFlag(1, out OVERRUN_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + OVERRUN_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "OVERRUN interrupt is disabled.") + .WithFlag(2, out WINMON_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + WINMON_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "WINMON Interrupt Enable") + .WithFlag(3, out SYNCRDY_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + SYNCRDY_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "SYNCRDY Interrupt Enable") + .WithTag("RESERVED", 4, 4); + + + Register.IntFlag.Define(this, 0x00, "IntenFlag") + .WithFlag(0, out RESRDY, FieldMode.WriteOneToClear | FieldMode.Read, name: "RESRDY") + .WithFlag(1, out OVERRUN, FieldMode.WriteOneToClear | FieldMode.Read, name: "OVERRUN") + .WithFlag(2, out WINMON, FieldMode.WriteOneToClear | FieldMode.Read, name: "WINMON") + .WithFlag(3, out SYNCRDY, FieldMode.WriteOneToClear | FieldMode.Read, name: "SYNCRDY") + .WithTag("RESERVED", 4, 4); + + Register.Status.Define(this, 0x00, "Status") + .WithValueField(0, 8, name: "unused"); ; + + Register.Result.Define(this, 0x00, "Result") + .WithValueField(0, 16, + valueProviderCallback: _ => + { + WINMON.Value = false; + RESRDY.Value = false; + UpdateInterrupts(); + this.Log(LogLevel.Info, "Read ADC result channel: {0} value: {1}", ChannelIndex.Value, adc_values[(int)ChannelIndex.Value]); + return adc_values[(int)ChannelIndex.Value]; + + }, name: "RESULT"); + + Register.WinLt.Define(this, 0x00, "WinLt") + .WithTag("Reserved", 0, 16); + + Register.WinUt.Define(this, 0x00, "WinUt") + .WithTag("Reserved", 0, 16); + + Register.GainCorr.Define(this, 0x00, "GainCorr") + .WithTag("Reserved", 0, 16); + + Register.OffsetCorr.Define(this, 0x00, "OffsetCorr") + .WithTag("Reserved", 0, 16); + + Register.Calibration.Define(this, 0x00, "Calibration") + .WithTag("Reserved", 0, 16); + + Register.DbgCtrl.Define(this, 0x00, "DbgCtrl") + .WithValueField(0, 8, name: "unused"); ; + + + + } + + private void UpdateInterrupts() + { + bool RESRDY_IntActive = false; + bool OVERRUN_IntActive = false; + bool WINMON_IntActive = false; + bool SYNCRDY_IntActive = false; + + if (RESRDY_Set.Value & RESRDY.Value) + { + RESRDY_IntActive = true; + } + + + if (OVERRUN_Set.Value & OVERRUN.Value) + { + OVERRUN_IntActive = true; + } + + if (WINMON_Set.Value & WINMON.Value) + { + WINMON_IntActive = true; + } + + if (SYNCRDY_Set.Value & SYNCRDY.Value) + { + SYNCRDY_IntActive = true; + } + // Set or Clear Interrupt + IRQ.Set(SYNCRDY_IntActive | WINMON_IntActive | OVERRUN_IntActive | RESRDY_IntActive); + + } + + + + + private enum Register : long + { + ControlA = 0x00, + RefCtrl = 0x01, + AvgCtrl = 0x02, + SampCtrl = 0x03, + ControlB = 0x04, + WinCtrl = 0x08, + SWTrig = 0x0C, + InputCtrl = 0x10, + EvCtrl = 0x14, + IntenClr = 0x16, + IntenSet = 0x17, + IntFlag = 0x18, + Status = 0x19, + Result = 0x1A, + WinLt = 0x1C, + WinUt = 0x20, + GainCorr = 0x24, + OffsetCorr = 0x26, + Calibration = 0x28, + DbgCtrl = 0x2A + } + } +} + diff --git a/src/Emulator/Peripherals/Peripherals/GPIOPort/SAMD20_GPIO.cs b/src/Emulator/Peripherals/Peripherals/GPIOPort/SAMD20_GPIO.cs new file mode 100644 index 000000000..84135cb09 --- /dev/null +++ b/src/Emulator/Peripherals/Peripherals/GPIOPort/SAMD20_GPIO.cs @@ -0,0 +1,375 @@ + +// +// Copyright (c) 2010-2018 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System.Collections.Generic; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using System; +using Antmicro.Migrant; +using Antmicro.Renode.Peripherals.GPIOPort; + +namespace Antmicro.Renode.Peripherals.GPIOPort +{ + + [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] + public class SAMD20_GPIO : BaseGPIOPort, IKnownSize, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral + { + + + public SAMD20_GPIO(Machine machine) : base(machine, NumberOfPins) + { + dwordregisters = new DoubleWordRegisterCollection(this); + + DefineRegisters(); + } + + + + + + public long Size => 0x100; + + + public override void OnGPIO(int number, bool value) + { + base.OnGPIO(number, value); + Connections[number].Set(value); + uint val = (uint)0x01 << number; + + if (value) + { + IN.Value |= val; + } + else + { + IN.Value &= ~val; + } + } + + private void UpdateState() + { + var value = OUT.Value; + for (var i = 0; i < NumberOfPins; i++) + { + var state = ((value & 1u) == 1); + + State[i] = state; + if (state) + { + Connections[i].Set(); + } + else + { + Connections[i].Unset(); + } + + value >>= 1; + } + } + + + + public override void Reset() + { + base.Reset(); + } + public ushort ReadWord(long offset) + { + return (ushort)ReadDoubleWord(offset); + } + + public void WriteWord(long offset, ushort value) + { + WriteDoubleWord(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte)ReadDoubleWord(offset); + } + + public void WriteByte(long offset, byte value) + { + WriteDoubleWord(offset, value); + } + + + + private readonly DoubleWordRegisterCollection dwordregisters; + private IValueRegisterField DIRSET; + private IValueRegisterField DIR; + private IValueRegisterField DIRCLR; + + private IValueRegisterField OUTSET; + private IValueRegisterField OUT; + private IValueRegisterField OUTCLR; + + private IValueRegisterField IN; + + private const int NumberOfPins = 32; + + private enum Registers : long + { + DIR = 0x00, + DIRCLR = 0x04, + DIRSET = 0x08, + DIRTGL = 0x0C, + OUT = 0x10, + OUTCLR = 0x14, + OUTSET = 0x18, + OUTTGL = 0x1C, + IN = 0x20, + CTRL = 0x24, + WRCONFIG = 0x28, + PMUX0 = 0x30, + PMUX1 = 0x31, + PMUX2 = 0x32, + PMUX3 = 0x33, + PMUX4 = 0x34, + PMUX5 = 0x35, + PMUX6 = 0x36, + PMUX7 = 0x37, + PMUX8 = 0x38, + PMUX9 = 0x39, + PMUX10 = 0x3A, + PMUX11 = 0x3B, + PMUX12 = 0x3C, + PMUX13 = 0x3D, + PMUX14 = 0x3E, + PMUX15 = 0x3F, + PINCFG0 = 0x40, + PINCFG1 = 0x41, + PINCFG2 = 0x42, + PINCFG3 = 0x43, + PINCFG4 = 0x44, + PINCFG5 = 0x45, + PINCFG6 = 0x46, + PINCFG7 = 0x47, + PINCFG8 = 0x48, + PINCFG9 = 0x49, + PINCFG10 = 0x4A, + PINCFG11 = 0x4B, + PINCFG12 = 0x4C, + PINCFG13 = 0x4D, + PINCFG14 = 0x4E, + PINCFG15 = 0x4F, + PINCFG16 = 0x50, + PINCFG17 = 0x51, + PINCFG18 = 0x52, + PINCFG19 = 0x53, + PINCFG20 = 0x54, + PINCFG21 = 0x55, + PINCFG22 = 0x56, + PINCFG23 = 0x57, + PINCFG24 = 0x58, + PINCFG25 = 0x59, + PINCFG26 = 0x5A, + PINCFG27 = 0x5B, + PINCFG28 = 0x5C, + PINCFG29 = 0x5D, + PINCFG30 = 0x5E, + PINCFG31 = 0x5F + } + + + private void DefineRegisters() + { + + Registers.DIR.Define(dwordregisters, 0x00000000, "DIR") + .WithValueField(0, 32, out DIR, name: "OUT"); + + Registers.DIRCLR.Define(dwordregisters, 0x00000000, "DIRCLR") + .WithValueField(0, 32, out DIRCLR, FieldMode.Read | FieldMode.Write, + writeCallback: (_, value) => + { + DIR.Value = ~value & DIR.Value; + DIRCLR.Value = ~DIR.Value; + DIRSET.Value = ~DIRCLR.Value; + }, name: "DIRCLR"); + + Registers.DIRSET.Define(dwordregisters, 0x00000000, "DIRSET") + .WithValueField(0, 32, out DIRSET, FieldMode.Read | FieldMode.Write, + writeCallback: (_, value) => + { + DIR.Value = value | DIR.Value; + DIRSET.Value = DIR.Value; + DIRCLR.Value = ~DIRSET.Value; + }, name: "DIRSET"); + + Registers.DIRTGL.Define(dwordregisters, 0x00, "DIRTGL") + .WithValueField(0, 32, name: "unused"); + + // + Registers.OUT.Define(dwordregisters, 0x00, "OUT") + .WithValueField(0, 32, out OUT, FieldMode.Read | FieldMode.Write, + writeCallback: (_, value) => + { + OUT.Value = value; + UpdateState(); + }, name: "OUT"); + + + Registers.OUTCLR.Define(dwordregisters, 0x00, "OUTCLR") + .WithValueField(0, 32, out OUTCLR, FieldMode.Read | FieldMode.Write, + writeCallback: (_, value) => + { + OUT.Value = ~value & OUT.Value; + OUTCLR.Value = ~OUT.Value; + OUTSET.Value = ~OUTCLR.Value; + UpdateState(); + }, name: "OUTCLR"); + + Registers.OUTSET.Define(dwordregisters, 0x00, "OUTSET") + .WithValueField(0, 32, out OUTSET, FieldMode.Read | FieldMode.Write, + writeCallback: (_, value) => + { + OUT.Value = value | OUT.Value; + OUTSET.Value = OUT.Value; + OUTCLR.Value = ~OUTSET.Value; + UpdateState(); + }, name: "OUTSET"); + + + Registers.OUTTGL.Define(dwordregisters, 0x00, "OUTTGL") + .WithValueField(0, 32, name: "unused"); + + Registers.IN.Define(dwordregisters, 0x00, "IN") + .WithValueField(0, 32, out IN, name: "IN"); + + Registers.CTRL.Define(dwordregisters, 0x00, "CTRL") + .WithValueField(0, 32, name: "unused"); + + Registers.WRCONFIG.Define(dwordregisters, 0x00, "WRCONFIG") + .WithValueField(0, 32, name: "unused"); + + Registers.PMUX0.Define(dwordregisters, 0x00, "PMUX0") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX1.Define(dwordregisters, 0x00, "PMUX1") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX2.Define(dwordregisters, 0x00, "PMUX2") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX3.Define(dwordregisters, 0x00, "PMUX3") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX4.Define(dwordregisters, 0x00, "PMUX4") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX5.Define(dwordregisters, 0x00, "PMUX5") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX6.Define(dwordregisters, 0x00, "PMUX6") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX7.Define(dwordregisters, 0x00, "PMUX7") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX8.Define(dwordregisters, 0x00, "PMUX8") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX9.Define(dwordregisters, 0x00, "PMUX9") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX10.Define(dwordregisters, 0x00, "PMUX10") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX11.Define(dwordregisters, 0x00, "PMUX11") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX12.Define(dwordregisters, 0x00, "PMUX12") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX13.Define(dwordregisters, 0x00, "PMUX13") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX14.Define(dwordregisters, 0x00, "PMUX14") + .WithValueField(0, 8, name: "unused"); + Registers.PMUX15.Define(dwordregisters, 0x00, "PMUX15") + .WithValueField(0, 8, name: "unused"); + + Registers.PINCFG0.Define(dwordregisters, 0x00, "PINCFG0") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG1.Define(dwordregisters, 0x00, "PINCFG1") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG2.Define(dwordregisters, 0x00, "PINCFG2") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG3.Define(dwordregisters, 0x00, "PINCFG3") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG4.Define(dwordregisters, 0x00, "PINCFG4") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG5.Define(dwordregisters, 0x00, "PINCFG5") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG6.Define(dwordregisters, 0x00, "PINCFG6") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG7.Define(dwordregisters, 0x00, "PINCFG7") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG8.Define(dwordregisters, 0x00, "PINCFG8") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG9.Define(dwordregisters, 0x00, "PINCFG9") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG10.Define(dwordregisters, 0x00, "PINCFG10") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG11.Define(dwordregisters, 0x00, "PINCFG11") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG12.Define(dwordregisters, 0x00, "PINCFG12") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG13.Define(dwordregisters, 0x00, "PINCFG13") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG14.Define(dwordregisters, 0x00, "PINCFG14") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG15.Define(dwordregisters, 0x00, "PINCFG15") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG16.Define(dwordregisters, 0x00, "PINCFG16") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG17.Define(dwordregisters, 0x00, "PINCFG17") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG18.Define(dwordregisters, 0x00, "PINCFG18") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG19.Define(dwordregisters, 0x00, "PINCFG19") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG20.Define(dwordregisters, 0x00, "PINCFG20") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG21.Define(dwordregisters, 0x00, "PINCFG21") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG22.Define(dwordregisters, 0x00, "PINCFG22") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG23.Define(dwordregisters, 0x00, "PINCFG23") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG24.Define(dwordregisters, 0x00, "PINCFG24") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG25.Define(dwordregisters, 0x00, "PINCFG25") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG26.Define(dwordregisters, 0x00, "PINCFG26") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG27.Define(dwordregisters, 0x00, "PINCFG27") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG28.Define(dwordregisters, 0x00, "PINCFG28") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG29.Define(dwordregisters, 0x00, "PINCFG29") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG30.Define(dwordregisters, 0x00, "PINCFG30") + .WithValueField(0, 8, name: "unused"); + Registers.PINCFG31.Define(dwordregisters, 0x00, "PINCFG31") + .WithValueField(0, 8, name: "unused"); + + } + + + + public uint ReadDoubleWord(long offset) + { + return dwordregisters.Read(offset); + } + + public void WriteDoubleWord(long offset, uint value) + { + dwordregisters.Write(offset, value); + } + + public Boolean IsGPIOHigh (int Pin) + { + Boolean retVal = false; + uint val = dwordregisters.Read(0x10); + uint test = 1; + uint bitpos = test << Pin; + uint result = bitpos & val; + if (result > 0) + retVal = true; + return retVal; + } + } +} \ No newline at end of file diff --git a/src/Emulator/Peripherals/Peripherals/I2C/SAMD20_I2C_Master.cs b/src/Emulator/Peripherals/Peripherals/I2C/SAMD20_I2C_Master.cs new file mode 100644 index 000000000..000e2a224 --- /dev/null +++ b/src/Emulator/Peripherals/Peripherals/I2C/SAMD20_I2C_Master.cs @@ -0,0 +1,345 @@ +// +// Copyright (c) 2010-2018 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System.Collections.Generic; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Core.Structure; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using Antmicro.Renode.Utilities; +using System; + +namespace Antmicro.Renode.Peripherals.I2C +{ + + [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] + public class SAMD20_I2C_Master : SimpleContainer, IKnownSize, IWordPeripheral, IBytePeripheral, IDoubleWordPeripheral + { + + public SAMD20_I2C_Master(Machine machine) : base(machine) + { + IRQ = new GPIO(); + dwordregisters = new DoubleWordRegisterCollection(this); + DefineRegisters(); + + + } + + + + + public ushort ReadWord(long offset) + { + return (ushort)ReadDoubleWord(offset); + } + + public void WriteWord(long offset, ushort value) + { + WriteDoubleWord(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte)ReadDoubleWord(offset); + } + + public void WriteByte(long offset, byte value) + { + WriteDoubleWord(offset, value); + } + + public long Size => 0x100; + + public GPIO IRQ { get; private set; } + + + public override void Reset() + { + dwordregisters.Reset(); + UpdateInterrupts(); + } + public uint ReadDoubleWord(long offset) + { + return dwordregisters.Read(offset); + } + + public void WriteDoubleWord(long offset, uint value) + { + dwordregisters.Write(offset, value); + UpdateInterrupts(); + } + + public enum Registers : long + { + ControlA = 0x0, + ControlB = 0x04, + DebugControl = 0x08, + Baudrate = 0x0A, + IntenClr = 0x0C, + IntenSet = 0x0D, + IntFlag = 0x0E, + Status = 0x10, + Address = 0x14, + Data = 0x18 + } + + private readonly DoubleWordRegisterCollection dwordregisters; + private int SlaveAddress = 0x00; + // private Boolean MB_Interrupt_Enabled; + private Boolean bReadActive; + + private IFlagRegisterField bMB; + private IFlagRegisterField bMB_Set; + private IFlagRegisterField bMB_Clear; + private IFlagRegisterField bSB; + private IFlagRegisterField bSB_Set; + private IFlagRegisterField bSB_Clear; + private IFlagRegisterField bBusError; + private IFlagRegisterField bArbLost; + private IFlagRegisterField bRxNack; + private IFlagRegisterField bLowTOut; + + private List txpacket = new List(); + + + private void DefineRegisters() + { + + Registers.ControlA.Define(dwordregisters, 0x00, "ControlA") + .WithFlag(0, name: "Software Reset") + .WithFlag(1, name: "Enable") + .WithValueField(2, 3, name: "Mode") + .WithTag("Reserved", 5, 2) + .WithFlag(7, name: "Run In Standby") + .WithTag("Reserved", 8, 8) + .WithFlag(16, name: "Pinout") + .WithTag("Reserved", 17, 3) + .WithValueField(20, 2, name: "SDAHold") + .WithTag("Reserved", 22, 6) + .WithValueField(28, 2, name: "InActOut") + .WithFlag(30, name: "LowTOut") + .WithTag("Reserved", 31, 1); + + Registers.ControlB.Define(dwordregisters, 0x00, "ControlB") + .WithTag("Reserved", 0, 8) + .WithFlag(8, name: "SMEN") + .WithFlag(9, name: "QCEN") + .WithTag("Reserved", 10, 6) + .WithValueField(16, 2, + writeCallback: (_, value) => + { + if (value == 0x03) + { + II2CPeripheral slave; + if (TryGetByAddress(SlaveAddress & 0xFE, out slave)) + { + slave.FinishTransmission(); + } + } + value = 0x00; + bSB.Value = false; + bMB.Value = false; + bReadActive = false; + }, + name: "Cmd") + .WithFlag(18, name: "AckAct") + .WithTag("RESERVED", 19, 13); + + Registers.DebugControl.Define(dwordregisters, 0x00, "DebugControl") + .WithTag("RESERVED", 0, 1); + + Registers.Baudrate.Define(dwordregisters, 0x00, "Baudrate") + .WithValueField(0, 8, name: "Baud") + .WithValueField(8, 8, name: "BaudLow"); + + Registers.IntenClr.Define(dwordregisters, 0x00, "IntenClr") + .WithFlag(0, out bMB_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bMB_Set.Value = false; + UpdateInterrupts(); + } + }, name: "MB Interrupt clear") + .WithFlag(1, out bSB_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bSB_Set.Value = false; + UpdateInterrupts(); + } + }, name: "SP interrupt clear.") + .WithTag("RESERVED", 2, 6); + + Registers.IntenSet.Define(dwordregisters, 0x00, "IntenSet") + .WithFlag(0, out bMB_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bMB_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "Interrupt Enable MB") + .WithFlag(1, out bSB_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bSB_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "interrupt enabled SB.") + .WithTag("RESERVED", 2, 6); + + Registers.IntFlag.Define(dwordregisters, 0x00, "IntFlag") + .WithFlag(0, out bMB, FieldMode.WriteOneToClear | FieldMode.Read, + writeCallback: (_, value) => + { + UpdateInterrupts(); + + }, name: "MB") + .WithFlag(1, out bSB, FieldMode.WriteOneToClear | FieldMode.Read, + writeCallback: (_, value) => + { + UpdateInterrupts(); + + }, name: "SB") + .WithTag("RESERVED", 2, 6); + + Registers.Status.Define(dwordregisters, 0x00, "Status") + .WithFlag(0, out bBusError, writeCallback: (_, value) => + { + if (value) + { + bBusError.Value = false; + } + }, name: "Bus Error") + .WithFlag(1, out bArbLost, writeCallback: (_, value) => + { + if (value) + { + bArbLost.Value = false; + } + }, name: "ArbLost") + .WithFlag(2, out bRxNack, writeCallback: (_, value) => + { + if (value) + { + bRxNack.Value = false; + } + }, name: "RxNack") + .WithTag("RESERVED", 3, 1) + .WithValueField(4, 2, name: "BusState") + .WithFlag(6, out bLowTOut, writeCallback: (_, value) => + { + if (value) + { + bLowTOut.Value = false; + } + }, name: "LowTOut") + .WithFlag(7, name: "ClkHold") + .WithTag("RESERVED", 8, 2) + .WithFlag(10, name: "SyncBusy") + .WithTag("RESERVED", 11, 5); + + Registers.Address.Define(dwordregisters, 0x00, "Adress") + .WithValueField(0, 8, + writeCallback: (_, value) => + { + if (0x01 == (value & 0x01)) // ReadAddress + { + bSB.Value = true; + bMB.Value = false; + bReadActive = true; + } + else // WriteAddress + { + bSB.Value = false; + bMB.Value = true; + bReadActive = false; + } + SlaveAddress = (int)value; // >> 1; + UpdateInterrupts(); + }, + name: "address") + .WithTag("RESERVED", 8, 8); + + Registers.Data.Define(dwordregisters, 0x00, "Data") + .WithValueField(0, 8, + writeCallback: (_, value) => + { + // bSB.Value = false; + bMB.Value = true; + II2CPeripheral slave; + this.Log(LogLevel.Noisy, "SAMD20 I2C Master send Data 0x{0:X}", value); + + if (TryGetByAddress(SlaveAddress, out slave)) + { + txpacket.Add((byte)value); + slave.Write(txpacket.ToArray()); + txpacket.Clear(); + } + UpdateInterrupts(); + + }, + valueProviderCallback: _ => + { + if (bReadActive) + bSB.Value = true; + // bMB.Value = false; + this.Log(LogLevel.Noisy, "SAMD20 I2C Master read Data"); + II2CPeripheral slave; + if (TryGetByAddress(SlaveAddress & 0xFE, out slave)) + { + var rxpacket = slave.Read(1); + UpdateInterrupts(); + return (rxpacket[0]); + } + return 0x00; // character; + }, name: "data") + .WithTag("RESERVED", 8, 8); + + } + + private void UpdateInterrupts() + { + bool bMB_IntActive = false; + bool bSB_IntActive = false; + + if (bMB_Set.Value & bMB.Value) + { + bMB_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD20 Int Active bMB"); + } + else + this.Log(LogLevel.Noisy, "SAMD20 Int OFF bMB"); + + + if (bSB_Set.Value & bSB.Value) + { + bSB_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD20 Int Active bSB"); + } + else + this.Log(LogLevel.Noisy, "SAMD20 Int OFF bSB"); + + + // Set or Clear Interrupt + IRQ.Set(bMB_IntActive | bSB_IntActive); + + } + + + + + + + } +} diff --git a/src/Emulator/Peripherals/Peripherals/Timers/SAMD20_Timer.cs b/src/Emulator/Peripherals/Peripherals/Timers/SAMD20_Timer.cs new file mode 100644 index 000000000..23fda9d23 --- /dev/null +++ b/src/Emulator/Peripherals/Peripherals/Timers/SAMD20_Timer.cs @@ -0,0 +1,412 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using Antmicro.Migrant; +using Antmicro.Renode.Time; +using Antmicro.Renode.Core.Structure; +using Antmicro.Renode.Peripherals.I2C; +using Antmicro.Renode.Peripherals.Sensors; + +namespace Antmicro.Renode.Peripherals.Timers +{ + [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] + public class SAMD20_Timer : IKnownSize, IDoubleWordPeripheral, IWordPeripheral, IBytePeripheral + { + + + public long Size => 0x100; + + public GPIO IRQ { get; private set; } + + + + public SAMD20_Timer(Machine machine, long frequency = DefaultPeripheralFrequency) + { + dwordregisters = new DoubleWordRegisterCollection(this); + + IRQ = new GPIO(); + + Timer0 = new LimitTimer(machine.ClockSource, frequency, this, nameof(Timer0), 65535, direction: Direction.Ascending, workMode: WorkMode.OneShot); + Timer1 = new LimitTimer(machine.ClockSource, frequency, this, nameof(Timer1), 65535, direction: Direction.Ascending, workMode: WorkMode.OneShot); + Clock = new LimitTimer(machine.ClockSource, 1, this, nameof(Clock), 1, Direction.Ascending, false, WorkMode.Periodic, true, true, 1); + + DefineRegisters(); + Reset(); + + Clock.LimitReached += TriggerTimer; + Clock.EventEnabled = true; + if (InputFrequency > 0) + Clock.Enabled = true; + else + Clock.Enabled = false; + + } + + public void SetInputSignal (long frequency, int DutyCycleInPercent = DefaultInputDutyCycleInPercent) + { + if (frequency > 0) + { + Clock.Enabled = false; + InputFrequency = frequency; + Clock.Frequency = InputFrequency; + Clock.Enabled = true; + } + else + { + Clock.Enabled = false; + InputFrequency = frequency; + } + + } + + public long GetInputSignal() + { + return InputFrequency; + } + + + public void TriggerTimer () + { + if ( (Timer1.Enabled == false) && (Enable.Value == true)) + { + Timer1.Value = 0x0000; + Timer1.Enabled = true; + } + else + { + Timer1.Enabled = false; + CC1.Value = (uint) Timer1.Value; + MC1.Value = true; + UpdateInterrupts(); + if (Enable.Value == true) + { + Timer1.Value = 0x0000; + Timer1.Enabled = true; + } + } + } + + + + public void Reset() + { + Timer0.Reset(); + Timer1.Reset(); + + dwordregisters.Reset(); + + UpdateInterrupts(); + } + + + public ushort ReadWord(long offset) + { + return (ushort)ReadDoubleWord(offset); + } + + public void WriteWord(long offset, ushort value) + { + WriteDoubleWord(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte)ReadDoubleWord(offset); + } + + public void WriteByte(long offset, byte value) + { + WriteDoubleWord(offset, value); + } + + public uint ReadDoubleWord(long offset) + { + return dwordregisters.Read(offset); + } + + public void WriteDoubleWord(long offset, uint value) + { + dwordregisters.Write(offset, value); + } + private readonly DoubleWordRegisterCollection dwordregisters; + + private IFlagRegisterField Enable; + private IFlagRegisterField OVF; + private IFlagRegisterField OVF_Clear; + private IFlagRegisterField OVF_Set; + + private IFlagRegisterField ERR; + private IFlagRegisterField ERR_Clear; + private IFlagRegisterField ERR_Set; + + private IFlagRegisterField SYNCRDY; + private IFlagRegisterField SYNCRDY_Clear; + private IFlagRegisterField SYNCRDY_Set; + + private IFlagRegisterField MC0; + private IFlagRegisterField MC0_Clear; + private IFlagRegisterField MC0_Set; + + private IFlagRegisterField MC1; + private IFlagRegisterField MC1_Clear; + private IFlagRegisterField MC1_Set; + + private IValueRegisterField CC0; + private IValueRegisterField CC1; + + private IFlagRegisterField STOP; + private const long DefaultPeripheralFrequency = 32000000; + private const long DefaultInputFrequency = 0; + private const int DefaultInputDutyCycleInPercent = 50; + private long InputFrequency = DefaultInputFrequency; + private LimitTimer Timer0; + private LimitTimer Timer1; + private LimitTimer Clock; + + private void DefineRegisters() + { + + Registers.CTRLA.Define(dwordregisters, 0x00, "CTRLA") + .WithFlag(0, FieldMode.WriteOneToClear | FieldMode.Read, + writeCallback: (_, value) => + { + if (value == true) + { + Reset(); + } + }, name: "SWRST") + + .WithFlag(1, out Enable, name: "Enable") + + .WithValueField(2, 14, name: "unused"); + + Registers.READREQ.Define(dwordregisters, 0x00, "READREQ") + .WithValueField(0, 16, name: "Reserved"); + + Registers.CTRLBCLR.Define(dwordregisters, 0x00, "CTRLBCLR") + .WithValueField(0, 8, name: "unused"); + + Registers.CTRLBSET.Define(dwordregisters, 0x00, "CTRLBSET") + .WithValueField(0, 8, name: "unused"); + + // + Registers.CTRLC.Define(dwordregisters, 0x00, "CTRLC") + .WithValueField(0, 8, name: "unused"); + + + Registers.DBGCTRL.Define(dwordregisters, 0x00, "DBGCTRL") + .WithValueField(0, 8, name: "unused"); + + Registers.EVCTRL.Define(dwordregisters, 0x00, "EVCTRL") + .WithValueField(0, 16, name: "unused"); + + + Registers.INTENCLR.Define(dwordregisters, 0x00, "INTENCLR") + .WithFlag(0, out OVF_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + OVF_Set.Value = false; + UpdateInterrupts(); + } + }, name: "OVF Interrupt is disabled") + .WithFlag(1, out ERR_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + ERR_Set.Value = false; + UpdateInterrupts(); + } + }, name: "ERR interrupt is disabled.") + .WithTag("RESERVED", 2, 1) + .WithFlag(3, out SYNCRDY_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + SYNCRDY_Set.Value = false; + UpdateInterrupts(); + } + }, name: "SYNCRDY Interrupt is disabled") + .WithFlag(4, out MC0_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + MC0_Set.Value = false; + UpdateInterrupts(); + } + }, name: "MC0 Interrupt is disabled") + .WithFlag(5, out MC1_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + MC1_Set.Value = false; + UpdateInterrupts(); + } + }, name: "MC1 Interrupt is disabled") + .WithTag("RESERVED", 6, 2); + + + + Registers.INTENSET.Define(dwordregisters, 0x00, "INTENSET") + .WithFlag(0, out OVF_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + OVF_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "OVF Interrupt is enabled") + .WithFlag(1, out ERR_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + ERR_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "ERR interrupt is enabled.") + .WithTag("RESERVED", 2, 1) + .WithFlag(3, out SYNCRDY_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + SYNCRDY_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "SYNCRDY Interrupt is enabled") + .WithFlag(4, out MC0_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + MC0_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "MC0 Interrupt is enabled") + .WithFlag(5, out MC1_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + MC1_Clear.Value = false; + UpdateInterrupts(); + } + }, name: "MC1 Interrupt is enabled") + .WithTag("RESERVED", 6, 2); + + Registers.INTFLAG.Define(dwordregisters, 0x00, "INTFLAG") + + .WithFlag(0, out OVF, FieldMode.WriteOneToClear | FieldMode.Read, name: "OVF") + .WithFlag(1, out ERR, FieldMode.WriteOneToClear | FieldMode.Read, name: "ERR") + .WithTag("RESERVED", 2, 1) + .WithFlag(3, out SYNCRDY, FieldMode.WriteOneToClear | FieldMode.Read, name: "SYNCRDY") + .WithFlag(4, out MC0, FieldMode.WriteOneToClear | FieldMode.Read, name: "MC0") + .WithFlag(5, out MC1, FieldMode.WriteOneToClear | FieldMode.Read, name: "MC1") + + .WithTag("RESERVED", 6, 2); + + + Registers.STATUS.Define(dwordregisters, 0x08, "STATUS") + .WithValueField(0, 3, name: "unused") + .WithFlag(3, out STOP, FieldMode.Write | FieldMode.Read, name: "stop") + .WithValueField(4, 4, name: "unused"); + + + Registers.COUNT.Define(dwordregisters, 0x00, "COUNT") + .WithValueField(0, 16, name: "unused"); + + Registers.CC0.Define(dwordregisters, 0x0000, "CC0") + .WithValueField(0, 16, out CC0, + readCallback: (_, __) => + { + MC0.Value = false; + UpdateInterrupts(); + }, name: "CC0"); + + Registers.CC1.Define(dwordregisters, 0x0000, "CC1") + .WithValueField(0, 16, out CC1, + readCallback: (_, __) => + { + MC1.Value = false; + UpdateInterrupts(); + }, name: "CC1"); + + + } + + private void UpdateInterrupts() + { + bool OVF_IntActive = false; + bool ERR_IntActive = false; + bool SYNCRDY_IntActive = false; + bool MC0_IntActive = false; + bool MC1_IntActive = false; + + + if (OVF_Set.Value & OVF.Value) + { + OVF_IntActive = true; + } + + + if (ERR_Set.Value & ERR.Value) + { + ERR_IntActive = true; + } + + if (SYNCRDY_Set.Value & SYNCRDY.Value) + { + SYNCRDY_IntActive = true; + } + + if (MC0_Set.Value & MC0.Value) + { + MC0_IntActive = true; + } + + if (MC1_Set.Value & MC1.Value) + { + MC1_IntActive = true; + } + // Set or Clear Interrupt + IRQ.Set(OVF_IntActive | ERR_IntActive | SYNCRDY_IntActive | MC0_IntActive | MC1_IntActive); + + + + } + + + + private enum Registers : long + { + CTRLA = 0x00, + READREQ = 0x02, + CTRLBCLR = 0x04, + CTRLBSET = 0x05, + CTRLC = 0x06, + DBGCTRL = 0x08, + EVCTRL = 0x0A, + INTENCLR = 0x0C, + INTENSET = 0x0D, + INTFLAG = 0x0E, + STATUS = 0x0F, + COUNT = 0x10, + CC0 = 0x18, + CC1 = 0x1A + } + + } +} \ No newline at end of file diff --git a/src/Emulator/Peripherals/Peripherals/UART/SAMD20_UART.cs b/src/Emulator/Peripherals/Peripherals/UART/SAMD20_UART.cs new file mode 100644 index 000000000..53a2e25b9 --- /dev/null +++ b/src/Emulator/Peripherals/Peripherals/UART/SAMD20_UART.cs @@ -0,0 +1,351 @@ +// +// Copyright (c) 2010-2018 Antmicro +// +// This file is licensed under the MIT License. +// Full license text is available in 'licenses/MIT.txt'. +// +using System.Collections.Generic; +using Antmicro.Renode.Peripherals.Bus; +using Antmicro.Renode.Core.Structure.Registers; +using Antmicro.Renode.Core; +using Antmicro.Renode.Logging; +using System; +using Antmicro.Migrant; + + +namespace Antmicro.Renode.Peripherals.UART +{ + [AllowedTranslations(AllowedTranslation.WordToDoubleWord | AllowedTranslation.ByteToDoubleWord)] + public class SAMD20_UART : IDoubleWordPeripheral, IUART, IKnownSize, IWordPeripheral, IBytePeripheral + { + + public event Action CharReceived; + + public SAMD20_UART(Machine machine) + { + IRQ = new GPIO(); + dwordregisters = new DoubleWordRegisterCollection(this); + + DefineRegisters(); + } + + + + + public long Size => 0x100; + + public GPIO IRQ { get; private set; } + + public Bits StopBits + { + get + { + if (bStopBit.Value == true) + return Bits.Two; + else + return Bits.One; + } + } + + public Parity ParityBit + { + get + { + if (bParity.Value==true) + return Parity.Odd; + else + return Parity.Even; + } + } + + public uint BaudRate + { + get + { + return baudrate.Value; + } + } + + + + public void Reset() + { + dwordregisters.Reset(); + UpdateInterrupts(); + } + + public void WriteChar(byte value) + { + receiveFifo.Enqueue(value); + bRXC.Value = true; + UpdateInterrupts(); + } + + public ushort ReadWord(long offset) + { + return (ushort)ReadDoubleWord(offset); + } + + public void WriteWord(long offset, ushort value) + { + WriteDoubleWord(offset, value); + } + + public byte ReadByte(long offset) + { + return (byte) ReadDoubleWord(offset); + } + + public void WriteByte(long offset, byte value) + { + WriteDoubleWord(offset, value); + } + + public uint ReadDoubleWord(long offset) + { + return (dwordregisters.Read(offset)); + } + + public void WriteDoubleWord(long offset, uint value) + { + dwordregisters.Write(offset, value); + UpdateInterrupts(); + } + + private readonly Queue receiveFifo = new Queue(); + + + private IFlagRegisterField bDRE; + private IFlagRegisterField bDRE_Clear; + private IFlagRegisterField bDRE_Set; + private IFlagRegisterField bTXC; + private IFlagRegisterField bTXC_Clear; + private IFlagRegisterField bTXC_Set; + private IFlagRegisterField bRXC; + private IFlagRegisterField bRXC_Clear; + private IFlagRegisterField bRXC_Set; + private IFlagRegisterField bRXS; + private IFlagRegisterField bRXS_Clear; + private IFlagRegisterField bRXS_Set; + private IFlagRegisterField bParity; + private IFlagRegisterField bStopBit; + private IValueRegisterField baudrate; + private DoubleWordRegisterCollection dwordregisters; + + private void DefineRegisters() + { + + Register.ControlA.Define(dwordregisters, 0x00, "ControlA") + .WithFlag(0, name: "Software Reset") + .WithFlag(1, name: "Enable") + .WithValueField(2, 3, name: "Mode") + .WithTag("Reserved", 5, 2) + .WithFlag(7, name: "Run In Standby") + .WithFlag(8, name: "Immediate Buffer Overflow Notification") + .WithTag("Reserved", 9, 7) + .WithFlag(16, name: "Transmit Data Pinout") + .WithTag("Reserved", 17, 2) + .WithValueField(20, 2, name: "Receive Data Pinout") + .WithTag("Reserved", 22, 2) + .WithValueField(24, 4, name: "Frame Format") + .WithFlag(28, name: "Communication Mode") + .WithFlag(29, name: "Clock Polarity") + .WithFlag(30, name: "Data Order") + .WithTag("Reserved", 31, 1); + + Register.ControlB.Define(dwordregisters, 0x00, "ControlB") + .WithValueField(0, 3, name: "Character Size") + .WithTag("Reserved", 3, 3) + .WithFlag(6, out bStopBit, FieldMode.Read | FieldMode.Write, name: "Stop Bit Mode") + .WithTag("Reserved", 7, 2) + .WithFlag(9, name: "SFDE") + .WithTag("Reserved", 10, 3) + .WithFlag(13, out bParity, FieldMode.Read | FieldMode.Write, name: "PMODE") + .WithTag("RESERVED", 14, 2) + .WithFlag(16, name: "TXEN") + .WithFlag(17, name: "RXEN") + .WithTag("RESERVED", 18, 14); + + Register.DebugControl.Define(dwordregisters, 0x00, "DebugControl") + .WithTag("RESERVED", 0, 1); + + + Register.Baudrate.Define(dwordregisters, 0x00, "Baudrate") + .WithValueField(0, 16, out baudrate, FieldMode.Read | FieldMode.Write, name: "Baudraute"); + + Register.IntenClr.Define(dwordregisters, 0x00, "IntenClr") + .WithFlag(0, out bDRE_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bDRE_Set.Value = false; + } + }, name: "Data Register Empty Interrupt Enable") + .WithFlag(1, out bTXC_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bTXC_Set.Value = false; + } + }, name: "Transmit Complete interrupt is disabled.") + .WithFlag(2, out bRXC_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bRXC_Set.Value = false; + } + }, name: "Receive Complete Interrupt Enable") + .WithFlag(3, out bRXS_Clear, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bRXS_Set.Value = false; + } + }, name: "Receive Start Interrupt Enable") + .WithTag("RESERVED", 4, 4); + + Register.IntenSet.Define(dwordregisters, 0x00, "IntenSet") + .WithFlag(0, out bDRE_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bDRE_Clear.Value = false; + } + }, name: "Data Register Empty Interrupt Enable") + .WithFlag(1, out bTXC_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bTXC_Clear.Value = false; + } + }, name: "Transmit Complete interrupt is disabled.") + .WithFlag(2, out bRXC_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bRXC_Clear.Value = false; + } + }, name: "Receive Complete Interrupt Enable") + .WithFlag(3, out bRXS_Set, FieldMode.Read | FieldMode.Set, + writeCallback: (_, value) => + { + if (value == true) + { + bRXS_Clear.Value = false; + } + }, name: "Receive Start Interrupt Enable") + .WithTag("RESERVED", 4, 4); + + + Register.IntFlag.Define(dwordregisters, 0x01, "IntFlag") + .WithFlag(0, out bDRE, FieldMode.Read, name: "Data Register Empty") + .WithFlag(1, out bTXC, FieldMode.WriteOneToClear | FieldMode.Read, name: "Transmit Complete.") + .WithFlag(2, out bRXC, FieldMode.Read, name: "Receive Complete") + .WithFlag(3, out bRXS, FieldMode.WriteOneToClear | FieldMode.Read, name: "Receive Start") + .WithTag("RESERVED", 4, 4); + + Register.Status.Define(dwordregisters, 0x00, "Status") + .WithFlag(0, name: "Parity Error") + .WithFlag(1, name: "Frame Error") + .WithFlag(2, name: "Buffer Overflow") + .WithTag("RESERVED", 3, 12) + .WithFlag(15, name: "Synchronization Busy"); + + Register.Data.Define(dwordregisters, 0x00, "Data") + .WithValueField(0, 9, + writeCallback: (_, value) => + { + this.Log(LogLevel.Noisy, "SAMD2x_UART: Data Send"); + bDRE.Value = false; + CharReceived?.Invoke((byte)value); + bTXC.Value = true; + bDRE.Value = true; + }, + valueProviderCallback: _ => + { + uint value = 0; + if (receiveFifo.Count > 0) + { + value = receiveFifo.Dequeue(); + this.Log(LogLevel.Noisy, "SAMD2x_UART: Data Receive"); + } + if (receiveFifo.Count == 0) + { + bRXC.Value = false; + this.Log(LogLevel.Noisy, "SAMD2x_UART: RXC = false"); + } + return value; + }, name: "data") + .WithTag("RESERVED", 9, 7); + + + } + + private void UpdateInterrupts() + { + bool bDRE_IntActive = false; + bool bTXC_IntActive = false; + bool bRXC_IntActive = false; + bool bRXS_IntActive = false; + + if (bDRE_Set.Value & bDRE.Value) + { + bDRE_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD2x_UART: DRE Int Active"); + } + else + this.Log(LogLevel.Noisy, "SAMD2x_UART: DRE Int Off"); + + + if (bTXC_Set.Value & bTXC.Value) + { + bTXC_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD2x_UART: TXC Int Active"); + } + else + this.Log(LogLevel.Noisy, "SAMD2x_UART: TXC Int Off"); + + if (bRXC_Set.Value & bRXC.Value) + { + bRXC_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD2x_UART: RXC Int Active"); + } + else + this.Log(LogLevel.Noisy, "SAMD2x_UART: RXC Int Off"); + + if (bRXS_Set.Value & bRXS.Value) + { + bRXS_IntActive = true; + this.Log(LogLevel.Noisy, "SAMD2x_UART: RXS Int Active"); + } + else + this.Log(LogLevel.Noisy, "SAMD2x_UART: RXS Int Off"); + + // Set or Clear Interrupt + IRQ.Set(bRXS_IntActive | bRXC_IntActive | bTXC_IntActive | bDRE_IntActive); + + } + + + private enum Register : long + { + ControlA= 0x00, + ControlB= 0x04, + DebugControl = 0x08, + Baudrate =0x0A, + IntenClr = 0x0C, + IntenSet = 0x0D, + IntFlag = 0x0E, + Status = 0x10, + Data = 0x18 + } + + } +} \ No newline at end of file From fa214f110ed93dfe99dc9286b31d1ae2e41353d0 Mon Sep 17 00:00:00 2001 From: guentherweber <38313940+guentherweber@users.noreply.github.com> Date: Sun, 5 Dec 2021 16:45:05 +0100 Subject: [PATCH 2/2] add SAMD20 perpherals to project file --- src/Emulator/Peripherals/Peripherals.csproj | 921 ++++++++++---------- 1 file changed, 462 insertions(+), 459 deletions(-) diff --git a/src/Emulator/Peripherals/Peripherals.csproj b/src/Emulator/Peripherals/Peripherals.csproj index b45305a5d..e3d4ea5e9 100644 --- a/src/Emulator/Peripherals/Peripherals.csproj +++ b/src/Emulator/Peripherals/Peripherals.csproj @@ -1,459 +1,462 @@ - - - - Debug - AnyCPU - {66400796-0C5B-4386-A859-50A2AC3F3DB7} - Library - Antmicro.Renode - Renode-peripherals - v4.5 - 8.0.30703 - 2.0 - ..\..\..\..\..\output\properties.csproj - - - - 7 - true - full - false - bin\Debug - DEBUG;$(DefineConstants) - prompt - 4 - false - true - - - 7 - none - true - bin\Release - prompt - 4 - false - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BitBanding.tt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RegisterEnumParser.tt - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TextTemplatingFileGenerator - BitBanding.cs - - - - - Peripherals\CPU\Registers\RegisterEnumParser.tt - TextTemplatingFileGenerator - RegisterEnumParser.cs - - - - - {2901AECB-A54F-4FD8-9AC1-033D86DC7257} - Emulator - - - {5F87C357-09FB-4F53-BE37-41FE5BD88957} - Migrant - - - {CF944E09-7C14-433C-A185-161848E989B3} - ELFSharp - - - {4C636FAF-4650-4088-8EA8-2FCCC225E9CF} - Extensions - - - {55ABBA4C-AAF9-4726-A592-0C92436CEC92} - PacketDotNet - - - - - - + + + + Debug + AnyCPU + {66400796-0C5B-4386-A859-50A2AC3F3DB7} + Library + Antmicro.Renode + Renode-peripherals + v4.5 + 8.0.30703 + 2.0 + ..\..\..\..\..\output\properties.csproj + + + + 7 + true + full + false + bin\Debug + DEBUG;$(DefineConstants) + prompt + 4 + false + true + + + 7 + none + true + bin\Release + prompt + 4 + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BitBanding.tt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RegisterEnumParser.tt + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TextTemplatingFileGenerator + BitBanding.cs + + + + + Peripherals\CPU\Registers\RegisterEnumParser.tt + TextTemplatingFileGenerator + RegisterEnumParser.cs + + + + + {2901AECB-A54F-4FD8-9AC1-033D86DC7257} + Emulator + + + {5F87C357-09FB-4F53-BE37-41FE5BD88957} + Migrant + + + {CF944E09-7C14-433C-A185-161848E989B3} + ELFSharp + + + {4C636FAF-4650-4088-8EA8-2FCCC225E9CF} + Extensions + + + {55ABBA4C-AAF9-4726-A592-0C92436CEC92} + PacketDotNet + + + + \ No newline at end of file