1+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
2+ #
3+ # Procedure: generate_mmi
4+ #
5+ # Arguments: - mmi_file
6+ # Name of the mmi file to be generated
7+ #
8+ # Use: Generate the .mmi file using the location information from the implemented design.
9+ #
10+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
11+
12+ proc generate_mmi {mmi_file} {
13+ # If the current open implemented design does not equal the latest implementation run, open the implemented design
14+ if {[current_run -implementation] != [current_design]} { open_run [current_run -implementation] }
15+ # Create a list of the BRAM locations in loc_list.
16+ set list_mem [get_property LOC [get_cells -hierarchical -filter { PRIMITIVE_TYPE =~ BMEM.bram.* && NAME =~ " uAHB2RAM*" }]]
17+ set loc_list {}
18+ foreach x $list_mem {
19+ lappend loc_list [string map {RAMB36_ {}} $x ]
20+ }
21+ # Write the header to the .mmi file.
22+ set DataWidth " \t\t\t\t\t <DataWidth MSB=\" 31\" LSB=\" 0\" />"
23+ set AddressRange " \t\t\t\t\t <AddressRange Begin=\" 0\" End=\" 4095\" />"
24+ set Parity " \t\t\t\t\t <Parity ON=\" false\" NumBits=\" 0\" />"
25+ set CloseBitLane " \t\t\t\t </BitLane>"
26+ set PreBitLane " \t\t\t\t <BitLane MemType=\" RAMB36\" Placement=\" "
27+ set PostBitLane " \" >"
28+ set fd [open " mmi.tmp" w]
29+ puts $fd " <?xml version=\" 1.0\" encoding=\" UTF-8\" ?>"
30+ puts $fd " <MemInfo Version=\" 1\" Minor=\" 15\" >"
31+ puts $fd " \t <Processor Endianness=\" Little\" InstPath=\" my_bram\" >"
32+ puts $fd " \t\t <AddressSpace Name=\" memory\" Begin=\" 0\" End=\" 16384\" >"
33+ puts $fd " \t\t\t <BusBlock>"
34+ set bString " "
35+ # Create a new BitLane object in the .mmi for each BRAM block in loc_list.
36+ foreach BitLane $loc_list {
37+ set bString " "
38+ append bString $PreBitLane $BitLane $PostBitLane
39+ puts $fd $bString
40+ puts $fd $DataWidth
41+ puts $fd $AddressRange
42+ puts $fd $Parity
43+ puts $fd $CloseBitLane
44+ }
45+ # Write the footer to the .mmi file.
46+ puts $fd " \t\t\t </BusBlock>"
47+ puts $fd " \t\t </AddressSpace>"
48+ puts $fd " \t </Processor>"
49+ puts $fd " \t <Config>"
50+ puts $fd " \t\t <Option Name=\" Part\" Val=\" xc7a35tcpg236-1\" />"
51+ puts $fd " \t </Config>"
52+ puts $fd " \t <DRC>"
53+ puts $fd " \t\t <Rule Name=\" RDADDRCHANGE\" Val=\" false\" />"
54+ puts $fd " \t </DRC>"
55+ puts $fd " </MemInfo>"
56+ # Move the file from mmi.tmp to bram.mmi, deleting the temporary file.
57+ close $fd
58+ file copy -force mmi.tmp bram.mmi
59+ file delete mmi.tmp
60+ }
61+
62+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
63+ #
64+ # Procedure: byte_reverse
65+ #
66+ # Arguments: - str
67+ # Hexadecimal string of integer number of bytes
68+ #
69+ # Use: Reverse the order of the bytes in a hexadecimal string.
70+ # Called by generate_mem when converting the .data file to .mem due to memory mapping in .mem format.
71+ #
72+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
73+
74+ proc byteReverse {str} {
75+ set strLength [string length $str ]
76+ set bytesPerString [ expr {$strLength / 2} ]
77+ set reverseString {}
78+ # Firstly, reverse the string: {0 1 2 3 4 5 6 7} -> {7 6 5 4 3 2 1 0}
79+ for {set i 0} {$i < $strLength } {incr i} {
80+ append reverseString [string index $str [expr {$strLength - $i - 1}]]
81+ }
82+ # Swap the order of the nibbles: {7 6 5 4 3 2 1 0} -> {6 7 4 5 2 3 0 1}
83+ set nibbleSwapString {}
84+ for {set i 0} {$i < $bytesPerString } {incr i} {
85+ append nibbleSwapString [string index $reverseString [expr {2*$i + 1}]]
86+ append nibbleSwapString [string index $reverseString [expr {2*$i }]]
87+ }
88+ set nibbleSwapString
89+ }
90+
91+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
92+ #
93+ # Procedure: generate_mem
94+ #
95+ # Arguments: - data_file
96+ # The name of the .data file containing the memory initialization data in hex.
97+ # - mem_file
98+ # The name of the .mem output file to be created.
99+ # This name is parameterized in update_bitstream.tcl to be passed to the updatemem command.
100+ #
101+ # Use: Convert the .data file to the .mem file, performing all of the byte mapping.
102+ #
103+ # Terms: Chunk - four 32-bit words (8 character hex strings) which are written in packets to the mem_file.
104+ #
105+ # # # # # # # # # # # # # # # # # # # # # # # # # # #
106+
107+ proc generate_mem {data_file mem_file} {
108+ # Write the Memory Address start prefix to the .mem file
109+ set prefix " @0000"
110+ set fo [open code.tmp w]
111+ puts $fo $prefix
112+ set fi [open $data_file r] ;# Open the file specified by data_file {code.data} for read.
113+ set bytes_per_word 4 ;# Bytes per word - hardcoded to 4 (32-bit words). Used for timing when to write chunks.
114+ set ChunksDone 1 ;# ChunksDone is set to <0 at EOF. Used to break out of while loop.
115+ set chunkCounter 0 ;# chunkCounter counts up to 4 for each word read in. Once it reaches four the chunk is written to the mem_file.
116+ set chunkList {0 0 0 0}
117+ while {($ChunksDone >= 0)} {
118+ set ChunksDone [gets $fi line] ;# chunksDone contains the latest line of the data_file.
119+ # If the loop has reached EOF, pad the chunkList with "00000000" and write it to the output file before exiting loop.
120+ if {$ChunksDone < 0} {
121+ for {set i $chunkCounter } {$i < $bytes_per_word } {incr i} {
122+ lset chunkList $i " 00000000"
123+ }
124+ # Write the padded chunk to the output file.
125+ for {set i 0} {$i < $bytes_per_word } {incr i} {
126+ set lineStr {}
127+ foreach line $chunkList {
128+ append lineStr [string index $line [expr {2*$i } ]]
129+ append lineStr [string index $line [expr {2*$i + 1} ]]
130+ }
131+ puts $fo $lineStr
132+ }
133+ # If the line was not EOF, add the reversed word to the chunkList and increment the loop indicating valid word.
134+ } else {
135+ lset chunkList $chunkCounter [byteReverse $line ]
136+ incr chunkCounter
137+ }
138+ # If the number of valid words in the chunk is 4, write the chunk to memory and reset the counter.
139+ if {$chunkCounter == 4} {
140+ set chunkCounter 0
141+ # Write the full chunk to the output file.
142+ for {set i 0} {$i < $bytes_per_word } {incr i} {
143+ set lineStr {}
144+ foreach line $chunkList {
145+ append lineStr [string index $line [expr {2*$i } ]]
146+ append lineStr [string index $line [expr {2*$i + 1} ]]
147+ }
148+ puts $fo $lineStr
149+ }
150+ }
151+ }
152+ close $fi ;# Close the file objects.
153+ close $fo
154+ file copy -force code.tmp $mem_file ;# Overwrite the existing .mem with the .tmp file
155+ file delete code.tmp ;# Delete code.tmp
156+ }
0 commit comments