art-decomp 0.3.0 → 0.4.0
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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/ad-kiss2vhdl +8 -0
- data/lib/art-decomp.rb +2 -0
- data/lib/art-decomp/bipainter.rb +36 -36
- data/lib/art-decomp/executable.rb +3 -3
- data/lib/art-decomp/fsm.rb +28 -3
- data/lib/art-decomp/graph.rb +19 -19
- data/lib/art-decomp/logging.rb +51 -34
- data/lib/art-decomp/uv_generator/braindead.rb +1 -2
- data/lib/art-decomp/vhdl.rb +72 -0
- data/spec/art-decomp/executable_spec.rb +2 -2
- data/spec/art-decomp/fsm_spec.rb +41 -0
- data/spec/art-decomp/logging_spec.rb +10 -24
- data/spec/art-decomp/vhdl_spec.rb +22 -0
- data/spec/fixtures/ex4.hot +44 -0
- data/spec/fixtures/ex4_hot.vhd +87 -0
- data/spec/fixtures/fsm.vhd +64 -0
- data/spec/fixtures/kirkman +374 -0
- data/spec/fixtures/mark1.hot +46 -0
- data/spec/fixtures/mark1.jed +48 -0
- data/spec/fixtures/mark1.nov +340 -0
- data/spec/fixtures/mark1.vhd +79 -0
- data/spec/fixtures/mark1.yml +86 -0
- data/spec/fixtures/mark1_hot.vhd +94 -0
- data/spec/fixtures/mark1_jed.vhd +94 -0
- data/spec/fixtures/mark1_nov.vhd +94 -0
- metadata +66 -30
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/bin/ad-kiss2vhdl
ADDED
data/lib/art-decomp.rb
CHANGED
@@ -37,6 +37,7 @@ end
|
|
37
37
|
|
38
38
|
|
39
39
|
require 'set'
|
40
|
+
require 'yaml'
|
40
41
|
|
41
42
|
require_relative 'core/enumerable'
|
42
43
|
require_relative 'core/file'
|
@@ -65,3 +66,4 @@ require_relative 'art-decomp/uv_relevance_generator'
|
|
65
66
|
require_relative 'art-decomp/uv_generator/braindead'
|
66
67
|
require_relative 'art-decomp/uv_generator/general_relevance'
|
67
68
|
require_relative 'art-decomp/uv_generator/unique_relevance'
|
69
|
+
require_relative 'art-decomp/vhdl'
|
data/lib/art-decomp/bipainter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module ArtDecomp class Bipainter
|
2
2
|
|
3
3
|
def initialize beta_q, beta_v, seps
|
4
|
-
raise 'non-disjoint beta_v'
|
4
|
+
raise 'non-disjoint beta_v' unless beta_v.ints.pairs.all? { |a, b| (a & b).zero? }
|
5
5
|
@beta_v = beta_v
|
6
6
|
@qv_colours = {}
|
7
7
|
@g_colours = {}
|
@@ -35,13 +35,13 @@ module ArtDecomp class Bipainter
|
|
35
35
|
@qv_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
36
36
|
end
|
37
37
|
|
38
|
-
def
|
39
|
-
|
40
|
-
@
|
41
|
-
|
42
|
-
@
|
43
|
-
@
|
44
|
-
|
38
|
+
def colour_g! g_vertex, colour
|
39
|
+
return if @g_colours[g_vertex] == colour
|
40
|
+
raise PaintingError if @g_colours[g_vertex] and @g_colours[g_vertex] != colour
|
41
|
+
raise PaintingError if @g_forbidden[g_vertex].include? colour
|
42
|
+
@g_colours[g_vertex] = colour
|
43
|
+
@g_graph.adjacent(g_vertex).each { |adjacent| forbid_g! adjacent, colour }
|
44
|
+
siblings_of(g_vertex).each { |sibling| colour_g! sibling, colour }
|
45
45
|
end
|
46
46
|
|
47
47
|
def colour_g_vertex! g_vertex
|
@@ -66,6 +66,25 @@ module ArtDecomp class Bipainter
|
|
66
66
|
colour_g_vertex! g_vertex if g_vertex
|
67
67
|
end
|
68
68
|
|
69
|
+
def colour_qv! qv_vertex, colour
|
70
|
+
return if @qv_colours[qv_vertex] == colour
|
71
|
+
raise PaintingError if @qv_colours[qv_vertex] and @qv_colours[qv_vertex] != colour
|
72
|
+
raise PaintingError if @qv_forbidden[qv_vertex].include? colour
|
73
|
+
@qv_colours[qv_vertex] = colour
|
74
|
+
@qv_graph.adjacent(qv_vertex).each { |adjacent| forbid_qv! adjacent, colour }
|
75
|
+
if @qv_colours.any? { |q, col| q != qv_vertex and col == colour }
|
76
|
+
@g_graph.vertices.select { |g| g & qv_vertex == g }.each do |g_vertex|
|
77
|
+
v_parent = @beta_v.ints.find { |v| v & g_vertex == g_vertex }
|
78
|
+
@g_graph.adjacent(g_vertex).select { |g| v_parent & g == g and qv_vertex & g != g }.each do |neighbour|
|
79
|
+
@qv_graph.vertices.select { |q| q & neighbour == neighbour }.each do |q_parent|
|
80
|
+
forbid_qv! q_parent, colour
|
81
|
+
end
|
82
|
+
end
|
83
|
+
siblings_of(g_vertex).each { |sibling| sync_colours g_vertex, sibling }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
69
88
|
def colour_qv_vertex! qv_vertex
|
70
89
|
begin
|
71
90
|
backup!
|
@@ -92,32 +111,17 @@ module ArtDecomp class Bipainter
|
|
92
111
|
@qv_forbidden[qv_vertex] << colour
|
93
112
|
end
|
94
113
|
|
95
|
-
def
|
96
|
-
|
97
|
-
raise PaintingError if @g_colours[g_vertex] and @g_colours[g_vertex] != colour
|
98
|
-
raise PaintingError if @g_forbidden[g_vertex].include? colour
|
99
|
-
@g_colours[g_vertex] = colour
|
100
|
-
@g_graph.adjacent(g_vertex).each { |adjacent| forbid_g! adjacent, colour }
|
101
|
-
siblings_of(g_vertex).each { |sibling| colour_g! sibling, colour }
|
114
|
+
def painted?
|
115
|
+
@qv_graph.vertices == @qv_colours.keys.to_set and @g_graph.vertices == @g_colours.keys.to_set
|
102
116
|
end
|
103
117
|
|
104
|
-
def
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
@
|
109
|
-
@
|
110
|
-
|
111
|
-
@g_graph.vertices.select { |g| g & qv_vertex == g }.each do |g_vertex|
|
112
|
-
v_parent = @beta_v.ints.find { |v| v & g_vertex == g_vertex }
|
113
|
-
@g_graph.adjacent(g_vertex).select { |g| v_parent & g == g and qv_vertex & g != g }.each do |neighbour|
|
114
|
-
@qv_graph.vertices.select { |q| q & neighbour == neighbour }.each do |q_parent|
|
115
|
-
forbid_qv! q_parent, colour
|
116
|
-
end
|
117
|
-
end
|
118
|
-
siblings_of(g_vertex).each { |sibling| sync_colours g_vertex, sibling }
|
119
|
-
end
|
120
|
-
end
|
118
|
+
def restore!
|
119
|
+
@g_colours = Marshal.load @backup[:g_colours]
|
120
|
+
@g_forbidden = Marshal.load @backup[:g_forbidden]
|
121
|
+
@qv_colours = Marshal.load @backup[:qv_colours]
|
122
|
+
@qv_forbidden = Marshal.load @backup[:qv_forbidden]
|
123
|
+
@g_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
124
|
+
@qv_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
121
125
|
end
|
122
126
|
|
123
127
|
def siblings_of g_vertex
|
@@ -135,8 +139,4 @@ module ArtDecomp class Bipainter
|
|
135
139
|
end
|
136
140
|
end
|
137
141
|
|
138
|
-
def painted?
|
139
|
-
@qv_graph.vertices == @qv_colours.keys.to_set and @g_graph.vertices == @g_colours.keys.to_set
|
140
|
-
end
|
141
|
-
|
142
142
|
end end
|
@@ -43,9 +43,9 @@ module ArtDecomp class Executable
|
|
43
43
|
@non_disjoint = opts[:non_disjoint]
|
44
44
|
@deep_ndj = opts[:deep_ndj]
|
45
45
|
|
46
|
-
@uv_gens = opts[:uv].map { |gen|
|
47
|
-
@qu_gens = opts[:qu].map { |gen|
|
48
|
-
@qv_gens = opts[:qv].map { |gen|
|
46
|
+
@uv_gens = opts[:uv].map { |gen| UVGenerator.const_get gen }
|
47
|
+
@qu_gens = opts[:qu].map { |gen| QuGenerator.const_get gen }
|
48
|
+
@qv_gens = opts[:qv].map { |gen| QvGenerator.const_get gen }
|
49
49
|
|
50
50
|
if opts[:log_given]
|
51
51
|
require_relative 'logging'
|
data/lib/art-decomp/fsm.rb
CHANGED
@@ -1,14 +1,27 @@
|
|
1
1
|
module ArtDecomp class FSM
|
2
2
|
|
3
|
+
attr_reader :codes
|
4
|
+
|
3
5
|
def self.from_kiss kiss
|
4
6
|
kiss = File.read kiss unless kiss.index "\n"
|
5
7
|
inputs, outputs, state, next_state = [], [], [], []
|
8
|
+
codes = Hash[kiss.lines.grep(/^\.code [^*]/).map(&:split).map { |_, state, code| [state.to_sym, code.to_sym] }]
|
9
|
+
codes = Hash[kiss.lines.grep(/^# States\./).map(&:split).map { |_, state, code| [state[7..-1].to_sym, code.to_sym] }] if codes.empty?
|
6
10
|
kiss.lines do |line|
|
7
11
|
case line
|
8
12
|
when /^\s*[01-]+\s+\S+\s+\S+\s+[01-]+\s*$/ then ins, st, nxt, outs = *line.split
|
9
13
|
when /^\s*[01-]+\s+[01-]+\s*$/ then st, nxt, ins, outs = DontCare, DontCare, *line.split
|
14
|
+
when /^\.end_kiss$/ then break
|
10
15
|
else next
|
11
16
|
end
|
17
|
+
next if [DontCare, '*'].include? nxt and outs =~ /^-*$/
|
18
|
+
if line =~ /^[01-]+\s+[01-]+$/ and not codes.empty?
|
19
|
+
size = codes.values.first.size
|
20
|
+
st = ins[-size..-1] == '-' * size ? DontCare : codes.invert[ins[-size..-1].to_sym]
|
21
|
+
nxt = outs[0...size] == '-' * size ? DontCare : codes.invert[outs[0...size].to_sym]
|
22
|
+
ins = ins[0...-size]
|
23
|
+
outs = outs[size..-1]
|
24
|
+
end
|
12
25
|
inputs << ins.split(//).map(&:to_sym)
|
13
26
|
outputs << outs.split(//).map(&:to_sym)
|
14
27
|
state << (st == '*' ? DontCare : st.to_sym)
|
@@ -22,11 +35,11 @@ module ArtDecomp class FSM
|
|
22
35
|
inputs << inputs[i]
|
23
36
|
outputs << outputs[i]
|
24
37
|
end if state.index DontCare
|
25
|
-
new inputs.transpose, outputs.transpose, state, next_state
|
38
|
+
new inputs.transpose, outputs.transpose, state, next_state, codes
|
26
39
|
end
|
27
40
|
|
28
|
-
def initialize inputs, outputs, state, next_state
|
29
|
-
@inputs, @outputs, @state, @next_state = inputs.freeze, outputs.freeze, state.freeze, next_state.freeze
|
41
|
+
def initialize inputs, outputs, state, next_state, codes = {}
|
42
|
+
@inputs, @outputs, @state, @next_state, @codes = inputs.freeze, outputs.freeze, state.freeze, next_state.freeze, codes.freeze
|
30
43
|
end
|
31
44
|
|
32
45
|
def == other
|
@@ -99,6 +112,14 @@ module ArtDecomp class FSM
|
|
99
112
|
"#{@inputs.size}/#{@outputs.size}+#{(@state.uniq - [DontCare]).size}s"
|
100
113
|
end
|
101
114
|
|
115
|
+
def structure
|
116
|
+
structure = Hash.new { |state, input| state[input] = {} }
|
117
|
+
@state.each_index do |row|
|
118
|
+
structure[@state[row]][@inputs.transpose[row].join] = {:next_state => @next_state[row], :output => @outputs.transpose[row].join}
|
119
|
+
end
|
120
|
+
structure
|
121
|
+
end
|
122
|
+
|
102
123
|
def to_kiss
|
103
124
|
st = @state.map { |e| e == DontCare ? '*' : e }
|
104
125
|
nxt = @next_state.map { |e| e == DontCare ? '*' : e }
|
@@ -108,6 +129,10 @@ module ArtDecomp class FSM
|
|
108
129
|
KISS.new(cols.transpose.map(&:join)).formatted
|
109
130
|
end
|
110
131
|
|
132
|
+
def to_vhdl name
|
133
|
+
VHDL.new(self).vhdl name
|
134
|
+
end
|
135
|
+
|
111
136
|
def truth_table?
|
112
137
|
@state.all? { |s| s == DontCare } and @next_state.all? { |ns| ns == DontCare }
|
113
138
|
end
|
data/lib/art-decomp/graph.rb
CHANGED
@@ -3,23 +3,23 @@ module ArtDecomp class Graph
|
|
3
3
|
def initialize blanket, seps
|
4
4
|
vertices = blanket.ints.dup
|
5
5
|
vertices.delete_if { |this| vertices.any? { |other| other != this and other & this == this } }
|
6
|
-
@
|
6
|
+
@neighbours = Hash[vertices.map { |vertex| [vertex, Set[]] }]
|
7
7
|
relevant = Hash[vertices.map { |v| [v, seps.select { |s| v&s != 0 and v&s != s }.to_set] }]
|
8
8
|
vertices.pairs.each do |a, b|
|
9
9
|
if (relevant[a] & relevant[b]).any? { |s| a&s != b&s }
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@neighbours[a] << b
|
11
|
+
@neighbours[b] << a
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
def adjacent *vertices
|
17
|
-
vertices.map { |vertex| @
|
17
|
+
vertices.map { |vertex| @neighbours[vertex] }.inject(:|) - vertices
|
18
18
|
end
|
19
19
|
|
20
20
|
def blanket_from_colouring
|
21
21
|
colours = {}
|
22
|
-
@
|
22
|
+
@neighbours.keys.sort_by { |vert| [-degree(vert), vert] }.each do |vertex|
|
23
23
|
forbidden = adjacent(vertex).map { |vert| colours[vert] }.to_set
|
24
24
|
# FIXME: consider selecting colours on the least-popular-first basis
|
25
25
|
colour = :a
|
@@ -32,21 +32,21 @@ module ArtDecomp class Graph
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def complete?
|
35
|
-
@
|
35
|
+
@neighbours.values.map(&:size).inject(:+) == @neighbours.size * (@neighbours.size - 1)
|
36
36
|
end
|
37
37
|
|
38
38
|
def degree vertex
|
39
|
-
@
|
39
|
+
@neighbours[vertex].size
|
40
40
|
end
|
41
41
|
|
42
42
|
def edges
|
43
|
-
@
|
43
|
+
@neighbours.map { |v, adjacents| adjacents.map { |adj| Set[v, adj] } }.flatten.to_set
|
44
44
|
end
|
45
45
|
|
46
46
|
def merge_by_edge_labels!
|
47
|
-
return self if @
|
48
|
-
pins = @
|
49
|
-
until @
|
47
|
+
return self if @neighbours.size == 1
|
48
|
+
pins = @neighbours.size.log2_ceil
|
49
|
+
until @neighbours.size.log2_ceil < pins
|
50
50
|
# FIXME: edge labels can/should be cached from previous computations
|
51
51
|
a, b = *edges.sort_by { |edge| yield *edge }.first
|
52
52
|
merge! a, b
|
@@ -55,9 +55,9 @@ module ArtDecomp class Graph
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def merge_by_vertex_degrees!
|
58
|
-
pins = @
|
59
|
-
until @
|
60
|
-
a, b = *@
|
58
|
+
pins = @neighbours.size.log2_ceil
|
59
|
+
until @neighbours.size.log2_ceil < pins or complete?
|
60
|
+
a, b = *@neighbours.keys.sort_by { |v| -degree(v) }.pairs.find { |v1, v2| not @neighbours[v1].include? v2 }
|
61
61
|
merge! a, b
|
62
62
|
end
|
63
63
|
self
|
@@ -69,7 +69,7 @@ module ArtDecomp class Graph
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def vertices
|
72
|
-
@
|
72
|
+
@neighbours.keys.to_set
|
73
73
|
end
|
74
74
|
|
75
75
|
private
|
@@ -77,10 +77,10 @@ module ArtDecomp class Graph
|
|
77
77
|
def merge! a, b
|
78
78
|
new = a | b
|
79
79
|
adjs = adjacent(a) | adjacent(b)
|
80
|
-
adjs.each { |adj| @
|
81
|
-
@
|
82
|
-
@
|
83
|
-
@
|
80
|
+
adjs.each { |adj| @neighbours[adj] << new }
|
81
|
+
@neighbours[new] = adjs
|
82
|
+
@neighbours.delete(a).each { |adj| @neighbours[adj].delete a } unless a == new
|
83
|
+
@neighbours.delete(b).each { |adj| @neighbours[adj].delete b } unless b == new
|
84
84
|
end
|
85
85
|
|
86
86
|
end end
|
data/lib/art-decomp/logging.rb
CHANGED
@@ -1,54 +1,71 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require 'gazer'
|
4
3
|
require 'logger'
|
4
|
+
require 'rcapture'
|
5
5
|
|
6
|
-
module ArtDecomp class Logging
|
6
|
+
module ArtDecomp class Logging
|
7
7
|
|
8
|
-
|
9
|
-
@@log.level
|
10
|
-
end
|
8
|
+
class << self
|
11
9
|
|
12
|
-
def
|
13
|
-
|
10
|
+
def level
|
11
|
+
@log.level
|
14
12
|
end
|
15
13
|
|
16
|
-
def
|
17
|
-
|
18
|
-
@@log.level = Logger::INFO
|
19
|
-
@@log.formatter = proc { |sev, date, name, msg| "#{date} #{msg}\n" }
|
20
|
-
@@indent = ''
|
21
|
-
apply!
|
22
|
-
@@start = Time.now
|
14
|
+
def level= level
|
15
|
+
@log.level = level
|
23
16
|
end
|
24
17
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
18
|
+
def log= log
|
19
|
+
@start = Time.now
|
20
|
+
@log = Logger.new log
|
21
|
+
@log.level = Logger::INFO
|
22
|
+
@log.formatter = proc do |sev, date, name, msg|
|
23
|
+
secs = (Time.now - @start).ceil
|
24
|
+
time = "#{secs / 60 / 60}h#{(secs / 60 % 60).to_s.rjust 2}m#{(secs % 60).to_s.rjust 2}s"
|
25
|
+
best = @best.nil? ? '' : @best.to_s + 'c'
|
26
|
+
path = @path.nil? ? '' : '/' + @path
|
27
|
+
"#{time.rjust 10} #{best.rjust 4} ·#{path.ljust 10} #{msg}\n"
|
28
|
+
end
|
29
|
+
add_logging
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
def off
|
33
|
+
# FIXME: if methods can be uncaptured, do that and close @log
|
34
|
+
@log = Logger.new '/dev/null'
|
33
35
|
end
|
34
36
|
|
35
|
-
|
36
|
-
@@indent = ' ' * (point.object.iters - point.args[1])
|
37
|
-
path = point.args[2][point.object.dir.size+1..-1]
|
38
|
-
archs = point.object.archs.map(&:to_s).sort.reverse.join '+'
|
39
|
-
@@log.info "#{@@indent}FSM #{point.args[0].stats} → #{archs} (#{path}) with #{point.object.gens} – #{point.object.best ? "best so far: #{point.object.best} cells" : 'no decomposition so far'}"
|
40
|
-
end
|
37
|
+
private
|
41
38
|
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
def add_logging
|
40
|
+
uv_gens = UVGenerator.constants.map { |c| UVGenerator.const_get c }
|
41
|
+
qu_gens = QuGenerator.constants.map { |c| QuGenerator.const_get c }
|
45
42
|
|
46
|
-
|
47
|
-
@@log.info "#{@@indent} U = #{point.args[1].sort.inspect}, V = #{point.args[2].sort.inspect}, Qu with #{point.object.class.to_s.split('::').last}"
|
48
|
-
end
|
43
|
+
(uv_gens + qu_gens + [Executable]).each { |c| c.class_eval { include RCapture::Interceptable } }
|
49
44
|
|
50
|
-
|
51
|
-
|
45
|
+
Executable.capture_pre :methods => :decompositions do |point|
|
46
|
+
@best = point.sender.best
|
47
|
+
@path = point.args[2][point.sender.dir.size+1..-1]
|
48
|
+
@log.info "#{point.args[0].stats} with #{point.sender.gens}"
|
49
|
+
end
|
50
|
+
|
51
|
+
uv_gens.each do |uv_gen|
|
52
|
+
uv_gen.capture_pre :methods => :uv_pairs do |point|
|
53
|
+
@uv_gen = uv_gen.to_s.split('::').last
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
qu_gens.each do |qu_gen|
|
58
|
+
qu_gen.capture_pre :methods => :blankets do |point|
|
59
|
+
@log.debug "#{point.args[1].sort.join(' ').ljust 10} #{point.args[2].sort.join(' ').ljust 10} via #{@uv_gen} with #{qu_gen.to_s.split('::').last}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Executable.capture_post :methods => :run do |point|
|
64
|
+
@best = point.sender.best
|
65
|
+
@log.info "took #{(Time.now - @start).ceil}s"
|
66
|
+
end
|
52
67
|
end
|
53
68
|
|
69
|
+
end
|
70
|
+
|
54
71
|
end end
|
@@ -2,13 +2,12 @@ module ArtDecomp class UVGenerator::Braindead
|
|
2
2
|
|
3
3
|
def uv_pairs fsm, archs
|
4
4
|
input_count = fsm.input_count
|
5
|
-
inputs = (0...input_count).to_a
|
6
5
|
max_v_size = archs.map(&:pins).max
|
7
6
|
Enumerator.new do |yielder|
|
8
7
|
(0...2**input_count).each do |vector|
|
9
8
|
u, v = Set[], Set[]
|
10
9
|
input_count.times do |bit|
|
11
|
-
(vector[bit].zero? ? u : v) <<
|
10
|
+
(vector[bit].zero? ? u : v) << bit
|
12
11
|
end
|
13
12
|
yielder.yield fsm.expand_x(v), u, v if v.size <= max_v_size
|
14
13
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ArtDecomp class VHDL
|
2
|
+
|
3
|
+
def initialize fsm
|
4
|
+
@fsm = fsm
|
5
|
+
end
|
6
|
+
|
7
|
+
def vhdl name
|
8
|
+
structure = @fsm.structure
|
9
|
+
logic = structure[DontCare].map do |input, results|
|
10
|
+
results[:next_state] = "s#{results[:next_state]}".to_sym if results[:next_state] =~ /^\d+$/
|
11
|
+
[
|
12
|
+
" if std_match(input, \"#{input}\") then next_state <= #{results[:next_state]}; output <= \"#{results[:output]}\";",
|
13
|
+
' else',
|
14
|
+
]
|
15
|
+
end
|
16
|
+
structure.delete DontCare
|
17
|
+
logic << ' case current_state is'
|
18
|
+
logic += structure.map do |state, transitions|
|
19
|
+
state = "s#{state}".to_sym if state =~ /^\d+$/
|
20
|
+
[
|
21
|
+
" when #{state} =>",
|
22
|
+
transitions.map.with_index do |(input, results), i|
|
23
|
+
results[:next_state] = "s#{results[:next_state]}".to_sym if results[:next_state] =~ /^\d+$/
|
24
|
+
" #{'els' if i > 0}if std_match(input, \"#{input}\") then next_state <= #{results[:next_state]}; output <= \"#{results[:output]}\";"
|
25
|
+
end,
|
26
|
+
' end if;',
|
27
|
+
]
|
28
|
+
end
|
29
|
+
logic << " when others => next_state <= \"#{'-' * @fsm.codes.values.first.size}\"; output <= \"#{'-' * structure.first.last.first.last[:output].size}\";" unless @fsm.codes.empty?
|
30
|
+
logic << ' end case;'
|
31
|
+
logic << ' end if;' if logic.flatten.include? ' else'
|
32
|
+
if @fsm.codes.empty?
|
33
|
+
states = [
|
34
|
+
" type state is (#{structure.keys.join ', '});",
|
35
|
+
' signal current_state, next_state: state;',
|
36
|
+
]
|
37
|
+
default_state = structure.keys.first
|
38
|
+
else
|
39
|
+
states = @fsm.codes.map do |state, code|
|
40
|
+
state = "s#{state}".to_sym if state =~ /^\d+$/
|
41
|
+
" constant #{state}: std_logic_vector(#{code.size - 1} downto 0) := \"#{code}\";"
|
42
|
+
end
|
43
|
+
states << " signal current_state, next_state: std_logic_vector(#{@fsm.codes.first.last.size - 1} downto 0);"
|
44
|
+
default_state = "\"#{'-' * @fsm.codes.values.first.size}\""
|
45
|
+
end
|
46
|
+
<<-VHDL
|
47
|
+
library ieee;
|
48
|
+
use ieee.numeric_std.all;
|
49
|
+
use ieee.std_logic_1164.all;
|
50
|
+
entity #{name} is
|
51
|
+
port(
|
52
|
+
clock: in std_logic;
|
53
|
+
input: in std_logic_vector(#{structure.first.last.first.first.size - 1} downto 0);
|
54
|
+
output: out std_logic_vector(#{structure.first.last.first.last[:output].size - 1} downto 0)
|
55
|
+
);
|
56
|
+
end #{name};
|
57
|
+
architecture behaviour of #{name} is
|
58
|
+
#{states.join "\n"}
|
59
|
+
begin
|
60
|
+
process(clock) begin
|
61
|
+
if rising_edge(clock) then current_state <= next_state;
|
62
|
+
end if;
|
63
|
+
end process;
|
64
|
+
process(input, current_state) begin
|
65
|
+
next_state <= #{default_state}; output <= "#{'-' * structure.first.last.first.last[:output].size}";
|
66
|
+
#{logic.join "\n"}
|
67
|
+
end process;
|
68
|
+
end behaviour;
|
69
|
+
VHDL
|
70
|
+
end
|
71
|
+
|
72
|
+
end end
|