rtl_circuit 0.7 → 0.7.4
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 +4 -4
- data/lib/rtl/canvas.rb +49 -0
- data/lib/rtl/circuit.rb +1 -1
- data/lib/rtl/def_gates.svg +99 -0
- data/lib/rtl/fdgd.rb +110 -0
- data/lib/rtl/graph.rb +156 -0
- data/lib/rtl/json_parser.rb +49 -0
- data/lib/rtl/placer.rb +179 -0
- data/lib/rtl/printer.rb +1 -1
- data/lib/rtl/vector.rb +66 -0
- data/lib/rtl/viewer.rb +267 -0
- metadata +9 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a185b02649b8dccfde92ceddba567e41a0a0bd3996142e4d44390316be24873
|
4
|
+
data.tar.gz: 96085d10887cbe7d99b531ce56ab4a403d15a3da700d62baf064d216c7ea8925
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afeef2e5c8b2a67b07f557bdc54f4bc76859d13f3898d3b88c15f4da41aae688207d6dc91b295eb6f19178cfc13b62b142957edc4311d4e0f2158e059b066d80
|
7
|
+
data.tar.gz: 6380f0c3470dda41a4cbca67520a947e71c7d96abe64c31b5549dad90e9a7dda3cd49b7e336c054004b8ca7fbc8d846f890159cf0daf969a8278cef097660f35
|
data/lib/rtl/canvas.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
class Canvas < Gtk::DrawingArea
|
3
|
+
attr_accessor :running
|
4
|
+
def initialize
|
5
|
+
super()
|
6
|
+
|
7
|
+
@running=false
|
8
|
+
set_size_request(800,100)
|
9
|
+
signal_connect('draw') do
|
10
|
+
redraw @graph
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear cr
|
15
|
+
cr.set_source_rgb(0.1, 0.1, 0.1)
|
16
|
+
cr.paint
|
17
|
+
end
|
18
|
+
|
19
|
+
def redraw graph=nil,zoom_factor=1,shift=Vector.new(0,0)
|
20
|
+
@graph=graph
|
21
|
+
cr = window.create_cairo_context
|
22
|
+
cr.set_line_width(0.8)
|
23
|
+
|
24
|
+
w = allocation.width
|
25
|
+
h = allocation.height
|
26
|
+
|
27
|
+
cr.translate(w/2, h/2)
|
28
|
+
|
29
|
+
clear cr
|
30
|
+
|
31
|
+
if graph
|
32
|
+
cr.set_source_rgb(0.4, 0.4, 0.4)
|
33
|
+
@graph.edges.each do |edge|
|
34
|
+
n1,n2=edge.source,edge.sink
|
35
|
+
cr.move_to(shift.x + n1.x*zoom_factor,shift.y + n1.y*zoom_factor)
|
36
|
+
cr.line_to(shift.x + n2.x*zoom_factor,shift.y + n2.y*zoom_factor)
|
37
|
+
cr.stroke
|
38
|
+
end
|
39
|
+
|
40
|
+
cr.set_source_rgb(0.9, 0.5, 0.2)
|
41
|
+
@graph.nodes.each do |node|
|
42
|
+
cr.arc(shift.x+node.x*zoom_factor, shift.y+node.y*zoom_factor, 10*zoom_factor, 0, 2.0 * Math::PI)
|
43
|
+
cr.fill_preserve()
|
44
|
+
cr.stroke
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/rtl/circuit.rb
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
<defs>
|
2
|
+
<symbol id="and2">
|
3
|
+
<path d="M 10 2
|
4
|
+
l 19 0
|
5
|
+
A 13 13 0 1 1 29 28
|
6
|
+
l -19 0
|
7
|
+
z
|
8
|
+
M 0 6 l 10 0
|
9
|
+
M 0 24 l 10 0
|
10
|
+
M 42 15 L 60 15"
|
11
|
+
fill="transparent"
|
12
|
+
stroke="black"/>
|
13
|
+
</symbol>
|
14
|
+
|
15
|
+
<symbol id="nand2">
|
16
|
+
<path d="M 10 2
|
17
|
+
l 19 0
|
18
|
+
A 13 13 0 1 1 29 28
|
19
|
+
l -19 0
|
20
|
+
z
|
21
|
+
M 0 6 l 10 0
|
22
|
+
M 0 24 l 10 0
|
23
|
+
M 42 15 A 4 4 0 0 0 50 15
|
24
|
+
M 42 15 A 4 4 0 0 1 50 15
|
25
|
+
|
26
|
+
M 50 15 L 60 15"
|
27
|
+
fill="transparent"
|
28
|
+
stroke="black"/>
|
29
|
+
</symbol>
|
30
|
+
|
31
|
+
<symbol id="or2">
|
32
|
+
<path d="M 10 2
|
33
|
+
l 13.484 0
|
34
|
+
A 26 26 0 0 1 46 15
|
35
|
+
A 26 26 0 0 1 23.484 28
|
36
|
+
L 10 28
|
37
|
+
A 26 26 0 0 0 10 2
|
38
|
+
M 0 6 l 11.5 0
|
39
|
+
M 0 24 l 11.5 0
|
40
|
+
M 46 15 L 60 15
|
41
|
+
"
|
42
|
+
stroke-linecap="round"
|
43
|
+
fill="transparent"
|
44
|
+
stroke="black"/>
|
45
|
+
</symbol>
|
46
|
+
|
47
|
+
<symbol id="nor2">
|
48
|
+
<path d="M 10 2
|
49
|
+
l 13.484 0
|
50
|
+
A 26 26 0 0 1 46 15
|
51
|
+
A 26 26 0 0 1 23.484 28
|
52
|
+
L 10 28
|
53
|
+
A 26 26 0 0 0 10 2
|
54
|
+
M 0 6 l 11.5 0
|
55
|
+
M 0 24 l 11.5 0
|
56
|
+
M 54 15 L 60 15
|
57
|
+
M 46 15 A 4 4 0 0 0 54 15
|
58
|
+
M 46 15 A 4 4 0 0 1 54 15
|
59
|
+
|
60
|
+
"
|
61
|
+
stroke-linecap="round"
|
62
|
+
fill="transparent"
|
63
|
+
stroke="black"/>
|
64
|
+
</symbol>
|
65
|
+
|
66
|
+
<symbol id="xor2">
|
67
|
+
<path d="M 10 2
|
68
|
+
l 13.484 0
|
69
|
+
A 26 26 0 0 1 46 15
|
70
|
+
A 26 26 0 0 1 23.484 28
|
71
|
+
L 10 28
|
72
|
+
A 26 26 0 0 0 10 2
|
73
|
+
M 0 6 l 12 0
|
74
|
+
M 0 24 l 12 0
|
75
|
+
M 46 15 L 60 15
|
76
|
+
M 6 2 A 26 26 0 0 1 6 28
|
77
|
+
"
|
78
|
+
stroke-linecap="round"
|
79
|
+
fill="transparent"
|
80
|
+
stroke="black"/>
|
81
|
+
</symbol>
|
82
|
+
|
83
|
+
<symbol id="not">
|
84
|
+
<path d="M 10 2
|
85
|
+
L 32.516 15
|
86
|
+
L 10 28
|
87
|
+
Z
|
88
|
+
M 33 15 A 4 4 0 0 0 41 15
|
89
|
+
M 33 15 A 4 4 0 0 1 41 15
|
90
|
+
M 41 15 L 60 15
|
91
|
+
M 0 15 L 10 15
|
92
|
+
"
|
93
|
+
stroke-linecap="round"
|
94
|
+
fill="transparent"
|
95
|
+
stroke="black"/>
|
96
|
+
</symbol>
|
97
|
+
|
98
|
+
|
99
|
+
</defs>
|
data/lib/rtl/fdgd.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require_relative 'graph'
|
2
|
+
require_relative 'vector'
|
3
|
+
|
4
|
+
|
5
|
+
class Fdgd
|
6
|
+
|
7
|
+
attr_accessor :graph
|
8
|
+
attr_accessor :stop
|
9
|
+
|
10
|
+
def initialize graph=nil
|
11
|
+
puts "FDGD: force-directed graph drawer"
|
12
|
+
@graph=graph
|
13
|
+
@l0=80
|
14
|
+
@c1=30
|
15
|
+
@epsilon=10
|
16
|
+
@damping=0.92
|
17
|
+
@timestep=0.1
|
18
|
+
@stop=false
|
19
|
+
end
|
20
|
+
|
21
|
+
def dist a,b
|
22
|
+
Math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2)
|
23
|
+
end
|
24
|
+
|
25
|
+
def angle a,b
|
26
|
+
if dist(a,b)!=0
|
27
|
+
if b.x > a.x
|
28
|
+
angle = Math.asin((b.y-a.y)/dist(a,b))
|
29
|
+
else
|
30
|
+
angle = Math::PI - Math.asin((b.y-a.y)/dist(a,b))
|
31
|
+
end
|
32
|
+
else
|
33
|
+
angle =0
|
34
|
+
end
|
35
|
+
return angle
|
36
|
+
end
|
37
|
+
|
38
|
+
def coulomb_repulsion a,b
|
39
|
+
angle = angle(a,b)
|
40
|
+
dab = dist(a,b)
|
41
|
+
c= -0.2*(a.radius*b.radius)/Math.sqrt(dab)
|
42
|
+
[c*Math.cos(angle),c*Math.sin(angle)]
|
43
|
+
end
|
44
|
+
|
45
|
+
def sign_minus(a,b)
|
46
|
+
a>b ? 1 : -1
|
47
|
+
end
|
48
|
+
|
49
|
+
def hooke_attraction a,b #,c1=10#,l0=40
|
50
|
+
angle = angle(a,b)
|
51
|
+
dab = dist(a,b)
|
52
|
+
c = @c1*Math.log((dab-@l0).abs)*sign_minus(dab,@l0)
|
53
|
+
[c*Math.cos(angle),c*Math.sin(angle)]
|
54
|
+
end
|
55
|
+
|
56
|
+
def run iter=2
|
57
|
+
if @graph
|
58
|
+
Thread.new do
|
59
|
+
step = 0
|
60
|
+
total_kinetic_energy=1000
|
61
|
+
next_pos={}
|
62
|
+
next_speed={}
|
63
|
+
until total_kinetic_energy < @epsilon or step==iter do
|
64
|
+
|
65
|
+
step+=1
|
66
|
+
total_kinetic_energy = 0
|
67
|
+
|
68
|
+
for node in graph.nodes
|
69
|
+
net_force = Vector.new(0, 0)
|
70
|
+
|
71
|
+
for other in graph.nodes-[node]
|
72
|
+
rep = coulomb_repulsion( node, other)
|
73
|
+
net_force += rep
|
74
|
+
end
|
75
|
+
|
76
|
+
for edge in graph.edges.select{|e| e.source==node or e.sink==node}
|
77
|
+
other = edge.sink==node ? edge.source : edge.sink
|
78
|
+
attr = hooke_attraction(node, other) #, c1=30,@l0)
|
79
|
+
net_force += attr
|
80
|
+
end
|
81
|
+
|
82
|
+
# without damping, it moves forever
|
83
|
+
speed = (node.speed + net_force.scale(@timestep)).scale(@damping)
|
84
|
+
next_pos[node.id] = node.pos + speed.scale(@timestep)
|
85
|
+
next_speed[node.id] = speed
|
86
|
+
total_kinetic_energy += node.radius * speed.squared
|
87
|
+
end
|
88
|
+
|
89
|
+
#puts total_kinetic_energy
|
90
|
+
yield if block_given?
|
91
|
+
#update nodes position
|
92
|
+
for node in graph.nodes
|
93
|
+
unless node.fixed.x
|
94
|
+
node.pos.x = next_pos[node.id].x
|
95
|
+
node.speed.x = next_speed[node.id].x
|
96
|
+
end
|
97
|
+
unless node.fixed.y
|
98
|
+
node.pos.y = next_pos[node.id].y
|
99
|
+
node.speed.y = next_speed[node.id].y
|
100
|
+
end
|
101
|
+
end
|
102
|
+
break if @stop
|
103
|
+
end
|
104
|
+
puts "algorithm end"
|
105
|
+
puts "reached epsilon" if total_kinetic_energy < @epsilon
|
106
|
+
puts "reached max iterations" if step==iter
|
107
|
+
end #thread
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/rtl/graph.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative 'vector'
|
2
|
+
require_relative 'json_parser'
|
3
|
+
|
4
|
+
class Node
|
5
|
+
attr_accessor :id,:pos,:dims,:speed,:fixed,:radius
|
6
|
+
def initialize params={}
|
7
|
+
puts "creating node #{params}"
|
8
|
+
@id =params["id"]
|
9
|
+
@radius=params["radius"] || rand(5..10)
|
10
|
+
@pos =Vector.new *params["pos"]
|
11
|
+
@speed =Vector.new *(params["speed"] || [0,0])
|
12
|
+
@fixed =Vector.new *(params["fixed"] || [false,false])
|
13
|
+
@dims =Vector.new *(params["dims"] || [10,5])
|
14
|
+
end
|
15
|
+
|
16
|
+
def x=(v)
|
17
|
+
@pos[0]=v
|
18
|
+
end
|
19
|
+
|
20
|
+
def y=(v)
|
21
|
+
@pos[1]=v
|
22
|
+
end
|
23
|
+
|
24
|
+
def x
|
25
|
+
@pos.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def y
|
29
|
+
@pos.last
|
30
|
+
end
|
31
|
+
|
32
|
+
def print_info
|
33
|
+
pp "node #{@id} : pos=#{@pos},dims=#{@dims},v=#{@velocity}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Edge
|
38
|
+
attr_accessor :source,:sink
|
39
|
+
def initialize params={}
|
40
|
+
unless params.empty?
|
41
|
+
@source=params["source"]
|
42
|
+
@sink =params["sink"]
|
43
|
+
puts "creating edge #{@source.id}-->#{@sink.id}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Graph
|
49
|
+
|
50
|
+
attr_accessor :nodes,:id,:edges,:map
|
51
|
+
|
52
|
+
def initialize id=nil,nodes=[],edges=[]
|
53
|
+
@id=id
|
54
|
+
@nodes,@edges=nodes,edges
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.read_file filename
|
58
|
+
Parser.new.parse filename
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_file filename
|
62
|
+
json=Code.new
|
63
|
+
json << "{"
|
64
|
+
json.indent=2
|
65
|
+
json << "\"id\" : \"#{id}\","
|
66
|
+
json << "\"nodes\" : ["
|
67
|
+
json.indent=4
|
68
|
+
nodes.each{|node| json << json_node(node)}
|
69
|
+
json.indent=2
|
70
|
+
json << "],"
|
71
|
+
json << "\"edges\" : ["
|
72
|
+
json.indent=4
|
73
|
+
edges.each{|edge| json << json_edge(edge)}
|
74
|
+
json.indent=2
|
75
|
+
json << "]"
|
76
|
+
json.indent=0
|
77
|
+
json << "}"
|
78
|
+
code=json.finalize
|
79
|
+
code.gsub!(/\,\s*\]/,']')
|
80
|
+
json=Code.new(code)
|
81
|
+
json.save_as filename
|
82
|
+
end
|
83
|
+
|
84
|
+
def json_node node
|
85
|
+
fixed=node.fixed.to_s
|
86
|
+
"{\"id\":\"#{node.id}\",\"pos\":#{node.pos.to_s},\"speed\":#{node.speed.to_s},\"fixed\":#{fixed}},"
|
87
|
+
end
|
88
|
+
|
89
|
+
def json_edge edge
|
90
|
+
"{\"source\":\"#{edge.source.id}\",\"sink\":\"#{edge.sink.id}\"},"
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.random(nbVertex,maxNbEdgesPerVertex=2)
|
94
|
+
nodes=(1..nbVertex).map{|i|
|
95
|
+
h={
|
96
|
+
"id" => "#{i}",
|
97
|
+
"pos"=> [rand(1000),rand(1000)]
|
98
|
+
}
|
99
|
+
Node.new(h)
|
100
|
+
}
|
101
|
+
edges=[]
|
102
|
+
nodes.each_with_index do |node,idx|
|
103
|
+
nb_edges=rand(0..maxNbEdgesPerVertex)
|
104
|
+
nb_edges.times do
|
105
|
+
edge=Edge.new
|
106
|
+
edge.source=node
|
107
|
+
edge.sink=sink=nodes.sample
|
108
|
+
(edges << edge) unless nodes.index(sink)==idx
|
109
|
+
end
|
110
|
+
end
|
111
|
+
Graph.new("g",nodes,edges)
|
112
|
+
end
|
113
|
+
|
114
|
+
def shuffle range=0..800
|
115
|
+
@nodes.each do |node|
|
116
|
+
nx,ny=rand(range),rand(range)
|
117
|
+
node.pos=Vector.new(nx,ny)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def print_info
|
122
|
+
puts "graph info".center(40,"=")
|
123
|
+
puts "#vertices".ljust(30,'.')+nodes.size.to_s
|
124
|
+
puts "#edges".ljust(30,'.')+edges.size.to_s
|
125
|
+
|
126
|
+
puts "nodes".center(40,'-')
|
127
|
+
nodes.each do |node|
|
128
|
+
puts "#{node.id.ljust(10)} #{node.pos.x} #{node.pos.y}"
|
129
|
+
end
|
130
|
+
puts "edges".center(40,'-')
|
131
|
+
edges.each do |edge|
|
132
|
+
puts "#{edge.source.id} --> #{edge.sink.id}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.rand_between min,max
|
137
|
+
(min..max).to_a.sample
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.random_pos(maxx=800,maxy=600)
|
141
|
+
x,y=maxx/2,maxy/2
|
142
|
+
[self.rand_between(-x,x),self.rand_between(-y,y)]
|
143
|
+
end
|
144
|
+
|
145
|
+
def each_vertex &block
|
146
|
+
@nodes.each do |node|
|
147
|
+
yield node
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def each_edge &block
|
152
|
+
@edges.each do |edge|
|
153
|
+
yield edge
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
require_relative 'graph'
|
4
|
+
|
5
|
+
class Parser
|
6
|
+
def parse filename
|
7
|
+
puts "parsing '#{filename}'"
|
8
|
+
json=JSON.parse(IO.read(filename))
|
9
|
+
gen_graph json
|
10
|
+
end
|
11
|
+
|
12
|
+
def gen_graph json
|
13
|
+
@sym={}
|
14
|
+
graph=Graph.new
|
15
|
+
json.each do |key,val|
|
16
|
+
case key
|
17
|
+
when "id"
|
18
|
+
graph.id=val
|
19
|
+
when "nodes"
|
20
|
+
graph.nodes=gen_nodes(val)
|
21
|
+
when "edges"
|
22
|
+
graph.edges=gen_edges(val)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return graph
|
26
|
+
end
|
27
|
+
|
28
|
+
def gen_nodes json
|
29
|
+
json.map{|j| gen_node(j)}
|
30
|
+
end
|
31
|
+
|
32
|
+
def gen_node json
|
33
|
+
node=Node.new(json)
|
34
|
+
@sym[node.id]=node
|
35
|
+
node
|
36
|
+
end
|
37
|
+
|
38
|
+
def gen_edges json
|
39
|
+
json.map{|j| gen_edge(j)}
|
40
|
+
end
|
41
|
+
|
42
|
+
def gen_edge json
|
43
|
+
a=json.map{|k,v| {k => @sym[v]}}
|
44
|
+
Edge.new(a.inject(:merge))
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
#pp Parser.new.parse("line.sexp")
|
data/lib/rtl/placer.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
require_relative "fdgd"
|
2
|
+
require_relative 'code'
|
3
|
+
|
4
|
+
module RTL
|
5
|
+
|
6
|
+
class Placer
|
7
|
+
|
8
|
+
attr_accessor :circuit
|
9
|
+
|
10
|
+
def place circuit
|
11
|
+
puts "placing '#{circuit.name}'"
|
12
|
+
@circuit=circuit
|
13
|
+
puts "creating p&r graph"
|
14
|
+
nodes=gen_pnr_nodes(circuit)
|
15
|
+
edges=gen_pnr_edges(circuit)
|
16
|
+
graph=Graph.new(circuit.name,nodes,edges)
|
17
|
+
graph.print_info
|
18
|
+
drawer=Fdgd.new(graph)
|
19
|
+
drawer.run 100
|
20
|
+
puts "final placement".center(40,'=')
|
21
|
+
graph.write_file "#{circuit.name}.json"
|
22
|
+
gen_svg graph
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def gen_pnr_nodes circuit
|
27
|
+
nodes=[]
|
28
|
+
@sym={} # internal references for p&r
|
29
|
+
@map={} # link to RTL::Circuit objects
|
30
|
+
circuit.inputs.each_with_index do |port,idx|
|
31
|
+
id=port.object_id.to_s
|
32
|
+
dy=600.0/circuit.inputs.size
|
33
|
+
params={"id" => id,
|
34
|
+
"pos" => [10,idx*dy],
|
35
|
+
"fixed" => [true,false],
|
36
|
+
}
|
37
|
+
nodes << node=Node.new(params)
|
38
|
+
@sym[id]=node
|
39
|
+
@map[node]=port
|
40
|
+
end
|
41
|
+
circuit.outputs.each_with_index do |port,idx|
|
42
|
+
id=port.object_id.to_s
|
43
|
+
dy=600.0/circuit.outputs.size
|
44
|
+
params={"id" => id,
|
45
|
+
"pos" => [500,dy*idx],
|
46
|
+
"fixed" => [true,false],
|
47
|
+
}
|
48
|
+
nodes << node=Node.new(params)
|
49
|
+
@sym[id]=node
|
50
|
+
@map[node]=port
|
51
|
+
end
|
52
|
+
circuit.signals.each do |port|
|
53
|
+
id=port.object_id.to_s
|
54
|
+
params={"id" => id,
|
55
|
+
"pos" => [rand(600),rand(600)]
|
56
|
+
}
|
57
|
+
nodes << node=Node.new(params)
|
58
|
+
@sym[id]=node
|
59
|
+
@map[node]=port
|
60
|
+
end
|
61
|
+
circuit.components.each do |comp|
|
62
|
+
id=comp.object_id.to_s
|
63
|
+
params={"id" => id,
|
64
|
+
"pos" => [rand(300),rand(300)],
|
65
|
+
}
|
66
|
+
nodes << node=Node.new(params)
|
67
|
+
@sym[id]=node
|
68
|
+
@map[node]=comp
|
69
|
+
end
|
70
|
+
nodes
|
71
|
+
end
|
72
|
+
|
73
|
+
def gen_pnr_edges circuit
|
74
|
+
edges=[]
|
75
|
+
circuit.inputs.each do |input|
|
76
|
+
input.fanout.each do |wire|
|
77
|
+
psource=wire.source
|
78
|
+
if psource.circuit==circuit #psink is a port of current circuit
|
79
|
+
source=psource
|
80
|
+
else
|
81
|
+
source=psource.circuit # one of the components
|
82
|
+
end
|
83
|
+
psink=wire.sink
|
84
|
+
if psink.circuit==circuit #psink is a port of current circuit
|
85
|
+
sink=psink
|
86
|
+
else
|
87
|
+
sink=psink.circuit # one of the components
|
88
|
+
end
|
89
|
+
id_source=source.object_id.to_s
|
90
|
+
id_sink =sink.object_id.to_s
|
91
|
+
node_source=@sym[id_source]
|
92
|
+
node_sink=@sym[id_sink]
|
93
|
+
params={"source" => node_source,
|
94
|
+
"sink" => node_sink
|
95
|
+
}
|
96
|
+
edges << Edge.new(params)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
circuit.signals.each do |sig|
|
100
|
+
sig.fanout.each do |wire|
|
101
|
+
psource=wire.source
|
102
|
+
if psource.circuit==circuit #psink is a port of current circuit
|
103
|
+
source=psource
|
104
|
+
else
|
105
|
+
source=psource.circuit # one of the components
|
106
|
+
end
|
107
|
+
psink=wire.sink
|
108
|
+
if psink.circuit==circuit #psink is a port of current circuit
|
109
|
+
sink=psink
|
110
|
+
else
|
111
|
+
sink=psink.circuit # one of the components
|
112
|
+
end
|
113
|
+
id_source=source.object_id.to_s
|
114
|
+
id_sink =sink.object_id.to_s
|
115
|
+
node_source=@sym[id_source]
|
116
|
+
node_sink=@sym[id_sink]
|
117
|
+
params={"source" => node_source,
|
118
|
+
"sink" => node_sink
|
119
|
+
}
|
120
|
+
edges << Edge.new(params)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
circuit.components.each do |comp|
|
124
|
+
comp.outputs.each do |output|
|
125
|
+
output.fanout.each do |wire|
|
126
|
+
psource=wire.source
|
127
|
+
if psource.circuit==circuit #psink is a port of current circuit
|
128
|
+
source=psource
|
129
|
+
else
|
130
|
+
source=psource.circuit # one of the components
|
131
|
+
end
|
132
|
+
psink=wire.sink
|
133
|
+
if psink.circuit==circuit #psink is a port of current circuit
|
134
|
+
sink=psink
|
135
|
+
else
|
136
|
+
sink=psink.circuit # one of the components
|
137
|
+
end
|
138
|
+
id_source=source.object_id.to_s
|
139
|
+
id_sink =sink.object_id.to_s
|
140
|
+
node_source=@sym[id_source]
|
141
|
+
node_sink=@sym[id_sink]
|
142
|
+
params={"source" => node_source,
|
143
|
+
"sink" => node_sink
|
144
|
+
}
|
145
|
+
edges << Edge.new(params)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
edges
|
150
|
+
end
|
151
|
+
|
152
|
+
SVG_ELEMENT={
|
153
|
+
"and" => "and2",
|
154
|
+
"nand" => "nand2",
|
155
|
+
"or" => "or2",
|
156
|
+
"nor" => "nor2",
|
157
|
+
"xor" => "xor2",
|
158
|
+
"not" => "not",
|
159
|
+
}
|
160
|
+
def gen_svg graph
|
161
|
+
svg=Code.new
|
162
|
+
svg << "<svg width=\"600\" height=\"300\""
|
163
|
+
svg << " xmlns=\"http://www.w3.org/2000/svg\""
|
164
|
+
svg << " xmlns:xlink=\"http://www.w3.org/1999/xlink\">"
|
165
|
+
svg << IO.read("/home/jcll/JCLL/dev/EDA-ESL/rtl/lib/rtl/def_gates.svg")
|
166
|
+
graph.nodes.each do |node|
|
167
|
+
circuit=@map[node]
|
168
|
+
klass=circuit.class.to_s.split("::").last.downcase
|
169
|
+
element=SVG_ELEMENT[klass] || "not"
|
170
|
+
pos=node.pos
|
171
|
+
x,y=pos.x,pos.y
|
172
|
+
svg << "<use xlink:href=\"##{element}\" x=\"#{x}\" y=\"#{y}\"/>"
|
173
|
+
end
|
174
|
+
svg << "</svg>"
|
175
|
+
filename="#{circuit.name}_pnr.svg"
|
176
|
+
svg.save_as filename
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
data/lib/rtl/printer.rb
CHANGED
@@ -12,7 +12,7 @@ module RTL
|
|
12
12
|
circuit.components.each do |comp|
|
13
13
|
inputs_dot ="{"+comp.ports[:in].collect{|e| "<#{e.name}>#{e.name}"}.join("|")+"}"
|
14
14
|
outputs_dot="{"+comp.ports[:out].collect{|e| "<#{e.name}>#{e.name}"}.join("|")+"}"
|
15
|
-
|
15
|
+
color=circuit.color
|
16
16
|
dot << "#{comp.iname}[ shape=record; style=filled ; color=#{color} ; label=\"{ #{inputs_dot}| #{comp.name} | #{outputs_dot} }\"];"
|
17
17
|
end
|
18
18
|
circuit.ports[:in].each do |p|
|
data/lib/rtl/vector.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
class Vector
|
2
|
+
def initialize x=nil,y=nil
|
3
|
+
@array=[x,y]
|
4
|
+
end
|
5
|
+
|
6
|
+
def x
|
7
|
+
return @array[0]
|
8
|
+
end
|
9
|
+
|
10
|
+
def y
|
11
|
+
return @array[1]
|
12
|
+
end
|
13
|
+
|
14
|
+
def x=(v)
|
15
|
+
@array[0]=v
|
16
|
+
end
|
17
|
+
|
18
|
+
def y=(v)
|
19
|
+
@array[1]=v
|
20
|
+
end
|
21
|
+
|
22
|
+
def first
|
23
|
+
@array.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def last
|
27
|
+
@array.last
|
28
|
+
end
|
29
|
+
|
30
|
+
def [](idx)
|
31
|
+
@array[idx]
|
32
|
+
end
|
33
|
+
|
34
|
+
def []=(idx,val)
|
35
|
+
@array[idx]=val
|
36
|
+
end
|
37
|
+
|
38
|
+
def +(other)
|
39
|
+
res=Vector.new
|
40
|
+
@array.each_with_index do |e,i|
|
41
|
+
res[i]=e + other[i]
|
42
|
+
end
|
43
|
+
return res
|
44
|
+
end
|
45
|
+
|
46
|
+
def scale int
|
47
|
+
res=Vector.new
|
48
|
+
@array.each_with_index do |e,i|
|
49
|
+
res[i]=e*int
|
50
|
+
end
|
51
|
+
return res
|
52
|
+
end
|
53
|
+
|
54
|
+
def squared
|
55
|
+
res=0
|
56
|
+
@array.each do |e|
|
57
|
+
res+=e*e
|
58
|
+
end
|
59
|
+
return res
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
"[#{@array.join(',')}]"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/lib/rtl/viewer.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
require 'gtk3'
|
2
|
+
|
3
|
+
require_relative 'fdgd'
|
4
|
+
require_relative 'canvas'
|
5
|
+
|
6
|
+
class Viewer < Gtk::Window
|
7
|
+
|
8
|
+
def initialize args={} # I want to show it's possible to pass some args
|
9
|
+
super() # mandatory parenthesis ! otherwise : wrong arguments: Gtk::Window#initialize({})
|
10
|
+
set_title 'jcll_3'
|
11
|
+
set_default_size 900,600
|
12
|
+
set_border_width 10
|
13
|
+
set_window_position :center
|
14
|
+
set_destroy_callback
|
15
|
+
|
16
|
+
@algorithm=Fdgd.new
|
17
|
+
@zoom_factor=1
|
18
|
+
@shift=Vector.new(0,0)
|
19
|
+
|
20
|
+
hbox = Gtk::Box.new(:horizontal, spacing=6)
|
21
|
+
add hbox
|
22
|
+
@canvas = Canvas.new
|
23
|
+
hbox.pack_start(@canvas,:expand=>true,:fill=> true)
|
24
|
+
#...instead of :
|
25
|
+
# hbox.add canvas
|
26
|
+
|
27
|
+
vbox = Gtk::Box.new(:vertical,spacing=6)
|
28
|
+
hbox.add vbox
|
29
|
+
|
30
|
+
button = Gtk::Button.new(label:"open")
|
31
|
+
button.signal_connect("clicked"){on_open_clicked(button)}
|
32
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
33
|
+
|
34
|
+
button = Gtk::Button.new(label:"random graph")
|
35
|
+
button.signal_connect("clicked"){on_random_clicked(button)}
|
36
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
37
|
+
|
38
|
+
label = Gtk::Label.new("number of nodes : ")
|
39
|
+
|
40
|
+
vbox.pack_start(label,:expand => false, :fill => false, :padding => 0)
|
41
|
+
|
42
|
+
spinner = Gtk::SpinButton.new(1,100,1)
|
43
|
+
spinner.value= @nb_value || 20
|
44
|
+
spinner.signal_connect("value-changed"){on_spin_changed(spinner)}
|
45
|
+
vbox.pack_start(spinner,:expand => false, :fill => false, :padding => 0)
|
46
|
+
|
47
|
+
button = Gtk::Button.new(:label => "run")
|
48
|
+
button.signal_connect("clicked"){on_run_clicked(button)}
|
49
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
50
|
+
|
51
|
+
button = Gtk::Button.new(:label => "stop")
|
52
|
+
button.signal_connect("clicked"){on_stop_clicked(button)}
|
53
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
54
|
+
|
55
|
+
button = Gtk::Button.new(:label => "step")
|
56
|
+
button.signal_connect("clicked"){on_step_clicked(button)}
|
57
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
58
|
+
|
59
|
+
button = Gtk::Button.new(:label => "shuffle")
|
60
|
+
button.signal_connect("clicked"){on_shuffle_clicked(button)}
|
61
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
62
|
+
|
63
|
+
button = Gtk::Button.new(:label => "center")
|
64
|
+
button.signal_connect("clicked"){on_center_clicked(button)}
|
65
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
66
|
+
|
67
|
+
button = Gtk::Button.new(:label => "zoom+")
|
68
|
+
button.signal_connect("clicked"){on_zoom_clicked(button)}
|
69
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
70
|
+
|
71
|
+
button = Gtk::Button.new(:label => "zoom-")
|
72
|
+
button.signal_connect("clicked"){on_unzoom_clicked(button)}
|
73
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
74
|
+
|
75
|
+
button = Gtk::Button.new(:label => "zoom fit")
|
76
|
+
button.signal_connect("clicked"){on_fit_clicked(button)}
|
77
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
78
|
+
|
79
|
+
button = Gtk::Button.new(:label => "save")
|
80
|
+
button.signal_connect("clicked"){on_save_clicked(button)}
|
81
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
82
|
+
|
83
|
+
button = Gtk::Button.new(:label => "quit")
|
84
|
+
button.signal_connect("clicked"){on_quit_clicked(button)}
|
85
|
+
vbox.pack_start(button,:expand => false, :fill => false, :padding => 0)
|
86
|
+
show_all
|
87
|
+
end
|
88
|
+
|
89
|
+
def on_open_clicked button
|
90
|
+
puts '"open" button was clicked'
|
91
|
+
dialog=Gtk::FileChooserDialog.new(
|
92
|
+
:title => "choose",
|
93
|
+
:parent => self,
|
94
|
+
:action => Gtk::FileChooserAction::OPEN,
|
95
|
+
:buttons => [[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT],
|
96
|
+
[Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
|
97
|
+
filter_json = Gtk::FileFilter.new
|
98
|
+
filter_json.name = "json filter"
|
99
|
+
filter_json.add_pattern("*.json")
|
100
|
+
dialog.add_filter(filter_json)
|
101
|
+
|
102
|
+
dialog.show_all
|
103
|
+
|
104
|
+
case dialog.run
|
105
|
+
when Gtk::ResponseType::ACCEPT
|
106
|
+
puts "filename = #{dialog.filename}"
|
107
|
+
#puts "uri = #{dialog.uri}"
|
108
|
+
@graph=Graph.read_file dialog.filename
|
109
|
+
puts @graph
|
110
|
+
@canvas.redraw @graph
|
111
|
+
set_title @graph.id
|
112
|
+
dialog.destroy
|
113
|
+
else
|
114
|
+
dialog.destroy
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_random_clicked button
|
119
|
+
puts 'button "random" clicked'
|
120
|
+
set_title "random"
|
121
|
+
@graph=Graph.random(@nb_nodes || 20)
|
122
|
+
@canvas.running=true
|
123
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
124
|
+
end
|
125
|
+
|
126
|
+
def on_spin_changed spinbutton
|
127
|
+
value=spinbutton.value
|
128
|
+
puts "spin button modified #{value}"
|
129
|
+
@nb_nodes=value.to_i
|
130
|
+
@graph=Graph.random(value.to_i)
|
131
|
+
@canvas.running=true
|
132
|
+
@canvas.redraw @graph
|
133
|
+
end
|
134
|
+
|
135
|
+
def on_run_clicked button
|
136
|
+
puts 'button "run" clicked'
|
137
|
+
@canvas.running=true
|
138
|
+
@algorithm.stop=false
|
139
|
+
@algorithm.graph=@graph
|
140
|
+
@algorithm.run(iter=1000){@canvas.redraw @graph,@zoom_factor,@shift}
|
141
|
+
end
|
142
|
+
|
143
|
+
def on_stop_clicked button
|
144
|
+
puts 'button "stop" clicked'
|
145
|
+
@algorithm.stop=true
|
146
|
+
end
|
147
|
+
|
148
|
+
def on_step_clicked button
|
149
|
+
puts 'button "step" clicked'
|
150
|
+
@algorithm.run(iter=1){@canvas.redraw @graph,@zoom_factor,@shift}
|
151
|
+
end
|
152
|
+
|
153
|
+
def on_shuffle_clicked button
|
154
|
+
puts 'button "shuffle" clicked'
|
155
|
+
if @graph
|
156
|
+
@graph.shuffle
|
157
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def on_center_clicked button
|
162
|
+
puts 'button "center" clicked'
|
163
|
+
if @graph
|
164
|
+
compute_shift get_enclosing_rect
|
165
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def on_zoom_clicked button
|
170
|
+
puts 'button "zoom" clicked'
|
171
|
+
if @graph
|
172
|
+
@zoom_factor*=1.2
|
173
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def on_unzoom_clicked button
|
178
|
+
puts 'button "unzoom" clicked'
|
179
|
+
if @graph
|
180
|
+
@zoom_factor/=1.2
|
181
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def on_fit_clicked button
|
186
|
+
puts 'button "fit" clicked'
|
187
|
+
if @graph
|
188
|
+
compute_zoom_and_shift
|
189
|
+
@canvas.redraw @graph,@zoom_factor,@shift
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def get_enclosing_rect
|
194
|
+
min_x=@graph.nodes.min_by{|node| node.x}.x
|
195
|
+
min_y=@graph.nodes.min_by{|node| node.y}.y
|
196
|
+
max_x=@graph.nodes.max_by{|node| node.x}.x
|
197
|
+
max_y=@graph.nodes.max_by{|node| node.y}.y
|
198
|
+
[Vector.new(min_x,min_y),Vector.new(max_x,max_y)]
|
199
|
+
end
|
200
|
+
|
201
|
+
def compute_zoom_and_shift
|
202
|
+
enclosing_rect=get_enclosing_rect()
|
203
|
+
compute_zoom(enclosing_rect)
|
204
|
+
compute_shift(enclosing_rect)
|
205
|
+
end
|
206
|
+
|
207
|
+
def compute_zoom enclosing_rect
|
208
|
+
min_x=enclosing_rect.first.x
|
209
|
+
min_y=enclosing_rect.first.y
|
210
|
+
max_x=enclosing_rect.last.x
|
211
|
+
max_y=enclosing_rect.last.y
|
212
|
+
|
213
|
+
graph_size=[(max_x-min_x).abs,(max_y-min_y).abs]
|
214
|
+
canvas_size=[@canvas.allocation.width,@canvas.allocation.height]
|
215
|
+
ratios=[(canvas_size.first.to_f)/graph_size.first,(canvas_size.last.to_f)/graph_size.last]
|
216
|
+
@zoom_factor=ratios.min*0.8
|
217
|
+
puts "zoom=#{@zoom_factor}"
|
218
|
+
end
|
219
|
+
|
220
|
+
def compute_shift enclosing_rect
|
221
|
+
rect_center_x=(enclosing_rect.first.x+enclosing_rect.last.x)/2.0
|
222
|
+
rect_center_y=(enclosing_rect.first.y+enclosing_rect.last.y)/2.0
|
223
|
+
@shift=Vector.new(-rect_center_x,-rect_center_y)
|
224
|
+
end
|
225
|
+
|
226
|
+
def on_save_clicked button
|
227
|
+
puts 'button "save" clicked'
|
228
|
+
|
229
|
+
dialog=Gtk::FileChooserDialog.new(
|
230
|
+
:title => "choose",
|
231
|
+
:parent => self,
|
232
|
+
:action => Gtk::FileChooserAction::SAVE,
|
233
|
+
:buttons => [[Gtk::Stock::SAVE, Gtk::ResponseType::ACCEPT],
|
234
|
+
[Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
|
235
|
+
filter_sexp = Gtk::FileFilter.new
|
236
|
+
filter_sexp.name = "s-expr filter"
|
237
|
+
filter_sexp.add_pattern("*.sexp")
|
238
|
+
filter_sexp.add_pattern("*.sxp")
|
239
|
+
dialog.add_filter(filter_sexp)
|
240
|
+
|
241
|
+
dialog.show_all
|
242
|
+
|
243
|
+
case dialog.run
|
244
|
+
when Gtk::ResponseType::ACCEPT
|
245
|
+
puts "filename = #{dialog.filename}"
|
246
|
+
#puts "uri = #{dialog.uri}"
|
247
|
+
@graph.id=File.basename(dialog.filename,'.sexp')
|
248
|
+
@graph.write_file dialog.filename
|
249
|
+
dialog.destroy
|
250
|
+
else
|
251
|
+
dialog.destroy
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def on_quit_clicked button
|
256
|
+
puts "Closing application"
|
257
|
+
Gtk.main_quit
|
258
|
+
end
|
259
|
+
|
260
|
+
def set_destroy_callback
|
261
|
+
signal_connect("destroy"){Gtk.main_quit}
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
window=Viewer.new
|
267
|
+
Gtk.main
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rtl_circuit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.7.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Christophe Le Lann
|
@@ -17,10 +17,18 @@ extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
19
|
- lib/rtl.rb
|
20
|
+
- lib/rtl/canvas.rb
|
20
21
|
- lib/rtl/circuit.rb
|
21
22
|
- lib/rtl/code.rb
|
23
|
+
- lib/rtl/def_gates.svg
|
24
|
+
- lib/rtl/fdgd.rb
|
25
|
+
- lib/rtl/graph.rb
|
26
|
+
- lib/rtl/json_parser.rb
|
22
27
|
- lib/rtl/library.rb
|
28
|
+
- lib/rtl/placer.rb
|
23
29
|
- lib/rtl/printer.rb
|
30
|
+
- lib/rtl/vector.rb
|
31
|
+
- lib/rtl/viewer.rb
|
24
32
|
- tests/json/testing_json.rb
|
25
33
|
- tests/pnr/pnr_0.rb
|
26
34
|
- tests/pnr/pnr_1.rb
|