[嵌入式系统-37]:龙芯1B 开发学习套件 -6-协处理器CP0之CPU异常处理与外部中断控制器的中断处理

news2024/11/25 23:42:44

目录

一、MPIS CPU Core与32个异常exception

1.1 龙芯1B的MIPS CPU IP Core

1.2 MIP32指令系统

1.3 MIPS CPU寄存器

1.4 龙芯异常exception与中断interrupt的区别

1.5 向量中断与非向量中断

 1.6 MIPS CPU的异常向量与异常向量号:向量中断的支持

二、协议处理器CP0的中断控制与8个中断

2.1 CP0概述

2.2 协处理器支持的32个寄存器与CP0寄存器操作指令

 2.3 CPU协处理器CP0支持的指令执行异常:32个异常​编辑

2.4 CPU协处理器CP0支持的中断:8个中断

2.4.1 默认的中断号定义

2.4.2 中断号的配置与控制

2.5 协处理器CP0的中断服务程序

三、4个外部中断控制器与128个外部中断

3.1 外部中断源与4个中断控制器:INT0、INT1、INT2、INT3

3.2 如何配置外部中断源

3.3 四个中断控制器控制的所有外部中断的中断向量表

3.2.1 软件中断向量表结构定义:ls1b_irq.c

3.2.2 软件中断向量表定义:ls1b_irq.c和ls1b_irq.h

3.3.3 默认的中断处理或中断服务程序:ls1b_irq.c

3.3.4 中断向量表的初始化

3.3.5 安装用户自定义的中断服务程序的安装与移除

3.4 4个中断控制器的中断相关的寄存器

3.4.1 中断相关的寄存器列表(每个中断控制器有一套寄存器)

3.4.2 32bit 中断寄存器含义

3.4.3 32bits如何与中断源对应起来

3.4.5 如何根据中断原因寄存器挨个、逐一分发中断服务程序

2.4.6 四个中断控制器对应的中断服务程序

2.4.7 CPU协处理器是如何调用4个中断控制器对应的中断服务器程序


一、MPIS CPU Core与32个异常exception

1.1 龙芯1B的MIPS CPU IP Core

1.2 MIP32指令系统

1.3 MIPS CPU寄存器

1.4 龙芯异常exception与中断interrupt的区别

龙芯处理器中的异常(exception)和中断(interrupt)在概念上是有区别的,它们分别代表了不同类型的事件和处理机制:

  1. 异常(Exception):异常是指在程序执行过程中出现的一种非正常事件,通常是由指令执行时产生的,可以看作是处理器内部的问题。异常可以是因为错误的操作码、内存访问冲突、算术错误等原因导致的,需要处理器暂停当前指令的执行并执行相应的异常处理程序。异常通常由处理器本身或者处理器内部逻辑主动触发,它跳转到异常处理程序,处理完异常后再恢复到正常指令流程。

  2. 中断(Interrupt):中断是指来自外部设备的一种请求要求处理器暂停当前正在执行的程序,转而执行与中断相关的处理程序。中断是处理器响应外部事件的一种方式,可以是来自设备的信号或者时钟,需要处理器打断当前执行的指令流程,执行相应的中断服务程序,处理完中断后再返回到被中断的程序继续执行。

        在龙芯处理器中,异常和中断的区别在于触发原因和处理方式上:异常通常是由指令执行过程中的内部错误或意外情况引发,需要处理器内部去处理;而中断是由外部事件触发,需要处理器响应外部设备的请求。处理器在接收到异常或中断信号后,会根据具体情况执行相应的处理程序,保证系统的稳定运行和正确性。

1.5 同步中断与非同步中断

同步中断和异步中断是计算机中两种不同类型的中断处理方式。

  1. 同步中断

    • 在同步中断中,中断事件的发生和处理是同步发生的,也就是说,处理器会立即响应中断请求,并在当前执行的指令之后立即处理中断。
    • 这种中断处理方式通常用于一些特定的同步事件,例如硬件错误、系统调用等。在这种情况下,处理器需要立即响应并处理中断,以保证系统的正确性和稳定性。
  2. 异步中断

    • 异步中断是指中断事件的发生和处理是异步的,处理器不会立即响应中断请求,而是在当前执行的指令结束后,再由中断控制器通知处理器发生了中断事件,然后才开始处理中断。
    • 典型的异步中断包括外部设备的输入输出请求、定时器中断等。这些中断事件的发生不受处理器当前指令的影响,因此称为异步中断

总的来说,同步中断是指中断事件和处理是同步发生的,而异步中断则是指中断事件和处理是异步的,处理器会在适当的时候才响应和处理中断请求。

1.6 向量中断与非向量中断

向量中断与非向量中断是处理器中处理中断的两种主要方式。

  1. 向量中断(Vectored Interrupts):

    • 在向量中断系统中,每个中断都有一个唯一的向量号
    • 处理器硬件可以根据中断向量号直接访问/调用中断服务程序的入口地址
    • 当中断发生时,处理器硬件会自动跳转到相应中断服务程序的入口地址。
    • 向量中断系统通常能够提供更快的中断响应时间,因为处理器软件不需要额外的逻辑来确定中断服务程序的入口地址。
  2. 非向量中断(Non-Vectored Interrupts):

    • 在非向量中断系统中,中断服务程序的入口地址不是由中断向量表直接确定的。
    • 处理器收到中断后,需要通过硬件设计或软件配置来确定统一的中断服务程序的入口地址。如在龙芯1B中为c_exception_handler。
    • 通常需要额外的逻辑来确定中断服务程序的入口地址,因此可能导致较长的中断响应时间。包括额外的硬件逻辑和额外的软件逻辑,硬件逻辑包括控制器和原因寄存器,软件包括读取中断原因寄存器,并根据中断原因寄存器执行中断,此时的中断向量表是通过软件数组来维护的。
    • 非向量中断系统在处理不同类型的中断时可能需要更多的处理逻辑。

 1.7 MIPS CPU的异常向量与异常向量号:向量中断的支持

龙芯1B GS232处理器支持向量中断(Non-Vectored Interrupts)和非向量中断

如下是1B GS232处理器支持的异常向量表:

