bat 1.0.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/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ +++ 1.0.0 2007-04-25
2
+
3
+ + 1 major enhancement:
4
+ + Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,37 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/version.rb
6
+ lib/ParseHelper.rb
7
+ lib/Parser.rb
8
+ lib/Inst.rb
9
+ lib/Port.rb
10
+ lib/OnePort.rb
11
+ lib/TwoPorts.rb
12
+ lib/ThreePorts.rb
13
+ lib/FourPorts.rb
14
+ lib/FivePorts.rb
15
+ lib/Input.rb
16
+ lib/Output.rb
17
+ lib/Dffpc.rb
18
+ lib/Bufz.rb
19
+ lib/Mux2.rb
20
+ lib/Buf1.rb
21
+ lib/Gnd.rb
22
+ lib/Inv.rb
23
+ lib/Nand2.rb
24
+ lib/Nand2c.rb
25
+ lib/Nand3.rb
26
+ lib/Nand3c.rb
27
+ lib/Nand4.rb
28
+ lib/Nand4c.rb
29
+ lib/Nor2.rb
30
+ lib/Nor2c.rb
31
+ lib/Nor3.rb
32
+ lib/Vdd.rb
33
+ lib/Xor2.rb
34
+ bin/bat
35
+ setup.rb
36
+ test/test_bat.rb
37
+ test/test_helper.rb
data/README.txt ADDED
@@ -0,0 +1,19 @@
1
+ README for bat
2
+ ==============
3
+
4
+ B^2 Logic Requirements
5
+ -BAT 1.0 is designed to work only with the BLT version of B^2 Logic 3.0, available at The University of Portland.
6
+
7
+ Design Considerations
8
+ -Inputs and Outputs
9
+ *B^2 Logic's EDF netlist does not make any distinction between active low input pad and active high input pads. Thus, all input pads are assumed to be active high. It is up to the designer to include inverters in the circuit itself, or assume that the inverted external signals will be available.
10
+ *Names of Input pads, Output pads and clocks must not contain any spaces or special characters. Valid names include only standard alphanumeric characters (A..Z, a..z, 0..9).
11
+
12
+ -BUFZ Implementation Details:
13
+ *If a BUFZ is used in a circuit, only the first (top) buffer on the BUFZ instance may be used. This is consistent with BLT implementation. One external pin is consumed per BUFZ and appears as instXpin in the final ABEL code. Tristated signals within the circuit will appear as an open input when in high impedance mode. Given this situation on CMOS technology, the signal will actually float to low rather than remain high impedance, as is typical of of any inputs that are left unconnected. TTL technology will float high in the same situation. Because of this, the designer must take care to ensure that the circuit is not designed expecting a true high impedance signal internal to the circuit (this is only achieved when the output is taken directly from the output pin consumed by the buffer).
14
+
15
+ -MUX2 Implementation Details:
16
+ *If a MUX2 is used in a circuit, only the first (top) MUX on the MUX2 package may be used. This is consistent with BLT implementation.
17
+
18
+ ABEL 7.0 Configuration
19
+ -Buffers are implemented by ORing the signal with itself to induce a single-gate propagation delay (4ns with Xilinx XC9536). Thus, if ABEL's preferences are set to reduce redundant logic the buffers will not work. If buffers are not included in a circuit, BAT designers recommend that ABEL bet set to reduce redundant logic, but ONLY if buffers are not used.
data/Rakefile ADDED
@@ -0,0 +1,65 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/rdoctask'
8
+ require 'rake/contrib/rubyforgepublisher'
9
+ require 'fileutils'
10
+ require 'hoe'
11
+ include FileUtils
12
+ require File.join(File.dirname(__FILE__), 'lib', 'version')
13
+
14
+ AUTHOR = ['Jamie Quint','Ian Tagge'] # can also be an array of Authors
15
+ EMAIL = "jamiequint@gmail.com"
16
+ DESCRIPTION = "B2 Logic to ABEL Translator"
17
+ GEM_NAME = 'bat' # what ppl will type to install your gem
18
+ RUBYFORGE_PROJECT = 'bat' # The unix name for your project
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
21
+
22
+ NAME = "bat"
23
+ REV = nil # UNCOMMENT IF REQUIRED: File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
+ VERS = Bat::VERSION::STRING + (REV ? ".#{REV}" : "")
25
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store']
26
+ RDOC_OPTS = ['--quiet', '--title', 'bat documentation',
27
+ "--opname", "index.html",
28
+ "--line-numbers",
29
+ "--main", "README",
30
+ "--inline-source"]
31
+
32
+ class Hoe
33
+ def extra_deps
34
+ @extra_deps.reject { |x| Array(x).first == 'hoe' }
35
+ end
36
+ end
37
+
38
+ # Generate all the Rake tasks
39
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
40
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
41
+ p.author = AUTHOR
42
+ p.description = DESCRIPTION
43
+ p.email = EMAIL
44
+ p.summary = DESCRIPTION
45
+ p.url = HOMEPATH
46
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
47
+ p.test_globs = ["test/**/test_*.rb"]
48
+ p.clean_globs = CLEAN #An array of file patterns to delete on clean.
49
+
50
+ # == Optional
51
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
52
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
53
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
54
+ end
55
+
56
+ task :check_version do
57
+ unless ENV['VERSION']
58
+ puts 'Must pass a VERSION=x.y.z release version'
59
+ exit
60
+ end
61
+ unless ENV['VERSION'] == VERS
62
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
63
+ exit
64
+ end
65
+ end
data/bin/bat ADDED
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # The is the main executable for project BAT it handles the command line input and checks to see if it is valid.
4
+ # It reads the input file into an array and passes it to a Parser object which handles the parsing. Then it iterates
5
+ # through the created Inst objects and calls their output methods to produce the ABEL output code. This code is
6
+ # written to a file with the same name as the input file whose extension has been replaced with the .edf extension.
7
+ # add lib directory to load path
8
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
9
+ %w[ParseHelper Parser Inst Port OnePort TwoPorts ThreePorts FourPorts FivePorts
10
+ Input Output Dffpc Bufz Mux2 Buf1 Gnd Inv Nand2 Nand2c Nand3 Nand3c Nand4
11
+ Nand4c Nor2 Nor2c Nor3 Vdd Xor2].each do |r|
12
+ require r
13
+ end
14
+
15
+ # Format: [chipname, available pins]
16
+ # The available pins are not currently used but may be used in the future for
17
+ # checking whether the users design will fit on the given chip.
18
+ CHIPNAMES = [["xc9536",34],["gal16v8",14], ["pal16v8",14]]
19
+
20
+ # this is used to fake out command line input for testing
21
+ # ARGV = ["xc9536","../examples/FULLCNTR.EDF"]
22
+
23
+ # test command line for correct number of arguments
24
+ if ARGV.length != 2
25
+ puts "Too many arguments - usage: bat chipname inputfilepath" if ARGV.length > 2
26
+ puts "Too few arguments - usage: bat chipname inputfilepath" if ARGV.length < 2
27
+ exit
28
+ else
29
+ # if the chipname is wrong, print out a list of proper chipnames
30
+ if CHIPNAMES.assoc(ARGV[0].downcase).nil?
31
+ errstr = ""
32
+ print "Invalid Chipname - Chipnames: "
33
+ CHIPNAMES.each do |c|
34
+ errstr << "#{c[0]}, "
35
+ end
36
+ # chop off the extra comma, print it, and quit
37
+ puts errstr.slice(0,errstr.length - 2)
38
+ exit
39
+ end
40
+ end
41
+
42
+ # check if the file exists
43
+ if File.exist?(ARGV[1])
44
+ # read EDF file into an array of lines
45
+ input_file = IO.readlines(ARGV[1])
46
+ else
47
+ puts "No such file or directory - #{ARGV[1]}"
48
+ exit
49
+ end
50
+
51
+ # pass the input file array to the parser to parse
52
+ begin
53
+ p = Parser.new()
54
+ insts = p.parse(input_file)
55
+ # catch any errors with the EDF file
56
+ rescue
57
+ puts "Invalid EDF File"
58
+ exit
59
+ end
60
+
61
+ # kill the extension
62
+ # TODO - make this look for the "." then chop
63
+ oname = ARGV[1].slice(0,ARGV[1].length - 4)
64
+ # see if the file exists and prompt user to overwrite if it does
65
+ if File.exist?("#{oname}.abl")
66
+ print "File #{oname}.abl already exists, overwrite? (Y/N): "
67
+ overwrite = STDIN.gets
68
+ exit if overwrite.chomp.downcase != "y"
69
+ end
70
+
71
+ begin
72
+ # open file to write
73
+ f = File.new("#{oname}.abl","w+")
74
+ # output all data
75
+ f.puts "Module BATcode"
76
+ f.puts "\n\"inputs"
77
+ insts.each_value {|val| f.print val.inputs}
78
+ f.puts "\n\"outputs"
79
+ insts.each_value {|val| f.print val.outputs}
80
+ f.puts "\n\"nodes"
81
+ insts.each_value {|val| f.print val.nodes}
82
+ f.puts "\nequations"
83
+ insts.each_value {|val| f.print val.abelout}
84
+ f.puts "\nend BATcode"
85
+ puts "ABEL output to file #{oname}.abl successful"
86
+ # catch any output exception and print the proper error message
87
+ rescue Exception => e
88
+ puts e
89
+ # make sure to quit regardless of what happens
90
+ ensure
91
+ exit
92
+ end
data/lib/Buf1.rb ADDED
@@ -0,0 +1,27 @@
1
+ # This class defines the Buffer part
2
+ class Buf1 < TwoPorts
3
+
4
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
5
+ # It is responsible for defining applicable nodes, then calling its superclass, TwoPorts, to complete other tasks.
6
+ def initialize(name)
7
+ super(name)
8
+ # set ABEL to not reduce redundant logic since this is a buffer
9
+ nodes << "#{name}p1\tnode;\n#{name}p1a\tnode;\n"
10
+ end
11
+
12
+ # This method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
13
+ # These connections are defined in the abelout method of this object's superclass, TwoPorts.
14
+ def abelout
15
+ super
16
+ s = "#{self.name}p1a = #{@p0};\n"
17
+ s << "#{self.name}p1 = #{@p0} # #{self.name}p1a;\n"
18
+ end
19
+
20
+ # TODO test istype 'keep' in ABEL and make sure that this logic is not reduced
21
+ # TODO jamie - if you have not already figured out how to search for the '.' and then chop of the end try this:
22
+ # TODO index = port.name.rindex('p'
23
+ # TODO portnum = port.name[index..-1]
24
+ # TODO owner = port.name[0...index]
25
+ # TODO exactly this implementation obviously will not work, but that is the method I used a while ago...
26
+
27
+ end
data/lib/Bufz.rb ADDED
@@ -0,0 +1,46 @@
1
+ # This class defines the Tri-State Buffer part
2
+ class Bufz < Inst
3
+
4
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
5
+ # Because of its unique functionality, this object does not call its superclass upon instantiation but rather handles all
6
+ # initialization procedures itself, it sets its attributes, defines the apropriate input and output pins, definines its nodes,
7
+ # and initializes the apropriate ports.
8
+ def initialize(name)
9
+ # TODO - it is retarted that this inherits from Inst since it never calls super
10
+ # make it so insts know their own name
11
+ self.name = name
12
+ self.inputs = ""
13
+ # create constant definitions for each output pin
14
+ self.nodes = "#{name}out\tnode;\n"
15
+ self.outputs = "#{name}pin\tpin;\n"
16
+ @iports = {}
17
+
18
+ # iterate to create input port(s)
19
+ (0..1).to_a.each do |d|
20
+ portname = "#{name}p#{d}"
21
+ @iports["#{portname}"] = Port.new(name, 'in', portname)
22
+ end
23
+
24
+ # Fake out an output port (we will act like we are connecting pins to this port, but really it references an output pin)
25
+ # ABEL doesn't know the difference since we have called our output pin the same name as this faked out port
26
+ @iports["#{name}out"] = Port.new(name, 'out', "#{name}out")
27
+ end
28
+
29
+ # This method defines the connections held by the ports of this object and returns the specific ABEL code to be output for this
30
+ # object based on the connections on its input ports.
31
+ def abelout
32
+ # create defs only for inputs to inst
33
+ # make these insts just for consistency's sake
34
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
35
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
36
+
37
+ # code for all tristate buffers on b2logic component
38
+ s = "\n\"tristate buffer - consumes one external pin\n#{self.name}pin.oe = 0;\n"
39
+ unless @p0.empty? || @p1.empty?
40
+ s << "WHEN (#{@p0}) THEN \n\t{#{self.name}pin.oe = 1;\n"
41
+ s << "\t#{self.name}pin = #{@p1};}\n"
42
+ end
43
+ s << "#{self.name}out = #{self.name}pin.pin;\n\n"
44
+ end
45
+
46
+ end
data/lib/Dffpc.rb ADDED
@@ -0,0 +1,40 @@
1
+ # This class defines the D Flip-Flop part
2
+ class Dffpc < Inst
3
+
4
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
5
+ # It is responsible for defining applicable nodes, then calling its superclass, Inst, to complete other tasks.
6
+ def initialize(name)
7
+ # TODO - make this cleaner, should either override the whole superclass or pass it the type of the node
8
+ super(name,[0,1,2,3],[4,5],false)
9
+ [4,5].each do |d|
10
+ # define these nodes separately from super because they are of type reg
11
+ nodes<<"#{name}p#{d}\tnode istype 'reg';\n"
12
+ end
13
+ end
14
+
15
+ # This method defines the connections held by the ports of this object and returns the specific ABEL code to be output for this
16
+ # object based on the connections on its input ports.
17
+ def abelout
18
+ # make these class variables just for consistency's sake
19
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
20
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
21
+ @p2 = self.get_port("p2").connections.collect{|p| p.name}.to_s
22
+ @p3 = self.get_port("p3").connections.collect{|p| p.name}.to_s
23
+ @p4 = self.get_port("p4").connections.collect{|p| p.name}.to_s
24
+ @p5 = self.get_port("p5").connections.collect{|p| p.name}.to_s
25
+ @p4 = self.get_port("p4").connections.collect{|p| p.name}.to_s
26
+ @p5 = self.get_port("p5").connections.collect{|p| p.name}.to_s
27
+
28
+ s = "\n\"d-ff\n"
29
+ unless @p4.empty?
30
+ s << "#{self.name}p4.ap = !#{@p0};\n#{self.name}p4.ar = !#{@p3};\n#{self.name}p4.clk = #{@p1};\n"
31
+ s << "#{self.name}p4 := #{@p2};\n\n"
32
+ end
33
+ unless @p5.empty?
34
+ s << "#{self.name}p5.ap = !#{@p0};\n#{self.name}p5.ar = !#{@p3};\n#{self.name}p5.clk = #{@p1};\n"
35
+ s << "#{self.name}p5 := !#{@p2};\n\n"
36
+ end
37
+ s
38
+ end
39
+
40
+ end
data/lib/FivePorts.rb ADDED
@@ -0,0 +1,19 @@
1
+ # This class is the superclass for all five port Inst objects
2
+ # Nand4c and Nand4 inherit from this class
3
+
4
+ class FivePorts < Inst
5
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
6
+ # It is responsible for calling its superclass Inst and passing to it the correct number of input ports and output ports to
7
+ # be created.
8
+ def initialize(name)
9
+ super(name,[0,1,2,3],[4])
10
+ end
11
+
12
+ # This method defines the connections held by the ports for this object's subclasses.
13
+ def abelout
14
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
15
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
16
+ @p2 = self.get_port("p2").connections.collect{|p| p.name}.to_s
17
+ @p3 = self.get_port("p3").connections.collect{|p| p.name}.to_s
18
+ end
19
+ end
data/lib/FourPorts.rb ADDED
@@ -0,0 +1,19 @@
1
+ # This class is the superclass for all four port Inst objects
2
+ # Nand3, Nor3, and Nand3c inherit from this class
3
+
4
+ class FourPorts < Inst
5
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
6
+ # It is responsible for calling its superclass Inst and passing to it the correct number of input ports and output ports to
7
+ # be created.
8
+ def initialize(name)
9
+ super(name,[0,1,2],[3])
10
+ end
11
+
12
+ # This method defines the connections held by the ports for this object's subclasses.
13
+ def abelout
14
+ @p0 = self.get_port("p0").connections.collect{|p| p.name}.to_s
15
+ @p1 = self.get_port("p1").connections.collect{|p| p.name}.to_s
16
+ @p2 = self.get_port("p2").connections.collect{|p| p.name}.to_s
17
+ end
18
+
19
+ end
data/lib/Gnd.rb ADDED
@@ -0,0 +1,10 @@
1
+ # This class defines the Ground part
2
+ class Gnd < OnePort
3
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
4
+ # It is responsible for defining applicable input pins, then calling its superclass, OnePort, to complete other tasks.
5
+ def initialize(name)
6
+ super(name)
7
+ # gnd is declared as a constant within the chip to save input pins
8
+ self.inputs = "#{self.name}p0 = 0;\n"
9
+ end
10
+ end
data/lib/Input.rb ADDED
@@ -0,0 +1,9 @@
1
+ # This class defines the Input pad part
2
+ class Input < OnePort
3
+ # This method is called when a new object is instantiated, it takes the name of the Inst object (name) as its only argument.
4
+ # It is responsible for defining applicable input pins, then calling its superclass, OnePort, to complete other tasks.
5
+ def initialize(name)
6
+ super(name)
7
+ self.inputs = "#{self.name}p0\tpin;\n"
8
+ end
9
+ end
data/lib/Inst.rb ADDED
@@ -0,0 +1,51 @@
1
+ # This class defines the Inst object. Inst is a superclass for many different subclasses.
2
+ # This class handles mostly generalizations of what happens in all of its subclasses. Inst objects are instantiated
3
+ # by the Parser component as they are found, and are connected to each other via their Port objects.
4
+ class Inst
5
+
6
+ attr_accessor :name, :nodes, :inputs, :outputs
7
+ # This method is responsible for creating the correct number of input ports and output ports for each Inst object based on the arguments
8
+ # it recieves (inputs and outputs). It is also responsible for generating nodes for each output pin (this is the default behavior)
9
+ # unless is is explicitly instructed not to do so via an argument (createnode).
10
+ def initialize(name,inputs = [], outputs = [], createnode = true)
11
+ # make it so insts know their own name
12
+ self.name = name
13
+ self.nodes = ""
14
+ self.inputs = ""
15
+ self.outputs = ""
16
+ @iports = {}
17
+
18
+ # iterate to create input port(s)
19
+ inputs.each do |d|
20
+ portname = "#{name}p#{d}"
21
+ @iports["#{portname}"] = Port.new(name, 'in', portname)
22
+ end
23
+ # iterate to create output port(s) and node(s) (for output pins)
24
+ outputs.each do |d|
25
+ portname = "#{name}p#{d}"
26
+ @iports["#{portname}"] = Port.new(name, 'out', portname)
27
+ nodes<<"#{name}p#{d}\tnode;\n" if createnode
28
+ end
29
+ end
30
+
31
+ # This method takes a port name as input (pname) and returns
32
+ # the port object corresponding to that port name
33
+ def get_port(pname)
34
+ # get the port from the iports hash
35
+ if pname =~ /p\d+/
36
+ @iports["#{self.name}#{pname}"]
37
+ elsif pname =~ /out/
38
+ @iports["#{self.name}out"]
39
+ else
40
+ []
41
+ end
42
+ end
43
+
44
+ # Generally this method returns the specific ABEL code to be output for this Inst object based on its connections on its input ports.
45
+ # The inst superclass defaults this value to a blank string so that if abelout is not defined in the subclass there will not be a
46
+ # method not found error.
47
+ def abelout
48
+ ""
49
+ end
50
+
51
+ end