|
| 1 | +#!/usr/bin/env python |
| 2 | + |
| 3 | +from jinja2 import Template |
| 4 | + |
| 5 | +class Reg( ): |
| 6 | + |
| 7 | + def __init__( self, num, name ): |
| 8 | + self.num = '{:X}'.format( num ) |
| 9 | + self.name = name |
| 10 | + self.name_lowcase = self.name.lower() |
| 11 | + self.bits = [] |
| 12 | + |
| 13 | + def add_bits( self, reg_bits ): |
| 14 | + self.bits.append( reg_bits ) |
| 15 | + |
| 16 | +class RegBits( ): |
| 17 | + |
| 18 | + def __init__( self, bit_msb, bit_lsb, name, mode = "RW", init_value = 0 ): |
| 19 | + self.bit_msb = bit_msb |
| 20 | + self.bit_lsb = bit_lsb |
| 21 | + self.width = bit_msb - bit_lsb + 1 |
| 22 | + self.name = name |
| 23 | + self.name_lowcase = self.name.lower() |
| 24 | + self.mode = mode |
| 25 | + self.init_value = '{:X}'.format( init_value ) |
| 26 | + |
| 27 | + # bit modes: |
| 28 | + # RO - read only |
| 29 | + # RO_CONST - read only, constant value |
| 30 | + # RO_LH - read only, latch high |
| 31 | + # RO_LL - read only, latch low |
| 32 | + # RW - read and write |
| 33 | + # RW_SC - read and write, self clear |
| 34 | + assert self.mode in ["RO", "RO_CONST", "RO_LH", "RO_LL", "RW", "RW_SC" ], "Unknown bit mode" |
| 35 | + |
| 36 | + if self.mode in ["RO_LH", "RO_LL", "RW_SC"]: |
| 37 | + assert self.width == 1, "Wrong width for this bit mod" |
| 38 | + |
| 39 | + self.port_signal_input = self.mode in ["RO", "RO_LH", "RO_LL"] |
| 40 | + self.port_signal_output = self.mode in ["RW", "RW_SC"] |
| 41 | + self.need_port_signal = self.port_signal_input or self.port_signal_output |
| 42 | + |
| 43 | +csr_map_template = Template(u""" |
| 44 | +{%- macro reg_name( r ) -%} |
| 45 | +reg_{{r.num}}_{{r.name_lowcase}} |
| 46 | +{%- endmacro %} |
| 47 | +
|
| 48 | +{%- macro reg_name_bits( r, b ) -%} |
| 49 | +reg_{{r.num}}_{{r.name_lowcase}}___{{b.name_lowcase}} |
| 50 | +{%- endmacro %} |
| 51 | +
|
| 52 | +{%- macro bit_init_value( b ) -%} |
| 53 | +{{b.width}}'h{{b.init_value}} |
| 54 | +{%- endmacro %} |
| 55 | +
|
| 56 | +{%- macro signal( width ) -%} |
| 57 | +[{{width-1}}:0] |
| 58 | +{%- endmacro %} |
| 59 | +
|
| 60 | +{%- macro print_port_signal( dir, width, name, eol="," ) -%} |
| 61 | +{{ " %-12s %-10s %-10s" | format( dir, signal( width ), name+eol ) }} |
| 62 | +{%- endmacro %} |
| 63 | +
|
| 64 | +// Generated using CSR map generator |
| 65 | +// https://github.com/johan92/csr-map-generator |
| 66 | +
|
| 67 | +module {{module_name}}( |
| 68 | +
|
| 69 | +{%- for p in data %} |
| 70 | + // Register {{p.name}} signals |
| 71 | +
|
| 72 | +{%- for b in p.bits %} |
| 73 | + {%- if b.port_signal_input %} |
| 74 | +{{print_port_signal( "input", b.width, b.name_lowcase )}} |
| 75 | + {%- elif b.port_signal_output %} |
| 76 | +{{print_port_signal( "output", b.width, b.name_lowcase )}} |
| 77 | + {%- endif %} |
| 78 | +{%- endfor %} |
| 79 | +{% endfor %} |
| 80 | +
|
| 81 | + // CSR interface |
| 82 | +{{print_port_signal( "input", 1, "reg_clk_i" ) }} |
| 83 | +{{print_port_signal( "input", 1, "reg_rst_i" ) }} |
| 84 | +{{print_port_signal( "input", reg_d_w, "reg_wr_data_i" ) }} |
| 85 | +{{print_port_signal( "input", 1, "reg_wr_en_i" ) }} |
| 86 | +{{print_port_signal( "input", 1, "reg_rd_en_i" ) }} |
| 87 | +{{print_port_signal( "input", reg_a_w, "reg_addr_i" ) }} |
| 88 | +{{print_port_signal( "output", reg_d_w, "reg_rd_data_o", "" ) }} |
| 89 | +); |
| 90 | +
|
| 91 | +
|
| 92 | +{%- for p in data %} |
| 93 | +
|
| 94 | +// ****************************************** |
| 95 | +// Register {{p.name}} |
| 96 | +// ****************************************** |
| 97 | +
|
| 98 | +logic [{{reg_d_w-1}}:0] {{reg_name( p )}}_read; |
| 99 | +
|
| 100 | +{%- for b in p.bits %} |
| 101 | +{%- if b.mode != "RO" %} |
| 102 | +logic [{{b.width-1}}:0] {{reg_name_bits( p, b )}} = {{bit_init_value( b )}}; |
| 103 | +{%- endif %} |
| 104 | +{%- endfor %} |
| 105 | +
|
| 106 | +{% for b in p.bits %} |
| 107 | +{%- if b.port_signal_output %} |
| 108 | +always_ff @( posedge reg_clk_i or posedge reg_rst_i ) |
| 109 | + if( reg_rst_i ) |
| 110 | + {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; |
| 111 | + else |
| 112 | + if( reg_wr_en_i && ( reg_addr_i == {{reg_a_w}}'h{{p.num}} ) ) |
| 113 | + {{reg_name_bits( p, b )}} <= reg_wr_data_i[{{b.bit_msb}}:{{b.bit_lsb}}]; |
| 114 | + {%-if b.mode == "RW_SC" %} |
| 115 | + else |
| 116 | + {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; |
| 117 | + {% endif %} |
| 118 | +{%- endif %} |
| 119 | +
|
| 120 | +{%- if b.mode == "RO_LH" or b.mode == "RO_LL" %} |
| 121 | +always_ff @( posedge reg_clk_i or posedge reg_rst_i ) |
| 122 | + if( reg_rst_i ) |
| 123 | + {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; |
| 124 | + else |
| 125 | + if( reg_rd_en_i && ( reg_addr_i == {{reg_a_w}}'h{{p.num}} ) ) |
| 126 | + {{reg_name_bits( p, b )}} <= {{bit_init_value( b )}}; |
| 127 | + else |
| 128 | + {%- if b.mode == "RO_LL" %} |
| 129 | + if( {{b.name_lowcase}} == '0 ) |
| 130 | + {{reg_name_bits( p, b )}} <= '1; |
| 131 | + {%- elif b.mode == "RO_LH" %} |
| 132 | + if( {{b.name_lowcase}} == '1 ) |
| 133 | + {{reg_name_bits( p, b )}} <= '1; |
| 134 | + {%- endif %} |
| 135 | +
|
| 136 | +{% endif %} |
| 137 | +{% endfor %} |
| 138 | +
|
| 139 | +// assigning to output |
| 140 | +{%- for b in p.bits %} |
| 141 | +{%- if b.port_signal_output %} |
| 142 | +assign {{b.name_lowcase}} = {{reg_name_bits( p, b )}}; |
| 143 | +{%- endif %} |
| 144 | +{%- endfor %} |
| 145 | +
|
| 146 | +// assigning to read data |
| 147 | +{%- macro print_in_always_comb( r, b, _right_value ) -%} |
| 148 | +{%- if b == "" -%} |
| 149 | +{{ " %s%-7s = %s;" | format( reg_name( r ) + "_read", "", _right_value ) }} |
| 150 | +{%- else -%} |
| 151 | +{{ " %s%-7s = %s;" | format( reg_name( r ) + "_read", "["+b.bit_msb|string+":"+b.bit_lsb|string+"]" , _right_value ) }} |
| 152 | +{%- endif %} |
| 153 | +{%- endmacro %} |
| 154 | +
|
| 155 | +always_comb |
| 156 | + begin |
| 157 | + {{print_in_always_comb( p, "", reg_d_w|string+"'h0" ) }} |
| 158 | +
|
| 159 | +{%- for b in p.bits %} |
| 160 | + {%- if b.mode == "RO" %} |
| 161 | + {{print_in_always_comb( p, b, b.name_lowcase )}} |
| 162 | + {%- else %} |
| 163 | + {{print_in_always_comb( p, b, reg_name_bits( p, b ) )}} |
| 164 | + {%- endif %} |
| 165 | +{%- endfor %} |
| 166 | + end |
| 167 | +
|
| 168 | +{%- endfor %} |
| 169 | +
|
| 170 | +
|
| 171 | +// ******* Reading stuff ******* |
| 172 | +logic [{{reg_d_w-1}}:0] reg_rd_data; |
| 173 | +
|
| 174 | +always_ff @( posedge reg_clk_i or posedge reg_rst_i ) |
| 175 | + if( reg_rst_i ) |
| 176 | + reg_rd_data <= {{reg_d_w}}'h0; |
| 177 | + else |
| 178 | + if( reg_rd_en_i ) |
| 179 | + begin |
| 180 | +
|
| 181 | + case( reg_addr_i ) |
| 182 | + {% for p in data %} |
| 183 | + {{reg_a_w}}'h{{p.num}}: |
| 184 | + begin |
| 185 | + reg_rd_data <= {{reg_name( p )}}_read; |
| 186 | + end |
| 187 | + {% endfor %} |
| 188 | + default: |
| 189 | + begin |
| 190 | + reg_rd_data <= {{reg_d_w}}'h0; |
| 191 | + end |
| 192 | +
|
| 193 | + endcase |
| 194 | +
|
| 195 | + end |
| 196 | +
|
| 197 | +assign reg_rd_data_o = reg_rd_data; |
| 198 | +
|
| 199 | +endmodule |
| 200 | +""") |
| 201 | + |
| 202 | +if __name__ == "__main__": |
| 203 | + |
| 204 | + r0 = Reg( 0x0, "FLOW_GEN") |
| 205 | + |
| 206 | + r0.add_bits( RegBits( 7, 0, "flow_num", "RW" ) ) |
| 207 | + r0.add_bits( RegBits( 15, 15, "flow_en" , "RW" ) ) |
| 208 | + r0.add_bits( RegBits( 17, 17, "flow_reset", "RW_SC" ) ) |
| 209 | + r0.add_bits( RegBits( 21, 21, "flow_error", "RO_LH" ) ) |
| 210 | + |
| 211 | + r1 = Reg( 0x1, "STAT" ) |
| 212 | + r1.add_bits( RegBits( 10, 0, "stat_addr", "RW", 0x15 ) ) |
| 213 | + r1.add_bits( RegBits( 15, 15, "stat_rd_en", "RW" ) ) |
| 214 | + r1.add_bits( RegBits( 25, 16, "stat_counter", "RO" ) ) |
| 215 | + r1.add_bits( RegBits( 31, 30, "stat_version", "RO_CONST", 0x3 ) ) |
| 216 | + |
| 217 | + reg_l = [r0, r1] |
| 218 | + |
| 219 | + res = csr_map_template.render( |
| 220 | + module_name = "my_csr_map", |
| 221 | + reg_d_w = 32, |
| 222 | + reg_a_w = 8, |
| 223 | + data = reg_l |
| 224 | + ) |
| 225 | + |
| 226 | + print res |
0 commit comments