2
2
// ////////////////////////////////////////////////////////////////////////////////
3
3
// Company:
4
4
// Engineer: Chris Shucksmith
5
- // Module: Scanning XML decoder, like a physical sax parser
5
+ // Module: High speed serial XML classifier, like a physical sax parser
6
+ //
7
+ // XML messages are delivered byte at a time. Internally we buffer four bytes from
8
+ // the input so that the comment/data streams can be seperated. The input stream
9
+ // can be paused for an arbitary period by lowering 'valid' which holds the pipeline
10
+ // and state machines in position.
11
+ //
12
+ // If eom is asserted, any 'valid' left in the pipeline is flushed iresspective of
13
+ // the valid signal. For the puposes of look ahead, bytes beyond the eop are defined
14
+ // as null so that processing can complete. One cycle after the last valid byte is
15
+ // flushed parser state is reset.
16
+ //
17
+ // As data bytes clock out of the 4 byte pipeline, several control signals are present
18
+ // to qualify where the data is a) valid, b) in a comment, tag or data c) position
19
+ // within the current document (tags visited at each nesting depth). bytes within tags
20
+ // are further classified into name, key and value elemnts.
21
+ //
22
+ // Transitions between tag nesting depths occur after presening the '>' tag close
23
+ // character, at whcih tagDepth, depthPush, depthPop and depth stack s0..s7 are updated
24
+ // for the cycle following a tag-close character '>'.
25
+ //
26
+ // After configuration an eop event is internally generated which ensures the nesting
27
+ // stack is clear if it is synthesised to block ram.
28
+ //
29
+ // XML doctypes are treated as a special case of self-closing tag which does not
30
+ // adjust the tag depth.
31
+ //
32
+ // This module can scan XML content at 1gb+ line speed on most mid range FPGAs
33
+ //
6
34
// ////////////////////////////////////////////////////////////////////////////////
7
35
module XMLDecoder (
8
36
input CLOCK,
9
- input reset,
37
+
10
38
input inValid,
39
+ input inEop,
11
40
input [7 :0 ] in,
12
- input newMsg,
13
41
14
- output outValid,
15
- output [7 :0 ] out,
16
- output outNewMsg,
42
+ output reg outValid = 0 ,
43
+ output reg outEop = 0 ,
44
+ output reg [7 :0 ] out = 0 ,
45
+
17
46
output isData,
18
47
output isTag,
19
- output isTagName,
20
- output isTagKey,
21
- output isTagValue,
22
- output isComment,
48
+ output reg isTagName = 0 ,
49
+ output reg isTagKey = 0 ,
50
+ output reg isTagValue = 0 ,
51
+ output reg isComment = 0 ,
23
52
24
- output [3 :0 ] tagDepth,
25
- output depthPush,
26
- output depthPop,
53
+ output reg [3 :0 ] tagDepth = 0 ,
54
+ output reg depthPush = 0 ,
55
+ output reg depthPop = 0 ,
27
56
28
57
output [7 :0 ] s0,
29
58
output [7 :0 ] s1,
@@ -35,46 +64,41 @@ module XMLDecoder(
35
64
output [7 :0 ] s7
36
65
);
37
66
38
- reg rnnn = 1 ;
39
- reg rnn = 0 ;
40
- reg rn = 0 ;
41
- reg r = 0 ;
67
+ reg eopn = 1 ;
68
+ reg eopnn = 1 ;
69
+ reg eopnnn = 1 ;
42
70
43
71
reg vnnn = 0 ;
44
72
reg vnn = 0 ;
45
73
reg vn = 0 ;
46
- reg v = 0 ;
74
+ // g v = 0;
47
75
reg vp = 0 ;
48
76
49
77
reg [7 :0 ] snnn = 0 ;
50
78
reg [7 :0 ] snn = 0 ;
51
79
reg [7 :0 ] sn = 0 ;
52
- reg [7 :0 ] s = 0 ;
80
+ // g [7:0] out = 0;
53
81
reg [7 :0 ] sp = 0 ;
54
82
reg [7 :0 ] spp = 0 ;
55
83
reg [7 :0 ] sppp = 0 ;
56
84
57
- reg _isTagName = 0 ;
58
- reg _isTagKey = 0 ;
59
- reg _isTagValue = 0 ;
60
- reg _isClosingTag = 0 ;
61
- reg _isSelfClosingTag = 0 ;
62
- reg _isComment = 0 ;
85
+ reg isClosingTag = 0 ;
86
+ reg isSelfClosingTag = 0 ;
87
+
88
+ reg intag = 0 ; // state of the input stream, after strippping comments: 1=tag 0=data
89
+
63
90
64
- reg intag = 0 ;
65
- reg [3 :0 ] tagdepth = 0 ;
66
91
reg [7 :0 ] tagno [0 :7 ]; // tag position at depth N.. if large enough will instantiate a block ram
67
- reg _isDepthPush = 0 ;
68
- reg _isDepthPop = 0 ;
69
92
70
93
// XML comment is <!--
71
94
wire onTagStartNext = sn == "<" && ! (snn== "!" && snnn== "-" ); // '<' but not <!-
72
- wire onTagClose = (s == ">" ); // '>'
73
- wire onSelfCloseTag = (s == "/" || s == "?" ) && sn == ">" ; // consider XML doctype self-closing
95
+ wire onTagClose = (out == ">" ); // '>'
96
+ wire onSelfCloseTag = (out == "/" || out == "?" ) && sn == ">" ; // consider XML doctype self-closing
74
97
wire onCloseThenData = onTagClose && sn != "<" ;
75
98
76
- wire _isOpeningTag = intag && ! _isSelfClosingTag && ! _isClosingTag;
77
- wire _isData = outValid && ! intag && ! _isComment;
99
+ wire isOpeningTag = intag && ! isSelfClosingTag && ! isClosingTag;
100
+ wire _isData = outValid && ! intag && ! isComment;
101
+ wire _isTag = intag && ! isComment;
78
102
79
103
// export the stack depth positions
80
104
assign s0 = tagno[0 ];
@@ -90,94 +114,92 @@ module XMLDecoder(
90
114
initial $readmemh ("xml/stack_zeros.txt" , tagno);
91
115
92
116
always @(posedge CLOCK) begin
93
- if (inValid || vnn || vn || v) begin
117
+ // pipeline the input so that we can see ahead by 4 'valid' characters to separate comment/data streams
118
+ // If eop is set, continue to flush the pipeline irrespective of 'valid' being de-asserted
119
+
120
+ // extend (ripple) eop
121
+ eopnnn <= inEop;
122
+ eopnn <= eopnnn;
123
+ eopn <= eopnn;
124
+ outEop <= eopn;
125
+
126
+ if (inValid || eopn || eopnn || eopnnn || inEop) begin
127
+
94
128
// ripple for valid signal
95
- vnnn <= inValid;
96
- vnn <= vnnn;
97
- vn <= vnn;
98
- v <= vn;
99
- vp <= v ;
129
+ vnnn <= inValid;
130
+ vnn <= vnnn;
131
+ vn <= vnn;
132
+ outValid <= vn;
133
+ vp <= outValid ;
100
134
// ripple for data look ahead/behind
101
- snnn <= in;
102
- snn <= snnn;
103
- sn <= snn;
104
- s <= sn;
105
- sp <= s;
106
- spp <= sp;
107
- sppp<= spp;
108
- // ripple for newMsg
109
- rnnn <= newMsg;
110
- rnn <= rnnn;
111
- rn <= rnn;
112
- r <= rn;
135
+ snnn <= in;
136
+ snn <= snnn;
137
+ sn <= snn;
138
+ out <= sn;
139
+ sp <= out;
140
+ spp <= sp;
141
+ sppp <= spp;
142
+ end else begin
143
+ outValid <= 0 ;
113
144
end
114
- if (reset || rn) begin
115
- tagdepth <= 0 ;
116
- tagno[0 ] <= 0 ;
117
- tagno[1 ] <= 0 ;
118
- tagno[2 ] <= 0 ;
119
- tagno[3 ] <= 0 ;
120
- tagno[4 ] <= 0 ;
121
- tagno[5 ] <= 0 ;
122
- tagno[6 ] <= 0 ;
123
- intag <= 0 ;
124
- _isClosingTag <= 0 ;
125
- _isSelfClosingTag <= 0 ;
126
- _isTagName <= 0 ;
127
- _isTagKey <= 0 ;
128
- _isTagValue <= 0 ;
129
- _isComment <= 0 ;
130
- _isDepthPush <= 0 ;
131
- _isDepthPop <= 0 ;
132
- end else if (vn || v) begin
133
- // handle comments, look ahead to start, look behind to end
134
- _isComment <= ( (sn == "<" && snn == "!" && snnn == "-" && in == "-" ) || _isComment )
135
- && ! (s == ">" && sp == "-" && spp == "-" );
145
+
146
+ if (outEop) begin // pipeline totally flushed, reset state
147
+ tagDepth <= 0 ;
148
+ tagno[0 ] <= 0 ;
149
+ tagno[1 ] <= 0 ;
150
+ tagno[2 ] <= 0 ;
151
+ tagno[3 ] <= 0 ;
152
+ tagno[4 ] <= 0 ;
153
+ tagno[5 ] <= 0 ;
154
+ tagno[6 ] <= 0 ;
155
+ intag <= 0 ;
156
+ isClosingTag <= 0 ;
157
+ isSelfClosingTag <= 0 ;
158
+ isTagName <= 0 ;
159
+ isTagKey <= 0 ;
160
+ isTagValue <= 0 ;
161
+ isComment <= 0 ;
162
+ depthPush <= 0 ;
163
+ depthPop <= 0 ;
164
+ end else if (vn || eopn || eopnn || eopnnn) begin // pipeline fully loaded with data or eop
165
+ // handle comments, look ahead to start, look behind to end, one cycle ahead of data/tag state
166
+ isComment <= (( (sn == "<" && ! eopn) && (snn == "!" && ! eopnn) && (snnn == "-" && ! eopnnn) && (in == "-" && ! inEop)) || isComment )
167
+ && ! (out == ">" && sp == "-" && spp == "-" );
136
168
137
169
// if we are not in a comment, stream is either a tag or data
138
- if (! _isComment ) begin
170
+ if (! isComment ) begin
139
171
intag <= (intag || onTagStartNext) && ! (onTagClose && ! onTagStartNext);
140
- _isTagName <= ((s == "<" && sn != "/" ) || (s == "/" && sp == "<" ) || _isTagName )
172
+ isTagName <= ((out == "<" && sn != "/" ) || (out == "/" && sp == "<" ) || isTagName )
141
173
&& ! (sn == " " || sn == ">" );
142
174
143
175
// for tag key/value logic, enable the alternator when intag & !isTagName
144
176
// <tagname key=value key=value key=value>
145
- _isTagKey <= (intag && s == " " || _isTagKey ) && sn!= "=" ;
146
- _isTagValue <= (intag && s == "=" || _isTagValue ) && ! (sn == " " || sn == ">" );
177
+ isTagKey <= (intag && out == " " || isTagKey ) && sn!= "=" ;
178
+ isTagValue <= (intag && out == "=" || isTagValue ) && ! (sn == " " || sn == ">" );
147
179
148
- _isClosingTag <= (s != ">" && _isClosingTag ) || (s == "<" && sn == "/" );
149
- _isSelfClosingTag <= (_isSelfClosingTag || onSelfCloseTag) && ! onTagStartNext;
180
+ isClosingTag <= (out != ">" && isClosingTag ) || (out == "<" && sn == "/" );
181
+ isSelfClosingTag <= (isSelfClosingTag || onSelfCloseTag) && ! onTagStartNext;
150
182
151
183
// a tag is either opening, closing or self-closing. At the end of the tag
152
184
// (onTagClose) we adjust and flag changes to depth based on the three possibilities.
153
- tagdepth <= tagdepth + (onTagClose && _isOpeningTag )
154
- - (onTagClose && _isClosingTag );
185
+ tagDepth <= tagDepth + (onTagClose && isOpeningTag )
186
+ - (onTagClose && isClosingTag );
155
187
156
- _isDepthPush <= onTagClose && _isOpeningTag ;
157
- _isDepthPop <= onTagClose && _isClosingTag ;
188
+ depthPush <= onTagClose && isOpeningTag ;
189
+ depthPop <= onTagClose && isClosingTag ;
158
190
159
191
if (onTagClose) begin
160
- if (_isClosingTag || _isSelfClosingTag ) begin
161
- tagno[tagdepth ] <= tagno[tagdepth ] + 1 ;
162
- tagno[tagdepth + 1 ] <= 0 ;
192
+ if (isClosingTag || isSelfClosingTag ) begin
193
+ tagno[tagDepth ] <= tagno[tagDepth ] + 1 ;
194
+ tagno[tagDepth + 1 ] <= 0 ;
163
195
end
164
196
end
165
197
end
166
198
end
167
199
end
168
200
169
- assign outNewMsg = r;
170
- assign out = s;
171
- assign outValid = v;
172
- assign isComment = _isComment;
173
- assign isTag = intag && ! _isComment;
201
+ assign isTag = _isTag;
174
202
assign isData = _isData;
175
- assign tagDepth = tagdepth;
176
- assign isTagKey = _isTagKey;
177
- assign isTagValue = _isTagValue;
178
- assign isTagName = _isTagName;
179
- assign depthPush = _isDepthPush;
180
- assign depthPop = _isDepthPop;
181
203
182
204
endmodule
183
205
0 commit comments