VIVADO中通过updatemem更新BlockRAM内容

在FPGA当中,SRAM一般是通过Block RAM实现的,如果在一些含有自定义的CPU CORE的FPGA中,我们希望更新CPU的程序而不经过重新编译,这个时候就需要通过updatemem修改生成的bit中的RAM中的内容,从而实现新固件的烧写,在ISE中这个操作是通过write_mem实现的,而升级到vivado之后,相应的工具变成updatemem,虽然工具有变化,但是实际的内容并没有太多变化,之前用的Memory位置描述是一个bmm文件,现在变成了mmi文件,相应的格式也有一定的变化,下面我们来看一下具体的实现过程。

首先我们知道FPGA中的SRAM一般是BlockRAM实现的,FPGA中block ram也有很多种类,在生成block的时候,FPGA一般会根据面积或者功耗动态的规划RAM的实现方式,因为一般SRAM会比较大,所以常常需要多块block ram拼接起来,这里就涉及到一个拼接方式,为了简化各种不同的拼接组合,我们选择采用固定的block ram类型比如(512x36)的block实现拼接,因为我们的设计中RAM和ROM的数据宽度一般是32位的,所以就不会涉及数据位上面的拼接操作,只是在地址空间上会罗列更多的block ram.

在更新bit文件的内容的时候我们需要知道RAM的位置信息,这个可以通过打开PR之后的dcp文件,在工程中查找blockram就可以列出所有用到的RAM信息,里面也包含了地址信息,通过这些地址信息我们就可以去生成我们需要的mmi文件,一个mmi文件的例子如下:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<MemInfo Minor="0" Version="1">

  <Processor Endianness="little" InstPath="dummy">
    <AddressSpace Begin="0" End="16383" Name="bram">
      <BusBlock>
        <BitLane MemType="RAMB32" Placement="X8Y62">
          <DataWidth LSB="0" MSB="31"/>
          <AddressRange Begin="0" End="4095"/>
          <Parity NumBits="0" ON="false"/>
        </BitLane>
      </BusBlock>

      <BusBlock>
        <BitLane MemType="RAMB32" Placement="X8Y61">
          <DataWidth LSB="0" MSB="31"/>
          <AddressRange Begin="0" End="4095"/>
          <Parity NumBits="0" ON="false"/>
        </BitLane>
      </BusBlock>

      <BusBlock>
        <BitLane MemType="RAMB32" Placement="X8Y64">
          <DataWidth LSB="0" MSB="31"/>
          <AddressRange Begin="0" End="4095"/>
          <Parity NumBits="0" ON="false"/>
        </BitLane>
      </BusBlock>

      <BusBlock>
        <BitLane MemType="RAMB32" Placement="X8Y63">
          <DataWidth LSB="0" MSB="31"/>
          <AddressRange Begin="0" End="4095"/>
          <Parity NumBits="0" ON="false"/>
        </BitLane>
      </BusBlock>

    </AddressSpace>
  </Processor>

  <Config>
    <Option Name="Part" Val="xcvu440-flga2892-1-c"/>
  </Config>

</MemInfo>

有了mmi文件之后我们就可以通过如下的命令更新需要的bit文件了:

 updatemem -meminfo rom.mmi -data ss.elf -bit rom_top.bit -proc dummy -out new.bit -force

为了方便起见,我写了一个从dcp中提取位置信息的脚本:

proc write_mmi {cell_name  max_addr} {
    set proj [current_project]
    set filename "${cell_name}.mmi"
    set fileout [open $filename "w"]
    set brams [get_cells -hier -filter [list REF_NAME =~ RAMB* && NAME =~ "*${cell_name}*"]]
        puts $fileout "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
        puts $fileout "<MemInfo Version=\"1\" Minor=\"0\">"
        puts $fileout "  <Processor Endianness=\"Little\" InstPath=\"dummy\">"
    puts $fileout "  <AddressSpace Name=\"bram\" Begin=\"0\" End=\"${max_addr}\">"
    puts $fileout "    <BusBlock>"
    foreach cell $brams {
        puts $cell
        puts $fileout "      <BitLane MemType=\"RAMB32\" Placement=\"[get_property LOC $cell]\">"
        puts $fileout "        <DataWidth LSB=\"0\" MSB=\"31\"/>"
        puts $fileout "        <AddressRange Begin=\"0\" End=\"4095\"/>"
        puts $fileout "        <Parity NumBits=\"0\" ON=\"false\"/>"
        puts $fileout "      </BitLane>"
        puts $fileout ""
    }
    puts $fileout "    </BusBlock>"
    puts $fileout "  </AddressSpace>"
    puts $fileout "</Processor>"

        puts $fileout "<Config>"
        puts $fileout "  <Option Name=\"Part\" Val=\"[get_property PART [current_project ]]\"/>"
        puts $fileout "</Config>"
        puts $fileout "</MemInfo>"
        puts "MMI file ($filename) created successfully."
    close $fileout
}

两个参数,cell_name是RAM所在路径包含的一个字符串,后面一个是总的地址空间范围,以上。

发表新评论