实际上,龙芯1B也支持非向量中断,非向量中断更加的灵活,大部分场景下,采用的是非向量中断,下面就阐述龙芯1B对非向量中断的支持。

二、协议处理器CP0的中断控制与8个中断

2.1 CP0概述

龙芯1B协处理器CP0(Coprocessor 0)是龙芯处理器(Loongson)中的一个重要组成部分,主要用于管理处理器的系统级行为和状态信息。CP0是一个与主处理器CPU紧密集成的协处理器,它的功能主要有以下几个方面:

  1. 地址转换和虚拟存储管理MMU:CP0可以实现物理地址的解析和转换,支持虚拟存储管理,使得应用程序可以像访问物理内存一样方便地访问虚拟内存区域。

  2. 异常和中断处理(本文要深入讨论的部分):CP0是处理器内部异常exception和外部中断Interrupt处理的核心,它存储了异常和中断向量表、错误状态码等信息,并负责中断的响应和异常处理程序的执行

  3. 性能计数器和性能分析:CP0中还包括可编程的性能计数器和时钟戳记寄存器,可以用于对程序的性能分析和调优,并支持操作系统的性能监控功能。

  4. 系统控制寄存器:CP0中还包含了一些系统级别的控制寄存器,可以用于修改处理器的运行状态,如设置缓存策略、开/关写缓冲等。

总之,龙芯1B协处理器CP0是Loongson处理器的重要组成部分,它管理和控制处理器中的系统级行为和状态信息,为操作系统和应用程序提供了重要的支持和保障。

2.2 协处理器支持的32个寄存器与CP0寄存器操作指令

协处理器支持32个寄存器,其中部分寄存器用于中断控制!!!

 2.3 CPU协处理器CP0支持的指令执行异常:32个异常

备注:

  • 异常代码0:代表8个中断异常,在异常编码中,编码最小,优先级最低。
  • 上述指令异常,部分需要软件处理,大部分是不需要软件处理的,而是有硬件电路进行处理
  • Cause寄存器中的代码,不需要提供中断服务程序,提供个软件记录和现实异常的原因,辅助定位,大部分的异常处理,是由硬件完成纠错和处理,不需要软件参与。软件只需要把这些异常的原因记录和现实下来。

/*
 * Define the name of the CPU family.
 */
#define CPU_NAME "MIPS"

/*
 * MIPS Vector numbers for exception conditions. This is a direct map to the causes.
 */
#define MIPS_EXCEPTION_BASE             0

#define MIPS_EXCEPTION_INT              MIPS_EXCEPTION_BASE+0
#define MIPS_EXCEPTION_MOD              MIPS_EXCEPTION_BASE+1
#define MIPS_EXCEPTION_TLBL             MIPS_EXCEPTION_BASE+2
#define MIPS_EXCEPTION_TLBS             MIPS_EXCEPTION_BASE+3
#define MIPS_EXCEPTION_ADEL             MIPS_EXCEPTION_BASE+4
#define MIPS_EXCEPTION_ADES             MIPS_EXCEPTION_BASE+5
#define MIPS_EXCEPTION_IBE              MIPS_EXCEPTION_BASE+6
#define MIPS_EXCEPTION_DBE              MIPS_EXCEPTION_BASE+7
#define MIPS_EXCEPTION_SYSCALL          MIPS_EXCEPTION_BASE+8
#define MIPS_EXCEPTION_BREAK            MIPS_EXCEPTION_BASE+9
#define MIPS_EXCEPTION_RI               MIPS_EXCEPTION_BASE+10
#define MIPS_EXCEPTION_CPU              MIPS_EXCEPTION_BASE+11
#define MIPS_EXCEPTION_OVERFLOW         MIPS_EXCEPTION_BASE+12
#define MIPS_EXCEPTION_TRAP             MIPS_EXCEPTION_BASE+13
#define MIPS_EXCEPTION_VCEI             MIPS_EXCEPTION_BASE+14
/* FPE only on mips2 and higher */
#define MIPS_EXCEPTION_FPE              MIPS_EXCEPTION_BASE+15
#define MIPS_EXCEPTION_C2E              MIPS_EXCEPTION_BASE+16
/* 17-22 reserved */
#define MIPS_EXCEPTION_WATCH            MIPS_EXCEPTION_BASE+23
/* 24-30 reserved */
#define MIPS_EXCEPTION_VCED             MIPS_EXCEPTION_BASE+31

#define MIPS_INTERRUPT_BASE             MIPS_EXCEPTION_BASE+32 

#define MIPS_EXCEPTION_BASE             0

#define MIPS_EXCEPTION_INT                   MIPS_EXCEPTION_BASE+0  # 中断异常

#define MIPS_EXCEPTION_WATCH            MIPS_EXCEPTION_BASE+23

#define MIPS_EXCEPTION_VCED               MIPS_EXCEPTION_BASE+31

#define MIPS_INTERRUPT_BASE                MIPS_EXCEPTION_BASE+32  //中断控制器的中断服务程序入口

2.4 CPU协处理器CP0支持的中断:8个中断

2.4.1 默认的中断号定义

/*
 * CP0 Cause ($12)  IP bit(15:8)=IP[7:0], IP[1:0] is soft-interrupt
 *     Status($13)  IM bit(15:8) if mask interrupts
 *
 */
#define LS1B_IRQ_SW0             (MIPS_INTERRUPT_BASE + 0)  //软件触发的中断SW0
#define LS1B_IRQ_SW1             (MIPS_INTERRUPT_BASE + 1)  //软件触发的中断SW1

#define LS1B_IRQ0_REQ    (MIPS_INTERRUPT_BASE + 2) //来自SOC芯片的中断控制器0
#define LS1B_IRQ1_REQ    (MIPS_INTERRUPT_BASE + 3) //来自SOC芯片的中断控制器1
#define LS1B_IRQ2_REQ    (MIPS_INTERRUPT_BASE + 4) //来自SOC芯片的中断控制器2
#define LS1B_IRQ3_REQ     (MIPS_INTERRUPT_BASE + 5)//来自SOC芯片的中断控制器3
#define LS1B_IRQ_PERF           (MIPS_INTERRUPT_BASE + 6) //来自CP0的性能统计
#define LS1B_IRQ_CNT            (MIPS_INTERRUPT_BASE + 7)  //来自CP0的Tick计数,用
于操作系统tick调度

