ruby-adept 0.0.1

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.
Files changed (55) hide show
  1. data/.gitignore +17 -0
  2. data/.travis.yml +6 -0
  3. data/Gemfile +10 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +16 -0
  7. data/adept.gemspec +33 -0
  8. data/autotest/discover.rb +2 -0
  9. data/bin/bprog +110 -0
  10. data/firmware/.gitignore +73 -0
  11. data/firmware/epp_stream/Basys2_100_250General.ucf +21 -0
  12. data/firmware/epp_stream/epp_controller.vhd +210 -0
  13. data/firmware/epp_stream/epp_stream.xise +355 -0
  14. data/firmware/epp_stream/fifo.vhd +178 -0
  15. data/firmware/epp_stream/tests/fifo_testbench.vhdl +164 -0
  16. data/lib/adept/boards/basys2.rb +84 -0
  17. data/lib/adept/boards.rb +2 -0
  18. data/lib/adept/connection_provider.rb +30 -0
  19. data/lib/adept/data_formats/bitstream.rb +116 -0
  20. data/lib/adept/data_formats/data_factories.rb +33 -0
  21. data/lib/adept/data_formats.rb +2 -0
  22. data/lib/adept/device.rb +127 -0
  23. data/lib/adept/error.rb +4 -0
  24. data/lib/adept/jtag/connection.rb +404 -0
  25. data/lib/adept/jtag/device.rb +178 -0
  26. data/lib/adept/jtag/devices/fpga.rb +162 -0
  27. data/lib/adept/jtag/devices/null.rb +0 -0
  28. data/lib/adept/jtag/devices/platform_flash.rb +23 -0
  29. data/lib/adept/jtag/devices.rb +2 -0
  30. data/lib/adept/jtag/error.rb +8 -0
  31. data/lib/adept/jtag/tap_state.rb +67 -0
  32. data/lib/adept/jtag/tap_states.rb +52 -0
  33. data/lib/adept/jtag.rb +11 -0
  34. data/lib/adept/low_level/connection.rb +59 -0
  35. data/lib/adept/low_level/device.rb +43 -0
  36. data/lib/adept/low_level/device_error.rb +22 -0
  37. data/lib/adept/low_level/device_manager.rb +142 -0
  38. data/lib/adept/low_level/enhanced_parallel.rb +151 -0
  39. data/lib/adept/low_level/error_handler.rb +60 -0
  40. data/lib/adept/low_level/jtag.rb +379 -0
  41. data/lib/adept/low_level/library.rb +173 -0
  42. data/lib/adept/low_level.rb +4 -0
  43. data/lib/adept/version.rb +3 -0
  44. data/lib/adept.rb +11 -0
  45. data/spec/firmware/epp_loopback.bit +0 -0
  46. data/spec/lib/adept/data_formats/bitstream_spec.rb +95 -0
  47. data/spec/lib/adept/data_formats/data_factories_spec.rb +42 -0
  48. data/spec/lib/adept/device_spec.rb +88 -0
  49. data/spec/lib/adept/jtag/connection_spec.rb +433 -0
  50. data/spec/lib/adept/jtag/device_spec.rb +107 -0
  51. data/spec/lib/adept/jtag/devices/fpga_spec.rb +71 -0
  52. data/spec/lib/adept/low_level/enhanced_parallel_spec.rb +72 -0
  53. data/spec/lib/adept/low_level/jtag_spec.rb +204 -0
  54. data/spec/spec_helpers.rb +25 -0
  55. metadata +240 -0
