axilite + ap_memory修饰数组
一、指令优化设计案例一#pragma HLS INTERFACE bram portxxx#pragma HLS INTERFACE s_axilite portreturn bundleCONTROL_BUS#pragma HLS INTERFACE s_axilite portxxx bundleCONTROL_BUS上述指令约束后产生单口的axilite_bramxxx_top_CONTROL_BUS_s_axi#(.C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_BUS_ADDR_WIDTH ),.C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_BUS_DATA_WIDTH ))xxx_top_CONTROL_BUS_s_axi_U(.AWVALID(s_axi_CONTROL_BUS_AWVALID),.AWREADY(s_axi_CONTROL_BUS_AWREADY),.AWADDR(s_axi_CONTROL_BUS_AWADDR),.WVALID(s_axi_CONTROL_BUS_WVALID),.WREADY(s_axi_CONTROL_BUS_WREADY),.WDATA(s_axi_CONTROL_BUS_WDATA),.WSTRB(s_axi_CONTROL_BUS_WSTRB),.ARVALID(s_axi_CONTROL_BUS_ARVALID),.ARREADY(s_axi_CONTROL_BUS_ARREADY),.ARADDR(s_axi_CONTROL_BUS_ARADDR),.RVALID(s_axi_CONTROL_BUS_RVALID),.RREADY(s_axi_CONTROL_BUS_RREADY),.RDATA(s_axi_CONTROL_BUS_RDATA),.RRESP(s_axi_CONTROL_BUS_RRESP),.BVALID(s_axi_CONTROL_BUS_BVALID),.BREADY(s_axi_CONTROL_BUS_BREADY),.BRESP(s_axi_CONTROL_BUS_BRESP),.ACLK(ap_clk),.ARESET(ap_rst_n_inv),.ACLK_EN(1b1),.ap_start(ap_start),.interrupt(interrupt),.ap_ready(ap_ready),.ap_done(ap_done),.ap_idle(ap_idle),.param_mem_V_address0(param_mem_V_address0),.param_mem_V_ce0(param_mem_V_ce0),.param_mem_V_q0(param_mem_V_q0));使用axilite和bram来约束顶层数组顶层数组综合不再只是一个ram接口了而是内部产生了一个RAM了。二、指令优化设计案例二//#pragma HLS INTERFACE bram portxxx//注释掉后默认就是ap_memory#pragma HLS INTERFACE s_axilite portreturn bundleCONTROL_BUS#pragma HLS INTERFACE s_axilite portxxx bundleCONTROL_BUS上述指令约束后产生单口的axilite_bramxxx_top_CONTROL_BUS_s_axi#(.C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_BUS_ADDR_WIDTH ),.C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_BUS_DATA_WIDTH ))xxx_top_CONTROL_BUS_s_axi_U(.AWVALID(s_axi_CONTROL_BUS_AWVALID),.AWREADY(s_axi_CONTROL_BUS_AWREADY),.AWADDR(s_axi_CONTROL_BUS_AWADDR),.WVALID(s_axi_CONTROL_BUS_WVALID),.WREADY(s_axi_CONTROL_BUS_WREADY),.WDATA(s_axi_CONTROL_BUS_WDATA),.WSTRB(s_axi_CONTROL_BUS_WSTRB),.ARVALID(s_axi_CONTROL_BUS_ARVALID),.ARREADY(s_axi_CONTROL_BUS_ARREADY),.ARADDR(s_axi_CONTROL_BUS_ARADDR),.RVALID(s_axi_CONTROL_BUS_RVALID),.RREADY(s_axi_CONTROL_BUS_RREADY),.RDATA(s_axi_CONTROL_BUS_RDATA),.RRESP(s_axi_CONTROL_BUS_RRESP),.BVALID(s_axi_CONTROL_BUS_BVALID),.BREADY(s_axi_CONTROL_BUS_BREADY),.BRESP(s_axi_CONTROL_BUS_BRESP),.ACLK(ap_clk),.ARESET(ap_rst_n_inv),.ACLK_EN(1b1),.ap_start(ap_start),.interrupt(interrupt),.ap_ready(ap_ready),.ap_done(ap_done),.ap_idle(ap_idle),.param_mem_V_address0(param_mem_V_address0),.param_mem_V_ce0(param_mem_V_ce0),.param_mem_V_q0(param_mem_V_q0));可见还是产生的axilite_1port_bram单口BRAM三、指令优化设计案例三//#pragma HLS INTERFACE bram portxxx//注释掉后默认就是ap_memory#pragma HLS RESOURCE variableparam_mem coreRAM_T2P_BRAM#pragma HLS INTERFACE s_axilite portreturn bundleCONTROL_BUS#pragma HLS INTERFACE s_axilite portxxx bundleCONTROL_BUS上述指令约束后产生单口的axilite_bramxxx_top_CONTROL_BUS_s_axi#(.C_S_AXI_ADDR_WIDTH( C_S_AXI_CONTROL_BUS_ADDR_WIDTH ),.C_S_AXI_DATA_WIDTH( C_S_AXI_CONTROL_BUS_DATA_WIDTH ))xxx_top_CONTROL_BUS_s_axi_U(.AWVALID(s_axi_CONTROL_BUS_AWVALID),.AWREADY(s_axi_CONTROL_BUS_AWREADY),.AWADDR(s_axi_CONTROL_BUS_AWADDR),.WVALID(s_axi_CONTROL_BUS_WVALID),.WREADY(s_axi_CONTROL_BUS_WREADY),.WDATA(s_axi_CONTROL_BUS_WDATA),.WSTRB(s_axi_CONTROL_BUS_WSTRB),.ARVALID(s_axi_CONTROL_BUS_ARVALID),.ARREADY(s_axi_CONTROL_BUS_ARREADY),.ARADDR(s_axi_CONTROL_BUS_ARADDR),.RVALID(s_axi_CONTROL_BUS_RVALID),.RREADY(s_axi_CONTROL_BUS_RREADY),.RDATA(s_axi_CONTROL_BUS_RDATA),.RRESP(s_axi_CONTROL_BUS_RRESP),.BVALID(s_axi_CONTROL_BUS_BVALID),.BREADY(s_axi_CONTROL_BUS_BREADY),.BRESP(s_axi_CONTROL_BUS_BRESP),.ACLK(ap_clk),.ARESET(ap_rst_n_inv),.ACLK_EN(1b1),.ap_start(ap_start),.interrupt(interrupt),.ap_ready(ap_ready),.ap_done(ap_done),.ap_idle(ap_idle),.param_mem_V_address0(param_mem_V_address0),.param_mem_V_ce0(param_mem_V_ce0),.param_mem_V_q0(param_mem_V_q0));加入#pragma HLS RESOURCE variableparam_mem coreRAM_T2P_BRAM真双口RAM优化还是产生的axilite_1port_bram单口BRAM四、说明1.上述各种指定接口数组使用各种优化看综合报告最终还是被综合为axiliteap_memoryINFO: [RTGEN 206-500] Setting interface mode on port xxx_top/param_mem_V to s_axilite ap_memory.2.bram axilite接口bram接口优化被丢弃WARNING: [XFORM 203-803] Dropped interface mode bram on param_mem.V as it is incompatible with its interface mode s_axilite同时指定了接口模式为 bram 和 s_axilite但这两个是冲突的工具丢弃了 bram 模式保留 s_axilite。3.axilite ap_memory修饰数组只可能被综合为单口RAM五、为什么axilite ap_memory修饰数组只可能被综合为单口RAMs_axilte和ap_memory组合作为一个混合接口数组的数据部分通过类似BRAM的模式进行传输。axilite主设备也就是ARM或者CPU在单个时钟周期内是没有办法对ap_memory接口来发起一次读和写的只能是要么发起读操作或者要么发起写操作虽然axilite的读写通道是独立的理论上是可以并发的但是ap_memory访问在hls中是FSM装天气控制状态机一次只能执行一个C语句也就是一次内存操作这就限制了同一个周期内无法从PS端发起两次独立的访问。ap_memory和s_axilite理论上可以共存因为一个管数据路径一个管控制路径。然而共存时数据路径的并发性就受限于AXI-Lite从接口的响应能力。在这种使用场景下工具分析不出需要双口的并发访问或者说生成的双口功能实际上无法被AXI-Lite主设备有效利用。六、axilite ap_memory修饰数组只可能被综合为单口RAM的结论1.当你在顶层数组接口上同时使用 s_axilite 和 ap_memory 时它被综合成单端口RAM几乎是必然的这个主要是ap_memory和axilite组合机制来决定的。2.ap_memory 接口是一个更通用、更简单的 RAM 接口。它生成像 q0、d0、addr0、ce0、we0 这样的低层级、无握手的并行信号。因为简单它可以被 HLS 内部的 AXI-Lite 适配器“消化”掉。3.当 ap_memory 和 s_axilite 并存时它们不冲突因为工作在不同层级对外物理接口完全就是一个 AXI4-Lite 从接口。CPU 只能看到一组寄存器地址。内部数据搬运HLS 会自动生成一个适配器模块将 AXI4-Lite 的事务“翻译”成一组启动 ap_memory 阵列所需的内部信号。这个自动生成的适配器才是单端口RAM限制的根源。4.为什么综合只能是单口RAM呢因为数据从 CPU 的 AXI4-Lite 总线流向这个阵列时必须经过翻译这个过程丢失了双端口的意义。即使 HLS 允许你强制将这个阵列的内部存储设为双端口比如用 #pragma HLS RESOURCE variablearr coreRAM_2P从外部 CPU 看来它依然是一个单端口的效果。原因一AXI4-Lite 协议的天然限制这是最致命的一点。AXI4-Lite 总线本身不支持同时读写。它的 5 个通道中读地址和写地址通道虽然独立但 AXI-Lite 规范严格限制所有事务必须按顺序完成。一个读事务必须等待上一个写事务的响应完成后才能发起。CPU 在单个时钟周期内绝不可能通过一条 AXI-Lite 总线对此设备进行“同时读写”。原因二适配器是“单线程”状态机HLS 生成的 AXI-Lite 适配器是一个顺序执行的状态机。它接收一个 AXI 请求然后驱动一次内部的 RAM 访问再返回响应。这个状态机一次只能处理一个请求无法生成两个独立的“读”和“写”的内部启动信号。原因三代码分析阶段的逻辑冲突既然 HLS 已经明确知道这个接口是 s_axilite它会认为顶层这个数组的访问源是单线程的 CPU。在分析你的函数代码时即使里面有机会并发的循环综合工具也会因为顶层接口的访问限制而放弃推断出需要双端口。最终综合出的 RTLCPU 看到的始终是一块平铺开的、可随机访问的、但同一时刻只能进行读或写操作的存储空间。七、如何解决双口RAM的问题一旦选择了 s_axilite ap_memory 这个组合双口 RAM 的所有好处就都被 AXI-Lite 的串行协议和适配器抹平了。如果你想实现真正的硬件层面并发读写的双口 RAM必须回归到纯硬件逻辑。路径非常明确放弃 s_axilite将数组接口指定为 bram 并正确编写并行的 C/C 代码或直接强制 coreRAM_2P。