// 备注:

//中断号越大,优先级越高

//中断号越小,优先级越低

2.4.2 中断号的配置与控制

默认情况下,性能统计和Tick计数的中断,其中断号是6和7,龙芯1B允许对该中断号进行修改,以降低其优先级,默认情况下,数值越大,优先级越高。

  • IPTI:自定义Tick计数器中断的中断号
  • IPPCI:自定义性能统计计数器中断的中断号
  • VS:定义中断向量表的地址间隔,0表示相邻,1表示相隔32字节.....

2.5 协处理器CP0的中断服务程序

void c_interrupt_handler(void *p)
{
	unsigned int sr;
	unsigned int cause;

	mips_get_sr(sr);
	
	mips_get_cause(cause);  

	cause &= (sr & SR_IMASK);
	cause >>= CAUSE_IPSHIFT;

	/******************************************************************
	 * XXX use as bsp system tick generator.
	 */
	if (cause & 0x80)			/* count/compare interrupt */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_CNT);
	}

	if (cause & 0x04)			/* Interrupt controller 0 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC0_BASE);
	}

	if (cause & 0x08)			/* Interrupt controller 1 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC1_BASE);
	}

	if (cause & 0x10)			/* Interrupt controller 2 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC2_BASE);
	}

	if (cause & 0x20)			/* Interrupt controller 3 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC3_BASE);
	}

#if defined(LS1B)

	if (cause & 0x40)			/* Performance counter */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_PERF);
	}

#elif defined(LS1C)

	if (cause & 0x40)			/* Interrupt controller 4 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC4_BASE);
	}

#endif

	if (cause & 0x02)			/* Soft Interrupt SW[1] */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_SW1);
	}
	
	if (cause & 0x01)			/* Soft Interrupt SW[0] */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_SW0);
	}
	
	// mips_set_cause(0);
}

三、4个外部中断控制器与128个外部中断

3.1 外部中断源与4个中断控制器:INT0、INT1、INT2、INT3

龙芯1B SOC芯片内置了4个简单、灵活的中断控制器,即INT0、INT1、INT2、INT3,用于管理SOC芯片外设和GPIO的中断。每个中断控制器最大管辖32个中断。

1B芯片的中断控制器除了管理 GPIO输入的中断信号外,中断控制器还处理内部设备引起的中断。所有的中断寄存器的位域安排相同,一个中断源对应其中一位

SOC的中断控制器共四个中断线输出连接到CPU模块,分别对应 INT0, INT1, INT2, INT3

SOC芯片中断控制器本身能够支持 64个内部中断和 64个 GPIO的中断,最大一共128个硬件外部中断源,这128个中断源分为四组,每组最大支持32个中断源,分别归组为:INT0, INT1, INT2, INT3。

其中 INT0和 INT1分别对应于 64个内部中断的前后 32位,INT2和 INT3对应于 64个外部 GPIO中断。但龙芯1B的实现过程中,并非所有的中断源都被使用,部分中断源是保留未使用,

具体中断源如下表所示: 

从上图可以看出:

(1)GPIO31、GPIO62、GPIO63都未使用,属于保留位,因此一个64-3=61个GPIO中断源。

(2)并非所有的INT0和INT1的外设中断都被使用上,实际上,龙芯1B SOC芯片,并没有那么多外设,因此,大量的位都是闲置的,属于保留为,未定义其行为。

3.2 如何配置外部中断源

3.3 四个中断控制器控制的所有外部中断的中断向量表

3.2.1 软件中断向量表结构定义:ls1b_irq.c

/* 中断向量表 */
typedef struct isr_tbl
{
	void (*handler)(int, void *);       // 中断句柄
	unsigned int arg;                   // 参数 
} isr_tbl_t;

3.2.2 软件中断向量表定义:ls1b_irq.c和ls1b_irq.h

定义龙芯1B实际支持的中断源(去除保留位)


/******************************************************************************
 * Interrupt Vector Numbers
 * MIPS_INTERRUPT_BASE should be 32 (0x20)
 ******************************************************************************/

/*
 * CP0 Cause ($12)  IP bit(15:8)=IP[7:0],

*       IP[1:0] is soft-interrupt
 *     Status($13)  IM bit(15:8) if mask interrupts
 *
 */
#define LS1B_IRQ_SW0            (MIPS_INTERRUPT_BASE + 0)   # 协处理器的软中断
#define LS1B_IRQ_SW1            (MIPS_INTERRUPT_BASE + 1)   # 协处理器的软中断
#define LS1B_IRQ0_REQ           (MIPS_INTERRUPT_BASE + 2)  # 协处理器的中断请求0
#define LS1B_IRQ1_REQ           (MIPS_INTERRUPT_BASE + 3)   # 协处理器的中断请求1
#define LS1B_IRQ2_REQ           (MIPS_INTERRUPT_BASE + 4)   # 协处理器的中断请求2
#define LS1B_IRQ3_REQ           (MIPS_INTERRUPT_BASE + 5)   # 协处理器的中断请求3
#define LS1B_IRQ_PERF           (MIPS_INTERRUPT_BASE + 6)   # 协处理器的性能统计中断
#define LS1B_IRQ_CNT            (MIPS_INTERRUPT_BASE + 7)    # 协处理器的计数或tick中断,操作系统调度使用

/*
 * Interrupt Control 0 Interrupts: 中断控制器0支持的外设中断数量:29个
 */
#define LS1B_IRQ0_BASE          (MIPS_INTERRUPT_BASE + 8)

