From c9d8272e9e2785121ec34bac3554f7a61984472b Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Thu, 20 Jul 2023 10:51:28 +0200 Subject: [PATCH 1/7] [RLE] Support multiple symbols/pairs in single transaction This commit adds valid signals to PlainData interface. CompressedData interface uses `count > 0` to define valid symbol count pair. This is in preparation for a multisymbol RLE encoder implementation. Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_common.x | 15 ++-- xls/modules/rle/rle_dec.x | 146 +++++++++++++++++++++++++++-------- xls/modules/rle/rle_enc.x | 126 +++++++++++++++++------------- 3 files changed, 196 insertions(+), 91 deletions(-) diff --git a/xls/modules/rle/rle_common.x b/xls/modules/rle/rle_common.x index 8b1217ff2c..525271fe7e 100644 --- a/xls/modules/rle/rle_common.x +++ b/xls/modules/rle/rle_common.x @@ -19,16 +19,17 @@ // Structure is used as an input and an output to and from // a preprocessing stage as well as an input to a RLE encoder. // It is also used as an output from RLE decoder. -pub struct PlainData { - symbol: bits[SYMB_WIDTH], // symbol - last: bool, // flush RLE +pub struct PlainData { + symbols: bits[SYMB_WIDTH][SYMB_COUNT], // symbols + symbol_valids: bits[1][SYMB_COUNT], // symbol valid + last: bool, // flush RLE } // Structure contains compressed (symbol, counter) pairs. // Structure is used as an output from RLE encoder and // as an input to RLE decoder. -pub struct CompressedData { - symbol: bits[SYMBOL_WIDTH], // symbol - count: bits[COUNT_WIDTH], // symbol counter - last: bool, // flush RLE +pub struct CompressedData { + symbols: bits[SYMBOL_WIDTH][PAIR_COUNT], // symbol + counts: bits[COUNT_WIDTH][PAIR_COUNT], // symbol counter + last: bool, // flush RLE } diff --git a/xls/modules/rle/rle_dec.x b/xls/modules/rle/rle_dec.x index b9d70808f6..65d4303b3e 100644 --- a/xls/modules/rle/rle_dec.x +++ b/xls/modules/rle/rle_dec.x @@ -63,8 +63,8 @@ struct RunLengthDecoderState { } // RLE decoder implementation pub proc RunLengthDecoder { - input_r: chan> in; - output_s: chan> out; + input_r: chan> in; + output_s: chan> out; init {( RunLengthDecoderState { @@ -75,34 +75,38 @@ pub proc RunLengthDecoder { )} config ( - input_r: chan> in, - output_s: chan> out, + input_r: chan> in, + output_s: chan> out, ) {(input_r, output_s)} next (tok: token, state: RunLengthDecoderState) { let state_input = DecInData { - symbol: state.symbol, - count: state.count, + symbols: [state.symbol], + counts: [state.count], last: state.last }; let recv_next_symbol = (state.count == bits[COUNT_WIDTH]:0); let (tok, input) = recv_if(tok, input_r, recv_next_symbol, state_input); - let next_count = if input.count == bits[COUNT_WIDTH]:0 { - fail!("invalid_count_0", input.count) + let next_count = if input.counts[0] == bits[COUNT_WIDTH]:0 { + input.counts[0] } else { - input.count - bits[COUNT_WIDTH]:1 + input.counts[0] - bits[COUNT_WIDTH]:1 }; let done_sending = (next_count == bits[COUNT_WIDTH]:0); let send_last = input.last && done_sending; - let data_tok = send(tok, output_s, DecOutData { - symbol: input.symbol, - last: send_last + let symbol_valid = input.counts[0] > bits[COUNT_WIDTH]:0; + let data_tok = send_if(tok, output_s, + symbol_valid || send_last, + DecOutData { + symbols: [input.symbols[0]], + symbol_valids: [symbol_valid], + last: send_last }); if (send_last) { zero!() } else { RunLengthDecoderState { - symbol: input.symbol, + symbol: input.symbols[0], count: next_count, last: input.last, } @@ -116,8 +120,8 @@ proc RunLengthDecoder32 { init {()} config ( - input_r: chan> in, - output_s: chan> out, + input_r: chan> in, + output_s: chan> out, ) { spawn RunLengthDecoder(input_r, output_s); () @@ -136,8 +140,8 @@ const TEST_COUNT_WIDTH = u32:32; type TestSymbol = bits[TEST_SYMBOL_WIDTH]; type TestCount = bits[TEST_COUNT_WIDTH]; type TestStimulus = (TestSymbol, TestCount); -type TestDecInData = DecInData; -type TestDecOutData = DecOutData; +type TestDecInData = DecInData; +type TestDecOutData = DecOutData; // Check RLE decoder on a transaction #[test_proc] @@ -171,13 +175,13 @@ proc RunLengthDecoderTransactionTest { in enumerate(TransactionTestStimuli) { let last = counter == (array_size(TransactionTestStimuli) - u32:1); let data_in = TestDecInData{ - symbol: stimulus.0, - count: stimulus.1, + symbols: [stimulus.0], + counts: [stimulus.1], last: last }; let tok = send(tok, dec_input_s, data_in); trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, count:{}, last: {}", - counter + u32:1, data_in.symbol, data_in.count, data_in.last); + counter + u32:1, data_in.symbols[0], data_in.counts[0], data_in.last); (tok) }(tok); let TransationTestOutputs: TestSymbol[14] = [ @@ -194,13 +198,14 @@ proc RunLengthDecoderTransactionTest { in enumerate(TransationTestOutputs) { let last = counter == (array_size(TransationTestOutputs) - u32:1); let data_out = TestDecOutData{ - symbol: symbol, + symbols: [symbol], + symbol_valids: [bits[1]:1], last: last }; let (tok, dec_output) = recv(tok, dec_output_r); trace_fmt!( "Received {} transactions, symbol: 0x{:x}, last: {}", - counter, dec_output.symbol, dec_output.last + counter, dec_output.symbols[0], dec_output.last ); assert_eq(dec_output, data_out); (tok) @@ -209,6 +214,81 @@ proc RunLengthDecoderTransactionTest { } } +// Check that RLE decoder will remove empty pairs, `count == 0`. +// Check that RLE decoder will set `symbol_valids` to 0 only in +// the last output packet. +#[test_proc] +proc RunLengthDecoderZeroCountTest { + terminator: chan out; // test termination request + dec_input_s: chan out; + dec_output_r: chan in; + + init {()} + + config(terminator: chan out) { + let (dec_input_s, dec_input_r) = chan; + let (dec_output_s, dec_output_r) = chan; + + spawn RunLengthDecoder( + dec_input_r, dec_output_s); + (terminator, dec_input_s, dec_output_r) + } + + next(tok: token, state: ()) { + let ZeroCountTestStimuli: TestStimulus[6] =[ + (TestSymbol:0xB, TestCount:0x2), + (TestSymbol:0x1, TestCount:0x0), + (TestSymbol:0xC, TestCount:0x1), + (TestSymbol:0xC, TestCount:0x0), + (TestSymbol:0x3, TestCount:0x3), + (TestSymbol:0x2, TestCount:0x0), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, (TestSymbol, TestCount)) , token) + in enumerate(ZeroCountTestStimuli) { + let last = counter == (array_size(ZeroCountTestStimuli) - u32:1); + let data_in = TestDecInData{ + symbols: [stimulus.0], + counts: [stimulus.1], + last: last + }; + let tok = send(tok, dec_input_s, data_in); + trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, count:{}, last: {}", + counter + u32:1, data_in.symbols[0], data_in.counts[0], data_in.last); + (tok) + }(tok); + let ZeroCountTestOutputs: TestDecOutData[7] = [ + TestDecOutData{symbols: [TestSymbol: 0xB], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0xB], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0xC], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0x3], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0x3], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0x3], + symbol_valids: [true], last: false}, + TestDecOutData{symbols: [TestSymbol: 0x2], + symbol_valids: [false], last: true}, + ]; + let tok = for ((counter, output), tok): + ((u32, TestDecOutData) , token) + in enumerate(ZeroCountTestOutputs) { + let (tok, dec_output) = recv(tok, dec_output_r); + trace_fmt!( + "Received {} transactions, symbols: 0x{:x}, last: {}", + counter + u32:1, dec_output.symbols, dec_output.last + ); + assert_eq(dec_output, output); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + // Check that RLE decoder will create 2 `last` output packets, // when 2 `last` input packets were consumed. #[test_proc] @@ -231,13 +311,13 @@ proc RunLengthDecoderLastAfterLastTest { next(tok: token, state: ()) { let LastAfterLastTestStimuli: TestDecInData[2] =[ TestDecInData { - symbol: TestSymbol:0x1, - count: TestCount:0x1, + symbols: [TestSymbol:0x1], + counts: [TestCount:0x1], last:true }, TestDecInData { - symbol: TestSymbol:0x2, - count: TestCount:0x1, + symbols: [TestSymbol:0x2], + counts: [TestCount:0x1], last:true }, ]; @@ -245,21 +325,23 @@ proc RunLengthDecoderLastAfterLastTest { ((u32, TestDecInData) , token) in enumerate(LastAfterLastTestStimuli) { let tok = send(tok, dec_input_s, stimulus); - trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, count:{}, last: {}", - counter + u32:1, stimulus.symbol, stimulus.count, stimulus.last); + trace_fmt!("Sent {} stimuli, symbols: 0x{:x}, counts:{}, last: {}", + counter + u32:1, stimulus.symbols, stimulus.counts, stimulus.last); (tok) }(tok); let LastAfterLastTestOutputs: TestDecOutData[2] = [ - TestDecOutData{symbol: TestSymbol: 0x1, last: true}, - TestDecOutData{symbol: TestSymbol: 0x2, last: true}, + TestDecOutData{symbols: [TestSymbol: 0x1], + symbol_valids: [true], last: true}, + TestDecOutData{symbols: [TestSymbol: 0x2], + symbol_valids: [true], last: true}, ]; let tok = for ((counter, output), tok): ((u32, TestDecOutData) , token) in enumerate(LastAfterLastTestOutputs) { let (tok, dec_output) = recv(tok, dec_output_r); trace_fmt!( - "Received {} transactions, symbol: 0x{:x}, last: {}", - counter + u32:1, dec_output.symbol, dec_output.last + "Received {} transactions, symbols: 0x{:x}, last: {}", + counter + u32:1, dec_output.symbols, dec_output.last ); assert_eq(dec_output, output); (tok) diff --git a/xls/modules/rle/rle_enc.x b/xls/modules/rle/rle_enc.x index 386faf9131..0ce2610663 100644 --- a/xls/modules/rle/rle_enc.x +++ b/xls/modules/rle/rle_enc.x @@ -66,8 +66,8 @@ struct RunLengthEncoderState { // RLE encoder implementation pub proc RunLengthEncoder { - input_r: chan> in; - output_s: chan> out; + input_r: chan> in; + output_s: chan> out; init {( RunLengthEncoderState { @@ -78,47 +78,49 @@ pub proc RunLengthEncoder { )} config ( - input_r: chan> in, - output_s: chan> out, + input_r: chan> in, + output_s: chan> out, ) {(input_r, output_s)} next (tok: token, state: RunLengthEncoderState) { let zero_input = EncInData { - symbol: bits[SYMBOL_WIDTH]:0, + symbols: bits[SYMBOL_WIDTH][1]:[bits[SYMBOL_WIDTH]:0], + symbol_valids: bits[1][1]:[bits[1]:0], last: false }; let (input_tok, input) = recv_if( tok, input_r, !state.prev_last, zero_input); + let symbol_valid = input.symbol_valids[0]; let prev_symbol_valid = state.prev_count != bits[COUNT_WIDTH]:0; - let symbol_differ = prev_symbol_valid && ( - input.symbol != state.prev_symbol); + let symbol_differ = prev_symbol_valid && symbol_valid && + (input.symbols[0] != state.prev_symbol); let overflow = state.prev_count == std::unsigned_max_value(); - let (symbol, count, last) = if (state.prev_last) { - ( - bits[SYMBOL_WIDTH]:0, - bits[COUNT_WIDTH]:0, - false - ) - } else if (symbol_differ || overflow) { - ( - input.symbol, - bits[COUNT_WIDTH]:1, - input.last, - ) + let count = match (symbol_valid, overflow, symbol_differ, state.prev_last) { + (true, true, _, false) => bits[COUNT_WIDTH]:1, + (true, false, true, false) => bits[COUNT_WIDTH]:1, + (true, false, false, false) => state.prev_count + bits[COUNT_WIDTH]:1, + (false, false, _, false) => state.prev_count, + _ => bits[COUNT_WIDTH]:0, + }; + + let symbol = if symbol_valid && (symbol_differ || !prev_symbol_valid) { + input.symbols[0] } else { - ( - input.symbol, - state.prev_count + bits[COUNT_WIDTH]:1, - input.last, - ) + state.prev_symbol + }; + + let last = match (state.prev_last, input.last) { + (true, false) => false, + (false, true) => true, + _ => state.prev_last, }; let data = EncOutData { - symbol: state.prev_symbol, - count: state.prev_count, + symbols: [state.prev_symbol], + counts: [state.prev_count], last: state.prev_last }; @@ -139,8 +141,8 @@ proc RunLengthEncoder32 { init {()} config ( - input_r: chan> in, - output_s: chan> out, + input_r: chan> in, + output_s: chan> out, ) { spawn RunLengthEncoder(input_r, output_s); () @@ -159,9 +161,9 @@ const TEST_COMMON_COUNT_WIDTH = u32:32; type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; -type TestCommonEncInData = EncInData; +type TestCommonEncInData = EncInData; type TestCommonEncOutData = - EncOutData; + EncOutData; // Simple transaction without overflow const CountSymbolTestSymbolWidth = TEST_COMMON_SYMBOL_WIDTH; @@ -197,10 +199,14 @@ proc RunLengthEncoderCountSymbolTest { ((u32, CountSymbolTestStimulus) , token) in enumerate(CountSymbolTestTestStimuli) { let last = counter == (array_size(CountSymbolTestTestStimuli) - u32:1); - let stimulus = CountSymbolTestEncInData{symbol: symbol, last: last}; + let stimulus = CountSymbolTestEncInData{ + symbols: [symbol], + symbol_valids: [bits[1]:1], + last: last + }; let tok = send(tok, enc_input_s, stimulus); trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, last: {}", - counter, stimulus.symbol, stimulus.last); + counter, stimulus.symbols[0], stimulus.last); (tok) }(tok); let CountSymbolTestTestOutput: @@ -213,11 +219,11 @@ proc RunLengthEncoderCountSymbolTest { in enumerate(CountSymbolTestTestOutput) { let last = counter == (array_size(CountSymbolTestTestOutput) - u32:1); let expected = CountSymbolTestEncOutData{ - symbol: symbol, count: count, last: last}; + symbols: [symbol], counts: [count], last: last}; let (tok, enc_output) = recv(tok, enc_output_r); trace_fmt!( "Received {} pairs, symbol: 0x{:x}, count: {}, last: {}", - counter, enc_output.symbol, enc_output.count, enc_output.last + counter, enc_output.symbols[0], enc_output.counts[0], enc_output.last ); assert_eq(enc_output, expected); (tok) @@ -235,7 +241,7 @@ type OverflowSymbol = TestCommonSymbol; type OverflowCount = bits[OverflowCountWidth]; type OverflowEncInData = TestCommonEncInData; type OverflowEncOutData = - EncOutData; + EncOutData; #[test_proc] proc RunLengthEncoderOverflowTest { @@ -267,10 +273,14 @@ proc RunLengthEncoderOverflowTest { in enumerate(OverflowTestStimuli) { let last = counter == ( array_size(OverflowTestStimuli) - u32:1); - let stimulus = OverflowEncInData{symbol: symbol, last: last}; + let stimulus = OverflowEncInData{ + symbols: [symbol], + symbol_valids: [bits[1]:1], + last: last + }; let tok = send(tok, enc_input_s, stimulus); trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, last: {}", - counter, stimulus.symbol, stimulus.last); + counter, stimulus.symbols[0], stimulus.last); (tok) }(tok); let OverflowTestOutput: @@ -287,11 +297,11 @@ proc RunLengthEncoderOverflowTest { in enumerate(OverflowTestOutput) { let last = counter == (array_size(OverflowTestOutput) - u32:1); let expected = OverflowEncOutData{ - symbol: symbol, count: count, last: last}; + symbols: [symbol], counts: [count], last: last}; let (tok, enc_output) = recv(tok, enc_output_r); trace_fmt!( "Received {} pairs, symbol: 0x{:x}, count: {}, last: {}", - counter, enc_output.symbol, enc_output.count, enc_output.last + counter, enc_output.symbols[0], enc_output.counts[0], enc_output.last ); assert_eq(enc_output, expected); (tok) @@ -329,25 +339,33 @@ proc RunLengthEncoderLastAfterLastTest { } next (tok: token, state:()) { let LastAfterLastTestStimuli: LastAfterLastStimulus[2] = [ - LastAfterLastStimulus {symbol: LastAfterLastSymbol:0x1, last: true}, - LastAfterLastStimulus {symbol: LastAfterLastSymbol:0x1, last: true}, + LastAfterLastStimulus { + symbols: [LastAfterLastSymbol:0x1], + symbol_valids: [bits[1]:1], + last: true + }, + LastAfterLastStimulus { + symbols: [LastAfterLastSymbol:0x1], + symbol_valids: [bits[1]:1], + last: true + }, ]; let tok = for ((counter, stimuli), tok): ((u32, LastAfterLastStimulus) , token) in enumerate(LastAfterLastTestStimuli) { let tok = send(tok, enc_input_s, stimuli); trace_fmt!("Sent {} transactions, symbol: 0x{:x}, last: {}", - counter, stimuli.symbol, stimuli.last); + counter, stimuli.symbols[0], stimuli.last); (tok) }(tok); let LastAfterLastTestOutput: LastAfterLastOutput[2] = [ LastAfterLastOutput { - symbol: LastAfterLastSymbol:0x1, - count: LastAfterLastCount:0x1, + symbols: [LastAfterLastSymbol:0x1], + counts: [LastAfterLastCount:0x1], last:true}, LastAfterLastOutput { - symbol: LastAfterLastSymbol:0x1, - count: LastAfterLastCount:0x1, + symbols: [LastAfterLastSymbol:0x1], + counts: [LastAfterLastCount:0x1], last:true}, ]; let tok = for ((counter, expected), tok): @@ -356,7 +374,7 @@ proc RunLengthEncoderLastAfterLastTest { let (tok, enc_output) = recv(tok, enc_output_r); trace_fmt!( "Received {} pairs, symbol: 0x{:x}, count: {}, last: {}", - counter, enc_output.symbol, enc_output.count, enc_output.last + counter, enc_output.symbols[0], enc_output.counts[0], enc_output.last ); assert_eq(enc_output, expected); @@ -377,7 +395,7 @@ type OverflowWithLastCount = type OverflowWithLastEncInData = TestCommonEncInData; type OverflowWithLastEncOutData = EncOutData; + OverflowWithLastCountWidth, 1>; #[test_proc] proc RunLengthEncoderOverflowWithLastTest { @@ -406,10 +424,14 @@ proc RunLengthEncoderOverflowWithLastTest { in enumerate(OverflowWithLastTestStimuli) { let last = counter == ( array_size(OverflowWithLastTestStimuli) - u32:1); - let stimulus = OverflowWithLastEncInData{symbol: symbol, last: last}; + let stimulus = OverflowWithLastEncInData{ + symbols: [symbol], + symbol_valids: [bits[1]:1], + last: last + }; let tok = send(tok, enc_input_s, stimulus); trace_fmt!("Sent {} stimuli, symbol: 0x{:x}, last: {}", - counter, stimulus.symbol, stimulus.last); + counter, stimulus.symbols[0], stimulus.last); (tok) }(tok); let OverflowWithLastTestOutput: @@ -422,11 +444,11 @@ proc RunLengthEncoderOverflowWithLastTest { in enumerate(OverflowWithLastTestOutput) { let last = counter == (array_size(OverflowWithLastTestOutput) - u32:1); let expected = OverflowWithLastEncOutData{ - symbol: symbol, count: count, last: last}; + symbols: [symbol], counts: [count], last: last}; let (tok, enc_output) = recv(tok, enc_output_r); trace_fmt!( "Received {} pairs, symbol: 0x{:x}, count: {}, last: {}", - counter, enc_output.symbol, enc_output.count, enc_output.last + counter, enc_output.symbols[0], enc_output.counts[0], enc_output.last ); assert_eq(enc_output, expected); (tok) From 13e09b9daea672e24956231181198d42a74c2511 Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Thu, 29 Jun 2023 16:17:53 +0200 Subject: [PATCH 2/7] [DSLX] Add advanced RunLengthEncoder This encoder is capable of ingesting multiple symbols and produces multiple compressed pairs. It should offer faster compression in exchange for area used. Signed-off-by: Maciej Dudek --- xls/modules/rle/BUILD | 209 ++++++ xls/modules/rle/rle_enc_adv.x | 479 +++++++++++++ .../rle/rle_enc_adv_adjust_width_stage.x | 563 +++++++++++++++ xls/modules/rle/rle_enc_adv_core.x | 669 ++++++++++++++++++ xls/modules/rle/rle_enc_adv_realign_stage.x | 405 +++++++++++ xls/modules/rle/rle_enc_adv_reduce_stage.x | 378 ++++++++++ 6 files changed, 2703 insertions(+) create mode 100644 xls/modules/rle/rle_enc_adv.x create mode 100644 xls/modules/rle/rle_enc_adv_adjust_width_stage.x create mode 100644 xls/modules/rle/rle_enc_adv_core.x create mode 100644 xls/modules/rle/rle_enc_adv_realign_stage.x create mode 100644 xls/modules/rle/rle_enc_adv_reduce_stage.x diff --git a/xls/modules/rle/BUILD b/xls/modules/rle/BUILD index ad255af4dd..c84cc8efa4 100644 --- a/xls/modules/rle/BUILD +++ b/xls/modules/rle/BUILD @@ -106,6 +106,215 @@ xls_benchmark_ir( }, ) +xls_dslx_library( + name = "rle_enc_adv_reduce_stage_dslx", + srcs = [ + "rle_enc_adv_reduce_stage.x", + ], + deps = [ + ":rle_common_dslx" + ], +) + +xls_dslx_test( + name = "rle_enc_adv_reduce_stage_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = "rle_enc_adv_reduce_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_reduce_stage_dslx_ir_test", + dslx_test_args = { + "compare": "interpreter", + }, + library = "rle_enc_adv_reduce_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_reduce_stage_dslx_jit_test", + dslx_test_args = { + "compare": "jit", + }, + library = "rle_enc_adv_reduce_stage_dslx", +) + +xls_dslx_library( + name = "rle_enc_adv_realign_stage_dslx", + srcs = [ + "rle_enc_adv_realign_stage.x", + ], + deps = [ + ":rle_common_dslx" + ], +) + +xls_dslx_test( + name = "rle_enc_adv_realign_stage_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = "rle_enc_adv_realign_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_realign_stage_dslx_ir_test", + dslx_test_args = { + "compare": "interpreter", + }, + library = "rle_enc_adv_realign_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_realign_stage_dslx_jit_test", + dslx_test_args = { + "compare": "jit", + }, + library = "rle_enc_adv_realign_stage_dslx", +) + +xls_dslx_library( + name = "rle_enc_adv_core_dslx", + srcs = [ + "rle_enc_adv_core.x", + ], + deps = [ + ":rle_common_dslx" + ], +) + +xls_dslx_test( + name = "rle_enc_adv_core_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = "rle_enc_adv_core_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_core_dslx_ir_test", + dslx_test_args = { + "compare": "interpreter", + }, + library = "rle_enc_adv_core_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_core_dslx_jit_test", + dslx_test_args = { + "compare": "jit", + }, + library = "rle_enc_adv_core_dslx", +) + +xls_dslx_library( + name = "rle_enc_adv_adjust_width_stage_dslx", + srcs = [ + "rle_enc_adv_adjust_width_stage.x", + ], + deps = [ + ":rle_common_dslx" + ], +) + +xls_dslx_test( + name = "rle_enc_adv_adjust_width_stage_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = "rle_enc_adv_adjust_width_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_adjust_width_stage_dslx_ir_test", + dslx_test_args = { + "compare": "interpreter", + }, + library = "rle_enc_adv_adjust_width_stage_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_adjust_width_stage_dslx_jit_test", + dslx_test_args = { + "compare": "jit", + }, + library = "rle_enc_adv_adjust_width_stage_dslx", +) + +xls_dslx_library( + name = "rle_enc_adv_dslx", + srcs = [ + "rle_enc_adv.x", + ], + deps = [ + ":rle_common_dslx", + ":rle_enc_adv_reduce_stage_dslx", + ":rle_enc_adv_realign_stage_dslx", + ":rle_enc_adv_core_dslx", + ":rle_enc_adv_adjust_width_stage_dslx", + ], +) + +xls_dslx_test( + name = "rle_enc_adv_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = "rle_enc_adv_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_dslx_ir_test", + dslx_test_args = { + "compare": "interpreter", + }, + library = "rle_enc_adv_dslx", +) + +xls_dslx_test( + name = "rle_enc_adv_dslx_jit_test", + dslx_test_args = { + "compare": "jit", + }, + library = "rle_enc_adv_dslx", +) + +xls_dslx_ir( + name = "rle_enc_adv_ir", + dslx_top = "RunLengthEncoder8_8_4_2", + library = "rle_enc_adv_dslx", + ir_file = "rle_enc_adv.ir", +) + +xls_ir_opt_ir( + name = "rle_enc_adv_opt_ir", + src = "rle_enc_adv.ir", + top = "__xls_modules_rle_rle_enc_adv_core__RunLengthEncoder8_8_4_2__RunLengthEncoderAdvanced__RunLengthEncoderAdvancedCoreStage_0__8_4_8_next", +) + +xls_ir_verilog( + name = "rle_enc_adv_verilog", + src = ":rle_enc_adv_opt_ir.opt.ir", + verilog_file = "rle_enc_adv.v", + codegen_args = { + "module_name": "rle_enc_adv", + "delay_model": "unit", + "pipeline_stages": "2", + "reset": "rst", + "use_system_verilog": "false", + }, +) + +xls_benchmark_ir( + name = "rle_enc_adv_ir_benchmark", + src = ":rle_enc_adv_opt_ir.opt.ir", + benchmark_ir_args = { + "pipeline_stages": "2", + "delay_model": "unit", + } +) + xls_dslx_library( name = "rle_dec_dslx", srcs = [ diff --git a/xls/modules/rle/rle_enc_adv.x b/xls/modules/rle/rle_enc_adv.x new file mode 100644 index 0000000000..451c5540aa --- /dev/null +++ b/xls/modules/rle/rle_enc_adv.x @@ -0,0 +1,479 @@ +// 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 encoder +// +// The encoder uses Run Length Encoding (RLE) to compress the input stream of +// repeating symbols to the output stream that contains the symbols and +// the number of its consequect occurrences in the input stream. +// Both the input and the output channels use additional `last` flag +// that indicates whether the packet ends the transmission. After sending +// the last packet encoder dumps all the data to the output stream. +// The behavior of the encoder is presented on the waveform below: +// ──────╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥──── +// next evaluation XXXXXX║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ ... +// ──────╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨──── +// ──────╥───────────╥─────╥─────╥─────╥─────╥────────── +// symbol XXXXXX║ A ║ B ║XXXXX║ B ║ C ║XXXXXXXXXX +// (input channel) ──────╨───────────╨─────╨─────╨─────╨─────╨────────── +// last ┌─────┐ ┌─────┐ +// (input channel) ──────────────────┘ └───────────┘ └────────── +// ╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥────────── +// state.prev_symbol ║ 0 ║ A ║ A ║ B ║ 0 ║ B ║ C ║ 0 +// (set state value) ╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨────────── +// ╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥────────── +// state.prev_count ║ 0 ║ 1 ║ 2 ║ 1 ║ 0 ║ 1 ║ 1 ║ 0 +// (set state value) ╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨────────── +// +// do_send ┌───────────┐ ┌───────────┐ +// ──────────────────┘ └─────┘ └──── +// ──────────────────╥─────╥─────╥─────╥─────╥─────╥──── +// symbol, count XXXXXXXXXXXXXXXXXX║ A,2 ║ B,1 ║XXXXX║ B,1 ║ C,1 ║XXXX +// (output channel) ──────────────────╨─────╨─────╨─────╨─────╨─────╨──── +// last ┌─────┐ ┌─────┐ +// (output channel) ────────────────────────┘ └───────────┘ └──── + +import std +import xls.modules.rle.rle_common as rle_common + +import xls.modules.rle.rle_enc_adv_reduce_stage as reduce_stage +import xls.modules.rle.rle_enc_adv_realign_stage as realign_stage +import xls.modules.rle.rle_enc_adv_core as core +import xls.modules.rle.rle_enc_adv_adjust_width_stage as adjust_width_stage + + +type EncInData = rle_common::PlainData; +type EncOutData = rle_common::CompressedData; + + +// RLE encoder implementation +pub proc RunLengthEncoderAdvanced { + + init {()} + + config ( + input_r: chan> in, + output_s: chan> out, + ) { + let (reduced_s, reduced_r) = chan< + EncOutData>; + spawn reduce_stage::RunLengthEncoderAdvancedReduceStage< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH>(input_r, reduced_s); + + let (realigned_s, realigned_r) = chan< + (EncOutData, u32, u32)>; + spawn realign_stage::RunLengthEncoderAdvancedRealignStage< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH>(reduced_r, realigned_s); + + let (compressed_s, compressed_r) = chan< + (EncOutData, u32)>; + + spawn core::RunLengthEncoderAdvancedCoreStage< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH>(realigned_r, compressed_s); + spawn adjust_width_stage::RunLengthEncoderAdvancedAdjustWidthStage< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH, OUTPUT_WIDTH>( + compressed_r, output_s); + () + } + + next (tok: token, state: ()) {()} +} + +// RLE encoder specialization for the codegen +proc RunLengthEncoder8_8_4_2 { + + init {()} + + config ( + input_r: chan> in, + output_s: chan> out, + ) { + spawn RunLengthEncoderAdvanced( + input_r, output_s); + () + } + + next (tok: token, state: ()) { + () + } +} + +// Testing +// Each subprocess is tested individually. + +const TEST_COMMON_SYMBOL_WIDTH = u32:32; +const TEST_COMMON_COUNT_WIDTH = u32:32; +const TEST_COMMON_INPUT_WIDTH = u32:4; +const TEST_COMMON_OUTPUT_WIDTH = u32:2; + +type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; +type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; + +type TestCommonSymbolsIn = TestCommonSymbol[TEST_COMMON_INPUT_WIDTH]; +type TestCommonSymbolValidsIn = bits[1][TEST_COMMON_INPUT_WIDTH]; +type TestCommonStimulus = (TestCommonSymbolsIn, TestCommonSymbolValidsIn); + +type TestCommonSymbolsOut = TestCommonSymbol[TEST_COMMON_OUTPUT_WIDTH]; +type TestCommonCountsOut = TestCommonCount[TEST_COMMON_OUTPUT_WIDTH]; +type TestCommonOutputs = (TestCommonSymbolsOut, TestCommonCountsOut); + +type TestCommonEncInData = EncInData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_INPUT_WIDTH>; +type TestCommonEncOutData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>; + + +#[test_proc] +proc ConsumeMultipleSymbolRepetitionsAtOnce { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init{()} + + config(terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + spawn RunLengthEncoderAdvanced< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH + >(enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[4] = [ + (TestCommonSymbolsIn:[0x1, 0x1, 0x1, 0x1], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + (TestCommonSymbolsIn:[0x1, 0x1, 0x1, 0x1], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + (TestCommonSymbolsIn:[0x1, 0x1, 0x1, 0x1], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + (TestCommonSymbolsIn:[0x1, 0x1, 0x1, 0x1], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.last); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonOutputs[1] = [ + (TestCommonSymbolsOut:[0x1, 0x0], + TestCommonCountsOut:[0x10, 0x0]), + ]; + + let tok = for ((counter, output), tok): + ((u32, TestCommonOutputs) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: output.0, + counts: output.1, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc ConsumeMultipleSymbolsAtOnce { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init{()} + + config(terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + spawn RunLengthEncoderAdvanced< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH + >(enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbolsIn:[0x1, 0x1, 0x2, 0x2], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.last); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonOutputs[1] = [ + (TestCommonSymbolsOut:[0x1, 0x2], + TestCommonCountsOut:[0x2, 0x2]), + ]; + + let tok = for ((counter, output), tok): + ((u32, TestCommonOutputs) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: output.0, + counts: output.1, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc ConsumePacketWithInvalidSymbols { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init{()} + + config(terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + spawn RunLengthEncoderAdvanced< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH + >(enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[4] = [ + (TestCommonSymbolsIn:[0x1, 0x0, 0x1, 0x0], + TestCommonSymbolValidsIn:[0x1, 0x0, 0x1, 0x0]), + (TestCommonSymbolsIn:[0x1, 0x1, 0x0, 0x1], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x0, 0x1]), + (TestCommonSymbolsIn:[0x0, 0x1, 0x1, 0x0], + TestCommonSymbolValidsIn:[0x0, 0x1, 0x1, 0x0]), + (TestCommonSymbolsIn:[0x0, 0x0, 0x0, 0x0], + TestCommonSymbolValidsIn:[0x0, 0x0, 0x0, 0x0]), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.last); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonOutputs[1] = [ + (TestCommonSymbolsOut:[0x1, 0x0], + TestCommonCountsOut:[0x7, 0x0]), + ]; + + let tok = for ((counter, output), tok): + ((u32, TestCommonOutputs) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: output.0, + counts: output.1, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc ConsumePacketWithAllDiffSymbols { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init{()} + + config(terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + spawn RunLengthEncoderAdvanced< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH + >(enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.last); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonOutputs[2] = [ + (TestCommonSymbolsOut:[0x1, 0x2], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x3, 0x4], + TestCommonCountsOut:[0x1, 0x1]), + ]; + + let tok = for ((counter, output), tok): + ((u32, TestCommonOutputs) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: output.0, + counts: output.1, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc ConsumePacketsWhereLastSymbolRepeats { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init{()} + + config(terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + spawn RunLengthEncoderAdvanced< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH + >(enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + (TestCommonSymbolsIn:[0x4, 0x4, 0x4, 0x4], + TestCommonSymbolValidsIn:[0x1, 0x1, 0x1, 0x1]), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.last); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonOutputs[2] = [ + (TestCommonSymbolsOut:[0x1, 0x2], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x3, 0x4], + TestCommonCountsOut:[0x1, 0x5]), + ]; + + let tok = for ((counter, output), tok): + ((u32, TestCommonOutputs) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: output.0, + counts: output.1, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} diff --git a/xls/modules/rle/rle_enc_adv_adjust_width_stage.x b/xls/modules/rle/rle_enc_adv_adjust_width_stage.x new file mode 100644 index 0000000000..9ede70289b --- /dev/null +++ b/xls/modules/rle/rle_enc_adv_adjust_width_stage.x @@ -0,0 +1,563 @@ +// 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. + +import std +import xls.modules.rle.rle_common as rle_common + +type EncInData = rle_common::PlainData; +type EncOutData = rle_common::CompressedData; + +struct RunLengthEncoderAdvancedAdjustWidthStageState< + SYMBOL_WIDTH:u32, COUNT_WIDTH:u32, PAIR_COUNT:u32> { + + stored_pairs: (bits[SYMBOL_WIDTH], bits[COUNT_WIDTH])[PAIR_COUNT], + stored_pairs_count: u32, + stored_last: bool, +} + +pub proc RunLengthEncoderAdvancedAdjustWidthStage< + SYMBOL_WIDTH: u32, COUNT_WIDTH: u32, INPUT_WIDTH:u32, OUTPUT_WIDTH:u32> { + + input_r: chan<(EncOutData, u32)> in; + output_s: chan> out; + + init {( + RunLengthEncoderAdvancedAdjustWidthStageState< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH> { + stored_pairs: zero!<(bits[SYMBOL_WIDTH], bits[COUNT_WIDTH])[INPUT_WIDTH]>(), + stored_pairs_count: u32:0, + stored_last: false, + } + )} + config ( + input_r: chan<(EncOutData, u32)> in, + output_s: chan> out, + ) {(input_r, output_s)} + + next (tok: token, state: RunLengthEncoderAdvancedAdjustWidthStageState< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH>) { + let recv_next_portion = !state.stored_last && + (state.stored_pairs_count <= OUTPUT_WIDTH); + let empty_input = ( + EncOutData { + symbols: zero!(), + counts: zero!(), + last: false + }, + u32:0, + ); + let (tok, input) = recv_if(tok, input_r, recv_next_portion, empty_input); + + let (pairs_to_send, pairs_to_send_count, input_processed_count) = + for (idx, (pairs, pairs_count, input_count)) in range(u32:0, OUTPUT_WIDTH) { + if pairs_count < state.stored_pairs_count { + (update(pairs, pairs_count, state.stored_pairs[pairs_count]), + pairs_count + u32:1, input_count) + } else if input_count < input.1 { + let input_pair = (input.0.symbols[input_count], + input.0.counts[input_count]); + (update(pairs, pairs_count, input_pair), + pairs_count + u32:1, input_count + u32:1) + } else { + (pairs, pairs_count, input_count) + } + } ((zero!<(bits[SYMBOL_WIDTH], bits[COUNT_WIDTH])[OUTPUT_WIDTH]>(), + u32:0, u32:0)); + + // If we recv data, all stored pairs are being send + let (pairs_to_state, pairs_count_to_state) = if recv_next_portion { + for (idx, (pairs, pairs_count)) in range(u32:0, INPUT_WIDTH) { + if input_processed_count <= idx && idx < input.1 { + (update(pairs, pairs_count, + (input.0.symbols[idx], input.0.counts[idx])), + pairs_count + u32:1) + } else { + (pairs, pairs_count) + } + }((zero!<(bits[SYMBOL_WIDTH], bits[COUNT_WIDTH])[INPUT_WIDTH]>(), u32:0)) + } else { + for (idx, (pairs, pairs_count)) in range(u32:0, INPUT_WIDTH){ + if pairs_to_send_count <= idx && idx < state.stored_pairs_count { + ( + update(pairs, pairs_count, state.stored_pairs[idx]), + pairs_count + u32:1 + ) + } else { + (pairs, pairs_count) + } + } ((state.stored_pairs, u32:0)) + }; + + let last_to_send = (state.stored_last || input.0.last) && + (pairs_count_to_state == u32:0); + let last_to_state = (state.stored_last || input.0.last) && + (pairs_count_to_state != u32:0); + + let (symbols_to_send, counts_to_send) = + for (idx, (symbols, counts)) in range(u32:0, OUTPUT_WIDTH) { + let pair = pairs_to_send[idx]; + (update(symbols, idx, pair.0), update(counts, idx, pair.1)) + }((zero!(), + zero!())); + + let output = EncOutData { + symbols: symbols_to_send, + counts: counts_to_send, + last: last_to_send, + }; + let tok = send(tok, output_s, output); + + RunLengthEncoderAdvancedAdjustWidthStageState< + SYMBOL_WIDTH, COUNT_WIDTH, INPUT_WIDTH> { + stored_pairs: pairs_to_state, + stored_pairs_count: pairs_count_to_state, + stored_last: last_to_state, + } + } +} + +const TEST_COMMON_SYMBOL_WIDTH = u32:32; +const TEST_COMMON_COUNT_WIDTH = u32:32; +const TEST_COMMON_INPUT_WIDTH = u32:4; +const TEST_COMMON_OUTPUT_WIDTH = u32:2; + +type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; +type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; + +type TestCommonSymbolsIn = TestCommonSymbol[TEST_COMMON_INPUT_WIDTH]; +type TestCommonCountsIn = TestCommonCount[TEST_COMMON_INPUT_WIDTH]; +type TestCommonSymbolsOut = TestCommonSymbol[TEST_COMMON_OUTPUT_WIDTH]; +type TestCommonCountsOut = TestCommonCount[TEST_COMMON_OUTPUT_WIDTH]; + +type TestCommonStimulus = (TestCommonSymbolsIn, TestCommonCountsIn, u32); + +type TestCommonEncInData = EncOutData; +type TestCommonEncInTuple = (TestCommonEncInData, u32); + +type TestCommonEncOutData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>; + +// Test simple case, where only last is set. +// Check handling of empty transaction. +#[test_proc] +proc PacketContainsOnlyLast { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x0, 0x0, 0x0, 0x0], + u32:0), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, _stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbolsOut, TestCommonCountsOut)[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0], + [TestCommonCount:0x0, TestCommonCount:0x0]), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbolsOut, TestCommonCountsOut)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Test simple case, where number of incoming pairs <= +// max output width +#[test_proc] +proc InputPairCountLessOrEqualOutputWidth { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x1, 0x1, 0x0, 0x0], + u32:2), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, _stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbolsOut, TestCommonCountsOut)[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2], + [TestCommonCount:0x1, TestCommonCount:0x1]), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbolsOut, TestCommonCountsOut)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Test simple case, where number of incoming pairs = input width +// It checks serialization +#[test_proc] +proc InputFullyFilled { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x1, 0x1, 0x1, 0x1], + u32:4), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, _stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbolsOut, TestCommonCountsOut)[2] = [ + (TestCommonSymbolsOut:[0x1, 0x2], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x3, 0x4], + TestCommonCountsOut:[0x1, 0x1]), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbolsOut, TestCommonCountsOut)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Send 2-packet ransaction, where first packet has 3 pairs, and second one has +// single pair. Checks that only 2 output packets are produced. +#[test_proc] +proc CombineStateWithNextInputPairs { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x1, 0x1, 0x1, 0x0], + u32:3), + (TestCommonSymbolsIn:[0x4, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x1, 0x0, 0x0, 0x0], + u32:1), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, _stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbolsOut, TestCommonCountsOut)[2] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2], + [TestCommonCount:0x1, TestCommonCount:0x1]), + ([TestCommonSymbol:0x3, TestCommonSymbol:0x4], + [TestCommonCount:0x1, TestCommonCount:0x1]), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbolsOut, TestCommonCountsOut)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Send 2-packet ransaction, where first packet has 3 pairs, and second one has +// 4 pairs. Checks that only 4 output packets are produced. +#[test_proc] +proc PairStateCombineWithStateUpdate { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + (TestCommonSymbolsIn:[0x1, 0x2, 0x3, 0x4], + TestCommonCountsIn:[0x1, 0x1, 0x1, 0x0], + u32:3), + (TestCommonSymbolsIn:[0x4, 0x5, 0x6, 0x7], + TestCommonCountsIn:[0x1, 0x1, 0x1, 0x1], + u32:4), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, _stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbolsOut, TestCommonCountsOut)[4] = [ + (TestCommonSymbolsOut:[0x1, 0x2], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x3, 0x4], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x5, 0x6], + TestCommonCountsOut:[0x1, 0x1]), + (TestCommonSymbolsOut:[0x7, 0x0], + TestCommonCountsOut:[0x1, 0x0]), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbolsOut, TestCommonCountsOut)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Send 2 transactions, where first one has 3 pairs, and second one has +// single pair. Checks that 2 transactions will be created, first one with 2 +// output packets and second one with single packet. +#[test_proc] +proc NoStateSipllAfterLast { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config(terminator: chan out) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedAdjustWidthStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH, TEST_COMMON_OUTPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok:token, state:()) { + let TestCommonTestStimuli: TestCommonEncInTuple[2] = [ + (TestCommonEncInData{ + symbols:[0x1, 0x2, 0x3, 0x4], + counts:[0x1, 0x1, 0x1, 0x0], + last:true + }, u32:3), + (TestCommonEncInData{ + symbols:[0x4, 0x2, 0x3, 0x4], + counts:[0x1, 0x0, 0x0, 0x0], + last:true + }, u32:1), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonEncInTuple) , token) + in enumerate(TestCommonTestStimuli) { + let tok = send(tok, enc_input_s, stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, pair_count: {}", + counter, stimulus.0.symbols, stimulus.0.counts, stimulus.0.last, stimulus.1); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonEncOutData[3] = [ + TestCommonEncOutData { + symbols: [0x1, 0x2], + counts: [0x1, 0x1], + last: false, + }, + TestCommonEncOutData { + symbols: [0x3, 0x0], + counts: [0x1, 0x0], + last: true, + }, + TestCommonEncOutData { + symbols: [0x4, 0x0], + counts: [0x1, 0x0], + last: true + }, + ]; + let tok = for ((counter, expected), tok): + ((u32, TestCommonEncOutData) , token) + in enumerate(TestCommonTestOutput) { + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} diff --git a/xls/modules/rle/rle_enc_adv_core.x b/xls/modules/rle/rle_enc_adv_core.x new file mode 100644 index 0000000000..bee778351d --- /dev/null +++ b/xls/modules/rle/rle_enc_adv_core.x @@ -0,0 +1,669 @@ +// 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. + +import std +import xls.modules.rle.rle_common as rle_common + +type EncInData = rle_common::PlainData; +type EncOutData = rle_common::CompressedData; + + +// structure to preserve the state of an RLE encoder +struct RunLengthEncoderAdvancedCoreState { + + // symbol from the previous RunLengthEncoder::next evaluation, + // valid if prev_count > 0 + prev_symbol: bits[SYMBOL_WIDTH], + // symbol count from the previous RunLengthEncoder::next evaluation. + // zero means that the previous evaluation sent all the data and + // we start counting from the beginning + prev_count: bits[COUNT_WIDTH], + // flag indicating that the previous symbol was the last one + // in the transmission + prev_last: bool, +} + +// RLE encoder implementation +pub proc RunLengthEncoderAdvancedCoreStage { + + input_r: chan<(EncOutData, + u32, u32)> in; + output_s: chan<(EncOutData, u32)> out; + + init {( + RunLengthEncoderAdvancedCoreState { + prev_symbol: bits[SYMBOL_WIDTH]:0, + prev_count: bits[COUNT_WIDTH]:0, + prev_last: false, + } + )} + + config ( + input_r: chan<(EncOutData, + u32, u32)> in, + output_s: chan<(EncOutData, + u32)> out, + ) {(input_r, output_s)} + + next (tok: token, state: RunLengthEncoderAdvancedCoreState) { + let empty = ( + EncOutData{ + symbols: zero!(), + counts: zero!(), + last: false + }, + u32:0, + u32:0, + ); + let (tok, input) = recv_if(tok, input_r, !state.prev_last, empty); + + let state_has_valid_symbol = + state.prev_count != zero!(); + let symbols_diff = state.prev_symbol != input.0.symbols[0] && + state_has_valid_symbol; + + let overflow = + (input.0.counts[input.1] as bits[COUNT_WIDTH + u32:1] + + state.prev_count as bits[COUNT_WIDTH + u32:1])[COUNT_WIDTH as s32:]; + + let pack_count = input.0.counts[input.1] + state.prev_count + + overflow as bits[COUNT_WIDTH]; + + let total_pair_count = match(symbols_diff, overflow, state.prev_last) { + (false, false, false) => input.2, + _ => input.2 + u32:1, + }; + + // Never true if state.prev_last is set as input.0.last is false + let combine_last = input.0.last && total_pair_count <= INPUT_WIDTH; + + let (symbols, counts) = match(symbols_diff, overflow) { + (true, _) => ( + (state.prev_symbol as bits[SYMBOL_WIDTH][1]) ++ input.0.symbols, + (state.prev_count as bits[COUNT_WIDTH][1]) ++ input.0.counts, + ), + (false, true) => { + let (symbols, counts, _) = for (idx, (symbols, counts, input_idx)) + in range(u32:0, INPUT_WIDTH + u32:1) { + if idx == input.1 { + (update(symbols, idx, input.0.symbols[input_idx]), + update(counts, idx, std::unsigned_max_value()), + input_idx) + } else if idx == (input.1 + u32:1) { + (update(symbols, idx, input.0.symbols[input_idx]), + update(counts, idx, pack_count), + input_idx + u32:1) + } else { + (update(symbols, idx, input.0.symbols[input_idx]), + update(counts, idx, input.0.counts[input_idx]), + input_idx + u32:1) + } + }((zero!(), + zero!(), + u32:0)); + (symbols, counts) + }, + (false, false) => ( + input.0.symbols ++ bits[SYMBOL_WIDTH]:0 as bits[SYMBOL_WIDTH][1], + update(input.0.counts, input.1, pack_count) ++ + bits[COUNT_WIDTH]:0 as bits[COUNT_WIDTH][1], + ), + _ => ( + zero!(), + zero!(), + ), + }; + + let (symobls_to_send, counts_to_send, last_to_send, pair_count_to_send) = + match (combine_last, state.prev_last) { + (false, false) => { + let idx = total_pair_count - u32:1; + let _symbols = update(symbols, idx, zero!()); + let _counts = update(counts, idx, zero!()); + (slice(_symbols, u32:0, zero!()), + slice(_counts, u32:0, zero!()), + false, idx) + }, + _ => (slice(symbols, u32:0, zero!()), + slice(counts, u32:0, zero!()), + true, total_pair_count), + }; + + let (symbol_to_state, count_to_state, last_to_state) = { + let idx = total_pair_count - u32:1; + match (combine_last, input.0.last) { + (false, true) => (symbols[idx], counts[idx], true), + (false, false) => (symbols[idx], counts[idx], false), + _ => (bits[SYMBOL_WIDTH]:0, bits[COUNT_WIDTH]:0, false), + } + }; + + let output = ( + EncOutData { + symbols: symobls_to_send, + counts: counts_to_send, + last: last_to_send, + }, + pair_count_to_send, + ); + let send = pair_count_to_send > u32:0 || last_to_send; + + let tok = send_if(tok, output_s, send, output); + RunLengthEncoderAdvancedCoreState{ + prev_symbol: symbol_to_state, + prev_count: count_to_state, + prev_last: last_to_state + } + } +} + +// Tests + +const TEST_COMMON_SYMBOL_WIDTH = u32:32; +const TEST_COMMON_COUNT_WIDTH = u32:32; +const TEST_COMMON_INPUT_WIDTH = u32:4; + +type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; +type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; + +type TestCommonSymbols = TestCommonSymbol[TEST_COMMON_INPUT_WIDTH]; +type TestCommonCounts = TestCommonCount[TEST_COMMON_INPUT_WIDTH]; + +type TestCommonStimulus = (TestCommonSymbols, TestCommonCounts, u32, u32); + +type TestCommonEncInData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_INPUT_WIDTH>; +type TestCommonEncInTuple = (TestCommonEncInData, u32, u32); + +type TestCommonEncOutData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_INPUT_WIDTH>; +type TestCommonEncOutTuple = (TestCommonEncOutData, u32); + +// Transaction with counter overflow +const TEST_OVERFLOW_SYMBOL_WIDTH = u32:32; +const TEST_OVERFLOW_COUNT_WIDTH = u32:2; +const TEST_OVERFLOW_INPUT_WIDTH = u32:4; + +type TestOverflowSymbol = bits[TEST_OVERFLOW_SYMBOL_WIDTH]; +type TestOverflowCount = bits[TEST_OVERFLOW_COUNT_WIDTH]; + +type TestOverflowSymbols = TestOverflowSymbol[TEST_OVERFLOW_INPUT_WIDTH]; +type TestOverflowCounts = TestOverflowCount[TEST_OVERFLOW_INPUT_WIDTH]; + +type TestOverflowStimulus = (TestOverflowSymbols, TestOverflowCounts, u32, u32); + +type TestOverflowEncInData = EncOutData; +type TestOverflowEncInTuple = (TestOverflowEncInData, u32, u32); + +type TestOverflowEncOutData = EncOutData; +type TestOverflowEncOutTuple = (TestOverflowEncOutData, u32); + + +// Check empty transaction +#[test_proc] +proc PacketOnlyWithLastSet { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + (TestCommonSymbols: [0x0, 0x0, 0x0, 0x0], + TestCommonCounts: [0x0, 0x0, 0x0, 0x0], + u32:0, u32:0), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, stimulus.3 + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, + _stimulus.1, _stimulus.2); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbols, TestCommonCounts, u32)[1] = [ + (TestCommonSymbols: [0x0, 0x0, 0x0, 0x0], + TestCommonCounts: [0x0, 0x0, 0x0, 0x0], u32:0), + ]; + + let tok = for ((counter, (symbols, counts, pairs)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }, pairs + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Test state interaction with packet that starts with pair which +// has `symbol` equal to RLE's `state.prev_symbol` and doesn't cause +// counter overflow +#[test_proc] +proc CombineWithoutOverflow { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + (TestCommonSymbols: [0x1, 0x0, 0x0, 0x0], + TestCommonCounts: [0x1, 0x0, 0x0, 0x0], + u32:0, u32:1), + (TestCommonSymbols: [0x1, 0x2, 0x3, 0x4], + TestCommonCounts: [0x1, 0x1, 0x1, 0x1], + u32:0, u32:4), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, stimulus.3 + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, + _stimulus.1, _stimulus.2); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbols, TestCommonCounts, u32)[1] = [ + (TestCommonSymbols: [0x1, 0x2, 0x3, 0x4], + TestCommonCounts: [0x2, 0x1, 0x1, 0x1], u32:4), + ]; + + let tok = for ((counter, (symbols, counts, pairs)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }, pairs + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Test state interaction with packet that starts with pair which +// has `symbol` equal to RLE's `state.prev_symbol` and does cause +// counter overflow +#[test_proc] +proc CombineWithOverflow { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_OVERFLOW_SYMBOL_WIDTH, TEST_OVERFLOW_COUNT_WIDTH, + TEST_OVERFLOW_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestOverflowTestStimuli: TestOverflowStimulus[2] = [ + (TestOverflowSymbols: [0x1, 0x0, 0x0, 0x0], + TestOverflowCounts: [0x1, 0x0, 0x0, 0x0], + u32:0, u32:1), + (TestOverflowSymbols: [0x1, 0x2, 0x3, 0x4], + TestOverflowCounts: [0x3, 0x1, 0x1, 0x1], + u32:0, u32:4), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestOverflowStimulus) , token) + in enumerate(TestOverflowTestStimuli) { + let last = counter == (array_size(TestOverflowTestStimuli) - u32:1); + let _stimulus = ( + TestOverflowEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, stimulus.3 + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, + _stimulus.1, _stimulus.2); + (tok) + }(tok); + + let TestOverflowTestOutput: (TestOverflowSymbols, TestOverflowCounts, u32)[2] = [ + (TestOverflowSymbols: [0x1, 0x1, 0x2, 0x3], + TestOverflowCounts: [0x3, 0x1, 0x1, 0x1], u32:4), + (TestOverflowSymbols: [0x4, 0x0, 0x0, 0x0], + TestOverflowCounts: [0x1, 0x0, 0x0, 0x0], u32:1), + ]; + + let tok = for ((counter, (symbols, counts, pairs)), tok): + ((u32, (TestOverflowSymbols, TestOverflowCounts, u32)) , token) + in enumerate(TestOverflowTestOutput) { + let last = counter == (array_size(TestOverflowTestOutput) - u32:1); + let expected = ( + TestOverflowEncOutData{ + symbols: symbols, + counts: counts, + last: last + }, pairs + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Check that state is correctly updated and contains lastest +// symbol, count pair +#[test_proc] +proc CombineAfterStateChange { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[3] = [ + (TestCommonSymbols: [0x1, 0x0, 0x0, 0x0], + TestCommonCounts: [0x1, 0x0, 0x0, 0x0], + u32:0, u32:1), + (TestCommonSymbols: [0x2, 0x3, 0x4, 0x5], + TestCommonCounts: [0x1, 0x1, 0x1, 0x1], + u32:0, u32:4), + (TestCommonSymbols: [0x5, 0x0, 0x0, 0x0], + TestCommonCounts: [0x1, 0x0, 0x0, 0x0], + u32:0, u32:1), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, stimulus.3 + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, + _stimulus.1, _stimulus.2); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbols, TestCommonCounts, u32)[2] = [ + (TestCommonSymbols: [0x1, 0x2, 0x3, 0x4], + TestCommonCounts: [0x1, 0x1, 0x1, 0x1], u32:4), + (TestCommonSymbols: [0x5, 0x0, 0x0, 0x0], + TestCommonCounts: [0x2, 0x0, 0x0, 0x0], u32:1), + ]; + + let tok = for ((counter, (symbols, counts, pairs)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }, pairs + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Check last_combine is correctly used +#[test_proc] +proc CombineStateWithLastPacket { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + (TestCommonSymbols: [0x1, 0x0, 0x0, 0x0], + TestCommonCounts: [0x1, 0x0, 0x0, 0x0], + u32:0, u32:1), + (TestCommonSymbols: [0x2, 0x3, 0x4, 0x0], + TestCommonCounts: [0x1, 0x1, 0x1, 0x0], + u32:0, u32:3), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = ( + TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }, stimulus.2, stimulus.3 + ); + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, _stimulus.0.symbols, _stimulus.0.counts, _stimulus.0.last, + _stimulus.1, _stimulus.2); + (tok) + }(tok); + + let TestCommonTestOutput: (TestCommonSymbols, TestCommonCounts, u32)[1] = [ + (TestCommonSymbols: [0x1, 0x2, 0x3, 0x4], + TestCommonCounts: [0x1, 0x1, 0x1, 0x1], u32:4), + ]; + + let tok = for ((counter, (symbols, counts, pairs)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }, pairs + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} + +// Check that state is correctly cleared after `last` is seen +#[test_proc] +proc NoStateSipllAfterLast { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + init{()} + config( + terminator: chan out + ) { + let (input_s, input_r) = chan; + let (output_s, output_r) = chan; + spawn RunLengthEncoderAdvancedCoreStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, + TEST_COMMON_INPUT_WIDTH>(input_r, output_s); + (terminator, input_s, output_r) + } + next(tok: token, state: ()) { + let TestCommonTestStimuli: TestCommonEncInTuple[2] = [ + (TestCommonEncInData { + symbols: TestCommonSymbols:[0x1, 0x0, 0x0, 0x0], + counts: TestCommonCounts:[0x1, 0x0, 0x0, 0x0], + last: true + }, u32:0, u32:1), + (TestCommonEncInData { + symbols: TestCommonSymbols:[0x1, 0x0, 0x0, 0x0], + counts: TestCommonCounts:[0x1, 0x0, 0x0, 0x0], + last: true + }, u32:0, u32:1), + ]; + + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonEncInTuple) , token) + in enumerate(TestCommonTestStimuli) { + let tok = send(tok, enc_input_s, stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}, propagation: {}, pair_count: {}", + counter, stimulus.0.symbols, stimulus.0.counts, stimulus.0.last, + stimulus.1, stimulus.2); + (tok) + }(tok); + + let TestCommonTestOutput: TestCommonEncOutTuple[2] = [ + (TestCommonEncOutData { + symbols: [0x1, 0x0, 0x0, 0x0], + counts: [0x1, 0x0, 0x0, 0x0], + last: true, + }, u32:1), + (TestCommonEncOutData { + symbols: [0x1, 0x0, 0x0, 0x0], + counts: [0x1, 0x0, 0x0, 0x0], + last: true, + }, u32:1), + ]; + + let tok = for ((counter, expected), tok): + ((u32, TestCommonEncOutTuple) , token) + in enumerate(TestCommonTestOutput) { + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, pairs: {}", + counter, enc_output.0.symbols, enc_output.0.counts, enc_output.0.last, + enc_output.1); + assert_eq(enc_output, expected); + (tok) + }(tok); + + send(tok, terminator, true); + () + } +} diff --git a/xls/modules/rle/rle_enc_adv_realign_stage.x b/xls/modules/rle/rle_enc_adv_realign_stage.x new file mode 100644 index 0000000000..30f3fe4cb7 --- /dev/null +++ b/xls/modules/rle/rle_enc_adv_realign_stage.x @@ -0,0 +1,405 @@ +// 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. + +import std +import xls.modules.rle.rle_common as rle_common + +type EncInData = rle_common::PlainData; +type EncOutData = rle_common::CompressedData; + +pub proc RunLengthEncoderAdvancedRealignStage< + SYMBOL_WIDTH: u32, COUNT_WIDTH: u32,INPUT_WIDTH:u32> { + + input_r: chan> in; + output_s: chan<(EncOutData, u32, u32)> out; + + init{()} + config( + input_r: chan> in, + output_s: chan<(EncOutData, u32, u32)> out, + ) {(input_r, output_s)} + + next (tok:token, state: ()) { + let (tok, input) = recv(tok, input_r); + let (symbols, counts, end) = + for (idx, (symbols, counts, insert_place)) in range(u32:0, INPUT_WIDTH) { + if input.counts[idx] != bits[COUNT_WIDTH]:0 { + ( + update(symbols, insert_place, input.symbols[idx]), + update(counts, insert_place, input.counts[idx]), + insert_place + u32:1 + ) + } else { + (symbols, counts, insert_place) + } + } ((zero!(), + zero!(), + u32:0)); + let output = EncOutData { + symbols: symbols, + counts: counts, + last: input.last, + }; + let (prop_count, _, _) = + for (idx, (p_count, symbol, valid)) in range(u32:1, INPUT_WIDTH) { + let symbol_eq = symbols[idx] == symbol; + match (valid, symbol_eq) { + (false, _) => (p_count, symbol, valid), + (true, true) => (p_count + u32:1, symbol, valid), + (true, false) => (p_count, symbol, false), + _ => (u32:0, bits[SYMBOL_WIDTH]:0, false), + } + } ((u32:0, symbols[u32:0], counts[u32:0] != bits[COUNT_WIDTH]:0)); + send(tok, output_s, (output, prop_count, end)); + () + } +} + +// Test RealignStage + +// Transaction without overflow +const TEST_COMMON_SYMBOL_WIDTH = u32:32; +const TEST_COMMON_COUNT_WIDTH = u32:32; +const TEST_COMMON_SYMBOL_COUNT = u32:4; + +type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; +type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; + +type TestCommonSymbols = TestCommonSymbol[TEST_COMMON_SYMBOL_COUNT]; +type TestCommonCounts = TestCommonCount[TEST_COMMON_SYMBOL_COUNT]; + +type TestCommonStimulus = (TestCommonSymbols, TestCommonCounts); + +type TestCommonEncData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>; + +type TestCommonEncInData = TestCommonEncData; +type TestCommonEncOutData = (TestCommonEncData, u32, u32); + +// Transaction with counter overflow +const OVERFLOW_COUNT_WIDTH = u32:2; + +type OverflowSymbol = TestCommonSymbol; +type OverflowCount = bits[OVERFLOW_COUNT_WIDTH]; + +type OverflowSymbols = OverflowSymbol[TEST_COMMON_SYMBOL_COUNT]; +type OverflowCounts = OverflowCount[TEST_COMMON_SYMBOL_COUNT]; + +type OverflowStimulus = (TestCommonSymbols, OverflowCounts); + +type OverflowEncData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, OVERFLOW_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>; + +type OverflowEncInData = OverflowEncData; +type OverflowEncOutData = (OverflowEncData, u32, u32); + +#[test_proc] +proc RunLengthEncoderAdvancedRealignStageNoPairs { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedRealignStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0,], + [TestCommonCount:0x0, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x0,] + ), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.counts, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbols, TestCommonCounts, u32, u32)[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0,], + [TestCommonCount:0x0, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x0,], + u32:0, + u32:0, + ), + ]; + let tok = for ((counter, (symbols, counts, propagation, end)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncData{ + symbols: symbols, + counts: counts, + last: last + }, + propagation, + end, + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, propagation: {}", + counter, enc_output.0.symbols, enc_output.0.counts, + enc_output.0.last, enc_output.1 + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedRealignStageAllPairsFilled { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedRealignStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2, + TestCommonSymbol:0x3, TestCommonSymbol:0x4,], + [TestCommonCount:0x1, TestCommonCount:0x1, + TestCommonCount:0x1, TestCommonCount:0x1,] + ), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, last: {}", + counter, _stimulus.symbols, _stimulus.counts, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbols, TestCommonCounts, u32, u32)[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2, + TestCommonSymbol:0x3, TestCommonSymbol:0x4,], + [TestCommonCount:0x1, TestCommonCount:0x1, + TestCommonCount:0x1, TestCommonCount:0x1,], + u32:0, + u32:4, + ), + ]; + let tok = for ((counter, (symbols, counts, propagation, end)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncData{ + symbols: symbols, + counts: counts, + last: last + }, + propagation, + end, + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, propagation: {}", + counter, enc_output.0.symbols, enc_output.0.counts, + enc_output.0.last, enc_output.1 + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedRealignStageFarAwayPair { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedRealignStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x1,], + [TestCommonCount:0x0, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x4,] + ), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.counts, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbol[4], TestCommonCount[4], u32, u32)[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0,], + [TestCommonCount:0x4, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x0,], + u32:0, + u32:1, + ), + ]; + let tok = for ((counter, (symbols, counts, propagation, end)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts, u32, u32)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = ( + TestCommonEncData{ + symbols: symbols, + counts: counts, + last: last + }, + propagation, + end, + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, propagation: {}", + counter, enc_output.0.symbols, enc_output.0.counts, + enc_output.0.last, enc_output.1 + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedRealignStagePropagataion { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedRealignStage< + TEST_COMMON_SYMBOL_WIDTH, OVERFLOW_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let OverflowTestStimuli: OverflowStimulus[1] = [ + ([OverflowSymbol:0x0, OverflowSymbol:0x0, + OverflowSymbol:0x1, OverflowSymbol:0x1,], + [OverflowCount:0x0, OverflowCount:0x0, + OverflowCount:0x3, OverflowCount:0x1,] + ), + ]; + let tok = for ((counter, stimulus), tok): + ((u32, OverflowStimulus) , token) + in enumerate(OverflowTestStimuli) { + let last = counter == (array_size(OverflowTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + counts: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, counts: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.counts, _stimulus.last); + (tok) + }(tok); + let OverflowTestOutput: + (OverflowSymbol[4], OverflowCount[4], u32, u32)[1] = [ + ([OverflowSymbol:0x1, OverflowSymbol:0x1, + OverflowSymbol:0x0, OverflowSymbol:0x0,], + [OverflowCount:0x3, OverflowCount:0x1, + OverflowCount:0x0, OverflowCount:0x0,], + u32:1, + u32:2, + ), + ]; + let tok = for ((counter, (symbols, counts, propagation, end)), tok): + ((u32, (TestCommonSymbols, OverflowCounts, u32, u32)) , token) + in enumerate(OverflowTestOutput) { + let last = counter == (array_size(OverflowTestOutput) - u32:1); + let expected = ( + TestCommonEncData{ + symbols: symbols, + counts: counts, + last: last + }, + propagation, + end, + ); + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}, propagation: {}", + counter, enc_output.0.symbols, enc_output.0.counts, + enc_output.0.last, enc_output.1 + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} diff --git a/xls/modules/rle/rle_enc_adv_reduce_stage.x b/xls/modules/rle/rle_enc_adv_reduce_stage.x new file mode 100644 index 0000000000..6db583bfbb --- /dev/null +++ b/xls/modules/rle/rle_enc_adv_reduce_stage.x @@ -0,0 +1,378 @@ +// 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. + +import std +import xls.modules.rle.rle_common as rle_common + +type EncInData = rle_common::PlainData; +type EncOutData = rle_common::CompressedData; + +pub proc RunLengthEncoderAdvancedReduceStage< + SYMBOL_WIDTH: u32, COUNT_WIDTH: u32,INPUT_WIDTH:u32> { + + input_r: chan> in; + output_s: chan> out; + + init {()} + config ( + input_r: chan> in, + output_s: chan> out, + ) {(input_r, output_s)} + + next (tok: token, state: ()) { + let (tok, input) = recv(tok, input_r); + let (symbols, counts, symbol, count) = + for (idx, (symbols, counts, symbol, count)) in range(u32:1, INPUT_WIDTH) { + let _symbol = input.symbols[idx]; + let valid = input.symbol_valids[idx]; + let symbols_diff = symbol != _symbol; + let overflow = count == std::unsigned_max_value(); + match (valid, overflow, symbols_diff) { + (false, _, _) => (symbols, counts, symbol, count), + (true, false, false) => (symbols, counts, + symbol, count + bits[COUNT_WIDTH]: 1), + _ => ( + update(symbols, idx - u32:1, symbol), + update(counts, idx - u32:1, count), + _symbol, + bits[COUNT_WIDTH]: 1, + ), + } + } ((zero!(), + zero!(), + input.symbols[u32:0], + input.symbol_valids[u32:0] as bits[COUNT_WIDTH])); + let symbols = update(symbols, INPUT_WIDTH - u32:1, symbol); + let counts = update(counts, INPUT_WIDTH - u32:1, count); + let output = EncOutData { + symbols: symbols, + counts: counts, + last: input.last, + }; + let not_empty = input.last || + or_reduce(std::convert_to_bits_msb0(input.symbol_valids)); + send_if(tok, output_s, not_empty, output); + () + } +} + +// Test ReduceStage + +// Transaction without overflow +const TEST_COMMON_SYMBOL_WIDTH = u32:32; +const TEST_COMMON_COUNT_WIDTH = u32:32; +const TEST_COMMON_SYMBOL_COUNT = u32:4; + +type TestCommonSymbol = bits[TEST_COMMON_SYMBOL_WIDTH]; +type TestCommonCount = bits[TEST_COMMON_COUNT_WIDTH]; + +type TestCommonSymbols = TestCommonSymbol[TEST_COMMON_SYMBOL_COUNT]; +type TestCommonCounts = TestCommonCount[TEST_COMMON_SYMBOL_COUNT]; + +type TestCommonStimulus = ( + TestCommonSymbols, bits[1][TEST_COMMON_SYMBOL_COUNT]); + +type TestCommonEncInData = EncInData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_SYMBOL_COUNT>; +type TestCommonEncOutData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>; + +// Transaction with counter overflow +const OVERFLOW_COUNT_WIDTH = u32:2; + +type OverflowSymbol = TestCommonSymbol; +type OverflowCount = bits[OVERFLOW_COUNT_WIDTH]; + +type OverflowSymbols = OverflowSymbol[TEST_COMMON_SYMBOL_COUNT]; +type OverflowCounts = OverflowCount[TEST_COMMON_SYMBOL_COUNT]; + +type OverflowStimulus = ( + TestCommonSymbols, bits[1][TEST_COMMON_SYMBOL_COUNT]); + +type OverflowEncInData = TestCommonEncInData; +type OverflowEncOutData = EncOutData< + TEST_COMMON_SYMBOL_WIDTH, OVERFLOW_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>; + + +#[test_proc] +proc RunLengthEncoderAdvancedReduceStageNoSymbols { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedReduceStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[2] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0], + [bits[1]:0, bits[1]:0, bits[1]:0, bits[1]:0], + ), + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0], + [bits[1]:0, bits[1]:0, bits[1]:0, bits[1]:0], + ) + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, symbol_valids: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.symbol_valids, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbols, TestCommonCounts)[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x0,], + [TestCommonCount:0x0, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x0,] + ), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbols, TestCommonCounts)) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedReduceStageNonRepeatingSymbols { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedReduceStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2, + TestCommonSymbol:0x3, TestCommonSymbol:0x4], + [bits[1]:1, bits[1]:1, bits[1]:1, bits[1]:1], + ) + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, symbol_valids: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.symbol_valids, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbol[4], TestCommonCount[4])[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x2, + TestCommonSymbol:0x3, TestCommonSymbol:0x4,], + [TestCommonCount:0x1, TestCommonCount:0x1, + TestCommonCount:0x1, TestCommonCount:0x1,] + ), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbol[4], TestCommonCount[4])) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedReduceStageRepeatingSymbolsNoOverflow { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedReduceStage< + TEST_COMMON_SYMBOL_WIDTH, TEST_COMMON_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let TestCommonTestStimuli: TestCommonStimulus[1] = [ + ([TestCommonSymbol:0x1, TestCommonSymbol:0x1, + TestCommonSymbol:0x1, TestCommonSymbol:0x1], + [bits[1]:1, bits[1]:1, bits[1]:1, bits[1]:1], + ) + ]; + let tok = for ((counter, stimulus), tok): + ((u32, TestCommonStimulus) , token) + in enumerate(TestCommonTestStimuli) { + let last = counter == (array_size(TestCommonTestStimuli) - u32:1); + let _stimulus = TestCommonEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, symbol_valids: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.symbol_valids, _stimulus.last); + (tok) + }(tok); + let TestCommonTestOutput: + (TestCommonSymbol[4], TestCommonCount[4])[1] = [ + ([TestCommonSymbol:0x0, TestCommonSymbol:0x0, + TestCommonSymbol:0x0, TestCommonSymbol:0x1,], + [TestCommonCount:0x0, TestCommonCount:0x0, + TestCommonCount:0x0, TestCommonCount:0x4,] + ), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (TestCommonSymbol[4], TestCommonCount[4])) , token) + in enumerate(TestCommonTestOutput) { + let last = counter == (array_size(TestCommonTestOutput) - u32:1); + let expected = TestCommonEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} + +#[test_proc] +proc RunLengthEncoderAdvancedReduceStageRepeatingSymbolsOverflow { + terminator: chan out; + enc_input_s: chan out; + enc_output_r: chan in; + + init {()} + config (terminator: chan out) { + let (enc_input_s, enc_input_r) = chan; + let (enc_output_s, enc_output_r) = chan; + + spawn RunLengthEncoderAdvancedReduceStage< + TEST_COMMON_SYMBOL_WIDTH, OVERFLOW_COUNT_WIDTH, TEST_COMMON_SYMBOL_COUNT>( + enc_input_r, enc_output_s); + (terminator, enc_input_s, enc_output_r) + } + next (tok: token, state:()) { + let OverflowTestStimuli: OverflowStimulus[1] = [ + ([OverflowSymbol:0x1, OverflowSymbol:0x1, + OverflowSymbol:0x1, OverflowSymbol:0x1], + [bits[1]:1, bits[1]:1, bits[1]:1, bits[1]:1], + ) + ]; + let tok = for ((counter, stimulus), tok): + ((u32, OverflowStimulus) , token) + in enumerate(OverflowTestStimuli) { + let last = counter == (array_size(OverflowTestStimuli) - u32:1); + let _stimulus = OverflowEncInData{ + symbols: stimulus.0, + symbol_valids: stimulus.1, + last: last + }; + let tok = send(tok, enc_input_s, _stimulus); + trace_fmt!("Sent {} stimuli, symbols: {:x}, symbol_valids: {:x}, lasts: {}", + counter, _stimulus.symbols, _stimulus.symbol_valids, _stimulus.last); + (tok) + }(tok); + let OverflowTestOutput: + (OverflowSymbol[4], OverflowCount[4])[1] = [ + ([OverflowSymbol:0x0, OverflowSymbol:0x0, + OverflowSymbol:0x1, OverflowSymbol:0x1,], + [OverflowCount:0x0, OverflowCount:0x0, + OverflowCount:0x3, OverflowCount:0x1,] + ), + ]; + let tok = for ((counter, (symbols, counts)), tok): + ((u32, (OverflowSymbol[4], OverflowCount[4])) , token) + in enumerate(OverflowTestOutput) { + let last = counter == (array_size(OverflowTestOutput) - u32:1); + let expected = OverflowEncOutData{ + symbols: symbols, + counts: counts, + last: last + }; + let (tok, enc_output) = recv(tok, enc_output_r); + trace_fmt!( + "Received {} pairs, symbols: {:x}, counts: {}, last: {}", + counter, enc_output.symbols, enc_output.counts, enc_output.last + ); + assert_eq(enc_output, expected); + (tok) + }(tok); + send(tok, terminator, true); + () + } +} From ccb35f709583fa975bebefa2a51dcec825e1c535 Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Mon, 31 Jul 2023 16:54:56 +0200 Subject: [PATCH 3/7] [RLE]: Improve high level overview on Multisymbol encoder Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_enc_adv.x | 41 +++++++++++++++-------------------- 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/xls/modules/rle/rle_enc_adv.x b/xls/modules/rle/rle_enc_adv.x index 451c5540aa..e34b4702ef 100644 --- a/xls/modules/rle/rle_enc_adv.x +++ b/xls/modules/rle/rle_enc_adv.x @@ -12,37 +12,30 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This file implements a parametric RLE encoder +// This file implements a parametric multisymbol RLE encoder // // The encoder uses Run Length Encoding (RLE) to compress the input stream of // repeating symbols to the output stream that contains the symbols and -// the number of its consequect occurrences in the input stream. +// the number of its consecutive occurrences in the input stream. // Both the input and the output channels use additional `last` flag // that indicates whether the packet ends the transmission. After sending // the last packet encoder dumps all the data to the output stream. // The behavior of the encoder is presented on the waveform below: -// ──────╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥──── -// next evaluation XXXXXX║ 0 ║ 1 ║ 2 ║ 3 ║ 4 ║ 5 ║ 6 ║ ... -// ──────╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨──── -// ──────╥───────────╥─────╥─────╥─────╥─────╥────────── -// symbol XXXXXX║ A ║ B ║XXXXX║ B ║ C ║XXXXXXXXXX -// (input channel) ──────╨───────────╨─────╨─────╨─────╨─────╨────────── -// last ┌─────┐ ┌─────┐ -// (input channel) ──────────────────┘ └───────────┘ └────────── -// ╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥────────── -// state.prev_symbol ║ 0 ║ A ║ A ║ B ║ 0 ║ B ║ C ║ 0 -// (set state value) ╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨────────── -// ╥─────╥─────╥─────╥─────╥─────╥─────╥─────╥────────── -// state.prev_count ║ 0 ║ 1 ║ 2 ║ 1 ║ 0 ║ 1 ║ 1 ║ 0 -// (set state value) ╨─────╨─────╨─────╨─────╨─────╨─────╨─────╨────────── -// -// do_send ┌───────────┐ ┌───────────┐ -// ──────────────────┘ └─────┘ └──── -// ──────────────────╥─────╥─────╥─────╥─────╥─────╥──── -// symbol, count XXXXXXXXXXXXXXXXXX║ A,2 ║ B,1 ║XXXXX║ B,1 ║ C,1 ║XXXX -// (output channel) ──────────────────╨─────╨─────╨─────╨─────╨─────╨──── -// last ┌─────┐ ┌─────┐ -// (output channel) ────────────────────────┘ └───────────┘ └──── + +// This encoder is implemented as a net of 4 processes. +// 1. Reduce stage - this process takes incoming symbols and symbol_valid +// and reduces them into symbol count pairs. This stage is stateless. +// 2. Realign stage - this process moves pairs emitted from previous stage +// so that they are align to the left, it also calculates propagation distance +// for the first pair. +// 3. Core stage - this stage is stateful. It takes align pairs, +// and combines them with its state.It outputs multiple symbol/count pairs. +// 4 - Adjust Width stage - this stage takes output from the core stage. +// If output can handle more or equal number of pairs as +// input number of symbols. This stage does nothing. +// If the output is narrower than the input, +// this stage will serialize symbol counter pairs. + import std import xls.modules.rle.rle_common as rle_common From f16f00e4ec48bb76a3643374d59a06539bd74bc4 Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Mon, 28 Aug 2023 12:06:56 +0200 Subject: [PATCH 4/7] xls:modules:rle: Review: update comments Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_enc_adv.x | 35 ++++++++++++++++++++---------- xls/modules/rle/rle_enc_adv_core.x | 4 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/xls/modules/rle/rle_enc_adv.x b/xls/modules/rle/rle_enc_adv.x index e34b4702ef..78f8ef1e68 100644 --- a/xls/modules/rle/rle_enc_adv.x +++ b/xls/modules/rle/rle_enc_adv.x @@ -22,19 +22,32 @@ // the last packet encoder dumps all the data to the output stream. // The behavior of the encoder is presented on the waveform below: -// This encoder is implemented as a net of 4 processes. -// 1. Reduce stage - this process takes incoming symbols and symbol_valid -// and reduces them into symbol count pairs. This stage is stateless. -// 2. Realign stage - this process moves pairs emitted from previous stage -// so that they are align to the left, it also calculates propagation distance -// for the first pair. -// 3. Core stage - this stage is stateful. It takes align pairs, -// and combines them with its state.It outputs multiple symbol/count pairs. -// 4 - Adjust Width stage - this stage takes output from the core stage. +// This encoder is implemented as a net of 4 proc. +// 1. Reduce step - this process takes incoming symbols and symbol_valid +// and reduces them into symbol count pairs. This step is stateless. +// 2. Realign step - this process moves pairs emitted from the reduce step +// so that they are aligned to the left, it also calculates propagation +// distance for the first pair. +// Example behaviours: +// 1) +// input: [.., (A, 2), .., (B, 2)] +// output: [(A, 2), (B, 2), .., ..] +// propagation distance: 0 +// 2) +// input: [.., .., (A, 3), (A, 1)] +// output: [(A, 3), (A, 1), .., ..] +// propagation distance: 1 +// 3. Core step - this step is stateful. It takes align pairs from +// the realign step, and combines them with its state to create multiple +// symbol/count pairs output. State is represented by following tuple +// ``. It contains symbol and count from last pair +// received from realign step, or current sum of repeating symbol spanning +// multiple input widths. +// 4. - Adjust Width step - this step takes output from the core step. // If output can handle more or equal number of pairs as -// input number of symbols. This stage does nothing. +// input number of symbols. This step does nothing. // If the output is narrower than the input, -// this stage will serialize symbol counter pairs. +// this step will serialize symbol counter pairs. import std diff --git a/xls/modules/rle/rle_enc_adv_core.x b/xls/modules/rle/rle_enc_adv_core.x index bee778351d..1a0d559f62 100644 --- a/xls/modules/rle/rle_enc_adv_core.x +++ b/xls/modules/rle/rle_enc_adv_core.x @@ -126,7 +126,7 @@ pub proc RunLengthEncoderAdvancedCoreStage { let idx = total_pair_count - u32:1; @@ -152,7 +152,7 @@ pub proc RunLengthEncoderAdvancedCoreStage { - symbols: symobls_to_send, + symbols: symbols_to_send, counts: counts_to_send, last: last_to_send, }, From a84a8eccc60d8803dc4429bd6a3899e122e62bba Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Tue, 29 Aug 2023 14:14:28 +0200 Subject: [PATCH 5/7] xls:modules:rle: Add description for Multisymbol RLE Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_enc_adv.md | 85 ++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 xls/modules/rle/rle_enc_adv.md diff --git a/xls/modules/rle/rle_enc_adv.md b/xls/modules/rle/rle_enc_adv.md new file mode 100644 index 0000000000..0f4358af78 --- /dev/null +++ b/xls/modules/rle/rle_enc_adv.md @@ -0,0 +1,85 @@ +# Multisymbol Run-length Encoder + +The encoder uses Run Length Encoding (RLE) to compress the input stream of +repeating symbols to the output stream that contains the symbols and +the number of its consecutive occurrences in the input stream. + +Overall, we can break down the data processing into four stages: reduction, alignment, compression, and output generation. The division of responsibility allowed the specialized blocks to efficiently process data and made it possible test each functionality separately. + +The first block is responsible for taking the input and reducing it to pairs of symbols and the number of its occurrences, as in the [basic RLE implementation](https://github.com/google/xls/pull/974). The second element of the encoder shifts the previously emitted pairs and adjusts them for further processing. Both of these elements have an empty state. The next block takes the prepared data and combines it with the information about previously processed symbols. The last element is responsible for adjusting the width of the output data to the receiver interface. + + +Input width is defined using the `INPUT_WIDTH` parameter and output width is defined with the `OUTPUT_WIDTH` parameter. +Both the input and the output channels use additional `last` flag +that indicates whether the packet ends the transmission. After sending +the last packet the encoder dumps all the data to the output stream. + +## Encoder processing pipeline detailed breakdown. + +### Initial conditions +- input width is 4 symbols wide, +- output width is 2 pairs wide, +- symbol counter is 2 bits wide. + +### Process +1. Reduce step - this process takes incoming symbols and symbol_valid +and reduces them into symbol count pairs. This step is stateless. + +Example: + +||| +|-----|-------| +|input|output | +|[(A, True), (A, True), (A, True), (A, True)]|[.., .., (A, 3), (A, 1)]| +|input|output | +|[(A, True), (A, True), (A, False), (A, True)]|[.., .., .., (A, 3)]| +|input|output | +|[(A, True), (B, True), (C, True), (D, True)]|[(A, 1), (B, 1), (C, 1), (D, 1)]| + +2. Realign step - this process moves pairs emitted from the reduce step +so that they are aligned to the left, it also calculates propagation +distance for the first pair. + +Example: + +|||| +|-----|-------|--------------------| +|input|output |propagation distance| +|[.., (A, 2), .., (B, 2)]|[(A, 2), (B, 2), .., ..]| 0| +|input|output |propagation distance| +|[.., .., (A, 3), (A, 1)]|[(A, 3), (A, 1), .., ..]| 1| + +3. Core step - this step is stateful. It takes align pairs from +the realign step, and combines them with its state to create multiple +symbol/count pairs output. State is represented by following tuple +``. It contains symbol and count from last pair +received from the realign step, or current sum of repeating symbol spanning +multiple input widths. + +Example: + +||||| +|------|-----|-------|----------| +|state |input|output |next state| +|(A, 2)| [(A, 2), (B, 2), .., ..]|[(A, 3), (A, 1), .., ..]| (B, 2)| +|state |input|output |next state| +|(A, 1)| [(A, 1), (B, 2), .., ..]|[(A, 2), .., .., ..]| (B, 2)| +|state |input|output |next state| +|(A, 1)| [(A, 1), .., .., ..]|[.., .., .., ..]| (A, 2)| + +4. Adjust Width step - this step takes output from the core step. +If output can handle more or equal number of pairs as +input number of symbols. This step does nothing. +If the output is narrower than the input, +this step will serialize symbol counter pairs. + +Example: + +||||| +|-----|-----|-------|-----------| +|state|input|output | next state| +|[]|[(A, 3), (A, 2), .., ..]|[(A, 3), (A, 2)]|[]| +|state|input|output | next state| +|[]|[(A, 1), (B, 1), (C, 1), (D, 1)]|[(A, 1), (B, 1)]|[(C, 1), (D, 1)]| +|state|input|output | next state| +|[(C, 1), (D, 1)]|ignored|[(C, 1), (D, 1)]|[]| \ No newline at end of file From 66ff96294da229148a4d9a3cd174cd08a3aea3dd Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Thu, 31 Aug 2023 16:42:54 +0200 Subject: [PATCH 6/7] xls:modules:rle: Review: Change step to proc Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_enc_adv.x | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xls/modules/rle/rle_enc_adv.x b/xls/modules/rle/rle_enc_adv.x index 78f8ef1e68..ec8d48c001 100644 --- a/xls/modules/rle/rle_enc_adv.x +++ b/xls/modules/rle/rle_enc_adv.x @@ -23,9 +23,9 @@ // The behavior of the encoder is presented on the waveform below: // This encoder is implemented as a net of 4 proc. -// 1. Reduce step - this process takes incoming symbols and symbol_valid +// 1. Reduce proc - this process takes incoming symbols and symbol_valid // and reduces them into symbol count pairs. This step is stateless. -// 2. Realign step - this process moves pairs emitted from the reduce step +// 2. Realign proc - this process moves pairs emitted from the reduce step // so that they are aligned to the left, it also calculates propagation // distance for the first pair. // Example behaviours: @@ -37,13 +37,13 @@ // input: [.., .., (A, 3), (A, 1)] // output: [(A, 3), (A, 1), .., ..] // propagation distance: 1 -// 3. Core step - this step is stateful. It takes align pairs from +// 3. Core proc - this step is stateful. It takes align pairs from // the realign step, and combines them with its state to create multiple // symbol/count pairs output. State is represented by following tuple // ``. It contains symbol and count from last pair // received from realign step, or current sum of repeating symbol spanning // multiple input widths. -// 4. - Adjust Width step - this step takes output from the core step. +// 4. Adjust Width proc - this step takes output from the core step. // If output can handle more or equal number of pairs as // input number of symbols. This step does nothing. // If the output is narrower than the input, From d28d81bb028765f2c1a9f28fd8d13e5fae294bfa Mon Sep 17 00:00:00 2001 From: Maciej Dudek Date: Fri, 6 Oct 2023 11:58:05 +0200 Subject: [PATCH 7/7] review: Update adv rle enc documentation Signed-off-by: Maciej Dudek --- xls/modules/rle/rle_dec.x | 1 - xls/modules/rle/rle_enc_adv.md | 29 +++++++++++++++---- xls/modules/rle/rle_enc_adv.x | 5 ---- .../rle/rle_enc_adv_adjust_width_stage.x | 6 ---- xls/modules/rle/rle_enc_adv_core.x | 6 ---- xls/modules/rle/rle_enc_adv_realign_stage.x | 5 ---- xls/modules/rle/rle_enc_adv_reduce_stage.x | 5 ---- 7 files changed, 23 insertions(+), 34 deletions(-) diff --git a/xls/modules/rle/rle_dec.x b/xls/modules/rle/rle_dec.x index 65d4303b3e..28e820ac51 100644 --- a/xls/modules/rle/rle_dec.x +++ b/xls/modules/rle/rle_dec.x @@ -285,7 +285,6 @@ proc RunLengthDecoderZeroCountTest { (tok) }(tok); send(tok, terminator, true); - () } } diff --git a/xls/modules/rle/rle_enc_adv.md b/xls/modules/rle/rle_enc_adv.md index 0f4358af78..9dcf4bae76 100644 --- a/xls/modules/rle/rle_enc_adv.md +++ b/xls/modules/rle/rle_enc_adv.md @@ -22,8 +22,9 @@ the last packet the encoder dumps all the data to the output stream. - symbol counter is 2 bits wide. ### Process -1. Reduce step - this process takes incoming symbols and symbol_valid -and reduces them into symbol count pairs. This step is stateless. +1. Reduce step - this process takes incoming symbols, symbol_valid, +last signal and reduces them into symbol count pairs. Last value is +passed through, so it's omitted from the example IO. This step is stateless. Example: @@ -38,7 +39,8 @@ Example: 2. Realign step - this process moves pairs emitted from the reduce step so that they are aligned to the left, it also calculates propagation -distance for the first pair. +distance for the first pair. This stage doesn't modify last signal value, +so it's omitted in the example. Example: @@ -54,9 +56,13 @@ the realign step, and combines them with its state to create multiple symbol/count pairs output. State is represented by following tuple ``. It contains symbol and count from last pair received from the realign step, or current sum of repeating symbol spanning -multiple input widths. +multiple input widths. -Example: +First set of examples assumes that state doesn't have last set nor +was last received. Second set of examples will indicate value of last +signal in the proc state or input data and how it's emitted to output. + +Example set 1: ||||| |------|-----|-------|----------| @@ -67,6 +73,17 @@ Example: |state |input|output |next state| |(A, 1)| [(A, 1), .., .., ..]|[.., .., .., ..]| (A, 2)| +Example set 2: + +||||| +|------|-----|-------|----------| +|state: pair, last |input|output |next state| +|(A, 2), false| [(A, 2), (B, 2), .., ..], true |[(A, 3), (A, 1), (B, 2), ..], true| (), false| +|state: pair, last |input|output |next state| +|(A, 1), false| [(B, 1), (C, 1), (D, 1), (A, 1)], true|[(A, 1), (B, 1), (C, 1), (D, 1)]| (A, 1), true| +|state |input|output |next state| +|(A, 1), true| no data taken from input |[(A, 1), .., .. , ..], true| (), false| + 4. Adjust Width step - this step takes output from the core step. If output can handle more or equal number of pairs as input number of symbols. This step does nothing. @@ -82,4 +99,4 @@ Example: |state|input|output | next state| |[]|[(A, 1), (B, 1), (C, 1), (D, 1)]|[(A, 1), (B, 1)]|[(C, 1), (D, 1)]| |state|input|output | next state| -|[(C, 1), (D, 1)]|ignored|[(C, 1), (D, 1)]|[]| \ No newline at end of file +|[(C, 1), (D, 1)]|ignored|[(C, 1), (D, 1)]|[]| diff --git a/xls/modules/rle/rle_enc_adv.x b/xls/modules/rle/rle_enc_adv.x index ec8d48c001..501c68e444 100644 --- a/xls/modules/rle/rle_enc_adv.x +++ b/xls/modules/rle/rle_enc_adv.x @@ -208,7 +208,6 @@ proc ConsumeMultipleSymbolRepetitionsAtOnce { }(tok); send(tok, terminator, true); - () } } @@ -273,7 +272,6 @@ proc ConsumeMultipleSymbolsAtOnce { }(tok); send(tok, terminator, true); - () } } @@ -344,7 +342,6 @@ proc ConsumePacketWithInvalidSymbols { }(tok); send(tok, terminator, true); - () } } @@ -411,7 +408,6 @@ proc ConsumePacketWithAllDiffSymbols { }(tok); send(tok, terminator, true); - () } } @@ -480,6 +476,5 @@ proc ConsumePacketsWhereLastSymbolRepeats { }(tok); send(tok, terminator, true); - () } } diff --git a/xls/modules/rle/rle_enc_adv_adjust_width_stage.x b/xls/modules/rle/rle_enc_adv_adjust_width_stage.x index 9ede70289b..4170ebac69 100644 --- a/xls/modules/rle/rle_enc_adv_adjust_width_stage.x +++ b/xls/modules/rle/rle_enc_adv_adjust_width_stage.x @@ -210,7 +210,6 @@ proc PacketContainsOnlyLast { }(tok); send(tok, terminator, true); - () } } @@ -275,7 +274,6 @@ proc InputPairCountLessOrEqualOutputWidth { }(tok); send(tok, terminator, true); - () } } @@ -342,7 +340,6 @@ proc InputFullyFilled { }(tok); send(tok, terminator, true); - () } } @@ -412,7 +409,6 @@ proc CombineStateWithNextInputPairs { }(tok); send(tok, terminator, true); - () } } @@ -486,7 +482,6 @@ proc PairStateCombineWithStateUpdate { }(tok); send(tok, terminator, true); - () } } @@ -558,6 +553,5 @@ proc NoStateSipllAfterLast { }(tok); send(tok, terminator, true); - () } } diff --git a/xls/modules/rle/rle_enc_adv_core.x b/xls/modules/rle/rle_enc_adv_core.x index 1a0d559f62..7d976e20e0 100644 --- a/xls/modules/rle/rle_enc_adv_core.x +++ b/xls/modules/rle/rle_enc_adv_core.x @@ -281,7 +281,6 @@ proc PacketOnlyWithLastSet { }(tok); send(tok, terminator, true); - () } } @@ -358,7 +357,6 @@ proc CombineWithoutOverflow { }(tok); send(tok, terminator, true); - () } } @@ -437,7 +435,6 @@ proc CombineWithOverflow { }(tok); send(tok, terminator, true); - () } } @@ -518,7 +515,6 @@ proc CombineAfterStateChange { }(tok); send(tok, terminator, true); - () } } @@ -593,7 +589,6 @@ proc CombineStateWithLastPacket { }(tok); send(tok, terminator, true); - () } } @@ -664,6 +659,5 @@ proc NoStateSipllAfterLast { }(tok); send(tok, terminator, true); - () } } diff --git a/xls/modules/rle/rle_enc_adv_realign_stage.x b/xls/modules/rle/rle_enc_adv_realign_stage.x index 30f3fe4cb7..6f74981ab3 100644 --- a/xls/modules/rle/rle_enc_adv_realign_stage.x +++ b/xls/modules/rle/rle_enc_adv_realign_stage.x @@ -62,7 +62,6 @@ pub proc RunLengthEncoderAdvancedRealignStage< } } ((u32:0, symbols[u32:0], counts[u32:0] != bits[COUNT_WIDTH]:0)); send(tok, output_s, (output, prop_count, end)); - () } } @@ -175,7 +174,6 @@ proc RunLengthEncoderAdvancedRealignStageNoPairs { (tok) }(tok); send(tok, terminator, true); - () } } @@ -250,7 +248,6 @@ proc RunLengthEncoderAdvancedRealignStageAllPairsFilled { (tok) }(tok); send(tok, terminator, true); - () } } @@ -325,7 +322,6 @@ proc RunLengthEncoderAdvancedRealignStageFarAwayPair { (tok) }(tok); send(tok, terminator, true); - () } } @@ -400,6 +396,5 @@ proc RunLengthEncoderAdvancedRealignStagePropagataion { (tok) }(tok); send(tok, terminator, true); - () } } diff --git a/xls/modules/rle/rle_enc_adv_reduce_stage.x b/xls/modules/rle/rle_enc_adv_reduce_stage.x index 6db583bfbb..a0f06dc70b 100644 --- a/xls/modules/rle/rle_enc_adv_reduce_stage.x +++ b/xls/modules/rle/rle_enc_adv_reduce_stage.x @@ -63,7 +63,6 @@ pub proc RunLengthEncoderAdvancedReduceStage< let not_empty = input.last || or_reduce(std::convert_to_bits_msb0(input.symbol_valids)); send_if(tok, output_s, not_empty, output); - () } } @@ -172,7 +171,6 @@ proc RunLengthEncoderAdvancedReduceStageNoSymbols { (tok) }(tok); send(tok, terminator, true); - () } } @@ -239,7 +237,6 @@ proc RunLengthEncoderAdvancedReduceStageNonRepeatingSymbols { (tok) }(tok); send(tok, terminator, true); - () } } @@ -306,7 +303,6 @@ proc RunLengthEncoderAdvancedReduceStageRepeatingSymbolsNoOverflow { (tok) }(tok); send(tok, terminator, true); - () } } @@ -373,6 +369,5 @@ proc RunLengthEncoderAdvancedReduceStageRepeatingSymbolsOverflow { (tok) }(tok); send(tok, terminator, true); - () } }