Skip to content

Commit b713fe3

Browse files
committed
first version of map generator
1 parent be692d4 commit b713fe3

File tree

2 files changed

+234
-1
lines changed

2 files changed

+234
-1
lines changed

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
11
# csr-map-generator
2-
Generator for CSR mapping module
2+
Generator for CSR (Control/Status Registers) mapping module
3+
4+
Can be useful for ASIC/FPGA designers.
5+
6+
Using Jinja2 ( http://jinja.pocoo.org/ ) and Python of course.
7+
8+
Have fun!
9+

csr_map_generator.py

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
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

Comments
 (0)