#define LS1B_UART0_IRQ          (LS1B_IRQ0_BASE + 2)
#define LS1B_UART1_IRQ          (LS1B_IRQ0_BASE + 3)
#define LS1B_UART2_IRQ          (LS1B_IRQ0_BASE + 4)
#define LS1B_UART3_IRQ          (LS1B_IRQ0_BASE + 5)
#define LS1B_CAN0_IRQ           (LS1B_IRQ0_BASE + 6)
#define LS1B_CAN1_IRQ           (LS1B_IRQ0_BASE + 7)
#define LS1B_SPI0_IRQ           (LS1B_IRQ0_BASE + 8)
#define LS1B_SPI1_IRQ           (LS1B_IRQ0_BASE + 9)
#define LS1B_AC97_IRQ           (LS1B_IRQ0_BASE + 10)
#define LS1B_DMA0_IRQ           (LS1B_IRQ0_BASE + 13)
#define LS1B_DMA1_IRQ           (LS1B_IRQ0_BASE + 14)
#define LS1B_DMA2_IRQ           (LS1B_IRQ0_BASE + 15)
#define LS1B_PWM0_IRQ           (LS1B_IRQ0_BASE + 17)
#define LS1B_PWM1_IRQ           (LS1B_IRQ0_BASE + 18)
#define LS1B_PWM2_IRQ           (LS1B_IRQ0_BASE + 19)
#define LS1B_PWM3_IRQ           (LS1B_IRQ0_BASE + 20)
#define LS1B_RTC0_IRQ           (LS1B_IRQ0_BASE + 21)
#define LS1B_RTC1_IRQ           (LS1B_IRQ0_BASE + 22)
#define LS1B_RTC2_IRQ           (LS1B_IRQ0_BASE + 23)
#define LS1B_TOY0_IRQ           (LS1B_IRQ0_BASE + 24)
#define LS1B_TOY1_IRQ           (LS1B_IRQ0_BASE + 25)
#define LS1B_TOY2_IRQ           (LS1B_IRQ0_BASE + 26)
#define LS1B_RTC_IRQ            (LS1B_IRQ0_BASE + 27)
#define LS1B_TOY_IRQ            (LS1B_IRQ0_BASE + 28)
#define LS1B_UART4_IRQ          (LS1B_IRQ0_BASE + 29)
#define LS1B_UART5_IRQ          (LS1B_IRQ0_BASE + 30)

/*
 * Interrupt Control 1 interrupts:中断控制器1支持的外设中断:4个
 */
#define LS1B_IRQ1_BASE          (MIPS_INTERRUPT_BASE + 40)

#define LS1B_EHCI_IRQ           (LS1B_IRQ1_BASE + 0)
#define LS1B_OHCI_IRQ           (LS1B_IRQ1_BASE + 1)
#define LS1B_GMAC0_IRQ          (LS1B_IRQ1_BASE + 2)
#define LS1B_GMAC1_IRQ          (LS1B_IRQ1_BASE + 3)

/*
 * Interrupt Control 2 interrupts (GPIO):中断控制器2支持的GPIO中断数:31个
 */
#define LS1B_IRQ2_BASE          (MIPS_INTERRUPT_BASE + 72)

#define LS1B_GPIO0_IRQ          (LS1B_IRQ2_BASE + 0)
#define LS1B_GPIO1_IRQ          (LS1B_IRQ2_BASE + 1)
#define LS1B_GPIO2_IRQ          (LS1B_IRQ2_BASE + 2)
#define LS1B_GPIO3_IRQ          (LS1B_IRQ2_BASE + 3)
#define LS1B_GPIO4_IRQ          (LS1B_IRQ2_BASE + 4)
#define LS1B_GPIO5_IRQ          (LS1B_IRQ2_BASE + 5)
#define LS1B_GPIO6_IRQ          (LS1B_IRQ2_BASE + 6)
#define LS1B_GPIO7_IRQ          (LS1B_IRQ2_BASE + 7)
#define LS1B_GPIO8_IRQ          (LS1B_IRQ2_BASE + 8)
#define LS1B_GPIO9_IRQ          (LS1B_IRQ2_BASE + 9)
#define LS1B_GPIO10_IRQ         (LS1B_IRQ2_BASE + 10)
#define LS1B_GPIO11_IRQ         (LS1B_IRQ2_BASE + 11)
#define LS1B_GPIO12_IRQ         (LS1B_IRQ2_BASE + 12)
#define LS1B_GPIO13_IRQ         (LS1B_IRQ2_BASE + 13)
#define LS1B_GPIO14_IRQ         (LS1B_IRQ2_BASE + 14)
#define LS1B_GPIO15_IRQ         (LS1B_IRQ2_BASE + 15)
#define LS1B_GPIO16_IRQ         (LS1B_IRQ2_BASE + 16)
#define LS1B_GPIO17_IRQ         (LS1B_IRQ2_BASE + 17)
#define LS1B_GPIO18_IRQ         (LS1B_IRQ2_BASE + 18)
#define LS1B_GPIO19_IRQ         (LS1B_IRQ2_BASE + 19)
#define LS1B_GPIO20_IRQ         (LS1B_IRQ2_BASE + 20)
#define LS1B_GPIO21_IRQ         (LS1B_IRQ2_BASE + 21)
#define LS1B_GPIO22_IRQ         (LS1B_IRQ2_BASE + 22)
#define LS1B_GPIO23_IRQ         (LS1B_IRQ2_BASE + 23)
#define LS1B_GPIO24_IRQ         (LS1B_IRQ2_BASE + 24)
#define LS1B_GPIO25_IRQ         (LS1B_IRQ2_BASE + 25)
#define LS1B_GPIO26_IRQ         (LS1B_IRQ2_BASE + 26)
#define LS1B_GPIO27_IRQ         (LS1B_IRQ2_BASE + 27)
#define LS1B_GPIO28_IRQ         (LS1B_IRQ2_BASE + 28)
#define LS1B_GPIO29_IRQ         (LS1B_IRQ2_BASE + 29)
#define LS1B_GPIO30_IRQ         (LS1B_IRQ2_BASE + 30)
 
/*
 * Interrupt Control 3 source bit (GPIO):中断控制器3支持的GPIO中断数:30个。
 */
#define LS1B_IRQ3_BASE          (MIPS_INTERRUPT_BASE + 104)

