本原创文章由深圳市小眼睛科技有限公司创作,版权归本公司所有,如需转载,需授权并注明出处(www.meyesemi.com)

1.实验简介

  实验目的:

   掌握紫光平台的 RAM、ROM、FIFO IP 的使用

  实验环境: Window11 PDS2022.2-SP6.4

   芯片型号: PG2L50H-484

2.实验原理

   不管是 Logos 系列或者是 Logos2 系列,其 IP 配置以及模式和功能均一致,不会像 PLL 那样有动态配置以及内部反馈选项的选择等之间的差异,所以是 RAM、ROM、FIFO 是通用的。

2.1. RAM 介绍

      RAM 即随机存取存储器。它可以在运行过程中把数据写进任意地址,也可以把数据从任意地址中读出。其作用可以拿来做数据缓存,也可以跨时钟,也可以存放算法中间的运算结果等。

      注意,PDS的IP配置工具中提供两种不同的RAM,一种是Distributed RAM(分布式RAM) 另一种是 DRM Based RAM,分布式 RAM 用的是 LUT(查找表)资源去构成的 RAM,这种 RAM 会消耗大量 LUT 资源,因此通常在一些比较小的存储才会用到这种 RAM,以节省 DRM 资源。而 DRM Based RAM 是利用片内的 DRM 资源去构成的 RAM,不占用逻辑资源,而且速度快, 通常设计中均使用 DRM Based RAM。

RAM 分为三种,如下表所示:

RAM类型特点
单端口 RAM只有一个端口可以读写,只有一个读写口和地址口
伪双端口 RAM有 wr 和 rd 两个端口,顾名思义,wr 只能写,rd 只能读
真双端口 RAM提供 A 和 B 两个端口,两个端口均可以独立进行读写

注意,当使用真双端口时,要避免出现同时读写同个地址,这会造成写入失败,在逻辑设计上需要避开这个情况。

以下给出比较常用的 RAM 的配置作为介绍,通常我们比较常用伪双端口 RAM 来设计,

如图所示:

下图为 IP 配置:

      注意,如果勾选 Enable Output Register(输出寄存),输出数据会延迟一个时钟周期。具体每个端口的含义这里参考官方手册,大家也可以自行查看 IP 手册,如下图所示:

      DRM Resource Type:用于配置所建 RAM IP 核用的是哪种资源,不同芯片型号可选资源是不一样的,有的是 9K,有的是 18K,有的是 36K,如果没有特殊情况,直接 AUTO 即可。

2.1.1. RAM 的读写时序

     配置成不同模式的时候,RAM 的读写时序是不一样的,真双端口和单端口的 RAM 配置均有三种模式,而伪双端口只有一种。由于真双端口和单端口的配置是一样的,这里以真双端口为例子。

    分为 NORMAL_WRITE( 正 常 模 式 ) 、 TRANSPARENT_WRITE( 直 写 ) 、 READ_BEFORE_WRITE(读优先模式)三种模式。

    而伪双端口不属于上面三种模式,有它独特的模式。这几种模式的差异就在于读写时序的不同,接下来,我们来分析读写时序。

    以下时序图均来自官方 IP 手册,并且均未使能输出寄存。注意 wr_en 为 1 时表示写数据, 为 0 表示读数据。

2.1.1.1.NORMAL_WRITE

    在 NORMAL_WRITE 这种模式下,可以看到,当时钟的上升沿到来,且 clk_en 和 wr_en均为高电平时,就会把数据写到对应的地址里面,如图中的 1 时刻。然后看读数据端口,当wr_en 不为 0 的时候,a_rd_data 一直为 Don’t Care 状态,而当时钟上升沿到来,且 clk_en为高电平,wr_en 为低电平时,a_rd_data 输出当前 a_addr 里的数据,即 Mem(ADDR1)和 ADDR0 里的 D0。

