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.6'
Class Method Summary collapse
-
.echo_commands ⇒ Object
echo_commands -> true or false.
-
.echo_commands=(b) ⇒ Object
echo_commands= (boolean).
-
.map(k, optimize_area = false, verbose: true) ⇒ Object
call-seq: map (lut_size, optimize_for_area = false, verbose: true) -> nb_nodes.
-
.method_missing(name, *args) ⇒ Object
call-seq: method_missing(method, *args).
-
.nb_ands ⇒ Object
nb_ands -> integer or nil.
-
.nb_latches ⇒ Object
nb_latches -> integer or nil.
-
.nb_levels ⇒ Object
nb_levels -> integer or nil.
-
.nb_nodes ⇒ Object
nb_nodes -> integer or nil.
-
.nb_primary_inputs ⇒ Object
nb_primary_inputs -> integer or nil.
-
.nb_primary_outputs ⇒ Object
nb_primary_outputs -> integer or nil.
-
.optimize(verbose: true) ⇒ Object
call-seq: optimize (verbose: true) -> nb_ands.
-
.print_stats ⇒ Object
call-seq: print_stats.
-
.run_command(cmd) ⇒ Object
run_command (string).
-
.synthesis(input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, help: nil, verbose: true) ⇒ Object
call-seq: synthesis (input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, verbose: true, help: nil).
Class Method Details
.echo_commands ⇒ Object
echo_commands -> true or false
Return if each command received is echoed back.
ABC.echo_commands #=> true
164 165 166 167 168 169 |
# File 'ext/ruby_abc.c', line 164
static VALUE rubyabc_get_echo_commands(VALUE self)
{
if (rubyabc_echo_commands)
return Qtrue;
return Qfalse;
}
|
.echo_commands=(b) ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 |
# File 'ext/ruby_abc.c', line 179
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, verbose: true) ⇒ Object
call-seq: map (lut_size, optimize_for_area = false, verbose: true) -> 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:
"choice2; if -K #{lut_size}#{optimize_for_area ? ' -a':''}; ps"
and stops when the number of nodes stop decreasing.
ABC.map(4)
87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/ruby_abc.rb', line 87 def self.map (k, optimize_area = false, verbose: true) map_cmd = "choice2; if -K #{k}#{optimize_area ? ' -a':''}#{verbose ? '; 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}"
112 113 114 115 116 |
# File 'lib/ruby_abc.rb', line 112 def self.method_missing (name, *args) cmd = name.to_s cmd += ' ' + args.join(' ') if args ABC::run_command cmd end |
.nb_ands ⇒ Object
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_latches ⇒ Object
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_levels ⇒ Object
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_nodes ⇒ Object
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_inputs ⇒ Object
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_outputs ⇒ Object
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);
}
|
.optimize(verbose: true) ⇒ Object
call-seq: optimize (verbose: true) -> 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 71 |
# File 'lib/ruby_abc.rb', line 61 def self.optimize (verbose: true) cmd = 'resyn; resyn2; resyn3' + (verbose ? '; ps' : '') n_ands = ABC::nb_ands loop do ABC::run_command(cmd) new_n_ands = ABC::nb_ands break unless new_n_ands < n_ands n_ands = new_n_ands end return ABC::nb_ands end |
.print_stats ⇒ Object
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 "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) ⇒ 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 150 151 152 153 154 |
# File 'ext/ruby_abc.c', line 138
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, help: nil, verbose: true) ⇒ Object
call-seq: synthesis (input: nil, output: nil, zero: false, sweep: false, retime: false, lcorr: false, area: false, lut_map: nil, verbose: true, 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)
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 |
# 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, help: nil, verbose: true) if help then puts <<EOS ABC::synthesis keyword arguments: 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 EOS 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 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, 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, 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, not(not(area)), verbose: verbose) 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 |