{"id":18352697,"url":"https://github.com/chipsalliance/f4pga-xc7-bram-patch","last_synced_at":"2025-07-14T03:11:16.916Z","repository":{"id":44536949,"uuid":"243115666","full_name":"chipsalliance/f4pga-xc7-bram-patch","owner":"chipsalliance","description":"Tool for updating the contents of BlockRAMs found in Xilinx 7 series bitstreams.","archived":false,"fork":false,"pushed_at":"2022-02-09T10:00:51.000Z","size":8029,"stargazers_count":18,"open_issues_count":10,"forks_count":5,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-06T11:46:12.305Z","etag":null,"topics":["bitstream","fasm","prjxray","prjxray-bram","symbiflow","verilog","vivado"],"latest_commit_sha":null,"homepage":null,"language":"LLVM","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chipsalliance.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-25T22:23:46.000Z","updated_at":"2025-02-10T17:05:16.000Z","dependencies_parsed_at":"2022-09-20T08:00:29.283Z","dependency_job_id":null,"html_url":"https://github.com/chipsalliance/f4pga-xc7-bram-patch","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chipsalliance/f4pga-xc7-bram-patch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chipsalliance%2Ff4pga-xc7-bram-patch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chipsalliance%2Ff4pga-xc7-bram-patch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chipsalliance%2Ff4pga-xc7-bram-patch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chipsalliance%2Ff4pga-xc7-bram-patch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chipsalliance","download_url":"https://codeload.github.com/chipsalliance/f4pga-xc7-bram-patch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chipsalliance%2Ff4pga-xc7-bram-patch/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265237121,"owners_count":23732507,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitstream","fasm","prjxray","prjxray-bram","symbiflow","verilog","vivado"],"created_at":"2024-11-05T21:36:55.401Z","updated_at":"2025-07-14T03:11:16.874Z","avatar_url":"https://github.com/chipsalliance.png","language":"LLVM","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 1. Overview\nThis software will take a bitstream and patch it with new memory contents to create a new bitstream.\n\nMore correctly, it will patch a .fasm file representing a bitstream to create a new .fasm file. \nIt relies on prjxray to actually convert between .bit and .fasm representations.\n\nIt works on designs that have come from Vivado and relies on a Tcl script to extract the needed \nmetadata (placed into a .mdd file) to understand which memory primitives in the bitstream correspond to which \"chunks\" \nof the original Verilog-specified memory.\n\nTypically, the memory contents in Verilog are included using $readmemb() or\n$readmemh() calls in Verilog to read the memory initialization contents from a text file. \nThis flow expects that and will allow you to supply a different memory contents file. \nIt will then patch that file contents into the BRAM primitives in the bitstream.\n\nThe tools relies on having a .mdd file to describe the contents of the memories in the \ncompiled designs.  In a Vivado flow, the .mdd file can be created using the \n_testing/gen.tcl_ script.  For other flows, a mechanism will be needed to generate such files\nfrom the tools in that other flow.\n\nSince designs will typically have multiple BRAM-based memories, the tools expect the name of the \nmemory to be patched to be specified.  The tool supports either hierarchical or flattened designs.\n\n# 2. Installation\n\n## 2.1 Linux, Python, and Vivado Versions\n* At the current time, symbiflow/prjxray requires Vivado version 2017.2.  \n* This tool was developed and has been tested on Ubuntu 16.04 with its native Python 3.5.\n\n## 2.2 Installing prjxray and prjxray-bram-patch\nAfter cloning both projects, follow the instructions on the prjxray github site for fully installing and configuring prjxray.  \n\nThere is nothing needed to be done to prjxray-bram-patch project once prjxray has been installed.\n\n## 2.3 Startup Scripts\nFor running with Vivado, put in the following lines in your .bashrc file:\n\n    # Adjust paths below as necessary\n    export XRAY_VIVADO_SETTINGS=${HOME}/Xilinx_2017.2/Vivado/2017.2/settings64.sh\n    source ${HOME}/prjxray/settings/artix7.sh\n    \n    export MEM_PATCH_DIR=${HOME}/prjxray-bram-patch\n\nThe first two lines are part of the prjxray installation.  The third line is required for prjxray-bram-patch and tells the tools where you installed it.   Note that you can run prjxray-bram-patch without Vivado installed --- the above is only included to be able to use Vivado to originally create designs.\n\n## 2.4 Sample Designs and the Test Database\nThere are a few sample designs in the \"samples\" directory.\n\nAdditionally, a large collection of sample designs have been created and typically live in $MEM_PATCH_DIR/testing/tests/master.  \nThey are not needed for just doing patching but are used for testing of the patcher.  And, they are large and so are not included in the repo but can be recreated by running:\n\n    python generate_tests.py\n\nwhich will run through a series of memory sizes and generate test cases using Vivado and other scripts.  You can modify the contents of \"generate_tests.py\" to alter which memory sizes are generated.\n\nIn fact, generate_tests.py and the scripts it calls are instructive to show how a design is generated, along with its .mdd file.\n\nNOTE: the above script will run for a LONG time.  But, you can go into the script and modify the list of the memory sizes it will generate test circuits for.\n\n\n# 3. Test infrastructure\nIn order to verify that the patcher works for all size/shapes/configurations of memories, a test infrastructure is included.  The main two steps for this are (1) generation of tests and (2) the actual running of the tests.\n\n## 3.1 Generation\nThis entails generating Verilog code which gets synthesized and implemented to a bitstream for each size of memory desired. \n\n### File: testing/generate_tests_script.sh\nThis script creates a single memory test case of ${DEPTH} words by ${WIDTH} bits wide.   The test case is placed into a directory: with the name ${DEPTH}b$WIDTH\" and that directory is placed into a location specified by a parameter to this script.\n\n1. It first creates the needed directory (referred to as _DIR_ in the discussion below).\n1. It then creates two randomly-filled memory initialization files called DIR/init/init.mem and DIR/init/alt.mem\n1. Next, it creates a customized SystemVerilog design in DIR/vivado which implements the memory and a top level design and which reads the memory's contents from DIR/init/init.mem.\n1. Vivado is then called and the design is compiled through to bitstream.\n1. The resulting bitstream is converted to a fasm file called: DIR/real.fasm\n1. Finally DIR/real.fasm is patched with random data and written to DIR/alt.fasm (to be used in the testing later)\n\nThe above script can be called in a stand-alone fashion as:\n```\ngenerate_tests_script.sh someDirName 16 128k 131072 \n```\nand the results will be placed into `someDirName/128kb16`.  The results will consist of some memory initialization files, a .sv design and associated bit file, a .mdd file, and real.fasm and alt.fasm.\n\n### File: generate_tests.py\nThis program is intended to generate and manage a large set of test designs (which it will place into `testing/tests/master`).  To do so it simply generates needed designs for all sizes by calling the program **testing/generate_tests_script.sh**.  The size of memories to generate designs for are given in a series of lists at the top of the code.  If a particular design already exists, then it will not re-generate it.\n  \n## 3.2 Testing\nThe program **run_tests.py** is used to actually do the testing.  The basic flow is as follows:\n1. It keeps lists of tests that have (a) passed, (b) failed, or were (c) incomplete.\n1. There is lots of flexibility provided to control which designs are tested:\n   * There are lists to specify sizes and shapes of memories to test.\n   * If the SKIP_PASSED flag is set to true, only those that have not yet passed will be tested.  \n   * You can supply command line parameters to specify the files to patch and test or just the directory where they are located.  Otherwise, it will run tests on all designs in testing/tests/master that are not in its `testing/tests/passed.txt` file.  \n\nIts basic operation is to patch the alt.fasm file with the contents of the init/init.mem file, writing the results into a patched.fasm file.  If the contents of patched.fasm match those of real.fasm the test is declared a success.\n\n# 4. Doing a Simple Patch\nYou need not use the above test framework to do a simple patch.  The directory `singletests/simple` contains an example of a stand-alone test that creates a specific memory design and then tests whether it can re-patch it without error.  You might try running the `prepTest.sh` script followed by the `runTest.sh` script to see how this is done.  \n\n## 4.1 Doing a Patch By Hand\nImagine that a design has been synthesized and implemented in Vivado.  The steps to patch its memory include the following:\n\n#### Step 1: Generate .mdd File\nWhile still in Vivado, do the following at the Tcl console:\n```\nsource testing/mdd_make.tcl   # May need to adjust path\nmddMake \"original.mdd\"\n```\nThis will generate a .mdd file.  This file will contain the metadata needed to describe how the memory in the original design was broken up across a collection of BRAM cells.  \n\n#### Step 2: Create New Memory Initialization File \nBased on the format of the original **$readmemb()** or **$readmemh()** file you used in your original Verilog, create a new memory initialization file to represent what you want the memory contents to be changed to.\n\nAt this point you should have the following files available (your filenames will be different):\n    \n    newMemContents.init\n    original.bit\n    original.mdd\n\n#### Step 3: Generate a .fasm File From .bit File\nNext, you convert your .bit file to a .fasm file using the following: \n\n    $XRAY_BIT2FASM original.bit \u003e orig.fasm\n\n#### Step 4: Patch the .fasm File\nTo replace the old memory contents in the bitstream with new contents, run the patch program using the following:\n\n    python patch_mem orig.fasm newMemContents.init original.mdd patched.fasm memoryName\n\nIn the above, the last parameter is the name of the memory to be patched.  This name can be derived from a .mdd file.  For example, here is an .mdd file for a memory that is 128 bits deep by 16 bits wide:\n\n    DESIGN design_1\n    PART xc7a50tfgg484-1\n    \n    CELL mem/ram_reg\n      TILE BRAM_L_X6Y20\n      CELLTYPE RAMB18E1\n      CELLPLACEMENT RAMB18_X0Y8\n      MEM.PORTA.DATA_BIT_LAYOUT p0_d16\n      RTL_RAM_NAME ram\n      RAM_EXTENSION_A NONE\n      RAM_MODE TDP\n      READ_WIDTH_A 18\n      READ_WIDTH_B 18\n      WRITE_WIDTH_A 18\n      WRITE_WIDTH_B 18\n      RAM_OFFSET NONE\n      BRAM_ADDR_BEGIN 0\n      BRAM_ADDR_END 1023\n      BRAM_SLICE_BEGIN 0\n      BRAM_SLICE_END 15\n      RAM_ADDR_BEGIN NONE\n      RAM_ADDR_END NONE\n      RAM_SLICE_BEGIN NONE\n      RAM_SLICE_END NONE\n    ENDCELL\n\nThe \"memoryName\" to provide when patching the design would be \"mem/ram\".  This is a combination of part of the CELL name (from the 1st line) and the RTL_RAM_NAME (from the 6th line).\n\nIn contrast, here is the top portion of a .mdd file for a hierarchical design containing multiple memories where the possible \"memoryName\" values to use would be either \"mem1/ram\" or \"mem2/mem2a/ram\".  As above you take all but the last component of the CELL value plus all of the RTL_RAM_NAME to create this.\n\nDESIGN design_1\nPART xc7a50tfgg484-1\n\n```\nCELL mem1/ram_reg\n  TILE BRAM_L_X6Y5\n  CELLTYPE RAMB18E1\n  CELLPLACEMENT RAMB18_X0Y2\n  MEM.PORTA.DATA_BIT_LAYOUT p0_d1\n  RTL_RAM_NAME ram\n  RAM_EXTENSION_A NONE\n\n  ...\n  \nENDCELL\n\nCELL mem2/mem2a/ram_reg\n  TILE BRAM_L_X6Y5\n  CELLTYPE RAMB18E1\n  CELLPLACEMENT RAMB18_X0Y3\n  MEM.PORTA.DATA_BIT_LAYOUT p0_d1\n  RTL_RAM_NAME ram\n  RAM_EXTENSION_A NONE\n  RAM_MODE TDP\n  READ_WIDTH_A 18\n```\n\nFinally, here is a fragment from a file containing a large memory which has been broken up into a large array BRAM cells (it is from a 128K by 8 bit memory which was divided by Vivado into an array of 4 x 8  RAMB36E1 cells):\n\n```\nDESIGN design_1\nPART xc7a50tfgg484-1\n\nCELL mem/ram_reg_0_0\n  TILE BRAM_L_X6Y30\n  CELLTYPE RAMB36E1\n  LOC RAMB36_X0Y6\n  MEM.PORTA.DATA_BIT_LAYOUT p0_d1\n  RTL_RAM_NAME ram\n  RAM_EXTENSION_A LOWER\n  ...\n```\nBecause the memory has been broken up into many BRAM primitives the CELL values will have the form \"mem/ram_reg_x_y\" where the x and y values signify the primitive's position in the 2D tiling of BRAMs required to make up the large memory.\n\nIn this case the correct \"memoryName\" would be _mem/ram_.\n\nFrom the above, it should be clear that the form of the name to use is the CELL value (minus the last component) concatenated with the RTL_RAM_NAME.\n\n#### Step 5: Generate New .fasm File to New .bit File\nFinally, you convert the new .fasm file to a .bit file using:\n\n    $XRAY_FASM2FRAMES patched.fasm patched.frm \\\n      $XRAY_TOOLS_DIR/xc7frames2bit \\\n          --part_name $XRAY_PART \\\n          --part_file $XRAY_PART_YAML \\\n          --frm_file patched.frm \\\n          --output_file patched.bit\n\n# 5. What Are MDD Files?\nWhen large memories are created by the Vivado tools, they are chopped up and mapped onto a collection of BRAM primitives on the FPGA.  The patching tool requires information on how that mapping was done so that memory initialization file contents can be appropriately divided up for patching to the bitstream.  \n\nThe MDD file contains the information needed to do that mapping.  It is generated by the Tcl script: **testing/mdd_make.tcl**.  If you are not using Vivado, you will need to create such an MDD file some other way.\n\nThe current MDD file contains information on mapped BRAM primitives. It contains a number of BRAM properties that are not currently used and thus could possibly be reduced in the future.\n\n# The bitMapping.py Program\nThe `bitMapping.py` program is intend to provide an understandable algorithm for computing the mapping between `init.mem` file bits and their location in the `INIT` and `INITP` strings in a FASM file as well as in frames of a bitstream.  \n\nThe first mapping (init -\u003e fasm) is based on experimentation with a set of test circuits.  The second mapping (fasm -\u003e bitstream) is based on the prjxray database files `/prjxray/database/artix7/segbits_bram_l.block_ram.db` and `/prjxray/database/artix7/segbits_bram_r.block_ram.db` files.\n\nWhen run, it returns a list of mappings.\n\nIt has a couple of command line flags to control verbosity and to print out the resulting mappings.\n\n# The checkTheBits.py Program\nThis program uses `bitMapping.py` and loads up a specific design and, for each bit in the `init/init.mem` file,   checks that the corresponding bit is correct in both the `real.fasm` and `vivado/designName.bit` files.\n\nIts behavior is controlled by command line options for verbosity, etc.\n\n# The checkAllTheBits.py Program\nThis program runs `checkTheBits.py` on all the designs in a directory.  It assumes a particular file naming convention.  See the code.\nIts behavior is controlled by command line options for verbosity, etc.\n\n# The fasm2init.py Program\nThis program uses `bitMapping.py` to get the mappings for a memory and then uses it to reconstruct an `init/init.mem` file from a corresponding FASM file.\n\n# The bits2init.py Program (to be completed)\nThis program uses `bitMapping.py` to get the mappings for a memory and then uses it to reconstruct an `init/init.mem` file from a bitstream file.\n\n## More Info\nRead the `The_Algorithm.md` file in this repo for more information on how memories are mapped to BRAMs and how the `bitMapping.py` program operates.\n\n# The findTheBits.py Program (deprecated)\nThe `findTheBits.py` program is intend to provide an understandable algorithm for computing the mapping between `init.mem` file bits and their location in the `INIT` and `INITP` strings in a FASM file.  \n\nIt then uses the prjxray database files to map those INIT and INITP bit locations to frame/offset locations in the real bitstream.  To do so it uses the `.../prjxray/database/artix7/segbits_bram_l.block_ram.db` file.\n\nIt then computes a mapping between those INIT and INITP string values and the bitstream's frames and bit offsets.  It does this using prjxray's `.../prjxray/database/artix7/segbits_bram_l.block_ram.db` file.\n\nAdditionally:\n1. It can also check, bit-by-bit, if the mapping was correct by comparing bits in the `init.mem` file with bits in the FASM file's `INIT` strings.  If the check is successful it will print a message.\n1. It has a verbose flag to help in debugging by printing out lots of information on how the mapping computation was done.\n\nAll of the 3 above options are controlled by command line options:\n\n## Usage of findTheBits.py (deprecated)\nIt is intended, like all programs in this project, using the prjxray environment.  For all examples below, leaving off the `--design designName` argument will cause it to run for _all_ designs in the given directory (see last example).\n```\n# Run the program on a specific design.  \n# If no assertion failures, then at least the program didn't crash. :-)\n# Not a particularly useful mode\npython findTheBits.py ./testing/tests/master --design 128b1\n\n# Run the program on a specific design\n# Check that the init.mem, FASM file, and bitstream file bit values match\npython findTheBits.py ./testing/tests/master --design 128b1 --check\n\n# Run the program on a specific design and print out the mappings\npython findTheBits.py ./testing/tests/master --design 128b1 --printmappings\n\n# Run the program on a specific design.\n# Print out the mappings and do the checking\npython findTheBits.py ./testing/tests/master --design 128b1 --printmappings --check\n\n# Run the program and generate tons of debug output\npython findTheBits.py ./testing/tests/master --design 128b1 --verbose\n\n# Run the program on ALL designs in a given directory\n# Will print out if the checks were succesful or will incur an asserter error\n# Useful for regression tests\npython findTheBits.py ./testing/tests/master --check\n```\n\n## Reversing the Process\nThe mapping information from above can be used to map bitstream bits to FASM INIT/INITP bits to init.mem values, meaning it can be _directly_ used to reconstruct an init.mem file from a bitstream (going through FASM as an intermediate step).\n\nOr, the prjxray database information could be used to directly extract the bits from a bitstream, allowing you to bypass the FASM file step completely.\n\n## More Info on findTheBits.py\nRead the `The_Algorithm.md` file in this repo for more information on how memories are mapped to BRAMs and how the `findTheBits.py` program operates.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchipsalliance%2Ff4pga-xc7-bram-patch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchipsalliance%2Ff4pga-xc7-bram-patch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchipsalliance%2Ff4pga-xc7-bram-patch/lists"}