2.1.1.2.READ_BEFORE_WRITE

     在 READ_BEFORE_WRITE 这种模式下,可以看到在 1 的时刻,时钟上升沿到来,且clk_en 和 wr_en 均为高电平,D0 写进了 ADDR0 里面,但是注意看此时的 a_rd_data 和a_addr,可以发现,此时 a_wr_en 并不为 0,可 a_rd_data 还是输出了上一刻 ADDR0 的数据(因为不是输出 D0)。之后,a_wr_en 拉低,此时才是读数据,在 3 时刻,把 ADDR0 的数据读出来,a_rd_data 才输出了 D0。

     所以总结一下,这个模式其实就是进行写操作时,读端口会把当前写的地址的原始数据输出,因此叫读优先模式很合情合理对吧,顾名思义,就是我优先把原来的数据读出来。

2.1.1.3.Transparent_Write

    在 Transparent_Write 这种模式下,可以看到在 1 的时刻,时钟上升沿到来, 且clk_en 和 wr_en 均为高电平,D0 写进了 ADDR0 里面,但是注意看此时的 a_rd_data 和a_addr,可以发现,此时 a_wr_en 并不为 0,可 a_rd_data 居然直接输出了 D0,之后 a_wr_en拉低,进入读状态,在 2 时刻,再一次把 ADDR0 的数据读出来,输出了 D0。

    分析总结一下,根据 1 时刻的情况,我们可以得出结论,在这种模式下,当我们进行写操作时,读端口会马上输出我们写入的数据。所以叫直写模式。

2.1.1.4. 伪双端口的读写时序

    注意:wr_en 为 1 时是写操作,为 0 是读操作。

    伪双端口的读写时序与上面三种都不同,我们看图 8 的时序来分析:

    注意看 1 时刻,此时 wr_en 和 wr_clk_en 均为高电平,所以是写操作,所以 1 时刻就是往地址 ADDR0 里写入 D0,注意此时的 rd_addr 和 rd_data,可以看到这一时刻 rd_addr 是 ADDR2,然后进行写操作时,rd_data 同样输出了 ADDR2 里的数据,而此时 wr_en 还是高电平。接下来看 2 和 3 时刻,此时 wr_en 为 0,rd_clk_en 是高电平,所以是读操作,此时分别读出 ADDR1 和 ADDR0 里的数据,之后 rd_clk_en 变成低电平,读时钟无效,可以看到rd_data 保持 D0 输出。

    分析总结一下,主要是 1 时刻,大家可以看到 1 时刻往 ADDR0 写入了 D0,读端口却输出了 ADDR2 中的数据。仔细观察可以得出结论:伪双端口 RAM 在进行写操作的时候,会把当前读端口指向的地址的数据输出。是不是有点像直写?只不过直写是输出写入的数据,而伪双端口是输出读端口指向的地址的数据。

    具体大家可以结合视频讲解。

2.2 ROM 介绍

     ROM 即只读存储器,在程序的运行过程中他只能被读取,无法被写入,因此我们应该在初始化的时候就给他配置初值,一般是在生成 IP 的时候通过导入.dat 文件对其进行初值配置。

     注意,PDS的 IP配置工具中提供两种不同的 ROM,一种是 Distributed ROM(分布式 ROM)另一种是 DRM Based ROM,分布式 ROM 用的是 LUT(查找表)资源去构成的 ROM,这种 ROM会消耗大量 LUT 资源,因此通常在一些比较小的存储才会用到这种 RAM,以节省 DRM 资源。而 DRM Based ROM 是利用片内的 DRM 资源去构成的 ROM,不占用逻辑资源,而且速度快,通常设计中均使用 DRM Based ROM。

     以下给出比较常用的 ROM 的配置作为介绍,由于只能读,因此其均为单端口 ROM 如图所示:

    下图为 IP 配置:

    注意,如果勾选 Enable Output Register(输出寄存),输出数据会延迟一个时钟周期。

    同时,可以看到 Enable Init 选项是默认勾选的,并且不可取消。

    导入的数据的格式只能为二进制或者是十六进制,demo 选择十六进制。

    具体每个端口的含义这里参考官方手册,大家也可以自行查看 IP 手册,如图所示:

      可以看到图中给出的是完整的接口列表,一般我们只需要 addr、rd_data、clk、rst这四个信号即可。

     以下时序图均来自官方 IP 手册,并且均未使能输出寄存。

