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