ruby_rtl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,564 @@
1
+ require_relative 'code'
2
+
3
+ module RubyRTL
4
+
5
+ class VhdlGenerator < Visitor
6
+
7
+ attr_accessor :entity
8
+ attr_accessor :ios
9
+ attr_accessor :archi_elements
10
+
11
+ def generate circuit
12
+ puts "[+] VHDL code generation"
13
+
14
+ code=Code.new
15
+ @circuit=circuit
16
+ @ios,@archi_elements=[],[]
17
+ @sigs={}
18
+ @fsm_defs=[]
19
+ @sequentials=[]
20
+ @states={}
21
+ gen_ruby_rtl_type_package
22
+ root=circuit.ast
23
+ return unless root
24
+
25
+ gen_type_package()
26
+ #root.ios.each{|io| io.accept(self)}
27
+ @typedecls=root.decls.select{|decl| decl.is_a? TypeDecl}
28
+ non_typedecls=root.decls.reject{|decl| decl.is_a? TypeDecl}
29
+ non_typedecls.each{|decl| decl.accept(self)}
30
+
31
+ code << gen_ieee_header()
32
+ code << gen_ruby_rtl_package_call()
33
+ code << gen_package_call(circuit)
34
+ code << gen_entity(circuit)
35
+ code.newline
36
+ code << gen_archi(circuit)
37
+ code=clean_vhdl(code)
38
+ puts code.finalize
39
+ code.save_as "#{name=circuit.name.downcase}.vhd"
40
+ end
41
+
42
+ def clean_vhdl(code)
43
+ txt=code.finalize
44
+ txt.gsub! /;(\s*)\)/,")"
45
+ txt.gsub! /,(\s*)\)/,")"
46
+ (code=Code.new) << txt
47
+ return code
48
+ end
49
+
50
+ def gen_ruby_rtl_package_call
51
+ code=Code.new
52
+ code << "library ruby_rtl;"
53
+ code << "use ruby_rtl.ruby_rtl_package.all;"
54
+ code.newline
55
+ code
56
+ end
57
+
58
+ def gen_ruby_rtl_type_package
59
+ code=Code.new
60
+ code << gen_ieee_header
61
+ code << "package ruby_rtl_type_package is "
62
+ code.newline
63
+ code.indent=2
64
+ $typedefs.each do |name,definition|
65
+ case definition
66
+ when RecordType
67
+ code << definition_s=definition.accept(self,name)
68
+ else
69
+ definition_s=definition.accept(self)
70
+ case definition
71
+ when IntType,UIntType,BitType
72
+ header="sub"
73
+ else
74
+ header=""
75
+ end
76
+ code << "#{header}type #{name} is #{definition_s};"
77
+ end
78
+ code.newline
79
+ end
80
+ code.indent=0
81
+ code << "end package;"
82
+ code.save_as "ruby_rtl_type_package.vhd"
83
+ end
84
+
85
+ def gen_type_package
86
+ name=@circuit.name.downcase
87
+ return unless ast=@circuit.ast
88
+ typdecls=ast.decls.select{|decl| decl.is_a?(TypeDecl)}
89
+ package=Code.new
90
+ package << gen_ieee_header
91
+ package << "package #{name}_package is"
92
+ package.indent=2
93
+ package.newline
94
+ typdecls.each do |decl|
95
+ definition=decl.definition.accept(self,decl.name)
96
+ package << definition
97
+ package.newline
98
+ end
99
+ package.indent=0
100
+ package << "end package;"
101
+ puts package.finalize
102
+ package.save_as "#{name}_package.vhd"
103
+ end
104
+
105
+ def gen_ieee_header
106
+ header=Code.new
107
+ header << "-- automatically generated by RubyRTL"
108
+ header << "library ieee;"
109
+ header << "use ieee.std_logic_1164.all;"
110
+ header << "use ieee.numeric_std.all;"
111
+ header.newline
112
+ header
113
+ end
114
+
115
+ def gen_package_call circuit
116
+ name=circuit.name.downcase
117
+ code=Code.new
118
+ code << "library #{name}_lib;"
119
+ code << "use #{name}_lib.#{name}_package.all;"
120
+ code.newline
121
+ code
122
+ end
123
+
124
+ def gen_entity circuit
125
+ entity=Code.new
126
+ entity << "entity #{name=circuit.name.downcase}_c is"
127
+ entity.indent=2
128
+ entity << "port ("
129
+ entity.indent=4
130
+ if circuit.has_sequential_statements
131
+ entity << "reset_n : in std_logic;"
132
+ entity << "clk : in std_logic;"
133
+ end
134
+ ios.each{|io| entity << io}
135
+ entity.indent=2
136
+ entity << ");"
137
+ entity.indent=0
138
+ entity << "end #{name}_c;"
139
+ end
140
+
141
+ def gen_archi circuit
142
+ body=circuit.ast.body
143
+ archi_elements=body.stmts.collect{|stmt| stmt.accept(self)}
144
+ archi=Code.new
145
+ archi << "architecture rtl of #{circuit.name.downcase}_c is"
146
+ archi.indent=2
147
+ @fsm_defs.each do |decl|
148
+ archi << decl
149
+ end
150
+ @typedecls.each do |typedecl|
151
+ archi << typedecl.accept(self)
152
+ end
153
+ @sigs.each do |sig,name|
154
+ archi << "signal #{name} : #{sig.type.accept(self)};"
155
+ end
156
+ archi.indent=0
157
+ archi << "begin"
158
+ archi.indent=2
159
+ archi.newline
160
+ archi_elements.each do |element|
161
+ archi << element
162
+ archi.newline
163
+ end
164
+ archi.indent=0
165
+ archi.newline
166
+ archi << "end rtl;"
167
+ archi
168
+ end
169
+
170
+ def visitComment comment,args=nil
171
+ "-- #{comment.str}"
172
+ end
173
+
174
+ def visitInput input,args=nil
175
+ name=@sigs[input] || input.name
176
+ adapt_name(name,args)
177
+ end
178
+
179
+ def visitOutput output,args=nil
180
+ name=@sigs[output] || output.name
181
+ adapt_name(name,args)
182
+ end
183
+
184
+ def visitSigDecl decl,args=nil
185
+ name=decl.name
186
+ name.sub!(/@/,'')
187
+ type=decl.sig.type.accept(self)
188
+ case decl.sig
189
+ when Input
190
+ ios << "#{name} : in #{type};"
191
+ when Output
192
+ ios << "#{name} : out #{type};"
193
+ when Sig
194
+ @sigs.merge!(decl.sig => name)
195
+ else
196
+ raise "ERROR : visitSigDecl : neither input ou output"
197
+ end
198
+ end
199
+
200
+ def visitSig sig,args=nil
201
+ name=sig.name
202
+ adapt_name(name,args)
203
+ end
204
+
205
+ def adapt_name name,kind
206
+ name=name.to_s
207
+ case kind
208
+ when :comb
209
+ name+="_c"
210
+ when :reg
211
+ name+="_r"
212
+ when :var
213
+ name+="_v"
214
+ end
215
+ name
216
+ end
217
+
218
+ def visitTypeDecl decl,args=nil
219
+ definition=decl.definition.accept(self,decl.name)
220
+ "type #{decl.name} is #{definition};"
221
+ end
222
+
223
+ def visitEnumType enum_type,name
224
+ if name
225
+ "type #{name} is (#{enum_type.items.join(',')});"
226
+ else
227
+ idx=$typedefs.values.index(enum_type)
228
+ $typedefs.keys[idx]
229
+ end
230
+ end
231
+
232
+ def visitRecordType rectype,name
233
+ if name
234
+ code=Code.new
235
+ code << "record"
236
+ code.indent=2
237
+ rectype.hash.each do |name,type|
238
+ type_s=type.accept(self)
239
+ code << "#{name} : #{type_s};"
240
+ end
241
+ code.indent=0
242
+ code << "end record;"
243
+ code
244
+ else
245
+ idx=$typedefs.values.index(rectype)
246
+ $typedefs.keys[idx]
247
+ end
248
+ end
249
+
250
+ def visitMemoryType memtype,name
251
+ if name
252
+ range="0 to #{memtype.size-1}"
253
+ type=memtype.type.accept(self)
254
+ "array(#{range}) of #{type}"
255
+ else
256
+ idx=$typedefs.values.index(memtype)
257
+ $typedefs.keys[idx]
258
+ end
259
+ end
260
+ # ====== body stuff ========
261
+ # === statements ===
262
+ def visitAssign assign,args=nil
263
+ lhs=assign.lhs.accept(self)
264
+ rhs=assign.rhs.accept(self)
265
+ "#{lhs} <= #{rhs};"
266
+ end
267
+
268
+ def visitCompDecl comp_decl,args=nil
269
+ comp=comp_decl.comp
270
+ instance_name=comp_decl.name
271
+ sig_decls=comp.ast.decls.select{|node| node.is_a? SigDecl}
272
+ inputs =sig_decls.select{|decl| decl.sig.is_a? Input}.map(&:sig)
273
+ outputs=sig_decls.select{|decl| decl.sig.is_a? Output}.map(&:sig)
274
+
275
+ instanciation=Code.new
276
+ instanciation << "#{instance_name} : entity work.#{comp.name}_c"
277
+ instanciation.indent=2
278
+ instanciation << "port map("
279
+ instanciation.indent=4
280
+ inputs.each do |input|
281
+ actual_sig_name="#{instance_name}_#{input.name}"
282
+ @sigs.merge!({input => actual_sig_name})
283
+ instanciation << "#{input.name} => #{actual_sig_name},"
284
+ end
285
+ outputs.each do |output|
286
+ actual_sig_name="#{instance_name}_#{output.name}"
287
+ @sigs.merge!(output => actual_sig_name)
288
+ instanciation << "#{output.name} => #{actual_sig_name},"
289
+ end
290
+ instanciation.indent=2
291
+ instanciation << ");"
292
+ instanciation.indent=0
293
+ instanciation.newline
294
+ instanciation
295
+ end
296
+
297
+ def visitCombinatorial comb,args=nil
298
+ code=Code.new
299
+ label=comb.label
300
+ code << "#{label} : process(all) --VHDL'08"
301
+ code << "begin"
302
+ code.indent=2
303
+ code << comb.body.accept(self)
304
+ code.indent=0
305
+ code << "end process;"
306
+ code
307
+ end
308
+
309
+ def visitSequential sequential,args=nil
310
+ code=Code.new
311
+ label=sequential.label
312
+ code << "#{label} : process(clk)"
313
+ code << "begin"
314
+ code.indent=2
315
+ code << "if rising_edge(clk) then"
316
+ code.indent=4
317
+ code << sequential.body.accept(self)
318
+ code.indent=2
319
+ code << "end if;"
320
+ code.indent=0
321
+ code << "end process;"
322
+ code
323
+ end
324
+
325
+ # statement
326
+ def visitBody body,args=nil
327
+ code=Code.new
328
+ body.stmts.each{|stmt| code << stmt.accept(self)}
329
+ code
330
+ end
331
+
332
+ def visitIf if_,args=nil
333
+ cond=if_.cond.accept(self)
334
+ if_body=if_.body.accept(self)
335
+ code=Code.new
336
+ code << "if #{cond} then"
337
+ code.indent=2
338
+ code << if_body
339
+ code.indent=0
340
+ if_.elsifs.each{|elsif_|
341
+ code << elsif_.accept(self)
342
+ }
343
+ code << if_.else.accept(self) if if_.else
344
+ code << "end if;"
345
+ code
346
+ end
347
+
348
+ def visitElsif elsif_,args=nil
349
+ cond=elsif_.cond.accept(self)
350
+ body=elsif_.body.accept(self)
351
+ code=Code.new
352
+ code << "elsif #{cond} then"
353
+ code.indent=2
354
+ code << body
355
+ code.indent=0
356
+ code
357
+ end
358
+
359
+ def visitElse else_,args=nil
360
+ body=else_.body.accept(self)
361
+ code=Code.new
362
+ code << "else "
363
+ code.indent=2
364
+ code << body
365
+ code.indent=0
366
+ code
367
+ end
368
+ # case / switch
369
+ def visitCase case_,args=nil
370
+ cond=case_.cond.accept(self)
371
+ code=Code.new
372
+ code << "case #{cond} is"
373
+ code.indent=2
374
+ code << case_.body.accept(self)
375
+ code.indent=0
376
+ code << "end case;"
377
+ code
378
+ end
379
+
380
+ def visitWhen when_,args=nil
381
+ unless (value=when_.value).is_a? Symbol
382
+ value=when_.value.accept(self)
383
+ end
384
+ code=Code.new
385
+ code << "when #{value} =>"
386
+ code.indent=2
387
+ code << when_.body.accept(self)
388
+ code.indent=0
389
+ code
390
+ end
391
+
392
+ # === FSM ===
393
+ def visitFsm fsm,args=nil
394
+ @fsm=fsm
395
+ state_names=fsm.states.map{|state| state.name}.join(",")
396
+ @fsm_defs << "type #{fsm.name}_state_t is (#{state_names});"
397
+ @fsm_defs << "signal #{fsm.name}_state : #{fsm.name}_state_t;"
398
+ body=Code.new
399
+ body << "#{fsm.name}_update : process(reset_n,clk)"
400
+ body << "begin"
401
+ body.indent=2
402
+ body << "if reset_n='0' then"
403
+ body.indent=4
404
+ body << "#{fsm.name}_state <= #{fsm.states.first.name};"
405
+ fsm.assignments.each do |assign|
406
+ lhs=assign.lhs.accept(self)
407
+ rhs=default_init(assign.lhs.type)
408
+ body << "#{lhs} <= #{rhs};"
409
+ end
410
+ body.indent=2
411
+ body << "elsif rising_edge(clk) then"
412
+ body.indent=4
413
+ body << "if sreset='1' then"
414
+ body.indent=6
415
+ body << "#{fsm.name}_state <= #{fsm.states.first.name};"
416
+ fsm.assignments.each do |assign|
417
+ lhs=assign.lhs.accept(self)
418
+ rhs=default_init(assign.lhs.type)
419
+ body << "#{lhs} <= #{rhs};"
420
+ end
421
+ body.indent=4
422
+ body << "else "
423
+ body.indent=6
424
+ body << state_cases(fsm)
425
+ body.indent=4
426
+ body << "end if;"
427
+ body.indent=2
428
+ body << "end if;"
429
+ body.indent=0
430
+ body << "end process;"
431
+ body
432
+ end
433
+
434
+ def state_cases fsm
435
+ code=Code.new
436
+ code << "case #{fsm.name}_state is"
437
+ code.indent=2
438
+ fsm.states.each do |state|
439
+ code << "when #{state.name} =>"
440
+ code.indent=4
441
+ code << state_body(state)
442
+ code.indent=2
443
+ end
444
+ code << "when others =>"
445
+ code << " null;"
446
+ code.indent=0
447
+ code << "end case;"
448
+ code
449
+ end
450
+
451
+ def state_body state
452
+ code=Code.new
453
+ state.body.each{|stmt| code << stmt.accept(self)}
454
+ code
455
+ end
456
+
457
+ def visitState state,args=nil
458
+ code << "when #{state.name}"
459
+ code
460
+ end
461
+
462
+ def visitNext next_state,args=nil
463
+ "#{@fsm.name}_state <= #{next_state.name};"
464
+ end
465
+
466
+ # === expressions ===
467
+ VHDL_OP={
468
+ "&" => "and",
469
+ "|" => "or",
470
+ "^" => "xor",
471
+ "=="=> "=",
472
+ "%" => "mod",
473
+ "!=" => "/="
474
+ }
475
+ def visitBinary bin,args=nil
476
+ lhs=bin.lhs.accept(self)
477
+ op=VHDL_OP[bin.op] || bin.op
478
+ rhs=bin.rhs.accept(self)
479
+ "(#{lhs} #{op} #{rhs})"
480
+ end
481
+
482
+ def visitFuncCall func,args=nil
483
+ name=func.name
484
+ argus=func.args.map{|arg| arg.accept(self)}.join(',')
485
+ "#{name}(#{argus})"
486
+ end
487
+
488
+ def visitIndexed indexed,args=nil
489
+ lhs=indexed.lhs.accept(self)
490
+ rhs=indexed.rhs.accept(self)
491
+ case indexed.rhs
492
+ when RUIntLit
493
+ else
494
+ conv_int_start="to_integer("
495
+ conv_int_end =")"
496
+ end
497
+ puts indexed.rhs
498
+ "#{lhs}(#{conv_int_start}#{rhs}#{conv_int_end})"
499
+ end
500
+
501
+ # === types
502
+ def visitBitType bit,args=nil
503
+ "std_logic"
504
+ end
505
+
506
+ def visitBitVectorType bv,args=nil
507
+ range="#{bv.bitwidth-1} downto 0"
508
+ "std_logic_vector(#{range})"
509
+ end
510
+
511
+ def visitUIntType uint,args=nil
512
+ range="#{uint.bitwidth-1} downto 0"
513
+ "unsigned(#{range})"
514
+ end
515
+
516
+ def visitIntType int,args=nil
517
+ range="#{int.bitwidth-1} downto 0"
518
+ "signed(#{range})"
519
+ end
520
+
521
+
522
+
523
+ def default_init type
524
+ case type
525
+ when BitType
526
+ return "'0'"
527
+ when BitVectorType
528
+ return "(others=>'0')"
529
+ when UintType
530
+ return "to_unsigned(0,#{type.bitwidth})"
531
+ when IntType
532
+ return "to_signed(0,#{type.bitwidth})"
533
+ else
534
+ raise "Cannot provide default init value for type #{type}"
535
+ end
536
+ ret
537
+ end
538
+
539
+ # === literals
540
+ def visitIntLit int,args=nil
541
+ "to_signed(#{int.val},#{int.type.bitwidth})"
542
+ end
543
+
544
+ def visitUIntLit uint,args=nil
545
+ "to_unsigned(#{uint.val},#{uint.type.bitwidth})"
546
+ end
547
+
548
+ def visitBitLit bit_lit,args=nil
549
+ "'#{bit_lit.val}'"
550
+ end
551
+
552
+ def visitBitVectorLit bit_lit,args=nil
553
+ "\"#{bit_lit.val}\""
554
+ end
555
+
556
+ def visitRIntLit lit,args=nil
557
+ lit.val
558
+ end
559
+
560
+ def visitRUIntLit lit,args=nil
561
+ lit.val
562
+ end
563
+ end
564
+ end
@@ -0,0 +1,163 @@
1
+
2
+ module RubyRTL
3
+ class Visitor
4
+
5
+ def visit circuit
6
+ circuit.ast.each{|node| node.accept(self)}
7
+ end
8
+
9
+ def visitComment node,args=nil
10
+ end
11
+
12
+ def visitSig node,args=nil
13
+ end
14
+
15
+ def visitPort node,args=nil
16
+ end
17
+
18
+ def visitInput node,args=nil
19
+ end
20
+
21
+ def visitOutput node,args=nil
22
+ end
23
+
24
+ def visitTypeDecl node,args=nil
25
+ end
26
+
27
+ def visitSigDecl node,args=nil
28
+ end
29
+
30
+ def visitCompDecl node,args=nil
31
+ end
32
+
33
+ def visitCircuitPart node,args=nil
34
+ end
35
+
36
+ def visitCombinatorial comb,args=nil
37
+ puts comb.body.class
38
+ comb.body.accept(self)
39
+ end
40
+
41
+ def visitSequential seq,args=nil
42
+ puts seq.body.class
43
+ seq.body.accept(self)
44
+ end
45
+
46
+ # === statements
47
+ def visitBody body,args=nil
48
+ body.each{|stmt| stmt.accept(self,args)}
49
+ end
50
+
51
+ def visitAssign node,args=nil
52
+ node.lhs.accept(self)
53
+ node.rhs.accept(self)
54
+ end
55
+
56
+ def visitIf node,args=nil
57
+ node.cond.accept(self)
58
+ node.body.accept(self)
59
+ node.elsifs.each{|elsif_| elsif_.accept(self)}
60
+ node.else.accept(self) if node.else
61
+ end
62
+
63
+ def visitElse else_,args=nil
64
+ else_.body.accept(self)
65
+ end
66
+
67
+ def visitElsif elsif_,args=nil
68
+ elsif_.cond.accept(self)
69
+ elsif_.body.accept(self)
70
+ end
71
+
72
+ def visitCase case_,args=nil
73
+ case_.cond.accept(self)
74
+ case_.body.accept(self)
75
+ end
76
+
77
+ def visitWhen when_,args=nil
78
+ when_.value.accept(self) unless when_.value.is_a?(Symbol)
79
+ when_.body.accept(self)
80
+ end
81
+
82
+ # === fsm
83
+ def visitFsm fsm,args=nil
84
+ fsm.body.accept(self)
85
+ end
86
+
87
+ def visitState state,args=nil
88
+ state.body.accept(self)
89
+ end
90
+
91
+ def visitNext node,args=nil
92
+ end
93
+
94
+ # === expr ===
95
+ def visitBinary node,args=nil
96
+ node.lhs.accept(self)
97
+ node.rhs.accept(self)
98
+ end
99
+
100
+ def visitUnary node,args=nil
101
+ node.expr.accept(self)
102
+ end
103
+
104
+ def visitIndexed indexed,args=nil
105
+ lhs=indexed.lhs.accept(self)
106
+ rhs=indexed.rhs.accept(self)
107
+ end
108
+ # === literals ===
109
+ def visitLiteral node,args=nil
110
+ node
111
+ end
112
+
113
+ def visitBitLit node,args=nil
114
+ node
115
+ end
116
+
117
+ def visitIntLit lit,args=nil
118
+ lit
119
+ end
120
+
121
+ def visitUIntLit lit,args=nil
122
+ lit
123
+ end
124
+
125
+ def visitRIntLit lit,args=nil
126
+ lit
127
+ end
128
+
129
+ def visitRUIntLit lit,args=nil
130
+ lit
131
+ end
132
+ # === types ===
133
+ def visitInteger int,args=nil
134
+ int
135
+ end
136
+
137
+ def visitType node,args=nil
138
+ end
139
+
140
+ def visitBitType node,args=nil
141
+ end
142
+
143
+ def visitBitVectorType node,args=nil
144
+ end
145
+
146
+ def visitIntType node,args=nil
147
+ end
148
+
149
+
150
+ def visitUIntType node,args=nil
151
+ end
152
+
153
+ def visitRIntType node,args=nil
154
+ end
155
+
156
+ def visitRUintType node,args=nil
157
+ end
158
+
159
+ def visitRecordType node,args=nil
160
+ end
161
+
162
+ end
163
+ end
data/lib/ruby_rtl.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative "ruby_rtl/ast"
2
+ require_relative "ruby_rtl/dsl"
3
+ require_relative "ruby_rtl/compiler"
4
+ require_relative "ruby_rtl/visitor"
5
+ require_relative "ruby_rtl/vhdl_generator"