2.2.1. ROM 的读时序

      可以看到该时序是非常简单的,比如在 TI 时刻,当 clk 上升沿到来时,且 clk_en 为高电平时,给出要读出的地址,rd_data 就会输出数据,在不勾选输出使能寄存的情况下,rd_data的输出会有延迟,具体时间可以从仿真里看到,所以我们在下个时钟周期的上升沿即 T2 时刻的上升沿才能获取到 ROM 读出的值。

      所以整体时序非常简单,如果勾选了 clk_en 信号,就要给 clke_en 高电平才能读数据,如果不勾选 clk_en 信号,就一直根据地址读取 ROM 数据。

2.3. FIFO 介绍

     FIFO 即先入先出,在 FPGA 中,FIFO 的作用就是对存储进来的数据具有一个先入先出特性的一个缓存器,经常用作数据缓存或者进行数据跨时钟域传输。FIFO 和 RAM 最大的区别就是 FIFO 不需要地址,采用的是顺序写入,顺序读出。

     在紫光的 IP 工具中又分为 Distribute FIFO 和 DRM FIFO,其实就是用不同的资源去构成,前者 Distribute FIFO 也就是分布式 FIFO,使用的是片上的 LUT 资源去构成,而 DRM FIFO 使用的是片上的 DRM 资源去构成,DRM 构成的 FIFO 其性能大于 LUT 资源构成的,不仅容量更大,且可配置更多功能。

     本章着重介绍 DRM Based FIFO。

     注意:FIFO 写满后禁止继续写入数据,否则将会写溢出。

     注意:FIFO 读空后禁止继续读数据,否则将会读溢出。

     以下给出常用的 FIFO 的配置作为介绍。

     注意,如果勾选 Enable Output Register(输出寄存),输出数据会延迟一个时钟周期。

     FIFO Type 有 SYNC 和 ASYNC 两种,第一种是同步 FIFO,读写端口共用一个时钟和复位,另一种是异步 FIFO,读写时钟和复位均独立。在平常设计中,比较常用的是异步 FIFO,因为同步 FIFO 和异步 FIFO 的读写时序一模一样,只有读写端口的时钟复位有差异,当异步 FIFO 的读写端口使用相同的时钟和复位,此时异步 FIFO 和同步 FIFO 基本是一致的。

     Reset Type 也可以选择 SYNC 和 ASYNC 两种,SYNC 模式下需要时钟的上升沿采样到复位有效才会复位,而在 ASYNC 模式下,复位一旦有,FIFO 立即复位。

     其余端口说明引用官方 IP 手册,如图所示:

     其中 rd_water_level 和 wr_water_level 分别代表”可读的数据量”和”已写入的数据量”,其含义与 Xilinx 的 FIFO 的 wr_data_count 和 rd_data_count 是一致的。

     当我们将 Enable Almost Full Water Level 和 Enable Almost Empty Water Level 勾选上,才能看到 rd_water_level 和 wr_water_level,而下面的 Almost Full Numbers 的设置是表示当写入 1020 个数据时,Almost Full 信号就会拉高,Almost Empty Numbers 的设置表示当可读数据剩下 4 个时 Almost Empty 信号就会拉高。

     同时 FIFO 支持混合位宽,例如写端口 16bit,读端口 8bit。如果写入 16’h0102,那么读出来会是 8’h02,8’h01,会先读出低位。

     如果写端口 8bit,读端口 16bit。当写入 8’h01,8’h02 时,读出来是 16’h0201,先写入的数据存放在低位。

2.3.1.FIFO的读写时序

     因为同步 FIFO 和异步 FIFO 的读写时序一致,这里用异步 FIFO 的读写时序图来做介绍。

     注意:复位时高电平有效。读出数据均未勾选 Enable Output Register(输出寄存)。

2.3.1.1.FIFO 未满时的写时序

     可以看到在 1 时刻,复位信号时低电平,处于工作状态,此时在 wr_clk 的上升沿且 wr_en 为高电平时将数据 D0 写入 FIFO,wr_water_level 也从 0 变 1,表示已经写入了一个数据,此时注意看读端口的 empty 信号,在 3 时刻 empty 信号从高变低,意味着读端口已经有数据可以读了,FIFO不再为空,而注意看,rd_clk和 wr_clk是不一样的,从 1写入到 3时刻 empty 拉低时,经过了 3 个 rd_clk。

     所以这里我们可以得出结论:rd_water_level 要滞后 wr_water_level 三个 rd_clk。

