-
Notifications
You must be signed in to change notification settings - Fork 184
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
modules/dbe: add lz4 encoder and decoder
Example implementation of Lz4 - a dictionary-based data compression algorithm. Signed-off-by: Roman Dobrodii <[email protected]>
- Loading branch information
Showing
6 changed files
with
1,823 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# 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. | ||
|
||
# Build rules for XLS DBE/LZ4 algorithm implementation. | ||
|
||
load( | ||
"//xls/build_rules:xls_build_defs.bzl", | ||
"xls_dslx_library", | ||
"xls_dslx_ir", | ||
"xls_ir_opt_ir", | ||
"xls_ir_verilog", | ||
"xls_dslx_test", | ||
) | ||
|
||
package( | ||
default_applicable_licenses = ["//:license"], | ||
default_visibility = ["//xls:xls_users"], | ||
licenses = ["notice"], | ||
) | ||
|
||
# --------------------------------------------------------------------------- | ||
# Common | ||
# --------------------------------------------------------------------------- | ||
|
||
xls_dslx_library( | ||
name = "dbe_common_dslx", | ||
srcs = [ | ||
"common.x", | ||
"common_test.x" | ||
], | ||
) | ||
|
||
# --------------------------------------------------------------------------- | ||
# LZ4 decoder | ||
# --------------------------------------------------------------------------- | ||
|
||
xls_dslx_library( | ||
name = "dbe_lz4_decoder_dslx", | ||
srcs = [ | ||
"lz4_decoder.x" | ||
], | ||
deps = [ | ||
":dbe_common_dslx", | ||
"//xls/examples:ram_dslx", | ||
], | ||
) | ||
|
||
xls_dslx_test( | ||
name = "dbe_lz4_decoder_dslx_test", | ||
dslx_test_args = { | ||
"compare": "none", | ||
}, | ||
library = "dbe_lz4_decoder_dslx", | ||
) | ||
|
||
xls_dslx_ir( | ||
name = "dbe_lz4_decoder_ir", | ||
dslx_top = "decoder", | ||
library = "dbe_lz4_decoder_dslx", | ||
ir_file = "dbe_lz4_decoder_ir.ir", | ||
) | ||
|
||
xls_ir_opt_ir( | ||
name = "dbe_lz4_decoder_opt_ir", | ||
src = "dbe_lz4_decoder_ir.ir", | ||
top = "__lz4_decoder__decoder__decoder_base_0__16_16_8_next", | ||
ram_rewrites = [ | ||
":lz4_decoder_ram1r1w_rewrites.textproto", | ||
], | ||
) | ||
|
||
xls_ir_verilog( | ||
name = "dbe_lz4_decoder_verilog", | ||
src = "dbe_lz4_decoder_opt_ir.opt.ir", | ||
verilog_file = "dbe_lz4_decoder.v", | ||
codegen_args = { | ||
"module_name": "dbe_lz4_decoder", | ||
"delay_model": "unit", | ||
"pipeline_stages": "3", | ||
"reset": "rst", | ||
"use_system_verilog": "false", | ||
"streaming_channel_data_suffix": "_data", | ||
"ram_configurations": "ram_hb:1R1W:{rd_req}:{rd_resp}:{wr_req}:{wr_comp}".format( | ||
rd_req = "ram_hb_read_req", | ||
rd_resp = "ram_hb_read_resp", | ||
wr_req = "ram_hb_write_req", | ||
wr_comp = "ram_hb_write_completion", | ||
), | ||
}, | ||
) | ||
|
||
# --------------------------------------------------------------------------- | ||
# LZ4 encoder | ||
# --------------------------------------------------------------------------- | ||
|
||
xls_dslx_library( | ||
name = "dbe_lz4_encoder_dslx", | ||
srcs = [ | ||
"lz4_encoder.x" | ||
], | ||
deps = [ | ||
":dbe_common_dslx", | ||
"//xls/examples:ram_dslx", | ||
# decoder is referenced by test code | ||
":dbe_lz4_decoder_dslx", | ||
], | ||
) | ||
|
||
xls_dslx_test( | ||
name = "dbe_lz4_encoder_dslx_test", | ||
dslx_test_args = { | ||
"compare": "none", | ||
}, | ||
library = "dbe_lz4_encoder_dslx", | ||
) | ||
|
||
#8K hash specialization | ||
xls_dslx_ir( | ||
name = "dbe_lz4_encoder_8k_ir", | ||
dslx_top = "encoder_8k", | ||
library = "dbe_lz4_encoder_dslx", | ||
ir_file = "dbe_lz4_encoder_8k_ir.ir", | ||
) | ||
|
||
xls_ir_opt_ir( | ||
name = "dbe_lz4_encoder_8k_opt_ir", | ||
src = "dbe_lz4_encoder_8k_ir.ir", | ||
top = "__lz4_encoder__encoder_8k__encoder_base_0__16_3_13_12_13_65536_8192_4_16_8_next", | ||
) | ||
|
||
xls_ir_verilog( | ||
name = "dbe_lz4_encoder_8k_verilog", | ||
src = "dbe_lz4_encoder_8k_opt_ir.opt.ir", | ||
verilog_file = "dbe_lz4_encoder_8k.v", | ||
codegen_args = { | ||
"module_name": "dbe_lz4_encoder", | ||
"delay_model": "unit", | ||
"pipeline_stages": "3", | ||
"worst_case_throughput": "3", | ||
"reset": "rst", | ||
"use_system_verilog": "false", | ||
"streaming_channel_data_suffix": "_data", | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// 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 | ||
|
||
pub enum Mark : u4 { | ||
// Default initialization value used when marker field is not needed | ||
NONE = 0, | ||
// Signals end of sequence/block | ||
END = 1, | ||
// Requests reset of the processing chain | ||
RESET = 2, | ||
|
||
_ERROR_FIRST = 8, | ||
// Only error marks have values >= __ERROR_FIRST | ||
ERROR_BAD_MARK = 8, | ||
ERROR_INVAL_CP = 9, | ||
} | ||
|
||
pub fn is_error(mark: Mark) -> bool { | ||
(mark as u32) >= (Mark::_ERROR_FIRST as u32) | ||
} | ||
|
||
pub enum TokenKind : u2 { | ||
LITERAL = 0, | ||
COPY_POINTER = 1, | ||
MARK = 2, | ||
} | ||
|
||
pub struct Token<SYM_WIDTH: u32, PTR_WIDTH: u32, CNT_WIDTH: u32> { | ||
kind: TokenKind, | ||
literal: uN[SYM_WIDTH], | ||
copy_pointer_offset: uN[PTR_WIDTH], | ||
copy_pointer_count: uN[CNT_WIDTH], | ||
mark: Mark | ||
} | ||
|
||
pub struct PlainData<DATA_WIDTH: u32> { | ||
is_mark: bool, | ||
data: uN[DATA_WIDTH], // symbol | ||
mark: Mark, // marker code | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
// 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 xls.modules.dbe.common as dbe | ||
|
||
type TokenKind = dbe::TokenKind; | ||
type Token = dbe::Token; | ||
type PlainData = dbe::PlainData; | ||
|
||
/// | ||
/// This library contains helper processes and functions used by DBE tests | ||
/// | ||
pub proc data_sender<NUM_SYMS: u32, SYM_WIDTH:u32> { | ||
data: PlainData<SYM_WIDTH>[NUM_SYMS]; | ||
o_data: chan<PlainData<SYM_WIDTH>> out; | ||
|
||
init { u32:0 } | ||
|
||
config ( | ||
data: PlainData<SYM_WIDTH>[NUM_SYMS], | ||
o_data: chan<PlainData<SYM_WIDTH>> out, | ||
) { | ||
(data, o_data) | ||
} | ||
|
||
next (tok: token, state: u32) { | ||
let next_idx = state + u32:1; | ||
let is_done = (state >= NUM_SYMS); | ||
|
||
if (!is_done) { | ||
let tosend = data[state]; | ||
trace_fmt!("Sending {}", tosend); | ||
send(tok, o_data, tosend); | ||
next_idx | ||
} else { | ||
state | ||
} | ||
} | ||
} | ||
|
||
pub proc data_validator<NUM_SYMS: u32, SYM_WIDTH:u32> { | ||
ref_data: PlainData<SYM_WIDTH>[NUM_SYMS]; | ||
i_data: chan<PlainData<SYM_WIDTH>> in; | ||
o_term: chan<bool> out; | ||
|
||
init { u32:0 } | ||
|
||
config( | ||
ref_data: PlainData<SYM_WIDTH>[NUM_SYMS], | ||
i_data: chan<PlainData<SYM_WIDTH>> in, | ||
o_term: chan<bool> out | ||
) { | ||
(ref_data, i_data, o_term) | ||
} | ||
|
||
next (tok: token, state: u32) { | ||
// state = [0, NUM_SYMS-1] - expect data | ||
// state >= NUM_SYMS - expect nothing | ||
let next_idx = state + u32:1; | ||
let is_end = (state == NUM_SYMS - u32:1); | ||
let is_done = (state >= NUM_SYMS); | ||
|
||
let (tok, rx) = recv(tok, i_data); | ||
trace_fmt!("Received {}", rx); | ||
|
||
let (fail, next_state) = if is_done { | ||
// Shouldn't get here | ||
(true, state) | ||
} else { | ||
let expect = ref_data[state]; | ||
let fail = if (rx != expect) { | ||
trace_fmt!("MISMATCH! Expected {}, got {}", expect, rx); | ||
true | ||
} else { | ||
false | ||
}; | ||
(fail, next_idx) | ||
}; | ||
|
||
send_if(tok, o_term, fail || is_end, !fail); | ||
|
||
next_state | ||
} | ||
} | ||
|
||
pub proc token_sender< | ||
NUM_TOKS: u32, SYM_WIDTH: u32, PTR_WIDTH: u32, CNT_WIDTH: u32> { | ||
toks: Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>[NUM_TOKS]; | ||
o_toks: chan<Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>> out; | ||
|
||
init { u32:0 } | ||
|
||
config ( | ||
toks: Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>[NUM_TOKS], | ||
o_toks: chan<Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>> out, | ||
) { | ||
(toks, o_toks) | ||
} | ||
|
||
next (tok: token, state: u32) { | ||
let next_idx = state + u32:1; | ||
let is_done = (state >= NUM_TOKS); | ||
|
||
if (!is_done) { | ||
let tosend = toks[state]; | ||
trace_fmt!("Sending {}", tosend); | ||
send(tok, o_toks, tosend); | ||
next_idx | ||
} else { | ||
state | ||
} | ||
} | ||
} | ||
|
||
pub proc token_validator< | ||
NUM_TOKS: u32, SYM_WIDTH: u32, PTR_WIDTH: u32, CNT_WIDTH: u32> { | ||
ref_toks: Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>[NUM_TOKS]; | ||
i_token: chan<Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>> in; | ||
o_term: chan<bool> out; | ||
|
||
init { u32:0 } | ||
|
||
config( | ||
ref_toks: Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>[NUM_TOKS], | ||
i_token: chan<Token<SYM_WIDTH, PTR_WIDTH, CNT_WIDTH>> in, | ||
o_term: chan<bool> out | ||
) { | ||
(ref_toks, i_token, o_term) | ||
} | ||
|
||
next (tok: token, state: u32) { | ||
// state = [0, NUM_TOKS-1] - expect token | ||
// state >= NUM_TOKS - expect nothing | ||
let next_idx = state + u32:1; | ||
let is_end = (state == NUM_TOKS - u32:1); | ||
let is_done = (state >= NUM_TOKS); | ||
|
||
let (tok, rx) = recv(tok, i_token); | ||
trace_fmt!("Received {}", rx); | ||
|
||
let (fail, next_state) = if is_done { | ||
// Shouldn't get here | ||
(true, state) | ||
} else { | ||
let expect = ref_toks[state]; | ||
let fail = if (rx != expect) { | ||
trace_fmt!("MISMATCH! Expected {}, got {}", expect, rx); | ||
true | ||
} else { | ||
false | ||
}; | ||
(fail, next_idx) | ||
}; | ||
|
||
send_if(tok, o_term, fail || is_end, !fail); | ||
|
||
next_state | ||
} | ||
} |
Oops, something went wrong.