-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Right now only simple implementation is provided. The provided tests check if: * output of the decoder matches the expected values Signed-off-by: Maciej Dudek <mdudek@antmicro.com>
- Loading branch information
Showing
2 changed files
with
304 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
// Copyright 2023 The XLS Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// This file implements a parametric RLE decoder | ||
// | ||
// The RLE decoder decompresses incoming stream of | ||
// (`symbol`, `count`) pairs, representing that `symbol` was | ||
// repeated `count` times in original stream. Output stream | ||
// should be equal to the RLE encoder input stream. | ||
// Both input and output channels use additional `last` flag | ||
// that indicates whether the packet ends the transmission. | ||
// Decoder in its current form only propagates last signal. | ||
// The behavior of the decoder is presented on the waveform below: | ||
// ──────╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥──── | ||
// next evaluation XXXXXX║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ ... | ||
// ──────╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨──── | ||
// do_recv ┌─────┐ ┌─────────────────┐ ┌──── | ||
// ──────┘ └─────┘ └───────────┘ | ||
// ──────╥─────╥─────╥─────╥─────╥─────╥──────────────── | ||
// symbol, count XXXXXX║ A,2 ║XXXXX║ B,1 ║ B,1 ║ C,3 ║XXXXXXXXXXXXXXXX | ||
// (input channel) ──────╨─────╨─────╨─────╨─────╨─────╨──────────────── | ||
// last ┌─────┐ ┌─────┐ | ||
// (input channel) ──────────────────┘ └─────┘ └──────────────── | ||
// ╥─────╥───────────╥───────────╥─────────────────╥──── | ||
// state.symbol ║ 0 ║ A ║ B ║ C ║ 0 | ||
// (set state value) ╨─────╨───────────╨───────────╨─────────────────╨──── | ||
// ╥─────╥─────╥─────╥───────────╥─────╥─────╥─────╥──── | ||
// state.count ║ 0 ║ 1 ║ 0 ║ 0 ║ 2 ║ 1 ║ 0 ║ 0 | ||
// (set state value) ╨─────╨─────╨─────╨───────────╨─────╨─────╨─────╨──── | ||
// | ||
// ──────╥───────────╥───────────╥─────────────────╥──── | ||
// symbol XXXXXX║ A ║ B ║ C ║XXXX | ||
// (output channel) ──────╨───────────╨───────────╨─────────────────╨──── | ||
// last ┌─────┐ ┌─────┐ | ||
// (output channel) ──────────────────┘ └─────────────────┘ └──── | ||
|
||
|
||
import std | ||
import xls.modules.rle.rle_common as rle_common | ||
|
||
type DecInData = rle_common::EncData; | ||
type DecOutData = rle_common::PlainData; | ||
|
||
// structure to preserve the state of an RLE decoder | ||
struct RLEDecState<SYMBOL_WIDTH: u32, COUNT_WIDTH: u32> { | ||
// symbol to be repeated on output | ||
symbol: bits[SYMBOL_WIDTH], | ||
// count of symbols that has to be send | ||
count: bits[COUNT_WIDTH], | ||
// send last when repeat ends | ||
last: bool, | ||
} | ||
// RLE decoder implementation | ||
pub proc RLEDec<SYMBOL_WIDTH: u32, COUNT_WIDTH: u32> { | ||
input_r: chan<DecInData<SYMBOL_WIDTH, COUNT_WIDTH>> in; | ||
output_s: chan<DecOutData<SYMBOL_WIDTH>> out; | ||
|
||
init {( | ||
RLEDecState<SYMBOL_WIDTH, COUNT_WIDTH> { | ||
symbol: bits[SYMBOL_WIDTH]:0, | ||
count: bits[COUNT_WIDTH]:0, | ||
last: bool:false, | ||
} | ||
)} | ||
|
||
config ( | ||
input_r: chan<DecInData<SYMBOL_WIDTH, COUNT_WIDTH>> in, | ||
output_s: chan<DecOutData<SYMBOL_WIDTH>> out, | ||
) {(input_r, output_s)} | ||
|
||
next (tok: token, state: RLEDecState<SYMBOL_WIDTH, COUNT_WIDTH>) { | ||
let zero_input = DecInData { symbol: bits[SYMBOL_WIDTH]:0, count: bits[COUNT_WIDTH]:0, last: false }; | ||
let empty = state.count == bits[COUNT_WIDTH]:0; | ||
let (input_tok, input) = recv_if(tok, input_r, empty, zero_input); | ||
let (next_symbol, next_count, next_last) = if (empty) { | ||
let t_count = input.count - bits[COUNT_WIDTH]:1; | ||
(input.symbol, t_count, input.last) | ||
} else { | ||
let t_count = state.count - bits[COUNT_WIDTH]:1; | ||
(state.symbol, t_count, state.last) | ||
}; | ||
let send_last = next_last & (next_count == bits[COUNT_WIDTH]:0); | ||
let data_tok = send(input_tok, output_s, DecOutData {symbol: next_symbol, last: send_last}); | ||
RLEDecState { | ||
symbol: next_symbol, | ||
count: next_count, | ||
last: next_last, | ||
} | ||
} | ||
} | ||
|
||
|
||
// RLE decoder specialization for the codegen | ||
proc RLEDec32 { | ||
init {()} | ||
|
||
config ( | ||
input_r: chan<DecInData<32, 2>> in, | ||
output_s: chan<DecOutData<32>> out, | ||
) { | ||
spawn RLEDec<u32:32, u32:2>(input_r, output_s); | ||
() | ||
} | ||
|
||
next (tok: token, state: ()) { | ||
() | ||
} | ||
} | ||
|
||
// Tests | ||
|
||
const TEST_SYMBOL_WIDTH = u32:32; | ||
const TEST_COUNT_WIDTH = u32:2; | ||
|
||
type TestSymbol = bits[TEST_SYMBOL_WIDTH]; | ||
type TestCount = bits[TEST_COUNT_WIDTH]; | ||
type TestDecInData = DecInData<TEST_SYMBOL_WIDTH, TEST_COUNT_WIDTH>; | ||
type TestDecOutData = DecOutData<TEST_SYMBOL_WIDTH>; | ||
|
||
// main proc used to test the RLE decoder | ||
#[test_proc] | ||
proc RLEDecTightTester { | ||
terminator: chan<bool> out; // test termination request | ||
dec_input_s: chan<TestDecInData> out; | ||
dec_output_r: chan<TestDecOutData> in; | ||
|
||
init {()} | ||
|
||
config(terminator: chan<bool> out) { | ||
let (dec_input_s, dec_input_r) = chan<TestDecInData>; | ||
let (dec_output_s, dec_output_r) = chan<TestDecOutData>; | ||
|
||
spawn RLEDec<TEST_SYMBOL_WIDTH, TEST_COUNT_WIDTH>(dec_input_r, dec_output_s); | ||
(terminator, dec_input_s, dec_output_r) | ||
} | ||
|
||
next(tok: token, state: ()) { | ||
|
||
// Simple transaction without repeats | ||
let trans_send: (TestSymbol, TestCount)[2] = | ||
[(TestSymbol:0xA, TestCount:0x3), (TestSymbol:0xB, TestCount:0x1)]; | ||
let tok = for ((counter, (symbol_in, count_in)), tok): ((u32, (TestSymbol, TestCount)) , token) in enumerate(trans_send) { | ||
let _last = counter == (array_size(trans_send) - u32:1); | ||
let data_in = TestDecInData{symbol: symbol_in, count: count_in, last: _last}; | ||
let tok = send(tok, dec_input_s, data_in); | ||
let _ = trace_fmt!("Sent {} transactions, symbol: 0x{:x}, count:{}, last: {}", | ||
counter, data_in.symbol, data_in.count, data_in.last); | ||
(tok) | ||
}(tok); | ||
let trans_recv: TestSymbol[4] = [ | ||
TestSymbol: 0xA, TestSymbol: 0xA, TestSymbol: 0xA, TestSymbol: 0xB | ||
]; | ||
let tok = for ((counter, symbol_out), tok): ((u32, TestSymbol) , token) in enumerate(trans_recv) { | ||
let _last = counter == (array_size(trans_recv) - u32:1); | ||
let data_out = TestDecOutData{symbol: symbol_out, last: _last}; | ||
let (tok, dec_output) = recv(tok, dec_output_r); | ||
let _ = trace_fmt!( | ||
"Received {} transactions, symbol: 0x{:x}, last: {}", | ||
counter, dec_output.symbol, dec_output.last | ||
); | ||
let _ = assert_eq(dec_output, data_out); | ||
(tok) | ||
}(tok); | ||
|
||
// Transaction with repeating symbols | ||
let trans_send: (TestSymbol, TestCount)[6] =[ | ||
(TestSymbol:0xB, TestCount:0x2), (TestSymbol:0x1, TestCount:0x1), | ||
(TestSymbol:0xC, TestCount:0x3), (TestSymbol:0xC, TestCount:0x3), | ||
(TestSymbol:0x3, TestCount:0x3), (TestSymbol:0x2, TestCount:0x2), | ||
]; | ||
let tok = for ((counter, (symbol_in, count_in)), tok): ((u32, (TestSymbol, TestCount)) , token) in enumerate(trans_send) { | ||
let _last = counter == (array_size(trans_send) - u32:1); | ||
let data_in = TestDecInData{symbol: symbol_in, count: count_in, last: _last}; | ||
let tok = send(tok, dec_input_s, data_in); | ||
let _ = trace_fmt!("Sent {} transactions, symbol: 0x{:x}, count:{}, last: {}", | ||
counter, data_in.symbol, data_in.count, data_in.last); | ||
(tok) | ||
}(tok); | ||
let trans_recv: TestSymbol[14] = [ | ||
TestSymbol: 0xB, TestSymbol: 0xB, TestSymbol: 0x1, TestSymbol: 0xC, | ||
TestSymbol: 0xC, TestSymbol: 0xC, TestSymbol: 0xC, TestSymbol: 0xC, | ||
TestSymbol: 0xC, TestSymbol: 0x3, TestSymbol: 0x3, TestSymbol: 0x3, | ||
TestSymbol: 0x2, TestSymbol: 0x2, | ||
]; | ||
let tok = for ((counter, symbol_out), tok): ((u32, TestSymbol) , token) in enumerate(trans_recv) { | ||
let _last = counter == (array_size(trans_recv) - u32:1); | ||
let data_out = TestDecOutData{symbol: symbol_out, last: _last}; | ||
let (tok, dec_output) = recv(tok, dec_output_r); | ||
let _ = trace_fmt!( | ||
"Received {} transactions, symbol: 0x{:x}, last: {}", | ||
counter, dec_output.symbol, dec_output.last | ||
); | ||
let _ = assert_eq(dec_output, data_out); | ||
(tok) | ||
}(tok); | ||
|
||
// `last` after `last` check | ||
let trans_send: TestDecInData[2] =[ | ||
TestDecInData {symbol: TestSymbol:0x1, count: TestCount:0x1, last:true}, | ||
TestDecInData {symbol: TestSymbol:0x1, count: TestCount:0x1, last:true}, | ||
]; | ||
let tok = for ((counter, data_in), tok): ((u32, TestDecInData) , token) in enumerate(trans_send) { | ||
let tok = send(tok, dec_input_s, data_in); | ||
let _ = trace_fmt!("Sent {} transactions, symbol: 0x{:x}, count:{}, last: {}", | ||
counter, data_in.symbol, data_in.count, data_in.last); | ||
(tok) | ||
}(tok); | ||
let trans_recv: TestDecOutData[2] = [ | ||
TestDecOutData{symbol: TestSymbol: 0x1, last: true}, | ||
TestDecOutData{symbol: TestSymbol: 0x1, last: true}, | ||
]; | ||
let tok = for ((counter, data_out), tok): ((u32, TestDecOutData) , token) in enumerate(trans_recv) { | ||
let (tok, dec_output) = recv(tok, dec_output_r); | ||
let _ = trace_fmt!( | ||
"Received {} transactions, symbol: 0x{:x}, last: {}", | ||
counter, dec_output.symbol, dec_output.last | ||
); | ||
let _ = assert_eq(dec_output, data_out); | ||
(tok) | ||
}(tok); | ||
let _ = send(tok, terminator, true); | ||
() | ||
} | ||
} |