2.3.1.2.FIFO 将满时的写时序

     将满时主要分析 full 和 almost_full 信号。假设 Almost Full Numbers 设置为 N-2,在 1时刻,此时已经写入了 N-6 个数据,意味着再写 6 个数据 FIFO 就满了,从 1 时刻到 2 时刻一共写入了 4 个数据,因此当 wr_water_level 变成 N-2 时,满足条件,可以看到 Almost Full信号拉高,再写两个数据 FIFO 就满了,所以再经过两个时钟周期后,Full 信号拉高。

2.3.1.3.FIFO 在满状态下的读时序

     在满状态下,FIFO 已经有 N 个数据了,此时在 1 状态下,rd_clk 的上升沿,且 rd_en 为 高 电 平 时 ,此 时 从 FIFO 里 读 出 数 据 (数 据 的 输 出 有 延 时 ,仿 真 中 延 时 0.2ns) 。此时 rd_water_level 变成 N-1,rd_data 输出 D0。然后看 2 时刻,full 信号拉低,此时可以看以下,在 1 时刻到 2 时刻期间一共经过了 3 个 wr_clk 写端口才能判断到此时数据量已经不为满。

     所以我们可以得出结论,wr_water_level 要滞后 rd_water_level 三个 wr_clk。

2.3.1.4.FIFO 将空时的读时序

     在 1 时刻,可读的数据量剩下 4,假设 Almost Empty Number 设为 2,在 1 时刻和 2 时刻分别读出了两个数据,所以在 2 时刻下,可读数据量剩下两个,达到 Almost Empty Number 触发条件,因此 almost_empty 信号拉高,再过两个时钟周期,即再读两个数据,FIFO 将变成空状态,也就是状态 3,此时 empty 信号拉高。

2.4. 接口列表

   该部分介绍每个顶层模块的接口。

ram_test_top.v

rom_test_top.v

fifo_test_top.v

3.代码仿真说明

     本次的顶层模块实际就是例化 IP,然后把端口引出而已,主要代码都在 testbench 里面,所以我们直接介绍仿真代码。

