sexpir 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/sexpir +5 -0
- data/lib/sexpir/ast.rb +98 -0
- data/lib/sexpir/ast_sexp.rb +144 -0
- data/lib/sexpir/checker.rb +14 -0
- data/lib/sexpir/code.rb +46 -0
- data/lib/sexpir/code_generator.rb +8 -0
- data/lib/sexpir/compiler.rb +39 -0
- data/lib/sexpir/graph.rb +116 -0
- data/lib/sexpir/log.rb +22 -0
- data/lib/sexpir/parser.rb +274 -0
- data/lib/sexpir/printer.rb +10 -0
- data/lib/sexpir/ruby_rtl_generator.rb +169 -0
- data/lib/sexpir/runner.rb +64 -0
- data/lib/sexpir/transformer.rb +9 -0
- data/lib/sexpir/version.rb +3 -0
- data/lib/sexpir/visitor.rb +76 -0
- data/lib/sexpir.rb +4 -0
- metadata +88 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 682317cfd3be1aa8cbdefa505279d36be704c833b4f9cfc1165dbfe6f17777c0
|
|
4
|
+
data.tar.gz: 739265b361bf8d05fa41c827d1db2b2a858306832343189eba1c5f368110000f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 60bff8d21a153e2c9f919b07d24647b55233f67170789ce247625f4f8e4024d5756dd85b200840a121df202441d1003505b9e31cda1003755d52e11fe6a03433
|
|
7
|
+
data.tar.gz: 0d501270fe47eaa5a1d46d71686ce1e0aba1dc19921fa579cedd6b029ea98faaf64102e2149bf6b8418c64abacfc6462eeedfa5eadbb16cc40ea294888dedd16
|
data/bin/sexpir
ADDED
data/lib/sexpir/ast.rb
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Sexpir
|
|
2
|
+
class Ast
|
|
3
|
+
attr_accessor :node
|
|
4
|
+
def accept(visitor, arg=nil)
|
|
5
|
+
name = self.class.name.split(/::/).last
|
|
6
|
+
visitor.send("visit#{name}".to_sym, self ,arg) # Metaprograming !
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Circuit < Ast
|
|
11
|
+
attr_accessor :name,:signals,:inputs,:outputs,:body
|
|
12
|
+
def initialize
|
|
13
|
+
@signals=[]
|
|
14
|
+
@inputs,@outputs=[],[]
|
|
15
|
+
@body=Body.new
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class Signal < Ast
|
|
20
|
+
attr_accessor :name,:type
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class Io < Signal
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Port < Io
|
|
27
|
+
attr_accessor :component_name,:name
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Input < Io
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Output < Io
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# statements
|
|
37
|
+
class Body < Ast
|
|
38
|
+
attr_accessor :stmts
|
|
39
|
+
def initialize
|
|
40
|
+
@stmts=[]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def << e
|
|
44
|
+
@stmts << e
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Combinatorial < Ast
|
|
49
|
+
attr_accessor :label,:body
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Sequential < Ast
|
|
53
|
+
attr_accessor :label,:body
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Assign < Ast
|
|
57
|
+
attr_accessor :lhs,:rhs
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class If < Ast
|
|
61
|
+
attr_accessor :cond,:then,:elsifs,:else
|
|
62
|
+
def initialize
|
|
63
|
+
@elsifs=[]
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
#===============================
|
|
67
|
+
class Component < Ast
|
|
68
|
+
attr_accessor :name,:type
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class Connect < Ast
|
|
72
|
+
attr_accessor :source,:sink
|
|
73
|
+
end
|
|
74
|
+
#================================
|
|
75
|
+
class Expression < Ast
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
class Binary < Expression
|
|
79
|
+
attr_accessor :lhs,:op,:rhs
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class Term < Expression
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Var < Term
|
|
86
|
+
attr_accessor :name
|
|
87
|
+
def initialize name
|
|
88
|
+
@name=name
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
class Const < Expression
|
|
93
|
+
attr_accessor :value
|
|
94
|
+
def initialize value
|
|
95
|
+
@value=value
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
require_relative 'code'
|
|
2
|
+
|
|
3
|
+
class Symbol
|
|
4
|
+
def sexp
|
|
5
|
+
self
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module Sexpir
|
|
10
|
+
|
|
11
|
+
class Circuit < Ast
|
|
12
|
+
def sexp
|
|
13
|
+
code=Code.new
|
|
14
|
+
code << "(circuit #{name}"
|
|
15
|
+
code.indent=2
|
|
16
|
+
signals.each{|sig| code << sig.sexp}
|
|
17
|
+
inputs.each{|input | code << input.sexp}
|
|
18
|
+
outputs.each{|output| code << output.sexp}
|
|
19
|
+
code.newline
|
|
20
|
+
code << body.sexp
|
|
21
|
+
code.indent=0
|
|
22
|
+
code << ")"
|
|
23
|
+
code.finalize
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class Signal < Ast
|
|
28
|
+
def sexp
|
|
29
|
+
"(signal #{name} #{type})"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Port < Io
|
|
34
|
+
def sexp
|
|
35
|
+
"(port #{component_name} #{name})"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class Input < Io
|
|
40
|
+
def sexp
|
|
41
|
+
"(input #{name} #{type})"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class Output < Io
|
|
46
|
+
def sexp
|
|
47
|
+
"(output #{name} #{type})"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class Body < Ast
|
|
52
|
+
def sexp
|
|
53
|
+
code=Code.new
|
|
54
|
+
stmts.each{|stmt| code << stmt.sexp}
|
|
55
|
+
code
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class Combinatorial < Ast
|
|
60
|
+
def sexp
|
|
61
|
+
code=Code.new
|
|
62
|
+
label_s=label ? label : "nil"
|
|
63
|
+
code << "(combinatorial #{label_s}"
|
|
64
|
+
code.indent=2
|
|
65
|
+
code << body.sexp
|
|
66
|
+
code.indent=0
|
|
67
|
+
code << ")"
|
|
68
|
+
code
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Sequential < Ast
|
|
73
|
+
def sexp
|
|
74
|
+
code=Code.new
|
|
75
|
+
label_s=label ? label : "nil"
|
|
76
|
+
code << "(sequential #{label_s}"
|
|
77
|
+
code.indent=2
|
|
78
|
+
code << body.sexp
|
|
79
|
+
code.indent=0
|
|
80
|
+
code << ")"
|
|
81
|
+
code
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Assign < Ast
|
|
86
|
+
def sexp
|
|
87
|
+
"(assign #{lhs.sexp} #{rhs.sexp})"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
class If < Ast
|
|
92
|
+
def sexp
|
|
93
|
+
code=Code.new
|
|
94
|
+
code << "(if #{cond.sexp}"
|
|
95
|
+
code.indent=2
|
|
96
|
+
code << "(then"
|
|
97
|
+
code.indent=4
|
|
98
|
+
code << self.then.sexp
|
|
99
|
+
code.indent=2
|
|
100
|
+
code << ")"
|
|
101
|
+
if self.else
|
|
102
|
+
code << "(else"
|
|
103
|
+
code.indent=4
|
|
104
|
+
code << self.else.sexp
|
|
105
|
+
code.indent=2
|
|
106
|
+
code << ")"
|
|
107
|
+
end
|
|
108
|
+
code.indent=0
|
|
109
|
+
code << ")"
|
|
110
|
+
code
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
#===============================
|
|
114
|
+
class Component < Ast
|
|
115
|
+
def sexp
|
|
116
|
+
"(component #{name} #{type})"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class Connect < Ast
|
|
121
|
+
def sexp
|
|
122
|
+
"(connect #{source.sexp} #{sink.sexp})"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
#================================
|
|
127
|
+
class Binary < Expression
|
|
128
|
+
def sexp
|
|
129
|
+
"(#{op} #{lhs.sexp} #{rhs.sexp})"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
class Var < Term
|
|
134
|
+
def sexp
|
|
135
|
+
name
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
class Const < Expression
|
|
140
|
+
def sexp
|
|
141
|
+
value
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
data/lib/sexpir/code.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Code
|
|
2
|
+
|
|
3
|
+
attr_accessor :indent,:lines
|
|
4
|
+
|
|
5
|
+
def initialize str=nil
|
|
6
|
+
@lines=[]
|
|
7
|
+
(@lines << str) if str
|
|
8
|
+
@indent=0
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def <<(thing)
|
|
12
|
+
if (code=thing).is_a? Code
|
|
13
|
+
code.lines.each do |line|
|
|
14
|
+
@lines << " "*@indent+line.to_s
|
|
15
|
+
end
|
|
16
|
+
elsif thing.is_a? Array
|
|
17
|
+
thing.each do |kode|
|
|
18
|
+
@lines << kode
|
|
19
|
+
end
|
|
20
|
+
elsif thing.nil?
|
|
21
|
+
else
|
|
22
|
+
@lines << " "*@indent+thing.to_s
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def finalize
|
|
27
|
+
return @lines.join("\n") if @lines.any?
|
|
28
|
+
""
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def newline
|
|
32
|
+
@lines << " "
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def save_as filename,verbose=true,sep="\n"
|
|
36
|
+
str=self.finalize
|
|
37
|
+
File.open(filename,'w'){|f| f.puts(str)}
|
|
38
|
+
return filename
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def size
|
|
42
|
+
@lines.size
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'sxp'
|
|
2
|
+
|
|
3
|
+
require_relative 'version'
|
|
4
|
+
require_relative 'ast'
|
|
5
|
+
require_relative 'parser'
|
|
6
|
+
require_relative 'printer'
|
|
7
|
+
require_relative 'checker'
|
|
8
|
+
require_relative 'transformer'
|
|
9
|
+
require_relative 'ruby_rtl_generator'
|
|
10
|
+
|
|
11
|
+
module Sexpir
|
|
12
|
+
|
|
13
|
+
class Compiler
|
|
14
|
+
|
|
15
|
+
include Log
|
|
16
|
+
attr_accessor :options
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def header
|
|
22
|
+
log "Sexpir compiler - version #{VERSION}"
|
|
23
|
+
#log "author : jean-christophe.le_lann@ensta-bretagne.fr"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def compile sexpfile
|
|
27
|
+
header
|
|
28
|
+
circuit=Parser.new.parse(sexpfile)
|
|
29
|
+
Printer.new.print(circuit)
|
|
30
|
+
Checker.new.check(circuit)
|
|
31
|
+
RubyRTLGenerator.new.generate(circuit)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def close
|
|
35
|
+
log "[+] closing : log is #{$log.inspect}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/sexpir/graph.rb
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require_relative "code"
|
|
2
|
+
|
|
3
|
+
module GRAPH
|
|
4
|
+
|
|
5
|
+
class Graph
|
|
6
|
+
|
|
7
|
+
attr_accessor :name,:nodes
|
|
8
|
+
def initialize name
|
|
9
|
+
@name=name
|
|
10
|
+
@nodes=[]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def << node
|
|
14
|
+
@nodes << node
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def size
|
|
18
|
+
@nodes.size
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def include? node
|
|
22
|
+
@nodes.include? node
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def connect source,sink,infos={}
|
|
26
|
+
raise "source nil" unless source
|
|
27
|
+
raise "sink nil" unless sink
|
|
28
|
+
@nodes << source unless @nodes.include? source
|
|
29
|
+
@nodes << sink unless @nodes.include? sink
|
|
30
|
+
source.to(sink,infos)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def connected? source,sink
|
|
34
|
+
source.succ_edges.select{|edge| edge.sink==sink}.any?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def unconnect source,sink
|
|
38
|
+
source.succ_edges.delete_if{|edge| edge.sink==sink}
|
|
39
|
+
sink.pred_edges.delete_if{|edge| edge.source==source}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def delete node
|
|
43
|
+
node.preds.each{|pred| unconnect(pred,node)}
|
|
44
|
+
node.succs.each{|succ| unconnect(node,succ)}
|
|
45
|
+
@nodes.delete(node)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def each_node &block
|
|
49
|
+
@nodes.each(&block)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def each_edge &block
|
|
53
|
+
edges.each(&block)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def edges
|
|
57
|
+
@nodes.collect{|n| n.succ_edges}.flatten
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_dot
|
|
61
|
+
dot_code=Code.new
|
|
62
|
+
dot_code << "digraph #{name} {"
|
|
63
|
+
dot_code.indent=2
|
|
64
|
+
|
|
65
|
+
each_node do |node|
|
|
66
|
+
dot_code << "#{node.object_id};"
|
|
67
|
+
end
|
|
68
|
+
each_edge do |edge|
|
|
69
|
+
label=edge.infos.to_s
|
|
70
|
+
dot_code << "#{edge.object_id} -> #{edge.object_id} [label=\"#{label}\"];"
|
|
71
|
+
end
|
|
72
|
+
dot_code.indent=0
|
|
73
|
+
dot_code << "}"
|
|
74
|
+
return dot_code
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def save_as dotfilename
|
|
78
|
+
dot_code||=to_dot()
|
|
79
|
+
dot_code.save_as dotfilename
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class Node
|
|
84
|
+
attr_accessor :infos
|
|
85
|
+
attr_accessor :succ_edges,:pred_edges
|
|
86
|
+
|
|
87
|
+
def initialize infos={}
|
|
88
|
+
@infos=infos
|
|
89
|
+
@succ_edges=[]
|
|
90
|
+
@pred_edges=[]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def to node,infos={}
|
|
94
|
+
e=Edge.new(self,node,infos)
|
|
95
|
+
@succ_edges << e
|
|
96
|
+
node.pred_edges << e
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def succs
|
|
100
|
+
@succ_edges.collect{|edge| edge.sink}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def preds
|
|
104
|
+
@pred_edges.collect{|edge| edge.source}
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class Edge
|
|
109
|
+
attr_accessor :name,:source,:sink,:infos
|
|
110
|
+
def initialize source,sink,infos={}
|
|
111
|
+
@infos=infos
|
|
112
|
+
@source=source
|
|
113
|
+
@sink=sink
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/lib/sexpir/log.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Log
|
|
2
|
+
|
|
3
|
+
def indent v,str
|
|
4
|
+
@indent=v
|
|
5
|
+
puts " "*@indent+str.to_s
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def log msg
|
|
9
|
+
puts msg
|
|
10
|
+
#log_dbg msg
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def log_dbg msg
|
|
14
|
+
puts msg
|
|
15
|
+
#$log.puts msg
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def step
|
|
19
|
+
log "press any key"
|
|
20
|
+
key=$stdin.gets
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
require 'sxp'
|
|
2
|
+
require_relative 'ast'
|
|
3
|
+
require_relative 'log'
|
|
4
|
+
|
|
5
|
+
module Sexpir
|
|
6
|
+
|
|
7
|
+
class Parser
|
|
8
|
+
|
|
9
|
+
include Log
|
|
10
|
+
|
|
11
|
+
attr_accessor :options
|
|
12
|
+
|
|
13
|
+
def initialize
|
|
14
|
+
@type_table={}
|
|
15
|
+
@var_table ={}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def parse sexpfile
|
|
19
|
+
log "[+] parsing '#{sexpfile}'"
|
|
20
|
+
sexp=SXP.read IO.read(sexpfile)
|
|
21
|
+
ast=objectify(sexp)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def objectify sexp
|
|
25
|
+
circ=Circuit.new
|
|
26
|
+
sexp.shift
|
|
27
|
+
circ.name=sexp.shift
|
|
28
|
+
while sexp.any?
|
|
29
|
+
s=sexp.shift
|
|
30
|
+
case s.first
|
|
31
|
+
when :signal
|
|
32
|
+
circ.signals << parse_signal(s)
|
|
33
|
+
when :input
|
|
34
|
+
circ.inputs << parse_input(s)
|
|
35
|
+
when :output
|
|
36
|
+
circ.outputs << parse_output(s)
|
|
37
|
+
when :assign
|
|
38
|
+
circ.body << parse_assign(s)
|
|
39
|
+
when :component
|
|
40
|
+
circ.body << parse_component(s)
|
|
41
|
+
when :connect
|
|
42
|
+
circ.body << parse_connect(s)
|
|
43
|
+
when :comb,:combinatorial
|
|
44
|
+
circ.body << parse_comb(s)
|
|
45
|
+
when :seq,:sync,:sequential
|
|
46
|
+
circ.body << parse_seq(s)
|
|
47
|
+
else
|
|
48
|
+
raise "unknown car #{s}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
circ
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def expect sexp,klass,value=nil
|
|
55
|
+
unless (kind=sexp.shift).is_a? klass
|
|
56
|
+
log "ERROR : expecting a #{klass}. Got a #{kind}."
|
|
57
|
+
raise "Syntax error"
|
|
58
|
+
end
|
|
59
|
+
if value
|
|
60
|
+
unless value==kind
|
|
61
|
+
log "ERROR : expecting value '#{value}'. Got '#{kind}'"
|
|
62
|
+
raise "Syntax error"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
return kind
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
#======== IO & Signals ===========
|
|
69
|
+
def parse_signal sexp
|
|
70
|
+
sig=Signal.new
|
|
71
|
+
sexp.shift
|
|
72
|
+
sig.name=sexp.shift
|
|
73
|
+
sig.type=sexp.shift
|
|
74
|
+
sig
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def parse_input sexp
|
|
78
|
+
input=Input.new
|
|
79
|
+
sexp.shift
|
|
80
|
+
input.name=sexp.shift
|
|
81
|
+
input.type=sexp.shift
|
|
82
|
+
input
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def parse_output sexp
|
|
86
|
+
output=Output.new
|
|
87
|
+
sexp.shift
|
|
88
|
+
output.name=sexp.shift
|
|
89
|
+
output.type=sexp.shift
|
|
90
|
+
output
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# ===== components stuff =====
|
|
96
|
+
def parse_component sexp
|
|
97
|
+
comp=Component.new
|
|
98
|
+
sexp.shift
|
|
99
|
+
comp.name=sexp.shift
|
|
100
|
+
comp.type=sexp.shift
|
|
101
|
+
comp
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def parse_connect sexp
|
|
105
|
+
con=Connect.new
|
|
106
|
+
sexp.shift
|
|
107
|
+
con.source=parse_port(sexp.shift)
|
|
108
|
+
con.sink =parse_port(sexp.shift)
|
|
109
|
+
con
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def parse_port sexp
|
|
113
|
+
case sexp
|
|
114
|
+
when Array
|
|
115
|
+
port=Port.new
|
|
116
|
+
sexp.shift
|
|
117
|
+
port.component_name=sexp.shift
|
|
118
|
+
port.name=sexp.shift
|
|
119
|
+
return port
|
|
120
|
+
else
|
|
121
|
+
return sexp
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# statements
|
|
126
|
+
def parse_statement sexp
|
|
127
|
+
case sexp.first
|
|
128
|
+
when :if
|
|
129
|
+
parse_if(sexp)
|
|
130
|
+
when :assign
|
|
131
|
+
parse_assign(sexp)
|
|
132
|
+
else
|
|
133
|
+
raise "unknow statement starting with : #{sexp.first}"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def parse_comb sexp
|
|
138
|
+
comb=Combinatorial.new
|
|
139
|
+
sexp.shift
|
|
140
|
+
label=sexp.shift
|
|
141
|
+
comb.body=parse_body(sexp)
|
|
142
|
+
comb
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def parse_body sexp
|
|
146
|
+
body=Body.new
|
|
147
|
+
while sexp.any?
|
|
148
|
+
body << parse_statement(sexp.shift)
|
|
149
|
+
end
|
|
150
|
+
body
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def parse_if sexp
|
|
154
|
+
if_=If.new
|
|
155
|
+
sexp.shift
|
|
156
|
+
if_.cond = parse_expression(sexp.shift)
|
|
157
|
+
while sexp.any?
|
|
158
|
+
case sexp.first.first
|
|
159
|
+
when :then
|
|
160
|
+
if_.then = parse_then(sexp.shift)
|
|
161
|
+
when :elsif
|
|
162
|
+
if_.elsifs << parse_elsif(sexp.shift)
|
|
163
|
+
when :else
|
|
164
|
+
if_.else = parse_else(sexp.shift)
|
|
165
|
+
else
|
|
166
|
+
raise "error parsing 'if' : #{sexp.first.first}"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
if_
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def parse_then sexp
|
|
173
|
+
sexp.shift
|
|
174
|
+
body=parse_body(sexp)
|
|
175
|
+
body
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def parse_elsif sexp
|
|
179
|
+
sexp.shift
|
|
180
|
+
body=parse_body(sexp)
|
|
181
|
+
body
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def parse_else sexp
|
|
185
|
+
sexp.shift
|
|
186
|
+
body=parse_body(sexp)
|
|
187
|
+
body
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def parse_assign sexp
|
|
191
|
+
assign=Assign.new
|
|
192
|
+
sexp.shift
|
|
193
|
+
assign.lhs=parse_expression(sexp.shift)
|
|
194
|
+
assign.rhs=parse_expression(sexp.shift)
|
|
195
|
+
assign
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# expressions
|
|
199
|
+
|
|
200
|
+
def parse_expression sexp
|
|
201
|
+
case sexp
|
|
202
|
+
when Array
|
|
203
|
+
case sexp.size
|
|
204
|
+
when 1
|
|
205
|
+
case sexp
|
|
206
|
+
when Symbol
|
|
207
|
+
return Var.new(sexp)
|
|
208
|
+
when Integer
|
|
209
|
+
return Const.new(sexp)
|
|
210
|
+
else
|
|
211
|
+
raise "unknown expression '#{sexp}'"
|
|
212
|
+
end
|
|
213
|
+
when 2
|
|
214
|
+
ret=parse_unary(sexp)
|
|
215
|
+
when 3
|
|
216
|
+
ret=parse_binary(sexp)
|
|
217
|
+
else
|
|
218
|
+
raise "unknown expression '#{sexp}'(size = '#{sexp.size}')"
|
|
219
|
+
end
|
|
220
|
+
when Symbol
|
|
221
|
+
ret=Var.new(sexp)
|
|
222
|
+
when Integer
|
|
223
|
+
ret=Const.new(sexp)
|
|
224
|
+
else
|
|
225
|
+
raise "unknown expression '#{sexp}'"
|
|
226
|
+
end
|
|
227
|
+
ret
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
OP_TRANSLATE={
|
|
231
|
+
"gt" => ">",
|
|
232
|
+
"lt" => "<",
|
|
233
|
+
"eq" => "=",
|
|
234
|
+
"neq"=> "/=",
|
|
235
|
+
"gte"=> ">=",
|
|
236
|
+
"lte"=> "<=",
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
NORMALIZED_OP={
|
|
240
|
+
"*" => "mul",
|
|
241
|
+
"+" => "add",
|
|
242
|
+
"-" => "sub",
|
|
243
|
+
"/" => "div",
|
|
244
|
+
"=" => "eq",
|
|
245
|
+
">=" => "gte",
|
|
246
|
+
"<=" => "lte",
|
|
247
|
+
"/=" => "neq"
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
def parse_binary sexp
|
|
251
|
+
case sexp.first
|
|
252
|
+
when :mread
|
|
253
|
+
ret=MRead.new
|
|
254
|
+
sexp.shift
|
|
255
|
+
ret.mem = Mem.new(sexp.shift) # memory name
|
|
256
|
+
ret.addr= parse_expression(sexp.shift)
|
|
257
|
+
else
|
|
258
|
+
ret=Binary.new
|
|
259
|
+
ret.op=sexp.shift
|
|
260
|
+
#ret.op=OP_TRANSLATE[ret.op.to_s]||ret.op.to_s
|
|
261
|
+
ret.op=NORMALIZED_OP[ret.op.to_s] || ret.op.to_s
|
|
262
|
+
ret.lhs=parse_expression(sexp.shift)
|
|
263
|
+
ret.rhs=parse_expression(sexp.shift)
|
|
264
|
+
end
|
|
265
|
+
ret
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def parse_unary sexp
|
|
269
|
+
ret=Unary.new
|
|
270
|
+
ret.op=sexp.shift
|
|
271
|
+
ret
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require_relative 'log'
|
|
2
|
+
class Symbol
|
|
3
|
+
def accept visitor,args=nil
|
|
4
|
+
self
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module Sexpir
|
|
9
|
+
class RubyRTLGenerator < Visitor
|
|
10
|
+
include Log
|
|
11
|
+
def generate circuit
|
|
12
|
+
log "[+] generating RubyRTL '#{circuit.name}'"
|
|
13
|
+
code=circuit.accept(self)
|
|
14
|
+
puts code.finalize
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def visitCircuit circuit,args=nil
|
|
18
|
+
code=Code.new
|
|
19
|
+
code << "require 'ruby_rtl'"
|
|
20
|
+
code << "class #{circuit.name.capitalize} < Circuit"
|
|
21
|
+
code.indent=2
|
|
22
|
+
circuit.inputs.each{|input| code << input.accept(self)}
|
|
23
|
+
circuit.outputs.each{|output| code << output.accept(self)}
|
|
24
|
+
circuit.signals.each{|signal| code << signal.accept(self)}
|
|
25
|
+
code.newline
|
|
26
|
+
code << circuit.body.accept(self)
|
|
27
|
+
code.indent=0
|
|
28
|
+
code << "end"
|
|
29
|
+
code
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def gen_type(type)
|
|
33
|
+
case num=type
|
|
34
|
+
when Integer
|
|
35
|
+
case num
|
|
36
|
+
when 1
|
|
37
|
+
return "bit"
|
|
38
|
+
else
|
|
39
|
+
return "bv#{num}"
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
return type
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def visitSignal sig,args=nil
|
|
47
|
+
sig.name
|
|
48
|
+
type=gen_type(sig.type)
|
|
49
|
+
"wire :#{sig.name} => :#{type}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def visitIo io,args=nil
|
|
53
|
+
io.name
|
|
54
|
+
io.type
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def visitPort port,args=nil
|
|
58
|
+
comp=port.component_name
|
|
59
|
+
name=port.name
|
|
60
|
+
"#{comp}.#{name}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def visitInput input,args=nil
|
|
64
|
+
input.name
|
|
65
|
+
input.type
|
|
66
|
+
"input :#{input.name} => :#{input.type}"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def visitOutput output,args=nil
|
|
70
|
+
output.name
|
|
71
|
+
output.type
|
|
72
|
+
"output :#{output.name} => :#{output.type}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# === statements ===
|
|
76
|
+
def visitBody body,args=nil
|
|
77
|
+
code=Code.new
|
|
78
|
+
body.stmts.each{|stmt| code << stmt.accept(self)}
|
|
79
|
+
code
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def visitCombinatorial comb,args=nil
|
|
83
|
+
code=Code.new
|
|
84
|
+
code << "combinatorial(#{comb.label}){"
|
|
85
|
+
code.indent=2
|
|
86
|
+
code << comb.body.accept(self)
|
|
87
|
+
code.indent=0
|
|
88
|
+
code << "}"
|
|
89
|
+
code
|
|
90
|
+
end
|
|
91
|
+
def visitSequential seq,args=nil
|
|
92
|
+
code=Code.new
|
|
93
|
+
code << "sequential(#{seq.label}){"
|
|
94
|
+
code.indent=2
|
|
95
|
+
code << seq.body.accept(self)
|
|
96
|
+
code.indent=0
|
|
97
|
+
code << "}"
|
|
98
|
+
code
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def visitAssign assign,args=nil
|
|
102
|
+
lhs=assign.lhs.accept(self)
|
|
103
|
+
rhs=assign.rhs.accept(self)
|
|
104
|
+
"assign(#{lhs} <= #{rhs})"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def visitIf if_,args=nil
|
|
108
|
+
cond=if_.cond.accept(self)
|
|
109
|
+
code=Code.new
|
|
110
|
+
code << "if (#{cond}"
|
|
111
|
+
code.indent=2
|
|
112
|
+
code << if_.then.accept(self)
|
|
113
|
+
if if_.else
|
|
114
|
+
code.indent=0
|
|
115
|
+
code << "else"
|
|
116
|
+
code.indent=2
|
|
117
|
+
code << if_.else.accept(self)
|
|
118
|
+
code.indent=0
|
|
119
|
+
end
|
|
120
|
+
code.indent=0
|
|
121
|
+
code << "end"
|
|
122
|
+
code
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# === component stuff ====
|
|
126
|
+
def visitComponent component,args=nil
|
|
127
|
+
name=component.name
|
|
128
|
+
type=component.type
|
|
129
|
+
"component :#{name} => #{type.capitalize}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def visitConnect connect,args=nil
|
|
133
|
+
source=connect.source.accept(self)
|
|
134
|
+
sink=connect.sink.accept(self)
|
|
135
|
+
"connect #{source} => #{sink}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#===========
|
|
139
|
+
def visitExpression expr,args=nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
SEXPIR_TO_RUBY_OP={
|
|
143
|
+
"and" => "&",
|
|
144
|
+
"or" => "|",
|
|
145
|
+
"xor" => "^",
|
|
146
|
+
"not" => "!",
|
|
147
|
+
}
|
|
148
|
+
def visitBinary binary,args=nil
|
|
149
|
+
lhs=binary.lhs.accept(self)
|
|
150
|
+
rhs=binary.rhs.accept(self)
|
|
151
|
+
op=SEXPIR_TO_RUBY_OP[binary.op] || binary.op
|
|
152
|
+
"(#{lhs} #{op} #{rhs})"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def visitTerm term,args=nil
|
|
156
|
+
term
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def visitVar var,args=nil
|
|
160
|
+
var.name
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def visitConst const,args=nil
|
|
164
|
+
const.value
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require "optparse"
|
|
2
|
+
|
|
3
|
+
require_relative "compiler"
|
|
4
|
+
|
|
5
|
+
module Sexpir
|
|
6
|
+
|
|
7
|
+
class Runner
|
|
8
|
+
|
|
9
|
+
def self.run *arguments
|
|
10
|
+
new.run(arguments)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def run arguments
|
|
14
|
+
compiler=Compiler.new
|
|
15
|
+
compiler.options = args = parse_options(arguments)
|
|
16
|
+
$options=compiler.options
|
|
17
|
+
|
|
18
|
+
if filename=args[:filename]
|
|
19
|
+
compiler.compile filename
|
|
20
|
+
else
|
|
21
|
+
puts "need an sexpir file : sexpir <file.sexp>"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
def parse_options(arguments)
|
|
27
|
+
|
|
28
|
+
size=arguments.size
|
|
29
|
+
|
|
30
|
+
parser = OptionParser.new
|
|
31
|
+
|
|
32
|
+
options = {}
|
|
33
|
+
|
|
34
|
+
parser.on("-h", "--help", "Show help message") do
|
|
35
|
+
puts parser
|
|
36
|
+
exit(true)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
parser.on("-v", "--version", "Show version number") do
|
|
40
|
+
puts VERSION
|
|
41
|
+
exit(true)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
parser.on("--verbose", "verbose mode") do
|
|
45
|
+
options[:verbose]=true
|
|
46
|
+
$VERBOSE=true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
parser.parse!(arguments)
|
|
50
|
+
|
|
51
|
+
options[:filename]=arguments.shift
|
|
52
|
+
|
|
53
|
+
if arguments.any?
|
|
54
|
+
puts "WARNING : superfluous arguments : #{arguments}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if size==0
|
|
58
|
+
puts parser
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
options
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Sexpir
|
|
2
|
+
|
|
3
|
+
class Visitor
|
|
4
|
+
|
|
5
|
+
def visitCircuit circuit,args=nil
|
|
6
|
+
circuit.name
|
|
7
|
+
circuit.inputs.each{|input| input.accept(self)}
|
|
8
|
+
circuit.outputs.each{|output| output.accept(self)}
|
|
9
|
+
circuit.signals.each{|signal| signal.accept(self)}
|
|
10
|
+
circuit.body.accept(self)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def visitSignal sig,args=nil
|
|
14
|
+
signal.name
|
|
15
|
+
signal.type
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def visitIo io,args=nil
|
|
19
|
+
io.name
|
|
20
|
+
io.type
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def visitPort port,args=nil
|
|
24
|
+
port.name
|
|
25
|
+
port.type
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def visitInput input,args=nil
|
|
29
|
+
input.name
|
|
30
|
+
input.type
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def visitOutput output,args=nil
|
|
34
|
+
output.name
|
|
35
|
+
output.type
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def visitBody body,args=nil
|
|
39
|
+
body.stmts.each{|stmt| stmt.accept(self)}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def visitAssign assign,args=nil
|
|
43
|
+
assign.lhs.accept(self)
|
|
44
|
+
assign.rhs.accept(self)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def visitComponent component,args=nil
|
|
48
|
+
name=component.name
|
|
49
|
+
type=component.type
|
|
50
|
+
"component #{name} => #{type}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def visitConnect connect,args=nil
|
|
54
|
+
connect.source
|
|
55
|
+
connect.sink
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#===========
|
|
59
|
+
def visitExpression expr,args=nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def visitBinary binary,args=nil
|
|
63
|
+
binary.lhs.accept(self)
|
|
64
|
+
binary.rhs.accept(self)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def visitTerm term,args=nil
|
|
68
|
+
term
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def visitVar var,args=nil
|
|
72
|
+
var.name
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
data/lib/sexpir.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sexpir
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jean-Christophe Le Lann
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-01-08 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: distribution
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.7.3
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - '='
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 0.7.3
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: colorize
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - '='
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.8.1
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - '='
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.8.1
|
|
41
|
+
description: sexpir is a sexp-based interchange format for RTL design
|
|
42
|
+
email: lelannje@ensta-bretagne.fr
|
|
43
|
+
executables:
|
|
44
|
+
- sexpir
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- bin/sexpir
|
|
49
|
+
- lib/sexpir.rb
|
|
50
|
+
- lib/sexpir/ast.rb
|
|
51
|
+
- lib/sexpir/ast_sexp.rb
|
|
52
|
+
- lib/sexpir/checker.rb
|
|
53
|
+
- lib/sexpir/code.rb
|
|
54
|
+
- lib/sexpir/code_generator.rb
|
|
55
|
+
- lib/sexpir/compiler.rb
|
|
56
|
+
- lib/sexpir/graph.rb
|
|
57
|
+
- lib/sexpir/log.rb
|
|
58
|
+
- lib/sexpir/parser.rb
|
|
59
|
+
- lib/sexpir/printer.rb
|
|
60
|
+
- lib/sexpir/ruby_rtl_generator.rb
|
|
61
|
+
- lib/sexpir/runner.rb
|
|
62
|
+
- lib/sexpir/transformer.rb
|
|
63
|
+
- lib/sexpir/version.rb
|
|
64
|
+
- lib/sexpir/visitor.rb
|
|
65
|
+
homepage: https://github.com/JC-LL/sexpir
|
|
66
|
+
licenses:
|
|
67
|
+
- MIT
|
|
68
|
+
metadata: {}
|
|
69
|
+
post_install_message: Thanks for installing ! Homepage :https://github.com/JC-LL/sexpir
|
|
70
|
+
rdoc_options: []
|
|
71
|
+
require_paths:
|
|
72
|
+
- lib
|
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
74
|
+
requirements:
|
|
75
|
+
- - ">="
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: 2.0.0
|
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
requirements: []
|
|
84
|
+
rubygems_version: 3.0.6
|
|
85
|
+
signing_key:
|
|
86
|
+
specification_version: 4
|
|
87
|
+
summary: interchange format for RTL designs
|
|
88
|
+
test_files: []
|