reggae_eda 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,102 @@
1
+ -- pong p.chu code.
2
+ library ieee;
3
+ use ieee.std_logic_1164.all;
4
+ use ieee.numeric_std.all;
5
+ entity uart_tx is
6
+ generic(
7
+ DBIT : integer := 8; -- # data bits
8
+ SB_TICK : integer := 16 -- # ticks for stop bits
9
+ );
10
+ port(
11
+ clk, reset_n : in std_logic;
12
+ tx_start : in std_logic;
13
+ s_tick : in std_logic;
14
+ din : in std_logic_vector(7 downto 0);
15
+ tx_done_tick : out std_logic;
16
+ tx : out std_logic
17
+ );
18
+ end uart_tx;
19
+
20
+ architecture arch of uart_tx is
21
+ type state_type is (idle, start, data, stop);
22
+ signal state_reg, state_next : state_type;
23
+ signal s_reg, s_next : unsigned(3 downto 0);
24
+ signal n_reg, n_next : unsigned(2 downto 0);
25
+ signal b_reg, b_next : std_logic_vector(7 downto 0);
26
+ signal tx_reg, tx_next : std_logic;
27
+ begin
28
+ -- FSMD state & data registers
29
+ process(clk, reset_n)
30
+ begin
31
+ if reset_n = '0' then
32
+ state_reg <= idle;
33
+ s_reg <= (others => '0');
34
+ n_reg <= (others => '0');
35
+ b_reg <= (others => '0');
36
+ tx_reg <= '1';
37
+ elsif (clk'event and clk = '1') then
38
+ state_reg <= state_next;
39
+ s_reg <= s_next;
40
+ n_reg <= n_next;
41
+ b_reg <= b_next;
42
+ tx_reg <= tx_next;
43
+ end if;
44
+ end process;
45
+ -- next-state logic & data path functional units/routing
46
+ process(state_reg, s_reg, n_reg, b_reg, s_tick,
47
+ tx_reg, tx_start, din)
48
+ begin
49
+ state_next <= state_reg;
50
+ s_next <= s_reg;
51
+ n_next <= n_reg;
52
+ b_next <= b_reg;
53
+ tx_next <= tx_reg;
54
+ tx_done_tick <= '0';
55
+ case state_reg is
56
+ when idle =>
57
+ tx_next <= '1';
58
+ if tx_start = '1' then
59
+ state_next <= start;
60
+ s_next <= (others => '0');
61
+ b_next <= din;
62
+ end if;
63
+ when start =>
64
+ tx_next <= '0';
65
+ if (s_tick = '1') then
66
+ if s_reg = 15 then
67
+ state_next <= data;
68
+ s_next <= (others => '0');
69
+ n_next <= (others => '0');
70
+ else
71
+ s_next <= s_reg + 1;
72
+ end if;
73
+ end if;
74
+ when data =>
75
+ tx_next <= b_reg(0);
76
+ if (s_tick = '1') then
77
+ if s_reg = 15 then
78
+ s_next <= (others => '0');
79
+ b_next <= '0' & b_reg(7 downto 1);
80
+ if n_reg = (DBIT-1) then
81
+ state_next <= stop;
82
+ else
83
+ n_next <= n_reg + 1;
84
+ end if;
85
+ else
86
+ s_next <= s_reg + 1;
87
+ end if;
88
+ end if;
89
+ when stop =>
90
+ tx_next <= '1';
91
+ if (s_tick = '1') then
92
+ if s_reg = (SB_TICK-1) then
93
+ state_next <= idle;
94
+ tx_done_tick <= '1';
95
+ else
96
+ s_next <= s_reg + 1;
97
+ end if;
98
+ end if;
99
+ end case;
100
+ end process;
101
+ tx <= tx_reg;
102
+ end arch;
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../lib/reggae'
3
+
4
+ reggae=Reggae::Compiler.new
5
+ reggae.analyze_options ARGV
6
+ reggae.compile
@@ -0,0 +1,3 @@
1
+ require_relative 'reggae/compiler'
2
+ module Reggae
3
+ end
@@ -0,0 +1,72 @@
1
+ module Reggae
2
+
3
+ module Visitable
4
+ def accept(visitor, arg=nil)
5
+ name = self.class.name.split(/::/)[1]
6
+ visitor.send("visit#{name}".to_sym, self ,arg) # Metaprograming !
7
+ end
8
+ end
9
+
10
+ class MemoryMap < Struct.new(:name,:parameters,:zones,:comments)
11
+ include Visitable
12
+ end
13
+
14
+ class Comment < Struct.new(:txt)
15
+ include Visitable
16
+ end
17
+
18
+ class Parameters < Struct.new(:bus,:range)
19
+ include Visitable
20
+ end
21
+
22
+ class Bus < Struct.new(:frequency,:address_size,:data_size)
23
+ include Visitable
24
+ end
25
+
26
+ class Range < Struct.new(:from,:to)
27
+ include Visitable
28
+ end
29
+
30
+ class Zone < Struct.new(:name,:range,:registers,:subzones,:instances)
31
+ include Visitable
32
+ end
33
+
34
+ class Instance < Struct.new(:name,:mapping)
35
+ include Visitable
36
+ end
37
+
38
+ class Connect < Struct.new(:formal,:actual)
39
+ include Visitable
40
+ end
41
+
42
+ class Input < Struct.new(:name)
43
+ include Visitable
44
+ end
45
+
46
+ class Output < Struct.new(:name)
47
+ include Visitable
48
+ end
49
+
50
+ class RegSig < Struct.new(:name,:field)
51
+ include Visitable
52
+ end
53
+
54
+ class Subzone < Zone
55
+ include Visitable
56
+ end
57
+
58
+ class Register < Struct.new(:name,:address,:init,:sampling,:writable,:bits,:bitfields)
59
+ include Visitable
60
+ def bit(n)
61
+ @bits.find{|bit| bit.position==n}
62
+ end
63
+ end
64
+
65
+ class Bit < Struct.new(:position,:name,:purpose,:toggle)
66
+ include Visitable
67
+ end
68
+
69
+ class Bitfield < Bit
70
+ include Visitable
71
+ end
72
+ end
@@ -0,0 +1,55 @@
1
+ class Code
2
+
3
+ attr_accessor :indent,:code
4
+
5
+ def initialize indent=0
6
+ @code=[]
7
+ @indent=indent
8
+ end
9
+
10
+ def empty?
11
+ @code.size==0
12
+ end
13
+
14
+ def <<(str)
15
+ if str.is_a? Code
16
+ str.code.each do |line|
17
+ @code << " "*@indent+line
18
+ end
19
+ elsif str.nil?
20
+ else
21
+ @code << " "*@indent+str
22
+ end
23
+ end
24
+
25
+ def finalize dot=false
26
+ if dot
27
+ return @code.join('\n')
28
+ end
29
+ @code.join("\n")
30
+ end
31
+
32
+ def newline
33
+ @code << " "
34
+ end
35
+
36
+ def save_as filename,verbose=true
37
+ str=self.finalize
38
+ if filename.end_with? ".vhd"
39
+ str=clean_vhdl(str)
40
+ end
41
+ File.open(filename,'w'){|f| f.puts(str)}
42
+ puts "saved code in file #{filename}" if verbose
43
+ return filename
44
+ end
45
+
46
+ def size
47
+ @code.size
48
+ end
49
+
50
+ def clean_vhdl str
51
+ str1=str.gsub(/\;\s*\)/,")")
52
+ str2=str1.gsub(/\,\s*\)/,")")
53
+ end
54
+
55
+ end
@@ -0,0 +1,110 @@
1
+ require 'pp'
2
+ require 'optparse'
3
+ require_relative 'parser'
4
+ require_relative 'pretty_printer'
5
+ require_relative 'vhdl_generator'
6
+ require_relative 'version'
7
+
8
+ module Reggae
9
+
10
+ class Compiler
11
+
12
+ attr_accessor :ast
13
+
14
+ def initialize
15
+ puts "Reggae generator #{VERSION}"
16
+ @options={}
17
+ end
18
+
19
+ def analyze_options args
20
+ args << "-h" if args.empty?
21
+
22
+ opt_parser = OptionParser.new do |opts|
23
+ opts.banner = "Usage: reggae <filename.sexp>"
24
+
25
+ opts.on("-v", "--version", "Prints version") do
26
+ puts VERSION
27
+ abort
28
+ end
29
+
30
+ opts.on("-h", "--help", "Prints this help") do
31
+ puts
32
+ puts "Generates an IP-based system, from its memory-map expressed in s-expressions."
33
+ puts
34
+ puts "Author mail: jean-christophe.le_lann@ensta-bretagne.fr"
35
+ puts
36
+ @options[:show_help]=true
37
+ puts opts
38
+ abort
39
+ end
40
+
41
+ opts.on("-s", "--system", "Generates a top-level system") do
42
+ @options[:gen_system]=true
43
+ end
44
+
45
+ opts.on("-d","Shows VHDL generated in the terminal,during generation") do
46
+ @options[:show_code]=true
47
+ end
48
+
49
+ opts.on("-u", "--include_uart", "Generates an UART Master in the system top-level") do
50
+ @options[:include_uart]=true
51
+ end
52
+
53
+ opts.on("--gen_ruby", "Generates Ruby code to interact with the system from a PC host") do
54
+ @options[:gen_ruby]=true
55
+ end
56
+
57
+ opts.on("-x", "--gen_xdc", "Generates a Xilinx XDC constraint file for Artix7 FPGA (IP only)") do
58
+ @options[:gen_xdc]=true
59
+ end
60
+
61
+ opts.on("--from_vivado_hls", "Indicates that the sexp file is generated from VHDL_WRAP tuned for VivadoHLS") do
62
+ @options[:from_vivado_hls]=true
63
+ end
64
+ end
65
+
66
+ begin
67
+ opt_parser.parse!(args)
68
+ rescue Exception => e
69
+ puts e
70
+ #puts e.backtrace
71
+ exit
72
+ end
73
+ @filename = ARGV.pop
74
+ $dirname = File.dirname(@filename) if @filename
75
+ unless @filename or @options[:show_help]
76
+ puts "Need to specify a filename to process"
77
+ #exit
78
+ end
79
+ end
80
+
81
+ def compile
82
+ if @options.any?
83
+ puts
84
+ puts "running with the following options :"
85
+ pp @options
86
+ puts
87
+ end
88
+ @ast=parse(@filename)
89
+ #pretty_print
90
+ generate_vhdl
91
+ end
92
+
93
+ def parse filename
94
+ puts "=> parsing #{filename}"
95
+ $working_dir=Dir.pwd
96
+ @ast=Reggae::Parser.new.parse(filename)
97
+ end
98
+
99
+ def pretty_print
100
+ puts "=> pretty print..."
101
+ Reggae::Visitor.new.visit(ast)
102
+ end
103
+
104
+ def generate_vhdl
105
+ puts "=> generating VHDL..."
106
+ Reggae::VHDLGenerator.new(@options).generate_from(ast)
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,281 @@
1
+ require 'sxp'
2
+ require 'pp'
3
+
4
+ require_relative 'ast'
5
+
6
+ class Array
7
+ def header
8
+ self.first
9
+ end
10
+ end
11
+
12
+ module Reggae
13
+
14
+ class Parser
15
+
16
+ def parse filename
17
+ str=IO.read(filename)
18
+ str=fix_sexpistol_bug(str)
19
+ mm_a=SXP.read(str)
20
+ parseMemoryMap(mm_a)
21
+ end
22
+
23
+ def fix_sexpistol_bug str
24
+ s1=str.gsub(/0x(\w+)/,'\1') #0x....
25
+ s2=s1.gsub(/(\d+)\.\.(\d+)/,'\1 \2') #range
26
+ end
27
+
28
+ def parseMemoryMap ary
29
+ mm=MemoryMap.new(nil,nil,[])
30
+ ary.shift
31
+ mm.name=ary.shift
32
+ while ary.any?
33
+ case h=ary.first.header
34
+ when :comment
35
+ mm.comments ||=[]
36
+ mm.comments << parseComment(ary.shift)
37
+ when :parameters
38
+ mm.parameters=parseParameters(ary.shift)
39
+ when :zone
40
+ mm.zones << parseZone(ary.shift)
41
+ else
42
+ raise "error.expecting 'zone' or 'parameters'. got a '#{h}'"
43
+ end
44
+ end
45
+ mm
46
+ end
47
+
48
+ def parseComment ary
49
+ comment=Comment.new(nil)
50
+ ary.shift
51
+ comment.txt=ary.shift
52
+ comment
53
+ end
54
+
55
+ def parseParameters ary
56
+ param=Parameters.new(nil,nil)
57
+ ary.shift
58
+ while ary.any?
59
+ case h=ary.first.header
60
+ when :bus
61
+ param.bus=parseBus(ary.shift)
62
+ when :range
63
+ param.range=parseRange(ary.shift)
64
+ else
65
+ raise "error.expecting 'bus' or 'range'. Got a '#{h}'"
66
+ end
67
+ end
68
+ @param=param
69
+ param
70
+ end
71
+
72
+ def parseBus ary
73
+ bus=Bus.new(nil,nil,nil)
74
+ ary.shift
75
+ while ary.any?
76
+ case h=ary.first.header
77
+ when :frequency
78
+ bus.frequency=ary.first.last.to_i
79
+ when :address_size
80
+ bus.address_size=ary.first.last.to_i
81
+ when :data_size
82
+ bus.data_size=ary.first.last.to_i
83
+ else
84
+ raise "error during parseBus. Expecting 'frequency','address_size' or 'data_size'. Got '#{h}'"
85
+ end
86
+ ary.shift
87
+ end
88
+ bus
89
+ end
90
+
91
+ def parseHexa sym
92
+ "0x#{sym}"
93
+ end
94
+
95
+ def parseRange ary
96
+ rg=Range.new(nil,nil)
97
+ rg.from=parseHexa(ary[1])
98
+ rg.to=parseHexa(ary[2])
99
+ rg
100
+ end
101
+
102
+ def parseZone ary
103
+ zone=Zone.new(nil,nil,[],[],[])
104
+ ary.shift
105
+ zone.name=ary.shift
106
+ while ary.any?
107
+ case h=ary.first.header
108
+ when :range
109
+ zone.range=parseRange(ary.shift)
110
+ when :register
111
+ zone.registers << parseRegister(ary.shift)
112
+ when :subzone
113
+ zone.subzones << parseSubZone(ary.shift)
114
+ when :instance
115
+ zone.instances << parseInstance(ary.shift)
116
+ else
117
+ raise "error during parseZone.Expecting 'range' or 'register'. Got '#{h}'"
118
+ end
119
+ end
120
+ zone
121
+ end
122
+
123
+ def parseInstance ary
124
+ inst=Instance.new(nil,[])
125
+ ary.shift
126
+ inst.name=ary.shift
127
+ while ary.any?
128
+ case h=ary.first.header
129
+ when :connect
130
+ inst.mapping << parseConnect(ary.shift)
131
+ else
132
+ raise "error during parseZone.Expecting 'connect'. Got '#{h}'"
133
+ end
134
+ end
135
+ inst
136
+ end
137
+
138
+ def parseConnect ary
139
+ map=Connect.new(nil,nil)
140
+ ary.shift
141
+ map.formal=parseFormalIO(ary.shift)
142
+ map.actual=parseRegSig(ary.shift)
143
+ map
144
+ end
145
+
146
+ def parseFormalIO ary
147
+ dir=ary.shift
148
+ case dir
149
+ when :input
150
+ return Input.new(ary.shift)
151
+ when :output
152
+ return Output.new(ary.shift)
153
+ else
154
+ raise "error in formal io : #{ary}"
155
+ end
156
+ end
157
+
158
+ def parseRegSig ary
159
+ sig=RegSig.new(nil,nil)
160
+ ary.shift #register
161
+ sig.name=ary.shift
162
+ sig.field=ary.shift
163
+ sig
164
+ end
165
+
166
+ def parseSubZone ary
167
+ zone=Subzone.new(nil,nil,[],[])
168
+ ary.shift
169
+ zone.name=ary.shift
170
+ while ary.any?
171
+ case h=ary.first.header
172
+ when :range
173
+ zone.range=parseRange(ary.shift)
174
+ when :register
175
+ zone.registers << parseRegister(ary.shift)
176
+ when :subzone
177
+ zone.subzones << parseSubZone(ary.shift)
178
+ else
179
+ raise "error during parseZone.Expecting 'range' or 'register'. Got '#{h}'"
180
+ end
181
+ end
182
+ zone
183
+ end
184
+
185
+ def parseRegister ary
186
+ reg=Register.new(nil,nil,nil,nil,true,[],[])
187
+ ary.shift
188
+ reg.name=ary.shift
189
+ while ary.any?
190
+ case h=ary.first.header
191
+ when :address
192
+ reg.address=parseAddress(ary.shift)
193
+ when :init
194
+ reg.init=parseInit(ary.shift)
195
+ when :sampling
196
+ reg.sampling=parseSampling(ary.shift)
197
+ when :writable
198
+ reg.writable=parseWritable(ary.shift)
199
+ when :bit
200
+ reg.bits << parseBit(ary.shift)
201
+ when :bitfield
202
+ reg.bitfields << parseBitfield(ary.shift)
203
+ else
204
+ raise "Error during parseRegister"
205
+ end
206
+ end
207
+ if reg.bits.empty? and reg.bitfields.empty?
208
+ bus_size=@param.bus.data_size
209
+ position=[bus_size-1,0]
210
+ reg.bitfields << Bitfield.new(position,name=:value,nil,nil)
211
+ end
212
+ reg
213
+ end
214
+
215
+ def parseAddress ary
216
+ parseHexa(ary.last)
217
+ end
218
+
219
+ def parseInit ary
220
+ parseHexa(ary.last)
221
+ end
222
+
223
+ def parseSampling ary
224
+ ary.shift
225
+ ary.shift==:true
226
+ end
227
+
228
+ def parseWritable ary
229
+ ary.shift
230
+ ary.shift==:true
231
+ end
232
+
233
+ def parseBit ary
234
+ bit=Bit.new(nil,nil,nil,nil)
235
+ ary.shift
236
+ bit.position=ary.shift.to_i
237
+ while ary.any?
238
+ case h=ary.first.header
239
+ when :name
240
+ bit.name=parseName(ary.shift)
241
+ when :purpose
242
+ bit.purpose=parsePurpose(ary.shift)
243
+ when :toggle
244
+ bit.toggle=parseToggle(ary.shift)
245
+ end
246
+ end
247
+ bit
248
+ end
249
+
250
+ def parseName ary
251
+ ary[1]
252
+ end
253
+
254
+ def parsePurpose ary
255
+ ary[1]
256
+ end
257
+
258
+ def parseToggle ary
259
+ ary[1]==:true
260
+ end
261
+
262
+ def parseBitfield ary
263
+ bf=Bitfield.new(nil,nil,nil,nil)
264
+ ary.shift
265
+ bf.position=[]
266
+ bf.position << ary.shift.to_s.to_i
267
+ bf.position << ary.shift.to_s.to_i
268
+ while ary.any?
269
+ case h=ary.first.header
270
+ when :name
271
+ bf.name=parseName(ary.shift)
272
+ when :purpose
273
+ bf.purpose=parsePurpose(ary.shift)
274
+ when :toggle
275
+ bf.toggle=parseToggle(ary.shift)
276
+ end
277
+ end
278
+ bf
279
+ end
280
+ end #parser
281
+ end #module