Module: ABC

Defined in:
ext/ruby_abc.c,
lib/ruby_abc.rb,
ext/ruby_abc.c

Overview

ABC module wrapps the command line interface of the Berkeley abc program. abc is a system for sequential synthesis and verification, developped at the University of California, Berkeley. Documentation on ABC can be found at [people.eecs.berkeley.edu/~alanmi/abc/](https://people.eecs.berkeley.edu/~alanmi/abc/)

The abc program is a command line interface: the user issue commands and adjust them according to the results he gets back. In order to automate this process, the ABC module allows to retreive some information on the logic network in ruby, such as the number of nodes or its logic level. The command adjustment can then be done in ruby instead of manually.

abc commands are issued with the ABC::run_command module method, thus the abc documentation is not covered in this API documentation. However, available commands can be retreived with ABC::run_command(‘help’), and the documentation of a given command can be retreived with ABC::run_command(‘command_name -h’).

Constant Summary collapse

VERSION =
'0.0.3'

Class Method Summary collapse

Class Method Details

.echo_commandsObject

echo_commands -> true or false

Return if each command received is echoed back.

ABC.echo_commands #=> true


159
160
161
162
163
164
# File 'ext/ruby_abc.c', line 159

static VALUE rubyabc_get_echo_commands(VALUE self)
{
  if (rubyabc_echo_commands)
    return Qtrue;
  return Qfalse;
}

.echo_commands=(b) ⇒ Object

echo_commands= (boolean)

Set whether each command is echoed or not.

ABC.echo_commands = false


174
175
176
177
178
179
180
181
182
183
184
# File 'ext/ruby_abc.c', line 174

static VALUE rubyabc_set_echo_commands(VALUE self, VALUE b)
{
  if (b == Qtrue)
    rubyabc_echo_commands = 1;
  else if (b == Qfalse || b == Qnil)
    rubyabc_echo_commands = 0;
  else
    rb_raise(rb_eTypeError, "expecting true or false");

  return Qnil;
}

.map(k, optimize_area = false) ⇒ Object

call-seq: map (lut_size, optimize_for_area = false) -> nb_nodes

Map the logic network to nodes with at most lut_size inputs. If optimize_for_area is true, minimize the number of nodes instead of minimizing the logic level of the network.

This method loops the command:

"choice; if -K #{lut_size}#{optimize_for_area ? ' -a':''}; ps"

and stops when the number of nodes stop decreasing.

ABC.map(4)


86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/ruby_abc.rb', line 86

def self.map (k, optimize_area = false)
  map_cmd = "choice; if -K #{k}#{optimize_area ? ' -a':''}; ps"

  n_nodes = -1
  loop do
    ABC::run_command(map_cmd)
    new_n_nodes = ABC::nb_nodes
    break if new_n_nodes >= n_nodes and n_nodes > 0
    n_nodes = new_n_nodes
  end
  return ABC::nb_nodes
end

.method_missing(name, *args) ⇒ Object

call-seq: method_missing(method, *args)

The method_missing method is implemented so that commands can be issued to abc without using ABC::run_command. Methods arguments are concatenated as strings to the command.

ABC.read '-m', filename
# equivalent to
ABC.run_command "read -m #{filename}"


111
112
113
114
115
# File 'lib/ruby_abc.rb', line 111

def self.method_missing (name, *args)
  cmd = name.to_s
  cmd += ' ' + args.join(' ') if args
  ABC::run_command cmd
end

.nb_andsObject

nb_ands -> integer or nil

Return the number of AND gate in the network. If no network have been loaded or the then network is not in AIG form, return nil.

ABC.nb_ands #=> 264


16
17
18
19
20
21
22
23
24
# File 'ext/ruby_abc.c', line 16

static VALUE rubyabc_n_ands(VALUE self)
{
  int res = rubyabc_c_n_ands();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.nb_latchesObject

nb_latches -> integer or nil

Return the number of latches in the network. If no network have been loaded, return nil.

ABC.nb_latches #=> 17


92
93
94
95
96
97
98
99
100
# File 'ext/ruby_abc.c', line 92

static VALUE rubyabc_n_latches(VALUE self)
{
  int res = rubyabc_c_n_latches();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.nb_levelsObject

nb_levels -> integer or nil

Return the number of logic levels. This is the number of combinatorial logic between two latches or primary input/output. If no network have been loaded, return nil.

ABC.nb_latches #=> 8


113
114
115
116
117
118
119
120
121
# File 'ext/ruby_abc.c', line 113

static VALUE rubyabc_n_levels(VALUE self)
{
  int res = rubyabc_c_n_levels();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.nb_nodesObject

nb_nodes -> integer or nil

Return the number combinatorial logic nodes in the network. If no network have been loaded or the then network is in AIG form, return nil.

ABC.nb_nodes #=> 114


35
36
37
38
39
40
41
42
43
# File 'ext/ruby_abc.c', line 35

static VALUE rubyabc_n_nodes(VALUE self)
{
  int res = rubyabc_c_n_nodes();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.nb_primary_inputsObject

nb_primary_inputs -> integer or nil

Return the number of primary inputs of the network. If no network have been loaded, return nil.

ABC.nb_primary_inputs #=> 7


54
55
56
57
58
59
60
61
62
# File 'ext/ruby_abc.c', line 54

static VALUE rubyabc_n_pis(VALUE self)
{
  int res = rubyabc_c_n_pis();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.nb_primary_outputsObject

nb_primary_outputs -> integer or nil

Return the number of primary outputs of the network. If no network have been loaded, return nil.

ABC.nb_primary_outputs #=> 6


73
74
75
76
77
78
79
80
81
# File 'ext/ruby_abc.c', line 73

static VALUE rubyabc_n_pos(VALUE self)
{
  int res = rubyabc_c_n_pos();

  if (res < 0)
    return Qnil;

  return INT2NUM(res);
}

.optimizeObject

call-seq: optimize -> nb_ands

Combinatorial synthesis of the network. This method loops the command “resyn; resyn2, resyn3, print_stats” and stops when the number of AND gates stop decreasing. At the end, the logic network is in AIG form.

“Fast and efficient synthesis is achieved by DAG-aware rewriting of the AIG. i Rewriting is performed using a library of pre-computed four-input AIGs (command rewrite; standard alias rw), or collapsing and refactoring of logic cones with 10-20 inputs (command refactor; standard alias rf). It can be experimentally shown that iterating these two transformations and interleaving them with AIG balancing (command balance; standard alias b) substantially reduces the AIG size and tends to reduce the number of AIG levels.”

ABC.optimize


61
62
63
64
65
66
67
68
69
70
# File 'lib/ruby_abc.rb', line 61

def self.optimize
  n_ands = ABC::nb_ands
  loop do
    ABC::run_command('resyn; resyn2; resyn3; ps')
    new_n_ands = ABC::nb_ands
    break unless new_n_ands < n_ands
    n_ands = new_n_ands
  end 
  return ABC::nb_ands
end

call-seq: print_stats

Print out network statistics.

ABC.print_stats
# Inputs: ..... 7
# Outputs: .... 6
# Nodes: .... 114
# Latches: ... 17
# Levels: .... 18
#=> nil


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/ruby_abc.rb', line 23

def self.print_stats
  n_pis     = ABC::nb_primary_inputs
  n_pos     = ABC::nb_primary_outputs
  n_nodes   = ABC::nb_nodes
  n_latches = ABC::nb_latches
  n_levels  = ABC::nb_levels
  n_ands    = ABC::nb_ands

  arr = [n_pis, n_pos, n_nodes, n_latches, n_levels, n_ands].reject{|v| v.nil?}
  return nil if arr.empty?
  max_len = arr.collect{|v| v.to_s.length}.max + 1

  puts "Inputs: ...#{(' ' + n_pis.to_s).rjust(max_len, '.')}"     if n_pis
  puts "Outputs: ..#{(' ' + n_pos.to_s).rjust(max_len, '.')}"     if n_pos
  puts "Nodes: ....#{(' ' + n_nodes.to_s).rjust(max_len, '.')}"   if n_nodes
  puts "Latches: ..#{(' ' + n_latches.to_s).rjust(max_len, '.')}" if n_latches
  puts "Levels: ...#{(' ' + n_levels.to_s).rjust(max_len, '.')}"  if n_levels
  puts "And gates: #{(' ' + n_ands.to_s).rjust(max_len, '.')}"    if n_ands
  return nil
end

.run_command(cmd) ⇒ Object

run_command (string)

Run the command string in ABC.

If ABC::echo_commands has been set to true, string will be echoed on STDOUT before it is given to abc.

ABC.run_command 'read netlist.blif; strash; resyn; if -K 4; write out.blif'
# To see available ABC commands:
ABC.run_command 'help'

# To get help on a particular command, use `-h' after the command name:
ABC.run_command 'csweep -h'


138
139
140
141
142
143
144
145
146
147
148
149
# File 'ext/ruby_abc.c', line 138

static VALUE rubyabc_run_command(VALUE self, VALUE cmd)
{
  Check_Type(cmd, T_STRING);

  if (rubyabc_echo_commands)
    rb_io_puts(1, &cmd, rb_stdout);

  if (rubyabc_c_run_command(StringValueCStr(cmd)))
    return Qfalse;

  return Qtrue;
}

.synthesis(input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, help: nil) ⇒ Object

call-seq: synthesis (input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, help: nil)

This method is an atempt to automate the logic synthesis process (combinatorial and sequential) according to some parameters.

Keyword parameters are:

  • input: (string) Input netilist file name

  • output: (string) Output netlist file name

  • zero: (boolean) Set latches initial value to zero (netlist functionality is keept by adding inverters around latches with initial value 1)

  • sweep: (boolean) Sweep logic network to remove dangling nodes

  • retime: (boolean) Retime the netlist (reduce logic level, but increase the number of latches)

  • lcorr: (boolean) Computes latch correspondence using 1-step induction

  • area: (boolean) Optimize for area (minimize number of nodes) instead of speed (minimize number of logic levels)

  • lut_map: (integer) Map the netlist to K-input LUTs. Optimize for area if area: == true

ABC.synthesis(input: 'generic.blif', output: 'maped.blif', lcorr: true, lut_map: 4, area: true)


136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/ruby_abc.rb', line 136

def self.synthesis(input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, help: nil)
  if help then
    puts "ABC::synthesis keyword arguments:\ninput:   (string)  Input netilist file name\noutput:  (string)  Output netlist file name\nzero:    (boolean) Set latches initial value to zero (netlist functionality is keept by adding inverters around latches with initial value 1)\nsweep:   (boolean) Sweep logic network to remove dangling nodes\nretime:  (boolean) Retime the netlist (reduce logic level, but increase the number of latches)\nlcorr:   (boolean) Computes latch correspondence using 1-step induction\narea:    (boolean) Optimize for area (minimize number of nodes) instead of speed (minimize number of logic levels)\nlut_map: (integer) Map the netlist to K-input LUTs. Optimize for area if area: == true\n"
    return
  end

  if input then
    raise "Expecting a string for :input argument" unless input.kind_of?(String)
    ABC::read input
  end

  puts "---- Input netlist ----"
  ABC::print_stats
  puts "-----------------------"

  ABC::ps

  if sweep then
    ABC::sweep
    ABC::ps
  end

  if zero and ABC::nb_latches > 0 then
    ABC::run_command 'strash; zero; ps'
  else
    ABC::run_command 'strash; ps'
  end

  ABC::lcorr if (lcorr and ABC::nb_latches > 0)

  if sweep then
    ABC::ssweep
    ABC::csweep
    ABC::ps
  end

  ABC::optimize

  if retime and ABC::nb_latches > 0 then
    level = ABC::nb_levels
    ABC::run_command('retime; strash; ps')
    if ABC::nb_levels >= level then
      ABC::run_command('dretime; strash; ps')
    end
    ABC::optimize
  end

  ABC::zero if zero

  if lut_map then
    raise "Expecting a strictly positive integer for argument :lut_map" unless (lut_map.kind_of?(Integer) and lut_map > 0)
    ABC::map(lut_map, not(not(area)))
  end

  if sweep then
    ABC::run_command 'sop; sweep; resyn; resyn2; resyn3; scleanup; resyn; scleanup; scleanup; scleanup; strash; ssweep; csweep; ps'
    ABC::optimize
    if lut_map then
      raise "Expecting a strictly positive integer for argument :lut_map" unless (lut_map.kind_of?(Integer) and lut_map > 0)
      ABC::map(lut_map, not(not(area)))
    end
  end

  if (lcorr and ABC::nb_latches > 0) then
    ABC::run_command 'strash; lcorr'
    if lut_map then
      raise "Expecting a strictly positive integer for argument :lut_map" unless (lut_map.kind_of?(Integer) and lut_map > 0)
      ABC::map(lut_map, not(not(area)))
    end
  end

  puts "---- output netlist ----"
  ABC::print_stats
  puts "------------------------"

  if output then
    raise "Expecting a string for :output argument" unless output.kind_of?(String)
    puts "Writing output netlist to file \"#{output}\""
    if input then
      ABC.write_hie input, output
    else
      ABC.write output
    end
  end
end