rtl_circuit 0.7 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|