3.1. RAM 仿真测试
`timescale 1ns/1nsmodule ram_test_tb();reg sys_clk;reg rd_clk;reg rst_n;reg rw_en; //读写使能信号reg [7:0] wr_data;reg [4:0] wr_addr;reg [4:0] rd_addr;wire [7:0] rd_data;reg [1:0] state;initial beginrst_n <= 1'd0;sys_clk <= 1'd0;rd_clk <= 1'd0;#20rst_n <= 1'd1;end//读写控制always@(posedge sys_clk or negedge rst_n) beginif(!rst_n) beginstate <= 2'd0;wr_data <= 8'd0;rw_en <= 1'd0;wr_addr <= 8'd0;rd_addr <= 8'd0;endelse begincase(state)2'd0: beginrw_en <= 1'd1;state <= 2'd1;end2'd1: beginif(wr_addr == 5'd31) beginrw_en <= 1'd0;state <= 2'd2;wr_data <= 8'd0;wr_addr <= 5'd0;rd_addr <= 5'd0;endelse beginstate <= 2'd1;wr_data <= wr_data+1'b1;rd_addr <= rd_addr+1'b1;wr_addr <= wr_addr+1'b1;endend2'd2: beginif(rd_addr == 5'd31) beginstate <= 2'd3;rd_addr <= 5'd0;endelse beginstate <= 2'd2;rd_addr <= rd_addr+1'b1;endend2'd3: beginstate <= 2'd0;enddefault: state <= 2'd0;endcaseendend//50MHZalways #10 sys_clk = ~sys_clk;GTP_GRS GRS_INST(.GRS_N(1'b1));ram_test_top u_ram_test_top(.wr_clk (sys_clk),.rd_clk (sys_clk),.rst_n (rst_n),.rw_en (rw_en),.wr_addr (wr_addr),.rd_addr (rd_addr),.wr_data (wr_data),.rd_data (rd_data));
endmodule

     涉及到 tb 的一些基础操作这里就不再详细讲解,只关注重点逻辑部分。从代码的 27 行到 80 行是 ram 的读写控制状态机。主要用来控制读写地址的生成和使能以及写入的数据。这里只讲解主要实现的功能,首先代码的 38-42 行,也就是 state=0 的时候,拉高 rw_en,并跳转到状态 1,此时进入写操作(没有使能 clk_en,可以不管),下个时钟周期开始写入数据(注意是时序逻辑,边沿采样,所以是下个时钟周期才开始写数据),即 state=1 的时候是一直在往 ram 里面写数据,在代码的 44 到 60 行就是写操作了,可以看到,当 wr_addr 不等于 31 的时候,wr_data 和 wr_addr 不断加 1(rd_addr 这里+1,可以看视频讲解,主要为了验证伪双端口的时序),当 wr_addr 等于 31 的时候,在下个时钟周期把数据清 0,状态跳转,在当前时钟周期下还会再往地址 31 里面写入数据,所以在该时钟周期,一共写入了 32 个数据(从地址 0 写到地址 31)。即状态 1 完成写入 32 个数据后跳转到 state=2 的逻辑。代码的 61-72 行,也就是 state=2 的时候,在每个周期的上升沿让 rd_addr 不断累加,直到 rd_addr=31 的时候,在下个时钟周期清空地址并让状态跳转的操作,而在当前时钟周期会继续把地址 31 的数据读出来,完成读取地址 0-31 的数据,一共 32 个数据,所以该状态主要完成读取 32 个数据,然后在下个时钟周期就跳转到 state=3。state=3 可以看到其主要作用就是等待一个时钟周期,然后跳转回去 state=0 下,起到一个延时作用。

 上图为写数据的波形,数据从 0 开始递增到 31,地址也是从 0 到 31。

上图为读数据波形,从地址 0-31 读出了 0-31 个数据。

      具体波形大家可以看视频仿真,或者自己尝试仿真,根据波形来看代码。因为这里是时序逻辑,所以如果是初学者,纯看文字可能会对 rd_addr=31 这一时刻还会再读一个数据感到疑惑,建议直接仿真,或者观看视频讲解的仿真部分,可以帮助快速理解。

      可以总结出一句话就是时序逻辑的赋值总在下一个时钟周期才生效。所以在rd_addr=31 时执行的操作要在下一个时钟周期才会被采样生效。所以当前时钟还是会再从RAM 读出一个数据。

      仿真代码的讲解到此结束,大家要注意时序逻辑的特点,具体的内容请看视频讲解。

3.2. ROM 仿真测试
`timescale 1ns/1nsmodule rom_test_tb();reg sys_clk;reg rst_n;reg [9:0] rd_addr;wire [63:0] rd_data;initial beginrst_n <= 1'd0;sys_clk <= 1'd0;#20rst_n <= 1'd1;end//50MHZalways #10 sys_clk = ~sys_clk;GTP_GRS GRS_INST(.GRS_N(1'b1));always@(posedge sys_clk or negedge rst_n) beginif(!rst_n)rd_addr <= 10'd0;elserd_addr <= #2 rd_addr + 1'b1;endrom_test_top u_rom_test_top(.rd_clk (sys_clk),.rst_n (rst_n),.rd_addr (rd_addr),.rd_data (rd_data));endmodule

      代码 31-36 行例化了 ROM 的顶层模块,该模块里面其实就是调用了 ROM IP,然后把信号引出端口,没有任何逻辑操作。

      代码 24-29 行通过一个 always 块不断生成地址,任何给到 ROM IP,将数据读出,由于没勾选 clk_en 信号,所以数据在 ROM 复位完成后就会不断读出。所以并没有复杂的逻辑,就是让地址从 0 不断累加,把数据读出。

      上图为读出数据的波形图,可以看到读出的数据和 dat 文件里的数据一致。

   仿真代码的讲解到此结束,大家要注意时序逻辑的特点,具体的内容请看视频讲解。

