//
// Copyright (c) 2010-2024 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.Utilities;
namespace Antmicro.Renode.Core.Structure.Registers
{
public static class PeripheralRegisterExtensions
{
///
/// Creates a fluent conditional wrapper for conditionally executing actions on a register.
///
/// The condition to evaluate.
/// An object wrapping the register.
///
/// This example demonstrates how to use the If and Else methods
/// of to conditionally define a field on a register:
///
/// Registers.Control.Define(this)
/// .WithValueField(0, 4, out transmissionSize, name: "TXSIZE")
/// .If(SupportsEncryption)
/// .Then(r => r.WithValueField(4, 12, out transmissionKey, name: "TXKEY"))
/// .Else(r => r.WithReservedBits(4, 12));
///
///
public static IfWrapper If(this T register, bool condition) where T : PeripheralRegister
{
return new IfWrapper(register, condition);
}
///
/// Fluent API for handling for loops. This helper is equivalent to calling the callback in a for loop
/// going from "start" to "end" being incremented by "step"
///
/// Callback to execute on each loop iteration
/// Starting value of the loop variable
/// Exclusive ending value of the loop variable
/// Amount that the loop variable will be incremented by after each iteration
/// This register after all loop iterations
public static T For(this T register, Action callback, int start, int end, int step = 1) where T : PeripheralRegister
{
for(var i = start; i < end; i += step)
{
callback(register, i);
}
return register;
}
///
/// Fluent API for flag field creation. For parameters see .
///
/// This register with a defined flag.
public static T WithFlag(this T register, int position, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for creation of a set of consecutive flag fields.
///
/// Offset in the register of the first field.
/// Number of flag fields to create.
/// Access modifiers of each field.
/// Method to be called whenever the containing register is read. The first parameter is the index of the flag field, the second is the value of this field before read,
/// the third parameter is the value after read. Note that it will also be called for unreadable fields.
/// Method to be called whenever the containing register is written to. The first parameter is the index of the flag, the second is the value of this field before write,
/// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.
/// Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the flag, the second is the value of this field before change,
/// the third parameter is the value after change. Note that it will also be called for unwrittable fields.
/// Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by
/// the value returned from it. This returned value is eventually passed as the second parameter of .
/// Indicates whether the field should be cleared by soft reset.
/// Ignored parameter, for convenience. Treat it as a comment.
/// This register with defined flags.
public static T WithFlags(this T register, int position, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
return WithFlags(register, position, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
}
///
/// Fluent API for value field creation. For parameters see .
///
/// This register with a defined value field.
public static T WithValueField(this T register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for creation of a set of consecutive value fields
///
/// Offset in the register of the first field.
/// Maximum width of the value, in terms of binary representation.
/// Number of flag fields to create.
/// Access modifiers of each field.
/// Method to be called whenever the containing register is read. The first parameter is the index of the value field, the second is the value of this field before read,
/// the third parameter is the value after read. Note that it will also be called for unreadable fields.
/// Method to be called whenever the containing register is written to. The first parameter is the index of the field, the second is the value of this field before write,
/// the third parameter is the value written (without any modification). Note that it will also be called for unwrittable fields.
/// Method to be called whenever this field's value is changed, either due to read or write. The first parameter is the index of the field, the second is the value of this field before change,
/// the third parameter is the value after change. Note that it will also be called for unwrittable fields.
/// Method to be called whenever this field is read. The value passed is the current field's value, that will be overwritten by
/// the value returned from it. This returned value is eventually passed as the second parameter of .
/// Indicates whether the field should be cleared by soft reset.
/// Ignored parameter, for convenience. Treat it as a comment.
/// This register with defined value fields.
public static T WithValueFields(this T register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
return WithValueFields(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
}
///
/// Fluent API for enum field creation. For parameters see .
///
/// This register with a defined enum field.
public static R WithEnumField(this R register, int position, int width, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null)
where R : PeripheralRegister
where T : struct, IConvertible
{
register.DefineEnumField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for tagged field creation. For parameters see .
///
/// This register with a defined tag field.
public static T WithTag(this T register, string name, int position, int width) where T : PeripheralRegister
{
register.Tag(name, position, width);
return register;
}
///
/// Fluent API for creating a set of tagged fields. For parameters see .
///
/// This register with a defined tag field set.
public static T WithTags(this T register, string name, int position, int width, int count) where T : PeripheralRegister
{
for(var i = 0; i < count; i++)
{
register.Tag(name == null ? null : $"{name}_{i}", position + (i * width), width);
}
return register;
}
///
/// Fluent API for tagged flag creation - a tag of width equal to 1. For parameters see .
///
/// This register with a defined tag field.
public static T WithTaggedFlag(this T register, string name, int position) where T : PeripheralRegister
{
register.Tag(name, position, 1);
return register;
}
///
/// Fluent API for creating a set of tagged flags - a tag of width equal to 1. For parameters see .
///
/// This register with a defined tag field set.
public static T WithTaggedFlags(this T register, string name, int position, int count) where T : PeripheralRegister
{
for(var i = 0; i < count; i++)
{
register.WithTaggedFlag(name == null ? null : $"{name}_{i}", position + i);
}
return register;
}
///
/// Fluent API for value field creation. For parameters see .
/// This overload allows you to retrieve the created field via valueField parameter.
///
/// This register with a defined value field.
public static T WithValueField(this T register, int position, int width, out IValueRegisterField valueField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null) where T : PeripheralRegister
{
valueField = register.DefineValueField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for creation of set of value fields. For parameters see the other overload of .
/// This overload allows you to retrieve the created array of fields via valueFields parameter.
///
/// This register with defined value fields.
public static T WithValueFields(this T register, int position, int width, int count, out IValueRegisterField[] valueFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
valueFields = new IValueRegisterField[count];
for(var i = 0; i < count; i++)
{
var j = i;
valueFields[j] = register.DefineValueField(position + (j * width), width, mode,
readCallback == null ? null : (Action)((x, y) => readCallback(j, x, y)),
writeCallback == null ? null : (Action)((x, y) => writeCallback(j, x, y)),
changeCallback == null ? null : (Action)((x, y) => changeCallback(j, x, y)),
valueProviderCallback == null ? null : (Func)((x) => valueProviderCallback(j, x)),
softResettable,
name == null ? null : $"{name}_{j}");
}
return register;
}
///
/// Fluent API for enum field creation. For parameters see .
/// This overload allows you to retrieve the created field via enumField parameter.
///
/// This register with a defined enum field.
public static R WithEnumField(this R register, int position, int width, out IEnumRegisterField enumField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null) where R : PeripheralRegister
where T : struct, IConvertible
{
enumField = register.DefineEnumField(position, width, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for creation of set of enum fields. For parameters see the other overload of .
/// This overload allows you to retrieve the created array of fields via enumFields parameter.
///
/// This register with defined enum fields.
public static R WithEnumFields(this R register, int position, int width, int count, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null)
where R : PeripheralRegister
where T : struct, IConvertible
{
return WithEnumFields(register, position, width, count, out var _, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
}
///
/// Fluent API for creation of set of enum fields. For parameters see the other overload of .
/// This overload allows you to retrieve the created array of fields via enumFields parameter.
///
/// This register with defined enum fields.
public static R WithEnumFields(this R register, int position, int width, int count, out IEnumRegisterField[] enumFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null)
where R : PeripheralRegister
where T : struct, IConvertible
{
enumFields = new IEnumRegisterField[count];
for(var i = 0; i < count; i++)
{
var j = i;
enumFields[j] = register.DefineEnumField(position + (j * width), width, mode,
readCallback == null ? null : (Action)((x, y) => readCallback(j, x, y)),
writeCallback == null ? null : (Action)((x, y) => writeCallback(j, x, y)),
changeCallback == null ? null : (Action)((x, y) => changeCallback(j, x, y)),
valueProviderCallback == null ? null : (Func)((x) => valueProviderCallback(j, x)),
softResettable,
name == null ? null : $"{name}_{j}");
}
return register;
}
///
/// Fluent API for flag field creation. For parameters see .
/// This overload allows you to retrieve the created field via flagField parameter.
///
/// This register with a defined flag.
public static T WithFlag(this T register, int position, out IFlagRegisterField flagField, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true, string name = null)
where T : PeripheralRegister
{
flagField = register.DefineFlagField(position, mode, readCallback, writeCallback, changeCallback, valueProviderCallback, softResettable, name);
return register;
}
///
/// Fluent API for creation of sets of flag fields. For parameters see the other overload of .
/// This overload allows you to retrieve the created array of fields via flagFields parameter.
///
/// This register with defined flags.
public static T WithFlags(this T register, int position, int count, out IFlagRegisterField[] flagFields, FieldMode mode = FieldMode.Read | FieldMode.Write, Action readCallback = null,
Action writeCallback = null, Action changeCallback = null, Func valueProviderCallback = null, bool softResettable = true,
string name = null) where T : PeripheralRegister
{
flagFields = new IFlagRegisterField[count];
for(var i = 0; i < count; i++)
{
var j = i;
flagFields[j] = register.DefineFlagField(position + j, mode,
readCallback == null ? null : (Action)((x, y) => readCallback(j, x, y)),
writeCallback == null ? null : (Action)((x, y) => writeCallback(j, x, y)),
changeCallback == null ? null : (Action)((x, y) => changeCallback(j, x, y)),
valueProviderCallback == null ? null : (Func)((x) => valueProviderCallback(j, x)),
softResettable,
name == null ? null : $"{name}_{j}");
}
return register;
}
///
/// Fluent API for tagging bits as "RESERVED". For description see .
///
/// This register with a new "RESERVED" tag.
public static T WithReservedBits(this T register, int position, int width, uint? allowedValue = null) where T : PeripheralRegister
{
register.Reserved(position, width, allowedValue);
return register;
}
///
/// Fluent API for tagging bits as ignored.
///
/// This defines a value field to avoid warnings about unhandled bits.
public static T WithIgnoredBits(this T register, int position, int width) where T : PeripheralRegister
{
return register.WithValueField(position, width, name: "ignored");
}
}
public static class QuadWordRegisterExtensions
{
///
/// Fluent API for read callback registration. For description see .
///
/// This register with a defined callback.
public static QuadWordRegister WithReadCallback(this QuadWordRegister register, Action readCallback)
{
register.DefineReadCallback(readCallback);
return register;
}
///
/// Fluent API for write callback registration. For description see .
///
/// This register with a defined callback.
public static QuadWordRegister WithWriteCallback(this QuadWordRegister register, Action writeCallback)
{
register.DefineWriteCallback(writeCallback);
return register;
}
///
/// Fluent API for change callback registration. For description see .
///
/// This register with a defined callback.
public static QuadWordRegister WithChangeCallback(this QuadWordRegister register, Action changeCallback)
{
register.DefineChangeCallback(changeCallback);
return register;
}
}
public static class DoubleWordRegisterExtensions
{
///
/// Fluent API for read callback registration. For description see .
///
/// This register with a defined callback.
public static DoubleWordRegister WithReadCallback(this DoubleWordRegister register, Action readCallback)
{
register.DefineReadCallback(readCallback);
return register;
}
///
/// Fluent API for write callback registration. For description see .
///
/// This register with a defined callback.
public static DoubleWordRegister WithWriteCallback(this DoubleWordRegister register, Action writeCallback)
{
register.DefineWriteCallback(writeCallback);
return register;
}
///
/// Fluent API for change callback registration. For description see .
///
/// This register with a defined callback.
public static DoubleWordRegister WithChangeCallback(this DoubleWordRegister register, Action changeCallback)
{
register.DefineChangeCallback(changeCallback);
return register;
}
}
public static class WordRegisterExtensions
{
///
/// Fluent API for read callback registration. For description see .
///
/// This register with a defined callback.
public static WordRegister WithReadCallback(this WordRegister register, Action readCallback)
{
register.DefineReadCallback(readCallback);
return register;
}
///
/// Fluent API for write callback registration. For description see .
///
/// This register with a defined callback.
public static WordRegister WithWriteCallback(this WordRegister register, Action writeCallback)
{
register.DefineWriteCallback(writeCallback);
return register;
}
///
/// Fluent API for change callback registration. For description see .
///
/// This register with a defined callback.
public static WordRegister WithChangeCallback(this WordRegister register, Action changeCallback)
{
register.DefineChangeCallback(changeCallback);
return register;
}
}
public static class ByteRegisterExtensions
{
///
/// Fluent API for read callback registration. For description see .
///
/// This register with a defined callback.
public static ByteRegister WithReadCallback(this ByteRegister register, Action readCallback)
{
register.DefineReadCallback(readCallback);
return register;
}
///
/// Fluent API for write callback registration. For description see .
///
/// This register with a defined callback.
public static ByteRegister WithWriteCallback(this ByteRegister register, Action writeCallback)
{
register.DefineWriteCallback(writeCallback);
return register;
}
///
/// Fluent API for change callback registration. For description see .
///
/// This register with a defined callback.
public static ByteRegister WithChangeCallback(this ByteRegister register, Action changeCallback)
{
register.DefineChangeCallback(changeCallback);
return register;
}
}
}