ruby-adept 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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