#define LS1B_GPIO32_IRQ         (LS1B_IRQ3_BASE + 0)
#define LS1B_GPIO33_IRQ         (LS1B_IRQ3_BASE + 1)
#define LS1B_GPIO34_IRQ         (LS1B_IRQ3_BASE + 2)
#define LS1B_GPIO35_IRQ         (LS1B_IRQ3_BASE + 3)
#define LS1B_GPIO36_IRQ         (LS1B_IRQ3_BASE + 4)
#define LS1B_GPIO37_IRQ         (LS1B_IRQ3_BASE + 5)
#define LS1B_GPIO38_IRQ         (LS1B_IRQ3_BASE + 6)
#define LS1B_GPIO39_IRQ         (LS1B_IRQ3_BASE + 7)
#define LS1B_GPIO40_IRQ         (LS1B_IRQ3_BASE + 8)
#define LS1B_GPIO41_IRQ         (LS1B_IRQ3_BASE + 9)
#define LS1B_GPIO42_IRQ         (LS1B_IRQ3_BASE + 10)
#define LS1B_GPIO43_IRQ         (LS1B_IRQ3_BASE + 11)
#define LS1B_GPIO44_IRQ         (LS1B_IRQ3_BASE + 12)
#define LS1B_GPIO45_IRQ         (LS1B_IRQ3_BASE + 13)
#define LS1B_GPIO46_IRQ         (LS1B_IRQ3_BASE + 14)
#define LS1B_GPIO47_IRQ         (LS1B_IRQ3_BASE + 15)
#define LS1B_GPIO48_IRQ         (LS1B_IRQ3_BASE + 16)
#define LS1B_GPIO49_IRQ         (LS1B_IRQ3_BASE + 17)
#define LS1B_GPIO50_IRQ         (LS1B_IRQ3_BASE + 18)
#define LS1B_GPIO51_IRQ         (LS1B_IRQ3_BASE + 19)
#define LS1B_GPIO52_IRQ         (LS1B_IRQ3_BASE + 20)
#define LS1B_GPIO53_IRQ         (LS1B_IRQ3_BASE + 21)
#define LS1B_GPIO54_IRQ         (LS1B_IRQ3_BASE + 22)
#define LS1B_GPIO55_IRQ         (LS1B_IRQ3_BASE + 23)
#define LS1B_GPIO56_IRQ         (LS1B_IRQ3_BASE + 24)
#define LS1B_GPIO57_IRQ         (LS1B_IRQ3_BASE + 25)
#define LS1B_GPIO58_IRQ         (LS1B_IRQ3_BASE + 26)
#define LS1B_GPIO59_IRQ         (LS1B_IRQ3_BASE + 27)
#define LS1B_GPIO60_IRQ         (LS1B_IRQ3_BASE + 28)
#define LS1B_GPIO61_IRQ         (LS1B_IRQ3_BASE + 29)

#define LS1B_MAXIMUM_VECTORS        (LS1B_GPIO61_IRQ+1)

#define BSP_INTERRUPT_VECTOR_MIN    0
#define BSP_INTERRUPT_VECTOR_MAX    LS1B_MAXIMUM_VECTORS

备注:中断向量表中一共支持8 + 29 + 4 + 31 + 30 = 8 + 33 + 61 = 102个中断。

中断向量表:

static isr_tbl_t isr_table[BSP_INTERRUPT_VECTOR_MAX];

3.3.3 默认的中断处理或中断服务程序:ls1b_irq.c

/*
 * 默认中断 
 */
static void mips_default_isr(int vector, void *arg)
{
	unsigned int sr;
	unsigned int cause;

	mips_get_sr(sr);
	mips_get_cause(cause);

	printf("Unhandled isr exception: vector 0x%02x, cause 0x%08X, sr 0x%08X\n",
	        vector, cause, sr);

	while (1)
	    ;
}

3.3.4 中断向量表的初始化

/* 
 * 初始化
 */ 
void mips_init_isr_table(void)
{
	unsigned int i;
	
	for (i=0; i<BSP_INTERRUPT_VECTOR_MAX; i++) 
    {
		isr_table[i].handler = mips_default_isr;
		isr_table[i].arg = i;
	}
}

使用默认的中断服务程序mips_default_isr初始化中断向量表。

3.3.5 安装用户自定义的中断服务程序的安装与移除

void ls1x_install_irq_handler(int vector, void (*isr)(int, void *), void *arg)
{
    if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
    {
        mips_interrupt_disable();
        isr_table[vector].handler = isr;
        isr_table[vector].arg = (unsigned int)arg;
        mips_interrupt_enable();
    }
}

void ls1x_remove_irq_handler(int vector)
{
    if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
    {
        mips_interrupt_disable();
        isr_table[vector].handler = mips_default_isr;
        isr_table[vector].arg = vector;
        mips_interrupt_enable();
    }
}

3.4 4个中断控制器的中断相关的寄存器

3.4.1 中断相关的寄存器列表(每个中断控制器有一套寄存器)

/*
 * Interrupt Control register
 */
#define LS1B_INTC0_BASE         0xBFD01040  #中断控制器0对应的寄存器的基地址
#define LS1B_INTC1_BASE         0xBFD01058  #中断控制器1对应的寄存器的基地址
#define LS1B_INTC2_BASE         0xBFD01070  #中断控制器2对应的寄存器的基地址
#define LS1B_INTC3_BASE         0xBFD01088  #中断控制器3对应的寄存器的基地址

#define LS1B_INTC_ISR(base)     (*(volatile unsigned int*)(base + 0x00))   /* 中断控制状态寄存器 */
#define LS1B_INTC_IEN(base)     (*(volatile unsigned int*)(base + 0x04))   /* 中断控制使能寄存器 */
#define LS1B_INTC_SET(base)     (*(volatile unsigned int*)(base + 0x08))   /* 中断置位寄存器 */
#define LS1B_INTC_CLR(base)     (*(volatile unsigned int*)(base + 0x0C))   /* 中断清空寄存器 */
#define LS1B_INTC_POL(base)     (*(volatile unsigned int*)(base + 0x10))   /* 高电平触发中断使能寄存器 */
                                                                           /* EDGE 电平触发时: 1=高电平触发, 0=低电平触发
                                                                              EDGE 边沿触发时: 1=上升沿触发, 0=下降沿触发 */
#define LS1B_INTC_EDGE(base)    (*(volatile unsigned int*)(base + 0x14))   /* 边沿触发中断使能寄存器; 1:边沿触发, 0: 电平触发 */

3.4.2 32bit 中断寄存器含义

(1)中断控制状态寄存器:表面是否有某种中断发生

