Module: ABC

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

Overview

This 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 http://people.eecs.berkeley.edu/~alanmi/abc/

The ABC program is a command line interface: the user issues 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 run_command module function, 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 withABC.run_command('command_name -h')`.

Constant Summary collapse

VERSION =

This gem version

'0.1.0'

Class Method Summary collapse

Class Method Details

.echo_commandsBoolean

Return if each command sent to ABC is to be echoed back.

Returns:

  • (Boolean)


136
137
138
139
140
141
# File 'ext/ruby_abc/ruby_abc.c', line 136

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

.echo_commands=(b) ⇒ Object

Set whether each command sent to ABC is to be echoed back or not.

Parameters:

  • b (Boolean)

Returns:

  • b



148
149
150
151
152
153
154
155
156
# File 'ext/ruby_abc/ruby_abc.c', line 148

static VALUE rubyabc_set_echo_commands(VALUE self, VALUE b)
{
	if (b == Qfalse || b == Qnil)
		rubyabc_echo_commands = 0;
	else
		rubyabc_echo_commands = 1;

	return Qnil;
}

.map(k, area: false, verbose: true) ⇒ Integer

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

This method loops the command: choice2; if -K #{lut_size}#{optimize_for_area ? ' -a' : ''}; ps and stops when the number of nodes stop decreasing.

Examples:

ABC.map(4)

Parameters:

  • area (Boolean) (defaults to: false)

    minimize area instead delay

  • verbose (Boolean) (defaults to: true)

Returns:

  • (Integer)

    number of AIG



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/ruby_abc.rb', line 87

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

  min_n_nodes = Float::INFINITY
  loop do
    ABC::run_command(map_cmd)
    n_nodes = ABC::nb_nodes
    break if n_nodes >= min_n_nodes
    min_n_nodes = [min_n_nodes, n_nodes].min
  end
  if ABC::nb_nodes > min_n_nodes then
    5.times do
      ABC::run_command(map_cmd)
      break if ABC::nb_nodes <= min_n_nodes
    end
  end
  return ABC::nb_nodes
end

.method_missing(name, *args) ⇒ Object

Send missing methods to ABC as commands.

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.

Examples:

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


116
117
118
119
120
# File 'lib/ruby_abc.rb', line 116

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

.nb_andsInteger?

Returns the number of AND-inverter gates in the network. If no network have been loaded or the then network is not in AIG form, returns nil.

Returns:

  • (Integer, nil)


12
13
14
15
16
17
18
19
20
# File 'ext/ruby_abc/ruby_abc.c', line 12

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.nb_latchesInteger?

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

Returns:

  • (Integer, nil)


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

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.nb_levelsInteger?

Returns 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.

Returns:

  • (Integer, nil)


89
90
91
92
93
94
95
96
97
# File 'ext/ruby_abc/ruby_abc.c', line 89

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.nb_nodesInteger?

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

Returns:

  • (Integer, nil)


27
28
29
30
31
32
33
34
35
# File 'ext/ruby_abc/ruby_abc.c', line 27

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.nb_primary_inputsInteger?

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

Returns:

  • (Integer, nil)


42
43
44
45
46
47
48
49
50
# File 'ext/ruby_abc/ruby_abc.c', line 42

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.nb_primary_outputsInteger?

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

Returns:

  • (Integer, nil)


57
58
59
60
61
62
63
64
65
# File 'ext/ruby_abc/ruby_abc.c', line 57

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

	if (res < 0)
		return Qnil;

	return INT2NUM(res);
}

.optimize(verbose: true) ⇒ Integer

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. 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."

Examples:

ABC.optimize

Parameters:

  • verbose (Boolean) (defaults to: true)

Returns:

  • (Integer)

    number of AIG



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ruby_abc.rb', line 56

def self.optimize(verbose: true)
  cmd = 'resyn; resyn2; resyn3' + (verbose ? '; ps' : '')
  min_n_ands = Float::INFINITY
  loop do
    ABC::run_command(cmd)
    n_ands = ABC::nb_ands
    break if n_ands >= min_n_ands
    min_n_ands = [min_n_ands, n_ands].min
  end 
  if ABC::nb_ands > min_n_ands then
    5.times do
      ABC::run_command(cmd)
      break if ABC::nb_ands <= min_n_ands
    end
  end
  return ABC::nb_ands
end

Print out network statistics.

Examples:

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

Returns:

  • (nil)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/ruby_abc.rb', line 18

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 "And gates: #{(' ' + n_ands.to_s).rjust(max_len, '.')}"    if n_ands
  puts "Levels: ...#{(' ' + n_levels.to_s).rjust(max_len, '.')}"  if n_levels
  return nil
end

.run_command(cmd) ⇒ Boolean

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.

Examples:

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'

Parameters:

  • cmd (String)

Returns:

  • (Boolean)

    true if the command succeeded, false otherwise.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'ext/ruby_abc/ruby_abc.c', line 114

static VALUE rubyabc_run_command(VALUE self, VALUE cmd)
{
	VALUE printed_str;

	Check_Type(cmd, T_STRING);


	if (rubyabc_echo_commands) {
		printed_str = rb_sprintf("Command: \"%"PRIsVALUE"\"", cmd);
		rb_io_puts(1, &printed_str, 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, verbose: true, gatelib: false) ⇒ nil

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

Examples:

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

Parameters:

  • input (String) (defaults to: nil)

    Input netilist file name

  • output (String) (defaults to: nil)

    Output netlist file name

  • zero (Boolean) (defaults to: false)

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

  • sweep (Boolean) (defaults to: false)

    Sweep logic network to remove dangling nodes

  • retime (Boolean) (defaults to: false)

    Retime the netlist (reduce logic level, but increase the number of latches)

  • lcorr (Boolean) (defaults to: false)

    Computes latch correspondence using 1-step induction

  • area (Boolean) (defaults to: false)

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

  • lut_map (Integer) (defaults to: nil)

    Map the netlist to K-input LUTs. Optimize for area if area: == true

  • gatelib (Boolean, String) (defaults to: false)

    Map the netlist to a logic gate library if true or a string (the library path)

Returns:

  • (nil)


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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/ruby_abc.rb', line 137

def self.synthesis(input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, verbose: true, gatelib: false)
  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 verbose

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

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

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

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

  ABC::optimize(verbose: verbose)

  if retime and ABC::nb_latches > 0 then
    level = ABC::nb_levels
    ABC::run_command('retime; strash')
    ABC::ps if verbose
    if ABC::nb_levels >= level then
      ABC::run_command('dretime; strash')
      ABC::ps if verbose
    end
    ABC::optimize(verbose: verbose)
  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, area: not(not(area)), verbose: verbose)
  end

  if sweep then
    ABC::run_command 'sop; sweep; resyn; resyn2; resyn3; scleanup; resyn; scleanup; scleanup; scleanup; strash; ssweep; csweep'
    ABC::ps if verbose
    ABC::optimize(verbose: verbose)
    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, area: not(not(area)), verbose: verbose)
    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, area: not(not(area)), verbose: verbose)
    end
  end

  if gatelib then
    gatelib = case gatelib
              when 'osu', true
                File.expand_path('../../share/osu018.genlib', __FILE__) 
              when 'simple'
                File.expand_path('../../share/simple.genlib', __FILE__) 
              when String
                gatelib = File.absolute_path(gatelib)
              end
    abort "ERROR: File \"#{gatelib}\" does not exist!" unless File.file?(gatelib)
    ABC::run_command("read_genlib#{verbose ? '' : ' -v'} '#{gatelib}'")
    ABC::run_command("print_genlib") if verbose

    map_cmd = "choice2; map#{area ? ' -a' : ''}#{sweep ? ' -s' : ''}#{verbose ? '; ps' : ''}"
    min_n_nodes = Float::INFINITY
    loop do
      ABC::run_command(map_cmd)
      n_nodes = ABC::nb_nodes
      break if n_nodes >= min_n_nodes
      min_n_nodes = [min_n_nodes, n_nodes].min
    end
    if ABC::nb_nodes > min_n_nodes then
      5.times do
        ABC::run_command(map_cmd)
        break if ABC::nb_nodes <= min_n_nodes
      end
    end
    ABC::run_command("print_gates") if verbose
  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

  nil
end