@@ -0,0 +1,164 @@
1
+ ----------------------------------------------------------------------------------
2
+ -- Simple Synchronous FIFO
3
+ --
4
+ -- Author: Kyle J. Temkin, <ktemkin@binghamton.edu>
5
+ -- Copyright (c) Kyle J. Temkin, 2013 Binghamton University
6
+ --
7
+ -- This program is free software: you can redistribute it and/or modify
8
+ -- it under the terms of the GNU General Public License as published by
9
+ -- the Free Software Foundation, either version 3 of the License, or
10
+ -- (at your option) any later version.
11
+ --
12
+ -- This program is distributed in the hope that it will be useful,
13
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ -- GNU General Public License for more details.
16
+ --
17
+ -- You should have received a copy of the GNU General Public License
18
+ -- along with this program. If not, see <http://www.gnu.org/licenses/>.-
19
+ --
20
+ ----------------------------------------------------------------------------------
21
+
22
+ library ieee;
23
+ use ieee.std_logic_1164.all;
24
+ use ieee.numeric_std.all;
25
+
26
+ entity fifo_testbench is
27
+ end fifo_testbench;
28
+
29
+ architecture behavior of fifo_testbench is
30
+
31
+ -- component declaration for the unit under test (uut)
32
+
33
+ component fifo
34
+ generic(
35
+ count_bits : integer;
36
+ element_width : integer
37
+ );
38
+ port(
39
+ clk : in std_logic;
40
+ reset : in std_logic;
41
+ data_in : in std_logic_vector(7 downto 0);
42
+ data_out : out std_logic_vector(7 downto 0);
43
+ count : out std_logic_vector(4 downto 0);
44
+ enqueue : in std_logic;
45
+ dequeue : in std_logic;
46
+ empty : out std_logic;
47
+ full : out std_logic
48
+ );
49
+ end component;
50
+
51
+ --
52
+ -- Convenience function which waits until juster the rising edge.
53
+ --
54
+ procedure wait_until_after_rising_edge(signal clk : in std_logic) is
55
+ begin
56
+ wait until rising_edge(clk);
57
+ wait for 1 ps;
58
+ end procedure wait_until_after_rising_edge;
59
+
60
+ --inputs
61
+ signal clk : std_logic := '0';
62
+ signal reset : std_logic := '1';
63
+ signal data_in : std_logic_vector(7 downto 0) := (others => '0');
64
+ signal enqueue : std_logic := '0';
65
+ signal dequeue : std_logic := '0';
66
+
67
+ --outputs
68
+ signal data_out : std_logic_vector(7 downto 0);
69
+ signal count : std_logic_vector(4 downto 0);
70
+ signal empty : std_logic;
71
+ signal full : std_logic;
72
+
73
+ -- clock period definitions
74
+ constant clk_period : time := 10 ns;
75
+
76
+ constant delta_delay : time := 1 ps;
77
+
78
+ begin
79
+
80
+ -- instantiate the unit under test (uut)
81
+ uut: fifo
82
+ generic map(
83
+ count_bits => 5,
84
+ element_width => 8
85
+ )
86
+ port map (
87
+ clk => clk,
88
+ reset => reset,
89
+ data_in => data_in,
90
+ data_out => data_out,
91
+ count => count,
92
+ enqueue => enqueue,
93
+ dequeue => dequeue,
94
+ empty => empty,
95
+ full => full
96
+ );
97
+
98
+ --Generate the system clock.
99
+ clk <= not clk after clk_period / 2;
100
+
101
+ -- stimulus process
102
+ stim_proc: process
103
+ begin
104
+
105
+ -- assert reset for 100ns;
106
+ wait for 100 ns;
107
+ reset <= '0';
108
+
109
+ --Assert conditions after reset.
110
+ assert data_out = x"00" report "Data_out should be zero after clear.";
111
+ assert count = "00000" report "Count should be zero after clear.";
112
+ assert empty = '1' report "Empty should be one after clear.";
113
+
114
+ --Add 31 elements to the FIFO.
115
+ enqueue <= '1';
116
+ dequeue <= '0';
117
+ for i in 1 to 31 loop
118
+
119
+ --Ensure that we're counting the values properly.
120
+ assert count = std_logic_vector(to_unsigned(i - 1, 5)) report "Count should be equal to the amount of elements enqueued.";
121
+
122
+ --Set up the FIFO to add a new, numbered element.
123
+ data_in <= std_logic_vector(to_unsigned(i, 8));
124
+
125
+ --Wait until just after the next rising-edge of the clock.
126
+ wait_until_after_rising_edge(clk);
127
+
128
+ --Check to see that our enqueue is behaving properly.
129
+ assert empty = '0' report "Empty should not be one while there are elements in the FIFO.";
130
+ assert data_out = x"01" report "Data out should show the first element enqueued until a dequeue is performed.";
131
+
132
+ end loop;
133
+
134
+ --Check to see that the FIFO is full.
135
+ assert full = '1' report "After adding 31 elements to the FIFO, it should be full.";
136
+
137
+ --Verify that we can perform simultaneous read/writes, even when the FIFO is full.
138
+ enqueue <= '1';
139
+ dequeue <= '1';
140
+ data_in <= x"20";
141
+ wait_until_after_rising_edge(clk);
142
+
143
+ --Check to ensure that the simultaneous enqueue/dequeue does not affect the count.
144
+ assert data_out = x"02" report "After a dequeue, the next value in the FIFO should be exposed.";
145
+ assert count = "11111" report "A simultaneous enqueue/dequeue should not affect the count.";
146
+
147
+ --Remove each of the elements from the FIFO.
148
+ enqueue <= '0';
149
+ dequeue <= '1';
150
+ for i in 2 to 32 loop
151
+ assert data_out = std_logic_vector(to_unsigned(i, 8)) report "Elements should be dequeued in the same ordered they were entered.";
152
+ assert count = std_logic_vector(to_unsigned(33 - i, 5)) report "Count should decrease as elements are dequeued.";
153
+ wait_until_after_rising_edge(clk);
154
+ end loop;
155
+
156
+ --Check to ensure that the FIFO is empty after all elements have been dequeued.
157
+ assert count = "00000" report "After all elements are dequeued, the count should be zero.";
158
+ assert empty = '1' report "After all elements are dequeued, the queue should be empty.";
159
+
160
+ report "Test complete.";
161
+ wait;
162
+ end process;
163
+
164
+ end;
@@ -0,0 +1,84 @@
1
+
2
+ require 'adept'
3
+
4
+ module Adept
5
+ module Boards
6
+
7
+ #
8
+ # Basys2 System Board
9
+ #
10
+ class Basys2 < Adept::Device
11
+
12
+ DEVICE_NAME = 'Basys2'
13
+
14
+ #
15
+ # Creates a new Basys2 board instance given the device's path.
16
+ # If no path is provided, the first connected Basys 2 board is used.
17
+ #
18
+ def initialize(path=nil)
19
+
20
+ #If no path was provided, use the path to the first device found.
21
+ path ||= Device.path_to(DEVICE_NAME)
22
+
23
+ #Delegate the connection tasks to the base class.
24
+ super(path)
25
+
26
+ end
27
+
28
+ #
29
+ # Creates a new Basys2 board instance, using the same syntax as new,
30
+ # but accepts an optional block. If a block is given, the device will
31
+ # be automatically closed after the block is complete.
32
+ #
33
+ # Yields and returns the newly-created device.
34
+ #
35
+ def self.open(path=nil)
36
+
37
+ #Create a new Basys2 device.
38
+ device = new(path)
39
+
40
+ #If we were provided with a block, yield the device to it,
41
+ #and then close the device afterwards
42
+ if block_given?
43
+ begin
44
+ yield device
45
+ ensure
46
+ device.close
47
+ end
48
+ end
49
+
50
+ #Return the newly created device.
51
+ device
52
+
53
+ end
54
+
55
+ #
56
+ # Configures the Basys2 board's on-board FPGA.
57
+ # Requires use of the board's JTAG port, and thus cannot be used when its JTAG
58
+ # port is open. (The JTAG device API provides an alternative method for device
59
+ # configuration.)
60
+ #
61
+ # bitstream: The bitstream to be programmed, as a Bitstream object or byte-string
62
+ # (without headers).
63
+ #
64
+ def configure_fpga(bitstream)
65
+
66
+ begin
67
+
68
+ #Create a new JTAG connection to the board's FPGA.
69
+ jtag = JTAG::Connection.new(self)
70
+ fpga = jtag.connected_devices.first
71
+
72
+ #Configure the FPGA.
73
+ fpga.configure(bitstream)
74
+
75
+ ensure
76
+ jtag.close
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,2 @@
1
+
2
+ require 'adept/boards/basys2'
@@ -0,0 +1,30 @@
1
+
2
+ module Adept
3
+
4
+ #
5
+ # Base for Adept connections.
6
+ #
7
+ module ConnectionProvider
8
+
9
+ # An internal list of connection types which are provided by this library.
10
+ # Each time a new Conneciton type is loaded, it is added to this array.
11
+ @supported_connections = []
12
+
13
+ #
14
+ # Triggered each time a target class extends this basic connection.
15
+ # Stores a list of all classes that extend ConnectionBase.
16
+ #
17
+ def self.extended(connection)
18
+ @supported_connections << connection
19
+ end
20
+
21
+ #
22
+ # Returns the list of all supported connection providers.
23
+ #
24
+ def self.providers
25
+ @supported_connections
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,116 @@
1
+
2
+ require 'date'
3
+ require 'bindata'
4
+
5
+ require 'adept/data_formats/data_factories'
6
+
7
+ module Adept
8
+ module DataFormats
9
+
10
+ #
11
+ # Class for the Xilinx bitstream file format.
12
+ #
13
+ # Format used was described at
14
+ # <http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm>
15
+ #
16
+ class Bitstream < BinData::Record
17
+ extend DataFactories
18
+
19
+ #Data is stored in the bitstream in big endian format.
20
+ endian :big
21
+
22
+ #Bit-file header.
23
+ uint16 :header_length
24
+ string :header, :read_length => :header_length
25
+ skip :length => 2
26
+
27
+ #Design information.
28
+ uint8 :a, :check_value => 'a'.ord
29
+ uint16 :info_length
30
+ string :info, :read_length => :info_length, :trim_padding => true
31
+
32
+ #Part information
33
+ uint8 :b, :check_value => 'b'.ord
34
+ uint16 :part_length
35
+ string :part, :read_length => :part_length, :trim_padding => true
36
+
37
+ #Date of creation.
38
+ uint8 :c, :check_value => 'c'.ord
39
+ uint16 :date_length
40
+ string :raw_date, :read_length => :date_length, :trim_padding => true
41
+
42
+ #Time of creation.
43
+ uint8 :d, :check_value => 'd'.ord
44
+ uint16 :time_length
45
+ string :raw_time, :read_length => :time_length, :trim_padding => true
46
+
47
+ #Raw binary configuration information
48
+ uint8 :e, :check_value => 'e'.ord
49
+ uint32 :bitstream_length
50
+ array :raw_bitstream, :type => :uint8, :initial_length => :bitstream_length
51
+
52
+ UsercodeFormat= /UserID=0x([0-9A-Fa-f]+)/
53
+
54
+ #
55
+ # Parses the given string as a Xilinx BitStream file.
56
+ #
57
+ def self.from_string(string)
58
+ read(string)
59
+ end
60
+
61
+ #
62
+ # Returns the routed logic ("ncd") filename from which this bitstream was created.
63
+ #
64
+ def filename
65
+ info.split(';').first
66
+ end
67
+
68
+ #
69
+ # Returns the usercode for the given design.
70
+ #
71
+ def usercode
72
+ UsercodeFormat.match(info)[1]
73
+ end
74
+
75
+ #
76
+ # Returns the time at which the bitfile was created.
77
+ #
78
+ def time_created
79
+ DateTime.parse("#{raw_date} #{raw_time}")
80
+ end
81
+
82
+ #
83
+ # Returns the length of the bitsream, in bits.
84
+ #
85
+ def bit_length
86
+ bitstream_length * 8
87
+ end
88
+
89
+ #
90
+ # Returns the bitstream as an arran array.
91
+ #
92
+ def to_a
93
+ raw_bitstream.to_a.map { |b| self.class.reverse_byte(b) }
94
+ end
95
+
96
+ #
97
+ # Returns the bitstream as a bit string.
98
+ #
99
+ def to_s
100
+ to_a.pack("C*")
101
+ end
102
+
103
+ private
104
+
105
+ #
106
+ # Reverses the bit order of a given byte, using a fast algorithm from the
107
+ # following page: http://graphics.stanford.edu/~seander/bithacks.html
108
+ #
109
+ def self.reverse_byte(byte)
110
+ (((byte * 0x0802 & 0x22110) | (byte * 0x8020 & 0x88440)) * 0x10101 >> 16) % 0x100;
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,33 @@
1
+
2
+ module Adept
3
+ module DataFormats
4
+
5
+ #
6
+ # Mixin which supports creating instances of data-storage containers
7
+ # from files. Classes which extend this mix-in should have a "from_string"
8
+ # class method.
9
+ #
10
+ module DataFactories
11
+
12
+ #
13
+ # Creates a new instance of the target class from a file or filename.
14
+ #
15
+ def from_file(file)
16
+
17
+ #If we have a file object, read it into memory.
18
+ if file.respond_to?(:read)
19
+ file = file.read
20
+ #Otherwise, assume we have a filename.
21
+ else
22
+ file = File::read(file)
23
+ end
24
+
25
+ #Create a new instance of the extending class from the given file.
26
+ from_string(file)
27
+
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ require 'require_all'
2
+ require_rel 'data_formats'
@@ -0,0 +1,127 @@
1
+
2
+ require 'adept/low_level'
3
+
4
+ require 'adept/connection_provider'
5
+ require 'adept/jtag'
6
+
7
+ module Adept
8
+
9
+ #
10
+ # Basic interface to a Digilent Adept device.
11
+ #
12
+ class Device
13
+
14
+ #Get an easy reference to the adept Device Manager API.
15
+ DeviceManager = LowLevel::DeviceManager
16
+
17
+ #Allow Device connections to be created with an open function,
18
+ #like Ruby I/O objects.
19
+ class << self
20
+ alias :open :new
21
+ end
22
+
23
+ #Allow access to the device's handle, for now.
24
+ attr_reader :handle
25
+
26
+ #
27
+ # Factory method which returns a connection to the device with the given name,
28
+ # or nil if no devices with that name could be found.
29
+ #
30
+ def self.by_name(name)
31
+
32
+ #Find path to the first device with the given name.
33
+ path = path_to(name)
34
+
35
+ #Return a new connection to the target device, or nil if no path was found.
36
+ path ? self.new(path) : nil
37
+
38
+ end
39
+
40
+ #
41
+ # Returns the path to first device with the given name,
42
+ # or nil if no devices with that name could be found.
43
+ #
44
+ def self.path_to(name)
45
+
46
+ #Find the first device with the given name.
47
+ target_device = connected_devices.find { |device| device[:name] == name }
48
+
49
+ #Return the path to the target device.
50
+ target_device ? target_device[:path] : nil
51
+
52
+ end
53
+
54
+
55
+ #
56
+ #Creates a new connection to a Digilent adept device.
57
+ #
58
+ def initialize(path)
59
+
60
+ #Open the device, and store its handle.
61
+ @handle = DeviceManager::open_device(path)
62
+
63
+ #If we didn't get a valid handle, raise the relevant exception.
64
+ if @handle.nil?
65
+ raise DeviceManager::last_error
66
+ end
67
+
68
+ end
69
+
70
+
71
+ #
72
+ # Closes the given device.
73
+ #
74
+ def close
75
+ ensure_handle_is_valid
76
+ DeviceManager::close_device(@handle)
77
+ end
78
+
79
+ #
80
+ # TODO: throw an exception of our handle is nil
81
+ #
82
+ def ensure_handle_is_valid
83
+
84
+ end
85
+
86
+ #
87
+ # Returns a list of connection methods supported by the current device.
88
+ #
89
+ def supported_connections
90
+ ConnectionProvider.providers.select { |connection| connection.supported_by?(@handle) }
91
+ end
92
+
93
+ #
94
+ # Returns an array of information regarding connected devices.
95
+ # Each array member is a hash, with three members:
96
+ # -:name, the device's shortname
97
+ # -:connection, the device's connection
98
+ # -:transport, a code indicating the method by which we're connecting to the device
99
+ #
100
+ def self.connected_devices
101
+
102
+ #Populate the internal device list, retrieving the amount of connected devices.
103
+ count = DeviceManager::populate_device_list
104
+
105
+ #Get the device information for each of the given devices.
106
+ devices = (0...count).map { |index| DeviceManager::get_device_info(index) }
107
+
108
+ #Free the internal device list.
109
+ DeviceManager::free_device_list
110
+
111
+ #and return the list of connected devices
112
+ devices
113
+
114
+ end
115
+
116
+ #
117
+ # Returns a new connection to the first connected device.
118
+ #
119
+ def self.open_first_connected_device
120
+ device = connected_devices.first
121
+ new(device[:path])
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
@@ -0,0 +1,4 @@
1
+ module Adept
2
+ class Error < StandardError; end
3
+ class CommunicationError < Error; end
4
+ end