(2)中断控制使能寄存器:使能某个中断控制器的某个中断

(3)中断置位寄存器:强制置位对应bits的中断

(4)中断清空寄存器:强制清空对应bit的中断

(5)高电平触发中断使能寄存器:中断使能

3.4.3 32bits如何与中断源对应起来

四个中断控制器对应的bits有各自的含义

/*
 * Interrupt Control 0 source bit:中断控制器0的中断源
 */
#define INTC0_UART5_BIT         bit(30)
#define INTC0_UART4_BIT         bit(29)
#define INTC0_TOY_BIT           bit(28)
#define INTC0_RTC_BIT           bit(27)
#define INTC0_TOY2_BIT          bit(26)
#define INTC0_TOY1_BIT          bit(25)
#define INTC0_TOY0_BIT          bit(24)
#define INTC0_RTC2_BIT          bit(23)
#define INTC0_RTC1_BIT          bit(22)
#define INTC0_RTC0_BIT          bit(21)
#define INTC0_PWM3_BIT          bit(20)
#define INTC0_PWM2_BIT          bit(19)
#define INTC0_PWM1_BIT          bit(18)
#define INTC0_PWM0_BIT          bit(17)
#define INTC0_DMA2_BIT          bit(15)
#define INTC0_DMA1_BIT          bit(14)
#define INTC0_DMA0_BIT          bit(13)
#define INTC0_AC97_BIT          bit(10)
#define INTC0_SPI1_BIT          bit(9)
#define INTC0_SPI0_BIT          bit(8)
#define INTC0_CAN1_BIT          bit(7)
#define INTC0_CAN0_BIT          bit(6)
#define INTC0_UART3_BIT         bit(5)
#define INTC0_UART2_BIT         bit(4)
#define INTC0_UART1_BIT         bit(3)
#define INTC0_UART0_BIT         bit(2)

/*
 * Interrupt Control 1 source bit:中断控制器1的中断源
 */
#define INTC1_GMAC1_BIT         bit(3)
#define INTC1_GMAC0_BIT         bit(2)
#define INTC1_OHCI_BIT          bit(1)
#define INTC1_EHCI_BIT          bit(0)

/*
 * Interrupt Control 2 source bit (GPIO) :中断控制器2对应的中断源
 */
#define INTC2_GPIO30_BIT        bit(30)
#define INTC2_GPIO29_BIT        bit(29)
#define INTC2_GPIO28_BIT        bit(28)
#define INTC2_GPIO27_BIT        bit(27)
#define INTC2_GPIO26_BIT        bit(26)
#define INTC2_GPIO25_BIT        bit(25)
#define INTC2_GPIO24_BIT        bit(24)
#define INTC2_GPIO23_BIT        bit(23)
#define INTC2_GPIO22_BIT        bit(22)
#define INTC2_GPIO21_BIT        bit(21)
#define INTC2_GPIO20_BIT        bit(20)
#define INTC2_GPIO19_BIT        bit(19)
#define INTC2_GPIO18_BIT        bit(18)
#define INTC2_GPIO17_BIT        bit(17)
#define INTC2_GPIO16_BIT        bit(16)
#define INTC2_GPIO15_BIT        bit(15)
#define INTC2_GPIO14_BIT        bit(14)
#define INTC2_GPIO13_BIT        bit(13)
#define INTC2_GPIO12_BIT        bit(12)
#define INTC2_GPIO11_BIT        bit(11)
#define INTC2_GPIO10_BIT        bit(10)
#define INTC2_GPIO9_BIT         bit(9)
#define INTC2_GPIO8_BIT         bit(8)
#define INTC2_GPIO7_BIT         bit(7)
#define INTC2_GPIO6_BIT         bit(6)
#define INTC2_GPIO5_BIT         bit(5)
#define INTC2_GPIO4_BIT         bit(4)
#define INTC2_GPIO3_BIT         bit(3)
#define INTC2_GPIO2_BIT         bit(2)
#define INTC2_GPIO1_BIT         bit(1)
#define INTC2_GPIO0_BIT         bit(0)

/*
 * Interrupt Control 3 source bit (GPIO):中断控制器3对应的中断源
 */
#define INTC3_GPIO61_BIT        bit(29)
#define INTC3_GPIO60_BIT        bit(28)
#define INTC3_GPIO59_BIT        bit(27)
#define INTC3_GPIO58_BIT        bit(26)
#define INTC3_GPIO57_BIT        bit(25)
#define INTC3_GPIO56_BIT        bit(24)
#define INTC3_GPIO55_BIT        bit(23)
#define INTC3_GPIO54_BIT        bit(22)
#define INTC3_GPIO53_BIT        bit(21)
#define INTC3_GPIO52_BIT        bit(20)
#define INTC3_GPIO51_BIT        bit(19)
#define INTC3_GPIO50_BIT        bit(18)
#define INTC3_GPIO49_BIT        bit(17)
#define INTC3_GPIO48_BIT        bit(16)
#define INTC3_GPIO47_BIT        bit(15)
#define INTC3_GPIO46_BIT        bit(14)
#define INTC3_GPIO45_BIT        bit(13)
#define INTC3_GPIO44_BIT        bit(12)
#define INTC3_GPIO43_BIT        bit(11)
#define INTC3_GPIO42_BIT        bit(10)
#define INTC3_GPIO41_BIT        bit(9)
#define INTC3_GPIO40_BIT        bit(8)
#define INTC3_GPIO39_BIT        bit(7)
#define INTC3_GPIO38_BIT        bit(6)
#define INTC3_GPIO37_BIT        bit(5)
#define INTC3_GPIO36_BIT        bit(4)
#define INTC3_GPIO35_BIT        bit(3)
#define INTC3_GPIO34_BIT        bit(2)
#define INTC3_GPIO33_BIT        bit(1)
#define INTC3_GPIO32_BIT        bit(0)

3.4.5 如何根据中断原因寄存器挨个、逐一分发中断服务程序

(1)读取中断原因寄存器

#define LS1B_INTC_ISR(base)     (*(volatile unsigned int*)(base + 0x00))   /* 中断控制状态寄存器 */

#define LS1x_INTC_ISR(base)     LS1B_INTC_ISR(base)

(2)逐一检查原因寄存器

