Files
simulation_Peripheral/LC3233_Timer_InterruptController_NO4.cs
2026-04-01 11:03:44 +08:00

442 lines
15 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//============================================================================
// 作者liuwenbo
// 日期2026-03-24-2026-03-25
//============================================================================
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Antmicro.Renode.Core;
using Antmicro.Renode.Core.Structure.Registers;
using Antmicro.Renode.Logging;
using Antmicro.Renode.Peripherals.Bus;
using Antmicro.Renode.Time;
using Antmicro.Renode.Peripherals;
using Antmicro.Renode.Peripherals.Timers;
using Antmicro.Renode.Peripherals.IRQControllers;
namespace Antmicro.Renode.Peripherals.Timers
{
public class LC3233_TaskTimer : BasicDoubleWordPeripheral, IKnownSize
{
public LC3233_TaskTimer(IMachine machine) : base(machine)
{
this.machine = machine;
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 定时器已初始化 @ 0x80000000");
this.Log(LogLevel.Info, " 周期: 250ms (4Hz), 用于VxWorks任务调度");
}
private void ScheduleNextTick()
{
if(timerScheduled || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
timerScheduled = true;
var generation = timerGeneration;
machine.ScheduleAction(TimeInterval.FromMilliseconds(250), _ =>
{
timerScheduled = false;
if(generation != timerGeneration || (timerCtrl & TIMER_CTRL_T0_EN) == 0)
{
return;
}
OnTimerExpired();
});
}
private void OnTimerExpired()
{
timerExpiredCount++;
//isPending = true;
this.Log(LogLevel.Info, "========== 定时器溢出 #{0} ==========", timerExpiredCount);
this.Log(LogLevel.Info, "准备触发中断线4...");
IRQ.Set(true);
this.Log(LogLevel.Info, "已调用 IRQ.Set(true),信号应发送到 lc3233IntCtrl@4");
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
IRQ.Set(false);
this.Log(LogLevel.Debug, "中断脉冲结束");
});
if ((timerCtrl & TIMER_CTRL_T0_LOEN) != 0)
{
timer0Cntr = timer0Reld;
ScheduleNextTick();
}
}
private void DefineRegisters()
{
Registers.TimerCtrl.Define(this)
.WithValueField(0, 32, name: "timer_ctrl",
writeCallback: (_, val) =>
{
timerCtrl = (uint)val;
// Bit 0: Timer0 Enable
bool t0Enable = (val & TIMER_CTRL_T0_EN) != 0;
if(!t0Enable)
{
timerGeneration++;
timerScheduled = false;
}
else
{
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
this.Log(LogLevel.Info, "TIMER_CTRL 写入: 0x{0:X8}", val);
this.Log(LogLevel.Info, " Timer0 Enable: {0}", t0Enable);
this.Log(LogLevel.Info, " Auto Reload: {0}", (val & TIMER_CTRL_T0_LOEN) != 0);
},
valueProviderCallback: _ => timerCtrl);
Registers.Timer0Cntr.Define(this)
.WithValueField(0, 32, name: "timer0_cntr",
writeCallback: (_, val) =>
{
timer0Cntr = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_CNTR 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Cntr);
Registers.Timer0Reld.Define(this)
.WithValueField(0, 32, name: "timer0_reld",
writeCallback: (_, val) =>
{
timer0Reld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0Reld);
Registers.Timer0DivFreq.Define(this)
.WithValueField(0, 32, name: "timer0_divfreq",
writeCallback: (_, val) =>
{
timer0DivFreq = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DIVFREQ 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DivFreq);
Registers.Timer0DfReld.Define(this)
.WithValueField(0, 32, name: "timer0_df_reld",
writeCallback: (_, val) =>
{
timer0DfReld = (uint)val;
this.Log(LogLevel.Debug, "TIMER0_DF_RELD 写入: 0x{0:X8}", val);
},
valueProviderCallback: _ => timer0DfReld);
}
public override void Reset()
{
base.Reset();
timerCtrl = TIMER_CTRL_T0_EN | TIMER_CTRL_T0_LOEN;
timer0Cntr = 0;
timer0Reld = 0;
timer0DivFreq = 0;
timer0DfReld = 0;
isPending = false;
timerExpiredCount = 0;
timerGeneration++;
timerScheduled = false;
ScheduleNextTick();
}
public long Size => 0x100;
public GPIO IRQ { get; } = new GPIO();
private enum Registers
{
TimerCtrl = 0x00,
Timer0Cntr = 0x04,
Timer0Reld = 0x08,
WdgCntr = 0x0C,
Timer1Cntr = 0x10,
Timer1Reld = 0x14,
Timer0DivFreq = 0x18,
Timer0DfReld = 0x1C,
}
private const uint TIMER_CTRL_T0_EN = 0x00000001;
private const uint TIMER_CTRL_T0_LOEN = 0x00000002;
private const uint TIMER_CTRL_T0_RSTA = 0x00000004;
private readonly IMachine machine;
private uint timerCtrl;
private uint timer0Cntr;
private uint timer0Reld;
private uint timer0DivFreq;
private uint timer0DfReld;
private bool isPending;
private bool timerScheduled;
private ulong timerGeneration;
private ulong timerExpiredCount;
}
}
namespace Antmicro.Renode.Peripherals.IRQControllers
{
public class LC3233_InterruptController : BasicDoubleWordPeripheral, IKnownSize, INumberedGPIOOutput, IGPIOReceiver
{
public LC3233_InterruptController(IMachine machine) : base(machine)
{
this.machine = machine;
connections = new Dictionary<int, IGPIO>();
for (int i = 0; i <= 15; i++)
{
connections[i] = new GPIO();
}
Connections = new ReadOnlyDictionary<int, IGPIO>(connections);
DefineRegisters();
Reset();
this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000");
this.Log(LogLevel.Info, " 管理15个中断源 (1-15)");
}
/// <summary>
/// 定义寄存器映射
/// </summary>
private void DefineRegisters()
{
// Registers.IntMaskPriority.Define(this)
// .WithValueField(0, 32, name: "int_mask_priority",
// writeCallback: (_, val) =>
// {
// intMaskPriority = (uint)val;
// this.Log(LogLevel.Info, "INT_MASK_PRIORITY 写入: 0x{0:X8}", val);
// this.Log(LogLevel.Info, " 临时兼容: IRQ4 强制视为使能");
// for (int i = 1; i <= 15; i++)
// {
// if ((val & (uint)(1 << i)) != 0)
// {
// this.Log(LogLevel.Debug, " 中断 {0} 已使能", i);
// }
// }
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intMaskPriority);
// Registers.IntFTP.Define(this)
// .WithValueField(0, 32, name: "int_f_t_p",
// writeCallback: (_, val) =>
// {
// intFTP |= (uint)val;
// this.Log(LogLevel.Debug, "INT_F_T_P 写入: 0x{0:X8}, 当前值: 0x{1:X8}", val, intFTP);
// UpdateInterrupts();
// },
// valueProviderCallback: _ => intFTP);
// Registers.IntForce.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_force",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Info, "INT_FORCE 写入: 0x{0:X8}", val);
// intFTP |= (uint)val;
// UpdateInterrupts();
// });
// Registers.IntClr.Define(this)
// .WithValueField(0, 32, FieldMode.Write, name: "int_clr",
// writeCallback: (_, val) =>
// {
// this.Log(LogLevel.Debug, "INT_CLR 写入: 0x{0:X8}", val);
// intFTP &= ~(uint)val;
// UpdateInterrupts();
// });
}
public void OnGPIO(int irq, bool value)
{
if (irq < 0 || irq > 15)
{
this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
return;
}
if(value)
{
this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// 自动使能中断
intMaskPriority |= (uint)(1 << irq);
this.Log(LogLevel.Info, "自动使能中断 {0}: INT_MASK_PRIORITY = 0x{1:X8}",
irq, intMaskPriority);
//设置挂起寄存器
intFTP |= (uint)(1 << irq);
this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
UpdateInterrupts();
}
else
{
}
//this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
//UpdateInterrupts();
// if (irq < 0 || irq > 15)
// {
// this.Log(LogLevel.Error, "无效的中断号: {0}", irq);
// return;
// }
// this.Log(LogLevel.Info, "*** 中断控制器接收到信号 IRQ{0}: {1} ***", irq, value ? "拉高" : "拉低");
// if (value)
// {
// intFTP |= (uint)(1 << irq);
// this.Log(LogLevel.Info, "设置挂起位: INT_F_T_P = 0x{0:X8}", intFTP);
// }
// else
// {
// }
// this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
// UpdateInterrupts();
}
private void UpdateInterrupts()
{
this.Log(LogLevel.Info, "调用 UpdateInterrupts() 检查是否转发到CPU...");
this.Log(LogLevel.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}",
intMaskPriority, intFTP);
for (int i = 15; i > 0; i--)
{
//bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4);
bool masked = ((intMaskPriority & (uint)(1 << i)) != 0);
bool pending = (intFTP & (uint)(1 << i)) != 0;
if (i == 5)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (i == 4)
{
this.Log(LogLevel.Info, "IRQ{0} 状态检查: masked={1}, pending={2}", i, masked, pending);
}
if (masked && pending)
{
if (Connections.TryGetValue(i, out var gpio))
{
gpio.Set(true);
this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i);
var localI = i;
machine.ScheduleAction(TimeInterval.FromMicroseconds(1),
_ => {
if (Connections.TryGetValue(localI, out var g))
{
g.Set(false);
machine.ScheduleAction(TimeInterval.FromMicroseconds(10),
_ => {
intFTP &= ~(uint)(1 << localI);
this.Log(LogLevel.Info, "*** 10us 安全期已过,自动清除中断 {0} 的挂起位 ***", localI);
UpdateInterrupts();
});
}
});
}
else
{
this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i);
}
}
}
}
public override void Reset()
{
base.Reset();
intMaskPriority = 0;
intFTP = 0;
intClr = 0;
}
public long Size => 0x10;
public IReadOnlyDictionary<int, IGPIO> Connections { get; }
private readonly IMachine machine;
private readonly Dictionary<int, IGPIO> connections;
private readonly Dictionary<IGPIO, int> gpioToIrqMap; // 字段声明
private readonly bool forceEnableIRQ4 = true;
private uint intMaskPriority;
private uint intFTP;
private uint intClr;
// 寄存器定义
private enum Registers
{
IntMaskPriority = 0x00,
IntFTP = 0x04,
IntForce = 0x08,
IntClr = 0x0C,
}
}
}