mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
151 lines
5.3 KiB
C#
151 lines
5.3 KiB
C#
//
|
|
// 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 Antmicro.Renode.Core;
|
|
using Antmicro.Renode.Core.Structure.Registers;
|
|
using Antmicro.Renode.Utilities;
|
|
using Antmicro.Renode.Logging;
|
|
using Antmicro.Renode.Time;
|
|
using Antmicro.Renode.Peripherals.Bus;
|
|
using System.Threading;
|
|
|
|
namespace Antmicro.Renode.Peripherals.Timers
|
|
{
|
|
// this is a model of LiteX timer in the Betrusted configuration:
|
|
// * width: 32 bits
|
|
// * csr data width: 32 bit
|
|
[AllowedTranslations(AllowedTranslation.ByteToDoubleWord)]
|
|
public class TickTimer : BasicDoubleWordPeripheral, IKnownSize
|
|
{
|
|
public TickTimer(Machine machine, ulong periodInMs = 1) : base(machine)
|
|
{
|
|
machine.ClockSource.AddClockEntry(new ClockEntry(periodInMs, 1000, OnTick, this, "TickTimer"));
|
|
this.IRQ = new GPIO();
|
|
DefineRegisters();
|
|
}
|
|
|
|
public override void Reset()
|
|
{
|
|
base.Reset();
|
|
tickValue = 0;
|
|
paused = true;
|
|
msleepTarget = 0;
|
|
}
|
|
|
|
private void OnTick()
|
|
{
|
|
if (!paused)
|
|
{
|
|
this.irqStatus = Interlocked.Increment(ref tickValue) >= (long)this.msleepTarget;
|
|
this.UpdateInterrupts();
|
|
}
|
|
}
|
|
|
|
private void UpdateInterrupts()
|
|
{
|
|
if ((Interlocked.Read(ref this.tickValue) >= (long)this.msleepTarget) && this.irqEnabled.Value)
|
|
{
|
|
this.irqPending.Value = true;
|
|
}
|
|
this.Log(LogLevel.Noisy, "Setting IRQ: {0} because tickValue {1} >= msleepTarget {2} ({3}) and irqEnabled = {4}",
|
|
irqPending.Value && this.irqEnabled.Value,
|
|
this.tickValue,
|
|
this.msleepTarget,
|
|
this.tickValue >= (long)this.msleepTarget, this.irqEnabled.Value);
|
|
IRQ.Set(this.irqPending.Value && this.irqEnabled.Value);
|
|
}
|
|
|
|
public long Size { get { return 0x20; } }
|
|
|
|
private void DefineRegisters()
|
|
{
|
|
Registers.Control.Define32(this)
|
|
.WithValueField(0, 32, name: "CONTROL", writeCallback: (_, val) =>
|
|
{
|
|
if ((val & 1) != 0)
|
|
{
|
|
tickValue = 0;
|
|
}
|
|
paused = (val & 2) != 0;
|
|
});
|
|
;
|
|
|
|
Registers.Time1.Define32(this)
|
|
.WithValueField(0, 32, FieldMode.Read, name: "Time1", valueProviderCallback: _ =>
|
|
{
|
|
return (uint)(tickValue >> 32);
|
|
})
|
|
;
|
|
|
|
Registers.Time0.Define32(this)
|
|
.WithValueField(0, 32, FieldMode.Read, name: "Time0", valueProviderCallback: _ =>
|
|
{
|
|
return (uint)(tickValue >> 0);
|
|
})
|
|
;
|
|
|
|
Registers.MsleepTarget1.Define32(this)
|
|
.WithValueField(0, 32, name: "MsleepTarget1", writeCallback: (_, value) =>
|
|
{
|
|
this.msleepTarget = (this.msleepTarget & 0x00000000ffffffff) | (value << 32);
|
|
this.Log(LogLevel.Noisy, "Setting MsleepTarget1: {0}, sleep target now: {1}", value, this.msleepTarget);
|
|
},
|
|
valueProviderCallback: _ =>
|
|
{
|
|
return (uint)(this.msleepTarget >> 32);
|
|
})
|
|
;
|
|
|
|
Registers.MsleepTarget0.Define32(this)
|
|
.WithValueField(0, 32, name: "MsleepTarget0",
|
|
writeCallback: (_, value) =>
|
|
{
|
|
this.msleepTarget = (this.msleepTarget & 0xffffffff00000000) | (value & 0xffffffff);
|
|
this.Log(LogLevel.Noisy, "Setting MsleepTarget0: {0}, sleep target now: {1}", value, this.msleepTarget);
|
|
},
|
|
valueProviderCallback: _ =>
|
|
{
|
|
return (uint)(this.msleepTarget >> 0);
|
|
})
|
|
;
|
|
|
|
Registers.EventStatus.Define32(this)
|
|
.WithFlag(0, FieldMode.Read, name: "EV_STATUS", valueProviderCallback: _ => irqStatus)
|
|
;
|
|
|
|
Registers.EventPending.Define32(this)
|
|
.WithFlag(0, out irqPending, FieldMode.Read | FieldMode.WriteOneToClear, name: "EV_PENDING", changeCallback: (_, __) => UpdateInterrupts())
|
|
;
|
|
|
|
Registers.EventEnable.Define32(this)
|
|
.WithFlag(0, out irqEnabled, name: "EV_ENABLE", changeCallback: (_, __) => UpdateInterrupts())
|
|
;
|
|
|
|
}
|
|
|
|
private IFlagRegisterField irqEnabled;
|
|
private IFlagRegisterField irqPending;
|
|
private bool irqStatus;
|
|
|
|
bool paused;
|
|
long tickValue;
|
|
ulong msleepTarget;
|
|
public GPIO IRQ { get; private set; }
|
|
|
|
private enum Registers
|
|
{
|
|
Control = 0x00,
|
|
Time1 = 0x04,
|
|
Time0 = 0x08,
|
|
MsleepTarget1 = 0x0c,
|
|
MsleepTarget0 = 0x10,
|
|
EventStatus = 0x14,
|
|
EventPending = 0x18,
|
|
EventEnable = 0x1c,
|
|
}
|
|
}
|
|
}
|