//-----------------------------------------------------------------------------

static void call_vectored_isr(void *p, unsigned int cause, void *ctrlr)
{
    unsigned int src;
    int index;

    /* check request */
    src = LS1x_INTC_ISR((unsigned int)ctrlr);
    index = 0;

    while (src)  //挨个检查所有的中断源
    {
        /* check LSB */
        if (src & 1) 
        {
            /* clear */
            LS1x_INTC_CLR((unsigned int)ctrlr) = (1 << index);
            asm volatile ("sync");
            
            if ((unsigned int)ctrlr == LS1x_INTC0_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ0_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC1_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ1_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC2_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ2_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC3_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ3_BASE + index);
            }
    #if defined(LS1C)
            else if ((unsigned int)ctrlr == LS1x_INTC4_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ4_BASE + index);
            }
    #endif
        }

        index++;

        /* shift, and make sure MSB is clear */
        src = (src >> 1) & 0x7fffffff;  //挨个检查所有的中断源
    }
}

(3)根据中断向量表执行中断服务器程序

//-----------------------------------------------------------------------------
// 中断分发 
//-----------------------------------------------------------------------------

static void bsp_irq_handler_dispatch(int vector)
{
	if ((vector >= 0) && (vector < BSP_INTERRUPT_VECTOR_MAX))
	{
	    if (isr_table[vector].handler)
        {
            /* 
             * 关中断由中断程序自己处理 
             */
             
            isr_table[vector].handler(vector, (void *)isr_table[vector].arg);
            
            /* 
             * 开中断由中断程序自己处理 
             */
        }
        else
        {
            mips_default_isr(vector, NULL);
        }
	}
	else
	{
		mips_default_isr(vector, NULL);
	}
}

2.4.6 四个中断控制器对应的中断服务程序

static void call_vectored_isr(void *p, unsigned int cause, void *ctrlr)
{
    unsigned int src;
    int index;

    /* check request */
    src = LS1x_INTC_ISR((unsigned int)ctrlr);
    index = 0;

    while (src) 
    {
        /* check LSB */
        if (src & 1) 
        {
            /* clear */
            LS1x_INTC_CLR((unsigned int)ctrlr) = (1 << index);
            asm volatile ("sync");
            
            if ((unsigned int)ctrlr == LS1x_INTC0_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ0_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC1_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ1_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC2_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ2_BASE + index);
            }
            else if ((unsigned int)ctrlr == LS1x_INTC3_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ3_BASE + index);
            }
    #if defined(LS1C)
            else if ((unsigned int)ctrlr == LS1x_INTC4_BASE)
            {
            	bsp_irq_handler_dispatch(LS1x_IRQ4_BASE + index);
            }
    #endif
        }

        index++;

        /* shift, and make sure MSB is clear */
        src = (src >> 1) & 0x7fffffff;
    }
}

2.4.7 CPU协处理器是如何调用4个中断控制器对应的中断服务器程序

void c_interrupt_handler(void *p)
{
	unsigned int sr;
	unsigned int cause;

	mips_get_sr(sr);
	
	mips_get_cause(cause);  

	cause &= (sr & SR_IMASK);
	cause >>= CAUSE_IPSHIFT;

	/******************************************************************
	 * XXX use as bsp system tick generator.
	 */
	if (cause & 0x80)			/* count/compare interrupt */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_CNT);
	}

	if (cause & 0x04)			/* Interrupt controller 0 中断控制器0对应的中断服务程序 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC0_BASE);
	}

	if (cause & 0x08)			/* Interrupt controller 1 中断控制器1对应的中断服务程序*/
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC1_BASE);
	}

	if (cause & 0x10)			/* Interrupt controller 2 中断控制器2对应的中断服务程序*/
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC2_BASE);
	}

	if (cause & 0x20)			/* Interrupt controller 3 中断控制器3对应的中断服务程序*/
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC3_BASE);
	}

#if defined(LS1B)

	if (cause & 0x40)			/* Performance counter */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_PERF);
	}

#elif defined(LS1C)

	if (cause & 0x40)			/* Interrupt controller 4 */
	{
		call_vectored_isr(p, cause, (void *)LS1x_INTC4_BASE);
	}

#endif

	if (cause & 0x02)			/* Soft Interrupt SW[1] */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_SW1);
	}
	
	if (cause & 0x01)			/* Soft Interrupt SW[0] */
	{
		bsp_irq_handler_dispatch(LS1x_IRQ_SW0);
	}
	
	// mips_set_cause(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1511581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PAT-素数专题、质因子分解、大整数计算

素数专题 1007.素数对的猜想 让我们定义dn​为&#xff1a;​ &#xff0c;其中pi​是第i个素数。显然有d1​1&#xff0c;且对于n>1有dn​是偶数。“素数对猜想”认为“存在无穷多对相邻且差为2的素数”。 现给定任意正整数N(<105)&#xff0c;请计算不超过N的满足猜想…

新火种AI|在撕裂中求前进:OpenAI最近的日子,属实不太好过。

作者&#xff1a;小岩 编辑&#xff1a;彩云 伴随着ChatGPT 火遍全球&#xff0c;OpenAI俨然成为了备受全世界关注的主角。因为有横空出世的GPT-4&#xff0c;重磅炸弹视频生成模型Sora等产品&#xff0c;OpenAI始终都是以行业霸主的姿态出现在人们的视野中。也正是因为OpenA…

vue使用elementPlus ui框架,如何给Dialog 对话框添加Loading 自定义类名显示隐藏

vue使用elementPlus ui框架时&#xff0c;如何给Dialog 对话框添加Loading 自定义类名&#xff0c;想要实现dialog对话框区域有loading效果 官方给出的这个API配置项customClass&#xff0c;使用不太明确。暂时无法实现绑定class。 最后的实现方式&#xff1a; <template&…

数据分析-Pandas如何观测数据的中心趋势度

数据分析-Pandas如何观测数据的中心趋势度 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据…

Redis中的缓存设计

缓存穿透 缓存穿透是指查询一个根本不存在的数据&#xff0c;缓存层和存储层都不会命中&#xff0c;通常处于容错的考虑&#xff0c;如果从存储层查不到数据则不写入缓存层。缓存穿透将导致不存在的数据每次请求都要到存储层去查询&#xff0c;失去了缓存保护后端存储的意义。…

