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
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "ffi"
4
+ gem "bindata"
5
+ gem "trollop"
6
+ gem "smart_colored"
7
+ gem "progressbar"
8
+
9
+ # Specify your gem's dependencies in adept.gemspec
10
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Kyle J. Temkin
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Adept
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'adept'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install adept
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => [:test_offline]
4
+
5
+ #Offline tests only: don't perform tests that require live hardware.
6
+ task :test_offline do
7
+ sh "rspec -Ilib --tag=~online"
8
+ end
9
+
10
+ task :test do
11
+ sh "rspec -Ilib"
12
+ end
13
+
14
+ task :install_adept do
15
+
16
+ end
data/adept.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'adept/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "ruby-adept"
8
+ gem.version = Adept::VERSION
9
+ gem.authors = ["Kyle J. Temkin"]
10
+ gem.email = ["ktemkin@binghamton.edu"]
11
+ gem.description =
12
+ 'Ruby library for working with Digilent devices via the Adept SDK.
13
+ Provides both low-level wrappers for the Adept SDK elements and high-level
14
+ interfaces, including simple programming and configuration routines.'
15
+ gem.summary = "Framework for working with Digilent Adept devices."
16
+ gem.homepage = "http://www.github.com/ktemkin/ruby-adept"
17
+
18
+ gem.add_runtime_dependency 'bindata'
19
+ gem.add_runtime_dependency 'ruby-ise'
20
+ gem.add_runtime_dependency 'trollop'
21
+ gem.add_runtime_dependency 'smart_colored'
22
+ gem.add_runtime_dependency 'ffi'
23
+ gem.add_runtime_dependency 'require_all'
24
+
25
+ gem.add_development_dependency 'rspec'
26
+ gem.add_development_dependency 'fakefs'
27
+
28
+
29
+ gem.files = `git ls-files`.split($/)
30
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
31
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
32
+ gem.require_paths = ["lib"]
33
+ end
@@ -0,0 +1,2 @@
1
+ #./autotest/discover.rb
2
+ Autotest.add_discovery {"rspec2"}
data/bin/bprog ADDED
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ise'
4
+ require 'adept'
5
+
6
+ require 'trollop'
7
+ require 'smart_colored/extend'
8
+
9
+ include Adept
10
+
11
+ #Add some separation before and after the output, to make it more visible.
12
+ puts
13
+ at_exit { puts }
14
+
15
+ #
16
+ #Output a formatted warning message.
17
+ #
18
+ def warn(message)
19
+ puts message.yellow
20
+ end
21
+
22
+ #
23
+ #Output a formatted error message.
24
+ #
25
+ def error(message, title="Oops!")
26
+ puts "#{title.bold} #{message}".red
27
+ end
28
+
29
+ #
30
+ # Output a formatted error message, and quit.
31
+ #
32
+ def fatal_error(message, title="Oops!")
33
+ error "#{message}", title
34
+ exit
35
+ end
36
+
37
+ #
38
+ # Get the currently connected device.
39
+ #
40
+ def get_target_connection(opts={})
41
+
42
+ #Ensure that we have a plugged-in board.
43
+ fatal_error "It doesn't look like there's a Digilent board plugged in, on or off." if Device::connected_devices.empty?
44
+
45
+ #By default, use the first connected device.
46
+ device = Device::open_first_connected_device
47
+ at_exit { device.close }
48
+
49
+ #If the device doesn't support JTAG, we can't program it.
50
+ fatal_error "This device isn't supported." unless device.supported_connections.include?(JTAG::Connection)
51
+
52
+ jtag = JTAG::Connection.new(device)
53
+ fatal_error "The power switch is off on your connected board! Turn it on, and try again." if jtag.connected_devices.empty?
54
+
55
+ jtag
56
+
57
+ end
58
+
59
+ #
60
+ # Get the target file.
61
+ #
62
+ def get_target_file(opts={})
63
+
64
+ #If a file was provided on the command line, use it.
65
+ file = ARGV.shift if ARGV
66
+
67
+ #Attempt to determine the target file automagically.
68
+ unless file
69
+
70
+ #Attempt to determine the file.
71
+ file = ISE::ProjectNavigator::most_recent_project.bit_file
72
+ fatal_error "You didn't specify a file to program, and I couldn't figure out a likely candidate.\n Perhaps you still need to generate a programming file?" unless file
73
+
74
+ #And warn the user of the file we chose.
75
+ warn "You didn't specify a file to program, so I assumed you wanted me to program:"
76
+ puts "#{File::dirname(file)}/#{File::basename(file).bold}"
77
+
78
+ end
79
+
80
+ fatal_error "The file you asked me to program doesn't seem to exist." unless File::exists?(file)
81
+
82
+ #Return the ascertained file.
83
+ file
84
+
85
+ end
86
+
87
+ def configure_fpga(jtag, bitfile_path)
88
+
89
+ #Find the first connected FPGA.
90
+ fpga = jtag.connected_devices.find { |device| device.is_a? JTAG::Devices::FPGA }
91
+ fatal_error "This board doesn't feature a supported FPGA!" unless fpga
92
+
93
+ #Get the bit-file in question.
94
+ bitstream = Adept::DataFormats::Bitstream.from_file(bitfile_path)
95
+ fpga.configure(bitstream)
96
+
97
+ end
98
+
99
+ connection = get_target_connection
100
+ file = get_target_file
101
+
102
+ begin
103
+ configure_fpga(connection, file)
104
+ rescue Error => e
105
+ puts
106
+ fatal_error e.message
107
+ end
108
+
109
+
110
+
@@ -0,0 +1,73 @@
1
+ # intermediate build files
2
+ *.bgn
3
+ *.bit
4
+ *.bld
5
+ *.cmd_log
6
+ *.drc
7
+ *.ll
8
+ *.lso
9
+ *.msd
10
+ *.msk
11
+ *.ncd
12
+ *.ngc
13
+ *.ngd
14
+ *.ngr
15
+ *.pad
16
+ *.par
17
+ *.pcf
18
+ *.prj
19
+ *.ptwx
20
+ *.rbb
21
+ *.rbd
22
+ *.stx
23
+ *.syr
24
+ *.twr
25
+ *.twx
26
+ *.unroutes
27
+ *.ut
28
+ *.xpi
29
+ *.xst
30
+ *_bitgen.xwbt
31
+ *_envsettings.html
32
+ *_map.map
33
+ *_map.mrp
34
+ *_map.ngm
35
+ *_map.xrpt
36
+ *_ngdbuild.xrpt
37
+ *_pad.csv
38
+ *_pad.txt
39
+ *_par.xrpt
40
+ *_summary.html
41
+ *_summary.xml
42
+ *_usage.xml
43
+ *_xst.xrpt
44
+ *.xmsgs
45
+
46
+ # IP-core-related generated files
47
+ xaw2vhdl.log
48
+
49
+ # project-wide generated files
50
+ *.gise
51
+ par_usage_statistics.html
52
+ usage_statistics_webtalk.html
53
+ webtalk.log
54
+ webtalk_pn.xml
55
+
56
+ # generated folders
57
+ iseconfig/
58
+ xlnx_auto_0_xdb/
59
+ xst/
60
+ _ngo/
61
+ _xmsgs/
62
+
63
+ #Simulation generated files
64
+ *isim_*.exe
65
+ *isim_*.wdb
66
+ fuse.log
67
+ fuse.log
68
+ fuse.xmsgs
69
+ fuseRelaunch.cmd
70
+ isim.cmd
71
+ isim.log
72
+ isim/
73
+ xilinxsim.ini
@@ -0,0 +1,21 @@
1
+ #Basys Board on-board clock.
2
+ NET "clk" LOC = "B8"; # Bank = 0, Signal name = MCLK
3
+
4
+ #Reset button.
5
+ NET "reset" LOC = "G12"; #PB12
6
+
7
+ #EPP Control Signals
8
+ NET "eppAddrStrobe" LOC = "F2"; # Bank = 3
9
+ NET "eppDataStrobe" LOC = "F1"; # Bank = 3
10
+ NET "eppReadNotWrite" LOC = "C2"; # Bank = 3
11
+ NET "eppAck" LOC = "D2"; # Bank = 3
12
+
13
+ #EPP Data Signals
14
+ NET "eppDataBus<0>" LOC = "N2"; # Bank = 2
15
+ NET "eppDataBus<1>" LOC = "M2"; # Bank = 2
16
+ NET "eppDataBus<2>" LOC = "M1"; # Bank = 3
17
+ NET "eppDataBus<3>" LOC = "L1"; # Bank = 3
18
+ NET "eppDataBus<4>" LOC = "L2"; # Bank = 3
19
+ NET "eppDataBus<5>" LOC = "H2"; # Bank = 3
20
+ NET "eppDataBus<6>" LOC = "H1"; # Bank = 3
21
+ NET "eppDataBus<7>" LOC = "H3"; # Bank = 3
@@ -0,0 +1,210 @@
1
+
2
+ ----------------------------------------------------------------------------------
3
+ -- EPP Controller
4
+ --
5
+ -- Original Author: Chris McClelland
6
+ -- Altered for use with EPP periperhals by Kyle Temkin
7
+ --
8
+ -- Portions copyright (c) 2013 Binghamton University
9
+ -- Copyright (c) 2011 Chris McClelland
10
+ --
11
+ -- This program is free software: you can redistribute it and/or modify
12
+ -- it under the terms of the GNU General Public License as published by
13
+ -- the Free Software Foundation, either version 3 of the License, or
14
+ -- (at your option) any later version.
15
+ --
16
+ -- This program is distributed in the hope that it will be useful,
17
+ -- but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ -- GNU General Public License for more details.
20
+ --
21
+ -- You should have received a copy of the GNU General Public License
22
+ -- along with this program. If not, see <http://www.gnu.org/licenses/>.-
23
+ --
24
+ ----------------------------------------------------------------------------------
25
+ library ieee;
26
+
27
+ use ieee.std_logic_1164.all;
28
+ use ieee.numeric_std.all;
29
+
30
+ entity TopLevel is
31
+ port(
32
+ -- Main 50MHz clock
33
+ clk : in std_logic;
34
+
35
+ -- Reset button (BTN0)
36
+ reset : in std_logic;
37
+
38
+ -- Host interface signals
39
+ eppDataBus : inout std_logic_vector(7 downto 0);
40
+ eppAddrStrobe : in std_logic;
41
+ eppDataStrobe : in std_logic;
42
+ eppReadNotWrite : in std_logic;
43
+ eppAck : out std_logic
44
+ );
45
+ end TopLevel;
46
+
47
+ architecture Behavioural of TopLevel is
48
+ type State is (-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
49
+
50
+ STATE_IDLE,
51
+
52
+ STATE_ADDR_WRITE_EXEC,
53
+ STATE_ADDR_WRITE_ACK,
54
+
55
+ STATE_DATA_WRITE_EXEC,
56
+ STATE_DATA_WRITE_ACK,
57
+
58
+ STATE_DATA_READ_EXEC,
59
+ STATE_DATA_READ_ACK
60
+ );
61
+
62
+ -- State and next-state
63
+ signal iThisState, iNextState : State;
64
+
65
+ -- Synchronised versions of asynchronous inputs
66
+ signal iSyncAddrStrobe : std_logic;
67
+ signal iSyncDataStrobe : std_logic;
68
+ signal iSyncReadNotWrite : std_logic;
69
+
70
+ -- Data to be mux'd back to host
71
+ signal iDataOutput : std_logic_vector(7 downto 0);
72
+
73
+ -- Registers
74
+ signal iThisRegAddr, iNextRegAddr : std_logic_vector(1 downto 0);
75
+ signal iThisAck, iNextAck : std_logic;
76
+ signal iThisR0, iNextR0 : std_logic_vector(7 downto 0);
77
+ signal iThisR1, iNextR1 : std_logic_vector(7 downto 0);
78
+ signal iThisR2, iNextR2 : std_logic_vector(7 downto 0);
79
+ signal iThisR3, iNextR3 : std_logic_vector(7 downto 0);
80
+
81
+ begin
82
+
83
+ -- Drive the outputs
84
+ eppAck <= iThisAck;
85
+
86
+ -- EPP operation
87
+ eppDataBus <=
88
+ iDataOutput when ( eppReadNotWrite = '1' ) else
89
+ "ZZZZZZZZ";
90
+
91
+ with ( iThisRegAddr ) select
92
+ iDataOutput <=
93
+ iThisR0 when "00",
94
+ iThisR1 when "01",
95
+ iThisR2 when "10",
96
+ iThisR3 when others;
97
+
98
+ -- Infer registers
99
+ process(clk, reset)
100
+ begin
101
+ if ( reset = '1' ) then
102
+ iThisState <= STATE_IDLE;
103
+ iThisRegAddr <= (others => '0');
104
+ iThisR0 <= (others => '0');
105
+ iThisR1 <= (others => '0');
106
+ iThisR2 <= (others => '0');
107
+ iThisR3 <= (others => '0');
108
+ iThisAck <= '0';
109
+ iSyncAddrStrobe <= '1';
110
+ iSyncDataStrobe <= '1';
111
+ iSyncReadNotWrite <= '1';
112
+ elsif ( clk'event and clk = '1' ) then
113
+ iThisState <= iNextState;
114
+ iThisRegAddr <= iNextRegAddr;
115
+ iThisR0 <= iNextR0;
116
+ iThisR1 <= iNextR1;
117
+ iThisR2 <= iNextR2;
118
+ iThisR3 <= iNextR3;
119
+ iThisAck <= iNextAck;
120
+ iSyncAddrStrobe <= eppAddrStrobe;
121
+ iSyncDataStrobe <= eppDataStrobe;
122
+ iSyncReadNotWrite <= eppReadNotWrite;
123
+ end if;
124
+ end process;
125
+
126
+ -- Next state logic
127
+ process(
128
+ eppDataBus, iThisState, iThisRegAddr,
129
+ iSyncAddrStrobe, iSyncDataStrobe, iSyncReadNotWrite,
130
+ iThisR0, iThisR1, iThisR2, iThisR3)
131
+ begin
132
+ iNextAck <= '0';
133
+ iNextState <= STATE_IDLE;
134
+ iNextRegAddr <= iThisRegAddr;
135
+ iNextR0 <= iThisR0;
136
+ iNextR1 <= iThisR1;
137
+ iNextR2 <= iThisR2;
138
+ iNextR3 <= iThisR3;
139
+ case iThisState is
140
+ when STATE_IDLE =>
141
+ if ( iSyncAddrStrobe = '0' ) then
142
+ -- Address can only be written, not read
143
+ if ( iSyncReadNotWrite = '0' ) then
144
+ iNextState <= STATE_ADDR_WRITE_EXEC;
145
+ end if;
146
+ elsif ( iSyncDataStrobe = '0' ) then
147
+ -- Register read or write
148
+ if ( iSyncReadNotWrite = '0' ) then
149
+ iNextState <= STATE_DATA_WRITE_EXEC;
150
+ else
151
+ iNextState <= STATE_DATA_READ_EXEC;
152
+ end if;
153
+ end if;
154
+
155
+ -- Write address register
156
+ when STATE_ADDR_WRITE_EXEC =>
157
+ iNextRegAddr <= eppDataBus(1 downto 0);
158
+ iNextState <= STATE_ADDR_WRITE_ACK;
159
+ iNextAck <= '0';
160
+ when STATE_ADDR_WRITE_ACK =>
161
+ if ( iSyncAddrStrobe = '0' ) then
162
+ iNextState <= STATE_ADDR_WRITE_ACK;
163
+ iNextAck <= '1';
164
+ else
165
+ iNextState <= STATE_IDLE;
166
+ iNextAck <= '0';
167
+ end if;
168
+
169
+ -- Write data register
170
+ when STATE_DATA_WRITE_EXEC =>
171
+ case iThisRegAddr is
172
+ when "00" =>
173
+ iNextR0 <= eppDataBus;
174
+ when "01" =>
175
+ iNextR1 <= eppDataBus;
176
+ when "10" =>
177
+ iNextR2 <= eppDataBus;
178
+ when others =>
179
+ iNextR3 <= eppDataBus;
180
+ end case;
181
+ iNextState <= STATE_DATA_WRITE_ACK;
182
+ iNextAck <= '1';
183
+ when STATE_DATA_WRITE_ACK =>
184
+ if ( iSyncDataStrobe = '0' ) then
185
+ iNextState <= STATE_DATA_WRITE_ACK;
186
+ iNextAck <= '1';
187
+ else
188
+ iNextState <= STATE_IDLE;
189
+ iNextAck <= '0';
190
+ end if;
191
+
192
+ -- Read data register
193
+ when STATE_DATA_READ_EXEC =>
194
+ iNextAck <= '1';
195
+ iNextState <= STATE_DATA_READ_ACK;
196
+ when STATE_DATA_READ_ACK =>
197
+ if ( iSyncDataStrobe = '0' ) then
198
+ iNextState <= STATE_DATA_READ_ACK;
199
+ iNextAck <= '1';
200
+ else
201
+ iNextState <= STATE_IDLE;
202
+ iNextAck <= '0';
203
+ end if;
204
+
205
+ -- Some unknown state
206
+ when others =>
207
+ iNextState <= STATE_IDLE;
208
+ end case;
209
+ end process;
210
+ end Behavioural;