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 CHANGED
@@ -34,7 +34,7 @@ Jeweler::Tasks.new do |gem|
34
34
 
35
35
  gem.files.exclude 'kiss/**/*'
36
36
 
37
- gem.add_dependency 'teejayvanslyke-gazer'
37
+ gem.add_dependency 'rcapture'
38
38
  gem.add_dependency 'trollop'
39
39
 
40
40
  gem.add_development_dependency 'diff-lcs'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative '../lib/art-decomp'
5
+
6
+ file = ARGV.first
7
+ name = File.basename(file).gsub /[^a-z0-9]/, '_'
8
+ puts ArtDecomp::FSM.from_kiss(file).to_vhdl name
@@ -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'
@@ -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' if beta_v.ints.pairs.any? { |a, b| a & b != 0 }
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 restore!
39
- @g_colours = Marshal.load @backup[:g_colours]
40
- @g_forbidden = Marshal.load @backup[:g_forbidden]
41
- @qv_colours = Marshal.load @backup[:qv_colours]
42
- @qv_forbidden = Marshal.load @backup[:qv_forbidden]
43
- @g_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
44
- @qv_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
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 colour_g! g_vertex, colour
96
- return if @g_colours[g_vertex] == colour
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 colour_qv! qv_vertex, colour
105
- return if @qv_colours[qv_vertex] == colour
106
- raise PaintingError if @qv_colours[qv_vertex] and @qv_colours[qv_vertex] != colour
107
- raise PaintingError if @qv_forbidden[qv_vertex].include? colour
108
- @qv_colours[qv_vertex] = colour
109
- @qv_graph.adjacent(qv_vertex).each { |adjacent| forbid_qv! adjacent, colour }
110
- if @qv_colours.any? { |q, col| q != qv_vertex and col == colour }
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| eval "UVGenerator::#{gen}" }
47
- @qu_gens = opts[:qu].map { |gen| eval "QuGenerator::#{gen}" }
48
- @qv_gens = opts[:qv].map { |gen| eval "QvGenerator::#{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'
@@ -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
@@ -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
- @edges = Hash[vertices.map { |vertex| [vertex, Set[]] }]
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
- @edges[a] << b
11
- @edges[b] << a
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| @edges[vertex] }.inject(:|) - vertices
17
+ vertices.map { |vertex| @neighbours[vertex] }.inject(:|) - vertices
18
18
  end
19
19
 
20
20
  def blanket_from_colouring
21
21
  colours = {}
22
- @edges.keys.sort_by { |vert| [-degree(vert), vert] }.each do |vertex|
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
- @edges.values.map(&:size).inject(:+) == @edges.size * (@edges.size - 1)
35
+ @neighbours.values.map(&:size).inject(:+) == @neighbours.size * (@neighbours.size - 1)
36
36
  end
37
37
 
38
38
  def degree vertex
39
- @edges[vertex].size
39
+ @neighbours[vertex].size
40
40
  end
41
41
 
42
42
  def edges
43
- @edges.map { |v, adjacents| adjacents.map { |adj| Set[v, adj] } }.flatten.to_set
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 @edges.size == 1
48
- pins = @edges.size.log2_ceil
49
- until @edges.size.log2_ceil < pins
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 = @edges.size.log2_ceil
59
- until @edges.size.log2_ceil < pins or complete?
60
- a, b = *@edges.keys.sort_by { |v| -degree(v) }.pairs.find { |v1, v2| not @edges[v1].include? v2 }
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
- @edges.keys.to_set
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| @edges[adj] << new }
81
- @edges[new] = adjs
82
- @edges.delete(a).each { |adj| @edges[adj].delete a } unless a == new
83
- @edges.delete(b).each { |adj| @edges[adj].delete b } unless b == new
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
@@ -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 < Gazer::Aspect::Base
6
+ module ArtDecomp class Logging
7
7
 
8
- def self.level
9
- @@log.level
10
- end
8
+ class << self
11
9
 
12
- def self.level= level
13
- @@log.level = level
10
+ def level
11
+ @log.level
14
12
  end
15
13
 
16
- def self.log= log
17
- @@log = Logger.new log
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 self.off
26
- # FIXME: if instances can be unadvised, do that and close @@log
27
- @@log = Logger.new '/dev/null'
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
- after instances_of(Executable) => :run do |point|
31
- secs = (Time.now - @@start).to_i
32
- @@log.info "#{point.object.best ? "final best decomposition: #{point.object.best} cells" : 'no final decomposition'}; done in #{secs}s (#{secs / 60 / 60}h #{secs / 60 % 60}m #{secs % 60}s)"
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
- before instances_of(Executable) => :decompositions do |point|
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
- before instances_of(UVGenerator.constants.map { |c| eval("UVGenerator::#{c}") }) => :uv_pairs do |point|
43
- @@log.info "#{@@indent} UV with #{point.object.class.to_s.split('::').last}"
44
- end
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
- before instances_of(QuGenerator.constants.map { |c| eval("QuGenerator::#{c}") }) => :blankets do |point|
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
- before instances_of(QvGenerator.constants.map { |c| eval("QvGenerator::#{c}") }) => :blankets do |point|
51
- @@log.debug "#{@@indent} |Qu| = #{point.args[3].size}, Qv+G with #{point.object.class.to_s.split('::').last}"
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) << inputs[bit]
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