在 MIPS 架构中,BadVAddr(Bad Virtual Address)寄存器主要用于存储导致内存管理异常(如访问非法虚拟地址)的虚拟地址。当处理器在内存访问过程中(例如通过加载 / 存储指令)检测到一个非法的虚拟地址时,这个地址会被记录在 BadVAddr 寄存器中。
- 详细作用:
- 故障诊断:对于软件调试和系统故障排查非常有用。例如,当一个程序出现段错误(Segmentation Fault),如访问了未分配的内存或者试图写入只读内存区域时,BadVAddr 寄存器会记录下引发这个错误的虚拟内存地址。操作系统或者调试工具可以读取这个寄存器来确定出错的位置,帮助程序员定位代码中的错误,比如是否是数组越界访问或者错误的指针操作导致的。
- 异常处理针对性:在异常处理程序中,BadVAddr 寄存器提供的信息可以帮助系统采取针对性的措施来处理内存访问异常。例如,如果是因为程序试图访问内核空间的受保护内存而导致的异常,根据 BadVAddr 的值可以确定具体是哪个地址引起的,从而决定是终止程序、向用户程序返回错误信息,还是尝试重新分配内存来解决问题。
AXI 的全称为 Advanced eXtensible Interface,是 AMBA 总线架构中最新且性能最好的一个总线标准,AXI的设计目标是可以在高时钟频率下运行,并在延滞时间长的状况下仍可达成高数据吞吐率
AXI总线将读/写请求与读/写结果相互分离、将数据写入和数据读出的信号相分离,可以同时进行写入和读出动作,从而最大限度地提高总线的数据吞吐率
在嵌入式设备和 FPAG 中,AXI 接口经常会用于连接各种类型的设备
AXI 接口中参与数据传输的设备可以分为 Master 端和 Slave 端,我们可以借助 Interconnect 将多个 Master 和多个 Slave 互联起来:
注意,在上图中,多个 Slave 对整个寻址空间进行了划分,每个 Slave 所对应的寻址空间不重叠,读写操作会被分配到其地址对应的 Slave 设备上
AXI 协议内容比较复杂,但是我们在实验中只会用到其中一部分,希望进一步了结 AXI 接口的同学可以查阅 AXI 接口的官方文档
实验需要用到的 AXI 总线信号可以划大致分成 5 个通道:
-
写地址通道,信号名称以 AW 开头
-
写数据通道,信号名称以 W 开头
-
写响应通道,信号名称以 R 开头
-
读地址通道,信号名称以 AR 开头
-
读数据操作,信号名称以 R 开头
-
全局信号,包括时钟信号 ACLK,和 ARESETn,注意 ARESETn 是低电平有
- AXI 写事务的产生
(1)AXI 协议概述
- AXI(Advanced eXtensible Interface)是一种高性能、高带宽的片上总线协议,用于连接处理器、内存和其他高性能设备。在 AXI 协议中,写事务用于将数据从主设备(Master)传输到从设备(Slave),比如处理器向内存写入数据。
(2)写事务产生过程
- 发起方(主设备)需求驱动:当主设备(如 CPU)需要将数据存储到外部设备(如内存)时,就会发起写事务。例如,在执行存储指令(如 MIPS 架构中的
sw
指令)时,CPU 确定要将寄存器中的数据写入内存的某个地址。这个存储操作的需求就触发了 AXI 写事务的开始。 - 信号传输过程:主设备首先通过 AXI 接口的地址通道(AW Channel)发送写地址(AWADDR)信号,这个信号包含了要写入数据的目标地址。同时,主设备在数据通道(W Channel)上准备好要写入的数据(WDATA)以及一些控制信号,如写数据有效(WVALID)信号,用于告知从设备数据是有效的。当从设备准备好接收数据时(通过 WREADY 信号表示),数据就从主设备传输到从设备,完成写事务的主要数据传输部分。
- AXI 写事务中 ID 的确定
(1)ID 的作用
- 在 AXI 协议中,ID(Transaction ID)用于标识一个事务。它主要用于支持乱序事务处理和事务的区分。例如,在一个复杂的系统中,主设备可能同时发起多个写事务,每个事务都有自己的 ID,这样可以方便地跟踪和管理这些事务,确保它们能够正确地完成,并且在需要时能够按照正确的顺序进行处理。
(2)ID 的确定方式
- 由主设备分配:ID 通常是由发起事务的主设备来确定的。主设备内部有自己的 ID 生成机制,这个机制可能是基于计数器或者其他逻辑。例如,主设备可以有一个简单的递增计数器,每发起一个新的写事务,就将计数器的值作为这个事务的 ID。这样可以保证每个事务都有一个唯一的标识符,在整个事务处理过程中(包括可能的重试、中断等情况)都能够被准确地识别。
- 考虑事务关联性:在一些情况下,ID 的分配可能还会考虑事务之间的关联性。例如,如果有一组相关的写事务(如连续写入一个数据块的多个部分),主设备可能会为它们分配一组连续的 ID 或者具有某种特定模式的 ID,以便从设备或者其他系统组件能够更容易地识别这些相关事务,并进行相应的优化处理,如缓存这些相关事务的数据,直到整个数据块都接收完成。
- AXI Burst 的概念
(1)定义
- AXI Burst 是指在 AXI 协议中,主设备可以在一次事务中连续发送多个数据单元的机制。它不是逐个发送数据,而是以突发(Burst)的方式进行传输,能够有效地提高数据传输的效率。例如,在批量数据传输的场景中,如从内存读取一个数据块或者向内存写入一个数据块,就可以使用 AXI Burst 来快速地完成传输。
(2)Burst 类型
- AXI 协议支持多种 Burst 类型,如固定突发(FIXED)、递增突发(INCR)和循环突发(WRAP)。
- 固定突发(FIXED):在整个突发传输过程中,数据单元的地址是固定不变的。这种方式适用于对同一个地址进行多次写入(如写入一个多字节的数据,每次写入一个字节,地址不变)或者从同一个地址重复读取数据的情况。
- 递增突发(INCR):数据单元的地址按照一个固定的增量逐个递增。这是最常见的一种突发类型,适用于连续的内存地址空间的数据传输,比如从一个数组的开头依次读取或写入数组元素。例如,在写入一个数组时,每次写入的地址会自动增加一个元素的大小,直到整个数组写入完成。
- 循环突发(WRAP):这种突发方式的地址会在一个特定的范围内循环变化。它在一些特定的缓存操作或者数据块循环访问的场景中比较有用,不过使用相对较少。例如,在一个循环缓冲区的数据写入操作中,可以使用循环突发来高效地利用缓冲区空间。
- 这个
soc_lite_top
模块是一个片上系统(SoC)的顶层模块,它包含了各种输入输出信号用于与外部设备交互,同时内部实例化了多个子模块来构建完整的系统功能。输入信号主要包括复位信号resetn
和时钟信号clk
,输出信号用于控制各种外部设备,如 LED 灯(led
、led_rg0
、led_rg1
)、数码管(num_csn
、num_a_g
)等,还有与按键相关的输入信号(switch
、btn_key_col
、btn_key_row
、btn_step
)用于接收用户输入。
- 通过两个
always
块,在时钟上升沿对复位信号进行同步处理。例如,always @(posedge cpu_clk)
块将外部输入的resetn
信号同步到cpu_resetn
信号,用于为 CPU 提供复位信号。这是为了避免复位信号的异步问题,确保系统的稳定复位。对于sys_resetn
信号也有类似的处理。在模拟情况下(SIMULATION
条件满足),clk_91m
作为模拟时钟信号,根据条件赋值给cpu_clk
,而sys_clk
可能直接来自外部输入clk
或者通过 PLL(锁相环)模块生成。
- 信号传递推测:
- 作为 CPU 的 AXI 接口封装模块,它会连接 CPU 的相关接口和 AXI 总线。它可能接收来自 CPU 的读写请求信号、地址信号、数据信号等,并将这些信号转换为符合 AXI 协议的格式,发送到 AXI 总线上。同时,也会接收来自 AXI 总线的响应信号(如数据读取完成信号、写入确认信号等),并转换后传递给 CPU。
- 功能推测:
- 主要功能是实现 CPU 与 AXI 总线之间的协议转换和接口适配。确保 CPU 能够正确地使用 AXI 协议与其他模块进行高效的数据传输和交互,隐藏 AXI 协议的复杂性,使 CPU 能够专注于指令执行和数据处理。
-
- 从名字推测,它主要用于处理 AXI 总线上不同时钟域之间的转换。它会接收不同频率的时钟信号(可能是
cpu_clk
、sys_clk
等),以及与 AXI 数据传输相关的信号(如地址、数据、控制信号)。
- 从名字推测,它主要用于处理 AXI 总线上不同时钟域之间的转换。它会接收不同频率的时钟信号(可能是
- 功能推测:
- 负责将在一个时钟域产生的 AXI 信号转换到另一个时钟域,确保数据在不同时钟频率的模块之间正确传输。例如,当 CPU 和存储模块(如
axi_wrap_ram
)的时钟频率不同时,它能够同步地址、数据和控制信号,避免由于时钟差异导致的数据丢失或错误传输
- 负责将在一个时钟域产生的 AXI 信号转换到另一个时钟域,确保数据在不同时钟频率的模块之间正确传输。例如,当 CPU 和存储模块(如
-
ext_int
的含义- 功能概述:
ext_int
是一个输入信号,用于接收外部中断(External Interrupt)。在处理器系统中,外部设备(如定时器、外部传感器、通信接口等)可以通过触发中断信号来请求处理器的注意,这个信号通常是高电平有效(high active
),意味着当该信号变为高电平时,表示有外部中断事件发生。 - 应用场景示例:假设系统中有一个外部定时器,当定时器计数到特定值时,它会拉高
ext_int
信号,向处理器发送中断请求。处理器在检测到这个高电平信号后,会暂停当前正在执行的任务(如果允许中断的话),转而执行与该中断对应的中断服务程序(Interrupt Service Routine,ISR)来处理定时器相关的事务,比如更新时间计数、执行定时任务等。
- 功能概述:
-
ext_int
赋值为6'd0
的含义- 值的解释:
6'd0
是一种在硬件描述语言(如 Verilog)中的常量表示方式,它表示一个 6 位宽(6
表示位宽)的十进制数(d
表示十进制),值为 0。在这里,将ext_int
赋值为6'd0
意味着在这个实例化过程中,初始情况下没有外部中断信号被触发。 - 可能的意图:这可能是用于初始化或者在某些特定的测试场景下,模拟没有外部中断的情况。例如,在系统启动阶段或者在进行一些不涉及外部中断处理的功能测试时,将
ext_int
设置为 0 可以确保处理器不会因为意外的外部中断而改变正常的执行流程,从而能够专注于其他功能(如指令执行、内部寄存器操作等)的测试或初始化操作
- 值的解释:
code
如果soc_axi_lite_top中,代码结构为
module soc_lite_top #(parameter SIMULATION=1'b0)
(
input resetn,
input clk,
//------gpio-------
output [15:0] led,
output [1 :0] led_rg0,
output [1 :0] led_rg1,
output [7 :0] num_csn,
output [6 :0] num_a_g,
input [7 :0] switch,
output [3 :0] btn_key_col,
input [3 :0] btn_key_row,
input [1 :0] btn_step
);
always @(posedge cpu_clk)
begin
cpu_resetn_t <= resetn;
cpu_resetn <= cpu_resetn_t;
end
always @(posedge sys_clk)
begin
sys_resetn_t <= resetn;
sys_resetn <= sys_resetn_t;
end
//simulation clk.
reg clk_91m;
initial
begin
clk_91m = 1'b0;
end
always #5.5 clk_91m = ~clk_91m;
generate if(SIMULATION && `SIMU_USE_PLL==0)
begin: speedup_simulation
assign cpu_clk = clk_91m;
assign sys_clk = clk;
end
else
begin: pll
clk_pll clk_pll
(
.clk_in1 (clk ),
.cpu_clk (cpu_clk),
.sys_clk (sys_clk)
);
end
endgenerate
mycpu_top u_cpu...
axi_wrap u_cpu_axi_wrap(....
axi_clock_converter u_axi_clock_sync(....
axi_crossbar_1x2 u_axi_crossbar_1x2(.....
axi_wrap_ram u_axi_ram.....
confreg #(.SIMULATION(SIMULATION)) u_confreg.....
那么各模块之间传递的信号是什么?功能是什么?
//simulation clk.
reg clk_91m;
initial
begin
clk_91m = 1'b0;
end
always #5.5 clk_91m = ~clk_91m;
generate if(SIMULATION && `SIMU_USE_PLL==0)
begin: speedup_simulation
assign cpu_clk = clk_91m;
assign sys_clk = clk;
end
else
begin: pll
clk_pll clk_pll
(
.clk_in1 (clk ),
.cpu_clk (cpu_clk),
.sys_clk (sys_clk)
);
end
endgenerate
这段什么意思?