基于PyTorch深度学习实战入门系列-Numpy基础全

Numpy的使用 导入Numpy模块 import numpy as np创建数组&#xff08;一维数组、小数数组、二维数组&#xff09; # 创建一个一维数组 n1 np.array([1, 2, 3]) # 创建一个含有小数的一维数组 n2 np.array([0.1, 0.2, 0.3]) # 创建一个简单的二维数组 n3 np.array([[1, 2], [3…

Apache SkyWalking 监控 Linux 实战

SkyWalking 从 8.4 版本开始支持监控主机&#xff0c;用户可以轻松从 dashboard 上检测可能的问题&#xff0c;例如当 CPU 使用过载、内存或磁盘空间不足或者当网络状态不健康时等。 与监控 MySQL Server 类似&#xff0c;SkyWalking 也是利用 Prometheus 和 OpenTelemetry 收集…

数据结构-链表(一)

一、链表简介 链表&#xff08;Linked List&#xff09;是一种常见的数据结构&#xff0c;用于存储和组织数据。与数组不同&#xff0c;链表的元素&#xff08;节点&#xff09;在内存中不必连续存储&#xff0c;而是通过指针链接在一起。 链表由多个节点组成&#xff0c;每个…

C++day2——引用、结构体、类

思维导图&#xff1a; 2、自己封装一个矩形类(Rect)&#xff0c; 拥有私有属性&#xff1a;宽度(width)、高度(height)&#xff0c; 定义公有成员函数初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w)更改高度的函数:set_h(int h) 输出该矩形的周长和面积函…

逆向案例七——中国天气质量参数搜不到加密,以及应对禁止打开开发者工具和反debuger技巧

进入相关城市数据页面&#xff0c;发现不能调试 应对方法&#xff0c;再另一个页面&#xff0c;打开开发者工具&#xff0c;选择取消停靠到单独页面 接着&#xff0c;复制链接在该页面打开。接着会遇到debugger 再debugger处打上断点&#xff0c;一律不在此处暂停。 然后点击继…

数据结构中的堆(Java)

文章目录 把普通数组转换大顶堆数组堆增删改查替换堆排序 把普通数组转换大顶堆数组 该方式适用索引为0起点的堆 在堆&#xff08;Heap&#xff09;这种数据结构中&#xff0c;节点被分为两类&#xff1a;叶子节点&#xff08;Leaf Nodes&#xff09;和非叶子节点&#xff08;N…

springboot的Converter和HttpMessageConveter

Converter和HttpMessageConveter是springboot和springmvc在处理请求的时候需要用到的。但是这两者的完全是不一样的&#xff0c;作用的地方也不一样。 1&#xff0c;springboot和springmvc处理请求的流程 先来回顾一下处理请求的流程&#xff1a; 用户向服务器发送请求&#…

云原生应用(2)之使用容器运行Nginx应用及Docker命令

一、使用Docker容器运行Nginx 1.1 使用docker run命令运行Nginx应用 1.1.1 观察下载容器镜像过程 查找本地容器镜像文件&#xff1b; 执行命令过程一&#xff1a;下载容器镜像 # docker run -d nginx:latest Unable to find image nginx:latest locally latest: Pulling from…

软考72-上午题-【面向对象技术2-UML】-UML中的图3

一、状态图 1-1、状态图的定义 状态图&#xff0c;展现了一个状态机&#xff0c;由&#xff1a;状态、转换、事件和活动组成&#xff0c;是系统的动态视图。 活动(动作) 可以在状态内执行也可以在状态转换(迁移) 时执行。 状态图强调&#xff1a;行为的事件顺序。 1-2、状态图…

【ollama】(4):在autodl中安装ollama工具,配置环境变量,修改端口,使用RTX 3080 Ti显卡,测试coder代码生成大模型

1&#xff0c;ollama项目 Ollama 是一个强大的框架&#xff0c;设计用于在 Docker 容器中部署 LLM。Ollama 的主要功能是在 Docker 容器内部署和管理 LLM 的促进者&#xff0c;它使该过程变得非常简单。它帮助用户快速在本地运行大模型&#xff0c;通过简单的安装指令&#xf…

【考研数学】660/880/1000/1800 使用手册

开门见山&#xff0c;直接介绍几个热门的习题册 660&#xff1a;660表面上叫基础通关660&#xff0c;但实际上很多题的难度并不适合基础阶段&#xff0c;建议在强化阶段搭配着 严选题做660&#xff0c;对提升做小题的速度和能力非常有帮助。 880&#xff1a;题量适中&#xf…

20240312-1-Graph(图)

Graph(图) 在面试的过程中,一般不会考到图相关的问题,因为图相关的问题难,而且描述起来很麻烦. 但是也会问道一下常见的问题,比如,最短路径,最小支撑树,拓扑排序都被问到过. 图常用的表示方法有两种: 分别是邻接矩阵和邻接表. 邻接矩阵是不错的一种图存储结构,对于边数相对顶点…

MooC下载pdf转为ppt后去除水印方法

1、从MooC下载的课件&#xff08;一般为pdf文件&#xff09;可能带有水印&#xff0c;如下图所示&#xff1a; 2、将pdf版课件转为ppt后&#xff0c;同样带有水印&#xff0c;如下图所示&#xff1a; 3、传统从pdf中去除水印方法不通用&#xff0c;未找到有效去除课件pdf方法…

c 语言中指针注意事项

看看下面两个 #include<iostream> using namespace std;int main() {int a 10;char p[6];*((int *)p) *(& a); // 正确写法*p *(&a); // 错误写法cout << *(int*)p; } 把原因写在评论区

飞塔防火墙开局百篇——002.FortiGate上网配置——在路由模式下使用虚拟接口对(virtual-wire-pair)

在路由模式下使用虚拟接口对&#xff08;virtual-wire-pair&#xff09; 拓扑配置接口配置策略 使用方有透明模式下一进一出的这样需求的组网&#xff0c;可以在路由模式下使用虚拟接口对&#xff08;virtual-wire-pair&#xff09;替代。 登陆FortiGate防火墙界面&#xff0c;…