3.3. FIFO 仿真测试
`timescale 1ns/1nsmodule fifo_test_tb();reg sys_clk;reg rst_n;reg [7:0] wr_data;reg wr_en;reg rd_en;reg rd_state; //读状态reg wr_state;wire [7:0] rd_data;reg [7:0] rd_cnt;wire [7:0] rd_water_level;wire [7:0] wr_water_level;initial beginrst_n <= 1'd0;sys_clk <= 1'd0;#20rst_n <= 1'd1;endalways #10 sys_clk = ~sys_clk; //50MHZalways@(posedge sys_clk or negedge rst_n) beginif(!rst_n) beginwr_state <= 1'd0;wr_en <= 1'd0;wr_data <= 8'd0;endelse begincase(wr_state)1'd0: if(wr_water_level == 127) //128 个数据beginwr_en <= #2 1'd0;wr_data <= #2 8'd0;wr_state <= #2 1'd1;endelsebeginwr_en <= #2 1'd1;wr_data <= #2 wr_data+1'b1;wr_state <= #2 1'd0;end1'd1: if(rd_cnt == 127)wr_state <= #2 1'd0;default: wr_state <= 1'd0;endcaseendendalways@(posedge sys_clk or negedge rst_n) beginif(!rst_n) beginrd_state <= 1'd0;rd_en <= 1'd0;rd_cnt <= 8'd0;endelse begincase(rd_state)1'd0: if(rd_water_level >= 8'd128) //等待 128 个数据beginrd_state <= #2 1'd1;rd_en <= #2 1'd1;endelsebeginrd_cnt <= #2 8'd0;rd_state <= #2 1'd0;end1'd1: beginrd_cnt <= #2 rd_cnt + 1'b1;if(rd_cnt == 127)beginrd_en <= #2 1'd0;rd_state <= #2 1'd0;endenddefault: rd_state <= 1'd0;endcaseendendGTP_GRS GRS_INST(.GRS_N(1'b1));fifo_test_top u_fifo_test_top(.sys_clk (sys_clk),.rst_n (rst_n),.wr_data (wr_data),.wr_en (wr_en),.rd_en (rd_en),.wr_water_level (wr_water_level),.rd_water_level (rd_water_level),.rd_data (rd_data));
endmodule

      涉及到 tb 的一些基础操作这里就不再详细讲解,只关注重点逻辑部分。整个设计分为读写两个状态的控制。分别完成了写入 128 个数据,和读出 128 个数据,由于 FIFO 不需要地址,所以只需要产生使能信号即可。

      首先看写状态,在 wr_state=0 时,拉高写使能,并让 wr_data 不断累加,往 FIFO 里面写数据,当 wr_water_level=127 的时候,拉低写使能,写数据置 0,写状态跳转到 1,注意此时还会再写入一个数据,所以到此一个写入了 128 个数据。至于拉低写使能,写数据置 0,写状态跳转到 1 这些操作将在下一个时钟周期才会被采样生效。之后,在 wr_state=1 时,不断等待 rd_cnt,该条件就是判断当读出 128 个数据的时候,wr_state 跳转到 0 状态。

      接下来看读状态,在 rd_state=0 的时候,一旦可读的数据量超过 128 个(包括 128),状态跳转到 rd_state=1 下,然后开始读出数据,同时在 rd_state=1 下用变量 rd_cnt 对我们的读出数据也进行计数,rd_cnt 从 0 开始计数,当 rd_cnt=127 的时候会再往 FIFO 读出一个数据,所以此时就一共读出了 128 个数据,下一个时钟周期 rd_en 和 rd_state 都将置 0。

写数据的波形如上所示,一共写入 128 个数据,从 1 写到 128。

读数据的波形如上所示,一共读出 128 个数据,从 1 读到 128。

      具体波形大家可以看视频仿真,或者自己尝试仿真,根据波形来看代码。因为这里是时序逻辑,所以如果是初学者,纯看文字可能会对 rd_cnt=127 这一时刻还会再读一个数据感到疑惑,建议直接仿真,或者观看视频讲解的仿真部分,可以帮助快速理解。

      可以总结出一句话就是时序逻辑的赋值总在下一个时钟周期才生效,所以在 rd_cnt=127 时执行的操作要在下一个时钟周期才会被采样生效。所以当前时钟 rd_en 还是 为 1,会再从 FIFO 读出一个数据。

      仿真代码的讲解到此结束,具体的内容请看视频讲解。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣-21.合并两个有序链表

题目链接 21.合并两个有序链表 class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode p1 list1;ListNode p2 list2;ListNode p new ListNode(0);ListNode cur p;while (p1 ! null && p2 ! null) {if (p1.val > p2.val) …

MoE混合专家模型:千亿参数的高效推理引擎与架构革命

本文由「大千AI助手」原创发布&#xff0c;专注用真话讲AI&#xff0c;回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我&#xff0c;一起撕掉过度包装&#xff0c;学习真实的AI技术&#xff01; 从稀疏激活到多模态协同的智能计算范式 &#x1f9e9; 一、核心思想与…

【论文笔记】BlockGaussian:巧妙解决大规模场景重建中的伪影问题

论文地址&#xff1a;https://arxiv.org/pdf/2504.09048 大规模场景的重建方法不仅仅对于高空航拍数据有效&#xff0c;而且对于地面大中场景也有增强效果&#xff0c;故专门来学习一下这一方向的知识。感谢作者大佬们的great work。 Abstract 三维高斯泼溅&#xff08;3DGS…

网络众筹项目数据库(2014-2024.11)

1727网络众筹项目数据库&#xff08;2014-2024.11&#xff09;数据简介作为新兴互联网融资模式&#xff0c;众筹已成为越来越多创业者和中小企业获取资金的渠道&#xff0c;但众筹项目一直面临融资成功率低的困难&#xff0c;成功融资的项目在许多平台上占比不足五成。而目前对…

k8s新增jupyter服务

k8s新增服务 常用命令 kubectl apply -f xxxxxx.yaml # 部署资源&#xff0c;顺序&#xff1a;namespace -> pvc -> deployment -> servicekubectl create namespace jupyter # 创建namespacekubectl get namespaces # 查看nskubectl get pods -n jupyter # 查看p…

结构化数据、非结构化数据区别

一、核心定义结构化数据&#xff1a;指具有固定格式、可直接用二维表&#xff08;如数据库表&#xff09;表示的数据&#xff0c;其字段&#xff08;列&#xff09;定义明确&#xff0c;数据之间的关系清晰。例如&#xff1a;Excel 表格中的数据、关系型数据库&#xff08;MySQ…

Linux修炼:基础指令

Hello大家好&#xff01;很高兴我们又见面啦&#xff01;给生活添点passion&#xff0c;开始今天的编程之路&#xff01; 我的博客&#xff1a;<但凡. 我的专栏&#xff1a;《编程之路》、《数据结构与算法之美》、《题海拾贝》、《C修炼之路》、《Linux修炼&#xff1a;终端…

【Linux网络】深入理解HTTP/HTTPS协议:原理、实现与加密机制全面解析

协议是通信双方必须遵守的规则&#xff0c;确保数据能够正确传输和解析&#xff0c;它规定了数据格式、传输顺序、错误处理等细节。应用层的协议一般都是我们自己进行定义的&#xff0c;但是有很多程序员前辈已经写出来了很哇塞的协议&#xff0c;我们直接进行学习和使用即可HT…

浅尝 Spring AI【使用超级简单~】

一直想要体验下 Spring AI&#xff0c;最近自己的一个工具有这个需求&#xff0c;所以这里准备使用下。其实使用起来超级简单。 1.IDEA 新建 Spring项目 1&#xff09;这里可以根据自己的喜好选择 项目名、jdk版本等 2&#xff09;这里选择 在ai中选择 openAI 即可。然后我另…

DDL期间TDSQL异常会话查询造成数据库主备切换

问题描述&#xff1a;7*24联机交易系统&#xff0c;傍晚时分&#xff0c;从客户端后台对3千万行的大表执行缩短varchar类型字段长度的ddl语句&#xff0c;执行期间&#xff0c;为了查看ddl进度&#xff0c;从TDSQL-MySQL赤兔前端页面点击异常会话查询&#xff0c;之后数据库卡住…

弧焊机器人气体全方位节能指南

氩弧焊&#xff08;TIG焊接&#xff09;作为其中一种高效且精密的技术&#xff0c;凭借其稳定性和高质量的焊接效果&#xff0c;在航空航天、汽车制造、船舶建造以及石油化工等领域占据了不可或缺的地位。氩弧焊通过使用惰性气体&#xff08;如氩气&#xff09;保护电弧和熔池&…

数据清洗(ETL/ELT)原理与工具选择指南:企业数字化转型的核心引擎​

目录 一、数据清洗&#xff08;ETL/ELT&#xff09;到底在干啥&#xff1f; 1.揪出并处理异常值 2.把缺失的数据补上&#xff08;或处理好&#xff09; 3.数据转换与标准化 4.一致性校验 二、工具怎么选&#xff1f;看菜吃饭&#xff0c;量体裁衣 1.数据量不大、要求不高…

阿里云服务器,CentOS7.9上安装YApi 接口管理平台

目录 1.node安装 1.1下载node,解压 1.2 部署bin文件 1.3 安装mongodb 2.启动yapi 2.1 前置命令 2.2 启动服务 3.利用pm2方便服务管理维护 3.1.安装pm2 3.2 常用 PM2 命令 4.常见问题 4.1. 确认 MongoDB 是否安装 4.2. 安装 MongoDB&#xff08;若未安装&#xff…

阿里云错题集分享

有最近想要考试阿里云的可以私信我 &#xff0c;一起加油错题集1.在使用阿里云的负载均衡SLB实例时&#xff0c;做了如下健康检查的配置:成功响应和超时响应时间均为1秒&#xff0c;健康检查间隔为2秒&#xff0c;不健康阈值为3&#xff0c;健康阈值为3。即对于确认一个云服务器…

Android 12 - 部分相机横屏显示方案

1.相机过渡界面方向旋转 Android 10 - 相机过渡界面默认角度 同A10 有些区别&#xff0c;再次增加记录修改。 这个文件没有修改&#xff0c;只是说明 src/com/android/camera/CameraActivity.javaprivate void freezeScreenCommon(boolean async) {long startTime System.…

Operation Blackout 2025 Phantom Check hayabusa+ControlSet001+VirtualBox

QAQA攻击者使用哪个 WMI 类来检索型号和制造商信息以进行虚拟化检测&#xff1f;Win32_ComputerSystem攻击者执行了哪个 WMI 查询来检索计算机的当前温度值&#xff1f;SELECT CurrentTemperature FROM MSAcpi_ThermalZoneTemperature攻击者加载了 PowerShell 脚本以检测虚拟化…

《O-PAS™标准的安全方法》白皮书:为工业自动化系统筑起安全防线

The Open Group 最新白皮书《O-PAS™标准的安全方法》重磅发布&#xff0c;为流程工业在迈向开放架构与多供应商互操作的过程中&#xff0c;指明了安全实践的方向。O-PAS™标准的安全方法ABOUT PUBLICATION亮点一&#xff1a;首次系统阐释 O-PAS™ 标准安全方法与 IEC/ISA 6244…

UML 图类型全解析:结构图与行为图分类详解

作为软件架构的核心建模语言&#xff0c;UML&#xff08;统一建模语言&#xff09;通过14种标准图表提供系统多维度视角。这些图表分为结构图&#xff08;静态模型&#xff09; 和 行为图&#xff08;动态模型&#xff09; 两大类&#xff0c;覆盖从需求到实现的完整生命周期。…

lodash不支持 Tree Shaking 而 lodash-es可以

lodash 无法有效支持 Tree Shaking 而 lodash-es 可以&#xff0c;核心区别在于‌模块规范、文件结构和静态分析兼容性‌。以下是具体原因分析&#xff1a; ⚙️ 一、模块规范差异&#xff08;核心原因&#xff09; lodash&#xff08;CommonJS 规范&#xff09;‌ 使用 requir…

java+vue+SpringBoo高校实习信息发布网站(程序+数据库+报告+部署教程+答辩指导)

源代码数据库LW文档&#xff08;1万字以上&#xff09;开题报告答辩稿ppt部署教程代码讲解代码时间修改工具 技术实现 开发语言&#xff1a;后端&#xff1a;Java 前端&#xff1a;vue框架&#xff1a;springboot数据库&#xff1a;mysql 开发工具 JDK版本&#xff1a;JDK1.8 数…