From 699d6216aef1cc4e69458d72f70ceb0facce850c Mon Sep 17 00:00:00 2001 From: liuwb Date: Wed, 25 Mar 2026 14:20:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=89=87+=E4=B8=AD=E6=96=AD?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=99=A8=E6=88=90=E5=8A=9F=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LC3233_Timer_InterruptController.cs | 387 ++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 LC3233_Timer_InterruptController.cs diff --git a/LC3233_Timer_InterruptController.cs b/LC3233_Timer_InterruptController.cs new file mode 100644 index 0000000..5368697 --- /dev/null +++ b/LC3233_Timer_InterruptController.cs @@ -0,0 +1,387 @@ +//============================================================================ +// 作者: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(); + for (int i = 0; i <= 15; i++) + { + connections[i] = new GPIO(); + } + + + Connections = new ReadOnlyDictionary(connections); + + DefineRegisters(); + Reset(); + + this.Log(LogLevel.Info, "LC3233 中断控制器已初始化 @ 0x80020000"); + this.Log(LogLevel.Info, " 管理15个中断源 (1-15)"); + } + + /// + /// 定义寄存器映射 + /// + 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; + } + + 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.Debug, "UpdateInterrupts: MASK=0x{0:X8}, PENDING=0x{1:X8}", + intMaskPriority, intFTP); + + + for (int i = 1; i <= 15; i++) + { + bool masked = ((intMaskPriority & (uint)(1 << i)) != 0) || (forceEnableIRQ4 && i == 4); + bool pending = (intFTP & (uint)(1 << i)) != 0; + + if (i == 4) + { + this.Log(LogLevel.Info, "IRQ4 状态检查: masked={0}, pending={1}", masked, pending); + } + + if (masked && pending) + { + + if (Connections.TryGetValue(i, out var gpio)) + { + this.Log(LogLevel.Info, "===> 转发中断 {0} 到MIC@{0} (CPU中断线{0})", i); + gpio.Set(true); + + + var localI = i; + machine.ScheduleAction(TimeInterval.FromMicroseconds(1), + _ => { + if (Connections.TryGetValue(localI, out var g)) + { + g.Set(false); + } + }); + } + else + { + this.Log(LogLevel.Warning, "中断 {0} 无法转发: 连接未找到!", i); + } + } + } + } + + public override void Reset() + { + base.Reset(); + intMaskPriority = 0; + intFTP = 0; + } + + public long Size => 0x10; + + public IReadOnlyDictionary Connections { get; } + + + private readonly IMachine machine; + private readonly Dictionary connections; + private readonly bool forceEnableIRQ4 = true; + private uint intMaskPriority; + private uint intFTP; + + // 寄存器定义 + private enum Registers + { + IntMaskPriority = 0x00, + IntFTP = 0x04, + IntForce = 0x08, + IntClr = 0x0C, + } + } +}