reggae_eda 0.0.6
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.
- checksums.yaml +7 -0
- data/assets/Nexys4DDR_Master.xdc +255 -0
- data/assets/fifo.vhd +109 -0
- data/assets/flag_buf.vhd +45 -0
- data/assets/mod_m_counter.vhd +36 -0
- data/assets/slow_ticker.vhd +49 -0
- data/assets/uart.vhd +69 -0
- data/assets/uart_bus_master.vhd +256 -0
- data/assets/uart_rx.vhd +90 -0
- data/assets/uart_tx.vhd +102 -0
- data/bin/reggae +6 -0
- data/lib/reggae.rb +3 -0
- data/lib/reggae/ast.rb +72 -0
- data/lib/reggae/code.rb +55 -0
- data/lib/reggae/compiler.rb +110 -0
- data/lib/reggae/parser.rb +281 -0
- data/lib/reggae/pretty_printer.rb +107 -0
- data/lib/reggae/version.rb +3 -0
- data/lib/reggae/vhdl_generator.rb +973 -0
- data/lib/reggae/visitor.rb +107 -0
- data/tests/regmap.sexp +139 -0
- metadata +64 -0
data/assets/uart_tx.vhd
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
-- pong p.chu code.
|
2
|
+
library ieee;
|
3
|
+
use ieee.std_logic_1164.all;
|
4
|
+
use ieee.numeric_std.all;
|
5
|
+
entity uart_tx is
|
6
|
+
generic(
|
7
|
+
DBIT : integer := 8; -- # data bits
|
8
|
+
SB_TICK : integer := 16 -- # ticks for stop bits
|
9
|
+
);
|
10
|
+
port(
|
11
|
+
clk, reset_n : in std_logic;
|
12
|
+
tx_start : in std_logic;
|
13
|
+
s_tick : in std_logic;
|
14
|
+
din : in std_logic_vector(7 downto 0);
|
15
|
+
tx_done_tick : out std_logic;
|
16
|
+
tx : out std_logic
|
17
|
+
);
|
18
|
+
end uart_tx;
|
19
|
+
|
20
|
+
architecture arch of uart_tx is
|
21
|
+
type state_type is (idle, start, data, stop);
|
22
|
+
signal state_reg, state_next : state_type;
|
23
|
+
signal s_reg, s_next : unsigned(3 downto 0);
|
24
|
+
signal n_reg, n_next : unsigned(2 downto 0);
|
25
|
+
signal b_reg, b_next : std_logic_vector(7 downto 0);
|
26
|
+
signal tx_reg, tx_next : std_logic;
|
27
|
+
begin
|
28
|
+
-- FSMD state & data registers
|
29
|
+
process(clk, reset_n)
|
30
|
+
begin
|
31
|
+
if reset_n = '0' then
|
32
|
+
state_reg <= idle;
|
33
|
+
s_reg <= (others => '0');
|
34
|
+
n_reg <= (others => '0');
|
35
|
+
b_reg <= (others => '0');
|
36
|
+
tx_reg <= '1';
|
37
|
+
elsif (clk'event and clk = '1') then
|
38
|
+
state_reg <= state_next;
|
39
|
+
s_reg <= s_next;
|
40
|
+
n_reg <= n_next;
|
41
|
+
b_reg <= b_next;
|
42
|
+
tx_reg <= tx_next;
|
43
|
+
end if;
|
44
|
+
end process;
|
45
|
+
-- next-state logic & data path functional units/routing
|
46
|
+
process(state_reg, s_reg, n_reg, b_reg, s_tick,
|
47
|
+
tx_reg, tx_start, din)
|
48
|
+
begin
|
49
|
+
state_next <= state_reg;
|
50
|
+
s_next <= s_reg;
|
51
|
+
n_next <= n_reg;
|
52
|
+
b_next <= b_reg;
|
53
|
+
tx_next <= tx_reg;
|
54
|
+
tx_done_tick <= '0';
|
55
|
+
case state_reg is
|
56
|
+
when idle =>
|
57
|
+
tx_next <= '1';
|
58
|
+
if tx_start = '1' then
|
59
|
+
state_next <= start;
|
60
|
+
s_next <= (others => '0');
|
61
|
+
b_next <= din;
|
62
|
+
end if;
|
63
|
+
when start =>
|
64
|
+
tx_next <= '0';
|
65
|
+
if (s_tick = '1') then
|
66
|
+
if s_reg = 15 then
|
67
|
+
state_next <= data;
|
68
|
+
s_next <= (others => '0');
|
69
|
+
n_next <= (others => '0');
|
70
|
+
else
|
71
|
+
s_next <= s_reg + 1;
|
72
|
+
end if;
|
73
|
+
end if;
|
74
|
+
when data =>
|
75
|
+
tx_next <= b_reg(0);
|
76
|
+
if (s_tick = '1') then
|
77
|
+
if s_reg = 15 then
|
78
|
+
s_next <= (others => '0');
|
79
|
+
b_next <= '0' & b_reg(7 downto 1);
|
80
|
+
if n_reg = (DBIT-1) then
|
81
|
+
state_next <= stop;
|
82
|
+
else
|
83
|
+
n_next <= n_reg + 1;
|
84
|
+
end if;
|
85
|
+
else
|
86
|
+
s_next <= s_reg + 1;
|
87
|
+
end if;
|
88
|
+
end if;
|
89
|
+
when stop =>
|
90
|
+
tx_next <= '1';
|
91
|
+
if (s_tick = '1') then
|
92
|
+
if s_reg = (SB_TICK-1) then
|
93
|
+
state_next <= idle;
|
94
|
+
tx_done_tick <= '1';
|
95
|
+
else
|
96
|
+
s_next <= s_reg + 1;
|
97
|
+
end if;
|
98
|
+
end if;
|
99
|
+
end case;
|
100
|
+
end process;
|
101
|
+
tx <= tx_reg;
|
102
|
+
end arch;
|
data/bin/reggae
ADDED
data/lib/reggae.rb
ADDED
data/lib/reggae/ast.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Reggae
|
2
|
+
|
3
|
+
module Visitable
|
4
|
+
def accept(visitor, arg=nil)
|
5
|
+
name = self.class.name.split(/::/)[1]
|
6
|
+
visitor.send("visit#{name}".to_sym, self ,arg) # Metaprograming !
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MemoryMap < Struct.new(:name,:parameters,:zones,:comments)
|
11
|
+
include Visitable
|
12
|
+
end
|
13
|
+
|
14
|
+
class Comment < Struct.new(:txt)
|
15
|
+
include Visitable
|
16
|
+
end
|
17
|
+
|
18
|
+
class Parameters < Struct.new(:bus,:range)
|
19
|
+
include Visitable
|
20
|
+
end
|
21
|
+
|
22
|
+
class Bus < Struct.new(:frequency,:address_size,:data_size)
|
23
|
+
include Visitable
|
24
|
+
end
|
25
|
+
|
26
|
+
class Range < Struct.new(:from,:to)
|
27
|
+
include Visitable
|
28
|
+
end
|
29
|
+
|
30
|
+
class Zone < Struct.new(:name,:range,:registers,:subzones,:instances)
|
31
|
+
include Visitable
|
32
|
+
end
|
33
|
+
|
34
|
+
class Instance < Struct.new(:name,:mapping)
|
35
|
+
include Visitable
|
36
|
+
end
|
37
|
+
|
38
|
+
class Connect < Struct.new(:formal,:actual)
|
39
|
+
include Visitable
|
40
|
+
end
|
41
|
+
|
42
|
+
class Input < Struct.new(:name)
|
43
|
+
include Visitable
|
44
|
+
end
|
45
|
+
|
46
|
+
class Output < Struct.new(:name)
|
47
|
+
include Visitable
|
48
|
+
end
|
49
|
+
|
50
|
+
class RegSig < Struct.new(:name,:field)
|
51
|
+
include Visitable
|
52
|
+
end
|
53
|
+
|
54
|
+
class Subzone < Zone
|
55
|
+
include Visitable
|
56
|
+
end
|
57
|
+
|
58
|
+
class Register < Struct.new(:name,:address,:init,:sampling,:writable,:bits,:bitfields)
|
59
|
+
include Visitable
|
60
|
+
def bit(n)
|
61
|
+
@bits.find{|bit| bit.position==n}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Bit < Struct.new(:position,:name,:purpose,:toggle)
|
66
|
+
include Visitable
|
67
|
+
end
|
68
|
+
|
69
|
+
class Bitfield < Bit
|
70
|
+
include Visitable
|
71
|
+
end
|
72
|
+
end
|
data/lib/reggae/code.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
class Code
|
2
|
+
|
3
|
+
attr_accessor :indent,:code
|
4
|
+
|
5
|
+
def initialize indent=0
|
6
|
+
@code=[]
|
7
|
+
@indent=indent
|
8
|
+
end
|
9
|
+
|
10
|
+
def empty?
|
11
|
+
@code.size==0
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(str)
|
15
|
+
if str.is_a? Code
|
16
|
+
str.code.each do |line|
|
17
|
+
@code << " "*@indent+line
|
18
|
+
end
|
19
|
+
elsif str.nil?
|
20
|
+
else
|
21
|
+
@code << " "*@indent+str
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def finalize dot=false
|
26
|
+
if dot
|
27
|
+
return @code.join('\n')
|
28
|
+
end
|
29
|
+
@code.join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
def newline
|
33
|
+
@code << " "
|
34
|
+
end
|
35
|
+
|
36
|
+
def save_as filename,verbose=true
|
37
|
+
str=self.finalize
|
38
|
+
if filename.end_with? ".vhd"
|
39
|
+
str=clean_vhdl(str)
|
40
|
+
end
|
41
|
+
File.open(filename,'w'){|f| f.puts(str)}
|
42
|
+
puts "saved code in file #{filename}" if verbose
|
43
|
+
return filename
|
44
|
+
end
|
45
|
+
|
46
|
+
def size
|
47
|
+
@code.size
|
48
|
+
end
|
49
|
+
|
50
|
+
def clean_vhdl str
|
51
|
+
str1=str.gsub(/\;\s*\)/,")")
|
52
|
+
str2=str1.gsub(/\,\s*\)/,")")
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'optparse'
|
3
|
+
require_relative 'parser'
|
4
|
+
require_relative 'pretty_printer'
|
5
|
+
require_relative 'vhdl_generator'
|
6
|
+
require_relative 'version'
|
7
|
+
|
8
|
+
module Reggae
|
9
|
+
|
10
|
+
class Compiler
|
11
|
+
|
12
|
+
attr_accessor :ast
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
puts "Reggae generator #{VERSION}"
|
16
|
+
@options={}
|
17
|
+
end
|
18
|
+
|
19
|
+
def analyze_options args
|
20
|
+
args << "-h" if args.empty?
|
21
|
+
|
22
|
+
opt_parser = OptionParser.new do |opts|
|
23
|
+
opts.banner = "Usage: reggae <filename.sexp>"
|
24
|
+
|
25
|
+
opts.on("-v", "--version", "Prints version") do
|
26
|
+
puts VERSION
|
27
|
+
abort
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Prints this help") do
|
31
|
+
puts
|
32
|
+
puts "Generates an IP-based system, from its memory-map expressed in s-expressions."
|
33
|
+
puts
|
34
|
+
puts "Author mail: jean-christophe.le_lann@ensta-bretagne.fr"
|
35
|
+
puts
|
36
|
+
@options[:show_help]=true
|
37
|
+
puts opts
|
38
|
+
abort
|
39
|
+
end
|
40
|
+
|
41
|
+
opts.on("-s", "--system", "Generates a top-level system") do
|
42
|
+
@options[:gen_system]=true
|
43
|
+
end
|
44
|
+
|
45
|
+
opts.on("-d","Shows VHDL generated in the terminal,during generation") do
|
46
|
+
@options[:show_code]=true
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on("-u", "--include_uart", "Generates an UART Master in the system top-level") do
|
50
|
+
@options[:include_uart]=true
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on("--gen_ruby", "Generates Ruby code to interact with the system from a PC host") do
|
54
|
+
@options[:gen_ruby]=true
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on("-x", "--gen_xdc", "Generates a Xilinx XDC constraint file for Artix7 FPGA (IP only)") do
|
58
|
+
@options[:gen_xdc]=true
|
59
|
+
end
|
60
|
+
|
61
|
+
opts.on("--from_vivado_hls", "Indicates that the sexp file is generated from VHDL_WRAP tuned for VivadoHLS") do
|
62
|
+
@options[:from_vivado_hls]=true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
begin
|
67
|
+
opt_parser.parse!(args)
|
68
|
+
rescue Exception => e
|
69
|
+
puts e
|
70
|
+
#puts e.backtrace
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
@filename = ARGV.pop
|
74
|
+
$dirname = File.dirname(@filename) if @filename
|
75
|
+
unless @filename or @options[:show_help]
|
76
|
+
puts "Need to specify a filename to process"
|
77
|
+
#exit
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def compile
|
82
|
+
if @options.any?
|
83
|
+
puts
|
84
|
+
puts "running with the following options :"
|
85
|
+
pp @options
|
86
|
+
puts
|
87
|
+
end
|
88
|
+
@ast=parse(@filename)
|
89
|
+
#pretty_print
|
90
|
+
generate_vhdl
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse filename
|
94
|
+
puts "=> parsing #{filename}"
|
95
|
+
$working_dir=Dir.pwd
|
96
|
+
@ast=Reggae::Parser.new.parse(filename)
|
97
|
+
end
|
98
|
+
|
99
|
+
def pretty_print
|
100
|
+
puts "=> pretty print..."
|
101
|
+
Reggae::Visitor.new.visit(ast)
|
102
|
+
end
|
103
|
+
|
104
|
+
def generate_vhdl
|
105
|
+
puts "=> generating VHDL..."
|
106
|
+
Reggae::VHDLGenerator.new(@options).generate_from(ast)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require 'sxp'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
require_relative 'ast'
|
5
|
+
|
6
|
+
class Array
|
7
|
+
def header
|
8
|
+
self.first
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Reggae
|
13
|
+
|
14
|
+
class Parser
|
15
|
+
|
16
|
+
def parse filename
|
17
|
+
str=IO.read(filename)
|
18
|
+
str=fix_sexpistol_bug(str)
|
19
|
+
mm_a=SXP.read(str)
|
20
|
+
parseMemoryMap(mm_a)
|
21
|
+
end
|
22
|
+
|
23
|
+
def fix_sexpistol_bug str
|
24
|
+
s1=str.gsub(/0x(\w+)/,'\1') #0x....
|
25
|
+
s2=s1.gsub(/(\d+)\.\.(\d+)/,'\1 \2') #range
|
26
|
+
end
|
27
|
+
|
28
|
+
def parseMemoryMap ary
|
29
|
+
mm=MemoryMap.new(nil,nil,[])
|
30
|
+
ary.shift
|
31
|
+
mm.name=ary.shift
|
32
|
+
while ary.any?
|
33
|
+
case h=ary.first.header
|
34
|
+
when :comment
|
35
|
+
mm.comments ||=[]
|
36
|
+
mm.comments << parseComment(ary.shift)
|
37
|
+
when :parameters
|
38
|
+
mm.parameters=parseParameters(ary.shift)
|
39
|
+
when :zone
|
40
|
+
mm.zones << parseZone(ary.shift)
|
41
|
+
else
|
42
|
+
raise "error.expecting 'zone' or 'parameters'. got a '#{h}'"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
mm
|
46
|
+
end
|
47
|
+
|
48
|
+
def parseComment ary
|
49
|
+
comment=Comment.new(nil)
|
50
|
+
ary.shift
|
51
|
+
comment.txt=ary.shift
|
52
|
+
comment
|
53
|
+
end
|
54
|
+
|
55
|
+
def parseParameters ary
|
56
|
+
param=Parameters.new(nil,nil)
|
57
|
+
ary.shift
|
58
|
+
while ary.any?
|
59
|
+
case h=ary.first.header
|
60
|
+
when :bus
|
61
|
+
param.bus=parseBus(ary.shift)
|
62
|
+
when :range
|
63
|
+
param.range=parseRange(ary.shift)
|
64
|
+
else
|
65
|
+
raise "error.expecting 'bus' or 'range'. Got a '#{h}'"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@param=param
|
69
|
+
param
|
70
|
+
end
|
71
|
+
|
72
|
+
def parseBus ary
|
73
|
+
bus=Bus.new(nil,nil,nil)
|
74
|
+
ary.shift
|
75
|
+
while ary.any?
|
76
|
+
case h=ary.first.header
|
77
|
+
when :frequency
|
78
|
+
bus.frequency=ary.first.last.to_i
|
79
|
+
when :address_size
|
80
|
+
bus.address_size=ary.first.last.to_i
|
81
|
+
when :data_size
|
82
|
+
bus.data_size=ary.first.last.to_i
|
83
|
+
else
|
84
|
+
raise "error during parseBus. Expecting 'frequency','address_size' or 'data_size'. Got '#{h}'"
|
85
|
+
end
|
86
|
+
ary.shift
|
87
|
+
end
|
88
|
+
bus
|
89
|
+
end
|
90
|
+
|
91
|
+
def parseHexa sym
|
92
|
+
"0x#{sym}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def parseRange ary
|
96
|
+
rg=Range.new(nil,nil)
|
97
|
+
rg.from=parseHexa(ary[1])
|
98
|
+
rg.to=parseHexa(ary[2])
|
99
|
+
rg
|
100
|
+
end
|
101
|
+
|
102
|
+
def parseZone ary
|
103
|
+
zone=Zone.new(nil,nil,[],[],[])
|
104
|
+
ary.shift
|
105
|
+
zone.name=ary.shift
|
106
|
+
while ary.any?
|
107
|
+
case h=ary.first.header
|
108
|
+
when :range
|
109
|
+
zone.range=parseRange(ary.shift)
|
110
|
+
when :register
|
111
|
+
zone.registers << parseRegister(ary.shift)
|
112
|
+
when :subzone
|
113
|
+
zone.subzones << parseSubZone(ary.shift)
|
114
|
+
when :instance
|
115
|
+
zone.instances << parseInstance(ary.shift)
|
116
|
+
else
|
117
|
+
raise "error during parseZone.Expecting 'range' or 'register'. Got '#{h}'"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
zone
|
121
|
+
end
|
122
|
+
|
123
|
+
def parseInstance ary
|
124
|
+
inst=Instance.new(nil,[])
|
125
|
+
ary.shift
|
126
|
+
inst.name=ary.shift
|
127
|
+
while ary.any?
|
128
|
+
case h=ary.first.header
|
129
|
+
when :connect
|
130
|
+
inst.mapping << parseConnect(ary.shift)
|
131
|
+
else
|
132
|
+
raise "error during parseZone.Expecting 'connect'. Got '#{h}'"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
inst
|
136
|
+
end
|
137
|
+
|
138
|
+
def parseConnect ary
|
139
|
+
map=Connect.new(nil,nil)
|
140
|
+
ary.shift
|
141
|
+
map.formal=parseFormalIO(ary.shift)
|
142
|
+
map.actual=parseRegSig(ary.shift)
|
143
|
+
map
|
144
|
+
end
|
145
|
+
|
146
|
+
def parseFormalIO ary
|
147
|
+
dir=ary.shift
|
148
|
+
case dir
|
149
|
+
when :input
|
150
|
+
return Input.new(ary.shift)
|
151
|
+
when :output
|
152
|
+
return Output.new(ary.shift)
|
153
|
+
else
|
154
|
+
raise "error in formal io : #{ary}"
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def parseRegSig ary
|
159
|
+
sig=RegSig.new(nil,nil)
|
160
|
+
ary.shift #register
|
161
|
+
sig.name=ary.shift
|
162
|
+
sig.field=ary.shift
|
163
|
+
sig
|
164
|
+
end
|
165
|
+
|
166
|
+
def parseSubZone ary
|
167
|
+
zone=Subzone.new(nil,nil,[],[])
|
168
|
+
ary.shift
|
169
|
+
zone.name=ary.shift
|
170
|
+
while ary.any?
|
171
|
+
case h=ary.first.header
|
172
|
+
when :range
|
173
|
+
zone.range=parseRange(ary.shift)
|
174
|
+
when :register
|
175
|
+
zone.registers << parseRegister(ary.shift)
|
176
|
+
when :subzone
|
177
|
+
zone.subzones << parseSubZone(ary.shift)
|
178
|
+
else
|
179
|
+
raise "error during parseZone.Expecting 'range' or 'register'. Got '#{h}'"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
zone
|
183
|
+
end
|
184
|
+
|
185
|
+
def parseRegister ary
|
186
|
+
reg=Register.new(nil,nil,nil,nil,true,[],[])
|
187
|
+
ary.shift
|
188
|
+
reg.name=ary.shift
|
189
|
+
while ary.any?
|
190
|
+
case h=ary.first.header
|
191
|
+
when :address
|
192
|
+
reg.address=parseAddress(ary.shift)
|
193
|
+
when :init
|
194
|
+
reg.init=parseInit(ary.shift)
|
195
|
+
when :sampling
|
196
|
+
reg.sampling=parseSampling(ary.shift)
|
197
|
+
when :writable
|
198
|
+
reg.writable=parseWritable(ary.shift)
|
199
|
+
when :bit
|
200
|
+
reg.bits << parseBit(ary.shift)
|
201
|
+
when :bitfield
|
202
|
+
reg.bitfields << parseBitfield(ary.shift)
|
203
|
+
else
|
204
|
+
raise "Error during parseRegister"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
if reg.bits.empty? and reg.bitfields.empty?
|
208
|
+
bus_size=@param.bus.data_size
|
209
|
+
position=[bus_size-1,0]
|
210
|
+
reg.bitfields << Bitfield.new(position,name=:value,nil,nil)
|
211
|
+
end
|
212
|
+
reg
|
213
|
+
end
|
214
|
+
|
215
|
+
def parseAddress ary
|
216
|
+
parseHexa(ary.last)
|
217
|
+
end
|
218
|
+
|
219
|
+
def parseInit ary
|
220
|
+
parseHexa(ary.last)
|
221
|
+
end
|
222
|
+
|
223
|
+
def parseSampling ary
|
224
|
+
ary.shift
|
225
|
+
ary.shift==:true
|
226
|
+
end
|
227
|
+
|
228
|
+
def parseWritable ary
|
229
|
+
ary.shift
|
230
|
+
ary.shift==:true
|
231
|
+
end
|
232
|
+
|
233
|
+
def parseBit ary
|
234
|
+
bit=Bit.new(nil,nil,nil,nil)
|
235
|
+
ary.shift
|
236
|
+
bit.position=ary.shift.to_i
|
237
|
+
while ary.any?
|
238
|
+
case h=ary.first.header
|
239
|
+
when :name
|
240
|
+
bit.name=parseName(ary.shift)
|
241
|
+
when :purpose
|
242
|
+
bit.purpose=parsePurpose(ary.shift)
|
243
|
+
when :toggle
|
244
|
+
bit.toggle=parseToggle(ary.shift)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
bit
|
248
|
+
end
|
249
|
+
|
250
|
+
def parseName ary
|
251
|
+
ary[1]
|
252
|
+
end
|
253
|
+
|
254
|
+
def parsePurpose ary
|
255
|
+
ary[1]
|
256
|
+
end
|
257
|
+
|
258
|
+
def parseToggle ary
|
259
|
+
ary[1]==:true
|
260
|
+
end
|
261
|
+
|
262
|
+
def parseBitfield ary
|
263
|
+
bf=Bitfield.new(nil,nil,nil,nil)
|
264
|
+
ary.shift
|
265
|
+
bf.position=[]
|
266
|
+
bf.position << ary.shift.to_s.to_i
|
267
|
+
bf.position << ary.shift.to_s.to_i
|
268
|
+
while ary.any?
|
269
|
+
case h=ary.first.header
|
270
|
+
when :name
|
271
|
+
bf.name=parseName(ary.shift)
|
272
|
+
when :purpose
|
273
|
+
bf.purpose=parsePurpose(ary.shift)
|
274
|
+
when :toggle
|
275
|
+
bf.toggle=parseToggle(ary.shift)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
bf
|
279
|
+
end
|
280
|
+
end #parser
|
281
|
+
end #module
|