Skip to content

Commit

Permalink
fixup! [fpga] Add flash info MMI dumps for earlgrey
Browse files Browse the repository at this point in the history
  • Loading branch information
a-will committed Nov 27, 2024
1 parent 9dfba8c commit 34bb743
Showing 1 changed file with 133 additions and 93 deletions.
226 changes: 133 additions & 93 deletions hw/top_earlgrey/util/vivado_hook_write_bitstream_pre.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -19,90 +19,96 @@ set_property BITSTREAM.CONFIG.USR_ACCESS TIMESTAMP [current_design]
#
# Args:
# filename: Path to the output file.
# brams: A list of BRAM cells.
# mem_type_regex: The BRAM type regex, dividing the mem type and site, e.g. {(RAMB\d+)_(\w+)}.
# fake_word_width: If non-zero, pretend that $brams covers
# `fake_word_width` bits. Influences the values of the
# MMI's <AddressSpace> and <DataWidth> tags.
# addr_end_multiplier: A coefficient applied to the address space. Influences
# the values of the MMI's <AddressSpace> and
# <AddressRange> tags.
# mem_info: Dictionary of dictionaries with following properties for each (inner) value:
# brams: A list of BRAM cells.
# mem_type_regex: The BRAM type regex, dividing the mem type and site, e.g. {(RAMB\d+)_(\w+)}.
# fake_word_width: If non-zero, pretend that $brams covers
# `fake_word_width` bits. Influences the values of the
# MMI's <AddressSpace> and <DataWidth> tags.
# addr_end_multiplier: A coefficient applied to the address space. Influences
# the values of the MMI's <AddressSpace> and
# <AddressRange> tags.
# designtask_count: A number used for logging with `send_msg`.
proc generate_mmi {filename brams mem_type_regex fake_word_width addr_end_multiplier designtask_count} {
proc generate_mmi {filename mem_infos designtask_count} {
send_msg "${designtask_count}-1" INFO "Dumping MMI to ${filename}"

if {[llen $brams] == 0} {
send_msg "${designtask_count}-1" INFO "Cannot make MMI for zero BRAMs"
return
}

set workroot [file dirname [info script]]
set filepath "${workroot}/${filename}"
set fileout [open $filepath "w"]

set fake_slice_width [expr $fake_word_width / [llen $brams]]

# Calculate the overall address space.
set space 0
foreach inst [lsort -dictionary $brams] {
set slice_begin [get_property ram_slice_begin [get_cells $inst]]
set slice_end [get_property ram_slice_end [get_cells $inst]]
if {$slice_begin eq {} || $slice_end eq {}} {
send_msg "${designtask_count}-2" ERROR "Extraction of ${filename} information failed."
}
set slice_width [expr {$slice_end - $slice_begin + 1}]
if {$slice_width < $fake_slice_width} {
set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
set slice_width $fake_slice_width
}
set addr_begin [get_property ram_addr_begin [get_cells $inst]]
set addr_end [get_property ram_addr_end [get_cells $inst]]
if {$addr_begin eq {} || $addr_end eq {}} {
send_msg "${designtask_count}-3" ERROR "Extraction of ${filename} MMI information failed."
}

# Calculate total number of bits.
set space [expr {$space + ($addr_end - $addr_begin + 1) * $slice_width}]
set last_slice_width $slice_width
}
set space [expr {($space * $addr_end_multiplier / 8) - 1}]

# Generate the MMI.
set part [get_property PART [current_design]]
puts $fileout "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
puts $fileout "<MemInfo Version=\"1\" Minor=\"1\">"
puts $fileout " <Processor Endianness=\"Little\" InstPath=\"dummy\">"
puts $fileout " <AddressSpace Name=\"dummy_addrspace\" Begin=\"0\" End=\"$space\">"
puts $fileout " <BusBlock>"

set part [get_property PART [current_design]]
foreach inst [lsort -dictionary $brams] {
set loc [get_property LOC [get_cells $inst]]
set loc_matches [regexp $mem_type_regex $loc loc_match loc_prefix loc_suffix]
if {$loc_matches == 0} {
send_msg "${designtask_count}-4" ERROR "Extraction of ${filename} mem location failed."
}
set slice_begin [get_property ram_slice_begin [get_cells $inst]]
set slice_end [get_property ram_slice_end [get_cells $inst]]
set slice_width [expr {$slice_end - $slice_begin + 1}]
if {$slice_width < $fake_slice_width} {
set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
set slice_width $fake_slice_width
dict for {id mem_info} $mem_infos {
dict with mem_info {
if {[llen $brams] == 0} {
send_msg "${designtask_count}-1" INFO "Cannot make MMI for zero BRAMs"
return
}

set fake_slice_width [expr $fake_word_width / [llen $brams]]

# Calculate the overall address space.
set space 0
foreach inst [lsort -dictionary $brams] {
set slice_begin [get_property ram_slice_begin [get_cells $inst]]
set slice_end [get_property ram_slice_end [get_cells $inst]]
if {$slice_begin eq {} || $slice_end eq {}} {
send_msg "${designtask_count}-2" ERROR "Extraction of ${filename} information failed."
}
set slice_width [expr {$slice_end - $slice_begin + 1}]
if {$slice_width < $fake_slice_width} {
set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
set slice_width $fake_slice_width
}
set addr_begin [get_property ram_addr_begin [get_cells $inst]]
set addr_end [get_property ram_addr_end [get_cells $inst]]
if {$addr_begin eq {} || $addr_end eq {}} {
send_msg "${designtask_count}-3" ERROR "Extraction of ${filename} MMI information failed."
}

# Calculate total number of bits.
set space [expr {$space + ($addr_end - $addr_begin + 1) * $slice_width}]
set last_slice_width $slice_width
}
set space [expr {($space * $addr_end_multiplier / 8) - 1}]

# Generate the MMI.
puts $fileout " <Processor Endianness=\"Little\" InstPath=\"$id\">"
puts $fileout " <AddressSpace Name=\"dummy_addrspace\" Begin=\"0\" End=\"$space\">"
puts $fileout " <BusBlock>"

foreach inst [lsort -dictionary $brams] {
set loc [get_property LOC [get_cells $inst]]
set loc_matches [regexp $mem_type_regex $loc loc_match loc_prefix loc_suffix]
if {$loc_matches == 0} {
send_msg "${designtask_count}-4" ERROR "Extraction of ${filename} mem location failed."
}
set slice_begin [get_property ram_slice_begin [get_cells $inst]]
set slice_end [get_property ram_slice_end [get_cells $inst]]
set slice_width [expr {$slice_end - $slice_begin + 1}]
if {$slice_width < $fake_slice_width} {
set slice_end [expr {$slice_begin + $fake_slice_width - 1}]
set slice_width $fake_slice_width
}
set addr_begin [get_property ram_addr_begin [get_cells $inst]]
set addr_end [get_property ram_addr_end [get_cells $inst]]
set addr_end [expr {($addr_end + 1) * $addr_end_multiplier - 1}]
puts $fileout " <BitLane MemType=\"$loc_prefix\" Placement=\"$loc_suffix\">"
puts $fileout " <DataWidth MSB=\"$slice_end\" LSB=\"$slice_begin\"/>"
puts $fileout " <AddressRange Begin=\"$addr_begin\" End=\"$addr_end\"/>"
puts $fileout " <Parity ON=\"false\" NumBits=\"0\"/>"
puts $fileout " </BitLane>"
}
puts $fileout " </BusBlock>"
puts $fileout " </AddressSpace>"
puts $fileout " </Processor>"
}
set addr_begin [get_property ram_addr_begin [get_cells $inst]]
set addr_end [get_property ram_addr_end [get_cells $inst]]
set addr_end [expr {($addr_end + 1) * $addr_end_multiplier - 1}]
puts $fileout " <BitLane MemType=\"$loc_prefix\" Placement=\"$loc_suffix\">"
puts $fileout " <DataWidth MSB=\"$slice_end\" LSB=\"$slice_begin\"/>"
puts $fileout " <AddressRange Begin=\"$addr_begin\" End=\"$addr_end\"/>"
puts $fileout " <Parity ON=\"false\" NumBits=\"0\"/>"
puts $fileout " </BitLane>"
}
puts $fileout " </BusBlock>"
puts $fileout " </AddressSpace>"
puts $fileout " </Processor>"
puts $fileout "<Config>"
puts $fileout " <Option Name=\"Part\" Val=\"$part\"/>"
puts $fileout "</Config>"

puts $fileout " <Config>"
puts $fileout " <Option Name=\"Part\" Val=\"$part\"/>"
puts $fileout " </Config>"
puts $fileout "</MemInfo>"
close $fileout
send_msg "${designtask_count}-4" INFO "MMI dumped to ${filepath}"
Expand Down Expand Up @@ -179,35 +185,69 @@ set mem_type_regex {(RAMB\d+)_(\w+)}
# A hack that works is to pretend the data width is actually 40 bits. Updatemem
# seems to write that extra zero bit into the ether without complaint.
set rom_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_rom_ctrl*"] " "]
generate_mmi "rom.mmi" $rom_brams $mem_type_regex 40 1 1
dict set memInfo rom brams $rom_brams
dict set memInfo rom mem_type_regex $mem_type_regex
dict set memInfo rom fake_word_width 40
dict set memInfo rom addr_end_multiplier 1
#generate_mmi "rom.mmi" $rom_brams $mem_type_regex 40 1 1

# OTP does not require faking the word width, but it has its own quirk. It seems
# each 22-bit OTP word is followed by 15 zero words. The MMI's <AddressSpace>
# and <AddressRange> tags need to account for this or else updatemem will think
# that its data input overruns the address space. The workaround is to pretend
# the address space is 16 times larger than we would normally compute.
set otp_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_otp_ctrl*"] " "]
generate_mmi "otp.mmi" $otp_brams $mem_type_regex 0 16 2
dict set memInfo otp brams $otp_brams
dict set memInfo otp mem_type_regex $mem_type_regex
dict set memInfo otp fake_word_width 0
dict set memInfo otp addr_end_multiplier 16
#generate_mmi "otp.mmi" $otp_brams $mem_type_regex 0 16 2

# For debugging purposes, dump the INIT_XX strings for ROM and OTP.
dump_init_strings "rom_init_strings.txt" $rom_brams 3
dump_init_strings "otp_init_strings.txt" $otp_brams 4

# The flash banks have 76-bit wide words. 64 bits are data, and 12 bits are metadata.
set flash0_info0_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[0].u_info_mem*"] " "]
generate_mmi "flash0_info0.mmi" $flash0_info0_brams $mem_type_regex 0 1 5

set flash0_info1_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[1].u_info_mem*"] " "]
generate_mmi "flash0_info1.mmi" $flash0_info1_brams $mem_type_regex 0 1 6

set flash0_info2_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[2].u_info_mem*"] " "]
generate_mmi "flash0_info2.mmi" $flash0_info2_brams $mem_type_regex 0 1 7

set flash1_info0_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[0].u_info_mem*"] " "]
generate_mmi "flash1_info0.mmi" $flash1_info0_brams $mem_type_regex 0 1 8

set flash1_info1_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[1].u_info_mem*"] " "]
generate_mmi "flash1_info1.mmi" $flash1_info1_brams $mem_type_regex 0 1 9

set flash1_info2_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[2].u_info_mem*"] " "]
generate_mmi "flash1_info2.mmi" $flash1_info2_brams $mem_type_regex 0 1 10
## The flash banks have 76-bit wide words. 64 bits are data, and 12 bits are metadata.
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[0].u_info_mem*"] " "]
#dict set memInfo flash0_info0 brams $flash_info_brams
#dict set memInfo flash0_info0 mem_type_regex $mem_type_regex
#dict set memInfo flash0_info0 fake_word_width 0
#dict set memInfo flash0_info0 addr_end_multiplier 1
##generate_mmi "flash0_info0.mmi" $flash0_info0_brams $mem_type_regex 0 1 5
#
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[1].u_info_mem*"] " "]
#dict set memInfo flash0_info1 brams $flash_info_brams
#dict set memInfo flash0_info1 mem_type_regex $mem_type_regex
#dict set memInfo flash0_info1 fake_word_width 0
#dict set memInfo flash0_info1 addr_end_multiplier 1
##generate_mmi "flash0_info1.mmi" $flash0_info1_brams $mem_type_regex 0 1 6
#
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[0]*gen_info_types[2].u_info_mem*"] " "]
#dict set memInfo flash0_info2 brams $flash_info_brams
#dict set memInfo flash0_info2 mem_type_regex $mem_type_regex
#dict set memInfo flash0_info2 fake_word_width 0
#dict set memInfo flash0_info2 addr_end_multiplier 1
##generate_mmi "flash0_info2.mmi" $flash0_info2_brams $mem_type_regex 0 1 7
#
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[0].u_info_mem*"] " "]
#dict set memInfo flash1_info0 brams $flash_info_brams
#dict set memInfo flash1_info0 mem_type_regex $mem_type_regex
#dict set memInfo flash1_info0 fake_word_width 0
#dict set memInfo flash1_info0 addr_end_multiplier 1
##generate_mmi "flash1_info0.mmi" $flash1_info0_brams $mem_type_regex 0 1 8
#
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[1].u_info_mem*"] " "]
#dict set memInfo flash1_info1 brams $flash_info_brams
#dict set memInfo flash1_info1 mem_type_regex $mem_type_regex
#dict set memInfo flash1_info1 fake_word_width 0
#dict set memInfo flash1_info1 addr_end_multiplier 1
##generate_mmi "flash1_info1.mmi" $flash1_info1_brams $mem_type_regex 0 1 9
#
#set flash_info_brams [split [get_cells -hierarchical -filter " PRIMITIVE_TYPE =~ ${bram_regex} && NAME =~ *u_flash_ctrl*gen_prim_flash_banks[1]*gen_info_types[2].u_info_mem*"] " "]
#dict set memInfo flash1_info2 brams $flash_info_brams
#dict set memInfo flash1_info2 mem_type_regex $mem_type_regex
#dict set memInfo flash1_info2 fake_word_width 0
#dict set memInfo flash1_info2 addr_end_multiplier 1
##generate_mmi "flash1_info2.mmi" $flash1_info2_brams $mem_type_regex 0 1 10

generate_mmi "memories.mmi" $memInfo 1

0 comments on commit 34bb743

Please sign in to comment.