Skip to content

Commit 4f0cdd2

Browse files
rw1nklerlpawelcz
authored andcommitted
modules/zstd: Add raw block decoder
Internal-tag: [#51343] Signed-off-by: Robert Winkler <[email protected]>
1 parent 4ff1fc3 commit 4f0cdd2

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

xls/modules/zstd/BUILD

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,19 @@ cc_test(
139139
"@com_google_fuzztest//fuzztest:googletest_fixture_adapter",
140140
],
141141
)
142+
143+
xls_dslx_library(
144+
name = "raw_block_dec_dslx",
145+
srcs = [
146+
"raw_block_dec.x",
147+
],
148+
deps = [
149+
":buffer_dslx",
150+
":common_dslx",
151+
],
152+
)
153+
154+
xls_dslx_test(
155+
name = "raw_block_dec_dslx_test",
156+
library = ":raw_block_dec_dslx",
157+
)

xls/modules/zstd/raw_block_dec.x

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2023 The XLS Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// This file contains the implementation of RawBlockDecoder responsible for decoding
16+
// ZSTD Raw Blocks. More information about Raw Block's format can be found in:
17+
// https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.2.2
18+
19+
import xls.modules.zstd.common as common
20+
21+
type BlockDataPacket = common::BlockDataPacket;
22+
type BlockPacketLength = common::BlockPacketLength;
23+
type BlockData = common::BlockData;
24+
type ExtendedBlockDataPacket = common::ExtendedBlockDataPacket;
25+
type CopyOrMatchContent = common::CopyOrMatchContent;
26+
type CopyOrMatchLength = common::CopyOrMatchLength;
27+
type SequenceExecutorMessageType = common::SequenceExecutorMessageType;
28+
29+
struct RawBlockDecoderState {
30+
prev_id: u32, // ID of the previous block
31+
prev_last: bool, // if the previous packet was the last one that makes up the whole block
32+
prev_valid: bool, // if prev_id and prev_last contain valid data
33+
}
34+
35+
const ZERO_RAW_BLOCK_DECODER_STATE = zero!<RawBlockDecoderState>();
36+
37+
// RawBlockDecoder is responsible for decoding Raw Blocks,
38+
// it should be a part of the ZSTD Decoder pipeline.
39+
pub proc RawBlockDecoder {
40+
input_r: chan<BlockDataPacket> in;
41+
output_s: chan<ExtendedBlockDataPacket> out;
42+
43+
init { (ZERO_RAW_BLOCK_DECODER_STATE) }
44+
45+
config(
46+
input_r: chan<BlockDataPacket> in,
47+
output_s: chan<ExtendedBlockDataPacket> out
48+
) {(input_r, output_s)}
49+
50+
next(tok: token, state: RawBlockDecoderState) {
51+
let (tok, data) = recv(tok, input_r);
52+
if state.prev_valid && (data.id != state.prev_id) && (state.prev_last == false) {
53+
trace_fmt!("ID changed but previous packet have no last!");
54+
fail!("no_last", ());
55+
} else {};
56+
57+
let output_data = ExtendedBlockDataPacket {
58+
// Decoded RAW block is always a literal
59+
msg_type: SequenceExecutorMessageType::LITERAL,
60+
packet: BlockDataPacket {
61+
last: data.last,
62+
last_block: data.last_block,
63+
id: data.id,
64+
data: data.data as BlockData,
65+
length: data.length as BlockPacketLength,
66+
},
67+
};
68+
69+
let tok = send(tok, output_s, output_data);
70+
71+
RawBlockDecoderState {
72+
prev_valid: true,
73+
prev_id: output_data.packet.id,
74+
prev_last: output_data.packet.last
75+
}
76+
}
77+
}
78+
79+
#[test_proc]
80+
proc RawBlockDecoderTest {
81+
terminator: chan<bool> out;
82+
dec_input_s: chan<BlockDataPacket> out;
83+
dec_output_r: chan<ExtendedBlockDataPacket> in;
84+
85+
config(terminator: chan<bool> out) {
86+
let (dec_input_s, dec_input_r) = chan<BlockDataPacket>;
87+
let (dec_output_s, dec_output_r) = chan<ExtendedBlockDataPacket>;
88+
spawn RawBlockDecoder(dec_input_r, dec_output_s);
89+
(terminator, dec_input_s, dec_output_r)
90+
}
91+
92+
init { }
93+
94+
next(tok: token, state: ()) {
95+
let data_to_send: BlockDataPacket[5] = [
96+
BlockDataPacket { id: u32:1, last: u1:false, last_block: u1:false, data: BlockData:1, length: BlockPacketLength:32 },
97+
BlockDataPacket { id: u32:1, last: u1:false, last_block: u1:false, data: BlockData:2, length: BlockPacketLength:32 },
98+
BlockDataPacket { id: u32:1, last: u1:true, last_block: u1:false, data: BlockData:3, length: BlockPacketLength:32 },
99+
BlockDataPacket { id: u32:2, last: u1:false, last_block: u1:false, data: BlockData:4, length: BlockPacketLength:32 },
100+
BlockDataPacket { id: u32:2, last: u1:true, last_block: u1:true, data: BlockData:5, length: BlockPacketLength:32 },
101+
];
102+
103+
let tok = for ((_, data), tok): ((u32, BlockDataPacket), token) in enumerate(data_to_send) {
104+
let tok = send(tok, dec_input_s, data);
105+
let (tok, received_data) = recv(tok, dec_output_r);
106+
let expected_data = ExtendedBlockDataPacket {
107+
msg_type: SequenceExecutorMessageType::LITERAL,
108+
packet: data,
109+
};
110+
assert_eq(expected_data, received_data);
111+
(tok)
112+
}(tok);
113+
114+
send(tok, terminator, true);
115+
}
116+
}

0 commit comments

Comments
 (0)