diff --git a/.github/workflows/modules-zstd.yml b/.github/workflows/modules-zstd.yml index 4272e4b91b..8265654a2c 100644 --- a/.github/workflows/modules-zstd.yml +++ b/.github/workflows/modules-zstd.yml @@ -45,7 +45,9 @@ jobs: - name: Test ZSTD Module - DSLX Tests (opt) if: ${{ !cancelled() }} run: | - bazel test -c opt --test_output=errors -- $(bazel query 'filter("_dslx_test$", kind(rule, //xls/modules/zstd/...))') + bazel test -c opt --test_output=errors -- $(bazel query 'filter("_dslx_test$", kind(rule, //xls/modules/zstd/...)) except filter("zstd_dec_dslx_test$", kind(rule, //xls/modules/zstd/...))'); + # Run all tests except those ending with `_skip` + bazel test -c opt --test_strategy=exclusive --test_output=errors --test_filter='^([^_]|_([^s]|$)|_s([^k]|$)|_sk([^i]|$)|_ski([^p]|$))*$' //xls/modules/zstd:zstd_dec_dslx_test; - name: Build ZSTD verilog targets (opt) if: ${{ !cancelled() }} diff --git a/MODULE.bazel b/MODULE.bazel index 388a8efd26..5f076198d4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -152,3 +152,7 @@ git_override( ) register_toolchains("//xls/common/toolchains:all") + +# Verilator support +bazel_dep(name = "aspect_bazel_lib", version = "2.19.4") +bazel_dep(name = "rules_perl", version = "0.4.2") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index c9d27b0531..d0326b6273 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -35,7 +35,9 @@ "https://bcr.bazel.build/modules/aspect_bazel_lib/1.38.0/MODULE.bazel": "6307fec451ba9962c1c969eb516ebfe1e46528f7fa92e1c9ac8646bef4cdaa3f", "https://bcr.bazel.build/modules/aspect_bazel_lib/1.40.3/MODULE.bazel": "668e6bcb4d957fc0e284316dba546b705c8d43c857f87119619ee83c4555b859", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/MODULE.bazel": "cb1ba9f9999ed0bc08600c221f532c1ddd8d217686b32ba7d45b0713b5131452", - "https://bcr.bazel.build/modules/aspect_bazel_lib/2.11.0/source.json": "92494d5aa43b96665397dd13ee16023097470fa85e276b93674d62a244de47ee", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.4/MODULE.bazel": "d39e4b18e594d81c526d7cfc513e7ecfa8ca9eb5b61488d1d790faa94b34f2d9", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.4/source.json": "506fa924e19fd8a33d617e33a17e4fce845f9ff9acb3a2aa7cf7300650698705", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.9.3/MODULE.bazel": "66baf724dbae7aff4787bf2245cc188d50cb08e07789769730151c0943587c14", @@ -305,6 +307,8 @@ "https://bcr.bazel.build/modules/highs/1.9.0/source.json": "40f023f93f0bdcaeb14cfd3975c9b6f2f9a0315201791611ca203450f2b4c028", "https://bcr.bazel.build/modules/highwayhash/0.0.0-20240305-5ad3bf8/MODULE.bazel": "5c7f29d5bd70feff14b0f65b39584957e18e4a8d555e5a29a4c36019afbb44b9", "https://bcr.bazel.build/modules/highwayhash/0.0.0-20240305-5ad3bf8/source.json": "211c0937ef5f537da6c3c135d12e60927c71b380642e207e4a02b86d29c55e85", + "https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f", + "https://bcr.bazel.build/modules/jq.bzl/0.1.0/source.json": "746bf13cac0860f091df5e4911d0c593971cd8796b5ad4e809b2f8e133eee3d5", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", @@ -340,6 +344,8 @@ "https://bcr.bazel.build/modules/opentracing-cpp/1.6.0/source.json": "da1cb1add160f5e5074b7272e9db6fd8f1b3336c15032cd0a653af9d2f484aed", "https://bcr.bazel.build/modules/or-tools/9.12/MODULE.bazel": "9b3c0a7f08772f51b4083ccca0e69abf49b1488e2fd9078e535d8855cdda0cf2", "https://bcr.bazel.build/modules/or-tools/9.12/source.json": "98c1da7031be89e3f58e95a16784c1f5524c0ff6d8ea436ac6df4e9efe03458b", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/MODULE.bazel": "fb8d25550742674d63d7b250063d4580ca530499f045d70748b1b142081ebb92", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/source.json": "e53a759a72488d2c0576f57491ef2da0cf4aab05ac0997314012495935531b73", "https://bcr.bazel.build/modules/pcre2/10.43/MODULE.bazel": "08eaa025111bd0fedc14a8187c2905fa6ee4501fbe558193e9bf6cc3e2cdf23c", "https://bcr.bazel.build/modules/pcre2/10.43/source.json": "8b4149e707094f1d5b57df7216539c3415226e814085c4d960bd9f3d49581b88", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", @@ -506,7 +512,8 @@ "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/MODULE.bazel": "b66eadebd10f1f1b25f52f95ab5213a57e82c37c3f656fcd9a57ad04d2264ce7", "https://bcr.bazel.build/modules/rules_nodejs/6.3.3/source.json": "45bd343155bdfed2543f0e39b80ff3f6840efc31975da4b5795797f4c94147ad", "https://bcr.bazel.build/modules/rules_perl/0.2.4/MODULE.bazel": "5f5af7be4bf5fb88d91af7469518f0fd2161718aefc606188f7cd51f436ca938", - "https://bcr.bazel.build/modules/rules_perl/0.2.4/source.json": "574317d6b3c7e4843fe611b76f15e62a1889949f5570702e1ee4ad335ea3c339", + "https://bcr.bazel.build/modules/rules_perl/0.4.2/MODULE.bazel": "ade797b135be13d4715f7bb045bb06593ea3b8604f71330981cda6e5f95e42d1", + "https://bcr.bazel.build/modules/rules_perl/0.4.2/source.json": "feb6b8996edcc944b5b82e6440c8104e5907f7eca7e0bf553c7c097d5181ac25", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", @@ -527,7 +534,8 @@ "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", "https://bcr.bazel.build/modules/rules_shell/0.4.0/MODULE.bazel": "0f8f11bb3cd11755f0b48c1de0bbcf62b4b34421023aa41a2fc74ef68d9584f0", - "https://bcr.bazel.build/modules/rules_shell/0.4.0/source.json": "1d7fa7f941cd41dc2704ba5b4edc2e2230eea1cc600d80bd2b65838204c50b95", + "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", + "https://bcr.bazel.build/modules/rules_shell/0.4.1/source.json": "4757bd277fe1567763991c4425b483477bb82e35e777a56fd846eb5cceda324a", "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", "https://bcr.bazel.build/modules/rules_swift/1.18.0/MODULE.bazel": "a6aba73625d0dc64c7b4a1e831549b6e375fbddb9d2dde9d80c9de6ec45b24c9", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", @@ -555,6 +563,8 @@ "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb", "https://bcr.bazel.build/modules/swig/4.3.0/MODULE.bazel": "51619e147172c5380869cc90460b1c7fecfe21d6f566e97bc7ecf61244bdc7b8", "https://bcr.bazel.build/modules/swig/4.3.0/source.json": "ea8dac67896e3a623cd92c48573a351c4bab1537f5aeb210c1c1e049994dd599", + "https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468", + "https://bcr.bazel.build/modules/tar.bzl/0.2.1/source.json": "600ac6ff61744667a439e7b814ae59c1f29632c3984fccf8000c64c9db8d7bb6", "https://bcr.bazel.build/modules/toolchains_llvm/1.4.0/MODULE.bazel": "05239402b7374293359c2f22806f420b75aa5d6f4b15a2eaa809a2c214d58b31", "https://bcr.bazel.build/modules/toolchains_llvm/1.4.0/source.json": "229a516d282b17a82be54c6e3ae220a1b750fb55a8495567e5c7a9d09423f3e2", "https://bcr.bazel.build/modules/upb/0.0.0-20211020-160625a/MODULE.bazel": "6cced416be2dc5b9c05efd5b997049ba795e5e4e6fafbe1624f4587767638928", @@ -567,6 +577,8 @@ "https://bcr.bazel.build/modules/xds/0.0.0-20240423-555b57e/source.json": "7227e1fcad55f3f3cab1a08691ecd753cb29cc6380a47bc650851be9f9ad6d20", "https://bcr.bazel.build/modules/xz/5.4.5.bcr.1/MODULE.bazel": "c037f75fa1b7e1ff15fbd15d807a8ce545e9b02f02df0a9777aa9aa7d8b268bb", "https://bcr.bazel.build/modules/xz/5.4.5.bcr.1/source.json": "766f28499a16fa9ed8dc94382d50e80ceda0d0ab80b79b7b104a67074ab10e1f", + "https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072", + "https://bcr.bazel.build/modules/yq.bzl/0.1.1/source.json": "2d2bad780a9f2b9195a4a370314d2c17ae95eaa745cefc2e12fbc49759b15aa3", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", "https://bcr.bazel.build/modules/zlib/1.2.13/MODULE.bazel": "aa6deb1b83c18ffecd940c4119aff9567cd0a671d7bba756741cb2ef043a29d5", @@ -670,7 +682,7 @@ }, "@@aspect_rules_esbuild~//esbuild:extensions.bzl%esbuild": { "general": { - "bzlTransitiveDigest": "8iOqbPY5ve3DvjzaI1mJZ8XTiJypN2PeWvcKOvmZLy8=", + "bzlTransitiveDigest": "8jv3p0xDR/oitFeH8y0+Y5xlyrUbfsTRlc9TSwYkwl8=", "usagesDigest": "iDVoyPxUeADmfK8ssoyG3Ehq1bj6p7A43LpEiE266os=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -2023,85 +2035,6 @@ "recordedRepoMappingEntries": [] } }, - "@@rules_perl~//perl:extensions.bzl%perl_repositories": { - "general": { - "bzlTransitiveDigest": "zKzjvlkMYt5ciDqNdVyTtZfAAPO39SuFy2B+xMqgTss=", - "usagesDigest": "tuJgAyNZD8Ewzr/MlAnnittbPMDC60XQF8aGrsjU+nY=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "perl_darwin_arm64": { - "bzlFile": "@@rules_perl~//perl:repo.bzl", - "ruleClassName": "perl_download", - "attributes": { - "strip_prefix": "perl-darwin-arm64", - "sha256": "285769f3c50c339fb59a3987b216ae3c5c573b95babe6875a1ef56fb178433da", - "urls": [ - "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-darwin-arm64.tar.xz" - ] - } - }, - "perl_darwin_amd64": { - "bzlFile": "@@rules_perl~//perl:repo.bzl", - "ruleClassName": "perl_download", - "attributes": { - "strip_prefix": "perl-darwin-amd64", - "sha256": "63bc5ee36f5394d71c50cca6cafdd333ee58f9eaa40bca63c85f9bd06f2c1fd6", - "urls": [ - "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-darwin-amd64.tar.xz" - ] - } - }, - "perl_linux_amd64": { - "bzlFile": "@@rules_perl~//perl:repo.bzl", - "ruleClassName": "perl_download", - "attributes": { - "strip_prefix": "perl-linux-amd64", - "sha256": "3bdffa9d7a3f97c0207314637b260ba5115b1d0829f97e3e2e301191a4d4d076", - "urls": [ - "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-linux-amd64.tar.xz" - ] - } - }, - "perl_linux_arm64": { - "bzlFile": "@@rules_perl~//perl:repo.bzl", - "ruleClassName": "perl_download", - "attributes": { - "strip_prefix": "perl-linux-arm64", - "sha256": "6fa4ece99e790ecbc2861f6ecb7b52694c01c2eeb215b4370f16a3b12d952117", - "urls": [ - "https://github.com/skaji/relocatable-perl/releases/download/5.36.0.1/perl-linux-arm64.tar.xz" - ] - } - }, - "perl_windows_x86_64": { - "bzlFile": "@@rules_perl~//perl:repo.bzl", - "ruleClassName": "perl_download", - "attributes": { - "strip_prefix": "", - "sha256": "aeb973da474f14210d3e1a1f942dcf779e2ae7e71e4c535e6c53ebabe632cc98", - "urls": [ - "https://mirror.bazel.build/strawberryperl.com/download/5.32.1.1/strawberry-perl-5.32.1.1-64bit.zip", - "https://strawberryperl.com/download/5.32.1.1/strawberry-perl-5.32.1.1-64bit.zip" - ] - } - } - }, - "recordedRepoMappingEntries": [ - [ - "rules_perl~", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_perl~", - "rules_perl", - "rules_perl~" - ] - ] - } - }, "@@rules_python~//python/extensions:pip.bzl%pip": { "general": { "bzlTransitiveDigest": "IydMzRepgVhGbwD4WBQd4WuJDipgbSZjrF0OvB+JldA=", @@ -2110,7 +2043,7 @@ "@@or-tools~//bazel/ortools_requirements.txt": "37e22395e78ef3572ab57b7717fd8f54851919bb73ca404f367536dc15a8e3eb", "@@pybind11_abseil~//pybind11_abseil/requirements/requirements_lock_3_11.txt": "7d1074311e9f32f25ca112fc86fbec98bc024d820a8dc00f94e8679a7e6b480c", "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d", - "@@//dependency_support/pip_requirements_lock.txt": "e813fef63629aaca3c070b25f1265afb21da8400c4dc846646f3056965670718", + "@@//dependency_support/pip_requirements_lock.txt": "9301da6c6a7b310ba10266bc5e9cc83aa0b693bf8471fba119f34133e0126d46", "@@or-tools~//bazel/notebook_requirements.txt": "ca78fad693f1b35eed8bb7c54e5ddf7ad255c4b9d94ce18efa55859759a8fb70", "@@protoc-gen-validate~//python/requirements.txt": "6a540bc029bbf3a5f78f9f9282bd30e2965c98eeb150f2cfc5facccbd8a98297", "@@pybind11_protobuf~//pybind11_protobuf/requirements/requirements_lock_3_10.txt": "afd6f9406f4e80a504f1575121a937f4c15388aec4a17393f0cb1ac9f09d18dd", @@ -14405,6 +14338,39 @@ "timeout": 600000 } }, + "xls_pip_deps_312_cocotb": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "cocotb==1.9.0 --hash=sha256:02a58ef6c941114964096e7c039bdd4e67e63816cfd2f6a9af6a34cd92b00e8e --hash=sha256:0819794ef5e8fd14fee0b265933226cf600e85edc2f1a749b4d5f8fa2d31ce4e --hash=sha256:0ba35617a677ff65a1273411a3dfdfc5f587128ad8cb9e941ab0eb17ec8fb3e2 --hash=sha256:17556e3a23562f64d577d0eb117fe02e384aedee997b29497b5c395f5010ff82 --hash=sha256:19b4e27b53a16e0b9c4cc5227c7f9d4dccac06e431a4f937e9f5513350196333 --hash=sha256:1a0381ced5590a726032ba2265c6b70ac12cfb49edb152be86a081bb7d104751 --hash=sha256:1aff68cf77059448a9a3278079037e34b50c8c2aee466d984295fa7fe699d390 --hash=sha256:277281420fd6fc3002bb85d6bec497bd20ff3a3905d4b5f1301faf975f750ede --hash=sha256:2daf743320331615f4e8ffb877ab0b04e6f913b911bb11bf9dbc1d876d9c4220 --hash=sha256:2e9bcdbfba3e99c9297bd0d74ba781772d89d2c86e893980784ada252bd1a0f8 --hash=sha256:3058c977f9d4e1f6333d505947f34b9142910719f1d8631c40a151dd86bad727 --hash=sha256:5832d894419a9e8fe5c242e3ac86588e16e2cb379822dcb154bfec8544ae858e --hash=sha256:598b841ed0809e5c64d8c383b8035f6ace5a6f9013f680cdc6981221911c005d --hash=sha256:5a5c91027d7652aaf10e101743edd6b1e832039a19af75fca301275ef30f01d4 --hash=sha256:61418f619af72c8cca8de622785b4f4bfc17ace09981de6eb44feae560cf3bbb --hash=sha256:784c914c8df3fd79cfb148d2bcd17c4b2703c89af1278ed98773afb57ceea3e6 --hash=sha256:87a19d3012f505ba7fda37483b851ef0ca40290ad8a9b28a820b84f8574287bb --hash=sha256:89503f0749362d36b6fab8636710f1848943c21f9d488672921bac21e9edd29f --hash=sha256:89e5189fd393918c27af2daefdcb13df4d52fa761f065d5964d2c4ff5c0642fb --hash=sha256:8cb4b0edf8f0b47c3b604b461cb574fc75fd97efa893cbaf828f4f2f71cf459e --hash=sha256:94e884e16186899ad5b4d131c3f7ff0a2277e67ea0660754e8810a4bbf2d610e --hash=sha256:997dbca2a2cd933fd0a44d9fadeebc1e8a40701db15ea06f207811933dceb350 --hash=sha256:a7cea13cb2fe4f5ca735490846342885117778a73008a67ed9cac667aaaf3f0d --hash=sha256:a84edfbfa57dc6e16845a55feb0b4e1c8b6bbfa5ef1ab6768beba8d81e0546aa --hash=sha256:a95b5e5708a3629d319d2b655d11345cc7e97fea9bdc9bc1df7435926ac30966 --hash=sha256:aa6818c39ca1ce699e4bb1d84899c4f98c2d25c7671bd6c7beee3b1ee9d68834 --hash=sha256:ab99bf7e055780b57419d4133fd4dca9c72a03b766a3e2200552f10498eb8845 --hash=sha256:b966f5560a494fd99f95a1562f9326ca20c35bb118d4e6b50db41da8e4a6f718 --hash=sha256:bc44a7708a5a63d3059a622c2fb90831dc33534c3343e971f5a6c78905097baa --hash=sha256:c11e21d291ba2f889e33c21d76e9aec6ffdfb5666053dc34452666579daa675b --hash=sha256:c848de13583478d71cc91e528e17c051ca6a3b92e89d703ac5015f17cab1287b --hash=sha256:d944aa5509a0f0786d6f30554a2f8b1f229847f9ac9988879d7a05497739f668 --hash=sha256:f50862153e1364f6edeaef9d70505093549fa097e9b2555ea46d1e4f94ac3287 --hash=sha256:f74c598e230e1035103f6e3a97dd7a0e1bcacf7f3ea7481cd3bcde477b74e379 --hash=sha256:fcb81c6c37e11b0729768dd8e192a9cfb809778699ab1fe89f4d92ba0beb3092 --hash=sha256:ff2ddc8b304eb7076ceead2534a1b9828df771798fa9c2601ea983c86d23ec08", + "timeout": 600000 + } + }, + "xls_pip_deps_312_cocotb_bus": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "cocotb-bus==0.2.1 --hash=sha256:a197aa4b0e0ad28469c8877b41b3fb2ec0206da9f491b9276d1578ce6dd8aa8d", + "timeout": 600000 + } + }, + "xls_pip_deps_312_cocotbext_axi": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "cocotbext-axi==0.1.24 --hash=sha256:3ed62dcaf9448833176826507c5bc5c346431c4846a731e409d87c862d960593 --hash=sha256:533ba6c7503c6302bdb9ef86e43a549ad5da876eafb1adce23d39751c54cced4", + "timeout": 600000 + } + }, "xls_pip_deps_312_contourpy": { "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", "ruleClassName": "whl_library", @@ -14427,6 +14393,17 @@ "timeout": 600000 } }, + "xls_pip_deps_312_find_libpython": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "find-libpython==0.4.0 --hash=sha256:034a4253bd57da3408aefc59aeac1650150f6c1f42e10fdd31615cf1df0842e3 --hash=sha256:46f9cdcd397ddb563b2d7592ded3796a41c1df5222443bd9d981721c906c03e6", + "timeout": 600000 + } + }, "xls_pip_deps_312_flask": { "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", "ruleClassName": "whl_library", @@ -14449,6 +14426,17 @@ "timeout": 600000 } }, + "xls_pip_deps_312_iniconfig": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "iniconfig==2.3.0 --hash=sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730 --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", + "timeout": 600000 + } + }, "xls_pip_deps_312_itsdangerous": { "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", "ruleClassName": "whl_library", @@ -14548,6 +14536,17 @@ "timeout": 600000 } }, + "xls_pip_deps_312_pluggy": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "pluggy==1.6.0 --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", + "timeout": 600000 + } + }, "xls_pip_deps_312_portpicker": { "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", "ruleClassName": "whl_library", @@ -14581,6 +14580,17 @@ "timeout": 600000 } }, + "xls_pip_deps_312_pytest": { + "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", + "ruleClassName": "whl_library", + "attributes": { + "dep_template": "@xls_pip_deps//{name}:{target}", + "python_interpreter_target": "@@rules_python~~python~python_3_12_host//:python", + "repo": "xls_pip_deps_312", + "requirement": "pytest==8.2.2 --hash=sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343 --hash=sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977", + "timeout": 600000 + } + }, "xls_pip_deps_312_python_dateutil": { "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl", "ruleClassName": "whl_library", @@ -15192,10 +15202,15 @@ "whl_map": { "blinker": "{\"xls_pip_deps_312_blinker\":[{\"version\":\"3.12\"}]}", "click": "{\"xls_pip_deps_312_click\":[{\"version\":\"3.12\"}]}", + "cocotb": "{\"xls_pip_deps_312_cocotb\":[{\"version\":\"3.12\"}]}", + "cocotb_bus": "{\"xls_pip_deps_312_cocotb_bus\":[{\"version\":\"3.12\"}]}", + "cocotbext_axi": "{\"xls_pip_deps_312_cocotbext_axi\":[{\"version\":\"3.12\"}]}", "contourpy": "{\"xls_pip_deps_312_contourpy\":[{\"version\":\"3.12\"}]}", "cycler": "{\"xls_pip_deps_312_cycler\":[{\"version\":\"3.12\"}]}", + "find_libpython": "{\"xls_pip_deps_312_find_libpython\":[{\"version\":\"3.12\"}]}", "flask": "{\"xls_pip_deps_312_flask\":[{\"version\":\"3.12\"}]}", "fonttools": "{\"xls_pip_deps_312_fonttools\":[{\"version\":\"3.12\"}]}", + "iniconfig": "{\"xls_pip_deps_312_iniconfig\":[{\"version\":\"3.12\"}]}", "itsdangerous": "{\"xls_pip_deps_312_itsdangerous\":[{\"version\":\"3.12\"}]}", "jinja2": "{\"xls_pip_deps_312_jinja2\":[{\"version\":\"3.12\"}]}", "kiwisolver": "{\"xls_pip_deps_312_kiwisolver\":[{\"version\":\"3.12\"}]}", @@ -15205,9 +15220,11 @@ "numpy": "{\"xls_pip_deps_312_numpy\":[{\"version\":\"3.12\"}]}", "packaging": "{\"xls_pip_deps_312_packaging\":[{\"version\":\"3.12\"}]}", "pillow": "{\"xls_pip_deps_312_pillow\":[{\"version\":\"3.12\"}]}", + "pluggy": "{\"xls_pip_deps_312_pluggy\":[{\"version\":\"3.12\"}]}", "portpicker": "{\"xls_pip_deps_312_portpicker\":[{\"version\":\"3.12\"}]}", "psutil": "{\"xls_pip_deps_312_psutil\":[{\"version\":\"3.12\"}]}", "pyparsing": "{\"xls_pip_deps_312_pyparsing\":[{\"version\":\"3.12\"}]}", + "pytest": "{\"xls_pip_deps_312_pytest\":[{\"version\":\"3.12\"}]}", "python_dateutil": "{\"xls_pip_deps_312_python_dateutil\":[{\"version\":\"3.12\"}]}", "pyyaml": "{\"xls_pip_deps_312_pyyaml\":[{\"version\":\"3.12\"}]}", "scipy": "{\"xls_pip_deps_312_scipy\":[{\"version\":\"3.12\"}]}", @@ -15219,10 +15236,15 @@ "packages": [ "blinker", "click", + "cocotb", + "cocotb_bus", + "cocotbext_axi", "contourpy", "cycler", + "find_libpython", "flask", "fonttools", + "iniconfig", "itsdangerous", "jinja2", "kiwisolver", @@ -15232,9 +15254,11 @@ "numpy", "packaging", "pillow", + "pluggy", "portpicker", "psutil", "pyparsing", + "pytest", "python_dateutil", "pyyaml", "scipy", diff --git a/dependency_support/com_github_alexforencich_verilog_axi/BUILD.bazel b/dependency_support/com_github_alexforencich_verilog_axi/BUILD.bazel new file mode 100644 index 0000000000..4a24c1372f --- /dev/null +++ b/dependency_support/com_github_alexforencich_verilog_axi/BUILD.bazel @@ -0,0 +1,15 @@ +# Copyright 2025 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. + +# Needed to make this a package. diff --git a/dependency_support/com_github_alexforencich_verilog_axi/bundled.BUILD.bazel b/dependency_support/com_github_alexforencich_verilog_axi/bundled.BUILD.bazel new file mode 100644 index 0000000000..296e2bc0f6 --- /dev/null +++ b/dependency_support/com_github_alexforencich_verilog_axi/bundled.BUILD.bazel @@ -0,0 +1,45 @@ +# Copyright 2025 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. + +load("@xls_pip_deps//:requirements.bzl", "requirement") + +package(default_visibility = ["//visibility:public"]) + +exports_files( + glob(["rtl/*.v"]), +) + +py_binary( + name = "axi_crossbar_wrap", + srcs = ["rtl/axi_crossbar_wrap.py"], + deps = [requirement("Jinja2")], +) + +py_binary( + name = "axi_interconnect_wrap", + srcs = ["rtl/axi_interconnect_wrap.py"], + deps = [requirement("Jinja2")], +) + +py_binary( + name = "axil_crossbar_wrap", + srcs = ["rtl/axi_crossbar_wrap.py"], + deps = [requirement("Jinja2")], +) + +py_binary( + name = "axil_interconnect_wrap", + srcs = ["rtl/axil_interconnect_wrap.py"], + deps = [requirement("Jinja2")], +) diff --git a/dependency_support/com_github_facebook_zstd/allow-specifying-max-window-log.patch b/dependency_support/com_github_facebook_zstd/allow-specifying-max-window-log.patch new file mode 100644 index 0000000000..988d501b37 --- /dev/null +++ b/dependency_support/com_github_facebook_zstd/allow-specifying-max-window-log.patch @@ -0,0 +1,68 @@ +From c052badd17fdb6751f3b5820ab6f7eab0cab196e Mon Sep 17 00:00:00 2001 +From: Mateusz Gancarz +Date: Fri, 5 Sep 2025 11:11:34 +0200 +Subject: [PATCH] decodecorpus: allow specifying max window log + +--- + tests/decodecorpus.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/tests/decodecorpus.c b/tests/decodecorpus.c +index f25e5dc7..085f7be2 100644 +--- a/tests/decodecorpus.c ++++ b/tests/decodecorpus.c +@@ -163,6 +163,7 @@ static double RAND_exp(U32* seed, double mean) + const char* BLOCK_TYPES[] = {"raw", "rle", "compressed"}; + + #define MAX_DECOMPRESSED_SIZE_LOG 20 ++#define MIN_WINDOW_LOG 10 + #define MAX_DECOMPRESSED_SIZE (1ULL << MAX_DECOMPRESSED_SIZE_LOG) + + #define MAX_WINDOW_LOG 22 /* Recommended support is 8MB, so limit to 4MB + mantissa */ +@@ -257,6 +258,7 @@ typedef enum { + * Global variables (set from command line) + *********************************************************/ + U32 g_maxDecompressedSizeLog = MAX_DECOMPRESSED_SIZE_LOG; /* <= 20 */ ++U32 g_maxWindowLog = MAX_WINDOW_LOG; /* 10 <= window log <= 22 */ + U32 g_maxBlockSize = ZSTD_BLOCKSIZE_MAX; /* <= 128 KB */ + + /*-******************************************************* +@@ -289,7 +291,7 @@ static void writeFrameHeader(U32* seed, frame_t* frame, dictInfo info) + /* generate window size */ + { + /* Follow window algorithm from specification */ +- int const exponent = RAND(seed) % (MAX_WINDOW_LOG - 10); ++ int const exponent = g_maxWindowLog > 10 ? RAND(seed) % (g_maxWindowLog - 10) : 0; + int const mantissa = RAND(seed) % 8; + windowByte = (BYTE) ((exponent << 3) | mantissa); + fh.windowSize = (1U << (exponent + 10)); +@@ -1231,7 +1233,7 @@ static U32 generateCompressedBlock(U32 seed, frame_t* frame, dictInfo info) + while (!blockWritten) { + size_t cSize; + /* generate window size */ +- { int const exponent = RAND(&seed) % (MAX_WINDOW_LOG - 10); ++ { int const exponent = g_maxWindowLog > 10 ? RAND(&seed) % (g_maxWindowLog - 10) : 0; + int const mantissa = RAND(&seed) % 8; + frame->header.windowSize = (1U << (exponent + 10)); + frame->header.windowSize += (frame->header.windowSize / 8) * mantissa; +@@ -1807,6 +1809,7 @@ static void advancedUsage(const char* programName) + DISPLAY( " --max-block-size-log=# : max block size log, must be in range [2, 17]\n"); + DISPLAY( " --max-content-size-log=# : max content size log, must be <= 20\n"); + DISPLAY( " (this is ignored with gen-blocks)\n"); ++ DISPLAY( " --max-window-log=# : max window log, must be in range [10, 22]\n"); + DISPLAY( " --block-type=# : force certain block type (raw=0, rle=1, compressed=2)\n"); + DISPLAY( " --frame-header-only : dump only frame header\n"); + DISPLAY( " --no-magic : do not add magic number\n"); +@@ -1931,6 +1934,9 @@ int main(int argc, char** argv) + U32 value = readU32FromChar(&argument); + g_maxDecompressedSizeLog = + MIN(MAX_DECOMPRESSED_SIZE_LOG, value); ++ } else if (longCommandWArg(&argument, "max-window-log=")) { ++ U32 value = readU32FromChar(&argument); ++ g_maxWindowLog = MIN(MAX_WINDOW_LOG, MAX(MIN_WINDOW_LOG, value)); + } else if (longCommandWArg(&argument, "block-type=")) { + U32 value = readU32FromChar(&argument); + opts.blockType = malloc(sizeof(blockType_e)); +-- +2.39.5 + diff --git a/dependency_support/load_external.bzl b/dependency_support/load_external.bzl index cdc9deebc8..f68a46413c 100644 --- a/dependency_support/load_external.bzl +++ b/dependency_support/load_external.bzl @@ -76,7 +76,19 @@ def load_external_repositories(): http_archive( name = "zstd", sha256 = "9ace5a1b3c477048c6e034fe88d2abb5d1402ced199cae8e9eef32fdc32204df", + patches = [ + Label("@//dependency_support/com_github_facebook_zstd:allow-specifying-max-window-log.patch"), + ], + patch_args = ["-p1"], strip_prefix = "zstd-fdfb2aff39dc498372d8c9e5f2330b692fea9794", urls = ["https://github.com/facebook/zstd/archive/fdfb2aff39dc498372d8c9e5f2330b692fea9794.zip"], build_file = Label("//dependency_support/com_github_facebook_zstd:bundled.BUILD.bazel"), ) + + http_archive( + name = "com_github_alexforencich_verilog_axi", + sha256 = "f3b58406b51950584cc7b0c67b0710cef10cb14e1f5576e97a2f0b1c0b12fcbe", + strip_prefix = "verilog-axi-516bd5dadc3365b7f9e225d2af8fe0b8d804fe53", + urls = ["https://github.com/alexforencich/verilog-axi/archive/516bd5dadc3365b7f9e225d2af8fe0b8d804fe53.zip"], + build_file = "//dependency_support/com_github_alexforencich_verilog_axi:bundled.BUILD.bazel", + ) diff --git a/dependency_support/pip_requirements.in b/dependency_support/pip_requirements.in index 9d86ed7c11..0b30315f05 100644 --- a/dependency_support/pip_requirements.in +++ b/dependency_support/pip_requirements.in @@ -15,3 +15,13 @@ pyyaml==6.0.1 # We build most of z3 ourselves but building python is really complicated. Just # use pypi version z3-solver==4.14.0.0 +pytest==8.2.2 +cocotb==1.9.0 +cocotbext-axi==0.1.24 +cocotb_bus==0.2.1 + +# Note: numpy and scipy version availability seems to differ between Ubuntu +# versions that we want to support (e.g. 18.04 vs 20.04), so we accept a +# range that makes successful installation on those platforms possible. +numpy>=1.21 +scipy>=1.5.4,<=1.16.3 diff --git a/dependency_support/pip_requirements_lock.txt b/dependency_support/pip_requirements_lock.txt index 65c9ff6478..b2aa7966a2 100644 --- a/dependency_support/pip_requirements_lock.txt +++ b/dependency_support/pip_requirements_lock.txt @@ -14,6 +14,56 @@ click==8.1.3 \ # via # -r dependency_support/pip_requirements.in # flask +cocotb==1.9.0 \ + --hash=sha256:02a58ef6c941114964096e7c039bdd4e67e63816cfd2f6a9af6a34cd92b00e8e \ + --hash=sha256:0819794ef5e8fd14fee0b265933226cf600e85edc2f1a749b4d5f8fa2d31ce4e \ + --hash=sha256:0ba35617a677ff65a1273411a3dfdfc5f587128ad8cb9e941ab0eb17ec8fb3e2 \ + --hash=sha256:17556e3a23562f64d577d0eb117fe02e384aedee997b29497b5c395f5010ff82 \ + --hash=sha256:19b4e27b53a16e0b9c4cc5227c7f9d4dccac06e431a4f937e9f5513350196333 \ + --hash=sha256:1a0381ced5590a726032ba2265c6b70ac12cfb49edb152be86a081bb7d104751 \ + --hash=sha256:1aff68cf77059448a9a3278079037e34b50c8c2aee466d984295fa7fe699d390 \ + --hash=sha256:277281420fd6fc3002bb85d6bec497bd20ff3a3905d4b5f1301faf975f750ede \ + --hash=sha256:2daf743320331615f4e8ffb877ab0b04e6f913b911bb11bf9dbc1d876d9c4220 \ + --hash=sha256:2e9bcdbfba3e99c9297bd0d74ba781772d89d2c86e893980784ada252bd1a0f8 \ + --hash=sha256:3058c977f9d4e1f6333d505947f34b9142910719f1d8631c40a151dd86bad727 \ + --hash=sha256:5832d894419a9e8fe5c242e3ac86588e16e2cb379822dcb154bfec8544ae858e \ + --hash=sha256:598b841ed0809e5c64d8c383b8035f6ace5a6f9013f680cdc6981221911c005d \ + --hash=sha256:5a5c91027d7652aaf10e101743edd6b1e832039a19af75fca301275ef30f01d4 \ + --hash=sha256:61418f619af72c8cca8de622785b4f4bfc17ace09981de6eb44feae560cf3bbb \ + --hash=sha256:784c914c8df3fd79cfb148d2bcd17c4b2703c89af1278ed98773afb57ceea3e6 \ + --hash=sha256:87a19d3012f505ba7fda37483b851ef0ca40290ad8a9b28a820b84f8574287bb \ + --hash=sha256:89503f0749362d36b6fab8636710f1848943c21f9d488672921bac21e9edd29f \ + --hash=sha256:89e5189fd393918c27af2daefdcb13df4d52fa761f065d5964d2c4ff5c0642fb \ + --hash=sha256:8cb4b0edf8f0b47c3b604b461cb574fc75fd97efa893cbaf828f4f2f71cf459e \ + --hash=sha256:94e884e16186899ad5b4d131c3f7ff0a2277e67ea0660754e8810a4bbf2d610e \ + --hash=sha256:997dbca2a2cd933fd0a44d9fadeebc1e8a40701db15ea06f207811933dceb350 \ + --hash=sha256:a7cea13cb2fe4f5ca735490846342885117778a73008a67ed9cac667aaaf3f0d \ + --hash=sha256:a84edfbfa57dc6e16845a55feb0b4e1c8b6bbfa5ef1ab6768beba8d81e0546aa \ + --hash=sha256:a95b5e5708a3629d319d2b655d11345cc7e97fea9bdc9bc1df7435926ac30966 \ + --hash=sha256:aa6818c39ca1ce699e4bb1d84899c4f98c2d25c7671bd6c7beee3b1ee9d68834 \ + --hash=sha256:ab99bf7e055780b57419d4133fd4dca9c72a03b766a3e2200552f10498eb8845 \ + --hash=sha256:b966f5560a494fd99f95a1562f9326ca20c35bb118d4e6b50db41da8e4a6f718 \ + --hash=sha256:bc44a7708a5a63d3059a622c2fb90831dc33534c3343e971f5a6c78905097baa \ + --hash=sha256:c11e21d291ba2f889e33c21d76e9aec6ffdfb5666053dc34452666579daa675b \ + --hash=sha256:c848de13583478d71cc91e528e17c051ca6a3b92e89d703ac5015f17cab1287b \ + --hash=sha256:d944aa5509a0f0786d6f30554a2f8b1f229847f9ac9988879d7a05497739f668 \ + --hash=sha256:f50862153e1364f6edeaef9d70505093549fa097e9b2555ea46d1e4f94ac3287 \ + --hash=sha256:f74c598e230e1035103f6e3a97dd7a0e1bcacf7f3ea7481cd3bcde477b74e379 \ + --hash=sha256:fcb81c6c37e11b0729768dd8e192a9cfb809778699ab1fe89f4d92ba0beb3092 \ + --hash=sha256:ff2ddc8b304eb7076ceead2534a1b9828df771798fa9c2601ea983c86d23ec08 + # via + # -r dependency_support/pip_requirements.in + # cocotb-bus + # cocotbext-axi +cocotb-bus==0.2.1 \ + --hash=sha256:a197aa4b0e0ad28469c8877b41b3fb2ec0206da9f491b9276d1578ce6dd8aa8d + # via + # -r dependency_support/pip_requirements.in + # cocotbext-axi +cocotbext-axi==0.1.24 \ + --hash=sha256:3ed62dcaf9448833176826507c5bc5c346431c4846a731e409d87c862d960593 \ + --hash=sha256:533ba6c7503c6302bdb9ef86e43a549ad5da876eafb1adce23d39751c54cced4 + # via -r dependency_support/pip_requirements.in contourpy==1.3.1 \ --hash=sha256:041b640d4ec01922083645a94bb3b2e777e6b626788f4095cf21abbe266413c1 \ --hash=sha256:05e806338bfeaa006acbdeba0ad681a10be63b26e1b17317bfac3c5d98f36cda \ @@ -74,6 +124,10 @@ cycler==0.12.1 \ --hash=sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 \ --hash=sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c # via matplotlib +find-libpython==0.4.0 \ + --hash=sha256:034a4253bd57da3408aefc59aeac1650150f6c1f42e10fdd31615cf1df0842e3 \ + --hash=sha256:46f9cdcd397ddb563b2d7592ded3796a41c1df5222443bd9d981721c906c03e6 + # via cocotb flask==2.3.2 \ --hash=sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0 \ --hash=sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef @@ -130,6 +184,10 @@ fonttools==4.55.8 \ --hash=sha256:f089e8da0990cfe2d67e81d9cf581ff372b48dc5acf2782701844211cd1f0eb3 \ --hash=sha256:f971aa5f50c22dc4b63a891503624ae2c77330429b34ead32f23c2260c5618cd # via matplotlib +iniconfig==2.3.0 \ + --hash=sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730 \ + --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12 + # via pytest itsdangerous==2.1.2 \ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \ --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a @@ -392,7 +450,9 @@ numpy==2.3.4 \ packaging==24.2 \ --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \ --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f - # via matplotlib + # via + # matplotlib + # pytest pillow==11.1.0 \ --hash=sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83 \ --hash=sha256:0a2f91f8a8b367e7a57c6e91cd25af510168091fb89ec5146003e424e1558a96 \ @@ -466,6 +526,10 @@ pillow==11.1.0 \ --hash=sha256:f86d3a7a9af5d826744fabf4afd15b9dfef44fe69a98541f666f66fbb8d3fef9 \ --hash=sha256:fbd43429d0d7ed6533b25fc993861b8fd512c42d04514a0dd6337fb3ccf22761 # via matplotlib +pluggy==1.6.0 \ + --hash=sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3 \ + --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 + # via pytest portpicker==1.3.1 \ --hash=sha256:d2cdc776873635ed421315c4d22e63280042456bbfa07397817e687b142b9667 # via -r dependency_support/pip_requirements.in @@ -486,6 +550,10 @@ pyparsing==3.2.1 \ --hash=sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1 \ --hash=sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a # via matplotlib +pytest==8.2.2 \ + --hash=sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343 \ + --hash=sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977 + # via -r dependency_support/pip_requirements.in python-dateutil==2.9.0.post0 \ --hash=sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3 \ --hash=sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 diff --git a/dependency_support/rules_hdl/add_standalone_verilator.patch b/dependency_support/rules_hdl/add_standalone_verilator.patch new file mode 100644 index 0000000000..321ad3f9bd --- /dev/null +++ b/dependency_support/rules_hdl/add_standalone_verilator.patch @@ -0,0 +1,85 @@ +--- dependency_support/verilator/verilator.BUILD.bazel ++++ dependency_support/verilator/verilator.BUILD.bazel +@@ -13,6 +13,7 @@ + # Original implementation by Kevin Kiningham (@kkiningh) in kkiningh/rules_verilator. + # Ported to bazel_rules_hdl by Stephen Tridgell (@stridge-cruxml) + ++load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") + load("@bazel_skylib//rules:write_file.bzl", "write_file") + load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") + load("@rules_hdl//dependency_support/com_github_westes_flex:flex.bzl", "genlex") +@@ -370,3 +371,74 @@ + visibility = ["//visibility:public"], + deps = [":verilator_libV3"], + ) ++ ++genrule( ++ name = "verilated_makefile", ++ srcs = ["include/verilated.mk.in"], ++ outs = ["include/verilated.mk"], ++ cmd = """ ++ cp "$(SRCS)" "$(OUTS)" ++ sed "s%@AR@%$(AR)%" "$(OUTS)" -i ++ sed "s%@CXX@%$(CC)%" "$(OUTS)" -i ++ sed "s%@LINK@%$(CC)%" "$(OUTS)" -i ++ sed "s%@PERL@%$(PERL)%" "$(OUTS)" -i ++ sed "s%@PYTHON3@%$(PYTHON3)%" "$(OUTS)" -i ++ sed "s%@OBJCACHE@%%" "$(OUTS)" -i ++ ++ if [ "$(C_COMPILER)" = "clang" ]; then ++ # Compiler option to put in front of filename to read precompiled header ++ sed "s%@CFG_CXXFLAGS_PCH_I@%-include-pch%" "$(OUTS)" -i ++ # Compiler's filename suffix for precompiled headers, .gch if clang, empty if GCC ++ sed "s%@CFG_GCH_IF_CLANG@%.gch%" "$(OUTS)" -i ++ else ++ sed "s%@CFG_CXXFLAGS_PCH_I@%-include%" "$(OUTS)" -i ++ sed "s%@CFG_GCH_IF_CLANG@%%" "$(OUTS)" -i ++ fi ++ ++ # Select language required to compile ++ sed "s%@CFG_CXXFLAGS_STD@%-x c++%" "$(OUTS)" -i ++ sed "s%@CFG_LDFLAGS_VERILATED@%-lstdc++%" "$(OUTS)" -i ++ ++ # Compiler flags to use to turn off unused and generated code warnings, such as -Wno-div-by-zero "$(OUTS)" -i ++ sed "s%@CFG_CXXFLAGS_NO_UNUSED@%-faligned-new -fcf-protection=none -Wno-bool-operation -Wno-shadow -Wno-sign-compare -Wno-subobject-linkage -Wno-tautological-compare -Wno-uninitialized -Wno-unused-but-set-parameter -Wno-unused-but-set-variable -Wno-unused-parameter -Wno-unused-variable%" "$(OUTS)" -i ++ # Linker libraries for multithreading ++ sed "s%@CFG_LDLIBS_THREADS@%-pthread -lpthread -latomic%" "$(OUTS)" -i ++ """, ++ toolchains = [ ++ "@bazel_tools//tools/cpp:current_cc_toolchain", ++ "@rules_python//python:current_py_toolchain", ++ "@rules_perl//:current_toolchain", ++ ], ++ visibility = ["//visibility:public"], ++) ++ ++filegroup( ++ name = "includes", ++ srcs = glob(["include/**"]), ++) ++ ++# The perl wrapper assumes that runtime resources are stored under $(realpath verilator)/../ ++# using perl binary would be problematic due to symlinks ++# potential alternative solution: write simplified perl wrapper that does not depend on realpath ++copy_to_bin( ++ name = "verilator_runtime_extras", ++ srcs = [ ++ "bin/verilator", ++ "bin/verilator_includer", ++ ":includes", ++ ], ++) ++ ++filegroup( ++ name = "standalone_verilator", ++ srcs = [ ++ ":verilated_config", ++ ":verilated_makefile", ++ ":verilator_executable", ++ ":verilator_runtime_extras", ++ "@bazel_tools//tools/cpp:current_cc_toolchain", ++ "@rules_perl//:current_toolchain", ++ "@rules_python//python:current_py_toolchain", ++ ], ++ visibility = ["//visibility:public"], ++) diff --git a/dependency_support/rules_hdl/bump_verilator.patch b/dependency_support/rules_hdl/bump_verilator.patch new file mode 100644 index 0000000000..447d89986e --- /dev/null +++ b/dependency_support/rules_hdl/bump_verilator.patch @@ -0,0 +1,65 @@ +--- dependency_support/verilator/verilator.bzl ++++ dependency_support/verilator/verilator.bzl +@@ -22,7 +22,7 @@ + http_archive, + name = "verilator", + build_file = Label("//dependency_support/verilator:verilator.BUILD.bazel"), +- urls = ["https://github.com/verilator/verilator/archive/refs/tags/v5.034.tar.gz"], +- sha256 = "002da98e316ca6eee40407f5deb7d7c43a0788847d39c90d4d31ddbbc03020e8", +- strip_prefix = "verilator-5.034", ++ urls = ["http://github.com/verilator/verilator/archive/435e1149d57b4f204b5dcff6e93135c0f79599fd.tar.gz"], # current as of 2025-10-01 ++ sha256 = "1e93d81a12529738b6b329191aaee7f84ef5a9d62237d972c1d2cad0a3ad6bb4", ++ strip_prefix = "verilator-435e1149d57b4f204b5dcff6e93135c0f79599fd", + ) +--- dependency_support/verilator/verilator.BUILD.bazel ++++ dependency_support/verilator/verilator.BUILD.bazel +@@ -90,6 +90,7 @@ + "src/V3AstNodeDType.h", + "src/V3AstNodeExpr.h", + "src/V3AstNodeOther.h", ++ "src/V3AstNodeStmt.h", + "src/V3DfgVertices.h", + "src/Verilator.cpp", + ], +@@ -106,6 +107,7 @@ + "V3Ast__gen_yystype.h", + "V3Dfg__gen_ast_to_dfg.h", + "V3Dfg__gen_auto_classes.h", ++ "V3Dfg__gen_clone_cases.h", + "V3Dfg__gen_dfg_to_ast.h", + "V3Dfg__gen_forward_class_decls.h", + "V3Dfg__gen_macros.h", +@@ -121,6 +123,8 @@ + "V3AstNodeExpr.h", + "--astdef", + "V3AstNodeOther.h", ++ "--astdef", ++ "V3AstNodeStmt.h", + "--dfgdef", + "V3DfgVertices.h", + "--classes", +@@ -135,6 +139,7 @@ + "src/V3AstNodeDType.h", + "src/V3AstNodeExpr.h", + "src/V3AstNodeOther.h", ++ "src/V3AstNodeStmt.h", + "src/V3Const.cpp", + "src/V3DfgVertices.h", + "src/Verilator.cpp", +@@ -149,6 +154,8 @@ + "V3AstNodeExpr.h", + "--astdef", + "V3AstNodeOther.h", ++ "--astdef", ++ "V3AstNodeStmt.h", + "--dfgdef", + "V3DfgVertices.h", + "V3Const.cpp", +@@ -234,6 +241,7 @@ + ":V3Const__gen.cpp", + ":V3Dfg__gen_ast_to_dfg.h", + ":V3Dfg__gen_auto_classes.h", ++ ":V3Dfg__gen_clone_cases.h", + ":V3Dfg__gen_dfg_to_ast.h", + ":V3Dfg__gen_forward_class_decls.h", + ":V3Dfg__gen_macros.h", diff --git a/dependency_support/rules_hdl/workspace.bzl b/dependency_support/rules_hdl/workspace.bzl index 32a346fcba..a449083211 100644 --- a/dependency_support/rules_hdl/workspace.bzl +++ b/dependency_support/rules_hdl/workspace.bzl @@ -40,4 +40,9 @@ def repo(): urls = [ "https://github.com/hdl/bazel_rules_hdl/archive/%s.tar.gz" % git_hash, ], + patches = [ + "@//dependency_support/rules_hdl:add_standalone_verilator.patch", + "@//dependency_support/rules_hdl:bump_verilator.patch", + ], + patch_tool = "patch", ) diff --git a/xls/examples/ram.x b/xls/examples/ram.x index 2e5081b864..985ec92ea1 100644 --- a/xls/examples/ram.x +++ b/xls/examples/ram.x @@ -576,7 +576,7 @@ proc SinglePortRamModelTest { } // Models a true dual-port RAM. -proc RamModel2RW IDLE ``` -After going through the initial stage of reading the configuration from the -CSRs, the decoder sends the processing requests to the underlying parts of the -decoder. The processing requests contain the addresses in the memory where -particular parts of the encoded ZSTD frames reside. The decoder, based on -responses from consecutive internal modules, calculates offsets from the base -address that was written to `Input Buffer` CSR and forms the requests for the -next internal modules, e.g.: for `BlockHeaderDecoder` or any of the processing -units (`RawBlockDecoder`, `RleBlockDecoder`, `CompressedBlockDecoder`). - -Each of the internal modules waits for the processing request. Once received, -the module fetches the data from the memory starting from the address received -in the processing request. `MemReader` procs are used by those modules to -communicate with the external memory through the AXI interface. Internal modules -decode the acquired parts of the frame and return responses with the results -back to the top level proc. - -The processing units also output the decoded blocks of data through a -stream-based interface to the `SequenceExecutor` proc. This proc performs the -last step of the decoding before the final output is sent out back to the memory -under the address stored in the `Output Buffer` CSR by the `MemWriter` proc. -Once the decoding process is completed and the decoded frame is written back to -the memory, the decoder sends the `Notify` signal and transitions back to the -`IDLE` state. - -### Internal modules - -#### FrameHeaderDecoder - -This proc receives requests with the address of the beginning of the ZSTD frame. -It then reads the frame data from the memory and starts parsing the frame -header. If the magic number is not detected or the frame header is invalid, the -proc will send a response with an error code. Otherwise, it will put the frame -header into internal DSLX representation, calculate the length of the header and -send those as a response with `OKAY` status. - -#### BlockHeaderDecoder - -ZSTD block header size is always 3 bytes. BlockHeaderDecoder always reads 4 -bytes of data. It extracts the information on block type, size and whether the -block is the last one in the ZSTD frame and puts that data in the response. The -additional byte is also placed in the response as an optimization for the -RleBlockDecoder. - -#### RawBlockDecoder - -This proc passes the data read from the memory directly to its output channel. -It preserves the block ID and attaches a tag, stating that the data contains -literals and should be placed in the history buffer unchanged, to each data -output. - -#### RleBlockDecoder - -This proc receives a tuple (s, N), where s is an 8-bit symbol and N is an -accompanying `symbol_count`. It does not have to read the 8-bit symbol from the -memory because `BlockHeaderDecoder` did that before and passed the symbol in the -processing request to the `RleBlockDecoder`. The proc produces `N*s` repeats of -the given symbol. This step preserves the block ID and attaches the literals tag -to all its outputs. - -#### CompressedBlockDecoder[^1] - -This part of the design is responsible for decoding the compressed data blocks. -It ingests the bytes stream, and internally translates and interprets incoming -data. Only this part of the design creates data chunks tagged both with -`literals` and/or `copy`. This step preserves the block ID. More in-depth -description can be found in [Compressed block decoder -architecture](#compressed-block-decoder-architecture1) paragraph of this doc. - -#### Commands aggregator (DecMux) - -This stage takes the output from either RAW, RLE or CompressedBlockDecoder and -sends it to the History buffer and command execution stage. This stage orders -streams based on the ID value assigned by the top level proc. It is expected -that single base decoders (RAW, RLE, compressed block decoder) will be -continuously transmitting a single ID to the point of sending the `last` signal -which marks the last packet of currently decoded block. That ID can change only -when mux receives the `last` signal or `last` and `last_block` signals. - -It works as a priority mux that waits for a stream with the expected ID. It -continues to read that stream until the `last` signal is set, then it switches -to the next stream ID. - -The command aggregator starts by waiting for `ID = 0`, after receiving the -`last` signal it expects `ID = 1` and so on. Only when both `last` and -`last_block` are set the command aggregator will wait for `ID = 0`. - -#### History buffer and command execution (SequenceExecutor) - -This stage receives data which is tagged either `literals` or `copy`. This stage -will show the following behavior, depending on the tag: +### AxiCsrAccessor + +This proc provides an AXI interface to the CSRs of the Decoder. +Any read / write operation on the AXI is translated to a read / write operation +on the CSRs. + +### CsrConfig + +This proc implements the Control and Status Registers (CSRs). It's responsible +for storing the state of the registers and handling read / write operations. + +### FrameHeaderDecoder + +This proc receives the address of the start of a ZSTD frame, reads the frame +data from memory, and parses the frame header. If the magic number is invalid +or the header is corrupted, it responds with an error code. Otherwise, +it converts the header into an internal DSLX representation, calculates its +length, and responds with `OKAY` status. + +### BlockHeaderDecoder + +It extracts the block type, size, and whether it is the last block in the frame, +and returns this information in the response. +ZSTD block headers are 3 bytes, but this proc always reads 4 bytes. +The extra byte is included to optimize processing for the RleBlockDecoder. + +### DecoderMux + +This stage collects outputs from `RAW`, `RLE`, or `CompressedBlockDecoder` +and forwards them to the history buffer and command execution stage. +Streams are processed in ID order assigned by the top-level proc. +Each decoder sends a single ID until the last packet of the block. +The aggregator waits for the expected ID, reads it until the last signal, +then moves to the next ID, starting from 0 and wrapping back after both `last` +and `last_block` are set. + +### RamPassthrough + +This proces is a simple wrapper for routing both read and write side of +RAM interface through a single proc, so the ram rewritting step available +in XLS toolchain can rewrite it to proper RAM interface in verilog. + +### SequenceExecutor + +This block is responsible for managing `HistoryBuffer` using the data obtained +from `RawBlockDecoder`, `RleBlockDecoder` and `CompressBlockDecoder`. +The data comming from RAW and RLE block are sent directy to the output and +history buffer. Wheras data from `CompressBlockDecoder` (sequences and literals) +are processed first in the +[sequence execution](https://datatracker.ietf.org/doc/html/rfc8878#name-sequence-execution) step. + +### RawBlockDecoder + +This proc forwards the block data directly to its output channel. +It preserves the block ID and tags all data as literals to be placed +unchanged in the history buffer. + +### RleBlockDecoder + +This proc receives a tuple `(s, N)` where `s` is an 8-bit symbol and `N` is +the repeat count. The symbol is provided by `BlockHeaderDecoder`. +The proc outputs `N` repetitions of the symbol, preserves the block ID, +and tags all outputs as literals. + +### CompressBlockDecoder + +This proc includes the `LiteralsDecoder` and `SequenceDecoder`, +which decode literals and sequences, along with control logic that manages +the decompression process. Both decoders use multiple sub-procs. + +The diagram below illustrates the structure of the `CompressedBlockDecoder`: +![Compress Block Decoder](img/zstd-compress-block-decoder.png) + +## LiteralsDecoder + +LiteralsDecoder block is used to decode literals, it comprises of a +dedicated `LiteralsHeaderDecoder` responsible for decoding the header of the +literals section, `RawLiteralsDecoder`, `RleLiteralsDecoder` and `HuffmanLiteralsDecoder` +for decoding three types of the literals that can be present in the literals section +and `LiteralsBuffer` for storing the decoded literals. The control +logic controling the decoding process is encapsulated in `LiteralsDecoderCtrl` block + +![LiteralsDecoder](img/literals-decoder.png) + +## RawLiteralsDecoder -* `literals` - * Packet contents placed as newest in the history buffer, - * Packet contents copied to the decoder's output, -* `copy` - * Wait for all previous writes to be completed, - * Copy `copy_length` literals starting `offset _length` from the newest in - history buffer to the decoder's output, - * Copy `copy_length` literals starting `offset _length` from the newest in - history buffer to the history buffer as the newest. +This proc is responsible for fetching literals from a given address in memory +and streaming them out as literal tokens. -### Compressed block decoder architecture[^1] {#compressed-block-decoder-architecture1} +## RleLiteralsDecoder -This part of the design is responsible for processing the compressed blocks up -to the `literals`/`copy` command sequence. This sequence is then processed by -the history buffer to generate the expected data output. An overview of the -architecture is provided in the diagram below. The architecture is split into 2 -paths: the literals path and the sequence path. Architecture is split into 3 -paths: literals path, FSE encoded Huffman trees and sequence path. Literals path -uses Huffman trees to decode some types of compressed blocks: Compressed and -Treeless blocks. +This proc expands repeated symbols into literal data. On request, it receives +the information about the symbol to be repeated and the regenerated size. +It streams the symbol multiple times to satisfy the regenerated size. -![data flow diagram of compressed block decoder](img/ZSTD_compressed_block_decoder.png) +## HuffmanLiteralsDecoder -#### Compressed block dispatcher +This is a module that wires together procs needed to decode Huffman-encoded +literals: `HuffmanControlAndSequence`, `HuffmanWeightsDecoder`, `WeightPreScan`, +`WeightCodeBuilder`, `HuffmanDataPreprocessor`, `HuffmanDecoder`, along with +procs needed for memory access. + +## HuffmanWeightsDecoder + +This proc decodes Huffman tree weights from memory. It supports both RAW and +FSE formats. It fetches the Huffman tree description from memory, decodes it, +and writes the decoded weights into an internal RAM. + +![HuffmanWeightsDecoder](img/huffman-weights-decoder.png) + +## LiteralsBuffer + +This module provides interfaces to store and retrieve literals. It handles all +types of decoded literals (RAW, RLE, and Huffman), and stores them in RAM. The +module offers a uniform interface to access these literals, treating all types +consistently. + +## SequenceDecoder + +This proc is responsible for decoding sequences. Its work consists of decoding +the sequence header and decoding FSE lookups for LL, OF and ML into execution +commands. + +![SequenceDecoder](img/sequence-decoder.png) + + +# Registers description + +The ZSTD Decoder operation is based on the values stored in a set of CSRs +accessible to the user through the AXI bus. The registers are defined below: + +| Register | Address | Description | +|---------------|---------|------------------------------------| +| Status | 0x00 | Current decoder state | +| Start | 0x08 | Write 1 in IDLE to start decoding | +| Input Buffer | 0x10 | Base address of input frame | +| Output Buffer | 0x18 | Base address of output buffer | + +### Status codes + +The following is a list of all available status codes that can be written in the +`Status` register. + +| Name | Value | Description | +|--------------------------------------|-------|-------------------------------------------------- | +| IDLE | 0 | Decoder idle, waiting for configuration and start | +| RUNNING | 1 | Decoding in progress | +| READ_CONFIG_OK | 2 | Configuration read successfully | +| FRAME_HEADER_OK | 3 | Frame header decoded | +| FRAME_HEADER_CORRUPTED | 4 | Invalid frame header | +| FRAME_HEADER_UNSUPPORTED_WINDOW_SIZE | 5 | Unsupported window size | +| BLOCK_HEADER_OK | 6 | Block header decoded | +| BLOCK_HEADER_CORRUPTED | 7 | Reserved block type | +| BLOCK_HEADER_MEMORY_ACCESS_ERROR | 8 | Memory access error | +| RAW_BLOCK_OK | 9 | RAW block decoded | +| RAW_BLOCK_ERROR | 10 | RAW block memory error | +| RLE_BLOCK_OK | 11 | RLE block decoded | + +# Controlling from software + +Software configuration must be performed while the decoder is in +the `IDLE` state, which is the only state in which CSRs are read and applied. +The software should first read the `Status` register to confirm the IDLE state. +It must then allocate memory for the input buffer, write the ZSTD frame to it, +and store its base address in the `Input Buffer` register. +Next, the software must allocate memory for the output buffer and writes +its base address to the `Output Buffer` register. + +Decoding is started by writing `1` to the `Start` register. +The decoder reads the configuration, transitions to the RUNNING state, +and begins decoding the input data. Upon successful completion, +the decoder returns to the `IDLE` state, asserts the `Notify` IRQ line, +and writes the decoded data to the output buffer. If an error occurs, +the decoder asserts the `Notify` IRQ line and writes the corresponding error +code to the `Status` register. + +# Testing methodology + +Testing is performed at two levels: decoder components and the +integrated decoder. + +Individual components are tested using DSLX tests on various, +usually small inputs that test dedicated scenarios. Most of the proc should +have dedicated tests in DSLX. + +Integration tests for the entire decoder are performed at both +DSLX and Verilog levels by comparing the decoder output against +the ZSTD reference library. Due to limitations of the frame generator, +only valid ZSTD frames are currently tested. + +Verilog tests use [cocotb](https://github.com/cocotb/cocotb) testbenches +with [cocotbext-axi](https://github.com/alexforencich/cocotbext-axi) extension +to model AXI memory and interact with CSR interfaces. The AXI manager from +the cocotb extension is used to interface with the decoder's CSRs +to simulate software control. + +A basic integration test: + +1. Generates a ZSTD frame using [decodecorpus](https://github.com/facebook/zstd/blob/dev/tests/decodecorpus.c) +1. Places the frame in AXI-connected memory. +1. Produces the expected output using the original [zstd library](https://github.com/facebook/zstd). +1. Configures and starts the decoder via CSRs. +1. Waits for `Notify` signal and compares memory output with the expected result. +1. Checks that the decoder returns to `IDLE` state with a `OKAY` in the `Status` CSR + +## Failure points + +The tests report a failure if any of the following conditions occur: + +- The top-level state machine enters the `ERROR` state due + to corrupted input data. +- An `assert!()` or `fail!()` is triggered during simulation, + indicating an internal error or incorrect decoder configuration. +- The decoded output size or content differs from the output of the reference + zstd library. +- Intermediate decoding results are incorrect, such as an invalid FSE table or + incorrect Huffman weights or codes. +- The input data requires a larger history buffer than supported by + the current decoder configuration, indicating a mismatch between + the test file and decoder setup. + +### Failures trigered by internal components + +Some errors, such as invalid magic numbers or frame headers, can be triggered +by modifying generated ZSTD frames. However most errors require deeper changes +to the compressed frame, so DSLX component tests are preferred for focused testing. + +Components may trigger `assert!()` or `fail!()` or propagate error states to +the top-level controller, causing it to enter the `ERROR` state. +In this state, the decoder writes an error code to the `Status` CSR and +asserts the `Notify` signal. + +The `ERROR` state can occur under these conditions: +- Frame header corruption + - Invalid magic number (not 0xFD2FB528) + - Reserved bit set + - Window size exceeding `WINDOW_LOG_MAX` (0x78000000) +- Block header corruption + - Block type set to `RESERVED` +- Raw block memory access error + +Assertions and failures occur in the following modules: + +- `DecoderMux`: `ExtendedBlockDataPacket` with an ID less than any previously processed packet, or missing ID 0 at the start of a frame +- `HuffmanDecoder` when input data cause invalid state transition +- `HuffmanFseDecoder` when the FSE-encoded stream of weight contains 8 or more bits of padding +- `AxiCsrAccessor` on access to non-existing CSR +- `CompLookupDecoder` when the accuracy log of FSE table to decode is bigger then the maximal allowed value +- `FseTableCreator` when thee corruption is detected during decoding of FSE lookup +- `FseDecoder` when the FSE-encoded stream of sequences contains 8 or more bits of padding +- `RefillingShiftBuffer` when internal state of the proc is incorrect + +Several `impossible cases` are also covered by `fail!()`, they should never +be triggered and were added to satisfy the type checking system. + +# ZSTD Encoder + +The ZSTD encoder provided in this directory is a work in progress. +Eventually, it should be compliant with +[RFC 8879](https://www.rfc-editor.org/rfc/rfc8878.html). +The encoder should act as a peripheral on the AXI bus and should expose input, +output, and a separate control interface. + +Currently, only input and output are exposed, and the configuration parameters +are placed directly in the code of the encoder. + +## Architecture + +The encoder consists of a few independent blocks that are used together +to generate the ZSTD-encoded bitstream. + +The general architecture of the design is presented in the picture below: +![ZSTD encoder](/home/rwinkler/Projects/xls_ws2/encoder.png) + +### ZstdEncoder + +`ZstdEncoder` is a proc that aggregates multiple modules needed to compress +data located in memory. The proc must be connected to memory and will +communicate with it using the `MemReader` and `MemWriter` procs. They are +defined in `modules/zstd/memory/mem_{reader,writer}.x` files. + +Upon receiving a request, ZstdEncoder requests input data from `MemReader`, +constructs a single frame with the data encoded as RAW blocks, and writes it +to memory using `MemWriter`. + +The number of generated blocks depends on the request +(`max_block_size` and `data_size`). + +### Frame Header Generator + +The Frame Header Generator is responsible for creating a +[Frame Header](https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.1) +that contains the compression parameters. + +To simplify the decoding process, the length of the decoded stream is always +included in the header. This means that the `Frame_Content_Size` field is +always present. + +### Block Header Writer + +The BlockHeaderWriter proc is responsible for creating a Block Header +in memory. Upon request, `BlockHeaderWriter` constructs a request to `MemWriter` +with the provided Block Header information. + +### Match Finder + +The `MatchFinder` block processes the data stream, searching for repeating +symbol patterns in its history. Symbols not found in the history are stored +directly as literals in the literals buffer, while symbols that have matches +are stored as sequences in the sequence buffer, using the matched offset +and length information. + +Upon receiving a request, the `MatchFinder` starts the history-matching process. +It reads data from the input buffer and sends it directly to the history buffer. +At the same time, it sends requests to the hash table to check for available +matches. If a match occurs, it reads the history buffer to determine how many +symbols following the match are repeating. If enough symbols repeat, it writes +the sequence description to the sequence buffer. +If the symbol does not repeat, it is written to the literals buffer. + +Literals are stored as-is. Sequences are encoded using the number of literals +that need to be copied from the last repetition, the match offset, and +the match length, each taking 16 bits. + +### Hash Table + +A simple hash table is used for fast lookup of repeating symbols in +the input data buffer. This table is implemented as RAM, where the address +serves as the key, and the data stored at that address represents the value. + +For compression, a set of symbols is hashed to generate a key using Knuth’s +multiplicative hashing, with `0x1e35a7bd` used as the constant: + +``` +hash = (value * CONSTANT) >> (32 - HASHBITS) +``` -This proc parses literals section headers to calculate block compression format, -Huffmman tree size (if applicable based on compression format), compressed and -regenerated sizes for literals. If compressed block format is -`Compressed_Literals_Block`, dispatcher reads Huffman tree header byte from -Huffman bitstream, and directs expected number of bytes to the Huffman tree -decoder. Following this step, the proc sends an appropriate number of bytes to -the literals decoder dispatcher. +The selected constant is a bijection for values in the range 0 to 2^32−1 and +has a good distribution of ones and zeros. `HASHBITS` should be adjusted so +that the hash uses the most well-mixed values. -After sending literals to literals decompression, it redirects the remaining -bytes to the sequence parsing stages. +The original symbols, together with their relative offset in the input buffer, +are stored as the value. The original symbols are used to check matches. -#### Command Constructor +### History Buffer -This stage takes literals length, offset length and copy length. When `literals -length` is greater than 0, it will send a request to the literals buffer to -obtain `literals length` literals and then send them to the history buffer. Then -based on the offset and copy length it either creates a match command using the -provided offset and match lengths, or uses repeated offset and updates the -repeated offset memory. Formed commands are sent to the Commands aggregator -(mux). +The History Buffer is used to track historical data. After a match is detected, +it is used to check how many symbols following the match are equal. +It can be implemented using a group of RAMs so that reads from arbitrary +offsets still return valid data. -#### Literals path architecture +The part related to managing multiple RAMs can be separated into a +`AlignedParallelRAM` proc. The `HistoryBuffer` can then be implemented on top of it. +The difference between these procs is that the HistoryBuffer refers to offsets +from its top (how many symbols back to read), instead of using absolute +addresses like the `AlignedParallelRAM` proc. -![data flow diagram of literals decoder](img/ZSTD_compressed_block_literals_decoder.png) +### RawMemcopy -##### Literals decoder dispatcher +The `RawMemcopy` block copies data from the input memory to the output memory +without any modification. It is used by `LiteralEncoder` when encoding RAW +literals. -This proc parses and consumes the literals section header. Based on the received -values it passes the remaining bytes to RAW/RLE/Huffman tree/Huffman code -decoders. It also controls the 4 stream operation mode [4-stream mode in -RFC](https://www.rfc-editor.org/rfc/rfc8878.html#name-jump_table). +### RleBlockEncoder -All packets sent to the Huffman bitstream buffer will be tagged either -`in_progress` or `finished`. If the compressed literals use the 4 streams -encoding, the dispatcher will send the `finished` tag 4 times, each time a fully -compressed stream is sent to the bitstream buffer. +The `RleBlockEncoder` encodes RLE literals. It first uses a simple heuristic to +check whether a block can be RLE-encoded. This is done by sampling the block at +uniform positions and checking whether all samples have the same value. If they +differ, the block is rejected early. If the samples match, the block is fully +checked. When encoding is possible, the encoder outputs a symbol and the number +of times it appears in the input stream. -##### RAW Literals +### SequenceEncoder -This stage simply passes the incoming bytes as literals to the literals buffer. +The `SequenceEncoder` encodes sequences stored in the sequence buffer using FSE +coding. It uses predefined FSE tables for the encoding process. -##### RLE Literals +### AlignedParallelRam -This stage works similarly to the [RLE stage](#rleblockdecoder) for RLE data -blocks. +The `AlignedParallelRam` proc combines eight RAMs, one per byte, to allow reading +and writing each byte of a 64-bit wide memory in a single cycle. It is used by +the `HistoryBuffer`. -##### Huffman bitstream buffer +### CompressBlockEncoder -This stage takes data from the literals decoder dispatcher and stores it in the -buffer memory. Once the data with the `finished` tag set is received, this stage -sends a tuple containing (start, end) positions for the current bitstream to the -Huffman codes decoder. This stage receives a response from the Huffman codes -decoder when decoding is done and all bits got processed. Upon receiving this -message, the buffer will reclaim free space. +The `CompressBlockEncoder` uses the `LiteralsEncoder` and the +`SequenceEncoder` to produce +[compressed blocks](https://datatracker.ietf.org/doc/html/rfc8878#name-compressed-blocks) +from the input data. -##### Huffman codes decoder +### MemReaderMux / MemWriterMux -This stage receives bitstream pointers from the Huffman bitstream buffer and -Huffman tree configuration from the Huffman tree builder. It accesses the -bitstream buffers memory to retrieve bitstream data in reversed byte order and -runs it through an array of comparators to decode Huffman code to correct -literals values. +These procs allow multiple procs to share a single `MemReader` or `MemWriter`. +They do this by multiplexing several input interfaces into one `MemReader` or +`MemWriter` proc. -##### Literals buffer +### MemReaderSimpleArbiter / MemWriterSimpleArbiter -This stage receives data either from RAW, RLE or Huffman decoder and stores it. -Upon receiving the literals copy command from the Command Constructor for `N` -number of bytes, it provides a reply with `N` literals. +These procs implement a simple round-robin arbiter. They control the +`MemReaderMux` and `MemWriterMux` so that access to the `MemReader` and +`MemWriter` interfaces is granted automatically. -#### FSE Huffman decoder architecture +### LiteralSectionHeaderWriter -![data flow diagram of weight decoders](img/ZSTD_compressed_block_Huffman_decoder.png) +The `LiteralSectionHeaderWriter` creates the +[literals section header](https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.3.1) +and writes it to memory -##### Huffman tree decoder dispatcher -This stage parses and consumes the Huffman tree description header. Based on the -value of the Huffman descriptor header, it passes the tree description to the -FSE decoder or to direct weight extraction. +### SequenceConfEncoder -##### FSE weight decoder +The `SequenceConfEncoder` creates the +[sequence section header](https://datatracker.ietf.org/doc/html/rfc8878#name-sequences_section_header) +and writes it to memory. -This stage performs multiple functions. +## Tests -1. It decodes and builds the FSE distribution table. -2. It stores all remaining bitstream data. -3. After receiving the last byte, it translates the bitstream to Huffman - weights using 2 interleaved FSE streams. +Testing of the ZSTD encoder is carried out on two levels: -##### Direct weight decoder +* Encoder components +* Integrated encoder -This stage takes the incoming bytes and translates them to the stream of Huffman -tree weights. The first byte of the transfer defines the number of symbols to be -decoded. +Each component of the encoder is tested individually using DSLX tests. +Testing at the DSLX level allows the creation of small test cases that check +the correct behavior of a given part of the design. -##### Weight aggregator +When needed, these test cases can be modified by the user to better understand +how the component operates. -This stage receives tree weights either from the FSE decoder or the direct -decoder and transfers them to Huffman tree builder. This stage also resolves the -number of bits of the final weight and the max number of bits required in the -tree representation. This stage will emit the weights and number of symbols of -the same weight before the current symbol for all possible byte values. +Tests of the integrated ZSTD encoder are carried out at the DSLX and +Verilog levels. The objective is to verify the functionality of +the encoder as a whole. -##### Huffman tree builder +- DSLX-level tests use hardcoded input and output. +- Verilog-level tests feed random input to the simulated encoder, + decompress its output using a reference implementation, and compare + the result against the input. -This stage takes `max_number_of_bits` (maximal length of Huffman code) as the -first value, then the number of symbols with lower weight for each possible -weight (11 bytes), followed by a tuple (number of preceding symbols with the -same weight, symbol's_weight). It's expected to receive weights for all possible -byte values in the correct order. Based on this information, this stage will -configure the Huffman codes decoder. +The basic test case for the ZstdEncoder is composed of the following steps: -#### Sequence path architecture +1. The testbench generates random input data. +2. Input data is placed in an AXI RAM model connected to the encoder’s memory + interface. +3. The testbench waits for the encoder response and forwards the encoder output + stored in memory to a reference decoder implementation. +4. The result is compared against the input data. -![data flow diagram of sequence decoder](img/ZSTD_compressed_block_sequence_decoder.png) +### Verilog Tests Details -##### Sequence Header parser and dispatcher +Verilog tests are written in Python using a +[cocotb](https://github.com/cocotb/cocotb) testbench. -This stage parses and consumes `Sequences_Section_Header`. Based on the parsed -data, it redirects FSE description to the FSE table decoder and triggers -Literals FSE, Offset FSE or Match FSE decoder to reconfigure its values based on -the FSE table decoder. After parsing the FSE tables, this stage buffers -bitstream and starts sending bytes, starting from the last one received as per -ZSTD format. Bytes are sent to all decoders at the same time. This stage -monitors and triggers sequence decoding phases starting from initialization, -followed by decode and state advance. FSE decoders send each other the number of -bits they read. +ZstdEncoder’s main communication interfaces are AXI buses. Due to the way +XLS handles code generation of DSLX channels that model AXI channels, +the generated ports do not correctly represent AXI signals. +This requires the use of a [Verilog wrapper](rtl/zstd_enc_wrapper.v) +that maps the generated ports to proper AXI ports +(see the AXI peripherals [README](memory/README.md) for more information). -##### Literals FSE decoder +The cocotb testbench interacts with the encoder using +the [cocotbext-axi](https://github.com/alexforencich/cocotbext-axi) +extension, which provides AXI bus models, drivers, monitors, +and an AXI-accessible RAM model. A cocotb AXI Master is connected to +the encoder’s CSR interface and is used to simulate software interaction +with the encoder. -This stage reconfigures its FSE table when triggered from [sequence header parse -and dispatcher](#sequence-header-parser-and-dispatcher). It initializes its -state as the first FSE decoder. In the decode phase, this stage is the last one -to decode extra raw bits from the bitstream, and the number of ingested bits is -transmitted to all other decoders. This stage is the first stage to get a new -FSE state from the bitstream, and it transmits the number of bits it used. +## Limitations -##### Offset FSE decoder +Not all heuristics used in the reference software implementation are feasible +in hardware. As a result, the hardware implementation may produce worse +compression in some cases. -This stage reconfigures its FSE table when triggered from [sequence header parse -and dispatcher](#sequence-header-parser-and-dispatcher). It initializes its -state as the second FSE decoder. In the decode phase, this stage is the first -one to decode extra raw bits from bitstream, and the number of ingested bits is -transmitted to all other decoders. This stage is the last decoder to update its -FSE state after the decode phase, and it transmits the number of used bits to -other decoders. - -##### Match FSE decoder - -This stage reconfigures its FSE table when triggered from [sequence header parse -and dispatcher](#sequence-header-parser-and-dispatcher). It initializes its -state as the last FSE decoder. In the decode phase, this stage is the second one -to decode extra raw bits from the bitstream, and the number of ingested bits is -transmitted to all other decoders. This stage is the second stage to update its -state after the decode phase, and the number of used bits is sent to all other -decoders. - -## Testing methodology - -Testing of the `ZSTD decoder` is carried out on two levels: - -* Decoder components -* Integrated decoder - -Each component of the decoder is tested individually in DSLX tests. Testing on -the DSLX level allows the creation of small test cases that test for positive -outcomes of a given part of the design. When need be, those test cases can be -also modified by the user to better understand how the component operates. - -Tests of the integrated ZSTD decoder are carried out on DSLX and Verilog levels. -The objective of those is to verify the functionality of the decoder as a whole. -Testing setup for the ZSTD decoder is based on comparing the simulated decoding -results against the decoding of the reference library. Currently, due to the -restrictions from the ZSTD frame generator, it is possible to test only the -positive cases (decoding valid ZSTD frames). - -ZstdDecoder's main communication interfaces are the AXI buses. Due to the way -XLS handles the codegen of DSLX channels that model the AXI channels, the -particular ports of the AXI channels are not represented correctly. This -enforces the introduction of a Verilog wrapper that maps the ports generated by -XLS into proper AXI ports (see AXI peripherals [README](memory/README.md) for -more information). Additionally, the wrapper is used to mux multiple AXI -interfaces from `Memory Readers` and `Memory Writer` into a single -outside-facing AXI interface (`Memory Interface`) that can be connected to the -external memory. The mux is implemented by a third-party [AXI -Crossbar](https://github.com/alexforencich/verilog-axi). - -![diagram of interfaces of decoder and its wrapper](img/ZSTD_decoder_wrapper.png) - -### Failure points - -#### User-facing decoder errors - -The design will fail the tests under the following conditions: - -* Straightforward failures: - * Top Level State Machine transitions to `ERROR` state - * Simulation encounters `assert!()` or `fail!()` statements - * The decoding result from the simulation has a different size than the - results from the reference library - * The decoding result from the simulation has different contents than the - results from the reference library - -Currently, all mentioned conditions lead to an eventual test failure. - -#### Failures in ZSTD Decoder components - -It is important to note that some of the errors (e.g. errors in magic number or -frame header decoding) are easy to trigger in the integration test cases by -manual modification of the generated ZSTD frames. However, the majority of the -errors require modification of the deeper parts of the raw ZSTD frame which is -significantly harder. Because of that, it is better to rely on DSLX tests for -the individual components where inputs for the test cases are smaller, easier to -understand and modify when needed. - -The components of the ZSTD decoder can fail on `assert!()` and `fail!()` -statements or propagate specific error states to the Top Level Proc and cause it -to transition to the `ERROR` state. Upon entering the `ERROR` state, the decoder -will write a specific error code to the `Status` CSR and send a `Notify` signal -to the output. The interacting software can then read the code from the register -and properly handle the error. - -The following enumeration will describe how to trigger each possible ZSTD -Decoder error. - -The `ERROR` state can be encountered under the following conditions when running -Top Level Proc Verilog tests but also in DSLX tests for the specific components: - -* Corrupted data on the frame header decoding stage - * Provide data for the decoding with the first 4 bytes not being the valid -`Magic Number` (0xFD2FB528) - * Set the `Reserved bit` in the frame header descriptor - * Set `Window Size` in frame header to value greater than `max window size` -calculated from current `WINDOW_LOG_MAX` (by default in Top Level Proc tests -`Window Size` must be greater than `0x78000000` to trigger the error) -* Corrupted data during Block Header decoding - * Set the `Block Type` of any block in the ZSTD frame to `RESERVED` - -The `assert!()` or `fail!()` will occur in: - -* RawBlockDecoder - * Receive `BlockDataPacket` with `ID` different than the previous packet - which did not have the `last` flag set -* DecoderMux - * At the beginning of the simulation or after receiving - `ExtendedBlockDataPacket` with `last` and `last_block` (decoding new - ZSTD frame) set receive on channels `raw_r`, `rle_r` and `cmp_r` - `ExtendedBlockDataPackets` without any of those having `ID==0` - * Receive `ExtendedBlockDataPacket` with a smaller `ID` than any of the - previously processed packets during the current ZSTD frame decoding -* SequenceExecutor - * Receive `SequenceExecutorPacket` with `msg_type==SEQUENCE` and `content` - field with value: `0` - -There are also several `impossible cases` covered by `fail!()`. -Those are mostly enforced by the type checker for the `match` expressions to -cover unreachable cases. -This is done for example in: - -* Frame header decoder -* SequenceExecutor +As of the current version of the encoder: +- The top module produces uncompressed output, but it is packed in proper + ZSTD control structures. +- Procs strictly related to compression, such as the Match Finder, are not yet + integrated into the encoding flow. diff --git a/xls/modules/zstd/aligned_parallel_ram.x b/xls/modules/zstd/aligned_parallel_ram.x new file mode 100644 index 0000000000..c2172a052d --- /dev/null +++ b/xls/modules/zstd/aligned_parallel_ram.x @@ -0,0 +1,988 @@ +// Copyright 2024 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 contains implementation of parallel RAMs with aligned access +// write requests' address should be a multiple of data width +// read requests` address dont have to be a multiple of data width + + +import std; +import xls.modules.zstd.common as common; +import xls.examples.ram; + +// Configurable RAM parameters, RAM_NUM has to be a power of 2 +pub const RAM_NUM = u32:8; +pub const RAM_NUM_W = std::clog2(RAM_NUM); + +pub struct AlignedParallelRamReadReq { + addr: uN[ADDR_W], +} + +pub struct AlignedParallelRamReadResp { + data: uN[DATA_W], +} + +pub struct AlignedParallelRamWriteReq { + addr: uN[ADDR_W], + data: uN[DATA_W], +} + +pub struct AlignedParallelRamWriteResp {} + +enum AlignedParallelRamReadRespHandlerFSM : u1 { + IDLE = 0, + READ_RESP = 1, +} + +struct AlignedParallelRamReadRespHandlerState { + fsm: AlignedParallelRamReadRespHandlerFSM, + ram_offset: uN[RAM_NUM_W], + resp_recv: bool[RAM_NUM], + resp_data: uN[RAM_DATA_W][RAM_NUM], +} + +struct AlignedParallelRamReadRespHandlerCtrl { + ram_offset: uN[RAM_NUM_W], +} + +proc AlignedParallelRamReadRespHandler< + DATA_W: u32, + RAM_DATA_W: u32 = {DATA_W / RAM_NUM}, +> { + type ReadResp = AlignedParallelRamReadResp; + type RamReadResp = ram::ReadResp; + + type FSM = AlignedParallelRamReadRespHandlerFSM; + type Ctrl = AlignedParallelRamReadRespHandlerCtrl; + type State = AlignedParallelRamReadRespHandlerState; + + ctrl_r: chan in; + + read_resp_s: chan out; + + ram_read_resp_0_r: chan in; + ram_read_resp_1_r: chan in; + ram_read_resp_2_r: chan in; + ram_read_resp_3_r: chan in; + ram_read_resp_4_r: chan in; + ram_read_resp_5_r: chan in; + ram_read_resp_6_r: chan in; + ram_read_resp_7_r: chan in; + + config ( + ctrl_r: chan in, + read_resp_s: chan out, + ram_read_resp_0_r: chan in, + ram_read_resp_1_r: chan in, + ram_read_resp_2_r: chan in, + ram_read_resp_3_r: chan in, + ram_read_resp_4_r: chan in, + ram_read_resp_5_r: chan in, + ram_read_resp_6_r: chan in, + ram_read_resp_7_r: chan in, + ) { + ( + ctrl_r, + read_resp_s, + ram_read_resp_0_r, + ram_read_resp_1_r, + ram_read_resp_2_r, + ram_read_resp_3_r, + ram_read_resp_4_r, + ram_read_resp_5_r, + ram_read_resp_6_r, + ram_read_resp_7_r, + ) + } + + init { zero!() } + + next (state: State) { + // receive ctrl + let (_, ctrl, ctrl_valid) = recv_if_non_blocking(join(), ctrl_r, state.fsm == FSM::IDLE, zero!()); + + let state = if ctrl_valid { + State { + fsm: FSM::READ_RESP, + ram_offset: ctrl.ram_offset, + ..state + } + } else { + state + }; + + // receive response from each RAM + let (_, ram_read_resp_0, ram_read_resp_0_valid) = recv_if_non_blocking( + join(), ram_read_resp_0_r, !state.resp_recv[u32:0] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_1, ram_read_resp_1_valid) = recv_if_non_blocking( + join(), ram_read_resp_1_r, !state.resp_recv[u32:1] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_2, ram_read_resp_2_valid) = recv_if_non_blocking( + join(), ram_read_resp_2_r, !state.resp_recv[u32:2] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_3, ram_read_resp_3_valid) = recv_if_non_blocking( + join(), ram_read_resp_3_r, !state.resp_recv[u32:3] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_4, ram_read_resp_4_valid) = recv_if_non_blocking( + join(), ram_read_resp_4_r, !state.resp_recv[u32:4] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_5, ram_read_resp_5_valid) = recv_if_non_blocking( + join(), ram_read_resp_5_r, !state.resp_recv[u32:5] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_6, ram_read_resp_6_valid) = recv_if_non_blocking( + join(), ram_read_resp_6_r, !state.resp_recv[u32:6] && state.fsm == FSM::READ_RESP, zero!() + ); + let (_, ram_read_resp_7, ram_read_resp_7_valid) = recv_if_non_blocking( + join(), ram_read_resp_7_r, !state.resp_recv[u32:7] && state.fsm == FSM::READ_RESP, zero!() + ); + + let ram_read_resp_valid = [ + ram_read_resp_0_valid, + ram_read_resp_1_valid, + ram_read_resp_2_valid, + ram_read_resp_3_valid, + ram_read_resp_4_valid, + ram_read_resp_5_valid, + ram_read_resp_6_valid, + ram_read_resp_7_valid, + ]; + + let ram_read_resp = [ + ram_read_resp_0, + ram_read_resp_1, + ram_read_resp_2, + ram_read_resp_3, + ram_read_resp_4, + ram_read_resp_5, + ram_read_resp_6, + ram_read_resp_7, + ]; + + let state = for (i, state) in u32:0..RAM_NUM { + if ram_read_resp_valid[i] { + State { + resp_recv: update(state.resp_recv, i, true), + resp_data: update(state.resp_data, i, ram_read_resp[i].data), + ..state + } + } else { + state + } + }(state); + + // check if all data is received + let all_received = for (i, all_received) in u32:0..RAM_NUM { + all_received & state.resp_recv[i] + }(true); + + // concatenate data + let concat_data = ( + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:7] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:6] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:5] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:4] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:3] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:2] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:1] ++ + state.resp_data[state.ram_offset + uN[RAM_NUM_W]:0] + ); + + // send response + send_if(join(), read_resp_s, all_received, ReadResp { + data: concat_data + }); + + // reset state + let state = if all_received { + zero!() + } else { + state + }; + + state + } +} + +struct AlignedParallelRamWriteRespHandlerState { + resp_recv: bool[RAM_NUM], +} + +proc AlignedParallelRamWriteRespHandler { + type WriteResp = AlignedParallelRamWriteResp; + type RamWriteResp = ram::WriteResp; + + type State = AlignedParallelRamWriteRespHandlerState; + + write_resp_s: chan out; + + ram_write_resp_0_r: chan in; + ram_write_resp_1_r: chan in; + ram_write_resp_2_r: chan in; + ram_write_resp_3_r: chan in; + ram_write_resp_4_r: chan in; + ram_write_resp_5_r: chan in; + ram_write_resp_6_r: chan in; + ram_write_resp_7_r: chan in; + + config ( + write_resp_s: chan out, + ram_write_resp_0_r: chan in, + ram_write_resp_1_r: chan in, + ram_write_resp_2_r: chan in, + ram_write_resp_3_r: chan in, + ram_write_resp_4_r: chan in, + ram_write_resp_5_r: chan in, + ram_write_resp_6_r: chan in, + ram_write_resp_7_r: chan in, + ) { + ( + write_resp_s, + ram_write_resp_0_r, + ram_write_resp_1_r, + ram_write_resp_2_r, + ram_write_resp_3_r, + ram_write_resp_4_r, + ram_write_resp_5_r, + ram_write_resp_6_r, + ram_write_resp_7_r, + ) + } + + init { zero!() } + + next (state: State) { + // receive response from each RAM + let (_, _, ram_read_resp_0_valid) = recv_if_non_blocking( + join(), ram_write_resp_0_r, !state.resp_recv[u32:0], zero!() + ); + let (_, _, ram_read_resp_1_valid) = recv_if_non_blocking( + join(), ram_write_resp_1_r, !state.resp_recv[u32:1], zero!() + ); + let (_, _, ram_read_resp_2_valid) = recv_if_non_blocking( + join(), ram_write_resp_2_r, !state.resp_recv[u32:2], zero!() + ); + let (_, _, ram_read_resp_3_valid) = recv_if_non_blocking( + join(), ram_write_resp_3_r, !state.resp_recv[u32:3], zero!() + ); + let (_, _, ram_read_resp_4_valid) = recv_if_non_blocking( + join(), ram_write_resp_4_r, !state.resp_recv[u32:4], zero!() + ); + let (_, _, ram_read_resp_5_valid) = recv_if_non_blocking( + join(), ram_write_resp_5_r, !state.resp_recv[u32:5], zero!() + ); + let (_, _, ram_read_resp_6_valid) = recv_if_non_blocking( + join(), ram_write_resp_6_r, !state.resp_recv[u32:6], zero!() + ); + let (_, _, ram_read_resp_7_valid) = recv_if_non_blocking( + join(), ram_write_resp_7_r, !state.resp_recv[u32:7], zero!() + ); + + let ram_read_resp_valid = [ + ram_read_resp_0_valid, + ram_read_resp_1_valid, + ram_read_resp_2_valid, + ram_read_resp_3_valid, + ram_read_resp_4_valid, + ram_read_resp_5_valid, + ram_read_resp_6_valid, + ram_read_resp_7_valid, + ]; + + let state = for (i, state) in u32:0..RAM_NUM { + if ram_read_resp_valid[i] { + State { + resp_recv: update(state.resp_recv, i, true), + } + } else { + state + } + }(state); + + // check if all data is received + let all_received = for (i, all_received) in u32:0..RAM_NUM { + all_received & state.resp_recv[i] + }(true); + + // send response + send_if(join(), write_resp_s, all_received, WriteResp {}); + + // reset state + let state = if all_received { + zero!() + } else { + state + }; + + state + } + +} + + +pub proc AlignedParallelRam< + SIZE: u32, + DATA_W: u32, + ADDR_W: u32 = {std::clog2(SIZE)}, + RAM_SIZE: u32 = {SIZE / RAM_NUM}, + RAM_DATA_W: u32 = {DATA_W / RAM_NUM}, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + RAM_PARTITION_SIZE: u32 = {RAM_DATA_W}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_PARTITION_SIZE, RAM_DATA_W)}, +> { + type ReadReq = AlignedParallelRamReadReq; + type ReadResp = AlignedParallelRamReadResp; + type WriteReq = AlignedParallelRamWriteReq; + type WriteResp = AlignedParallelRamWriteResp; + + type RamReadReq = ram::ReadReq; + type RamReadResp = ram::ReadResp; + type RamWriteReq = ram::WriteReq; + type RamWriteResp = ram::WriteResp; + + read_req_r: chan in; + write_req_r: chan in; + + read_resp_handler_ctrl_s: chan out; + + // RAMs read interfaces + ram_read_req_0_s: chan out; + ram_read_req_1_s: chan out; + ram_read_req_2_s: chan out; + ram_read_req_3_s: chan out; + ram_read_req_4_s: chan out; + ram_read_req_5_s: chan out; + ram_read_req_6_s: chan out; + ram_read_req_7_s: chan out; + + // RAMs write interfaces + ram_write_req_0_s: chan out; + ram_write_req_1_s: chan out; + ram_write_req_2_s: chan out; + ram_write_req_3_s: chan out; + ram_write_req_4_s: chan out; + ram_write_req_5_s: chan out; + ram_write_req_6_s: chan out; + ram_write_req_7_s: chan out; + + config ( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan[RAM_NUM] out, + ram_read_resp_r: chan[RAM_NUM] in, + ram_write_req_s: chan[RAM_NUM] out, + ram_write_resp_r: chan[RAM_NUM] in, + ) { + let (read_resp_handler_ctrl_s, read_resp_handler_ctrl_r) = + chan("read_resp_handler_ctrl"); + + spawn AlignedParallelRamReadRespHandler( + read_resp_handler_ctrl_r, + read_resp_s, + ram_read_resp_r[0], + ram_read_resp_r[1], + ram_read_resp_r[2], + ram_read_resp_r[3], + ram_read_resp_r[4], + ram_read_resp_r[5], + ram_read_resp_r[6], + ram_read_resp_r[7], + ); + + spawn AlignedParallelRamWriteRespHandler ( + write_resp_s, + ram_write_resp_r[0], + ram_write_resp_r[1], + ram_write_resp_r[2], + ram_write_resp_r[3], + ram_write_resp_r[4], + ram_write_resp_r[5], + ram_write_resp_r[6], + ram_write_resp_r[7], + ); + + ( + read_req_r, + write_req_r, + read_resp_handler_ctrl_s, + ram_read_req_s[0], + ram_read_req_s[1], + ram_read_req_s[2], + ram_read_req_s[3], + ram_read_req_s[4], + ram_read_req_s[5], + ram_read_req_s[6], + ram_read_req_s[7], + ram_write_req_s[0], + ram_write_req_s[1], + ram_write_req_s[2], + ram_write_req_s[3], + ram_write_req_s[4], + ram_write_req_s[5], + ram_write_req_s[6], + ram_write_req_s[7], + ) + } + + init { } + + next (state: ()) { + // handle read request + let (tok_read, read_req, read_req_valid) = recv_non_blocking(join(), read_req_r, zero!()); + + // send ctrl to read resp hanlder + let read_resp_handler_ctrl = AlignedParallelRamReadRespHandlerCtrl { + ram_offset: read_req.addr as uN[RAM_NUM_W], + }; + send_if(tok_read, read_resp_handler_ctrl_s, read_req_valid, read_resp_handler_ctrl); + + // send requests to each RAM + let ram_read_req = for (i, ram_read_req) in u32:0..RAM_NUM { + let offset = if read_req.addr as uN[RAM_NUM_W] > i as uN[RAM_NUM_W] { + uN[RAM_ADDR_W]:1 + } else { + uN[RAM_ADDR_W]:0 + }; + update(ram_read_req, i, RamReadReq { + addr: (read_req.addr >> std::clog2(RAM_NUM)) as uN[RAM_ADDR_W] + offset, + mask: !uN[RAM_NUM_PARTITIONS]:0, + }) + }(zero!()); + send_if(tok_read, ram_read_req_0_s, read_req_valid, ram_read_req[0]); + send_if(tok_read, ram_read_req_1_s, read_req_valid, ram_read_req[1]); + send_if(tok_read, ram_read_req_2_s, read_req_valid, ram_read_req[2]); + send_if(tok_read, ram_read_req_3_s, read_req_valid, ram_read_req[3]); + send_if(tok_read, ram_read_req_4_s, read_req_valid, ram_read_req[4]); + send_if(tok_read, ram_read_req_5_s, read_req_valid, ram_read_req[5]); + send_if(tok_read, ram_read_req_6_s, read_req_valid, ram_read_req[6]); + send_if(tok_read, ram_read_req_7_s, read_req_valid, ram_read_req[7]); + + // handle write request + let (tok_write, write_req, write_req_valid) = recv_non_blocking(join(), write_req_r, zero!()); + + // send requests to each RAM + let ram_write_req = for (i, ram_write_req) in u32:0..RAM_NUM { + update(ram_write_req, i, RamWriteReq { + addr: (write_req.addr >> std::clog2(RAM_NUM)) as uN[RAM_ADDR_W], + data: (write_req.data >> (RAM_DATA_W * i)) as uN[RAM_DATA_W], + mask: !uN[RAM_NUM_PARTITIONS]:0, + }) + }(zero!()); + send_if(tok_read, ram_write_req_0_s, write_req_valid, ram_write_req[0]); + send_if(tok_read, ram_write_req_1_s, write_req_valid, ram_write_req[1]); + send_if(tok_read, ram_write_req_2_s, write_req_valid, ram_write_req[2]); + send_if(tok_read, ram_write_req_3_s, write_req_valid, ram_write_req[3]); + send_if(tok_read, ram_write_req_4_s, write_req_valid, ram_write_req[4]); + send_if(tok_read, ram_write_req_5_s, write_req_valid, ram_write_req[5]); + send_if(tok_read, ram_write_req_6_s, write_req_valid, ram_write_req[6]); + send_if(tok_read, ram_write_req_7_s, write_req_valid, ram_write_req[7]); + } +} + + +const INST_SIZE = u32:1024; +const INST_DATA_W = u32:64; +const INST_ADDR_W = std::clog2(INST_SIZE); +const INST_RAM_SIZE = INST_SIZE / RAM_NUM; +const INST_RAM_DATA_W = {INST_DATA_W / RAM_NUM}; +const INST_RAM_ADDR_W = {std::clog2(INST_RAM_SIZE)}; +const INST_RAM_PARTITION_SIZE = {INST_RAM_DATA_W}; +const INST_RAM_NUM_PARTITIONS = {ram::num_partitions(INST_RAM_PARTITION_SIZE, INST_RAM_DATA_W)}; + +proc AlignedParallelRamInst { + type InstReadReq = AlignedParallelRamReadReq; + type InstReadResp = AlignedParallelRamReadResp; + type InstWriteReq = AlignedParallelRamWriteReq; + type InstWriteResp = AlignedParallelRamWriteResp; + + type InstRamReadReq = ram::ReadReq; + type InstRamReadResp = ram::ReadResp; + type InstRamWriteReq = ram::WriteReq; + type InstRamWriteResp = ram::WriteResp; + + config ( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan[RAM_NUM] out, + ram_read_resp_r: chan[RAM_NUM] in, + ram_write_req_s: chan[RAM_NUM] out, + ram_write_resp_r: chan[RAM_NUM] in, + ) { + spawn AlignedParallelRam( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + } + + init { } + + next (state: ()) { } +} + + +const TEST_SIZE = u32:1024; +const TEST_DATA_W = u32:64; +const TEST_ADDR_W = std::clog2(TEST_SIZE); +const TEST_RAM_SIZE = TEST_SIZE / RAM_NUM; +const TEST_RAM_DATA_W = {TEST_DATA_W / RAM_NUM}; +const TEST_RAM_ADDR_W = {std::clog2(TEST_RAM_SIZE)}; +const TEST_RAM_PARTITION_SIZE = {TEST_RAM_DATA_W}; +const TEST_RAM_NUM_PARTITIONS = {ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W)}; + +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; + +type TestReadReq = AlignedParallelRamReadReq; +type TestReadResp = AlignedParallelRamReadResp; +type TestWriteReq = AlignedParallelRamWriteReq; +type TestWriteResp = AlignedParallelRamWriteResp; + +type TestRamReadReq = ram::ReadReq; +type TestRamReadResp = ram::ReadResp; +type TestRamWriteReq = ram::WriteReq; +type TestRamWriteResp = ram::WriteResp; + +struct TestData { + addr: uN[TEST_ADDR_W], + data: uN[TEST_DATA_W], +} + +const TEST_DATA = TestData[64]:[ + TestData {addr: uN[TEST_ADDR_W]:0x0c8, data: uN[TEST_DATA_W]:0x698dbd57f739d8ce}, + TestData {addr: uN[TEST_ADDR_W]:0x248, data: uN[TEST_DATA_W]:0x4cf6fc9b695676ad}, + TestData {addr: uN[TEST_ADDR_W]:0x3a0, data: uN[TEST_DATA_W]:0x5da52c3bd7b39603}, + TestData {addr: uN[TEST_ADDR_W]:0x208, data: uN[TEST_DATA_W]:0x5afa80c1c45a5bd2}, + TestData {addr: uN[TEST_ADDR_W]:0x068, data: uN[TEST_DATA_W]:0x27befcb367237e3f}, + TestData {addr: uN[TEST_ADDR_W]:0x358, data: uN[TEST_DATA_W]:0xa477d4887cec7fc2}, + TestData {addr: uN[TEST_ADDR_W]:0x328, data: uN[TEST_DATA_W]:0x38ecf19cf314ba5c}, + TestData {addr: uN[TEST_ADDR_W]:0x258, data: uN[TEST_DATA_W]:0x97a504cfa39e6750}, + TestData {addr: uN[TEST_ADDR_W]:0x1b8, data: uN[TEST_DATA_W]:0x2fa75c1effecf687}, + TestData {addr: uN[TEST_ADDR_W]:0x2e8, data: uN[TEST_DATA_W]:0xb1315d70b63629d8}, + TestData {addr: uN[TEST_ADDR_W]:0x2f0, data: uN[TEST_DATA_W]:0x44c025ebee513c44}, + TestData {addr: uN[TEST_ADDR_W]:0x250, data: uN[TEST_DATA_W]:0x295250fa0d795902}, + TestData {addr: uN[TEST_ADDR_W]:0x2a0, data: uN[TEST_DATA_W]:0x1f76bb3cf745235e}, + TestData {addr: uN[TEST_ADDR_W]:0x168, data: uN[TEST_DATA_W]:0x0d06b1d161037460}, + TestData {addr: uN[TEST_ADDR_W]:0x010, data: uN[TEST_DATA_W]:0x0c7b320db86382df}, + TestData {addr: uN[TEST_ADDR_W]:0x178, data: uN[TEST_DATA_W]:0x547e5874fdae8c09}, + TestData {addr: uN[TEST_ADDR_W]:0x0f8, data: uN[TEST_DATA_W]:0xc75ca52d83d65bba}, + TestData {addr: uN[TEST_ADDR_W]:0x0d0, data: uN[TEST_DATA_W]:0x3c10031e89ac070a}, + TestData {addr: uN[TEST_ADDR_W]:0x3f8, data: uN[TEST_DATA_W]:0xe881ce7c3e4515b4}, + TestData {addr: uN[TEST_ADDR_W]:0x378, data: uN[TEST_DATA_W]:0xa10c92b84419eb3d}, + TestData {addr: uN[TEST_ADDR_W]:0x018, data: uN[TEST_DATA_W]:0x7b9537f92c4958e0}, + TestData {addr: uN[TEST_ADDR_W]:0x350, data: uN[TEST_DATA_W]:0x38a1a5e8a7206e81}, + TestData {addr: uN[TEST_ADDR_W]:0x030, data: uN[TEST_DATA_W]:0xda2cf6b0b380862c}, + TestData {addr: uN[TEST_ADDR_W]:0x248, data: uN[TEST_DATA_W]:0xa56492b3fb19c8b8}, + TestData {addr: uN[TEST_ADDR_W]:0x258, data: uN[TEST_DATA_W]:0x9cbfccbf72c7948b}, + TestData {addr: uN[TEST_ADDR_W]:0x008, data: uN[TEST_DATA_W]:0x7fb6d361a608db56}, + TestData {addr: uN[TEST_ADDR_W]:0x108, data: uN[TEST_DATA_W]:0xba2aef614c7c5c1e}, + TestData {addr: uN[TEST_ADDR_W]:0x090, data: uN[TEST_DATA_W]:0xe7a5ab55633078fa}, + TestData {addr: uN[TEST_ADDR_W]:0x0c0, data: uN[TEST_DATA_W]:0xb5132e7e378f3f5b}, + TestData {addr: uN[TEST_ADDR_W]:0x198, data: uN[TEST_DATA_W]:0xeac9fe191bfd8b31}, + TestData {addr: uN[TEST_ADDR_W]:0x218, data: uN[TEST_DATA_W]:0x82ad45d959f8dbec}, + TestData {addr: uN[TEST_ADDR_W]:0x070, data: uN[TEST_DATA_W]:0x4d4e255058d00ccb}, + TestData {addr: uN[TEST_ADDR_W]:0x3a0, data: uN[TEST_DATA_W]:0x2a69306cf695b2f5}, + TestData {addr: uN[TEST_ADDR_W]:0x1e0, data: uN[TEST_DATA_W]:0x571a30f8cd940e39}, + TestData {addr: uN[TEST_ADDR_W]:0x300, data: uN[TEST_DATA_W]:0x7069a4c406076fd9}, + TestData {addr: uN[TEST_ADDR_W]:0x2a8, data: uN[TEST_DATA_W]:0x9af366c878230764}, + TestData {addr: uN[TEST_ADDR_W]:0x328, data: uN[TEST_DATA_W]:0x1e6bc1e2df3c8a7b}, + TestData {addr: uN[TEST_ADDR_W]:0x298, data: uN[TEST_DATA_W]:0x1ff9be4f810cd87a}, + TestData {addr: uN[TEST_ADDR_W]:0x250, data: uN[TEST_DATA_W]:0x9ad30cee350aebfa}, + TestData {addr: uN[TEST_ADDR_W]:0x090, data: uN[TEST_DATA_W]:0x31fca7f91dfcafb5}, + TestData {addr: uN[TEST_ADDR_W]:0x3b8, data: uN[TEST_DATA_W]:0xe434deef583c3cd1}, + TestData {addr: uN[TEST_ADDR_W]:0x3c0, data: uN[TEST_DATA_W]:0x4170c371a2025f27}, + TestData {addr: uN[TEST_ADDR_W]:0x0e8, data: uN[TEST_DATA_W]:0x616754a100d9decc}, + TestData {addr: uN[TEST_ADDR_W]:0x1f0, data: uN[TEST_DATA_W]:0x8d93fa35edab37b7}, + TestData {addr: uN[TEST_ADDR_W]:0x208, data: uN[TEST_DATA_W]:0x6582012a83ffcec3}, + TestData {addr: uN[TEST_ADDR_W]:0x3d0, data: uN[TEST_DATA_W]:0x6c66a69e87eac130}, + TestData {addr: uN[TEST_ADDR_W]:0x248, data: uN[TEST_DATA_W]:0xbfd5e4e261bbd7e3}, + TestData {addr: uN[TEST_ADDR_W]:0x058, data: uN[TEST_DATA_W]:0x2f8ba1fd6a8b6ee9}, + TestData {addr: uN[TEST_ADDR_W]:0x1a0, data: uN[TEST_DATA_W]:0xef9ab2936ef6833e}, + TestData {addr: uN[TEST_ADDR_W]:0x380, data: uN[TEST_DATA_W]:0x279130ba7b5ced6f}, + TestData {addr: uN[TEST_ADDR_W]:0x170, data: uN[TEST_DATA_W]:0xc1977f6a2153db09}, + TestData {addr: uN[TEST_ADDR_W]:0x3d8, data: uN[TEST_DATA_W]:0xd4ea85571e440cef}, + TestData {addr: uN[TEST_ADDR_W]:0x360, data: uN[TEST_DATA_W]:0x9bc5756ab3328603}, + TestData {addr: uN[TEST_ADDR_W]:0x2f8, data: uN[TEST_DATA_W]:0x14217d1804170f39}, + TestData {addr: uN[TEST_ADDR_W]:0x268, data: uN[TEST_DATA_W]:0x0098755165e9ae81}, + TestData {addr: uN[TEST_ADDR_W]:0x050, data: uN[TEST_DATA_W]:0x3ee0b48789cc94e0}, + TestData {addr: uN[TEST_ADDR_W]:0x398, data: uN[TEST_DATA_W]:0x9ff7fbc9906d3d63}, + TestData {addr: uN[TEST_ADDR_W]:0x068, data: uN[TEST_DATA_W]:0x507bc61f805b0e68}, + TestData {addr: uN[TEST_ADDR_W]:0x350, data: uN[TEST_DATA_W]:0x77802819dc14663a}, + TestData {addr: uN[TEST_ADDR_W]:0x168, data: uN[TEST_DATA_W]:0xd8ca0711ca37bfa9}, + TestData {addr: uN[TEST_ADDR_W]:0x068, data: uN[TEST_DATA_W]:0x30464e3d2630b6de}, + TestData {addr: uN[TEST_ADDR_W]:0x360, data: uN[TEST_DATA_W]:0xdbac58596c50f62f}, + TestData {addr: uN[TEST_ADDR_W]:0x2e0, data: uN[TEST_DATA_W]:0x9992cfd966824669}, + TestData {addr: uN[TEST_ADDR_W]:0x2e0, data: uN[TEST_DATA_W]:0x1a4a65b0257c223b}, +]; + +#[test_proc] +proc AlignedParallelRam_test_aligned_read { + terminator: chan out; + read_req_s: chan out; + read_resp_r: chan in; + write_req_s: chan out; + write_resp_r: chan in; + + config (terminator: chan out) { + let (read_req_s, read_req_r) = chan("read_req"); + let (read_resp_s, read_resp_r) = chan("read_resp"); + let (write_req_s, write_req_r) = chan("write_req"); + let (write_resp_s, write_resp_r) = chan("write_resp"); + + let (ram_read_req_s, ram_read_req_r) = chan[RAM_NUM]("ram_read_req"); + let (ram_read_resp_s, ram_read_resp_r) = chan[RAM_NUM]("ram_read_resp"); + let (ram_write_req_s, ram_write_req_r) = chan[RAM_NUM]("ram_write_req"); + let (ram_write_resp_s, ram_write_resp_r) = chan[RAM_NUM]("ram_write_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[0], ram_read_resp_s[0], ram_write_req_r[0], ram_write_resp_s[0], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[1], ram_read_resp_s[1], ram_write_req_r[1], ram_write_resp_s[1], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[2], ram_read_resp_s[2], ram_write_req_r[2], ram_write_resp_s[2], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[3], ram_read_resp_s[3], ram_write_req_r[3], ram_write_resp_s[3], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[4], ram_read_resp_s[4], ram_write_req_r[4], ram_write_resp_s[4], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[5], ram_read_resp_s[5], ram_write_req_r[5], ram_write_resp_s[5], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[6], ram_read_resp_s[6], ram_write_req_r[6], ram_write_resp_s[6], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[7], ram_read_resp_s[7], ram_write_req_r[7], ram_write_resp_s[7], + ); + + spawn AlignedParallelRam( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + + ( + terminator, + read_req_s, + read_resp_r, + write_req_s, + write_resp_r, + ) + } + + init { } + + next (state: ()) { + let tok = join(); + + let tok = for (i, tok):(u32, token) in u32:0..array_size(TEST_DATA) { + let test_data = TEST_DATA[i]; + + let write_req = TestWriteReq { + addr: test_data.addr, + data: test_data.data, + }; + let tok = send(tok, write_req_s, write_req); + trace_fmt!("Sent #{} write request {:#x}", i + u32:1, write_req); + + let (tok, write_resp) = recv(tok, write_resp_r); + trace_fmt!("Received #{} write response {:#x}", i + u32:1, write_resp); + + let read_req = TestReadReq { + addr: test_data.addr, + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{} read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{} read response {:#x}", i + u32:1, read_resp); + + assert_eq(test_data.data, read_resp.data); + + tok + }(tok); + + send(tok, terminator, true); + } +} + +const TEST_RAM_CONTENT = uN[TEST_DATA_W][64]:[ + uN[TEST_DATA_W]:0x2122337ed367496b, uN[TEST_DATA_W]:0x33de22e4291ecb66, + uN[TEST_DATA_W]:0x62052eccbde0009d, uN[TEST_DATA_W]:0xfa179c402e7b5f47, + uN[TEST_DATA_W]:0x118fa2c81d1230e9, uN[TEST_DATA_W]:0xe48ee076b41120c0, + uN[TEST_DATA_W]:0xa33d467d80575e5b, uN[TEST_DATA_W]:0x61213ebe00890570, + uN[TEST_DATA_W]:0xe9210eae2507442f, uN[TEST_DATA_W]:0x4b8c721627c19c44, + uN[TEST_DATA_W]:0x55e768d2e4586bba, uN[TEST_DATA_W]:0x2fc234017ac1deb5, + uN[TEST_DATA_W]:0xdc6afd5db30446aa, uN[TEST_DATA_W]:0xe91512402a2f68ab, + uN[TEST_DATA_W]:0x13fd96b93aef2c85, uN[TEST_DATA_W]:0x980b4054b9f66fc2, + uN[TEST_DATA_W]:0xa8bf09e77757ca28, uN[TEST_DATA_W]:0x94a67ff04004de7b, + uN[TEST_DATA_W]:0x6d1f3071a446b0c3, uN[TEST_DATA_W]:0x01605527a50fdecf, + uN[TEST_DATA_W]:0xd839258508c3efd1, uN[TEST_DATA_W]:0x1207a4d0de5c9724, + uN[TEST_DATA_W]:0xef39682f0810f43c, uN[TEST_DATA_W]:0x4781977bc26ce834, + uN[TEST_DATA_W]:0x0805a350ed25812f, uN[TEST_DATA_W]:0x8ad82cb67bf49cef, + uN[TEST_DATA_W]:0x2fd11ff78f85f169, uN[TEST_DATA_W]:0xd624be58457eab2a, + uN[TEST_DATA_W]:0x873e4be71afa1355, uN[TEST_DATA_W]:0x6e0e9f264151b531, + uN[TEST_DATA_W]:0xa69015c537b4da78, uN[TEST_DATA_W]:0x0879638aa8045ad9, + uN[TEST_DATA_W]:0x30dd170b7bf89cbf, uN[TEST_DATA_W]:0xcbfeb8219960a267, + uN[TEST_DATA_W]:0x9f6fcd2d4a4ba9f2, uN[TEST_DATA_W]:0xdf0ead33b3e55ac3, + uN[TEST_DATA_W]:0x64a24c19037f850b, uN[TEST_DATA_W]:0x4dcbb4de2d3aba5a, + uN[TEST_DATA_W]:0xa40749b2be1450b6, uN[TEST_DATA_W]:0x99bed65d2d28d1f6, + uN[TEST_DATA_W]:0xbe8d35f27bb892b4, uN[TEST_DATA_W]:0x23315a3a70110048, + uN[TEST_DATA_W]:0x68b0e22cb8885787, uN[TEST_DATA_W]:0xcac1a152d43dae98, + uN[TEST_DATA_W]:0x1fb5cec8c64ad46a, uN[TEST_DATA_W]:0xcbe25f0d2b21e9a1, + uN[TEST_DATA_W]:0x46e161fd5f490ae7, uN[TEST_DATA_W]:0xff2dd0e7a120d222, + uN[TEST_DATA_W]:0xa764165b6d09fb90, uN[TEST_DATA_W]:0xee4d9484b63f6a66, + uN[TEST_DATA_W]:0x204d6d789e9fe377, uN[TEST_DATA_W]:0x9ad53311a1a95bcf, + uN[TEST_DATA_W]:0x63d497f105d8661f, uN[TEST_DATA_W]:0x40e7a242cc26483c, + uN[TEST_DATA_W]:0x5a82a7265627cab1, uN[TEST_DATA_W]:0x42de42323222a24b, + uN[TEST_DATA_W]:0xdede8c218f3ef36a, uN[TEST_DATA_W]:0xec86b8e8734da0c7, + uN[TEST_DATA_W]:0x9b209d6959c36b79, uN[TEST_DATA_W]:0x829c158fd6678675, + uN[TEST_DATA_W]:0x5c59a4845b68a509, uN[TEST_DATA_W]:0xcc9e851a38b01d04, + uN[TEST_DATA_W]:0x5e15f41bd09acd33, uN[TEST_DATA_W]:0x953425686ce51623, +]; + +const TEST_READ_ADDR = uN[TEST_ADDR_W][128]:[ + uN[TEST_ADDR_W]:0x0d0, uN[TEST_ADDR_W]:0x01c, uN[TEST_ADDR_W]:0x094, uN[TEST_ADDR_W]:0x153, + uN[TEST_ADDR_W]:0x1cb, uN[TEST_ADDR_W]:0x14f, uN[TEST_ADDR_W]:0x021, uN[TEST_ADDR_W]:0x1f5, + uN[TEST_ADDR_W]:0x155, uN[TEST_ADDR_W]:0x0db, uN[TEST_ADDR_W]:0x070, uN[TEST_ADDR_W]:0x13a, + uN[TEST_ADDR_W]:0x0bf, uN[TEST_ADDR_W]:0x16b, uN[TEST_ADDR_W]:0x143, uN[TEST_ADDR_W]:0x0b4, + uN[TEST_ADDR_W]:0x1f4, uN[TEST_ADDR_W]:0x17f, uN[TEST_ADDR_W]:0x096, uN[TEST_ADDR_W]:0x03a, + uN[TEST_ADDR_W]:0x0ec, uN[TEST_ADDR_W]:0x030, uN[TEST_ADDR_W]:0x0e1, uN[TEST_ADDR_W]:0x1e7, + uN[TEST_ADDR_W]:0x006, uN[TEST_ADDR_W]:0x088, uN[TEST_ADDR_W]:0x1e9, uN[TEST_ADDR_W]:0x16f, + uN[TEST_ADDR_W]:0x152, uN[TEST_ADDR_W]:0x1a2, uN[TEST_ADDR_W]:0x0ac, uN[TEST_ADDR_W]:0x0d3, + uN[TEST_ADDR_W]:0x0d5, uN[TEST_ADDR_W]:0x107, uN[TEST_ADDR_W]:0x121, uN[TEST_ADDR_W]:0x01a, + uN[TEST_ADDR_W]:0x1c2, uN[TEST_ADDR_W]:0x117, uN[TEST_ADDR_W]:0x0e9, uN[TEST_ADDR_W]:0x0ac, + uN[TEST_ADDR_W]:0x16e, uN[TEST_ADDR_W]:0x105, uN[TEST_ADDR_W]:0x01e, uN[TEST_ADDR_W]:0x186, + uN[TEST_ADDR_W]:0x1bb, uN[TEST_ADDR_W]:0x05b, uN[TEST_ADDR_W]:0x07a, uN[TEST_ADDR_W]:0x1d3, + uN[TEST_ADDR_W]:0x120, uN[TEST_ADDR_W]:0x142, uN[TEST_ADDR_W]:0x0ee, uN[TEST_ADDR_W]:0x083, + uN[TEST_ADDR_W]:0x1ce, uN[TEST_ADDR_W]:0x016, uN[TEST_ADDR_W]:0x041, uN[TEST_ADDR_W]:0x040, + uN[TEST_ADDR_W]:0x073, uN[TEST_ADDR_W]:0x197, uN[TEST_ADDR_W]:0x1d1, uN[TEST_ADDR_W]:0x074, + uN[TEST_ADDR_W]:0x087, uN[TEST_ADDR_W]:0x168, uN[TEST_ADDR_W]:0x1f7, uN[TEST_ADDR_W]:0x19e, + uN[TEST_ADDR_W]:0x06f, uN[TEST_ADDR_W]:0x0c9, uN[TEST_ADDR_W]:0x102, uN[TEST_ADDR_W]:0x077, + uN[TEST_ADDR_W]:0x0ff, uN[TEST_ADDR_W]:0x1ac, uN[TEST_ADDR_W]:0x02c, uN[TEST_ADDR_W]:0x116, + uN[TEST_ADDR_W]:0x04d, uN[TEST_ADDR_W]:0x16b, uN[TEST_ADDR_W]:0x14c, uN[TEST_ADDR_W]:0x173, + uN[TEST_ADDR_W]:0x055, uN[TEST_ADDR_W]:0x1e1, uN[TEST_ADDR_W]:0x028, uN[TEST_ADDR_W]:0x103, + uN[TEST_ADDR_W]:0x01c, uN[TEST_ADDR_W]:0x168, uN[TEST_ADDR_W]:0x096, uN[TEST_ADDR_W]:0x15b, + uN[TEST_ADDR_W]:0x1aa, uN[TEST_ADDR_W]:0x010, uN[TEST_ADDR_W]:0x08c, uN[TEST_ADDR_W]:0x083, + uN[TEST_ADDR_W]:0x014, uN[TEST_ADDR_W]:0x013, uN[TEST_ADDR_W]:0x00d, uN[TEST_ADDR_W]:0x1eb, + uN[TEST_ADDR_W]:0x09d, uN[TEST_ADDR_W]:0x079, uN[TEST_ADDR_W]:0x146, uN[TEST_ADDR_W]:0x191, + uN[TEST_ADDR_W]:0x070, uN[TEST_ADDR_W]:0x1bc, uN[TEST_ADDR_W]:0x037, uN[TEST_ADDR_W]:0x130, + uN[TEST_ADDR_W]:0x0d8, uN[TEST_ADDR_W]:0x0d1, uN[TEST_ADDR_W]:0x136, uN[TEST_ADDR_W]:0x05b, + uN[TEST_ADDR_W]:0x1f3, uN[TEST_ADDR_W]:0x036, uN[TEST_ADDR_W]:0x0db, uN[TEST_ADDR_W]:0x149, + uN[TEST_ADDR_W]:0x11e, uN[TEST_ADDR_W]:0x1c2, uN[TEST_ADDR_W]:0x0a3, uN[TEST_ADDR_W]:0x061, + uN[TEST_ADDR_W]:0x0eb, uN[TEST_ADDR_W]:0x131, uN[TEST_ADDR_W]:0x04a, uN[TEST_ADDR_W]:0x0ab, + uN[TEST_ADDR_W]:0x0d5, uN[TEST_ADDR_W]:0x083, uN[TEST_ADDR_W]:0x1cb, uN[TEST_ADDR_W]:0x03f, + uN[TEST_ADDR_W]:0x02d, uN[TEST_ADDR_W]:0x14d, uN[TEST_ADDR_W]:0x120, uN[TEST_ADDR_W]:0x194, + uN[TEST_ADDR_W]:0x062, uN[TEST_ADDR_W]:0x182, uN[TEST_ADDR_W]:0x124, uN[TEST_ADDR_W]:0x06d, +]; + +#[test_proc] +proc AlignedParallelRam_test_non_aligned_read { + terminator: chan out; + read_req_s: chan out; + read_resp_r: chan in; + write_req_s: chan out; + write_resp_r: chan in; + + config (terminator: chan out) { + let (read_req_s, read_req_r) = chan("read_req"); + let (read_resp_s, read_resp_r) = chan("read_resp"); + let (write_req_s, write_req_r) = chan("write_req"); + let (write_resp_s, write_resp_r) = chan("write_resp"); + + let (ram_read_req_s, ram_read_req_r) = chan[RAM_NUM]("ram_read_req"); + let (ram_read_resp_s, ram_read_resp_r) = chan[RAM_NUM]("ram_read_resp"); + let (ram_write_req_s, ram_write_req_r) = chan[RAM_NUM]("ram_write_req"); + let (ram_write_resp_s, ram_write_resp_r) = chan[RAM_NUM]("ram_write_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[0], ram_read_resp_s[0], ram_write_req_r[0], ram_write_resp_s[0], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[1], ram_read_resp_s[1], ram_write_req_r[1], ram_write_resp_s[1], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[2], ram_read_resp_s[2], ram_write_req_r[2], ram_write_resp_s[2], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[3], ram_read_resp_s[3], ram_write_req_r[3], ram_write_resp_s[3], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[4], ram_read_resp_s[4], ram_write_req_r[4], ram_write_resp_s[4], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[5], ram_read_resp_s[5], ram_write_req_r[5], ram_write_resp_s[5], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[6], ram_read_resp_s[6], ram_write_req_r[6], ram_write_resp_s[6], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[7], ram_read_resp_s[7], ram_write_req_r[7], ram_write_resp_s[7], + ); + + spawn AlignedParallelRam( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + + ( + terminator, + read_req_s, + read_resp_r, + write_req_s, + write_resp_r, + ) + } + + init { } + + next (state: ()) { + let tok = join(); + + // write RAM content + let tok = for (i, tok):(u32, token) in u32:0..array_size(TEST_RAM_CONTENT) { + let test_data = TEST_RAM_CONTENT[i]; + + let write_req = TestWriteReq { + addr: (i * TEST_RAM_DATA_W) as uN[TEST_ADDR_W], + data: test_data, + }; + let tok = send(tok, write_req_s, write_req); + trace_fmt!("Sent #{} write request {:#x}", i + u32:1, write_req); + + let (tok, write_resp) = recv(tok, write_resp_r); + trace_fmt!("Received #{} write response {:#x}", i + u32:1, write_resp); + + let read_req = TestReadReq { + addr: (i * TEST_RAM_DATA_W) as uN[TEST_ADDR_W], + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{} read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{} read response {:#x}", i + u32:1, read_resp); + + assert_eq(test_data, read_resp.data); + + tok + }(tok); + + // read unaligned data + let tok = for (i, tok):(u32, token) in u32:0..array_size(TEST_READ_ADDR) { + let test_read_addr = TEST_READ_ADDR[i]; + + let read_req = TestReadReq { + addr: test_read_addr, + }; + + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{} read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{} read response {:#x}", i + u32:1, read_resp); + + let ram_offset = test_read_addr as uN[RAM_NUM_W]; + let expected_data = if ram_offset == uN[RAM_NUM_W]:0 { + TEST_RAM_CONTENT[test_read_addr >> RAM_NUM_W] + } else { + let data_0 = TEST_RAM_CONTENT[test_read_addr >> RAM_NUM_W]; + let data_1 = TEST_RAM_CONTENT[(test_read_addr >> RAM_NUM_W) + uN[TEST_ADDR_W]:1]; + ( + (data_0 >> (TEST_RAM_DATA_W * ram_offset as u32)) | + (data_1 << (TEST_RAM_DATA_W * (RAM_NUM - ram_offset as u32))) + ) + }; + + assert_eq(expected_data, read_resp.data); + + tok + }(tok); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/block_header.x b/xls/modules/zstd/block_header.x index 9e8679a72d..fd8d084271 100644 --- a/xls/modules/zstd/block_header.x +++ b/xls/modules/zstd/block_header.x @@ -12,16 +12,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -// This file contains utilities related to ZSTD Block Header parsing. +// This file contains utilities and type definitions related to +// ZSTD Block Header parsing and the implementation of BlockHeaderWriter proc. // More information about the ZSTD Block Header can be found in: // https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.2 import std; + import xls.modules.zstd.common as common; +import xls.modules.zstd.memory.mem_writer as mem_writer; type BlockType = common::BlockType; type BlockSize = common::BlockSize; +type MemWriterResp = mem_writer::MemWriterResp; +type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + // Status values reported by the block header parsing function pub enum BlockHeaderStatus: u2 { OK = 0, @@ -36,6 +42,11 @@ pub struct BlockHeader { size: BlockSize, } +pub struct BlockHeaderWriterReq { + addr: uN[ADDR_W], + header: BlockHeader, +} + // Auxiliary constant that can be used to initialize Proc's state // with empty FrameHeader, because `zero!` cannot be used in that context pub const ZERO_BLOCK_HEADER = zero!(); @@ -49,3 +60,237 @@ pub fn extract_block_header(data:u24) -> BlockHeader { last: data[0:1], } } + +pub enum BlockHeaderWriterStatus: u1 { + OKAY = 0, + ERROR = 1 +} + +pub struct BlockHeaderWriterResp { + status: BlockHeaderWriterStatus, +} + +pub proc BlockHeaderWriter { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + req_r: chan> in; + resp_s: chan out; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + config( + req_r: chan> in, + resp_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + (req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r) + } + + init {} + next(state: ()) { + let tok = join(); + let (tok, request) = recv(tok, req_r); + + // write this to memory at address request.addr + let bytes = request.header.size as u21 ++ + request.header.btype as u2 ++ + request.header.last as u1; + + let writer_request = MemWriterReq { + addr: request.addr, + length: uN[ADDR_W]:3, + }; + let tok = send(tok, mem_wr_req_s, writer_request); + + // Pass data to MemWriter + let writer_data = MemWriterDataPacket { + data: bytes as uN[DATA_W], + length: uN[ADDR_W]:3, + last: true, + }; + + let tok = send(tok, mem_wr_data_s, writer_data); + + // Check response from MemWriter + let (tok, memory_response) = recv(tok, mem_wr_resp_r); + + let status = if (memory_response.status == MemWriterRespStatus::OKAY) { + BlockHeaderWriterStatus::OKAY + } else { + BlockHeaderWriterStatus::ERROR + }; + + send(tok, resp_s, BlockHeaderWriterResp {status}); + } +} + +const INST_DATA_W = u32:64; +const INST_ADDR_W = u32:32; + +proc BlockHeaderWriterInst { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + config( + req_r: chan> in, + resp_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + spawn BlockHeaderWriter(req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r); + } + + init { } + next (state: ()) { } +} + +const TEST_ADDR_W = u32:64; +const TEST_DATA_W = u32:32; + +type MemWriterReq = mem_writer::MemWriterReq; +type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + +struct TestCase { + request: BlockHeaderWriterReq, + expected_mem_writer_req: MemWriterReq, + expected_mem_writer_data: MemWriterDataPacket, + mem_writer_resp: MemWriterResp, + expected_resp: BlockHeaderWriterResp, +} + +const TEST_CASES = TestCase[3]:[ + TestCase { + request: BlockHeaderWriterReq { + addr: uN[TEST_ADDR_W]:0x43210000, + header: BlockHeader { + last: true, + btype: BlockType::RAW, + size: BlockSize:0x1000, + }, + }, + expected_mem_writer_req: MemWriterReq { + addr: uN[TEST_ADDR_W]:0x43210000, + length: uN[TEST_ADDR_W]:3, + }, + expected_mem_writer_data: MemWriterDataPacket{ + data: (u21:0x1000 ++ u2:0 ++ u1:1) as uN[TEST_DATA_W], + length: uN[TEST_ADDR_W]: 3, + last: true, + }, + mem_writer_resp: MemWriterResp { + status: MemWriterRespStatus::OKAY, + }, + expected_resp: BlockHeaderWriterResp { + status: BlockHeaderWriterStatus::OKAY, + }, + }, + TestCase { + request: BlockHeaderWriterReq { + addr: uN[TEST_ADDR_W]:0xaaaaaaa0, + header: BlockHeader { + last: false, + btype: BlockType::COMPRESSED, + size: BlockSize:0x20, + }, + }, + expected_mem_writer_req: MemWriterReq { + addr: uN[TEST_ADDR_W]:0xaaaaaaa0, + length: uN[TEST_ADDR_W]:3, + }, + expected_mem_writer_data: MemWriterDataPacket { + data: (u21:0x20 ++ u2:2 ++ u1:0) as uN[TEST_DATA_W], + length: uN[TEST_ADDR_W]: 3, + last: true, + }, + mem_writer_resp: MemWriterResp { + status: MemWriterRespStatus::OKAY, + }, + expected_resp: BlockHeaderWriterResp { + status: BlockHeaderWriterStatus::OKAY, + }, + }, + TestCase { + request: BlockHeaderWriterReq { + addr: uN[TEST_ADDR_W]:0xc0c0a000, + header: BlockHeader { + last: true, + btype: BlockType::RLE, + size: BlockSize:0x60, + }, + }, + expected_mem_writer_req: MemWriterReq { + addr: uN[TEST_ADDR_W]:0xc0c0a000, + length: uN[TEST_ADDR_W]:3, + }, + expected_mem_writer_data: MemWriterDataPacket { + data: (u21:0x60 ++ u2:1 ++ u1:1) as uN[TEST_DATA_W], + length: uN[TEST_ADDR_W]: 3, + last: true, + }, + mem_writer_resp: MemWriterResp { + status: MemWriterRespStatus::ERROR, + }, + expected_resp: BlockHeaderWriterResp { + status: BlockHeaderWriterStatus::ERROR, + }, + }, +]; + +#[test_proc] +proc Tester { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + terminator: chan out; + + // IO for BlockHeaderWriter + req_s: chan> out; + resp_r: chan in; + mem_wr_req_r: chan in; + mem_wr_data_r: chan in; + mem_wr_resp_s: chan out; + + init {} + + config(terminator: chan out) { + let (req_s, req_r) = chan>("req"); + let (resp_s, resp_r) = chan("resp"); + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_resp"); + + spawn BlockHeaderWriter(req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r); + + (terminator, req_s, resp_r, mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s) + } + + next(state: ()) { + let tok = join(); + for (test_case, ()) : (TestCase, ()) in TEST_CASES { + // send request + let tok = send(tok, req_s, test_case.request); + + // verify request to MemWriter + let (tok, val) = recv(tok, mem_wr_req_r); + assert_eq(val, test_case.expected_mem_writer_req); + + // verify data to MemWriter + let (tok, val) = recv(tok, mem_wr_data_r); + assert_eq(val, test_case.expected_mem_writer_data); + + // send memory response + let tok = send(tok, mem_wr_resp_s, test_case.mem_writer_resp); + + // verify final response from BlockHeaderWriter + let (tok, val) = recv(tok, resp_r); + assert_eq(val, test_case.expected_resp); + }(()); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/block_size.x b/xls/modules/zstd/block_size.x new file mode 100644 index 0000000000..ea169b99d6 --- /dev/null +++ b/xls/modules/zstd/block_size.x @@ -0,0 +1,65 @@ +// Copyright 2025 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.zstd.common; + +type BlockSize = common::BlockSize; + +// The simples heuristic the estimate block size for input data, +// to be used as the first stage of data splitting. +// uses: +// * RFC-defined maximum block size, +// * parameter-defined maximum block size, +// * size of input data +// to provide the result BlockSize +pub fn get_block_size( + size: u32, + max_block_size: BlockSize, +) -> BlockSize { + std::min(size, std::min(max_block_size, common::MAX_BLOCK_SIZE) as u32) as BlockSize +} + +#[test] +fn test_get_block_size() { + // size greater than the protocol allows to fit in a block - 129KB + let size = (u32:129 << 10) as u32; + assert_eq( + get_block_size(size, common::MAX_BLOCK_SIZE), + common::MAX_BLOCK_SIZE as BlockSize + ); + + // size greater than the selected block size, below RFC-defined limit + let size = (u32:100 << 10) as u32; // 100KB + let selected_block_size = (u32:90 << 10) as BlockSize; // 90KB + assert_eq( + get_block_size(size, selected_block_size), + selected_block_size as BlockSize + ); + + // size smaller than the selected block size + let size = u32:100; + assert_eq( + get_block_size(size, selected_block_size), + size as BlockSize + ); + + // zero data to compress + let size = u32:0; + assert_eq( + get_block_size(size, selected_block_size), + size as BlockSize + ); +} diff --git a/xls/modules/zstd/cocotb/BUILD b/xls/modules/zstd/cocotb/BUILD new file mode 100644 index 0000000000..738fcc7833 --- /dev/null +++ b/xls/modules/zstd/cocotb/BUILD @@ -0,0 +1,84 @@ +# Copyright 2024 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. + +load("@xls_pip_deps//:requirements.bzl", "requirement") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//xls:xls_users"], + licenses = ["notice"], +) + +py_library( + name = "channel", + srcs = ["channel.py"], + deps = [ + ":xlsstruct", + requirement("cocotb"), + requirement("cocotb_bus"), + ], +) + +py_library( + name = "memory", + srcs = ["memory.py"], + deps = [ + requirement("cocotbext-axi"), + ], +) + +py_library( + name = "scoreboard", + srcs = ["scoreboard.py"], + deps = [ + ":channel", + ":xlsstruct", + requirement("cocotb"), + ], +) + +py_library( + name = "utils", + srcs = ["utils.py"], + deps = [ + requirement("cocotb"), + "//xls/common:runfiles", + ], +) + +py_library( + name = "xlsstruct", + srcs = ["xlsstruct.py"], + deps = [ + requirement("cocotb"), + ], +) + +py_library( + name = "data_generator", + srcs = ["data_generator.py"], + deps = [ + "//xls/common:runfiles", + "@zstd//:decodecorpus", + "@zstd//:zstd_cli", + ], +) + +py_library( + name = "fse_table_record", + srcs = ["fse_table_record.py"], + deps = [ + ":xlsstruct" + ] +) diff --git a/xls/modules/zstd/cocotb/channel.py b/xls/modules/zstd/cocotb/channel.py new file mode 100644 index 0000000000..01b84b54f0 --- /dev/null +++ b/xls/modules/zstd/cocotb/channel.py @@ -0,0 +1,133 @@ +# Copyright 2024 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. + +"""Cocotb interfaces for XLS channels using data, valid, and ready signals.""" + +from typing import Any, Sequence, Type, Union + +import cocotb +from cocotb.handle import SimHandleBase +from cocotb.triggers import RisingEdge +from cocotb_bus.bus import Bus +from cocotb_bus.drivers import BusDriver +from cocotb_bus.monitors import BusMonitor + +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct + +Transaction = Union[XLSStruct, Sequence[XLSStruct]] + +XLS_CHANNEL_SIGNALS = ["data", "rdy", "vld"] +XLS_CHANNEL_OPTIONAL_SIGNALS = [] + + +class XLSChannel(Bus): + """Represents an XLS- channel with ready/valid handshake.""" + _signals = XLS_CHANNEL_SIGNALS + _optional_signals = XLS_CHANNEL_OPTIONAL_SIGNALS + + def __init__(self, entity, name, clk, *, start_now=False, **kwargs: Any): + super().__init__( + entity, name, self._signals, self._optional_signals, **kwargs + ) + self.clk = clk + if start_now: + self.start_recv_loop() + + @cocotb.coroutine + async def recv(self): + while True: + await RisingEdge(self.clk) + if self.rdy.value and self.vld.value: + return self.data.value + + @cocotb.coroutine + async def recv_as(self, xlsstruct_type): + return xlsstruct_type.from_int(await self.recv()) + + @cocotb.coroutine + async def recv_channel(self): + """Cocotb coroutine that acts as a proc receiving data from a channel.""" + self.rdy.setimmediatevalue(1) + while True: + await RisingEdge(self.clk) + + def start_recv_loop(self): + cocotb.start_soon(self.recv_channel()) + + +class XLSChannelDriver(BusDriver): + """Drives transactions on an XLS channel.""" + _signals = XLS_CHANNEL_SIGNALS + _optional_signals = XLS_CHANNEL_OPTIONAL_SIGNALS + + def __init__( + self, + entity: SimHandleBase, + name: str, + clock: SimHandleBase, + **kwargs: Any + ): + BusDriver.__init__(self, entity, name, clock, **kwargs) + + self.bus.data.setimmediatevalue(0) + self.bus.vld.setimmediatevalue(0) + + async def _driver_send( + self, + transaction: Transaction, + sync: bool = True, + **kwargs: Any + ) -> None: + if sync: + await RisingEdge(self.clock) + + data_to_send = ( + transaction if isinstance(transaction, Sequence) else [transaction] + ) + + for word in data_to_send: + self.bus.vld.value = 1 + self.bus.data.value = word.binaryvalue + + while True: + await RisingEdge(self.clock) + if self.bus.rdy.value: + break + + self.bus.vld.value = 0 + + +class XLSChannelMonitor(BusMonitor): + """Monitors and decodes transactions on an XLS channel.""" + _signals = XLS_CHANNEL_SIGNALS + _optional_signals = XLS_CHANNEL_OPTIONAL_SIGNALS + + def __init__( + self, + entity: SimHandleBase, + name: str, + clock: SimHandleBase, + struct: Type[XLSStruct], + **kwargs: Any + ): + BusMonitor.__init__(self, entity, name, clock, **kwargs) + self.struct = struct + + @cocotb.coroutine + async def _monitor_recv(self) -> None: + while True: + await RisingEdge(self.clock) + if self.bus.rdy.value and self.bus.vld.value: + vec = self.struct.from_int(self.bus.data.value.integer) + self._recv(vec) diff --git a/xls/modules/zstd/cocotb/data_generator.py b/xls/modules/zstd/cocotb/data_generator.py new file mode 100644 index 0000000000..592f930771 --- /dev/null +++ b/xls/modules/zstd/cocotb/data_generator.py @@ -0,0 +1,101 @@ +# Copyright 2024 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. + +"""Module for generating and decompressing test frames.""" + +import pathlib +import enum + +from xls.common import runfiles +import subprocess +import tempfile + +class BlockType(enum.Enum): + """Enum encoding of ZSTD block types.""" + + RAW = 0 + RLE = 1 + COMPRESSED = 2 + RANDOM = 3 + + def __str__(self): + return self.name + + @staticmethod + def from_string(s): + try: + return BlockType[s] + except KeyError as e: + raise ValueError(str(e)) from e + +class LiteralType(enum.Enum): + """Enum encoding of ZSTD literal types.""" + + RAW = 0 + RLE = 1 + COMPRESSED = 2 + RANDOM = 3 + + def __str__(self): + return self.name + + @staticmethod + def from_string(s): + try: + return BlockType[s] + except KeyError as e: + raise ValueError(str(e)) from e + +def CallDecodecorpus(args): + decodecorpus = pathlib.Path( + runfiles.get_path("decodecorpus", repository = "zstd") + ) + cmd = args + cmd.insert(0, str(decodecorpus)) + cmd_concat = " ".join(cmd) + subprocess.run(cmd_concat, shell=True, check=True) + +def DecompressFrame(data): + zstd_cli = pathlib.Path(runfiles.get_path("zstd_cli", repository = "zstd")) + with tempfile.NamedTemporaryFile(mode='wb') as input_data, \ + tempfile.NamedTemporaryFile(mode='wb') as output_data: + input_data.write(data) + input_data.flush() + cmd = f"{str(zstd_cli)} -f -d {input_data.name} -o {output_data.name}" + output_data.close() + subprocess.run(cmd, shell=True, check=True) + with open(output_data.name, "rb") as output_data: + return output_data.read() + +def GenerateFrame(seed, btype, output_path, ltype=LiteralType.RANDOM): + args = [] + args.append("-s" + str(seed)) + if (btype != BlockType.RANDOM): + args.append("--block-type=" + str(btype.value)) + + if (ltype != LiteralType.RANDOM): + args.append("--literal-type=" + str(ltype.value)) + + args.append("--content-size") + # Test payloads up to 16KB + args.append("--max-content-size-log=14") + # Window log 15 is our maximum allowed value, + # as then the max window size is equal to 61 440 bytes + # which fits into the zstd decoder history buffer + # with size of 65 536 bytes. + args.append("--max-window-log=15") + args.append("-p" + output_path) + args.append("-vvvvvvv") + + CallDecodecorpus(args) diff --git a/xls/modules/zstd/cocotb/fse_table_record.py b/xls/modules/zstd/cocotb/fse_table_record.py new file mode 100644 index 0000000000..eaf35f789a --- /dev/null +++ b/xls/modules/zstd/cocotb/fse_table_record.py @@ -0,0 +1,12 @@ +from xls.modules.zstd.cocotb import xlsstruct + + +SYMBOL_W = 8 +NUM_OF_BITS_W = 8 +BASE_W = 16 + +@xlsstruct.xls_dataclass +class FseTableRecord(xlsstruct.XLSStruct): + base: BASE_W + num_of_bits: NUM_OF_BITS_W + symbol: SYMBOL_W diff --git a/xls/modules/zstd/cocotb/memory.py b/xls/modules/zstd/cocotb/memory.py new file mode 100644 index 0000000000..d0850d2dea --- /dev/null +++ b/xls/modules/zstd/cocotb/memory.py @@ -0,0 +1,56 @@ +# Copyright 2024 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. + +""" +Extensions of the cocotb AXI RAM models to memory contents from a binary file. +""" + +import os + +from cocotbext.axi.axi_ram import AxiRam +from cocotbext.axi.axi_ram import AxiRamRead +from cocotbext.axi.axi_ram import AxiRamWrite +from cocotbext.axi.sparse_memory import SparseMemory + + +def init_axi_mem(path: os.PathLike[str], kwargs): + with open(path, "rb") as f: + sparse_mem = SparseMemory(size=kwargs["size"]) + sparse_mem.write(0x0, f.read()) + kwargs["mem"] = sparse_mem + + +class AxiRamReadFromFile(AxiRamRead): + def __init__(self, *args, path: os.PathLike[str], **kwargs): + init_axi_mem(path, kwargs) + super().__init__(*args, **kwargs) + + +class AxiRamFromFile(AxiRam): + def __init__(self, *args, path: os.PathLike[str], **kwargs): + init_axi_mem(path, kwargs) + super().__init__(*args, **kwargs) + + +class AxiRamWriteFromFile(AxiRamWrite): + def __init__(self, *args, path: os.PathLike[str], **kwargs): + init_axi_mem(path, kwargs) + super().__init__(*args, **kwargs) + +class AxiRamFromArray(AxiRam): + def __init__(self, *args, arr: bytearray, **kwargs): + sparse_mem = SparseMemory(size=kwargs["size"]) + sparse_mem.write(0x0, arr) + kwargs["mem"] = sparse_mem + super().__init__(*args, **kwargs) diff --git a/xls/modules/zstd/cocotb/scoreboard.py b/xls/modules/zstd/cocotb/scoreboard.py new file mode 100644 index 0000000000..b3dfca1e3a --- /dev/null +++ b/xls/modules/zstd/cocotb/scoreboard.py @@ -0,0 +1,82 @@ +# Copyright 2024 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. + +"""Scoreboard creator for measuring request-response latency. + +Tracks transactions from channel monitors, computes cycle-based latency, +and logs results. +""" + +import dataclasses +import queue + +from cocotb.clock import Clock +from cocotb.log import SimLog +from cocotb.utils import get_sim_time + +from xls.modules.zstd.cocotb.channel import XLSChannelMonitor +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct + + +@dataclasses.dataclass +class LatencyQueueItem: + """ + Data container for items in a latency queue. + """ + + transaction: XLSStruct + timestamp: int + + +class LatencyScoreboard: + """Tracks and reports latency between request and response transactions.""" + + def __init__(self, dut, clock: Clock, req_monitor: XLSChannelMonitor, resp_monitor: XLSChannelMonitor): + self.dut = dut + self.log = SimLog(f"zstd.cocotb.scoreboard.{self.dut._name}") + self.clock = clock + self.req_monitor = req_monitor + self.resp_monitor = resp_monitor + self.pending_req = queue.Queue() + self.results = [] + + self.req_monitor.add_callback(self._req_callback) + self.resp_monitor.add_callback(self._resp_callback) + + def _current_cycle(self): + return get_sim_time(units='step') / self.clock.period + + def _req_callback(self, transaction: XLSStruct): + self.pending_req.put(LatencyQueueItem(transaction, self._current_cycle())) + + def _resp_callback(self, unused_transaction: XLSStruct): + latency_item = self.pending_req.get() + self.results.append(self._current_cycle() - latency_item.timestamp) + + def average_latency(self): + return sum(self.results)/len(self.results) + + def report_result(self): + """Logs a summary of latency measurements and any unfulfilled requests.""" + if not self.pending_req.empty(): + self.log.warning(f"There are unfulfilled requests from channel {self.req_monitor.name}") + while not self.pending_req.empty(): + self.log.warning(f"Unfulfilled request: {self.pending_req.get()}") + if self.results: + self.log.info(f"Latency report - 1st latency: {self.results[0]}") + if len(self.results) > 1: + self.log.info(f"Latency report - 2nd latency: {self.results[1]}") + if len(self.results) > 2: + avg = sum(self.results[2:])/len(self.results[2:]) + self.log.info(f"Latency report - rest of the latencies (average): {avg}") diff --git a/xls/modules/zstd/cocotb/utils.py b/xls/modules/zstd/cocotb/utils.py new file mode 100644 index 0000000000..7a402cddd3 --- /dev/null +++ b/xls/modules/zstd/cocotb/utils.py @@ -0,0 +1,137 @@ +# Copyright 2024 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. + +"""Helpers for setting up and running simulations using Icarus Verilog with Cocotb.""" + +import os +import pathlib + +import subprocess +import cocotb +from cocotb.runner import check_results_file +from cocotb.runner import get_runner +from cocotb.triggers import ClockCycles +import cocotbext.axi.axi_channels as axi + +from xls.common import runfiles + +import tempfile + +def add_to_path(executable): + dir = str(pathlib.Path(executable).parent) + os.environ["PATH"] = dir + os.pathsep + os.environ["PATH"] + +def setup_verilator(): + build_dir = pathlib.Path("sim_build").absolute() + build_dir.mkdir(parents=True, exist_ok=True) + if not os.path.exists(build_dir / "external"): + # verilator will be launched in build dir. We need to link external there + # to make relative paths to toolchains (CC and other) work + os.symlink(os.path.relpath("external", build_dir), build_dir / "external") + + # cocotb does something like `perl $(which verilator) so we have to add both of them to $PATH + verilator_perl_wrapper_path = runfiles.get_path("bin/verilator", repository = "verilator") + add_to_path(verilator_perl_wrapper_path) + add_to_path(os.environ["PERL"]) + + # normally verilator's perl wrapper exepects that binary is located next to it under name "verilator_bin" + # rules_hdl uses different location and name so we have to use $VERILATOR_BIN. + verilator_binary_path = pathlib.Path(runfiles.get_path("verilator_executable", repository = "verilator")) + os.environ["VERILATOR_BIN"] = str(verilator_binary_path) + + os.environ.pop("VERILATOR_ROOT", None) # prevent picking wrong env from host + + return build_dir + + +def setup_com_iverilog(): + iverilog_path = pathlib.Path( + runfiles.get_path("iverilog", repository = "com_icarus_iverilog") + ) + vvp_path = pathlib.Path( + runfiles.get_path("vvp", repository = "com_icarus_iverilog") + ) + os.environ["PATH"] += os.pathsep + str(iverilog_path.parent) + os.environ["PATH"] += os.pathsep + str(vvp_path.parent) + build_dir = pathlib.Path("sim_build").absolute() + return build_dir + + +def run_test(toplevel, test_module, verilog_sources, timescale=("1ns", "1ps"), sim="icarus", build_args=[]): + """Builds and runs a Cocotb testbench""" + build_dir = setup_verilator() if sim == "verilator" else setup_com_iverilog() + runner = get_runner(sim) + + if sim == "verilator": + defines = {"SIMULATION": "1", "ASSERT_ON": "1"} + else: # icarus does not support concurent assertion generated by xls + defines = {"SIMULATION": "1"} + + runner.build( + verilog_sources=verilog_sources, + hdl_toplevel=toplevel, + timescale=("1ns", "1ps"), + build_dir=build_dir, + defines={"SIMULATION": "1"}, + waves=True, + build_args=build_args, + ) + + try: + results_xml = runner.test( + hdl_toplevel=toplevel, + test_module=test_module, + waves=True, + ) + finally: + check_results_file(results_xml) + +@cocotb.coroutine +async def reset(clk, rst, cycles=1): + """Cocotb coroutine that performs the reset.""" + rst.value = 1 + await ClockCycles(clk, cycles) + rst.value = 0 + +def connect_axi_read_bus(dut, name=""): + AXI_AR = "axi_ar" + AXI_R = "axi_r" + + if name != "": + name += "_" + + bus_axi_ar = axi.AxiARBus.from_prefix(dut, name + AXI_AR) + bus_axi_r = axi.AxiRBus.from_prefix(dut, name + AXI_R) + + return axi.AxiReadBus(bus_axi_ar, bus_axi_r) + +def connect_axi_write_bus(dut, name=""): + AXI_AW = "axi_aw" + AXI_W = "axi_w" + AXI_B = "axi_b" + + if name != "": + name += "_" + + bus_axi_aw = axi.AxiAWBus.from_prefix(dut, name + AXI_AW) + bus_axi_b = axi.AxiBBus.from_prefix(dut, name + AXI_B) + bus_axi_w = axi.AxiWBus.from_prefix(dut, name + AXI_W) + + return axi.AxiWriteBus(bus_axi_aw, bus_axi_w, bus_axi_b) + +def connect_axi_bus(dut, name=""): + bus_axi_read = connect_axi_read_bus(dut, name) + bus_axi_write = connect_axi_write_bus(dut, name) + + return axi.AxiBus(bus_axi_write, bus_axi_read) diff --git a/xls/modules/zstd/cocotb/xlsstruct.py b/xls/modules/zstd/cocotb/xlsstruct.py new file mode 100644 index 0000000000..131be8e663 --- /dev/null +++ b/xls/modules/zstd/cocotb/xlsstruct.py @@ -0,0 +1,174 @@ +# Copyright 2024 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. + +""" +Provides utilities for defining Python representations of XLS structs. +""" + +import random +import dataclasses + +from cocotb.binary import BinaryValue + + +class TruncationError(Exception): + pass + +def xls_dataclass(cls): + """Class decorator for XLS structs. + + Usage: + + @xls_dataclass + class MyStruct(XLSStruct): + ... + Args: + cls (type): The class to decorate. + + Returns: + type: The dataclass-decorated class with repr disabled. + """ + return dataclasses.dataclass(cls, repr=False) + +@dataclasses.dataclass +class XLSStruct: + """Represents XLS struct on the Python side. + + Allows serialization/deserialization to/from common formats and usage with + XLS{Driver, Monitor}. + + The intended way to use this class is to inherit from it, specify the fields + with : [= ] syntax and decorate the inheriting + class with @XLSDataclass. Objects of this class can be instantiated and used + like usual dataclass objects, with a few extra methods and properties + available. They can also be passed as arguments to XLSChannelDriver.send and + will be serialized to expected bit vector. Class can be passed to + XLSChannelMonitor ``struct`` constructor argument to automatically + deserialize all transfers to the provided struct. + + Example: + + from xlsstruct import XLSDataclass, XLSStruct + + @XLSDataclass + class MyStruct(XLSStruct): + data: 32 + ok: 1 + id: 4 = 0 + + monitor = XLSChannelMonitor(dut, CHANNEL_PREFIX, dut.clk, MyStruct) + + driver = XLSChannelDriver(dut, CHANNEL_PREFIX, dut.clk) + driver.send(MyStruct( + data = 0xdeadbeef, + ok = 1, + id = 3, + )) + # struct fields can also be randomized + driver.send(MyStruct.randomize()) + """ + + @classmethod + def _masks(cls): + """Returns a list of field-sized bitmasks. + + For example for fields of widths 2, 3, 4 + returns [2'b11, 3'b111, 4'b1111]. + """ + masks = [] + for field in dataclasses.fields(cls): + width = field.type + masks += [(1 << width) - 1] + return masks + + @classmethod + def _positions(cls): + """Returns a list of start positions in a bit vector for struct's fields. + + For example for fields of widths 1, 2, 3, 4, 5, 6 + returns [20, 18, 15, 11, 6, 0] + """ + positions = [] + for i, field in enumerate(dataclasses.fields(cls)): + width = field.type + if i == 0: + positions += [cls.total_width - width] + else: + positions += [positions[i-1] - width] + return positions + + @classmethod + @property + def total_width(cls): + """Returns total bit width of the struct.""" + return sum(field.type for field in dataclasses.fields(cls)) + + @property + def value(self): + """Returns struct's value as a Python integer.""" + value = 0 + masks = self._masks() + positions = self._positions() + for field_val, mask, pos in zip( + dataclasses.astuple(self), masks, positions): + if field_val > mask: + raise TruncationError("Signal value is wider than its bit width") + value |= (field_val & mask) << pos + return value + + @property + def binaryvalue(self): + """Returns struct's value as a cocotb.binary.BinaryValue.""" + return BinaryValue(self.binstr) + + @property + def binstr(self): + """Returns struct's value as a string with its binary representation.""" + return f"{self.value:>0{self.total_width}b}" + + @property + def hexstr(self): + """Returns struct's value as a string with its hex representation. + + The result does NOT have leading "0x". + """ + return f"{self.value:>0{self.total_width // 4}x}" + + @classmethod + def from_int(cls, value): + """Returns an instance of the struct from Python integer.""" + instance = {} + masks = cls._masks() + positions = cls._positions() + for field, mask, pos in zip(dataclasses.fields(cls), masks, positions): + instance[field.name] = (value >> pos) & mask + return cls(**instance) + + @classmethod + def randomize(cls): + """Returns an instance of the struct with all fields' values randomized.""" + instance = {} + for field in dataclasses.fields(cls): + instance[field.name] = random.randrange(0, 2**field.type) + return cls(**instance) + + def __str__(self): + return self.__repr__() + + def __repr__(self): + classname = self.__class__.__name__ + class_fields = [ + f"{name}={hex(value)}" for name, value in dataclasses.asdict(self).items() + ] + return f"{classname}({', '.join(class_fields)})" diff --git a/xls/modules/zstd/command_constructor.x b/xls/modules/zstd/command_constructor.x index 35d58f31b3..a6aa934e45 100644 --- a/xls/modules/zstd/command_constructor.x +++ b/xls/modules/zstd/command_constructor.x @@ -33,213 +33,43 @@ type ExtendedBlockDataPacket = common::ExtendedBlockDataPacket; type BlockSyncData = common::BlockSyncData; type BlockDataPacket = common::BlockDataPacket; -enum Status : u1 { - RECV_COMMAND = 0, - RECV_LITERALS = 1, -} - -struct State { - status: Status, - received_literals: CopyOrMatchLength, - literals_to_receive: CopyOrMatchLength, - command: CommandConstructorData, -} - pub proc CommandConstructor { sequence_decoder_r: chan in; command_aggregator_s: chan out; - literals_buffer_resp_r: chan in; - literals_buffer_req_s: chan out; config(sequence_decoder_r: chan in, - command_aggregator_s: chan out, - literals_buffer_resp_r: chan in, - literals_buffer_req_s: chan out) { - (sequence_decoder_r, command_aggregator_s, literals_buffer_resp_r, literals_buffer_req_s) + command_aggregator_s: chan out) { + (sequence_decoder_r, command_aggregator_s) } - init { zero!() } + init { } - next(state: State) { + next(state: ()) { let tok0 = join(); - let recv_command = state.status == Status::RECV_COMMAND; - let (tok1_0, command) = recv_if(tok0, sequence_decoder_r, recv_command, state.command); - if recv_command { - trace_fmt!("[CommandConstructor] Received command: {:#x}", command); - } else {}; - - let recv_literals = state.status == Status::RECV_LITERALS; - let (tok1_1, literals) = recv_if(tok0, literals_buffer_resp_r, recv_literals, zero!()); - if recv_literals { - trace_fmt!("[CommandConstructor] Received literals: {:#x}", literals); - } else {}; - - let tok1 = join(tok1_0, tok1_1); - - let (new_state, do_send_command, do_send_literals_req) = match (state.status) { - Status::RECV_COMMAND => { - if (command.data.msg_type == SequenceExecutorMessageType::LITERAL) && - (command.data.length != CopyOrMatchLength:0) { - ( - State { - status: Status::RECV_LITERALS, - received_literals: CopyOrMatchLength:0, - literals_to_receive: command.data.length, - command: command, - }, false, true, - ) - } else { - (zero!(), true, false) - } - }, - Status::RECV_LITERALS => { - let received_literals = state.received_literals + literals.length; - if received_literals < state.literals_to_receive { - (State { received_literals, ..state }, true, false) - } else { - assert!( - received_literals >= state.literals_to_receive, - "Too many literals received"); - (zero!(), true, false) - } - }, - _ => fail!("impossible_case", (zero!(), false, false)), - }; - - let req = LiteralsBufferCtrl { length: command.data.length as u32, last: command.data.last}; // FIXME: remove cast after unifying types of 'length' fields - send_if(tok1, literals_buffer_req_s, do_send_literals_req, req); - - let resp = match(state.status) { - // sent only if the original message was of type SEQUENCE - Status::RECV_COMMAND => ExtendedBlockDataPacket { - msg_type: command.data.msg_type, - packet: BlockDataPacket { - last: command.data.last, - last_block: command.sync.last_block, - id: command.sync.id, - data: command.data.content, - length: command.data.length as u32, // FIXME: remove cast after unifying types of 'length' fields - } - }, - Status::RECV_LITERALS => ExtendedBlockDataPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { - last: literals.last & command.data.last, - last_block: command.sync.last_block, - id: command.sync.id, - data: literals.content, - length: literals.length as u32, // FIXME: remove cast after unifying types of 'length' fields - } - }, - _ => fail!("resp_match_unreachable", zero!()) - }; - send_if(tok1, command_aggregator_s, do_send_command, resp); - if do_send_command { - trace_fmt!("[CommandConstructor] Sending command: {:#x}", resp); - } else {}; - - new_state - } -} - -// Tests - -enum FakeLiteralsBufferStatus : u1 { - RECV = 0, - SEND = 1, -} - -struct FakeLiteralsBufferState { - status: FakeLiteralsBufferStatus, - literals_left_to_send: CopyOrMatchLength, -} - -pub fn get_dummy_content(length: CopyOrMatchLength) -> CopyOrMatchContent { - let value = std::unsigned_max_value() >> (CopyOrMatchLength:64 - length); - value as CopyOrMatchContent -} - -proc FakeLiteralsBuffer { - literals_buffer_resp_s: chan out; - literals_buffer_req_r: chan in; - - config(literals_buffer_resp_s: chan out, - literals_buffer_req_r: chan in) { - (literals_buffer_resp_s, literals_buffer_req_r) - } - - init { zero!() } - - next(state: FakeLiteralsBufferState) { - let tok = join(); - let do_recv_req = state.status == FakeLiteralsBufferStatus::RECV; - let (tok, resp) = - recv_if(tok, literals_buffer_req_r, do_recv_req, zero!()); - - let (new_state, do_send, resp) = match (state.status) { - FakeLiteralsBufferStatus::RECV => { - ( - FakeLiteralsBufferState { - status: FakeLiteralsBufferStatus::SEND, - literals_left_to_send: resp.length as u64 // FIXME: remove cast after unifying types of 'length' fields - }, false, zero!(), - ) - }, - FakeLiteralsBufferStatus::SEND => { - let length = std::min(state.literals_left_to_send, CopyOrMatchLength:64); - let next_left_to_send = state.literals_left_to_send - length; - let last = next_left_to_send == CopyOrMatchLength:0; - let resp = SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - content: get_dummy_content(length), - length, - last - }; - - if last { - ( - FakeLiteralsBufferState { - status: FakeLiteralsBufferStatus::RECV, - literals_left_to_send: CopyOrMatchLength:0 - }, true, resp, - ) - } else { - ( - FakeLiteralsBufferState { - status: FakeLiteralsBufferStatus::SEND, - literals_left_to_send: next_left_to_send - }, true, resp, - ) - } + let (tok0, sequence_command) = recv(tok0, sequence_decoder_r); + trace_fmt!("[CommandConstructor] Received sequence command: {:#x}", sequence_command); + + let resp = ExtendedBlockDataPacket { + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { + last: sequence_command.data.last, + last_block: sequence_command.sync.last_block, + id: sequence_command.sync.id, + data: sequence_command.data.content, + length: sequence_command.data.length as u32, }, - _ => { - fail!( - "impossible_case", - (zero!(), false, zero!())) - }, }; - send_if(tok, literals_buffer_resp_s, do_send, resp); - new_state - } -} - -fn cmd_constr_to_ext_block(data: CommandConstructorData) -> ExtendedBlockDataPacket { - ExtendedBlockDataPacket { - msg_type: data.data.msg_type, - packet: BlockDataPacket { - last: data.data.last, - last_block: data.sync.last_block, - id: data.sync.id, - data: data.data.content, - length: data.data.length as u32, - } + let tok0 = send(tok0, command_aggregator_s, resp); + trace_fmt!("[CommandConstructor] Sending command: {:#x}", resp); } } #[test_proc] proc CommandConstructorTest { + type SequenceExecutorPacket = common::SequenceExecutorPacket; + terminator: chan out; sequence_decoder_s: chan out; command_aggregator_r: chan in; @@ -248,13 +78,7 @@ proc CommandConstructorTest { let (sequence_decoder_s, sequence_decoder_r) = chan("sequence_decoder"); let (command_aggregator_s, command_aggregator_r) = chan("command_aggregator"); - let (literals_buffer_resp_s, literals_buffer_resp_r) = chan("literals_buffer_resp"); - let (literals_buffer_req_s, literals_buffer_req_r) = chan("literals_buffer_req"); - - spawn CommandConstructor( - sequence_decoder_r, command_aggregator_s, literals_buffer_resp_r, literals_buffer_req_s); - - spawn FakeLiteralsBuffer(literals_buffer_resp_s, literals_buffer_req_r); + spawn CommandConstructor(sequence_decoder_r, command_aggregator_s); (terminator, sequence_decoder_s, command_aggregator_r) } @@ -262,16 +86,14 @@ proc CommandConstructorTest { init { } next(state: ()) { - const EMPTY_PACKET = zero!(); - let tok = join(); let sequence_packet1 = CommandConstructorData { data: SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - content: CopyOrMatchContent:11, - length: CopyOrMatchLength:4, - last: true, + content: CopyOrMatchContent:0x1005b, + length: CopyOrMatchLength:9, + last: false, }, sync: BlockSyncData { id: u32:1234, @@ -280,67 +102,18 @@ proc CommandConstructorTest { }; let tok = send(tok, sequence_decoder_s, sequence_packet1); let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(cmd_constr_to_ext_block(sequence_packet1), resp); - - let literals_packet1 = CommandConstructorData { - data: SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, - ..EMPTY_PACKET - }, - sync: BlockSyncData { - id: u32:1234, - last_block: false, - }, - }; - let tok = send(tok, sequence_decoder_s, literals_packet1); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:4), resp.packet.data); - - let literals_packet2 = CommandConstructorData { - data: SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:65, - ..EMPTY_PACKET - }, - sync: BlockSyncData { - id: u32:1234, - last_block: false, - }, - }; - let tok = send(tok, sequence_decoder_s, literals_packet2); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:64), resp.packet.data); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:1), resp.packet.data); - let literals_packet3 = CommandConstructorData { - data: SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:64, - ..EMPTY_PACKET - }, - sync: BlockSyncData { + trace_fmt!("[CommandConstructorTest] Received command: {:#x}", resp); + assert_eq(resp, ExtendedBlockDataPacket { + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { + last: u1:0, + last_block: u1:0, id: u32:1234, - last_block: false, + data: CopyOrMatchContent:0x1005b, + length: u32:9, }, - }; - let tok = send(tok, sequence_decoder_s, literals_packet3); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:64), resp.packet.data); - - let literals_packet4 = CommandConstructorData { - data: SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:128, - ..EMPTY_PACKET - }, - sync: BlockSyncData { - id: u32:1234, - last_block: false, - }, - }; - let tok = send(tok, sequence_decoder_s, literals_packet4); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:64), resp.packet.data); - let (tok, resp) = recv(tok, command_aggregator_r); - assert_eq(get_dummy_content(CopyOrMatchLength:64), resp.packet.data); + }); let tok = send(tok, terminator, true); } diff --git a/xls/modules/zstd/common.x b/xls/modules/zstd/common.x index 640682b8e4..46135b4680 100644 --- a/xls/modules/zstd/common.x +++ b/xls/modules/zstd/common.x @@ -16,17 +16,28 @@ import std; import xls.examples.ram; import xls.modules.zstd.shift_buffer; -pub const DATA_WIDTH = u32:64; +pub const AXI_DATA_W = u32:64; +pub const AXI_ADDR_W = u32:32; +pub const AXI_DATA_BYTES_W = AXI_DATA_W / u32:8; + +pub const SYMBOLS_IN_PACKET = AXI_DATA_W / u32:8; + +pub const DATA_WIDTH = AXI_DATA_W; pub const MAX_ID = u32::MAX; pub const SYMBOL_WIDTH = u32:8; pub const BLOCK_SIZE_WIDTH = u32:21; pub const OFFSET_WIDTH = u32:22; + +// u32 here is sufficient for the maximum size of the history buffer +// as RFC 8878 states that 3.75 TB is the maximum allowed value for +// a window size and storing this value in KB units allows it to be +// saved in a 32-bit unsigned integer (2^32 * 2^10 > 3.75 TB) +// https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.1.2-6 pub const HISTORY_BUFFER_SIZE_KB = u32:64; + pub const BUFFER_WIDTH = u32:128; -pub const MAX_BLOCK_SIZE_KB = u32:64; pub const BLOCK_PACKET_WIDTH = u32:32; -pub const SYMBOLS_IN_PACKET = DATA_WIDTH/SYMBOL_WIDTH; pub type BlockData = bits[DATA_WIDTH]; pub type BlockPacketLength = bits[BLOCK_PACKET_WIDTH]; @@ -34,6 +45,12 @@ pub type BlockSize = bits[BLOCK_SIZE_WIDTH]; pub type CopyOrMatchContent = BlockData; pub type CopyOrMatchLength = u64; pub type Offset = bits[OFFSET_WIDTH]; +pub type RefillingSBLength = uN[std::clog2(AXI_DATA_W) + u32:1]; + +// BlockSize is limited by the smallest of: (Window_Size, 128KB) +// see https://datatracker.ietf.org/doc/html/rfc8878#name-block_content-and-block_max +pub const MAX_BLOCK_SIZE_KB = u32:128; +pub const MAX_BLOCK_SIZE = (MAX_BLOCK_SIZE_KB << 10) as BlockSize; pub enum BlockType : u2 { RAW = 0, @@ -50,7 +67,7 @@ pub struct BlockDataPacket { length: BlockPacketLength, } -pub enum SequenceExecutorMessageType : u1 { +pub enum SequenceExecutorMessageType: u1 { LITERAL = 0, SEQUENCE = 1, } @@ -62,7 +79,6 @@ pub struct ExtendedBlockDataPacket { pub struct SequenceExecutorPacket { msg_type: SequenceExecutorMessageType, - // TODO: this should be max(8, clog2(maximum match value)) length: CopyOrMatchLength, // Literal length or match length content: uN[DATA_W * u32:8], // Literal data or match offset last: bool, // Last packet in frame @@ -122,8 +138,6 @@ pub const FSE_PROB_DIST_WIDTH = u32:16; pub const FSE_MAX_PROB_DIST = u32:256; pub const FSE_SYMBOL_WIDTH = u32:16; -// FIXME: Tests in DSLX interpreter require smaller RAMs due to the problem -// with ram consumtopn descibed in https://github.com/google/xls/issues/1042 pub const TEST_FSE_MAX_ACCURACY_LOG = u32:9; pub type FseRemainingProba = uN[FSE_REMAINING_PROBA_WIDTH]; @@ -172,8 +186,8 @@ pub struct FseTableRecord { base: u16 } -pub struct FseRemainder { value: u1, valid: bool } -pub struct FseProbaFreqDecoderCtrl { remainder: FseRemainder, finished: bool } +pub struct Remainder { value: u1, valid: bool } +pub struct FseProbaFreqDecoderCtrl { remainder: Remainder, finished: bool } pub struct FseTableCreatorCtrl { accuracy_log: FseAccuracyLog, @@ -249,7 +263,8 @@ pub type SeqDecShiftBufferStatus = shift_buffer::ShiftBufferStatus; pub const RLE_LITERALS_DATA_WIDTH = u32:8; pub const RLE_LITERALS_REPEAT_WIDTH = u32:20; -pub const LITERALS_DATA_WIDTH = u32:64; +pub const LITERALS_IN_PACKET = AXI_DATA_W / u32:8; +pub const LITERALS_DATA_WIDTH = LITERALS_IN_PACKET * u32:8; pub const LITERALS_LENGTH_WIDTH = std::clog2( std::ceil_div(LITERALS_DATA_WIDTH, RLE_LITERALS_DATA_WIDTH) + u32:1 ); @@ -306,11 +321,14 @@ pub enum LookupDecoderStatus: u1 { ERROR = u1:1, } -pub struct LookupDecoderReq {} +pub struct LookupDecoderReq { + remainder: Remainder +} pub struct LookupDecoderResp { status: LookupDecoderStatus, accuracy_log: FseAccuracyLog, + remainder: Remainder, } pub struct DataArray{ diff --git a/xls/modules/zstd/comp_block_dec.x b/xls/modules/zstd/comp_block_dec.x index 9b35558522..79ff160946 100644 --- a/xls/modules/zstd/comp_block_dec.x +++ b/xls/modules/zstd/comp_block_dec.x @@ -29,7 +29,7 @@ import xls.modules.zstd.fse_proba_freq_dec; import xls.modules.zstd.fse_table_creator; import xls.modules.zstd.ram_mux; -type SequenceExecutorPacket = common::SequenceExecutorPacket; +type SequenceExecutorPacket = common::SequenceExecutorPacket; type ExtendedPacket = common::ExtendedBlockDataPacket; type SequenceExecutorMessageType = common::SequenceExecutorMessageType; type BlockDataPacket = common::BlockDataPacket; @@ -283,38 +283,13 @@ pub proc CompressBlockDecoder< huffman_weights_fse_decoder_dec_axi_r_r: chan in, // Literals buffer internal memory - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in, + rd_req_m_s: chan[common::LITERALS_IN_PACKET] out, + rd_resp_m_r: chan[common::LITERALS_IN_PACKET] in, + wr_req_m_s: chan[common::LITERALS_IN_PACKET] out, + wr_resp_m_r: chan[common::LITERALS_IN_PACKET] in, + + lit_buf_ctrl_r: chan in, + lit_buf_out_s: chan out, // Huffman weights memory huffman_lit_weights_mem_rd_req_s: chan out, @@ -348,18 +323,12 @@ pub proc CompressBlockDecoder< huffman_lit_weights_fse_wr_req_s: chan out, huffman_lit_weights_fse_wr_resp_r: chan in, ) { - // TODO: for consistency all MemReaders should be in toplevel ZSTD decoder - // so we should move them up in the hierarchy from LiteralsDecoder - // and SequenceDecoder to the toplevel const CHANNEL_DEPTH = u32:1; let (lit_ctrl_req_s, lit_ctrl_req_r) = chan("lit_ctrl_req"); let (lit_ctrl_resp_s, lit_ctrl_resp_r) = chan("lit_ctrl_resp"); let (lit_ctrl_header_s, lit_ctrl_header_r) = chan("lit_header"); - let (lit_buf_ctrl_s, lit_buf_ctrl_r) = chan("lit_buf_ctrl"); - let (lit_buf_out_s, lit_buf_out_r) = chan("lit_buf_out"); - spawn literals_decoder::LiteralsDecoder< HISTORY_BUFFER_SIZE_KB, AXI_DATA_W, AXI_ADDR_W, AXI_ID_W, AXI_DEST_W, @@ -380,14 +349,7 @@ pub proc CompressBlockDecoder< huffman_weights_fse_decoder_dec_axi_ar_s, huffman_weights_fse_decoder_dec_axi_r_r, lit_ctrl_req_r, lit_ctrl_resp_s, lit_ctrl_header_s, lit_buf_ctrl_r, lit_buf_out_s, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + rd_req_m_s, rd_resp_m_r, wr_req_m_s, wr_resp_m_r, huffman_lit_weights_mem_rd_req_s, huffman_lit_weights_mem_rd_resp_r, huffman_lit_weights_mem_wr_req_s, huffman_lit_weights_mem_wr_resp_r, huffman_lit_prescan_mem_rd_req_s, huffman_lit_prescan_mem_rd_resp_r, @@ -433,8 +395,6 @@ pub proc CompressBlockDecoder< spawn command_constructor::CommandConstructor( seq_dec_command_r, cmd_constr_out_s, - lit_buf_out_r, - lit_buf_ctrl_s, ); ( @@ -497,15 +457,15 @@ pub proc CompressBlockDecoder< } } -const TEST_CASE_RAM_DATA_W = u32:64; +const TEST_CASE_RAM_DATA_W = common::AXI_DATA_W; const TEST_CASE_RAM_SIZE = u32:256; const TEST_CASE_RAM_ADDR_W = std::clog2(TEST_CASE_RAM_SIZE); -const TEST_CASE_RAM_WORD_PARTITION_SIZE = TEST_CASE_RAM_DATA_W / u32:8; +const TEST_CASE_RAM_WORD_PARTITION_SIZE = u32:8; const TEST_CASE_RAM_NUM_PARTITIONS = ram::num_partitions( TEST_CASE_RAM_WORD_PARTITION_SIZE, TEST_CASE_RAM_DATA_W); const TEST_CASE_RAM_BASE_ADDR = u32:0; -const TEST_AXI_DATA_W = u32:64; +const TEST_AXI_DATA_W = common::AXI_DATA_W; const TEST_AXI_ADDR_W = u32:32; const TEST_AXI_ID_W = u32:4; const TEST_AXI_DEST_W = u32:4; @@ -587,6 +547,7 @@ const TEST_HUFFMAN_PRESCAN_RAM_NUM_PARTITIONS: u32 = huffman_literals_dec::PRESC const TEST_LITERALS_BUFFER_RAM_ADDR_W: u32 = parallel_rams::ram_addr_width(HISTORY_BUFFER_SIZE_KB); const TEST_LITERALS_BUFFER_RAM_SIZE: u32 = parallel_rams::ram_size(HISTORY_BUFFER_SIZE_KB); const TEST_LITERALS_BUFFER_RAM_DATA_W: u32 = literals_buffer::RAM_DATA_WIDTH; +const TEST_LITERALS_BUFFER_RAM_NUM: u32 = literals_buffer::RAM_NUM; const TEST_LITERALS_BUFFER_RAM_NUM_PARTITIONS: u32 = literals_buffer::RAM_NUM_PARTITIONS; const TEST_LITERALS_BUFFER_RAM_WORD_PARTITION_SIZE: u32 = TEST_LITERALS_BUFFER_RAM_DATA_W; @@ -629,31 +590,19 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u64:0x252c492, u64:0, ... ], - u32:6, + u32:3, ExtendedPacket[128]:[ - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: u64:0x431fba7f9f155239, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: u64:0xe75b86b1dfe3, length: u32:6 } - }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: u64:0x192, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: u64:0xd6c643, length: u32:3 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: uN[TEST_AXI_DATA_W]:0x1920008, length: u32:14 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: u64:0x223, length: u32:3 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:0, data: uN[TEST_AXI_DATA_W]:0x2230003, length: u32:3 } }, ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: true, last_block: false, id: u32:0, data: u64:0x00, length: u32:1 } + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { last: true, last_block: false, id: u32:0, data: uN[TEST_AXI_DATA_W]:0x0, length: u32:1 } }, zero!(), ... ] @@ -693,47 +642,15 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u64:0x13d608b30001d27d, u64:0, ... ], - u32:10, + u32:2, ExtendedPacket[128]:[ - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0xa2bbc79280150052, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x2e159be2210a8b13, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x2bcd291994532c42, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x64de1c37a8940c11, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x9fa347, length: u32:3 } - }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x116, length: u32:4 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x9b679780bbc95f95, length: u32:8 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: uN[TEST_AXI_DATA_W]:0x1160004, length: u32:35 } }, ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0xd90c2f2b9757c107, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:1, data: u64:0x58ba369e427a819d, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: true, last_block: false, id: u32:1, data: u64:0xd27d5a829f, length: u32:5 } + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { last: true, last_block: false, id: u32:1, data: uN[TEST_AXI_DATA_W]:0x0, length: u32:29 } }, zero!(), ... ] @@ -772,127 +689,67 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u64:0x40381ea080, u64:0, ... ], - u32:30, + u32:15, ExtendedPacket[128]:[ - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } - }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x1f50, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x76767676, length: u32:4 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x1f500003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x21a, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x21a0003, length: u32:4 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x2, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x20003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x1bee, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x76, length: u32:1 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x1bee0003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x2026, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x20260003, length: u32:1 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x1d93, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x76, length: u32:1 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x1d930003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x2a39, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x76, length: u32:1 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x2a390003, length: u32:1 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x3111, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x76, length: u32:1 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x31110003, length: u32:1 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0xe76, length: u32:4 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0xe760004, length: u32:1 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x303d, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x303d0003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x3, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x30003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x36ea, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x7676767676, length: u32:5 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x36ea0003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x53be, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x53be0003, length: u32:5 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x14ef, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: u64:0x0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x14ef0003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: true, last_block: false, id: u32:2, data: u64:0x2ce2, length: u32:4 } + packet: BlockDataPacket { last: true, last_block: false, id: u32:2, data: uN[TEST_AXI_DATA_W]:0x2ce20004, length: u32:0 } }, zero!(), ... ], @@ -925,71 +782,19 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u64:0x9570, u64:0, ... ], - u32:16, + u32:3, ExtendedPacket[128]:[ - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5, length: u32:6 } - }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0x2, length: u32:4 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5, length: u32:4 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: uN[TEST_AXI_DATA_W]:0x20004, length: u32:14 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0x4c, length: u32:6 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: uN[TEST_AXI_DATA_W]:0x4c0006, length: u32:4 } }, ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:3, data: u64:0xf5f5f5f5f5f5f5f5, length: u32:8 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: true, last_block: false, id: u32:3, data: u64:0xf5f5f5f5, length: u32:4 } + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { last: true, last_block: false, id: u32:3, data: uN[TEST_AXI_DATA_W]:0, length: u32:84 } }, zero!(), ... ] @@ -1025,8 +830,8 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u32:1, ExtendedPacket[128]:[ ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: true, last_block: false, id: u32:4, data: u64:0x0, length: u32:0 } + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { last: true, last_block: false, id: u32:4, data: uN[TEST_AXI_DATA_W]:0x0, length: u32:0 } }, zero!(), ... ] @@ -1058,23 +863,15 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u64:0x1020070, u64:0, ... ], - u32:4, + u32:2, ExtendedPacket[128]:[ - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:5, data: u64:0x0, length: u32:0 } - }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: false, last_block: false, id: u32:5, data: u64:0xf06, length: u32:3 } - }, - ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: false, last_block: false, id: u32:5, data: u64:0, length: u32:0 } + packet: BlockDataPacket { last: false, last_block: false, id: u32:5, data: uN[TEST_AXI_DATA_W]:0xf060003, length: u32:0 } }, ExtendedPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - packet: BlockDataPacket { last: true, last_block: false, id: u32:5, data: u64:0x2b77, length: u32:4 } + packet: BlockDataPacket { last: true, last_block: false, id: u32:5, data: uN[TEST_AXI_DATA_W]:0x2b770004, length: u32:0 } }, zero!(), ... ], @@ -1108,8 +905,8 @@ const COMP_BLOCK_DEC_TESTCASES: (u32, u64[64], u32, ExtendedPacket[128])[7] = [ u32:1, ExtendedPacket[128]:[ ExtendedPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - packet: BlockDataPacket { last: true, last_block: false, id: u32:6, data: u64:0x215a, length: u32:2 } + msg_type: SequenceExecutorMessageType::SEQUENCE, + packet: BlockDataPacket { last: true, last_block: false, id: u32:6, data: uN[TEST_AXI_DATA_W]:0x0, length: u32:2 } }, zero!(), ... ], @@ -1159,7 +956,7 @@ proc CompressBlockDecoderTest { type LiteralsDecResp = literals_decoder::LiteralsDecoderCtrlResp; type LiteralsBufCtrl = common::LiteralsBufferCtrl; - type SequenceExecutorPacket = common::SequenceExecutorPacket; + type SequenceExecutorPacket = common::SequenceExecutorPacket; type CommandConstructorData = common::CommandConstructorData; type HuffmanWeightsReadReq = ram::ReadReq; @@ -1239,6 +1036,9 @@ proc CompressBlockDecoderTest { // output from Command constructor to Sequence executor let (cmd_constr_out_s, cmd_constr_out_r) = chan("cmd_constr_out"); + let (_lit_buf_ctrl_s, lit_buf_ctrl_r) = chan("lit_buf_ctrl"); + let (lit_buf_out_s, _lit_buf_out_r) = chan("lit_buf_out"); + // Huffman weights memory let (huffman_lit_weights_mem_rd_req_s, huffman_lit_weights_mem_rd_req_r) = chan("huffman_lit_weights_mem_rd_req"); let (huffman_lit_weights_mem_rd_resp_s, huffman_lit_weights_mem_rd_resp_r) = chan("huffman_lit_weights_mem_rd_resp"); @@ -1342,11 +1142,12 @@ proc CompressBlockDecoderTest { }(()); // Literals buffer RAMs - let (litbuf_rd_req_s, litbuf_rd_req_r) = chan[u32:8]("litbuf_rd_req"); - let (litbuf_rd_resp_s, litbuf_rd_resp_r) = chan[u32:8]("litbuf_rd_resp"); - let (litbuf_wr_req_s, litbuf_wr_req_r) = chan[u32:8]("litbuf_wr_req"); - let (litbuf_wr_resp_s, litbuf_wr_resp_r) = chan[u32:8]("litbuf_wr_resp"); - unroll_for! (i, ()): (u32, ()) in u32:0..u32:8 { + const LITERALS_IN_PACKET = common::LITERALS_IN_PACKET; + let (litbuf_rd_req_s, litbuf_rd_req_r) = chan[LITERALS_IN_PACKET]("litbuf_rd_req"); + let (litbuf_rd_resp_s, litbuf_rd_resp_r) = chan[LITERALS_IN_PACKET]("litbuf_rd_resp"); + let (litbuf_wr_req_s, litbuf_wr_req_r) = chan[LITERALS_IN_PACKET]("litbuf_wr_req"); + let (litbuf_wr_resp_s, litbuf_wr_resp_r) = chan[LITERALS_IN_PACKET]("litbuf_wr_resp"); + unroll_for! (i, ()): (u32, ()) in u32:0..LITERALS_IN_PACKET { spawn ram::RamModel< TEST_LITERALS_BUFFER_RAM_DATA_W, TEST_LITERALS_BUFFER_RAM_SIZE, TEST_LITERALS_BUFFER_RAM_WORD_PARTITION_SIZE, TEST_RAM_SIM_RW_BEHAVIOR, TEST_RAM_INITIALIZED @@ -1513,14 +1314,11 @@ proc CompressBlockDecoderTest { axi_ram_ar_s[8], axi_ram_r_r[8], axi_ram_ar_s[9], axi_ram_r_r[9], axi_ram_ar_s[10], axi_ram_r_r[10], - litbuf_rd_req_s[0], litbuf_rd_req_s[1], litbuf_rd_req_s[2], litbuf_rd_req_s[3], - litbuf_rd_req_s[4], litbuf_rd_req_s[5], litbuf_rd_req_s[6], litbuf_rd_req_s[7], - litbuf_rd_resp_r[0], litbuf_rd_resp_r[1], litbuf_rd_resp_r[2], litbuf_rd_resp_r[3], - litbuf_rd_resp_r[4], litbuf_rd_resp_r[5], litbuf_rd_resp_r[6], litbuf_rd_resp_r[7], - litbuf_wr_req_s[0], litbuf_wr_req_s[1], litbuf_wr_req_s[2], litbuf_wr_req_s[3], - litbuf_wr_req_s[4], litbuf_wr_req_s[5], litbuf_wr_req_s[6], litbuf_wr_req_s[7], - litbuf_wr_resp_r[0], litbuf_wr_resp_r[1], litbuf_wr_resp_r[2], litbuf_wr_resp_r[3], - litbuf_wr_resp_r[4], litbuf_wr_resp_r[5], litbuf_wr_resp_r[6], litbuf_wr_resp_r[7], + litbuf_rd_req_s, litbuf_rd_resp_r, + litbuf_wr_req_s, litbuf_wr_resp_r, + + lit_buf_ctrl_r, lit_buf_out_s, + huffman_lit_weights_mem_rd_req_s, huffman_lit_weights_mem_rd_resp_r, huffman_lit_weights_mem_wr_req_s, huffman_lit_weights_mem_wr_resp_r, huffman_lit_prescan_mem_rd_req_s, huffman_lit_prescan_mem_rd_resp_r, @@ -1603,8 +1401,7 @@ proc CompressBlockDecoderTest { let tok = send(tok, ml_sel_test_req_s, u1:1); let (tok, _) = recv(tok, ml_sel_test_resp_r); - // TODO: Enable more test cases when posssible. Currently their number is limited to lower the RAM consumption - let tok = unroll_for!(test_i, tok): (u32, token) in u32[2]:[u32:0, u32:4] { + let tok = unroll_for!(test_i, tok): (u32, token) in u32[7]:[u32:0, u32:1, u32:2, u32:3, u32:4, u32:5, u32:6] { let (input_length, input, output_length, output) = COMP_BLOCK_DEC_TESTCASES[test_i]; trace_fmt!("Loading testcase {}", test_i); diff --git a/xls/modules/zstd/comp_block_enc.x b/xls/modules/zstd/comp_block_enc.x new file mode 100644 index 0000000000..cc3b1a9c90 --- /dev/null +++ b/xls/modules/zstd/comp_block_enc.x @@ -0,0 +1,274 @@ +// Copyright 2025 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 contains CompressBlockEncoder proc implementation +// The proc: +// 1. runs MatchFinder on input data which populates literals and sequences buffers +// 2. runs LiteralsEncoder on the literals from the literals buffer (RAW for now) +// 3. runs SequenceEncoder on the sequences (only PREDEFINED for now) +import std; + +import xls.examples.ram; +import xls.modules.zstd.common; +import xls.modules.zstd.mem_copy; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.history_buffer; +import xls.modules.zstd.hash_table; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.match_finder; +import xls.modules.zstd.literal_encoder; +import xls.modules.zstd.sequence_encoder; + +pub struct CompressBlockEncoderReq { + addr: uN[ADDR_W], + size: uN[ADDR_W], + out_addr: uN[ADDR_W], +} + +pub enum CompressBlockEncoderStatus : u1 { + OK = 0, + ERROR = 1, +} + +pub struct CompressBlockEncoderResp { + status: CompressBlockEncoderStatus, + length: uN[ADDR_W], +} + +pub proc CompressBlockEncoder +{ + type Req = CompressBlockEncoderReq; + type Resp = CompressBlockEncoderResp; + type Status = CompressBlockEncoderStatus; + // input/output + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemReaderStatus = mem_reader::MemReaderStatus; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + // match finder + type MfResp = match_finder::MatchFinderResp; + type MfParams = match_finder::ZstdParams; + type MfReq = match_finder::MatchFinderReq; + type MfRespStatus = match_finder::MatchFinderRespStatus; + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + type HashTableRdReq = hash_table::HashTableReadReq; + type HashTableRdResp = hash_table::HashTableReadResp; + type HashTableWrReq = hash_table::HashTableWriteReq; + type HashTableWrResp = hash_table::HashTableWriteResp; + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + // literals encoder + type RawMemcopyBlockType = mem_copy::RawMemcopyBlockType; + type RawMemcopyStatus = mem_copy::RawMemcopyStatus; + type RawMemcopyReq = mem_copy::RawMemcopyReq; + type RawMemcopyResp = mem_copy::RawMemcopyResp; + // sequence encoder + type SeReq = sequence_encoder::SequenceEncoderReq; + type SeResp = sequence_encoder::SequenceEncoderResp; + type SeRespStatus = sequence_encoder::SequenceEncoderStatus; + type CTableRamRdReq = ram::ReadReq; + type CTableRamRdResp = ram::ReadResp; + type TTableRamRdReq = ram::ReadReq; + type TTableRamRdResp = ram::ReadResp; + req_r: chan in; + resp_s: chan out; + mf_req_s: chan out; + mf_resp_r: chan in; + le_req_s: chan out; + le_resp_r: chan in; + se_req_s: chan out; + se_resp_r: chan in; + + // input/output + + // match finder + + // literals encoder + + // sequence encoder + config(req_r: chan in, resp_s: chan out, input_mem_rd_req_s: chan out, + input_mem_rd_resp_r: chan in, mf_buf_mem_rd_req_s: chan out, + mf_buf_mem_rd_resp_r: chan in, + mf_buf_mem_wr_req_s: chan out, + mf_buf_mem_wr_data_s: chan out, + mf_buf_mem_wr_resp_r: chan in, + hb_ram_rd_req_s: chan[HB_RAM_NUM] out, + hb_ram_rd_resp_r: chan[HB_RAM_NUM] in, + hb_ram_wr_req_s: chan[HB_RAM_NUM] out, + hb_ram_wr_resp_r: chan[HB_RAM_NUM] in, + ht_ram_rd_req_s: chan out, + ht_ram_rd_resp_r: chan in, + ht_ram_wr_req_s: chan out, + ht_ram_wr_resp_r: chan in, + lhw_output_mem_wr_req_s: chan out, + lhw_output_mem_wr_data_s: chan out, + lhw_output_mem_wr_resp_r: chan in, + le_output_mem_wr_req_s: chan out, + le_output_mem_wr_data_s: chan out, + le_output_mem_wr_resp_r: chan in, + se_output_mem_wr_req_s: chan out, + se_output_mem_wr_data_s: chan out, + se_output_mem_wr_resp_r: chan in, + ml_ctable_ram_rd_req_s: chan out, + ml_ctable_ram_rd_resp_r: chan in, + ll_ctable_ram_rd_req_s: chan out, + ll_ctable_ram_rd_resp_r: chan in, + of_ctable_ram_rd_req_s: chan out, + of_ctable_ram_rd_resp_r: chan in, + ml_ttable_ram_rd_req_s: chan out, + ml_ttable_ram_rd_resp_r: chan in, + ll_ttable_ram_rd_req_s: chan out, + ll_ttable_ram_rd_resp_r: chan in, + of_ttable_ram_rd_req_s: chan out, + of_ttable_ram_rd_resp_r: chan in) { + const CHANNEL_DEPTH = u32:1; + + // match finder + let (mf_req_s, mf_req_r) = chan("mf_req"); + let (mf_resp_s, mf_resp_r) = chan("mf_resp"); + let (ht_rd_req_s, ht_rd_req_r) = chan("ht_rd_req"); + let (ht_rd_resp_s, ht_rd_resp_r) = chan("ht_rd_resp"); + let (ht_wr_req_s, ht_wr_req_r) = chan("ht_wr_req"); + let (ht_wr_resp_s, ht_wr_resp_r) = chan("ht_wr_resp"); + let (hb_rd_req_s, hb_rd_req_r) = chan("hb_rd_req"); + let (hb_rd_resp_s, hb_rd_resp_r) = chan("hb_rd_resp"); + let (hb_wr_req_s, hb_wr_req_r) = chan("hb_wr_req"); + let (hb_wr_resp_s, hb_wr_resp_r) = chan("hb_wr_resp"); + + let (n_mf_buf_mem_rd_req_s, n_mf_buf_mem_rd_req_r) = + chan[3]("n_mf_buf_rd_req"); + let (n_mf_buf_mem_rd_resp_s, n_mf_buf_mem_rd_resp_r) = + chan[3]("n_mf_buf_rd_resp"); + let (mem_wr_req_s, mem_wr_req_r) = + chan[2]("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = + chan[2]("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = + chan[2]("mem_wr_resp"); + + // literals encoder + let (le_req_s, le_req_r) = chan("le_req"); + let (le_resp_s, le_resp_r) = chan("le_resp"); + + // sequence encoder + let (se_req_s, se_req_r) = chan("se_req"); + let (se_resp_s, se_resp_r) = chan("se_resp"); + + // match finder + spawn hash_table::HashTable( + ht_rd_req_r, ht_rd_resp_s, ht_wr_req_r, ht_wr_resp_s, ht_ram_rd_req_s, ht_ram_rd_resp_r, + ht_ram_wr_req_s, ht_ram_wr_resp_r); + spawn history_buffer::HistoryBuffer( + hb_rd_req_r, hb_rd_resp_s, hb_wr_req_r, hb_wr_resp_s, hb_ram_rd_req_s, hb_ram_rd_resp_r, + hb_ram_wr_req_s, hb_ram_wr_resp_r); + spawn match_finder::MatchFinder< + ADDR_W, DATA_W, HT_SIZE, HB_SIZE, MIN_SEQ_LEN, DATA_W_LOG2, HT_KEY_W, HT_VALUE_W, HT_SIZE_W, HB_DATA_W, HB_OFFSET_W>( + mf_req_r, mf_resp_s, input_mem_rd_req_s, input_mem_rd_resp_r, mf_buf_mem_wr_req_s, + mf_buf_mem_wr_data_s, mf_buf_mem_wr_resp_r, ht_rd_req_s, ht_rd_resp_r, ht_wr_req_s, + ht_wr_resp_r, hb_rd_req_s, hb_rd_resp_r, hb_wr_req_s, hb_wr_resp_r); + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter( + n_mf_buf_mem_rd_req_r, n_mf_buf_mem_rd_resp_s, mf_buf_mem_rd_req_s, mf_buf_mem_rd_resp_r); + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter( + mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s, + le_output_mem_wr_req_s, le_output_mem_wr_data_s, le_output_mem_wr_resp_r, + ); + // literals encoder + spawn literal_encoder::LiteralsEncoder( + le_req_r, le_resp_s, + n_mf_buf_mem_rd_req_s[0], n_mf_buf_mem_rd_resp_r[0], + lhw_output_mem_wr_req_s, lhw_output_mem_wr_data_s, lhw_output_mem_wr_resp_r, + mem_wr_req_s[0], mem_wr_data_s[0], mem_wr_resp_r[0], + n_mf_buf_mem_rd_req_s[1], n_mf_buf_mem_rd_resp_r[1], + mem_wr_req_s[1], mem_wr_data_s[1], mem_wr_resp_r[1] + ); + + // sequence encoder + spawn sequence_encoder::SequenceEncoder< + ADDR_W, DATA_W, FSE_TABLE_RAM_ADDR_W, FSE_CTABLE_RAM_DATA_W, FSE_CTABLE_RAM_NUM_PARTITIONS, FSE_TTABLE_RAM_DATA_W, FSE_TTABLE_RAM_NUM_PARTITIONS, BITSTREAM_BUFFER_W>( + se_req_r, se_resp_s, n_mf_buf_mem_rd_req_s[2], n_mf_buf_mem_rd_resp_r[2], + se_output_mem_wr_req_s, se_output_mem_wr_data_s, se_output_mem_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, ll_ctable_ram_rd_req_s, + ll_ctable_ram_rd_resp_r, of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, ll_ttable_ram_rd_req_s, + ll_ttable_ram_rd_resp_r, of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r); + + (req_r, resp_s, mf_req_s, mf_resp_r, le_req_s, le_resp_r, se_req_s, se_resp_r) + } + + init { } + + next(state: ()) { + type Addr = uN[ADDR_W]; + + let tok = join(); + let (tok, req) = recv(tok, req_r); + trace_fmt!("[CompressBlockEncoder] received compression request {:#x}", req); + + let tok = send( + tok, mf_req_s, + MfReq { + input_addr: req.addr, + input_size: req.size, + output_lit_addr: LITERALS_BUFFER_AXI_ADDR as Addr, + output_seq_addr: SEQUENCE_BUFFER_AXI_ADDR as Addr, + zstd_params: MfParams { num_entries_log2: std::clog2(HT_SIZE) as uN[HT_SIZE_W] }, + }); + let (tok, mf_resp) = recv(tok, mf_resp_r); + trace_fmt!("[CompressBlockEncoder] received Match Finder response {:#x}", mf_resp); + + let tok = send( + tok, le_req_s, + RawMemcopyReq { + lit_addr: LITERALS_BUFFER_AXI_ADDR, + lit_cnt: mf_resp.lit_cnt, + out_addr: req.out_addr, + }); + let (tok, le_resp) = recv(tok, le_resp_r); + trace_fmt!("[CompressBlockEncoder] received Literals encoder response {:#x}", le_resp); + + let tok = send( + tok, se_req_s, + SeReq { + addr: req.out_addr + le_resp.length, + seq_addr: SEQUENCE_BUFFER_AXI_ADDR, + seq_cnt: mf_resp.seq_cnt as u17, + }); + let (tok, se_resp) = recv(tok, se_resp_r); + + trace_fmt!("[CompressBlockEncoder] received Sequence encoder response {:#x}", se_resp); + + let resp = Resp { length: le_resp.length + se_resp.length, status: Status::OK }; + trace_fmt!("[CompressBlockEncoder] sent back response {:#x}", resp); + let tok = send(tok, resp_s, resp); + } +} diff --git a/xls/modules/zstd/comp_lookup_dec.x b/xls/modules/zstd/comp_lookup_dec.x index aab59ba0a2..c90c7f5a72 100644 --- a/xls/modules/zstd/comp_lookup_dec.x +++ b/xls/modules/zstd/comp_lookup_dec.x @@ -33,6 +33,7 @@ pub struct CompLookupDecoderResp { status: CompLookupDecoderStatus, accuracy_log: AccuracyLog, consumed_bytes: ConsumedFseBytes, + remainder: common::Remainder, } pub proc CompLookupDecoder< @@ -132,7 +133,7 @@ pub proc CompLookupDecoder< let (fse_pf_dec_resp_s, fse_pf_dec_resp_r) = chan("fse_pf_dec_resp"); spawn fse_proba_freq_dec::FseProbaFreqDecoder< - DPD_RAM_DATA_W, DPD_RAM_ADDR_W, DPD_RAM_NUM_PARTITIONS, + DPD_RAM_DATA_W, DPD_RAM_ADDR_W, DPD_RAM_NUM_PARTITIONS, AXI_DATA_W, SB_LENGTH_W >( fse_pf_dec_req_r, fse_pf_dec_resp_s, buffer_ctrl_s, buffer_data_out_r, @@ -151,7 +152,7 @@ pub proc CompLookupDecoder< let (tok, start_req) = recv(tok, req_r); // start FSE probability frequency decoder - let tok = send(tok, fse_pf_dec_req_s, FsePFDecReq {}); + let tok = send(tok, fse_pf_dec_req_s, FsePFDecReq { remainder: start_req.remainder }); // wait for completion from FSE probability frequency decoder let (tok, pf_dec_res) = recv(tok, fse_pf_dec_resp_r); @@ -173,6 +174,7 @@ pub proc CompLookupDecoder< status: Status::OK, accuracy_log: pf_dec_res.accuracy_log, consumed_bytes: pf_dec_res.consumed_bytes, + remainder: pf_dec_res.remainder, } } else { Resp { status: Status::ERROR, ..zero!() } @@ -268,7 +270,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x0, num_of_bits: u8:0x0, base: u16:0x15 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3} + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3, remainder: zero!() } ), ( u64[64]:[u64:0x1861862062081932, u64:0xC18628A106184184, u64:0x850720FACC49238, u64:0, ...], @@ -403,7 +405,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x9, num_of_bits: u8:0x6, base: u16:0x40 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:7, consumed_bytes: ConsumedFseBytes:21} + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:7, consumed_bytes: ConsumedFseBytes:21, remainder: zero!() } ), ( u64[64]:[u64:0x60C3082082085072, u64:0x1C06F8077D850F20, u64:0, ...], @@ -538,7 +540,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0xb, num_of_bits: u8:0x3, base: u16:0x58 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:7, consumed_bytes: ConsumedFseBytes:13 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:7, consumed_bytes: ConsumedFseBytes:13, remainder: zero!() } ), ( u64[64]:[u64:0x41081C158003A5D0, u64:0, ...], @@ -577,7 +579,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x0, num_of_bits: u8:0x0, base: u16:0x17 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3, remainder: zero!() } ), ( u64[64]:[u64:0x1101141108088A1, u64:0xA210842108421011, u64:0xAC90E792007A5B4, u64:0, ...], @@ -648,7 +650,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x1c, num_of_bits: u8:0x3, base: u16:0x8 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:6, consumed_bytes: ConsumedFseBytes:19 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:6, consumed_bytes: ConsumedFseBytes:19, remainder: zero!() } ), ( u64[64]:[u64:0x4AF830AC90E7920, u64:0, ...], @@ -687,7 +689,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x1, num_of_bits: u8:0x1, base: u16:0xa }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3, remainder: zero!() } ), ( u64[64]:[u64:0xF47FFEBBFF1D25C0, u64:0, ...], @@ -726,7 +728,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x0, num_of_bits: u8:0x0, base: u16:0x15 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:3, remainder: zero!() } ), ( u64[64]:[u64:0xA84DF134544CA40, u64:0xEEC609988403B0C, u64:0, ...], @@ -765,7 +767,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x14, num_of_bits: u8:0x3, base: u16:0x8 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:10 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:10, remainder: zero!() } ), ( u64[64]:[u64:0x38100EEC60998840, u64:0, ...], @@ -804,7 +806,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x7, num_of_bits: u8:0x2, base: u16:0xc }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:6 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:6, remainder: zero!() } ), ( u64[64]:[u64:0x6B1CA24D0CE43810, u64:0x6651065104A4DFFD, u64:0, ...], @@ -843,7 +845,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0xf, num_of_bits: u8:0x3, base: u16:0x8 }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:10 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, consumed_bytes: ConsumedFseBytes:10, remainder: zero!() } ), ( u64[64]:[u64:0x604FC0502602814, u64:0xE030505040131FF6, u64:0, ...], @@ -1361,7 +1363,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x10, num_of_bits: u8:0x2, base: u16:0x1fc }, FseTableRecord { symbol: u8:0x5, num_of_bits: u8:0x2, base: u16:0x1fc }, ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:9, consumed_bytes: ConsumedFseBytes:10 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:9, consumed_bytes: ConsumedFseBytes:10, remainder: zero!() } ), ( u64[64]:[u64:0x140FE03050504013, u64:0, ...], @@ -1624,7 +1626,7 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x5, num_of_bits: u8:0x2, base: u16:0xfc }, zero!(), ... ], - CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:8, consumed_bytes: ConsumedFseBytes:7 } + CompLookupDecoderResp { status: CompLookupDecoderStatus::OK, accuracy_log: AccuracyLog:8, consumed_bytes: ConsumedFseBytes:7, remainder: zero!() } ), ]; @@ -1793,7 +1795,7 @@ proc CompLookupDecoderTest { next(_: ()) { let tok = join(); // This has to be outside of unroll_for!, otherwise typechecker reports type mismatch on identical types - let req_start = Req {}; + let req_start = zero!(); let tok = unroll_for!(test_i, tok): (u32, token) in u32:0..array_size(COMP_LOOKUP_DECODER_TESTCASES) { let (input, output, resp_ok) = COMP_LOOKUP_DECODER_TESTCASES[test_i]; diff --git a/xls/modules/zstd/data/comp_frame.x b/xls/modules/zstd/data/comp_frame.x index 9d0c1a0f4c..dec43eab0b 100644 --- a/xls/modules/zstd/data/comp_frame.x +++ b/xls/modules/zstd/data/comp_frame.x @@ -21,7 +21,7 @@ pub const FRAMES:DataArray< >[1] = [DataArray<64, 50>{ length: u32:51, array_length: u32:7, - data: uN[64][50]:[uN[64]:0x00504784fd2fb528, uN[64]:0xcf95700001150000, uN[64]:0xe17d50b989ac93c4, uN[64]:0x0daf000895a6e608, uN[64]:0xb96010b86f7602a4, uN[64]:0x05b0e051238666e8, uN[64]:0x8470e3, uN[64]:0, ...] + data: uN[64][50]:[uN[64]:0x00502f84fd2fb528, uN[64]:0xcf95700001150000, uN[64]:0xe17d50b989ac93c4, uN[64]:0x0daf000895a6e608, uN[64]:0xb96010b86f7602a4, uN[64]:0x05b0e051238666e8, uN[64]:0x8470e3, uN[64]:0, ...] }]; pub const DECOMPRESSED_FRAMES:DataArray< u32:64, diff --git a/xls/modules/zstd/data/comp_frame_fse_comp.x b/xls/modules/zstd/data/comp_frame_fse_comp.x index faf3ff66e2..dd2427d39c 100644 --- a/xls/modules/zstd/data/comp_frame_fse_comp.x +++ b/xls/modules/zstd/data/comp_frame_fse_comp.x @@ -21,7 +21,7 @@ pub const FRAMES:DataArray< >[1] = [DataArray<64, 50>{ length: u32:66, array_length: u32:9, - data: uN[64][50]:[uN[64]:0x00545084fd2fb528, uN[64]:0x4236d000018d0000, uN[64]:0x1d98357537f4050f, uN[64]:0x8d92b5aed6d7791b, uN[64]:0x51538ed729019574, uN[64]:0x701101fb8611a803, uN[64]:0x8acfff857107d159, uN[64]:0x548604b38e0a63fd, uN[64]:0xc551, uN[64]:0, ...] + data: uN[64][50]:[uN[64]:0x00542f84fd2fb528, uN[64]:0x4236d000018d0000, uN[64]:0x1d98357537f4050f, uN[64]:0x8d92b5aed6d7791b, uN[64]:0x51538ed729019574, uN[64]:0x701101fb8611a803, uN[64]:0x8acfff857107d159, uN[64]:0x548604b38e0a63fd, uN[64]:0xc551, uN[64]:0, ...] }]; pub const DECOMPRESSED_FRAMES:DataArray< u32:64, diff --git a/xls/modules/zstd/data/comp_frame_huffman.x b/xls/modules/zstd/data/comp_frame_huffman.x index b41ddf275f..c4ce570089 100644 --- a/xls/modules/zstd/data/comp_frame_huffman.x +++ b/xls/modules/zstd/data/comp_frame_huffman.x @@ -21,7 +21,7 @@ pub const FRAMES:DataArray< >[1] = [DataArray<64, 50>{ length: u32:93, array_length: u32:12, - data: uN[64][50]:[uN[64]:0x00704484fd2fb528, uN[64]:0xac033a0002650000, uN[64]:0x1111111111118e00, uN[64]:0x0007000700071011, uN[64]:0x131a053a5606874c, uN[64]:0x93b7146cb45c3584, uN[64]:0x06499215949aa275, uN[64]:0x0132000c0126fd3b, uN[64]:0x15a7b54443de03b8, uN[64]:0x5da6a9b37c005000, uN[64]:0x4e0200656960219d, uN[64]:0x912a65cf0b, uN[64]:0, ...] + data: uN[64][50]:[uN[64]:0x00702f84fd2fb528, uN[64]:0xac033a0002650000, uN[64]:0x1111111111118e00, uN[64]:0x0007000700071011, uN[64]:0x131a053a5606874c, uN[64]:0x93b7146cb45c3584, uN[64]:0x06499215949aa275, uN[64]:0x0132000c0126fd3b, uN[64]:0x15a7b54443de03b8, uN[64]:0x5da6a9b37c005000, uN[64]:0x4e0200656960219d, uN[64]:0x912a65cf0b, uN[64]:0, ...] }]; pub const DECOMPRESSED_FRAMES:DataArray< u32:64, diff --git a/xls/modules/zstd/data/comp_frame_huffman_fse.x b/xls/modules/zstd/data/comp_frame_huffman_fse.x index c1e78b95cb..781657ec31 100644 --- a/xls/modules/zstd/data/comp_frame_huffman_fse.x +++ b/xls/modules/zstd/data/comp_frame_huffman_fse.x @@ -22,7 +22,7 @@ pub const FRAMES:DataArray< >[1] = [DataArray<64, 50>{ length: u32:64, array_length: u32:8, - data: uN[64][50]:[uN[64]:0x007e4f84fd2fb528, uN[64]:0x00068e00017d0000, uN[64]:0xd5764f39f0080008, uN[64]:0x04000400045c4f40, uN[64]:0xcfefff3e7fefff00, uN[64]:0x5dff77afbdffef3f, uN[64]:0x1de190b0000301fb, uN[64]:0x807e83a8084e0c21, uN[64]:0, ...] + data: uN[64][50]:[uN[64]:0x007e2f84fd2fb528, uN[64]:0x00068e00017d0000, uN[64]:0xd5764f39f0080008, uN[64]:0x04000400045c4f40, uN[64]:0xcfefff3e7fefff00, uN[64]:0x5dff77afbdffef3f, uN[64]:0x1de190b0000301fb, uN[64]:0x807e83a8084e0c21, uN[64]:0, ...] }]; pub const DECOMPRESSED_FRAMES:DataArray< u32:64, diff --git a/xls/modules/zstd/data/comp_frame_unsupported_window.x b/xls/modules/zstd/data/comp_frame_unsupported_window.x new file mode 100644 index 0000000000..c98a50cb61 --- /dev/null +++ b/xls/modules/zstd/data/comp_frame_unsupported_window.x @@ -0,0 +1,36 @@ +// Copyright 2025 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.zstd.common; +type DataArray = common::DataArray; + +// Same data as comp_frame.x, but with too large required window size +// for current ZSTD decoder parameters: 491520 vs 65536 bytes. + +pub const FRAMES:DataArray< + u32:64, + u32:50 +>[1] = [DataArray<64, 50>{ + length: u32:51, + array_length: u32:7, + data: uN[64][50]:[uN[64]:0x00504784fd2fb528, uN[64]:0xcf95700001150000, uN[64]:0xe17d50b989ac93c4, uN[64]:0x0daf000895a6e608, uN[64]:0xb96010b86f7602a4, uN[64]:0x05b0e051238666e8, uN[64]:0x8470e3, uN[64]:0, ...] +}]; +pub const DECOMPRESSED_FRAMES:DataArray< + u32:64, + u32:50 +>[1] = [DataArray<64, 50>{ + length: u32:80, + array_length: u32:10, + data: uN[64][50]:[uN[64]:0xc4c4cf95cf95cf95, uN[64]:0x93c4c4c4c4c4c4c4, uN[64]:0xacc493c493c493c4, uN[64]:0xc493c493c493c489, uN[64]:0x93c493c489acc493, uN[64]:0x08e17d50b9c493c4, uN[64]:0xc4c4c4cf9595a6e6, uN[64]:0x93c493c4c4c4c4c4, uN[64]:0xc489acc493c493c4, uN[64]:0xc493c493c493c493, uN[64]:0, ...] +}]; diff --git a/xls/modules/zstd/data/enc_pregenerate.sh b/xls/modules/zstd/data/enc_pregenerate.sh new file mode 100755 index 0000000000..d4be5bccf9 --- /dev/null +++ b/xls/modules/zstd/data/enc_pregenerate.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +DATA_DIR="xls/modules/zstd/data" +sizes=(1024 1030 200 300 500 2000) + +for size in "${sizes[@]}";do + filename=enc_pregenerated_"$size"B + filepath="$DATA_DIR/$filename" + dd if=/dev/urandom of="$filepath" bs=1B count="$size" +done diff --git a/xls/modules/zstd/data/enc_pregenerated_1024B b/xls/modules/zstd/data/enc_pregenerated_1024B new file mode 100644 index 0000000000..e28237f6cb Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_1024B differ diff --git a/xls/modules/zstd/data/enc_pregenerated_1030B b/xls/modules/zstd/data/enc_pregenerated_1030B new file mode 100644 index 0000000000..209dfa766d Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_1030B differ diff --git a/xls/modules/zstd/data/enc_pregenerated_2000B b/xls/modules/zstd/data/enc_pregenerated_2000B new file mode 100644 index 0000000000..819843b169 Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_2000B differ diff --git a/xls/modules/zstd/data/enc_pregenerated_200B b/xls/modules/zstd/data/enc_pregenerated_200B new file mode 100644 index 0000000000..e6623c2882 Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_200B differ diff --git a/xls/modules/zstd/data/enc_pregenerated_300B b/xls/modules/zstd/data/enc_pregenerated_300B new file mode 100644 index 0000000000..1c55237b22 Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_300B differ diff --git a/xls/modules/zstd/data/enc_pregenerated_500B b/xls/modules/zstd/data/enc_pregenerated_500B new file mode 100644 index 0000000000..be3337a56c Binary files /dev/null and b/xls/modules/zstd/data/enc_pregenerated_500B differ diff --git a/xls/modules/zstd/dec_mux.x b/xls/modules/zstd/dec_mux.x index 681b1b402d..0f4c4d51b7 100644 --- a/xls/modules/zstd/dec_mux.x +++ b/xls/modules/zstd/dec_mux.x @@ -23,12 +23,12 @@ type BlockDataPacket = common::BlockDataPacket; type ExtendedBlockDataPacket = common::ExtendedBlockDataPacket; type BlockData = common::BlockData; type BlockPacketLength = common::BlockPacketLength; -type CopyOrMatchContent = common::CopyOrMatchContent; +type CopyOrMatchContent = uN[common::LITERALS_IN_PACKET * u32:8]; type CopyOrMatchLength = common::CopyOrMatchLength; type SequenceExecutorMessageType = common::SequenceExecutorMessageType; -type SequenceExecutorPacket = common::SequenceExecutorPacket; +type SequenceExecutorPacket = common::SequenceExecutorPacket; -const MAX_ID = common::DATA_WIDTH; +const MAX_ID = all_ones!(); const DATA_WIDTH = common::DATA_WIDTH; struct DecoderMuxState { diff --git a/xls/modules/zstd/frame_header.x b/xls/modules/zstd/frame_header.x index 8159f1e47e..fab943ad5a 100644 --- a/xls/modules/zstd/frame_header.x +++ b/xls/modules/zstd/frame_header.x @@ -425,27 +425,17 @@ fn test_parse_frame_content_size() { assert_eq(frame_content_size, u64:0x0); } -// Calculate maximal accepted window_size for given WINDOW_LOG_MAX and return whether given -// window_size should be accepted or discarded. -// Based on window_size calculation from: RFC 8878 -// https://datatracker.ietf.org/doc/html/rfc8878#name-window-descriptor -fn window_size_valid(window_size: WindowSize) -> bool { - let max_window_size = (WindowSize:1 << WINDOW_LOG_MAX) + (((WindowSize:1 << WINDOW_LOG_MAX) >> WindowSize:3) * MAX_MANTISSA); - - window_size <= max_window_size -} - // Parses a Buffer with data and extracts Frame_Header information. The buffer // is assumed to contain a valid Frame_Header The function returns FrameHeaderResult // with BufferResult that contains outcome of the operations on the Buffer, // FrameHeader with the extracted frame header if the parsing was successful, // and the status of the operation in FrameHeaderStatus. On failure, the returned // buffer is the same as the input buffer. -// WINDOW_LOG_MAX is the base 2 logarithm used for calculating the maximal allowed -// window_size. Frame header parsing function must discard all frames that -// have window_size above the maximal allowed window_size. +// WINDOW_SIZE_MAX is the maximal window size allowed by the decoder and the +// frame header parsing function must discard all frames that +// requires a window size above the maximal allowed window size. // CAPACITY is the buffer capacity -pub fn parse_frame_header(buffer: Buffer) -> FrameHeaderResult { +pub fn parse_frame_header(buffer: Buffer) -> FrameHeaderResult { trace_fmt!("parse_frame_header: ==== Parsing ==== \n"); trace_fmt!("parse_frame_header: initial buffer: {:#x}", buffer); @@ -539,7 +529,7 @@ pub fn parse_frame_header(buffer: Buf buffer: zero!(), header: zero!(), } - } else if (!window_size_valid(header.window_size)) { + } else if (header.window_size > WINDOW_SIZE_MAX) { trace_fmt!("parse_frame_header: frame discarded: window_size to big: {}", header.window_size); FrameHeaderResult { status: FrameHeaderStatus::UNSUPPORTED_WINDOW_SIZE, @@ -553,12 +543,13 @@ pub fn parse_frame_header(buffer: Buf // The largest allowed WindowLog for DSLX tests pub const TEST_WINDOW_LOG_MAX = WindowSize:22; +pub const TEST_WINDOW_SIZE_MAX = calc_max_window_size(); #[test] fn test_parse_frame_header() { // normal cases let buffer = Buffer { content: bits[128]:0x1234567890ABCDEF_CAFE_09_C2, length: u32:96 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::OK, buffer: Buffer { @@ -575,7 +566,7 @@ fn test_parse_frame_header() { // SingleSegmentFlag is set and FrameContentSize is bigger than accepted window_size let buffer = Buffer { content: bits[128]:0x1234567890ABCDEF_CAFE_E2, length: u32:88 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::UNSUPPORTED_WINDOW_SIZE, buffer: Buffer { content: bits[128]:0x0, length: u32:0 }, @@ -583,7 +574,7 @@ fn test_parse_frame_header() { }); let buffer = Buffer { content: bits[128]:0xaa20, length: u32:16 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::OK, buffer: Buffer { @@ -600,7 +591,7 @@ fn test_parse_frame_header() { // when buffer is too short let buffer = Buffer { content: bits[128]:0x0, length: u32:0 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::NO_ENOUGH_DATA, buffer: buffer, @@ -608,7 +599,7 @@ fn test_parse_frame_header() { }); let buffer = Buffer { content: bits[128]:0xC2, length: u32:8 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::NO_ENOUGH_DATA, buffer: buffer, @@ -616,7 +607,7 @@ fn test_parse_frame_header() { }); let buffer = Buffer { content: bits[128]:0x09_C2, length: u32:16 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::NO_ENOUGH_DATA, buffer: buffer, @@ -624,7 +615,7 @@ fn test_parse_frame_header() { }); let buffer = Buffer { content: bits[128]:0x1234_09_C2, length: u32:32 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::NO_ENOUGH_DATA, buffer: buffer, @@ -632,7 +623,7 @@ fn test_parse_frame_header() { }); let buffer = Buffer { content: bits[128]:0x1234_09_C2, length: u32:32 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::NO_ENOUGH_DATA, buffer: buffer, @@ -641,7 +632,7 @@ fn test_parse_frame_header() { // when frame header descriptor is corrupted let buffer = Buffer { content: bits[128]:0x1234567890ABCDEF_1234_09_CA, length: u32:96 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::CORRUPTED, buffer: Buffer { content: bits[128]:0x0, length: u32:0 }, @@ -651,7 +642,7 @@ fn test_parse_frame_header() { // Frame Header is discarded because Window size required by frame is too big for given decoder // configuration let buffer = Buffer { content: bits[128]:0xd310, length: u32:16 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::UNSUPPORTED_WINDOW_SIZE, buffer: Buffer { content: bits[128]:0x0, length: u32:0 }, @@ -661,7 +652,7 @@ fn test_parse_frame_header() { // Frame Header is discarded because Frame Content Size required by frame is too big for given decoder // configuration let buffer = Buffer { content: bits[128]:0xf45b5b5b0db1, length: u32:48 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::UNSUPPORTED_WINDOW_SIZE, buffer: Buffer { content: bits[128]:0x0, length: u32:0 }, @@ -676,7 +667,7 @@ fn test_parse_frame_header() { // Frame Header is discarded because Frame Content Size required by frame is too big (above 64bits) for given decoder // configuration let buffer = Buffer { content: bits[128]:0xc0659db6813a16b33f3da53a79e4, length: u32:112 }; - let frame_header_result = parse_frame_header(buffer); + let frame_header_result = parse_frame_header(buffer); assert_eq(frame_header_result, FrameHeaderResult { status: FrameHeaderStatus::UNSUPPORTED_WINDOW_SIZE, buffer: Buffer { content: bits[128]:0x0, length: u32:0 }, diff --git a/xls/modules/zstd/frame_header_dec.x b/xls/modules/zstd/frame_header_dec.x index 8647435996..3b8e8ede18 100644 --- a/xls/modules/zstd/frame_header_dec.x +++ b/xls/modules/zstd/frame_header_dec.x @@ -180,15 +180,12 @@ fn test_frame_content_size_exists() { assert_eq(frame_content_size_exists(desc), true); } - -// Calculate maximal accepted window_size for given WINDOW_LOG_MAX and return whether given -// window_size should be accepted or discarded. +// Calculate maximal accepted window_size for given WINDOW_LOG_MAX // Based on window_size calculation from: RFC 8878 // https://datatracker.ietf.org/doc/html/rfc8878#name-window-descriptor -fn window_size_valid(window_size: WindowSize) -> bool { - let max_window_size = (WindowSize:1 << WINDOW_LOG_MAX) + (((WindowSize:1 << WINDOW_LOG_MAX) >> WindowSize:3) * MAX_MANTISSA); - - window_size <= max_window_size +pub fn calc_max_window_size() -> WindowSize { + const MAX_MANTISSA = WindowSize:0b111; + (WindowSize:1 << WINDOW_LOG_MAX) + (((WindowSize:1 << WINDOW_LOG_MAX) >> WindowSize:3) * MAX_MANTISSA) } @@ -381,7 +378,7 @@ struct FrameHeaderDecoderState { } pub proc FrameHeaderDecoder< - WINDOW_LOG_MAX: u32, + WINDOW_SIZE_MAX: WindowSize, DATA_W: u32, ADDR_W: u32, XFERS_FOR_HEADER: u32 = {((MAX_MAGIC_PLUS_HEADER_LEN * u32:8) / DATA_W) + u32:1}, @@ -430,7 +427,7 @@ pub proc FrameHeaderDecoder< let status = if (!header_ok || !magic_number_ok) { FrameHeaderDecoderStatus::CORRUPTED - } else if (!window_size_valid(decoded_header.window_size)) { + } else if (decoded_header.window_size > WINDOW_SIZE_MAX) { FrameHeaderDecoderStatus::UNSUPPORTED_WINDOW_SIZE } else { FrameHeaderDecoderStatus::OKAY @@ -473,6 +470,7 @@ pub proc FrameHeaderDecoder< // The largest allowed WindowLog for DSLX tests pub const TEST_WINDOW_LOG_MAX = u32:22; +pub const TEST_WINDOW_SIZE_MAX = calc_max_window_size(); pub const TEST_DATA_W = u32:32; pub const TEST_ADDR_W = u32:16; pub const TEST_XFERS_FOR_HEADER = ((MAX_MAGIC_PLUS_HEADER_LEN * u32:8) / TEST_DATA_W) + u32:1; @@ -497,7 +495,7 @@ proc FrameHeaderDecoderTest { let (reader_resp_s, reader_resp_r) = chan("reader_resp"); let (decode_req_s, decode_req_r) = chan("decode_req"); let (decode_resp_s, decode_resp_r) = chan("decode_resp"); - spawn FrameHeaderDecoder( + spawn FrameHeaderDecoder( reader_req_s, reader_resp_r, decode_req_r, @@ -636,6 +634,7 @@ proc FrameHeaderDecoderTest { // https://github.com/facebook/zstd/blob/v1.4.7/lib/decompress/zstd_decompress.c#L296 // Use only in C++ tests when comparing DSLX ZSTD Decoder with libzstd pub const TEST_WINDOW_LOG_MAX_LIBZSTD = u32:30; +pub const TEST_WINDOW_SIZE_MAX_LIBZSTD = calc_max_window_size(); proc FrameHeaderDecoderInst { type Req = FrameHeaderDecoderReq; @@ -655,7 +654,7 @@ proc FrameHeaderDecoderInst { decode_req_r: chan in, decode_resp_s: chan out, ) { - spawn FrameHeaderDecoder( + spawn FrameHeaderDecoder( reader_req_s, reader_resp_r, decode_req_r, diff --git a/xls/modules/zstd/frame_header_enc.x b/xls/modules/zstd/frame_header_enc.x new file mode 100644 index 0000000000..6ba9e4da8d --- /dev/null +++ b/xls/modules/zstd/frame_header_enc.x @@ -0,0 +1,496 @@ +// Copyright 2025 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.zstd.frame_header_dec; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.memory.mem_writer_data_downscaler; + + +pub type FrameContentSize = u64; +pub type DictionaryId = u32; +pub type HeaderSize = u5; + +type FrameHeader = frame_header_dec::FrameHeader; +type FrameHeaderDescriptor = frame_header_dec::FrameHeaderDescriptor; + +const MAX_WINDOW_LOG = u32:22; +const WINDOW_LOG_W = std::clog2(MAX_WINDOW_LOG + u32:1); +type WindowLog = uN[WINDOW_LOG_W]; + +pub struct FrameHeaderEncoderReq { + addr: uN[ADDR_W], + window_log: WindowLog, + src_size: u64, + dict_id: u32, + max_block_size: u64, + provide_dict_id: bool, + provide_checksum: bool, + provide_content_size: bool, + provide_window_size: bool, +} + +pub enum FrameHeaderEncoderStatus : u1 { + OKAY = 0, + ERROR = 1, +} + +pub struct FrameHeaderEncoderResp { + status: FrameHeaderEncoderStatus, + length: HeaderSize +} + +const MAGIC_NUMBER = u32:0xFD2FB528; +const MAGIC_NUMBER_LEN = u32:4; +const ZSTD_WINDOW_LOG_MIN = WindowLog:10; + +// Implemented as in https://github.com/facebook/zstd/blob/12ea5f6e30c5b0411dd39d29089b5ee4e0044403/lib/compress/zstd_compress.c#L4703 +fn create_frame_header_data( + window_log: WindowLog, src_size: u64, dict_id: u32, + provide_dict_id: bool, provide_checksum: bool, provide_content_size: bool, provide_window_size: bool, + max_block_size: u64 +) -> (uN[144], HeaderSize) { + type Size = HeaderSize; + type WindowSize = u64; + + const UNUSED_BIT = u1:0; + const RESERVED_BIT = u1:0; + + let dict_id_size_code_length = match (dict_id) { + u32:0 .. u32:1 => u2:0, + u32:1 .. u32:256 => u2:1, + u32:256 .. u32:65536 => u2:2, + _ => u2:3, + }; + let dict_id_size_code = if provide_dict_id { dict_id_size_code_length } else { u2:0 }; + + let window_size = WindowSize:1 << window_log; + let single_segment = provide_content_size && (window_size >= src_size) && max_block_size <= src_size; + let window_log_byte = ((window_log as u8 - ZSTD_WINDOW_LOG_MIN as u8) << 3) as u8; + + let fcs_code_length = match (src_size) { + u64:0 .. u64:256 => u2:0, + u64:256 .. u64:65792 => u2:1, + u64:65792 .. u64:0xFFFFFFFF => u2:2, + _ => u2:3 + }; + let fcs_code = if provide_content_size { fcs_code_length } else { u2:0 }; + let frame_header_desc_byte = fcs_code_length ++ single_segment ++ UNUSED_BIT + ++ RESERVED_BIT ++ provide_checksum ++ dict_id_size_code; + let raw_header = (frame_header_desc_byte as uN[112]) ++ MAGIC_NUMBER; + + // magic number + let (raw_header, size) = if !single_segment && provide_window_size { + (bit_slice_update(raw_header, u32:40, window_log_byte), Size:6) // size = magic number (4B) + desc (1B) + window (1B) + } else { + (raw_header, Size:5) // size = magic number + desc + }; + + let size_in_bits = size as u32 << 3; + let (raw_header, size) = match (provide_dict_id, dict_id_size_code) { + (false, _) => (raw_header, size), + (true, u2:0) => (raw_header, size), + (true, u2:1) => (bit_slice_update(raw_header, size_in_bits, dict_id as u8), size + Size:1), + (true, u2:2) => (bit_slice_update(raw_header, size_in_bits, dict_id as u16), size + Size:2), + (true, u2:3) => (bit_slice_update(raw_header, size_in_bits, dict_id as u32), size + Size:4), + _ => fail!("dictionary_id_unreachable", (raw_header, size)), + }; + + let size_in_bits = size as u32 << 3; + let (raw_header, size) = match (provide_content_size, fcs_code) { + (false, _) => { + (raw_header, size) + }, + (true, u2:0) => { + if single_segment { + (bit_slice_update(raw_header, size_in_bits, src_size as u8), size + Size:1) + } else { + (raw_header, size) + } + }, + (true, u2:1) => (bit_slice_update(raw_header, size_in_bits, (src_size - u64:256) as u16), size + Size:2), + (true, u2:2) => (bit_slice_update(raw_header, size_in_bits, src_size as u32), size + Size:4), + (true, u2:3) => (bit_slice_update(raw_header, size_in_bits, src_size as u64), size + Size:8), + _ => fail!("frame_content_size_unreachable", (raw_header, size)), + }; + + (raw_header, size) +} + +pub const TEST_DATA_W = u32:32; +pub const TEST_ADDR_W = u32:16; + +pub proc FrameHeaderEncoder< + DATA_W: u32, ADDR_W: u32, WINDOW_LOG_MAX: u32 = { MAX_WINDOW_LOG as u32 }, + MAX_HEADER_SIZE: u32 = {u32:144}, +> { + type Req = FrameHeaderEncoderReq; + type Resp = FrameHeaderEncoderResp; + type Status = FrameHeaderEncoderStatus; + type Addr = uN[ADDR_W]; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataWide = mem_writer::MemWriterDataPacket; + + req_r: chan in; + resp_s: chan out; + mem_wr_req_s: chan out; + mem_wr_data_wide_s: chan out; + mem_wr_resp_r: chan in; + + config( + req_r: chan in, + resp_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in + ) { + + let (mem_wr_data_wide_s, mem_wr_data_wide_r) = chan("mem_wr_data_wide"); + spawn mem_writer_data_downscaler::MemWriterDataDownscaler( + mem_wr_data_wide_r, mem_wr_data_s, + ); + + ( + req_r, resp_s, + mem_wr_req_s, mem_wr_data_wide_s, mem_wr_resp_r + ) + } + + init { () } + + next(state: ()) { + let tok0 = join(); + let (tok1, req) = recv(tok0, req_r); + let (data, data_len) = create_frame_header_data( + req.window_log, req.src_size, req.dict_id, + req.provide_dict_id, req.provide_checksum, req.provide_content_size, req.provide_window_size, + req.max_block_size + ); + + let length = checked_cast(data_len); + + let mem_wr_req = MemWriterReq { addr: req.addr, length }; + let tok2_0 = send(tok1, mem_wr_req_s, mem_wr_req); + let tok2_1 = send(tok1, mem_wr_data_wide_s, MemWriterDataWide { data, length, last: true }); + let tok2 = join(tok2_0, tok2_1); + let (tok3, mem_wr_resp) = recv(tok2, mem_wr_resp_r); + let status = if mem_wr_resp.status == mem_writer::MemWriterRespStatus::OKAY { Status::OKAY } else {Status::ERROR}; + let tok = send(tok3, resp_s, Resp { status, length: data_len }); + } +} + +proc FrameHeaderEncoderInst { + type Req = FrameHeaderEncoderReq; + type Resp = FrameHeaderEncoderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + config( + req_r: chan in, + resp_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + spawn FrameHeaderEncoder< TEST_DATA_W, TEST_ADDR_W>( + req_r, resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ); + + () + } + + init { } + next(state: ()) { } +} + +struct TestCase { + req: FrameHeaderEncoderReq, + resp: FrameHeaderEncoderResp, + mem_wr_req: mem_writer::MemWriterReq, + mem_wr_resp: mem_writer::MemWriterResp, + mem_wr_data: mem_writer::MemWriterDataPacket[5], + mem_wr_data_length: u32, +} + +#[test_proc] +proc FrameHeaderEncoderTest { + type Req = FrameHeaderEncoderReq; + type Resp = FrameHeaderEncoderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + type TestCase = TestCase; + + type Data = uN[TEST_DATA_W]; + type Addr = uN[TEST_ADDR_W]; + + terminator: chan out; + req_s: chan out; + resp_r: chan in; + + mem_wr_req_r: chan in; + mem_wr_data_r: chan in; + mem_wr_resp_s: chan out; + + config(terminator: chan out) { + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + + spawn FrameHeaderEncoder( + req_r, resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ); + + ( + terminator, + req_s, resp_r, + mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s + ) + } + + init { } + + next(state: ()) { + const TEST_CASES = [ + TestCase { // 0 + // * content size encoding + // * window size encoding + // * no single segment + req: FrameHeaderEncoderReq { + addr: Addr:1234, + window_log: WindowLog:22, + src_size: u64:0x3a16b33f3da53a79, + max_block_size: u64:0x1000, + dict_id: u32:0, + provide_dict_id: false, + provide_checksum: true, + provide_content_size: true, + provide_window_size: true, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:14 }, + mem_wr_req: MemWriterReq { addr: Addr:1234, length: Addr:14 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x3A7960C4, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0xB33F3DA5, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00003A16, length: Addr:2, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:4, + }, + TestCase { // 1 + // * dict id encoding + req: FrameHeaderEncoderReq { + addr: Addr:1234, + window_log: WindowLog:22, + src_size: u64:0x3a16b33f3da53a79, + max_block_size: u64:0x1000, + dict_id: u32:0xCAFE, + provide_dict_id: true, + provide_checksum: true, + provide_content_size: true, + provide_window_size: true, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:16 }, + mem_wr_req: MemWriterReq { addr: Addr:1234, length: Addr:16 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0xCAFE60C6, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x3DA53A79, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x3A16B33F, length: Addr:4, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:4, + }, + TestCase { // 2 + // * checksum flag disabled + req: FrameHeaderEncoderReq { + addr: Addr:1234, + window_log: WindowLog:22, + src_size: u64:0x3a16b33f3da53a79, + max_block_size: u64:0x1000, + dict_id: u32:0xCAFE, + provide_dict_id: true, + provide_checksum: false, + provide_content_size: true, + provide_window_size: true, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:16 }, + mem_wr_req: MemWriterReq { addr: Addr:1234, length: Addr:16 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0xCAFE60C2, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x3DA53A79, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x3A16B33F, length: Addr:4, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:4, + }, + TestCase { // 3 + // * data in a single segment + // * different response length + req: FrameHeaderEncoderReq { + addr: Addr:1999, + window_log: WindowLog:22, + src_size: u64:0x200, + dict_id: u32:0xCAFE, + max_block_size: u64:0x200, + provide_dict_id: true, + provide_checksum: false, + provide_content_size: true, + provide_window_size: true, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:9 }, + mem_wr_req: MemWriterReq { addr: Addr:1999, length: Addr:9 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00CAFE62, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00000001, length: Addr:1, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:3, + }, + TestCase { // 4 + // * data of size 0 + req: FrameHeaderEncoderReq { + addr: Addr:1999, + window_log: WindowLog:22, + src_size: u64:0x0, + dict_id: u32:0xCAFE, + max_block_size: u64:0x0, + provide_dict_id: true, + provide_checksum: false, + provide_content_size: true, + provide_window_size: true, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:8 }, + mem_wr_req: MemWriterReq { addr: Addr:1999, length: Addr:8 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00CAFE22, length: Addr:4, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:2, + }, + TestCase { // 5 + req: FrameHeaderEncoderReq { + addr: Addr:1999, + window_log: WindowLog:22, + src_size: u64:0x0, + dict_id: u32:0xCAFE, + max_block_size: u64:0x0, + provide_dict_id: false, + provide_checksum: true, + provide_content_size: true, + provide_window_size: false, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::OKAY, length: HeaderSize:6 }, + mem_wr_req: MemWriterReq { addr: Addr:1999, length: Addr:6 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::OKAY }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00000024, length: Addr:2, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:2, + }, + TestCase { // 6 + // test + // * write error + req: FrameHeaderEncoderReq { + addr: Addr:1999, + window_log: WindowLog:22, + src_size: u64:0x0, + dict_id: u32:0xCAFE, + max_block_size: u64:0x0, + provide_dict_id: false, + provide_checksum: true, + provide_content_size: true, + provide_window_size: false, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::ERROR, length: HeaderSize:6 }, + mem_wr_req: MemWriterReq { addr: Addr:1999, length: Addr:6 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::ERROR }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00000024, length: Addr:2, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:2, + }, + TestCase { // 7 + // * skip content size + // * shortest possible header + req: FrameHeaderEncoderReq { + addr: Addr:1999, + window_log: WindowLog:22, + src_size: u64:0x0, + dict_id: u32:0xCAFE, + max_block_size: u64:0x0, + provide_dict_id: false, + provide_checksum: false, + provide_content_size: false, + provide_window_size: false, + }, + resp: FrameHeaderEncoderResp { status: FrameHeaderEncoderStatus::ERROR, length: HeaderSize:5 }, + mem_wr_req: MemWriterReq { addr: Addr:1999, length: Addr:5 }, + mem_wr_resp: MemWriterResp { status: MemWriterRespStatus::ERROR }, + mem_wr_data: MemWriterDataPacket[5]:[ + MemWriterDataPacket { data: Data:0xFD2FB528, length: Addr:4, last: u1:0 }, + MemWriterDataPacket { data: Data:0x00000000, length: Addr:1, last: u1:1 }, + zero!(), ... + ], + mem_wr_data_length: u32:2, + }, + + ]; + + let tok = for (test_case, tok): (TestCase, token) in TEST_CASES { + let tok = send(tok, req_s, test_case.req); + let tok = send(tok, mem_wr_resp_s, test_case.mem_wr_resp); + + let (tok, mem_wr_req) = recv(tok, mem_wr_req_r); + assert_eq(mem_wr_req, test_case.mem_wr_req); + + let tok = for (i, tok): (u32, token) in u32:0..array_size(test_case.mem_wr_data) { + if i < test_case.mem_wr_data_length { + let (tok, mem_wr_data) = recv(tok, mem_wr_data_r); + assert_eq(mem_wr_data, test_case.mem_wr_data[i]); + tok + } else { tok } + }(tok); + + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, test_case.resp); + + tok + }(join()); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/fse_dec.x b/xls/modules/zstd/fse_dec.x index fba9954c2a..29950a0474 100644 --- a/xls/modules/zstd/fse_dec.x +++ b/xls/modules/zstd/fse_dec.x @@ -30,6 +30,7 @@ type CopyOrMatchContent = common::CopyOrMatchContent; type RefillingSBCtrl = refilling_shift_buffer::RefillingShiftBufferCtrl; type RefillingSBOutput = refilling_shift_buffer::RefillingShiftBufferOutput; +type RefillingSBLength = common::RefillingSBLength; pub enum FseDecoderStatus : u1 { OK = 0, @@ -47,13 +48,13 @@ pub struct FseDecoderCtrl { pub struct FseDecoderFinish { status: FseDecoderStatus } -pub fn extract_triplet(num: u64, sz0: u8, sz1: u8, sz2: u8) -> (u64, u64, u64) { +pub fn extract_triplet(num: uN[AXI_DATA_W], sz0: u8, sz1: u8, sz2: u8) -> (uN[AXI_DATA_W], uN[AXI_DATA_W], uN[AXI_DATA_W]) { let shifted2 = num; let shifted1 = shifted2 >> sz2; let shifted0 = shifted1 >> sz1; ( - shifted0 & ((u64:1 << sz0) - u64:1), shifted1 & ((u64:1 << sz1) - u64:1), - shifted2 & ((u64:1 << sz2) - u64:1), + shifted0 & ((uN[AXI_DATA_W]:1 << sz0) - uN[AXI_DATA_W]:1), shifted1 & ((uN[AXI_DATA_W]:1 << sz1) - uN[AXI_DATA_W]:1), + shifted2 & ((uN[AXI_DATA_W]:1 << sz2) - uN[AXI_DATA_W]:1), ) } @@ -99,22 +100,21 @@ enum FseDecoderFSM : u4 { SEND_FINISH = 9, } -enum FseDecoderCommandFSM : u2 { +enum FseDecoderCommandFSM : u1 { IDLE = 0, - LITERAL = 1, - SEQUENCE = 2, + SEQUENCE = 1, } struct FseDecoderCommandReq { send_second: bool, - cmd0: CommandConstructorData, - cmd1: CommandConstructorData, + sequence_command: CommandConstructorData, } -struct FseDecoderCommandState { fsm: FseDecoderCommandFSM, req: FseDecoderCommandReq } +fn pack_offset_and_match_length(offset: u32, match_length: u32) -> u32 { + (offset << 16) | (match_length & u32:0xFFFF) +} proc FseDecoderCommand { - type State = FseDecoderCommandState; type Req = FseDecoderCommandReq; type Fsm = FseDecoderCommandFSM; req_r: chan in; @@ -122,31 +122,16 @@ proc FseDecoderCommand { config(req_r: chan in, command_s: chan out) { (req_r, command_s) } - init { zero!() } + init { } - next(state: State) { + next(state: ()) { let tok = join(); - match (state.fsm) { - Fsm::IDLE => { - let (tok, req) = recv(tok, req_r); - State { fsm: Fsm::LITERAL, req } - }, - Fsm::LITERAL => { - let tok = send(tok, command_s, state.req.cmd0); - State { - fsm: if state.req.send_second { Fsm::SEQUENCE } else { Fsm::IDLE }, - ..state - } - }, - Fsm::SEQUENCE => { - let tok = send(tok, command_s, state.req.cmd1); - zero!() - }, - } + let (tok, req) = recv(tok, req_r); + let tok = send(tok, command_s, req.sequence_command); } } -struct FseDecoderState { +struct FseDecoderState { fsm: FseDecoderFSM, ctrl: FseDecoderCtrl, sequences_count: u24, @@ -163,20 +148,18 @@ struct FseDecoderState { of_state: u16, ll_state: u16, ml_state: u16, - read_bits: u64, - read_bits_length: u7, - read_bits_needed: u7, + read_bits: uN[AXI_DATA_W], + read_bits_length: RefillingSBLength, + read_bits_needed: RefillingSBLength, sent_buf_ctrl: bool, shift_buffer_error: bool, padding: u4, } -pub proc FseDecoder +pub proc FseDecoder { + type FseDecoderState = FseDecoderState; type FseRamRdReq = ram::ReadReq; type FseRamRdResp = ram::ReadResp; type RefillingSBCtrl = refilling_shift_buffer::RefillingShiftBufferCtrl; @@ -282,8 +265,8 @@ u32 = { let do_send_buf_ctrl = do_read_bits && !state.sent_buf_ctrl; let buf_ctrl_length = - if (state.read_bits_needed - state.read_bits_length) > REFILLING_SB_DATA_W as u7 { - REFILLING_SB_DATA_W as u7 + if (state.read_bits_needed - state.read_bits_length) > REFILLING_SB_DATA_W as RefillingSBLength { + REFILLING_SB_DATA_W as RefillingSBLength } else { state.read_bits_needed - state.read_bits_length }; @@ -325,34 +308,25 @@ u32 = { let do_send_command = (state.fsm == FseDecoderFSM::SEND_COMMAND || state.fsm == FseDecoderFSM::SEND_LEFTOVER_LITERALS_REQ); + let last = (state.sequences_count == u24:1) && + (state.literals_count == state.ctrl.literals_count); let command = if state.fsm == FseDecoderFSM::SEND_COMMAND { FseDecoderCommandReq { - send_second: true, - cmd0: CommandConstructorData { - sync: state.ctrl.sync, - data: SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: state.ll, - content: CopyOrMatchContent:0, - last: false, - }, - }, - cmd1: CommandConstructorData { + send_second: !last, + sequence_command: CommandConstructorData { sync: state.ctrl.sync, data: SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: state.ml, - content: state.of, - last: - (state.sequences_count == u24:1) && - (state.literals_count == state.ctrl.literals_count), + length: state.ll, + content: pack_offset_and_match_length(state.of as u32, state.ml as u32) as CopyOrMatchContent, + last, }, }, } } else { FseDecoderCommandReq { send_second: false, - cmd0: CommandConstructorData { + sequence_command: CommandConstructorData { sync: state.ctrl.sync, data: SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, @@ -362,7 +336,6 @@ u32 = { last: true, }, }, - cmd1: zero!(), } }; @@ -395,9 +368,9 @@ u32 = { FseDecoderState { fsm: FseDecoderFSM::PADDING, ctrl, - read_bits: u64:0, - read_bits_length: u7:0, - read_bits_needed: u7:1, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, + read_bits_needed: RefillingSBLength:1, ..state } } @@ -416,9 +389,9 @@ u32 = { if padding_available { FseDecoderState { fsm: FseDecoderFSM::PADDING, - read_bits: u64:0, - read_bits_length: u7:0, - read_bits_needed: u7:1, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, + read_bits_needed: RefillingSBLength:1, padding, ..state } @@ -426,11 +399,11 @@ u32 = { trace_fmt!("padding is: {:#x}", padding); FseDecoderState { fsm: FseDecoderFSM::INIT_STATE, - read_bits: u64:0, - read_bits_length: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, read_bits_needed: - state.ctrl.of_acc_log + state.ctrl.ll_acc_log + - state.ctrl.ml_acc_log, + (state.ctrl.of_acc_log + state.ctrl.ll_acc_log + + state.ctrl.ml_acc_log) as RefillingSBLength, ..state } } @@ -451,9 +424,9 @@ u32 = { ll_state: ll_state as u16, ml_state: ml_state as u16, of_state: of_state as u16, - read_bits: u64:0, - read_bits_length: u7:0, - read_bits_needed: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, + read_bits_needed: RefillingSBLength:0, ..state } } else { @@ -509,13 +482,13 @@ u32 = { trace_fmt!("all states received: {:#x}", state); FseDecoderState { fsm: FseDecoderFSM::READ_BITS, - read_bits: u64:0, - read_bits_length: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, read_bits_needed: (state.of_fse_table_record.symbol as u8 + SEQ_MATCH_LENGTH_EXTRA_BITS[state.ml_fse_table_record.symbol] + SEQ_LITERAL_LENGTH_EXTRA_BITS[state.ll_fse_table_record.symbol]) as - u7, + RefillingSBLength, ..state } } else { @@ -545,9 +518,9 @@ u32 = { ml, ll, of_state, - read_bits: u64:0, - read_bits_length: u7:0, - read_bits_needed: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, + read_bits_needed: RefillingSBLength:0, literals_count: state.literals_count + ll as u20, ..state } @@ -557,13 +530,13 @@ u32 = { of, ml, ll, - read_bits: u64:0, - read_bits_length: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, read_bits_needed: (state.ml_fse_table_record.num_of_bits + state.of_fse_table_record.num_of_bits + state.ll_fse_table_record.num_of_bits) as - u7, + RefillingSBLength, literals_count: state.literals_count + ll as u20, ..state } @@ -588,9 +561,9 @@ u32 = { ll_state, ml_state, of_state, - read_bits: u64:0, - read_bits_length: u7:0, - read_bits_needed: u7:0, + read_bits: uN[AXI_DATA_W]:0, + read_bits_length: RefillingSBLength:0, + read_bits_needed: RefillingSBLength:0, ..state } } else { @@ -641,7 +614,7 @@ const INST_RAM_ADDR_W = std::clog2(INST_RAM_SIZE); const INST_RAM_DATA_W = u32:32; const INST_RAM_WORD_PARTITION_SIZE = INST_RAM_DATA_W / u32:3; const INST_RAM_NUM_PARTITIONS = ram::num_partitions(INST_RAM_WORD_PARTITION_SIZE, INST_RAM_DATA_W); -const INST_AXI_DATA_W = u32:64; +const INST_AXI_DATA_W = common::AXI_DATA_W; const INST_REFILLING_SB_DATA_W = INST_AXI_DATA_W; const INST_REFILLING_SB_LENGTH_W = refilling_shift_buffer::length_width(INST_REFILLING_SB_DATA_W); @@ -668,783 +641,3 @@ pub proc FseDecoderInst { next(state: ()) { } } - -// test data was generated using decodecorpus and educational_decoder from zstd repository -// block #0 seed: 58602 -// block #1 seed: 48401 - -const TEST_OF_TABLE = u32[256][2]:[ - [ - u32:0x00_03_0008, u32:0x02_02_0004, u32:0x03_02_0014, u32:0x03_02_0018, u32:0x04_03_0008, - u32:0x00_03_0010, u32:0x02_02_0008, u32:0x03_02_001c, u32:0x03_01_0000, u32:0x04_03_0010, - u32:0x02_02_000c, u32:0x02_02_0010, u32:0x03_01_0002, u32:0x04_03_0018, u32:0x00_03_0018, - u32:0x02_02_0014, u32:0x03_01_0004, u32:0x03_01_0006, u32:0x04_02_0000, u32:0x02_02_0018, - u32:0x02_02_001c, u32:0x03_01_0008, u32:0x03_01_000a, u32:0x00_02_0000, u32:0x02_01_0000, - u32:0x03_01_000c, u32:0x03_01_000e, u32:0x04_02_0004, u32:0x00_02_0004, u32:0x02_01_0002, - u32:0x03_01_0010, u32:0x03_01_0012, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0031, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x31_51_0100, u32:0x00_00_0101, u32:0x00_00_0003, u32:0x00_00_0101, u32:0x00_00_0301, - u32:0x00_00_0101, u32:0x00_00_0301, u32:0x00_00_0100, u32:0x03_08_0101, u32:0x02_00_0103, - u32:0x02_04_0101, u32:0x02_00_0001, u32:0x03_14_0101, u32:0x03_00_0301, u32:0x02_18_0100, - u32:0x02_00_0101, u32:0x01_08_0000, u32:0x03_00_0000, u32:0x02_10_0000, u32:0x02_00_0000, - u32:0x01_08_0031, u32:0x03_00_0000, u32:0x03_1c_0000, u32:0x02_00_0000, u32:0x01_00_0103, - u32:0x01_00_0101, u32:0x02_10_0303, u32:0x02_00_0101, u32:0x02_0c_0301, u32:0x01_00_0101, - u32:0x01_10_0301, u32:0x02_00_0103, u32:0x01_02_0000, u32:0x01_00_0002, u32:0x01_18_0000, - u32:0x02_00_0200, u32:0x02_18_0000, u32:0x01_00_0200, u32:0x01_14_0002, u32:0x01_00_0000, - u32:0x00_04_0000, u32:0x00_00_0000, u32:0x00_06_0000, u32:0x00_00_0000, u32:0x00_00_0051, - u32:0x00_00_0000, u32:0x00_18_0000, u32:0x00_00_0000, u32:0x51_1c_0008, u32:0x00_00_000c, - u32:0x00_08_000e, u32:0x00_00_0010, u32:0x00_0a_0008, u32:0x00_00_0010, u32:0x00_00_0012, - u32:0x00_00_0014, u32:0x08_00_0016, u32:0x00_00_0010, u32:0x04_0c_0018, u32:0x00_00_001a, - u32:0x14_0e_001c, u32:0x00_00_0018, u32:0x18_04_0018, u32:0x00_00_001e, u32:0x08_04_0000, - u32:0x00_00_0001, u32:0x10_02_0000, u32:0x00_00_0002, u32:0x08_10_0003, u32:0x00_00_0004, - u32:0x1c_12_0005, u32:0x00_00_0000, u32:0x00_00_0006, u32:0x00_00_0007, u32:0x10_00_0008, - u32:0x00_00_0004, u32:0x0c_00_0004, u32:0x00_00_0009, u32:0x10_00_000a, u32:0x00_00_000b, - u32:0x02_31_0000, u32:0x00_00_0000, u32:0x18_00_0000, u32:0x00_00_0000, u32:0x18_00_0411, - u32:0x00_00_0000, u32:0x14_00_0000, u32:0x00_00_0000, u32:0x04_00_3230, u32:0x00_01_3020, - u32:0x06_01_2030, u32:0x00_01_3233, u32:0x00_03_3033, u32:0x00_00_2020, u32:0x18_01_3030, - u32:0x00_01_3020, u32:0x1c_01_2031, u32:0x00_03_3033, u32:0x08_01_3333, u32:0x00_01_2020, - u32:0x0a_01_3830, u32:0x00_03_3020, u32:0x00_00_2031, u32:0x00_01_3333, u32:0x00_01_3333, - u32:0x00_01_2020, u32:0x0c_03_3030, u32:0x00_01_3020, u32:0x0e_01_2031, u32:0x00_01_3033, - u32:0x04_01_3032, u32:0x00_00_2020, u32:0x04_01_6530, u32:0x00_01_3020, u32:0x02_01_2031, - u32:0x00_03_3032, u32:0x10_00_3133, u32:0x00_01_2020, u32:0x12_01_3030, u32:0x00_01_3020, - u32:0x00_00_2031, u32:0x00_00_3032, u32:0x00_00_3032, u32:0x00_00_2020, u32:0x00_00_3231, - u32:0x00_00_3020, u32:0x00_00_2031, u32:0x00_00_3032, u32:0x31_31_3133, u32:0x00_00_2020, - u32:0x00_00_3030, u32:0x00_00_3020, u32:0x00_00_2030, u32:0x00_00_3033, u32:0x00_00_3233, - u32:0x00_00_2020, u32:0x00_03_000a, u32:0x01_01_0000, u32:0x01_01_0000, u32:0x01_01_0000, - u32:0x03_03_0000, u32:0x00_03_0000, u32:0x01_01_0000, u32:0x01_01_0000, u32:0x01_01_0000, - u32:0x03_03_0000, u32:0x01_01_0000, u32:0x01_01_0000, u32:0x01_01_0000, u32:0x03_03_0000, - u32:0x00_03_0000, u32:0x01_01_0000, u32:0x01_00_0000, u32:0x01_00_0000, u32:0x03_02_0000, - u32:0x01_00_0000, u32:0x01_00_0000, u32:0x01_00_0000, u32:0x01_00_0000, u32:0x00_02_0000, - u32:0x01_00_0000, u32:0x01_00_0000, u32:0x01_00_0000, u32:0x03_02_0000, u32:0x00_02_0000, - u32:0x01_00_0000, u32:0x01_00_0000, u32:0x01_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x31_51_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x03_08_0000, - u32:0x01_00_0000, u32:0x01_0c_0000, u32:0x01_00_0000, u32:0x03_0e_0000, u32:0x03_00_0000, - u32:0x01_10_0000, u32:0x01_00_0000, u32:0x01_08_0000, u32:0x03_00_0000, u32:0x01_10_0000, - u32:0x01_00_0000, u32:0x01_12_0000, u32:0x03_00_0000, u32:0x03_14_0000, u32:0x01_00_0000, - u32:0x00_16_0000, u32:0x00_00_0000, u32:0x02_10_0000, u32:0x00_00_0000, u32:0x00_18_0000, - u32:0x00_00_0000, u32:0x00_1a_0000, u32:0x02_00_0000, u32:0x00_1c_0000, u32:0x00_00_0000, - u32:0x00_18_0000, u32:0x02_00_0000, u32:0x02_18_0000, u32:0x00_00_0000, u32:0x00_1e_0000, - u32:0x00_00_0000, - ], - [ - u32:0x00_05_0000, u32:0x06_04_0000, u32:0x09_05_0000, u32:0x0f_05_0000, u32:0x15_05_0000, - u32:0x03_05_0000, u32:0x07_04_0000, u32:0x0c_05_0000, u32:0x12_05_0000, u32:0x17_05_0000, - u32:0x05_05_0000, u32:0x08_04_0000, u32:0x0e_05_0000, u32:0x14_05_0000, u32:0x02_05_0000, - u32:0x07_04_0010, u32:0x0b_05_0000, u32:0x11_05_0000, u32:0x16_05_0000, u32:0x04_05_0000, - u32:0x08_04_0010, u32:0x0d_05_0000, u32:0x13_05_0000, u32:0x01_05_0000, u32:0x06_04_0010, - u32:0x0a_05_0000, u32:0x10_05_0000, u32:0x1c_05_0000, u32:0x1b_05_0000, u32:0x1a_05_0000, - u32:0x19_05_0000, u32:0x18_05_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0051, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x31_51_0100, u32:0x00_00_0302, u32:0x00_00_0605, u32:0x00_00_0a08, u32:0x00_00_100d, - u32:0x00_00_1613, u32:0x00_00_1c19, u32:0x00_00_211f, u32:0x05_00_2523, u32:0x04_00_2927, - u32:0x05_00_2d2b, u32:0x05_00_0201, u32:0x05_00_0403, u32:0x05_00_0706, u32:0x04_00_0c09, - u32:0x05_00_120f, u32:0x05_00_1815, u32:0x05_00_1e1b, u32:0x05_00_2220, u32:0x04_00_2624, - u32:0x05_00_2a28, u32:0x05_00_012c, u32:0x05_00_0201, u32:0x04_00_0504, u32:0x05_00_0807, - u32:0x05_00_0e0b, u32:0x05_00_1411, u32:0x05_00_1a17, u32:0x04_00_341d, u32:0x05_00_3233, - u32:0x05_00_3031, u32:0x05_00_2e2f, u32:0x04_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, - u32:0x05_00_0000, u32:0x05_00_0051, u32:0x05_00_0000, u32:0x05_10_0000, u32:0x05_00_0000, - u32:0x00_00_0406, u32:0x00_00_0505, u32:0x00_00_0505, u32:0x00_00_0605, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, u32:0x51_10_0606, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_00_0404, u32:0x00_00_0505, u32:0x00_00_0505, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_10_0606, u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_00_0406, u32:0x00_00_0404, u32:0x00_00_0505, u32:0x00_00_0505, - u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0091, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_51_0000, u32:0x00_00_0000, u32:0x00_00_0020, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x10_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_01_0000, - u32:0x00_02_0000, u32:0x00_03_0000, u32:0x00_05_0000, u32:0x00_06_0000, u32:0x00_08_0000, - u32:0x00_0a_0000, u32:0x10_0d_0000, u32:0x00_10_0000, u32:0x00_13_0000, u32:0x00_16_0000, - u32:0x00_19_0000, u32:0x00_1c_0000, u32:0x00_1f_0010, u32:0x00_21_0000, u32:0x10_23_0020, - u32:0x00_25_0000, u32:0x00_27_0020, u32:0x00_29_0000, u32:0x00_2b_0000, u32:0x00_2d_0000, - u32:0x00_01_0000, u32:0x00_02_0000, u32:0x00_03_0000, u32:0x00_04_0000, u32:0x00_06_0000, - u32:0x00_07_0000, u32:0x00_09_0000, u32:0x00_0c_0000, u32:0x00_0f_0000, u32:0x00_12_0000, - u32:0x00_15_0000, u32:0x00_18_0000, u32:0x00_1b_0000, u32:0x00_1e_0020, u32:0x00_20_0030, - u32:0x00_22_0010, u32:0x00_24_0020, u32:0x00_26_0020, u32:0x51_28_0020, u32:0x00_2a_0020, - u32:0x00_2c_0000, u32:0x00_01_0000, u32:0x00_01_0000, u32:0x00_02_0000, u32:0x00_04_0000, - u32:0x00_05_0000, u32:0x00_07_0000, u32:0x01_08_0000, u32:0x02_0b_0000, u32:0x03_0e_0000, - u32:0x05_11_0000, u32:0x06_14_0000, u32:0x08_17_0000, u32:0x0a_1a_0000, u32:0x0d_1d_0000, - u32:0x10_34_0000, u32:0x13_33_0000, u32:0x16_32_0000, u32:0x19_31_0411, u32:0x1c_30_0000, - u32:0x1f_2f_0000, u32:0x21_2e_0000, u32:0x23_00_6430, u32:0x25_00_3020, u32:0x27_00_2030, - u32:0x29_00_3436, u32:0x2b_00_3033, u32:0x2d_00_2020, u32:0x01_00_3532, u32:0x02_00_3020, - u32:0x03_51_2030, u32:0x04_00_3033, u32:0x06_00_3333, u32:0x07_00_2020, u32:0x09_00_3630, - u32:0x0c_00_3020, u32:0x0f_00_2030, u32:0x12_00_3333, u32:0x15_06_3333, u32:0x18_04_2020, - u32:0x1b_05_3730, u32:0x1e_05_3020, u32:0x20_05_2035, u32:0x22_05_3033, u32:0x24_05_3032, - u32:0x26_06_2020, u32:0x28_06_3032, u32:0x2a_06_3020, u32:0x2c_06_2035, u32:0x01_06_3032, - u32:0x01_06_3533, u32:0x02_06_2020, u32:0x04_06_3230, u32:0x05_06_3020, u32:0x07_06_2036, - u32:0x08_06_3032, u32:0x0b_06_3032, u32:0x0e_06_2020, u32:0x11_06_3430, u32:0x14_06_3020, - u32:0x17_04_2036, u32:0x1a_04_3032, u32:0x1d_05_3633, u32:0x34_05_2020, u32:0x33_05_6131, - u32:0x32_05_3020, u32:0x31_06_2034, u32:0x30_06_3033, u32:0x2f_06_3233, u32:0x2e_06_2020, - u32:0x00_06_000a, u32:0x00_06_0000, u32:0x00_06_0000, u32:0x00_06_0000, u32:0x00_06_0000, - u32:0x00_06_0000, u32:0x00_06_0000, u32:0x00_06_0000, u32:0x51_06_0000, u32:0x00_06_0000, - u32:0x00_06_0000, u32:0x00_04_0000, u32:0x00_04_0000, u32:0x00_04_0000, u32:0x00_05_0000, - u32:0x00_05_0000, - ], -]; - -const TEST_ML_TABLE = u32[256][2]:[ - [ - u32:0x00_03_0008, u32:0x01_01_000c, u32:0x01_01_000e, u32:0x01_01_0010, u32:0x03_03_0008, - u32:0x00_03_0010, u32:0x01_01_0012, u32:0x01_01_0014, u32:0x01_01_0016, u32:0x03_03_0010, - u32:0x01_01_0018, u32:0x01_01_001a, u32:0x01_01_001c, u32:0x03_03_0018, u32:0x00_03_0018, - u32:0x01_01_001e, u32:0x01_00_0000, u32:0x01_00_0001, u32:0x03_02_0000, u32:0x01_00_0002, - u32:0x01_00_0003, u32:0x01_00_0004, u32:0x01_00_0005, u32:0x00_02_0000, u32:0x01_00_0006, - u32:0x01_00_0007, u32:0x01_00_0008, u32:0x03_02_0004, u32:0x00_02_0004, u32:0x01_00_0009, - u32:0x01_00_000a, u32:0x01_00_000b, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0411, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x31_51_3030, u32:0x00_00_3520, u32:0x00_00_2031, u32:0x00_00_3033, u32:0x00_00_3033, - u32:0x00_00_2020, u32:0x00_00_3030, u32:0x00_00_3020, u32:0x03_08_2030, u32:0x01_00_3533, - u32:0x01_0c_3333, u32:0x01_00_2020, u32:0x03_0e_3130, u32:0x03_00_3020, u32:0x01_10_2063, - u32:0x01_00_3333, u32:0x01_08_3333, u32:0x03_00_2020, u32:0x01_10_3130, u32:0x01_00_3020, - u32:0x01_12_2030, u32:0x03_00_3033, u32:0x03_14_3032, u32:0x01_00_2020, u32:0x00_16_3130, - u32:0x00_00_3120, u32:0x02_10_2032, u32:0x00_00_3032, u32:0x00_18_3033, u32:0x00_00_2020, - u32:0x00_1a_3030, u32:0x02_00_3020, u32:0x00_1c_2030, u32:0x00_00_3032, u32:0x00_18_3032, - u32:0x02_00_2020, u32:0x02_18_3030, u32:0x00_00_3120, u32:0x00_1e_2061, u32:0x00_00_3032, - u32:0x00_00_3136, u32:0x00_00_2020, u32:0x00_01_3030, u32:0x00_00_3020, u32:0x00_00_2030, - u32:0x00_00_3033, u32:0x00_02_3233, u32:0x00_00_2020, u32:0x51_03_000a, u32:0x00_00_0000, - u32:0x00_04_0000, u32:0x00_00_0000, u32:0x00_05_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x08_06_0000, u32:0x00_00_0000, u32:0x0c_07_0000, u32:0x00_00_0000, - u32:0x0e_08_0000, u32:0x00_00_0000, u32:0x10_04_0000, u32:0x00_00_0000, u32:0x08_04_0000, - u32:0x00_00_0000, u32:0x10_09_0000, u32:0x00_00_0000, u32:0x12_0a_0000, u32:0x00_00_0000, - u32:0x14_0b_0000, u32:0x00_00_0000, u32:0x16_00_0000, u32:0x00_00_0000, u32:0x10_00_0000, - u32:0x00_00_0000, u32:0x18_00_0000, u32:0x00_00_0000, u32:0x1a_00_0000, u32:0x00_00_0000, - u32:0x1c_11_0000, u32:0x00_04_0000, u32:0x18_00_0000, u32:0x00_00_0000, u32:0x18_00_0000, - u32:0x00_00_0000, u32:0x1e_00_0000, u32:0x00_00_0000, u32:0x00_31_0000, u32:0x00_30_0000, - u32:0x01_20_0000, u32:0x00_33_0000, u32:0x00_31_0000, u32:0x00_20_0000, u32:0x02_30_0000, - u32:0x00_30_0000, u32:0x03_30_0000, u32:0x00_30_0000, u32:0x04_20_0000, u32:0x00_20_0000, - u32:0x05_30_0000, u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_33_0000, u32:0x06_30_0000, - u32:0x00_20_0000, u32:0x07_30_0000, u32:0x00_30_0000, u32:0x08_30_0000, u32:0x00_30_0000, - u32:0x04_20_0000, u32:0x00_20_0000, u32:0x04_30_0000, u32:0x00_37_0000, u32:0x09_20_0000, - u32:0x00_32_0000, u32:0x0a_30_0000, u32:0x00_20_0000, u32:0x0b_30_0000, u32:0x00_30_0000, - u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_20_0000, u32:0x00_30_0000, - u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_32_0000, u32:0x11_30_0000, u32:0x04_20_0000, - u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_20_0000, - u32:0x00_20_0000, u32:0x31_30_0000, u32:0x31_30_0000, u32:0x20_20_0000, u32:0x33_33_0000, - u32:0x30_30_0000, u32:0x20_20_0000, u32:0x30_30_0000, u32:0x30_30_0000, u32:0x30_30_0000, - u32:0x30_30_0000, u32:0x20_20_0000, u32:0x20_20_0000, u32:0x33_32_0000, u32:0x30_30_0000, - u32:0x20_20_0000, u32:0x33_33_0000, u32:0x30_30_0000, u32:0x20_20_0000, u32:0x30_30_0000, - u32:0x30_30_0000, u32:0x30_30_0000, u32:0x30_30_0000, u32:0x20_20_0000, u32:0x20_20_0000, - u32:0x33_32_0000, u32:0x30_30_0000, u32:0x20_20_0000, u32:0x32_32_0000, u32:0x30_30_0000, - u32:0x20_20_0000, u32:0x30_30_0000, u32:0x30_30_0000, u32:0x30_30_0000, u32:0x30_30_0000, - u32:0x20_20_0000, u32:0x20_20_0000, u32:0x32_33_0000, u32:0x30_30_0000, u32:0x20_20_0000, - u32:0x32_33_0000, u32:0x30_33_0000, u32:0x20_20_0000, u32:0x30_30_0000, u32:0x30_30_0000, - u32:0x30_30_0000, u32:0x30_30_0000, u32:0x20_20_0000, u32:0x20_20_0000, u32:0x33_0a_0000, - u32:0x30_00_0000, u32:0x20_00_0000, u32:0x33_00_0000, u32:0x30_00_0000, u32:0x20_00_0000, - u32:0x30_00_0000, u32:0x30_00_0000, u32:0x30_00_0000, u32:0x30_00_0000, u32:0x20_00_0000, - u32:0x20_00_0000, u32:0x32_00_0000, u32:0x30_00_0000, u32:0x20_00_0000, u32:0x30_00_0000, - u32:0x30_00_0000, u32:0x20_00_0000, u32:0x30_00_0000, u32:0x30_00_0000, u32:0x30_00_0000, - u32:0x30_00_0000, u32:0x20_00_0000, u32:0x20_00_0000, u32:0x32_00_0000, u32:0x30_00_0000, - u32:0x20_00_0000, u32:0x30_00_0000, u32:0x30_00_0000, u32:0x20_00_0000, u32:0x30_00_0000, - u32:0x30_00_0000, - ], - [ - u32:0x00_06_0000, u32:0x01_04_0000, u32:0x02_05_0020, u32:0x03_05_0000, u32:0x05_05_0000, - u32:0x06_05_0000, u32:0x08_05_0000, u32:0x0a_06_0000, u32:0x0d_06_0000, u32:0x10_06_0000, - u32:0x13_06_0000, u32:0x16_06_0000, u32:0x19_06_0000, u32:0x1c_06_0000, u32:0x1f_06_0000, - u32:0x21_06_0000, u32:0x23_06_0000, u32:0x25_06_0000, u32:0x27_06_0000, u32:0x29_06_0000, - u32:0x2b_06_0000, u32:0x2d_06_0000, u32:0x01_04_0010, u32:0x02_04_0000, u32:0x03_05_0020, - u32:0x04_05_0000, u32:0x06_05_0020, u32:0x07_05_0000, u32:0x09_06_0000, u32:0x0c_06_0000, - u32:0x0f_06_0000, u32:0x12_06_0000, u32:0x15_06_0000, u32:0x18_06_0000, u32:0x1b_06_0000, - u32:0x1e_06_0000, u32:0x20_06_0000, u32:0x22_06_0000, u32:0x24_06_0000, u32:0x26_06_0000, - u32:0x28_06_0000, u32:0x2a_06_0000, u32:0x2c_06_0000, u32:0x01_04_0020, u32:0x01_04_0030, - u32:0x02_04_0010, u32:0x04_05_0020, u32:0x05_05_0020, u32:0x07_05_0020, u32:0x08_05_0020, - u32:0x0b_06_0000, u32:0x0e_06_0000, u32:0x11_06_0000, u32:0x14_06_0000, u32:0x17_06_0000, - u32:0x1a_06_0000, u32:0x1d_06_0000, u32:0x34_06_0000, u32:0x33_06_0000, u32:0x32_06_0000, - u32:0x31_06_0000, u32:0x30_06_0000, u32:0x2f_06_0000, u32:0x2e_06_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0411, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x51_91_3030, u32:0x00_00_3920, u32:0x00_00_2031, - u32:0x00_00_3033, u32:0x00_00_3033, u32:0x00_00_2020, u32:0x00_00_3030, u32:0x00_00_3020, - u32:0x06_00_2030, u32:0x04_00_3933, u32:0x05_00_3333, u32:0x05_00_2020, u32:0x05_20_3530, - u32:0x05_00_3020, u32:0x05_00_2030, u32:0x06_00_3333, u32:0x06_00_3333, u32:0x06_00_2020, - u32:0x06_00_3530, u32:0x06_00_3020, u32:0x06_00_2030, u32:0x06_00_3033, u32:0x06_00_3032, - u32:0x06_00_2020, u32:0x06_00_3630, u32:0x06_00_3020, u32:0x06_00_2030, u32:0x06_00_3032, - u32:0x06_00_3033, u32:0x06_00_2020, u32:0x04_00_3630, u32:0x04_00_3020, u32:0x05_00_2030, - u32:0x05_00_3032, u32:0x05_00_3032, u32:0x05_00_2020, u32:0x06_00_3430, u32:0x06_00_3020, - u32:0x06_00_2030, u32:0x06_00_3032, u32:0x06_00_3033, u32:0x06_00_2020, u32:0x06_00_3630, - u32:0x06_00_3020, u32:0x06_00_2030, u32:0x06_00_3033, u32:0x06_00_3233, u32:0x06_00_2020, - u32:0x06_00_000a, u32:0x06_00_0000, u32:0x06_00_0000, u32:0x04_00_0000, u32:0x04_10_0000, - u32:0x04_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_20_0000, u32:0x05_00_0000, - u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_20_0000, u32:0x06_00_0000, u32:0x06_00_0000, - u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_00_0000, - u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_00_0000, u32:0x06_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x91_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x20_00_0000, - u32:0x00_00_0000, u32:0x00_20_0000, u32:0x00_00_0000, u32:0x00_30_0000, u32:0x00_00_0000, - u32:0x00_10_0000, u32:0x00_00_0000, u32:0x00_20_0000, u32:0x00_00_0000, u32:0x00_20_0000, - u32:0x00_00_0000, u32:0x00_20_0000, u32:0x00_00_0000, u32:0x00_20_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x10_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x20_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x20_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_11_0000, u32:0x00_04_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_30_0000, - u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_33_0000, u32:0x00_30_0000, u32:0x00_20_0000, - u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_20_0000, - u32:0x00_20_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_33_0000, - u32:0x00_30_0000, u32:0x00_20_0000, u32:0x00_30_0000, u32:0x00_30_0000, u32:0x00_30_0000, - u32:0x00_30_0000, u32:0x20_20_0000, u32:0x00_20_0000, u32:0x30_30_0000, u32:0x00_30_0000, - u32:0x10_20_0000, u32:0x00_32_0000, u32:0x20_30_0000, u32:0x00_20_0000, u32:0x20_30_0000, - u32:0x00_30_0000, - ], -]; - -const TEST_LL_TABLE = u32[256][2]:[ - [ - u32:0x00_01_000e, u32:0x00_01_0010, u32:0x00_01_0012, u32:0x00_01_0014, u32:0x01_02_0004, - u32:0x00_01_0016, u32:0x00_01_0018, u32:0x00_01_001a, u32:0x01_02_0008, u32:0x01_02_000c, - u32:0x00_01_001c, u32:0x00_01_001e, u32:0x00_00_0000, u32:0x01_02_0010, u32:0x00_00_0001, - u32:0x00_00_0002, u32:0x00_00_0003, u32:0x01_02_0014, u32:0x01_02_0018, u32:0x00_00_0004, - u32:0x00_00_0005, u32:0x00_00_0006, u32:0x01_02_001c, u32:0x00_00_0007, u32:0x00_00_0008, - u32:0x00_00_0009, u32:0x00_00_000a, u32:0x01_01_0000, u32:0x00_00_000b, u32:0x00_00_000c, - u32:0x00_00_000d, u32:0x01_01_0002, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0031, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x31_51_0200, u32:0x00_00_0303, u32:0x00_00_0004, u32:0x00_00_0302, u32:0x00_00_0403, - u32:0x00_00_0202, u32:0x00_00_0403, u32:0x00_00_0200, u32:0x01_0e_0303, u32:0x01_00_0204, - u32:0x01_10_0302, u32:0x01_00_0003, u32:0x02_12_0302, u32:0x01_00_0403, u32:0x01_14_0200, - u32:0x01_00_0303, u32:0x02_04_0000, u32:0x02_00_0000, u32:0x01_16_0000, u32:0x01_00_0000, - u32:0x00_18_0031, u32:0x02_00_0000, u32:0x00_1a_0000, u32:0x00_00_0000, u32:0x00_08_0203, - u32:0x02_00_0202, u32:0x02_0c_0303, u32:0x00_00_0202, u32:0x00_1c_0301, u32:0x00_00_0202, - u32:0x02_1e_0301, u32:0x00_00_0203, u32:0x00_00_0101, u32:0x00_00_0202, u32:0x00_10_0102, - u32:0x01_00_0201, u32:0x00_01_0101, u32:0x00_00_0201, u32:0x00_02_0102, u32:0x01_00_0101, - u32:0x00_03_0000, u32:0x00_00_0000, u32:0x00_14_0000, u32:0x00_00_0000, u32:0x00_18_0051, - u32:0x00_00_0000, u32:0x00_04_0000, u32:0x00_00_0000, u32:0x51_05_0008, u32:0x00_00_0004, - u32:0x00_06_0014, u32:0x00_00_0018, u32:0x00_1c_0008, u32:0x00_00_0010, u32:0x00_07_0008, - u32:0x00_00_001c, u32:0x0e_08_0000, u32:0x00_00_0010, u32:0x10_09_000c, u32:0x00_00_0010, - u32:0x12_0a_0002, u32:0x00_00_0018, u32:0x14_00_0018, u32:0x00_00_0014, u32:0x04_0b_0004, - u32:0x00_00_0006, u32:0x16_0c_0000, u32:0x00_00_0018, u32:0x18_0d_001c, u32:0x00_00_0008, - u32:0x1a_02_000a, u32:0x00_00_0000, u32:0x08_00_0000, u32:0x00_00_000c, u32:0x0c_00_000e, - u32:0x00_00_0004, u32:0x1c_00_0004, u32:0x00_00_0002, u32:0x1e_00_0010, u32:0x00_00_0012, - u32:0x00_31_0000, u32:0x00_00_0000, u32:0x10_00_0000, u32:0x00_00_0000, u32:0x01_00_0031, - u32:0x00_00_0000, u32:0x02_00_0000, u32:0x00_00_0000, u32:0x03_00_0100, u32:0x00_02_0101, - u32:0x14_03_0003, u32:0x00_03_0101, u32:0x18_04_0301, u32:0x00_00_0101, u32:0x04_02_0301, - u32:0x00_03_0100, u32:0x05_03_0101, u32:0x00_04_0103, u32:0x06_02_0101, u32:0x00_02_0001, - u32:0x1c_03_0101, u32:0x00_04_0301, u32:0x07_00_0100, u32:0x00_02_0101, u32:0x08_03_0000, - u32:0x00_03_0000, u32:0x09_04_0000, u32:0x00_02_0000, u32:0x0a_02_0031, u32:0x00_03_0000, - u32:0x00_03_0000, u32:0x00_00_0000, u32:0x0b_02_0103, u32:0x00_03_0101, u32:0x0c_03_0303, - u32:0x00_04_0101, u32:0x0d_00_0301, u32:0x00_02_0101, u32:0x02_03_0301, u32:0x00_03_0103, - u32:0x00_00_0000, u32:0x00_00_0002, u32:0x00_00_0000, u32:0x00_00_0200, u32:0x00_00_0000, - u32:0x00_00_0200, u32:0x00_00_0002, u32:0x00_00_0000, u32:0x31_31_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0051, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_03_0008, u32:0x02_02_000c, u32:0x03_02_000e, u32:0x03_02_0010, - u32:0x04_03_0008, u32:0x00_03_0010, u32:0x02_02_0012, u32:0x03_02_0014, u32:0x03_01_0016, - u32:0x04_03_0010, u32:0x02_02_0018, u32:0x02_02_001a, u32:0x03_01_001c, u32:0x04_03_0018, - u32:0x00_03_0018, u32:0x02_02_001e, u32:0x03_01_0000, u32:0x03_01_0001, u32:0x04_02_0000, - u32:0x02_02_0002, u32:0x02_02_0003, u32:0x03_01_0004, u32:0x03_01_0005, u32:0x00_02_0000, - u32:0x02_01_0006, u32:0x03_01_0007, u32:0x03_01_0008, u32:0x04_02_0004, u32:0x00_02_0004, - u32:0x02_01_0009, u32:0x03_01_000a, u32:0x03_01_000b, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0411, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x31_51_3030, u32:0x00_00_3520, u32:0x00_00_2031, u32:0x00_00_3033, - u32:0x00_00_3033, u32:0x00_00_2020, u32:0x00_00_3030, u32:0x00_00_3020, u32:0x03_08_2030, - u32:0x02_00_3533, u32:0x02_04_3333, u32:0x02_00_2020, u32:0x03_14_3230, u32:0x03_00_3020, - u32:0x02_18_2034, u32:0x02_00_3333, u32:0x01_08_3333, u32:0x03_00_2020, u32:0x02_10_3230, - u32:0x02_00_3020, u32:0x01_08_2030, u32:0x03_00_3033, u32:0x03_1c_3032, u32:0x02_00_2020, - u32:0x01_00_3130, u32:0x01_00_3020, u32:0x02_10_2038, u32:0x02_00_3032, u32:0x02_0c_3033, - u32:0x01_00_2020, u32:0x01_10_3130, u32:0x02_00_3020, u32:0x01_02_2030, u32:0x01_00_3032, - u32:0x01_18_3032, u32:0x02_00_2020, u32:0x02_18_3130, u32:0x01_00_3120, u32:0x01_14_2030, - u32:0x01_00_3032, - ], - [ - u32:0x00_02_0010, u32:0x00_02_0014, u32:0x01_03_0008, u32:0x03_03_0008, u32:0x0d_03_0008, - u32:0x00_02_0018, u32:0x00_02_001c, u32:0x03_03_0010, u32:0x05_03_0008, u32:0x0d_03_0010, - u32:0x00_01_0000, u32:0x01_03_0010, u32:0x03_03_0018, u32:0x0d_03_0018, u32:0x00_01_0002, - u32:0x00_01_0004, u32:0x01_03_0018, u32:0x05_03_0010, u32:0x0d_02_0000, u32:0x00_01_0006, - u32:0x01_02_0000, u32:0x03_02_0000, u32:0x05_03_0018, u32:0x00_01_0008, u32:0x00_01_000a, - u32:0x01_02_0004, u32:0x05_02_0000, u32:0x0d_02_0004, u32:0x00_01_000c, u32:0x00_01_000e, - u32:0x03_02_0004, u32:0x05_02_0004, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0031, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x31_51_0600, u32:0x00_00_0f09, u32:0x00_00_0315, u32:0x00_00_0c07, u32:0x00_00_1712, - u32:0x00_00_0805, u32:0x00_00_140e, u32:0x00_00_0702, u32:0x02_10_110b, u32:0x02_00_0416, - u32:0x03_14_0d08, u32:0x03_00_0113, u32:0x03_08_0a06, u32:0x02_00_1c10, u32:0x02_08_1a1b, - u32:0x03_00_1819, u32:0x03_08_0000, u32:0x03_00_0000, u32:0x01_18_0000, u32:0x03_00_0000, - u32:0x03_1c_0031, u32:0x03_00_0000, u32:0x01_10_0000, u32:0x01_00_0000, u32:0x03_08_0405, - u32:0x03_00_0505, u32:0x02_10_0505, u32:0x01_00_0504, u32:0x02_00_0505, u32:0x02_00_0405, - u32:0x03_10_0505, u32:0x01_00_0405, u32:0x01_18_0505, u32:0x02_00_0505, u32:0x02_18_0504, - u32:0x02_00_0505, u32:0x01_02_0504, u32:0x01_00_0505, u32:0x02_04_0505, u32:0x02_00_0505, - u32:0x00_18_0000, u32:0x00_00_0000, u32:0x00_10_0000, u32:0x00_00_0000, u32:0x00_00_0051, - u32:0x00_00_0000, u32:0x00_06_0000, u32:0x00_00_0000, u32:0x51_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_18_0000, u32:0x00_00_0000, u32:0x00_08_0000, - u32:0x00_00_0000, u32:0x10_0a_0000, u32:0x00_00_0000, u32:0x14_04_0000, u32:0x00_00_0000, - u32:0x08_00_0000, u32:0x00_00_0000, u32:0x08_04_0000, u32:0x00_00_0010, u32:0x08_0c_0000, - u32:0x00_00_0000, u32:0x18_0e_0000, u32:0x00_00_0000, u32:0x1c_04_0010, u32:0x00_00_0000, - u32:0x10_04_0000, u32:0x00_00_0000, u32:0x08_00_0010, u32:0x00_00_0000, u32:0x10_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x10_00_0000, u32:0x00_00_0000, - u32:0x18_31_0000, u32:0x00_00_0000, u32:0x18_00_0000, u32:0x00_00_0000, u32:0x02_00_0051, - u32:0x00_00_0000, u32:0x04_00_0000, u32:0x00_00_0000, u32:0x18_00_0100, u32:0x00_06_0302, - u32:0x10_09_0605, u32:0x00_0f_0a08, u32:0x00_15_100d, u32:0x00_03_1613, u32:0x06_07_1c19, - u32:0x00_0c_211f, u32:0x00_12_2523, u32:0x00_17_2927, u32:0x00_05_2d2b, u32:0x00_08_0201, - u32:0x18_0e_0403, u32:0x00_14_0706, u32:0x08_02_0c09, u32:0x00_07_120f, u32:0x0a_0b_1815, - u32:0x00_11_1e1b, u32:0x04_16_2220, u32:0x00_04_2624, u32:0x00_08_2a28, u32:0x00_0d_012c, - u32:0x04_13_0201, u32:0x00_01_0504, u32:0x0c_06_0807, u32:0x00_0a_0e0b, u32:0x0e_10_1411, - u32:0x00_1c_1a17, u32:0x04_1b_341d, u32:0x00_1a_3233, u32:0x04_19_3031, u32:0x00_18_2e2f, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0051, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x31_31_0406, u32:0x00_00_0505, - u32:0x00_00_0505, u32:0x00_00_0605, u32:0x00_00_0606, u32:0x00_00_0606, u32:0x00_00_0606, - u32:0x00_00_0606, u32:0x00_05_0606, u32:0x06_04_0606, u32:0x09_05_0606, u32:0x0f_05_0404, - u32:0x15_05_0505, u32:0x03_05_0505, u32:0x07_04_0606, u32:0x0c_05_0606, u32:0x12_05_0606, - u32:0x17_05_0606, u32:0x05_05_0606, u32:0x08_04_0606, u32:0x0e_05_0606, u32:0x14_05_0406, - u32:0x02_05_0404, u32:0x07_04_0505, u32:0x0b_05_0505, u32:0x11_05_0606, u32:0x16_05_0606, - u32:0x04_05_0606, u32:0x08_04_0606, u32:0x0d_05_0606, u32:0x13_05_0606, u32:0x01_05_0606, - u32:0x06_04_0000, u32:0x0a_05_0000, u32:0x10_05_0000, u32:0x1c_05_0000, u32:0x1b_05_0091, - u32:0x1a_05_0000, u32:0x19_05_0000, u32:0x18_05_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0020, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x31_51_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, - u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x00_00_0000, u32:0x05_00_0000, - u32:0x04_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, - u32:0x04_00_0010, u32:0x05_00_0000, u32:0x05_00_0020, u32:0x05_00_0000, u32:0x05_00_0020, - u32:0x04_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x04_00_0000, - u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x04_00_0000, - u32:0x05_00_0000, u32:0x05_00_0000, u32:0x05_00_0000, u32:0x04_00_0000, u32:0x05_00_0000, - u32:0x05_00_0000, u32:0x05_00_0020, u32:0x05_00_0030, u32:0x05_00_0010, u32:0x05_10_0020, - u32:0x05_00_0020, - ], -]; - -const TEST_SYNC = BlockSyncData[2]:[ - BlockSyncData { id: u32:1234, last_block: false }, - BlockSyncData { id: u32:1235, last_block: true }, -]; - -const TEST_CTRL = FseDecoderCtrl[2]:[ - FseDecoderCtrl { - sync: TEST_SYNC[0], - sequences_count: u24:8, - literals_count: u20:0, - of_acc_log: u7:5, - ll_acc_log: u7:5, - ml_acc_log: u7:5, - }, - FseDecoderCtrl { - sync: TEST_SYNC[1], - sequences_count: u24:7, - literals_count: u20:0, - of_acc_log: u7:5, - ll_acc_log: u7:5, - ml_acc_log: u7:6, - }, -]; - -const TEST_AXI_DATA_W = u32:64; -const TEST_REFILLING_SB_DATA_W = TEST_AXI_DATA_W; -const TEST_REFILLING_SB_LENGTH_W = refilling_shift_buffer::length_width(TEST_REFILLING_SB_DATA_W); -const TEST_RAM_DATA_W = u32:32; -const TEST_RAM_SIZE = common::FSE_MAX_SYMBOLS; -const TEST_RAM_ADDR_W = std::clog2(TEST_RAM_SIZE); -const TEST_RAM_WORD_PARTITION_SIZE = TEST_RAM_DATA_W / u32:3; -const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_WORD_PARTITION_SIZE, TEST_RAM_DATA_W); - -type TestRefillingSBOutput = -refilling_shift_buffer::RefillingShiftBufferOutput; - -fn test_command - (block_idx: u32, msg_type: SequenceExecutorMessageType, length: CopyOrMatchLength, - content: CopyOrMatchContent, last: bool) -> CommandConstructorData { - CommandConstructorData { - sync: TEST_SYNC[block_idx], - data: SequenceExecutorPacket { msg_type, length, content, last }, - } -} - -const TEST_DATA_0 = TestRefillingSBOutput[48]:[ - TestRefillingSBOutput { error: false, data: u64:0b11111, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b101, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b100, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b110, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b11, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b1, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b101, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b1, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b11, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b1000, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, -]; - -const TEST_DATA_1 = TestRefillingSBOutput[42]:[ - TestRefillingSBOutput { error: false, data: u64:0b10000, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b1110, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b11001, length: u7:6 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b110, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b1110, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b1, length: u7:6 }, - TestRefillingSBOutput { error: false, data: u64:0b101, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b110, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b11, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b1, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b10011, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b11, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:2 }, - TestRefillingSBOutput { error: false, data: u64:0b1, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:3 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b1010, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b1110, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:1 }, - TestRefillingSBOutput { error: false, data: u64:0b11, length: u7:6 }, - TestRefillingSBOutput { error: false, data: u64:0b10011, length: u7:5 }, - TestRefillingSBOutput { error: false, data: u64:0b10, length: u7:4 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, - TestRefillingSBOutput { error: false, data: u64:0b0, length: u7:0 }, -]; - -// FIXME: test error propagation with TestRefillingSBOutput { error: true, ...} - -const TEST_EXPECTED_COMMANDS_0 = CommandConstructorData[16]:[ - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:1, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:1, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:3, CopyOrMatchContent:6, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:1, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:8, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:11, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:16, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:13, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:6, CopyOrMatchContent:7, - false), - test_command( - u32:0, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:0, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:3, CopyOrMatchContent:24, - true), -]; - -const TEST_EXPECTED_COMMANDS_1 = CommandConstructorData[14]:[ - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:1, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:7, CopyOrMatchContent:4, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:3, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:3, CopyOrMatchContent:6, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:14, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:5, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:19, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:13, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:4, CopyOrMatchContent:1, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:3, CopyOrMatchContent:46, - false), - test_command( - u32:1, SequenceExecutorMessageType::LITERAL, CopyOrMatchLength:0, CopyOrMatchContent:0, - false), - test_command( - u32:1, SequenceExecutorMessageType::SEQUENCE, CopyOrMatchLength:6, CopyOrMatchContent:18, - true), -]; -//#[test_proc] -//proc FseDecoderTest { -// type FseRamRdReq = ram::ReadReq; -// type FseRamRdResp = ram::ReadResp; -// -// type FseRamWrReq = ram::WriteReq; -// type FseRamWrResp = ram::WriteResp; -// -// type RefillingSBCtrl = -// refilling_shift_buffer::RefillingShiftBufferCtrl; -// type RefillingSBOutput = -// refilling_shift_buffer::RefillingShiftBufferOutput; -// -// terminator: chan out; -// -// ctrl_s: chan out; -// finish_r: chan in; -// -// rsb_ctrl_r: chan in; -// rsb_data_s: chan out; -// -// command_r: chan in; -// -// ll_fse_wr_req_s: chan out; -// ll_fse_wr_resp_r: chan in; -// -// ml_fse_wr_req_s: chan out; -// ml_fse_wr_resp_r: chan in; -// -// of_fse_wr_req_s: chan out; -// of_fse_wr_resp_r: chan in; -// -// config (terminator: chan out) { -// let (ctrl_s, ctrl_r) = chan("ctrl"); -// let (finish_s, finish_r) = chan("finish"); -// -// let (rsb_ctrl_s, rsb_ctrl_r) = chan("rsb_ctrl"); -// let (rsb_data_s, rsb_data_r) = chan("rsb_out_data"); -// -// let (command_s, command_r) = chan("command"); -// -// // RAM with FSE lookup for Literal Lengths -// let (ll_fse_rd_req_s, ll_fse_rd_req_r) = chan("ll_fse_rd_req"); -// let (ll_fse_rd_resp_s, ll_fse_rd_resp_r) = chan("ll_fse_rd_resp"); -// let (ll_fse_wr_req_s, ll_fse_wr_req_r) = chan("ll_fse_wr_req"); -// let (ll_fse_wr_resp_s, ll_fse_wr_resp_r) = chan("ll_fse_wr_resp"); -// -// spawn ram::RamModel< -// TEST_RAM_DATA_W, -// TEST_RAM_SIZE, -// TEST_RAM_WORD_PARTITION_SIZE, -// >(ll_fse_rd_req_r, ll_fse_rd_resp_s, ll_fse_wr_req_r, ll_fse_wr_resp_s); -// -// // RAM with FSE lookup for Match Lengths -// let (ml_fse_rd_req_s, ml_fse_rd_req_r) = chan("ml_fse_rd_req"); -// let (ml_fse_rd_resp_s, ml_fse_rd_resp_r) = chan("ml_fse_rd_resp"); -// let (ml_fse_wr_req_s, ml_fse_wr_req_r) = chan("ml_fse_wr_req"); -// let (ml_fse_wr_resp_s, ml_fse_wr_resp_r) = chan("ml_fse_wr_resp"); -// -// spawn ram::RamModel< -// TEST_RAM_DATA_W, -// TEST_RAM_SIZE, -// TEST_RAM_WORD_PARTITION_SIZE, -// >(ml_fse_rd_req_r, ml_fse_rd_resp_s, ml_fse_wr_req_r, ml_fse_wr_resp_s); -// -// // RAM with FSE lookup for Offsets -// let (of_fse_rd_req_s, of_fse_rd_req_r) = chan("of_fse_rd_req"); -// let (of_fse_rd_resp_s, of_fse_rd_resp_r) = chan("of_fse_rd_resp"); -// let (of_fse_wr_req_s, of_fse_wr_req_r) = chan("of_fse_wr_req"); -// let (of_fse_wr_resp_s, of_fse_wr_resp_r) = chan("of_fse_wr_resp"); -// -// spawn ram::RamModel< -// TEST_RAM_DATA_W, -// TEST_RAM_SIZE, -// TEST_RAM_WORD_PARTITION_SIZE, -// >(of_fse_rd_req_r, of_fse_rd_resp_s, of_fse_wr_req_r, of_fse_wr_resp_s); -// -// spawn FseDecoder< -// TEST_RAM_DATA_W, TEST_RAM_ADDR_W, TEST_RAM_NUM_PARTITIONS, -// TEST_AXI_DATA_W, -// >( -// ctrl_r, finish_s, -// rsb_ctrl_s, rsb_data_r, -// command_s, -// ll_fse_rd_req_s, ll_fse_rd_resp_r, -// ml_fse_rd_req_s, ml_fse_rd_resp_r, -// of_fse_rd_req_s, of_fse_rd_resp_r, -// ); -// -// ( -// terminator, -// ctrl_s, finish_r, -// rsb_ctrl_r, rsb_data_s, -// command_r, -// ll_fse_wr_req_s, ll_fse_wr_resp_r, -// ml_fse_wr_req_s, ml_fse_wr_resp_r, -// of_fse_wr_req_s, of_fse_wr_resp_r, -// ) -// } -// -// init { u32:0 } -// -// next (state: u32) { -// let tok = join(); -// -// // write OF table -// let tok = for ((i, of_record), tok): ((u32, u32), token) in -// enumerate(TEST_OF_TABLE[state]) { -// let tok = send(tok, of_fse_wr_req_s, FseRamWrReq { -// addr: i as u8, -// data: of_record, -// mask: u4:0xf, -// }); -// let (tok, _) = recv(tok, of_fse_wr_resp_r); -// tok -// }(tok); -// -// // write ML table -// let tok = for ((i, ml_record), tok): ((u32, u32), token) in -// enumerate(TEST_ML_TABLE[state]) { -// let tok = send(tok, ml_fse_wr_req_s, FseRamWrReq { -// addr: i as u8, -// data: ml_record, -// mask: u4:0xf, -// }); -// let (tok, _) = recv(tok, ml_fse_wr_resp_r); -// tok -// }(tok); -// -// // write LL table -// let tok = for ((i, ll_record), tok): ((u32, u32), token) in -// enumerate(TEST_LL_TABLE[state]) { -// let tok = send(tok, ll_fse_wr_req_s, FseRamWrReq { -// addr: i as u8, -// data: ll_record, -// mask: u4:0xf, -// }); -// let (tok, _) = recv(tok, ll_fse_wr_resp_r); -// tok -// }(tok); -// -// // send ctrl -// let tok = send(tok, ctrl_s, TEST_CTRL[state]); -// trace_fmt!("Sent ctrl {:#x}", TEST_CTRL[state]); -// -// match state { -// u32:0 => { -// // block #0 -// // send data -// let tok = for ((i, data), tok): ((u32, RefillingSBOutput), token) in -// enumerate(TEST_DATA_0) { -// let (tok, buf_ctrl) = recv(tok, rsb_ctrl_r); -// trace_fmt!("Received #{} buf ctrl {:#x}", i + u32:1, buf_ctrl); -// assert_eq(RefillingSBCtrl {length: data.length}, buf_ctrl); -// let tok = send(tok, rsb_data_s, data); -// trace_fmt!("Sent #{} buf data {:#x}", i + u32:1, data); -// tok -// }(tok); -// -// // recv commands -// let tok = for ((i, expected_cmd), tok): ((u32, CommandConstructorData), token) in -// enumerate(TEST_EXPECTED_COMMANDS_0) { -// let (tok, cmd) = recv(tok, command_r); -// trace_fmt!("Received #{} cmd {:#x}", i + u32:1, cmd); -// assert_eq(expected_cmd, cmd); -// tok -// }(tok); -// -// // recv finish -// let (tok, _) = recv(tok, finish_r); -// }, -// u32:1 => { -// // block #1 -// // send data -// let tok = for ((i, data), tok): ((u32, RefillingSBOutput), token) in -// enumerate(TEST_DATA_1) { -// let (tok, buf_ctrl) = recv(tok, rsb_ctrl_r); -// trace_fmt!("Received #{} buf ctrl {:#x}", i + u32:1, buf_ctrl); -// assert_eq(RefillingSBCtrl {length: data.length}, buf_ctrl); -// let tok = send(tok, rsb_data_s, data); -// trace_fmt!("Sent #{} buf data {:#x}", i + u32:1, data); -// tok -// }(tok); -// -// // recv commands -// let tok = for ((i, expected_cmd), tok): ((u32, CommandConstructorData), token) in -// enumerate(TEST_EXPECTED_COMMANDS_1) { -// let (tok, cmd) = recv(tok, command_r); -// trace_fmt!("Received #{} cmd {:#x}", i + u32:1, cmd); -// assert_eq(expected_cmd, cmd); -// tok -// }(tok); -// -// // recv finish -// let (tok, _) = recv(tok, finish_r); -// -// send(tok, terminator, true); -// }, -// }; -// -// state + u32:1 -// } -//} diff --git a/xls/modules/zstd/fse_lookup_dec.x b/xls/modules/zstd/fse_lookup_dec.x index 7a3707a443..cc39be1768 100644 --- a/xls/modules/zstd/fse_lookup_dec.x +++ b/xls/modules/zstd/fse_lookup_dec.x @@ -21,8 +21,6 @@ import xls.modules.zstd.memory.mem_reader; import xls.modules.zstd.memory.axi_ram_reader; import xls.modules.zstd.fse_table_creator; import xls.modules.zstd.refilling_shift_buffer; -import xls.modules.zstd.fse_proba_freq_dec; -import xls.modules.zstd.shift_buffer; import xls.modules.zstd.comp_lookup_dec; import xls.modules.zstd.rle_lookup_dec; import xls.modules.zstd.refilling_shift_buffer_mux; @@ -30,7 +28,10 @@ import xls.modules.zstd.ram_mux; type AccuracyLog = common::FseAccuracyLog; -pub struct FseLookupDecoderReq { is_rle: bool } +pub struct FseLookupDecoderReq { + is_rle: bool, + remainder: common::Remainder +} pub type FseLookupDecoderStatus = common::LookupDecoderStatus; pub type FseLookupDecoderResp = common::LookupDecoderResp; @@ -233,12 +234,12 @@ pub proc FseLookupDecoder< let tok3 = join(tok3_1, tok3_0); - let tok4_0 = send_if(tok3, rle_lookup_req_s, req.is_rle, LookupDecoderReq {}); + let tok4_0 = send_if(tok3, rle_lookup_req_s, req.is_rle, zero!()); if req.is_rle { trace_fmt!("[FseLookupDecoder]: Send request to RLE lookup decoder"); } else { }; let (tok5_0, rle_lookup_resp) = recv_if(tok4_0, rle_lookup_resp_r, req.is_rle, zero!()); if req.is_rle { trace_fmt!("[FseLookupDecoder]: Received response from RLE lookup decoder"); } else { }; - let tok4_1 = send_if(tok3, comp_lookup_req_s, !req.is_rle, CompLookupDecoderReq {}); + let tok4_1 = send_if(tok3, comp_lookup_req_s, !req.is_rle, CompLookupDecoderReq { remainder: req.remainder }); if !req.is_rle { trace_fmt!("[FseLookupDecoder]: Send request to Comp lookup decoder"); } else { }; let (tok5_1, comp_lookup_resp) = recv_if(tok4_1, comp_lookup_resp_r, !req.is_rle, zero!()); if !req.is_rle { trace_fmt!("[FseLookupDecoder]: Received response from Comp lookup decoder"); } else { }; @@ -248,7 +249,8 @@ pub proc FseLookupDecoder< let resp = if req.is_rle { rle_lookup_resp } else { Resp { status: comp_lookup_resp.status, - accuracy_log: comp_lookup_resp.accuracy_log + accuracy_log: comp_lookup_resp.accuracy_log, + remainder: comp_lookup_resp.remainder, } }; let tok6 = send(tok5, fse_lookup_dec_resp_s, resp); @@ -322,8 +324,8 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0xa, num_of_bits: u8:0x0, base: u16:0x0 }, zero!(), ... ], - FseLookupDecoderReq { is_rle: true }, - FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0 } + FseLookupDecoderReq { is_rle: true, remainder: zero!() }, + FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0, remainder: zero!() } ), ( u64[64]:[u64:0x2, u64:0, ...], @@ -331,8 +333,8 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x2, num_of_bits: u8:0x0, base: u16:0x0 }, zero!(), ... ], - FseLookupDecoderReq { is_rle: true }, - FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0 } + FseLookupDecoderReq { is_rle: true, remainder: zero!() }, + FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0, remainder: zero!() } ), ( u64[64]:[u64:0x7, u64:0, ...], @@ -340,8 +342,8 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x7, num_of_bits: u8:0x0, base: u16:0x0 }, zero!(), ... ], - FseLookupDecoderReq { is_rle: true }, - FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0 } + FseLookupDecoderReq { is_rle: true, remainder: zero!() }, + FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:0, remainder: zero!() } ), // COMPRESSED @@ -382,8 +384,8 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x0, num_of_bits: u8:0x0, base: u16:0x15 }, zero!(), ... ], - FseLookupDecoderReq { is_rle: false }, - FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5 } + FseLookupDecoderReq { is_rle: false, remainder: zero!() }, + FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, remainder: zero!() } ), ( u64[64]:[u64:0x41081C158003A5D0, u64:0, ...], @@ -422,8 +424,8 @@ const COMP_LOOKUP_DECODER_TESTCASES: (u64[64], FseTableRecord[TEST_FSE_RAM_SIZE] FseTableRecord { symbol: u8:0x0, num_of_bits: u8:0x0, base: u16:0x17 }, zero!(), ... ], - FseLookupDecoderReq { is_rle: false }, - FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5 } + FseLookupDecoderReq { is_rle: false, remainder: zero!() }, + FseLookupDecoderResp { status: FseLookupDecoderStatus::OK, accuracy_log: AccuracyLog:5, remainder: zero!() } ), ]; diff --git a/xls/modules/zstd/fse_proba_freq_dec.x b/xls/modules/zstd/fse_proba_freq_dec.x index a894685246..83f72fc8a4 100644 --- a/xls/modules/zstd/fse_proba_freq_dec.x +++ b/xls/modules/zstd/fse_proba_freq_dec.x @@ -42,8 +42,6 @@ type SequenceData = common::SequenceData; const SYMBOL_COUNT_WIDTH = common::FSE_SYMBOL_COUNT_WIDTH; const ACCURACY_LOG_WIDTH = common::FSE_ACCURACY_LOG_WIDTH; -pub struct Remainder { value: u1, valid: bool } - pub enum FseProbaFreqDecoderStatus: u1 { OK = 0, ERROR = 1, @@ -57,12 +55,15 @@ const MAX_CONSUMED_FSE_BYTES = MAX_CONSUMED_FSE_BITS / u32:8; const CONSUMED_FSE_BYTES_WIDTH = std::clog2(MAX_CONSUMED_FSE_BYTES); pub type ConsumedFseBytes = uN[CONSUMED_FSE_BYTES_WIDTH]; -pub struct FseProbaFreqDecoderReq {} +pub struct FseProbaFreqDecoderReq { + remainder: common::Remainder +} pub struct FseProbaFreqDecoderResp { status: FseProbaFreqDecoderStatus, accuracy_log: AccuracyLog, symbol_count: SymbolCount, consumed_bytes: ConsumedFseBytes, + remainder: common::Remainder, } enum Fsm : u4 { @@ -83,7 +84,7 @@ struct State { // accuracy log used in the FSE decoding table accuracy_log: AccuracyLog, // remaining bit that can be a leftover from parsing small probability frequencies - remainder: Remainder, + remainder: common::Remainder, // indicates if one more packet with zero probabilities is expected next_recv_zero: bool, // information about remaining probability points @@ -172,7 +173,7 @@ fn get_threshold(bit_width: u16, remaining_proba: u16) -> u16 { } // get the adjusted stream value for calculating probability points -fn get_adjusted_value(data: u16, remainder: Remainder) -> u16 { +fn get_adjusted_value(data: u16, remainder: common::Remainder) -> u16 { if remainder.valid { (data << u16:1) | (remainder.value as u16) } else { data } } @@ -254,7 +255,7 @@ pub proc FseProbaFreqDecoder< let do_recv_req = (state.fsm == Fsm::IDLE); let tok0 = join(); - let (tok1_0, _) = recv_if(tok0, req_r, do_recv_req, zero!()); + let (tok1_0, req) = recv_if(tok0, req_r, do_recv_req, zero!()); let do_buff_data_recv = match (state.fsm) { Fsm::RECV_ACCURACY_LOG => true, @@ -274,33 +275,47 @@ pub proc FseProbaFreqDecoder< let tok1 = join(tok1_1, tok1_2); + trace_fmt!("[FseProbaFreqDec] State: {}", state); + trace_fmt!("[FseProbaFreqDec] Read bits {}", read_bits); + trace_fmt!("[FseProbaFreqDec] Read bits mod 8 {}", read_bits_mod8); + let (buffer_ctrl_option, ram_option, resp_option, new_state) = match state.fsm { Fsm::IDLE => { + trace_fmt!("[FseProbaFreqDec] Req: {}", req); ( (false, zero!()), (false, zero!()), (false, zero!()), - State { fsm: Fsm::SEND_ACCURACY_LOG_REQ, ..state }, + State { + fsm: Fsm::SEND_ACCURACY_LOG_REQ, + remainder: req.remainder, + read_bits: req.remainder.valid as ConsumedFseBits, + read_bits_mod8: req.remainder.valid as u3, + ..state + }, ) }, Fsm::SEND_ACCURACY_LOG_REQ => { ( - (true, BufferCtrl { length: ACCURACY_LOG_WIDTH as Length }), + (true, BufferCtrl { length: ACCURACY_LOG_WIDTH as Length - state.read_bits as Length }), (false, zero!()), (false, zero!()), - State { fsm: Fsm::RECV_ACCURACY_LOG, written_symbol_count, ..state }, + State { + fsm: Fsm::RECV_ACCURACY_LOG, + written_symbol_count, + ..state }, ) }, Fsm::RECV_ACCURACY_LOG => { - let accuracy_log = AccuracyLog:5 + out_data.data as AccuracyLog; + let accuracy_log = AccuracyLog:5 + get_adjusted_value(out_data.data as u16, state.remainder) as AccuracyLog; let remaining_proba = RemainingProba:1 << accuracy_log; - ( (false, zero!()), (false, zero!()), (false, zero!()), State { fsm: Fsm::SEND_SYMBOL_REQ, + remainder: zero!(), accuracy_log, remaining_proba, written_symbol_count, @@ -330,17 +345,15 @@ pub proc FseProbaFreqDecoder< let lower_mask = get_lower_mask(bit_width); let threshold = get_threshold(bit_width, state.remaining_proba as u16); - let mask = (u16:1 << out_data.length) - u16:1; let data = out_data.data as u16; - assert!(data & mask == data, "data should not contain additional bits"); let value = get_adjusted_value(data, state.remainder); let (remainder, value) = if (value & lower_mask) < threshold { - (Remainder { value: value[bit_width - u16:1+:u1], valid: true }, value & lower_mask) + (common::Remainder { value: value[bit_width - u16:1+:u1], valid: true }, value & lower_mask) } else if value > lower_mask { - (zero!(), value - threshold) + (zero!(), value - threshold) } else { - (zero!(), value) + (zero!(), value) }; let proba = value as s16 - s16:1; @@ -451,7 +464,7 @@ pub proc FseProbaFreqDecoder< (false, zero!()), State { fsm: new_fsm, - remainder: zero!(), + remainder: zero!(), written_symbol_count, data_invalid, read_bits, @@ -468,7 +481,7 @@ pub proc FseProbaFreqDecoder< (false, zero!()), State { fsm: Fsm::WRITE_ZERO_PROBA, - remainder: zero!(), + remainder: zero!(), written_symbol_count, zero_proba_count, next_recv_zero, @@ -541,9 +554,15 @@ pub proc FseProbaFreqDecoder< }, Fsm::WAIT_FOR_COMPLETION => { if written_symbol_count == state.symbol_count { + let leave_remainder = state.read_bits_mod8 == u3:1 && state.remainder.valid; + let shift_bits = if leave_remainder { + u3:0 + } else { + state.read_bits_mod8 + }; ( - if state.read_bits_mod8 != u3:0 { - (true, BufferCtrl { length: Length:8 - state.read_bits_mod8 as Length }) + if shift_bits != u3:0 { + (true, BufferCtrl { length: Length:8 - shift_bits as Length }) } else { (false, zero!()) }, @@ -552,7 +571,8 @@ pub proc FseProbaFreqDecoder< State { fsm: Fsm::CONSUME_PADDING, read_bits, - read_bits_mod8, + read_bits_mod8: if leave_remainder { u3:0 } else { read_bits_mod8 }, + remainder: if leave_remainder { state.remainder } else { zero!() }, ..state } ) @@ -576,8 +596,9 @@ pub proc FseProbaFreqDecoder< accuracy_log: state.accuracy_log, symbol_count: state.symbol_count, consumed_bytes: checked_cast(read_bits >> 3), + remainder: state.remainder }), - zero!() + zero!(), ) }, _ => { @@ -744,11 +765,12 @@ proc FseProbaFreqDecoderTest { accuracy_log: AccuracyLog:8, symbol_count: SymbolCount:12, consumed_bytes: ConsumedFseBytes:6, + remainder: zero!(), }); // check that the proc consumed the padding by sending request // and checking over 100 cycles that it won't be served - let tok = send(tok, buff_in_ctrl_s, BufferCtrl { length: u7:0x1 }); + let tok = send(tok, buff_in_ctrl_s, BufferCtrl { length: uN[TEST_LENGTH_WIDTH]:0x1 }); let tok = for (_, tok): (u32, token) in u32:0..u32:100 { let (tok, _, valid) = recv_non_blocking(tok, buff_out_data_r, zero!()); assert_eq(valid, false); @@ -797,6 +819,7 @@ proc FseProbaFreqDecoderTest { accuracy_log: AccuracyLog:9, symbol_count: SymbolCount:2, consumed_bytes: ConsumedFseBytes:2, + remainder: zero!(), }); for ((i, exp_val), tok): ((u32, RamData), token) in enumerate(EXPECTED_RAM_CONTENTS) { @@ -834,6 +857,7 @@ proc FseProbaFreqDecoderTest { accuracy_log: AccuracyLog:9, symbol_count: SymbolCount:2, consumed_bytes: ConsumedFseBytes:2, + remainder: zero!(), }); for ((i, exp_val), tok): ((u32, RamData), token) in enumerate(EXPECTED_RAM_CONTENTS) { @@ -847,9 +871,6 @@ proc FseProbaFreqDecoderTest { tok }((tok)); - // FIXME: test error path: error propagated from ShiftBuffer and assigning more - // probability points than available - let tok = send(tok, terminator, true); } } diff --git a/xls/modules/zstd/fse_table_creator.x b/xls/modules/zstd/fse_table_creator.x index 5e3cdcb5eb..ba7c965f9c 100644 --- a/xls/modules/zstd/fse_table_creator.x +++ b/xls/modules/zstd/fse_table_creator.x @@ -45,7 +45,6 @@ struct FseTableCreatorState { status: Status, req: bool, idx: u10, - // TODO: num_symbs is u8, possibly other fields as well num_symbs: u8, curr_symbol: u8, state_desc_for_symbol: u16, @@ -192,6 +191,9 @@ pub proc FseTableCreator< let receive_start = (state.status == Status::RECEIVE_START); let (tok1, fse_start_msg) = recv_if(tok0, fse_table_start_r, receive_start, zero!()); + if receive_start { + trace_fmt!("[FseTableCreator] received start: {}", fse_start_msg); + } else {}; let get_dpd_data = state.status == Status::TEST_NEGATIVE_PROB || state.status == Status::TEST_POSITIVE_PROB || @@ -237,7 +239,6 @@ pub proc FseTableCreator< data: checked_cast(u16:1), mask: TMP_RAM_REQ_MASK_ALL }); - let (tok5, _) = recv_if(tok5, tmp_wr_resp_r, handle_negative_prob_resp, TestRamWriteResp {}); let handle_positive_prob_write_state_desc = (state.status == Status::HANDLE_POSITIVE_PROB_WRITE_STATE_DESC); let addr = if handle_positive_prob_write_state_desc { @@ -252,7 +253,6 @@ pub proc FseTableCreator< mask: TMP_RAM_REQ_MASK_ALL } ); - let (tok6, _) = recv_if(tok6, tmp_wr_resp_r, handle_positive_prob_write_state_desc, TmpRamWriteResp {}); let inner_for_start_counting = state.status == Status::START_ITERATING_POS; let negative_proba_count = (u16:1 << state.accuracy_log) - state.high_threshold; @@ -282,34 +282,36 @@ pub proc FseTableCreator< let (tok4, _) = recv_if(tok4, tmp2_wr_resp_r, inner_for_write_sym, FseRamWriteResp {}); let last_for = state.status == Status::LAST_FOR; - let tok8 = send_if(tok0, tmp2_rd_req_s, last_for, + // tmp2 read and tmp2 write are sent in different states, so it's safe to use the same token here + let tok_tmp2_rd = send_if(tok0, tmp2_rd_req_s, last_for, Tmp2RamReadReq { addr: checked_cast(state.idx), mask: TMP2_RAM_REQ_MASK_ALL, } ); - let (tok8, fse_resp) = recv_if(tok8, tmp2_rd_resp_r, last_for, zero!()); + let (tok_tmp2_rd, fse_resp) = recv_if(tok_tmp2_rd, tmp2_rd_resp_r, last_for, zero!()); let fse_record_symbol = fse_resp.data; let get_state_desc = state.status == Status::GET_STATE_DESC; let symbol = state.curr_symbol; - let tok8 = send_if(tok8, tmp_rd_req_s, get_state_desc, + let tok_tmp_rd = send_if(tok0, tmp_rd_req_s, get_state_desc, TmpRamReadReq { addr: checked_cast(symbol), mask: TMP_RAM_REQ_MASK_ALL } ); - let (tok8, tmp_resp) = recv_if(tok8, tmp_rd_resp_r, get_state_desc, zero!()); + let (tok_tmp_rd, tmp_resp) = recv_if(tok_tmp_rd, tmp_rd_resp_r, get_state_desc, zero!()); let set_state_desc = state.status == Status::SET_STATE_DESC; - let tok9 = send_if(tok8, tmp_wr_req_s, set_state_desc, + let tok_tmp_wr = send_if(tok_tmp_rd, tmp_wr_req_s, set_state_desc, TmpRamWriteReq { addr: checked_cast(symbol), data: checked_cast(state.state_desc_for_symbol + u16:1), mask: TMP_RAM_REQ_MASK_ALL } ); - let (tok9, _) = recv_if(tok9, tmp_wr_resp_r, set_state_desc, TmpRamWriteResp {}); + + let (_, _) = recv_if(tok_tmp_wr, tmp_wr_resp_r, set_state_desc || handle_positive_prob_write_state_desc || handle_negative_prob_resp, TestRamWriteResp {}); let num_bits = state.accuracy_log - common::highest_set_bit(state.state_desc_for_symbol); let size = u16:1 << state.accuracy_log; @@ -327,8 +329,8 @@ pub proc FseTableCreator< data: checked_cast(complete_record_as_bits), mask: FSE_RAM_REQ_MASK_ALL }; - let tok10 = send_if(tok8, fse_wr_req_s, set_state_desc, fse_wr_req); - let (tok10, _) = recv_if(tok10, fse_wr_resp_r, set_state_desc, FseRamWriteResp {}); + let tok_fse_wr = send_if(tok0, fse_wr_req_s, set_state_desc, fse_wr_req); + let (tok_fse_wr, _) = recv_if(tok_fse_wr, fse_wr_resp_r, set_state_desc, FseRamWriteResp {}); let send_finish = state.status == Status::SEND_FINISH; let tok11 = send_if(tok0, fse_table_finish_s, send_finish, ()); diff --git a/xls/modules/zstd/hash_table.x b/xls/modules/zstd/hash_table.x new file mode 100644 index 0000000000..7cd26607ee --- /dev/null +++ b/xls/modules/zstd/hash_table.x @@ -0,0 +1,473 @@ +// Copyright 2024 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.examples.ram; + +pub struct HashTableReadReq< + KEY_W: u32, SIZE: u32, + SIZE_W:u32 = {std::clog2(SIZE + u32:1)} +> { + num_entries_log2: uN[SIZE_W], // number of HashTable entries used in the runtime + key: uN[KEY_W], +} + +pub struct HashTableReadResp { + is_match: bool, + value: uN[VALUE_W] +} + +pub struct HashTableWriteReq< + KEY_W: u32, VALUE_W: u32, SIZE: u32, + SIZE_W:u32 = {std::clog2(SIZE + u32:1)} +> { + num_entries_log2: uN[SIZE_W], // number of HashTable entries used in the runtime + key: uN[KEY_W], + value: uN[VALUE_W], +} + +pub struct HashTableWriteResp {} + +fn knuth_hash_slow(key: uN[KEY_W]) -> uN[HASH_W] { + (((key * CONSTANT) as u32) >> (u32:32 - HASH_W)) as uN[HASH_W] +} + +fn knuth_hash(key: uN[KEY_W]) -> uN[HASH_W] { + let result = for (i, result): (u32, uN[KEY_W]) in u32:0..u32:32 { + if (CONSTANT >> i) as u1 { result + (key << i) } else { result } + }(uN[KEY_W]:0); + + (result >> (u32:32 - HASH_W)) as uN[HASH_W] +} + +#[test] +fn knuth_hash_check() { + const KNUTH_CONSTANT = u32:0x1e35a7bd; + const HASH_W = u32:32; + + for (i, ()) in u32:0..(u32:1 << u32:7) { + let hash_slow = knuth_hash_slow(i); + let hash_fast = knuth_hash(i); + assert_eq(hash_slow, hash_fast); + }(()); +} + +struct RamData { + value: uN[VALUE_W], + valid: bool, +} + +proc HashTableReadReqHandler< + KEY_W: u32, VALUE_W: u32, SIZE: u32, KNUTH_CONSTANT: u32, + SIZE_W: u32 = {std::clog2(SIZE + u32:1)}, + HASH_W: u32 = {std::clog2(SIZE)}, + RAM_DATA_W: u32 = {VALUE_W + u32:1}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(u32:1, RAM_DATA_W)} +> { + type ReadReq = HashTableReadReq; + type RamReadReq = ram::ReadReq; + + read_req_r: chan in; + ram_read_req_s: chan out; + + config( + read_req_r: chan in, + ram_read_req_s: chan out + ) { + (read_req_r, ram_read_req_s) + } + + init { } + + next(state: ()) { + let tok = join(); + + let (tok_read, read_req, read_req_valid) = + recv_non_blocking(tok, read_req_r, zero!()); + + let ram_read_req = if read_req_valid { + let hash_mask = (uN[HASH_W]:1 << read_req.num_entries_log2) - uN[HASH_W]:1; + let hash = knuth_hash(read_req.key) & hash_mask; + RamReadReq { addr: hash, mask: !uN[RAM_NUM_PARTITIONS]:0 } + } else { + zero!() + }; + + send_if(tok_read, ram_read_req_s, read_req_valid, ram_read_req); + } +} + +proc HashTableReadRespHandler< + VALUE_W: u32, + RAM_DATA_W: u32 = {VALUE_W + u32:1} // value width + data valid width, +> { + type RamReadResp = ram::ReadResp; + type ReadResp = HashTableReadResp; + + ram_read_resp_r: chan in; + read_resp_s: chan out; + + config( + ram_read_resp_r: chan in, + read_resp_s: chan out + ) { + (ram_read_resp_r, read_resp_s) + } + + init { } + + next(state: ()) { + let tok = join(); + + let (tok, ram_read_resp, ram_read_resp_valid) = + recv_non_blocking(tok, ram_read_resp_r, zero!()); + + let read_resp = if ram_read_resp_valid { + let ram_data = RamData { + value: (ram_read_resp.data >> u32:1) as uN[VALUE_W], + valid: ram_read_resp.data as u1, + }; + ReadResp { + is_match: ram_data.valid, + value: ram_data.value + } + } else { + zero!() + }; + + send_if(tok, read_resp_s, ram_read_resp_valid, read_resp); + } +} + +proc HashTableWriteReqHandler< + KEY_W: u32, VALUE_W: u32, SIZE: u32, KNUTH_CONSTANT: u32, + SIZE_W: u32 = {std::clog2(SIZE + u32:1)}, + HASH_W: u32 = {std::clog2(SIZE)}, + RAM_DATA_W: u32 = {VALUE_W + u32:1}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(u32:1, RAM_DATA_W)} +> { + type WriteReq = HashTableWriteReq; + type RamWriteReq = ram::WriteReq; + + write_req_r: chan in; + ram_write_req_s: chan out; + + config( + write_req_r: chan in, + ram_write_req_s: chan out + ) { + (write_req_r, ram_write_req_s) + } + + init { } + + next(state: ()) { + let tok = join(); + + let (tok_write, write_req, write_req_valid) = + recv_non_blocking(tok, write_req_r, zero!()); + + let ram_write_req = if write_req_valid { + let hash_mask = (uN[HASH_W]:1 << write_req.num_entries_log2) - uN[HASH_W]:1; + let hash = knuth_hash(write_req.key) & hash_mask; + let data = write_req.value ++ true; + RamWriteReq { addr: hash, data, mask: !uN[RAM_NUM_PARTITIONS]:0 } + } else { + zero!() + }; + + send_if(tok_write, ram_write_req_s, write_req_valid, ram_write_req); + } +} + +proc HashTableWriteRespHandler { + type RamWriteResp = ram::WriteResp; + type WriteResp = HashTableWriteResp; + + ram_write_resp_r: chan in; + write_resp_s: chan out; + + config( + ram_write_resp_r: chan in, + write_resp_s: chan out + ) { + (ram_write_resp_r, write_resp_s) + } + + init { } + + next(state: ()) { + let tok = join(); + + let (tok, _, ram_write_resp_valid) = + recv_non_blocking(tok, ram_write_resp_r, zero!()); + + send_if(tok, write_resp_s, ram_write_resp_valid, WriteResp {}); + } +} + +pub proc HashTable< + KEY_W: u32, VALUE_W: u32, SIZE: u32, + SIZE_W: u32 = {std::clog2(SIZE + u32:1)}, + HASH_W: u32 = {std::clog2(SIZE)}, + KNUTH_CONSTANT: u32 = {u32:0x1e35a7bd}, + RAM_DATA_W: u32 = {VALUE_W + u32:1}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(u32:1, RAM_DATA_W)} +> { + type ReadReq = HashTableReadReq; + type ReadResp = HashTableReadResp; + type WriteReq = HashTableWriteReq; + type WriteResp = HashTableWriteResp; + + type RamReadReq = ram::ReadReq; + type RamReadResp = ram::ReadResp; + type RamWriteReq = ram::WriteReq; + type RamWriteResp = ram::WriteResp; + + config( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan out, + ram_read_resp_r: chan in, + ram_write_req_s: chan out, + ram_write_resp_r: chan in + ) { + spawn HashTableReadReqHandler< + KEY_W, VALUE_W, SIZE, KNUTH_CONSTANT, + // FIXME: Remove below parameters when resolving default values is fixed + SIZE_W, HASH_W, RAM_DATA_W, RAM_NUM_PARTITIONS, + >( + read_req_r, ram_read_req_s + ); + spawn HashTableReadRespHandler< + VALUE_W, + // FIXME: Remove below parameters when resolving default values is fixed + RAM_DATA_W, + >( + ram_read_resp_r, read_resp_s + ); + spawn HashTableWriteReqHandler< + KEY_W, VALUE_W, SIZE, KNUTH_CONSTANT, + // FIXME: Remove below parameters when resolving default values is fixed + SIZE_W, HASH_W, RAM_DATA_W, RAM_NUM_PARTITIONS, + >( + write_req_r, ram_write_req_s + ); + spawn HashTableWriteRespHandler( + ram_write_resp_r, write_resp_s + ); + } + + init { } + + next(state: ()) { } +} + +const INST_KEY_W = u32:32; +const INST_VALUE_W = u32:32; +const INST_SIZE = u32:512; +const INST_SIZE_W = std::clog2(INST_SIZE + u32:1); +const INST_HASH_W = std::clog2(INST_SIZE); +const INST_RAM_DATA_W = INST_VALUE_W + u32:1; +const INST_RAM_NUM_PARTITIONS = ram::num_partitions(u32:1, INST_RAM_DATA_W); + +proc HashTableInst { + type InstReadReq = HashTableReadReq; + type InstReadResp = HashTableReadResp; + type InstWriteReq = HashTableWriteReq; + type InstWriteResp = HashTableWriteResp; + + type InstRamReadReq = ram::ReadReq; + type InstRamReadResp = ram::ReadResp; + type InstRamWriteReq = ram::WriteReq; + type InstRamWriteResp = ram::WriteResp; + + config( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan out, + ram_read_resp_r: chan in, + ram_write_req_s: chan out, + ram_write_resp_r: chan in + ) { + spawn HashTable( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r + ); + } + + init { } + + next(state: ()) { } +} + +const TEST_KEY_W = u32:32; +const TEST_VALUE_W = u32:32; +const TEST_SIZE = u32:512; +const TEST_SIZE_W = std::clog2(TEST_SIZE + u32:1); +const TEST_HASH_W = std::clog2(TEST_SIZE); +const TEST_RAM_DATA_W = TEST_VALUE_W + u32:1; +const TEST_WORD_PARTITION_SIZE = u32:1; +const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_WORD_PARTITION_SIZE, TEST_RAM_DATA_W); +const TEST_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_INITIALIZED = true; + +type TestReadReq = HashTableReadReq; +type TestReadResp = HashTableReadResp; +type TestWriteReq = HashTableWriteReq; +type TestWriteResp = HashTableWriteResp; + +type TestRamReadReq = ram::ReadReq; +type TestRamReadResp = ram::ReadResp; +type TestRamWriteReq = ram::WriteReq; +type TestRamWriteResp = ram::WriteResp; + +struct TestData { + num_entries_log2: uN[TEST_SIZE_W], + key: uN[TEST_KEY_W], + value: uN[TEST_VALUE_W] +} + +const TEST_DATA = TestData[32]:[ + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0x6109d84c, value: uN[TEST_VALUE_W]:0xdb370dd7}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:7, key: uN[TEST_KEY_W]:0xe773dc7f, value: uN[TEST_VALUE_W]:0xc8f9f817}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:8, key: uN[TEST_KEY_W]:0xd2254d4a, value: uN[TEST_VALUE_W]:0xa0b4c4bd}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0x4c794548, value: uN[TEST_VALUE_W]:0x8a3e6693}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:3, key: uN[TEST_KEY_W]:0xed1884be, value: uN[TEST_VALUE_W]:0x1787d635}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:5, key: uN[TEST_KEY_W]:0x6c40cc5d, value: uN[TEST_VALUE_W]:0x1e0916a3}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0xa7ad798c, value: uN[TEST_VALUE_W]:0x6efa1a96}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:3, key: uN[TEST_KEY_W]:0x8e3bb720, value: uN[TEST_VALUE_W]:0x6d0a7d57}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0xbf9f7bd4, value: uN[TEST_VALUE_W]:0x46ff026c}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:3, key: uN[TEST_KEY_W]:0xd8c1cd03, value: uN[TEST_VALUE_W]:0xdb5b0ded}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0xd1b33035, value: uN[TEST_VALUE_W]:0x7a21e0ed}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:5, key: uN[TEST_KEY_W]:0x8d512e0c, value: uN[TEST_VALUE_W]:0x708a536b}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0x1a950036, value: uN[TEST_VALUE_W]:0x9097f883}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:3, key: uN[TEST_KEY_W]:0x00707a86, value: uN[TEST_VALUE_W]:0xbcb29fa7}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0x2fcd78a1, value: uN[TEST_VALUE_W]:0x71bae380}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:8, key: uN[TEST_KEY_W]:0x34d8adc5, value: uN[TEST_VALUE_W]:0xdff20f62}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:5, key: uN[TEST_KEY_W]:0xd04ebdda, value: uN[TEST_VALUE_W]:0x9c785523}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:5, key: uN[TEST_KEY_W]:0x9b419a1a, value: uN[TEST_VALUE_W]:0xf1d27361}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0x9eb7784d, value: uN[TEST_VALUE_W]:0x58a9d8f2}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:7, key: uN[TEST_KEY_W]:0x6d7499ef, value: uN[TEST_VALUE_W]:0x40387b18}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:8, key: uN[TEST_KEY_W]:0xb255d705, value: uN[TEST_VALUE_W]:0x73ecbb7b}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:8, key: uN[TEST_KEY_W]:0x132c9499, value: uN[TEST_VALUE_W]:0x48b85084}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0xd3acf006, value: uN[TEST_VALUE_W]:0xbbd2f2b9}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:2, key: uN[TEST_KEY_W]:0x0dd951cd, value: uN[TEST_VALUE_W]:0x975ab3fe}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:6, key: uN[TEST_KEY_W]:0x3d6cd6b1, value: uN[TEST_VALUE_W]:0xe18f2e83}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:5, key: uN[TEST_KEY_W]:0xf511fadb, value: uN[TEST_VALUE_W]:0xb99e2ab4}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:2, key: uN[TEST_KEY_W]:0x90bea2bb, value: uN[TEST_VALUE_W]:0xc88b54c2}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0xf2513572, value: uN[TEST_VALUE_W]:0x42ef67d9}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0x2dd80b55, value: uN[TEST_VALUE_W]:0x3b399d05}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0x823af460, value: uN[TEST_VALUE_W]:0x89d154ba}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:9, key: uN[TEST_KEY_W]:0x8ab8897e, value: uN[TEST_VALUE_W]:0xb30eb8c5}, + TestData {num_entries_log2: uN[TEST_SIZE_W]:2, key: uN[TEST_KEY_W]:0xe9499524, value: uN[TEST_VALUE_W]:0xb4a30d68}, +]; + + +#[test_proc] +proc HashTable_test { + terminator_s: chan out; + read_req_s: chan out; + read_resp_r: chan in; + write_req_s: chan out; + write_resp_r: chan in; + + config(terminator_s: chan out) { + let (read_req_s, read_req_r) = chan("read_req"); + let (read_resp_s, read_resp_r) = chan("read_resp"); + let (write_req_s, write_req_r) = chan("write_req"); + let (write_resp_s, write_resp_r) = chan("write_resp"); + + let (ram_read_req_s, ram_read_req_r) = chan("ram_read_req"); + let (ram_read_resp_s, ram_read_resp_r) = chan("ram_read_resp"); + let (ram_write_req_s, ram_write_req_r) = chan("ram_write_req"); + let (ram_write_resp_s, ram_write_resp_r) = chan("ram_write_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_SIZE, TEST_WORD_PARTITION_SIZE, + TEST_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_INITIALIZED + >(ram_read_req_r, ram_read_resp_s, ram_write_req_r, ram_write_resp_s); + + spawn HashTable( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r + ); + + ( + terminator_s, + read_req_s, read_resp_r, + write_req_s, write_resp_r + ) + } + + init { } + + next(state: ()) { + let tok = join(); + + let tok = for ((i, test_data), tok): ((u32, TestData), token) in enumerate(TEST_DATA) { + // try to read data that was not written + let read_req = TestReadReq { + num_entries_log2: test_data.num_entries_log2, + key: test_data.key + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{}.1 read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{}.1 read response {:#x}", i + u32:1, read_resp); + if read_resp.is_match { + // there may be match in case of a conflict + assert_eq(false, test_data.value == read_resp.value); + } else { }; + + // write data + let write_req = TestWriteReq { + num_entries_log2: test_data.num_entries_log2, + key: test_data.key, + value: test_data.value, + }; + let tok = send(tok, write_req_s, write_req); + trace_fmt!("Sent #{} write request {:#x}", i + u32:1, write_req); + + let (tok, write_resp) = recv(tok, write_resp_r); + trace_fmt!("Received #{} write response {:#x}", i + u32:1, write_resp); + + // read data after it was written + let read_req = TestReadReq { + num_entries_log2: test_data.num_entries_log2, + key: test_data.key + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{}.2 read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{}.2 read response {:#x}", i + u32:1, read_resp); + assert_eq(TestReadResp { is_match: true, value: test_data.value }, read_resp); + + tok + }(tok); + + send(tok, terminator_s, true); + } +} diff --git a/xls/modules/zstd/history_buffer.x b/xls/modules/zstd/history_buffer.x new file mode 100644 index 0000000000..15edb7e597 --- /dev/null +++ b/xls/modules/zstd/history_buffer.x @@ -0,0 +1,491 @@ +// Copyright 2024 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 contains implementation of HistoryBuffer. + + +import std; + +import xls.examples.ram as ram; +import xls.modules.zstd.aligned_parallel_ram as aligned_parallel_ram; + +const RAM_NUM = aligned_parallel_ram::RAM_NUM; +const RAM_NUM_W = aligned_parallel_ram::RAM_NUM_W; + + +pub struct HistoryBufferReadReq { + offset: uN[OFFSET_W], +} + +pub struct HistoryBufferReadResp { + data: uN[DATA_W], +} + +pub struct HistoryBufferWriteReq { + data: uN[DATA_W], +} + +pub struct HistoryBufferWriteResp {} + +struct HistoryBufferState { + curr_offset: uN[OFFSET_W], + length: uN[OFFSET_W], +} + +proc HistoryBufferReadRespHandler { + type ReadResp = HistoryBufferReadResp; + type ParallelRamReadResp = aligned_parallel_ram::AlignedParallelRamReadResp; + + parallel_ram_read_resp_r: chan in; + read_resp_s: chan out; + + config( + parallel_ram_read_resp_r: chan in, + read_resp_s: chan out, + ) { + ( + parallel_ram_read_resp_r, + read_resp_s, + ) + } + + init { } + + next (state: ()) { + let (tok, parallel_ram_read_resp, parallel_ram_read_resp_valid) = recv_non_blocking( + join(), parallel_ram_read_resp_r, zero!() + ); + + let read_resp = ReadResp { + data: parallel_ram_read_resp.data, + }; + + send_if(tok, read_resp_s, parallel_ram_read_resp_valid, read_resp); + } +} + +proc HistoryBufferWriteRespHandler { + type WriteResp = HistoryBufferWriteResp; + type ParallelRamWriteResp = aligned_parallel_ram::AlignedParallelRamWriteResp; + + parallel_ram_write_resp_r: chan in; + write_resp_s: chan out; + + config( + parallel_ram_write_resp_r: chan in, + write_resp_s: chan out, + ) { + ( + parallel_ram_write_resp_r, + write_resp_s, + ) + } + + init { } + + next (state: ()) { + let (tok, _, parallel_ram_write_resp_valid) = recv_non_blocking( + join(), parallel_ram_write_resp_r, zero!() + ); + + let write_resp = WriteResp { }; + + send_if(tok, write_resp_s, parallel_ram_write_resp_valid, write_resp); + } +} + +pub proc HistoryBuffer< + SIZE: u32, + DATA_W: u32, + OFFSET_W: u32 = {std::clog2(SIZE)}, + RAM_SIZE: u32 = {SIZE / RAM_NUM}, + RAM_DATA_W: u32 = {DATA_W / RAM_NUM}, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + RAM_PARTITION_SIZE: u32 = {RAM_DATA_W}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_PARTITION_SIZE, RAM_DATA_W)}, +>{ + type ReadReq = HistoryBufferReadReq; + type ReadResp = HistoryBufferReadResp; + type WriteReq = HistoryBufferWriteReq; + type WriteResp = HistoryBufferWriteResp; + + type ParallelRamReadReq = aligned_parallel_ram::AlignedParallelRamReadReq; + type ParallelRamReadResp = aligned_parallel_ram::AlignedParallelRamReadResp; + type ParallelRamWriteReq = aligned_parallel_ram::AlignedParallelRamWriteReq; + type ParallelRamWriteResp = aligned_parallel_ram::AlignedParallelRamWriteResp; + + type RamReadReq = ram::ReadReq; + type RamReadResp = ram::ReadResp; + type RamWriteReq = ram::WriteReq; + type RamWriteResp = ram::WriteResp; + + type State = HistoryBufferState; + type Offset = uN[OFFSET_W]; + + read_req_r: chan in; + write_req_r: chan in; + + // RAM interface + parallel_ram_read_req_s: chan out; + parallel_ram_write_req_s: chan out; + + config ( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan[RAM_NUM] out, + ram_read_resp_r: chan[RAM_NUM] in, + ram_write_req_s: chan[RAM_NUM] out, + ram_write_resp_r: chan[RAM_NUM] in, + ) { + let (parallel_ram_read_req_s, parallel_ram_read_req_r) = chan("parallel_ram_read_req"); + let (parallel_ram_read_resp_s, parallel_ram_read_resp_r) = chan("parallel_ram_read_resp"); + let (parallel_ram_write_req_s, parallel_ram_write_req_r) = chan("parallel_ram_write_req"); + let (parallel_ram_write_resp_s, parallel_ram_write_resp_r) = chan("parallel_ram_write_resp"); + + spawn HistoryBufferReadRespHandler ( + parallel_ram_read_resp_r, read_resp_s, + ); + + spawn HistoryBufferWriteRespHandler ( + parallel_ram_write_resp_r, write_resp_s, + ); + + spawn aligned_parallel_ram::AlignedParallelRam( + parallel_ram_read_req_r, parallel_ram_read_resp_s, + parallel_ram_write_req_r, parallel_ram_write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + + ( + read_req_r, + write_req_r, + parallel_ram_read_req_s, + parallel_ram_write_req_s, + ) + } + + init { zero!() } + + next (state: State) { + const ONE_TRANSFER_WIDTH = ((DATA_W as uN[OFFSET_W]) >> u32:3); + const MAX_OFFSET = zero!(); + + // handle read request + let (tok, read_req, read_req_valid) = recv_non_blocking(join(), read_req_r, zero!()); + let offset_invalid = (read_req.offset > state.length - ONE_TRANSFER_WIDTH); + if read_req_valid & offset_invalid { + trace_fmt!("WARNING: Asking for too high offset (req: {:#x}, max: {:#x})", + read_req.offset, state.length - ONE_TRANSFER_WIDTH); + } else {}; + + let parallel_ram_read_req = ParallelRamReadReq { + addr: state.curr_offset - read_req.offset - ONE_TRANSFER_WIDTH, + }; + + send_if(tok, parallel_ram_read_req_s, read_req_valid, parallel_ram_read_req); + + // handle write request + let (tok, write_req, write_req_valid) = recv_non_blocking(join(), write_req_r, zero!()); + + let parallel_ram_write_req = ParallelRamWriteReq { + addr: state.curr_offset, + data: write_req.data, + }; + + send_if(tok, parallel_ram_write_req_s, write_req_valid, parallel_ram_write_req); + + // update offset + if write_req_valid { + let next_length = if state.length > MAX_OFFSET - ONE_TRANSFER_WIDTH { + MAX_OFFSET + } else { + state.length + ONE_TRANSFER_WIDTH + }; + + State { + curr_offset: state.curr_offset + ONE_TRANSFER_WIDTH, + length: next_length, + } + } else { + state + } + } +} + +const INST_SIZE = u32:1024; +const INST_DATA_W = u32:64; +const INST_OFFSET_W = {std::clog2(INST_SIZE)}; +const INST_RAM_SIZE = INST_SIZE / RAM_NUM; +const INST_RAM_DATA_W = {INST_DATA_W / RAM_NUM}; +const INST_RAM_ADDR_W = {std::clog2(INST_RAM_SIZE)}; +const INST_RAM_PARTITION_SIZE = {INST_RAM_DATA_W}; +const INST_RAM_NUM_PARTITIONS = {ram::num_partitions(INST_RAM_PARTITION_SIZE, INST_RAM_DATA_W)}; + +proc HistoryBufferInst { + type InstReadReq = HistoryBufferReadReq; + type InstReadResp = HistoryBufferReadResp; + type InstWriteReq = HistoryBufferWriteReq; + type InstWriteResp = HistoryBufferWriteResp; + + type InstParallelRamReadReq = aligned_parallel_ram::AlignedParallelRamReadReq; + type InstParallelRamReadResp = aligned_parallel_ram::AlignedParallelRamReadResp; + type InstParallelRamWriteReq = aligned_parallel_ram::AlignedParallelRamWriteReq; + type InstParallelRamWriteResp = aligned_parallel_ram::AlignedParallelRamWriteResp; + + type InstRamReadReq = ram::ReadReq; + type InstRamReadResp = ram::ReadResp; + type InstRamWriteReq = ram::WriteReq; + type InstRamWriteResp = ram::WriteResp; + + config ( + read_req_r: chan in, + read_resp_s: chan out, + write_req_r: chan in, + write_resp_s: chan out, + ram_read_req_s: chan[RAM_NUM] out, + ram_read_resp_r: chan[RAM_NUM] in, + ram_write_req_s: chan[RAM_NUM] out, + ram_write_resp_r: chan[RAM_NUM] in, + ) { + spawn HistoryBuffer ( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + } + + init { } + + next (state: ()) { } +} + +const TEST_SIZE = u32:128; +const TEST_DATA_W = u32:64; +const TEST_OFFSET_W = {std::clog2(TEST_SIZE)}; +const TEST_RAM_SIZE = TEST_SIZE / aligned_parallel_ram::RAM_NUM; +const TEST_RAM_DATA_W = {TEST_DATA_W / RAM_NUM}; +const TEST_RAM_ADDR_W = {std::clog2(TEST_RAM_SIZE)}; +const TEST_RAM_PARTITION_SIZE = {TEST_RAM_DATA_W}; +const TEST_RAM_NUM_PARTITIONS = {ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W)}; + +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; + +type TestReadReq = HistoryBufferReadReq; +type TestReadResp = HistoryBufferReadResp; +type TestWriteReq = HistoryBufferWriteReq; +type TestWriteResp = HistoryBufferWriteResp; + +type TestRamReadReq = ram::ReadReq; +type TestRamReadResp = ram::ReadResp; +type TestRamWriteReq = ram::WriteReq; +type TestRamWriteResp = ram::WriteResp; + +const TEST_DATA = uN[TEST_DATA_W][64]:[ + uN[TEST_DATA_W]:0x44f9_072b_5ef2_8a80, uN[TEST_DATA_W]:0x4c01_2eda_5f3d_f4e1, + uN[TEST_DATA_W]:0x75ac_641d_fd42_0551, uN[TEST_DATA_W]:0x3bd0_3798_b29b_725f, + uN[TEST_DATA_W]:0x840e_71e9_e0e6_4fe1, uN[TEST_DATA_W]:0x9436_c1e7_bf3c_14e2, + uN[TEST_DATA_W]:0x1c64_9595_300d_4e0c, uN[TEST_DATA_W]:0x26ad_a821_926d_d9e5, + uN[TEST_DATA_W]:0x27e4_6ce8_a2b4_3a71, uN[TEST_DATA_W]:0xf9d6_cf94_6a39_5c5d, + uN[TEST_DATA_W]:0x7894_d415_88b5_dd0c, uN[TEST_DATA_W]:0x5c4e_4607_96bc_5d54, + uN[TEST_DATA_W]:0x29a4_3388_8b44_d9eb, uN[TEST_DATA_W]:0xda83_ee49_d921_7fb6, + uN[TEST_DATA_W]:0xf25f_c785_12e6_dfd0, uN[TEST_DATA_W]:0x1b8c_06fb_32ea_165a, + uN[TEST_DATA_W]:0x5dda_92e0_faca_af84, uN[TEST_DATA_W]:0x1157_8f9a_6e5c_7e78, + uN[TEST_DATA_W]:0xc908_a151_5b8c_b908, uN[TEST_DATA_W]:0xe978_4a80_f2e9_b11a, + uN[TEST_DATA_W]:0xc34e_96c0_4ae1_dfa9, uN[TEST_DATA_W]:0x4b06_4c8c_df6d_cae5, + uN[TEST_DATA_W]:0x9d51_4716_fd6f_afe9, uN[TEST_DATA_W]:0xfe42_4a9d_29ae_4bc4, + uN[TEST_DATA_W]:0x77ec_b4dd_9238_38b9, uN[TEST_DATA_W]:0xdf45_a790_a3da_1768, + uN[TEST_DATA_W]:0x45e9_5594_ffca_0604, uN[TEST_DATA_W]:0xe496_09f4_18ca_f955, + uN[TEST_DATA_W]:0x57cb_3c3d_ed78_62fd, uN[TEST_DATA_W]:0x0254_24bc_24fa_99f8, + uN[TEST_DATA_W]:0xc405_370f_a58a_1303, uN[TEST_DATA_W]:0xa451_310a_65b2_4785, + uN[TEST_DATA_W]:0x4373_65ac_f3ce_97ec, uN[TEST_DATA_W]:0x2a85_abd3_afde_133c, + uN[TEST_DATA_W]:0x836e_ce62_56cb_50ec, uN[TEST_DATA_W]:0x53ce_ab2f_d079_eb9a, + uN[TEST_DATA_W]:0xae76_7db7_0e64_8b88, uN[TEST_DATA_W]:0x079a_c187_642d_cbac, + uN[TEST_DATA_W]:0x2d07_5e3b_6150_d5c5, uN[TEST_DATA_W]:0x7865_5206_3c5a_98ed, + uN[TEST_DATA_W]:0xe905_351c_edda_0682, uN[TEST_DATA_W]:0xf41d_f3f2_1106_3639, + uN[TEST_DATA_W]:0xa44c_05c0_24b3_86ad, uN[TEST_DATA_W]:0xaa1f_c6b5_4c02_1f0c, + uN[TEST_DATA_W]:0xad67_cc1a_8740_87ae, uN[TEST_DATA_W]:0xf382_3bbf_f4b8_2f81, + uN[TEST_DATA_W]:0xe0cd_1eb3_b8c0_820b, uN[TEST_DATA_W]:0xb5d5_1c98_3415_1319, + uN[TEST_DATA_W]:0x583e_9722_ed31_84e6, uN[TEST_DATA_W]:0x6063_ccb6_6228_286e, + uN[TEST_DATA_W]:0xc642_cca8_e04f_769e, uN[TEST_DATA_W]:0x7cc7_ab72_7a9c_05d8, + uN[TEST_DATA_W]:0x4a66_f7c1_7b5e_6d30, uN[TEST_DATA_W]:0xd3d2_5e04_0310_7689, + uN[TEST_DATA_W]:0xe99d_a201_5dee_8e16, uN[TEST_DATA_W]:0xee15_ca30_c679_e1dd, + uN[TEST_DATA_W]:0xe61c_4ac3_183e_9478, uN[TEST_DATA_W]:0x2528_e948_2349_f8fd, + uN[TEST_DATA_W]:0xf15d_4275_a042_2135, uN[TEST_DATA_W]:0x05b5_3768_34e9_4bca, + uN[TEST_DATA_W]:0x1e00_a1a9_cffd_7a84, uN[TEST_DATA_W]:0x3396_a42c_2433_76f2, + uN[TEST_DATA_W]:0x80ba_e00e_9b93_7d76, uN[TEST_DATA_W]:0x85d4_10e6_404f_fa4d, +]; + +#[test_proc] +proc HistoryBuffer_test { + terminator: chan out; + + read_req_s: chan out; + read_resp_r: chan in; + write_req_s: chan out; + write_resp_r: chan in; + + config (terminator: chan out) { + let (read_req_s, read_req_r) = chan("read_req"); + let (read_resp_s, read_resp_r) = chan("read_resp"); + let (write_req_s, write_req_r) = chan("write_req"); + let (write_resp_s, write_resp_r) = chan("write_resp"); + + let (ram_read_req_s, ram_read_req_r) = chan[RAM_NUM]("ram_read_req"); + let (ram_read_resp_s, ram_read_resp_r) = chan[RAM_NUM]("ram_read_resp"); + let (ram_write_req_s, ram_write_req_r) = chan[RAM_NUM]("ram_write_req"); + let (ram_write_resp_s, ram_write_resp_r) = chan[RAM_NUM]("ram_write_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[0], ram_read_resp_s[0], ram_write_req_r[0], ram_write_resp_s[0], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[1], ram_read_resp_s[1], ram_write_req_r[1], ram_write_resp_s[1], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[2], ram_read_resp_s[2], ram_write_req_r[2], ram_write_resp_s[2], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[3], ram_read_resp_s[3], ram_write_req_r[3], ram_write_resp_s[3], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[4], ram_read_resp_s[4], ram_write_req_r[4], ram_write_resp_s[4], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[5], ram_read_resp_s[5], ram_write_req_r[5], ram_write_resp_s[5], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[6], ram_read_resp_s[6], ram_write_req_r[6], ram_write_resp_s[6], + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED + >( + ram_read_req_r[7], ram_read_resp_s[7], ram_write_req_r[7], ram_write_resp_s[7], + ); + + spawn HistoryBuffer ( + read_req_r, read_resp_s, + write_req_r, write_resp_s, + ram_read_req_s, ram_read_resp_r, + ram_write_req_s, ram_write_resp_r, + ); + + ( + terminator, + read_req_s, read_resp_r, + write_req_s, write_resp_r, + ) + } + + init { } + + next (state: ()) { + let tok = join(); + + let tok = for (i, tok) in u32:0..array_size(TEST_DATA) { + let test_data = TEST_DATA[i]; + + // write current test data + let write_req = TestWriteReq { + data: test_data, + }; + let tok = send(tok, write_req_s, write_req); + trace_fmt!("Sent #{} write request {:#x}", i + u32:1, write_req); + + let (tok, _) = recv(tok, write_resp_r); + trace_fmt!("Received #{} write response", i + u32:1); + + // check written data + let read_req = TestReadReq { + offset: uN[TEST_OFFSET_W]:0, + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{} read request {:#x}", i + u32:1, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{} read response {:#x}", i + u32:1, read_resp); + assert_eq(test_data, read_resp.data); + + // check previously saved data + let tok = for (offset, tok) in u32:0..(TEST_SIZE - TEST_DATA_W) { + // check only offsets where data was written also dont check for all offsets + // to speedup the test + if (offset < RAM_NUM * i) && ((offset + i) % u32:13 == u32:0) { + let data_idx_0 = ((i * RAM_NUM - offset) >> RAM_NUM_W) % array_size(TEST_DATA); + let data_idx_1 = (((i * RAM_NUM - offset) >> RAM_NUM_W) + u32:1) % array_size(TEST_DATA); + let ram_offset = (offset) as uN[RAM_NUM_W]; + let prev_test_data = if ram_offset == uN[RAM_NUM_W]:0 { + TEST_DATA[data_idx_0] + } else { + ( + TEST_DATA[data_idx_1] << (TEST_RAM_DATA_W * ram_offset as u32) | + TEST_DATA[data_idx_0] >> (TEST_RAM_DATA_W * (aligned_parallel_ram::RAM_NUM - ram_offset as u32)) + ) + }; + + let read_req = TestReadReq { + offset: offset as uN[TEST_OFFSET_W], + }; + let tok = send(tok, read_req_s, read_req); + trace_fmt!("Sent #{}.{} read request {:#x}", i + u32:1, offset, read_req); + + let (tok, read_resp) = recv(tok, read_resp_r); + trace_fmt!("Received #{}.{} read response {:#x}", i + u32:1, offset, read_resp); + assert_eq(prev_test_data, read_resp.data); + + tok + } else { + tok + } + }(tok); + + tok + }(tok); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/huffman_algorithm.x b/xls/modules/zstd/huffman_algorithm.x new file mode 100644 index 0000000000..9f19a96c7a --- /dev/null +++ b/xls/modules/zstd/huffman_algorithm.x @@ -0,0 +1,1062 @@ +// Copyright 2025 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 contains huffman algorithm implementation +// The algorithm is based on ZSTD implementation (https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L1273) +// +// 1. Build an initial tree based on the frequencies, sort it in descending order based on frequencies +// 2. Build an unlimited-depth Huffman tree +// 3. Enforce max-depth=11 +// 4. Convert the tree to encoding +// } + +import std; + +const MAX_HUFFMAN_BITS = u32:11; +type HuffmanPrefix = uN[MAX_HUFFMAN_BITS]; + +pub struct HuffmanPrefixEntry { + nbits: u4, + encoding: HuffmanPrefix +} + +// TODO: change MAX_SYMBOL_TYPE to u32 when it's supported +// NOTE: MAX_SYMBOL is generic for testing purposes +struct HuffmanPrefixTable { + data: HuffmanPrefixEntry[MAX_SYMBOL + u32:1] +} + +struct FrequencyTable { + data: uN[ADDR_W][MAX_SYMBOL + u32:1] +} + +struct HuffmanNode { + symbol: u8, + freq: uN[ADDR_W], + parent: uN[ADDR_W] +} + +struct HuffmanTree { + data: HuffmanNode[MAX_SYMBOL + u32:1] // zero +} + +fn huffman_first_nonzero_rank(tree: HuffmanTree) -> u32 { + const TABLE_LENGTH = MAX_SYMBOL + u32:1; + + let huff_node = tree.data; + for (i, max_ix) in u32:0..TABLE_LENGTH { + let ix = MAX_SYMBOL - i; + if huff_node[max_ix].freq != u32:0 { + max_ix + } else if huff_node[ix].freq != u32:0 { + ix + } else { + max_ix + } + }(MAX_SYMBOL) +} + +fn huffman_max_nbits(table: HuffmanPrefixTable) -> u4 { + for (e, max) in table.data { + if e.nbits > max { + e.nbits + } else { + max + } + }(u4:0) +} + +fn huffman_tree_to_table( + leafs: HuffmanTree, + leafs_len: u32, + nonleafs: HuffmanTree, + nonleafs_len: u32 +) -> HuffmanPrefixTable { + type Table = HuffmanPrefixTable; + type Tree = HuffmanTree; + const TABLE_LENGTH = MAX_SYMBOL + u32:1; + type RankTable = u16[TABLE_LENGTH]; + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L709-L714 + let root_table = + for (i, table) in u32:0..TABLE_LENGTH { + let ix = MAX_SYMBOL - i; + if ix >= nonleafs_len { + table + } else if ix == nonleafs_len - u32:1 { + // root = zero bits + Table{data: update(table.data, ix, HuffmanPrefixEntry{nbits: u4:0, encoding: HuffmanPrefix:0})} + } else { + let parent = table.data[nonleafs.data[ix].parent]; + Table{data: update(table.data, ix, HuffmanPrefixEntry{nbits: parent.nbits + u4:1, encoding: HuffmanPrefix:0})} + } + }(zero!()); + + let (prefix_table, nb_per_rank) = + for (i, (table, nb_per_rank)) in u32:0..TABLE_LENGTH { + if i >= leafs_len { + (table, nb_per_rank) + } else { + let nbits = root_table.data[leafs.data[i].parent].nbits + u4:1; + let my_symbol = leafs.data[i].symbol; + ( + Table{data: update(table.data, my_symbol, HuffmanPrefixEntry{nbits: nbits, encoding: HuffmanPrefix:0})}, + update(nb_per_rank, nbits, nb_per_rank[nbits] + u16:1) + ) + } + }((zero!
(), zero!())); + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L741-L747 + let (val_per_rank, _) = + for (i, (val_per_rank, min)) in u32:0..MAX_SYMBOL { + let n = MAX_SYMBOL - i; + let next_min = (min + nb_per_rank[n]) >> 1; + (update(val_per_rank, n, min), next_min) + }((zero!(), u16:0)); + + let (prefix_table, _) = + for (i, (table, val_per_rank)) in u32:0..TABLE_LENGTH { + let nbits = table.data[i].nbits; + let encoding = val_per_rank[nbits] as HuffmanPrefix; + + ( + Table{data: update(table.data, i, HuffmanPrefixEntry{nbits: nbits, encoding: encoding})}, + update(val_per_rank, nbits, val_per_rank[nbits] + u16:1) + ) + }((prefix_table, val_per_rank)); + prefix_table +} + +// https://github.com/facebook/zstd/blob/f9a6031963dee08620855545bdad7d519c208e8a/lib/compress/huf_compress.c#L681 +// returns leafs, leaf set size, nonleafs, nonleaf set size +fn huffman_build_tree(leafs: HuffmanTree) -> (HuffmanTree, u32, HuffmanTree, u32) { + const TABLE_LENGTH = MAX_SYMBOL + u32:1; + const STARTNODE = u32:0; // here it differs, ZSTD places everything in "huffNode" buffer + type Addr = uN[ADDR_W]; + type Tree = HuffmanTree; + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L684-L693 + let nonnull_rank = huffman_first_nonzero_rank(leafs); + + if nonnull_rank == u32:0 { + (leafs, u32:1, zero!(), u32:0) + } else { + let node_nb = STARTNODE; + let nonleafs = zero!(); + let low_n = node_nb; + let low_s = nonnull_rank; + let node_root = low_s - u32:1; + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L694-L696 + // this tree can be of the same size as leafs since a full binary tree contains n leafs and n-1 non-leafs + let nonleafs = Tree { data: update(nonleafs.data, node_nb, + HuffmanNode { + freq: leafs.data[low_s].freq + leafs.data[low_s-u32:1].freq, + symbol: u8:0, + parent: Addr:0 + } + )}; + let leafs = Tree { data: update(leafs.data, low_s, + HuffmanNode { + parent: node_nb, + ..leafs.data[low_s] + } + )}; + let leafs = Tree { data: update(leafs.data, low_s-u32:1, + HuffmanNode { + parent: node_nb, + ..leafs.data[low_s-u32:1] + } + )}; + let node_nb = node_nb + u32:1; + let low_s = low_s - u32:2; + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L697 + let nonleafs = + for (i, t) in u32:0..TABLE_LENGTH { + if i < node_nb || i > node_root { + t + } else { + Tree{data: update(t.data, i, HuffmanNode { + freq: all_ones!(), + symbol: u8:0, + parent: Addr:0 + })} + } + }(nonleafs); + + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L700-L707 + let (nonleafs, leafs, node_nb, low_s, low_n) = + for (_, (nonleafs, leafs, node_nb, low_s, low_n)) in u32:0..TABLE_LENGTH { + trace_fmt!("{} {} {}", node_nb, low_s, low_n); + + if node_nb <= node_root { + let (n1, n2, low_s, low_n, first_in_leafs, second_in_leafs) = if low_s != all_ones!() { + let (n1, low_s, low_n, first_in_leafs) = if leafs.data[low_s].freq < nonleafs.data[low_n].freq { + (low_s, low_s - u32:1, low_n, true) + } else { + (low_n, low_s, low_n + u32:1, false) + }; + + let (n2, low_s, low_n, second_in_leafs) = + if low_s == all_ones!() { + (low_n, low_s, low_n + u32:1, false) + } else { + if leafs.data[low_s].freq < nonleafs.data[low_n].freq { + (low_s, low_s - u32:1, low_n, true) + } else { + (low_n, low_s, low_n + u32:1, false) + } + }; + + (n1, n2, low_s, low_n, first_in_leafs, second_in_leafs) + } else { + (low_n, low_n + u32:1, low_s, low_n + u32:2, false, false) + }; + + let freq1 = if first_in_leafs { leafs.data[n1].freq } else { nonleafs.data[n1].freq }; + let freq2 = if second_in_leafs { leafs.data[n2].freq } else { nonleafs.data[n2].freq }; + let first_tree = if first_in_leafs { u32:0 } else { u32:1 }; + let second_tree = if second_in_leafs { u32:0 } else { u32:1 }; + trace_fmt!("Huffman algorithm: joining [{}]:{} <-> [{}]:{}", first_tree, n1, second_tree, n2); + + + let nonleafs = Tree { data: update(nonleafs.data, node_nb, + HuffmanNode { + freq: freq1 + freq2, + symbol: u8:0, + parent: Addr:0 + } + )}; + + let (leafs, nonleafs) = if first_in_leafs { + ( + Tree { data: update(leafs.data, n1, + HuffmanNode { + parent: node_nb, + ..leafs.data[n1] + } + )}, + nonleafs + ) + } else { + ( + leafs, + Tree { data: update(nonleafs.data, n1, + HuffmanNode { + parent: node_nb, + ..nonleafs.data[n1] + } + )} + ) + }; + + let (leafs, nonleafs) = if second_in_leafs { + ( + Tree { data: update(leafs.data, n2, + HuffmanNode { + parent: node_nb, + ..leafs.data[n2] + } + )}, + nonleafs + ) + } else { + ( + leafs, + Tree { data: update(nonleafs.data, n2, + HuffmanNode { + parent: node_nb, + ..nonleafs.data[n2] + } + )} + ) + }; + + (nonleafs, leafs, node_nb+u32:1, low_s, low_n) + } else { + (nonleafs, leafs, node_nb, low_s, low_n) + } + }((nonleafs, leafs, node_nb, low_s, low_n)); + (leafs, nonnull_rank + u32:1, nonleafs, node_root + u32:1) + } +} + +fn swap_tree_elem(t: HuffmanTree, i: u32, j: u32) -> HuffmanTree { + HuffmanTree { + data: update(update(t.data, i, t.data[j]), j, t.data[i]) + } +} + +fn bitonic_sort_descending_order + (tree: HuffmanTree) -> HuffmanTree { + + assert!(std::is_pow2(SIZE), "For bitonic sorting the array size must be a power of two"); + const LOG_SIZE = std::clog2(SIZE); + + let (sort_tree, _) = for (_, (tree, k)) in u32:0..LOG_SIZE { + let (sort_tree, _) = for (_, (tree, j)) in u32:0..LOG_SIZE { + if (j == u32:0) { + (tree, j) + } else { + let sort_tree = for (i, tree) in u32:0..SIZE { + let l = i ^ j; + if (l <= i) { + (tree) + } else { + if ((((i & k) == u32:0) && (tree.data[i].freq < tree.data[l].freq)) || + (((i & k) != u32:0) && (tree.data[i].freq > tree.data[l].freq))) { + swap_tree_elem(tree, i, l) + } else { + (tree) + } + } + } (tree); + (sort_tree, j / u32:2) + } + } ((tree, k / u32:2)); + (sort_tree, k * u32:2) + } ((tree, u32:2)); + sort_tree +} + + +// create a flattened tree with elements in a descending order +fn huffman_initial_tree(freq: FrequencyTable) -> HuffmanTree { + type Tree = HuffmanTree; + type Addr = uN[ADDR_W]; + const TABLE_LENGTH = MAX_SYMBOL + u32:1; + + // first copy everything as is to the tree + let tree = + for (i, t) in u32:0..TABLE_LENGTH { + Tree { + data: update(t.data, i, HuffmanNode { + symbol: i as u8, + freq: freq.data[i], + parent: Addr:0 + }) + } + }(zero!()); + + bitonic_sort_descending_order(tree) +} + +fn huffman_bits_to_weight(nbits: u4, max_nbits: u4) -> u4 { + if nbits == u4:0 { + u4:0 + } else { + max_nbits + u4:1 - nbits + } +} + +fn huffman_enforce_max_depth( + table: HuffmanPrefixTable, + max_nbits: u4, + nbits_bnd: u4 +) -> HuffmanPrefixTable { + type Table = HuffmanPrefixTable; + type Tree = HuffmanTree; + const TABLE_LENGTH = MAX_SYMBOL + u32:1; + type RankTable = u16[TABLE_LENGTH]; + + let base_cost = u32:1 << (max_nbits - nbits_bnd); + + // step 1: denormalize by enforcing the nbits < nbits_bnd condition + // https://github.com/facebook/zstd/blob/f9938c217da17ec3e9dcd2a2d99c5cf39536aeb9/lib/compress/huf_compress.c#L393-L397 + let (table_denorm, total_cost) = + for (i, (table, total_cost)) in u32:0..TABLE_LENGTH { + if table.data[i].nbits > nbits_bnd { + let this_cost = base_cost - (u32:1 << (max_nbits - table.data[i].nbits)); + ( + Table{data: update(table.data, i, HuffmanPrefixEntry{nbits: nbits_bnd, ..table.data[i]})}, + total_cost + this_cost + ) + } else { + (table, total_cost) + } + }((table, u32:0)); + + // step 2: renormalize + // simplified version compared to ZSTD, creates an unoptimal, but correct Huffman dictionary + // it assumes 2^(nbits_bnd) leafs with nbits=nbits_bnd and recreates the encoding under that assumption + let nb_per_rank = + for (i, nb_per_rank) in u32:0..TABLE_LENGTH { + let nbits = table_denorm.data[i].nbits; + if nbits == u4:0 { + nb_per_rank + } else { + update(nb_per_rank, nbits, nb_per_rank[nbits] + u16:1) + } + }(zero!()); + + let (val_per_rank, _) = + for (i, (val_per_rank, min)) in u32:0..MAX_SYMBOL { + let n = MAX_SYMBOL - i; + trace_fmt!("min {}: {}", i, min); + let rank_cnt = if n == nbits_bnd as u32 { + u16:1 << (n - u32:1) + } else { + nb_per_rank[n] + }; + + let next_min = (min + rank_cnt) >> 1; + (update(val_per_rank, n, min), next_min) + }((zero!(), u16:0)); + + let (table_norm, _) = + for (i, (table, val_per_rank)) in u32:0..TABLE_LENGTH { + let nbits = table.data[i].nbits; + let encoding = val_per_rank[nbits] as HuffmanPrefix; + + ( + Table{data: update(table.data, i, HuffmanPrefixEntry{nbits: nbits, encoding: encoding})}, + update(val_per_rank, nbits, val_per_rank[nbits] + u16:1) + ) + }((table_denorm, val_per_rank)); + + table_norm +} + +fn huffman_get_prefixes(freq: FrequencyTable) -> HuffmanPrefixTable { + type PrefixTable = HuffmanPrefixTable; + type FrequencyTable = FrequencyTable; + const HUFFMAN_MAX_LOG = u4:11; + + let tree = huffman_initial_tree(freq); + let (leafs, leafs_len, nonleafs, nonleafs_len) = huffman_build_tree(tree); + let prefix_table = huffman_tree_to_table(leafs, leafs_len, nonleafs, nonleafs_len); + let max_nbits = huffman_max_nbits(prefix_table); + + + if max_nbits > HUFFMAN_MAX_LOG { + // see: https://datatracker.ietf.org/doc/html/rfc8878#section-4.2.1 + huffman_enforce_max_depth(prefix_table, max_nbits, HUFFMAN_MAX_LOG) + } else { + prefix_table + } +} + +const TEST_ADDR_W = u32:32; +const TEST_MAX_SYMBOL = u32:5; + +type TestHuffmanTree = HuffmanTree; +type TestHuffmanNode = HuffmanNode; +type TestHuffmanPrefixTable = HuffmanPrefixTable; +type TestFrequencyTable = FrequencyTable; + +struct BuildTreeTestEntry { + initial_tree: TestHuffmanTree, + expected_leafs: TestHuffmanTree, + expected_leafs_len: u32, + expected_nonleafs: TestHuffmanTree, + expected_nonleafs_len: u32 +} + +#[test] +fn huffman_build_tree_test() { + type Addr = uN[TEST_ADDR_W]; + let test_cases = [ + BuildTreeTestEntry { // testcase 1. + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:3, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:0, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:2}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:2}, + TestHuffmanNode{symbol: u8:4, freq: Addr:3, parent: Addr:1}, + TestHuffmanNode{symbol: u8:3, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:0, parent: Addr:0}, + ]}, + expected_leafs_len: u32:5, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:3, parent: Addr:1}, + TestHuffmanNode{symbol: u8:0, freq: Addr:6, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:9, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:0}, + zero!(), + zero!() + ]}, + expected_nonleafs_len: u32:4 + }, + BuildTreeTestEntry { // testcase 2. + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:100, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:9, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:6, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:100, parent: Addr:4}, + TestHuffmanNode{symbol: u8:3, freq: Addr:9, parent: Addr:2}, + TestHuffmanNode{symbol: u8:5, freq: Addr:6, parent: Addr:2}, + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:1}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs_len: u32:6, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:1}, + TestHuffmanNode{symbol: u8:0, freq: Addr:10, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:25, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:125, parent: Addr:0}, + zero!(), + ]}, + expected_nonleafs_len: u32:5 + }, + BuildTreeTestEntry { // testcase 3. uniform distribution + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:2}, + TestHuffmanNode{symbol: u8:1, freq: Addr:1, parent: Addr:2}, + TestHuffmanNode{symbol: u8:2, freq: Addr:1, parent: Addr:1}, + TestHuffmanNode{symbol: u8:3, freq: Addr:1, parent: Addr:1}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs_len: u32:6, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:4, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:6, parent: Addr:0}, + zero!(), + ]}, + expected_nonleafs_len: u32:5 + }, + BuildTreeTestEntry { // testcase 4. 2^k + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:32, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:16, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:8, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:32, parent: Addr:4}, + TestHuffmanNode{symbol: u8:1, freq: Addr:16, parent: Addr:3}, + TestHuffmanNode{symbol: u8:2, freq: Addr:8, parent: Addr:2}, + TestHuffmanNode{symbol: u8:3, freq: Addr:4, parent: Addr:1}, + TestHuffmanNode{symbol: u8:4, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs_len: u32:6, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:3, parent: Addr:1}, + TestHuffmanNode{symbol: u8:0, freq: Addr:7, parent: Addr:2}, + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:31, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:63, parent: Addr:0}, + zero!(), + ]}, + expected_nonleafs_len: u32:5 + }, + BuildTreeTestEntry { // testcase 5. single symbol + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:0, parent: Addr:2}, + TestHuffmanNode{symbol: u8:1, freq: Addr:0, parent: Addr:2}, + TestHuffmanNode{symbol: u8:2, freq: Addr:0, parent: Addr:1}, + TestHuffmanNode{symbol: u8:3, freq: Addr:0, parent: Addr:1}, + TestHuffmanNode{symbol: u8:4, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + expected_leafs_len: u32:6, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:0, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:0, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + zero!(), + ]}, + expected_nonleafs_len: u32:5 + }, + BuildTreeTestEntry { // testcase 6. minimal tree + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:3, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:2, parent: Addr:0}, + zero!(), + zero!(), + zero!(), + zero!(), + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:3, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:2, parent: Addr:0}, + zero!(), + zero!(), + zero!(), + zero!() + ]}, + expected_leafs_len: u32:2, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:0}, + zero!(), + zero!(), + zero!(), + zero!(), + zero!(), + ]}, + expected_nonleafs_len: u32:1 + }, + BuildTreeTestEntry { // testcase 7. unbalanced tree + initial_tree: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:5, freq: Addr:45, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:16, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:13, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:12, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:9, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:0}, + ]}, + expected_leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:5, freq: Addr:45, parent: Addr:4}, + TestHuffmanNode{symbol: u8:4, freq: Addr:16, parent: Addr:2}, + TestHuffmanNode{symbol: u8:3, freq: Addr:13, parent: Addr:1}, + TestHuffmanNode{symbol: u8:2, freq: Addr:12, parent: Addr:1}, + TestHuffmanNode{symbol: u8:1, freq: Addr:9, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:0}, + ]}, + expected_leafs_len: u32:6, + expected_nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:14, parent: Addr:2}, + TestHuffmanNode{symbol: u8:0, freq: Addr:25, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:30, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:55, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:100, parent: Addr:0}, + zero!(), + ]}, + expected_nonleafs_len: u32:5 + } + ]; + + for ((i, entry), _) in enumerate(test_cases) { + let (leafs, leafs_len, nonleafs, nonleafs_len) = huffman_build_tree(entry.initial_tree); + assert_eq(leafs, entry.expected_leafs); + assert_eq(leafs_len, entry.expected_leafs_len); + assert_eq(nonleafs, entry.expected_nonleafs); + assert_eq(nonleafs_len, entry.expected_nonleafs_len); + trace_fmt!("[TEST] huffman_build_tree_test::{} passed", i); + }(()); +} + +struct TreeToTableTestEntry { + leafs: TestHuffmanTree, + leafs_len: u32, + nonleafs: TestHuffmanTree, + nonleafs_len: u32, + expected_table: TestHuffmanPrefixTable, + expected_max_nbits: u4 +} + +#[test] +fn huffman_tree_to_table_test(){ + type Addr = uN[TEST_ADDR_W]; + + let test_cases = [ + TreeToTableTestEntry { + leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:2}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:2}, + TestHuffmanNode{symbol: u8:4, freq: Addr:3, parent: Addr:1}, + TestHuffmanNode{symbol: u8:3, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:0, parent: Addr:0}, + ]}, + leafs_len: u32:5, + nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:3, parent: Addr:1}, + TestHuffmanNode{symbol: u8:0, freq: Addr:6, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:9, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:0}, + zero!(), + zero!() + ]}, + nonleafs_len: u32:4, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b000 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b01 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + zero!() + ] + }, + expected_max_nbits: u4:3 + }, + TreeToTableTestEntry { + leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:100, parent: Addr:4}, + TestHuffmanNode{symbol: u8:3, freq: Addr:9, parent: Addr:2}, + TestHuffmanNode{symbol: u8:5, freq: Addr:6, parent: Addr:2}, + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:1}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + ]}, + leafs_len: u32:6, + nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:1}, + TestHuffmanNode{symbol: u8:0, freq: Addr:10, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:25, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:125, parent: Addr:0}, + zero!(), + ]}, + nonleafs_len: u32:5, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:1, encoding: HuffmanPrefix:0b1 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0000 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b010 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b011 }, + ] + }, + expected_max_nbits: u4:4 + }, + TreeToTableTestEntry { + leafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:2}, + TestHuffmanNode{symbol: u8:1, freq: Addr:1, parent: Addr:2}, + TestHuffmanNode{symbol: u8:2, freq: Addr:1, parent: Addr:1}, + TestHuffmanNode{symbol: u8:3, freq: Addr:1, parent: Addr:1}, + TestHuffmanNode{symbol: u8:4, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:1, parent: Addr:0}, + ]}, + leafs_len: u32:6, + nonleafs: TestHuffmanTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:3}, + TestHuffmanNode{symbol: u8:0, freq: Addr:2, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:4, parent: Addr:4}, + TestHuffmanNode{symbol: u8:0, freq: Addr:6, parent: Addr:0}, + zero!(), + ]}, + nonleafs_len: u32:5, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b000 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b010 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b011 }, + ] + }, + expected_max_nbits: u4:3 + }, + ]; + for ((i, entry), _) in enumerate(test_cases) { + let prefix_table = huffman_tree_to_table(entry.leafs, entry.leafs_len, entry.nonleafs, entry.nonleafs_len); + let max_nbits = huffman_max_nbits(prefix_table); + assert_eq(entry.expected_table, prefix_table); + assert_eq(entry.expected_max_nbits, max_nbits); + trace_fmt!("[TEST] huffman_tree_to_table_test::{} passed", i); + }(()); +} + +struct MaxDepthTestEntry { + input_table: TestHuffmanPrefixTable, + nbits_bnd: u4, + expected_table: TestHuffmanPrefixTable +} + +#[test] +fn huffman_enforce_max_depth_test() { + type Addr = uN[TEST_ADDR_W]; + + let test_cases = [ + MaxDepthTestEntry { + input_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:12, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:11, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:10, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:11, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:13, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:1, encoding: HuffmanPrefix:0 }, + ] + }, + nbits_bnd: u4:5, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00000 }, + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00001 }, + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00010 }, + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00011 }, + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00100 }, + HuffmanPrefixEntry { nbits: u4:1, encoding: HuffmanPrefix:0b1 }, + ] + } + }, + MaxDepthTestEntry { + input_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:12, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:11, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:10, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:11, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:13, encoding: HuffmanPrefix:0 }, + HuffmanPrefixEntry { nbits: u4:1, encoding: HuffmanPrefix:0 }, + ] + }, + nbits_bnd: u4:4, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0000 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0001 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0010 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0011 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0100 }, + HuffmanPrefixEntry { nbits: u4:1, encoding: HuffmanPrefix:0b1 }, + ] + } + }, + MaxDepthTestEntry { + input_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0000 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b010 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b011 }, + ] + }, + nbits_bnd: u4:3, + expected_table: TestHuffmanPrefixTable{ + data: [ + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b000 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b010 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b011 }, + ] + } + } + ]; + + for ((i, entry), _) in enumerate(test_cases) { + let max_nbits = huffman_max_nbits(entry.input_table); + assert_eq(entry.expected_table, huffman_enforce_max_depth(entry.input_table, max_nbits, entry.nbits_bnd)); + trace_fmt!("[TEST] huffman_enforce_max_depth_test::{} passed", i); + }(()); +} + +// The biggest symbol has been increased to a power of two minus one +// due to the limitations of bitonic sorting. +const TEST_MAX_SYMBOL_INIT_TREE = u32:7; + +type TestHuffmanTreeInitTree = HuffmanTree; +type TestFrequencyTableInitTree = FrequencyTable; +type TestHuffmanPrefixTableInitTree = HuffmanPrefixTable; + +#[test] +fn huffman_initial_tree_test() { + type Addr = uN[TEST_ADDR_W]; + let test_cases = [ + ( + TestHuffmanTreeInitTree{data: [ + TestHuffmanNode{symbol: u8:7, freq: Addr:7, parent: Addr:0}, + TestHuffmanNode{symbol: u8:6, freq: Addr:6, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:5, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:3, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:2, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:1, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:0, parent: Addr:0}, + ]}, + TestFrequencyTableInitTree{data: [Addr:1, Addr:4, Addr:5, Addr:2, Addr:3, Addr:0, Addr:6, Addr:7]}, + ), + ( + TestHuffmanTreeInitTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:100, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:66, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:22, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:9, parent: Addr:0}, + TestHuffmanNode{symbol: u8:7, freq: Addr:6, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:5, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:4, parent: Addr:0}, + TestHuffmanNode{symbol: u8:6, freq: Addr:1, parent: Addr:0}, + ]}, + TestFrequencyTableInitTree{data: [Addr:100, Addr:66, Addr:22, Addr:4, Addr:5, Addr:9, Addr:1, Addr:6]}, + ), + ( + TestHuffmanTreeInitTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:6, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:7, freq: Addr:0, parent: Addr:0}, + ]}, + TestFrequencyTableInitTree{data: [Addr:0, Addr:0, Addr:0, Addr:0, Addr:0, Addr:0, Addr:0, Addr:0]}, + ), + ( + TestHuffmanTreeInitTree{data: [ + TestHuffmanNode{symbol: u8:0, freq: Addr:15, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:10, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:5, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:6, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:7, freq: Addr:0, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:0, parent: Addr:0}, + ]}, + TestFrequencyTableInitTree{data: [Addr:15, Addr:10, Addr:0, Addr:0, Addr:0, Addr:5, Addr:0, Addr:0]}, + ), + ( + TestHuffmanTreeInitTree{data: [ + TestHuffmanNode{symbol: u8:7, freq: Addr:45, parent: Addr:0}, + TestHuffmanNode{symbol: u8:6, freq: Addr:40, parent: Addr:0}, + TestHuffmanNode{symbol: u8:5, freq: Addr:35, parent: Addr:0}, + TestHuffmanNode{symbol: u8:4, freq: Addr:16, parent: Addr:0}, + TestHuffmanNode{symbol: u8:3, freq: Addr:13, parent: Addr:0}, + TestHuffmanNode{symbol: u8:2, freq: Addr:12, parent: Addr:0}, + TestHuffmanNode{symbol: u8:1, freq: Addr:9, parent: Addr:0}, + TestHuffmanNode{symbol: u8:0, freq: Addr:5, parent: Addr:0}, + ]}, + TestFrequencyTableInitTree{data: [Addr:5, Addr:9, Addr:12, Addr:13, Addr:16, Addr:35, Addr:40, Addr:45]} + ) + ]; + + for ((i, (expected_tree, frequencies)), _) in enumerate(test_cases) { + assert_eq(expected_tree, huffman_initial_tree(frequencies)); + trace_fmt!("[TEST] huffman_initial_tree_test::{} passed", i); + }(()); +} + +#[test] +fn huffman_bits_to_weight_test() { + // testcase directly from RFC https://datatracker.ietf.org/doc/html/rfc8878#section-4.2.1 + type Addr = uN[TEST_ADDR_W]; + const MAX_NBITS = u4:4; + + let test_cases = [ + (u4:1, u4:4), + (u4:2, u4:3), + (u4:3, u4:2), + (u4:0, u4:0), + (u4:4, u4:1), + ]; + + for ((i, (nbits, expected_weight)), _) in enumerate(test_cases) { + assert_eq(expected_weight, huffman_bits_to_weight(nbits, MAX_NBITS)); + trace_fmt!("[TEST] huffman_bits_to_weight_test::{} passed", i); + }(()); +} + + +#[test] +fn huffman_get_prefixes_test() { + type Addr = uN[TEST_ADDR_W]; + let test_cases = [ + ( + TestHuffmanPrefixTableInitTree{ + data: [ + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0000 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b010 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0001 }, + HuffmanPrefixEntry { nbits: u4:3, encoding: HuffmanPrefix:0b011 }, + zero!() + ] + }, + TestFrequencyTableInitTree{data: [Addr:1, Addr:4, Addr:5, Addr:6, Addr:7, Addr:2, Addr:3, Addr:0]} + ), + ( + TestHuffmanPrefixTableInitTree{ + data: [ + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00000 }, + HuffmanPrefixEntry { nbits: u4:5, encoding: HuffmanPrefix:0b00001 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0001 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0010 }, + HuffmanPrefixEntry { nbits: u4:4, encoding: HuffmanPrefix:0b0011 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b01 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b10 }, + HuffmanPrefixEntry { nbits: u4:2, encoding: HuffmanPrefix:0b11 }, + ] + }, + TestFrequencyTableInitTree{data: [Addr:5, Addr:9, Addr:12, Addr:13, Addr:16, Addr:35, Addr:40, Addr:45]} + ) + ]; + + for ((i, (expected_prefixes, frequencies)), _) in enumerate(test_cases) { + assert_eq(expected_prefixes, huffman_get_prefixes(frequencies)); + trace_fmt!("[TEST] huffman_get_prefixes_test::{} passed", i); + }(()); +} + +// Instances for codegen +const INST_ADDR_W = u32:32; + +// The biggest symbol has to be a power of two minus one +// due to the limitations of bitonic sorting. + +// TODO: The target value of INST_MAX_SYMBOL is 255, but it has been temporarily +// set to a lower value because it is still a work in progress. +const INST_MAX_SYMBOL = u32:15; + +fn huffman_initial_tree_inst(freq: FrequencyTable) -> HuffmanTree { + huffman_initial_tree(freq) +} + +fn huffman_get_prefixes_inst(freq: FrequencyTable) -> HuffmanPrefixTable { + huffman_get_prefixes(freq) +} + +fn huffman_build_tree_inst(leafs: HuffmanTree) -> (HuffmanTree, u32, HuffmanTree, u32) { + huffman_build_tree(leafs) +} + +fn huffman_tree_to_table_inst(leafs: HuffmanTree, leafs_len: u32, nonleafs: HuffmanTree, nonleafs_len: u32) -> HuffmanPrefixTable { + huffman_tree_to_table(leafs, leafs_len, nonleafs, nonleafs_len) +} + +fn huffman_max_nbits_inst(tab: HuffmanPrefixTable) -> u4 { + huffman_max_nbits(tab) +} diff --git a/xls/modules/zstd/huffman_axi_reader.x b/xls/modules/zstd/huffman_axi_reader.x index 99098992ee..c4c98fdbfb 100644 --- a/xls/modules/zstd/huffman_axi_reader.x +++ b/xls/modules/zstd/huffman_axi_reader.x @@ -66,7 +66,7 @@ pub proc HuffmanAxiReader("mem_rd_req"); let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); - spawn mem_reader::MemReader ( + spawn mem_reader::MemReader ( mem_rd_req_r, mem_rd_resp_s, axi_ar_s, diff --git a/xls/modules/zstd/huffman_code_builder.x b/xls/modules/zstd/huffman_code_builder.x index 06b057212f..3ce9f41b33 100644 --- a/xls/modules/zstd/huffman_code_builder.x +++ b/xls/modules/zstd/huffman_code_builder.x @@ -57,19 +57,8 @@ import xls.modules.zstd.huffman_common as hcommon; const MAX_WEIGHT = hcommon::MAX_WEIGHT; const WEIGHT_LOG = hcommon::WEIGHT_LOG; -const MAX_SYMBOL_COUNT = hcommon::MAX_SYMBOL_COUNT; - -const PARALLEL_ACCESS_WIDTH = hcommon::PARALLEL_ACCESS_WIDTH; const COUNTER_WIDTH = hcommon::COUNTER_WIDTH; -const RECV_COUNT = MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH; -// recv_counter is used to iterate: -// 0...MAX_RECV -// (MAX_RECV+1)...MAX_RECV*2 -// so the counter type must be wide enough to store (MAX_RECV*2) -const RECV_COUNT_W = std::clog2((RECV_COUNT * u32:2) + u32:1); -const MAX_RECV = RECV_COUNT as uN[RECV_COUNT_W]; - type WeightPreScanMetaData = hcommon::WeightPreScanMetaData; type WeightPreScanOutput = hcommon::WeightPreScanOutput; type CodeBuilderToPreDecoderOutput = hcommon::CodeBuilderToPreDecoderOutput; @@ -82,7 +71,7 @@ enum WeightCodeBuilderFSM: u2 { GENERATE_CODES_RUN = u2:3, } -struct WeightCodeBuilderState { +struct WeightCodeBuilderState { fsm: WeightCodeBuilderFSM, recv_counter: uN[RECV_COUNT_W], loopback_counter: uN[RECV_COUNT_W], @@ -93,13 +82,27 @@ struct WeightCodeBuilderState { huffman_base_codes: uN[MAX_WEIGHT][MAX_WEIGHT + u32:1] } -pub proc WeightCodeBuilder -// TODO: enable parametric expresion when they start working -//proc WeightCodeBuilder< -// PARALLEL_ACCESS_WIDTH: u32 = {u32:8}, -//> { -{ - type State = WeightCodeBuilderState; +fn highbit(val: u32) -> u32 { + if val == u32:0 { + // val is zero and thus has no highbit, + // permit it and return some garbage result because it doesn't change anything in the algorithm outcome + u32:0 + } else { + u32:31 - clz(val) + } +} + +pub proc WeightCodeBuilder< + MAX_SYMBOL_COUNT: u32 = {u32:256}, + PARALLEL_ACCESS_WIDTH: u32 = {u32:8}, + RECV_COUNT: u32 = {MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH}, + // recv_counter is used to iterate: + // 0...MAX_RECV + // (MAX_RECV+1)...MAX_RECV*2 + // so the counter type must be wide enough to store (MAX_RECV*2) + RECV_COUNT_W: u32 = {std::clog2((RECV_COUNT * u32:2) + u32:1)}, +> { + type State = WeightCodeBuilderState; type FSM = WeightCodeBuilderFSM; type PreScanData = WeightPreScanOutput; type DecoderOutput = CodeBuilderToDecoderOutput; @@ -127,6 +130,7 @@ pub proc WeightCodeBuilder init {zero!()} next(state: State) { + const MAX_RECV = RECV_COUNT as uN[RECV_COUNT_W]; let tok = join(); let (recv_start, recv_prescan) = match state.fsm { @@ -134,10 +138,6 @@ pub proc WeightCodeBuilder FSM::GATHER_WEIGHTS_RUN => (false, true), FSM::COMPUTE_MAX_LENGTH => (false, false), FSM::GENERATE_CODES_RUN => (false, true), - _ => { - assert!(false, "Invalid state"); - (false, false) - } }; let (_, start, start_valid) = recv_if_non_blocking(tok, start_r, recv_start, false); let (_, prescan_data, prescan_data_valid) = recv_if_non_blocking(tok, weight_r, recv_prescan, zero!()); @@ -158,10 +158,6 @@ pub proc WeightCodeBuilder let advance_state = state.recv_counter == (MAX_RECV * uN[RECV_COUNT_W]:2); (advance_state, advance_state, prescan_data_valid) }, - _ => { - assert!(false, "Invalid state"); - (false, false, false) - } }; let next_fsm_state = match(state.fsm, advance_state) { @@ -182,10 +178,6 @@ pub proc WeightCodeBuilder FSM::IDLE }, (_, false) => state.fsm, - _ => { - assert!(false, "Invalid state"); - FSM::IDLE - } }; let meta_data = prescan_data.meta_data; @@ -254,7 +246,7 @@ pub proc WeightCodeBuilder }; // compute max number of bits - let max_number_of_bits = encode(sum_of_weights_powers >> u32:1) as uN[WEIGHT_LOG]; + let max_number_of_bits = highbit(sum_of_weights_powers as u32 >> u32:1) as uN[WEIGHT_LOG]; let huffman_codes = match(state.fsm, advance_state) { (FSM::IDLE, _) => { @@ -325,10 +317,6 @@ pub proc WeightCodeBuilder ..state } }, - _ => { - assert!(false, "Invalid state"); - zero!() - } }; let lookahead_packet = PreDecoderOutput { @@ -374,129 +362,32 @@ pub proc WeightCodeBuilder } } -//#[test_proc] -//proc WeightCodeBuilderSimpleTest{ -// type PrescanOut = WeightPreScanOutput; -// type DecoderOutput = CodeBuilderToDecoderOutput; -// type PreDecoderOutput = CodeBuilderToPreDecoderOutput; -// -// terminator: chan out; -//// external_ram_req: chan out; -//// external_ram_resp: chan in; -//// start_prescan: chan out; -//// prescan_response: chan in; -// init{()} -//// config (terminator: chan out) { -//// // Emulate external memory -//// let (RAMExternalWriteReq_s, RAMExternalWriteReq_r) = chan("Write_channel_req"); -//// let (RAMExternalWriteResp_s, RAMExternalWriteResp_r) = chan("Write_channel_resp"); -//// let (RAMExternalReadReq_s, RAMExternalReadReq_r) = chan("Read_channel_req"); -//// let (RAMExternalReadResp_s, RAMExternalReadResp_r) = chan("Read_channel_resp"); -//// spawn ram::RamModel( -//// RAMExternalReadReq_r, RAMExternalReadResp_s, RAMExternalWriteReq_r, RAMExternalWriteResp_s -//// ); -//// -//// // Emulate Internal prescan memory -//// let (RAMInternalWriteReq_s, RAMInternalWriteReq_r) = chan("Internal_write_channel_req"); -//// let (RAMInternalWriteResp_s, RAMInternalWriteResp_r) = chan("Internal_write_channel_resp"); -//// let (RAMInternalReadReq_s, RAMInternalReadReq_r) = chan("Internal_read_channel_req"); -//// let (RAMInternalReadResp_s, RAMInternalReadResp_r) = chan("Internal_read_channel_resp"); -//// spawn ram::RamModel<{WeightPreScanMetaDataSize()}, RAM_SIZE, {WeightPreScanMetaDataSize()}>( -//// RAMInternalReadReq_r, RAMInternalReadResp_s, RAMInternalWriteReq_r, RAMInternalWriteResp_s -//// ); -//// -//// let (PreScanStart_s, PreScanStart_r) = chan("Start_prescan"); -//// let (PreScanResponse_s, PreScanResponse_r) = chan("Start_prescan"); -//// spawn WeightPreScan( -//// PreScanStart_r, RAMExternalReadReq_s,RAMExternalReadResp_r, PreScanResponse_s, -//// RAMInternalReadReq_s, RAMInternalReadResp_r, RAMInternalWriteReq_s, RAMInternalWriteResp_r); -//// (terminator, RAMExternalWriteReq_s, RAMExternalWriteResp_r, PreScanStart_s, PreScanResponse_r) -//// } -//// next(state: ()) { -//// let tok = join(); -//// let rand_state = random::rng_new(random::rng_deterministic_seed()); -//// // Setup external memory with random values -//// for (i, rand_state) in u32:0..MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH { -//// let (new_rand_state, data_to_send) = for (j, (rand_state, data_to_send)) in u32:0..PARALLEL_ACCESS_WIDTH { -//// let (new_rand_state, data) = random::rng_next(rand_state); -//// let weight = (data - (data/u32:12) * u32:12) as u4; -//// let new_data_to_send = update(data_to_send as uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], j, weight) as external_ram_data; -//// (new_rand_state, new_data_to_send) -//// }((rand_state, zero!())); -//// let external_w_req = WriteReq { -//// addr: i as u5, -//// data: data_to_send, -//// mask: u1:1 -//// }; -//// send(tok, external_ram_req, external_w_req); -//// recv(tok, external_ram_resp); -//// new_rand_state -//// }(rand_state); -//// send(tok, start_prescan, true); -//// // First run -//// for (_, rand_state) in u32:0..MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH { -//// // Generate expected output -//// let (new_rand_state, expected_data) = for (j, (rand_state, data_to_send)) in u32:0..PARALLEL_ACCESS_WIDTH { -//// let (new_rand_state, data) = random::rng_next(rand_state); -//// let weight = (data - (data/u32:12) * u32:12) as u4; -//// let new_data_to_send = update(data_to_send as uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], j, weight) as external_ram_data; -//// (new_rand_state, new_data_to_send) -//// }((rand_state, zero!())); -//// let (_, prescan_resp) = recv(tok, prescan_response); -//// let expected_data = PrescanOut { -//// weights: expected_data as uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], -//// meta_data: zero!() -//// }; -//// assert_eq(prescan_resp, expected_data); -//// new_rand_state -//// }(rand_state); -//// -//// // Second run -//// for (_, rand_state) in u32:0..MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH { -//// // Generate expected output -//// let (new_rand_state, expected_data) = for (j, (rand_state, data_to_send)) in u32:0..PARALLEL_ACCESS_WIDTH { -//// let (new_rand_state, data) = random::rng_next(rand_state); -//// let weight = (data - (data/u32:12) * u32:12) as u4; -//// let new_data_to_send = update(data_to_send as uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], j, weight) as external_ram_data; -//// (new_rand_state, new_data_to_send) -//// }((rand_state, zero!())); -//// let expected_data = expected_data as uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH]; -//// let valid_weights = for (i, seen_weights) in u32:0..PARALLEL_ACCESS_WIDTH { -//// update(seen_weights, expected_data[i], true) -//// }(zero!()); -//// let occurance_number = for (i, occurance_number) in u32:0..PARALLEL_ACCESS_WIDTH { -//// let number = for (j, number) in u32:0..PARALLEL_ACCESS_WIDTH{ -//// if (j < i && expected_data[j] == expected_data[i]) { -//// number + u4:1 -//// } else { -//// number -//// } -//// }(zero!()); -//// update(occurance_number, i, number) -//// }(zero!()); -//// let weights_count = for (i, weights_count) in u32:0..MAX_WEIGHT + u32:1 { -//// let count = for (j, count) in u32:0..PARALLEL_ACCESS_WIDTH { -//// if (expected_data[j] == i as uN[COUNTER_WIDTH]) { -//// count + uN[COUNTER_WIDTH]:1 -//// } else { -//// count -//// } -//// }(zero!()); -//// update(weights_count, i, count) -//// }(zero!()); -//// let (_, prescan_resp) = recv(tok, prescan_response); -//// let expected_data = PrescanOut { -//// weights: expected_data, -//// meta_data: WeightPreScanMetaData { -//// occurance_number: occurance_number, -//// valid_weights: valid_weights, -//// weights_count: weights_count, -//// } -//// }; -//// assert_eq(prescan_resp, expected_data); -//// new_rand_state -//// }(rand_state); -//// -//// send(tok, terminator, true); -//// } -//} +const INST_MAX_WEIGHT = hcommon::MAX_WEIGHT; + +pub proc WeightCodeBuilderInst { + type PreScanData = WeightPreScanOutput; + type DecoderOutput = CodeBuilderToDecoderOutput; + type PreDecoderOutput = CodeBuilderToPreDecoderOutput; + + config( + start_r: chan in, + weight_r: chan in, + codes_s: chan out, + lookahead_config_s: chan out, + weights_pow_sum_loopback_s: chan out, + weights_pow_sum_loopback_r: chan in, + ) { + spawn WeightCodeBuilder ( + start_r, + weight_r, + codes_s, + lookahead_config_s, + weights_pow_sum_loopback_s, + weights_pow_sum_loopback_r, + ); + } + + init { } + + next (state: ()) { } +} diff --git a/xls/modules/zstd/huffman_common.x b/xls/modules/zstd/huffman_common.x index 7661f42315..52115cf099 100644 --- a/xls/modules/zstd/huffman_common.x +++ b/xls/modules/zstd/huffman_common.x @@ -30,27 +30,10 @@ pub struct WeightPreScanMetaData { weights_count: uN[COUNTER_WIDTH][MAX_WEIGHT + u32:1], } -// TODO: Enable once parametrics work -//pub struct WeightPreScanMetaData < -// PARALLEL_ACCESS_WIDTH: u32, -// COUNTER_WIDTH: u32 = {std::clog2(PARALLEL_ACCESS_WIDTH + u32:1)} -//> { -// occurance_number: uN[COUNTER_WIDTH][PARALLEL_ACCESS_WIDTH], -// valid_weights: u1[MAX_WEIGHT + u32:1], -// weights_count: uN[COUNTER_WIDTH][MAX_WEIGHT + u32:1], -//} - pub struct WeightPreScanOutput { weights: uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], meta_data: WeightPreScanMetaData, } -// TODO: Use parametrics when they work -//pub struct WeightPreScanOutput< -// PARALLEL_ACCESS_WIDTH: u32, WEIGHT_LOG: u32 -//> { -// weights: uN[WEIGHT_LOG][PARALLEL_ACCESS_WIDTH], -// meta_data: WeightPreScanMetaData, -//} pub struct CodeBuilderToPreDecoderOutput { max_code_length: uN[WEIGHT_LOG], diff --git a/xls/modules/zstd/huffman_ctrl.x b/xls/modules/zstd/huffman_ctrl.x index 52758ec6b0..d259a7e210 100644 --- a/xls/modules/zstd/huffman_ctrl.x +++ b/xls/modules/zstd/huffman_ctrl.x @@ -357,9 +357,11 @@ pub proc HuffmanControlAndSequence { (tok, zero!(), ctrl.len) }; - let tok = send(tok, prescan_start_s, true); - let tok = send(tok, code_builder_start_s, true); - trace_fmt!("[HuffmanControlAndSequence] Sent START to prescan and code builder"); + if ctrl.new_config { + let tok = send(tok, prescan_start_s, true); + let tok = send(tok, code_builder_start_s, true); + trace_fmt!("[HuffmanControlAndSequence] Sent START to prescan and code builder"); + } else {}; let tok = send( tok, multi_stream_config_s, MultiStreamConfig { @@ -522,14 +524,6 @@ proc HuffmanControlAndSequence_test { }; let tok = send(tok, ctrl_s, ctrl); - let (tok, prescan_start) = recv(tok, prescan_start_r); - trace_fmt!("[TEST] Received prescan START"); - assert_eq(true, prescan_start); - - let (tok, code_builder_start) = recv(tok, code_builder_start_r); - trace_fmt!("[TEST] Received code builder START"); - assert_eq(true, code_builder_start); - let (tok, axi_reader_ctrl) = recv(tok, axi_reader_ctrl_r); trace_fmt!("[TEST] Received AXI reader CTRL"); assert_eq(AxiReaderCtrl {base_addr: ctrl.base_addr, len: ctrl.len}, axi_reader_ctrl); @@ -628,14 +622,6 @@ proc HuffmanControlAndSequence_test { uN[TEST_AXI_ADDR_W]:0x3, ]; - let (tok, prescan_start) = recv(tok, prescan_start_r); - trace_fmt!("[TEST] Received prescan START"); - assert_eq(true, prescan_start); - - let (tok, code_builder_start) = recv(tok, code_builder_start_r); - trace_fmt!("[TEST] Received code builder START"); - assert_eq(true, code_builder_start); - for (i, tok) in u32:0..u32:4 { trace_fmt!("[TEST] Stream #{}", i); diff --git a/xls/modules/zstd/huffman_decoder.x b/xls/modules/zstd/huffman_decoder.x index 5e33c26c7d..bddf9eaab3 100644 --- a/xls/modules/zstd/huffman_decoder.x +++ b/xls/modules/zstd/huffman_decoder.x @@ -223,7 +223,7 @@ pub proc HuffmanDecoder { trace_fmt!("[HuffmanDecoder] Received codes:"); for (i, ()) in u32:0..SYMBOLS_N { if symbol_valid[i] { - trace_fmt!("[HuffmanDecoder] {:#b} (len {}) -> {:#x}", symbol_code[i], symbol_code_len[i], i); + trace_fmt!("[HuffmanDecoder] {:#x} (len {}) -> {:#x}", symbol_code[i], symbol_code_len[i], i); } else {}; }(()); FSM::READ_DATA diff --git a/xls/modules/zstd/huffman_literals_dec.x b/xls/modules/zstd/huffman_literals_dec.x index 22f328688d..eb4f6b536f 100644 --- a/xls/modules/zstd/huffman_literals_dec.x +++ b/xls/modules/zstd/huffman_literals_dec.x @@ -200,27 +200,27 @@ pub proc HuffmanLiteralsDecoder< jump_table_mem_rd_resp_r, ); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( jump_table_mem_rd_req_r, jump_table_mem_rd_resp_s, jump_table_axi_ar_s, jump_table_axi_r_r ); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( weights_header_dec_mem_rd_req_r, weights_header_dec_mem_rd_resp_s, weights_header_dec_axi_ar_s, weights_header_dec_axi_r_r ); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( weights_raw_dec_mem_rd_req_r, weights_raw_dec_mem_rd_resp_s, weights_raw_dec_axi_ar_s, weights_raw_dec_axi_r_r ); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( weights_fse_lookup_dec_mem_rd_req_r, weights_fse_lookup_dec_mem_rd_resp_s, weights_fse_lookup_dec_axi_ar_s, weights_fse_lookup_dec_axi_r_r ); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( weights_fse_decoder_dec_mem_rd_req_r, weights_fse_decoder_dec_mem_rd_resp_s, weights_fse_decoder_dec_axi_ar_s, weights_fse_decoder_dec_axi_r_r ); @@ -245,7 +245,11 @@ pub proc HuffmanLiteralsDecoder< weights_fse_rd_req_s, weights_fse_rd_resp_r, weights_fse_wr_req_s, weights_fse_wr_resp_r, ); - spawn prescan::WeightPreScan( + spawn prescan::WeightPreScan< + hcommon::MAX_SYMBOL_COUNT, + hcommon::PARALLEL_ACCESS_WIDTH, + hcommon::MAX_WEIGHT, + >( prescan_start_r, weights_ram_rd_req_s, weights_ram_rd_resp_r, @@ -256,7 +260,10 @@ pub proc HuffmanLiteralsDecoder< prescan_ram_wr_resp_r, ); - spawn code_builder::WeightCodeBuilder( + spawn code_builder::WeightCodeBuilder< + hcommon::MAX_SYMBOL_COUNT, + hcommon::PARALLEL_ACCESS_WIDTH, + >( code_builder_start_r, prescan_response_r, code_builder_codes_s, @@ -588,12 +595,12 @@ const TEST_MEMORY: TestAxiRamWrReq[7] = [ // HTD Header: 0x84 (Direct representation, HTD length: 3) // Huffman Tree Description // code symbol length weight - // N/A 0x03 0 0 + // N/A 0x02 0 0 // 0b0000 0x04 4 1 // 0b0001 0x05 4 1 // last weight implicit - // 0b001 0x02 3 2 - // 0b01 0x01 2 3 - // 0b1 0x00 1 4 + // 0b001 0x03 3 2 + // 0b01 0x00 2 3 + // 0b1 0x01 1 4 // 0b00001 padding TestAxiRamWrReq { addr: TestAxiRamAddr:0x0, data: (u16:0b00001_1_01_0000_0001 ++ u24:0x100234 ++ u8:0x84) as TestAxiRamData, mask: TestAxiRamMask:0xFF }, @@ -615,12 +622,12 @@ const TEST_MEMORY: TestAxiRamWrReq[7] = [ // Jump Table: 0x0002_0002_0002 (Stream1: 2 bytes; Stream2: 2 bytes; Stream3: 2 bytes) // Huffman Tree Description // code symbol length weight - // N/A 0x03 0 0 + // N/A 0x02 0 0 // 0b0000 0x04 4 1 // 0b0001 0x05 4 1 // last weight implicit - // 0b001 0x02 3 2 - // 0b01 0x01 2 3 - // 0b1 0x00 1 4 + // 0b001 0x03 3 2 + // 0b01 0x00 2 3 + // 0b1 0x01 1 4 // 0b00001 padding TestAxiRamWrReq { addr: TestAxiRamAddr:0x40, data: (u32:0x0002_0002 ++ u24:0x100234 ++ u8:0x84) as TestAxiRamData, mask: TestAxiRamMask:0xFF }, // AXI addr: 0x200 ^ ^ ^ @@ -689,7 +696,7 @@ const TEST_CTRL: TestCtrl[4] = [ const TEST_DECODED_LITERALS = common::LiteralsDataWithSync[10]:[ // Literals #0 common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: true, id: u32:0, @@ -697,7 +704,7 @@ const TEST_DECODED_LITERALS = common::LiteralsDataWithSync[10]:[ }, // Literals #1 common::LiteralsDataWithSync { - data: common::LitData:0x0001_0405, + data: common::LitData:0x0100_0405, length: common::LitLength:4, last: true, id: u32:1, @@ -705,28 +712,28 @@ const TEST_DECODED_LITERALS = common::LiteralsDataWithSync[10]:[ }, // Literals #2 common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:2, literals_last: false, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:2, literals_last: false, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:2, literals_last: false, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: true, id: u32:2, @@ -734,28 +741,28 @@ const TEST_DECODED_LITERALS = common::LiteralsDataWithSync[10]:[ }, // Literals #3 common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:3, literals_last: true, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:3, literals_last: true, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: false, id: u32:3, literals_last: true, }, common::LiteralsDataWithSync { - data: common::LitData:0x0504_0100, + data: common::LitData:0x0504_0001, length: common::LitLength:4, last: true, id: u32:3, @@ -1116,116 +1123,3 @@ proc HuffmanLiteralsDecoder_test { send(tok, terminator, true); } } - -// TODO: implement tests with the following Huffman Tree -//const TEST_DATA_LEN_0 = u32:64; -//const TEST_DATA_0 = ( -// u8:0b001_1_010_0 ++ // 0x34 <- last byte in the memory -// u8:0b11_1_1_0001 ++ // 0xF1 -// u8:0b01_010_000 ++ // 0x50 -// u8:0b001_010_1_0 ++ // 0x2A -// u8:0b11_010_1_00 ++ // 0xD4 -// u8:0b0100_001_0 ++ // 0x42 -// u8:0b01_010_1_01 ++ // 0x55 -// u8:0b1_001_010_1 // 0x95 <- first byte in the memory -//); -// -//// code symbol length weight -//// 0b1 0x47 1 9 -//// 0b001 0x41 3 7 -//// 0b010 0x8A 3 7 -//// 0b011 0xD2 3 7 -//// 0b000001 0x45 6 4 -//// 0b000010 0x7A 6 4 -//// 0b000011 0x89 6 4 -//// 0b000100 0x8D 6 4 -//// 0b000101 0xD1 6 4 -//// 0b000110 0xD3 6 4 -//// 0b000111 0xDA 6 4 -//// 0b000000000 0x12 9 1 -//// 0b000000001 0x8F 9 1 -//// 0b000000010 0xAC 9 1 -//// 0b000000011 0xD4 9 1 -//// 0b000000100 0xD7 9 1 -//// 0b000000101 0xDB 9 1 -//// 0b000000110 0xDE 9 1 -//// 0b000000111 0xFE 9 1 -// -//const TEST_WEIGHT_MEMORY_0 = TestRamEntry[32]:[ -// // x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x0x -// TestRamEntry:0x_0__0__1__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x1x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x2x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x3x -// TestRamEntry:0x_0__7__0__0__0__4__0__9, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x4x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x5x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x6x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__4__0__0__0__0__0, // 0x7x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__4__7__0__0__4__0__1, // 0x8x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0x9x -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__1__0__0__0, // 0xAx -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0xBx -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0xCx -// TestRamEntry:0x_0__4__7__4__1__0__0__1, TestRamEntry:0x_0__0__4__1__0__0__1__0, // 0xDx -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__0__0, // 0xEx -// TestRamEntry:0x_0__0__0__0__0__0__0__0, TestRamEntry:0x_0__0__0__0__0__0__1__0, // 0xFx -//]; -// -//const TEST_DECODED_LITERALS_0 = common::LiteralsDataWithSync[3]:[ -// common::LiteralsDataWithSync { -// data: common::LitData:0x458A_D147_47D2_8A47, -// length: common::LitLength:8, -// last: false, -// id: u32:0, -// literals_last: false, -// }, -// common::LiteralsDataWithSync { -// data: common::LitData:0x4141_8D47_8AD2_478A, -// length: common::LitLength:8, -// last: false, -// id: u32:0, -// literals_last: false, -// }, -// common::LiteralsDataWithSync { -// data: common::LitData:0x478A_41D2_478A, -// length: common::LitLength:6, -// last: true, -// id: u32:0, -// literals_last: false, -// }, -//]; -// -//// data for test case #1 (same config) -//const TEST_CTRL_1 = TestCtrl { -// base_addr: uN[TEST_AXI_RAM_ADDR_W]:0x20, -// len: uN[TEST_AXI_RAM_ADDR_W]:0x4, -// new_config: false, -// multi_stream: false, -// id: u32:1, -// literals_last: true, -//}; -// -//const TEST_DATA_LEN_1 = u32:32; -//const TEST_DATA_1 = ( -// u8:0b001_011_1_1 ++ // 0x2F <- last byte in the memory -// u8:0b1_1_000000 ++ // 0xC0 -// u8:0b000_0_000 ++ // 0x00 -// u8:0b0010_1_010 // 0x2A <- first byte in the memory -//); -// -//const TEST_DECODED_LITERALS_1 = common::LiteralsDataWithSync[2]:[ -// common::LiteralsDataWithSync { -// data: common::LitData:0x47AC_1247_4747_47D2, -// length: common::LitLength:8, -// last: false, -// id: u32:1, -// literals_last: true, -// }, -// common::LiteralsDataWithSync { -// data: common::LitData:0x8A, -// length: common::LitLength:1, -// last: true, -// id: u32:1, -// literals_last: true, -// }, -//]; diff --git a/xls/modules/zstd/huffman_prescan.x b/xls/modules/zstd/huffman_prescan.x index b940cb90e5..f599fb92d1 100644 --- a/xls/modules/zstd/huffman_prescan.x +++ b/xls/modules/zstd/huffman_prescan.x @@ -45,44 +45,14 @@ import xls.examples.ram; import xls.modules.zstd.common as common; import xls.modules.zstd.huffman_common as hcommon; -// TODO: Enable once parametrics work -//fn WeightPreScanMetaDataSize(PARALLEL_ACCESS_WIDTH: u32) -> u32 { -// let COUNTER_WIDTH = {std::clog2(PARALLEL_ACCESS_WIDTH + u32:1)}; -// (COUNTER_WIDTH as u32) * (PARALLEL_ACCESS_WIDTH as u32) + -// (MAX_WEIGHT as u32) + u32:1 + -// (COUNTER_WIDTH as u32) * (MAX_WEIGHT as u32 + u32:1) -//} -// -//fn InternalStructToBits< -// PARALLEL_ACCESS_WIDTH: u32, -// BITS: u32 = {WeightPreScanMetaDataSize(PARALLEL_ACCESS_WIDTH)} -//> (internalStruct: WeightPreScanMetaData) -> bits[BITS] { -// internalStruct as bits[BITS] -//} -// -//fn BitsToInternalStruct< -// PARALLEL_ACCESS_WIDTH: u32, -// BITS: u32 = {WeightPreScanMetaDataSize(PARALLEL_ACCESS_WIDTH)} -//> (rawBits: bits[BITS]) -> WeightPreScanMetaData { -// rawBits as WeightPreScanMetaData -//} - -const MAX_WEIGHT = hcommon::MAX_WEIGHT; -const WEIGHT_LOG = hcommon::WEIGHT_LOG; -const MAX_SYMBOL_COUNT = hcommon::MAX_SYMBOL_COUNT; - -const PARALLEL_ACCESS_WIDTH = hcommon::PARALLEL_ACCESS_WIDTH; -const COUNTER_WIDTH = hcommon::COUNTER_WIDTH; - type WeightPreScanMetaData = hcommon::WeightPreScanMetaData; type WeightPreScanOutput = hcommon::WeightPreScanOutput; -pub const WEIGHT_PRESCAN_METADATA_SIZE = - (COUNTER_WIDTH as u32) * (PARALLEL_ACCESS_WIDTH as u32) + - (MAX_WEIGHT as u32) + u32:1 + - (COUNTER_WIDTH as u32) * (MAX_WEIGHT as u32 + u32:1); - fn InternalStructToBits< + PARALLEL_ACCESS_WIDTH: u32, + MAX_WEIGHT: u32, + COUNTER_WIDTH: u32, + WEIGHT_PRESCAN_METADATA_SIZE: u32, BITS: u32 = {WEIGHT_PRESCAN_METADATA_SIZE}, OCCURANCE_WIDTH: u32 ={COUNTER_WIDTH * PARALLEL_ACCESS_WIDTH}, > (internalStruct: WeightPreScanMetaData) -> bits[BITS] { @@ -92,6 +62,10 @@ fn InternalStructToBits< } fn BitsToInternalStruct< + PARALLEL_ACCESS_WIDTH: u32, + MAX_WEIGHT: u32, + COUNTER_WIDTH: u32, + WEIGHT_PRESCAN_METADATA_SIZE: u32, BITS: u32 = {WEIGHT_PRESCAN_METADATA_SIZE}, OCCURANCE_WIDTH: u32 ={COUNTER_WIDTH * PARALLEL_ACCESS_WIDTH}, > (rawBits: bits[BITS]) -> WeightPreScanMetaData { @@ -102,23 +76,6 @@ fn BitsToInternalStruct< } } -#[quickcheck(test_count=50000)] -fn bits_to_struct_to_bits_qtest(x: bits[WEIGHT_PRESCAN_METADATA_SIZE]) -> bool { - x == InternalStructToBits(BitsToInternalStruct(x)) -} - -#[quickcheck(test_count=50000)] -fn struct_to_bots_to_struct_qtest(x: WeightPreScanMetaData) -> bool { - x == BitsToInternalStruct(InternalStructToBits(x)) -} - -pub const RAM_SIZE = MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH * u32:8 / WEIGHT_LOG; -pub const RAM_ADDR_WIDTH = {std::clog2(RAM_SIZE)}; -pub const RAM_ACCESS_WIDTH = PARALLEL_ACCESS_WIDTH * WEIGHT_LOG; -const RAM_PARTITION_SIZE = RAM_ACCESS_WIDTH / u32:8; -const RAM_NUM_PARTITIONS = ram::num_partitions(RAM_PARTITION_SIZE, RAM_ACCESS_WIDTH); -const MAX_RAM_ADDR = MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH; - enum WeightPreScanFSM: u2 { IDLE = u2:0, FIRST_RUN = u2:1, @@ -131,16 +88,23 @@ struct WeightPreScanState { internal_addr: u9, } -pub proc WeightPreScan -// TODO: enable parametric expresion when they start working -//proc WeightPreScan< -// PARALLEL_ACCESS_WIDTH: u32 = {u32:8}, -// RAM_SIZE: u32 = {MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH}, -// RAM_ADDR_WIDTH: u32 = {std::clog2(RAM_SIZE)}, -// RAM_ACCESS_WIDTH: u32 = {PARALLEL_ACCESS_WIDTH * WEIGHT_LOG}, -// MAX_RAM_ADDR: u32 = {(u32:1< { -{ +pub proc WeightPreScan< + MAX_SYMBOL_COUNT: u32 = {u32:256}, + PARALLEL_ACCESS_WIDTH: u32 = {u32:8}, + MAX_WEIGHT: u32 = {u32:11}, + WEIGHT_LOG: u32 = {std::clog2(MAX_WEIGHT + u32:1)}, + COUNTER_WIDTH: u32 = {std::clog2(PARALLEL_ACCESS_WIDTH + u32:1)}, + RAM_SIZE: u32 = {MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH * u32:8 / WEIGHT_LOG}, + RAM_ADDR_WIDTH: u32 = {std::clog2(RAM_SIZE)}, + RAM_ACCESS_WIDTH: u32 = {PARALLEL_ACCESS_WIDTH * WEIGHT_LOG}, + RAM_PARTITION_SIZE: u32 = {RAM_ACCESS_WIDTH / u32:8}, + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_PARTITION_SIZE, RAM_ACCESS_WIDTH)}, + MAX_RAM_ADDR: u32 = {MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH}, + WEIGHT_PRESCAN_METADATA_SIZE: u32 = { + (COUNTER_WIDTH as u32) * (PARALLEL_ACCESS_WIDTH as u32) + + (MAX_WEIGHT as u32) + u32:1 + + (COUNTER_WIDTH as u32) * (MAX_WEIGHT as u32 + u32:1)}, +> { type State = WeightPreScanState; type FSM = WeightPreScanFSM; @@ -204,10 +168,6 @@ pub proc WeightPreScan let valid_data = state.addr < state.internal_addr || state.internal_addr as u32 == MAX_RAM_ADDR - u32:1; (false, valid_data, false, valid_data, state.addr as ExternalRamAddr) }, - _ => { - assert!(false, "Invalid state"); - (false, false, false, false, u9:0 as ExternalRamAddr) - } }; let (tok, start) = recv_if(tok, start_r, recv_start, false); if recv_start { @@ -284,7 +244,12 @@ pub proc WeightPreScan }; let tok = send_if(tok, internal_read_req_s, read_internal, internal_ram_r_req); let (tok, meta_data_flat) = recv_if(tok, internal_read_rsp_r, read_internal, zero!()); - let meta_data = BitsToInternalStruct(meta_data_flat.data); + let meta_data = BitsToInternalStruct< + PARALLEL_ACCESS_WIDTH, + MAX_WEIGHT, + COUNTER_WIDTH, + WEIGHT_PRESCAN_METADATA_SIZE, + >(meta_data_flat.data); if read_internal { trace_fmt!("[WeightPreScan] Reading internal memory data: {:#x}", meta_data); @@ -326,7 +291,12 @@ pub proc WeightPreScan let internal_ram_w_req = InternalWriteReq { addr: addr, - data: InternalStructToBits(_meta_data), + data: InternalStructToBits< + PARALLEL_ACCESS_WIDTH, + MAX_WEIGHT, + COUNTER_WIDTH, + WEIGHT_PRESCAN_METADATA_SIZE, + >(_meta_data), mask: u1:1 }; let tok = send_if(tok, internal_write_req_s, write_internal, internal_ram_w_req); @@ -340,6 +310,64 @@ pub proc WeightPreScan } } +const MAX_WEIGHT = hcommon::MAX_WEIGHT; +const WEIGHT_LOG = hcommon::WEIGHT_LOG; +const MAX_SYMBOL_COUNT = hcommon::MAX_SYMBOL_COUNT; +const PARALLEL_ACCESS_WIDTH = hcommon::PARALLEL_ACCESS_WIDTH; +const COUNTER_WIDTH = hcommon::COUNTER_WIDTH; +pub const WEIGHT_PRESCAN_METADATA_SIZE = + (COUNTER_WIDTH as u32) * (PARALLEL_ACCESS_WIDTH as u32) + + (MAX_WEIGHT as u32) + u32:1 + + (COUNTER_WIDTH as u32) * (MAX_WEIGHT as u32 + u32:1); +pub const RAM_SIZE = MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH * u32:8 / WEIGHT_LOG; +pub const RAM_ADDR_WIDTH = {std::clog2(RAM_SIZE)}; +pub const RAM_ACCESS_WIDTH = PARALLEL_ACCESS_WIDTH * WEIGHT_LOG; +const RAM_PARTITION_SIZE = RAM_ACCESS_WIDTH / u32:8; +const RAM_NUM_PARTITIONS = ram::num_partitions(RAM_PARTITION_SIZE, RAM_ACCESS_WIDTH); +const MAX_RAM_ADDR = MAX_SYMBOL_COUNT/PARALLEL_ACCESS_WIDTH; + +pub proc WeightPreScanInst { + type ReadReq = ram::ReadReq; + type ReadResp = ram::ReadResp; + + type OutData = WeightPreScanOutput; + + type InternalRamAddr = uN[RAM_ADDR_WIDTH]; + type InternalData = WeightPreScanMetaData; + type InternalRamData = bits[WEIGHT_PRESCAN_METADATA_SIZE]; + + type InternalReadReq = ram::ReadReq; + type InternalReadResp = ram::ReadResp; + type InternalWriteReq = ram::WriteReq; + type InternalWriteResp = ram::WriteResp; + + config( + start_r: chan in, + read_req_s: chan out, + read_rsp_r: chan in, + weight_s: chan out, + internal_read_req_s: chan out, + internal_read_rsp_r: chan in, + internal_write_req_s: chan out, + internal_write_rsp_r: chan in + ) { + spawn WeightPreScan ( + start_r, + read_req_s, + read_rsp_r, + weight_s, + internal_read_req_s, + internal_read_rsp_r, + internal_write_req_s, + internal_write_rsp_r, + ); + } + + init { } + + next (state: ()) { } +} + #[test_proc] proc Prescan_test{ type external_ram_addr = uN[RAM_ADDR_WIDTH]; diff --git a/xls/modules/zstd/huffman_weights_dec.x b/xls/modules/zstd/huffman_weights_dec.x index 86d1a5c7d0..45c82c8940 100644 --- a/xls/modules/zstd/huffman_weights_dec.x +++ b/xls/modules/zstd/huffman_weights_dec.x @@ -28,6 +28,7 @@ import xls.modules.zstd.math; const HUFFMAN_FSE_MAX_ACCURACY_LOG = u32:9; const HUFFMAN_FSE_ACCURACY_W = std::clog2(HUFFMAN_FSE_MAX_ACCURACY_LOG + u32:1); +const BITS_PER_RAW_WEIGHT = u32:4; struct HuffmanRawWeightsDecoderReq { addr: uN[AXI_ADDR_W], @@ -43,11 +44,12 @@ struct HuffmanRawWeightsDecoderResp { status: HuffmanRawWeightsDecoderStatus, } -enum HuffmanRawWeightsDecoderFSM : u2 { +enum HuffmanRawWeightsDecoderFSM : u3 { IDLE = 0, DECODING = 1, - FILL_ZERO = 2, - RESP = 3, + SENDING_LAST_WEIGHT = 2, + FILL_ZERO = 3, + RESP = 4, } struct HuffmanRawWeightsDecoderState< @@ -63,6 +65,7 @@ struct HuffmanRawWeightsDecoderState< buffer: uN[BUFF_LEN], buffer_len: uN[BUFF_LEN_LOG2], ram_wr_resp_to_handle: u4, + pending_last_weight: bool, sum: u32, // The sum of 2^(weight-1) from HTD } @@ -172,45 +175,56 @@ proc HuffmanRawWeightsDecoder< let last_weight = (next_power - state.sum) as u4; // It is required to change the ordering of the weights. - // Huffman literals decoder expects the weight of the first symbol + // - First symbol is stored in the most significant nibble of given input + // byte requiring us to swap each adjecent weights (rfc8878#section-4.2.1.1). + // - Huffman literals decoder expects the weight of the first symbol // as the most significant nibble at the most significant byte - // in the first cell of the WeightsMemory. - - // Inject the last weight, take into the acount the reverse - let weights = if (state.req.n_symbols > u8:0 && (mem_rd_resp_valid && mem_rd_resp.last)) { - trace_fmt!("[RAW] The sum of weight's powers of 2's: {}", state.sum); - trace_fmt!("[RAW] The last weight: {}", last_weight); - trace_fmt!("[RAW] Injected {:#x} into weights[{}]", last_weight, MAX_WEIGHTS_IN_PACKET as u8 - state.req.n_symbols); - update(weights, (MAX_WEIGHTS_IN_PACKET as u8 - (state.req.n_symbols % MAX_WEIGHTS_IN_PACKET as u8)), last_weight) - } else { - weights - }; + // in the first cell of the WeightsMemory requiring us to reverse them. - let reversed_weights = match(AXI_DATA_W) { + let weights = match(AXI_DATA_W) { u32:32 => ( - weights[7] ++ weights[6] ++ weights[5] ++ weights[4] ++ - weights[3] ++ weights[2] ++ weights[1] ++ weights[0] + weights[6] ++ weights[7] ++ weights[4] ++ weights[5] ++ + weights[2] ++ weights[3] ++ weights[0] ++ weights[1] ) as uN[AXI_DATA_W], u32:64 => ( - weights[15] ++ weights[14] ++ weights[13] ++ weights[12] ++ - weights[11] ++ weights[10] ++ weights[9] ++ weights[8] ++ - weights[7] ++ weights[6] ++ weights[5] ++ weights[4] ++ - weights[3] ++ weights[2] ++ weights[1] ++ weights[0] + weights[14] ++ weights[15] ++ weights[12] ++ weights[13] ++ + weights[10] ++ weights[11] ++ weights[8] ++ weights[9] ++ + weights[6] ++ weights[7] ++ weights[4] ++ weights[5] ++ + weights[2] ++ weights[3] ++ weights[0] ++ weights[1] ) as uN[AXI_DATA_W], _ => fail!("unsupported_axi_data_width", uN[AXI_DATA_W]:0), - }; + } as u4[MAX_WEIGHTS_IN_PACKET]; + + let received_last_data = mem_rd_resp_valid && mem_rd_resp.last; + let last_weight_index = state.req.n_symbols % MAX_WEIGHTS_IN_PACKET as u8; + let pending_last_weight = (state.req.n_symbols % (WEIGHTS_RAM_DATA_W / BITS_PER_RAW_WEIGHT) as u8) == u8:0 && received_last_data; + + let weights = if (state.req.n_symbols > u8:0 && received_last_data && last_weight_index > u8:0) || state.pending_last_weight { + trace_fmt!("[RAW] The sum of weight's powers of 2's: {}", state.sum); + trace_fmt!("[RAW] The last weight: {}", last_weight); + trace_fmt!("[RAW] MAX_WEIGHTS: {}", MAX_WEIGHTS_IN_PACKET); + trace_fmt!("[RAW] Injected {:#x} into weights[{}]", last_weight, last_weight_index); + update(weights, last_weight_index, last_weight) + } else { + weights + } as uN[AXI_DATA_W]; - if do_recv_data && mem_rd_resp_valid { + if do_recv_data && mem_rd_resp_valid || state.pending_last_weight { trace_fmt!("[RAW] Weights: {:#x}", weights); } else {}; - if do_recv_data && mem_rd_resp_valid { - trace_fmt!("[RAW] Weights: {:#x}", weights); - } else {}; + let state = if (pending_last_weight) { + State { + pending_last_weight, + ..state + } + } else { + state + }; - let (buffer, buffer_len) = if do_recv_data && mem_rd_resp_valid { + let (buffer, buffer_len) = if (do_recv_data && mem_rd_resp_valid) || state.fsm == FSM::SENDING_LAST_WEIGHT { ( - buffer | ((reversed_weights as uN[BUFF_LEN] << (BUFF_LEN - AXI_DATA_W - buffer_len as u32))), + buffer | ((weights as uN[BUFF_LEN] << (BUFF_LEN - AXI_DATA_W - buffer_len as u32))), buffer_len + (AXI_DATA_W as uN[BUFF_LEN_LOG2]), ) } else { @@ -220,7 +234,7 @@ proc HuffmanRawWeightsDecoder< ) }; // Send to RAM - let do_send_data = state.fsm == FSM::DECODING && buffer_len >= (WEIGHTS_RAM_DATA_W as uN[BUFF_LEN_LOG2]); + let do_send_data = (state.fsm == FSM::DECODING || state.fsm == FSM::SENDING_LAST_WEIGHT) && buffer_len >= (WEIGHTS_RAM_DATA_W as uN[BUFF_LEN_LOG2]); let weights_ram_wr_req = WeightsRamWrReq { addr: state.ram_addr, data: buffer[-(WEIGHTS_RAM_DATA_W as s32):] as uN[WEIGHTS_RAM_DATA_W], @@ -228,6 +242,7 @@ proc HuffmanRawWeightsDecoder< }; let tok = send_if(tok, weights_ram_wr_req_s, do_send_data, weights_ram_wr_req); if do_send_data { + trace_fmt!("[RAW] Buffer: {}", buffer); trace_fmt!("[RAW] Buffer length: {}", buffer_len); trace_fmt!("[RAW] Sent RAM write request {:#x}", weights_ram_wr_req); } else {}; @@ -300,12 +315,22 @@ proc HuffmanRawWeightsDecoder< } } else { State { - fsm: FSM::FILL_ZERO, + fsm: if state.pending_last_weight { FSM::SENDING_LAST_WEIGHT } else { FSM::FILL_ZERO }, ram_addr: state.ram_addr + (data_decoded / WEIGHTS_RAM_DATA_W as uN[AXI_ADDR_W]) as uN[WEIGHTS_RAM_ADDR_W], + buffer: buffer, + buffer_len: buffer_len, ..state } } }, + FSM::SENDING_LAST_WEIGHT => { + State { + fsm: FSM::FILL_ZERO, + ram_addr: state.ram_addr + uN[WEIGHTS_RAM_ADDR_W]:1, + pending_last_weight: false, + ..state + } + }, FSM::FILL_ZERO => { if state.ram_addr < !uN[WEIGHTS_RAM_ADDR_W]:0 { trace_fmt!("[RAW] Filling with zeros {} / {}", state.ram_addr + uN[WEIGHTS_RAM_ADDR_W]:1, !uN[WEIGHTS_RAM_ADDR_W]:0); @@ -367,7 +392,7 @@ enum HuffmanFseDecoderFSM : u4 { FILL_ZEROS = 13, SEND_FINISH = 14, } -struct HuffmanFseDecoderState { +struct HuffmanFseDecoderState { fsm: HuffmanFseDecoderFSM, ctrl: HuffmanFseDecoderCtrl, // decode request even: u8, @@ -379,7 +404,7 @@ struct HuffmanFseDecoderState { even_state: u16, // analogous to state1 in educational ZSTD decoder odd_state: u16, // analogous to state1 in educational ZSTD decoder // https://github.com/facebook/zstd/blob/fe34776c207f3f879f386ed4158a38d927ff6d10/doc/educational_decoder/zstd_decompress.c#L2069 - read_bits_needed: u7, // how many bits to request from the ShiftBuffer next + read_bits_needed: uN[REFILLING_SB_LENGTH_W], // how many bits to request from the ShiftBuffer next sent_buf_ctrl: bool, // have we sent request to ShiftBuffer in this FSM state already? shift_buffer_error: bool, // sticky flag, asserted if ShiftBuffer returns error in data // payload, cleared when going to initial state @@ -409,7 +434,8 @@ pub proc HuffmanFseDecoder< type Ctrl = HuffmanFseDecoderCtrl; type Finish = HuffmanFseDecoderFinish; type Status = HuffmanFseDecoderStatus; - type State = HuffmanFseDecoderState; + type State = HuffmanFseDecoderState; + type ShiftBufferLength = uN[REFILLING_SB_LENGTH_W]; type FSM = HuffmanFseDecoderFSM; type FseRamRdReq = ram::ReadReq; @@ -447,6 +473,7 @@ pub proc HuffmanFseDecoder< weights_wr_req_s: chan out, weights_wr_resp_r: chan in, ) { + const_assert!(AXI_DATA_W == REFILLING_SB_DATA_W); ( ctrl_r, finish_s, rsb_ctrl_s, rsb_data_r, @@ -513,12 +540,12 @@ pub proc HuffmanFseDecoder< let do_send_buf_ctrl = do_read_bits && !state.sent_buf_ctrl && state.stream_len > u16:0; let read_length = if state.read_bits_needed as u16 > state.stream_len { - state.stream_len as u7 + state.stream_len as ShiftBufferLength } else { - state.read_bits_needed + state.read_bits_needed as ShiftBufferLength }; - let state = if state.read_bits_needed > u7:0 { + let state = if state.read_bits_needed > ShiftBufferLength:0 { HuffmanFseDecoderState { stream_empty: state.read_bits_needed as u16 > state.stream_len, ..state @@ -530,7 +557,7 @@ pub proc HuffmanFseDecoder< } else {}; send_if(tok, rsb_ctrl_s, do_send_buf_ctrl, RefillingSBCtrl { - length: read_length, + length: read_length as ShiftBufferLength, }); let state = if do_send_buf_ctrl { @@ -590,7 +617,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::PADDING, ctrl: ctrl, - read_bits_needed: u7:1, + read_bits_needed: ShiftBufferLength:1, ..state } } else { state } @@ -604,7 +631,7 @@ pub proc HuffmanFseDecoder< if padding_available { State { fsm: FSM::PADDING, - read_bits_needed: u7:1, + read_bits_needed: ShiftBufferLength:1, padding, ..state } } else { @@ -612,7 +639,7 @@ pub proc HuffmanFseDecoder< trace_fmt!("[HuffmanFseDecoder] padding is: {:#x}", padding); State { fsm: FSM::INIT_EVEN_STATE, - read_bits_needed: state.ctrl.acc_log as u7, + read_bits_needed: state.ctrl.acc_log as ShiftBufferLength, ..state } } @@ -624,7 +651,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::INIT_ODD_STATE, even_state: buf_data.data as u16, - read_bits_needed: state.ctrl.acc_log as u7, + read_bits_needed: state.ctrl.acc_log as ShiftBufferLength, ..state } } else { state } @@ -635,7 +662,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::SEND_RAM_EVEN_RD_REQ, odd_state: buf_data.data as u16, - read_bits_needed: u7:0, + read_bits_needed: ShiftBufferLength:0, ..state } } else { state } @@ -717,7 +744,7 @@ pub proc HuffmanFseDecoder< fsm: FSM::UPDATE_EVEN_STATE, odd: state.odd_table_record.symbol, weights_pow_of_two_sum: state.weights_pow_of_two_sum + pow, - read_bits_needed: state.even_table_record.num_of_bits as u7, + read_bits_needed: state.even_table_record.num_of_bits as ShiftBufferLength, ..state } } @@ -729,7 +756,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::SEND_WEIGHT, even_state: state.even_table_record.base + buf_data.data as u16, - read_bits_needed: state.odd_table_record.num_of_bits as u7, + read_bits_needed: state.odd_table_record.num_of_bits as ShiftBufferLength, last_weight_is_odd: false, ..state } @@ -738,7 +765,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::UPDATE_ODD_STATE, even_state: state.even_table_record.base + buf_data.data as u16, - read_bits_needed: state.odd_table_record.num_of_bits as u7, + read_bits_needed: state.odd_table_record.num_of_bits as ShiftBufferLength, ..state } } else { state } @@ -749,7 +776,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::SEND_WEIGHT, odd_state: state.odd_table_record.base + buf_data.data as u16, - read_bits_needed: u7:0, + read_bits_needed: ShiftBufferLength:0, last_weight_is_odd: true, ..state } @@ -758,7 +785,7 @@ pub proc HuffmanFseDecoder< State { fsm: FSM::SEND_WEIGHT, odd_state: state.odd_table_record.base + buf_data.data as u16, - read_bits_needed: u7:0, + read_bits_needed: ShiftBufferLength:0, ..state } } else { state } @@ -804,7 +831,7 @@ pub proc HuffmanFseDecoder< if state.last_weight_is_odd { FSM::SEND_RAM_EVEN_RD_REQ } else { - FSM::SEND_RAM_ODD_RD_REQ + FSM::DECODE_LAST_WEIGHT } } } else { @@ -1067,7 +1094,7 @@ proc HuffmanFseWeightsDecoder< let tok = send(tok, fld_rsb_start_req_s, fld_rsb_start_req); trace_fmt!("[FSE] Sent refilling shift buffer start request {:#x}", fld_rsb_start_req); - let fld_req = CompLookupDecoderReq {}; + let fld_req = zero!(); let tok = send(tok, fld_req_s, fld_req); trace_fmt!("[FSE] Sent FSE lookup decoding request {:#x}", fld_req); @@ -1405,9 +1432,11 @@ pub proc HuffmanWeightsDecoder< let resp = match weights_type { WeightsType::RAW => { + // based on https://datatracker.ietf.org/doc/html/rfc8878#section-4.2.1.1 + let weights_size = (raw_weights_req.n_symbols + u8:1) >> u8:1; // equivalent of ceil(n_symbols/2) Resp { status: raw_status, - tree_description_size: (((header_byte - u8:127) >> u8:1) + u8:1) as uN[AXI_ADDR_W] + uN[AXI_ADDR_W]:1, // include header size + tree_description_size: weights_size as uN[AXI_ADDR_W] + uN[AXI_ADDR_W]:1, // include header size } }, WeightsType::FSE => { @@ -1598,7 +1627,7 @@ const TEST_AXI_ID_W = u32:8; const TEST_RAM_DATA_W = TEST_AXI_DATA_W; const TEST_RAM_SIZE = u32:1024; const TEST_RAM_ADDR_W = TEST_AXI_ADDR_W; -const TEST_RAM_PARTITION_SIZE = TEST_RAM_DATA_W / u32:8; +const TEST_RAM_PARTITION_SIZE = u32:8; const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W); const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; const TEST_RAM_INITIALIZED = true; @@ -1641,20 +1670,8 @@ const TEST_TMP2_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_TMP2_RAM_WORD_PART // RAW weights const TEST_RAW_INPUT_ADDR = uN[TEST_AXI_ADDR_W]:0x40; -// Weights sum is 1010, so the last one will be 14 -const TEST_RAW_DATA = u8[65]:[ - // len x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF - u8:248, u8:0xB__6, u8:0x8__5, u8:0x6__A, u8:0x9__C, u8:0x0__C, u8:0xA__9, u8:0x0__0, u8:0xD__0, // 0x0x - u8:0x6__E, u8:0x3__9, u8:0x8__4, u8:0x7__C, u8:0xC__2, u8:0x4__2, u8:0xB__A, u8:0x4__E, // 0x1x - u8:0xF__6, u8:0x2__7, u8:0x9__4, u8:0xD__1, u8:0xD__8, u8:0x2__B, u8:0xE__2, u8:0xD__1, // 0x2x - u8:0x8__F, u8:0x2__4, u8:0xD__3, u8:0x0__E, u8:0xF__E, u8:0x1__B, u8:0xF__9, u8:0x8__2, // 0x3x - u8:0xC__A, u8:0x6__1, u8:0x0__3, u8:0xD__C, u8:0xF__5, u8:0x1__D, u8:0x7__0, u8:0x1__6, // 0x4x - u8:0xA__A, u8:0x3__2, u8:0x8__8, u8:0x0__6, u8:0xE__7, u8:0x6__7, u8:0x8__E, u8:0x6__2, // 0x5x - u8:0x1__F, u8:0x3__E, u8:0xF__0, u8:0xC__7, u8:0x4__1, u8:0x7__E, u8:0x8__C, u8:0x8__4, // 0x6x - u8:0x3__3, u8:0xA__8, u8:0xE__E, u8:0x4__B, u8:0x0__0, u8:0x0__0, u8:0x0__0, u8:0x0__0, // 0x7x -]; - -const TEST_RAW_DATA_LAST_WEIGHT = u8:0xA; +const_assert!(TEST_WEIGHTS_RAM_DATA_W == u32:32); +const TEST_RAW_RAM_PACKET_COUNT = TEST_WEIGHTS_RAM_SIZE / TEST_WEIGHTS_RAM_PARTITION_SIZE; // FSE weights const TEST_FSE_INPUT_ADDR = uN[TEST_AXI_ADDR_W]:0x200; @@ -2126,84 +2143,140 @@ proc HuffmanWeightsDecoder_test { let tok = join(); - // RAW weights + // RAW tests + const TEST_MAX_WEIGHTS_STREAM = u32:21; + const TEST_NUM_OF_RAW_CASES = u32:3; + let raw_tests: (u32, u8[TEST_MAX_WEIGHTS_STREAM], uN[TEST_WEIGHTS_RAM_DATA_W][TEST_RAW_RAM_PACKET_COUNT])[TEST_NUM_OF_RAW_CASES] = [ + ( + // normal case + u32:15, // (header + weight stream) + u8[TEST_MAX_WEIGHTS_STREAM]:[ + u8:155, // header + // weights stream + u8:0x75, u8:0x66, u8:0x66, u8:0x66, + u8:0x66, u8:0x66, u8:0x55, u8:0x55, + u8:0x44, u8:0x44, u8:0x33, u8:0x31, + u8:0x11, u8:0x00, + // dummy leftover + u8:0x00, u8:0x00, + u8:0xDE, u8:0xAD, u8:0xBE, u8:0xEF, ... + ], + uN[TEST_WEIGHTS_RAM_DATA_W][TEST_RAW_RAM_PACKET_COUNT]:[ + uN[TEST_WEIGHTS_RAM_DATA_W]:0x75666666, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x66665555, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x44443331, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x11001000, + // ^- last weight + uN[TEST_WEIGHTS_RAM_DATA_W]:0x0, ... + ] + ), + ( + // case with last weight at modulo index 0 + u32:17, // (header + weight stream) + u8[TEST_MAX_WEIGHTS_STREAM]:[ + u8:159, // header + // weights stream + u8:0x75, u8:0x55, u8:0x66, u8:0x66, + u8:0x66, u8:0x66, u8:0x65, u8:0x55, + u8:0x55, u8:0x43, u8:0x33, u8:0x21, + u8:0x21, u8:0x11, u8:0x11, u8:0x01, + // dummy leftover + u8:0xDE, u8:0xAD, u8:0xBE, u8:0xEF, ... + ], + uN[TEST_WEIGHTS_RAM_DATA_W][TEST_RAW_RAM_PACKET_COUNT]:[ + uN[TEST_WEIGHTS_RAM_DATA_W]:0x75556666, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x66666555, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x55433321, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x21111101, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x10000000, + // ^- last weight + uN[TEST_WEIGHTS_RAM_DATA_W]:0x0, ... + ] + ), + ( + // case with last weight at modulo index 8 (middle position of the received weights packet) + u32:13, // (header + weight stream) + u8[TEST_MAX_WEIGHTS_STREAM]:[ + u8:0x97, // header + // weights stream + u8:0x86, u8:0x66, u8:0x66, u8:0x66, + u8:0x66, u8:0x55, u8:0x55, u8:0x43, + u8:0x43, u8:0x11, u8:0x21, u8:0x11, + // dummy leftover + u8:0xDE, u8:0xAD, u8:0xBE, u8:0xEF, ... + ], + uN[TEST_WEIGHTS_RAM_DATA_W][TEST_RAW_RAM_PACKET_COUNT]:[ + uN[TEST_WEIGHTS_RAM_DATA_W]:0x86666666, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x66555543, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x43112111, + uN[TEST_WEIGHTS_RAM_DATA_W]:0x10000000, + // ^- last weight + uN[TEST_WEIGHTS_RAM_DATA_W]:0x0, ... + ] + ) + ]; - // Fill input RAM - for (i, tok) in u32:0..(array_size(TEST_RAW_DATA) + TEST_DATA_PER_RAM_WRITE - u32:1) / TEST_DATA_PER_RAM_WRITE { - let ram_data = for (j, ram_data) in u32:0..TEST_DATA_PER_RAM_WRITE { - let data_idx = i * TEST_DATA_PER_RAM_WRITE + j; - if (data_idx < array_size(TEST_RAW_DATA)) { - ram_data | ((TEST_RAW_DATA[data_idx] as uN[TEST_RAM_DATA_W]) << (u32:8 * j)) - } else { - ram_data - } - }(uN[TEST_RAM_DATA_W]:0); + let tok = for ((_, (data_length, weights_stream, expected)), tok): ((u32, (u32, u8[TEST_MAX_WEIGHTS_STREAM], uN[TEST_WEIGHTS_RAM_DATA_W][TEST_RAW_RAM_PACKET_COUNT])), token) in enumerate(raw_tests) { + // Fill input RAM + for (i, tok) in u32:0..(array_size(weights_stream) + TEST_DATA_PER_RAM_WRITE - u32:1) / TEST_DATA_PER_RAM_WRITE { + let ram_data = for (j, ram_data) in u32:0..TEST_DATA_PER_RAM_WRITE { + let data_idx = i * TEST_DATA_PER_RAM_WRITE + j; + if (data_idx < array_size(weights_stream)) { + ram_data | ((weights_stream[data_idx] as uN[TEST_RAM_DATA_W]) << (u32:8 * j)) + } else { + ram_data + } + }(uN[TEST_RAM_DATA_W]:0); - let input_ram_wr_req = InputBufferRamWrReq { - addr: (TEST_RAW_INPUT_ADDR / u32:8) + i as uN[TEST_RAM_ADDR_W], - data: ram_data, - mask: !uN[TEST_RAM_NUM_PARTITIONS]:0, - }; + let input_ram_wr_req = InputBufferRamWrReq { + addr: (TEST_RAW_INPUT_ADDR / u32:8) + i as uN[TEST_RAM_ADDR_W], + data: ram_data, + mask: !uN[TEST_RAM_NUM_PARTITIONS]:0, + }; + + let tok = unroll_for! (i, tok) in u32:0..TEST_RAM_N { + let tok = send(tok, input_ram_wr_req_s[i], input_ram_wr_req); + let (tok, _) = recv(tok, input_ram_wr_resp_r[i]); + tok + }(tok); + + trace_fmt!("[TEST] Sent RAM write request to input RAMs {:#x}", input_ram_wr_req); - let tok = unroll_for! (i, tok) in u32:0..TEST_RAM_N { - let tok = send(tok, input_ram_wr_req_s[i], input_ram_wr_req); - let (tok, _) = recv(tok, input_ram_wr_resp_r[i]); tok }(tok); - trace_fmt!("[TEST] Sent RAM write request to input RAMs {:#x}", input_ram_wr_req); + // Send decoding request + let req = Req { + addr: TEST_RAW_INPUT_ADDR, + }; + let tok = send(tok, req_s, req); + trace_fmt!("[TEST] Sent request {:#x}", req); - tok - }(tok); + // Receive response + let (tok, resp) = recv(tok, resp_r); + trace_fmt!("[TEST] Received respose {:#x}", resp); + assert_eq(HuffmanWeightsDecoderStatus::OKAY, resp.status); + assert_eq(data_length as uN[TEST_AXI_ADDR_W], resp.tree_description_size); - // Send decoding request - let req = Req { - addr: TEST_RAW_INPUT_ADDR, - }; - let tok = send(tok, req_s, req); - trace_fmt!("[TEST] Sent request {:#x}", req); - - // Receive response - let (tok, resp) = recv(tok, resp_r); - trace_fmt!("[TEST] Received respose {:#x}", resp); - assert_eq(HuffmanWeightsDecoderStatus::OKAY, resp.status); - assert_eq((((TEST_RAW_DATA[0] - u8:127) >> u32:1) + u8:2) as uN[TEST_AXI_ADDR_W], resp.tree_description_size); - - // Insert last weight in test data - let last_weight_idx = ((TEST_RAW_DATA[0] as u32 - u32:127) / u32:2) + u32:1; - let last_weight_entry = ( - TEST_RAW_DATA[last_weight_idx] | - (TEST_RAW_DATA_LAST_WEIGHT << (u32:4 * (u32:1 - ((TEST_RAW_DATA[0] - u8:127) as u1 as u32)))) - ); - let test_data = update(TEST_RAW_DATA, last_weight_idx, last_weight_entry); - - // Check output RAM - let tok = for (i, tok) in u32:0..u32:32 { - let expected_value = if i < u32:16 { - ( - (test_data[4*i + u32:1] as u4) ++ ((test_data[4*i + u32:1] >> u32:4) as u4) ++ - (test_data[4*i + u32:2] as u4) ++ ((test_data[4*i + u32:2] >> u32:4) as u4) ++ - (test_data[4*i + u32:3] as u4) ++ ((test_data[4*i + u32:3] >> u32:4) as u4) ++ - (test_data[4*i + u32:4] as u4) ++ ((test_data[4*i + u32:4] >> u32:4) as u4) - ) - } else { - u32:0 - }; + // Check output RAM + let tok = for (i, tok) in u32:0..array_size(expected) { + let expected_value = expected[i]; + let weights_ram_rd_req = WeightsRamRdReq { + addr: i as uN[TEST_WEIGHTS_RAM_ADDR_W], + mask: !uN[TEST_WEIGHTS_RAM_NUM_PARTITIONS]:0, + }; + let tok = send(tok, weights_ram_rd_req_s, weights_ram_rd_req); + let (tok, weights_ram_rd_resp) = recv(tok, weights_ram_rd_resp_r); + trace_fmt!("[TEST] Weights RAM content - addr: {:#x} data: expected {:#x}, got {:#x}", i, expected_value, weights_ram_rd_resp.data); - let weights_ram_rd_req = WeightsRamRdReq { - addr: i as uN[TEST_WEIGHTS_RAM_ADDR_W], - mask: !uN[TEST_WEIGHTS_RAM_NUM_PARTITIONS]:0, - }; - let tok = send(tok, weights_ram_rd_req_s, weights_ram_rd_req); - let (tok, weights_ram_rd_resp) = recv(tok, weights_ram_rd_resp_r); - trace_fmt!("[TEST] Weights RAM content - addr: {:#x} data: expected {:#x}, got {:#x}", i, expected_value, weights_ram_rd_resp.data); + assert_eq(expected_value, weights_ram_rd_resp.data); - assert_eq(expected_value, weights_ram_rd_resp.data); + tok + }(tok); tok }(tok); - // FSE-encoded weights unroll_for! (i, tok) in u32:0..array_size(TESTCASES_FSE) { let (TEST_FSE_DATA, TEST_FSE_WEIGHTS) = TESTCASES_FSE[i]; diff --git a/xls/modules/zstd/img/huffman-weights-decoder.png b/xls/modules/zstd/img/huffman-weights-decoder.png new file mode 100644 index 0000000000..387e94a9ff Binary files /dev/null and b/xls/modules/zstd/img/huffman-weights-decoder.png differ diff --git a/xls/modules/zstd/img/literals-decoder.png b/xls/modules/zstd/img/literals-decoder.png new file mode 100644 index 0000000000..225e56017b Binary files /dev/null and b/xls/modules/zstd/img/literals-decoder.png differ diff --git a/xls/modules/zstd/img/sequence-decoder.png b/xls/modules/zstd/img/sequence-decoder.png new file mode 100644 index 0000000000..5a79c40f7e Binary files /dev/null and b/xls/modules/zstd/img/sequence-decoder.png differ diff --git a/xls/modules/zstd/img/zstd-compress-block-decoder.png b/xls/modules/zstd/img/zstd-compress-block-decoder.png new file mode 100644 index 0000000000..24c276295a Binary files /dev/null and b/xls/modules/zstd/img/zstd-compress-block-decoder.png differ diff --git a/xls/modules/zstd/img/zstd-decoder-wrapper.png b/xls/modules/zstd/img/zstd-decoder-wrapper.png new file mode 100644 index 0000000000..6ad15e22cd Binary files /dev/null and b/xls/modules/zstd/img/zstd-decoder-wrapper.png differ diff --git a/xls/modules/zstd/img/zstd-decoder.png b/xls/modules/zstd/img/zstd-decoder.png new file mode 100644 index 0000000000..4d48ea0242 Binary files /dev/null and b/xls/modules/zstd/img/zstd-decoder.png differ diff --git a/xls/modules/zstd/literal_encoder.x b/xls/modules/zstd/literal_encoder.x new file mode 100644 index 0000000000..bbf20a933d --- /dev/null +++ b/xls/modules/zstd/literal_encoder.x @@ -0,0 +1,812 @@ +// Copyright 2024 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 contains implementation of LiteralsEncoder + +import std; + +import xls.examples.ram; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.axi_ram_reader; +import xls.modules.zstd.memory.axi_ram_writer; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.mem_copy; +import xls.modules.zstd.rle_block_encoder; + +type RawMemcopyBlockType = mem_copy::RawMemcopyBlockType; + +// This parameter controls the sampling in RleBlockEncoder. +// It's the number of samples read from memory for a quick check +// before full scan is done to verify if all bytes are of the same value. +// TODO verify if it should be moved to ZstdEncoder +const RLE_HEURISTIC_SAMPLE_COUNT = u32:8; + +enum LiteralSectionHeaderWriterStatus: u1 { + OK = 0, + ERROR = 1 +} + +struct LiteralSectionHeaderWriterReq { + addr: uN[ADDR_W], + btype: RawMemcopyBlockType, + regenerated_size: u20, + compressed_size: u18, +} + +struct LiteralSectionHeaderWriterResp { + status: LiteralSectionHeaderWriterStatus, + length: uN[ADDR_W], +} + +proc LiteralSectionHeaderWriter { + type Req = LiteralSectionHeaderWriterReq; + type Resp = LiteralSectionHeaderWriterResp; + type Status = LiteralSectionHeaderWriterStatus; + + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + type Data = uN[DATA_W]; + type Length = uN[ADDR_W]; + + req_r: chan in; + resp_s: chan out; + + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + init {} + + config( + req_r: chan in, + resp_s: chan out, + + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + ( + req_r, resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ) + } + + next(state: ()) { + let (req_tok, req) = recv(join(), req_r); + + // TODO: Implement for Compressed_Literals_Block and Treeless_Literals_Block as well. + assert!(req.btype == RawMemcopyBlockType::RAW || req.btype == RawMemcopyBlockType::RLE, "unsupported_literal_type"); + let btype = match (req.btype) { + RawMemcopyBlockType::RAW => u2:0, + RawMemcopyBlockType::RLE => u2:1, + _ => u2:0, + }; + + + let (data, length) = if req.regenerated_size <= u20:0x1F { // regenerated_size <= 31 + let size_format = u1:0; + let regenerated_size = checked_cast(req.regenerated_size); + let data = (regenerated_size ++ size_format ++ btype) as Data; + + (data, Length:1) + + } else if req.regenerated_size <= u20:0xFFF { // regenerated size <= 4095 + let size_format = u2:0b01; + let regenerated_size = checked_cast(req.regenerated_size); + let data = (regenerated_size ++ size_format ++ btype) as Data; + + (data, Length:2) + + } else { + // regenerated size <= 1048575 + // No need to check the value as the whole range of u20 is covered. + let size_format = u2:0b11; + let regenerated_size = checked_cast(req.regenerated_size); + let data = (regenerated_size ++ size_format ++ btype) as Data; + + (data, Length:3) + }; + + let mem_wr_req = MemWriterReq { addr: req.addr, length }; + let mem_wr_tok = send(req_tok, mem_wr_req_s, mem_wr_req); + + let mem_wr_data = MemWriterData { data, length, last: true }; + let mem_wr_data_tok = send(mem_wr_tok, mem_wr_data_s, mem_wr_data); + + let (tok, resp) = recv(mem_wr_data_tok, mem_wr_resp_r); + trace_fmt!("[LiteralSectionHeaderWriter] {} {}", req.regenerated_size, resp); + let status = if resp.status == MemWriterStatus::OKAY { Status::OK } else { Status::ERROR }; + + let resp = Resp { length, status }; + send(mem_wr_data_tok, resp_s, resp); + } +} + +pub proc LiteralsEncoder { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemReaderStatus = mem_reader::MemReaderStatus; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + type HeaderWriterReq = LiteralSectionHeaderWriterReq; + type HeaderWriterResp = LiteralSectionHeaderWriterResp; + + type RawMemcopyReq = mem_copy::RawMemcopyReq; + type RawMemcopyResp = mem_copy::RawMemcopyResp; + type RawMemcopyStatus = mem_copy::RawMemcopyStatus; + + type Status = mem_copy::RawMemcopyStatus; + + type RleBlockEncoderReq = rle_block_encoder::RleBlockEncoderReq; + type RleBlockEncoderResp = rle_block_encoder::RleBlockEncoderResp; + type RleBlockEncoderStatus = rle_block_encoder::RleBlockEncoderStatus; + + init {} + + req_r: chan in; + resp_s: chan out; + + lshwr_req_s: chan out; + lshwr_resp_r: chan in; + + raw_req_s: chan out; + raw_resp_r: chan in; + + rle_req_s: chan out; + rle_resp_r: chan in; + + rle_mem_wr_req_s: chan out; + rle_mem_wr_data_s: chan out; + rle_mem_wr_resp_r: chan in; + + config( + req_r: chan in, + resp_s: chan out, + + raw_mem_rd_req_s: chan out, + raw_mem_rd_resp_r: chan in, + + lshwr_mem_wr_req_s: chan out, + lshwr_mem_wr_data_s: chan out, + lshwr_mem_wr_resp_r: chan in, + + raw_mem_wr_req_s: chan out, + raw_mem_wr_data_s: chan out, + raw_mem_wr_resp_r: chan in, + + rle_mem_rd_req_s: chan out, + rle_mem_rd_resp_r: chan in, + + rle_mem_wr_req_s: chan out, + rle_mem_wr_data_s: chan out, + rle_mem_wr_resp_r: chan in, + ) { + + let (lshwr_req_s, lshwr_req_r) = chan("lshwr_req"); + let (lshwr_resp_s, lshwr_resp_r) = chan("lshwr_resp"); + + spawn LiteralSectionHeaderWriter( + lshwr_req_r, lshwr_resp_s, + lshwr_mem_wr_req_s, lshwr_mem_wr_data_s, lshwr_mem_wr_resp_r, + ); + + let (raw_req_s, raw_req_r) = chan("raw_req"); + let (raw_resp_s, raw_resp_r) = chan("raw_resp"); + + spawn mem_copy::RawMemcopy( + raw_req_r, raw_resp_s, + raw_mem_rd_req_s, raw_mem_rd_resp_r, + raw_mem_wr_req_s, raw_mem_wr_data_s, raw_mem_wr_resp_r, + ); + + let (rle_req_s, rle_req_r) = chan("rle_req"); + let (rle_resp_s, rle_resp_r) = chan("rle_resp"); + + spawn rle_block_encoder::RleBlockEncoder + ( + rle_req_r, rle_resp_s, + rle_mem_rd_req_s, rle_mem_rd_resp_r + ); + + ( + req_r, resp_s, + lshwr_req_s, lshwr_resp_r, + raw_req_s, raw_resp_r, + rle_req_s, rle_resp_r, + rle_mem_wr_req_s, rle_mem_wr_data_s, rle_mem_wr_resp_r, + ) + } + + next(state: ()) { + let (tok, req) = recv(join(), req_r); + + // step 1: choose block type + let tok = send(tok, rle_req_s, RleBlockEncoderReq { + addr: req.lit_addr, + length: req.lit_cnt as uN[ADDR_W] + }); + + trace_fmt!("sent RleBlockEncoder req: {:#x}",RleBlockEncoderReq { + addr: req.lit_addr, + length: req.lit_cnt as uN[ADDR_W] + } ); + let (tok, rle_resp) = recv(tok, rle_resp_r); + trace_fmt!("received RleBlockEncoder resp: {:#x}", rle_resp); + let (btype, literals_stream_size) = if rle_resp.status == RleBlockEncoderStatus::OK { + (RawMemcopyBlockType::RLE, u32:1) + } else { + (RawMemcopyBlockType::RAW, req.lit_cnt) + }; + + + // step2: Write Literals Section Header + let lshw_req = match(btype) { + RawMemcopyBlockType::RAW => HeaderWriterReq { + addr: req.out_addr, + btype, + regenerated_size: checked_cast(req.lit_cnt), + compressed_size: u18:0, + }, + RawMemcopyBlockType::RLE => HeaderWriterReq { + addr: req.out_addr, + btype, + regenerated_size: checked_cast(req.lit_cnt), + compressed_size: u18:0 + }, + _ => fail!("impossible_case_0", zero!()) + }; + + trace_fmt!("sending header write req: {:#x}", lshw_req); + let tok = send(tok, lshwr_req_s, lshw_req); + let (tok, lshwr_resp) = recv(tok, lshwr_resp_r); + + let lshwr_error = (lshwr_resp.status != LiteralSectionHeaderWriterStatus::OK); + let literals_out_addr = req.out_addr + lshwr_resp.length; + + // step3: Write Literals Stream + let (tok, status, literals_stream_size) = match (btype, lshwr_error) { + (RawMemcopyBlockType::RLE, false) => { + let tok = send(tok, rle_mem_wr_req_s, MemWriterReq { + addr: literals_out_addr, length: uN[ADDR_W]:1 + }); + let tok = send(tok, rle_mem_wr_data_s, MemWriterData { + data: rle_resp.symbol as uN[DATA_W], + length: uN[ADDR_W]:1, + last: true + }); + trace_fmt!("writing rle symbol: {:#x} size: {})", rle_resp.symbol, literals_stream_size); + let (tok, rle_resp) = recv(tok, rle_mem_wr_resp_r); + let status = if rle_resp.status == MemWriterStatus::OKAY { Status::OK } else { Status::ERROR }; + (tok, status, uN[ADDR_W]:1) + }, + (RawMemcopyBlockType::RAW, false) => { + let tok = send(tok, raw_req_s, RawMemcopyReq { + lit_addr: req.lit_addr, + lit_cnt: req.lit_cnt, + out_addr: literals_out_addr + }); + let (tok, memcpy_resp) = recv(tok, raw_resp_r); + + let status = if memcpy_resp.status == RawMemcopyStatus::OK { Status::OK } else { Status::ERROR }; + (tok, status, req.lit_cnt) + }, + (_, false) => { + trace_fmt!("Unsupported literal type"); + (tok, Status::ERROR, uN[ADDR_W]:0) + }, + (_, true) => { + trace_fmt!("Writing literals section header failed"); + (tok, Status::ERROR, uN[ADDR_W]:0) + }, + }; + + let length = lshwr_resp.length + literals_stream_size; + let resp = RawMemcopyResp { btype, length, status }; + send(tok, resp_s, resp); + } +} + +const TEST_MEM_READER_N = u32:2; +const TEST_MEM_WRITER_N = u32:4; // LiteralsEncoder uses 3, the test uses 1. + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:64; +const TEST_DATA_W_DIV8 = TEST_DATA_W / u32:8; +const TEST_DEST_W = u32:8; +const TEST_ID_W = u32:8; +const TEST_WRITER_ID = u32:1; + +const TEST_RAM_DATA_W = TEST_DATA_W; +const TEST_RAM_SIZE = u32:1024; +const TEST_RAM_ADDR_W = TEST_ADDR_W; +const TEST_RAM_PARTITION_SIZE = u32:8; +const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W); +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; +const TEST_RAM_ASSERT_VALID_READ = true; + +const TEST_CASES = [ + ( + u32:25, // number of bytes in input + [ // input data + u64:0x8877_6655_4433_2211, + u64:0xFFEE_DDCC_BBAA_0099, + u64:0x0807_0605_0403_0201, + u64:0x09, + u64:0x0, + u64:0x0, + u64:0x0, + ], + RawMemcopyBlockType::RAW, + u32:26, // number of bytes in output + [ + // expected output + // Literals_Section_Header (8 bits) == 0xc8 + // - Literals_Block_Type (2 bits) == 0 (Raw_Literals_block) + // - Size_format (1 bit) == 0 + // - Regenerated_Size (5 bits) == 0x19 + // - [Compressed_Size] - not present + u64:0x7766_5544_3322_11_c8, + u64:0xeedd_ccbb_aa00_9988, + u64:0x706_0504_0302_01ff, + u64:0x908, + u64:0x0, + u64:0x0, + u64:0x0, + ] + ), + ( + u32:47, + [ + u64:0x8877_6655_4433_2211, + u64:0xFFEE_DDCC_BBAA_0099, + u64:0x0807_0605_0403_0201, + u64:0x100f_0e0d_0c0b_0a09, + u64:0x1817_1615_1413_1211, + u64:0x001f_1e1d_1c1b_1a19, + u64:0x0, + ], + RawMemcopyBlockType::RAW, + u32:49, + [ + // Literals_Section_Header (16 bits) == 0x02f4 + // - Literals_Block_Type (2 bits) == 0 (Raw_Literals_block) + // - Size_format (2 bits) == 1 + // - Regenerated_Size (12 bits) == 0x2f + // - [Compressed_Size] - not present + u64:0x6655_4433_2211_02f4, + u64:0xDDCC_BBAA_0099_8877, + u64:0x0605_0403_0201_FFEE, + u64:0x0e0d_0c0b_0a09_0807, + u64:0x1615_1413_1211_100f, + u64:0x1e1d_1c1b_1a19_1817, + u64:0x1f, + ] + ), + ( + u32:1, + [ + u64:0x11, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + ], + RawMemcopyBlockType::RLE, + u32:2, + [ + // Literals_Section_Header (8 bits) == 0x09 + // - Literals_Block_Type (2 bits) == 1 (RLE_Literals_block) + // - Size_format (1 bit) == 0 + // - Regenerated_Size (5 bits) == 0x01 + // - [Compressed_Size] - not present + u64:0x1109, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + ] + ), + ( + u32:25, + [ + u64:0x1111_1111_1111_1111, + u64:0x1111_1111_1111_1111, + u64:0x1111_1111_1111_1111, + u64:0x11, + u64:0x0, + u64:0x0, + u64:0x0, + ], + RawMemcopyBlockType::RLE, + u32:2, + [ + // expected output + // Literals_Section_Header (8 bits) == 0xc9 + // - Literals_Block_Type (2 bits) == 1 (RLE_Literals_block) + // - Size_format (1 bit) == 0 + // - Regenerated_Size (5 bits) == 0x19 + // - [Compressed_Size] - not present + u64:0x11c9, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + ] + ), + ( + u32:45, + [ + u64:0x5555_5555_5555_5555, + u64:0x5555_5555_5555_5555, + u64:0x5555_5555_5555_5555, + u64:0x5555_5555_5555_5555, + u64:0x5555_5555_5555_5555, + u64:0x0000_0055_5555_5555, + u64:0x0, + ], + RawMemcopyBlockType::RLE, + u32:3, + [ + // Literals_Section_Header (16 bits) == 0x2d5 + // - Literals_Block_Type (2 bits) == 1 (RLE_Literals_block) + // - Size_format (2 bits) == 1 + // - Regenerated_Size (12 bits) == 0x2d + // - [Compressed_Size] - not present + u64:0x55_02d5, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + u64:0x0, + ] + ), +]; + +// Test the case with size > 4095 +const LARGE_TEST_BYTES = u32:5000; +const LARGE_TEST_VALUES = [ + ( + // value to write + u64:0xfa, + // expected type + RawMemcopyBlockType::RAW, + // expected number of bytes + LARGE_TEST_BYTES + u32:3, + // expected first word value + // Literals_Section_Header (24 bits) == 0x01_388c + // - Literals_Block_Type (2 bits) == 0 (Raw_Literals_block) + // - Size_format (2 bits) == 1 + // - Regenerated_Size (20 bits) == 0x1388 + // - [Compressed_Size] - not present + u64:0xfa01_388c + ), + ( + u64:0x2222_2222_2222_2222, + RawMemcopyBlockType::RLE, + u32:4, // 3 bytes for the header, one byte for repeated 0x22 + // Literals_Section_Header (24 bits) == 0x01_388d + // - Literals_Block_Type (2 bits) == 1 (Raw_Literals_block) + // - Size_format (2 bits) == 1 + // - Regenerated_Size (20 bits) == 0x1388 + // - [Compressed_Size] - not present + u64:0x2201_388d + ), +]; + +#[test_proc] +proc LiteralsEncoderTest { + type Req = mem_copy::RawMemcopyReq; + type Resp = mem_copy::RawMemcopyResp; + type Status = mem_copy::RawMemcopyStatus; + type Addr = uN[TEST_ADDR_W]; + type Length = uN[TEST_ADDR_W]; + type Data = uN[TEST_DATA_W]; + + type InputRamRdReq = ram::ReadReq; + type InputRamRdResp = ram::ReadResp; + type InputRamWrReq = ram::WriteReq; + type InputRamWrResp = ram::WriteResp; + + type OutputRamRdReq = ram::ReadReq; + type OutputRamRdResp = ram::ReadResp; + type OutputRamWrReq = ram::WriteReq; + type OutputRamWrResp = ram::WriteResp; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + terminator: chan out; + + req_s: chan out; + resp_r: chan in; + + input_ram_wr_req_s: chan out; + input_ram_wr_resp_r: chan in; + + output_ram_rd_req_s: chan out; + output_ram_rd_resp_r: chan in; + + output_mem_wr_req_s: chan out; + output_mem_wr_data_s: chan out; + output_mem_wr_resp_r: chan in; + + init {} + + config(terminator: chan out) { + + // RamModel <-> AxiRamReader channels + let (input_ram_rd_req_s, input_ram_rd_req_r) = chan("input_ram_rd_req"); + let (input_ram_rd_resp_s, input_ram_rd_resp_r) = chan("input_ram_rd_resp"); + + // Test writes the input to RamModel + let (input_ram_wr_req_s, input_ram_wr_req_r) = chan("input_ram_wr_req"); + let (input_ram_wr_resp_s, input_ram_wr_resp_r) = chan("input_ram_wr_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, + >( + input_ram_rd_req_r, input_ram_rd_resp_s, + input_ram_wr_req_r, input_ram_wr_resp_s, + ); + + // MemReader <-> AxiRamReader channels + let (mem_axi_ar_s, mem_axi_ar_r) = chan("mem_axi_ar"); + let (mem_axi_r_s, mem_axi_r_r) = chan("mem_axi_r"); + + spawn axi_ram_reader::AxiRamReader< + TEST_ADDR_W, TEST_DATA_W, + TEST_DEST_W, TEST_ID_W, + TEST_RAM_SIZE, + >( + mem_axi_ar_r, mem_axi_r_s, + input_ram_rd_req_s, input_ram_rd_resp_r, + ); + + // MemReader <-> MemReadSimpleArbiter channels + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + + spawn mem_reader::MemReader< + TEST_DATA_W, TEST_ADDR_W, TEST_DEST_W, TEST_ID_W, + >( + mem_rd_req_r, mem_rd_resp_s, + mem_axi_ar_s, mem_axi_r_r, + ); + + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[TEST_MEM_READER_N]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[TEST_MEM_READER_N]("n_mem_rd_resp"); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + // Output Access + + // RamModel <-> test output interface + let (output_ram_rd_req_s, output_ram_rd_req_r) = chan("output_ram_rd_req"); + let (output_ram_rd_resp_s, output_ram_rd_resp_r) = chan("output_ram_rd_resp"); + + // RamModel <-> AxiRamWriter + let (output_ram_wr_req_s, output_ram_wr_req_r) = chan("output_ram_wr_req"); + let (output_ram_wr_resp_s, output_ram_wr_resp_r) = chan("output_ram_wr_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, + >( + output_ram_rd_req_r, output_ram_rd_resp_s, + output_ram_wr_req_r, output_ram_wr_resp_s, + ); + + // MemWriter <-> AxiRamWriter channels + let (output_ram_axi_aw_s, output_ram_axi_aw_r) = chan("output_ram_axi_aw"); + let (output_ram_axi_w_s, output_ram_axi_w_r) = chan("output_ram_axi_w"); + let (output_ram_axi_b_s, output_ram_axi_b_r) = chan("output_ram_axi_b"); + + spawn axi_ram_writer::AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_ID_W, TEST_RAM_SIZE, TEST_RAM_ADDR_W + >( + output_ram_axi_aw_r, output_ram_axi_w_r, output_ram_axi_b_s, + output_ram_wr_req_s, output_ram_wr_resp_r + ); + + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + + spawn mem_writer::MemWriter( + mem_wr_req_r, mem_wr_data_r, + output_ram_axi_aw_s, output_ram_axi_w_s, output_ram_axi_b_r, + mem_wr_resp_s, + ); + + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[TEST_MEM_WRITER_N]("n_mem_wr_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[TEST_MEM_WRITER_N]("n_mem_wr_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[TEST_MEM_WRITER_N]("n_mem_wr_resp"); + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + // Literals Encoder + + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn LiteralsEncoder( + req_r, resp_s, + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + ); + + ( + terminator, + req_s, resp_r, + input_ram_wr_req_s, input_ram_wr_resp_r, + output_ram_rd_req_s, output_ram_rd_resp_r, + // MemWriter interface to write zeros to the output memory before each test case + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3] + ) + } + + next(state: ()) { + let tok = join(); + + let tok = for ((i, (input_bytes, input_data, btype, expected_bytes, expected_data)), tok) in enumerate(TEST_CASES) { + trace_fmt!("test case: {}", i); + + // write input data + let tok = for ((j, input_data_word), tok) in enumerate(input_data) { + let ram_wr_req = InputRamWrReq { + addr: j as uN[TEST_ADDR_W], + data: input_data_word, + mask: !uN[TEST_RAM_NUM_PARTITIONS]:0, + }; + + let tok = send(tok, input_ram_wr_req_s, ram_wr_req); + let (tok, _) = recv(tok, input_ram_wr_resp_r); + tok + }(tok); + + // Literals Encoder Request + let req = Req { + lit_addr: Addr:0, + lit_cnt: input_bytes, + out_addr: Addr:0, + }; + let tok = send(tok, req_s, req); + + // Literals Encoder Response + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, Resp { + status: Status::OK, + btype: btype, + length: expected_bytes as Length + }); + + // read output, compare with the expected values + let tok = for ((j, expected_data_word), tok) in enumerate(expected_data) { + let ram_rd_req = OutputRamRdReq { + addr: j as uN[TEST_ADDR_W], + mask: !uN[TEST_RAM_NUM_PARTITIONS]:0, + }; + + let tok = send(tok, output_ram_rd_req_s, ram_rd_req); + let (tok, resp) = recv(tok, output_ram_rd_resp_r); + trace_fmt!("read data: {:#x}", resp.data); + trace_fmt!("expected data: {:#x}", expected_data_word); + assert_eq(resp.data, expected_data_word); + tok + }(tok); + + // clear the output memory + let mem_wr_req = MemWriterReq { addr: Addr:0, length: TEST_RAM_SIZE as uN[TEST_ADDR_W] }; + let tok = send(tok, output_mem_wr_req_s, mem_wr_req); + for (_, tok) in u32:0..((TEST_RAM_SIZE/TEST_DATA_W_DIV8)-u32:1) { + let mem_wr_data = MemWriterData {data: Data:0, length: TEST_DATA_W_DIV8, last: false }; + let tok = send(tok, output_mem_wr_data_s, mem_wr_data); + tok + }(tok); + let mem_wr_data = MemWriterData {data: Data:0, length: TEST_DATA_W_DIV8, last: true }; + let tok = send(tok, output_mem_wr_data_s, mem_wr_data); + let (tok, _) = recv(tok, output_mem_wr_resp_r); + + tok + }(tok); + + let tok = for ((_, (value, btype, result_size, expected_data_word)), tok) in enumerate(LARGE_TEST_VALUES) { + + // write input data + let tok = for (j, tok) in u32:0..(LARGE_TEST_BYTES/TEST_DATA_W_DIV8) { + let ram_wr_req = InputRamWrReq { + addr: j as Addr, + data: value as Data, + mask: all_ones!(), + }; + + let tok = send(tok, input_ram_wr_req_s, ram_wr_req); + let (tok, _) = recv(tok, input_ram_wr_resp_r); + tok + }(tok); + + // Literals Encoder Request + let req = Req { + lit_addr: Addr:0, + lit_cnt: LARGE_TEST_BYTES, + out_addr: Addr:0, + }; + let tok = send(tok, req_s, req); + + // Literals Encoder Response + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, Resp { + status: Status::OK, + btype: btype, + length: result_size as Length + }); + + let ram_rd_req = OutputRamRdReq { + addr: Addr:0, + mask: !uN[TEST_RAM_NUM_PARTITIONS]:0, + }; + + let tok = send(tok, output_ram_rd_req_s, ram_rd_req); + let (tok, resp) = recv(tok, output_ram_rd_resp_r); + // The large test asserts the first value read only, + // which contains the header and the beginning of data. + assert_eq(resp.data, expected_data_word); + tok + }(tok); + + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/literals_block_header_dec.x b/xls/modules/zstd/literals_block_header_dec.x index 6d8e4b0f80..5d993bbcd6 100644 --- a/xls/modules/zstd/literals_block_header_dec.x +++ b/xls/modules/zstd/literals_block_header_dec.x @@ -203,7 +203,6 @@ pub proc LiteralsHeaderDecoder { // max number of bytes that the header can have, see RFC8878 Section 3.1.1.3.1.1. length: uN[AXI_ADDR_W]:5, }); - // TODO: handle multiple receives on mem_rd_resp_r when AXI_DATA_W < 40 const_assert!(AXI_DATA_W >= u32:64); let (tok, raw) = recv(tok, mem_rd_resp_r); let (header, length, symbol) = parse_literals_header(raw.data[:40]); diff --git a/xls/modules/zstd/literals_buffer.x b/xls/modules/zstd/literals_buffer.x index 38318fecf1..d5c7bc6139 100644 --- a/xls/modules/zstd/literals_buffer.x +++ b/xls/modules/zstd/literals_buffer.x @@ -23,8 +23,6 @@ import xls.modules.zstd.common as common; import xls.modules.zstd.parallel_rams as parallel_rams; import xls.modules.zstd.ram_printer as ram_printer; -type CopyOrMatchContent = common::CopyOrMatchContent; -type CopyOrMatchLength = common::CopyOrMatchLength; type LitData = common::LitData; type LitID = common::LitID; type LitLength = common::LitLength; @@ -44,12 +42,20 @@ type RamWrRespHandlerResp = parallel_rams::RamWrRespHandlerResp; // Constants calculated from RAM parameters pub const RAM_NUM = parallel_rams::RAM_NUM; const RAM_NUM_WIDTH = parallel_rams::RAM_NUM_WIDTH; -pub const RAM_DATA_WIDTH = common::SYMBOL_WIDTH + u32:1; // the +1 is used to store "last" flag +const NUM_OF_LITERALS = RAM_NUM; + +// the +1 is used to store "last" flag +pub const RAM_DATA_WIDTH = common::SYMBOL_WIDTH + u32:1; +pub const LITERALS_DATA_WIDTH = NUM_OF_LITERALS + u32:1; + pub const RAM_WORD_PARTITION_SIZE = RAM_DATA_WIDTH; pub const RAM_NUM_PARTITIONS = ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH); // Literals data with last flag -type LiteralsWithLast = uN[RAM_DATA_WIDTH * RAM_NUM]; +type LiteralsWithLast = uN[LITERALS_DATA_WIDTH * u32:8]; + +type CopyOrMatchContent = uN[NUM_OF_LITERALS * u32:8]; +type CopyOrMatchLength = common::CopyOrMatchLength; // RAM related constants common for tests const TEST_HISTORY_BUFFER_SIZE_KB = u32:1; @@ -106,13 +112,13 @@ struct LiteralsBufferReaderToWriterSync { // handler, removing the "literals_last" flag from each literal and adding this flag // to the packet. It also validates the data. proc PacketDecoder { - literals_in_r: chan> in; - literals_out_s: chan> out; + literals_in_r: chan> in; + literals_out_s: chan> out; buffer_sync_s: chan out; config( - literals_in_r: chan> in, - literals_out_s: chan> out, + literals_in_r: chan> in, + literals_out_s: chan> out, buffer_sync_s: chan out, ) { (literals_in_r, literals_out_s, buffer_sync_s) @@ -139,11 +145,8 @@ proc PacketDecoder { }(bool[RAM_NUM]:[0, ...]); let literals_last = literals_lasts[literals.length - u64:1]; - // TODO: Restore this check after extending request to CommandConstructor - // assert!(literals.last == literals_last, "Invalid packet"); - // Send literals data - let literals_out = SequenceExecutorPacket { + let literals_out = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: literals.length, content: literals_data, @@ -158,7 +161,7 @@ proc PacketDecoder { } } -fn literals_content(literal: u8, last: u1, pos: u3) -> LiteralsWithLast { +fn literals_content(literal: u8, last: u1, pos: u32) -> LiteralsWithLast { ( literal as LiteralsWithLast | ((last as LiteralsWithLast) << common::SYMBOL_WIDTH)) << (RAM_DATA_WIDTH * (pos as u32) @@ -166,70 +169,70 @@ fn literals_content(literal: u8, last: u1, pos: u3) -> LiteralsWithLast { } -const TEST_LITERALS_IN: SequenceExecutorPacket[4] = [ - SequenceExecutorPacket { +const TEST_LITERALS_IN: SequenceExecutorPacket[4] = [ + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, - content: literals_content(u8:0xAB, u1:0, u3:0), + content: literals_content(u8:0xAB, u1:0, u32:0), last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:2, content: ( - literals_content(u8:0x12, u1:0, u3:1) | - literals_content(u8:0x34, u1:0, u3:0) + literals_content(u8:0x12, u1:0, u32:1) | + literals_content(u8:0x34, u1:0, u32:0) ), last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, content: ( - literals_content(u8:0xFE, u1:0, u3:7) | - literals_content(u8:0xDC, u1:0, u3:6) | - literals_content(u8:0xBA, u1:0, u3:5) | - literals_content(u8:0x98, u1:0, u3:4) | - literals_content(u8:0x76, u1:0, u3:3) | - literals_content(u8:0x54, u1:0, u3:2) | - literals_content(u8:0x32, u1:0, u3:1) | - literals_content(u8:0x10, u1:0, u3:0) + literals_content(u8:0xFE, u1:0, u32:7) | + literals_content(u8:0xDC, u1:0, u32:6) | + literals_content(u8:0xBA, u1:0, u32:5) | + literals_content(u8:0x98, u1:0, u32:4) | + literals_content(u8:0x76, u1:0, u32:3) | + literals_content(u8:0x54, u1:0, u32:2) | + literals_content(u8:0x32, u1:0, u32:1) | + literals_content(u8:0x10, u1:0, u32:0) ), last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, content: ( - literals_content(u8:0xAA, u1:1, u3:3) | - literals_content(u8:0xBB, u1:1, u3:2) | - literals_content(u8:0xCC, u1:0, u3:1) | - literals_content(u8:0xDD, u1:0, u3:0) + literals_content(u8:0xAA, u1:1, u32:3) | + literals_content(u8:0xBB, u1:1, u32:2) | + literals_content(u8:0xCC, u1:0, u32:1) | + literals_content(u8:0xDD, u1:0, u32:0) ), last: true, }, ]; -const TEST_LITERALS_OUT: SequenceExecutorPacket[4] = [ - SequenceExecutorPacket { +const TEST_LITERALS_OUT: SequenceExecutorPacket[4] = [ + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, content: CopyOrMatchContent:0xAB, last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:2, content: CopyOrMatchContent:0x1234, last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, content: CopyOrMatchContent:0xFEDC_BA98_7654_3210, last: false, }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, content: CopyOrMatchContent:0xAABB_CCDD, @@ -241,13 +244,13 @@ const TEST_LITERALS_OUT: SequenceExecutorPacket[4] = [ proc PacketDecoder_test { terminator: chan out; - literals_in_s: chan> out; - literals_out_r: chan> in; + literals_in_s: chan> out; + literals_out_r: chan> in; buffer_sync_r: chan in; config(terminator: chan out) { - let (literals_in_s, literals_in_r) = chan>("literals_in"); - let (literals_out_s, literals_out_r) = chan>("literals_out"); + let (literals_in_s, literals_in_r) = chan>("literals_in"); + let (literals_out_s, literals_out_r) = chan>("literals_out"); let (buffer_sync_s, buffer_sync_r) = chan("buffer_sync"); spawn PacketDecoder(literals_in_r, literals_out_s, buffer_sync_s); @@ -397,51 +400,27 @@ proc LiteralsBufferWriter< buffer_sync_r: chan in; buffer_sync_s: chan out; - wr_req_m0_s: chan out; - wr_req_m1_s: chan out; - wr_req_m2_s: chan out; - wr_req_m3_s: chan out; - wr_req_m4_s: chan out; - wr_req_m5_s: chan out; - wr_req_m6_s: chan out; - wr_req_m7_s: chan out; + wr_req_m_s: chan[RAM_NUM] out; config ( literals_r: chan in, buffer_sync_r: chan in, buffer_sync_s: chan out, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in + wr_req_m_s: chan[RAM_NUM] out, + wr_resp_m_r: chan[RAM_NUM] in, ) { let (ram_comp_input_s, ram_comp_input_r) = chan, u32:1>("ram_comp_input"); let (ram_comp_output_s, ram_comp_output_r) = chan, u32:1>("ram_comp_output"); - spawn parallel_rams::RamWrRespHandler( - ram_comp_input_r, ram_comp_output_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + spawn parallel_rams::RamWrRespHandler( + ram_comp_input_r, ram_comp_output_s, wr_resp_m_r, ); ( literals_r, ram_comp_input_s, ram_comp_output_r, buffer_sync_r, buffer_sync_s, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, + wr_req_m_s, ) } @@ -459,7 +438,6 @@ proc LiteralsBufferWriter< } next (state: State) { let tok0 = join(); - // TODO: Remove this workaround when fixed: https://github.com/google/xls/issues/1368 type State = LiteralsBufferWriterState; type WriteReq = ram::WriteReq; @@ -486,14 +464,14 @@ proc LiteralsBufferWriter< data | (literal << (RAM_DATA_WIDTH * i)) }(LiteralsWithLast:0); - let packet = SequenceExecutorPacket { + let packet = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: literals_data.length as CopyOrMatchLength, content: packet_data, last: literals_data.last, }; let (write_reqs, new_hyp_ptr) = parallel_rams::literal_packet_to_write_reqs< - HISTORY_BUFFER_SIZE_KB, RAM_ADDR_WIDTH, RAM_DATA_WIDTH + HISTORY_BUFFER_SIZE_KB, RAM_NUM, RAM_ADDR_WIDTH, LITERALS_DATA_WIDTH, RAM_DATA_WIDTH, u32:1 >( state.hyp_ptr, packet ); @@ -507,16 +485,12 @@ proc LiteralsBufferWriter< }; // send write requests to RAMs - let tok2_0 = send_if(tok1, wr_req_m0_s, write_reqs[0].mask != RAM_REQ_MASK_NONE, write_reqs[0]); - let tok2_1 = send_if(tok1, wr_req_m1_s, write_reqs[1].mask != RAM_REQ_MASK_NONE, write_reqs[1]); - let tok2_2 = send_if(tok1, wr_req_m2_s, write_reqs[2].mask != RAM_REQ_MASK_NONE, write_reqs[2]); - let tok2_3 = send_if(tok1, wr_req_m3_s, write_reqs[3].mask != RAM_REQ_MASK_NONE, write_reqs[3]); - let tok2_4 = send_if(tok1, wr_req_m4_s, write_reqs[4].mask != RAM_REQ_MASK_NONE, write_reqs[4]); - let tok2_5 = send_if(tok1, wr_req_m5_s, write_reqs[5].mask != RAM_REQ_MASK_NONE, write_reqs[5]); - let tok2_6 = send_if(tok1, wr_req_m6_s, write_reqs[6].mask != RAM_REQ_MASK_NONE, write_reqs[6]); - let tok2_7 = send_if(tok1, wr_req_m7_s, write_reqs[7].mask != RAM_REQ_MASK_NONE, write_reqs[7]); - - let tok2 = join(tok2_0, tok2_1, tok2_2, tok2_3, tok2_4, tok2_5, tok2_6, tok2_7); + let tok2 = + unroll_for! (i, all_reqs): + (u32, token) in u32:0..RAM_NUM { + let req_tok = send_if(tok1, wr_req_m_s[i], write_reqs[i].mask != RAM_REQ_MASK_NONE, write_reqs[i]); + join(all_reqs, req_tok) + }(tok1); // write completion let (do_write, wr_resp_handler_data) = parallel_rams::create_ram_wr_data(write_reqs, state.hyp_ptr); @@ -561,7 +535,7 @@ proc LiteralsBufferWriter< let tok3 = join(tok3_0, tok3_1); let sync_data = LiteralsBufferWriterToReaderSync { - literals_written: comp_data.length, + literals_written: comp_data.length as LitLength, }; let tok4 = send_if(tok3, buffer_sync_s, comp_data_valid, sync_data); @@ -590,50 +564,27 @@ proc LiteralsBufferReader< type State = LiteralsBufferReaderState; literals_buf_ctrl_r: chan in; - literals_s: chan> out; + literals_s: chan> out; ram_resp_input_s: chan out; buffer_sync_r: chan in; - rd_req_m0_s: chan out; - rd_req_m1_s: chan out; - rd_req_m2_s: chan out; - rd_req_m3_s: chan out; - rd_req_m4_s: chan out; - rd_req_m5_s: chan out; - rd_req_m6_s: chan out; - rd_req_m7_s: chan out; + rd_req_m_s: chan[RAM_NUM] out; config ( literals_buf_ctrl_r: chan in, - literals_s: chan> out, + literals_s: chan> out, buffer_sync_r: chan in, buffer_sync_s: chan out, - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, + rd_req_m_s: chan[RAM_NUM] out, + rd_resp_m_r: chan[RAM_NUM] in, ) { let (ram_resp_input_s, ram_resp_input_r) = chan("ram_resp_input"); - let (literals_enc_s, literals_enc_r) = chan, u32:1>("literals_enc"); + let (literals_enc_s, literals_enc_r) = chan, u32:1>("literals_enc"); - spawn parallel_rams::RamRdRespHandler( - ram_resp_input_r, literals_enc_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, + spawn parallel_rams::RamRdRespHandler( + ram_resp_input_r, literals_enc_s, rd_resp_m_r, ); spawn PacketDecoder( @@ -645,8 +596,7 @@ proc LiteralsBufferReader< literals_s, ram_resp_input_s, buffer_sync_r, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, + rd_req_m_s, ) } @@ -665,7 +615,6 @@ proc LiteralsBufferReader< next (state: State) { let tok0 = join(); - // TODO: Remove this workaround when fixed: https://github.com/google/xls/issues/1368 type ReadReq = ram::ReadReq; type State = LiteralsBufferReaderState; @@ -689,7 +638,6 @@ proc LiteralsBufferReader< }; // read literals from RAM - // limit read to 8 literals let literals_to_read = if (left_to_read > (RAM_NUM as u32)) { RAM_NUM as u32 } else { @@ -702,7 +650,7 @@ proc LiteralsBufferReader< literals_to_read }; - let packet = SequenceExecutorPacket { + let packet = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: literals_to_read as CopyOrMatchLength, content: state.hb_len as LiteralsWithLast, @@ -710,7 +658,7 @@ proc LiteralsBufferReader< }; let (read_reqs, read_start, read_len, _, _) = parallel_rams::sequence_packet_to_read_reqs< - HISTORY_BUFFER_SIZE_KB, RAM_ADDR_WIDTH, RAM_DATA_WIDTH + HISTORY_BUFFER_SIZE_KB, RAM_NUM, RAM_ADDR_WIDTH, LITERALS_DATA_WIDTH >( state.hyp_ptr, packet, state.hb_len ); @@ -739,17 +687,13 @@ proc LiteralsBufferReader< ) }; - // read requests - let tok2_0 = send_if(tok1, rd_req_m0_s, read_reqs[0].mask != RAM_REQ_MASK_NONE, read_reqs[0]); - let tok2_1 = send_if(tok1, rd_req_m1_s, read_reqs[1].mask != RAM_REQ_MASK_NONE, read_reqs[1]); - let tok2_2 = send_if(tok1, rd_req_m2_s, read_reqs[2].mask != RAM_REQ_MASK_NONE, read_reqs[2]); - let tok2_3 = send_if(tok1, rd_req_m3_s, read_reqs[3].mask != RAM_REQ_MASK_NONE, read_reqs[3]); - let tok2_4 = send_if(tok1, rd_req_m4_s, read_reqs[4].mask != RAM_REQ_MASK_NONE, read_reqs[4]); - let tok2_5 = send_if(tok1, rd_req_m5_s, read_reqs[5].mask != RAM_REQ_MASK_NONE, read_reqs[5]); - let tok2_6 = send_if(tok1, rd_req_m6_s, read_reqs[6].mask != RAM_REQ_MASK_NONE, read_reqs[6]); - let tok2_7 = send_if(tok1, rd_req_m7_s, read_reqs[7].mask != RAM_REQ_MASK_NONE, read_reqs[7]); - - let tok2 = join(tok2_0, tok2_1, tok2_2, tok2_3, tok2_4, tok2_5, tok2_6, tok2_7); + let tok2 = + unroll_for! (i, all_reqs): + (u32, token) in u32:0..RAM_NUM { + let req_tok = send_if(tok1, rd_req_m_s[i], read_reqs[i].mask != RAM_REQ_MASK_NONE, read_reqs[i]); + join(all_reqs, req_tok) + }(tok1); + let last_access = if (state.left_to_read > u32:0) { false } else { @@ -757,7 +701,7 @@ proc LiteralsBufferReader< }; let (do_read, rd_resp_handler_data) = - parallel_rams::create_ram_rd_data( + parallel_rams::create_ram_rd_data( read_reqs, read_start, read_len, last_access, !last_access ); if do_read { @@ -810,39 +754,11 @@ pub proc LiteralsBuffer< rle_literals_r: chan in, huff_literals_r: chan in, literals_buf_ctrl_r: chan in, - literals_s: chan> out, - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in + literals_s: chan> out, + rd_req_m_s: chan[RAM_NUM] out, + rd_resp_m_r: chan[RAM_NUM] in, + wr_req_m_s: chan[RAM_NUM] out, + wr_resp_m_r: chan[RAM_NUM] in, ) { type SyncWriterToReader = LiteralsBufferWriterToReaderSync; type SyncReaderToWriter = LiteralsBufferReaderToWriterSync; @@ -861,10 +777,7 @@ pub proc LiteralsBuffer< > ( sync_literals_r, buffer_sync_reader_to_writer_r, buffer_sync_writer_to_reader_s, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + wr_req_m_s, wr_resp_m_r, ); spawn LiteralsBufferReader< @@ -872,21 +785,19 @@ pub proc LiteralsBuffer< > ( literals_buf_ctrl_r, literals_s, buffer_sync_writer_to_reader_r, buffer_sync_reader_to_writer_s, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, + rd_req_m_s, rd_resp_m_r, ); } next (state: ()) { } } -const INST_HISTORY_BUFFER_SIZE_KB = u32:64; +const INST_HISTORY_BUFFER_SIZE_KB = common::HISTORY_BUFFER_SIZE_KB; const INST_RAM_ADDR_WIDTH = parallel_rams::ram_addr_width(INST_HISTORY_BUFFER_SIZE_KB); +const INST_RAM_NUM = RAM_NUM; const INST_RAM_NUM_PARTITIONS = RAM_NUM_PARTITIONS; const INST_RAM_DATA_WIDTH = RAM_DATA_WIDTH; -const INST_SYMBOL_WIDTH = common::SYMBOL_WIDTH; +const INST_SYMBOL_WIDTH = NUM_OF_LITERALS; pub proc LiteralsBufferInst { type ReadReq = ram::ReadReq; @@ -902,50 +813,16 @@ pub proc LiteralsBufferInst { huff_literals_r: chan in, literals_buf_ctrl_r: chan in, literals_s: chan> out, - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in + rd_req_m_s: chan[INST_RAM_NUM] out, + rd_resp_m_r: chan[INST_RAM_NUM] in, + wr_req_m_s: chan[INST_RAM_NUM] out, + wr_resp_m_r: chan[INST_RAM_NUM] in ) { spawn LiteralsBuffer ( raw_literals_r, rle_literals_r, huff_literals_r, literals_buf_ctrl_r, literals_s, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + rd_req_m_s, rd_resp_m_r, + wr_req_m_s, wr_resp_m_r, ); } @@ -992,76 +869,76 @@ const TEST_BUFFER_CTRL: LiteralsBufferCtrl[11] = [ LiteralsBufferCtrl {length: u32:1, last: true}, ]; -const TEST_EXPECTED_PACKETS: SequenceExecutorPacket[11] = [ +const TEST_EXPECTED_PACKETS: SequenceExecutorPacket[11] = [ // Literal #0 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:2, content: CopyOrMatchContent:0x789A, last: false }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, content: CopyOrMatchContent:0x56, last: false }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:2, content: CopyOrMatchContent:0x1234, last: true }, // Literal #1 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, content: CopyOrMatchContent:0xBBBB_BBBB, last: true }, // Literal #2 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, content: CopyOrMatchContent:0x64, last: true }, // Literal #3 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, content: CopyOrMatchContent:0xABCD_DCBA_1234_4321, last: true }, // Literal #4 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:3, content: CopyOrMatchContent:0x21_4365, last: true }, // Literal #5 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:7, content: CopyOrMatchContent:0xAA_BBBB_CCCC_DDDD, last: true }, // Literal #6 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, content: CopyOrMatchContent:0xDCBA_ABCD_1234_4321, last: false }, - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, content: CopyOrMatchContent:0x78, last: true }, // Literal #7 - SequenceExecutorPacket { + SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:1, content: CopyOrMatchContent:0x26, @@ -1078,7 +955,7 @@ proc LiteralsBuffer_test { huff_literals_s: chan out; literals_buf_ctrl_s: chan out; - literals_r: chan> in; + literals_r: chan> in; print_start_s: chan<()> out; print_finish_r: chan<()> in; @@ -1094,7 +971,7 @@ proc LiteralsBuffer_test { let (huff_literals_s, huff_literals_r) = chan("huff_literals"); let (literals_buf_ctrl_s, literals_buf_ctrl_r) = chan("literals_buf_ctrl"); - let (literals_s, literals_r) = chan>("literals"); + let (literals_s, literals_r) = chan>("literals"); let (print_start_s, print_start_r) = chan<()>("print_start"); let (print_finish_s, print_finish_r) = chan<()>("print_finish"); @@ -1112,14 +989,8 @@ proc LiteralsBuffer_test { > ( raw_literals_r, rle_literals_r, huff_literals_r, literals_buf_ctrl_r, literals_s, - ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], - ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], - ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], - ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], - ram_wr_req_s[0], ram_wr_req_s[1], ram_wr_req_s[2], ram_wr_req_s[3], - ram_wr_req_s[4], ram_wr_req_s[5], ram_wr_req_s[6], ram_wr_req_s[7], - ram_wr_resp_r[0], ram_wr_resp_r[1], ram_wr_resp_r[2], ram_wr_resp_r[3], - ram_wr_resp_r[4], ram_wr_resp_r[5], ram_wr_resp_r[6], ram_wr_resp_r[7] + ram_rd_req_s, ram_rd_resp_r, + ram_wr_req_s, ram_wr_resp_r ); spawn ram_printer::RamPrinter< RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_NUM_PARTITIONS, @@ -1193,7 +1064,7 @@ proc LiteralsBuffer_test { }(tok); // receive and check packets - let tok = for ((i, test_exp_literals), tok): ((u32, SequenceExecutorPacket), token) in enumerate(TEST_EXPECTED_PACKETS) { + let tok = for ((i, test_exp_literals), tok): ((u32, SequenceExecutorPacket), token) in enumerate(TEST_EXPECTED_PACKETS) { let (tok, literals) = recv(tok, literals_r); trace_fmt!("Received #{} literals packet {:#x}", i + u32:1, literals); assert_eq(test_exp_literals, literals); diff --git a/xls/modules/zstd/literals_decoder.x b/xls/modules/zstd/literals_decoder.x index d9c58ae478..c115c053f6 100644 --- a/xls/modules/zstd/literals_decoder.x +++ b/xls/modules/zstd/literals_decoder.x @@ -24,13 +24,10 @@ import xls.modules.zstd.memory.axi as axi; import xls.modules.zstd.memory.axi_ram_reader; import xls.modules.zstd.memory.mem_reader as mem_reader; import xls.modules.zstd.parallel_rams as parallel_rams; -import xls.modules.zstd.ram_printer as ram_printer; import xls.modules.zstd.raw_literals_dec as raw_literals_dec; import xls.modules.zstd.rle_literals_dec as rle_literals_dec; import xls.modules.zstd.huffman_literals_dec as huffman_literals_dec; -type CopyOrMatchContent = common::CopyOrMatchContent; -type CopyOrMatchLength = common::CopyOrMatchLength; type LitData = common::LitData; type LitLength = common::LitLength; type LiteralsBlockType = literals_block_header_dec::LiteralsBlockType; @@ -39,7 +36,9 @@ type LiteralsData = common::LiteralsData; type LiteralsDataWithSync = common::LiteralsDataWithSync; type LiteralsPathCtrl = common::LiteralsPathCtrl; type SequenceExecutorMessageType = common::SequenceExecutorMessageType; -type SequenceExecutorPacket = common::SequenceExecutorPacket; +type SequenceExecutorPacket = common::SequenceExecutorPacket; +type CopyOrMatchContent = uN[common::LITERALS_IN_PACKET * u32:8]; +type CopyOrMatchLength = common::CopyOrMatchLength; type Streams = common::Streams; pub struct LiteralsDecoderCtrlReq { @@ -588,14 +587,13 @@ proc LiteralsDecoderCtrl_test { let tok = send(tok, rle_lit_resp_s, rle_lit_resp); trace_fmt!("Test: Sent RleResp: {:#x}", rle_lit_resp); } else { - //let (tok, huffman_lit_req) = recv(tok, huffman_lit_req_r); - //trace_fmt!("Test: Received HuffmanReq: {:#x}", huffman_lit_req); - //let expected_huffman_lit_req = HuffmanReq { - //}; - //assert_eq(huffman_lit_req, expected_huffman_lit_req); - //let huffman_lit_resp = HuffmanResp { status: HuffmanStatus::OKAY }; - //let tok = send(tok, huffman_lit_resp_s, huffman_lit_resp); - //trace_fmt!("Test: Sent HuffmanResp: {:#x}", huffman_lit_resp); + let (tok, huffman_lit_req) = recv(tok, huffman_lit_req_r); + trace_fmt!("Test: Received HuffmanReq: {:#x}", huffman_lit_req); + let expected_huffman_lit_req = zero!(); + assert_eq(huffman_lit_req, expected_huffman_lit_req); + let huffman_lit_resp = HuffmanResp { status: HuffmanStatus::OKAY }; + let tok = send(tok, huffman_lit_resp_s, huffman_lit_resp); + trace_fmt!("Test: Sent HuffmanResp: {:#x}", huffman_lit_resp); }; let (tok, lit_ctrl_resp) = recv(tok, lit_ctrl_resp_r); @@ -646,9 +644,8 @@ pub proc LiteralsDecoder< type CtrlReq = LiteralsDecoderCtrlReq; type CtrlResp = LiteralsDecoderCtrlResp; type BufferCtrl = common::LiteralsBufferCtrl; - type BufferOut = common::SequenceExecutorPacket; + type BufferOut = common::SequenceExecutorPacket; - // TODO: make sure those can use the same parameters type HuffmanWeightsReadReq = ram::ReadReq; type HuffmanWeightsReadResp = ram::ReadResp; type HuffmanWeightsWriteReq = ram::WriteReq; @@ -722,38 +719,10 @@ pub proc LiteralsDecoder< lit_buf_out_s: chan out, // Internal memory - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in, + rd_req_m_s: chan[common::LITERALS_IN_PACKET] out, + rd_resp_m_r: chan[common::LITERALS_IN_PACKET] in, + wr_req_m_s: chan[common::LITERALS_IN_PACKET] out, + wr_resp_m_r: chan[common::LITERALS_IN_PACKET] in, // Huffman weights memory huffman_lit_weights_mem_rd_req_s: chan out, @@ -802,7 +771,7 @@ pub proc LiteralsDecoder< let (lit_header_mem_rd_req_s, lit_header_mem_rd_req_r) = chan("lit_header_mem_rd_req"); let (lit_header_mem_rd_resp_s, lit_header_mem_rd_resp_r) = chan("lit_header_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( lit_header_mem_rd_req_r, lit_header_mem_rd_resp_s, lit_header_axi_ar_s, lit_header_axi_r_r ); @@ -819,7 +788,7 @@ pub proc LiteralsDecoder< let (raw_lit_mem_rd_req_s, raw_lit_mem_rd_req_r) = chan("raw_lit_mem_rd_req"); let (raw_lit_mem_rd_resp_s, raw_lit_mem_rd_resp_r) = chan("raw_lit_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( raw_lit_mem_rd_req_r, raw_lit_mem_rd_resp_s, raw_lit_axi_ar_s, raw_lit_axi_r_r ); @@ -885,14 +854,7 @@ pub proc LiteralsDecoder< > ( raw_lit_output_r, rle_lit_output_r, huffman_lit_output_r, lit_buf_ctrl_r, lit_buf_out_s, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + rd_req_m_s, rd_resp_m_r, wr_req_m_s, wr_resp_m_r, ); spawn LiteralsDecoderCtrl ( @@ -911,7 +873,7 @@ pub proc LiteralsDecoder< next (state: ()) { } } -const ZSTD_HISTORY_BUFFER_SIZE_KB: u32 = u32:64; +const ZSTD_HISTORY_BUFFER_SIZE_KB: u32 = common::HISTORY_BUFFER_SIZE_KB; const ZSTD_RAM_ADDR_WIDTH: u32 = parallel_rams::ram_addr_width(ZSTD_HISTORY_BUFFER_SIZE_KB); const INST_AXI_DATA_W:u32 = u32:64; const INST_AXI_ID_W:u32 = u32:4; @@ -967,7 +929,7 @@ proc LiteralsDecoderInst { type CtrlReq = LiteralsDecoderCtrlReq; type CtrlResp = LiteralsDecoderCtrlResp; type BufferCtrl = common::LiteralsBufferCtrl; - type BufferOut = common::SequenceExecutorPacket; + type BufferOut = common::SequenceExecutorPacket; type HuffmanWeightsReadReq = ram::ReadReq; type HuffmanWeightsReadResp = ram::ReadResp; @@ -1042,38 +1004,10 @@ proc LiteralsDecoderInst { lit_buf_out_s: chan out, // Internal memory - rd_req_m0_s: chan out, - rd_req_m1_s: chan out, - rd_req_m2_s: chan out, - rd_req_m3_s: chan out, - rd_req_m4_s: chan out, - rd_req_m5_s: chan out, - rd_req_m6_s: chan out, - rd_req_m7_s: chan out, - rd_resp_m0_r: chan in, - rd_resp_m1_r: chan in, - rd_resp_m2_r: chan in, - rd_resp_m3_r: chan in, - rd_resp_m4_r: chan in, - rd_resp_m5_r: chan in, - rd_resp_m6_r: chan in, - rd_resp_m7_r: chan in, - wr_req_m0_s: chan out, - wr_req_m1_s: chan out, - wr_req_m2_s: chan out, - wr_req_m3_s: chan out, - wr_req_m4_s: chan out, - wr_req_m5_s: chan out, - wr_req_m6_s: chan out, - wr_req_m7_s: chan out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in, + rd_req_m_s: chan[literals_buffer::RAM_NUM] out, + rd_resp_m_r: chan[literals_buffer::RAM_NUM] in, + wr_req_m_s: chan[literals_buffer::RAM_NUM] out, + wr_resp_m_r: chan[literals_buffer::RAM_NUM] in, // Huffman weights memory huffman_lit_weights_mem_rd_req_s: chan out, @@ -1137,14 +1071,8 @@ proc LiteralsDecoderInst { // Literals Decoder output control lit_buf_ctrl_r, lit_buf_out_s, // Internal memory - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + rd_req_m_s, rd_resp_m_r, + wr_req_m_s, wr_resp_m_r, // Huffman weights memory huffman_lit_weights_mem_rd_req_s, huffman_lit_weights_mem_rd_resp_r, huffman_lit_weights_mem_wr_req_s, huffman_lit_weights_mem_wr_resp_r, @@ -1197,7 +1125,7 @@ const TEST_AXI_RAM_MODEL_NUM = u32:1; const TEST_LITERALS_BUFFER_RAM_MODEL_DATA_WIDTH:u32 = literals_buffer::RAM_DATA_WIDTH; const TEST_LITERALS_BUFFER_RAM_MODEL_SIZE:u32 = parallel_rams::ram_size(TEST_HISTORY_BUFFER_SIZE_KB); const TEST_LITERALS_BUFFER_RAM_MODEL_ADDR_WIDTH:u32 = parallel_rams::ram_addr_width(TEST_HISTORY_BUFFER_SIZE_KB); -const TEST_LITERALS_BUFFER_RAM_MODEL_WORD_PARTITION_SIZE:u32 = literals_buffer::RAM_WORD_PARTITION_SIZE; +const TEST_LITERALS_BUFFER_RAM_MODEL_WORD_PARTITION_SIZE:u32 = TEST_LITERALS_BUFFER_RAM_MODEL_DATA_WIDTH; const TEST_LITERALS_BUFFER_RAM_MODEL_NUM_PARTITIONS:u32 = literals_buffer::RAM_NUM_PARTITIONS; const TEST_LITERALS_BUFFER_RAM_MODEL_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; const TEST_LITERALS_BUFFER_RAM_MODEL_INITIALIZED = true; @@ -1319,7 +1247,7 @@ proc LiteralsDecoder_test { type CtrlResp = LiteralsDecoderCtrlResp; type CtrlStatus = LiteralsDecoderCtrlStatus; type BufferCtrl = common::LiteralsBufferCtrl; - type BufferOut = common::SequenceExecutorPacket; + type BufferOut = common::SequenceExecutorPacket; type AxiRamData = uN[TEST_AXI_RAM_MODEL_DATA_WIDTH]; type AxiRamAddr = uN[TEST_AXI_RAM_MODEL_ADDR_WIDTH]; @@ -1340,9 +1268,6 @@ proc LiteralsDecoder_test { buf_ctrl_s: chan out; buf_out_r: chan in; - print_start_s: chan<()> out; - print_finish_r: chan<()> in; - ram_wr_req_header_s : chan out; ram_wr_resp_header_r : chan in; ram_wr_req_raw_s : chan out; @@ -1392,9 +1317,6 @@ proc LiteralsDecoder_test { let (buf_ctrl_s, buf_ctrl_r) = chan("buf_ctrl"); let (buf_out_s, buf_out_r) = chan("buf_out"); - let (print_start_s, print_start_r) = chan<()>("print_start"); - let (print_finish_s, print_finish_r) = chan<()>("print_finish"); - let (ram_rd_req_s, ram_rd_req_r) = chan[literals_buffer::RAM_NUM]("ram_rd_req"); let (ram_rd_resp_s, ram_rd_resp_r) = chan[literals_buffer::RAM_NUM]("ram_rd_resp"); let (ram_wr_req_s, ram_wr_req_r) = chan[literals_buffer::RAM_NUM]("ram_wr_req"); @@ -1450,14 +1372,7 @@ proc LiteralsDecoder_test { huffman_weights_fse_decoder_dec_axi_ar_s, huffman_weights_fse_decoder_dec_axi_r_r, ctrl_req_r, ctrl_resp_s, ctrl_header_s, buf_ctrl_r, buf_out_s, - ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], - ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], - ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], - ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], - ram_wr_req_s[0], ram_wr_req_s[1], ram_wr_req_s[2], ram_wr_req_s[3], - ram_wr_req_s[4], ram_wr_req_s[5], ram_wr_req_s[6], ram_wr_req_s[7], - ram_wr_resp_r[0], ram_wr_resp_r[1], ram_wr_resp_r[2], ram_wr_resp_r[3], - ram_wr_resp_r[4], ram_wr_resp_r[5], ram_wr_resp_r[6], ram_wr_resp_r[7], + ram_rd_req_s, ram_rd_resp_r, ram_wr_req_s, ram_wr_resp_r, huffman_lit_weights_mem_rd_req_s, huffman_lit_weights_mem_rd_resp_r, huffman_lit_weights_mem_wr_req_s, huffman_lit_weights_mem_wr_resp_r, huffman_lit_prescan_mem_rd_req_s, huffman_lit_prescan_mem_rd_resp_r, @@ -1472,16 +1387,6 @@ proc LiteralsDecoder_test { huffman_lit_weights_fse_wr_req_s, huffman_lit_weights_fse_wr_resp_r, ); - spawn ram_printer::RamPrinter< - TEST_LITERALS_BUFFER_RAM_MODEL_DATA_WIDTH, - TEST_LITERALS_BUFFER_RAM_MODEL_SIZE, - TEST_LITERALS_BUFFER_RAM_MODEL_NUM_PARTITIONS, - TEST_LITERALS_BUFFER_RAM_MODEL_ADDR_WIDTH, - TEST_LITERALS_BUFFER_RAM_MODEL_NUM - > ( - print_start_r, print_finish_s, ram_rd_req_s, ram_rd_resp_r - ); - spawn ram::RamModel< TEST_LITERALS_BUFFER_RAM_MODEL_DATA_WIDTH, TEST_LITERALS_BUFFER_RAM_MODEL_SIZE, @@ -1850,7 +1755,6 @@ proc LiteralsDecoder_test { terminator, ctrl_req_s, ctrl_resp_r, ctrl_header_r, buf_ctrl_s, buf_out_r, - print_start_s, print_finish_r, ram_wr_req_header_s, ram_wr_resp_header_r, ram_wr_req_raw_s, ram_wr_resp_raw_r, ram_wr_req_huffman_s, ram_wr_resp_huffman_r, @@ -2001,7 +1905,7 @@ proc LiteralsDecoder_test { SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, - content: CopyOrMatchContent:0x0504_0100, + content: CopyOrMatchContent:0x0504_0001, last: true }, // Literals #5 (RLE) @@ -2021,7 +1925,7 @@ proc LiteralsDecoder_test { SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:4, - content: CopyOrMatchContent:0x0001_0405, + content: CopyOrMatchContent:0x0100_0405, last: true }, // Literals #7 (RLE) @@ -2030,13 +1934,13 @@ proc LiteralsDecoder_test { SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x0504_0100_0504_0100, + content: CopyOrMatchContent:0x0504_0001_0504_0001, last: false }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x0504_0100_0504_0100, + content: CopyOrMatchContent:0x0504_0001_0504_0001, last: true }, // Literals #9 (RAW) @@ -2068,13 +1972,13 @@ proc LiteralsDecoder_test { SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x0504_0100_0504_0100, + content: CopyOrMatchContent:0x0504_0001_0504_0001, last: false }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x0504_0100_0504_0100, + content: CopyOrMatchContent:0x0504_0001_0504_0001, last: true }, ]; @@ -2131,267 +2035,6 @@ proc LiteralsDecoder_test { tok }(tok); - //// print RAM content - //let tok = send(tok, print_start_s, ()); - //let (tok, _) = recv(tok, print_finish_r); - send(tok, terminator, true); } } - -// TODO: Uncomment this test when fixed: https://github.com/google/xls/issues/1502 -// type RamData = uN[literals_buffer::RAM_DATA_WIDTH]; - -// // Expected RAM content after each ctrl -// const TEST_EXPECTED_RAM_CONTENT = RamData[literals_buffer::RAM_NUM][10][7]:[ -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData: 0x0, RamData: 0x0, RamData:0x035, RamData:0x035, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData:0x053, RamData:0x070, RamData:0x035, RamData:0x035, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData:0x1a9, RamData:0x16d, RamData:0x04c, RamData:0x0fb, RamData:0x041, RamData:0x0c6, RamData:0x07b, RamData:0x060], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData:0x19b, RamData:0x10f, RamData:0x19c, RamData:0x1e1, RamData:0x1ba], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData:0x053, RamData:0x070, RamData:0x035, RamData:0x035, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData:0x1a9, RamData:0x16d, RamData:0x04c, RamData:0x0fb, RamData:0x041, RamData:0x0c6, RamData:0x07b, RamData:0x060], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x19b, RamData:0x10f, RamData:0x19c, RamData:0x1e1, RamData:0x1ba], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData:0x05a], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData:0x053, RamData:0x070, RamData:0x035, RamData:0x035, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData:0x1a9, RamData:0x16d, RamData:0x04c, RamData:0x0fb, RamData:0x041, RamData:0x0c6, RamData:0x07b, RamData:0x060], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x19b, RamData:0x10f, RamData:0x19c, RamData:0x1e1, RamData:0x1ba], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData:0x05a], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// [ -// [RamData:0x016, RamData:0x057, RamData:0x034, RamData:0x065, RamData:0x0a6, RamData:0x0db, RamData:0x05d, RamData:0x0b0], -// [RamData:0x053, RamData:0x070, RamData:0x035, RamData:0x035, RamData:0x023, RamData:0x023, RamData:0x023, RamData:0x023], -// [RamData:0x1a9, RamData:0x16d, RamData:0x04c, RamData:0x0fb, RamData:0x041, RamData:0x0c6, RamData:0x07b, RamData:0x060], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x19b, RamData:0x10f, RamData:0x19c, RamData:0x1e1, RamData:0x1ba], -// [RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a, RamData:0x05a], -// [RamData:0x094, RamData:0x03e, RamData:0x096, RamData:0x018, RamData:0x034, RamData:0x0c2, RamData:0x047, RamData:0x05a], -// [RamData:0x002, RamData:0x0d0, RamData:0x0e8, RamData:0x0d7, RamData:0x028, RamData:0x09a, RamData:0x0be, RamData:0x060], -// [RamData:0x064, RamData:0x0c3, RamData:0x08b, RamData:0x0e1, RamData:0x0fa, RamData:0x08d, RamData:0x012, RamData:0x0bc], -// [RamData:0x119, RamData:0x163, RamData:0x1f1, RamData:0x1ce, RamData:0x121, RamData:0x1c2, RamData:0x194, RamData:0x0f8], -// [RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0, RamData: 0x0], -// ], -// ]; - -// const CYCLES_PER_RAM_READ = u32:16; - -// #[test_proc] -// proc LiteralsDecoderRamContent_test { -// terminator: chan out; - -// literals_ctrl_s: chan out; -// literals_data_s: chan out; -// literals_buf_ctrl_s: chan out; -// literals_r: chan in; - -// ram_rd_req_m0_s: chan out; -// ram_rd_req_m1_s: chan out; -// ram_rd_req_m2_s: chan out; -// ram_rd_req_m3_s: chan out; -// ram_rd_req_m4_s: chan out; -// ram_rd_req_m5_s: chan out; -// ram_rd_req_m6_s: chan out; -// ram_rd_req_m7_s: chan out; - -// ram_rd_resp_m0_r: chan in; -// ram_rd_resp_m1_r: chan in; -// ram_rd_resp_m2_r: chan in; -// ram_rd_resp_m3_r: chan in; -// ram_rd_resp_m4_r: chan in; -// ram_rd_resp_m5_r: chan in; -// ram_rd_resp_m6_r: chan in; -// ram_rd_resp_m7_r: chan in; - -// config (terminator: chan out) { -// let (literals_ctrl_s, literals_ctrl_r) = chan("literals_ctrl"); -// let (literals_buf_ctrl_s, literals_buf_ctrl_r) = chan("literals_buf_ctrl"); -// let (literals_s, literals_r) = chan("literals"); - -// let (ram_rd_req_s, ram_rd_req_r) = chan[literals_buffer::RAM_NUM]("ram_rd_req"); -// let (ram_rd_resp_s, ram_rd_resp_r) = chan[literals_buffer::RAM_NUM]("ram_rd_resp"); -// let (ram_wr_req_s, ram_wr_req_r) = chan[literals_buffer::RAM_NUM]("ram_wr_req"); -// let (ram_wr_resp_s, ram_wr_resp_r) = chan[literals_buffer::RAM_NUM]("ram_wr_resp"); - -// spawn LiteralsDecoder( -// literals_ctrl_r, -// literals_buf_ctrl_r, literals_s, -// ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], -// ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], -// ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], -// ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], -// ram_wr_req_s[0], ram_wr_req_s[1], ram_wr_req_s[2], ram_wr_req_s[3], -// ram_wr_req_s[4], ram_wr_req_s[5], ram_wr_req_s[6], ram_wr_req_s[7], -// ram_wr_resp_r[0], ram_wr_resp_r[1], ram_wr_resp_r[2], ram_wr_resp_r[3], -// ram_wr_resp_r[4], ram_wr_resp_r[5], ram_wr_resp_r[6], ram_wr_resp_r[7] -// ); - -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[0], ram_rd_resp_s[0], ram_wr_req_r[0], ram_wr_resp_s[0]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[1], ram_rd_resp_s[1], ram_wr_req_r[1], ram_wr_resp_s[1]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[2], ram_rd_resp_s[2], ram_wr_req_r[2], ram_wr_resp_s[2]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[3], ram_rd_resp_s[3], ram_wr_req_r[3], ram_wr_resp_s[3]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[4], ram_rd_resp_s[4], ram_wr_req_r[4], ram_wr_resp_s[4]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[5], ram_rd_resp_s[5], ram_wr_req_r[5], ram_wr_resp_s[5]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[6], ram_rd_resp_s[6], ram_wr_req_r[6], ram_wr_resp_s[6]); -// spawn ram::RamModel< -// literals_buffer::RAM_DATA_WIDTH, TEST_RAM_SIZE, literals_buffer::RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[7], ram_rd_resp_s[7], ram_wr_req_r[7], ram_wr_resp_s[7]); - -// ( -// terminator, -// literals_ctrl_s, literals_data_s, -// literals_buf_ctrl_s, literals_r, -// ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], -// ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], -// ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], -// ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], -// ) -// } - -// init { u32:0 } - -// next (state: u32) { -// // send literals -// let ok = if (state == u32:0) { -// for ((i, test_data), tok): ((u32, LiteralsData), token) in enumerate(TEST_DATA) { -// let tok = send(tok, literals_data_s, test_data); -// trace_fmt!("Sent #{} literals data, {:#x}", i + u32:1, test_data); -// tok -// }(tok) -// } else { tok }; - -// // send ctrl and read RAM content -// let tok = for ((i, test_ctrl), tok): ((u32, LiteralsPathCtrl), token) in enumerate(TEST_CTRL) { -// if (state == i * CYCLES_PER_RAM_READ) { -// let tok = send(tok, literals_ctrl_s, test_ctrl); -// trace_fmt!("Sent #{} literals ctrl, {:#x}", i + u32:1, test_ctrl); -// tok -// } else if (state == (i + u32:1) * CYCLES_PER_RAM_READ - u32:1) { -// for (addr, tok): (u32, token) in u32:0..u32:10 { -// let read_req = TestReadReq { -// addr: addr as uN[TEST_RAM_ADDR_WIDTH], -// mask: u1:1 -// }; - -// let tok = send(tok, ram_rd_req_m0_s, read_req); -// let tok = send(tok, ram_rd_req_m1_s, read_req); -// let tok = send(tok, ram_rd_req_m2_s, read_req); -// let tok = send(tok, ram_rd_req_m3_s, read_req); -// let tok = send(tok, ram_rd_req_m4_s, read_req); -// let tok = send(tok, ram_rd_req_m5_s, read_req); -// let tok = send(tok, ram_rd_req_m6_s, read_req); -// let tok = send(tok, ram_rd_req_m7_s, read_req); - -// let (tok, ram_rd_resp_m0) = recv(tok, ram_rd_resp_m0_r); -// let (tok, ram_rd_resp_m1) = recv(tok, ram_rd_resp_m1_r); -// let (tok, ram_rd_resp_m2) = recv(tok, ram_rd_resp_m2_r); -// let (tok, ram_rd_resp_m3) = recv(tok, ram_rd_resp_m3_r); -// let (tok, ram_rd_resp_m4) = recv(tok, ram_rd_resp_m4_r); -// let (tok, ram_rd_resp_m5) = recv(tok, ram_rd_resp_m5_r); -// let (tok, ram_rd_resp_m6) = recv(tok, ram_rd_resp_m6_r); -// let (tok, ram_rd_resp_m7) = recv(tok, ram_rd_resp_m7_r); -// trace_fmt!( -// "Received RAM read responses: [{:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}]", -// ram_rd_resp_m7.data, ram_rd_resp_m6.data, ram_rd_resp_m5.data, ram_rd_resp_m4.data, -// ram_rd_resp_m3.data, ram_rd_resp_m2.data, ram_rd_resp_m1.data, ram_rd_resp_m0.data, -// ); - -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][7], ram_rd_resp_m0.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][6], ram_rd_resp_m1.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][5], ram_rd_resp_m2.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][4], ram_rd_resp_m3.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][3], ram_rd_resp_m4.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][2], ram_rd_resp_m5.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][1], ram_rd_resp_m6.data); -// assert_eq(TEST_EXPECTED_RAM_CONTENT[i][addr][0], ram_rd_resp_m7.data); - -// tok -// }(tok) -// } else { -// tok -// } -// }(tok); - -// send_if(tok, terminator, state == array_size(TEST_CTRL) * CYCLES_PER_RAM_READ, true); - -// state + u32:1 -// } -// } diff --git a/xls/modules/zstd/match_finder.x b/xls/modules/zstd/match_finder.x new file mode 100644 index 0000000000..096c283719 --- /dev/null +++ b/xls/modules/zstd/match_finder.x @@ -0,0 +1,1305 @@ +// Copyright 2024-2025 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 contains implementation of MatchFinder +// +// # Match Finder Processing Logic +// +// 1. If the symbol is already in the hash table (i.e., it was seen before), then: +// 1.1 Compare the sequence in the history buffer (starting after the previous occurrence of the symbol) +// with the current sequence in memory. +// 1.2 If a match is found (i.e., the sequences are equal up to some point), +// and the match is at least as long as the configured minimum: +// 1.2.1 Emit a sequence (A, B, C) where: +// A - literals collected since the last match +// B - offset of the match (from the hash table) +// C - length of the match +// +// 2. If no valid match is found (either not long enough or the symbol is new), +// add the current symbol to the hash table. +// +// 3. Copy all processed symbols from memory into the history buffer. +// +// 4. After processing the last symbol, if it wasn’t part of a match, +// emit a final sequence for the remaining (trailing) literals. +// --- +// +// ## Example +// +// - Minimum match length: 3 +// - Input symbols: [1, 2, 8, 5, 6, 1, 8, 5, 6, 9] +// +// 1. The first few symbols are all new, so they are added to literals. +// - Literals: [1, 2, 8, 5, 6] +// - Sequences: [] +// +// 2. At index 5, the symbol `1` is seen again. +// - Check for a match in the history buffer: +// - History: [1, 2, 8, 5, 6], current: [1, 8, 5, 6...] +// - Only the first symbol matches (match length = 1), which is below the minimum. +// - So, `1` is added to literals. +// - Literals: [1, 2, 8, 5, 6, 1] +// - Sequences: [] +// +// 3. At index 6, the symbol `8` is seen again. +// - Matching sequence found: [8, 5, 6] (length = 3) +// - A sequence is emitted: +// - Offset: 6 (index of current `8`) +// - Match start: index 3 (prior occurrence of `8`) +// - Match length: 3 +// - Literals: [1, 2, 8, 5, 6, 1] +// - Sequences: [(6, 4, 3)] +// +// 4. At index 9, symbol `9` is new and added to literals. +// - It's the last symbol, so trailing literals are flushed. +// - A dummy sequence is added to mark the trailing literal. +// - Literals: [1, 2, 8, 5, 6, 1, 9] +// - Sequences: [(6, 4, 3), (1, 0, 0)] +// +// NOTE: assumes DATA_W <= SEQUENCE_RECORD_W + +import std; + +import xls.examples.ram; +import xls.modules.zstd.common; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.axi_ram_reader; +import xls.modules.zstd.memory.axi_ram_writer; +import xls.modules.zstd.history_buffer; +import xls.modules.zstd.hash_table; +import xls.modules.zstd.aligned_parallel_ram; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.sequence_encoder; +import xls.modules.zstd.memory.mem_writer_data_downscaler; + +const KEY_WIDTH = common::SYMBOL_WIDTH; +const DEFAULT_HT_KEY_W = u32:32; +const DEFAULT_HB_DATA_W = u32:64; +const WIDER_BUS_DATA_W = u32:64; + +pub struct ZstdParams { + num_entries_log2: uN[HT_SIZE_W], +} + +pub enum MatchFinderRespStatus : u1 { + OK = 0, + ERROR = 1, +} + +pub struct MatchFinderReq { + input_addr: uN[ADDR_W], + input_size: uN[ADDR_W], + output_lit_addr: uN[ADDR_W], + output_seq_addr: uN[ADDR_W], + zstd_params: ZstdParams, +} + +pub struct MatchFinderResp { + status: MatchFinderRespStatus, // indicate the state of the operation + lit_cnt: u32, // number of literals + seq_cnt: u32, // number of sequences +} + +struct MatchFinderInternalLoopState< + ADDR_W: u32, + HT_SIZE_W: u32, +> { + active: bool, + lit_addr_offset: uN[ADDR_W], + seq_addr_offset: uN[ADDR_W], + lit_cnt: u32, + seq_cnt: u32, + lit_since_last_sequence: u32, + hb_entry_cnt: u32, + + current_input_addr: uN[ADDR_W], + output_lit_addr: uN[ADDR_W], + output_seq_addr: uN[ADDR_W], + num_entries_log2: uN[HT_SIZE_W], + remaining_size: uN[ADDR_W], +} + +struct MatchFinderInternalHistoryCompareConf< + ADDR_W: u32, + HB_OFFSET_W: u32 +>{ + current_hb_offset: uN[HB_OFFSET_W], + current_input_addr: uN[ADDR_W], +} + +struct MatchFinderInternalHistoryCompareResp{ + match_found: bool, + match_length: u32, + last: bool +} + +struct MatchFinderInternalHistoryCompareState< + ADDR_W: u32, + HB_OFFSET_W: u32 +> { + active: bool, + conf: MatchFinderInternalHistoryCompareConf, + match_length: u32, +} + +struct MatchFinderInternalLiteralCopyConf { + input_addr: uN[ADDR_W], + output_addr: uN[ADDR_W], + size: uN[ADDR_W], + move_literals: bool, +} + +struct MatchFinderInternalLiteralCopyState { + active: bool, + conf: MatchFinderInternalLiteralCopyConf, +} + +struct MatchFinderInternalLiteralCopyResp { + addr: uN[ADDR_W] +} + + +proc MatchFinderInternalLiteralCopy< + ADDR_W: u32, DATA_W: u32, HB_SIZE: u32, MIN_SEQ_LEN: u32, + HB_DATA_W: u32 = {DEFAULT_HB_DATA_W}, + HB_OFFSET_W: u32 = {std::clog2(HB_SIZE)} +> +{ + type State = MatchFinderInternalLiteralCopyState; + type Config = MatchFinderInternalLiteralCopyConf; + type Resp = MatchFinderInternalLiteralCopyResp; + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type NarrowMemWriterDataPacket = mem_writer::MemWriterDataPacket; + type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + + type Addr = uN[ADDR_W]; + + hb_wr_req_s: chan out; + hb_wr_resp_r: chan in; + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + mem_wr_req_s: chan out; + mem_wr_packet_s: chan out; + mem_wr_resp_r: chan in; + conf_r: chan in; + resp_s: chan out; + + init { zero!() } + + config( + hb_wr_req_s: chan out, + hb_wr_resp_r: chan in, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + mem_wr_req_s: chan out, + mem_wr_packet_s: chan out, + mem_wr_resp_r: chan in, + conf_r: chan in, + resp_s: chan out, + ) { + ( + hb_wr_req_s, hb_wr_resp_r, + mem_rd_req_s, mem_rd_resp_r, + mem_wr_req_s, mem_wr_packet_s, mem_wr_resp_r, + conf_r, resp_s + ) + } + + next(state: State) { + const KEY_WIDTH_BYTES = KEY_WIDTH as Addr / Addr:8; + let tok = join(); + let conf = state.conf; + + if !state.active { + let (tok, conf) = recv(tok, conf_r); + State { active: true, conf: conf } + } else if conf.size == Addr:0 { + // copy done + let tok = send(tok, resp_s, Resp { addr: state.conf.input_addr }); + zero!() + } else { + let tok = send( + tok, mem_rd_req_s, MemReaderReq { + addr: conf.input_addr, + length: KEY_WIDTH_BYTES + } + ); + + // place in history buffer + let (tok, mem_resp) = recv(tok, mem_rd_resp_r); + let tok = send(tok, hb_wr_req_s, HistoryBufferWrReq { + data: mem_resp.data as uN[HB_DATA_W] + }); + let (tok1, _) = recv(tok, hb_wr_resp_r); + + let status = if conf.move_literals { + // place in literals memory + let tok2 = send(tok, mem_wr_req_s, MemWriterReq { + addr: conf.output_addr, + length: KEY_WIDTH_BYTES + }); + let tok2 = send(tok, mem_wr_packet_s, MemWriterDataPacket { + data: mem_resp.data as uN[HB_DATA_W], + length: KEY_WIDTH_BYTES, + last: true + }); + let (tok2, resp) = recv(tok, mem_wr_resp_r); + trace_fmt!("|- writing literal value {:#x} at {:#x} -> {:#x} [{}]", mem_resp.data, conf.input_addr, conf.output_addr, resp.status); + resp.status + } else { + mem_writer::MemWriterRespStatus::OKAY + }; + + State { + active: status == mem_writer::MemWriterRespStatus::OKAY, + conf: Config{ + input_addr: conf.input_addr + KEY_WIDTH_BYTES, + output_addr: conf.output_addr + KEY_WIDTH_BYTES, + size: conf.size - KEY_WIDTH_BYTES, + ..conf + } + } + } + + } +} +proc MatchFinderInternalHistoryCompare< + ADDR_W: u32, DATA_W: u32, HB_SIZE: u32, MIN_SEQ_LEN: u32, + HB_DATA_W: u32 = {DEFAULT_HB_DATA_W}, + HB_OFFSET_W: u32 = {std::clog2(HB_SIZE)}, +>{ + type State = MatchFinderInternalHistoryCompareState; + type Config = MatchFinderInternalHistoryCompareConf; + type Resp = MatchFinderInternalHistoryCompareResp; + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type NarrowMemWriterDataPacket = mem_writer::MemWriterDataPacket; + type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type Addr = uN[ADDR_W]; + + hb_rd_req_s: chan out; + hb_rd_resp_r: chan in; + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + conf_r: chan in; + resp_s: chan out; + + init {zero!()} + config( + hb_rd_req_s: chan out, + hb_rd_resp_r: chan in, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + conf_r: chan in, + resp_s: chan out, + ) { + ( + hb_rd_req_s, hb_rd_resp_r, + mem_rd_req_s, mem_rd_resp_r, + conf_r, resp_s + ) + } + + next(state: State) { + const KEY_WIDTH_BYTES = KEY_WIDTH as Addr / Addr:8; + const HB_DATA_BYTES = HB_DATA_W / u32:8; + + let tok = join(); + if !state.active { + let (tok, conf) = recv(tok, conf_r); + State { + active: true, + match_length: u32:1, + conf: conf, + } + + } else { + let tok = send( + tok, mem_rd_req_s, MemReaderReq { + addr: state.conf.current_input_addr, + length: KEY_WIDTH_BYTES + } + ); + let (tok, mem_resp) = recv(tok, mem_rd_resp_r); + + let tok = send(tok, hb_rd_req_s, HistoryBufferRdReq { + offset: state.conf.current_hb_offset, + }); + + let (tok, hb_resp) = recv(tok, hb_rd_resp_r); + + trace_fmt!("comparing {:#x} ({:#x})=={:#x}", hb_resp.data, state.conf.current_hb_offset, mem_resp.data); + + let diff = hb_resp.data != mem_resp.data as uN[HB_DATA_W] || state.conf.current_hb_offset == uN[HB_OFFSET_W]:0; + let match_length_increment_cornercase = if state.conf.current_hb_offset == uN[HB_OFFSET_W]:0 && hb_resp.data == mem_resp.data as uN[HB_DATA_W] { u32:1 } else { u32:0 }; + + let tok = send_if(tok, resp_s, diff, Resp { + match_found: true, + match_length: state.match_length + match_length_increment_cornercase, + last: mem_resp.last + }); + + State { + active: !diff, + match_length: u32:1 + state.match_length, + conf: Config { + current_input_addr: state.conf.current_input_addr + KEY_WIDTH_BYTES, + current_hb_offset: state.conf.current_hb_offset - HB_DATA_BYTES as uN[HB_OFFSET_W], + } + } + } + + } +} + +pub proc MatchFinder< + ADDR_W: u32, DATA_W: u32, HT_SIZE: u32, HB_SIZE: u32, MIN_SEQ_LEN: u32, + DATA_W_LOG2: u32 = {std::clog2(DATA_W + u32:1)}, + + HT_KEY_W: u32 = {DEFAULT_HT_KEY_W}, + HT_VALUE_W: u32 = {HT_KEY_W + ADDR_W}, + HT_SIZE_W: u32 = {std::clog2(HT_SIZE + u32:1)}, + + HB_DATA_W: u32 = {DEFAULT_HB_DATA_W}, + HB_OFFSET_W: u32 = {std::clog2(HB_SIZE)}, +> { + type State = MatchFinderInternalLoopState; + type Resp = MatchFinderResp; + type Req = MatchFinderReq; + type RespStatus = MatchFinderRespStatus; + + type HistoryCompareConfig = MatchFinderInternalHistoryCompareConf; + type HistoryCompareResp = MatchFinderInternalHistoryCompareResp; + type HistoryCompareConfig = MatchFinderInternalHistoryCompareConf; + type CopyConfig = MatchFinderInternalLiteralCopyConf; + type CopyResp = MatchFinderInternalLiteralCopyResp; + + type HashTableRdReq = hash_table::HashTableReadReq; + type HashTableRdResp = hash_table::HashTableReadResp; + type HashTableWrReq = hash_table::HashTableWriteReq; + type HashTableWrResp = hash_table::HashTableWriteResp; + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type NarrowMemWriterDataPacket = mem_writer::MemWriterDataPacket; + type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + + type Addr = uN[ADDR_W]; + + ht_rd_req_s: chan out; + ht_rd_resp_r: chan in; + ht_wr_req_s: chan out; + ht_wr_resp_r: chan in; + + mem_wr_req_s: chan out; + mem_wr_packet_s: chan out; + mem_wr_resp_r: chan in; + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + + req_r: chan in; + resp_s: chan out; + + hb_mlen_conf_s: chan out; + hb_mlen_resp_r: chan in; + copy_conf_s: chan out; + copy_resp_r: chan in; + + init { zero!() } + + config( + req_r: chan in, + resp_s: chan out, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + mem_wr_req_s: chan out, + mem_wr_packet_s: chan out, + mem_wr_resp_r: chan in, + ht_rd_req_s: chan out, + ht_rd_resp_r: chan in, + ht_wr_req_s: chan out, + ht_wr_resp_r: chan in, + hb_rd_req_s: chan out, + hb_rd_resp_r: chan in, + hb_wr_req_s: chan out, + hb_wr_resp_r: chan in, + ) { + let (hb_mlen_conf_s, hb_reader_conf_r) = chan("hb_reader_conf"); + let (hb_reader_resp_s, hb_mlen_resp_r) = chan("hb_reader_resp"); + let (copy_conf_s, copy_conf_r) = chan("copy_conf"); + let (copy_resp_s, copy_resp_r) = chan("copy_resp"); + + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[2]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[2]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[2]("n_resp"); + + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[3]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[3]("n_mem_rd_resp"); + + let (wider_mem_wr_packet_s, wider_mem_wr_packet_r) = chan("wider_mem_wr_packet"); + + spawn mem_writer_data_downscaler::MemWriterDataDownscaler< + ADDR_W, WIDER_BUS_DATA_W, DATA_W, + > (wider_mem_wr_packet_r, mem_wr_packet_s); + + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, wider_mem_wr_packet_s, mem_wr_resp_r, + ); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn MatchFinderInternalHistoryCompare< + ADDR_W, DATA_W, + HB_SIZE, MIN_SEQ_LEN, + > + ( + hb_rd_req_s, hb_rd_resp_r, + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + hb_reader_conf_r, hb_reader_resp_s, + ); + + spawn MatchFinderInternalLiteralCopy< + ADDR_W, DATA_W, + HB_SIZE, MIN_SEQ_LEN, + > + ( + hb_wr_req_s, hb_wr_resp_r, + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + copy_conf_r, copy_resp_s + ); + + ( + ht_rd_req_s, ht_rd_resp_r, + ht_wr_req_s, ht_wr_resp_r, + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + req_r, resp_s, + hb_mlen_conf_s, hb_mlen_resp_r, + copy_conf_s, copy_resp_r + ) + } + + next(state: State) { + const KEY_WIDTH_BYTES = KEY_WIDTH as Addr / Addr:8; + const HB_DATA_BYTES = HB_DATA_W / u32:8; + const SEQUENCE_RECORD_B = sequence_encoder::SEQUENCE_RECORD_W / u32:8; + let tok = join(); + + if !state.active { + let (tok, req) = recv(tok, req_r); + trace_fmt!("Started encoding"); + State { + active: true, + output_lit_addr: req.output_lit_addr, + output_seq_addr: req.output_seq_addr, + current_input_addr: req.input_addr, + num_entries_log2: req.zstd_params.num_entries_log2, + remaining_size: req.input_size, + ..zero!() + } + } else if state.remaining_size == uN[ADDR_W]:0 { + // https://datatracker.ietf.org/doc/html/rfc8878#name-sequences_section + // When all sequences are decoded, if there are literals left in the Literals_Section, these bytes are added at the end of the block. + trace_fmt!("Literals left ({}, {}, {})", state.lit_since_last_sequence, u32:0, u32:0); + trace_fmt!("Encoding finished"); + let tok = send(tok, resp_s, Resp { + status: RespStatus::OK, + lit_cnt: state.lit_cnt, + seq_cnt: state.seq_cnt, + }); + zero!() + } else { + let tok = send( + tok, mem_rd_req_s, MemReaderReq { + addr: state.current_input_addr, + length: KEY_WIDTH_BYTES + } + ); + let (tok, resp) = recv(tok, mem_rd_resp_r); + let ht_key = resp.data as uN[HT_KEY_W]; + + // Step 1: read from hashtable and check if there's a match (+ corner cases) + let tok = send(tok, ht_rd_req_s, HashTableRdReq { + num_entries_log2: state.num_entries_log2, + key: ht_key, + }); + let (tok, ht_rd_resp) = recv(tok, ht_rd_resp_r); + let matched = ht_rd_resp.is_match && + resp.data == (ht_rd_resp.value >> ADDR_W) as uN[DATA_W] && + state.current_input_addr - ht_rd_resp.value as Addr > KEY_WIDTH_BYTES; + + // Step 2: compute history buffer offset and get match length + let offset = ((state.current_input_addr - (ht_rd_resp.value as Addr)) as uN[HB_OFFSET_W] - uN[HB_OFFSET_W]:2) * HB_DATA_BYTES as uN[HB_OFFSET_W]; + + // cornercase: prevent inter-block matches + let matched = matched && offset as u32 < HB_DATA_BYTES * state.hb_entry_cnt; + + let tok = send_if(tok, hb_mlen_conf_s, matched, HistoryCompareConfig { + current_hb_offset: offset, + current_input_addr: state.current_input_addr + KEY_WIDTH_BYTES, + }); + let (tok, cmp_resp) = recv_if(tok, hb_mlen_resp_r, matched, HistoryCompareResp { + match_length: Addr:1, + ..zero!() + }); + + // Step 3: compute parameters for sequence and write it if it's long enough + let encode_sequence = cmp_resp.match_length >= MIN_SEQ_LEN && matched; + let match_offset = offset / HB_DATA_BYTES as uN[HB_OFFSET_W] + uN[HB_OFFSET_W]:2; + + let tok3 = send_if(tok, mem_wr_req_s, encode_sequence, MemWriterReq { + addr: state.seq_addr_offset + state.output_seq_addr, + length: SEQUENCE_RECORD_B, + }); + + let seq_bytes = sequence_encoder::serialize_sequence( + sequence_encoder::Sequence { + literals_len: state.lit_since_last_sequence as u16, + // https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.3.2.1.1 + // match length code is incremented by 3 when decoding (TODO: make sure baselines are handled correctly) + match_len: cmp_resp.match_length as u16 - u16:3, + // https://datatracker.ietf.org/doc/html/rfc8878#name-sequence-execution + // if Offset_Value > 3, then the offset is Offset_Value - 3 => offset += 3 (we don't use repeat offsets for now) + offset: match_offset as u16 + u16:3 + } + ) as uN[WIDER_BUS_DATA_W]; + + let tok3 = send_if(tok3, mem_wr_packet_s, encode_sequence, MemWriterDataPacket { + data: seq_bytes, + length: SEQUENCE_RECORD_B, + last: true, + }); + let (tok3, wr_resp) = recv_if(tok3, mem_wr_resp_r, encode_sequence, zero!()); + if encode_sequence { + trace_fmt!("|- writing sequence ({}, {}, {}) (serialized: {:#x}), at {:#x} [{}], hb offset was {}", + state.lit_since_last_sequence, match_offset, cmp_resp.match_length, seq_bytes, + state.seq_addr_offset + state.output_seq_addr,wr_resp.status, offset + ); + } else {}; + + // Step 4: copy processed literals to history buffer (and literals memory if sequence wasn't written) + let copy_conf = CopyConfig { + input_addr: state.current_input_addr, + output_addr: state.lit_addr_offset + state.output_lit_addr, + size: cmp_resp.match_length * KEY_WIDTH_BYTES, + move_literals: !encode_sequence + }; + let tok4 = send(tok, copy_conf_s, copy_conf); + let (tok4, copy_resp) = recv(tok4, copy_resp_r); + + // Step 5: write current data in hashtable + let tok5 = send(tok, ht_wr_req_s, HashTableWrReq { + num_entries_log2: state.num_entries_log2, + key: ht_key, + value: ( + (ht_key) ++ + (state.current_input_addr) + ), + }); + let (tok5, ht_wr_resp) = recv(tok, ht_wr_resp_r); + let tok = join(tok3, tok4, tok5); + // Step 6: compute next iteration parameters + let address_increment = KEY_WIDTH_BYTES * cmp_resp.match_length; + let lit_cnt_increment = if encode_sequence { uN[ADDR_W]:0 } else { cmp_resp.match_length }; + let lit_address_increment = if encode_sequence { uN[ADDR_W]:0 } else { KEY_WIDTH_BYTES * cmp_resp.match_length }; + let seq_address_increment = if encode_sequence { SEQUENCE_RECORD_B } else { uN[ADDR_W]:0 }; + let seq_cnt_increment = encode_sequence as Addr; // if encode_sequence: seq_cnt ++ + let lit_since_last_sequence = if encode_sequence { Addr:0 } else { state.lit_since_last_sequence + cmp_resp.match_length }; + let remaining_size = if state.remaining_size < address_increment { u32:0 } else { state.remaining_size - address_increment }; + let hb_entry_cnt = state.hb_entry_cnt + cmp_resp.match_length as u32; + + State { + active: true, + current_input_addr: copy_resp.addr, + remaining_size: remaining_size, + lit_addr_offset: state.lit_addr_offset + lit_address_increment, + lit_cnt: state.lit_cnt + lit_cnt_increment, + lit_since_last_sequence: lit_since_last_sequence, + seq_addr_offset: state.seq_addr_offset + seq_address_increment, + seq_cnt: state.seq_cnt + seq_cnt_increment, + hb_entry_cnt: hb_entry_cnt, + ..state + } + } + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; +const INST_MIN_SEQ_LEN = u32:3; +const INST_DATA_W_LOG2 = std::clog2(INST_DATA_W + u32:1); + +const INST_HT_SIZE = u32:512; +const INST_HT_SIZE_W = std::clog2(INST_HT_SIZE + u32:1); +const INST_HT_KEY_W = u32:32; +const INST_HT_VALUE_W = INST_HT_KEY_W + INST_ADDR_W; // original symbol + address +const INST_HB_DATA_W = u32:64; +const INST_HB_SIZE = u32:1024; +const INST_HB_OFFSET_W = std::clog2(INST_HB_SIZE); + +proc MatchFinderInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type NarrowMemWriterDataPacket = mem_writer::MemWriterDataPacket; + + type HashTableRdReq = hash_table::HashTableReadReq; + type HashTableRdResp = hash_table::HashTableReadResp; + type HashTableWrReq = hash_table::HashTableWriteReq; + type HashTableWrResp = hash_table::HashTableWriteResp; + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + + type Req = MatchFinderReq; + type Resp = MatchFinderResp; + + config ( + // Req & Resp + req_r: chan in, + resp_s: chan out, + + // Access to input + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + + // Output + mem_wr_req_s: chan out, + mem_wr_packet_s: chan out, + mem_wr_resp_r: chan in, + + // HashTable RAM interface + ht_rd_req_s: chan out, + ht_rd_resp_r: chan in, + ht_wr_req_s: chan out, + ht_wr_resp_r: chan in, + + // HistoryBuffer RAM interface + hb_rd_req_s: chan out, + hb_rd_resp_r: chan in, + hb_wr_req_s: chan out, + hb_wr_resp_r: chan in, + ) { + spawn MatchFinder< + INST_ADDR_W, INST_DATA_W, INST_HT_SIZE, INST_HB_SIZE, INST_MIN_SEQ_LEN, + INST_DATA_W_LOG2, + INST_HT_KEY_W, INST_HT_VALUE_W, INST_HT_SIZE_W, + INST_HB_DATA_W, INST_HB_OFFSET_W, + >( + req_r, resp_s, + mem_rd_req_s, mem_rd_resp_r, + mem_wr_req_s, mem_wr_packet_s, mem_wr_resp_r, + ht_rd_req_s, ht_rd_resp_r, ht_wr_req_s, ht_wr_resp_r, + hb_rd_req_s, hb_rd_resp_r, hb_wr_req_s, hb_wr_resp_r, + ); + } + + init {} + + next (state: ()) {} +} + +const COCOTB_ADDR_W = u32:32; +const COCOTB_DATA_W = u32:64; +const COCOTB_MIN_SEQ_LEN = u32:3; +const COCOTB_DATA_W_LOG2 = std::clog2(COCOTB_DATA_W + u32:1); +const COCOTB_DEST_W = u32:8; +const COCOTB_ID_W = u32:8; + +const COCOTB_HT_SIZE = u32:512; +const COCOTB_HT_SIZE_W = std::clog2(COCOTB_HT_SIZE + u32:1); +const COCOTB_HT_KEY_W = u32:32; +const COCOTB_HT_VALUE_W = COCOTB_HT_KEY_W + COCOTB_ADDR_W; +const COCOTB_HT_HASH_W = std::clog2(COCOTB_HT_SIZE); +const COCOTB_HT_RAM_DATA_W = COCOTB_HT_VALUE_W + u32:1; +const COCOTB_HT_RAM_WORD_PARTITION_SIZE = u32:1; +const COCOTB_HT_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_HT_RAM_WORD_PARTITION_SIZE, COCOTB_HT_RAM_DATA_W); +const COCOTB_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const COCOTB_HT_RAM_INITIALIZED = true; + +const COCOTB_HB_DATA_W = u32:64; +const COCOTB_HB_SIZE = u32:1024; +const COCOTB_HB_OFFSET_W = std::clog2(COCOTB_HB_SIZE); +const COCOTB_HB_RAM_NUM = u32:8; +const COCOTB_HB_RAM_SIZE = COCOTB_HB_SIZE / COCOTB_HB_RAM_NUM; +const COCOTB_HB_RAM_DATA_W = COCOTB_HB_DATA_W / COCOTB_HB_RAM_NUM; +const COCOTB_HB_RAM_ADDR_W = std::clog2(COCOTB_HB_RAM_SIZE); +const COCOTB_HB_RAM_PARTITION_SIZE = COCOTB_HB_RAM_DATA_W; +const COCOTB_HB_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_HB_RAM_PARTITION_SIZE, COCOTB_HB_RAM_DATA_W); +const COCOTB_HB_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const COCOTB_HB_RAM_INITIALIZED = true; + +const COCOTB_RAM_DATA_W = COCOTB_DATA_W; +const COCOTB_RAM_SIZE = u32:2048; +const COCOTB_RAM_ADDR_W = COCOTB_ADDR_W; +const COCOTB_RAM_PARTITION_SIZE = COCOTB_RAM_DATA_W / u32:8; +const COCOTB_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_RAM_PARTITION_SIZE, COCOTB_RAM_DATA_W); +const COCOTB_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const COCOTB_RAM_INITIALIZED = true; +const COCOTB_RAM_ASSERT_VALID_READ = true; + +proc MatchFinderCocotbInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + type HashTableRdReq = hash_table::HashTableReadReq; + type HashTableRdResp = hash_table::HashTableReadResp; + type HashTableWrReq = hash_table::HashTableWriteReq; + type HashTableWrResp = hash_table::HashTableWriteResp; + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + type Req = MatchFinderReq; + type Resp = MatchFinderResp; + + config ( + // Req & Resp + req_r: chan in, + resp_s: chan out, + // External AXI bussies + axi_aw_s: chan out, + axi_w_s: chan out, + axi_b_r: chan in, + axi_ar_s: chan out, + axi_r_r: chan in, + // hash table + ht_ram_rd_req_s: chan out, + ht_ram_rd_resp_r: chan in, + ht_ram_wr_req_s: chan out, + ht_ram_wr_resp_r: chan in, + // history buffer + hb_ram_rd_req_s: chan[8] out, + hb_ram_rd_resp_r: chan[8] in, + hb_ram_wr_req_s: chan[8] out, + hb_ram_wr_resp_r: chan[8] in, + ) { + let (ht_rd_req_s, ht_rd_req_r) = chan("ht_rd_req"); + let (ht_rd_resp_s, ht_rd_resp_r) = chan("ht_rd_resp"); + let (ht_wr_req_s, ht_wr_req_r) = chan("ht_wr_req"); + let (ht_wr_resp_s, ht_wr_resp_r) = chan("ht_wr_resp"); + let (hb_rd_req_s, hb_rd_req_r) = chan("hb_rd_req"); + let (hb_rd_resp_s, hb_rd_resp_r) = chan("hb_rd_resp"); + let (hb_wr_req_s, hb_wr_req_r) = chan("hb_wr_req"); + let (hb_wr_resp_s, hb_wr_resp_r) = chan("hb_wr_resp"); + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + + spawn hash_table::HashTable( + ht_rd_req_r, ht_rd_resp_s, + ht_wr_req_r, ht_wr_resp_s, + ht_ram_rd_req_s, ht_ram_rd_resp_r, + ht_ram_wr_req_s, ht_ram_wr_resp_r, + ); + + spawn history_buffer::HistoryBuffer( + hb_rd_req_r, hb_rd_resp_s, + hb_wr_req_r, hb_wr_resp_s, + hb_ram_rd_req_s, hb_ram_rd_resp_r, + hb_ram_wr_req_s, hb_ram_wr_resp_r, + ); + + spawn mem_reader::MemReader< + COCOTB_DATA_W, COCOTB_ADDR_W, COCOTB_DEST_W, COCOTB_ID_W + >( + mem_rd_req_r, mem_rd_resp_s, + axi_ar_s, axi_r_r, + ); + + spawn mem_writer::MemWriter< + COCOTB_ADDR_W, COCOTB_DATA_W, COCOTB_DEST_W, COCOTB_ID_W, u32:0 + >( + mem_wr_req_r, mem_wr_data_r, + axi_aw_s, axi_w_s, axi_b_r, + mem_wr_resp_s + ); + + spawn MatchFinder< + COCOTB_ADDR_W, COCOTB_DATA_W, COCOTB_HT_SIZE, COCOTB_HB_SIZE, COCOTB_MIN_SEQ_LEN, + COCOTB_DATA_W_LOG2, + COCOTB_HT_KEY_W, COCOTB_HT_VALUE_W, COCOTB_HT_SIZE_W, + COCOTB_HB_DATA_W, COCOTB_HB_OFFSET_W, + >( + req_r, resp_s, + mem_rd_req_s, mem_rd_resp_r, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ht_rd_req_s, ht_rd_resp_r, ht_wr_req_s, ht_wr_resp_r, + hb_rd_req_s, hb_rd_resp_r, hb_wr_req_s, hb_wr_resp_r, + ); + } + + init {} + next (state: ()) { } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:64; +const TEST_MIN_SEQ_LEN = u32:3; +const TEST_HT_SIZE = u32:512; +const TEST_HB_SIZE = u32:1024; +const TEST_DATA_W_LOG2 = std::clog2(TEST_DATA_W + u32:1); +const TEST_DEST_W = u32:8; +const TEST_ID_W = u32:8; + +const TEST_HT_KEY_W = u32:32; // TODO: hash computation doesn't work properly for smaller keys +const TEST_HT_VALUE_W = TEST_HT_KEY_W + TEST_ADDR_W; // original symbol + address +const TEST_HT_HASH_W = std::clog2(TEST_HT_SIZE); +const TEST_HT_RAM_DATA_W = TEST_HT_VALUE_W + u32:1; // value + valid +const TEST_HT_RAM_WORD_PARTITION_SIZE = u32:1; +const TEST_HT_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_HT_RAM_WORD_PARTITION_SIZE, TEST_HT_RAM_DATA_W); +const TEST_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_HT_RAM_INITIALIZED = true; +const TEST_HT_SIZE_W = std::clog2(TEST_HT_SIZE + u32:1); + +const TEST_HB_RAM_NUM = u32:8; +const TEST_HB_DATA_W = u32:64; +const TEST_HB_OFFSET_W = std::clog2(TEST_HB_SIZE); +const TEST_HB_RAM_SIZE = TEST_HB_SIZE / TEST_HB_RAM_NUM; +const TEST_HB_RAM_DATA_W = TEST_HB_DATA_W / TEST_HB_RAM_NUM; +const TEST_HB_RAM_ADDR_W = std::clog2(TEST_HB_RAM_SIZE); +const TEST_HB_RAM_PARTITION_SIZE = TEST_HB_RAM_DATA_W; +const TEST_HB_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_HB_RAM_PARTITION_SIZE, TEST_HB_RAM_DATA_W); +const TEST_HB_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_HB_RAM_INITIALIZED = true; + +const TEST_RAM_DATA_W = TEST_DATA_W; +const TEST_RAM_SIZE = u32:2048; +const TEST_RAM_ADDR_W = TEST_ADDR_W; +const TEST_RAM_PARTITION_SIZE = TEST_RAM_DATA_W / u32:8; +const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W); +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; +const TEST_RAM_ASSERT_VALID_READ = true; + +const TEST_OUTPUT_LIT_ADDR = uN[TEST_ADDR_W]:0x100; +const TEST_OUTPUT_SEQ_ADDR = uN[TEST_ADDR_W]:0x200; + +const TEST_DATA = [ + u8:0x1, + u8:0xA, + u8:0xB, + u8:0xC, + u8:0x1, + u8:0x2, + u8:0x1, + u8:0x4, + u8:0xA, + u8:0xB, + u8:0xC, + u8:0x5, + u8:0xA, + u8:0xB, + u8:0xC, + u8:0x9, +]; + +#[test_proc] +proc MatchFinderTest { + // Memory Reader + Input + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type InputBufferRamRdReq = ram::ReadReq; + type InputBufferRamRdResp = ram::ReadResp; + type InputBufferRamWrReq = ram::WriteReq; + type InputBufferRamWrResp = ram::WriteResp; + + type OutputBufferRamRdReq = ram::ReadReq; + type OutputBufferRamRdResp = ram::ReadResp; + type OutputBufferRamWrReq = ram::WriteReq; + type OutputBufferRamWrResp = ram::WriteResp; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + // Memory Writer + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + // Hash Table + + type HashTableRdReq = hash_table::HashTableReadReq; + type HashTableRdResp = hash_table::HashTableReadResp; + type HashTableWrReq = hash_table::HashTableWriteReq; + type HashTableWrResp = hash_table::HashTableWriteResp; + + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + + // History Buffer + + type HistoryBufferRdReq = history_buffer::HistoryBufferReadReq; + type HistoryBufferRdResp = history_buffer::HistoryBufferReadResp; + type HistoryBufferWrReq = history_buffer::HistoryBufferWriteReq; + type HistoryBufferWrResp = history_buffer::HistoryBufferWriteResp; + + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + + // Match Finder + + type Req = MatchFinderReq; + type Resp = MatchFinderResp; + + // Other + + type NumEntriesLog2 = uN[TEST_HT_SIZE_W]; + type RamAddr = uN[TEST_RAM_ADDR_W]; + type RamMask = uN[TEST_RAM_NUM_PARTITIONS]; + + terminator: chan out; + + req_s: chan out; + resp_r: chan in; + + + input_mem_wr_req_s: chan out; + input_mem_wr_data_s: chan out; + input_mem_wr_resp_r: chan in; + output_rd_req_s: chan out; + output_rd_resp_r: chanin; + + config(terminator: chan out) { + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + // procs + let (ht_ram_rd_req_s, ht_ram_rd_req_r) = chan("ht_ram_rd_req"); + let (ht_ram_rd_resp_s, ht_ram_rd_resp_r) = chan("ht_ram_rd_resp"); + let (ht_ram_wr_req_s, ht_ram_wr_req_r) = chan("ht_ram_wr_req"); + let (ht_ram_wr_resp_s, ht_ram_wr_resp_r) = chan("ht_ram_wr_resp"); + let (ht_rd_req_s, ht_rd_req_r) = chan("ht_rd_req"); + let (ht_rd_resp_s, ht_rd_resp_r) = chan("ht_rd_resp"); + let (ht_wr_req_s, ht_wr_req_r) = chan("ht_wr_req"); + let (ht_wr_resp_s, ht_wr_resp_r) = chan("ht_wr_resp"); + let (hb_rd_req_s, hb_rd_req_r) = chan("hb_rd_req"); + let (hb_rd_resp_s, hb_rd_resp_r) = chan("hb_rd_resp"); + let (hb_wr_req_s, hb_wr_req_r) = chan("hb_wr_req"); + let (hb_wr_resp_s, hb_wr_resp_r) = chan("hb_wr_resp"); + // rams + let (hb_ram_rd_req_s, hb_ram_rd_req_r) = chan[8]("hb_ram_rd_req"); + let (hb_ram_rd_resp_s, hb_ram_rd_resp_r) = chan[8]("hb_ram_rd_resp"); + let (hb_ram_wr_req_s, hb_ram_wr_req_r) = chan[8]("hb_ram_wr_req"); + let (hb_ram_wr_resp_s, hb_ram_wr_resp_r) = chan[8]("hb_ram_wr_resp"); + let (input_ram_rd_req_s, input_ram_rd_req_r) = chan("input_ram_rd_req"); + let (input_ram_rd_resp_s, input_ram_rd_resp_r) = chan("input_ram_rd_resp"); + let (input_ram_wr_req_s, input_ram_wr_req_r) = chan("input_ram_wr_req"); + let (input_ram_wr_resp_s, input_ram_wr_resp_r) = chan("input_ram_wr_resp"); + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (output_wr_req_s, output_wr_req_r) = chan("output_wr_req"); + let (output_wr_resp_s, output_wr_resp_r) = chan("output_wr_resp"); + // axi + let (input_axi_ar_s, input_axi_ar_r) = chan("input_axi_ar"); + let (input_axi_r_s, input_axi_r_r) = chan("input_axi_r"); + let (input_axi_aw_s, input_axi_aw_r) = chan("input_axi_aw"); + let (input_axi_w_s, input_axi_w_r) = chan("input_axi_w"); + let (input_axi_b_s, input_axi_b_r) = chan("input_axi_b"); + let (output_axi_aw_s, output_axi_aw_r) = chan("output_axi_aw"); + let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); + let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); + let (input_mem_rd_req_s, input_mem_rd_req_r) = chan("input_mem_rd_req"); + let (input_mem_rd_resp_s,input_mem_rd_resp_r) = chan("input_mem_rd_resp"); + let (input_mem_wr_req_s, input_mem_wr_req_r) = chan("input_mem_wr_req"); + let (input_mem_wr_data_s, input_mem_wr_data_r) = chan("input_mem_wr_data"); + let (input_mem_wr_resp_s, input_mem_wr_resp_r) = chan("input_mem_wr_resp"); + let (output_mem_wr_req_s, output_mem_wr_req_r) = chan("output_mem_wr_req"); + let (output_mem_wr_data_s,output_mem_wr_data_r) = chan("output_mem_wr_data"); + let (output_mem_wr_resp_s,output_mem_wr_resp_r) = chan("output_mem_wr_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, + >( + input_ram_rd_req_r, input_ram_rd_resp_s, + input_ram_wr_req_r, input_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, + >( + output_rd_req_r, output_rd_resp_s, + output_wr_req_r, output_wr_resp_s + ); + + spawn ram::RamModel< + TEST_HT_RAM_DATA_W, TEST_HT_SIZE, TEST_HT_RAM_WORD_PARTITION_SIZE, + TEST_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_HT_RAM_INITIALIZED + >( + ht_ram_rd_req_r, ht_ram_rd_resp_s, + ht_ram_wr_req_r, ht_ram_wr_resp_s + ); + + unroll_for! (i, _) : (u32, ()) in u32:0..u32:8 { + spawn ram::RamModel< + TEST_HB_RAM_DATA_W, TEST_HB_RAM_SIZE, TEST_HB_RAM_PARTITION_SIZE, + TEST_HB_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_HB_RAM_INITIALIZED + >( + hb_ram_rd_req_r[i], hb_ram_rd_resp_s[i], + hb_ram_wr_req_r[i], hb_ram_wr_resp_s[i], + ); + }(()); + + spawn axi_ram_reader::AxiRamReader< + TEST_ADDR_W, TEST_DATA_W, + TEST_DEST_W, TEST_ID_W, + TEST_RAM_SIZE, + >( + input_axi_ar_r, input_axi_r_s, + input_ram_rd_req_s, input_ram_rd_resp_r, + ); + + spawn axi_ram_writer::AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, + TEST_ID_W, TEST_RAM_SIZE, TEST_ADDR_W + >( + input_axi_aw_r, input_axi_w_r, input_axi_b_s, + input_ram_wr_req_s, input_ram_wr_resp_r + ); + + spawn axi_ram_writer::AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, + TEST_ID_W, TEST_RAM_SIZE, TEST_ADDR_W + >( + output_axi_aw_r, output_axi_w_r, output_axi_b_s, + output_wr_req_s, output_wr_resp_r + ); + + spawn mem_reader::MemReader< + TEST_DATA_W, TEST_ADDR_W, TEST_DEST_W, TEST_ID_W, + >( + input_mem_rd_req_r, input_mem_rd_resp_s, + input_axi_ar_s, input_axi_r_r, + ); + + spawn mem_writer::MemWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_DEST_W, TEST_ID_W, u32:0 + >( + output_mem_wr_req_r, output_mem_wr_data_r, + output_axi_aw_s, output_axi_w_s, output_axi_b_r, + output_mem_wr_resp_s + ); + + spawn mem_writer::MemWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_DEST_W, TEST_ID_W, u32:0 + >( + input_mem_wr_req_r, input_mem_wr_data_r, + input_axi_aw_s, input_axi_w_s, input_axi_b_r, + input_mem_wr_resp_s + ); + + + spawn hash_table::HashTable( + ht_rd_req_r, ht_rd_resp_s, + ht_wr_req_r, ht_wr_resp_s, + ht_ram_rd_req_s, ht_ram_rd_resp_r, + ht_ram_wr_req_s, ht_ram_wr_resp_r, + ); + + spawn history_buffer::HistoryBuffer( + hb_rd_req_r, hb_rd_resp_s, + hb_wr_req_r, hb_wr_resp_s, + hb_ram_rd_req_s, hb_ram_rd_resp_r, + hb_ram_wr_req_s, hb_ram_wr_resp_r, + ); + + spawn MatchFinder< + TEST_ADDR_W, TEST_DATA_W, TEST_HT_SIZE, TEST_HB_SIZE, TEST_MIN_SEQ_LEN, + TEST_DATA_W_LOG2, + TEST_HT_KEY_W, TEST_HT_VALUE_W, TEST_HT_SIZE_W, + TEST_HB_DATA_W, TEST_HB_OFFSET_W, + >( + req_r, resp_s, + input_mem_rd_req_s, input_mem_rd_resp_r, + output_mem_wr_req_s, output_mem_wr_data_s, output_mem_wr_resp_r, + ht_rd_req_s, ht_rd_resp_r, ht_wr_req_s, ht_wr_resp_r, + hb_rd_req_s, hb_rd_resp_r, hb_wr_req_s, hb_wr_resp_r, + ); + + ( + terminator, + req_s, resp_r, + input_mem_wr_req_s, input_mem_wr_data_s, input_mem_wr_resp_r, + output_rd_req_s, output_rd_resp_r, + ) + } + + init { } + + next(state: ()) { + + let tok = join(); + + // arrange: create input data + let tok = send(tok, input_mem_wr_req_s, MemWriterReq { + addr: RamAddr:0, + length: array_size(TEST_DATA) + }); + + for ((i, test_data), tok) in enumerate(TEST_DATA) { + let ram_wr_req = MemWriterDataPacket { + data: test_data as uN[TEST_DATA_W], + length: RamAddr:1, + last: i == array_size(TEST_DATA) - u32:1 + }; + let tok = send(tok, input_mem_wr_data_s, ram_wr_req); + trace_fmt!("[TEST] Sent #{} data to input RAM {:#x}", i + u32:1, ram_wr_req); + tok + }(tok); + + let (tok, _) = recv(tok, input_mem_wr_resp_r); + + let req = Req { + input_addr: uN[TEST_ADDR_W]:0x0, + input_size: array_size(TEST_DATA) as u32, + output_lit_addr: TEST_OUTPUT_LIT_ADDR, + output_seq_addr: TEST_OUTPUT_SEQ_ADDR, + zstd_params: ZstdParams { + num_entries_log2: NumEntriesLog2:9, + }, + }; + + // act: run match finder + let tok = send(tok, req_s, req); + trace_fmt!("[TEST] Sent request to the MatchFinder: {:#x}", req); + let (tok, resp) = recv(tok, resp_r); + + // assert: literals + assert_eq(resp.lit_cnt, u32:10); + for ((i, expected), tok) in enumerate([ + // <--- l3l2l1 + u64:0x040102010C0B0A01, + u64:0x0905 + + ]) { + let tok = send(tok, output_rd_req_s, OutputBufferRamRdReq { + addr: TEST_OUTPUT_LIT_ADDR / RamAddr:8 + i, + mask: uN[8]: 0xFF + }); + + let (tok, resp) = recv(tok, output_rd_resp_r); + if resp.data != expected { + trace_fmt!("[TEST] {:#x} != {:#x} at {:#x}", resp.data, expected, TEST_OUTPUT_LIT_ADDR + i * KEY_WIDTH / u32:8); + } else {}; + assert_eq(resp.data, expected); + tok + }(join()); + + // assert: sequences + assert_eq(resp.seq_cnt, u32:2); + for ((i, expected), tok) in enumerate([ + // legend: + // LL : literals_len, + // MO : match offset, + // ML : match len + + // seq2 seq1 + // MLML LLLL MOMO MLML + u64:0x0000_0008_000A_0000, + // seq2 + // LLLL MOMO + u64:0x0000_0000_0001_0007, + ]) { + let tok = send(tok, output_rd_req_s, OutputBufferRamRdReq { + addr: TEST_OUTPUT_SEQ_ADDR / RamAddr:8 + i, + mask: uN[8]: 0xFF + }); + + let (tok, resp) = recv(tok, output_rd_resp_r); + if resp.data != expected { + trace_fmt!("[TEST] {:#x} != {:#x} at {:#x}", resp.data, expected, TEST_OUTPUT_LIT_ADDR + i * KEY_WIDTH / u32:8); + } else {}; + assert_eq(resp.data, expected); + tok + }(join()); + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/match_finder_cocotb_test.py b/xls/modules/zstd/match_finder_cocotb_test.py new file mode 100644 index 0000000000..e4420a0cf2 --- /dev/null +++ b/xls/modules/zstd/match_finder_cocotb_test.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# Copyright 2025 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 random +import cocotb +import cocotbext.axi.axi_channels as axi + +from pathlib import Path +from cocotb.clock import Clock +from cocotb.triggers import Event, ClockCycles +from xls.modules.zstd.cocotb.channel import ( + XLSChannel, + XLSChannelDriver, + XLSChannelMonitor, +) +from xls.modules.zstd.cocotb.memory import AxiRamFromArray +from xls.modules.zstd.cocotb.utils import reset, run_test, connect_axi_bus +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct, xls_dataclass + +DATA_W = 64 +ADDR_W = 32 +STATUS_W = 1 +LAST_W = 1 +STATUS_W = 1 +ERROR_W = 1 +ID_W = 4 +DEST_W = 4 +HT_SIZE_W = 10 + +MEM_SIZE = 0x10000 +OBUF_ADDR = 0x2000 +LITERALS_OBUF_ADDR = OBUF_ADDR + 0x1000 +SEQUENCES_OBUF_ADDR = OBUF_ADDR + 0x2000 +INPUT_RANGE = (0, 10) +INPUT_SIZE = 0x1000 + +SEQ_CNT=None +LIT_CNT=None +STATUS=None + +signal_widths = {"bresp": 3} +axi.AxiBBus._signal_widths = signal_widths +axi.AxiBTransaction._signal_widths = signal_widths +axi.AxiBSource._signal_widths = signal_widths +axi.AxiBSink._signal_widths = signal_widths +axi.AxiBMonitor._signal_widths = signal_widths +signal_widths = {"rresp": 3, "rlast": 1} +axi.AxiRBus._signal_widths = signal_widths +axi.AxiRTransaction._signal_widths = signal_widths +axi.AxiRSource._signal_widths = signal_widths +axi.AxiRSink._signal_widths = signal_widths +axi.AxiRMonitor._signal_widths = signal_widths + +@xls_dataclass +class Req(XLSStruct): + input_addr: ADDR_W + input_size: ADDR_W + output_lit_addr: ADDR_W + output_seq_addr: ADDR_W + zstd_params: HT_SIZE_W + +@xls_dataclass +class Resp(XLSStruct): + status: STATUS_W + lit_cnt: 32 + seq_cnt: 32 + +def set_termination_event(monitor, event, transactions): + def terminate_cb(resp): + global SEQ_CNT, LIT_CNT, STATUS + if monitor.stats.received_transactions == transactions: + event.set() + SEQ_CNT = resp.seq_cnt + LIT_CNT = resp.lit_cnt + STATUS = resp.status + monitor.add_callback(terminate_cb) + +def deserialized_sequences(sequences): + def word_from_bytes(bytes, ix): + return int(bytes[ix]) + (int(bytes[ix+1]) << 8) + for i in range(0, len(sequences), 6): + match_length = word_from_bytes(sequences, i) + 3 + step_back = word_from_bytes(sequences, i + 2) - 3 + copy_length = word_from_bytes(sequences, i + 4) + yield (match_length, step_back, copy_length) + +def simple_decode(literals, sequences): + literals_ix = 0 + decoded = [] + for seq in deserialized_sequences(sequences): + (match_length, step_back, copy_length) = seq + print(f"Processing sequence ({seq})...") + for j in range(literals_ix, (literals_ix + copy_length)): + print(f"{hex(len(decoded))} = {hex(literals[j])}") + decoded.append(literals[j]) + matched = [] + current_decoded_len = len(decoded) + for j in range( + current_decoded_len - step_back, + current_decoded_len - (step_back - match_length)): + matched.append(decoded[j]) + print(f"{hex(len(decoded))} = {[hex(ma) for ma in matched]}") + decoded += matched + literals_ix += copy_length + # Append the remaining literals + for i in range(literals_ix, len(literals)): + decoded.append(literals[i]) + + return decoded + +def generate_input_data(): + random.seed(42) # for reproducibility + return bytearray(random.randint(*INPUT_RANGE) for _ in range(INPUT_SIZE)) + + +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def basic_test(dut): + + dut.rst.setimmediatevalue(0) + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + input_data = generate_input_data() + memory = AxiRamFromArray( + connect_axi_bus(dut, "memory"), + dut.clk, dut.rst, + arr=input_data, size=MEM_SIZE + ) + req = Req( + input_addr=0x0, + input_size=INPUT_SIZE, + output_lit_addr=LITERALS_OBUF_ADDR, + output_seq_addr=SEQUENCES_OBUF_ADDR, + zstd_params=9 + ) + + # channels + _ = XLSChannel(dut, "resp_s", dut.clk, start_now=True) + drv_req = XLSChannelDriver(dut, "req_r", dut.clk) + _ = XLSChannelMonitor(dut, "req_r", dut.clk, Req) + mon_resp = XLSChannelMonitor(dut, "resp_s", dut.clk, Resp) + terminate = Event() + set_termination_event(mon_resp, terminate, 1) + + # run benchmark + await reset(dut.clk, dut.rst, cycles=1000) + await cocotb.start(drv_req.send(req)) + await terminate.wait() + + assert STATUS == 0 + await ClockCycles(dut.clk, 1000) # make sure all memory writes finish + + literals = memory.read(LITERALS_OBUF_ADDR, LIT_CNT) + sequences = memory.read(SEQUENCES_OBUF_ADDR, SEQ_CNT * 6) + decoded = simple_decode(literals, sequences) + + all_equal = True + for i in range(0, INPUT_SIZE): + if input_data[i] != decoded[i]: + all_equal = False + print( + f''' + Bytes not equal at {hex(i)}: + expected {hex(input_data[i])}, + actual {hex(decoded[i])} + ''' + ) + + assert all_equal + + +if __name__ == "__main__": + toplevel = "match_finder_wrapper" + verilog_sources = [ + "xls/modules/zstd/match_finder_cocotb.v", + "xls/modules/zstd/rtl/ram_1r1w.sv", + "xls/modules/zstd/rtl/xls_fifo_wrapper.sv", + "xls/modules/zstd/rtl/match_finder_wrapper.sv", + ] + test_module=[Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) + diff --git a/xls/modules/zstd/math.x b/xls/modules/zstd/math.x index c2c92a259f..f68131dcc1 100644 --- a/xls/modules/zstd/math.x +++ b/xls/modules/zstd/math.x @@ -16,7 +16,8 @@ import std; // Return given value with m first bits masked pub fn mask(n: bits[N], m: bits[M]) -> bits[N] { - n & (std::mask_bits() >> (N as bits[M] - m)) + let shift = if m as u32 > N { bits[M]:0 } else { N as bits[M] - m }; + n & (std::mask_bits() >> shift) } #[test] @@ -26,6 +27,10 @@ fn mask_test() { assert_eq(mask(u8:0b11111111, u4:2), u8:0b00000011); assert_eq(mask(u8:0b11111111, u4:4), u8:0b00001111); assert_eq(mask(u8:0b11111111, u4:8), u8:0b11111111); - assert_eq(mask(u8:0b11111111, u4:9), u8:0b00000000); // FIXME: sketchy result, I would expect - // 0b11111111 + assert_eq(mask(u8:0b11111111, u4:9), u8:0b11111111); + assert_eq(mask(u8:0b00000101, u4:0), u8:0b00000000); + assert_eq(mask(u8:0b00000101, u4:1), u8:0b00000001); + assert_eq(mask(u8:0b00000101, u4:2), u8:0b00000001); + assert_eq(mask(u8:0b00000101, u4:3), u8:0b00000101); + assert_eq(mask(u8:0b00000101, u4:4), u8:0b00000101); } diff --git a/xls/modules/zstd/mem_copy.x b/xls/modules/zstd/mem_copy.x new file mode 100644 index 0000000000..16004a9964 --- /dev/null +++ b/xls/modules/zstd/mem_copy.x @@ -0,0 +1,197 @@ +// Copyright 2025 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 contains implementation of RawMemcopy + +import std; + +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.mem_writer; + +pub enum RawMemcopyStatus: u1 { + OK = 0, + ERROR = 1, +} + +pub enum RawMemcopyBlockType: u3 { + RAW = 0, + RLE = 1, + COMP = 2, + COMP_4 = 3, + TREELESS = 4, + TREELESS_4 = 5, +} + +pub struct RawMemcopyReq { + lit_addr: uN[ADDR_W], + lit_cnt: u32, + out_addr: uN[ADDR_W] +} + +pub struct RawMemcopyResp { + status: RawMemcopyStatus, + btype: RawMemcopyBlockType, + length: uN[ADDR_W], +} + +proc RawMemcopyInternal { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemReaderStatus = mem_reader::MemReaderStatus; + + init {} + + mem_reader_resp_r: chan in; + mem_writer_data_s: chan out; + done_s: chan out; + + config( + mem_reader_resp_r: chan in, + mem_writer_data_s: chan out, + done_s: chan out, + ) { + (mem_reader_resp_r, mem_writer_data_s, done_s) + } + + next(state: ()) { + let (resp_tok, resp) = recv(join(), mem_reader_resp_r); + + let is_ok = (resp.status == MemReaderStatus::OKAY); + let mem_writer_data = MemWriterData { + data: resp.data, + length: resp.length, + last: resp.last, + }; + let data_tok = send_if(resp_tok, mem_writer_data_s, is_ok, mem_writer_data); + + let do_send_done = !is_ok || resp.last; + send_if(data_tok, done_s, do_send_done, resp.status); + } +} + +pub proc RawMemcopy { + type Req = RawMemcopyReq; + type Resp = RawMemcopyResp; + type Status = RawMemcopyStatus; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemReaderStatus = mem_reader::MemReaderStatus; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + init {} + + req_r: chan in; + resp_s: chan out; + + mem_rd_req_s: chan out; + mem_copy_done_r: chan in; + + mem_wr_req_s: chan out; + mem_wr_resp_r: chan in; + + config( + req_r: chan in, + resp_s: chan out, + + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + + let (mem_copy_done_s, mem_copy_done_r) = chan("mem_copy_done"); + + spawn RawMemcopyInternal( + mem_rd_resp_r, + mem_wr_data_s, + mem_copy_done_s, + ); + + ( + req_r, resp_s, + mem_rd_req_s, mem_copy_done_r, + mem_wr_req_s, mem_wr_resp_r, + ) + } + + next(state: ()) { + let (req_tok, req) = recv(join(), req_r); + + let mem_rd_req = MemReaderReq { addr: req.lit_addr, length: req.lit_cnt }; + let mem_rd_req_tok = send(req_tok, mem_rd_req_s, mem_rd_req); + + let mem_wr_req = MemWriterReq { addr: req.out_addr, length: req.lit_cnt }; + let mem_wr_req_tok = send(req_tok, mem_wr_req_s, mem_wr_req); + + let mem_req_tok = join(mem_rd_req_tok, mem_wr_req_tok); + let (mem_copy_done_tok, mem_rd_status) = recv(mem_req_tok, mem_copy_done_r); + let (mem_wr_resp_tok, mem_wr_resp) = recv_if( + mem_req_tok, mem_wr_resp_r, + mem_rd_status == MemReaderStatus::OKAY, + MemWriterResp { status: mem_writer::MemWriterRespStatus::ERROR } + ); + + let mem_resp_tok = join(mem_copy_done_tok, mem_wr_resp_tok); + + let mem_rd_ok = (mem_rd_status == MemReaderStatus::OKAY); + let mem_wr_ok = (mem_wr_resp.status == MemWriterStatus::OKAY); + let status = if (mem_rd_ok && mem_wr_ok) { Status::OK } else { Status::ERROR }; + + let resp = RawMemcopyResp { + btype: RawMemcopyBlockType::RAW, + length: req.lit_cnt, + status, + }; + + send(mem_resp_tok, resp_s, resp); + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; + +proc RawMemcopyInst { + type Req = RawMemcopyReq; + type Resp = RawMemcopyResp; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + init {} + + config( + req_r: chan in, + resp_s: chan out, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + ) { + spawn RawMemcopy(req_r, resp_s, mem_rd_req_s, mem_rd_resp_r, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r); + } + + next(state: ()) { } +} diff --git a/xls/modules/zstd/mem_reader_mux.x b/xls/modules/zstd/mem_reader_mux.x new file mode 100644 index 0000000000..13e3316b48 --- /dev/null +++ b/xls/modules/zstd/mem_reader_mux.x @@ -0,0 +1,213 @@ +// Copyright 2025 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.zstd.memory.mem_reader; + +struct MemReaderMuxState< + N: u32, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + sel: uN[N_WIDTH], + active: bool, +} + +pub proc MemReaderMux< + ADDR_W: u32, DATA_W: u32, N: u32, + INIT_SEL: u32 = {u32:0}, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type State = MemReaderMuxState; + type Sel = uN[N_WIDTH]; + + sel_req_r: chan in; + sel_resp_s: chan<()> out; + + n_req_r: chan[N] in; + n_resp_s: chan[N] out; + + req_s: chan out; + resp_r: chan in; + + config( + sel_req_r: chan in, + sel_resp_s: chan<()> out, + + n_req_r: chan[N] in, + n_resp_s: chan[N] out, + + req_s: chan out, + resp_r: chan in, + ) { + ( + sel_req_r, sel_resp_s, + n_req_r, n_resp_s, + req_s, resp_r, + ) + } + + init { + State { + sel: checked_cast(INIT_SEL), + active: false, + } + } + + next(state: State) { + let tok0 = join(); + + let (tok1_0, n_req, n_req_valid) = unroll_for! (i, (tok, resp, valid)): (uN[N_WIDTH], (token, MemReaderReq, bool)) in uN[N_WIDTH]:0..N as uN[N_WIDTH] { + let (tok, r, v) = recv_if_non_blocking(tok, n_req_r[i], state.sel == i && !state.active, zero!()); + if v { (tok, r, true) } else { (tok, resp, valid) } + }((tok0, zero!(), false)); + + let tok2_0 = send_if(tok1_0, req_s, n_req_valid, n_req); + + let active = state.active || n_req_valid; + + let (tok2_1, resp, resp_valid) = recv_if_non_blocking(tok1_0, resp_r, active, zero!()); + + let tok3_0 = unroll_for! (i, tok): (uN[N_WIDTH], token) in uN[N_WIDTH]:0..N as uN[N_WIDTH] { + send_if(tok, n_resp_s[i], state.sel == i && resp_valid, resp) + }(tok2_1); + + let active = (state.active || n_req_valid) && !(resp_valid && resp.last); + + let (tok3_1, sel, sel_valid) = recv_if_non_blocking(tok2_1, sel_req_r, !active, state.sel); + let tok4_0 = send_if(tok3_1, sel_resp_s, !active && sel_valid, ()); + + State { active, sel } + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:32; +const INST_N = u32:5; +const INST_N_WIDTH = std::clog2(INST_N + u32:1); + +proc MemReaderMuxInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type State = MemReaderMuxState; + type Sel = uN[INST_N_WIDTH]; + + init {} + config( + sel_req_r: chan in, + sel_resp_s: chan<()> out, + n_req_r: chan[INST_N] in, + n_resp_s: chan[INST_N] out, + req_s: chan out, + resp_r: chan in, + ) { + + spawn MemReaderMux( + sel_req_r, sel_resp_s, + n_req_r, n_resp_s, + req_s, resp_r, + ); + + () + } + + next(state: ()) {} +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:32; +const TEST_N = u32:5; +const TEST_N_WIDTH = std::clog2(TEST_N + u32:1); + +#[test_proc] +proc MemReaderMuxTest { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type State = MemReaderMuxState; + type Sel = uN[TEST_N_WIDTH]; + + terminator: chan out; + + sel_req_s: chan out; + sel_resp_r: chan<()> in; + + n_req_s: chan[TEST_N] out; + n_resp_r: chan[TEST_N] in; + + req_r: chan in; + resp_s: chan out; + + init {} + config(terminator: chan out,) { + + let (sel_req_s, sel_req_r) = chan("sel_req"); + let (sel_resp_s, sel_resp_r) = chan<()>("sel_resp"); + + let (n_req_s, n_req_r) = chan[TEST_N]("n_req"); + let (n_resp_s, n_resp_r) = chan[TEST_N]("n_resp"); + + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn MemReaderMux( + sel_req_r, sel_resp_s, + n_req_r, n_resp_s, + req_s, resp_r, + ); + + ( + terminator, + sel_req_s, sel_resp_r, + n_req_s, n_resp_r, + req_r, resp_s, + ) + } + + next(state: ()) { + let tok = join(); + + let tok = send(tok, sel_req_s, Sel:3); + let (tok, _) = recv(tok, sel_resp_r); + + let tok = send(tok, n_req_s[3], zero!()); + let (tok, _) = recv(tok, req_r); + + // Cannot switch during the transmission + let tok = send(tok, sel_req_s, Sel:1); + + let tok = send(tok, resp_s, MemReaderResp { + last: true, + ..zero!() + }); + let (tok, _) = recv(tok, n_resp_r[3]); + + // Now we should be able to receive the select + let (tok, _) = recv(tok, sel_resp_r); + + let tok = send(tok, n_req_s[1], zero!()); + let (tok, _) = recv(tok, req_r); + + let tok = send(tok, resp_s, MemReaderResp { + last: true, + ..zero!() + }); + let (tok, _) = recv(tok, n_resp_r[1]); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/mem_reader_simple_arbiter.x b/xls/modules/zstd/mem_reader_simple_arbiter.x new file mode 100644 index 0000000000..47baf9de86 --- /dev/null +++ b/xls/modules/zstd/mem_reader_simple_arbiter.x @@ -0,0 +1,181 @@ +// Copyright 2025 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.zstd.mem_reader_mux; +import xls.modules.zstd.memory.mem_reader; + +struct MemReaderSimpleArbiterState< + N: u32, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +>{ + cnt: uN[N_WIDTH], +} + +pub proc MemReaderSimpleArbiter< + ADDR_W: u32, DATA_W: u32, N: u32, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type Sel = uN[N_WIDTH]; + type State = MemReaderSimpleArbiterState; + + sel_req_s: chan out; + sel_resp_r: chan<()> in; + + config( + n_req_r: chan[N] in, + n_resp_s: chan[N] out, + req_s: chan out, + resp_r: chan in, + ) { + + let (sel_req_s, sel_req_r) = chan("sel_req"); + let (sel_resp_s, sel_resp_r) = chan<(), u32:1>("sel_resp"); + + spawn mem_reader_mux::MemReaderMux( + sel_req_r, sel_resp_s, + n_req_r, n_resp_s, + req_s, resp_r, + ); + + (sel_req_s, sel_resp_r) + } + + init { zero!() } + + next(state: State) { + let tok0 = join(); + + let tok = send(join(), sel_req_s, state.cnt); + let (tok, _) = recv(tok, sel_resp_r); + + if state.cnt == N as uN[N_WIDTH] - uN[N_WIDTH]:1 { + zero!() + } else { + State {cnt: state.cnt + uN[N_WIDTH]:1 } + } + } +} + + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:32; +const INST_NUM_PARTITIONS = u32:32; +const INST_N = u32:5; +const INST_N_WIDTH = std::clog2(INST_N + u32:1); + +proc MemReaderSimpleArbiterInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type Addr = uN[INST_ADDR_W]; + type Length = uN[INST_ADDR_W]; + type Data = uN[INST_DATA_W]; + + init {} + config( + n_req_r: chan[INST_N] in, + n_resp_s: chan[INST_N] out, + req_s: chan out, + resp_r: chan in, + ) { + spawn MemReaderSimpleArbiter( + n_req_r, n_resp_s, + req_s, resp_r, + ); + } + + next(state: ()) { + } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:32; +const TEST_NUM_PARTITIONS = u32:32; +const TEST_N = u32:5; +const TEST_N_WIDTH = std::clog2(TEST_N + u32:1); + +#[test_proc] +proc MemReaderSimpleArbiterTest { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + + type Addr = uN[TEST_ADDR_W]; + type Length = uN[TEST_ADDR_W]; + + terminator: chan out; + + n_req_s: chan[TEST_N] out; + n_resp_r: chan[TEST_N] in; + + req_r: chan in; + resp_s: chan out; + + init {} + config(terminator: chan out,) { + + let (n_req_s, n_req_r) = chan[TEST_N]("n_req"); + let (n_resp_s, n_resp_r) = chan[TEST_N]("n_resp"); + + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn MemReaderSimpleArbiter( + n_req_r, n_resp_s, + req_s, resp_r, + ); + + ( + terminator, + n_req_s, n_resp_r, + req_r, resp_s, + ) + } + + next(state: ()) { + let tok = unroll_for! (i, tok): (u32, token) in u32:0..TEST_N { + let req = MemReaderReq { + addr: i as Addr, + length: (TEST_DATA_W / u32:8) as Length, + }; + trace_fmt!("Sending request {:#x} on channel: {}", req, i); + let tok = send(tok, n_req_s[i], req); + + let resp = MemReaderResp { + last: true, + ..zero!() + }; + + trace_fmt!("Sending response {:#x} on channel: {}", resp, i); + let tok = send(tok, resp_s, resp); + + tok + }(join()); + + let tok = unroll_for! (i, tok): (u32, token) in u32:0..TEST_N { + let (tok, req) = recv(tok, req_r); + trace_fmt!("Received req {:#x} on channel {}", req, i); + let (tok, resp) = recv(tok, n_resp_r[i]); + trace_fmt!("Received response {:#x} on channel: {}", resp, i); + + tok + }(join()); + + send(tok, terminator, true); + } +} + diff --git a/xls/modules/zstd/mem_writer_mux.x b/xls/modules/zstd/mem_writer_mux.x new file mode 100644 index 0000000000..f22a0b46a2 --- /dev/null +++ b/xls/modules/zstd/mem_writer_mux.x @@ -0,0 +1,230 @@ +// Copyright 2025 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.zstd.memory.mem_writer; + +struct MemWriterMuxState< + N: u32, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + sel: uN[N_WIDTH], + active: bool, +} + +pub proc MemWriterMux< + ADDR_W: u32, DATA_W: u32, N: u32, + INIT_SEL: u32 = {u32:0}, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type State = MemWriterMuxState; + type Sel = uN[N_WIDTH]; + + sel_req_r: chan in; + sel_resp_s: chan<()> out; + + n_req_r: chan[N] in; + n_data_r: chan[N] in; + n_resp_s: chan[N] out; + + req_s: chan out; + data_s: chan out; + resp_r: chan in; + + config( + sel_req_r: chan in, + sel_resp_s: chan<()> out, + + n_req_r: chan[N] in, + n_data_r: chan[N] in, + n_resp_s: chan[N] out, + + req_s: chan out, + data_s: chan out, + resp_r: chan in, + ) { + ( + sel_req_r, sel_resp_s, + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ) + } + + init { + State { + sel: checked_cast(INIT_SEL), + active: false, + } + } + + next(state: State) { + let tok0 = join(); + + let (tok1_0, n_req, n_req_valid) = unroll_for! (i, (tok, resp, valid)): (uN[N_WIDTH], (token, MemWriterReq, bool)) in uN[N_WIDTH]:0..N as uN[N_WIDTH] { + let (tok, r, v) = recv_if_non_blocking(tok, n_req_r[i], state.sel == i && !state.active, zero!()); + if v { (tok, r, true) } else { (tok, resp, valid) } + }((tok0, zero!(), false)); + + let tok2_0 = send_if(tok1_0, req_s, n_req_valid, n_req); + + let active = state.active || n_req_valid; + + let (tok2_1, n_data, n_data_valid) = unroll_for! (i, (tok, resp, valid)): (uN[N_WIDTH], (token, MemWriterData, bool)) in uN[N_WIDTH]:0..N as uN[N_WIDTH] { + let (tok, r, v) = recv_if_non_blocking(tok, n_data_r[i], state.sel == i && active, zero!()); + if v { (tok, r, true) } else { (tok, resp, valid) } + }((tok1_0, zero!(), false)); + + let tok3_0 = send_if(tok2_1, data_s, n_data_valid, n_data); + + let (tok2_2, resp, resp_valid) = recv_if_non_blocking(tok1_0, resp_r, active, zero!()); + + let tok3_1 = unroll_for! (i, tok): (uN[N_WIDTH], token) in uN[N_WIDTH]:0..N as uN[N_WIDTH] { + send_if(tok, n_resp_s[i], state.sel == i && resp_valid, resp) + }(tok2_2); + let active = (state.active || n_req_valid) && !(resp_valid); + let (tok3_2, sel, sel_valid) = recv_if_non_blocking(tok2_2, sel_req_r, !active, state.sel); + let tok4_0 = send_if(tok3_2, sel_resp_s, sel_valid, ()); + State { active, sel } + } +} + + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:32; +const INST_N = u32:5; +const INST_N_WIDTH = std::clog2(INST_N + u32:1); + +proc MemWriterMuxInst { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type State = MemWriterMuxState; + type Sel = uN[INST_N_WIDTH]; + + init {} + config( + sel_req_r: chan in, + sel_resp_s: chan<()> out, + n_req_r: chan[INST_N] in, + n_data_r: chan[INST_N] in, + n_resp_s: chan[INST_N] out, + req_s: chan out, + data_s: chan out, + resp_r: chan in, + ) { + spawn MemWriterMux( + sel_req_r, sel_resp_s, + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ); + + () + } + + next(state: ()) {} +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:32; +const TEST_N = u32:5; +const TEST_N_WIDTH = std::clog2(TEST_N + u32:1); + +#[test_proc] +proc MemWriterMuxTest { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type State = MemWriterMuxState; + type Sel = uN[TEST_N_WIDTH]; + + terminator: chan out; + + sel_req_s: chan out; + sel_resp_r: chan<()> in; + + n_req_s: chan[TEST_N] out; + n_data_s: chan[TEST_N] out; + n_resp_r: chan[TEST_N] in; + + req_r: chan in; + data_r: chan in; + resp_s: chan out; + + init {} + config(terminator: chan out,) { + + let (sel_req_s, sel_req_r) = chan("sel_req"); + let (sel_resp_s, sel_resp_r) = chan<()>("sel_resp"); + + let (n_req_s, n_req_r) = chan[TEST_N]("n_req"); + let (n_data_s, n_data_r) = chan[TEST_N]("n_data"); + let (n_resp_s, n_resp_r) = chan[TEST_N]("n_resp"); + + let (req_s, req_r) = chan("req"); + let (data_s, data_r) = chan("data"); + let (resp_s, resp_r) = chan("resp"); + + spawn MemWriterMux( + sel_req_r, sel_resp_s, + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ); + + ( + terminator, + sel_req_s, sel_resp_r, + n_req_s, n_data_s, n_resp_r, + req_r, data_r, resp_s, + ) + } + + next(state: ()) { + let tok = join(); + + let tok = send(tok, sel_req_s, Sel:3); + let (tok, _) = recv(tok, sel_resp_r); + + let tok = send(tok, n_req_s[3], zero!()); + let (tok, _) = recv(tok, req_r); + + // Cannot switch during the transmission + let tok = send(tok, sel_req_s, Sel:1); + + let tok = send(tok, n_data_s[3], zero!()); + let (tok, _) = recv(tok, data_r); + + let tok = send(tok, resp_s, zero!()); + let (tok, _) = recv(tok, n_resp_r[3]); + + // Now we should be able to receive the select + let (tok, _) = recv(tok, sel_resp_r); + + let tok = send(tok, n_req_s[1], zero!()); + let (tok, _) = recv(tok, req_r); + + let tok = send(tok, n_data_s[1], zero!()); + let (tok, _) = recv(tok, data_r); + + let tok = send(tok, resp_s, zero!()); + let (tok, _) = recv(tok, n_resp_r[1]); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/mem_writer_simple_arbiter.x b/xls/modules/zstd/mem_writer_simple_arbiter.x new file mode 100644 index 0000000000..be2b1b4404 --- /dev/null +++ b/xls/modules/zstd/mem_writer_simple_arbiter.x @@ -0,0 +1,202 @@ +// Copyright 2025 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.zstd.mem_writer_mux; +import xls.modules.zstd.memory.mem_writer; + +struct MemWriterSimpleArbiterState< + N: u32, N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + cnt: uN[N_WIDTH], +} + +pub proc MemWriterSimpleArbiter< + ADDR_W: u32, DATA_W: u32, N: u32, + N_WIDTH: u32 = {std::clog2(N + u32:1)} +> { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type Sel = uN[N_WIDTH]; + type State = MemWriterSimpleArbiterState; + + + sel_req_s: chan out; + sel_resp_r: chan<()> in; + + + config( + n_req_r: chan[N] in, + n_data_r: chan[N] in, + n_resp_s: chan[N] out, + + req_s: chan out, + data_s: chan out, + resp_r: chan in, + ) { + + let (sel_req_s, sel_req_r) = chan("sel_req"); + let (sel_resp_s, sel_resp_r) = chan<(), u32:1>("sel_resp"); + + spawn mem_writer_mux::MemWriterMux( + sel_req_r, sel_resp_s, + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ); + + (sel_req_s, sel_resp_r) + } + + init { zero!() } + + next(state: State) { + let tok0 = join(); + + let tok = send(join(), sel_req_s, state.cnt); + let (tok, _) = recv(tok, sel_resp_r); + + if state.cnt == N as uN[N_WIDTH] - uN[N_WIDTH]:1 { + zero!() + } else { + State {cnt: state.cnt + uN[N_WIDTH]:1 } + } + } +} + + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:32; +const INST_NUM_PARTITIONS = u32:32; +const INST_N = u32:5; +const INST_N_WIDTH = std::clog2(INST_N + u32:1); + +proc MemWriterSimpleArbiterInst { + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type Addr = uN[INST_ADDR_W]; + type Length = uN[INST_ADDR_W]; + type Data = uN[INST_DATA_W]; + + init {} + config( + n_req_r: chan[INST_N] in, + n_data_r: chan[INST_N] in, + n_resp_s: chan[INST_N] out, + req_s: chan out, + data_s: chan out, + resp_r: chan in, + ) { + spawn MemWriterSimpleArbiter( + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ); + } + + next(state: ()) { + } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:32; +const TEST_NUM_PARTITIONS = u32:32; +const TEST_N = u32:5; +const TEST_N_WIDTH = std::clog2(TEST_N + u32:1); + +#[test_proc] +proc MemWriterSimpleArbiterTest { + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterData = mem_writer::MemWriterDataPacket; + + type Addr = uN[TEST_ADDR_W]; + type Length = uN[TEST_ADDR_W]; + type Data = uN[TEST_DATA_W]; + + terminator: chan out; + + n_req_s: chan[TEST_N] out; + n_data_s: chan[TEST_N] out; + n_resp_r: chan[TEST_N] in; + + req_r: chan in; + data_r: chan in; + resp_s: chan out; + + init {} + config(terminator: chan out,) { + + let (n_req_s, n_req_r) = chan[TEST_N]("n_req"); + let (n_data_s, n_data_r) = chan[TEST_N]("n_data"); + let (n_resp_s, n_resp_r) = chan[TEST_N]("n_resp"); + + let (req_s, req_r) = chan("req"); + let (data_s, data_r) = chan("data"); + let (resp_s, resp_r) = chan("resp"); + + spawn MemWriterSimpleArbiter( + n_req_r, n_data_r, n_resp_s, + req_s, data_s, resp_r, + ); + + ( + terminator, + n_req_s, n_data_s, n_resp_r, + req_r, data_r, resp_s, + ) + } + + next(state: ()) { + let tok = unroll_for! (i, tok): (u32, token) in u32:0..TEST_N { + let req = MemWriterReq { + addr: i as Addr, + length: (TEST_DATA_W / u32:8) as Length, + }; + trace_fmt!("Sending request {:#x} on channel: {}", req, i); + let tok = send(tok, n_req_s[i], req); + + let data = MemWriterData { + data: i as Data + Data:0x1000, + length: (TEST_DATA_W / u32:8) as Length, + last: true, + }; + trace_fmt!("Sending data {:#x} on channel: {}", data, i); + let tok = send(tok, n_data_s[i], data); + + let resp = zero!(); + trace_fmt!("Sending response {:#x} on channel: {}", resp, i); + let tok = send(tok, resp_s, resp); + + tok + }(join()); + + let tok = unroll_for! (i, tok): (u32, token) in u32:0..TEST_N { + let (tok, req) = recv(tok, req_r); + trace_fmt!("Received req {:#x} on channel {}", req, i); + let (tok, data) = recv(tok, data_r); + trace_fmt!("Received data {:#x} on channel {}", data, i); + let (tok, resp) = recv(tok, n_resp_r[i]); + trace_fmt!("Received response {:#x} on channel: {}", resp, i); + + tok + }(join()); + + send(tok, terminator, true); + } +} + diff --git a/xls/modules/zstd/memory/BUILD b/xls/modules/zstd/memory/BUILD index 9ffabd741e..4673e5b65d 100644 --- a/xls/modules/zstd/memory/BUILD +++ b/xls/modules/zstd/memory/BUILD @@ -12,15 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. +# pytype binary, library load("@rules_hdl//place_and_route:build_defs.bzl", "place_and_route") load("@rules_hdl//synthesis:build_defs.bzl", "benchmark_synth", "synthesize_rtl") load("@rules_hdl//verilog:providers.bzl", "verilog_library") +load("@xls_pip_deps//:requirements.bzl", "requirement") load( "//xls/build_rules:xls_build_defs.bzl", "xls_benchmark_ir", "xls_dslx_library", "xls_dslx_test", "xls_dslx_verilog", + "xls_dslx_fmt_test", ) load("//xls/common:openroad_warnings.bzl", "ASAP7_SUPPPRESSED_WARNINGS") @@ -67,12 +70,12 @@ common_codegen_args = { "streaming_channel_data_suffix": "_data", "fifo_module": "", "materialize_internal_fifos": "true", - - # TODO: This should be adjusted when per channel separation of IO options is enabled "flop_inputs_kind": "skid", "flop_outputs_kind": "skid", } +# AxiReader (FSM-based) + xls_dslx_library( name = "axi_reader_dslx", srcs = ["axi_reader.x"], @@ -89,12 +92,10 @@ xls_dslx_test( tags = ["manual"], ) -# FIXME: Improve the proc to achieve CLOCK_PERIOD_PS -AXI_READER_CLOCK_PERIOD_PS = "1700" - axi_reader_codegen_args = common_codegen_args | { - "clock_period_ps": AXI_READER_CLOCK_PERIOD_PS, + "clock_period_ps": CLOCK_PERIOD_PS, "module_name": "axi_reader", + "worst_case_throughput": "2", } xls_dslx_verilog( @@ -139,7 +140,7 @@ benchmark_synth( place_and_route( name = "axi_reader_place_and_route", - clock_period = AXI_READER_CLOCK_PERIOD_PS, + clock_period = axi_reader_codegen_args["clock_period_ps"], core_padding_microns = 2, min_pin_distance = "0.5", placement_density = "0.30", @@ -150,6 +151,81 @@ place_and_route( target_die_utilization_percentage = "10", ) +# AxiReader (no FSM) + +axi_reader_no_fsm_codegen_args = common_codegen_args | { + "worst_case_throughput": "4", + "module_name": "axi_reader", +} + +xls_dslx_verilog( + name = "axi_reader_no_fsm_verilog", + codegen_args = axi_reader_no_fsm_codegen_args, + dslx_top = "AxiReaderInst", + library = ":axi_reader_dslx", + tags = ["manual"], + verilog_file = "axi_reader_no_fsm.v", +) + +xls_benchmark_ir( + name = "axi_reader_no_fsm_opt_ir_benchmark", + src = ":axi_reader_no_fsm_verilog.opt.ir", + benchmark_ir_args = axi_reader_no_fsm_codegen_args, + tags = ["manual"], +) + +verilog_library( + name = "axi_reader_no_fsm_verilog_lib", + srcs = [ + ":axi_reader_no_fsm.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "axi_reader_no_fsm_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "axi_reader", + deps = [ + ":axi_reader_no_fsm_verilog_lib", + ], +) + +benchmark_synth( + name = "axi_reader_no_fsm_benchmark_synth", + synth_target = ":axi_reader_no_fsm_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "axi_reader_no_fsm_place_and_route", + clock_period = axi_reader_codegen_args["clock_period_ps"], + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":axi_reader_no_fsm_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +axi_reader_internal_r_codegen_args = common_codegen_args | { + "worst_case_throughput": "1", + "module_name": "axi_reader_internal_r", +} + +xls_dslx_verilog( + name = "axi_reader_internal_r_verilog", + codegen_args = axi_reader_internal_r_codegen_args, + dslx_top = "AxiReaderInternalRInst", + library = ":axi_reader_dslx", + tags = ["manual"], + verilog_file = "axi_reader_internal_r.v", +) + +# AxiStreamRemoveEmpty + xls_dslx_library( name = "axi_stream_remove_empty_dslx", srcs = ["axi_stream_remove_empty.x"], @@ -210,6 +286,8 @@ place_and_route( target_die_utilization_percentage = "10", ) +# RemoveEmptyBytes + xls_dslx_verilog( name = "remove_empty_bytes_verilog", codegen_args = common_codegen_args | {"module_name": "remove_empty_bytes"}, @@ -263,6 +341,8 @@ place_and_route( target_die_utilization_percentage = "10", ) +# AxiStreamDownscaler + xls_dslx_library( name = "axi_stream_downscaler_dslx", srcs = ["axi_stream_downscaler.x"], @@ -330,6 +410,8 @@ place_and_route( target_die_utilization_percentage = "10", ) +# AxiRamReader + xls_dslx_library( name = "axi_ram_reader_dslx", srcs = ["axi_ram_reader.x"], @@ -345,9 +427,7 @@ xls_dslx_test( library = ":axi_ram_reader_dslx", ) -# FIXME: Improve the proc to achieve CLOCK_PERIOD_PS AXI_RAM_READER_CLOCK_PERIOD_PS = "850" - axi_ram_reader_codegen_args = common_codegen_args | { "module_name": "axi_ram_reader", "clock_period_ps": AXI_RAM_READER_CLOCK_PERIOD_PS, @@ -414,6 +494,8 @@ place_and_route( target_die_utilization_percentage = "10", ) +# MemReader (FSM-based) + xls_dslx_library( name = "mem_reader_dslx", srcs = ["mem_reader.x"], @@ -432,12 +514,9 @@ xls_dslx_test( tags = ["manual"], ) -# FIXME: Improve the proc to achieve CLOCK_PERIOD_PS -MEM_READER_CLOCK_PERIOD_PS = "2600" - mem_reader_codegen_args = common_codegen_args | { - "clock_period_ps": MEM_READER_CLOCK_PERIOD_PS, "module_name": "mem_reader", + "worst_case_throughput": "2", } xls_dslx_verilog( @@ -482,7 +561,7 @@ benchmark_synth( place_and_route( name = "mem_reader_place_and_route", - clock_period = CLOCK_PERIOD_PS, + clock_period = mem_reader_codegen_args["clock_period_ps"], core_padding_microns = 2, min_pin_distance = "0.5", placement_density = "0.30", @@ -493,9 +572,84 @@ place_and_route( target_die_utilization_percentage = "10", ) +# MemReader (no FSM) + +mem_reader_no_fsm_codegen_args = common_codegen_args | { + "module_name": "mem_reader", + "worst_case_throughput": "4", +} + +xls_dslx_verilog( + name = "mem_reader_no_fsm_verilog", + codegen_args = mem_reader_no_fsm_codegen_args, + dslx_top = "MemReaderNoFsmInst", + library = ":mem_reader_dslx", + tags = ["manual"], + verilog_file = "mem_reader_no_fsm.v", +) + +verilog_library( + name = "mem_reader_no_fsm_verilog_lib", + srcs = [ + ":mem_reader_no_fsm.v", + ], + tags = ["manual"], +) + +xls_benchmark_ir( + name = "mem_reader_no_fsm_opt_ir_benchmark", + src = ":mem_reader_no_fsm_verilog.opt.ir", + benchmark_ir_args = mem_reader_no_fsm_codegen_args, + tags = ["manual"], +) + +synthesize_rtl( + name = "mem_reader_no_fsm_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "mem_reader", + deps = [ + ":mem_reader_no_fsm_verilog_lib", + ], +) + +benchmark_synth( + name = "mem_reader_no_fsm_benchmark_synth", + synth_target = ":mem_reader_no_fsm_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "mem_reader_no_fsm_place_and_route", + clock_period = mem_reader_no_fsm_codegen_args["clock_period_ps"], + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":mem_reader_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +xls_dslx_verilog( + name = "mem_reader_internal_no_fsm_verilog", + codegen_args = mem_reader_no_fsm_codegen_args, + dslx_top = "MemReaderInternalNoFsmInst", + library = ":mem_reader_dslx", + tags = ["manual"], + verilog_file = "mem_reader_internal_no_fsm.v", +) + +# MemReaderAdv (FSM-based) + +mem_reader_adv_codegen_args = common_codegen_args | { + "module_name": "mem_reader_adv", + "worst_case_throughput": "2" +} + xls_dslx_verilog( name = "mem_reader_adv_verilog", - codegen_args = mem_reader_codegen_args | {"module_name": "mem_reader_adv"}, + codegen_args = mem_reader_adv_codegen_args, dslx_top = "MemReaderAdvInst", library = ":mem_reader_dslx", tags = ["manual"], @@ -505,7 +659,7 @@ xls_dslx_verilog( xls_benchmark_ir( name = "mem_reader_adv_opt_ir_benchmark", src = ":mem_reader_adv_verilog.opt.ir", - benchmark_ir_args = mem_reader_codegen_args, + benchmark_ir_args = mem_reader_adv_codegen_args, tags = ["manual"], ) @@ -546,6 +700,125 @@ place_and_route( target_die_utilization_percentage = "10", ) +py_test( + name = "mem_reader_adv_cocotb_test", + srcs = [ + "mem_reader_adv_cocotb_test.py", + "mem_reader_cocotb.py" + ], + data = [ + ":mem_reader_adv.v", + "//xls/modules/zstd/memory/rtl:mem_reader_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:memory", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# MemReader (no FSM) + +mem_reader_adv_no_fsm_codegen_args = common_codegen_args | { + "module_name": "mem_reader_adv", + "worst_case_throughput": "4", +} + +xls_dslx_verilog( + name = "mem_reader_adv_no_fsm_verilog", + codegen_args = mem_reader_adv_no_fsm_codegen_args, + dslx_top = "MemReaderAdvNoFsmInst", + library = ":mem_reader_dslx", + tags = ["manual"], + verilog_file = "mem_reader_adv_no_fsm.v", +) + +xls_benchmark_ir( + name = "mem_reader_adv_no_fsm_opt_ir_benchmark", + src = ":mem_reader_adv_no_fsm_verilog.opt.ir", + benchmark_ir_args = mem_reader_adv_no_fsm_codegen_args, + tags = ["manual"], +) + +verilog_library( + name = "mem_reader_adv_no_fsm_verilog_lib", + srcs = [ + ":mem_reader_adv_no_fsm.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "mem_reader_adv_no_fsm_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "mem_reader_adv", + deps = [ + ":mem_reader_adv_no_fsm_verilog_lib", + ], +) + +benchmark_synth( + name = "mem_reader_adv_no_fsm_benchmark_synth", + synth_target = ":mem_reader_adv_no_fsm_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "mem_reader_adv_no_fsm_place_and_route", + clock_period = CLOCK_PERIOD_PS, + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":mem_reader_adv_no_fsm_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +py_test( + name = "mem_reader_adv_no_fsm_cocotb_test", + srcs = [ + "mem_reader_adv_no_fsm_cocotb_test.py", + "mem_reader_cocotb.py" + ], + data = [ + ":mem_reader_adv_no_fsm.v", + "//xls/modules/zstd/memory/rtl:mem_reader_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + env = {"BUILD_WORKING_DIRECTORY": "sim_build"}, + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + requirement("pytest"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:memory", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# AxiWriter (FSM-based) + xls_dslx_library( name = "axi_writer_dslx", srcs = ["axi_writer.x"], @@ -562,9 +835,13 @@ xls_dslx_test( tags = ["manual"], ) +axi_writer_codegen_args = common_codegen_args | { + "module_name": "axi_writer" +} + xls_dslx_verilog( name = "axi_writer_verilog", - codegen_args = common_codegen_args | {"module_name": "axi_writer"}, + codegen_args = axi_writer_codegen_args, dslx_top = "AxiWriterInst", library = ":axi_writer_dslx", tags = ["manual"], @@ -574,7 +851,7 @@ xls_dslx_verilog( xls_benchmark_ir( name = "axi_writer_opt_ir_benchmark", src = ":axi_writer_verilog.opt.ir", - benchmark_ir_args = common_codegen_args, + benchmark_ir_args = axi_writer_codegen_args, tags = ["manual"], ) @@ -604,7 +881,7 @@ benchmark_synth( place_and_route( name = "axi_writer_place_and_route", - clock_period = CLOCK_PERIOD_PS, + clock_period = axi_writer_codegen_args["clock_period_ps"], core_padding_microns = 2, min_pin_distance = "0.5", placement_density = "0.30", @@ -615,6 +892,123 @@ place_and_route( target_die_utilization_percentage = "10", ) +py_test( + name = "axi_writer_cocotb_test", + srcs = [ + "axi_writer_cocotb_test.py", + "axi_writer_cocotb.py" + ], + data = [ + ":axi_writer.v", + "//xls/modules/zstd/memory/rtl:axi_writer_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# AxiWriter (no FSM) + +axi_writer_no_fsm_codegen_args = common_codegen_args | { + "module_name": "axi_writer", + "worst_case_throughput": "4" +} + +xls_dslx_verilog( + name = "axi_writer_no_fsm_verilog", + codegen_args = axi_writer_no_fsm_codegen_args, + dslx_top = "AxiWriterNoFsmInst", + library = ":axi_writer_dslx", + tags = ["manual"], + verilog_file = "axi_writer_no_fsm.v", +) + +xls_benchmark_ir( + name = "axi_writer_no_fsm_opt_ir_benchmark", + src = ":axi_writer_no_fsm_verilog.opt.ir", + benchmark_ir_args = axi_writer_no_fsm_codegen_args, + tags = ["manual"], +) + +verilog_library( + name = "axi_writer_no_fsm_verilog_lib", + srcs = [ + ":axi_writer_no_fsm.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "axi_writer_no_fsm_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "axi_writer", + deps = [ + ":axi_writer_no_fsm_verilog_lib", + ], +) + +benchmark_synth( + name = "axi_writer_no_fsm_benchmark_synth", + synth_target = ":axi_writer_no_fsm_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "axi_writer_no_fsm_place_and_route", + clock_period = axi_writer_codegen_args["clock_period_ps"], + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":axi_writer_no_fsm_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +py_test( + name = "axi_writer_no_fsm_cocotb_test", + srcs = [ + "axi_writer_no_fsm_cocotb_test.py", + "axi_writer_cocotb.py" + ], + data = [ + ":axi_writer_no_fsm.v", + "//xls/modules/zstd/memory/rtl:axi_writer_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + env = {"BUILD_WORKING_DIRECTORY": "sim_build"}, + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + requirement("pytest"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# AxiStreamAddEmpty + xls_dslx_library( name = "axi_stream_add_empty_dslx", srcs = ["axi_stream_add_empty.x"], @@ -690,6 +1084,12 @@ place_and_route( target_die_utilization_percentage = "10", ) +# MemWriter (FSM-based) + +mem_writer_codegen_args = common_codegen_args | { + "module_name": "mem_writer" +} + xls_dslx_library( name = "mem_writer_dslx", srcs = ["mem_writer.x"], @@ -710,7 +1110,7 @@ xls_dslx_test( xls_dslx_verilog( name = "mem_writer_verilog", - codegen_args = common_codegen_args | {"module_name": "mem_writer"}, + codegen_args = mem_writer_codegen_args, dslx_top = "MemWriterInst", library = ":mem_writer_dslx", tags = ["manual"], @@ -753,3 +1153,269 @@ place_and_route( tags = ["manual"], target_die_utilization_percentage = "10", ) + +py_test( + name = "mem_writer_cocotb_test", + srcs = [ + "mem_writer_cocotb_test.py", + "mem_writer_cocotb.py" + ], + data = [ + ":mem_writer.v", + "//xls/modules/zstd/memory/rtl:mem_writer_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# MemWriter (no FSM) + +mem_writer_no_fsm_codegen_args = common_codegen_args | { + "module_name": "mem_writer", + "worst_case_throughput": "4", +} + +xls_dslx_verilog( + name = "mem_writer_no_fsm_verilog", + codegen_args = mem_writer_no_fsm_codegen_args, + dslx_top = "MemWriterNoFsmInst", + library = ":mem_writer_dslx", + tags = ["manual"], + verilog_file = "mem_writer_no_fsm.v", +) + +verilog_library( + name = "mem_writer_no_fsm_verilog_lib", + srcs = [ + ":mem_writer.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "mem_writer_no_fsm_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "mem_writer", + deps = [ + ":mem_writer_no_fsm_verilog_lib", + ], +) + +benchmark_synth( + name = "mem_writer_no_fsm_benchmark_synth", + synth_target = ":mem_writer_no_fsm_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "mem_writer_no_fsm_place_and_route", + clock_period = mem_writer_codegen_args["clock_period_ps"], + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":mem_writer_no_fsm_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +py_test( + name = "mem_writer_no_fsm_cocotb_test", + srcs = [ + "mem_writer_no_fsm_cocotb_test.py", + "mem_writer_cocotb.py" + ], + data = [ + ":mem_writer_no_fsm.v", + "//xls/modules/zstd/memory/rtl:mem_writer_wrapper.v", + "@com_icarus_iverilog//:iverilog", + "@com_icarus_iverilog//:vvp", + ], + env = {"BUILD_WORKING_DIRECTORY": "sim_build"}, + tags = ["manual"], + visibility = ["//xls:xls_users"], + deps = [ + requirement("cocotb"), + requirement("cocotbext-axi"), + requirement("pytest"), + "//xls/common:runfiles", + "//xls/modules/zstd/cocotb:channel", + "//xls/modules/zstd/cocotb:utils", + "//xls/modules/zstd/cocotb:xlsstruct", + "@abseil-py//absl:app", + "@abseil-py//absl/flags", + "@com_google_protobuf//:protobuf_python", + ], +) + +# AxiRamWriter + +xls_dslx_library( + name = "axi_ram_writer_dslx", + srcs = ["axi_ram_writer.x"], + deps = [ + ":mem_writer_dslx", + "//xls/examples:ram_dslx", + "//xls/modules/zstd:math_dslx", + ], +) + +xls_dslx_test( + name = "axi_ram_writer_dslx_test", + library = ":axi_ram_writer_dslx", +) + +axi_ram_writer_codegen_args = common_codegen_args | { + "module_name": "AxiRamWriter", + "clock_period_ps": "750", + "pipeline_stages": "8", + "worst_case_throughput": "1", + "materialize_internal_fifos": "true" +} + +xls_dslx_verilog( + name = "axi_ram_writer_verilog", + codegen_args = axi_ram_writer_codegen_args, + dslx_top = "AxiRamWriterInst", + library = ":axi_ram_writer_dslx", + tags = ["manual"], + verilog_file = "axi_ram_writer.v", +) + +xls_benchmark_ir( + name = "axi_ram_writer_opt_ir_benchmark", + src = ":axi_ram_writer_verilog.opt.ir", + codegen_args = axi_ram_writer_codegen_args, + benchmark_ir_args = common_codegen_args, + tags = ["manual"], +) + +verilog_library( + name = "axi_ram_writer_verilog_lib", + srcs = [ + ":axi_ram_writer.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "axi_ram_writer_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "AxiRamWriter", + deps = [ + ":axi_ram_writer_verilog_lib", + ], +) + +benchmark_synth( + name = "axi_ram_writer_benchmark_synth", + synth_target = ":axi_ram_writer_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "axi_ram_writer_place_and_route", + clock_period = CLOCK_PERIOD_PS, + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":axi_ram_writer_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +# MemWriterDataDownscaler + +xls_dslx_library( + name = "mem_writer_data_downscaler_dslx", + srcs = ["mem_writer_data_downscaler.x"], + deps = [ + ":mem_writer_dslx", + ], +) + +xls_dslx_test( + name = "mem_writer_data_downscaler_dslx_test", + library = ":mem_writer_data_downscaler_dslx", +) + +xls_dslx_verilog( + name = "mem_writer_data_downscaler_verilog", + codegen_args = common_codegen_args, + dslx_top = "MemWriterDataDownscalerInst", + library = ":mem_writer_data_downscaler_dslx", + tags = ["manual"], + verilog_file = "mem_writer_data_downscaler.v", +) + +xls_benchmark_ir( + name = "mem_writer_data_downscaler_opt_ir_benchmark", + src = ":mem_writer_data_downscaler_verilog.opt.ir", + benchmark_ir_args = common_codegen_args, + tags = ["manual"], +) + +verilog_library( + name = "mem_writer_data_downscaler_verilog_lib", + srcs = [ + ":mem_writer_data_downscaler.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "mem_writer_data_downscaler_synth_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "__mem_writer_data_downscaler__MemWriterDataDownscalerInst_0_next", + deps = [ + ":mem_writer_data_downscaler_verilog_lib", + ], +) + +benchmark_synth( + name = "mem_writer_data_downscaler_benchmark_synth", + synth_target = ":mem_writer_data_downscaler_synth_asap7", + tags = ["manual"], +) + +place_and_route( + name = "mem_writer_data_downscaler_place_and_route", + clock_period = CLOCK_PERIOD_PS, + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + synthesized_rtl = ":mem_writer_data_downscaler_synth_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +xls_dslx_library( + name = "mem_reader_data_upscaler_dslx", + srcs = ["mem_reader_data_upscaler.x"], + deps = [ + ":mem_reader_dslx", + ], +) + +xls_dslx_fmt_test( + name = "mem_reader_data_upscaler_fmt_test", + src = "mem_reader_data_upscaler.x" +) diff --git a/xls/modules/zstd/memory/README.md b/xls/modules/zstd/memory/README.md index 37c20c45a3..ad7d874218 100644 --- a/xls/modules/zstd/memory/README.md +++ b/xls/modules/zstd/memory/README.md @@ -89,3 +89,44 @@ The list below shows the usage of the `MemWriter` proc: 3. Wait for the response submitted on the `resp_s` channel, which indicates if the write operation was successful or an error occurred. + +## Cocotb Simulation + +This directory also contains Verilog simulations of the created modules, +which test their interaction with RAM attached to the AXI bus. These Verilog +simulations provide insight into the design's latency and achievable throughput. + +The simulation interacts with verilog file generated from the particular DSLX +proc through a verilog wrapper. The wrapper is used to create an interface that +is compliant with the AXI specification so that the cocotb testbench can +interact with the DUT with the help of an extension tailored for handling the +AXI bus. + +### Usage + +1. Run the simulation with the following command: + +``` +bazel run -c opt //xls/modules/zstd/memory:_cocotb_test -- --logtostderr +``` + +2. Observe simulation results, e.g. for `mem_writer_cocotb_test`: + +``` +************************************************************************************************************************************************************* +** TEST STATUS SIM TIME (ns) REAL TIME (s) RATIO (ns/s) ** +************************************************************************************************************************************************************* +** mem_writer_cocotb_test.ram_test_single_burst_1_transfer PASS 1970000.00 0.05 40004933.01 ** +** mem_writer_cocotb_test.ram_test_single_burst_2_transfers PASS 2140000.00 0.04 52208013.80 ** +** mem_writer_cocotb_test.ram_test_single_burst_almost_max_burst_transfer PASS 42620000.00 1.00 42734572.11 ** +** mem_writer_cocotb_test.ram_test_single_burst_max_burst_transfer PASS 43380000.00 1.03 42245987.95 ** +** mem_writer_cocotb_test.ram_test_multiburst_2_full_bursts PASS 85940000.00 2.00 42978720.13 ** +** mem_writer_cocotb_test.ram_test_multiburst_1_full_burst_and_single_transfer PASS 44510000.00 1.02 43487911.16 ** +** mem_writer_cocotb_test.ram_test_multiburst_crossing_4kb_boundary PASS 3740000.00 0.06 60190612.91 ** +** mem_writer_cocotb_test.ram_test_multiburst_crossing_4kb_boundary_with_perfectly_aligned_full_bursts PASS 21440000.00 0.50 42469371.00 ** +** mem_writer_cocotb_test.ram_test_multiburst_crossing_4kb_boundary_with_2_full_bursts_and_1_transfer PASS 87070000.00 2.01 43348812.05 ** +** mem_writer_cocotb_test.ram_test_random PASS 4491230000.00 109.05 41184670.96 ** +************************************************************************************************************************************************************* +** TESTS=10 PASS=10 FAIL=0 SKIP=0 4824040000.01 116.82 41296261.92 ** +************************************************************************************************************************************************************* +``` diff --git a/xls/modules/zstd/memory/axi_ram_reader.x b/xls/modules/zstd/memory/axi_ram_reader.x index 0b9c2d9cb0..9f9c3ec2f7 100644 --- a/xls/modules/zstd/memory/axi_ram_reader.x +++ b/xls/modules/zstd/memory/axi_ram_reader.x @@ -30,8 +30,7 @@ enum AxiRamReaderStatus: u1 { READ_BURST = 1, } -// FIXME: add default value for RAM_DATA_W_PLUS1_LOG2 = {std::clog2(AXI_DATA_W + u32:1)} (https://github.com/google/xls/issues/992) -struct AxiRamReaderSync { +struct AxiRamReaderSync { do_recv_ram_resp: bool, read_data_size: uN[RAM_DATA_W_PLUS1_LOG2], read_data_offset: uN[RAM_DATA_W_PLUS1_LOG2], @@ -49,8 +48,7 @@ struct AxiRamReaderRequesterState { ram_rd_req_idx: u8, } -// FIXME: add default value for AXI_DATA_W_PLUS1_LOG2 = {std::clog2(AXI_DATA_W + u32:1)} (https://github.com/google/xls/issues/992) -struct AxiRamReaderResponderState { +struct AxiRamReaderResponderState { data: uN[AXI_DATA_W], data_size: uN[AXI_DATA_W_PLUS1_LOG2], } @@ -104,9 +102,6 @@ proc AxiRamReaderRequester< // validate bundle let ar_bundle_ok = ar_bundle_valid && ((ar_bundle.size as u32 + u32:3) <= AXI_DATA_W_LOG2); - //if ar_bundle_valid { - // trace_fmt!("{:#x}", ar_bundle); - //} else {}; let error = ar_bundle_valid && !ar_bundle_ok; let tok = send_if(tok, sync_s, error, Sync { @@ -131,9 +126,6 @@ proc AxiRamReaderRequester< mask: !uN[RAM_NUM_PARTITIONS]:0, }; let tok = send_if(join(), rd_req_s, do_read_from_ram, ram_read_req); - if do_read_from_ram { - trace_fmt!("Sent RAM read request {:#x}", ram_read_req); - } else {}; // send sync let resp = if addr_valid { @@ -254,13 +246,9 @@ proc AxiRamReaderResponder< // receive sync let (tok, sync_data) = recv(tok, sync_r); - trace_fmt!("Received sync {:#x}", sync_data); // receive RAM read respose let (tok, ram_read_resp) = recv_if(tok, rd_resp_r, sync_data.do_recv_ram_resp, zero!()); - if sync_data.do_recv_ram_resp { - trace_fmt!("Received RAM response {:#x}", ram_read_resp); - } else {}; let mask = (uN[RAM_DATA_W]:1 << sync_data.read_data_size) as uN[RAM_DATA_W] - uN[RAM_DATA_W]:1; let mask = (mask << state.data_size); @@ -362,9 +350,7 @@ const INST_RAM_NUM_PARTITIONS = INST_RAM_DATA_W / INST_RAM_WORD_PARTITION_SIZE; const INST_BASE_ADDR = u32:0x8000; -proc AxiRamReaderInst< - FAKE_PARAM: u32 = {u32:0} // FIXME: remove after https://github.com/google/xls/issues/1415 is fixed -> { +proc AxiRamReaderInst { type AxiAr = axi::AxiAr; type AxiR = axi::AxiR; type ReadReq = ram::ReadReq; @@ -696,7 +682,6 @@ proc AxiRamReaderTest { for (j, tok): (u32, token) in u32:0..TEST_RAM_SIZE { if (j <= data_len) { let (tok, data) = recv(tok, axi_r_r); - trace_fmt!("Received data #{} {:#x}", j, data); // compute address let araddr = match axi_ar_bundle.burst { AxiAxBurst::FIXED => { diff --git a/xls/modules/zstd/memory/axi_ram_writer.x b/xls/modules/zstd/memory/axi_ram_writer.x new file mode 100644 index 0000000000..91ca802dd9 --- /dev/null +++ b/xls/modules/zstd/memory/axi_ram_writer.x @@ -0,0 +1,602 @@ +// Copyright 2025 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.zstd.math; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.mem_writer; +import xls.examples.ram; + +struct AxiRamWriterSync { + id: uN[ID_W], + error_code: axi::AxiWriteResp +} + +struct AxiRamWriterRequesterInternalConf { + addr: uN[RAM_ADDR_W], + burst: axi::AxiAxBurst, + transaction_size: u8, + id: uN[ID_W], + addr_overflow: bool, +} + +struct AxiRamWriterRequesterInternalState { + active: bool, + conf: AxiRamWriterRequesterInternalConf, +} + +proc AxiRamWriterRequesterInternal< + ADDR_W: u32, DATA_W: u32, ID_W: u32, RAM_SIZE: u32, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + NUM_PARTITIONS: u32 = { DATA_W / u32:8 }, +> { + type Conf = AxiRamWriterRequesterInternalConf; + type State = AxiRamWriterRequesterInternalState; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type WriteReq = ram::WriteReq; + type WriteResp = ram::WriteResp; + type Sync = AxiRamWriterSync; + + conf_r: chan in; + sync_s: chan out; + + axi_w_r: chan in; + wr_req_s: chan out; + wr_resp_r: chan in; + + init { zero!()} + + config( + conf_r: chan in, + sync_s: chan out, + axi_w_r: chan in, + wr_req_s: chan out, + wr_resp_r: chan in, + ) { + (conf_r, sync_s, axi_w_r, wr_req_s, wr_resp_r) + } + + next(state: State) { + let tok = join(); + + if !state.active { + let (tok, conf) = recv(tok, conf_r); + if conf.addr_overflow { + trace_fmt!("Overflow error: {:#x}", conf); + let tok = send(tok, sync_s, Sync { id: state.conf.id, error_code: axi::AxiWriteResp::DECERR }); + State { active: false, conf: zero!() } + } else { + State { active: true, conf } + } + } else { + let (tok, axi_w) = recv(tok, axi_w_r); + + let (new_addr, supported_mode) = if state.conf.burst == axi::AxiAxBurst::INCR { + (state.conf.addr + uN[RAM_ADDR_W]:1, true) + } else if state.conf.burst == axi::AxiAxBurst::FIXED { + (state.conf.addr, true) + } else { + (state.conf.addr, false) + }; + + if supported_mode { + let tok = send(tok, wr_req_s, WriteReq { + addr: state.conf.addr, + data: axi_w.data, + mask: axi_w.strb, + }); + let (tok, _) = recv(tok, wr_resp_r); // synchronize burst packets with Ram + + if axi_w.last { + let tok = send(tok, sync_s, Sync { id: state.conf.id, error_code: axi::AxiWriteResp::OKAY }); + State { active: false, conf: zero!() } + } else { + State { + active: true, + conf: Conf { addr: new_addr, ..state.conf } + } + } + } else { + trace_fmt!("Unsupported burst type error: {:#x}", state.conf); + let tok = send(tok, sync_s, Sync { id: state.conf.id, error_code: axi::AxiWriteResp::UNSUPPORTED }); + State { active: false, conf: zero!() } + } + } + } +} + +proc AxiRamWriterRequester< + ADDR_W: u32, DATA_W: u32, ID_W: u32, RAM_SIZE: u32, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + NUM_PARTITIONS: u32 = { DATA_W / u32:8 }, + DATA_W_BYTES: u32 = {DATA_W / u32:8 } +> { + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + type WriteReq = ram::WriteReq; + type WriteResp = ram::WriteResp; + type Conf = AxiRamWriterRequesterInternalConf; + type Sync = AxiRamWriterSync; + type Addr = uN[ADDR_W]; + + axi_aw_r: chan in; + axi_w_r: chan in; + axi_b_s: chan out; + wr_req_s: chan out; + conf_s: chan out; + sync_s: chan out; + + init { } + + config( + axi_aw_r: chan in, + axi_w_r: chan in, + axi_b_s: chan out, + wr_req_s: chan out, + wr_resp_r: chan in, + sync_s: chan out, + ) { + const CONF_FIFO_DEPTH=u32:1; + let (conf_s, conf_r) = chan("conf"); + + spawn AxiRamWriterRequesterInternal< + ADDR_W, DATA_W, ID_W, RAM_SIZE, + RAM_ADDR_W, NUM_PARTITIONS + > ( + conf_r, sync_s, axi_w_r, wr_req_s, wr_resp_r + ); + + (axi_aw_r, axi_w_r, axi_b_s, wr_req_s, conf_s, sync_s) + } + + next(state: ()) { + let (tok, aw_bundle) = recv(join(), axi_aw_r); + // convert received address to ram cell address + let addr = (aw_bundle.addr / DATA_W_BYTES); + let tok = send(tok, conf_s, Conf { + addr: addr as uN[RAM_ADDR_W], + burst: aw_bundle.burst, + transaction_size: aw_bundle.len, + id: aw_bundle.id, + addr_overflow: addr > std::unsigned_max_value() as uN[ADDR_W] // address invalid condition + }); + } +} + +proc AxiRamWriterResponder< + ADDR_W: u32, DATA_W: u32, ID_W: u32, RAM_SIZE: u32, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + NUM_PARTITIONS: u32 = { DATA_W / u32:8 }, +> { + type AxiB = axi::AxiB; + type Sync = AxiRamWriterSync; + + axi_b_s: chan out; + sync_r: chan in; + + init { } + + config( + axi_b_s: chan out, + sync_r: chan in, + ) { + (axi_b_s, sync_r) + } + + next(state: ()) { + let (tok, sync) = recv(join(), sync_r); + let axi_response = AxiB { + id: sync.id, + resp: sync.error_code + }; + + send(tok, axi_b_s, axi_response); + } +} + +const SYNC_FIFO_DEPTH=u32:1; +pub proc AxiRamWriter< + ADDR_W: u32, DATA_W: u32,ID_W: u32, RAM_SIZE: u32, + RAM_ADDR_W: u32 = {std::clog2(RAM_SIZE)}, + NUM_PARTITIONS: u32 = { DATA_W / u32:8 }, +> { + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + type WriteReq = ram::WriteReq; + type WriteResp = ram::WriteResp; + type Sync = AxiRamWriterSync; + + init { } + + config( + // AXI interface + axi_aw_r: chan in, + axi_w_r: chan in, + axi_b_s: chan out, + // RAM interface + wr_req_s: chan out, + wr_resp_r: chan in, + ) { + let (sync_s, sync_r) = chan("sync"); + + spawn AxiRamWriterRequester< + ADDR_W, DATA_W, ID_W, RAM_SIZE, + RAM_ADDR_W, NUM_PARTITIONS, + >(axi_aw_r, axi_w_r, axi_b_s, wr_req_s, wr_resp_r, sync_s); + + spawn AxiRamWriterResponder< + ADDR_W, DATA_W, ID_W, RAM_SIZE, + RAM_ADDR_W, NUM_PARTITIONS, + >(axi_b_s, sync_r); + } + + next(state: ()) { } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:32; +const INST_ID_W = u32:8; +const INST_RAM_SIZE = u32:128; +const INST_RAM_ADDR_W: u32 = {std::clog2(INST_RAM_SIZE)}; +const INST_NUM_PARTITIONS = INST_DATA_W / u32:8; + +proc AxiRamWriterInst{ + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + type WriteReq = ram::WriteReq; + type WriteResp = ram::WriteResp; + + init { } + + config( + // AXI interface + axi_aw_r: chan in, + axi_w_r: chan in, + axi_b_s: chan out, + // RAM interface + wr_req_s: chan out, + wr_resp_r: chan in, + ) { + spawn AxiRamWriter< + INST_ADDR_W, INST_DATA_W, INST_ID_W, INST_RAM_SIZE, + INST_RAM_ADDR_W, INST_NUM_PARTITIONS, + > (axi_aw_r, axi_w_r, axi_b_s, wr_req_s, wr_resp_r); + } + + next(state: ()) { } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:32; +const TEST_ID_W = u32:8; +const TEST_RAM_SIZE = u32:128; +const TEST_RAM_ADDR_W: u32 = {std::clog2(INST_RAM_SIZE)}; +const TEST_RAM_WORD = u32:8; +const TEST_NUM_PARTITIONS = TEST_DATA_W / u32:8; +const TEST_RAM_REQ_MASK_ALL = std::unsigned_max_value(); + +type TestAxiAw = axi::AxiAw; +type TestAxiW = axi::AxiW; +type TestAxiB = axi::AxiB; +type TestReadReq = ram::ReadReq; +type TestReadResp = ram::ReadResp; +type TestWriteReq = ram::WriteReq; +type TestWriteResp = ram::WriteResp; +type TestAxiSize = axi::AxiAxSize; +type TestAxiBurst = axi::AxiAxBurst; +type TestAxiId = uN[TEST_ID_W]; +type TestAxiAddr = uN[TEST_ADDR_W]; +type TestDataBits = uN[TEST_DATA_W]; +type TestStrobe = uN[TEST_NUM_PARTITIONS]; +type TestRamAddr = bits[TEST_RAM_ADDR_W]; + + +const ZERO_AXI_AW = zero!(); + +#[test_proc] +proc AxiRamWriterTest { + type RamAddr = uN[TEST_RAM_ADDR_W]; + + terminator: chan out; + axi_aw_s: chan out; + axi_w_s: chan out; + axi_b_r: chan in; + rd_req_s: chan out; + rd_resp_r: chan in; + + init {} + + config( + terminator: chan out, + ) { + let (rd_req_s, rd_req_r) = chan("rd_req"); + let (rd_resp_s, rd_resp_r) = chan("rd_resp"); + let (wr_req_s, wr_req_r) = chan("wr_req"); + let (wr_resp_s, wr_resp_r) = chan("wr_resp"); + + spawn ram::RamModel ( + rd_req_r, rd_resp_s, wr_req_r, wr_resp_s + ); + + let (axi_aw_s, axi_aw_r) = chan("axi_aw"); + let (axi_w_s, axi_w_r) = chan("axi_w"); + let (axi_b_s, axi_b_r) = chan("axi_b"); + + spawn AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_ID_W, TEST_RAM_SIZE, + TEST_RAM_ADDR_W, TEST_NUM_PARTITIONS + > (axi_aw_r, axi_w_r, axi_b_s, wr_req_s, wr_resp_r); + ( + terminator, axi_aw_s, axi_w_s, axi_b_r, rd_req_s, rd_resp_r, + ) + } + next(state: ()) { + let tok = + for((_, (axi_aw, n_axi_w, n_expected, n_addresses)), tok): ((u32, (TestAxiAw, TestAxiW[3], TestDataBits[3], RamAddr[3])), token) in enumerate( + [ + ( + TestAxiAw { + id: TestAxiId:7, + addr: TestAxiAddr:0x4, + size: TestAxiSize::MAX_4B_TRANSFER, + len: u8:2, + burst: TestAxiBurst::INCR + }, + [ + TestAxiW { + data: TestDataBits:0xBEEF, + strb: u4:0b1111, + last: false, + }, + TestAxiW { + data: TestDataBits:0x89ABCDEF, + strb: u4: 0b1111, + last: false + }, + TestAxiW { + data: TestDataBits:0xBADB055, + strb: u4: 0b1111, + last: true + }, + ], + [ + TestDataBits:0xBEEF, + TestDataBits:0x89ABCDEF, + TestDataBits: 0xBADB055 + ], + [ + RamAddr:0x1, RamAddr:0x2, RamAddr:0x3 + ] + ), + ( + TestAxiAw { + id: TestAxiId:7, + addr: TestAxiAddr:0x4, + size: TestAxiSize::MAX_4B_TRANSFER, + len: u8:2, + burst: TestAxiBurst::FIXED + }, + [ + TestAxiW { + data: TestDataBits:0xCC, + strb: u4:0b0001, + last: false, + }, + TestAxiW { + data: TestDataBits:0xBEEF0000, + strb: u4:0b1100, + last: false, + }, + TestAxiW { + data: TestDataBits:0x88888888, + strb: u4:0b0001, + last: true, + }, + ], + [ + TestDataBits:0xBEEFBE88, + TestDataBits:0xBEEFBE88, + TestDataBits:0xBEEFBE88, + ], + [ + RamAddr: 0x1, RamAddr:0x1, RamAddr:0x1 + ] + ) + ] + ) { + let tok = send(tok, axi_aw_s, axi_aw); + let tok = + for ((_, axi_w), tok) in enumerate(n_axi_w) { + let tok = send(tok, axi_w_s, axi_w); + tok + }(tok); + + let (tok, resp) = recv(tok, axi_b_r); + assert_eq( + resp, TestAxiB { + resp: axi::AxiWriteResp::OKAY, + id: axi_aw.id, + } + ); + + let tok = + for ((i, expected), tok) in enumerate(n_expected) { + let tok = send(tok, rd_req_s, TestReadReq { addr: n_addresses[i], mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(expected, resp.data); + tok + }(tok); + + tok + }(join()); + + send(tok, terminator, true); + } +} + +type TestMemWriterReq = mem_writer::MemWriterReq; +type TestMemWriterData = mem_writer::MemWriterDataPacket; +type TestMemWriterResp = mem_writer::MemWriterResp; +type TestMemWriterStatus = mem_writer::MemWriterRespStatus; +const TEST_WRITER_ID = u32:1; + +#[test_proc] +proc AxiRamWriterMemWriterTest { + terminator: chan out; + rd_req_s: chan out; + rd_resp_r: chan in; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + init {} + + config( + terminator: chan out, + ) { + let (rd_req_s, rd_req_r) = chan("rd_req"); + let (rd_resp_s, rd_resp_r) = chan("rd_resp"); + let (wr_req_s, wr_req_r) = chan("wr_req"); + let (wr_resp_s, wr_resp_r) = chan("wr_resp"); + + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_data"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_data"); + + spawn ram::RamModel ( + rd_req_r, rd_resp_s, wr_req_r, wr_resp_s + ); + + let (axi_aw_s, axi_aw_r) = chan("axi_aw"); + let (axi_w_s, axi_w_r) = chan("axi_w"); + let (axi_b_s, axi_b_r) = chan("axi_b"); + + spawn AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_ID_W, TEST_RAM_SIZE, + TEST_RAM_ADDR_W, TEST_NUM_PARTITIONS + > (axi_aw_r, axi_w_r, axi_b_s, wr_req_s, wr_resp_r); + + spawn mem_writer::MemWriter( + mem_wr_req_r, mem_wr_data_r, + axi_aw_s, axi_w_s, axi_b_r, + mem_wr_resp_s, + ); + + ( + terminator, rd_req_s, rd_resp_r, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ) + } + next(state: ()) { + let tok = + for ((_, (req, data, expected)), tok): ((u32, (TestMemWriterReq, TestMemWriterData, u32)), token) in enumerate( + [ + ( + TestMemWriterReq { addr: TestAxiAddr:0, length: u32:4 }, + TestMemWriterData { data: TestDataBits: 0xB16B00B5, last: true, length: u32: 4}, + TestDataBits: 0xB16B00B5, + ), + ( + TestMemWriterReq { addr: TestAxiAddr:0, length: u32:3 }, + TestMemWriterData { data: TestDataBits: 0x888888, last: true, length: u32: 3}, + TestDataBits: 0xB1888888, + ), // test masking + ( + TestMemWriterReq { addr: TestAxiAddr:1, length: u32:3 }, + TestMemWriterData { data: TestDataBits: 0xAAAAAAAA, last: true, length: u32: 3}, + TestDataBits: 0xAAAAAA88, + ), // test unaligned write + ( + TestMemWriterReq { addr: TestAxiAddr:4, length: u32:4 }, + TestMemWriterData { data: TestDataBits: 0xB105F00D, last: true, length: u32: 4}, + TestDataBits: 0xB105F00D, + ), + ( + TestMemWriterReq { addr: TestAxiAddr:6, length: u32:2 }, + TestMemWriterData { data: TestDataBits: 0x0BAD, last: true, length: u32: 2}, + TestDataBits: 0xBADF00D, + ), // test unaligned write + ( + TestMemWriterReq { addr: TestAxiAddr:4, length: u32:2 }, + TestMemWriterData { data: TestDataBits: 0xB055, last: true, length: u32: 2}, + TestDataBits: 0x0BADB055, + ), // test masking + ( + TestMemWriterReq { addr: TestAxiAddr:0, length: u32:4 }, + TestMemWriterData { data: TestDataBits: 0xDEADBEEF, last: true, length: u32: 4}, + TestDataBits: 0xDEADBEEF, + ), + ( + TestMemWriterReq { addr: TestAxiAddr:0x3, length: u32:1 }, + TestMemWriterData { data: TestDataBits: 0xBA, last: true, length: u32: 1}, + TestDataBits: 0xBAADBEEF, + ), // test masking + + ] + ) { + // write data + let tok = send(tok, mem_wr_req_s, req); + let tok = send(tok, mem_wr_data_s, data); + let (tok, resp) = recv(tok, mem_wr_resp_r); + assert_eq(resp.status, TestMemWriterStatus::OKAY); + + // read directly from memory cell to see if it's correct + let cell = req.addr as TestRamAddr / TEST_NUM_PARTITIONS as TestRamAddr; + let tok = send(tok, rd_req_s, TestReadReq { addr: cell as TestRamAddr, mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(expected, resp.data); + + tok + }(join()); + + // test multiple data transactions + let tok = send(tok, mem_wr_req_s, TestMemWriterReq { addr: TestAxiAddr:0x40, length: u32:16 }); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { data: TestDataBits: 0x12345678, last: false, length: u32: 4}); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { data: TestDataBits: 0x89ABCDEF, last: false, length: u32: 4}); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { data: TestDataBits: 0xFEDCBA98, last: false, length: u32: 4}); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { data: TestDataBits: 0x76543210, last: true, length: u32: 4}); + let (tok, resp) = recv(tok, mem_wr_resp_r); + assert_eq(resp.status, TestMemWriterStatus::OKAY); + // read directly from memory cells to see if it's correct + let cell = TestRamAddr:0x40 / TEST_NUM_PARTITIONS as TestRamAddr; + let tok = send(tok, rd_req_s, TestReadReq { addr: cell, mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(u32:0x12345678, resp.data); + let cell = TestRamAddr:0x44 / TEST_NUM_PARTITIONS as TestRamAddr; + let tok = send(tok, rd_req_s, TestReadReq { addr: cell, mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(u32:0x89ABCDEF, resp.data); + let cell = TestRamAddr:0x48 / TEST_NUM_PARTITIONS as TestRamAddr; + let tok = send(tok, rd_req_s, TestReadReq { addr: cell, mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(u32:0xFEDCBA98, resp.data); + let cell = TestRamAddr:0x4C / TEST_NUM_PARTITIONS as TestRamAddr; + let tok = send(tok, rd_req_s, TestReadReq { addr: cell, mask: TEST_RAM_REQ_MASK_ALL }); + let (tok, resp) = recv(tok, rd_resp_r); + assert_eq(u32:0x76543210, resp.data); + + // test invalid address + let tok = send(tok, mem_wr_req_s, TestMemWriterReq { addr: TEST_NUM_PARTITIONS as TestAxiAddr * TEST_RAM_SIZE as TestAxiAddr, length: u32:4 }); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { data: TestDataBits: 0x12345678, last: false, length: u32: 4}); + let (tok, resp) = recv(tok, mem_wr_resp_r); + + assert_eq(resp.status, TestMemWriterStatus::ERROR); + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/memory/axi_reader.x b/xls/modules/zstd/memory/axi_reader.x index 43504eea30..11a5663e42 100644 --- a/xls/modules/zstd/memory/axi_reader.x +++ b/xls/modules/zstd/memory/axi_reader.x @@ -14,6 +14,9 @@ // This file contains implementation of AxiReader proc that can be used to // to issue AXI read requests as an AXI Manager device +// The AxiReader starts by getting a request. +// It sends a read address (AR), then waits for the AxiReaderInternalR to handle all the read data (R). +// After that, it either sends another AR or returns a response if there's no more data import std; @@ -39,7 +42,7 @@ pub enum AxiReaderError: u1 { TRANSFER_ERROR = 0, } -// Returnes true if the provided data width is correct, +// Returns true if the provided data width is correct, // according to the AXI specification. Otherwise it retuns false. fn is_valid_axi_data_width(x: u32) -> bool { match (x) { @@ -75,6 +78,239 @@ struct AxiReaderState< req_high_lane: uN[LANE_W], // high byte lane calculated from the request } +struct AxiReaderInternalRConfig { + addr: uN[ADDR_W], + len: uN[ADDR_W], + ar_len: u8, // transfer len requested in the last AR + req_low_lane: uN[LANE_W], // low byte lane calculated for the first transaction + req_high_lane: uN[LANE_W], // high byte lane calculated from the request +} + +struct AxiReaderInternalRState { + active: bool, + conf: AxiReaderInternalRConfig +} + +struct AxiReaderInternalState { + active: bool, + addr: uN[ADDR_W], + len: uN[ADDR_W] +} + +pub proc AxiReaderInternalR< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, + + DATA_W_DIV8:u32 = {DATA_W / u32:8}, + LANE_W: u32 = {std::clog2(DATA_W_DIV8)}, + LANE_DATA_W_DIV8_PLUS_ONE: u32 = {std::clog2(DATA_W_DIV8) + u32:1}, + TRAN_W: u32 = {std::clog2((u32:1 << ADDR_W) / DATA_W_DIV8)}, +> { + type State = AxiReaderInternalRState; + type Conf = AxiReaderInternalRConfig; + + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + type AxiRResp = axi::AxiReadResp; + + type Data = uN[DATA_W]; + type Length = uN[ADDR_W]; + type Addr = uN[ADDR_W]; + type Lane = uN[LANE_W]; + + conf_r: chan in; + resp_s: chan out; + axi_r_r: chan in; + axi_st_s: chan out; + + init { zero!() } + config( + conf_r: chan in, + resp_s: chan out, + axi_r_r: chan in, + axi_st_s: chan out, + ) { + ( + conf_r, resp_s, + axi_r_r, axi_st_s + ) + } + next(state: State) { + const MAX_LANE = !Lane:0; + + let tok = join(); + let conf = state.conf; + + if (!state.active) { + let (tok, conf) = recv(tok, conf_r); + State { + active: true, + conf: conf + } + } else { + let (tok, axi_r) = recv(tok, axi_r_r); + let is_err = axi_r.resp != AxiRResp::OKAY; + let is_last_group = (conf.ar_len == u8:0); + let is_last_tran = (conf.len == Addr:0); + + let low_lane = conf.req_low_lane; + let high_lane = if is_last_group { conf.req_high_lane } else { MAX_LANE }; + let mask = common::lane_mask(low_lane, high_lane); + + let tok = send_if(tok, axi_st_s, !is_err, + AxiStream { + data: axi_r.data, + str: mask, + keep: mask, + last: is_last_group & is_last_tran, + id: uN[ID_W]:0, + dest: uN[DEST_W]:0, + } + ); + + if is_last_group { + let tok = send(tok, resp_s, is_err); + zero!() + } else { + State { + active: true, + conf: Conf { + ar_len: conf.ar_len - u8:1, + req_low_lane: uN[LANE_W]:0, + ..conf + } + } + } + } + } +} + +pub proc AxiReaderNoFsm< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, + + DATA_W_DIV8:u32 = {DATA_W / u32:8}, + LANE_W: u32 = {std::clog2(DATA_W_DIV8)}, + LANE_DATA_W_DIV8_PLUS_ONE: u32 = {std::clog2(DATA_W_DIV8) + u32:1}, + TRAN_W: u32 = {std::clog2((u32:1 << ADDR_W) / DATA_W_DIV8)}, +> { + type State = AxiReaderInternalState; + type Req = AxiReaderReq; + type Resp = axi::AxiReadResp; + type Error = AxiReaderError; + type Rconf = AxiReaderInternalRConfig; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + + type Data = uN[DATA_W]; + type Length = uN[ADDR_W]; + type Addr = uN[ADDR_W]; + type Lane = uN[LANE_W]; + + const_assert!(is_valid_axi_data_width(DATA_W)); + const_assert!(is_valid_axi_addr_width(ADDR_W)); + + req_r: chan in; + axi_ar_s: chan out; + err_s: chan out; + + rconf_s: chan out; + rresp_r: chan in; + + init { zero!() } + + config( + req_r: chan in, + axi_ar_s: chan out, + axi_r_r: chan in, + axi_st_s: chan out, + err_s: chan out + ) { + let (rconf_s, rconf_r) = chan("rconf"); + let (rresp_s, rresp_r) = chan("rresp"); + + spawn AxiReaderInternalR + ( + rconf_r, rresp_s, axi_r_r, axi_st_s + ); + + ( + req_r, axi_ar_s, err_s, + rconf_s, rresp_r + ) + } + + next(state: State) { + const BYTES_IN_TRANSFER = DATA_W_DIV8 as Addr; + const MAX_AXI_BURST_BYTES = Addr:256 * BYTES_IN_TRANSFER; + + let tok = join(); + if !state.active { + let (tok, req) = recv(tok, req_r); + State { + active: true, + addr: req.addr, + len: req.len + } + } else { + // send AR + let aligned_addr = common::align(state.addr); + let aligned_offset = common::offset(state.addr); + + let bytes_to_max_burst = MAX_AXI_BURST_BYTES - aligned_offset as Length; + let bytes_to_4k = common::bytes_to_4k_boundary(state.addr); + + let tran_len = std::min(state.len, std::min(bytes_to_4k, bytes_to_max_burst)); + let (req_low_lane, req_high_lane) = common::get_lanes(state.addr, tran_len); + let adjusted_tran_len = aligned_offset as Addr + tran_len; + let rest = std::mod_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) != Length:0; + let ar_len = if rest { + std::div_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) as u8 + } else { + (std::div_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) - Length:1) as u8 + }; + + let next_addr = state.addr + tran_len; + let next_len = state.len - tran_len; + + let tok1 = send(tok, axi_ar_s, axi::AxiAr { + id: uN[ID_W]:0, + addr: aligned_addr, + region: u4:0, + len: ar_len, + size: common::axsize(), + burst: axi::AxiAxBurst::INCR, + cache: axi::AxiArCache::DEV_NO_BUF, + prot: u3:0, + qos: u4:0, + } + ); + let tok2 = send(tok, rconf_s, Rconf { + addr: aligned_addr, + len: next_len, + ar_len: ar_len, + req_high_lane: req_high_lane, + req_low_lane: req_low_lane + }); + let (tok, is_err) = recv(join(tok1, tok2), rresp_r); + let tok = send_if(tok, err_s, is_err, Error::TRANSFER_ERROR); + + + let next_len_or_exit = if is_err { Addr:0 } else { next_len }; + + if next_len_or_exit == Addr:0 { + zero!() + } else { + State { + active: true, + addr: next_addr, + len: next_len_or_exit + } + } + } + } +} + // Proc responsible for issuing AXI read request as an AXI Manager device. // Supports unaligned transactions, and respects the 4kB boundaries. @@ -266,6 +502,58 @@ proc AxiReaderInst { next(state: ()) { } } +proc AxiReaderNoFsmInst { + type Req = AxiReaderReq; + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + type Error = AxiReaderError; + + config( + req_r: chan in, + axi_ar_s: chan out, + axi_r_r: chan in, + axi_st_s: chan out, + err_s: chan out, + ) { + + spawn AxiReaderNoFsm( + req_r, axi_ar_s, axi_r_r, axi_st_s, err_s + ); + } + + init { () } + next(state: ()) { } +} + +const INST_ADV_AXI_DATA_W = u32:128; +const INST_ADV_AXI_ADDR_W = u32:16; +const INST_ADV_AXI_DEST_W = u32:8; +const INST_ADV_AXI_ID_W = u32:8; +const INST_ADV_AXI_DATA_W_DIV8 = INST_ADV_AXI_DATA_W / u32:8; +const INST_ADV_AXI_LANE_W = std::clog2(INST_ADV_AXI_DATA_W_DIV8); + +proc AxiReaderInternalRInst { + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + type Conf = AxiReaderInternalRConfig; + + config( + conf_r: chan in, + resp_s: chan out, + axi_r_r: chan in, + axi_st_s: chan out, + ) { + + spawn AxiReaderInternalR( + conf_r, resp_s, axi_r_r, axi_st_s + ); + } + + init { () } + next(state: ()) { } +} + const TEST_ADDR_W = u32:16; const TEST_DATA_W = u32:32; @@ -317,7 +605,7 @@ proc AxiReaderTest { let (axi_st_s, axi_st_r) = chan("axi_st"); let (err_s, err_r) = chan("error"); - spawn AxiReader( + spawn AxiReaderNoFsm( req_r, axi_ar_s, axi_r_r, axi_st_s, err_s); (terminator, req_s, axi_ar_r, axi_r_s, axi_st_r, err_r) diff --git a/xls/modules/zstd/memory/axi_stream_remove_empty.x b/xls/modules/zstd/memory/axi_stream_remove_empty.x index 4e5b1f0de7..1dd70c123f 100644 --- a/xls/modules/zstd/memory/axi_stream_remove_empty.x +++ b/xls/modules/zstd/memory/axi_stream_remove_empty.x @@ -364,7 +364,7 @@ pub proc AxiStreamRemoveEmpty< stream_in_r: chan in, stream_out_s: chan out, ) { - let (continuous_stream_s, continuous_stream_r) = chan("continuous_stream"); + let (continuous_stream_s, continuous_stream_r) = chan("continuous_stream"); spawn RemoveEmptyBytes( stream_in_r, diff --git a/xls/modules/zstd/memory/axi_writer.x b/xls/modules/zstd/memory/axi_writer.x index 1a5e7c5eef..09c307ec6c 100644 --- a/xls/modules/zstd/memory/axi_writer.x +++ b/xls/modules/zstd/memory/axi_writer.x @@ -75,6 +75,246 @@ struct AxiWriterState< req_high_lane: uN[LANE_W], } +struct AxiWriterInternalWConfig { + addr: uN[ADDR_W], + len: uN[ADDR_W], + aw_len: u8, + req_low_lane: uN[LANE_W], + req_high_lane: uN[LANE_W], +} + +struct AxiWriterInternalWState { + active: bool, + conf: AxiWriterInternalWConfig +} + +struct AxiWriterInternalState { + active: bool, + addr: uN[ADDR_W], + len: uN[ADDR_W], + is_err: bool, + bundle_id: uN[ADDR_W], +} + + +pub proc AxiWriterInternalW< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, + + DATA_W_DIV8: u32 = {DATA_W / u32:8}, + LANE_W: u32 = {std::clog2(DATA_W / u32:8)} +> { + type State = AxiWriterInternalWState; + type Conf = AxiWriterInternalWConfig; + + type AxiStream = axi_st::AxiStream; + type AxiW = axi::AxiW; + + type Addr = uN[ADDR_W]; + type Lane = uN[LANE_W]; + type Id = uN[ID_W]; + type Length = uN[ADDR_W]; + + conf_r: chan in; + resp_s: chan<()> out; + axi_w_s: chan out; + axi_st_r: chan in; + + init { zero!() } + config( + conf_r: chan in, + resp_s: chan<()> out, + axi_w_s: chan out, + axi_st_r: chan in + ) { + ( + conf_r, resp_s, + axi_w_s, axi_st_r + ) + } + next(state: State) { + const MAX_LANE = std::unsigned_max_value(); + + let tok = join(); + let conf = state.conf; + + if !state.active { + let (tok, conf) = recv(tok, conf_r); + State { + active: true, + conf: conf + } + } else { + let (tok, r_data) = recv(tok, axi_st_r); + let is_last_group = (conf.aw_len == u8:0); + + let low_lane = conf.req_low_lane; + let high_lane = if is_last_group { conf.req_high_lane } else { MAX_LANE }; + let mask = common::lane_mask(low_lane, high_lane); + + let tok = send(tok, axi_w_s, AxiW { + data: r_data.data, + strb: mask, + last: is_last_group, + }); + + if is_last_group { + let tok = send(tok, resp_s, ()); + zero!() + } else { + State { + active: true, + conf: Conf { + aw_len: conf.aw_len - u8:1, + req_low_lane: uN[LANE_W]:0, + ..conf + } + } + } + } + } +} + +pub proc AxiWriterNoFsm< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, + + DATA_W_DIV8: u32 = {DATA_W / u32:8}, + LANE_W: u32 = {std::clog2(DATA_W / u32:8)} +> { + type State = AxiWriterInternalState; + type Req = AxiWriterRequest; + type Wconf = AxiWriterInternalWConfig; + + type AxiStream = axi_st::AxiStream; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + type AxiResp = axi::AxiWriteResp; + type AxiAxSize = axi::AxiAxSize; + type AxiAxBurst = axi::AxiAxBurst; + + type Addr = uN[ADDR_W]; + type Lane = uN[LANE_W]; + type Id = uN[ID_W]; + type Length = uN[ADDR_W]; + + req_r: chan in; + resp_s: chan out; + axi_aw_s: chan out; + axi_b_r: chan in; + + wconf_s: chan out; + wresp_r: chan<()> in; + + + config( + req_r: chan in, + resp_s: chan out, + axi_aw_s: chan out, + axi_w_s: chan out, + axi_b_r: chan in, + axi_st_r: chan in + ) { + let (wconf_s, wconf_r) = chan("wconf"); + let (wresp_s, wresp_r) = chan<(), u32:1>("wresp"); + + + spawn AxiWriterInternalW + ( + wconf_r, wresp_s, + axi_w_s, axi_st_r + ); + + ( + req_r, resp_s, axi_aw_s, axi_b_r, + wconf_s, wresp_r + ) + } + + init { + zero!() + } + + next(state: State) { + const BYTES_IN_TRANSFER = DATA_W_DIV8 as Addr; + const MAX_AXI_BURST_BYTES = Addr:256 * BYTES_IN_TRANSFER; + + let tok = join(); + if (!state.active) { + let (tok, req) = recv(tok, req_r); + State { + active: true, + addr: req.address, + len: req.length, + ..state + } + } else { + let aligned_addr = common::align(state.addr); + let aligned_offset = common::offset(state.addr) as Addr; + + let bytes_to_max_burst = MAX_AXI_BURST_BYTES - aligned_offset as Addr; + let bytes_to_4k = common::bytes_to_4k_boundary(state.addr); + + let tran_len = std::min(state.len, std::min(bytes_to_4k, bytes_to_max_burst)); + let (req_low_lane, req_high_lane) = common::get_lanes(state.addr, tran_len); + let adjusted_tran_len = aligned_offset as Addr + tran_len; + let rest = std::mod_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) != Length:0; + let aw_len = if rest { + std::div_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) as u8 + } else { + (std::div_pow2(adjusted_tran_len, BYTES_IN_TRANSFER) - Length:1) as u8 + }; + + let next_addr = state.addr + tran_len; + let next_len = state.len - tran_len; + + let aw_bundle = AxiAw { + id: uN[ID_W]:1 + state.bundle_id as uN[ID_W], + addr: aligned_addr, + size: common::axsize(), + len: aw_len, + burst: AxiAxBurst::INCR, + }; + + let tok = send(tok, axi_aw_s, aw_bundle); + let tok = send(tok, wconf_s, + Wconf { + addr: aligned_addr, + len: next_len, + aw_len: aw_len, + req_high_lane: req_high_lane, + req_low_lane: req_low_lane + } + ); + + let (tok, _) = recv(tok, wresp_r); + let (tok, axi_b) = recv(tok, axi_b_r); + let is_err = axi_b.resp != AxiResp::OKAY; + + let is_last_tran = (next_len == Addr:0); + if is_last_tran || is_err { + let status = if state.is_err { AxiWriterRespStatus::ERROR } else { AxiWriterRespStatus::OKAY }; + let tok = send(tok, resp_s, AxiWriterResp { + status: status + }); + State { + bundle_id: state.bundle_id + Addr:1, + ..zero!() + } + } else { + State { + bundle_id: state.bundle_id + Addr:1, + active: true, + addr: next_addr, + len: next_len, + is_err: is_err, + } + } + } + + } +} + + pub proc AxiWriter< ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, DATA_W_DIV8: u32 = {DATA_W / u32:8}, @@ -328,6 +568,32 @@ proc AxiWriterInst { next(state: ()) { } } +proc AxiWriterNoFsmInst { + type InstReq = AxiWriterRequest; + type InstAxiWriterResp = AxiWriterResp; + type InstAxiStream = axi_st::AxiStream; + type InstAxiAw = axi::AxiAw; + type InstAxiW = axi::AxiW; + type InstAxiB = axi::AxiB; + + config(ch_write_req: chan in, + ch_write_resp: chan out, + ch_axi_aw: chan out, + ch_axi_w: chan out, + ch_axi_b: chan in, + ch_axi_st_read: chan in) { + + spawn AxiWriterNoFsm< + INST_ADDR_W, INST_DATA_W, INST_DEST_W, INST_ID_W>( + ch_write_req, ch_write_resp, ch_axi_aw, ch_axi_w, ch_axi_b, ch_axi_st_read); + () + } + + init { () } + + next(state: ()) { } +} + const TEST_ADDR_W = u32:16; const TEST_DATA_W = u32:32; const TEST_DATA_W_DIV8 = INST_DATA_W / u32:8; @@ -372,7 +638,7 @@ proc AxiWriterTest { let (axi_b_s, axi_b_r) = chan("axi_b"); let (axi_st_read_s, axi_st_read_r) = chan("axi_st"); - spawn AxiWriter< + spawn AxiWriterNoFsm< TEST_ADDR_W, TEST_DATA_W, TEST_DEST_W, TEST_ID_W >(write_req_r, write_resp_s, axi_aw_s, axi_w_s, axi_b_r, axi_st_read_r); (terminator, write_req_s, write_resp_r, axi_aw_r, axi_w_r, axi_b_s, axi_st_read_s) diff --git a/xls/modules/zstd/memory/axi_writer_cocotb.py b/xls/modules/zstd/memory/axi_writer_cocotb.py new file mode 100644 index 0000000000..d655c6f8e0 --- /dev/null +++ b/xls/modules/zstd/memory/axi_writer_cocotb.py @@ -0,0 +1,245 @@ +#!/usr/bin/env python +# Copyright 2024 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 random +import logging +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles, Event +from cocotb.binary import BinaryValue +from cocotb_bus.scoreboard import Scoreboard + +from cocotbext.axi.axis import AxiStreamSource, AxiStreamBus, AxiStreamFrame +from cocotbext.axi.axi_channels import AxiAWBus, AxiWBus, AxiBBus, AxiWriteBus, AxiAWMonitor, AxiWMonitor, AxiBMonitor, AxiBTransaction, AxiBSource, AxiBSink +from cocotbext.axi.axi_ram import AxiRamWrite +from cocotbext.axi.sparse_memory import SparseMemory + +from xls.modules.zstd.cocotb.channel import ( + XLSChannel, + XLSChannelDriver, + XLSChannelMonitor, +) +from xls.modules.zstd.cocotb.utils import reset, run_test +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct, xls_dataclass + +ID_WIDTH = 4 +ADDR_WIDTH = 16 + +# Override default widths of AXI response signals +signal_widths = {"bresp": 3} +AxiBBus._signal_widths = signal_widths +AxiBTransaction._signal_widths = signal_widths +AxiBSource._signal_widths = signal_widths +AxiBSink._signal_widths = signal_widths +AxiBMonitor._signal_widths = signal_widths + +@xls_dataclass +class AxiWriterRespStruct(XLSStruct): + status: 1 + +@xls_dataclass +class WriteRequestStruct(XLSStruct): + address: ADDR_WIDTH + length: ADDR_WIDTH + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + event.set() + monitor.add_callback(terminate_cb) + +@cocotb.test(timeout_time=20000, timeout_unit="ms") +async def ram_test(dut): + GENERIC_ADDR_REQ_CHANNEL = "write_req" + GENERIC_ADDR_RESP_CHANNEL = "write_resp" + AXI_STREAM_CHANNEL = "axi_st_read" + AXI_AW_CHANNEL = "axi_aw" + AXI_W_CHANNEL = "axi_w" + AXI_B_CHANNEL = "axi_b" + + terminate = Event() + + mem_size = 2**ADDR_WIDTH + test_count = 200 + + (addr_req_input, axi_st_input, addr_resp_expect, memory_verification, expected_memory) = generate_test_data_random(test_count, mem_size) + + dut.rst.setimmediatevalue(0) + + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + resp_bus = XLSChannel(dut, GENERIC_ADDR_RESP_CHANNEL, dut.clk, start_now=True) + + driver_addr_req = XLSChannelDriver(dut, GENERIC_ADDR_REQ_CHANNEL, dut.clk) + driver_axi_st = AxiStreamSource(AxiStreamBus.from_prefix(dut, AXI_STREAM_CHANNEL), dut.clk, dut.rst) + + bus_axi_aw = AxiAWBus.from_prefix(dut, AXI_AW_CHANNEL) + bus_axi_w = AxiWBus.from_prefix(dut, AXI_W_CHANNEL) + bus_axi_b = AxiBBus.from_prefix(dut, AXI_B_CHANNEL) + bus_axi_write = AxiWriteBus(bus_axi_aw, bus_axi_w, bus_axi_b) + + monitor_addr_req = XLSChannelMonitor(dut, GENERIC_ADDR_REQ_CHANNEL, dut.clk, WriteRequestStruct) + monitor_addr_resp = XLSChannelMonitor(dut, GENERIC_ADDR_RESP_CHANNEL, dut.clk, AxiWriterRespStruct) + monitor_axi_aw = AxiAWMonitor(bus_axi_aw, dut.clk, dut.rst) + monitor_axi_w = AxiWMonitor(bus_axi_w, dut.clk, dut.rst) + monitor_axi_b = AxiBMonitor(bus_axi_b, dut.clk, dut.rst) + + set_termination_event(monitor_addr_resp, terminate, test_count) + + memory = AxiRamWrite(bus_axi_write, dut.clk, dut.rst, size=mem_size) + + log = logging.getLogger("cocotb.tb") + log.setLevel(logging.WARNING) + memory.log.setLevel(logging.WARNING) + driver_axi_st.log.setLevel(logging.WARNING) + + scoreboard = Scoreboard(dut) + scoreboard.add_interface(monitor_addr_resp, addr_resp_expect) + + await reset(dut.clk, dut.rst, cycles=10) + await cocotb.start(driver_addr_req.send(addr_req_input)) + await cocotb.start(drive_axi_st(driver_axi_st, axi_st_input)) + await terminate.wait() + + for bundle in memory_verification: + memory_contents = bytearray(memory.read(bundle["base_address"], bundle["length"])) + expected_memory_contents = bytearray(expected_memory.read(bundle["base_address"], bundle["length"])) + assert memory_contents == expected_memory_contents, "{} bytes of memory contents at base address {}:\n{}\nvs\n{}\nHEXDUMP:\n{}\nvs\n{}".format(hex(bundle["length"]), hex(bundle["base_address"]), memory_contents, expected_memory_contents, memory.hexdump(bundle["base_address"], bundle["length"]), expected_memory.hexdump(bundle["base_address"], bundle["length"])) + +@cocotb.coroutine +async def drive_axi_st(driver, inputs): + for axi_st_input in inputs: + await driver.send(axi_st_input) + +def generate_test_data_random(test_count, mem_size): + AXI_AXSIZE_ENCODING_MAX_4B_TRANSFER = 2 # Must be in sync with AXI_AXSIZE_ENCODING enum in axi.x + + addr_req_input = [] + axi_st_input = [] + addr_resp_expect = [] + memory_verification = [] + memory = SparseMemory(mem_size) + + random.seed(1234) + + for i in range(test_count): + xfer_addr = random.randrange(0, mem_size) + # Don't allow unaligned writes + xfer_addr_aligned = (xfer_addr // 4) * 4 + # Make sure we don't write beyond available memory + memory_size_max_xfer_len = mem_size - xfer_addr_aligned + arbitrary_max_xfer_len = 0x5000 # 20kB + xfer_max_len = min(arbitrary_max_xfer_len, memory_size_max_xfer_len) + xfer_len = random.randrange(1, xfer_max_len) + transfer_req = WriteRequestStruct( + address = xfer_addr_aligned, + length = xfer_len, + ) + addr_req_input.append(transfer_req) + + data_to_write = random.randbytes(xfer_len) + axi_st_frame = AxiStreamFrame(tdata=data_to_write, tkeep=[15]*xfer_len, tid=(i % (1 << ID_WIDTH)), tdest=(i % (1 << ID_WIDTH))) + axi_st_input.append(axi_st_frame) + + write_expected_memory(transfer_req, axi_st_frame.tdata, memory) + + memory_bundle = { + "base_address": transfer_req.address, + "length": transfer_req.length, + } + memory_verification.append(memory_bundle) + + addr_resp_expect = [AxiWriterRespStruct(status=False)] * test_count + + return (addr_req_input, axi_st_input, addr_resp_expect, memory_verification, memory) + +def bytes_to_4k_boundary(addr): + AXI_4K_BOUNDARY = 0x1000 + return AXI_4K_BOUNDARY - (addr % AXI_4K_BOUNDARY) + +def write_expected_memory(transfer_req, data_to_write, memory): + """ + Write test data to reference memory keeping the AXI 4kb boundary + by spliting the write requests into smaller ones. + """ + prev_id = 0 + address = transfer_req.address + length = transfer_req.length + + BYTES_IN_TRANSFER = 4 + MAX_AXI_BURST_BYTES = 256 * BYTES_IN_TRANSFER + + while (length > 0): + bytes_to_4k = bytes_to_4k_boundary(address) + new_len = min(length, min(bytes_to_4k, MAX_AXI_BURST_BYTES)) + new_data = data_to_write[prev_id:prev_id+new_len] + memory.write(address, new_data) + address = address + new_len + length = length - new_len + prev_id = prev_id + new_len + +def generate_test_data_arbitrary(mem_size): + AXI_AXSIZE_ENCODING_MAX_4B_TRANSFER = 2 # Must be in sync with AXI_AXSIZE_ENCODING enum in axi.x + + addr_req_input = [] + axi_st_input = [] + addr_resp_expect = [] + memory_verification = [] + memory = SparseMemory(mem_size) + + xfer_addr_begin = [0, 8, 512, 1000, 0x1234, 256] + xfer_len = [1, 2, 4, 8, 0x48d, 4] + assert len(xfer_len) == len(xfer_addr_begin) + testcase_num = len(xfer_addr_begin) # test cases to execute + for i in range(testcase_num): + transfer_req = WriteRequestStruct( + address = xfer_addr_begin[i], + length = xfer_len[i] * 4, # xfer_len[i] transfers per 4 bytes + ) + addr_req_input.append(transfer_req) + + data_chunks = [] + data_bytes = [[(0xEF + j) & 0xFF, 0xBE, 0xAD, 0xDE] for j in range(xfer_len[i])] + data_words = [int.from_bytes(data_bytes[j]) for j in range(xfer_len[i])] + for j in range(xfer_len[i]): + data_chunks += data_bytes[j] + data_to_write = bytearray(data_chunks) + axi_st_frame = AxiStreamFrame(tdata=data_to_write, tkeep=[15]*xfer_len[i], tid=i, tdest=i) + axi_st_input.append(axi_st_frame) + + write_expected_memory(transfer_req, axi_st_frame.tdata, memory) + + memory_bundle = { + "base_address": transfer_req.address, + "length": transfer_req.length, # 4 byte words + } + memory_verification.append(memory_bundle) + + addr_resp_expect = [AxiWriterRespStruct(status=False)] * testcase_num + + return (addr_req_input, axi_st_input, addr_resp_expect, memory_verification, memory) + +if __name__ == "__main__": + toplevel = "axi_writer_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/axi_writer.v", + "xls/modules/zstd/memory/rtl/axi_writer_wrapper.v", + ] + test_module=[Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/axi_writer_cocotb_test.py b/xls/modules/zstd/memory/axi_writer_cocotb_test.py new file mode 100644 index 0000000000..61cc3185a4 --- /dev/null +++ b/xls/modules/zstd/memory/axi_writer_cocotb_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# Copyright 2025 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + toplevel = "axi_writer_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/axi_writer.v", + "xls/modules/zstd/memory/rtl/axi_writer_wrapper.sv", + ] + test_module=[ "axi_writer_cocotb" ] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/axi_writer_no_fsm_cocotb_test.py b/xls/modules/zstd/memory/axi_writer_no_fsm_cocotb_test.py new file mode 100644 index 0000000000..1eed4ecf4a --- /dev/null +++ b/xls/modules/zstd/memory/axi_writer_no_fsm_cocotb_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# Copyright 2025 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + toplevel = "axi_writer_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/axi_writer_no_fsm.v", + "xls/modules/zstd/memory/rtl/axi_writer_wrapper.sv", + ] + test_module=[ "axi_writer_cocotb" ] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/mem_reader.x b/xls/modules/zstd/memory/mem_reader.x index f96257663c..42b04da513 100644 --- a/xls/modules/zstd/memory/mem_reader.x +++ b/xls/modules/zstd/memory/mem_reader.x @@ -62,6 +62,110 @@ struct MemReaderState { base: uN[AXI_ADDR_W], } +struct MemReaderInternalState { + active: bool +} + +proc MemReaderInternalNoFsm< + // DSLX side parameters + DSLX_DATA_W: u32, DSLX_ADDR_W: u32, + // AXI side parameters + AXI_DATA_W: u32, AXI_ADDR_W: u32, AXI_DEST_W: u32, AXI_ID_W: u32, + // parameters calculated from other values + DSLX_DATA_W_DIV8: u32 = {DSLX_DATA_W / u32:8}, + AXI_DATA_W_DIV8: u32 = {AXI_DATA_W / u32:8}, + AXI_TO_DSLX_RATIO: u32 = {AXI_DATA_W / DSLX_DATA_W}, + AXI_TO_DSLX_RATIO_W: u32 = {std::clog2((AXI_DATA_W / DSLX_DATA_W) + u32:1)} +> { + type Req = MemReaderReq; + type Resp = MemReaderResp; + type Length = uN[DSLX_ADDR_W]; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiReaderError = axi_reader::AxiReaderError; + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStreamInput = axi_st::AxiStream; + type AxiStreamOutput = axi_st::AxiStream; + + type State = MemReaderInternalState; + type Fsm = MemReaderFsm; + + // Assumptions related to parameters + const_assert!(DSLX_DATA_W % u32:8 == u32:0); // DSLX-side data width should be divisible by 8 + const_assert!(AXI_DATA_W % u32:8 == u32:0); // AXI-side data width should be divisible by 8 + const_assert!(AXI_DATA_W >= DSLX_DATA_W); // AXI-side width should be wider or has the same width as DSLX-side + const_assert!(AXI_DATA_W % DSLX_DATA_W == u32:0); // DSLX-side width should be a multiple of AXI-side width + + // checks for parameters + const_assert!(DSLX_DATA_W_DIV8 == DSLX_DATA_W / u32:8); + const_assert!(AXI_DATA_W_DIV8 == AXI_DATA_W / u32:8); + const_assert!(AXI_TO_DSLX_RATIO == AXI_DATA_W / DSLX_DATA_W); + const_assert!(AXI_TO_DSLX_RATIO_W == std::clog2((AXI_DATA_W / DSLX_DATA_W) + u32:1)); + + req_r: chan in; + resp_s: chan out; + + reader_req_s: chan out; + reader_err_r: chan in; + + axi_st_out_r: chan in; + + config( + req_r: chan in, + resp_s: chan out, + reader_req_s: chan out, + reader_err_r: chan in, + axi_st_out_r: chan in, + ) { + (req_r, resp_s, reader_req_s, reader_err_r, axi_st_out_r) + } + + init { zero!() } + + next(state: State) { + type Resp = MemReaderResp; + type DslxData = uN[DSLX_DATA_W]; + type DslxLength = uN[DSLX_ADDR_W]; + type AxiLength = uN[AXI_ADDR_W]; + type AxiStr = uN[AXI_DATA_W_DIV8]; + type AxiKeep = uN[AXI_DATA_W_DIV8]; + type Status = MemReaderStatus; + + const READER_RESP_ERROR = Resp { status: Status::ERROR, ..zero!() }; + const READER_RESP_ZERO = Resp { status: Status::OKAY, last: true, ..zero!() }; + + let tok = join(); + + if (!state.active) { + let (tok, req) = recv(tok, req_r); + let tok = send_if(tok, reader_req_s, req.length != Length:0, axi_reader::AxiReaderReq { + addr: req.addr, + len: req.length + }); + + let tok = send_if(tok, resp_s, req.length == Length:0, READER_RESP_ZERO); // explicitly handle zero length corner-case + + State { + active: req.length != Length:0, + } + } else { + // simultaneously check for error and a new stream message + let (tok, _, error) = recv_non_blocking(tok, reader_err_r, zero!()); + let (tok, st, st_received) = recv_non_blocking(tok, axi_st_out_r, zero!()); + + let length = std::popcount(st.str | st.keep) as Length; + let tok = send_if(tok, resp_s, !error && st_received, Resp { status: Status::OKAY, data: st.data, length, last: st.last }); + let tok = send_if(tok, resp_s, error, READER_RESP_ERROR); + let next_active = (!st_received || !st.last) && !error; + + State { + active: next_active, + } + } + } +} + // A proc implementing the logic for issuing requests to AxiReader, // receiving the data, and convering the data to the specified output format. proc MemReaderInternal< @@ -229,7 +333,7 @@ pub proc MemReaderAdv< type AxiAr = axi::AxiAr; type AxiStreamInput = axi_st::AxiStream; type AxiStreamOutput = axi_st::AxiStream; - type AxiReaderError = axi_reader::AxiReaderError; + type AxiReaderError = axi_reader::AxiReaderError; config( req_r: chan in, @@ -237,12 +341,12 @@ pub proc MemReaderAdv< axi_ar_s: chan out, axi_r_r: chan in ) { - let (reader_req_s, reader_req_r) = chan("reader_req"); - let (reader_err_s, reader_err_r) = chan("reader_err"); + let (reader_req_s, reader_req_r) = chan("reader_req"); + let (reader_err_s, reader_err_r) = chan("reader_err"); - let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); - let (axi_st_remove_s, axi_st_remove_r) = chan("axi_st_remove"); - let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); + let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); + let (axi_st_remove_s, axi_st_remove_r) = chan("axi_st_remove"); + let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); spawn MemReaderInternal< DSLX_DATA_W, DSLX_ADDR_W, @@ -260,8 +364,66 @@ pub proc MemReaderAdv< spawn axi_stream_remove_empty::AxiStreamRemoveEmpty< DSLX_DATA_W, AXI_DEST_W, AXI_ID_W >(axi_st_remove_r, axi_st_out_s); + } - () + init { } + next(state: ()) { } +} + +// A proc that integrates other procs to create a functional design for +// performing AXI read transactions. It allows for connecting narrow DSLX-side +// with wider AXI-side, if the wider side has to be a multiple of the narrower side. +// This implementation does not use FSMs +pub proc MemReaderAdvNoFsm< + // DSLX side parameters + DSLX_DATA_W: u32, DSLX_ADDR_W: u32, + // AXI side parameters + AXI_DATA_W: u32, AXI_ADDR_W: u32, AXI_DEST_W: u32, AXI_ID_W: u32, + // parameters calculated from other values + DSLX_DATA_W_DIV8: u32 = {DSLX_DATA_W / u32:8}, + AXI_DATA_W_DIV8: u32 = {AXI_DATA_W / u32:8}, + AXI_TO_DSLX_RATIO: u32 = {AXI_DATA_W / DSLX_DATA_W}, + AXI_TO_DSLX_RATIO_W: u32 = {std::clog2((AXI_DATA_W / DSLX_DATA_W) + u32:1)} +> { + type Req = MemReaderReq; + type Resp = MemReaderResp; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiR = axi::AxiR; + type AxiAr = axi::AxiAr; + type AxiStreamInput = axi_st::AxiStream; + type AxiStreamOutput = axi_st::AxiStream; + type AxiReaderError = axi_reader::AxiReaderError; + + config( + req_r: chan in, + resp_s: chan out, + axi_ar_s: chan out, + axi_r_r: chan in + ) { + let (reader_req_s, reader_req_r) = chan("reader_req"); + let (reader_err_s, reader_err_r) = chan("reader_err"); + + let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); + let (axi_st_remove_s, axi_st_remove_r) = chan("axi_st_remove"); + let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); + + spawn MemReaderInternalNoFsm< + DSLX_DATA_W, DSLX_ADDR_W, + AXI_DATA_W, AXI_ADDR_W, AXI_DEST_W, AXI_ID_W, + >(req_r, resp_s, reader_req_s, reader_err_r, axi_st_out_r); + + spawn axi_reader::AxiReaderNoFsm< + AXI_ADDR_W, AXI_DATA_W, AXI_DEST_W, AXI_ID_W + >(reader_req_r, axi_ar_s, axi_r_r, axi_st_in_s, reader_err_s); + + spawn axi_stream_downscaler::AxiStreamDownscaler< + AXI_DATA_W, DSLX_DATA_W, AXI_DEST_W, AXI_ID_W + >(axi_st_in_r, axi_st_remove_s); + + spawn axi_stream_remove_empty::AxiStreamRemoveEmpty< + DSLX_DATA_W, AXI_DEST_W, AXI_ID_W + >(axi_st_remove_r, axi_st_out_s); } init { } @@ -273,7 +435,6 @@ pub proc MemReaderAdv< // AXI bus that has the same data width as DSLX-side of the design. pub proc MemReader< DATA_W: u32, ADDR_W: u32, DEST_W: u32, ID_W: u32, - CHANNEL_DEPTH: u32 = {u32:0}, DATA_W_DIV8: u32 = {DATA_W / u32:8}, > { type Req = MemReaderReq; @@ -292,11 +453,11 @@ pub proc MemReader< axi_ar_s: chan out, axi_r_r: chan in ) { - let (reader_req_s, reader_req_r) = chan("reader_req"); - let (reader_err_s, reader_err_r) = chan("reader_err"); + let (reader_req_s, reader_req_r) = chan("reader_req"); + let (reader_err_s, reader_err_r) = chan("reader_err"); - let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); - let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); + let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); + let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); spawn MemReaderInternal< DATA_W, ADDR_W, DATA_W, ADDR_W, DEST_W, ID_W @@ -317,6 +478,55 @@ pub proc MemReader< } +// A proc that integrates other procs to create a functional design for +// performing AXI read transactions. The proc allows for interfacing with +// AXI bus that has the same data width as DSLX-side of the design. +// This implementation does not use FSMs +pub proc MemReaderNoFsm< + DATA_W: u32, ADDR_W: u32, DEST_W: u32, ID_W: u32, + DATA_W_DIV8: u32 = {DATA_W / u32:8}, +> { + type Req = MemReaderReq; + type Resp = MemReaderResp; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiR = axi::AxiR; + type AxiAr = axi::AxiAr; + type AxiStreamInput = axi_st::AxiStream; + type AxiStreamOutput = axi_st::AxiStream; + type AxiReaderError = axi_reader::AxiReaderError; + + config( + req_r: chan in, + resp_s: chan out, + axi_ar_s: chan out, + axi_r_r: chan in + ) { + let (reader_req_s, reader_req_r) = chan("reader_req"); + let (reader_err_s, reader_err_r) = chan("reader_err"); + + let (axi_st_in_s, axi_st_in_r) = chan("axi_st_in"); + let (axi_st_out_s, axi_st_out_r) = chan("axi_st_out"); + + spawn MemReaderInternalNoFsm< + DATA_W, ADDR_W, DATA_W, ADDR_W, DEST_W, ID_W + >(req_r, resp_s, reader_req_s, reader_err_r, axi_st_out_r); + + spawn axi_reader::AxiReaderNoFsm< + ADDR_W, DATA_W, DEST_W, ID_W + >(reader_req_r, axi_ar_s, axi_r_r, axi_st_in_s, reader_err_s); + + spawn axi_stream_remove_empty::AxiStreamRemoveEmpty< + DATA_W, DEST_W, ID_W + >(axi_st_in_r, axi_st_out_s); + () + } + + init { } + next(state: ()) { } +} + + const INST_ADV_AXI_DATA_W = u32:128; const INST_ADV_AXI_ADDR_W = u32:16; const INST_ADV_AXI_DEST_W = u32:8; @@ -357,6 +567,36 @@ proc MemReaderAdvInst { next(state: ()) { } } +proc MemReaderAdvNoFsmInst { + type Req = MemReaderReq; + type Resp = MemReaderResp; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + + type State = MemReaderState; + type Fsm = MemReaderFsm; + + config( + req_r: chan in, + resp_s: chan out, + axi_ar_s: chan out, + axi_r_r: chan in + ) { + spawn MemReaderAdvNoFsm< + INST_ADV_DSLX_DATA_W, INST_ADV_DSLX_ADDR_W, + INST_ADV_AXI_DATA_W, INST_ADV_AXI_ADDR_W, INST_ADV_AXI_DEST_W, INST_ADV_AXI_ID_W, + >(req_r, resp_s, axi_ar_s, axi_r_r); + + () + } + + init { } + next(state: ()) { } +} + proc MemReaderInternalInst { type Req = MemReaderReq; type Resp = MemReaderResp; @@ -386,6 +626,37 @@ proc MemReaderInternalInst { next(state: ()) { } } +proc MemReaderInternalNoFsmInst { + type Req = MemReaderReq; + type Resp = MemReaderResp; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiReaderError = axi_reader::AxiReaderError; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStreamOutput = axi_st::AxiStream; + + config( + req_r: chan in, + resp_s: chan out, + reader_req_s: chan out, + reader_err_r: chan in, + axi_st_out_r: chan in + ) { + spawn MemReaderInternalNoFsm< + INST_ADV_DSLX_DATA_W, INST_ADV_DSLX_ADDR_W, + INST_ADV_AXI_DATA_W, INST_ADV_AXI_ADDR_W, INST_ADV_AXI_DEST_W, INST_ADV_AXI_ID_W, + >(req_r, resp_s, reader_req_s, reader_err_r, axi_st_out_r); + () + } + + init { } + next(state: ()) { } +} + + + const INST_DATA_W = u32:64; const INST_ADDR_W = u32:16; const INST_DEST_W = u32:8; @@ -422,6 +693,36 @@ proc MemReaderInst { next(state: ()) { } } +proc MemReaderNoFsmInst { + type Req = MemReaderReq; + type Resp = MemReaderResp; + + type AxiReaderReq = axi_reader::AxiReaderReq; + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiStream = axi_st::AxiStream; + + type State = MemReaderState; + type Fsm = MemReaderFsm; + + config( + req_r: chan in, + resp_s: chan out, + axi_ar_s: chan out, + axi_r_r: chan in + ) { + spawn MemReaderNoFsm< + INST_DATA_W, INST_ADDR_W, INST_DEST_W, INST_ID_W, + >(req_r, resp_s, axi_ar_s, axi_r_r); + + () + } + + init { } + next(state: ()) { } +} + + const TEST_AXI_DATA_W = u32:128; const TEST_AXI_ADDR_W = u32:16; const TEST_AXI_DEST_W = u32:8; diff --git a/xls/modules/zstd/memory/mem_reader_adv_cocotb_test.py b/xls/modules/zstd/memory/mem_reader_adv_cocotb_test.py new file mode 100644 index 0000000000..034efc20bb --- /dev/null +++ b/xls/modules/zstd/memory/mem_reader_adv_cocotb_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright 2025 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + sys.path.append(str(Path(__file__).parent)) + + toplevel = "mem_reader_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_reader_adv.v", + "xls/modules/zstd/memory/rtl/mem_reader_wrapper.v", + ] + test_module = [ "mem_reader_cocotb" ] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/mem_reader_adv_no_fsm_cocotb_test.py b/xls/modules/zstd/memory/mem_reader_adv_no_fsm_cocotb_test.py new file mode 100644 index 0000000000..8bac70ba1d --- /dev/null +++ b/xls/modules/zstd/memory/mem_reader_adv_no_fsm_cocotb_test.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# Copyright 2024 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + sys.path.append(str(Path(__file__).parent)) + + toplevel = "mem_reader_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_reader_adv_no_fsm.v", + "xls/modules/zstd/memory/rtl/mem_reader_wrapper.v", + ] + test_module = [ "mem_reader_cocotb" ] + run_test(toplevel, test_module, verilog_sources) + diff --git a/xls/modules/zstd/memory/mem_reader_cocotb.py b/xls/modules/zstd/memory/mem_reader_cocotb.py new file mode 100644 index 0000000000..97cf9bed70 --- /dev/null +++ b/xls/modules/zstd/memory/mem_reader_cocotb.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python +# Copyright 2024 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 random +import sys +import warnings +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles, Event +from cocotb_bus.scoreboard import Scoreboard +from cocotbext.axi.axi_channels import AxiARBus, AxiRBus, AxiReadBus, AxiRTransaction, AxiRSource, AxiRSink, AxiRMonitor +from cocotbext.axi.axi_ram import AxiRamRead +from cocotbext.axi.sparse_memory import SparseMemory + +from xls.modules.zstd.cocotb.channel import ( + XLSChannel, + XLSChannelDriver, + XLSChannelMonitor, +) +from xls.modules.zstd.cocotb.utils import reset, run_test +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct, xls_dataclass + +# to disable warnings from hexdiff used by cocotb's Scoreboard +warnings.filterwarnings("ignore", category=DeprecationWarning) + +DSLX_DATA_W = 64 +DSLX_ADDR_W = 16 + +AXI_DATA_W = 128 +AXI_ADDR_W = 16 + +LAST_W = 1 +STATUS_W = 1 +ERROR_W = 1 +ID_W = 4 +DEST_W = 4 + +# AXI +AXI_AR_PREFIX = "axi_ar" +AXI_R_PREFIX = "axi_r" + +# MemReader +MEM_READER_REQ_CHANNEL = "req" +MEM_READER_RESP_CHANNEL = "resp" + +# Override default widths of AXI response signals +signal_widths = {"rresp": 3, "rlast": 1} +AxiRBus._signal_widths = signal_widths +AxiRTransaction._signal_widths = signal_widths +AxiRSource._signal_widths = signal_widths +AxiRSink._signal_widths = signal_widths +AxiRMonitor._signal_widths = signal_widths + +@xls_dataclass +class MemReaderReq(XLSStruct): + addr: DSLX_ADDR_W + length: DSLX_ADDR_W + + +@xls_dataclass +class MemReaderResp(XLSStruct): + status: STATUS_W + data: DSLX_DATA_W + length: DSLX_ADDR_W + last: LAST_W + + +@xls_dataclass +class AxiReaderReq(XLSStruct): + addr: AXI_ADDR_W + len: AXI_ADDR_W + + +@xls_dataclass +class AxiStream(XLSStruct): + data: AXI_DATA_W + str: AXI_DATA_W // 8 + keep: AXI_DATA_W // 8 = 0 + last: LAST_W = 0 + id: ID_W = 0 + dest: DEST_W = 0 + + +@xls_dataclass +class AxiReaderError(XLSStruct): + error: ERROR_W + + +@xls_dataclass +class AxiAr(XLSStruct): + id: ID_W + addr: AXI_ADDR_W + region: 4 + len: 8 + size: 3 + burst: 2 + cache: 4 + prot: 3 + qos: 4 + + +@xls_dataclass +class AxiR(XLSStruct): + id: ID_W + data: AXI_DATA_W + resp: 3 + last: 1 + + +def print_callback(name: str = "monitor"): + def _print_callback(transaction): + print(f" [{name}]: {transaction}") + + return _print_callback + + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + print("all transactions received") + event.set() + + monitor.add_callback(terminate_cb) + + +def generate_test_data(test_cases, xfer_base=0x0, seed=1234): + random.seed(seed) + mem_size = 2**AXI_ADDR_W + data_w_div8 = DSLX_DATA_W // 8 + + assert xfer_base < mem_size, "Base address outside the memory span" + + req = [] + resp = [] + mem_writes = {} + + for xfer_offset, xfer_length in test_cases: + xfer_addr = xfer_base + xfer_offset + xfer_max_addr = xfer_addr + xfer_length + + if xfer_length == 0: + req += [MemReaderReq(addr=xfer_addr, length=0)] + resp += [MemReaderResp(status=0, data=0, length=0, last=1)] + resp += [MemReaderResp(status=0, data=0, length=0, last=1)] + + assert xfer_max_addr < mem_size, "Max address outside the memory span" + req += [MemReaderReq(addr=xfer_addr, length=xfer_length)] + + rem = xfer_length % data_w_div8 + for addr in range(xfer_addr, xfer_max_addr - (data_w_div8 - 1), data_w_div8): + last = ((addr + data_w_div8) >= xfer_max_addr) & (rem == 0) + data = random.randint(0, 1 << (data_w_div8 * 8)) + mem_writes.update({addr: data}) + resp += [MemReaderResp(status=0, data=data, length=data_w_div8, last=last)] + + if rem > 0: + addr = xfer_max_addr - rem + mask = (1 << (rem * 8)) - 1 + data = random.randint(0, 1 << (data_w_div8 * 8)) + mem_writes.update({addr: data}) + resp += [MemReaderResp(status=0, data=data & mask, length=rem, last=1)] + + return (req, resp, mem_writes) + + +async def test_mem_reader(dut, req_input, resp_output, mem_contents={}): + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + mem_reader_resp_bus = XLSChannel( + dut, MEM_READER_RESP_CHANNEL, dut.clk, start_now=True + ) + mem_reader_req_driver = XLSChannelDriver(dut, MEM_READER_REQ_CHANNEL, dut.clk) + mem_reader_resp_monitor = XLSChannelMonitor( + dut, MEM_READER_RESP_CHANNEL, dut.clk, MemReaderResp, callback=print_callback() + ) + + terminate = Event() + set_termination_event(mem_reader_resp_monitor, terminate, len(resp_output)) + + scoreboard = Scoreboard(dut) + scoreboard.add_interface(mem_reader_resp_monitor, resp_output) + + ar_bus = AxiARBus.from_prefix(dut, AXI_AR_PREFIX) + r_bus = AxiRBus.from_prefix(dut, AXI_R_PREFIX) + axi_read_bus = AxiReadBus(ar=ar_bus, r=r_bus) + + mem_size = 2**AXI_ADDR_W + sparse_mem = SparseMemory(mem_size) + for addr, data in mem_contents.items(): + sparse_mem.write(addr, (data).to_bytes(8, "little")) + + memory = AxiRamRead(axi_read_bus, dut.clk, dut.rst, size=mem_size, mem=sparse_mem) + + await reset(dut.clk, dut.rst, cycles=10) + await mem_reader_req_driver.send(req_input) + await terminate.wait() + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_zero_length_req(dut): + req, resp, _ = generate_test_data( + xfer_base=0xFFF, test_cases=[(0x101, 0)] + ) + await test_mem_reader(dut, req, resp) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_aligned_transfer_shorter_than_bus(dut): + req, resp, mem_contents = generate_test_data( + xfer_base=0xFFF, test_cases=[(0x101, 1)] + ) + await test_mem_reader(dut, req, resp, mem_contents) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_aligned_transfer_shorter_than_bus1(dut): + req, resp, mem_contents = generate_test_data( + xfer_base=0xFFF, test_cases=[(0x2, 1)] + ) + await test_mem_reader(dut, req, resp, mem_contents) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_aligned_transfer_shorter_than_bus2(dut): + req, resp, mem_contents = generate_test_data( + xfer_base=0xFFF, test_cases=[(0x2, 17)] + ) + await test_mem_reader(dut, req, resp, mem_contents) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_aligned_transfer_shorter_than_bus3(dut): + req, resp, mem_contents = generate_test_data( + xfer_base=0xFFF, test_cases=[(0x0, 0x1000)] + ) + await test_mem_reader(dut, req, resp, mem_contents) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def mem_reader_aligned_transfer_shorter_than_bus4(dut): + req, resp, mem_contents = generate_test_data( + xfer_base=0x1, test_cases=[(0x0, 0xFFF), (0x1000, 0x1)] + ) + await test_mem_reader(dut, req, resp, mem_contents) + + +if __name__ == "__main__": + sys.path.append(str(Path(__file__).parent)) + + toplevel = "mem_reader_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_reader_adv.v", + "xls/modules/zstd/memory/rtl/mem_reader_wrapper.v", + ] + test_module = [Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) + + toplevel = "mem_reader_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_reader_adv.v", + "xls/modules/zstd/memory/rtl/mem_reader_wrapper.v", + ] + test_module = [Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/mem_reader_data_upscaler.x b/xls/modules/zstd/memory/mem_reader_data_upscaler.x new file mode 100644 index 0000000000..b04dd9c594 --- /dev/null +++ b/xls/modules/zstd/memory/mem_reader_data_upscaler.x @@ -0,0 +1,53 @@ +// Copyright 2024 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.zstd.memory.mem_reader; + +struct MemReaderDataUpscalerState { + response: mem_reader::MemReaderResp, +} + +pub proc MemReaderDataUpscaler { + type InData = mem_reader::MemReaderResp; + type OutData = mem_reader::MemReaderResp; + type State = MemReaderDataUpscalerState; + type Status = mem_reader::MemReaderStatus; + const_assert!(DATA_IN_W <= DATA_OUT_W); + // input should be narrower than output + in_r: chan in; + out_s: chan out; + + config(in_r: chan in, out_s: chan out) { (in_r, out_s) } + + init { zero!() } + + next(state: State) { + const IN_FULL_LENGTH = (DATA_IN_W / u32:8) as uN[ADDR_W]; + const OUT_FULL_LENGTH = (DATA_OUT_W / u32:8) as uN[ADDR_W]; + let (tok, data) = recv(join(), in_r); + trace_fmt!("[MemReaderDataUpscaler] data: {}", data); + let last = data.length < IN_FULL_LENGTH; + let shift_bits = state.response.length * uN[ADDR_W]:8; + let response = OutData { + status: Status::OKAY, + data: (data.data as uN[DATA_OUT_W] << shift_bits) | state.response.data, + length: state.response.length + data.length, + last, + }; + let tok = send_if(tok, out_s, response.length == OUT_FULL_LENGTH || last, response); + + State { response: if last { zero!() } else { response } } + } +} diff --git a/xls/modules/zstd/memory/mem_writer.x b/xls/modules/zstd/memory/mem_writer.x index f49d147785..400f079dd6 100644 --- a/xls/modules/zstd/memory/mem_writer.x +++ b/xls/modules/zstd/memory/mem_writer.x @@ -55,8 +55,7 @@ pub struct MemWriterDataPacket { enum MemWriterFsm : u2 { RECV_REQ = 0, SEND_WRITE_REQ = 1, - RECV_DATA = 2, - SEND_DATA = 3, + SEND_DATA = 2, } struct MemWriterState< @@ -71,6 +70,90 @@ struct MemWriterState< axi_writer_req: axi_writer::AxiWriterRequest, } +struct MemWriterInternalState< + ADDR_W: u32 +> { + active: bool, + req_len: sN[ADDR_W] +} + +proc MemWriterInternalNoFsm< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, WRITER_ID: u32, + DATA_W_DIV8: u32 = {DATA_W / u32:8} +> { + type Req = MemWriterReq; + type Data = MemWriterDataPacket; + type AxiWriterReq = axi_writer::AxiWriterRequest; + type PaddingReq = axi_writer::AxiWriterRequest; + type AxiStream = axi_st::AxiStream; + type State = MemWriterInternalState; + type Fsm = MemWriterFsm; + + type Length = uN[ADDR_W]; + type sLength = sN[ADDR_W]; + type Strobe = uN[DATA_W_DIV8]; + type Id = uN[ID_W]; + type Dest = uN[DEST_W]; + + req_in_r: chan in; + data_in_r: chan in; + axi_writer_req_s: chan out; + padding_req_s: chan out; + axi_st_raw_s: chan out; + + config( + req_in_r: chan in, + data_in_r: chan in, + axi_writer_req_s: chan out, + padding_req_s: chan out, + axi_st_raw_s: chan out, + ) { + + (req_in_r, data_in_r, axi_writer_req_s, padding_req_s, axi_st_raw_s) + } + + init { zero!() } + + next(state: State) { + let tok = join(); + if !state.active { + let (tok, req) = recv(tok, req_in_r); + + let axi_writer_req = AxiWriterReq { + address: req.addr, + length: req.length + }; + + let tok = send(tok, axi_writer_req_s, axi_writer_req); + let tok = send(tok, padding_req_s, axi_writer_req); + + State { + active: true, + req_len: req.length as sLength + } + } else { + let (tok, data_in) = recv(tok, data_in_r); + + let next_req_len = state.req_len - data_in.length as sLength; + let str_keep = ((Length:1 << data_in.length) - Length:1) as Strobe; + + let tok = send(tok, axi_st_raw_s, AxiStream { + data: data_in.data, + str: str_keep, + keep: str_keep, + last: (next_req_len <= sLength:0), + id: WRITER_ID as Id, + dest: WRITER_ID as Dest + }); + + State { + active: next_req_len > sLength:0, + req_len: next_req_len + } + } + } +} + proc MemWriterInternal< ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, WRITER_ID: u32, DATA_W_DIV8: u32 = {DATA_W / u32:8} @@ -140,10 +223,6 @@ proc MemWriterInternal< ..state } }, - _ => { - assert!(false, "Invalid state"); - state - } }; let raw_axi_st_frame = match(state.fsm) { @@ -232,11 +311,11 @@ pub proc MemWriter< axi_b_r: chan in, resp_s: chan out, ) { - let (axi_writer_req_s, axi_writer_req_r) = chan("axi_writer_req"); - let (padding_req_s, padding_req_r) = chan("padding_req"); - let (axi_st_raw_s, axi_st_raw_r) = chan("axi_st_raw"); - let (axi_st_clean_s, axi_st_clean_r) = chan("axi_st_clean"); - let (axi_st_padded_s, axi_st_padded_r) = chan("axi_st_padded"); + let (axi_writer_req_s, axi_writer_req_r) = chan("axi_writer_req"); + let (padding_req_s, padding_req_r) = chan("padding_req"); + let (axi_st_raw_s, axi_st_raw_r) = chan("axi_st_raw"); + let (axi_st_clean_s, axi_st_clean_r) = chan("axi_st_clean"); + let (axi_st_padded_s, axi_st_padded_r) = chan("axi_st_padded"); spawn MemWriterInternal< ADDR_W, DATA_W, DEST_W, ID_W, WRITER_ID @@ -287,6 +366,90 @@ proc MemWriterInst { next(state: ()) { } } +pub proc MemWriterNoFsm< + ADDR_W: u32, DATA_W: u32, DEST_W: u32, ID_W: u32, WRITER_ID: u32, + DATA_W_DIV8: u32 = {DATA_W / u32:8} +> { + type Req = MemWriterReq; + type Data = MemWriterDataPacket; + type AxiWriterReq = axi_writer::AxiWriterRequest; + type PaddingReq = axi_writer::AxiWriterRequest; + type AxiStream = axi_st::AxiStream; + type AxiAW = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + type State = MemWriterState; + type Fsm = MemWriterFsm; + + type Length = uN[ADDR_W]; + type sLength = sN[ADDR_W]; + type Strobe = uN[DATA_W_DIV8]; + type Id = uN[ID_W]; + type Dest = uN[DEST_W]; + + config( + req_in_r: chan in, + data_in_r: chan in, + axi_aw_s: chan out, + axi_w_s: chan out, + axi_b_r: chan in, + resp_s: chan out, + ) { + let (axi_writer_req_s, axi_writer_req_r) = chan("axi_writer_req"); + let (padding_req_s, padding_req_r) = chan("padding_req"); + let (axi_st_raw_s, axi_st_raw_r) = chan("axi_st_raw"); + let (axi_st_clean_s, axi_st_clean_r) = chan("axi_st_clean"); + let (axi_st_padded_s, axi_st_padded_r) = chan("axi_st_padded"); + + spawn MemWriterInternalNoFsm< + ADDR_W, DATA_W, DEST_W, ID_W, WRITER_ID + >(req_in_r, data_in_r, axi_writer_req_s, padding_req_s, axi_st_raw_s); + spawn axi_stream_remove_empty::AxiStreamRemoveEmpty< + DATA_W, DEST_W, ID_W + >(axi_st_raw_r, axi_st_clean_s); + spawn axi_stream_add_empty::AxiStreamAddEmpty< + DATA_W, DEST_W, ID_W, ADDR_W + >(padding_req_r, axi_st_clean_r, axi_st_padded_s); + spawn axi_writer::AxiWriterNoFsm< + ADDR_W, DATA_W, DEST_W, ID_W + >(axi_writer_req_r, resp_s, axi_aw_s, axi_w_s, axi_b_r, axi_st_padded_r); + + () + } + + init {} + + next(state: ()) {} +} + +proc MemWriterNoFsmInst { + type InstReq = MemWriterReq; + type InstData = MemWriterDataPacket; + type InstAxiStream = axi_st::AxiStream; + type InstAxiAW = axi::AxiAw; + type InstAxiW = axi::AxiW; + type InstAxiB = axi::AxiB; + type InstMemWriterResp = MemWriterResp; + + config( + req_in_r: chan in, + data_in_r: chan in, + axi_aw_s: chan out, + axi_w_s: chan out, + axi_b_r: chan in, + resp_s: chan out + ) { + spawn MemWriterNoFsm< + INST_ADDR_W, INST_DATA_W, INST_DEST_W, INST_ID_W, INST_WRITER_ID + >(req_in_r, data_in_r, axi_aw_s, axi_w_s, axi_b_r, resp_s); + () + } + + init { () } + + next(state: ()) { } +} + const TEST_ADDR_W = u32:16; const TEST_DATA_W = u32:32; const TEST_DATA_W_DIV8 = TEST_DATA_W / u32:8; diff --git a/xls/modules/zstd/memory/mem_writer_cocotb.py b/xls/modules/zstd/memory/mem_writer_cocotb.py new file mode 100644 index 0000000000..79d37439fb --- /dev/null +++ b/xls/modules/zstd/memory/mem_writer_cocotb.py @@ -0,0 +1,659 @@ +#!/usr/bin/env python +# Copyright 2024 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 random +import logging +from enum import Enum +from pathlib import Path + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles, Event +from cocotb.binary import BinaryValue +from cocotb_bus.scoreboard import Scoreboard + +from cocotbext.axi.axis import AxiStreamSource, AxiStreamBus, AxiStreamFrame +from cocotbext.axi.axi_channels import AxiAWBus, AxiWBus, AxiBBus, AxiWriteBus, AxiAWMonitor, AxiWMonitor, AxiBMonitor, AxiBTransaction, AxiBSource, AxiBSink +from cocotbext.axi.axi_ram import AxiRamWrite +from cocotbext.axi.sparse_memory import SparseMemory + +from xls.modules.zstd.cocotb.channel import ( + XLSChannel, + XLSChannelDriver, + XLSChannelMonitor, +) +from xls.modules.zstd.cocotb.utils import reset, run_test +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct, xls_dataclass + +DATA_WIDTH = 32 +ADDR_WIDTH = 16 + +# Override default widths of AXI response signals +signal_widths = {"bresp": 3} +AxiBBus._signal_widths = signal_widths +AxiBTransaction._signal_widths = signal_widths +AxiBSource._signal_widths = signal_widths +AxiBSink._signal_widths = signal_widths +AxiBMonitor._signal_widths = signal_widths + +@xls_dataclass +class DataInStruct(XLSStruct): + data: DATA_WIDTH + length: ADDR_WIDTH + last: 1 + +@xls_dataclass +class WriteReqStruct(XLSStruct): + offset: ADDR_WIDTH + length: ADDR_WIDTH + +@xls_dataclass +class MemWriterRespStruct(XLSStruct): + status: 1 + +class MemWriterRespStatus(Enum): + OKAY = 0 + ERROR = 1 + +@xls_dataclass +class WriteRequestStruct(XLSStruct): + address: ADDR_WIDTH + length: ADDR_WIDTH + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + event.set() + monitor.add_callback(terminate_cb) + +async def test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt): + GENERIC_WRITE_REQ_CHANNEL = "req" + GENERIC_WRITE_RESP_CHANNEL = "resp" + GENERIC_DATA_IN_CHANNEL = "data_in" + AXI_AW_CHANNEL = "axi_aw" + AXI_W_CHANNEL = "axi_w" + AXI_B_CHANNEL = "axi_b" + + terminate = Event() + + dut.rst.setimmediatevalue(0) + + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + resp_bus = XLSChannel(dut, GENERIC_WRITE_RESP_CHANNEL, dut.clk, start_now=True) + + driver_write_req = XLSChannelDriver(dut, GENERIC_WRITE_REQ_CHANNEL, dut.clk) + driver_data_in = XLSChannelDriver(dut, GENERIC_DATA_IN_CHANNEL, dut.clk) + + bus_axi_aw = AxiAWBus.from_prefix(dut, AXI_AW_CHANNEL) + bus_axi_w = AxiWBus.from_prefix(dut, AXI_W_CHANNEL) + bus_axi_b = AxiBBus.from_prefix(dut, AXI_B_CHANNEL) + bus_axi_write = AxiWriteBus(bus_axi_aw, bus_axi_w, bus_axi_b) + + monitor_write_req = XLSChannelMonitor(dut, GENERIC_WRITE_REQ_CHANNEL, dut.clk, WriteRequestStruct) + monitor_data_in = XLSChannelMonitor(dut, GENERIC_DATA_IN_CHANNEL, dut.clk, WriteRequestStruct) + monitor_write_resp = XLSChannelMonitor(dut, GENERIC_WRITE_RESP_CHANNEL, dut.clk, MemWriterRespStruct) + monitor_axi_aw = AxiAWMonitor(bus_axi_aw, dut.clk, dut.rst) + monitor_axi_w = AxiWMonitor(bus_axi_w, dut.clk, dut.rst) + monitor_axi_b = AxiBMonitor(bus_axi_b, dut.clk, dut.rst) + + set_termination_event(monitor_write_resp, terminate, resp_cnt) + + memory = AxiRamWrite(bus_axi_write, dut.clk, dut.rst, size=mem_size) + + log = logging.getLogger("cocotb.tb") + log.setLevel(logging.WARNING) + memory.log.setLevel(logging.WARNING) + + scoreboard = Scoreboard(dut) + scoreboard.add_interface(monitor_write_resp, write_resp_expect) + + await reset(dut.clk, dut.rst, cycles=10) + await cocotb.start(driver_write_req.send(write_req_input)) + await cocotb.start(driver_data_in.send(data_in_input)) + + await terminate.wait() + + for bundle in memory_verification: + memory_contents = bytearray(memory.read(bundle["base_address"], bundle["length"])) + expected_memory_contents = bytearray(expected_memory.read(bundle["base_address"], bundle["length"])) + assert memory_contents == expected_memory_contents, "{} bytes of memory contents at base address {}:\n{}\nvs\n{}\nHEXDUMP:\n{}\nvs\n{}".format(hex(bundle["length"]), hex(bundle["base_address"]), memory_contents, expected_memory_contents, memory.hexdump(bundle["base_address"], bundle["length"]), expected_memory.hexdump(bundle["base_address"], bundle["length"])) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_single_burst_1_transfer(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_single_burst_1_transfer) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_single_burst_2_transfers(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_single_burst_2_transfers) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_single_burst_almost_max_burst_transfer(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_single_burst_almost_max_burst_transfer) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_single_burst_max_burst_transfer(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_single_burst_max_burst_transfer) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_multiburst_2_full_bursts(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_multiburst_2_full_bursts) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_multiburst_1_full_burst_and_single_transfer(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_multiburst_1_full_burst_and_single_transfer) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_multiburst_crossing_4kb_boundary(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_multiburst_crossing_4kb_boundary) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_multiburst_crossing_4kb_boundary_with_perfectly_aligned_full_bursts(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_multiburst_crossing_4kb_boundary_with_perfectly_aligned_full_bursts) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=2000, timeout_unit="ms") +async def ram_test_multiburst_crossing_4kb_boundary_with_2_full_bursts_and_1_transfer(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_arbitrary(mem_size, test_cases_multiburst_crossing_4kb_boundary_with_2_full_bursts_and_1_transfer) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=5000, timeout_unit="ms") +async def ram_test_not_full_packets(dut): + mem_size = 2**ADDR_WIDTH + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_padded_test_data_arbitrary(mem_size, test_cases_not_full_packets) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +@cocotb.test(timeout_time=5000, timeout_unit="ms") +async def ram_test_random(dut): + mem_size = 2**ADDR_WIDTH + test_count = 50 + + (write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) = generate_test_data_random(test_count, mem_size) + await test_writer(dut, mem_size, write_req_input, data_in_input, write_resp_expect, memory_verification, expected_memory, resp_cnt) + +def generate_test_data_random(test_count, mem_size): + AXI_AXSIZE_ENCODING_MAX_4B_TRANSFER = 2 # Must be in sync with AXI_AXSIZE_ENCODING enum in axi.x + + write_req_input = [] + data_in_input = [] + write_resp_expect = [] + memory_verification = [] + memory = SparseMemory(mem_size) + + random.seed(1234) + + xfer_baseaddr = 0 + + for i in range(test_count): + # Generate offset from the absolute address + max_xfer_offset = mem_size - xfer_baseaddr + xfer_offset = random.randrange(0, max_xfer_offset) + xfer_addr = xfer_baseaddr + xfer_offset + # Make sure we don't write beyond available memory + memory_size_max_xfer_len = mem_size - xfer_addr + arbitrary_max_xfer_len = 0x5000 # 20kB + xfer_max_len = min(arbitrary_max_xfer_len, memory_size_max_xfer_len) + xfer_len = random.randrange(1, xfer_max_len) + + write_req = WriteReqStruct( + offset = xfer_offset, + length = xfer_len, + ) + write_req_input.append(write_req) + + data_to_write = random.randbytes(xfer_len) + rem = xfer_len % 4 + for j in list(range(0, xfer_len-3, 4)): + last = ((j + 4) >= xfer_len) & (rem == 0) + data_in = DataInStruct( + data = int.from_bytes(data_to_write[j:j+4], byteorder='little'), + length = 4, + last = last + ) + data_in_input.append(data_in) + if (rem > 0): + data_in = DataInStruct( + data = int.from_bytes(data_to_write[-rem:], byteorder='little'), + length = rem, + last = True + ) + data_in_input.append(data_in) + + + transfer_req = WriteRequestStruct( + address = xfer_addr, + length = xfer_len, + ) + write_expected_memory(transfer_req, data_to_write, memory) + + memory_bundle = { + "base_address": transfer_req.address, + "length": transfer_req.length, + } + memory_verification.append(memory_bundle) + + write_resp_expect = [MemWriterRespStruct(status=MemWriterRespStatus.OKAY.value)] * test_count + + return (write_req_input, data_in_input, write_resp_expect, memory_verification, memory, test_count) + +def bytes_to_4k_boundary(addr): + AXI_4K_BOUNDARY = 0x1000 + return AXI_4K_BOUNDARY - (addr % AXI_4K_BOUNDARY) + +def write_expected_memory(transfer_req, data_to_write, memory): + """ + Write test data to reference memory keeping the AXI 4kb boundary + by spliting the write requests into smaller ones. + """ + prev_id = 0 + address = transfer_req.address + length = transfer_req.length + + BYTES_IN_TRANSFER = 4 + MAX_AXI_BURST_BYTES = 256 * BYTES_IN_TRANSFER + + while (length > 0): + bytes_to_4k = bytes_to_4k_boundary(address) + new_len = min(length, min(bytes_to_4k, MAX_AXI_BURST_BYTES)) + new_data = data_to_write[prev_id:prev_id+new_len] + memory.write(address, new_data) + address = address + new_len + length = length - new_len + prev_id = prev_id + new_len + +def generate_test_data_arbitrary(mem_size, test_cases): + AXI_AXSIZE_ENCODING_MAX_4B_TRANSFER = 2 # Must be in sync with AXI_AXSIZE_ENCODING enum in axi.x + test_count = len(test_cases) + + random.seed(1234) + + write_req_input = [] + data_in_input = [] + write_resp_expect = [] + memory_verification = [] + memory = SparseMemory(mem_size) + + xfer_baseaddr = 0x0 + assert xfer_baseaddr < mem_size + + max_xfer_offset = mem_size - xfer_baseaddr + + for xfer_offset, xfer_len in test_cases: + assert xfer_offset <= max_xfer_offset + xfer_addr = xfer_baseaddr + xfer_offset + # Make sure we don't write beyond available memory + memory_size_max_xfer_len = mem_size - xfer_addr + arbitrary_max_xfer_len = 0x5000 # 20kB + xfer_max_len = min(arbitrary_max_xfer_len, memory_size_max_xfer_len) + assert xfer_len <= xfer_max_len + + write_req = WriteReqStruct( + offset = xfer_offset, + length = xfer_len, + ) + write_req_input.append(write_req) + + data_to_write = random.randbytes(xfer_len) + rem = xfer_len % 4 + for j in list(range(0, xfer_len-3, 4)): + last = ((j + 4) >= xfer_len) & (rem == 0) + data_in = DataInStruct( + data = int.from_bytes(data_to_write[j:j+4], byteorder='little'), + length = 4, + last = last + ) + data_in_input.append(data_in) + if (rem > 0): + data_in = DataInStruct( + data = int.from_bytes(data_to_write[-rem:], byteorder='little'), + length = rem, + last = True + ) + data_in_input.append(data_in) + + + transfer_req = WriteRequestStruct( + address = xfer_addr, + length = xfer_len, + ) + write_expected_memory(transfer_req, data_to_write, memory) + + memory_bundle = { + "base_address": transfer_req.address, + "length": transfer_req.length, + } + memory_verification.append(memory_bundle) + + write_resp_expect = [MemWriterRespStruct(status=MemWriterRespStatus.OKAY.value)] * test_count + + return (write_req_input, data_in_input, write_resp_expect, memory_verification, memory, test_count) + +def generate_padded_test_data_arbitrary(mem_size, test_cases): + AXI_AXSIZE_ENCODING_MAX_4B_TRANSFER = 2 # Must be in sync with AXI_AXSIZE_ENCODING enum in axi.x + test_count = len(test_cases) + + random.seed(1234) + + write_req_input = [] + data_in_input = [] + write_resp_expect = [] + memory_verification = [] + memory = SparseMemory(mem_size) + + xfer_baseaddr = 0x0 + assert xfer_baseaddr < mem_size + + max_xfer_offset = mem_size - xfer_baseaddr + + for xfer_offset, xfer_len in test_cases: + assert xfer_offset <= max_xfer_offset + xfer_addr = xfer_baseaddr + xfer_offset + # Make sure we don't write beyond available memory + memory_size_max_xfer_len = mem_size - xfer_addr + arbitrary_max_xfer_len = 0x5000 # 20kB + xfer_max_len = min(arbitrary_max_xfer_len, memory_size_max_xfer_len) + assert xfer_len <= xfer_max_len + + write_req = WriteReqStruct( + offset = xfer_offset, + length = xfer_len, + ) + write_req_input.append(write_req) + + data_to_write = random.randbytes(xfer_len) + bytes_to_packetize = xfer_len + packetized_bytes = 0 + while(bytes_to_packetize): + packet_len = random.randint(1, 4) + + if (bytes_to_packetize < packet_len): + packet_len = bytes_to_packetize + + last = packet_len == bytes_to_packetize + + data_in = DataInStruct( + data = int.from_bytes(data_to_write[packetized_bytes:packetized_bytes+packet_len], byteorder='little'), + length = packet_len, + last = last + ) + data_in_input.append(data_in) + + bytes_to_packetize -= packet_len + packetized_bytes += packet_len + assert xfer_len == packetized_bytes + + + transfer_req = WriteRequestStruct( + address = xfer_addr, + length = xfer_len, + ) + write_expected_memory(transfer_req, data_to_write, memory) + + memory_bundle = { + "base_address": transfer_req.address, + "length": transfer_req.length, + } + memory_verification.append(memory_bundle) + + write_resp_expect = [MemWriterRespStruct(status=MemWriterRespStatus.OKAY.value)] * test_count + + return (write_req_input, data_in_input, write_resp_expect, memory_verification, memory, test_count) + + +test_cases_single_burst_1_transfer = [ + # Aligned Address; Aligned Length + (0x0, 0x4), + # Aligned Address; Unaligned Length + (0x10, 0x1), + (0x24, 0x2), + (0x38, 0x3), + # Unaligned Address; Aligned Length + (0x41, 0x4), + (0x52, 0x4), + (0x63, 0x4), + # Unaligned Address; Unaligned Length + (0x71, 0x1), + (0x81, 0x2), + (0x91, 0x3), + (0xa2, 0x1), + (0xb2, 0x2), + (0xc2, 0x3), + (0xd3, 0x1), + (0xe3, 0x2), + (0xf3, 0x3) +] + +test_cases_single_burst_2_transfers = [ + # Aligned Address; Aligned Length + (0x100, 0x8), + # Aligned Address; Unaligned Length + (0x110, 0x5), + (0x120, 0x6), + (0x130, 0x7), + # Unaligned Address; Aligned Length + (0x141, 0x8), + (0x152, 0x8), + (0x163, 0x8), + # Unaligned Address; Unaligned Length + (0x171, 0x5), + (0x182, 0x5), + (0x193, 0x5), + (0x1A1, 0x6), + (0x1B2, 0x6), + (0x1C3, 0x6), + (0x1D1, 0x7), + (0x1E2, 0x7), + (0x1F3, 0x7) +] + +test_cases_single_burst_almost_max_burst_transfer = [ + # Aligned Address; Aligned Length + (0x200, 0x3FC), + # Aligned Address; Unaligned Length + (0x600, 0x3F9), + (0xA00, 0x3FA), + (0x1000, 0x3FB), + # Unaligned Address; Aligned Length + (0x1401, 0x3FC), + (0x1802, 0x3FC), + (0x2003, 0x3FC), + # Unaligned Address; Unaligned Length + (0x2401, 0x3F9), + (0x2802, 0x3F9), + (0x2C03, 0x3F9), + (0x3001, 0x3FA), + (0x3402, 0x3FA), + (0x3803, 0x3FA), + (0x3C01, 0x3FB), + (0x4002, 0x3FB), + (0x4403, 0x3FB) +] + +test_cases_single_burst_max_burst_transfer = [ + # Aligned Address; Aligned Length + (0x4800, 0x400), + # Aligned Address; Unaligned Length + (0x4C00, 0x3FD), + (0x5000, 0x3FE), + (0x5400, 0x3FF), + # Unaligned Address; Aligned Length + (0x5801, 0x400), + (0x6002, 0x400), + (0x6803, 0x400), + # Unaligned Address; Unaligned Length + (0x7001, 0x3FD), + (0x7802, 0x3FD), + (0x8003, 0x3FD), + (0x8801, 0x3FE), + (0x9002, 0x3FE), + (0x9803, 0x3FE), + (0xA001, 0x3FF), + (0xA802, 0x3FF), + (0xB003, 0x3FF) +] + +test_cases_multiburst_2_full_bursts = [ + # Aligned Address; Aligned Length + (0x0400, 0x800), + # Aligned Address; Unaligned Length + (0x1000, 0x7FD), + (0x1800, 0x7FE), + (0x2000, 0x7FF), + # Unaligned Address; Aligned Length + (0x2801, 0x800), + (0x3002, 0x800), + (0x3803, 0x800), + # Unaligned Address; Unaligned Length + (0x4001, 0x7FD), + (0x5002, 0x7FD), + (0x6003, 0x7FD), + (0x7001, 0x7FE), + (0x8002, 0x7FE), + (0x9003, 0x7FE), + (0xA001, 0x7FF), + (0xB002, 0x7FF), + (0xF003, 0x7FF) +] + +test_cases_multiburst_1_full_burst_and_single_transfer = [ + # Aligned Address; Aligned Length; Multi-Burst + (0x0000, 0x404), + # Aligned Address; Unaligned Length; Multi-Burst + (0x0800, 0x401), + (0x1000, 0x402), + (0x1800, 0x403), + # Unaligned Address; Aligned Length; Multi-Burst + (0x2000, 0x404), + (0x2800, 0x404), + (0x3000, 0x404), + # Unaligned Address; Unaligned Length; Multi-Burst + (0x3801, 0x401), + (0x5002, 0x401), + (0x5803, 0x401), + (0x6001, 0x402), + (0x6802, 0x402), + (0x7003, 0x402), + (0x7801, 0x403), + (0x8002, 0x403), + (0x8803, 0x403) +] + +test_cases_multiburst_crossing_4kb_boundary = [ + # Aligned Address; Aligned Length + (0x0FFC, 0x8), + # Aligned Address; Unaligned Length + (0x1FFC, 0x5), + (0x2FFC, 0x6), + (0x3FFC, 0x7), + # Unaligned Address; Aligned Length + (0x4FFD, 0x8), + (0x5FFE, 0x8), + (0x6FFF, 0x8), + # Unaligned Address; Unaligned Length + (0x7FFD, 0x5), + (0x8FFD, 0x6), + (0x9FFD, 0x7), + (0xAFFE, 0x5), + (0xBFFE, 0x6), + (0xCFFE, 0x7), + (0xDFFF, 0x5), + (0xEFFF, 0x6), + # End of address space - wrap around + (0x0FFF, 0x7), +] + +test_cases_multiburst_crossing_4kb_boundary_with_perfectly_aligned_full_bursts = [ + # Aligned Address; Aligned Length; Multi-Burst; crossing 4kB boundary with perfectly aligned full bursts + (0x0C00, 0x800), + # Unaligned Address; Unaligned Length; Multi-Burst; crossing 4kB boundary with perfectly aligned full bursts + (0x1C01, 0x7FF), + (0x2C02, 0x7FE), + (0x3C03, 0x7FD), +] + +test_cases_multiburst_crossing_4kb_boundary_with_2_full_bursts_and_1_transfer = [ + # Aligned Address; Aligned Length + (0x0C04, 0x800), + # Aligned Address; Unaligned Length + (0x1C04, 0x801), + (0x2C04, 0x802), + (0x3C04, 0x803), + # Unaligned Address; Aligned Length + (0x4C01, 0x800), + (0x5C02, 0x800), + (0x6C03, 0x800), + # Unaligned Address; Unaligned Length + (0x7C01, 0x801), + (0x8C02, 0x802), + (0x9C03, 0x803), + (0xAC01, 0x802), + (0xBC02, 0x802), + (0xCC03, 0x802), + (0xDC01, 0x803), + (0xEC02, 0x803), + # End of address space - wrap around + (0x0C03, 0x803), +] + +test_cases_not_full_packets = [ + # Aligned Address; Aligned Length + (0x0000, 0x20), + # Aligned Address; Unaligned Length + (0x100, 0x21), + (0x200, 0x22), + (0x300, 0x23), + # Unaligned Address; Aligned Length + (0x401, 0x20), + (0x502, 0x20), + (0x603, 0x20), + # Unaligned Address; Unaligned Length + (0x701, 0x21), + (0x802, 0x22), + (0x903, 0x23), + (0xA01, 0x22), + (0xB02, 0x22), + (0xC03, 0x22), + (0xD01, 0x23), + (0xE02, 0x23), + (0xF03, 0x23), +] diff --git a/xls/modules/zstd/memory/mem_writer_cocotb_test.py b/xls/modules/zstd/memory/mem_writer_cocotb_test.py new file mode 100644 index 0000000000..f3e720e867 --- /dev/null +++ b/xls/modules/zstd/memory/mem_writer_cocotb_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright 2025 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + sys.path.append(str(Path(__file__).parent)) + + toplevel = "mem_writer_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_writer.v", + "xls/modules/zstd/memory/rtl/mem_writer_wrapper.v", + ] + test_module = [ "mem_writer_cocotb" ] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/mem_writer_data_downscaler.x b/xls/modules/zstd/memory/mem_writer_data_downscaler.x new file mode 100644 index 0000000000..5d133448a5 --- /dev/null +++ b/xls/modules/zstd/memory/mem_writer_data_downscaler.x @@ -0,0 +1,179 @@ +// Copyright 2024 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.zstd.memory.mem_writer; + +struct MemWriterDataDownscalerState< + ADDR_W: u32, DATA_IN_W: u32, DATA_OUT_W: u32, + RATIO: u32, RATIO_W: u32, +> { + packet: mem_writer::MemWriterDataPacket, + i: uN[RATIO_W], +} + +pub proc MemWriterDataDownscaler< + ADDR_W: u32, DATA_IN_W: u32, DATA_OUT_W: u32, + RATIO: u32 = {std::ceil_div(DATA_IN_W, DATA_OUT_W)}, + RATIO_W: u32 = {u32:3}, //{std::clog2(RATIO + u32:1)} +> { + type InData = mem_writer::MemWriterDataPacket; + type OutData = mem_writer::MemWriterDataPacket; + type State = MemWriterDataDownscalerState; + + const_assert!(DATA_IN_W >= DATA_OUT_W); // input should be wider than output + + in_r: chan in; + out_s: chan out; + + config( + in_r: chan in, + out_s: chan out + ) { (in_r, out_s) } + + init { zero!() } + + next(state: State) { + const FULL_LENGTH = (DATA_OUT_W / u32:8) as uN[ADDR_W]; + + let do_recv = (state.i == uN[RATIO_W]:0); + let (tok, packet) = recv_if(join(), in_r, do_recv, state.packet); + + trace_fmt!("packet: {}", packet); + + let data = packet.data[DATA_OUT_W * state.i as u32 +: uN[DATA_OUT_W]]; + let (length, last) = if packet.length > FULL_LENGTH { + (FULL_LENGTH, u1:0) + } else { + (packet.length, packet.last) + }; + + let out_data = OutData { data, length, last }; + let tok = send(tok, out_s, out_data); + + if last { + zero!() + } else { + State { + i: state.i + uN[RATIO_W]:1, + packet: InData { + data: packet.data, + last: packet.last, + length: packet.length - FULL_LENGTH + } + } + } + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_IN_W = u32:144; +const INST_DATA_OUT_W = u32:32; + +proc MemWriterDataDownscalerInst { + type InDataPacket = mem_writer::MemWriterDataPacket; + type OutDataPacket = mem_writer::MemWriterDataPacket; + + config( + in_r: chan in, + out_s: chan out + ) { + spawn MemWriterDataDownscaler< + INST_ADDR_W, INST_DATA_IN_W, INST_DATA_OUT_W, + >(in_r, out_s); + } + + init { } + + next(state: ()) { } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_IN_W = u32:144; +const TEST_DATA_OUT_W = u32:32; + +#[test_proc] +proc MemWriterDownscalerTest { + type Addr = uN[TEST_ADDR_W]; + type InData = uN[TEST_DATA_IN_W]; + type InDataPacket = mem_writer::MemWriterDataPacket; + type OutData = uN[TEST_DATA_OUT_W]; + type OutDataPacket = mem_writer::MemWriterDataPacket; + + + terminator: chan out; + in_s: chan out; + out_r: chan in; + + config(terminator: chan out) { + let (in_s, in_r) = chan("in"); + let (out_s, out_r) = chan("out"); + + spawn MemWriterDataDownscaler< + TEST_ADDR_W, TEST_DATA_IN_W, TEST_DATA_OUT_W, + > (in_r, out_s); + + (terminator, in_s, out_r) + } + + init { } + + next(state: ()) { + let tok = join(); + + let tok = send(tok, in_s, InDataPacket { + data: InData:0x2211_FFEE_DDCC_BBAA_0099_8877_6655_4433_2211, + length: Addr:18, + last: u1:1, + }); + + let (tok, data) = recv(tok, out_r); + assert_eq(data, OutDataPacket { + data: OutData:0x4433_2211, + length: Addr:4, + last: u1:0, + }); + + let (tok, data) = recv(tok, out_r); + assert_eq(data, OutDataPacket { + data: OutData:0x8877_6655, + length: Addr:4, + last: u1:0, + }); + + let (tok, data) = recv(tok, out_r); + assert_eq(data, OutDataPacket { + data: OutData:0xBBAA_0099, + length: Addr:4, + last: u1:0, + }); + + + let (tok, data) = recv(tok, out_r); + assert_eq(data, OutDataPacket { + data: OutData:0xFFEE_DDCC, + length: Addr:4, + last: u1:0, + }); + + let (tok, data) = recv(tok, out_r); + assert_eq(data, OutDataPacket { + data: OutData:0x2211, + length: Addr:2, + last: u1:1, + }); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/memory/mem_writer_no_fsm_cocotb_test.py b/xls/modules/zstd/memory/mem_writer_no_fsm_cocotb_test.py new file mode 100644 index 0000000000..0d23bd595f --- /dev/null +++ b/xls/modules/zstd/memory/mem_writer_no_fsm_cocotb_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright 2025 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 sys + +from pathlib import Path +from xls.modules.zstd.cocotb.utils import run_test + +if __name__ == "__main__": + sys.path.append(str(Path(__file__).parent)) + + toplevel = "mem_writer_wrapper" + verilog_sources = [ + "xls/modules/zstd/memory/mem_writer_no_fsm.v", + "xls/modules/zstd/memory/rtl/mem_writer_wrapper.v", + ] + test_module = [ "mem_writer_cocotb" ] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/memory/rtl/BUILD b/xls/modules/zstd/memory/rtl/BUILD new file mode 100644 index 0000000000..96029da06d --- /dev/null +++ b/xls/modules/zstd/memory/rtl/BUILD @@ -0,0 +1,39 @@ +# Copyright 2024 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. + +"""Collection of simulation sources + +This package exports verilog sources required by the Memory Writer and Read +in the verilog tests. + +The sources contain: + * Wrapper for the MemReader used in the verilog tests + * Wrapper for the MemWriter used in the verilog tests + * Wrapper for the AxiWriter used in the verilog tests + +""" + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//xls:xls_users"], + licenses = ["notice"], +) + +exports_files( + [ + "mem_reader_wrapper.v", + "mem_writer_wrapper.v", + "axi_writer_wrapper.v", + ], +) diff --git a/xls/modules/zstd/memory/rtl/axi_writer_wrapper.v b/xls/modules/zstd/memory/rtl/axi_writer_wrapper.v new file mode 100644 index 0000000000..15788cd41d --- /dev/null +++ b/xls/modules/zstd/memory/rtl/axi_writer_wrapper.v @@ -0,0 +1,122 @@ +// Copyright 2024 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 module wraps the AXI Writer verilog sources generated from DSLX to +// form a DUT for verilog tests with consistent IO. + +`default_nettype none + +module axi_writer_wrapper ( + input wire clk, + input wire rst, + + output wire write_resp_data, + output wire write_resp_vld, + input wire write_resp_rdy, + + input wire [31:0] write_req_data, + input wire write_req_vld, + output wire write_req_rdy, + + input wire [31:0] axi_st_read_tdata, + input wire [3:0] axi_st_read_tstr, + input wire [3:0] axi_st_read_tkeep, + input wire [0:0] axi_st_read_tlast, + input wire [3:0] axi_st_read_tid, + input wire [3:0] axi_st_read_tdest, + input wire axi_st_read_tvalid, + output wire axi_st_read_tready, + + output wire [3:0] axi_aw_awid, + output wire [15:0] axi_aw_awaddr, + output wire [2:0] axi_aw_awsize, + output wire [7:0] axi_aw_awlen, + output wire [1:0] axi_aw_awburst, + output wire axi_aw_awvalid, + input wire axi_aw_awready, + + output wire [31:0] axi_w_wdata, + output wire [3:0] axi_w_wstrb, + output wire [0:0] axi_w_wlast, + output wire axi_w_wvalid, + input wire axi_w_wready, + + input wire [2:0] axi_b_bresp, + input wire [3:0] axi_b_bid, + input wire axi_b_bvalid, + output wire axi_b_bready + +); + + wire [32:0] axi_writer__ch_axi_aw_data; + wire [36:0] axi_writer__ch_axi_w_data; + wire [ 6:0] axi_writer__ch_axi_b_data; + + wire [15:0] write_req_data_address; + wire [15:0] write_req_data_length; + + wire [48:0] axi_st_read_data; + + assign {write_req_data_address, write_req_data_length} = write_req_data; + + assign { axi_aw_awid, + axi_aw_awaddr, + axi_aw_awsize, + axi_aw_awlen, + axi_aw_awburst } = axi_writer__ch_axi_aw_data; + + assign {axi_w_wdata, axi_w_wstrb, axi_w_wlast} = axi_writer__ch_axi_w_data; + + assign axi_writer__ch_axi_b_data = {axi_b_bresp, axi_b_bid}; + + assign axi_st_read_data = { + axi_st_read_tdata, + axi_st_read_tstr, + axi_st_read_tkeep, + axi_st_read_tlast, + axi_st_read_tid, + axi_st_read_tdest + }; + + axi_writer axi_writer ( + .clk(clk), + .rst(rst), + + .axi_writer__ch_write_req_data(write_req_data), + .axi_writer__ch_write_req_rdy (write_req_rdy), + .axi_writer__ch_write_req_vld (write_req_vld), + + .axi_writer__ch_write_resp_rdy (write_resp_rdy), + .axi_writer__ch_write_resp_vld (write_resp_vld), + .axi_writer__ch_write_resp_data(write_resp_data), + + .axi_writer__ch_axi_aw_data(axi_writer__ch_axi_aw_data), + .axi_writer__ch_axi_aw_rdy (axi_aw_awready), + .axi_writer__ch_axi_aw_vld (axi_aw_awvalid), + + .axi_writer__ch_axi_w_data(axi_writer__ch_axi_w_data), + .axi_writer__ch_axi_w_rdy (axi_w_wready), + .axi_writer__ch_axi_w_vld (axi_w_wvalid), + + .axi_writer__ch_axi_b_data(axi_writer__ch_axi_b_data), + .axi_writer__ch_axi_b_rdy (axi_b_bready), + .axi_writer__ch_axi_b_vld (axi_b_bvalid), + + .axi_writer__ch_axi_st_read_data(axi_st_read_data), + .axi_writer__ch_axi_st_read_rdy (axi_st_read_tready), + .axi_writer__ch_axi_st_read_vld (axi_st_read_tvalid) + ); + + +endmodule : axi_writer_wrapper diff --git a/xls/modules/zstd/memory/rtl/mem_reader_wrapper.v b/xls/modules/zstd/memory/rtl/mem_reader_wrapper.v new file mode 100644 index 0000000000..12e1fe4478 --- /dev/null +++ b/xls/modules/zstd/memory/rtl/mem_reader_wrapper.v @@ -0,0 +1,114 @@ +// Copyright 2024 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 module wraps the Memory Reader verilog sources generated from DSLX to +// form a DUT for verilog tests with consistent IO. + +`default_nettype none + +module mem_reader_wrapper #( + parameter int DSLX_DATA_W = 64, + parameter int DSLX_ADDR_W = 16, + parameter int AXI_DATA_W = 128, + parameter int AXI_ADDR_W = 16, + parameter int AXI_DEST_W = 8, + parameter int AXI_ID_W = 8, + + parameter int CTRL_W = (DSLX_ADDR_W), + parameter int REQ_W = (2 * DSLX_ADDR_W), + parameter int RESP_W = (1 + DSLX_DATA_W + DSLX_ADDR_W + 1), + parameter int AXI_AR_W = (AXI_ID_W + AXI_ADDR_W + 28), + parameter int AXI_R_W = (AXI_ID_W + AXI_DATA_W + 4) +) ( + input wire clk, + input wire rst, + + output wire req_rdy, + input wire req_vld, + input wire [REQ_W-1:0] req_data, + + output wire resp_vld, + input wire resp_rdy, + output wire [RESP_W-1:0] resp_data, + + output wire axi_ar_arvalid, + input wire axi_ar_arready, + output wire [ AXI_ID_W-1:0] axi_ar_arid, + output wire [AXI_ADDR_W-1:0] axi_ar_araddr, + output wire [ 3:0] axi_ar_arregion, + output wire [ 7:0] axi_ar_arlen, + output wire [ 2:0] axi_ar_arsize, + output wire [ 1:0] axi_ar_arburst, + output wire [ 3:0] axi_ar_arcache, + output wire [ 2:0] axi_ar_arprot, + output wire [ 3:0] axi_ar_arqos, + + input wire axi_r_rvalid, + output wire axi_r_rready, + input wire [ AXI_ID_W-1:0] axi_r_rid, + input wire [AXI_DATA_W-1:0] axi_r_rdata, + input wire [ 2:0] axi_r_rresp, + input wire axi_r_rlast +); + + wire [AXI_AR_W-1:0] axi_ar_data; + wire axi_ar_rdy; + wire axi_ar_vld; + + assign axi_ar_rdy = axi_ar_arready; + + assign axi_ar_arvalid = axi_ar_vld; + assign { + axi_ar_arid, + axi_ar_araddr, + axi_ar_arregion, + axi_ar_arlen, + axi_ar_arsize, + axi_ar_arburst, + axi_ar_arcache, + axi_ar_arprot, + axi_ar_arqos +} = axi_ar_data; + + wire [AXI_R_W-1:0] axi_r_data; + wire axi_r_vld; + wire axi_r_rdy; + + assign axi_r_data = {axi_r_rid, axi_r_rdata, axi_r_rresp, axi_r_rlast}; + assign axi_r_vld = axi_r_rvalid; + + assign axi_r_rready = axi_r_rdy; + + mem_reader_adv mem_reader_adv ( + .clk(clk), + .rst(rst), + + .mem_reader__req_r_data(req_data), + .mem_reader__req_r_rdy (req_rdy), + .mem_reader__req_r_vld (req_vld), + + .mem_reader__resp_s_data(resp_data), + .mem_reader__resp_s_rdy (resp_rdy), + .mem_reader__resp_s_vld (resp_vld), + + .mem_reader__axi_ar_s_data(axi_ar_data), + .mem_reader__axi_ar_s_rdy (axi_ar_rdy), + .mem_reader__axi_ar_s_vld (axi_ar_vld), + + .mem_reader__axi_r_r_data(axi_r_data), + .mem_reader__axi_r_r_vld (axi_r_vld), + .mem_reader__axi_r_r_rdy (axi_r_rdy) + ); + +endmodule diff --git a/xls/modules/zstd/memory/rtl/mem_writer_wrapper.v b/xls/modules/zstd/memory/rtl/mem_writer_wrapper.v new file mode 100644 index 0000000000..1eee0dbd16 --- /dev/null +++ b/xls/modules/zstd/memory/rtl/mem_writer_wrapper.v @@ -0,0 +1,124 @@ +// Copyright 2024 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 module wraps the Memory Writer verilog sources generated from DSLX to +// form a DUT for verilog tests with consistent IO. + +`default_nettype none + +module mem_writer_wrapper ( + input wire clk, + input wire rst, + + input wire [31:0] req_data, + input wire req_vld, + output wire req_rdy, + + input wire [48:0] data_in_data, + input wire data_in_vld, + output wire data_in_rdy, + + output wire resp_data, + output wire resp_vld, + input wire resp_rdy, + + output wire [3:0] axi_aw_awid, + output wire [15:0] axi_aw_awaddr, + output wire [2:0] axi_aw_awsize, + output wire [7:0] axi_aw_awlen, + output wire [1:0] axi_aw_awburst, + output wire axi_aw_awvalid, + input wire axi_aw_awready, + + output wire [31:0] axi_w_wdata, + output wire [3:0] axi_w_wstrb, + output wire [0:0] axi_w_wlast, + output wire axi_w_wvalid, + input wire axi_w_wready, + + input wire [2:0] axi_b_bresp, + input wire [3:0] axi_b_bid, + input wire axi_b_bvalid, + output wire axi_b_bready +); + + wire [15:0] req_f_addr; + wire [15:0] req_f_length; + + wire [31:0] data_in_f_data; + wire [15:0] data_in_f_length; + wire [0:0] data_in_f_last; + + wire [36:0] axi_w_data; + wire axi_w_vld; + wire axi_w_rdy; + + wire [32:0] axi_aw_data; + wire axi_aw_vld; + wire axi_aw_rdy; + + wire [6:0] axi_b_data; + wire axi_b_rdy; + wire axi_b_vld; + + assign {req_f_addr, req_f_length} = req_data; + + assign {data_in_f_data, data_in_f_length, data_in_f_last} = data_in_data; + + assign {axi_aw_awid, axi_aw_awaddr, axi_aw_awsize, axi_aw_awlen, axi_aw_awburst} = axi_aw_data; + assign axi_aw_awvalid = axi_aw_vld; + assign axi_aw_rdy = axi_aw_awready; + + assign {axi_w_wdata, axi_w_wstrb, axi_w_wlast} = axi_w_data; + assign axi_w_wvalid = axi_w_vld; + assign axi_w_rdy = axi_w_wready; + + assign axi_b_data = {axi_b_bresp, axi_b_bid}; + assign axi_b_vld = axi_b_bvalid; + assign axi_b_bready = axi_b_rdy; + + mem_writer mem_writer ( + .clk(clk), + .rst(rst), + + // MemWriter Write Request + .mem_writer__req_in_r_data(req_data), + .mem_writer__req_in_r_vld (req_vld), + .mem_writer__req_in_r_rdy (req_rdy), + + // Data to write + .mem_writer__data_in_r_data(data_in_data), + .mem_writer__data_in_r_vld (data_in_vld), + .mem_writer__data_in_r_rdy (data_in_rdy), + + // Response channel + .mem_writer__resp_s_data(resp_data), + .mem_writer__resp_s_rdy (resp_rdy), + .mem_writer__resp_s_vld (resp_vld), + + // Memory AXI + .mem_writer__axi_w_s_data(axi_w_data), + .mem_writer__axi_w_s_vld (axi_w_vld), + .mem_writer__axi_w_s_rdy (axi_w_rdy), + + .mem_writer__axi_aw_s_data(axi_aw_data), + .mem_writer__axi_aw_s_vld (axi_aw_vld), + .mem_writer__axi_aw_s_rdy (axi_aw_rdy), + + .mem_writer__axi_b_r_data(axi_b_data), + .mem_writer__axi_b_r_vld (axi_b_vld), + .mem_writer__axi_b_r_rdy (axi_b_rdy) + ); + +endmodule : mem_writer_wrapper diff --git a/xls/modules/zstd/parallel_rams.x b/xls/modules/zstd/parallel_rams.x index 6a48ae8072..f4180682eb 100644 --- a/xls/modules/zstd/parallel_rams.x +++ b/xls/modules/zstd/parallel_rams.x @@ -28,7 +28,8 @@ type BlockPacketLength = common::BlockPacketLength; pub type Offset = common::Offset; // Configurable RAM parameters, RAM_NUM has to be a power of 2 -pub const RAM_NUM = u32:8; +pub const RAM_NUM = common::LITERALS_IN_PACKET; +pub type RamIndex = uN[std::clog2(RAM_NUM)]; // Constants calculated from RAM parameters pub const RAM_NUM_WIDTH = std::clog2(RAM_NUM); @@ -37,11 +38,11 @@ pub type RamNumber = bits[RAM_NUM_WIDTH]; pub type RamReadStart = bits[RAM_NUM_WIDTH]; pub type RamReadLen = bits[std::clog2(RAM_NUM + u32:1)]; -pub fn ram_size(hb_size_kb: u32) -> u32 { +pub fn ram_size(hb_size_kb: u32) -> u32 { (hb_size_kb * u32:1024 * u32:8) / RAM_DATA_WIDTH / RAM_NUM } -pub fn ram_addr_width(hb_size_kb: u32) -> u32 { +pub fn ram_addr_width(hb_size_kb: u32) -> u32 { std::clog2(ram_size(hb_size_kb)) } @@ -49,14 +50,16 @@ pub fn ram_addr_width(hb_size_kb: const TEST_HISTORY_BUFFER_SIZE_KB = u32:1; const TEST_RAM_SIZE = ram_size(TEST_HISTORY_BUFFER_SIZE_KB); const TEST_RAM_ADDR_WIDTH = ram_addr_width(TEST_HISTORY_BUFFER_SIZE_KB); -const TEST_RAM_DATA_WIDTH = common::SYMBOL_WIDTH; +const TEST_RAM_DATA_WIDTH = u32:8; const TEST_RAM_WORD_PARTITION_SIZE = TEST_RAM_DATA_WIDTH; const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_WORD_PARTITION_SIZE, TEST_RAM_DATA_WIDTH); +const TEST_RAM_NUM = u32:8; const TEST_RAM_INITIALIZED = true; const TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; const TEST_RAM_REQ_MASK_ALL = std::unsigned_max_value(); const TEST_RAM_REQ_MASK_NONE = bits[TEST_RAM_NUM_PARTITIONS]:0; +type TestCopyOrMatchContent = uN[TEST_RAM_DATA_WIDTH * u32:8]; type TestRamAddr = bits[TEST_RAM_ADDR_WIDTH]; type TestWriteReq = ram::WriteReq; type TestWriteResp = ram::WriteResp; @@ -213,13 +216,13 @@ fn test_hb_ptr_from_offset_forw() { fn literal_packet_to_single_write_req< HISTORY_BUFFER_SIZE_KB: u32, RAM_ADDR_WIDTH: u32 = {ram_addr_width(HISTORY_BUFFER_SIZE_KB)}, - RAM_DATA_WIDTH: u32 = {common::SYMBOL_WIDTH}, + RAM_DATA_WIDTH: u32 = {common::SYMBOLS_IN_PACKET}, RAM_WORD_PARTITION_SIZE: u32 = {RAM_DATA_WIDTH}, RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH)} >(ptr: HistoryBufferPtr, literal: SequenceExecutorPacket, number: RamNumber) - -> ram::WriteReq { - type RamData = uN[RAM_DATA_WIDTH]; - type WriteReq = ram::WriteReq; + -> ram::WriteReq { + type RamData = uN[RAM_WORD_PARTITION_SIZE]; + type WriteReq = ram::WriteReq; let offset = std::mod_pow2(RAM_NUM - ptr.number as u32 + number as u32, RAM_NUM) as Offset; let we = literal.length >= offset as CopyOrMatchLength + CopyOrMatchLength:1; @@ -227,7 +230,7 @@ fn literal_packet_to_single_write_req< if (we) { WriteReq { - data: literal.content[offset as u32 * RAM_DATA_WIDTH+:RamData] as RamData, + data: literal.content[offset as u32 * RAM_WORD_PARTITION_SIZE+:RamData] as RamData, addr: hb.addr, mask: std::unsigned_max_value() } @@ -250,40 +253,34 @@ fn test_literal_packet_to_single_write_req() { let literals = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: CopyOrMatchLength:7, - content: CopyOrMatchContent:0x77_6655_4433_2211, + content: TestCopyOrMatchContent:0x77_6655_4433_2211, last: false }; assert_eq( - literal_packet_to_single_write_req(ptr, literals, RamNumber:0), + literal_packet_to_single_write_req(ptr, literals, RamNumber:0), TestWriteReq { data: RamData:0x22, addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }); assert_eq( - literal_packet_to_single_write_req(ptr, literals, RamNumber:3), + literal_packet_to_single_write_req(ptr, literals, RamNumber:3), TestWriteReq { data: RamData:0x55, addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }); assert_eq( - literal_packet_to_single_write_req(ptr, literals, RamNumber:6), + literal_packet_to_single_write_req(ptr, literals, RamNumber:6), zero!()); } pub fn literal_packet_to_write_reqs< HISTORY_BUFFER_SIZE_KB: u32, + RAM_NUM: u32, RAM_ADDR_WIDTH: u32 = {ram_addr_width(HISTORY_BUFFER_SIZE_KB)}, - RAM_DATA_WIDTH: u32 = {common::SYMBOL_WIDTH}, + RAM_DATA_WIDTH: u32 = {common::SYMBOLS_IN_PACKET}, RAM_WORD_PARTITION_SIZE: u32 = {RAM_DATA_WIDTH}, - RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH)} + RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH)}, >( ptr: HistoryBufferPtr, literal: SequenceExecutorPacket -) -> (ram::WriteReq[RAM_NUM], HistoryBufferPtr) { - type WriteReq = ram::WriteReq; - let result = WriteReq[RAM_NUM]:[ - literal_packet_to_single_write_req(ptr, literal, RamNumber:0), - literal_packet_to_single_write_req(ptr, literal, RamNumber:1), - literal_packet_to_single_write_req(ptr, literal, RamNumber:2), - literal_packet_to_single_write_req(ptr, literal, RamNumber:3), - literal_packet_to_single_write_req(ptr, literal, RamNumber:4), - literal_packet_to_single_write_req(ptr, literal, RamNumber:5), - literal_packet_to_single_write_req(ptr, literal, RamNumber:6), - literal_packet_to_single_write_req(ptr, literal, RamNumber:7), - ]; +) -> (ram::WriteReq[RAM_NUM], HistoryBufferPtr) { + type WriteReq = ram::WriteReq; + let result = unroll_for! (i, data): (u32, WriteReq[RAM_NUM]) in u32:0..RAM_NUM { + update(data, i, literal_packet_to_single_write_req(ptr, literal, i as RamNumber)) + }(zero!()); let ptr_offset = literal.length; (result, hb_ptr_from_offset_forw(ptr, ptr_offset as Offset)) @@ -302,14 +299,14 @@ fn test_literal_packet_to_write_reqs() { let ptr = HistoryBufferPtr { number: RamNumber:7, addr: TestRamAddr:0x2 }; let literals = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, - content: CopyOrMatchContent:0x11, + content: TestCopyOrMatchContent:0x11, length: CopyOrMatchLength:1, last: false }; assert_eq( - literal_packet_to_write_reqs(ptr, literals), + literal_packet_to_write_reqs(ptr, literals), ( - TestWriteReq[RAM_NUM]:[ + TestWriteReq[TEST_RAM_NUM]:[ zero!(), zero!(), zero!(), zero!(), zero!(), zero!(), zero!(), @@ -327,14 +324,14 @@ fn test_literal_packet_to_write_reqs() { let ptr = HistoryBufferPtr { number: RamNumber:7, addr: TestRamAddr:2 }; let literals = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, - content: CopyOrMatchContent:0x8877_6655_4433_2211, + content: TestCopyOrMatchContent:0x8877_6655_4433_2211, length: CopyOrMatchLength:8, last: false }; assert_eq( - literal_packet_to_write_reqs(ptr, literals), + literal_packet_to_write_reqs(ptr, literals), ( - TestWriteReq[RAM_NUM]:[ + TestWriteReq[TEST_RAM_NUM]:[ TestWriteReq { data: RamData:0x22, addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, TestWriteReq { data: RamData:0x33, addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, TestWriteReq { data: RamData:0x44, addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, @@ -350,7 +347,7 @@ fn test_literal_packet_to_write_reqs() { fn max_hb_ptr_for_sequence_packet< HISTORY_BUFFER_SIZE_KB: u32, RAM_ADDR_WIDTH: u32 = {ram_addr_width(HISTORY_BUFFER_SIZE_KB)}, - RAM_DATA_WIDTH: u32 = {common::SYMBOL_WIDTH}, + RAM_DATA_WIDTH: u32 = {common::SYMBOLS_IN_PACKET}, > ( ptr: HistoryBufferPtr, seq: SequenceExecutorPacket ) -> HistoryBufferPtr { @@ -360,7 +357,7 @@ fn max_hb_ptr_for_sequence_packet< fn sequence_packet_to_single_read_req< HISTORY_BUFFER_SIZE_KB: u32, RAM_ADDR_WIDTH: u32 = {ram_addr_width(HISTORY_BUFFER_SIZE_KB)}, - RAM_DATA_WIDTH: u32 = {common::SYMBOL_WIDTH}, + RAM_DATA_WIDTH: u32 = {common::SYMBOLS_IN_PACKET}, RAM_WORD_PARTITION_SIZE: u32 = {RAM_DATA_WIDTH}, RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH)} > ( @@ -398,7 +395,7 @@ fn test_sequence_packet_to_single_read_req() { let ptr = HistoryBufferPtr { number: RamNumber:1, addr: TestRamAddr:0x3 }; let sequence = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - content: CopyOrMatchContent:11, + content: TestCopyOrMatchContent:11, length: CopyOrMatchLength:4, last: false }; @@ -407,34 +404,35 @@ fn test_sequence_packet_to_single_read_req() { >(ptr, sequence); assert_eq( - sequence_packet_to_single_read_req( + sequence_packet_to_single_read_req( ptr, max_ptr, sequence, RamNumber:0), TestReadReq { addr: TestRamAddr:0x2, mask: TEST_RAM_REQ_MASK_ALL }); assert_eq( - sequence_packet_to_single_read_req( + sequence_packet_to_single_read_req( ptr, max_ptr, sequence, RamNumber:1), TestReadReq { addr: TestRamAddr:0x2, mask: TEST_RAM_REQ_MASK_ALL }); assert_eq( - sequence_packet_to_single_read_req( + sequence_packet_to_single_read_req( ptr, max_ptr, sequence, RamNumber:2), zero!()); assert_eq( - sequence_packet_to_single_read_req( + sequence_packet_to_single_read_req( ptr, max_ptr, sequence, RamNumber:7), TestReadReq { addr: TestRamAddr:0x1, mask: TEST_RAM_REQ_MASK_ALL }); assert_eq( - sequence_packet_to_single_read_req( + sequence_packet_to_single_read_req( ptr, max_ptr, sequence, RamNumber:6), TestReadReq { addr: TestRamAddr:0x1, mask: TEST_RAM_REQ_MASK_ALL }); } pub fn sequence_packet_to_read_reqs< HISTORY_BUFFER_SIZE_KB: u32, + RAM_NUM: u32, RAM_ADDR_WIDTH: u32 = {ram_addr_width(HISTORY_BUFFER_SIZE_KB)}, - RAM_DATA_WIDTH: u32 = {common::SYMBOL_WIDTH}, + RAM_DATA_WIDTH: u32 = {common::SYMBOLS_IN_PACKET}, RAM_WORD_PARTITION_SIZE: u32 = {RAM_DATA_WIDTH}, RAM_NUM_PARTITIONS: u32 = {ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH)} > ( @@ -477,16 +475,10 @@ pub fn sequence_packet_to_read_reqs< }; let max_ptr = max_hb_ptr_for_sequence_packet(ptr, curr_seq); - let req0 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:0); - let req1 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:1); - let req2 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:2); - let req3 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:3); - let req4 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:4); - let req5 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:5); - let req6 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:6); - let req7 = sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, RamNumber:7); - let reqs = ReadReq[RAM_NUM]:[req0, req1, req2, req3, req4, req5, req6, req7]; + let reqs = unroll_for! (i, data): (u32, ReadReq[RAM_NUM]) in u32:0..RAM_NUM { + update(data, i, sequence_packet_to_single_read_req(ptr, max_ptr, curr_seq, i as RamNumber)) + }(zero!()); (reqs, max_ptr.number, max_len as RamReadLen, next_seq, next_seq_valid) } @@ -505,17 +497,18 @@ fn test_sequence_packet_to_read_reqs() { let ptr = HistoryBufferPtr { number: RamNumber:1, addr: TestRamAddr:0x3 }; let sequence = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - content: CopyOrMatchContent:11, + content: TestCopyOrMatchContent:11, length: CopyOrMatchLength:4, last: false }; - let result = sequence_packet_to_read_reqs( + let result = sequence_packet_to_read_reqs( ptr, sequence, HistoryBufferLength:20); let expected = ( - TestReadReq[RAM_NUM]:[ + TestReadReq[TEST_RAM_NUM]:[ + TestReadReq { addr: TestRamAddr:0x2, mask: TEST_RAM_REQ_MASK_ALL }, TestReadReq { addr: TestRamAddr:0x2, mask: TEST_RAM_REQ_MASK_ALL }, - TestReadReq { addr: TestRamAddr:0x2, mask: TEST_RAM_REQ_MASK_ALL }, zero!(), - zero!(), zero!(), zero!(), + zero!(), zero!(), + zero!(), zero!(), TestReadReq { addr: TestRamAddr:0x1, mask: TEST_RAM_REQ_MASK_ALL }, TestReadReq { addr: TestRamAddr:0x1, mask: TEST_RAM_REQ_MASK_ALL }, ], @@ -535,14 +528,14 @@ fn test_sequence_packet_to_read_reqs() { let ptr = HistoryBufferPtr { number: RamNumber:0, addr: TestRamAddr:0x4 }; let sequence = Packet { msg_type: SequenceExecutorMessageType::SEQUENCE, - content: CopyOrMatchContent:10, + content: TestCopyOrMatchContent:10, length: CopyOrMatchLength:9, last: false }; - let result = sequence_packet_to_read_reqs( + let result = sequence_packet_to_read_reqs( ptr, sequence, HistoryBufferLength:20); let expected = ( - TestReadReq[RAM_NUM]:[ + TestReadReq[TEST_RAM_NUM]:[ TestReadReq { addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, TestReadReq { addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, TestReadReq { addr: TestRamAddr:0x3, mask: TEST_RAM_REQ_MASK_ALL }, @@ -556,7 +549,7 @@ fn test_sequence_packet_to_read_reqs() { RamReadLen:8, Packet { msg_type: SequenceExecutorMessageType::SEQUENCE, - content: CopyOrMatchContent:10, + content: TestCopyOrMatchContent:10, length: CopyOrMatchLength:1, last: false }, true, @@ -591,44 +584,29 @@ pub fn create_ram_wr_data { input_r: chan> in; output_s: chan> out; - wr_resp_m0_r: chan in; - wr_resp_m1_r: chan in; - wr_resp_m2_r: chan in; - wr_resp_m3_r: chan in; - wr_resp_m4_r: chan in; - wr_resp_m5_r: chan in; - wr_resp_m6_r: chan in; - wr_resp_m7_r: chan in; + wr_resp_m_r: chan[RAM_NUM] in; config(input_r: chan> in, output_s: chan> out, - wr_resp_m0_r: chan in, wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, wr_resp_m7_r: chan in) { + wr_resp_m_r: chan[RAM_NUM] in) { ( - input_r, output_s, wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, wr_resp_m4_r, - wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r, + input_r, output_s, wr_resp_m_r, ) } init { } next(state: ()) { - let tok0 = join(); - let (tok1, input) = recv(tok0, input_r); - - let (tok2_0, _) = recv_if(tok1, wr_resp_m0_r, input.resp[0], zero!()); - let (tok2_1, _) = recv_if(tok1, wr_resp_m1_r, input.resp[1], zero!()); - let (tok2_2, _) = recv_if(tok1, wr_resp_m2_r, input.resp[2], zero!()); - let (tok2_3, _) = recv_if(tok1, wr_resp_m3_r, input.resp[3], zero!()); - let (tok2_4, _) = recv_if(tok1, wr_resp_m4_r, input.resp[4], zero!()); - let (tok2_5, _) = recv_if(tok1, wr_resp_m5_r, input.resp[5], zero!()); - let (tok2_6, _) = recv_if(tok1, wr_resp_m6_r, input.resp[6], zero!()); - let (tok2_7, _) = recv_if(tok1, wr_resp_m7_r, input.resp[7], zero!()); - let tok2 = join(tok2_0, tok2_1, tok2_2, tok2_3, tok2_4, tok2_5, tok2_6, tok2_7); - - let tok3 = send(tok2, output_s, RamWrRespHandlerResp { + let tok = join(); + let (tok, input) = recv(tok, input_r); + + let all_resps = unroll_for! (i, all_resps): + (u32, token) in u32:0..RAM_NUM { + let (tok_resp, _) = recv_if(tok, wr_resp_m_r[i], input.resp[i], zero!()); + (join(tok_resp, all_resps)) + }((tok)); + + let tok = send(all_resps, output_s, RamWrRespHandlerResp { length: std::popcount(std::convert_to_bits_msb0(input.resp)) as uN[std::clog2(RAM_NUM + u32:1)], ptr: input.ptr }); @@ -657,67 +635,43 @@ pub fn create_ram_rd_data { +pub proc RamRdRespHandler { input_r: chan in; output_s: chan> out; - rd_resp_m0_r: chan> in; - rd_resp_m1_r: chan> in; - rd_resp_m2_r: chan> in; - rd_resp_m3_r: chan> in; - rd_resp_m4_r: chan> in; - rd_resp_m5_r: chan> in; - rd_resp_m6_r: chan> in; - rd_resp_m7_r: chan> in; + rd_resp_m_r: chan>[RAM_NUM] in; config(input_r: chan in, output_s: chan> out, - rd_resp_m0_r: chan> in, - rd_resp_m1_r: chan> in, - rd_resp_m2_r: chan> in, - rd_resp_m3_r: chan> in, - rd_resp_m4_r: chan> in, - rd_resp_m5_r: chan> in, - rd_resp_m6_r: chan> in, - rd_resp_m7_r: chan> in) { + rd_resp_m_r: chan>[RAM_NUM] in) { ( - input_r, output_s, rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, rd_resp_m4_r, - rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, + input_r, output_s, rd_resp_m_r, ) } init { } next(state: ()) { - let tok0 = join(); - type ReadResp = ram::ReadResp; + let tok = join(); + type ReadResp = ram::ReadResp; type Content = uN[RAM_DATA_WIDTH * u32:8]; - let (tok1, input) = recv(tok0, input_r); - - let (tok2_0, resp_0) = recv_if(tok1, rd_resp_m0_r, input.resp[0], zero!()); - let (tok2_1, resp_1) = recv_if(tok1, rd_resp_m1_r, input.resp[1], zero!()); - let (tok2_2, resp_2) = recv_if(tok1, rd_resp_m2_r, input.resp[2], zero!()); - let (tok2_3, resp_3) = recv_if(tok1, rd_resp_m3_r, input.resp[3], zero!()); - let (tok2_4, resp_4) = recv_if(tok1, rd_resp_m4_r, input.resp[4], zero!()); - let (tok2_5, resp_5) = recv_if(tok1, rd_resp_m5_r, input.resp[5], zero!()); - let (tok2_6, resp_6) = recv_if(tok1, rd_resp_m6_r, input.resp[6], zero!()); - let (tok2_7, resp_7) = recv_if(tok1, rd_resp_m7_r, input.resp[7], zero!()); - let tok2 = join(tok2_0, tok2_1, tok2_2, tok2_3, tok2_4, tok2_5, tok2_6, tok2_7); - - let resp_data = [ - resp_0.data, resp_1.data, resp_2.data, resp_3.data, - resp_4.data, resp_5.data, resp_6.data, resp_7.data - ]; - - let content = ( - resp_data[input.read_start + u3:7] ++ - resp_data[input.read_start + u3:6] ++ - resp_data[input.read_start + u3:5] ++ - resp_data[input.read_start + u3:4] ++ - resp_data[input.read_start + u3:3] ++ - resp_data[input.read_start + u3:2] ++ - resp_data[input.read_start + u3:1] ++ - resp_data[input.read_start + u3:0] - ); + let (tok1, input) = recv(tok, input_r); + + let (tok2, resp_data) = + unroll_for! (i, (all_resps, resp_data)): + (u32, (token, ReadResp[RAM_NUM])) in u32:0..RAM_NUM { + let (resp_tok, resp) = recv_if(tok1, rd_resp_m_r[i], input.resp[i], zero!()); + ( + join(all_resps, resp_tok), + update(resp_data, i, resp) + ) + }((tok1, zero!())); + + let content = + unroll_for! (i, content): + (u32, Content) in u32:0..RAM_NUM { + let index = input.read_start + i as RamIndex; + bit_slice_update(content, i * RAM_WORD_PARTITION_SIZE, resp_data[index].data) + }(zero!()); let output_data = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, diff --git a/xls/modules/zstd/perf_report.py b/xls/modules/zstd/perf_report.py new file mode 100644 index 0000000000..60df3c2162 --- /dev/null +++ b/xls/modules/zstd/perf_report.py @@ -0,0 +1,30 @@ +# Copyright 2025 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 pathlib +import os + +_report_file = pathlib.Path("report_perf.log") +_report_file.parent.mkdir(exist_ok=True) + +def create_report_file(): + with _report_file.open('w') as f: + f.write("| test name | total cycles | latency [cycles] | total bytes decoded | throughput [GiB/s] |\n") + f.write("| --------- | ------------ | ---------------- | ------------------- | ------------------ |\n") + +create_report_file() + +def report_test_result(test_name, duration, latency, total_decoded_bytes, gigabytes_per_second): + with _report_file.open("a") as f: + f.write(f"| {test_name} | {round(duration)} | {round(latency)} | {round(total_decoded_bytes)} | {gigabytes_per_second:.3f} |\n") diff --git a/xls/modules/zstd/ram_cocotb_test.py b/xls/modules/zstd/ram_cocotb_test.py new file mode 100644 index 0000000000..0a224b9946 --- /dev/null +++ b/xls/modules/zstd/ram_cocotb_test.py @@ -0,0 +1,75 @@ +# Copyright 2025 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 pathlib + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import ClockCycles, RisingEdge + +from xls.modules.zstd.cocotb.utils import run_test + +async def reset_dut(dut, rst_len=10): + dut.rst.setimmediatevalue(0) + await ClockCycles(dut.clk, rst_len) + dut.rst.setimmediatevalue(1) + await RisingEdge(dut.clk) + dut.rst.setimmediatevalue(0) + +@cocotb.test(timeout_time=200, timeout_unit="ms") +async def comp_frame(dut): + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + await reset_dut(dut) + + dut.wr_en_0.value = 0x1 + dut.addr_0.value = 0x0 + dut.data_0.value = 0x2 + + await RisingEdge(dut.clk) + + dut.wr_en_0.value = 0x0 + dut.rd_en_0.value = 0x1 + dut.addr_0.value = 0x0 + + dut.wr_en_1.value = 0x1 + dut.addr_1.value = 0xc + dut.data_1.value = 0x7 + + await RisingEdge(dut.clk) + + dut.rd_en_0.value = 0x0 + + dut.wr_en_1.value = 0x0 + dut.rd_en_1.value = 0x1 + dut.addr_1.value = 0xc + + await RisingEdge(dut.clk) + + dut.rd_en_1.value = 0x0 + + await ClockCycles(dut.clk, 5) + + assert(dut.rd_data_0.value == 0x2) + assert(dut.rd_data_1.value == 0x7) + + +if __name__ == "__main__": + toplevel = "ram_2rw" + verilog_sources = [ + "xls/modules/zstd/rtl/ram_2rw.sv", + ] + test_module = [pathlib.Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/ram_demux.x b/xls/modules/zstd/ram_demux.x index 78a0c594e5..fe395b7121 100644 --- a/xls/modules/zstd/ram_demux.x +++ b/xls/modules/zstd/ram_demux.x @@ -235,7 +235,7 @@ pub proc RamDemux< } } -// FIXME: This process wraps RamDemux with additional logic as a workaround +// This process wraps RamDemux with additional logic as a workaround // to prevent artificial responses on the write channel caused by RAM rewriting. pub proc RamDemuxWrapped< ADDR_WIDTH: u32, @@ -746,7 +746,7 @@ pub proc RamDemuxNaive< } } -// FIXME: This process wraps RamDemux with additional logic as a workaround +// This process wraps RamDemux with additional logic as a workaround // to prevent artificial responses on the write channel caused by RAM rewriting. pub proc RamDemuxNaiveWrapped< ADDR_WIDTH: u32, diff --git a/xls/modules/zstd/ram_demux_cocotb_test.py b/xls/modules/zstd/ram_demux_cocotb_test.py new file mode 100644 index 0000000000..36382bf3af --- /dev/null +++ b/xls/modules/zstd/ram_demux_cocotb_test.py @@ -0,0 +1,173 @@ +# Copyright 2024 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 pathlib +import random +import sys +import warnings + +import cocotb +from cocotb.binary import BinaryValue +from cocotb.clock import Clock +from cocotb.triggers import Event, ClockCycles, RisingEdge +from cocotb_bus.scoreboard import Scoreboard +from cocotbext.axi import axi_channels +from cocotbext.axi.axi_ram import AxiRamRead +from cocotbext.axi.sparse_memory import SparseMemory + +import xls.modules.zstd.cocotb.channel as xlschannel +from xls.modules.zstd.cocotb import utils +from xls.modules.zstd.cocotb import xlsstruct + +warnings.filterwarnings("ignore", category=DeprecationWarning) + +ADDR_W = 10 +DATA_W = 64 +NUM_PARTITIONS = 64 +SEL_W = 1 + + +@xlsstruct.xls_dataclass +class SelReq(xlsstruct.XLSStruct): + sel: SEL_W + + +@xlsstruct.xls_dataclass +class ReadReq(xlsstruct.XLSStruct): + addr: ADDR_W + mask: NUM_PARTITIONS + + +@xlsstruct.xls_dataclass +class ReadResp(xlsstruct.XLSStruct): + data: DATA_W + + +@xlsstruct.xls_dataclass +class WriteReq(xlsstruct.XLSStruct): + addr: ADDR_W + data: DATA_W + mask: NUM_PARTITIONS + + +@xlsstruct.xls_dataclass +class WriteResp(xlsstruct.XLSStruct): + pass + + +def print_callback(name: str = "monitor"): + def _print_callback(transaction): + print(f" [{name}]: {transaction}") + + return _print_callback + + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + print("all transactions received") + event.set() + + monitor.add_callback(terminate_cb) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def test_mem_reader(dut): + + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + sel_resp_channel = xlschannel.XLSChannel(dut, "ram_demux__sel_resp_s", dut.clk) + rd_resp_channel = xlschannel.XLSChannel(dut, "ram_demux__rd_resp_s", dut.clk) + wr_resp_channel = xlschannel.XLSChannel( + dut, "ram_demux__wr_resp_s", dut.clk, start_now=True + ) + + sel_driver = xlschannel.XLSChannelDriver(dut, "ram_demux__sel_req_r", dut.clk) + rd_req_driver = xlschannel.XLSChannelDriver(dut, "ram_demux__rd_req_r", dut.clk) + wr_req_driver = xlschannel.XLSChannelDriver(dut, "ram_demux__wr_req_r", dut.clk) + + dut.rst.setimmediatevalue(0) + await ClockCycles(dut.clk, 10) + dut.rst.setimmediatevalue(1) + await ClockCycles(dut.clk, 10) + dut.rst.setimmediatevalue(0) + + sel_resp_channel.rdy.setimmediatevalue(1) + rd_resp_channel.rdy.setimmediatevalue(1) + wr_resp_channel.rdy.setimmediatevalue(1) + + await sel_driver.send(SelReq(0)) + while True: + await RisingEdge(dut.clk) + if sel_resp_channel.rdy.value and sel_resp_channel.vld.value: + break + + await wr_req_driver.send(WriteReq(addr=123, data=0x10, mask=0xFFFF_FFFF_FFFF_FFFF)) + while True: + await RisingEdge(dut.clk) + if wr_resp_channel.rdy.value and wr_resp_channel.vld.value: + break + + await sel_driver.send(SelReq(1)) + while True: + await RisingEdge(dut.clk) + if sel_resp_channel.rdy.value and sel_resp_channel.vld.value: + break + + await wr_req_driver.send(WriteReq(addr=256, data=0x3, mask=0xFFFF_FFFF_FFFF_FFFF)) + while True: + await RisingEdge(dut.clk) + if wr_resp_channel.rdy.value and wr_resp_channel.vld.value: + break + + await sel_driver.send(SelReq(0)) + while True: + await RisingEdge(dut.clk) + if sel_resp_channel.rdy.value and sel_resp_channel.vld.value: + break + + await rd_req_driver.send(ReadReq(addr=123, mask=0xFFFF_FFFF_FFFF_FFFF)) + while True: + await RisingEdge(dut.clk) + if rd_resp_channel.rdy.value and rd_resp_channel.vld.value: + assert rd_resp_channel.data.value == 0x10 + break + + await sel_driver.send(SelReq(1)) + while True: + await RisingEdge(dut.clk) + if sel_resp_channel.rdy.value and sel_resp_channel.vld.value: + break + + await rd_req_driver.send(ReadReq(addr=256, mask=0xFFFF_FFFF_FFFF_FFFF)) + while True: + await RisingEdge(dut.clk) + if rd_resp_channel.rdy.value and rd_resp_channel.vld.value: + assert rd_resp_channel.data.value == 0x3 + break + + +if __name__ == "__main__": + sys.path.append(str(pathlib.Path(__file__).parent)) + + toplevel = "ram_demux_wrapper" + verilog_sources = [ + "xls/modules/zstd/ram_demux.v", + "xls/modules/zstd/rtl/ram_1r1w.sv", + "xls/modules/zstd/rtl/ram_demux_wrapper.sv", + ] + test_module = [pathlib.Path(__file__).stem] + utils.run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/raw_block_dec.x b/xls/modules/zstd/raw_block_dec.x index 3617a41783..b8f9a22673 100644 --- a/xls/modules/zstd/raw_block_dec.x +++ b/xls/modules/zstd/raw_block_dec.x @@ -166,7 +166,7 @@ pub proc RawBlockDecoderInst { next (state: ()) { } } -const TEST_DATA_W = u32:64; +const TEST_DATA_W = common::DATA_WIDTH; const TEST_ADDR_W = u32:32; #[test_proc] diff --git a/xls/modules/zstd/raw_literals_dec.x b/xls/modules/zstd/raw_literals_dec.x index 853062ed0b..23744150d9 100644 --- a/xls/modules/zstd/raw_literals_dec.x +++ b/xls/modules/zstd/raw_literals_dec.x @@ -155,7 +155,7 @@ pub proc RawLiteralsDecoderInst { next(state: ()) {} } -const TEST_DATA_W = u32:64; +const TEST_DATA_W = common::AXI_DATA_W; const TEST_ADDR_W = u32:16; #[test_proc] diff --git a/xls/modules/zstd/refilling_shift_buffer.x b/xls/modules/zstd/refilling_shift_buffer.x index 78f6f2982e..c31af0f939 100644 --- a/xls/modules/zstd/refilling_shift_buffer.x +++ b/xls/modules/zstd/refilling_shift_buffer.x @@ -79,7 +79,7 @@ proc RefillingShiftBufferInternal< DATA_W: u32, ADDR_W: u32, BACKWARDS: bool = {false}, INSTANCE: u32 = {u32:0}, LENGTH_W: u32 = {length_width(DATA_W)}, DATA_W_DIV8: u32 = {DATA_W / u32:8}, - BUFFER_W: u32 = {DATA_W * u32:2}, // TODO: fix implementation detail of ShiftBuffer leaking here + BUFFER_W: u32 = {DATA_W * u32:2}, BUFFER_W_CLOG2: u32 = {std::clog2(BUFFER_W) + u32:1}, >{ type MemReaderReq = mem_reader::MemReaderReq; @@ -175,7 +175,7 @@ proc RefillingShiftBufferInternal< // on send to buffer_data_in_s if the proc sending control requests isn't // receiving the data on the output channel fast enough, but this is true // of any proc that uses MemReader and we don't consider this an issue - let buf_will_have_enough_space = state.future_buf_occupancy <= DATA_W as BufferSize; // TODO: fix implementation detail of ShiftBuffer leaking here + let buf_will_have_enough_space = state.future_buf_occupancy <= DATA_W as BufferSize; let do_refill_cycle = state.fsm == Fsm::REFILLING && buf_will_have_enough_space; // send request to memory for more data under the assumption // that there's enough space in the ShiftBuffer to fit it @@ -265,7 +265,7 @@ proc RefillingShiftBufferInternal< let forward_snooped_data = snoop_data_valid && !flushing; let tok = send_if(tok, buffer_data_out_s, forward_snooped_data, RSBOutput { data: if BACKWARDS { - rev(snoop_data.data) >> (u32:64 - snoop_data.length as u32) + rev(snoop_data.data) >> (DATA_W - snoop_data.length as u32) } else { snoop_data.data }, @@ -442,7 +442,7 @@ const TEST_DATA_W = u32:64; const TEST_ADDR_W = u32:32; const TEST_LENGTH_W = length_width(TEST_DATA_W); const TEST_DATA_W_DIV8 = TEST_DATA_W / u32:8; -const TEST_BUFFER_W = TEST_DATA_W * u32:2; // TODO: fix implementation detail of ShiftBuffer leaking here +const TEST_BUFFER_W = TEST_DATA_W * u32:2; const TEST_BUFFER_W_CLOG2 = std::clog2(TEST_BUFFER_W); proc RefillingShiftBufferTest { diff --git a/xls/modules/zstd/rle_block_encoder.x b/xls/modules/zstd/rle_block_encoder.x new file mode 100644 index 0000000000..6795b34616 --- /dev/null +++ b/xls/modules/zstd/rle_block_encoder.x @@ -0,0 +1,750 @@ +// Copyright 2025 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 contains implementation of RleBlockEncoder +// +// The proc is supposed to: +// 1. run a heuristic to determine if a block can be RLE Encoded (RleBlockEncoderSampler) +// 1.1 uniformly sample from the entire block +// 1.2 see if all samples are equal +// 1.3 early exit if not +// 2. run the encoding (check if all symbols are equal along the way) (RleBlockEncoderFullSearch) +// 3. if the encoding was successful return a **single** RLE pair (symbol, length) + +import std; + +import xls.examples.ram; +import xls.modules.zstd.common; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.axi_ram_reader; +import xls.modules.zstd.memory.axi_ram_writer; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.mem_reader_simple_arbiter; + +pub struct RleBlockEncoderReq { + addr: uN[ADDR_W], // start address + length: uN[ADDR_W] // length of the block + } + +pub enum RleBlockEncoderStatus: u2 { + OK = 0, + INCOMPRESSIBLE = 1, + ERROR = 2 +} + +pub struct RleBlockEncoderResp { + symbol: u8, + length: uN[LENGTH_W], + status: RleBlockEncoderStatus +} + +struct RleBlockEncoderSamplerResp { + value: u8, + read_success: bool, + all_equal: bool, +} + +struct RleBlockEncoderInternalConfig { + address: uN[ADDR_W], + stride: uN[ADDR_W], + left: u32 +} + +struct RleBlockEncoderSamplerState { + active: bool, + previous: u8, + conf: RleBlockEncoderInternalConfig, + first_read: bool +} + +struct RleBlockEncoderFullSearchState { + active: bool, + check_symbol: u8, + all_equal: bool, + all_reads_successful: bool, + queried_left: u32, + conf: RleBlockEncoderInternalConfig, + first_read: bool +} + + +fn entire_word_of_equal_bytes(word: uN[DATA_W], to_check: u8) -> bool { + const DATA_W_B = DATA_W as u8 / u8:8; + let symbol = word as u8; + + unroll_for! (i, eq) : (u8, bool) in u8:0..DATA_W_B { + let next_byte = (word >> (i as uN[DATA_W] * uN[DATA_W]:8)) as u8; + if i >= to_check { + eq + } else { + eq && (next_byte == symbol) + } + }(true) +} + +pub proc RleBlockEncoderFullSearch { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemReaderStatus = mem_reader::MemReaderStatus; + + type State = RleBlockEncoderFullSearchState; + type Resp = RleBlockEncoderSamplerResp; + type Config = RleBlockEncoderInternalConfig; + + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + req_r: chan in; + resp_s: chan out; + + config( + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + req_r: chan in, + resp_s: chan out, + ) { + ( + mem_rd_req_s, mem_rd_resp_r, + req_r, resp_s, + ) + } + + init { zero!() } + + next(state: State) { + let tok = join(); + let conf = state.conf; + + if !state.active { + let (tok, conf) = recv(tok, req_r); + + let query_size = if conf.left < MAX_TX_PER_REQ { conf.left } else { MAX_TX_PER_REQ }; + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: conf.address, + length: query_size + }); + + State { + active: true, + all_equal: true, + conf: Config { + left: conf.left, + address: conf.address + query_size, + ..conf + }, + queried_left: query_size, + first_read: true, + all_reads_successful: true, + ..zero!() + } + + } else if state.conf.left == u32:0 + || (state.queried_left == u32:0 && (!state.all_equal || !state.all_reads_successful)) { + + let tok = send(tok, resp_s, Resp { + value: state.check_symbol, + read_success: state.all_reads_successful, + all_equal: state.all_equal + }); + + zero!() + } else if state.queried_left == u32:0 { + // reducing read requests mechanism + // 1. every MAX_TX_PER_REQ tokens make a new read request + // 2. also check if it should early-abort (notice the above branch) + let query_size = if conf.left < MAX_TX_PER_REQ { conf.left } else { MAX_TX_PER_REQ }; + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: conf.address, + length: query_size + }); + + State { + queried_left: query_size, + conf: Config { + address: conf.address + query_size, + ..conf + }, + ..state + } + } else { + let (tok, resp) = recv(tok, mem_rd_resp_r); + let check_symbol = if state.first_read { + resp.data as u8 + } else { + state.check_symbol + }; + let all_equal_next = entire_word_of_equal_bytes(resp.data, resp.length as u8) && resp.data as u8 == check_symbol && state.all_equal; + + State { + active: true, + all_equal: all_equal_next, + conf: Config { + left: conf.left - resp.length, + ..conf + }, + queried_left: state.queried_left - resp.length, + check_symbol: check_symbol, + first_read: false, + all_reads_successful: resp.status == MemReaderStatus::OKAY && state.all_reads_successful + } + } + + } + +} + + +pub proc RleBlockEncoderSampler { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemReaderStatus = mem_reader::MemReaderStatus; + + type State = RleBlockEncoderSamplerState; + type Resp = RleBlockEncoderSamplerResp; + type Config = RleBlockEncoderInternalConfig; + + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + req_r: chan in; + resp_s: chan out; + + config( + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + req_r: chan in, + resp_s: chan out, + ) { + ( + mem_rd_req_s, mem_rd_resp_r, + req_r, resp_s, + ) + } + + init { zero!() } + + next(state: State) { + const DATA_W_B = DATA_W / u32:8; + + let tok = join(); + let conf = state.conf; + + if !state.active { + let (tok,conf) = recv(tok, req_r); + State { + active: true, + conf: Config { + address: conf.address, + left: conf.left, + ..conf + }, + first_read: true, + ..zero!() + } + } else if state.conf.left == u32:0 { + let tok = send(tok, resp_s, Resp { + value: state.previous, + read_success: true, + all_equal: true + }); + zero!() + } else { + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: conf.address, + length: DATA_W_B + }); + let (tok, mem_resp) = recv(tok, mem_rd_resp_r); + let equal = mem_resp.data as u8 == state.previous && entire_word_of_equal_bytes(mem_resp.data, DATA_W_B as u8); + + if mem_resp.status == MemReaderStatus::OKAY && (state.first_read || equal) { + State { + active: true, + conf: Config { + address: conf.address + conf.stride, + left: conf.left - u32:1, + ..conf + }, + previous: mem_resp.data as u8, + first_read: false + } + } else { + let tok = send(tok, resp_s, Resp { + value: mem_resp.data as u8, + read_success: mem_resp.status == MemReaderStatus::OKAY, + all_equal: false + }); + + State { + ..zero!() + } + } + } + } +} + +pub proc RleBlockEncoder { + type Req = RleBlockEncoderReq; + type Resp = RleBlockEncoderResp; + type Status = RleBlockEncoderStatus; + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type LoopResp = RleBlockEncoderSamplerResp; + type LoopConfig = RleBlockEncoderInternalConfig; + + req: chan in; + resp: chan out; + loop_req_s: chan out; + loop_resp_r: chan in; + heuristic_req_s: chan out; + heuristic_resp_r: chan in; + + config( + req: chan in, + resp: chan out, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in + ) { + let (loop_req_s, loop_req_r) = chan("loop_req"); + let (loop_resp_s, loop_resp_r) = chan("loop_resp"); + let (heuristic_req_s, heuristic_req_r) = chan("loop_req"); + let (heuristic_resp_s, heuristic_resp_r) = chan("loop_resp"); + + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[2]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[2]("n_mem_rd_resp"); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn RleBlockEncoderFullSearch + ( + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + loop_req_r, loop_resp_s, + ); + + spawn RleBlockEncoderSampler + ( + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + heuristic_req_r, heuristic_resp_s, + ); + + ( + req, resp, + loop_req_s, loop_resp_r, + heuristic_req_s, heuristic_resp_r, + ) + } + + init { } + + next(state: ()) { + let (tok, req) = recv(join(), req); + let stride = req.length / (SAMPLE_COUNT); + + // Only do sample scan for data large enough + // so that sample scan doesn't perform full scan actually. + let do_sample_scan: bool = stride > (DATA_W / u32:8); + + let tok1 = send_if( + tok, + heuristic_req_s, + do_sample_scan, + LoopConfig { + address: req.addr, + stride: stride, + left: SAMPLE_COUNT + } + ); + + let (tok1, loop_resp) = recv_if(tok1, heuristic_resp_r, do_sample_scan, zero!()); + + let do_full_scan: bool = (do_sample_scan && loop_resp.all_equal) || !do_sample_scan; + + let tok2 = send_if( + tok, + loop_req_s, + do_full_scan, + LoopConfig { + address: req.addr, + stride: uN[ADDR_W]:1, + left: req.length + } + ); + + let (result, symbol) = if do_sample_scan && !loop_resp.read_success { + (Status::ERROR, u8:0) + } else if do_sample_scan && !loop_resp.all_equal { + (Status::INCOMPRESSIBLE, u8:0) + } else { + let (tok2, loop_resp) = recv(tok2, loop_resp_r); + if !loop_resp.read_success { + (Status::ERROR, u8:0) + } else if !loop_resp.all_equal { + (Status::INCOMPRESSIBLE, u8:0) + } else { + (Status::OK, loop_resp.value) + } + }; + + let tok = send(tok, resp, Resp { + symbol: symbol, + length: req.length, + status: result, + }); + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; +const INST_LENGTH_W = u32:32; +const INST_SAMPLE_COUNT = u32:8; + +proc RleBlockEncoderInst { + type Req = RleBlockEncoderReq; + type Resp = RleBlockEncoderResp; + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type Status = RleBlockEncoderStatus; + + config( + req: chan in, + resp: chan out, + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + ) { + spawn RleBlockEncoder + ( + req, resp, + mem_rd_req_s, mem_rd_resp_r + ); + } + + init { } + next(state: ()) { } +} + + +const TEST_ADDR_W = u32:32; +const TEST_AXI_ADDR_W = u32:32; +const TEST_AXI_DATA_W = u32:64; +const TEST_AXI_DEST_W = u32:8; +const TEST_AXI_ID_W = u32:4; +const TEST_WRITER_ID = u32:3; + +const TEST_RAM_SIZE = u32:200; +const TEST_RAM_DATA_W = u32:64; +const TEST_RAM_WORD_PARTITION_SIZE = u32:8; +const TEST_RAM_NUM_PARTITIONS = TEST_RAM_DATA_W / TEST_RAM_WORD_PARTITION_SIZE; +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; +const TEST_RAM_ASSERT_VALID_READ = true; + +const TEST_LENGTH_W = u32:32; +const TEST_SAMPLE_COUNT = u32:2; +const TEST_MAX_TX_PER_REQ = u32:16; + +type TestLen = bits[TEST_LENGTH_W]; +type TestReq = RleBlockEncoderReq; +type TestResp = RleBlockEncoderResp; +type TestStatus = RleBlockEncoderStatus; +type TestAddr = bits[TEST_ADDR_W]; + +const TEST_CASES = [ + ( + [ + u64:0x00FF_FFFF_FFFF_FFFF, + u64:0x0000_0000_0000_0000, + u64:0x0000_0000_0000_0000, + u64:0x0000_0000_0000_0000, + u64:0x0000_0000_0000_0000, + u64:0x0000_0000_0000_0000, + ], + TestLen:7, + TestResp { + symbol: u8:0xFF, + length: TestLen:7, + status: TestStatus::OK + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:48, + TestResp { + symbol: u8:0xFF, + length: TestLen:48, + status: TestStatus::OK + } + ), + ( + [ + u64:0xBBBB_BBBB_BBBB_BBBB, + u64:0xBBBB_BBBB_BBBB_BBBB, + u64:0xBBBB_BBBB_BBBB_BBBB, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:24, + TestResp { + symbol: u8:0xBB, + length: TestLen:24, + status: TestStatus::OK + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFBB, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:48, + TestResp { + symbol: u8:0x0, + length: TestLen:48, + status: TestStatus::INCOMPRESSIBLE + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:4, + TestResp { + symbol: u8:0xFF, + length: TestLen:4, + status: TestStatus::OK + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FF88, + ], + TestLen:48, + TestResp { + symbol: u8:0x0, + length: TestLen:48, + status: TestStatus::INCOMPRESSIBLE + } + ), + ( + [ + u64:0x88FF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FF88, + ], + TestLen:48, + TestResp { + symbol: u8:0x0, + length: TestLen:48, + status: TestStatus::INCOMPRESSIBLE + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_77FF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:48, + TestResp { + symbol: u8:0x00, + length: TestLen:48, + status: TestStatus::INCOMPRESSIBLE + } + ), + ( + [ + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FF77, + u64:0xFFFF_FFFF_FFFF_FFFF, + u64:0xFFFF_FFFF_FFFF_FFFF, + ], + TestLen:48, + TestResp { + symbol: u8:0x0, + length: TestLen:48, + status: TestStatus::INCOMPRESSIBLE + } + ) +]; + +#[test_proc] +proc RleBlockEncoderTest { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + type TestReadReq = ram::ReadReq; + type TestWriteReq = ram::WriteReq; + type TestReadResp = ram::ReadResp; + type TestWriteResp = ram::WriteResp; + type TestMemReaderReq = mem_reader::MemReaderReq; + type TestMemReaderResp = mem_reader::MemReaderResp; + type TestMemWriterReq = mem_writer::MemWriterReq; + type TestMemWriterData = mem_writer::MemWriterDataPacket; + type TestMemWriterResp = mem_writer::MemWriterResp; + type TestMemWriterStatus = mem_writer::MemWriterRespStatus; + + terminator: chan out; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + req_s: chan out; + resp_r: chan in; + + init { } + + config(terminator: chan out) { + + // IO for RAM + let (rd_req_s, rd_req_r) = chan("input_rd_req"); + let (rd_resp_s, rd_resp_r) = chan("input_rd_resp"); + let (wr_req_s, wr_req_r) = chan("input_wr_req"); + let (wr_resp_s, wr_resp_r) = chan("input_wr_resp"); + + // IO for AxiRamReader <-> MemReader + let (input_axi_ar_s, input_axi_ar_r) = chan("input_axi_ar"); + let (input_axi_r_s, input_axi_r_r) = chan("input_axi_r"); + + // IO for MemReader <-> Encoder + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + + // IO for AxiRamWriter <-> MemWriter + let (output_axi_aw_s, output_axi_aw_r) = chan("output_axi_aw"); + let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); + let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); + + // IO for MemWriter <-> Encoder + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + + // IO for RleBlockEncoder + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, TEST_RAM_ASSERT_VALID_READ, TEST_AXI_ADDR_W + >( + rd_req_r, rd_resp_s, + wr_req_r, wr_resp_s + ); + + spawn axi_ram_reader::AxiRamReader< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_RAM_SIZE + >( + input_axi_ar_r, input_axi_r_s, + rd_req_s, rd_resp_r + ); + + spawn mem_reader::MemReader( + mem_rd_req_r, mem_rd_resp_s, + input_axi_ar_s, input_axi_r_r + ); + + spawn axi_ram_writer::AxiRamWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_ID_W, TEST_RAM_SIZE, TEST_ADDR_W, TEST_RAM_NUM_PARTITIONS, + >( + output_axi_aw_r, output_axi_w_r, output_axi_b_s, + wr_req_s, wr_resp_r + ); + + spawn mem_writer::MemWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_WRITER_ID + >( + mem_wr_req_r, mem_wr_data_r, + output_axi_aw_s, output_axi_w_s, output_axi_b_r, + mem_wr_resp_s + ); + + spawn RleBlockEncoder + ( + req_r, resp_s, + mem_rd_req_s, mem_rd_resp_r + ); + + ( + terminator, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + req_s, resp_r + ) + } + + next(state: ()) { + let tok = for ((_, (TEST_DATA, size_bytes, expected)), tok) in enumerate(TEST_CASES) { + // arrange + for ((i, test_data), tok) in enumerate(TEST_DATA) { + let tok = send(tok, mem_wr_req_s, TestMemWriterReq { + addr: i * TEST_RAM_DATA_W / u32:8 as TestAddr, + length: TEST_RAM_DATA_W / u32:8 + }); + let tok = send(tok, mem_wr_data_s, TestMemWriterData { + data: test_data, + last: true, + length: TEST_RAM_DATA_W + }); + let (tok, _) = recv(tok, mem_wr_resp_r); + tok + }(tok); + + // act + let tok = send(tok, req_s, TestReq { + addr: uN[TEST_ADDR_W]:0, + length: size_bytes + }); + let (tok, response) = recv(tok, resp_r); + + // assert + if (response != expected) { + trace_fmt!("Received {:#x} != {:#x}", response, expected); + } else {}; + assert_eq(response, expected); + tok + }(join()); + send(tok, terminator, true); + } +} + diff --git a/xls/modules/zstd/rle_lookup_dec.x b/xls/modules/zstd/rle_lookup_dec.x index b965d119c2..4251889f20 100644 --- a/xls/modules/zstd/rle_lookup_dec.x +++ b/xls/modules/zstd/rle_lookup_dec.x @@ -93,6 +93,7 @@ pub proc RleLookupDecoder< let tok = send(tok, resp_s, Resp { status: if byte.error { Status::ERROR } else { Status::OK }, accuracy_log: common::FseAccuracyLog:0, + remainder: zero!(), }); } } @@ -163,7 +164,7 @@ proc RleLookupDecoderTest { next(_: ()) { let tok = join(); - let tok = send(tok, req_s, Req {}); + let tok = send(tok, req_s, zero!()); let (tok, buf_req) = recv(tok, buffer_ctrl_r); assert_eq(buf_req, SBCtrl { length: uN[TEST_SB_LENGTH_W]:8 @@ -184,6 +185,7 @@ proc RleLookupDecoderTest { assert_eq(resp, Resp { status: Status::OK, accuracy_log: common::FseAccuracyLog:0, + remainder: zero!(), }); send(tok, terminator, true); } diff --git a/xls/modules/zstd/rtl/BUILD b/xls/modules/zstd/rtl/BUILD index 4447877821..0a1d6f13e0 100644 --- a/xls/modules/zstd/rtl/BUILD +++ b/xls/modules/zstd/rtl/BUILD @@ -23,6 +23,7 @@ The sources contain: """ +# pytype binary, library load("@rules_hdl//verilog:providers.bzl", "verilog_library") package( @@ -34,7 +35,13 @@ package( exports_files( [ "zstd_dec_wrapper.sv", + "zstd_enc_wrapper.sv", "xls_fifo_wrapper.sv", + "ram_demux_wrapper.sv", + "match_finder_wrapper.sv", + "ram_1r1w.sv", + "ram_2rw.sv", + "cocotb_public_vars.vlt", ], ) diff --git a/xls/modules/zstd/rtl/cocotb_public_vars.vlt b/xls/modules/zstd/rtl/cocotb_public_vars.vlt new file mode 100644 index 0000000000..2238cb24c8 --- /dev/null +++ b/xls/modules/zstd/rtl/cocotb_public_vars.vlt @@ -0,0 +1,126 @@ +`verilator_config + +// Signals needed for tests of decoder "internals" + +public_flat_rd -module "ram_1r1w" -var "mem" +public_flat_rd -module "ram_2rw" -var "mem" + +public_flat_rd -module "xls_modules_zstd_sequence_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__SequenceDecoderCtrl_0__FseLookupCtrl_0_next" -var "*" +public_flat_rd -module "xls_modules_zstd_comp_lookup_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanFseWeightsDecoder_0__CompLookupDecoder_0__64_8_16_1_15_8_32_1_7_9_8_1_8_16_1_next" -var "*" +public_flat_rd -module "xls_modules_zstd_fse_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__FseDecoder_0__64_15_32_1_64_7_next" -var "*" +public_flat_rd -module "xls_modules_zstd_sequence_executor__ZstdDecoderInst__ZstdDecoder_0__SequenceExecutor_0__32_64_64_0_0_0_13_8192_65536_next" -var "*" +public_flat_rd -module "xls_modules_zstd_fse_table_creator__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__FseLookupDecoder_0__CompLookupDecoder_0__FseTableCreator_0__8_16_1_15_32_1_9_8_1_8_16_1_next_inst16" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_code_builder__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__WeightCodeBuilder_0__256_8_32_7_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_ctrl__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanControlAndSequence_0__32_64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_block_header_dec__ZstdDecoderInst__ZstdDecoder_0__BlockHeaderDecoder_0__32_64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_raw_block_dec__ZstdDecoderInst__ZstdDecoder_0__RawBlockDecoder_0__32_64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_rle_block_dec__ZstdDecoderInst__ZstdDecoder_0__RleBlockDecoder_0__64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_comp_block_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__32_64_8_4_4_16_256_64_6_92_1_8_16_1_8_32_1_6_32_8_9_8_1_8_16_1_13_9_1_8_16_1_15_15_32_1_9_8_1_8_16_1_next" -var "*" +public_flat_rd -module "xls_modules_zstd_literals_block_header_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__LiteralsHeaderDecoder_0__32_64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_raw_literals_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__RawLiteralsDecoder_0__32_64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_rle_literals_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__RleLiteralsDecoder_0__64_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_decoder__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanDecoder_0_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__32_64_4_8_16_1_8_32_1_9_8_1_8_16_1_6_32_8_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanRawWeightsDecoder_0__32_64_96_7_6_32_8_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanFseWeightsDecoder_0__32_64_4_8_16_1_8_32_1_64_7_9_8_1_8_16_1_6_32_8_next" -var "*" +public_flat_rd -module "xls_modules_zstd_huffman_ctrl__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanControlAndSequence_0__HuffmanControlAndSequenceMultiStreamHandler_0__HuffmanControlAndSequenceInternal_0__32_next" -var "*" +public_flat_rd -module "xls_modules_zstd_sequence_conf_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__SequenceConfDecoder_0__32_64_next" -var "*" + + +// Signals of top module +// Commented ones are currently not used by tests (but might be needed +// in the future) +public_flat_rw -module "zstd_dec_wrapper" -var "clk" +public_flat_rw -module "zstd_dec_wrapper" -var "rst" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_aw_awready" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_w_wready" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_b_bid" +// public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_b_bresp" +// public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_b_buser" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_b_bvalid" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_ar_arready" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_rid" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_rdata" +// public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_rresp" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_rlast" +// public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_ruser" +public_flat_rw -module "zstd_dec_wrapper" -var "memory_axi_r_rvalid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awaddr" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awlen" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awsize" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awburst" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awlock" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awcache" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awprot" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awqos" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awregion" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awuser" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_aw_awvalid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_w_wdata" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_w_wstrb" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_w_wlast" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_w_wuser" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_w_wvalid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_b_bready" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_araddr" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arlen" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arsize" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arburst" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arlock" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arcache" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arprot" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arqos" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arregion" +// public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_aruser" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_ar_arvalid" +public_flat_rw -module "zstd_dec_wrapper" -var "csr_axi_r_rready" +public_flat_rw -module "zstd_dec_wrapper" -var "notify_rdy" + +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awid" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awaddr" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awlen" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awsize" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awburst" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awlock" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awcache" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awprot" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awqos" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awregion" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awuser" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_aw_awvalid" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_w_wdata" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_w_wstrb" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_w_wlast" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_w_wuser" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_w_wvalid" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_b_bready" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arid" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_araddr" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arlen" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arsize" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arburst" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arlock" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arcache" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arprot" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arqos" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arregion" +// public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_aruser" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_ar_arvalid" +public_flat_rd -module "zstd_dec_wrapper" -var "memory_axi_r_rready" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_aw_awready" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_w_wready" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_b_bid" +// public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_b_bresp" +// public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_b_buser" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_b_bvalid" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_ar_arready" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_rid" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_rdata" +// public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_rresp" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_rlast" +// public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_ruser" +public_flat_rd -module "zstd_dec_wrapper" -var "csr_axi_r_rvalid" +public_flat_rd -module "zstd_dec_wrapper" -var "notify_data" +public_flat_rd -module "zstd_dec_wrapper" -var "notify_vld" diff --git a/xls/modules/zstd/rtl/match_finder_wrapper.sv b/xls/modules/zstd/rtl/match_finder_wrapper.sv new file mode 100644 index 0000000000..00bb48d236 --- /dev/null +++ b/xls/modules/zstd/rtl/match_finder_wrapper.sv @@ -0,0 +1,359 @@ +// Copyright 2025 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. + +`default_nettype none + +module match_finder_wrapper #( + parameter AXI_DATA_W = 64, + parameter AXI_ADDR_W = 32, + parameter S_AXI_ID_W = 4, + parameter M_AXI_ID_W = 6, + parameter AXI_STRB_W = 8, + parameter AWUSER_WIDTH = 1, + parameter WUSER_WIDTH = 1, + parameter BUSER_WIDTH = 1, + parameter ARUSER_WIDTH = 1, + parameter RUSER_WIDTH = 1 +) ( + input wire clk, + input wire rst, + // request + input wire [137:0] req_r_data, + input wire req_r_vld, + output wire req_r_rdy, + + // response + output wire [137:0] resp_s_data, + output wire resp_s_rdy, + input wire resp_s_vld, + + // memory + output wire [M_AXI_ID_W-1:0] memory_axi_aw_awid, + output wire [AXI_ADDR_W-1:0] memory_axi_aw_awaddr, + output wire [7:0] memory_axi_aw_awlen, + output wire [2:0] memory_axi_aw_awsize, + output wire [1:0] memory_axi_aw_awburst, + output wire memory_axi_aw_awlock, + output wire [3:0] memory_axi_aw_awcache, + output wire [3:0] memory_axi_aw_awqos, + output wire [3:0] memory_axi_aw_awregion, + output wire [AWUSER_WIDTH-1:0] memory_axi_aw_awuser, + output wire memory_axi_aw_awvalid, + input wire memory_axi_aw_awready, + output wire [AXI_DATA_W-1:0] memory_axi_w_wdata, + output wire [AXI_STRB_W-1:0] memory_axi_w_wstrb, + output wire memory_axi_w_wlast, + output wire [WUSER_WIDTH-1:0] memory_axi_w_wuser, + output wire memory_axi_w_wvalid, + input wire memory_axi_w_wready, + input wire [M_AXI_ID_W-1:0] memory_axi_b_bid, + input wire [2:0] memory_axi_b_bresp, + input wire [BUSER_WIDTH-1:0] memory_axi_b_buser, + input wire memory_axi_b_bvalid, + output wire memory_axi_b_bready, + + output wire [M_AXI_ID_W-1:0] memory_axi_ar_arid, + output wire [AXI_ADDR_W-1:0] memory_axi_ar_araddr, + output wire [7:0] memory_axi_ar_arlen, + output wire [2:0] memory_axi_ar_arsize, + output wire [1:0] memory_axi_ar_arburst, + output wire memory_axi_ar_arlock, + output wire [3:0] memory_axi_ar_arcache, + output wire [2:0] memory_axi_ar_arprot, + output wire [3:0] memory_axi_ar_arqos, + output wire [3:0] memory_axi_ar_arregion, + output wire [ARUSER_WIDTH-1:0] memory_axi_ar_aruser, + output wire memory_axi_ar_arvalid, + input wire memory_axi_ar_arready, + input wire [M_AXI_ID_W-1:0] memory_axi_r_rid, + input wire [AXI_DATA_W-1:0] memory_axi_r_rdata, + input wire [2:0] memory_axi_r_rresp, + input wire memory_axi_r_rlast, + input wire [RUSER_WIDTH-1:0] memory_axi_r_ruser, + input wire memory_axi_r_rvalid, + output wire memory_axi_r_rready +); + localparam XLS_AXI_AW_SIZE_W = 3; + localparam XLS_AXI_AW_BURST_W = 2; + localparam XLS_AXI_AW_W = AXI_ADDR_W + S_AXI_ID_W + XLS_AXI_AW_SIZE_W + XLS_AXI_AW_BURST_W; + + localparam XLS_AXI_W_LAST_W = 1; + localparam XLS_AXI_W_W = AXI_DATA_W + AXI_STRB_W + XLS_AXI_W_LAST_W; + + localparam XLS_AXI_B_RESP_W = 3; + localparam XLS_AXI_B_W = XLS_AXI_B_RESP_W + S_AXI_ID_W; + + localparam XLS_AXI_AR_PROT_W = 3; + localparam XLS_AXI_AR_SIZE_W = 3; + localparam XLS_AXI_AR_CACHE_W = 4; + localparam XLS_AXI_AR_QOS_W = 4; + localparam XLS_AXI_AR_LEN_W = 8; + localparam XLS_AXI_AR_BURST_W = 2; + localparam XLS_AXI_AR_REGION_W = 4; + localparam XLS_AXI_AR_W = S_AXI_ID_W + AXI_ADDR_W + XLS_AXI_AR_CACHE_W + XLS_AXI_AR_LEN_W + XLS_AXI_AR_PROT_W + XLS_AXI_AR_BURST_W + XLS_AXI_AR_QOS_W + XLS_AXI_AR_SIZE_W + XLS_AXI_AR_REGION_W; + + localparam XLS_AXI_R_RESP_W = 3; + localparam XLS_AXI_R_LAST_W = 1; + localparam XLS_AXI_R_W = S_AXI_ID_W + AXI_DATA_W + XLS_AXI_R_RESP_W + XLS_AXI_R_LAST_W; + + wire [XLS_AXI_AW_W-1:0] match_finder__axi_aw; + wire match_finder__axi_aw_rdy; + wire match_finder__axi_aw_vld; + wire [XLS_AXI_W_W-1:0] match_finder__axi_w; + wire match_finder__axi_w_rdy; + wire match_finder__axi_w_vld; + wire [ XLS_AXI_B_W-1:0] match_finder__axi_b; + wire match_finder__axi_b_rdy; + wire match_finder__axi_b_vld; + wire [XLS_AXI_AR_W-1:0] match_finder__axi_ar; + wire match_finder__axi_ar_rdy; + wire match_finder__axi_ar_vld; + wire [XLS_AXI_R_W-1:0] match_finder__axi_r; + wire match_finder__axi_r_rdy; + wire match_finder__axi_r_vld; + + assign { + memory_axi_aw_awid, + memory_axi_aw_awaddr, + memory_axi_aw_awsize, + memory_axi_aw_awlen, + memory_axi_aw_awburst + } = match_finder__axi_aw; + assign memory_axi_aw_awvalid = match_finder__axi_aw_vld; + assign match_finder__axi_aw_rdy = memory_axi_aw_awready; + assign { + memory_axi_w_wdata, + memory_axi_w_wstrb, + memory_axi_w_wlast + } = match_finder__axi_w; + assign memory_axi_w_wvalid = match_finder__axi_w_vld; + assign match_finder__axi_w_rdy = memory_axi_w_wready; + assign match_finder__axi_b = { + memory_axi_b_bresp, + memory_axi_b_bid + }; + assign match_finder__axi_b_vld = memory_axi_b_bvalid; + assign memory_axi_b_bready = match_finder__axi_b_rdy; + assign { + memory_axi_ar_arid, + memory_axi_ar_araddr, + memory_axi_ar_arregion, + memory_axi_ar_arlen, + memory_axi_ar_arsize, + memory_axi_ar_arburst, + memory_axi_ar_arcache, + memory_axi_ar_arprot, + memory_axi_ar_arqos + } = match_finder__axi_ar; + assign memory_axi_ar_arvalid = match_finder__axi_ar_vld; + assign match_finder__axi_ar_rdy = memory_axi_ar_arready; + assign match_finder__axi_r = { + memory_axi_r_rid, + memory_axi_r_rdata, + memory_axi_r_rresp, + memory_axi_r_rlast + }; + assign match_finder__axi_r_vld = memory_axi_r_rvalid; + assign memory_axi_r_rready = match_finder__axi_r_rdy; + + // History Buffer + + localparam HB_SIZE = 1024; + localparam HB_RAM_NUM = 8; + localparam HB_DATA_W = 8; + localparam HB_RAM_SIZE = HB_SIZE / HB_RAM_NUM; + localparam HB_ADDR_W = $clog2(HB_RAM_SIZE); + localparam HB_NUM_PARTITIONS = 1; + + wire [HB_ADDR_W-1:0] hb_ram_rd_addr [0:7]; + wire [HB_DATA_W-1:0] hb_ram_rd_data [0:7]; + wire hb_ram_rd_en [0:7]; + wire [HB_NUM_PARTITIONS-1:0] hb_ram_rd_mask [0:7]; + + wire [HB_ADDR_W-1:0] hb_ram_wr_addr [0:7]; + wire [HB_DATA_W-1:0] hb_ram_wr_data [0:7]; + wire hb_ram_wr_en [0:7]; + wire [HB_NUM_PARTITIONS-1:0] hb_ram_wr_mask [0:7]; + + genvar i; + generate + for (i = 0; i < 8; i = i + 1) begin : hb_loop + ram_1r1w #( + .DATA_WIDTH(HB_DATA_W), + .ADDR_WIDTH(HB_ADDR_W), + .SIZE(HB_SIZE), + .NUM_PARTITIONS(HB_NUM_PARTITIONS) + ) hb_ram ( + .clk(clk), + .rst(rst), + .rd_addr (hb_ram_rd_addr[i]), + .rd_data (hb_ram_rd_data[i]), + .rd_en (hb_ram_rd_en[i]), + .rd_mask (hb_ram_rd_mask[i]), + .wr_data (hb_ram_wr_data[i]), + .wr_addr (hb_ram_wr_addr[i]), + .wr_en (hb_ram_wr_en[i]), + .wr_mask (hb_ram_wr_mask[i]) + ); + end + endgenerate + + // Hash Table + localparam HT_KEY_W = 32; + localparam HT_SIZE = 512; + localparam HT_ADDR_W = $clog2(HT_SIZE); + localparam HT_ENTRY_W = HT_KEY_W + 32; + localparam HT_DATA_W = HT_ENTRY_W + 1; // 32 (KEY_WIDTH) + 32 (ADDR_W) + 1 (match or not); + localparam HT_NUM_PARTITIONS = HT_DATA_W; + + wire [HT_DATA_W-1:0] ht_ram_rd_data; + wire [HT_ADDR_W-1:0] ht_ram_rd_addr; + wire ht_ram_rd_en; + wire [HT_NUM_PARTITIONS-1:0] ht_ram_rd_mask; + + wire [HT_DATA_W-1:0] ht_ram_wr_data; + wire [HT_ADDR_W-1:0] ht_ram_wr_addr; + wire ht_ram_wr_en; + wire [HT_NUM_PARTITIONS-1:0] ht_ram_wr_mask; + + ram_1r1w #( + .DATA_WIDTH(HT_DATA_W), + .ADDR_WIDTH(HT_ADDR_W), + .SIZE(HT_SIZE), + .NUM_PARTITIONS(HT_NUM_PARTITIONS) + ) ht_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ht_ram_rd_addr), + .rd_data (ht_ram_rd_data), + .rd_en (ht_ram_rd_en), + .rd_mask (ht_ram_rd_mask), + .wr_addr (ht_ram_wr_addr), + .wr_data (ht_ram_wr_data), + .wr_en (ht_ram_wr_en), + .wr_mask (ht_ram_wr_mask) + ); + + MatchFinder match_finder_benchmark ( + .clk(clk), + .rst(rst), + // reader + .match_finder__axi_ar_s(match_finder__axi_ar), + .match_finder__axi_ar_s_vld(match_finder__axi_ar_vld), + .match_finder__axi_ar_s_rdy(match_finder__axi_ar_rdy), + .match_finder__axi_r_r(match_finder__axi_r), + .match_finder__axi_r_r_vld(match_finder__axi_r_vld), + .match_finder__axi_r_r_rdy(match_finder__axi_r_rdy), + + // writer + .match_finder__axi_b_r(match_finder__axi_b), + .match_finder__axi_b_r_vld(match_finder__axi_b_vld), + .match_finder__axi_b_r_rdy(match_finder__axi_b_rdy), + .match_finder__axi_aw_s(match_finder__axi_aw), + .match_finder__axi_aw_s_rdy(match_finder__axi_aw_rdy), + .match_finder__axi_aw_s_vld(match_finder__axi_aw_vld), + .match_finder__axi_w_s(match_finder__axi_w), + .match_finder__axi_w_s_rdy(match_finder__axi_w_rdy), + .match_finder__axi_w_s_vld(match_finder__axi_w_vld), + + .match_finder__resp_s(resp_s_data), + .match_finder__resp_s_rdy(resp_s_rdy), + .match_finder__resp_s_vld(resp_s_vld), + .match_finder__req_r(req_r_data), + .match_finder__req_r_rdy(req_r_rdy), + .match_finder__req_r_vld(req_r_vld), + + .hb_ram0_rd_addr(hb_ram_rd_addr[0]), + .hb_ram0_rd_data(hb_ram_rd_data[0]), + .hb_ram0_rd_en (hb_ram_rd_en[0]), + .hb_ram0_rd_mask(hb_ram_rd_mask[0]), + .hb_ram0_wr_addr(hb_ram_wr_addr[0]), + .hb_ram0_wr_data(hb_ram_wr_data[0]), + .hb_ram0_wr_en (hb_ram_wr_en[0]), + .hb_ram0_wr_mask(hb_ram_wr_mask[0]), + + .hb_ram1_rd_addr(hb_ram_rd_addr[1]), + .hb_ram1_rd_data(hb_ram_rd_data[1]), + .hb_ram1_rd_en (hb_ram_rd_en[1]), + .hb_ram1_rd_mask(hb_ram_rd_mask[1]), + .hb_ram1_wr_addr(hb_ram_wr_addr[1]), + .hb_ram1_wr_data(hb_ram_wr_data[1]), + .hb_ram1_wr_en (hb_ram_wr_en[1]), + .hb_ram1_wr_mask(hb_ram_wr_mask[1]), + + .hb_ram2_rd_addr(hb_ram_rd_addr[2]), + .hb_ram2_rd_data(hb_ram_rd_data[2]), + .hb_ram2_rd_en (hb_ram_rd_en[2]), + .hb_ram2_rd_mask(hb_ram_rd_mask[2]), + .hb_ram2_wr_addr(hb_ram_wr_addr[2]), + .hb_ram2_wr_data(hb_ram_wr_data[2]), + .hb_ram2_wr_en (hb_ram_wr_en[2]), + .hb_ram2_wr_mask(hb_ram_wr_mask[2]), + + .hb_ram3_rd_addr(hb_ram_rd_addr[3]), + .hb_ram3_rd_data(hb_ram_rd_data[3]), + .hb_ram3_rd_en (hb_ram_rd_en[3]), + .hb_ram3_rd_mask(hb_ram_rd_mask[3]), + .hb_ram3_wr_addr(hb_ram_wr_addr[3]), + .hb_ram3_wr_data(hb_ram_wr_data[3]), + .hb_ram3_wr_en (hb_ram_wr_en[3]), + .hb_ram3_wr_mask(hb_ram_wr_mask[3]), + + .hb_ram4_rd_addr(hb_ram_rd_addr[4]), + .hb_ram4_rd_data(hb_ram_rd_data[4]), + .hb_ram4_rd_en (hb_ram_rd_en[4]), + .hb_ram4_rd_mask(hb_ram_rd_mask[4]), + .hb_ram4_wr_addr(hb_ram_wr_addr[4]), + .hb_ram4_wr_data(hb_ram_wr_data[4]), + .hb_ram4_wr_en (hb_ram_wr_en[4]), + .hb_ram4_wr_mask(hb_ram_wr_mask[4]), + + .hb_ram5_rd_addr(hb_ram_rd_addr[5]), + .hb_ram5_rd_data(hb_ram_rd_data[5]), + .hb_ram5_rd_en (hb_ram_rd_en[5]), + .hb_ram5_rd_mask(hb_ram_rd_mask[5]), + .hb_ram5_wr_addr(hb_ram_wr_addr[5]), + .hb_ram5_wr_data(hb_ram_wr_data[5]), + .hb_ram5_wr_en (hb_ram_wr_en[5]), + .hb_ram5_wr_mask(hb_ram_wr_mask[5]), + + .hb_ram6_rd_addr(hb_ram_rd_addr[6]), + .hb_ram6_rd_data(hb_ram_rd_data[6]), + .hb_ram6_rd_en (hb_ram_rd_en[6]), + .hb_ram6_rd_mask(hb_ram_rd_mask[6]), + .hb_ram6_wr_addr(hb_ram_wr_addr[6]), + .hb_ram6_wr_data(hb_ram_wr_data[6]), + .hb_ram6_wr_en (hb_ram_wr_en[6]), + .hb_ram6_wr_mask(hb_ram_wr_mask[6]), + + .hb_ram7_rd_addr(hb_ram_rd_addr[7]), + .hb_ram7_rd_data(hb_ram_rd_data[7]), + .hb_ram7_rd_en (hb_ram_rd_en[7]), + .hb_ram7_rd_mask(hb_ram_rd_mask[7]), + .hb_ram7_wr_addr(hb_ram_wr_addr[7]), + .hb_ram7_wr_data(hb_ram_wr_data[7]), + .hb_ram7_wr_en (hb_ram_wr_en[7]), + .hb_ram7_wr_mask(hb_ram_wr_mask[7]), + + .ht_ram_rd_addr(ht_ram_rd_addr), + .ht_ram_rd_data(ht_ram_rd_data), + .ht_ram_rd_en (ht_ram_rd_en), + .ht_ram_rd_mask(ht_ram_rd_mask), + .ht_ram_wr_addr(ht_ram_wr_addr), + .ht_ram_wr_data(ht_ram_wr_data), + .ht_ram_wr_en (ht_ram_wr_en), + .ht_ram_wr_mask(ht_ram_wr_mask) + ); + +endmodule diff --git a/xls/modules/zstd/rtl/ram_1r1w.sv b/xls/modules/zstd/rtl/ram_1r1w.sv new file mode 100644 index 0000000000..ec3da544a6 --- /dev/null +++ b/xls/modules/zstd/rtl/ram_1r1w.sv @@ -0,0 +1,90 @@ +// Copyright 2025 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. + +module ram_1r1w # ( + parameter DATA_WIDTH = 4, + parameter SIZE = 32, + parameter NUM_PARTITIONS = 1, + parameter ADDR_WIDTH = $clog2(SIZE), + parameter INIT_FILE = "" +) ( + input wire clk, + input wire rst, + + input wire [ DATA_WIDTH -1:0 ] wr_data, + input wire [ ADDR_WIDTH -1:0 ] wr_addr, + input wire wr_en, + input wire [ NUM_PARTITIONS -1:0 ] wr_mask, + + output reg [ DATA_WIDTH -1:0 ] rd_data, + input wire [ ADDR_WIDTH -1:0 ] rd_addr, + input wire rd_en, + input wire [ NUM_PARTITIONS -1:0 ] rd_mask +); + +localparam PARTITION_WIDTH = (DATA_WIDTH / NUM_PARTITIONS); + +reg [DATA_WIDTH-1:0] mem [SIZE]; + +integer i; + +always @(rst) begin + if (INIT_FILE != "") begin + $readmemh(INIT_FILE, mem); + end + else begin + for (i = 0; i < SIZE; i++) begin + mem[i] <= {DATA_WIDTH{1'b0}}; + end + end +end + +reg [DATA_WIDTH-1:0] wr_exp_mask; +reg [DATA_WIDTH-1:0] rd_exp_mask; + +genvar j; +generate +for (j = 0; j < NUM_PARTITIONS; j = j + 1) begin + always @(*) begin + if (wr_mask[j]) begin + wr_exp_mask[((j+1)*PARTITION_WIDTH)-1 : j*PARTITION_WIDTH] <= {PARTITION_WIDTH{1'b1}}; + end else begin + wr_exp_mask[((j+1)*PARTITION_WIDTH)-1 : j*PARTITION_WIDTH] <= {PARTITION_WIDTH{1'b0}}; + end + + if (rd_mask[j]) begin + rd_exp_mask[((j+1)*PARTITION_WIDTH)-1:j*PARTITION_WIDTH] <= {PARTITION_WIDTH{1'b1}}; + end else begin + rd_exp_mask[((j+1)*PARTITION_WIDTH)-1:j*PARTITION_WIDTH] <= {PARTITION_WIDTH{1'b0}}; + end + end +end +endgenerate + +wire [DATA_WIDTH-1:0] rd_data_masked; +wire [DATA_WIDTH-1:0] wr_data_masked; + +assign rd_data_masked = mem[rd_addr] & rd_exp_mask; +assign wr_data_masked = (mem[wr_addr] & ~wr_exp_mask) | (wr_data & wr_exp_mask); + +always @(posedge clk) begin + if (rd_en) begin + rd_data <= rd_data_masked; + end + + if (wr_en) begin + mem[wr_addr] <= wr_data_masked; + end +end +endmodule diff --git a/xls/modules/zstd/rtl/ram_2rw.sv b/xls/modules/zstd/rtl/ram_2rw.sv new file mode 100644 index 0000000000..bffdad4f3d --- /dev/null +++ b/xls/modules/zstd/rtl/ram_2rw.sv @@ -0,0 +1,69 @@ +// Copyright 2025 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. + +module ram_2rw # ( + parameter DATA_WIDTH = 4, + parameter SIZE = 32, + parameter ADDR_WIDTH = $clog2(SIZE), + parameter INIT_FILE = "" +) ( + input wire clk, + input wire rst, + + input wire [DATA_WIDTH - 1:0] data_0, + input wire [ADDR_WIDTH - 1:0] addr_0, + input wire wr_en_0, + input wire rd_en_0, + input wire [DATA_WIDTH - 1:0] data_1, + input wire [ADDR_WIDTH - 1:0] addr_1, + input wire wr_en_1, + input wire rd_en_1, + + output reg [DATA_WIDTH - 1:0] rd_data_0, + output reg [DATA_WIDTH - 1:0] rd_data_1 +); + +reg [DATA_WIDTH-1:0] mem [SIZE]; + +integer i; + +always @(rst) begin + if (INIT_FILE != "") begin + $readmemh(INIT_FILE, mem); + end + else begin + for (i = 0; i < SIZE; i++) begin + mem[i] <= {DATA_WIDTH{1'b0}}; + end + end +end + +integer j; + +always @(posedge clk) begin + if (rd_en_0) begin + rd_data_0 <= mem[addr_0]; + end + if (rd_en_1) begin + rd_data_1 <= mem[addr_1]; + end + + if (wr_en_0) begin + mem[addr_0] <= data_0; + end + if (wr_en_1) begin + mem[addr_1] <= data_1; + end +end +endmodule diff --git a/xls/modules/zstd/rtl/ram_demux_wrapper.sv b/xls/modules/zstd/rtl/ram_demux_wrapper.sv new file mode 100644 index 0000000000..973b0b18a4 --- /dev/null +++ b/xls/modules/zstd/rtl/ram_demux_wrapper.sv @@ -0,0 +1,155 @@ +// Copyright 2025 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. + +module ram_demux_wrapper #( + parameter DATA_WIDTH = 64, + parameter SIZE = 1024, + parameter ADDR_WIDTH = $clog2(SIZE), + parameter NUM_PARTITIONS = 64 +) ( + input wire clk, + input wire rst, + + input wire ram_demux__sel_req_r_data, + input wire ram_demux__sel_req_r_vld, + output wire ram_demux__sel_req_r_rdy, + + input wire ram_demux__sel_resp_s_rdy, + output wire ram_demux__sel_resp_s_vld, + + input wire [ NUM_PARTITIONS + ADDR_WIDTH - 1:0 ] ram_demux__rd_req_r_data, + input wire ram_demux__rd_req_r_vld, + output wire ram_demux__rd_req_r_rdy, + + output wire [ DATA_WIDTH -1:0 ] ram_demux__rd_resp_s_data, + output wire ram_demux__rd_resp_s_vld, + input wire ram_demux__rd_resp_s_rdy, + + input wire [ DATA_WIDTH + NUM_PARTITIONS + ADDR_WIDTH -1:0 ] ram_demux__wr_req_r_data, + input wire ram_demux__wr_req_r_vld, + output wire ram_demux__wr_req_r_rdy, + + input wire ram_demux__wr_resp_s_rdy, + output wire ram_demux__wr_resp_s_vld +); + +wire [ DATA_WIDTH -1:0 ] ram0_wr_data; +wire [ ADDR_WIDTH -1:0 ] ram0_wr_addr; +wire ram0_wr_en; +wire [ NUM_PARTITIONS -1:0 ] ram0_wr_mask; + +wire [ DATA_WIDTH -1:0 ] ram0_rd_data; +wire [ ADDR_WIDTH -1:0 ] ram0_rd_addr; +wire ram0_rd_en; +wire [ NUM_PARTITIONS -1:0 ] ram0_rd_mask; + +ram_1r1w # ( + .DATA_WIDTH(DATA_WIDTH), + .SIZE(SIZE), + .NUM_PARTITIONS(NUM_PARTITIONS), + .ADDR_WIDTH(ADDR_WIDTH) +) ram0 ( + .clk (clk), + .rst (rst), + + .wr_data (ram0_wr_data), + .wr_addr (ram0_wr_addr), + .wr_en (ram0_wr_en), + .wr_mask (ram0_wr_mask), + + .rd_data (ram0_rd_data), + .rd_addr (ram0_rd_addr), + .rd_en (ram0_rd_en), + .rd_mask (ram0_rd_mask) +); + +wire [ DATA_WIDTH -1:0 ] ram1_wr_data; +wire [ ADDR_WIDTH -1:0 ] ram1_wr_addr; +wire ram1_wr_en; +wire [ NUM_PARTITIONS -1:0 ] ram1_wr_mask; + +wire [ DATA_WIDTH -1:0 ] ram1_rd_data; +wire [ ADDR_WIDTH -1:0 ] ram1_rd_addr; +wire ram1_rd_en; +wire [ NUM_PARTITIONS -1:0 ] ram1_rd_mask; + + +ram_1r1w # ( + .DATA_WIDTH(DATA_WIDTH), + .SIZE(SIZE), + .NUM_PARTITIONS(NUM_PARTITIONS), + .ADDR_WIDTH(ADDR_WIDTH) +) ram1 ( + .clk (clk), + .rst (rst), + + .wr_data (ram1_wr_data), + .wr_addr (ram1_wr_addr), + .wr_en (ram1_wr_en), + .wr_mask (ram1_wr_mask), + + .rd_data (ram1_rd_data), + .rd_addr (ram1_rd_addr), + .rd_en (ram1_rd_en), + .rd_mask (ram1_rd_mask) +); + +RamDemux demux ( + .clk(clk), + .rst(rst), + + .ram_demux__rd_req_r_data(ram_demux__rd_req_r_data), + .ram_demux__rd_req_r_vld(ram_demux__rd_req_r_vld), + .ram_demux__rd_req_r_rdy(ram_demux__rd_req_r_rdy), + + .ram_demux__sel_req_r_data(ram_demux__sel_req_r_data), + .ram_demux__sel_req_r_rdy(ram_demux__sel_req_r_rdy), + .ram_demux__sel_req_r_vld(ram_demux__sel_req_r_vld), + + .ram_demux__sel_resp_s_rdy(ram_demux__sel_resp_s_rdy), + .ram_demux__sel_resp_s_vld(ram_demux__sel_resp_s_vld), + + .ram_demux__wr_req_r_vld(ram_demux__wr_req_r_vld), + .ram_demux__wr_req_r_rdy(ram_demux__wr_req_r_rdy), + .ram_demux__wr_req_r_data(ram_demux__wr_req_r_data), + + .ram_demux__wr_resp_s_rdy(ram_demux__wr_resp_s_rdy), + .ram_demux__wr_resp_s_vld(ram_demux__wr_resp_s_vld), + + .ram_demux__rd_resp_s_rdy(ram_demux__rd_resp_s_rdy), + .ram_demux__rd_resp_s_data(ram_demux__rd_resp_s_data), + .ram_demux__rd_resp_s_vld(ram_demux__rd_resp_s_vld), + + .ram0_rd_data (ram0_rd_data), + .ram0_rd_addr (ram0_rd_addr), + .ram0_rd_mask (ram0_rd_mask), + .ram0_rd_en (ram0_rd_en), + + .ram0_wr_addr (ram0_wr_addr), + .ram0_wr_data (ram0_wr_data), + .ram0_wr_mask (ram0_wr_mask), + .ram0_wr_en (ram0_wr_en), + + .ram1_rd_data (ram1_rd_data), + .ram1_rd_addr (ram1_rd_addr), + .ram1_rd_mask (ram1_rd_mask), + .ram1_rd_en (ram1_rd_en), + + .ram1_wr_addr (ram1_wr_addr), + .ram1_wr_data (ram1_wr_data), + .ram1_wr_mask (ram1_wr_mask), + .ram1_wr_en (ram1_wr_en) +); + +endmodule diff --git a/xls/modules/zstd/rtl/zstd_dec_wrapper.sv b/xls/modules/zstd/rtl/zstd_dec_wrapper.sv index 8a616f3f23..2e3e128d98 100644 --- a/xls/modules/zstd/rtl/zstd_dec_wrapper.sv +++ b/xls/modules/zstd/rtl/zstd_dec_wrapper.sv @@ -22,9 +22,9 @@ module zstd_dec_wrapper #( parameter int AXI_DATA_W = 64, - parameter int AXI_ADDR_W = 16, + parameter int AXI_ADDR_W = 32, parameter int S_AXI_ID_W = 4, - parameter int M_AXI_ID_W = 6, + parameter int M_AXI_ID_W = 8, parameter int AXI_STRB_W = 8, parameter int AWUSER_WIDTH = 1, parameter int WUSER_WIDTH = 1, @@ -426,68 +426,1847 @@ module zstd_dec_wrapper #( assign csr_axi_r_ruser = 1'b0; assign notify_data = notify_vld; + // Axi Subordinate Interface for axi_ram_s__0 + wire axi_ram_s__0_axi_ar_arvalid; + wire axi_ram_s__0_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__0_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__0_axi_ar_araddr; + wire [ 3:0] axi_ram_s__0_axi_ar_arregion; + wire [ 7:0] axi_ram_s__0_axi_ar_arlen; + wire [ 2:0] axi_ram_s__0_axi_ar_arsize; + wire [ 1:0] axi_ram_s__0_axi_ar_arburst; + wire [ 3:0] axi_ram_s__0_axi_ar_arcache; + wire [ 2:0] axi_ram_s__0_axi_ar_arprot; + wire [ 3:0] axi_ram_s__0_axi_ar_arqos; + + wire axi_ram_s__0_axi_r_rvalid; + wire axi_ram_s__0_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__0_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__0_axi_r_rdata; + wire [ 2:0] axi_ram_s__0_axi_r_rresp; + wire axi_ram_s__0_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__0; + wire zstd_dec__axi_ram_ar_s__0_rdy; + wire zstd_dec__axi_ram_ar_s__0_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__0; + wire zstd_dec__axi_ram_r_r__0_rdy; + wire zstd_dec__axi_ram_r_r__0_vld; + + assign { + axi_ram_s__0_axi_ar_arid, + axi_ram_s__0_axi_ar_araddr, + axi_ram_s__0_axi_ar_arregion, + axi_ram_s__0_axi_ar_arlen, + axi_ram_s__0_axi_ar_arsize, + axi_ram_s__0_axi_ar_arburst, + axi_ram_s__0_axi_ar_arcache, + axi_ram_s__0_axi_ar_arprot, + axi_ram_s__0_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__0; + assign axi_ram_s__0_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__0_vld; + assign zstd_dec__axi_ram_ar_s__0_rdy = axi_ram_s__0_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__0 = { + axi_ram_s__0_axi_r_rid, + axi_ram_s__0_axi_r_rdata, + axi_ram_s__0_axi_r_rresp, + axi_ram_s__0_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__0_vld = axi_ram_s__0_axi_r_rvalid; + assign axi_ram_s__0_axi_r_rready = zstd_dec__axi_ram_r_r__0_rdy; + assign axi_ram_s__0_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__1 + wire axi_ram_s__1_axi_ar_arvalid; + wire axi_ram_s__1_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__1_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__1_axi_ar_araddr; + wire [ 3:0] axi_ram_s__1_axi_ar_arregion; + wire [ 7:0] axi_ram_s__1_axi_ar_arlen; + wire [ 2:0] axi_ram_s__1_axi_ar_arsize; + wire [ 1:0] axi_ram_s__1_axi_ar_arburst; + wire [ 3:0] axi_ram_s__1_axi_ar_arcache; + wire [ 2:0] axi_ram_s__1_axi_ar_arprot; + wire [ 3:0] axi_ram_s__1_axi_ar_arqos; + + wire axi_ram_s__1_axi_r_rvalid; + wire axi_ram_s__1_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__1_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__1_axi_r_rdata; + wire [ 2:0] axi_ram_s__1_axi_r_rresp; + wire axi_ram_s__1_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__1; + wire zstd_dec__axi_ram_ar_s__1_rdy; + wire zstd_dec__axi_ram_ar_s__1_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__1; + wire zstd_dec__axi_ram_r_r__1_rdy; + wire zstd_dec__axi_ram_r_r__1_vld; + + assign { + axi_ram_s__1_axi_ar_arid, + axi_ram_s__1_axi_ar_araddr, + axi_ram_s__1_axi_ar_arregion, + axi_ram_s__1_axi_ar_arlen, + axi_ram_s__1_axi_ar_arsize, + axi_ram_s__1_axi_ar_arburst, + axi_ram_s__1_axi_ar_arcache, + axi_ram_s__1_axi_ar_arprot, + axi_ram_s__1_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__1; + assign axi_ram_s__1_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__1_vld; + assign zstd_dec__axi_ram_ar_s__1_rdy = axi_ram_s__1_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__1 = { + axi_ram_s__1_axi_r_rid, + axi_ram_s__1_axi_r_rdata, + axi_ram_s__1_axi_r_rresp, + axi_ram_s__1_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__1_vld = axi_ram_s__1_axi_r_rvalid; + assign axi_ram_s__1_axi_r_rready = zstd_dec__axi_ram_r_r__1_rdy; + assign axi_ram_s__1_axi_r_rresp[2] = '0; + + + // Axi Subordinate Interface for axi_ram_s__2 + wire axi_ram_s__2_axi_ar_arvalid; + wire axi_ram_s__2_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__2_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__2_axi_ar_araddr; + wire [ 3:0] axi_ram_s__2_axi_ar_arregion; + wire [ 7:0] axi_ram_s__2_axi_ar_arlen; + wire [ 2:0] axi_ram_s__2_axi_ar_arsize; + wire [ 1:0] axi_ram_s__2_axi_ar_arburst; + wire [ 3:0] axi_ram_s__2_axi_ar_arcache; + wire [ 2:0] axi_ram_s__2_axi_ar_arprot; + wire [ 3:0] axi_ram_s__2_axi_ar_arqos; + + wire axi_ram_s__2_axi_r_rvalid; + wire axi_ram_s__2_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__2_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__2_axi_r_rdata; + wire [ 2:0] axi_ram_s__2_axi_r_rresp; + wire axi_ram_s__2_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__2; + wire zstd_dec__axi_ram_ar_s__2_rdy; + wire zstd_dec__axi_ram_ar_s__2_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__2; + wire zstd_dec__axi_ram_r_r__2_rdy; + wire zstd_dec__axi_ram_r_r__2_vld; + + assign { + axi_ram_s__2_axi_ar_arid, + axi_ram_s__2_axi_ar_araddr, + axi_ram_s__2_axi_ar_arregion, + axi_ram_s__2_axi_ar_arlen, + axi_ram_s__2_axi_ar_arsize, + axi_ram_s__2_axi_ar_arburst, + axi_ram_s__2_axi_ar_arcache, + axi_ram_s__2_axi_ar_arprot, + axi_ram_s__2_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__2; + assign axi_ram_s__2_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__2_vld; + assign zstd_dec__axi_ram_ar_s__2_rdy = axi_ram_s__2_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__2 = { + axi_ram_s__2_axi_r_rid, + axi_ram_s__2_axi_r_rdata, + axi_ram_s__2_axi_r_rresp, + axi_ram_s__2_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__2_vld = axi_ram_s__2_axi_r_rvalid; + assign axi_ram_s__2_axi_r_rready = zstd_dec__axi_ram_r_r__2_rdy; + assign axi_ram_s__2_axi_r_rresp[2] = '0; + + + // Axi Subordinate Interface for axi_ram_s__3 + wire axi_ram_s__3_axi_ar_arvalid; + wire axi_ram_s__3_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__3_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__3_axi_ar_araddr; + wire [ 3:0] axi_ram_s__3_axi_ar_arregion; + wire [ 7:0] axi_ram_s__3_axi_ar_arlen; + wire [ 2:0] axi_ram_s__3_axi_ar_arsize; + wire [ 1:0] axi_ram_s__3_axi_ar_arburst; + wire [ 3:0] axi_ram_s__3_axi_ar_arcache; + wire [ 2:0] axi_ram_s__3_axi_ar_arprot; + wire [ 3:0] axi_ram_s__3_axi_ar_arqos; + + wire axi_ram_s__3_axi_r_rvalid; + wire axi_ram_s__3_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__3_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__3_axi_r_rdata; + wire [ 2:0] axi_ram_s__3_axi_r_rresp; + wire axi_ram_s__3_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__3; + wire zstd_dec__axi_ram_ar_s__3_rdy; + wire zstd_dec__axi_ram_ar_s__3_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__3; + wire zstd_dec__axi_ram_r_r__3_rdy; + wire zstd_dec__axi_ram_r_r__3_vld; + + assign { + axi_ram_s__3_axi_ar_arid, + axi_ram_s__3_axi_ar_araddr, + axi_ram_s__3_axi_ar_arregion, + axi_ram_s__3_axi_ar_arlen, + axi_ram_s__3_axi_ar_arsize, + axi_ram_s__3_axi_ar_arburst, + axi_ram_s__3_axi_ar_arcache, + axi_ram_s__3_axi_ar_arprot, + axi_ram_s__3_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__3; + assign axi_ram_s__3_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__3_vld; + assign zstd_dec__axi_ram_ar_s__3_rdy = axi_ram_s__3_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__3 = { + axi_ram_s__3_axi_r_rid, + axi_ram_s__3_axi_r_rdata, + axi_ram_s__3_axi_r_rresp, + axi_ram_s__3_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__3_vld = axi_ram_s__3_axi_r_rvalid; + assign axi_ram_s__3_axi_r_rready = zstd_dec__axi_ram_r_r__3_rdy; + assign axi_ram_s__3_axi_r_rresp[2] = '0; + + + // Axi Subordinate Interface for axi_ram_s__4 + wire axi_ram_s__4_axi_ar_arvalid; + wire axi_ram_s__4_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__4_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__4_axi_ar_araddr; + wire [ 3:0] axi_ram_s__4_axi_ar_arregion; + wire [ 7:0] axi_ram_s__4_axi_ar_arlen; + wire [ 2:0] axi_ram_s__4_axi_ar_arsize; + wire [ 1:0] axi_ram_s__4_axi_ar_arburst; + wire [ 3:0] axi_ram_s__4_axi_ar_arcache; + wire [ 2:0] axi_ram_s__4_axi_ar_arprot; + wire [ 3:0] axi_ram_s__4_axi_ar_arqos; + + wire axi_ram_s__4_axi_r_rvalid; + wire axi_ram_s__4_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__4_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__4_axi_r_rdata; + wire [ 2:0] axi_ram_s__4_axi_r_rresp; + wire axi_ram_s__4_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__4; + wire zstd_dec__axi_ram_ar_s__4_rdy; + wire zstd_dec__axi_ram_ar_s__4_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__4; + wire zstd_dec__axi_ram_r_r__4_rdy; + wire zstd_dec__axi_ram_r_r__4_vld; + + assign { + axi_ram_s__4_axi_ar_arid, + axi_ram_s__4_axi_ar_araddr, + axi_ram_s__4_axi_ar_arregion, + axi_ram_s__4_axi_ar_arlen, + axi_ram_s__4_axi_ar_arsize, + axi_ram_s__4_axi_ar_arburst, + axi_ram_s__4_axi_ar_arcache, + axi_ram_s__4_axi_ar_arprot, + axi_ram_s__4_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__4; + assign axi_ram_s__4_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__4_vld; + assign zstd_dec__axi_ram_ar_s__4_rdy = axi_ram_s__4_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__4 = { + axi_ram_s__4_axi_r_rid, + axi_ram_s__4_axi_r_rdata, + axi_ram_s__4_axi_r_rresp, + axi_ram_s__4_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__4_vld = axi_ram_s__4_axi_r_rvalid; + assign axi_ram_s__4_axi_r_rready = zstd_dec__axi_ram_r_r__4_rdy; + assign axi_ram_s__4_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__5 + wire axi_ram_s__5_axi_ar_arvalid; + wire axi_ram_s__5_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__5_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__5_axi_ar_araddr; + wire [ 3:0] axi_ram_s__5_axi_ar_arregion; + wire [ 7:0] axi_ram_s__5_axi_ar_arlen; + wire [ 2:0] axi_ram_s__5_axi_ar_arsize; + wire [ 1:0] axi_ram_s__5_axi_ar_arburst; + wire [ 3:0] axi_ram_s__5_axi_ar_arcache; + wire [ 2:0] axi_ram_s__5_axi_ar_arprot; + wire [ 3:0] axi_ram_s__5_axi_ar_arqos; + + wire axi_ram_s__5_axi_r_rvalid; + wire axi_ram_s__5_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__5_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__5_axi_r_rdata; + wire [ 2:0] axi_ram_s__5_axi_r_rresp; + wire axi_ram_s__5_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__5; + wire zstd_dec__axi_ram_ar_s__5_rdy; + wire zstd_dec__axi_ram_ar_s__5_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__5; + wire zstd_dec__axi_ram_r_r__5_rdy; + wire zstd_dec__axi_ram_r_r__5_vld; + + assign { + axi_ram_s__5_axi_ar_arid, + axi_ram_s__5_axi_ar_araddr, + axi_ram_s__5_axi_ar_arregion, + axi_ram_s__5_axi_ar_arlen, + axi_ram_s__5_axi_ar_arsize, + axi_ram_s__5_axi_ar_arburst, + axi_ram_s__5_axi_ar_arcache, + axi_ram_s__5_axi_ar_arprot, + axi_ram_s__5_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__5; + assign axi_ram_s__5_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__5_vld; + assign zstd_dec__axi_ram_ar_s__5_rdy = axi_ram_s__5_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__5 = { + axi_ram_s__5_axi_r_rid, + axi_ram_s__5_axi_r_rdata, + axi_ram_s__5_axi_r_rresp, + axi_ram_s__5_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__5_vld = axi_ram_s__5_axi_r_rvalid; + assign axi_ram_s__5_axi_r_rready = zstd_dec__axi_ram_r_r__5_rdy; + assign axi_ram_s__5_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__6 + wire axi_ram_s__6_axi_ar_arvalid; + wire axi_ram_s__6_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__6_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__6_axi_ar_araddr; + wire [ 3:0] axi_ram_s__6_axi_ar_arregion; + wire [ 7:0] axi_ram_s__6_axi_ar_arlen; + wire [ 2:0] axi_ram_s__6_axi_ar_arsize; + wire [ 1:0] axi_ram_s__6_axi_ar_arburst; + wire [ 3:0] axi_ram_s__6_axi_ar_arcache; + wire [ 2:0] axi_ram_s__6_axi_ar_arprot; + wire [ 3:0] axi_ram_s__6_axi_ar_arqos; + + wire axi_ram_s__6_axi_r_rvalid; + wire axi_ram_s__6_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__6_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__6_axi_r_rdata; + wire [ 2:0] axi_ram_s__6_axi_r_rresp; + wire axi_ram_s__6_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__6; + wire zstd_dec__axi_ram_ar_s__6_rdy; + wire zstd_dec__axi_ram_ar_s__6_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__6; + wire zstd_dec__axi_ram_r_r__6_rdy; + wire zstd_dec__axi_ram_r_r__6_vld; + + assign { + axi_ram_s__6_axi_ar_arid, + axi_ram_s__6_axi_ar_araddr, + axi_ram_s__6_axi_ar_arregion, + axi_ram_s__6_axi_ar_arlen, + axi_ram_s__6_axi_ar_arsize, + axi_ram_s__6_axi_ar_arburst, + axi_ram_s__6_axi_ar_arcache, + axi_ram_s__6_axi_ar_arprot, + axi_ram_s__6_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__6; + assign axi_ram_s__6_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__6_vld; + assign zstd_dec__axi_ram_ar_s__6_rdy = axi_ram_s__6_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__6 = { + axi_ram_s__6_axi_r_rid, + axi_ram_s__6_axi_r_rdata, + axi_ram_s__6_axi_r_rresp, + axi_ram_s__6_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__6_vld = axi_ram_s__6_axi_r_rvalid; + assign axi_ram_s__6_axi_r_rready = zstd_dec__axi_ram_r_r__6_rdy; + assign axi_ram_s__6_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__7 + wire axi_ram_s__7_axi_ar_arvalid; + wire axi_ram_s__7_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__7_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__7_axi_ar_araddr; + wire [ 3:0] axi_ram_s__7_axi_ar_arregion; + wire [ 7:0] axi_ram_s__7_axi_ar_arlen; + wire [ 2:0] axi_ram_s__7_axi_ar_arsize; + wire [ 1:0] axi_ram_s__7_axi_ar_arburst; + wire [ 3:0] axi_ram_s__7_axi_ar_arcache; + wire [ 2:0] axi_ram_s__7_axi_ar_arprot; + wire [ 3:0] axi_ram_s__7_axi_ar_arqos; + + wire axi_ram_s__7_axi_r_rvalid; + wire axi_ram_s__7_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__7_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__7_axi_r_rdata; + wire [ 2:0] axi_ram_s__7_axi_r_rresp; + wire axi_ram_s__7_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__7; + wire zstd_dec__axi_ram_ar_s__7_rdy; + wire zstd_dec__axi_ram_ar_s__7_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__7; + wire zstd_dec__axi_ram_r_r__7_rdy; + wire zstd_dec__axi_ram_r_r__7_vld; + + assign { + axi_ram_s__7_axi_ar_arid, + axi_ram_s__7_axi_ar_araddr, + axi_ram_s__7_axi_ar_arregion, + axi_ram_s__7_axi_ar_arlen, + axi_ram_s__7_axi_ar_arsize, + axi_ram_s__7_axi_ar_arburst, + axi_ram_s__7_axi_ar_arcache, + axi_ram_s__7_axi_ar_arprot, + axi_ram_s__7_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__7; + assign axi_ram_s__7_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__7_vld; + assign zstd_dec__axi_ram_ar_s__7_rdy = axi_ram_s__7_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__7 = { + axi_ram_s__7_axi_r_rid, + axi_ram_s__7_axi_r_rdata, + axi_ram_s__7_axi_r_rresp, + axi_ram_s__7_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__7_vld = axi_ram_s__7_axi_r_rvalid; + assign axi_ram_s__7_axi_r_rready = zstd_dec__axi_ram_r_r__7_rdy; + assign axi_ram_s__7_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__8 + wire axi_ram_s__8_axi_ar_arvalid; + wire axi_ram_s__8_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__8_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__8_axi_ar_araddr; + wire [ 3:0] axi_ram_s__8_axi_ar_arregion; + wire [ 7:0] axi_ram_s__8_axi_ar_arlen; + wire [ 2:0] axi_ram_s__8_axi_ar_arsize; + wire [ 1:0] axi_ram_s__8_axi_ar_arburst; + wire [ 3:0] axi_ram_s__8_axi_ar_arcache; + wire [ 2:0] axi_ram_s__8_axi_ar_arprot; + wire [ 3:0] axi_ram_s__8_axi_ar_arqos; + + wire axi_ram_s__8_axi_r_rvalid; + wire axi_ram_s__8_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__8_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__8_axi_r_rdata; + wire [ 2:0] axi_ram_s__8_axi_r_rresp; + wire axi_ram_s__8_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__8; + wire zstd_dec__axi_ram_ar_s__8_rdy; + wire zstd_dec__axi_ram_ar_s__8_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__8; + wire zstd_dec__axi_ram_r_r__8_rdy; + wire zstd_dec__axi_ram_r_r__8_vld; + + assign { + axi_ram_s__8_axi_ar_arid, + axi_ram_s__8_axi_ar_araddr, + axi_ram_s__8_axi_ar_arregion, + axi_ram_s__8_axi_ar_arlen, + axi_ram_s__8_axi_ar_arsize, + axi_ram_s__8_axi_ar_arburst, + axi_ram_s__8_axi_ar_arcache, + axi_ram_s__8_axi_ar_arprot, + axi_ram_s__8_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__8; + assign axi_ram_s__8_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__8_vld; + assign zstd_dec__axi_ram_ar_s__8_rdy = axi_ram_s__8_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__8 = { + axi_ram_s__8_axi_r_rid, + axi_ram_s__8_axi_r_rdata, + axi_ram_s__8_axi_r_rresp, + axi_ram_s__8_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__8_vld = axi_ram_s__8_axi_r_rvalid; + assign axi_ram_s__8_axi_r_rready = zstd_dec__axi_ram_r_r__8_rdy; + assign axi_ram_s__8_axi_r_rresp[2] = '0; + + // Axi Subordinate Interface for axi_ram_s__9 + wire axi_ram_s__9_axi_ar_arvalid; + wire axi_ram_s__9_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__9_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__9_axi_ar_araddr; + wire [ 3:0] axi_ram_s__9_axi_ar_arregion; + wire [ 7:0] axi_ram_s__9_axi_ar_arlen; + wire [ 2:0] axi_ram_s__9_axi_ar_arsize; + wire [ 1:0] axi_ram_s__9_axi_ar_arburst; + wire [ 3:0] axi_ram_s__9_axi_ar_arcache; + wire [ 2:0] axi_ram_s__9_axi_ar_arprot; + wire [ 3:0] axi_ram_s__9_axi_ar_arqos; + + wire axi_ram_s__9_axi_r_rvalid; + wire axi_ram_s__9_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__9_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__9_axi_r_rdata; + wire [ 2:0] axi_ram_s__9_axi_r_rresp; + wire axi_ram_s__9_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__9; + wire zstd_dec__axi_ram_ar_s__9_rdy; + wire zstd_dec__axi_ram_ar_s__9_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__9; + wire zstd_dec__axi_ram_r_r__9_rdy; + wire zstd_dec__axi_ram_r_r__9_vld; + + assign { + axi_ram_s__9_axi_ar_arid, + axi_ram_s__9_axi_ar_araddr, + axi_ram_s__9_axi_ar_arregion, + axi_ram_s__9_axi_ar_arlen, + axi_ram_s__9_axi_ar_arsize, + axi_ram_s__9_axi_ar_arburst, + axi_ram_s__9_axi_ar_arcache, + axi_ram_s__9_axi_ar_arprot, + axi_ram_s__9_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__9; + assign axi_ram_s__9_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__9_vld; + assign zstd_dec__axi_ram_ar_s__9_rdy = axi_ram_s__9_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__9 = { + axi_ram_s__9_axi_r_rid, + axi_ram_s__9_axi_r_rdata, + axi_ram_s__9_axi_r_rresp, + axi_ram_s__9_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__9_vld = axi_ram_s__9_axi_r_rvalid; + assign axi_ram_s__9_axi_r_rready = zstd_dec__axi_ram_r_r__9_rdy; + assign axi_ram_s__9_axi_r_rresp[2] = '0; + + + // Axi Subordinate Interface for axi_ram_s__10 + wire axi_ram_s__10_axi_ar_arvalid; + wire axi_ram_s__10_axi_ar_arready; + wire [S_AXI_ID_W-1:0] axi_ram_s__10_axi_ar_arid; + wire [AXI_ADDR_W-1:0] axi_ram_s__10_axi_ar_araddr; + wire [ 3:0] axi_ram_s__10_axi_ar_arregion; + wire [ 7:0] axi_ram_s__10_axi_ar_arlen; + wire [ 2:0] axi_ram_s__10_axi_ar_arsize; + wire [ 1:0] axi_ram_s__10_axi_ar_arburst; + wire [ 3:0] axi_ram_s__10_axi_ar_arcache; + wire [ 2:0] axi_ram_s__10_axi_ar_arprot; + wire [ 3:0] axi_ram_s__10_axi_ar_arqos; + + wire axi_ram_s__10_axi_r_rvalid; + wire axi_ram_s__10_axi_r_rready; + wire [S_AXI_ID_W-1:0] axi_ram_s__10_axi_r_rid; + wire [AXI_DATA_W-1:0] axi_ram_s__10_axi_r_rdata; + wire [ 2:0] axi_ram_s__10_axi_r_rresp; + wire axi_ram_s__10_axi_r_rlast; + + wire [XlsAxiArW-1:0] zstd_dec__axi_ram_ar_s__10; + wire zstd_dec__axi_ram_ar_s__10_rdy; + wire zstd_dec__axi_ram_ar_s__10_vld; + wire [ XlsAxiRW-1:0] zstd_dec__axi_ram_r_r__10; + wire zstd_dec__axi_ram_r_r__10_rdy; + wire zstd_dec__axi_ram_r_r__10_vld; + + assign { + axi_ram_s__10_axi_ar_arid, + axi_ram_s__10_axi_ar_araddr, + axi_ram_s__10_axi_ar_arregion, + axi_ram_s__10_axi_ar_arlen, + axi_ram_s__10_axi_ar_arsize, + axi_ram_s__10_axi_ar_arburst, + axi_ram_s__10_axi_ar_arcache, + axi_ram_s__10_axi_ar_arprot, + axi_ram_s__10_axi_ar_arqos + } = zstd_dec__axi_ram_ar_s__10; + assign axi_ram_s__10_axi_ar_arvalid = zstd_dec__axi_ram_ar_s__10_vld; + assign zstd_dec__axi_ram_ar_s__10_rdy = axi_ram_s__10_axi_ar_arready; + + assign zstd_dec__axi_ram_r_r__10 = { + axi_ram_s__10_axi_r_rid, + axi_ram_s__10_axi_r_rdata, + axi_ram_s__10_axi_r_rresp, + axi_ram_s__10_axi_r_rlast}; + assign zstd_dec__axi_ram_r_r__10_vld = axi_ram_s__10_axi_r_rvalid; + assign axi_ram_s__10_axi_r_rready = zstd_dec__axi_ram_r_r__10_rdy; + assign axi_ram_s__10_axi_r_rresp[2] = '0; + + + // RAM instance for history_buffer_ram0 + logic [7:0] history_buffer_ram0_data[2]; + logic [12:0] history_buffer_ram0_addr[2]; + logic history_buffer_ram0_wr_en[2]; + logic history_buffer_ram0_rd_en[2]; + logic [7:0] history_buffer_ram0_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram0_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram0_data[0]), + .addr_0(history_buffer_ram0_addr[0]), + .wr_en_0(history_buffer_ram0_wr_en[0]), + .rd_en_0(history_buffer_ram0_rd_en[0]), + .rd_data_0(history_buffer_ram0_rd_data[0]), + .data_1(history_buffer_ram0_data[1]), + .addr_1(history_buffer_ram0_addr[1]), + .wr_en_1(history_buffer_ram0_wr_en[1]), + .rd_en_1(history_buffer_ram0_rd_en[1]), + .rd_data_1(history_buffer_ram0_rd_data[1]) + ); + + // RAM instance for history_buffer_ram1 + logic [7:0] history_buffer_ram1_data[2]; + logic [12:0] history_buffer_ram1_addr[2]; + logic history_buffer_ram1_wr_en[2]; + logic history_buffer_ram1_rd_en[2]; + logic [7:0] history_buffer_ram1_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram1_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram1_data[0]), + .addr_0(history_buffer_ram1_addr[0]), + .wr_en_0(history_buffer_ram1_wr_en[0]), + .rd_en_0(history_buffer_ram1_rd_en[0]), + .rd_data_0(history_buffer_ram1_rd_data[0]), + .data_1(history_buffer_ram1_data[1]), + .addr_1(history_buffer_ram1_addr[1]), + .wr_en_1(history_buffer_ram1_wr_en[1]), + .rd_en_1(history_buffer_ram1_rd_en[1]), + .rd_data_1(history_buffer_ram1_rd_data[1]) + ); + + // RAM instance for history_buffer_ram2 + logic [7:0] history_buffer_ram2_data[2]; + logic [12:0] history_buffer_ram2_addr[2]; + logic history_buffer_ram2_wr_en[2]; + logic history_buffer_ram2_rd_en[2]; + logic [7:0] history_buffer_ram2_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram2_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram2_data[0]), + .addr_0(history_buffer_ram2_addr[0]), + .wr_en_0(history_buffer_ram2_wr_en[0]), + .rd_en_0(history_buffer_ram2_rd_en[0]), + .rd_data_0(history_buffer_ram2_rd_data[0]), + .data_1(history_buffer_ram2_data[1]), + .addr_1(history_buffer_ram2_addr[1]), + .wr_en_1(history_buffer_ram2_wr_en[1]), + .rd_en_1(history_buffer_ram2_rd_en[1]), + .rd_data_1(history_buffer_ram2_rd_data[1]) + ); + + // RAM instance for history_buffer_ram3 + logic [7:0] history_buffer_ram3_data[2]; + logic [12:0] history_buffer_ram3_addr[2]; + logic history_buffer_ram3_wr_en[2]; + logic history_buffer_ram3_rd_en[2]; + logic [7:0] history_buffer_ram3_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram3_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram3_data[0]), + .addr_0(history_buffer_ram3_addr[0]), + .wr_en_0(history_buffer_ram3_wr_en[0]), + .rd_en_0(history_buffer_ram3_rd_en[0]), + .rd_data_0(history_buffer_ram3_rd_data[0]), + .data_1(history_buffer_ram3_data[1]), + .addr_1(history_buffer_ram3_addr[1]), + .wr_en_1(history_buffer_ram3_wr_en[1]), + .rd_en_1(history_buffer_ram3_rd_en[1]), + .rd_data_1(history_buffer_ram3_rd_data[1]) + ); + + // RAM instance for history_buffer_ram4 + logic [7:0] history_buffer_ram4_data[2]; + logic [12:0] history_buffer_ram4_addr[2]; + logic history_buffer_ram4_wr_en[2]; + logic history_buffer_ram4_rd_en[2]; + logic [7:0] history_buffer_ram4_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram4_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram4_data[0]), + .addr_0(history_buffer_ram4_addr[0]), + .wr_en_0(history_buffer_ram4_wr_en[0]), + .rd_en_0(history_buffer_ram4_rd_en[0]), + .rd_data_0(history_buffer_ram4_rd_data[0]), + .data_1(history_buffer_ram4_data[1]), + .addr_1(history_buffer_ram4_addr[1]), + .wr_en_1(history_buffer_ram4_wr_en[1]), + .rd_en_1(history_buffer_ram4_rd_en[1]), + .rd_data_1(history_buffer_ram4_rd_data[1]) + ); + + // RAM instance for history_buffer_ram5 + logic [7:0] history_buffer_ram5_data[2]; + logic [12:0] history_buffer_ram5_addr[2]; + logic history_buffer_ram5_wr_en[2]; + logic history_buffer_ram5_rd_en[2]; + logic [7:0] history_buffer_ram5_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram5_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram5_data[0]), + .addr_0(history_buffer_ram5_addr[0]), + .wr_en_0(history_buffer_ram5_wr_en[0]), + .rd_en_0(history_buffer_ram5_rd_en[0]), + .rd_data_0(history_buffer_ram5_rd_data[0]), + .data_1(history_buffer_ram5_data[1]), + .addr_1(history_buffer_ram5_addr[1]), + .wr_en_1(history_buffer_ram5_wr_en[1]), + .rd_en_1(history_buffer_ram5_rd_en[1]), + .rd_data_1(history_buffer_ram5_rd_data[1]) + ); + + // RAM instance for history_buffer_ram6 + logic [7:0] history_buffer_ram6_data[2]; + logic [12:0] history_buffer_ram6_addr[2]; + logic history_buffer_ram6_wr_en[2]; + logic history_buffer_ram6_rd_en[2]; + logic [7:0] history_buffer_ram6_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram6_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram6_data[0]), + .addr_0(history_buffer_ram6_addr[0]), + .wr_en_0(history_buffer_ram6_wr_en[0]), + .rd_en_0(history_buffer_ram6_rd_en[0]), + .rd_data_0(history_buffer_ram6_rd_data[0]), + .data_1(history_buffer_ram6_data[1]), + .addr_1(history_buffer_ram6_addr[1]), + .wr_en_1(history_buffer_ram6_wr_en[1]), + .rd_en_1(history_buffer_ram6_rd_en[1]), + .rd_data_1(history_buffer_ram6_rd_data[1]) + ); + + // RAM instance for history_buffer_ram7 + logic [7:0] history_buffer_ram7_data[2]; + logic [12:0] history_buffer_ram7_addr[2]; + logic history_buffer_ram7_wr_en[2]; + logic history_buffer_ram7_rd_en[2]; + logic [7:0] history_buffer_ram7_rd_data[2]; + + ram_2rw #( + .DATA_WIDTH(8), + .SIZE(8192), + .ADDR_WIDTH(13) + ) history_buffer_ram7_ram ( + .clk(clk), + .rst(rst), + .data_0(history_buffer_ram7_data[0]), + .addr_0(history_buffer_ram7_addr[0]), + .wr_en_0(history_buffer_ram7_wr_en[0]), + .rd_en_0(history_buffer_ram7_rd_en[0]), + .rd_data_0(history_buffer_ram7_rd_data[0]), + .data_1(history_buffer_ram7_data[1]), + .addr_1(history_buffer_ram7_addr[1]), + .wr_en_1(history_buffer_ram7_wr_en[1]), + .rd_en_1(history_buffer_ram7_rd_en[1]), + .rd_data_1(history_buffer_ram7_rd_data[1]) + ); + + // RAM instance for dpd_ram + logic [15:0] dpd_ram_wr_data; + logic [7:0] dpd_ram_wr_addr; + logic dpd_ram_wr_en; + logic dpd_ram_wr_mask; + logic [15:0] dpd_ram_rd_data; + logic [7:0] dpd_ram_rd_addr; + logic dpd_ram_rd_en; + logic dpd_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(16), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(8) + ) dpd_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(dpd_ram_wr_data), + .wr_addr(dpd_ram_wr_addr), + .wr_en(dpd_ram_wr_en), + .wr_mask(dpd_ram_wr_mask), + .rd_data(dpd_ram_rd_data), + .rd_addr(dpd_ram_rd_addr), + .rd_en(dpd_ram_rd_en), + .rd_mask(dpd_ram_rd_mask) + ); + + // RAM instance for fse_tmp_ram + logic [15:0] fse_tmp_ram_wr_data; + logic [7:0] fse_tmp_ram_wr_addr; + logic fse_tmp_ram_wr_en; + logic fse_tmp_ram_wr_mask; + logic [15:0] fse_tmp_ram_rd_data; + logic [7:0] fse_tmp_ram_rd_addr; + logic fse_tmp_ram_rd_en; + logic fse_tmp_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(16), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(8) + ) fse_tmp_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(fse_tmp_ram_wr_data), + .wr_addr(fse_tmp_ram_wr_addr), + .wr_en(fse_tmp_ram_wr_en), + .wr_mask(fse_tmp_ram_wr_mask), + .rd_data(fse_tmp_ram_rd_data), + .rd_addr(fse_tmp_ram_rd_addr), + .rd_en(fse_tmp_ram_rd_en), + .rd_mask(fse_tmp_ram_rd_mask) + ); + + // RAM instance for fse_tmp2_ram + logic [7:0] fse_tmp2_ram_wr_data; + logic [8:0] fse_tmp2_ram_wr_addr; + logic fse_tmp2_ram_wr_en; + logic fse_tmp2_ram_wr_mask; + logic [7:0] fse_tmp2_ram_rd_data; + logic [8:0] fse_tmp2_ram_rd_addr; + logic fse_tmp2_ram_rd_en; + logic fse_tmp2_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(8), + .SIZE(512), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(9) + ) fse_tmp2_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(fse_tmp2_ram_wr_data), + .wr_addr(fse_tmp2_ram_wr_addr), + .wr_en(fse_tmp2_ram_wr_en), + .wr_mask(fse_tmp2_ram_wr_mask), + .rd_data(fse_tmp2_ram_rd_data), + .rd_addr(fse_tmp2_ram_rd_addr), + .rd_en(fse_tmp2_ram_rd_en), + .rd_mask(fse_tmp2_ram_rd_mask) + ); + + // RAM instance for ll_def_fse_ram + logic [31:0] ll_def_fse_ram_wr_data; + logic [14:0] ll_def_fse_ram_wr_addr; + logic ll_def_fse_ram_wr_en; + logic ll_def_fse_ram_wr_mask; + logic [31:0] ll_def_fse_ram_rd_data; + logic [14:0] ll_def_fse_ram_rd_addr; + logic ll_def_fse_ram_rd_en; + logic ll_def_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15), + .INIT_FILE("../xls/modules/zstd/zstd_dec_ll_fse_default.mem") + ) ll_def_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(ll_def_fse_ram_wr_data), + .wr_addr(ll_def_fse_ram_wr_addr), + .wr_en(ll_def_fse_ram_wr_en), + .wr_mask(ll_def_fse_ram_wr_mask), + .rd_data(ll_def_fse_ram_rd_data), + .rd_addr(ll_def_fse_ram_rd_addr), + .rd_en(ll_def_fse_ram_rd_en), + .rd_mask(ll_def_fse_ram_rd_mask) + ); + + // RAM instance for ll_fse_ram + logic [31:0] ll_fse_ram_wr_data; + logic [14:0] ll_fse_ram_wr_addr; + logic ll_fse_ram_wr_en; + logic ll_fse_ram_wr_mask; + logic [31:0] ll_fse_ram_rd_data; + logic [14:0] ll_fse_ram_rd_addr; + logic ll_fse_ram_rd_en; + logic ll_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(32768), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15) + ) ll_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(ll_fse_ram_wr_data), + .wr_addr(ll_fse_ram_wr_addr), + .wr_en(ll_fse_ram_wr_en), + .wr_mask(ll_fse_ram_wr_mask), + .rd_data(ll_fse_ram_rd_data), + .rd_addr(ll_fse_ram_rd_addr), + .rd_en(ll_fse_ram_rd_en), + .rd_mask(ll_fse_ram_rd_mask) + ); + + // RAM instance for ml_def_fse_ram + logic [31:0] ml_def_fse_ram_wr_data; + logic [14:0] ml_def_fse_ram_wr_addr; + logic ml_def_fse_ram_wr_en; + logic ml_def_fse_ram_wr_mask; + logic [31:0] ml_def_fse_ram_rd_data; + logic [14:0] ml_def_fse_ram_rd_addr; + logic ml_def_fse_ram_rd_en; + logic ml_def_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15), + .INIT_FILE("../xls/modules/zstd/zstd_dec_ml_fse_default.mem") + ) ml_def_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(ml_def_fse_ram_wr_data), + .wr_addr(ml_def_fse_ram_wr_addr), + .wr_en(ml_def_fse_ram_wr_en), + .wr_mask(ml_def_fse_ram_wr_mask), + .rd_data(ml_def_fse_ram_rd_data), + .rd_addr(ml_def_fse_ram_rd_addr), + .rd_en(ml_def_fse_ram_rd_en), + .rd_mask(ml_def_fse_ram_rd_mask) + ); + + // RAM instance for ml_fse_ram + logic [31:0] ml_fse_ram_wr_data; + logic [14:0] ml_fse_ram_wr_addr; + logic ml_fse_ram_wr_en; + logic ml_fse_ram_wr_mask; + logic [31:0] ml_fse_ram_rd_data; + logic [14:0] ml_fse_ram_rd_addr; + logic ml_fse_ram_rd_en; + logic ml_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(32768), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15) + ) ml_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(ml_fse_ram_wr_data), + .wr_addr(ml_fse_ram_wr_addr), + .wr_en(ml_fse_ram_wr_en), + .wr_mask(ml_fse_ram_wr_mask), + .rd_data(ml_fse_ram_rd_data), + .rd_addr(ml_fse_ram_rd_addr), + .rd_en(ml_fse_ram_rd_en), + .rd_mask(ml_fse_ram_rd_mask) + ); + + // RAM instance for of_def_fse_ram + logic [31:0] of_def_fse_ram_wr_data; + logic [14:0] of_def_fse_ram_wr_addr; + logic of_def_fse_ram_wr_en; + logic of_def_fse_ram_wr_mask; + logic [31:0] of_def_fse_ram_rd_data; + logic [14:0] of_def_fse_ram_rd_addr; + logic of_def_fse_ram_rd_en; + logic of_def_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15), + .INIT_FILE("../xls/modules/zstd/zstd_dec_of_fse_default.mem") + ) of_def_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(of_def_fse_ram_wr_data), + .wr_addr(of_def_fse_ram_wr_addr), + .wr_en(of_def_fse_ram_wr_en), + .wr_mask(of_def_fse_ram_wr_mask), + .rd_data(of_def_fse_ram_rd_data), + .rd_addr(of_def_fse_ram_rd_addr), + .rd_en(of_def_fse_ram_rd_en), + .rd_mask(of_def_fse_ram_rd_mask) + ); + + // RAM instance for of_fse_ram + logic [31:0] of_fse_ram_wr_data; + logic [14:0] of_fse_ram_wr_addr; + logic of_fse_ram_wr_en; + logic of_fse_ram_wr_mask; + logic [31:0] of_fse_ram_rd_data; + logic [14:0] of_fse_ram_rd_addr; + logic of_fse_ram_rd_en; + logic of_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(32768), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(15) + ) of_fse_ram ( + .clk(clk), + .rst(rst), + .wr_data(of_fse_ram_wr_data), + .wr_addr(of_fse_ram_wr_addr), + .wr_en(of_fse_ram_wr_en), + .wr_mask(of_fse_ram_wr_mask), + .rd_data(of_fse_ram_rd_data), + .rd_addr(of_fse_ram_rd_addr), + .rd_en(of_fse_ram_rd_en), + .rd_mask(of_fse_ram_rd_mask) + ); + + // RAM instance for huffman_literals_prescan_ram + logic [91:0] huffman_literals_prescan_ram_wr_data; + logic [5:0] huffman_literals_prescan_ram_wr_addr; + logic huffman_literals_prescan_ram_wr_en; + logic huffman_literals_prescan_ram_wr_mask; + logic [91:0] huffman_literals_prescan_ram_rd_data; + logic [5:0] huffman_literals_prescan_ram_rd_addr; + logic huffman_literals_prescan_ram_rd_en; + logic huffman_literals_prescan_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(92), + .SIZE(64), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(6) + ) huffman_literals_prescan_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_prescan_ram_wr_data), + .wr_addr(huffman_literals_prescan_ram_wr_addr), + .wr_en(huffman_literals_prescan_ram_wr_en), + .wr_mask(huffman_literals_prescan_ram_wr_mask), + .rd_data(huffman_literals_prescan_ram_rd_data), + .rd_addr(huffman_literals_prescan_ram_rd_addr), + .rd_en(huffman_literals_prescan_ram_rd_en), + .rd_mask(huffman_literals_prescan_ram_rd_mask) + ); + + // RAM instance for huffman_literals_weights_mem_ram + logic [31:0] huffman_literals_weights_mem_ram_wr_data; + logic [5:0] huffman_literals_weights_mem_ram_wr_addr; + logic huffman_literals_weights_mem_ram_wr_en; + logic [7:0] huffman_literals_weights_mem_ram_wr_mask; + logic [31:0] huffman_literals_weights_mem_ram_rd_data; + logic [5:0] huffman_literals_weights_mem_ram_rd_addr; + logic huffman_literals_weights_mem_ram_rd_en; + logic [7:0] huffman_literals_weights_mem_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(64), + .NUM_PARTITIONS(8), + .ADDR_WIDTH(6) + ) huffman_literals_weights_mem_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_weights_mem_ram_wr_data), + .wr_addr(huffman_literals_weights_mem_ram_wr_addr), + .wr_en(huffman_literals_weights_mem_ram_wr_en), + .wr_mask(huffman_literals_weights_mem_ram_wr_mask), + .rd_data(huffman_literals_weights_mem_ram_rd_data), + .rd_addr(huffman_literals_weights_mem_ram_rd_addr), + .rd_en(huffman_literals_weights_mem_ram_rd_en), + .rd_mask(huffman_literals_weights_mem_ram_rd_mask) + ); + + // RAM instance for literals_buffer_ram0 + logic [8:0] literals_buffer_ram0_wr_data; + logic [12:0] literals_buffer_ram0_wr_addr; + logic literals_buffer_ram0_wr_en; + logic literals_buffer_ram0_wr_mask; + logic [8:0] literals_buffer_ram0_rd_data; + logic [12:0] literals_buffer_ram0_rd_addr; + logic literals_buffer_ram0_rd_en; + logic literals_buffer_ram0_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram0_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram0_wr_data), + .wr_addr(literals_buffer_ram0_wr_addr), + .wr_en(literals_buffer_ram0_wr_en), + .wr_mask(literals_buffer_ram0_wr_mask), + .rd_data(literals_buffer_ram0_rd_data), + .rd_addr(literals_buffer_ram0_rd_addr), + .rd_en(literals_buffer_ram0_rd_en), + .rd_mask(literals_buffer_ram0_rd_mask) + ); + + // RAM instance for literals_buffer_ram1 + logic [8:0] literals_buffer_ram1_wr_data; + logic [12:0] literals_buffer_ram1_wr_addr; + logic literals_buffer_ram1_wr_en; + logic literals_buffer_ram1_wr_mask; + logic [8:0] literals_buffer_ram1_rd_data; + logic [12:0] literals_buffer_ram1_rd_addr; + logic literals_buffer_ram1_rd_en; + logic literals_buffer_ram1_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram1_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram1_wr_data), + .wr_addr(literals_buffer_ram1_wr_addr), + .wr_en(literals_buffer_ram1_wr_en), + .wr_mask(literals_buffer_ram1_wr_mask), + .rd_data(literals_buffer_ram1_rd_data), + .rd_addr(literals_buffer_ram1_rd_addr), + .rd_en(literals_buffer_ram1_rd_en), + .rd_mask(literals_buffer_ram1_rd_mask) + ); + + // RAM instance for literals_buffer_ram2 + logic [8:0] literals_buffer_ram2_wr_data; + logic [12:0] literals_buffer_ram2_wr_addr; + logic literals_buffer_ram2_wr_en; + logic literals_buffer_ram2_wr_mask; + logic [8:0] literals_buffer_ram2_rd_data; + logic [12:0] literals_buffer_ram2_rd_addr; + logic literals_buffer_ram2_rd_en; + logic literals_buffer_ram2_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram2_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram2_wr_data), + .wr_addr(literals_buffer_ram2_wr_addr), + .wr_en(literals_buffer_ram2_wr_en), + .wr_mask(literals_buffer_ram2_wr_mask), + .rd_data(literals_buffer_ram2_rd_data), + .rd_addr(literals_buffer_ram2_rd_addr), + .rd_en(literals_buffer_ram2_rd_en), + .rd_mask(literals_buffer_ram2_rd_mask) + ); + + // RAM instance for literals_buffer_ram3 + logic [8:0] literals_buffer_ram3_wr_data; + logic [12:0] literals_buffer_ram3_wr_addr; + logic literals_buffer_ram3_wr_en; + logic literals_buffer_ram3_wr_mask; + logic [8:0] literals_buffer_ram3_rd_data; + logic [12:0] literals_buffer_ram3_rd_addr; + logic literals_buffer_ram3_rd_en; + logic literals_buffer_ram3_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram3_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram3_wr_data), + .wr_addr(literals_buffer_ram3_wr_addr), + .wr_en(literals_buffer_ram3_wr_en), + .wr_mask(literals_buffer_ram3_wr_mask), + .rd_data(literals_buffer_ram3_rd_data), + .rd_addr(literals_buffer_ram3_rd_addr), + .rd_en(literals_buffer_ram3_rd_en), + .rd_mask(literals_buffer_ram3_rd_mask) + ); + + // RAM instance for literals_buffer_ram4 + logic [8:0] literals_buffer_ram4_wr_data; + logic [12:0] literals_buffer_ram4_wr_addr; + logic literals_buffer_ram4_wr_en; + logic literals_buffer_ram4_wr_mask; + logic [8:0] literals_buffer_ram4_rd_data; + logic [12:0] literals_buffer_ram4_rd_addr; + logic literals_buffer_ram4_rd_en; + logic literals_buffer_ram4_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram4_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram4_wr_data), + .wr_addr(literals_buffer_ram4_wr_addr), + .wr_en(literals_buffer_ram4_wr_en), + .wr_mask(literals_buffer_ram4_wr_mask), + .rd_data(literals_buffer_ram4_rd_data), + .rd_addr(literals_buffer_ram4_rd_addr), + .rd_en(literals_buffer_ram4_rd_en), + .rd_mask(literals_buffer_ram4_rd_mask) + ); + + // RAM instance for literals_buffer_ram5 + logic [8:0] literals_buffer_ram5_wr_data; + logic [12:0] literals_buffer_ram5_wr_addr; + logic literals_buffer_ram5_wr_en; + logic literals_buffer_ram5_wr_mask; + logic [8:0] literals_buffer_ram5_rd_data; + logic [12:0] literals_buffer_ram5_rd_addr; + logic literals_buffer_ram5_rd_en; + logic literals_buffer_ram5_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram5_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram5_wr_data), + .wr_addr(literals_buffer_ram5_wr_addr), + .wr_en(literals_buffer_ram5_wr_en), + .wr_mask(literals_buffer_ram5_wr_mask), + .rd_data(literals_buffer_ram5_rd_data), + .rd_addr(literals_buffer_ram5_rd_addr), + .rd_en(literals_buffer_ram5_rd_en), + .rd_mask(literals_buffer_ram5_rd_mask) + ); + + // RAM instance for literals_buffer_ram6 + logic [8:0] literals_buffer_ram6_wr_data; + logic [12:0] literals_buffer_ram6_wr_addr; + logic literals_buffer_ram6_wr_en; + logic literals_buffer_ram6_wr_mask; + logic [8:0] literals_buffer_ram6_rd_data; + logic [12:0] literals_buffer_ram6_rd_addr; + logic literals_buffer_ram6_rd_en; + logic literals_buffer_ram6_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram6_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram6_wr_data), + .wr_addr(literals_buffer_ram6_wr_addr), + .wr_en(literals_buffer_ram6_wr_en), + .wr_mask(literals_buffer_ram6_wr_mask), + .rd_data(literals_buffer_ram6_rd_data), + .rd_addr(literals_buffer_ram6_rd_addr), + .rd_en(literals_buffer_ram6_rd_en), + .rd_mask(literals_buffer_ram6_rd_mask) + ); + + // RAM instance for literals_buffer_ram7 + logic [8:0] literals_buffer_ram7_wr_data; + logic [12:0] literals_buffer_ram7_wr_addr; + logic literals_buffer_ram7_wr_en; + logic literals_buffer_ram7_wr_mask; + logic [8:0] literals_buffer_ram7_rd_data; + logic [12:0] literals_buffer_ram7_rd_addr; + logic literals_buffer_ram7_rd_en; + logic literals_buffer_ram7_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(9), + .SIZE(8192), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(13) + ) literals_buffer_ram7_ram ( + .clk(clk), + .rst(rst), + .wr_data(literals_buffer_ram7_wr_data), + .wr_addr(literals_buffer_ram7_wr_addr), + .wr_en(literals_buffer_ram7_wr_en), + .wr_mask(literals_buffer_ram7_wr_mask), + .rd_data(literals_buffer_ram7_rd_data), + .rd_addr(literals_buffer_ram7_rd_addr), + .rd_en(literals_buffer_ram7_rd_en), + .rd_mask(literals_buffer_ram7_rd_mask) + ); + + // RAM instance for huffman_literals_weights_dpd_ram + logic [15:0] huffman_literals_weights_dpd_ram_wr_data; + logic [7:0] huffman_literals_weights_dpd_ram_wr_addr; + logic huffman_literals_weights_dpd_ram_wr_en; + logic huffman_literals_weights_dpd_ram_wr_mask; + logic [15:0] huffman_literals_weights_dpd_ram_rd_data; + logic [7:0] huffman_literals_weights_dpd_ram_rd_addr; + logic huffman_literals_weights_dpd_ram_rd_en; + logic huffman_literals_weights_dpd_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(16), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(8) + ) huffman_literals_weights_dpd_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_weights_dpd_ram_wr_data), + .wr_addr(huffman_literals_weights_dpd_ram_wr_addr), + .wr_en(huffman_literals_weights_dpd_ram_wr_en), + .wr_mask(huffman_literals_weights_dpd_ram_wr_mask), + .rd_data(huffman_literals_weights_dpd_ram_rd_data), + .rd_addr(huffman_literals_weights_dpd_ram_rd_addr), + .rd_en(huffman_literals_weights_dpd_ram_rd_en), + .rd_mask(huffman_literals_weights_dpd_ram_rd_mask) + ); + + // RAM instance for huffman_literals_weights_tmp_ram + logic [15:0] huffman_literals_weights_tmp_ram_wr_data; + logic [7:0] huffman_literals_weights_tmp_ram_wr_addr; + logic huffman_literals_weights_tmp_ram_wr_en; + logic huffman_literals_weights_tmp_ram_wr_mask; + logic [15:0] huffman_literals_weights_tmp_ram_rd_data; + logic [7:0] huffman_literals_weights_tmp_ram_rd_addr; + logic huffman_literals_weights_tmp_ram_rd_en; + logic huffman_literals_weights_tmp_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(16), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(8) + ) huffman_literals_weights_tmp_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_weights_tmp_ram_wr_data), + .wr_addr(huffman_literals_weights_tmp_ram_wr_addr), + .wr_en(huffman_literals_weights_tmp_ram_wr_en), + .wr_mask(huffman_literals_weights_tmp_ram_wr_mask), + .rd_data(huffman_literals_weights_tmp_ram_rd_data), + .rd_addr(huffman_literals_weights_tmp_ram_rd_addr), + .rd_en(huffman_literals_weights_tmp_ram_rd_en), + .rd_mask(huffman_literals_weights_tmp_ram_rd_mask) + ); + + // RAM instance for huffman_literals_weights_tmp2_ram + logic [7:0] huffman_literals_weights_tmp2_ram_wr_data; + logic [8:0] huffman_literals_weights_tmp2_ram_wr_addr; + logic huffman_literals_weights_tmp2_ram_wr_en; + logic huffman_literals_weights_tmp2_ram_wr_mask; + logic [7:0] huffman_literals_weights_tmp2_ram_rd_data; + logic [8:0] huffman_literals_weights_tmp2_ram_rd_addr; + logic huffman_literals_weights_tmp2_ram_rd_en; + logic huffman_literals_weights_tmp2_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(8), + .SIZE(512), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(9) + ) huffman_literals_weights_tmp2_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_weights_tmp2_ram_wr_data), + .wr_addr(huffman_literals_weights_tmp2_ram_wr_addr), + .wr_en(huffman_literals_weights_tmp2_ram_wr_en), + .wr_mask(huffman_literals_weights_tmp2_ram_wr_mask), + .rd_data(huffman_literals_weights_tmp2_ram_rd_data), + .rd_addr(huffman_literals_weights_tmp2_ram_rd_addr), + .rd_en(huffman_literals_weights_tmp2_ram_rd_en), + .rd_mask(huffman_literals_weights_tmp2_ram_rd_mask) + ); + + // RAM instance for huffman_literals_weights_fse_ram + logic [31:0] huffman_literals_weights_fse_ram_wr_data; + logic [7:0] huffman_literals_weights_fse_ram_wr_addr; + logic huffman_literals_weights_fse_ram_wr_en; + logic huffman_literals_weights_fse_ram_wr_mask; + logic [31:0] huffman_literals_weights_fse_ram_rd_data; + logic [7:0] huffman_literals_weights_fse_ram_rd_addr; + logic huffman_literals_weights_fse_ram_rd_en; + logic huffman_literals_weights_fse_ram_rd_mask; + + ram_1r1w #( + .DATA_WIDTH(32), + .SIZE(256), + .NUM_PARTITIONS(1), + .ADDR_WIDTH(8) + ) huffman_literals_weights_fse_ram_ram ( + .clk(clk), + .rst(rst), + .wr_data(huffman_literals_weights_fse_ram_wr_data), + .wr_addr(huffman_literals_weights_fse_ram_wr_addr), + .wr_en(huffman_literals_weights_fse_ram_wr_en), + .wr_mask(huffman_literals_weights_fse_ram_wr_mask), + .rd_data(huffman_literals_weights_fse_ram_rd_data), + .rd_addr(huffman_literals_weights_fse_ram_rd_addr), + .rd_en(huffman_literals_weights_fse_ram_rd_en), + .rd_mask(huffman_literals_weights_fse_ram_rd_mask) + ); + /* * ZSTD Decoder instance */ + + ZstdDecoder ZstdDecoder ( - .clk(clk), - .rst(rst), + .clk(clk), + .rst(rst), - // CSR Interface - .zstd_dec__csr_axi_aw_r(zstd_dec__csr_axi_aw), - .zstd_dec__csr_axi_aw_r_vld(zstd_dec__csr_axi_aw_vld), - .zstd_dec__csr_axi_aw_r_rdy(zstd_dec__csr_axi_aw_rdy), - .zstd_dec__csr_axi_w_r(zstd_dec__csr_axi_w), - .zstd_dec__csr_axi_w_r_vld(zstd_dec__csr_axi_w_vld), - .zstd_dec__csr_axi_w_r_rdy(zstd_dec__csr_axi_w_rdy), - .zstd_dec__csr_axi_b_s(zstd_dec__csr_axi_b), - .zstd_dec__csr_axi_b_s_vld(zstd_dec__csr_axi_b_vld), - .zstd_dec__csr_axi_b_s_rdy(zstd_dec__csr_axi_b_rdy), - .zstd_dec__csr_axi_ar_r(zstd_dec__csr_axi_ar), - .zstd_dec__csr_axi_ar_r_vld(zstd_dec__csr_axi_ar_vld), - .zstd_dec__csr_axi_ar_r_rdy(zstd_dec__csr_axi_ar_rdy), - .zstd_dec__csr_axi_r_s(zstd_dec__csr_axi_r), - .zstd_dec__csr_axi_r_s_vld(zstd_dec__csr_axi_r_vld), - .zstd_dec__csr_axi_r_s_rdy(zstd_dec__csr_axi_r_rdy), + .zstd_dec__axi_ram_ar_s__0_data(zstd_dec__axi_ram_ar_s__0), + .zstd_dec__axi_ram_ar_s__0_vld(zstd_dec__axi_ram_ar_s__0_vld), + .zstd_dec__axi_ram_ar_s__0_rdy(zstd_dec__axi_ram_ar_s__0_rdy), + .zstd_dec__axi_ram_r_r__0_data(zstd_dec__axi_ram_r_r__0), + .zstd_dec__axi_ram_r_r__0_vld(zstd_dec__axi_ram_r_r__0_vld), + .zstd_dec__axi_ram_r_r__0_rdy(zstd_dec__axi_ram_r_r__0_rdy), - // FrameHeaderDecoder - .zstd_dec__fh_axi_ar_s(zstd_dec__fh_axi_ar), - .zstd_dec__fh_axi_ar_s_vld(zstd_dec__fh_axi_ar_vld), - .zstd_dec__fh_axi_ar_s_rdy(zstd_dec__fh_axi_ar_rdy), - .zstd_dec__fh_axi_r_r(zstd_dec__fh_axi_r), - .zstd_dec__fh_axi_r_r_vld(zstd_dec__fh_axi_r_vld), - .zstd_dec__fh_axi_r_r_rdy(zstd_dec__fh_axi_r_rdy), + .zstd_dec__axi_ram_ar_s__1_data(zstd_dec__axi_ram_ar_s__1), + .zstd_dec__axi_ram_ar_s__1_vld(zstd_dec__axi_ram_ar_s__1_vld), + .zstd_dec__axi_ram_ar_s__1_rdy(zstd_dec__axi_ram_ar_s__1_rdy), + .zstd_dec__axi_ram_r_r__1_data(zstd_dec__axi_ram_r_r__1), + .zstd_dec__axi_ram_r_r__1_vld(zstd_dec__axi_ram_r_r__1_vld), + .zstd_dec__axi_ram_r_r__1_rdy(zstd_dec__axi_ram_r_r__1_rdy), - // BlockHeaderDecoder - .zstd_dec__bh_axi_ar_s(zstd_dec__bh_axi_ar), - .zstd_dec__bh_axi_ar_s_vld(zstd_dec__bh_axi_ar_vld), - .zstd_dec__bh_axi_ar_s_rdy(zstd_dec__bh_axi_ar_rdy), - .zstd_dec__bh_axi_r_r(zstd_dec__bh_axi_r), - .zstd_dec__bh_axi_r_r_vld(zstd_dec__bh_axi_r_vld), - .zstd_dec__bh_axi_r_r_rdy(zstd_dec__bh_axi_r_rdy), + .zstd_dec__axi_ram_ar_s__2_data(zstd_dec__axi_ram_ar_s__2), + .zstd_dec__axi_ram_ar_s__2_vld(zstd_dec__axi_ram_ar_s__2_vld), + .zstd_dec__axi_ram_ar_s__2_rdy(zstd_dec__axi_ram_ar_s__2_rdy), + .zstd_dec__axi_ram_r_r__2_data(zstd_dec__axi_ram_r_r__2), + .zstd_dec__axi_ram_r_r__2_vld(zstd_dec__axi_ram_r_r__2_vld), + .zstd_dec__axi_ram_r_r__2_rdy(zstd_dec__axi_ram_r_r__2_rdy), - // RawBlockDecoder - .zstd_dec__raw_axi_ar_s(zstd_dec__raw_axi_ar), - .zstd_dec__raw_axi_ar_s_vld(zstd_dec__raw_axi_ar_vld), - .zstd_dec__raw_axi_ar_s_rdy(zstd_dec__raw_axi_ar_rdy), - .zstd_dec__raw_axi_r_r(zstd_dec__raw_axi_r), - .zstd_dec__raw_axi_r_r_vld(zstd_dec__raw_axi_r_vld), - .zstd_dec__raw_axi_r_r_rdy(zstd_dec__raw_axi_r_rdy), - - // Output Writer - .zstd_dec__output_axi_aw_s(zstd_dec__output_axi_aw), - .zstd_dec__output_axi_aw_s_vld(zstd_dec__output_axi_aw_vld), - .zstd_dec__output_axi_aw_s_rdy(zstd_dec__output_axi_aw_rdy), - .zstd_dec__output_axi_w_s(zstd_dec__output_axi_w), - .zstd_dec__output_axi_w_s_vld(zstd_dec__output_axi_w_vld), - .zstd_dec__output_axi_w_s_rdy(zstd_dec__output_axi_w_rdy), - .zstd_dec__output_axi_b_r(zstd_dec__output_axi_b), - .zstd_dec__output_axi_b_r_vld(zstd_dec__output_axi_b_vld), - .zstd_dec__output_axi_b_r_rdy(zstd_dec__output_axi_b_rdy), - - // Other ports - .zstd_dec__notify_s_vld(notify_vld), - .zstd_dec__notify_s_rdy(notify_rdy) + .zstd_dec__axi_ram_ar_s__3_data(zstd_dec__axi_ram_ar_s__3), + .zstd_dec__axi_ram_ar_s__3_vld(zstd_dec__axi_ram_ar_s__3_vld), + .zstd_dec__axi_ram_ar_s__3_rdy(zstd_dec__axi_ram_ar_s__3_rdy), + .zstd_dec__axi_ram_r_r__3_data(zstd_dec__axi_ram_r_r__3), + .zstd_dec__axi_ram_r_r__3_vld(zstd_dec__axi_ram_r_r__3_vld), + .zstd_dec__axi_ram_r_r__3_rdy(zstd_dec__axi_ram_r_r__3_rdy), + + .zstd_dec__axi_ram_ar_s__4_data(zstd_dec__axi_ram_ar_s__4), + .zstd_dec__axi_ram_ar_s__4_vld(zstd_dec__axi_ram_ar_s__4_vld), + .zstd_dec__axi_ram_ar_s__4_rdy(zstd_dec__axi_ram_ar_s__4_rdy), + .zstd_dec__axi_ram_r_r__4_data(zstd_dec__axi_ram_r_r__4), + .zstd_dec__axi_ram_r_r__4_vld(zstd_dec__axi_ram_r_r__4_vld), + .zstd_dec__axi_ram_r_r__4_rdy(zstd_dec__axi_ram_r_r__4_rdy), + + .zstd_dec__axi_ram_ar_s__5_data(zstd_dec__axi_ram_ar_s__5), + .zstd_dec__axi_ram_ar_s__5_vld(zstd_dec__axi_ram_ar_s__5_vld), + .zstd_dec__axi_ram_ar_s__5_rdy(zstd_dec__axi_ram_ar_s__5_rdy), + .zstd_dec__axi_ram_r_r__5_data(zstd_dec__axi_ram_r_r__5), + .zstd_dec__axi_ram_r_r__5_vld(zstd_dec__axi_ram_r_r__5_vld), + .zstd_dec__axi_ram_r_r__5_rdy(zstd_dec__axi_ram_r_r__5_rdy), + + .zstd_dec__axi_ram_ar_s__6_data(zstd_dec__axi_ram_ar_s__6), + .zstd_dec__axi_ram_ar_s__6_vld(zstd_dec__axi_ram_ar_s__6_vld), + .zstd_dec__axi_ram_ar_s__6_rdy(zstd_dec__axi_ram_ar_s__6_rdy), + .zstd_dec__axi_ram_r_r__6_data(zstd_dec__axi_ram_r_r__6), + .zstd_dec__axi_ram_r_r__6_vld(zstd_dec__axi_ram_r_r__6_vld), + .zstd_dec__axi_ram_r_r__6_rdy(zstd_dec__axi_ram_r_r__6_rdy), + + .zstd_dec__axi_ram_ar_s__7_data(zstd_dec__axi_ram_ar_s__7), + .zstd_dec__axi_ram_ar_s__7_vld(zstd_dec__axi_ram_ar_s__7_vld), + .zstd_dec__axi_ram_ar_s__7_rdy(zstd_dec__axi_ram_ar_s__7_rdy), + .zstd_dec__axi_ram_r_r__7_data(zstd_dec__axi_ram_r_r__7), + .zstd_dec__axi_ram_r_r__7_vld(zstd_dec__axi_ram_r_r__7_vld), + .zstd_dec__axi_ram_r_r__7_rdy(zstd_dec__axi_ram_r_r__7_rdy), + + .zstd_dec__axi_ram_ar_s__8_data(zstd_dec__axi_ram_ar_s__8), + .zstd_dec__axi_ram_ar_s__8_vld(zstd_dec__axi_ram_ar_s__8_vld), + .zstd_dec__axi_ram_ar_s__8_rdy(zstd_dec__axi_ram_ar_s__8_rdy), + .zstd_dec__axi_ram_r_r__8_data(zstd_dec__axi_ram_r_r__8), + .zstd_dec__axi_ram_r_r__8_vld(zstd_dec__axi_ram_r_r__8_vld), + .zstd_dec__axi_ram_r_r__8_rdy(zstd_dec__axi_ram_r_r__8_rdy), + + .zstd_dec__axi_ram_ar_s__9_data(zstd_dec__axi_ram_ar_s__9), + .zstd_dec__axi_ram_ar_s__9_vld(zstd_dec__axi_ram_ar_s__9_vld), + .zstd_dec__axi_ram_ar_s__9_rdy(zstd_dec__axi_ram_ar_s__9_rdy), + .zstd_dec__axi_ram_r_r__9_data(zstd_dec__axi_ram_r_r__9), + .zstd_dec__axi_ram_r_r__9_vld(zstd_dec__axi_ram_r_r__9_vld), + .zstd_dec__axi_ram_r_r__9_rdy(zstd_dec__axi_ram_r_r__9_rdy), + + .zstd_dec__axi_ram_ar_s__10_data(zstd_dec__axi_ram_ar_s__10), + .zstd_dec__axi_ram_ar_s__10_vld(zstd_dec__axi_ram_ar_s__10_vld), + .zstd_dec__axi_ram_ar_s__10_rdy(zstd_dec__axi_ram_ar_s__10_rdy), + .zstd_dec__axi_ram_r_r__10_data(zstd_dec__axi_ram_r_r__10), + .zstd_dec__axi_ram_r_r__10_vld(zstd_dec__axi_ram_r_r__10_vld), + .zstd_dec__axi_ram_r_r__10_rdy(zstd_dec__axi_ram_r_r__10_rdy), + + // Huffman literals memories + .huffman_literals_weights_dpd_ram_rd_data(huffman_literals_weights_dpd_ram_rd_data), + .huffman_literals_weights_dpd_ram_rd_addr(huffman_literals_weights_dpd_ram_rd_addr), + .huffman_literals_weights_dpd_ram_rd_mask(huffman_literals_weights_dpd_ram_rd_mask), + .huffman_literals_weights_dpd_ram_rd_en(huffman_literals_weights_dpd_ram_rd_en), + .huffman_literals_weights_dpd_ram_wr_addr(huffman_literals_weights_dpd_ram_wr_addr), + .huffman_literals_weights_dpd_ram_wr_data(huffman_literals_weights_dpd_ram_wr_data), + .huffman_literals_weights_dpd_ram_wr_mask(huffman_literals_weights_dpd_ram_wr_mask), + .huffman_literals_weights_dpd_ram_wr_en(huffman_literals_weights_dpd_ram_wr_en), + + .huffman_literals_weights_tmp_ram_rd_data(huffman_literals_weights_tmp_ram_rd_data), + .huffman_literals_weights_tmp_ram_rd_addr(huffman_literals_weights_tmp_ram_rd_addr), + .huffman_literals_weights_tmp_ram_rd_mask(huffman_literals_weights_tmp_ram_rd_mask), + .huffman_literals_weights_tmp_ram_rd_en(huffman_literals_weights_tmp_ram_rd_en), + .huffman_literals_weights_tmp_ram_wr_addr(huffman_literals_weights_tmp_ram_wr_addr), + .huffman_literals_weights_tmp_ram_wr_data(huffman_literals_weights_tmp_ram_wr_data), + .huffman_literals_weights_tmp_ram_wr_mask(huffman_literals_weights_tmp_ram_wr_mask), + .huffman_literals_weights_tmp_ram_wr_en(huffman_literals_weights_tmp_ram_wr_en), + + .huffman_literals_weights_tmp2_ram_rd_data(huffman_literals_weights_tmp2_ram_rd_data), + .huffman_literals_weights_tmp2_ram_rd_addr(huffman_literals_weights_tmp2_ram_rd_addr), + .huffman_literals_weights_tmp2_ram_rd_mask(huffman_literals_weights_tmp2_ram_rd_mask), + .huffman_literals_weights_tmp2_ram_rd_en(huffman_literals_weights_tmp2_ram_rd_en), + .huffman_literals_weights_tmp2_ram_wr_addr(huffman_literals_weights_tmp2_ram_wr_addr), + .huffman_literals_weights_tmp2_ram_wr_data(huffman_literals_weights_tmp2_ram_wr_data), + .huffman_literals_weights_tmp2_ram_wr_mask(huffman_literals_weights_tmp2_ram_wr_mask), + .huffman_literals_weights_tmp2_ram_wr_en(huffman_literals_weights_tmp2_ram_wr_en), + + .huffman_literals_weights_fse_ram_rd_data(huffman_literals_weights_fse_ram_rd_data), + .huffman_literals_weights_fse_ram_rd_addr(huffman_literals_weights_fse_ram_rd_addr), + .huffman_literals_weights_fse_ram_rd_mask(huffman_literals_weights_fse_ram_rd_mask), + .huffman_literals_weights_fse_ram_rd_en(huffman_literals_weights_fse_ram_rd_en), + .huffman_literals_weights_fse_ram_wr_addr(huffman_literals_weights_fse_ram_wr_addr), + .huffman_literals_weights_fse_ram_wr_data(huffman_literals_weights_fse_ram_wr_data), + .huffman_literals_weights_fse_ram_wr_mask(huffman_literals_weights_fse_ram_wr_mask), + .huffman_literals_weights_fse_ram_wr_en(huffman_literals_weights_fse_ram_wr_en), + + // History buffers memories + .ram0_0_addr(history_buffer_ram0_addr[0]), + .ram0_0_wr_data(history_buffer_ram0_data[0]), + .ram0_0_we(history_buffer_ram0_wr_en[0]), + .ram0_0_re(history_buffer_ram0_rd_en[0]), + .ram0_0_rd_data(history_buffer_ram0_rd_data[0]), + .ram1_0_addr(history_buffer_ram1_addr[0]), + .ram1_0_wr_data(history_buffer_ram1_data[0]), + .ram1_0_we(history_buffer_ram1_wr_en[0]), + .ram1_0_re(history_buffer_ram1_rd_en[0]), + .ram1_0_rd_data(history_buffer_ram1_rd_data[0]), + .ram2_0_addr(history_buffer_ram2_addr[0]), + .ram2_0_wr_data(history_buffer_ram2_data[0]), + .ram2_0_we(history_buffer_ram2_wr_en[0]), + .ram2_0_re(history_buffer_ram2_rd_en[0]), + .ram2_0_rd_data(history_buffer_ram2_rd_data[0]), + .ram3_0_addr(history_buffer_ram3_addr[0]), + .ram3_0_wr_data(history_buffer_ram3_data[0]), + .ram3_0_we(history_buffer_ram3_wr_en[0]), + .ram3_0_re(history_buffer_ram3_rd_en[0]), + .ram3_0_rd_data(history_buffer_ram3_rd_data[0]), + .ram4_0_addr(history_buffer_ram4_addr[0]), + .ram4_0_wr_data(history_buffer_ram4_data[0]), + .ram4_0_we(history_buffer_ram4_wr_en[0]), + .ram4_0_re(history_buffer_ram4_rd_en[0]), + .ram4_0_rd_data(history_buffer_ram4_rd_data[0]), + .ram5_0_addr(history_buffer_ram5_addr[0]), + .ram5_0_wr_data(history_buffer_ram5_data[0]), + .ram5_0_we(history_buffer_ram5_wr_en[0]), + .ram5_0_re(history_buffer_ram5_rd_en[0]), + .ram5_0_rd_data(history_buffer_ram5_rd_data[0]), + .ram6_0_addr(history_buffer_ram6_addr[0]), + .ram6_0_wr_data(history_buffer_ram6_data[0]), + .ram6_0_we(history_buffer_ram6_wr_en[0]), + .ram6_0_re(history_buffer_ram6_rd_en[0]), + .ram6_0_rd_data(history_buffer_ram6_rd_data[0]), + .ram7_0_addr(history_buffer_ram7_addr[0]), + .ram7_0_wr_data(history_buffer_ram7_data[0]), + .ram7_0_we(history_buffer_ram7_wr_en[0]), + .ram7_0_re(history_buffer_ram7_rd_en[0]), + .ram7_0_rd_data(history_buffer_ram7_rd_data[0]), + .ram0_1_addr(history_buffer_ram0_addr[1]), + .ram0_1_wr_data(history_buffer_ram0_data[1]), + .ram0_1_we(history_buffer_ram0_wr_en[1]), + .ram0_1_re(history_buffer_ram0_rd_en[1]), + .ram0_1_rd_data(history_buffer_ram0_rd_data[1]), + .ram1_1_addr(history_buffer_ram1_addr[1]), + .ram1_1_wr_data(history_buffer_ram1_data[1]), + .ram1_1_we(history_buffer_ram1_wr_en[1]), + .ram1_1_re(history_buffer_ram1_rd_en[1]), + .ram1_1_rd_data(history_buffer_ram1_rd_data[1]), + .ram2_1_addr(history_buffer_ram2_addr[1]), + .ram2_1_wr_data(history_buffer_ram2_data[1]), + .ram2_1_we(history_buffer_ram2_wr_en[1]), + .ram2_1_re(history_buffer_ram2_rd_en[1]), + .ram2_1_rd_data(history_buffer_ram2_rd_data[1]), + .ram3_1_addr(history_buffer_ram3_addr[1]), + .ram3_1_wr_data(history_buffer_ram3_data[1]), + .ram3_1_we(history_buffer_ram3_wr_en[1]), + .ram3_1_re(history_buffer_ram3_rd_en[1]), + .ram3_1_rd_data(history_buffer_ram3_rd_data[1]), + .ram4_1_addr(history_buffer_ram4_addr[1]), + .ram4_1_wr_data(history_buffer_ram4_data[1]), + .ram4_1_we(history_buffer_ram4_wr_en[1]), + .ram4_1_re(history_buffer_ram4_rd_en[1]), + .ram4_1_rd_data(history_buffer_ram4_rd_data[1]), + .ram5_1_addr(history_buffer_ram5_addr[1]), + .ram5_1_wr_data(history_buffer_ram5_data[1]), + .ram5_1_we(history_buffer_ram5_wr_en[1]), + .ram5_1_re(history_buffer_ram5_rd_en[1]), + .ram5_1_rd_data(history_buffer_ram5_rd_data[1]), + .ram6_1_addr(history_buffer_ram6_addr[1]), + .ram6_1_wr_data(history_buffer_ram6_data[1]), + .ram6_1_we(history_buffer_ram6_wr_en[1]), + .ram6_1_re(history_buffer_ram6_rd_en[1]), + .ram6_1_rd_data(history_buffer_ram6_rd_data[1]), + .ram7_1_addr(history_buffer_ram7_addr[1]), + .ram7_1_wr_data(history_buffer_ram7_data[1]), + .ram7_1_we(history_buffer_ram7_wr_en[1]), + .ram7_1_re(history_buffer_ram7_rd_en[1]), + .ram7_1_rd_data(history_buffer_ram7_rd_data[1]), + + .dpd_ram_rd_data(dpd_ram_rd_data), + .dpd_ram_rd_addr(dpd_ram_rd_addr), + .dpd_ram_rd_mask(dpd_ram_rd_mask), + .dpd_ram_rd_en(dpd_ram_rd_en), + .dpd_ram_wr_addr(dpd_ram_wr_addr), + .dpd_ram_wr_data(dpd_ram_wr_data), + .dpd_ram_wr_mask(dpd_ram_wr_mask), + .dpd_ram_wr_en(dpd_ram_wr_en), + + .fse_tmp_ram_rd_data(fse_tmp_ram_rd_data), + .fse_tmp_ram_rd_addr(fse_tmp_ram_rd_addr), + .fse_tmp_ram_rd_mask(fse_tmp_ram_rd_mask), + .fse_tmp_ram_rd_en(fse_tmp_ram_rd_en), + .fse_tmp_ram_wr_addr(fse_tmp_ram_wr_addr), + .fse_tmp_ram_wr_data(fse_tmp_ram_wr_data), + .fse_tmp_ram_wr_mask(fse_tmp_ram_wr_mask), + .fse_tmp_ram_wr_en(fse_tmp_ram_wr_en), + + .fse_tmp2_ram_rd_data(fse_tmp2_ram_rd_data), + .fse_tmp2_ram_rd_addr(fse_tmp2_ram_rd_addr), + .fse_tmp2_ram_rd_mask(fse_tmp2_ram_rd_mask), + .fse_tmp2_ram_rd_en(fse_tmp2_ram_rd_en), + .fse_tmp2_ram_wr_addr(fse_tmp2_ram_wr_addr), + .fse_tmp2_ram_wr_data(fse_tmp2_ram_wr_data), + .fse_tmp2_ram_wr_mask(fse_tmp2_ram_wr_mask), + .fse_tmp2_ram_wr_en(fse_tmp2_ram_wr_en), + + .ll_def_fse_ram_rd_data(ll_def_fse_ram_rd_data), + .ll_def_fse_ram_rd_addr(ll_def_fse_ram_rd_addr), + .ll_def_fse_ram_rd_mask(ll_def_fse_ram_rd_mask), + .ll_def_fse_ram_rd_en(ll_def_fse_ram_rd_en), + .ll_def_fse_ram_wr_addr(ll_def_fse_ram_wr_addr), + .ll_def_fse_ram_wr_data(ll_def_fse_ram_wr_data), + .ll_def_fse_ram_wr_mask(ll_def_fse_ram_wr_mask), + .ll_def_fse_ram_wr_en(ll_def_fse_ram_wr_en), + + .ll_fse_ram_rd_data(ll_fse_ram_rd_data), + .ll_fse_ram_rd_addr(ll_fse_ram_rd_addr), + .ll_fse_ram_rd_mask(ll_fse_ram_rd_mask), + .ll_fse_ram_rd_en(ll_fse_ram_rd_en), + .ll_fse_ram_wr_addr(ll_fse_ram_wr_addr), + .ll_fse_ram_wr_data(ll_fse_ram_wr_data), + .ll_fse_ram_wr_mask(ll_fse_ram_wr_mask), + .ll_fse_ram_wr_en(ll_fse_ram_wr_en), + + .ml_def_fse_ram_rd_data(ml_def_fse_ram_rd_data), + .ml_def_fse_ram_rd_addr(ml_def_fse_ram_rd_addr), + .ml_def_fse_ram_rd_mask(ml_def_fse_ram_rd_mask), + .ml_def_fse_ram_rd_en(ml_def_fse_ram_rd_en), + .ml_def_fse_ram_wr_addr(ml_def_fse_ram_wr_addr), + .ml_def_fse_ram_wr_data(ml_def_fse_ram_wr_data), + .ml_def_fse_ram_wr_mask(ml_def_fse_ram_wr_mask), + .ml_def_fse_ram_wr_en(ml_def_fse_ram_wr_en), + + .ml_fse_ram_rd_data(ml_fse_ram_rd_data), + .ml_fse_ram_rd_addr(ml_fse_ram_rd_addr), + .ml_fse_ram_rd_mask(ml_fse_ram_rd_mask), + .ml_fse_ram_rd_en(ml_fse_ram_rd_en), + .ml_fse_ram_wr_addr(ml_fse_ram_wr_addr), + .ml_fse_ram_wr_data(ml_fse_ram_wr_data), + .ml_fse_ram_wr_mask(ml_fse_ram_wr_mask), + .ml_fse_ram_wr_en(ml_fse_ram_wr_en), + + .of_def_fse_ram_rd_data(of_def_fse_ram_rd_data), + .of_def_fse_ram_rd_addr(of_def_fse_ram_rd_addr), + .of_def_fse_ram_rd_mask(of_def_fse_ram_rd_mask), + .of_def_fse_ram_rd_en(of_def_fse_ram_rd_en), + .of_def_fse_ram_wr_addr(of_def_fse_ram_wr_addr), + .of_def_fse_ram_wr_data(of_def_fse_ram_wr_data), + .of_def_fse_ram_wr_mask(of_def_fse_ram_wr_mask), + .of_def_fse_ram_wr_en(of_def_fse_ram_wr_en), + + .of_fse_ram_rd_data(of_fse_ram_rd_data), + .of_fse_ram_rd_addr(of_fse_ram_rd_addr), + .of_fse_ram_rd_mask(of_fse_ram_rd_mask), + .of_fse_ram_rd_en(of_fse_ram_rd_en), + .of_fse_ram_wr_addr(of_fse_ram_wr_addr), + .of_fse_ram_wr_data(of_fse_ram_wr_data), + .of_fse_ram_wr_mask(of_fse_ram_wr_mask), + .of_fse_ram_wr_en(of_fse_ram_wr_en), + + .huffman_literals_prescan_ram_rd_data(huffman_literals_prescan_ram_rd_data), + .huffman_literals_prescan_ram_rd_addr(huffman_literals_prescan_ram_rd_addr), + .huffman_literals_prescan_ram_rd_mask(huffman_literals_prescan_ram_rd_mask), + .huffman_literals_prescan_ram_rd_en(huffman_literals_prescan_ram_rd_en), + .huffman_literals_prescan_ram_wr_addr(huffman_literals_prescan_ram_wr_addr), + .huffman_literals_prescan_ram_wr_data(huffman_literals_prescan_ram_wr_data), + .huffman_literals_prescan_ram_wr_mask(huffman_literals_prescan_ram_wr_mask), + .huffman_literals_prescan_ram_wr_en(huffman_literals_prescan_ram_wr_en), + + .huffman_literals_weights_mem_ram_rd_data(huffman_literals_weights_mem_ram_rd_data), + .huffman_literals_weights_mem_ram_rd_addr(huffman_literals_weights_mem_ram_rd_addr), + .huffman_literals_weights_mem_ram_rd_mask(huffman_literals_weights_mem_ram_rd_mask), + .huffman_literals_weights_mem_ram_rd_en(huffman_literals_weights_mem_ram_rd_en), + .huffman_literals_weights_mem_ram_wr_addr(huffman_literals_weights_mem_ram_wr_addr), + .huffman_literals_weights_mem_ram_wr_data(huffman_literals_weights_mem_ram_wr_data), + .huffman_literals_weights_mem_ram_wr_mask(huffman_literals_weights_mem_ram_wr_mask), + .huffman_literals_weights_mem_ram_wr_en(huffman_literals_weights_mem_ram_wr_en), + + .literals_buffer_ram0_rd_data(literals_buffer_ram0_rd_data), + .literals_buffer_ram0_rd_addr(literals_buffer_ram0_rd_addr), + .literals_buffer_ram0_rd_mask(literals_buffer_ram0_rd_mask), + .literals_buffer_ram0_rd_en(literals_buffer_ram0_rd_en), + .literals_buffer_ram0_wr_addr(literals_buffer_ram0_wr_addr), + .literals_buffer_ram0_wr_data(literals_buffer_ram0_wr_data), + .literals_buffer_ram0_wr_mask(literals_buffer_ram0_wr_mask), + .literals_buffer_ram0_wr_en(literals_buffer_ram0_wr_en), + + .literals_buffer_ram1_rd_data(literals_buffer_ram1_rd_data), + .literals_buffer_ram1_rd_addr(literals_buffer_ram1_rd_addr), + .literals_buffer_ram1_rd_mask(literals_buffer_ram1_rd_mask), + .literals_buffer_ram1_rd_en(literals_buffer_ram1_rd_en), + .literals_buffer_ram1_wr_addr(literals_buffer_ram1_wr_addr), + .literals_buffer_ram1_wr_data(literals_buffer_ram1_wr_data), + .literals_buffer_ram1_wr_mask(literals_buffer_ram1_wr_mask), + .literals_buffer_ram1_wr_en(literals_buffer_ram1_wr_en), + + .literals_buffer_ram2_rd_data(literals_buffer_ram2_rd_data), + .literals_buffer_ram2_rd_addr(literals_buffer_ram2_rd_addr), + .literals_buffer_ram2_rd_mask(literals_buffer_ram2_rd_mask), + .literals_buffer_ram2_rd_en(literals_buffer_ram2_rd_en), + .literals_buffer_ram2_wr_addr(literals_buffer_ram2_wr_addr), + .literals_buffer_ram2_wr_data(literals_buffer_ram2_wr_data), + .literals_buffer_ram2_wr_mask(literals_buffer_ram2_wr_mask), + .literals_buffer_ram2_wr_en(literals_buffer_ram2_wr_en), + + .literals_buffer_ram3_rd_data(literals_buffer_ram3_rd_data), + .literals_buffer_ram3_rd_addr(literals_buffer_ram3_rd_addr), + .literals_buffer_ram3_rd_mask(literals_buffer_ram3_rd_mask), + .literals_buffer_ram3_rd_en(literals_buffer_ram3_rd_en), + .literals_buffer_ram3_wr_addr(literals_buffer_ram3_wr_addr), + .literals_buffer_ram3_wr_data(literals_buffer_ram3_wr_data), + .literals_buffer_ram3_wr_mask(literals_buffer_ram3_wr_mask), + .literals_buffer_ram3_wr_en(literals_buffer_ram3_wr_en), + + .literals_buffer_ram4_rd_data(literals_buffer_ram4_rd_data), + .literals_buffer_ram4_rd_addr(literals_buffer_ram4_rd_addr), + .literals_buffer_ram4_rd_mask(literals_buffer_ram4_rd_mask), + .literals_buffer_ram4_rd_en(literals_buffer_ram4_rd_en), + .literals_buffer_ram4_wr_addr(literals_buffer_ram4_wr_addr), + .literals_buffer_ram4_wr_data(literals_buffer_ram4_wr_data), + .literals_buffer_ram4_wr_mask(literals_buffer_ram4_wr_mask), + .literals_buffer_ram4_wr_en(literals_buffer_ram4_wr_en), + + .literals_buffer_ram5_rd_data(literals_buffer_ram5_rd_data), + .literals_buffer_ram5_rd_addr(literals_buffer_ram5_rd_addr), + .literals_buffer_ram5_rd_mask(literals_buffer_ram5_rd_mask), + .literals_buffer_ram5_rd_en(literals_buffer_ram5_rd_en), + .literals_buffer_ram5_wr_addr(literals_buffer_ram5_wr_addr), + .literals_buffer_ram5_wr_data(literals_buffer_ram5_wr_data), + .literals_buffer_ram5_wr_mask(literals_buffer_ram5_wr_mask), + .literals_buffer_ram5_wr_en(literals_buffer_ram5_wr_en), + + .literals_buffer_ram6_rd_data(literals_buffer_ram6_rd_data), + .literals_buffer_ram6_rd_addr(literals_buffer_ram6_rd_addr), + .literals_buffer_ram6_rd_mask(literals_buffer_ram6_rd_mask), + .literals_buffer_ram6_rd_en(literals_buffer_ram6_rd_en), + .literals_buffer_ram6_wr_addr(literals_buffer_ram6_wr_addr), + .literals_buffer_ram6_wr_data(literals_buffer_ram6_wr_data), + .literals_buffer_ram6_wr_mask(literals_buffer_ram6_wr_mask), + .literals_buffer_ram6_wr_en(literals_buffer_ram6_wr_en), + + .literals_buffer_ram7_rd_data(literals_buffer_ram7_rd_data), + .literals_buffer_ram7_rd_addr(literals_buffer_ram7_rd_addr), + .literals_buffer_ram7_rd_mask(literals_buffer_ram7_rd_mask), + .literals_buffer_ram7_rd_en(literals_buffer_ram7_rd_en), + .literals_buffer_ram7_wr_addr(literals_buffer_ram7_wr_addr), + .literals_buffer_ram7_wr_data(literals_buffer_ram7_wr_data), + .literals_buffer_ram7_wr_mask(literals_buffer_ram7_wr_mask), + .literals_buffer_ram7_wr_en(literals_buffer_ram7_wr_en), + + // CSR Interface + .zstd_dec__csr_axi_aw_r_data(zstd_dec__csr_axi_aw), + .zstd_dec__csr_axi_aw_r_vld(zstd_dec__csr_axi_aw_vld), + .zstd_dec__csr_axi_aw_r_rdy(zstd_dec__csr_axi_aw_rdy), + .zstd_dec__csr_axi_w_r_data(zstd_dec__csr_axi_w), + .zstd_dec__csr_axi_w_r_vld(zstd_dec__csr_axi_w_vld), + .zstd_dec__csr_axi_w_r_rdy(zstd_dec__csr_axi_w_rdy), + .zstd_dec__csr_axi_b_s_data(zstd_dec__csr_axi_b), + .zstd_dec__csr_axi_b_s_vld(zstd_dec__csr_axi_b_vld), + .zstd_dec__csr_axi_b_s_rdy(zstd_dec__csr_axi_b_rdy), + .zstd_dec__csr_axi_ar_r_data(zstd_dec__csr_axi_ar), + .zstd_dec__csr_axi_ar_r_vld(zstd_dec__csr_axi_ar_vld), + .zstd_dec__csr_axi_ar_r_rdy(zstd_dec__csr_axi_ar_rdy), + .zstd_dec__csr_axi_r_s_data(zstd_dec__csr_axi_r), + .zstd_dec__csr_axi_r_s_vld(zstd_dec__csr_axi_r_vld), + .zstd_dec__csr_axi_r_s_rdy(zstd_dec__csr_axi_r_rdy), + + // FrameHeaderDecoder + .zstd_dec__fh_axi_ar_s_data(zstd_dec__fh_axi_ar), + .zstd_dec__fh_axi_ar_s_vld(zstd_dec__fh_axi_ar_vld), + .zstd_dec__fh_axi_ar_s_rdy(zstd_dec__fh_axi_ar_rdy), + .zstd_dec__fh_axi_r_r_data(zstd_dec__fh_axi_r), + .zstd_dec__fh_axi_r_r_vld(zstd_dec__fh_axi_r_vld), + .zstd_dec__fh_axi_r_r_rdy(zstd_dec__fh_axi_r_rdy), + + // BlockHeaderDecoder + .zstd_dec__bh_axi_ar_s_data(zstd_dec__bh_axi_ar), + .zstd_dec__bh_axi_ar_s_vld(zstd_dec__bh_axi_ar_vld), + .zstd_dec__bh_axi_ar_s_rdy(zstd_dec__bh_axi_ar_rdy), + .zstd_dec__bh_axi_r_r_data(zstd_dec__bh_axi_r), + .zstd_dec__bh_axi_r_r_vld(zstd_dec__bh_axi_r_vld), + .zstd_dec__bh_axi_r_r_rdy(zstd_dec__bh_axi_r_rdy), + + // RawBlockDecoder + .zstd_dec__raw_axi_ar_s_data(zstd_dec__raw_axi_ar), + .zstd_dec__raw_axi_ar_s_vld(zstd_dec__raw_axi_ar_vld), + .zstd_dec__raw_axi_ar_s_rdy(zstd_dec__raw_axi_ar_rdy), + .zstd_dec__raw_axi_r_r_data(zstd_dec__raw_axi_r), + .zstd_dec__raw_axi_r_r_vld(zstd_dec__raw_axi_r_vld), + .zstd_dec__raw_axi_r_r_rdy(zstd_dec__raw_axi_r_rdy), + + // Output Writer + .zstd_dec__output_axi_aw_s_data(zstd_dec__output_axi_aw), + .zstd_dec__output_axi_aw_s_vld(zstd_dec__output_axi_aw_vld), + .zstd_dec__output_axi_aw_s_rdy(zstd_dec__output_axi_aw_rdy), + .zstd_dec__output_axi_w_s_data(zstd_dec__output_axi_w), + .zstd_dec__output_axi_w_s_vld(zstd_dec__output_axi_w_vld), + .zstd_dec__output_axi_w_s_rdy(zstd_dec__output_axi_w_rdy), + .zstd_dec__output_axi_b_r_data(zstd_dec__output_axi_b), + .zstd_dec__output_axi_b_r_vld(zstd_dec__output_axi_b_vld), + .zstd_dec__output_axi_b_r_rdy(zstd_dec__output_axi_b_rdy), + + // Other ports + .zstd_dec__notify_s_vld(notify_vld), + .zstd_dec__notify_s_rdy(notify_rdy) ); assign frame_header_decoder_axi_r_rresp[2] = '0; @@ -499,6 +2278,9 @@ module zstd_dec_wrapper #( /* * AXI Interconnect */ + +// parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT), + axi_crossbar_wrapper #( .DATA_WIDTH(AXI_DATA_W), .ADDR_WIDTH(AXI_ADDR_W), @@ -531,7 +2313,7 @@ module zstd_dec_wrapper #( .s00_axi_wstrb('0), .s00_axi_wlast('0), .s00_axi_wuser('0), - .s00_axi_wvalid(), + .s00_axi_wvalid('0), .s00_axi_wready(), .s00_axi_bid(), .s00_axi_bresp(), @@ -575,7 +2357,7 @@ module zstd_dec_wrapper #( .s01_axi_wstrb('0), .s01_axi_wlast('0), .s01_axi_wuser('0), - .s01_axi_wvalid(), + .s01_axi_wvalid('0), .s01_axi_wready(), .s01_axi_bid(), .s01_axi_bresp(), @@ -619,7 +2401,7 @@ module zstd_dec_wrapper #( .s02_axi_wstrb('0), .s02_axi_wlast('0), .s02_axi_wuser('0), - .s02_axi_wvalid(), + .s02_axi_wvalid('0), .s02_axi_wready(), .s02_axi_bid(), .s02_axi_bresp(), @@ -666,7 +2448,7 @@ module zstd_dec_wrapper #( .s03_axi_wvalid(output_axi_w_wvalid), .s03_axi_wready(output_axi_w_wready), .s03_axi_bid(output_axi_b_bid), - .s03_axi_bresp(output_axi_b_bresp), + .s03_axi_bresp(output_axi_b_bresp[1:0]), .s03_axi_buser(), .s03_axi_bvalid(output_axi_b_bvalid), .s03_axi_bready(output_axi_b_bready), @@ -690,6 +2472,490 @@ module zstd_dec_wrapper #( .s03_axi_rvalid(), .s03_axi_rready('0), + // axi_ram_s__0 + .s04_axi_awid('0), + .s04_axi_awaddr('0), + .s04_axi_awlen('0), + .s04_axi_awsize('0), + .s04_axi_awburst('0), + .s04_axi_awlock('0), + .s04_axi_awcache('0), + .s04_axi_awprot('0), + .s04_axi_awqos('0), + .s04_axi_awuser('0), + .s04_axi_awvalid('0), + .s04_axi_awready(), + .s04_axi_wdata('0), + .s04_axi_wstrb('0), + .s04_axi_wlast('0), + .s04_axi_wuser('0), + .s04_axi_wvalid('0), + .s04_axi_wready(), + .s04_axi_bid(), + .s04_axi_bresp(), + .s04_axi_buser(), + .s04_axi_bvalid(), + .s04_axi_bready('0), + .s04_axi_arid(axi_ram_s__0_axi_ar_arid), + .s04_axi_araddr(axi_ram_s__0_axi_ar_araddr), + .s04_axi_arlen(axi_ram_s__0_axi_ar_arlen), + .s04_axi_arsize(axi_ram_s__0_axi_ar_arsize), + .s04_axi_arburst(axi_ram_s__0_axi_ar_arburst), + .s04_axi_arlock('0), + .s04_axi_arcache(axi_ram_s__0_axi_ar_arcache), + .s04_axi_arprot(axi_ram_s__0_axi_ar_arprot), + .s04_axi_arqos(axi_ram_s__0_axi_ar_arqos), + .s04_axi_aruser('0), + .s04_axi_arvalid(axi_ram_s__0_axi_ar_arvalid), + .s04_axi_arready(axi_ram_s__0_axi_ar_arready), + .s04_axi_rid(axi_ram_s__0_axi_r_rid), + .s04_axi_rdata(axi_ram_s__0_axi_r_rdata), + .s04_axi_rresp(axi_ram_s__0_axi_r_rresp[1:0]), + .s04_axi_rlast(axi_ram_s__0_axi_r_rlast), + .s04_axi_ruser(), + .s04_axi_rvalid(axi_ram_s__0_axi_r_rvalid), + .s04_axi_rready(axi_ram_s__0_axi_r_rready), + + // axi_ram_s__1 + .s05_axi_awid('0), + .s05_axi_awaddr('0), + .s05_axi_awlen('0), + .s05_axi_awsize('0), + .s05_axi_awburst('0), + .s05_axi_awlock('0), + .s05_axi_awcache('0), + .s05_axi_awprot('0), + .s05_axi_awqos('0), + .s05_axi_awuser('0), + .s05_axi_awvalid('0), + .s05_axi_awready(), + .s05_axi_wdata('0), + .s05_axi_wstrb('0), + .s05_axi_wlast('0), + .s05_axi_wuser('0), + .s05_axi_wvalid('0), + .s05_axi_wready(), + .s05_axi_bid(), + .s05_axi_bresp(), + .s05_axi_buser(), + .s05_axi_bvalid(), + .s05_axi_bready('0), + .s05_axi_arid(axi_ram_s__1_axi_ar_arid), + .s05_axi_araddr(axi_ram_s__1_axi_ar_araddr), + .s05_axi_arlen(axi_ram_s__1_axi_ar_arlen), + .s05_axi_arsize(axi_ram_s__1_axi_ar_arsize), + .s05_axi_arburst(axi_ram_s__1_axi_ar_arburst), + .s05_axi_arlock('0), + .s05_axi_arcache(axi_ram_s__1_axi_ar_arcache), + .s05_axi_arprot(axi_ram_s__1_axi_ar_arprot), + .s05_axi_arqos(axi_ram_s__1_axi_ar_arqos), + .s05_axi_aruser('0), + .s05_axi_arvalid(axi_ram_s__1_axi_ar_arvalid), + .s05_axi_arready(axi_ram_s__1_axi_ar_arready), + .s05_axi_rid(axi_ram_s__1_axi_r_rid), + .s05_axi_rdata(axi_ram_s__1_axi_r_rdata), + .s05_axi_rresp(axi_ram_s__1_axi_r_rresp[1:0]), + .s05_axi_rlast(axi_ram_s__1_axi_r_rlast), + .s05_axi_ruser(), + .s05_axi_rvalid(axi_ram_s__1_axi_r_rvalid), + .s05_axi_rready(axi_ram_s__1_axi_r_rready), + + // axi_ram_s__2 + .s06_axi_awid('0), + .s06_axi_awaddr('0), + .s06_axi_awlen('0), + .s06_axi_awsize('0), + .s06_axi_awburst('0), + .s06_axi_awlock('0), + .s06_axi_awcache('0), + .s06_axi_awprot('0), + .s06_axi_awqos('0), + .s06_axi_awuser('0), + .s06_axi_awvalid('0), + .s06_axi_awready(), + .s06_axi_wdata('0), + .s06_axi_wstrb('0), + .s06_axi_wlast('0), + .s06_axi_wuser('0), + .s06_axi_wvalid('0), + .s06_axi_wready(), + .s06_axi_bid(), + .s06_axi_bresp(), + .s06_axi_buser(), + .s06_axi_bvalid(), + .s06_axi_bready('0), + .s06_axi_arid(axi_ram_s__2_axi_ar_arid), + .s06_axi_araddr(axi_ram_s__2_axi_ar_araddr), + .s06_axi_arlen(axi_ram_s__2_axi_ar_arlen), + .s06_axi_arsize(axi_ram_s__2_axi_ar_arsize), + .s06_axi_arburst(axi_ram_s__2_axi_ar_arburst), + .s06_axi_arlock('0), + .s06_axi_arcache(axi_ram_s__2_axi_ar_arcache), + .s06_axi_arprot(axi_ram_s__2_axi_ar_arprot), + .s06_axi_arqos(axi_ram_s__2_axi_ar_arqos), + .s06_axi_aruser('0), + .s06_axi_arvalid(axi_ram_s__2_axi_ar_arvalid), + .s06_axi_arready(axi_ram_s__2_axi_ar_arready), + .s06_axi_rid(axi_ram_s__2_axi_r_rid), + .s06_axi_rdata(axi_ram_s__2_axi_r_rdata), + .s06_axi_rresp(axi_ram_s__2_axi_r_rresp[1:0]), + .s06_axi_rlast(axi_ram_s__2_axi_r_rlast), + .s06_axi_ruser(), + .s06_axi_rvalid(axi_ram_s__2_axi_r_rvalid), + .s06_axi_rready(axi_ram_s__2_axi_r_rready), + + // axi_ram_s__3 + .s07_axi_awid('0), + .s07_axi_awaddr('0), + .s07_axi_awlen('0), + .s07_axi_awsize('0), + .s07_axi_awburst('0), + .s07_axi_awlock('0), + .s07_axi_awcache('0), + .s07_axi_awprot('0), + .s07_axi_awqos('0), + .s07_axi_awuser('0), + .s07_axi_awvalid('0), + .s07_axi_awready(), + .s07_axi_wdata('0), + .s07_axi_wstrb('0), + .s07_axi_wlast('0), + .s07_axi_wuser('0), + .s07_axi_wvalid('0), + .s07_axi_wready(), + .s07_axi_bid(), + .s07_axi_bresp(), + .s07_axi_buser(), + .s07_axi_bvalid(), + .s07_axi_bready('0), + .s07_axi_arid(axi_ram_s__3_axi_ar_arid), + .s07_axi_araddr(axi_ram_s__3_axi_ar_araddr), + .s07_axi_arlen(axi_ram_s__3_axi_ar_arlen), + .s07_axi_arsize(axi_ram_s__3_axi_ar_arsize), + .s07_axi_arburst(axi_ram_s__3_axi_ar_arburst), + .s07_axi_arlock('0), + .s07_axi_arcache(axi_ram_s__3_axi_ar_arcache), + .s07_axi_arprot(axi_ram_s__3_axi_ar_arprot), + .s07_axi_arqos(axi_ram_s__3_axi_ar_arqos), + .s07_axi_aruser('0), + .s07_axi_arvalid(axi_ram_s__3_axi_ar_arvalid), + .s07_axi_arready(axi_ram_s__3_axi_ar_arready), + .s07_axi_rid(axi_ram_s__3_axi_r_rid), + .s07_axi_rdata(axi_ram_s__3_axi_r_rdata), + .s07_axi_rresp(axi_ram_s__3_axi_r_rresp[1:0]), + .s07_axi_rlast(axi_ram_s__3_axi_r_rlast), + .s07_axi_ruser(), + .s07_axi_rvalid(axi_ram_s__3_axi_r_rvalid), + .s07_axi_rready(axi_ram_s__3_axi_r_rready), + + // axi_ram_s__4 + .s08_axi_awid('0), + .s08_axi_awaddr('0), + .s08_axi_awlen('0), + .s08_axi_awsize('0), + .s08_axi_awburst('0), + .s08_axi_awlock('0), + .s08_axi_awcache('0), + .s08_axi_awprot('0), + .s08_axi_awqos('0), + .s08_axi_awuser('0), + .s08_axi_awvalid('0), + .s08_axi_awready(), + .s08_axi_wdata('0), + .s08_axi_wstrb('0), + .s08_axi_wlast('0), + .s08_axi_wuser('0), + .s08_axi_wvalid('0), + .s08_axi_wready(), + .s08_axi_bid(), + .s08_axi_bresp(), + .s08_axi_buser(), + .s08_axi_bvalid(), + .s08_axi_bready('0), + .s08_axi_arid(axi_ram_s__4_axi_ar_arid), + .s08_axi_araddr(axi_ram_s__4_axi_ar_araddr), + .s08_axi_arlen(axi_ram_s__4_axi_ar_arlen), + .s08_axi_arsize(axi_ram_s__4_axi_ar_arsize), + .s08_axi_arburst(axi_ram_s__4_axi_ar_arburst), + .s08_axi_arlock('0), + .s08_axi_arcache(axi_ram_s__4_axi_ar_arcache), + .s08_axi_arprot(axi_ram_s__4_axi_ar_arprot), + .s08_axi_arqos(axi_ram_s__4_axi_ar_arqos), + .s08_axi_aruser('0), + .s08_axi_arvalid(axi_ram_s__4_axi_ar_arvalid), + .s08_axi_arready(axi_ram_s__4_axi_ar_arready), + .s08_axi_rid(axi_ram_s__4_axi_r_rid), + .s08_axi_rdata(axi_ram_s__4_axi_r_rdata), + .s08_axi_rresp(axi_ram_s__4_axi_r_rresp[1:0]), + .s08_axi_rlast(axi_ram_s__4_axi_r_rlast), + .s08_axi_ruser(), + .s08_axi_rvalid(axi_ram_s__4_axi_r_rvalid), + .s08_axi_rready(axi_ram_s__4_axi_r_rready), + + // axi_ram_s__5 + .s09_axi_awid('0), + .s09_axi_awaddr('0), + .s09_axi_awlen('0), + .s09_axi_awsize('0), + .s09_axi_awburst('0), + .s09_axi_awlock('0), + .s09_axi_awcache('0), + .s09_axi_awprot('0), + .s09_axi_awqos('0), + .s09_axi_awuser('0), + .s09_axi_awvalid('0), + .s09_axi_awready(), + .s09_axi_wdata('0), + .s09_axi_wstrb('0), + .s09_axi_wlast('0), + .s09_axi_wuser('0), + .s09_axi_wvalid('0), + .s09_axi_wready(), + .s09_axi_bid(), + .s09_axi_bresp(), + .s09_axi_buser(), + .s09_axi_bvalid(), + .s09_axi_bready('0), + .s09_axi_arid(axi_ram_s__5_axi_ar_arid), + .s09_axi_araddr(axi_ram_s__5_axi_ar_araddr), + .s09_axi_arlen(axi_ram_s__5_axi_ar_arlen), + .s09_axi_arsize(axi_ram_s__5_axi_ar_arsize), + .s09_axi_arburst(axi_ram_s__5_axi_ar_arburst), + .s09_axi_arlock('0), + .s09_axi_arcache(axi_ram_s__5_axi_ar_arcache), + .s09_axi_arprot(axi_ram_s__5_axi_ar_arprot), + .s09_axi_arqos(axi_ram_s__5_axi_ar_arqos), + .s09_axi_aruser('0), + .s09_axi_arvalid(axi_ram_s__5_axi_ar_arvalid), + .s09_axi_arready(axi_ram_s__5_axi_ar_arready), + .s09_axi_rid(axi_ram_s__5_axi_r_rid), + .s09_axi_rdata(axi_ram_s__5_axi_r_rdata), + .s09_axi_rresp(axi_ram_s__5_axi_r_rresp[1:0]), + .s09_axi_rlast(axi_ram_s__5_axi_r_rlast), + .s09_axi_ruser(), + .s09_axi_rvalid(axi_ram_s__5_axi_r_rvalid), + .s09_axi_rready(axi_ram_s__5_axi_r_rready), + + // axi_ram_s__6 + .s10_axi_awid('0), + .s10_axi_awaddr('0), + .s10_axi_awlen('0), + .s10_axi_awsize('0), + .s10_axi_awburst('0), + .s10_axi_awlock('0), + .s10_axi_awcache('0), + .s10_axi_awprot('0), + .s10_axi_awqos('0), + .s10_axi_awuser('0), + .s10_axi_awvalid('0), + .s10_axi_awready(), + .s10_axi_wdata('0), + .s10_axi_wstrb('0), + .s10_axi_wlast('0), + .s10_axi_wuser('0), + .s10_axi_wvalid('0), + .s10_axi_wready(), + .s10_axi_bid(), + .s10_axi_bresp(), + .s10_axi_buser(), + .s10_axi_bvalid(), + .s10_axi_bready('0), + .s10_axi_arid(axi_ram_s__6_axi_ar_arid), + .s10_axi_araddr(axi_ram_s__6_axi_ar_araddr), + .s10_axi_arlen(axi_ram_s__6_axi_ar_arlen), + .s10_axi_arsize(axi_ram_s__6_axi_ar_arsize), + .s10_axi_arburst(axi_ram_s__6_axi_ar_arburst), + .s10_axi_arlock('0), + .s10_axi_arcache(axi_ram_s__6_axi_ar_arcache), + .s10_axi_arprot(axi_ram_s__6_axi_ar_arprot), + .s10_axi_arqos(axi_ram_s__6_axi_ar_arqos), + .s10_axi_aruser('0), + .s10_axi_arvalid(axi_ram_s__6_axi_ar_arvalid), + .s10_axi_arready(axi_ram_s__6_axi_ar_arready), + .s10_axi_rid(axi_ram_s__6_axi_r_rid), + .s10_axi_rdata(axi_ram_s__6_axi_r_rdata), + .s10_axi_rresp(axi_ram_s__6_axi_r_rresp[1:0]), + .s10_axi_rlast(axi_ram_s__6_axi_r_rlast), + .s10_axi_ruser(), + .s10_axi_rvalid(axi_ram_s__6_axi_r_rvalid), + .s10_axi_rready(axi_ram_s__6_axi_r_rready), + + // axi_ram_s__7 + .s11_axi_awid('0), + .s11_axi_awaddr('0), + .s11_axi_awlen('0), + .s11_axi_awsize('0), + .s11_axi_awburst('0), + .s11_axi_awlock('0), + .s11_axi_awcache('0), + .s11_axi_awprot('0), + .s11_axi_awqos('0), + .s11_axi_awuser('0), + .s11_axi_awvalid('0), + .s11_axi_awready(), + .s11_axi_wdata('0), + .s11_axi_wstrb('0), + .s11_axi_wlast('0), + .s11_axi_wuser('0), + .s11_axi_wvalid('0), + .s11_axi_wready(), + .s11_axi_bid(), + .s11_axi_bresp(), + .s11_axi_buser(), + .s11_axi_bvalid(), + .s11_axi_bready('0), + .s11_axi_arid(axi_ram_s__7_axi_ar_arid), + .s11_axi_araddr(axi_ram_s__7_axi_ar_araddr), + .s11_axi_arlen(axi_ram_s__7_axi_ar_arlen), + .s11_axi_arsize(axi_ram_s__7_axi_ar_arsize), + .s11_axi_arburst(axi_ram_s__7_axi_ar_arburst), + .s11_axi_arlock('0), + .s11_axi_arcache(axi_ram_s__7_axi_ar_arcache), + .s11_axi_arprot(axi_ram_s__7_axi_ar_arprot), + .s11_axi_arqos(axi_ram_s__7_axi_ar_arqos), + .s11_axi_aruser('0), + .s11_axi_arvalid(axi_ram_s__7_axi_ar_arvalid), + .s11_axi_arready(axi_ram_s__7_axi_ar_arready), + .s11_axi_rid(axi_ram_s__7_axi_r_rid), + .s11_axi_rdata(axi_ram_s__7_axi_r_rdata), + .s11_axi_rresp(axi_ram_s__7_axi_r_rresp[1:0]), + .s11_axi_rlast(axi_ram_s__7_axi_r_rlast), + .s11_axi_ruser(), + .s11_axi_rvalid(axi_ram_s__7_axi_r_rvalid), + .s11_axi_rready(axi_ram_s__7_axi_r_rready), + + // axi_ram_s__8 + .s12_axi_awid('0), + .s12_axi_awaddr('0), + .s12_axi_awlen('0), + .s12_axi_awsize('0), + .s12_axi_awburst('0), + .s12_axi_awlock('0), + .s12_axi_awcache('0), + .s12_axi_awprot('0), + .s12_axi_awqos('0), + .s12_axi_awuser('0), + .s12_axi_awvalid('0), + .s12_axi_awready(), + .s12_axi_wdata('0), + .s12_axi_wstrb('0), + .s12_axi_wlast('0), + .s12_axi_wuser('0), + .s12_axi_wvalid('0), + .s12_axi_wready(), + .s12_axi_bid(), + .s12_axi_bresp(), + .s12_axi_buser(), + .s12_axi_bvalid(), + .s12_axi_bready('0), + .s12_axi_arid(axi_ram_s__8_axi_ar_arid), + .s12_axi_araddr(axi_ram_s__8_axi_ar_araddr), + .s12_axi_arlen(axi_ram_s__8_axi_ar_arlen), + .s12_axi_arsize(axi_ram_s__8_axi_ar_arsize), + .s12_axi_arburst(axi_ram_s__8_axi_ar_arburst), + .s12_axi_arlock('0), + .s12_axi_arcache(axi_ram_s__8_axi_ar_arcache), + .s12_axi_arprot(axi_ram_s__8_axi_ar_arprot), + .s12_axi_arqos(axi_ram_s__8_axi_ar_arqos), + .s12_axi_aruser('0), + .s12_axi_arvalid(axi_ram_s__8_axi_ar_arvalid), + .s12_axi_arready(axi_ram_s__8_axi_ar_arready), + .s12_axi_rid(axi_ram_s__8_axi_r_rid), + .s12_axi_rdata(axi_ram_s__8_axi_r_rdata), + .s12_axi_rresp(axi_ram_s__8_axi_r_rresp[1:0]), + .s12_axi_rlast(axi_ram_s__8_axi_r_rlast), + .s12_axi_ruser(), + .s12_axi_rvalid(axi_ram_s__8_axi_r_rvalid), + .s12_axi_rready(axi_ram_s__8_axi_r_rready), + + // axi_ram_s__9 + .s13_axi_awid('0), + .s13_axi_awaddr('0), + .s13_axi_awlen('0), + .s13_axi_awsize('0), + .s13_axi_awburst('0), + .s13_axi_awlock('0), + .s13_axi_awcache('0), + .s13_axi_awprot('0), + .s13_axi_awqos('0), + .s13_axi_awuser('0), + .s13_axi_awvalid('0), + .s13_axi_awready(), + .s13_axi_wdata('0), + .s13_axi_wstrb('0), + .s13_axi_wlast('0), + .s13_axi_wuser('0), + .s13_axi_wvalid('0), + .s13_axi_wready(), + .s13_axi_bid(), + .s13_axi_bresp(), + .s13_axi_buser(), + .s13_axi_bvalid(), + .s13_axi_bready('0), + .s13_axi_arid(axi_ram_s__9_axi_ar_arid), + .s13_axi_araddr(axi_ram_s__9_axi_ar_araddr), + .s13_axi_arlen(axi_ram_s__9_axi_ar_arlen), + .s13_axi_arsize(axi_ram_s__9_axi_ar_arsize), + .s13_axi_arburst(axi_ram_s__9_axi_ar_arburst), + .s13_axi_arlock('0), + .s13_axi_arcache(axi_ram_s__9_axi_ar_arcache), + .s13_axi_arprot(axi_ram_s__9_axi_ar_arprot), + .s13_axi_arqos(axi_ram_s__9_axi_ar_arqos), + .s13_axi_aruser('0), + .s13_axi_arvalid(axi_ram_s__9_axi_ar_arvalid), + .s13_axi_arready(axi_ram_s__9_axi_ar_arready), + .s13_axi_rid(axi_ram_s__9_axi_r_rid), + .s13_axi_rdata(axi_ram_s__9_axi_r_rdata), + .s13_axi_rresp(axi_ram_s__9_axi_r_rresp[1:0]), + .s13_axi_rlast(axi_ram_s__9_axi_r_rlast), + .s13_axi_ruser(), + .s13_axi_rvalid(axi_ram_s__9_axi_r_rvalid), + .s13_axi_rready(axi_ram_s__9_axi_r_rready), + + // axi_ram_s__10 + .s14_axi_awid('0), + .s14_axi_awaddr('0), + .s14_axi_awlen('0), + .s14_axi_awsize('0), + .s14_axi_awburst('0), + .s14_axi_awlock('0), + .s14_axi_awcache('0), + .s14_axi_awprot('0), + .s14_axi_awqos('0), + .s14_axi_awuser('0), + .s14_axi_awvalid('0), + .s14_axi_awready(), + .s14_axi_wdata('0), + .s14_axi_wstrb('0), + .s14_axi_wlast('0), + .s14_axi_wuser('0), + .s14_axi_wvalid('0), + .s14_axi_wready(), + .s14_axi_bid(), + .s14_axi_bresp(), + .s14_axi_buser(), + .s14_axi_bvalid(), + .s14_axi_bready('0), + .s14_axi_arid(axi_ram_s__10_axi_ar_arid), + .s14_axi_araddr(axi_ram_s__10_axi_ar_araddr), + .s14_axi_arlen(axi_ram_s__10_axi_ar_arlen), + .s14_axi_arsize(axi_ram_s__10_axi_ar_arsize), + .s14_axi_arburst(axi_ram_s__10_axi_ar_arburst), + .s14_axi_arlock('0), + .s14_axi_arcache(axi_ram_s__10_axi_ar_arcache), + .s14_axi_arprot(axi_ram_s__10_axi_ar_arprot), + .s14_axi_arqos(axi_ram_s__10_axi_ar_arqos), + .s14_axi_aruser('0), + .s14_axi_arvalid(axi_ram_s__10_axi_ar_arvalid), + .s14_axi_arready(axi_ram_s__10_axi_ar_arready), + .s14_axi_rid(axi_ram_s__10_axi_r_rid), + .s14_axi_rdata(axi_ram_s__10_axi_r_rdata), + .s14_axi_rresp(axi_ram_s__10_axi_r_rresp[1:0]), + .s14_axi_rlast(axi_ram_s__10_axi_r_rlast), + .s14_axi_ruser(), + .s14_axi_rvalid(axi_ram_s__10_axi_r_rvalid), + .s14_axi_rready(axi_ram_s__10_axi_r_rready), + /* * AXI Manager interface */ diff --git a/xls/modules/zstd/rtl/zstd_enc_wrapper.sv b/xls/modules/zstd/rtl/zstd_enc_wrapper.sv new file mode 100644 index 0000000000..e992d5244b --- /dev/null +++ b/xls/modules/zstd/rtl/zstd_enc_wrapper.sv @@ -0,0 +1,591 @@ +// Copyright 2025 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. + +`default_nettype none + +module zstd_enc_wrapper #( + parameter AXI_DATA_W = 32, + parameter AXI_ADDR_W = 32, + parameter S_AXI_ID_W = 4, + parameter M_AXI_ID_W = 6, + parameter AXI_STRB_W = 4, + parameter AWUSER_WIDTH = 1, + parameter WUSER_WIDTH = 1, + parameter BUSER_WIDTH = 1, + parameter ARUSER_WIDTH = 1, + parameter RUSER_WIDTH = 1, + parameter CONF_W = 2, + parameter REQ_W = AXI_DATA_W + AXI_ADDR_W + AXI_ADDR_W + AXI_DATA_W + CONF_W, + parameter RESP_W = AXI_ADDR_W + 1 +) ( + input wire clk, + input wire rst, + // request + input wire [REQ_W-1:0] req_r_data, + input wire req_r_vld, + output wire req_r_rdy, + + // response + output wire [RESP_W-1:0] resp_s_data, + output wire resp_s_rdy, + input wire resp_s_vld, + + // memory + output wire [M_AXI_ID_W-1:0] memory_axi_aw_awid, + output wire [AXI_ADDR_W-1:0] memory_axi_aw_awaddr, + output wire [7:0] memory_axi_aw_awlen, + output wire [2:0] memory_axi_aw_awsize, + output wire [1:0] memory_axi_aw_awburst, + output wire memory_axi_aw_awlock, + output wire [3:0] memory_axi_aw_awcache, + output wire [AWUSER_WIDTH-1:0] memory_axi_aw_awuser, + output wire memory_axi_aw_awvalid, + input wire memory_axi_aw_awready, + output wire [AXI_DATA_W-1:0] memory_axi_w_wdata, + output wire [AXI_STRB_W-1:0] memory_axi_w_wstrb, + output wire memory_axi_w_wlast, + output wire [WUSER_WIDTH-1:0] memory_axi_w_wuser, + output wire memory_axi_w_wvalid, + input wire memory_axi_w_wready, + input wire [M_AXI_ID_W-1:0] memory_axi_b_bid, + input wire [2:0] memory_axi_b_bresp, + input wire [BUSER_WIDTH-1:0] memory_axi_b_buser, + input wire memory_axi_b_bvalid, + output wire memory_axi_b_bready, + + output wire [M_AXI_ID_W-1:0] memory_axi_ar_arid, + output wire [AXI_ADDR_W-1:0] memory_axi_ar_araddr, + output wire [7:0] memory_axi_ar_arlen, + output wire [2:0] memory_axi_ar_arsize, + output wire [1:0] memory_axi_ar_arburst, + output wire memory_axi_ar_arlock, + output wire [3:0] memory_axi_ar_arcache, + output wire [2:0] memory_axi_ar_arprot, + output wire [3:0] memory_axi_ar_arqos, + output wire [3:0] memory_axi_ar_arregion, + output wire [ARUSER_WIDTH-1:0] memory_axi_ar_aruser, + output wire memory_axi_ar_arvalid, + input wire memory_axi_ar_arready, + input wire [M_AXI_ID_W-1:0] memory_axi_r_rid, + input wire [AXI_DATA_W-1:0] memory_axi_r_rdata, + input wire [2:0] memory_axi_r_rresp, + input wire memory_axi_r_rlast, + input wire [RUSER_WIDTH-1:0] memory_axi_r_ruser, + input wire memory_axi_r_rvalid, + output wire memory_axi_r_rready +); + + localparam XLS_AXI_AW_SIZE_W = 3; + localparam XLS_AXI_AW_BURST_W = 2; + localparam XLS_AXI_AW_W = AXI_ADDR_W + S_AXI_ID_W + XLS_AXI_AW_SIZE_W + XLS_AXI_AW_BURST_W; + + localparam XLS_AXI_W_LAST_W = 1; + localparam XLS_AXI_W_W = AXI_DATA_W + AXI_STRB_W + XLS_AXI_W_LAST_W; + + localparam XLS_AXI_B_RESP_W = 3; + localparam XLS_AXI_B_W = XLS_AXI_B_RESP_W + S_AXI_ID_W; + + localparam XLS_AXI_AR_PROT_W = 3; + localparam XLS_AXI_AR_SIZE_W = 3; + localparam XLS_AXI_AR_CACHE_W = 4; + localparam XLS_AXI_AR_QOS_W = 4; + localparam XLS_AXI_AR_LEN_W = 8; + localparam XLS_AXI_AR_BURST_W = 2; + localparam XLS_AXI_AR_REGION_W = 4; + localparam XLS_AXI_AR_W = S_AXI_ID_W + AXI_ADDR_W + XLS_AXI_AR_CACHE_W + XLS_AXI_AR_LEN_W + XLS_AXI_AR_PROT_W + XLS_AXI_AR_BURST_W + XLS_AXI_AR_QOS_W + XLS_AXI_AR_SIZE_W + XLS_AXI_AR_REGION_W; + + localparam XLS_AXI_R_RESP_W = 3; + localparam XLS_AXI_R_LAST_W = 1; + localparam XLS_AXI_R_W = S_AXI_ID_W + AXI_DATA_W + XLS_AXI_R_RESP_W + XLS_AXI_R_LAST_W; + + wire [XLS_AXI_AW_W-1:0] zstd_enc__axi_aw; + wire zstd_enc__axi_aw_rdy; + wire zstd_enc__axi_aw_vld; + wire [XLS_AXI_W_W-1:0] zstd_enc__axi_w; + wire zstd_enc__axi_w_rdy; + wire zstd_enc__axi_w_vld; + wire [ XLS_AXI_B_W-1:0] zstd_enc__axi_b; + wire zstd_enc__axi_b_rdy; + wire zstd_enc__axi_b_vld; + wire [XLS_AXI_AR_W-1:0] zstd_enc__axi_ar; + wire zstd_enc__axi_ar_rdy; + wire zstd_enc__axi_ar_vld; + wire [ XLS_AXI_R_W-1:0] zstd_enc__axi_r; + wire zstd_enc__axi_r_rdy; + wire zstd_enc__axi_r_vld; + + assign { + memory_axi_aw_awid, + memory_axi_aw_awaddr, + memory_axi_aw_awsize, + memory_axi_aw_awlen, + memory_axi_aw_awburst + } = zstd_enc__axi_aw; + assign memory_axi_aw_awvalid = zstd_enc__axi_aw_vld; + assign zstd_enc__axi_aw_rdy = memory_axi_aw_awready; + assign { + memory_axi_w_wdata, + memory_axi_w_wstrb, + memory_axi_w_wlast + } = zstd_enc__axi_w; + assign memory_axi_w_wvalid = zstd_enc__axi_w_vld; + assign zstd_enc__axi_w_rdy = memory_axi_w_wready; + assign zstd_enc__axi_b = { + memory_axi_b_bresp, + memory_axi_b_bid + }; + assign zstd_enc__axi_b_vld = memory_axi_b_bvalid; + assign memory_axi_b_bready = zstd_enc__axi_b_rdy; + assign { + memory_axi_ar_arid, + memory_axi_ar_araddr, + memory_axi_ar_arregion, + memory_axi_ar_arlen, + memory_axi_ar_arsize, + memory_axi_ar_arburst, + memory_axi_ar_arcache, + memory_axi_ar_arprot, + memory_axi_ar_arqos + } = zstd_enc__axi_ar; + assign memory_axi_ar_arvalid = zstd_enc__axi_ar_vld; + assign zstd_enc__axi_ar_rdy = memory_axi_ar_arready; + assign zstd_enc__axi_r = { + memory_axi_r_rid, + memory_axi_r_rdata, + memory_axi_r_rresp, + memory_axi_r_rlast + }; + assign memory_axi_b_buser = 1'b0; + assign memory_axi_r_ruser = 1'b0; + + assign zstd_enc__axi_r_vld = memory_axi_r_rvalid; + assign memory_axi_r_rready = zstd_enc__axi_r_rdy; + + localparam HB_SIZE = 1024; + localparam HB_RAM_NUM = 8; + localparam HB_DATA_W = 8; + localparam HB_RAM_SIZE = HB_SIZE / HB_RAM_NUM; + localparam HB_ADDR_W = $clog2(HB_RAM_SIZE); + localparam HB_NUM_PARTITIONS = 1; + wire [HB_ADDR_W-1:0] hb_ram_rd_addr [0:7]; + wire [HB_DATA_W-1:0] hb_ram_rd_data [0:7]; + wire hb_ram_rd_en [0:7]; + wire [HB_NUM_PARTITIONS-1:0] hb_ram_rd_mask [0:7]; + wire [HB_ADDR_W-1:0] hb_ram_wr_addr [0:7]; + wire [HB_DATA_W-1:0] hb_ram_wr_data [0:7]; + wire hb_ram_wr_en [0:7]; + wire [HB_NUM_PARTITIONS-1:0] hb_ram_wr_mask [0:7]; + + genvar i; + generate + for (i = 0; i < 8; i = i + 1) begin : hb_loop + ram_1r1w #( + .DATA_WIDTH(HB_DATA_W), + .ADDR_WIDTH(HB_ADDR_W), + .SIZE(HB_SIZE), + .NUM_PARTITIONS(HB_NUM_PARTITIONS) + ) hb_ram ( + .clk(clk), + .rst(rst), + .rd_addr (hb_ram_rd_addr[i]), + .rd_data (hb_ram_rd_data[i]), + .rd_en (hb_ram_rd_en[i]), + .rd_mask (hb_ram_rd_mask[i]), + .wr_data (hb_ram_wr_data[i]), + .wr_addr (hb_ram_wr_addr[i]), + .wr_en (hb_ram_wr_en[i]), + .wr_mask (hb_ram_wr_mask[i]) + ); + end + endgenerate + + localparam HT_KEY_W = 32; + localparam HT_SIZE = 512; + localparam HT_ADDR_W = $clog2(HT_SIZE); + localparam HT_ENTRY_W = HT_KEY_W + 32; + localparam HT_DATA_W = HT_ENTRY_W + 1; // 32 (KEY_WIDTH) + 32 (ADDR_W) + 1 (match or not); + localparam HT_NUM_PARTITIONS = HT_DATA_W; + wire [HT_DATA_W-1:0] ht_ram_rd_data; + wire [HT_ADDR_W-1:0] ht_ram_rd_addr; + wire ht_ram_rd_en; + wire [HT_NUM_PARTITIONS-1:0] ht_ram_rd_mask; + wire [HT_DATA_W-1:0] ht_ram_wr_data; + wire [HT_ADDR_W-1:0] ht_ram_wr_addr; + wire ht_ram_wr_en; + wire [HT_NUM_PARTITIONS-1:0] ht_ram_wr_mask; + + ram_1r1w #( + .DATA_WIDTH(HT_DATA_W), + .ADDR_WIDTH(HT_ADDR_W), + .SIZE(HT_SIZE), + .NUM_PARTITIONS(HT_NUM_PARTITIONS) + ) ht_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ht_ram_rd_addr), + .rd_data (ht_ram_rd_data), + .rd_en (ht_ram_rd_en), + .rd_mask (ht_ram_rd_mask), + .wr_addr (ht_ram_wr_addr), + .wr_data (ht_ram_wr_data), + .wr_en (ht_ram_wr_en), + .wr_mask (ht_ram_wr_mask) + ); + + // fse table buffers + + localparam FSE_TABLE_RAM_ADDR_W = 32; + localparam FSE_CTABLE_RAM_DATA_W = 16; + localparam FSE_TTABLE_RAM_DATA_W = 64; + localparam FSE_CTABLE_NUM_PARTITIONS = 2; + localparam FSE_TTABLE_NUM_PARTITIONS = 4; + + localparam FSE_MAX_ACCURACY_LOG = 13; + localparam FSE_RAM_SIZE = 1 << FSE_MAX_ACCURACY_LOG; + + wire [FSE_CTABLE_RAM_DATA_W-1:0] ll_ctable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ll_ctable_ram_rd_addr; + wire ll_ctable_ram_rd_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] ll_ctable_ram_rd_mask; + wire [FSE_CTABLE_RAM_DATA_W-1:0] ll_ctable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ll_ctable_ram_wr_addr; + wire ll_ctable_ram_wr_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] ll_ctable_ram_wr_mask; + + wire [FSE_CTABLE_RAM_DATA_W-1:0] ml_ctable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ml_ctable_ram_rd_addr; + wire ml_ctable_ram_rd_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] ml_ctable_ram_rd_mask; + wire [FSE_CTABLE_RAM_DATA_W-1:0] ml_ctable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ml_ctable_ram_wr_addr; + wire ml_ctable_ram_wr_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] ml_ctable_ram_wr_mask; + + wire [FSE_CTABLE_RAM_DATA_W-1:0] of_ctable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] of_ctable_ram_rd_addr; + wire of_ctable_ram_rd_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] of_ctable_ram_rd_mask; + wire [FSE_CTABLE_RAM_DATA_W-1:0] of_ctable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] of_ctable_ram_wr_addr; + wire of_ctable_ram_wr_en; + wire [FSE_CTABLE_NUM_PARTITIONS-1:0] of_ctable_ram_wr_mask; + + wire [FSE_TTABLE_RAM_DATA_W-1:0] ll_ttable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ll_ttable_ram_rd_addr; + wire ll_ttable_ram_rd_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] ll_ttable_ram_rd_mask; + wire [FSE_TTABLE_RAM_DATA_W-1:0] ll_ttable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ll_ttable_ram_wr_addr; + wire ll_ttable_ram_wr_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] ll_ttable_ram_wr_mask; + + wire [FSE_TTABLE_RAM_DATA_W-1:0] ml_ttable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ml_ttable_ram_rd_addr; + wire ml_ttable_ram_rd_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] ml_ttable_ram_rd_mask; + wire [FSE_TTABLE_RAM_DATA_W-1:0] ml_ttable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] ml_ttable_ram_wr_addr; + wire ml_ttable_ram_wr_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] ml_ttable_ram_wr_mask; + + wire [FSE_TTABLE_RAM_DATA_W-1:0] of_ttable_ram_rd_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] of_ttable_ram_rd_addr; + wire of_ttable_ram_rd_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] of_ttable_ram_rd_mask; + wire [FSE_TTABLE_RAM_DATA_W-1:0] of_ttable_ram_wr_data; + wire [FSE_TABLE_RAM_ADDR_W-1:0] of_ttable_ram_wr_addr; + wire of_ttable_ram_wr_en; + wire [FSE_TTABLE_NUM_PARTITIONS-1:0] of_ttable_ram_wr_mask; + + ram_1r1w #( + .DATA_WIDTH(FSE_CTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_CTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_ll_ctable_default.mem") + ) ll_ctable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ll_ctable_ram_rd_addr), + .rd_data (ll_ctable_ram_rd_data), + .rd_en (ll_ctable_ram_rd_en), + .rd_mask (ll_ctable_ram_rd_mask), + .wr_addr (ll_ctable_ram_wr_addr), + .wr_data (ll_ctable_ram_wr_data), + .wr_en (ll_ctable_ram_wr_en), + .wr_mask (ll_ctable_ram_wr_mask) + ); + + ram_1r1w #( + .DATA_WIDTH(FSE_CTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_CTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_ml_ctable_default.mem") + ) ml_ctable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ml_ctable_ram_rd_addr), + .rd_data (ml_ctable_ram_rd_data), + .rd_en (ml_ctable_ram_rd_en), + .rd_mask (ml_ctable_ram_rd_mask), + .wr_addr (ml_ctable_ram_wr_addr), + .wr_data (ml_ctable_ram_wr_data), + .wr_en (ml_ctable_ram_wr_en), + .wr_mask (ml_ctable_ram_wr_mask) + ); + + ram_1r1w #( + .DATA_WIDTH(FSE_CTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_CTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_of_ctable_default.mem") + ) ol_ctable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (of_ctable_ram_rd_addr), + .rd_data (of_ctable_ram_rd_data), + .rd_en (of_ctable_ram_rd_en), + .rd_mask (of_ctable_ram_rd_mask), + .wr_addr (of_ctable_ram_wr_addr), + .wr_data (of_ctable_ram_wr_data), + .wr_en (of_ctable_ram_wr_en), + .wr_mask (of_ctable_ram_wr_mask) + ); + + ram_1r1w #( + .DATA_WIDTH(FSE_TTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_TTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_ll_ttable_default.mem") + ) ll_ttable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ll_ttable_ram_rd_addr), + .rd_data (ll_ttable_ram_rd_data), + .rd_en (ll_ttable_ram_rd_en), + .rd_mask (ll_ttable_ram_rd_mask), + .wr_addr (ll_ttable_ram_wr_addr), + .wr_data (ll_ttable_ram_wr_data), + .wr_en (ll_ttable_ram_wr_en), + .wr_mask (ll_ttable_ram_wr_mask) + ); + + ram_1r1w #( + .DATA_WIDTH(FSE_TTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_TTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_ml_ttable_default.mem") + ) ml_ttable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (ml_ttable_ram_rd_addr), + .rd_data (ml_ttable_ram_rd_data), + .rd_en (ml_ttable_ram_rd_en), + .rd_mask (ml_ttable_ram_rd_mask), + .wr_addr (ml_ttable_ram_wr_addr), + .wr_data (ml_ttable_ram_wr_data), + .wr_en (ml_ttable_ram_wr_en), + .wr_mask (ml_ttable_ram_wr_mask) + ); + + ram_1r1w #( + .DATA_WIDTH(FSE_TTABLE_RAM_DATA_W), + .ADDR_WIDTH(FSE_TABLE_RAM_ADDR_W), + .SIZE(FSE_RAM_SIZE), + .NUM_PARTITIONS(FSE_TTABLE_NUM_PARTITIONS), + .INIT_FILE("../xls/modules/zstd/zstd_enc_of_ttable_default.mem") + ) of_ttable_ram ( + .clk(clk), + .rst(rst), + .rd_addr (of_ttable_ram_rd_addr), + .rd_data (of_ttable_ram_rd_data), + .rd_en (of_ttable_ram_rd_en), + .rd_mask (of_ttable_ram_rd_mask), + .wr_addr (of_ttable_ram_wr_addr), + .wr_data (of_ttable_ram_wr_data), + .wr_en (of_ttable_ram_wr_en), + .wr_mask (of_ttable_ram_wr_mask) + ); + + ZstdEncoder zstd_encoder_benchmark ( + .clk(clk), + .rst(rst), + + // reader + .zstd_enc__axi_ar_s(zstd_enc__axi_ar), + .zstd_enc__axi_ar_s_vld(zstd_enc__axi_ar_vld), + .zstd_enc__axi_ar_s_rdy(zstd_enc__axi_ar_rdy), + .zstd_enc__axi_r_r(zstd_enc__axi_r), + .zstd_enc__axi_r_r_vld(zstd_enc__axi_r_vld), + .zstd_enc__axi_r_r_rdy(zstd_enc__axi_r_rdy), + + // writer + .zstd_enc__axi_b_r(zstd_enc__axi_b), + .zstd_enc__axi_b_r_vld(zstd_enc__axi_b_vld), + .zstd_enc__axi_b_r_rdy(zstd_enc__axi_b_rdy), + .zstd_enc__axi_aw_s(zstd_enc__axi_aw), + .zstd_enc__axi_aw_s_rdy(zstd_enc__axi_aw_rdy), + .zstd_enc__axi_aw_s_vld(zstd_enc__axi_aw_vld), + .zstd_enc__axi_w_s(zstd_enc__axi_w), + .zstd_enc__axi_w_s_rdy(zstd_enc__axi_w_rdy), + .zstd_enc__axi_w_s_vld(zstd_enc__axi_w_vld), + + .zstd_enc__enc_resp_s(resp_s_data), + .zstd_enc__enc_resp_s_rdy(resp_s_rdy), + .zstd_enc__enc_resp_s_vld(resp_s_vld), + .zstd_enc__enc_req_r(req_r_data), + .zstd_enc__enc_req_r_rdy(req_r_rdy), + .zstd_enc__enc_req_r_vld(req_r_vld), + + .hb_ram0_rd_addr(hb_ram_rd_addr[0]), + .hb_ram0_rd_data(hb_ram_rd_data[0]), + .hb_ram0_rd_en (hb_ram_rd_en[0]), + .hb_ram0_rd_mask(hb_ram_rd_mask[0]), + .hb_ram0_wr_addr(hb_ram_wr_addr[0]), + .hb_ram0_wr_data(hb_ram_wr_data[0]), + .hb_ram0_wr_en (hb_ram_wr_en[0]), + .hb_ram0_wr_mask(hb_ram_wr_mask[0]), + + .hb_ram1_rd_addr(hb_ram_rd_addr[1]), + .hb_ram1_rd_data(hb_ram_rd_data[1]), + .hb_ram1_rd_en (hb_ram_rd_en[1]), + .hb_ram1_rd_mask(hb_ram_rd_mask[1]), + .hb_ram1_wr_addr(hb_ram_wr_addr[1]), + .hb_ram1_wr_data(hb_ram_wr_data[1]), + .hb_ram1_wr_en (hb_ram_wr_en[1]), + .hb_ram1_wr_mask(hb_ram_wr_mask[1]), + + .hb_ram2_rd_addr(hb_ram_rd_addr[2]), + .hb_ram2_rd_data(hb_ram_rd_data[2]), + .hb_ram2_rd_en (hb_ram_rd_en[2]), + .hb_ram2_rd_mask(hb_ram_rd_mask[2]), + .hb_ram2_wr_addr(hb_ram_wr_addr[2]), + .hb_ram2_wr_data(hb_ram_wr_data[2]), + .hb_ram2_wr_en (hb_ram_wr_en[2]), + .hb_ram2_wr_mask(hb_ram_wr_mask[2]), + + .hb_ram3_rd_addr(hb_ram_rd_addr[3]), + .hb_ram3_rd_data(hb_ram_rd_data[3]), + .hb_ram3_rd_en (hb_ram_rd_en[3]), + .hb_ram3_rd_mask(hb_ram_rd_mask[3]), + .hb_ram3_wr_addr(hb_ram_wr_addr[3]), + .hb_ram3_wr_data(hb_ram_wr_data[3]), + .hb_ram3_wr_en (hb_ram_wr_en[3]), + .hb_ram3_wr_mask(hb_ram_wr_mask[3]), + + .hb_ram4_rd_addr(hb_ram_rd_addr[4]), + .hb_ram4_rd_data(hb_ram_rd_data[4]), + .hb_ram4_rd_en (hb_ram_rd_en[4]), + .hb_ram4_rd_mask(hb_ram_rd_mask[4]), + .hb_ram4_wr_addr(hb_ram_wr_addr[4]), + .hb_ram4_wr_data(hb_ram_wr_data[4]), + .hb_ram4_wr_en (hb_ram_wr_en[4]), + .hb_ram4_wr_mask(hb_ram_wr_mask[4]), + + .hb_ram5_rd_addr(hb_ram_rd_addr[5]), + .hb_ram5_rd_data(hb_ram_rd_data[5]), + .hb_ram5_rd_en (hb_ram_rd_en[5]), + .hb_ram5_rd_mask(hb_ram_rd_mask[5]), + .hb_ram5_wr_addr(hb_ram_wr_addr[5]), + .hb_ram5_wr_data(hb_ram_wr_data[5]), + .hb_ram5_wr_en (hb_ram_wr_en[5]), + .hb_ram5_wr_mask(hb_ram_wr_mask[5]), + + .hb_ram6_rd_addr(hb_ram_rd_addr[6]), + .hb_ram6_rd_data(hb_ram_rd_data[6]), + .hb_ram6_rd_en (hb_ram_rd_en[6]), + .hb_ram6_rd_mask(hb_ram_rd_mask[6]), + .hb_ram6_wr_addr(hb_ram_wr_addr[6]), + .hb_ram6_wr_data(hb_ram_wr_data[6]), + .hb_ram6_wr_en (hb_ram_wr_en[6]), + .hb_ram6_wr_mask(hb_ram_wr_mask[6]), + + .hb_ram7_rd_addr(hb_ram_rd_addr[7]), + .hb_ram7_rd_data(hb_ram_rd_data[7]), + .hb_ram7_rd_en (hb_ram_rd_en[7]), + .hb_ram7_rd_mask(hb_ram_rd_mask[7]), + .hb_ram7_wr_addr(hb_ram_wr_addr[7]), + .hb_ram7_wr_data(hb_ram_wr_data[7]), + .hb_ram7_wr_en (hb_ram_wr_en[7]), + .hb_ram7_wr_mask(hb_ram_wr_mask[7]), + + .ht_ram_rd_addr(ht_ram_rd_addr), + .ht_ram_rd_data(ht_ram_rd_data), + .ht_ram_rd_en (ht_ram_rd_en), + .ht_ram_rd_mask(ht_ram_rd_mask), + .ht_ram_wr_addr(ht_ram_wr_addr), + .ht_ram_wr_data(ht_ram_wr_data), + .ht_ram_wr_en (ht_ram_wr_en), + .ht_ram_wr_mask(ht_ram_wr_mask), + + .ll_ctable_ram_rd_addr(ll_ctable_ram_rd_addr), + .ll_ctable_ram_rd_data(ll_ctable_ram_rd_data), + .ll_ctable_ram_rd_en (ll_ctable_ram_rd_en), + .ll_ctable_ram_rd_mask(ll_ctable_ram_rd_mask), + .ll_ctable_ram_wr_addr(ll_ctable_ram_wr_addr), + .ll_ctable_ram_wr_data(ll_ctable_ram_wr_data), + .ll_ctable_ram_wr_en (ll_ctable_ram_wr_en), + .ll_ctable_ram_wr_mask(ll_ctable_ram_wr_mask), + + .ml_ctable_ram_rd_addr(ml_ctable_ram_rd_addr), + .ml_ctable_ram_rd_data(ml_ctable_ram_rd_data), + .ml_ctable_ram_rd_en (ml_ctable_ram_rd_en), + .ml_ctable_ram_rd_mask(ml_ctable_ram_rd_mask), + .ml_ctable_ram_wr_addr(ml_ctable_ram_wr_addr), + .ml_ctable_ram_wr_data(ml_ctable_ram_wr_data), + .ml_ctable_ram_wr_en (ml_ctable_ram_wr_en), + .ml_ctable_ram_wr_mask(ml_ctable_ram_wr_mask), + + .of_ctable_ram_rd_addr(of_ctable_ram_rd_addr), + .of_ctable_ram_rd_data(of_ctable_ram_rd_data), + .of_ctable_ram_rd_en (of_ctable_ram_rd_en), + .of_ctable_ram_rd_mask(of_ctable_ram_rd_mask), + .of_ctable_ram_wr_addr(of_ctable_ram_wr_addr), + .of_ctable_ram_wr_data(of_ctable_ram_wr_data), + .of_ctable_ram_wr_en (of_ctable_ram_wr_en), + .of_ctable_ram_wr_mask(of_ctable_ram_wr_mask), + + .ll_ttable_ram_rd_addr(ll_ttable_ram_rd_addr), + .ll_ttable_ram_rd_data(ll_ttable_ram_rd_data), + .ll_ttable_ram_rd_en (ll_ttable_ram_rd_en), + .ll_ttable_ram_rd_mask(ll_ttable_ram_rd_mask), + .ll_ttable_ram_wr_addr(ll_ttable_ram_wr_addr), + .ll_ttable_ram_wr_data(ll_ttable_ram_wr_data), + .ll_ttable_ram_wr_en (ll_ttable_ram_wr_en), + .ll_ttable_ram_wr_mask(ll_ttable_ram_wr_mask), + + .ml_ttable_ram_rd_addr(ml_ttable_ram_rd_addr), + .ml_ttable_ram_rd_data(ml_ttable_ram_rd_data), + .ml_ttable_ram_rd_en (ml_ttable_ram_rd_en), + .ml_ttable_ram_rd_mask(ml_ttable_ram_rd_mask), + .ml_ttable_ram_wr_addr(ml_ttable_ram_wr_addr), + .ml_ttable_ram_wr_data(ml_ttable_ram_wr_data), + .ml_ttable_ram_wr_en (ml_ttable_ram_wr_en), + .ml_ttable_ram_wr_mask(ml_ttable_ram_wr_mask), + + .of_ttable_ram_rd_addr(of_ttable_ram_rd_addr), + .of_ttable_ram_rd_data(of_ttable_ram_rd_data), + .of_ttable_ram_rd_en (of_ttable_ram_rd_en), + .of_ttable_ram_rd_mask(of_ttable_ram_rd_mask), + .of_ttable_ram_wr_addr(of_ttable_ram_wr_addr), + .of_ttable_ram_wr_data(of_ttable_ram_wr_data), + .of_ttable_ram_wr_en (of_ttable_ram_wr_en), + .of_ttable_ram_wr_mask(of_ttable_ram_wr_mask) + ); + +endmodule diff --git a/xls/modules/zstd/sequence_conf_dec.x b/xls/modules/zstd/sequence_conf_dec.x index 72c3e3ceee..13c1317405 100644 --- a/xls/modules/zstd/sequence_conf_dec.x +++ b/xls/modules/zstd/sequence_conf_dec.x @@ -152,8 +152,6 @@ pub proc SequenceConfDecoder { // max number of bytes that the header can have, see RFC8878 Section 3.1.1.3.2.1. length: uN[AXI_ADDR_W]:4, }); - // TODO: handle multiple receives on mem_rd_resp_r when AXI_DATA_W < 32 - const_assert!(AXI_DATA_W >= u32:32); let (tok, raw) = recv(tok, mem_rd_resp_r); let (header, length) = parse_sequence_conf(raw.data[:32]); let tok = send(tok, resp_s, Resp { diff --git a/xls/modules/zstd/sequence_conf_enc.x b/xls/modules/zstd/sequence_conf_enc.x new file mode 100644 index 0000000000..d3d7505b84 --- /dev/null +++ b/xls/modules/zstd/sequence_conf_enc.x @@ -0,0 +1,323 @@ +// Copyright 2025 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 contains implementation of SequenceHeaderWriter + +import std; + +import xls.modules.zstd.common; +import xls.modules.zstd.memory.mem_writer; + +pub struct SequenceSectionHeaderWriterReq { addr: uN[ADDR_W], conf: common::SequenceConf } + +pub enum SequenceSectionHeaderWriterStatus : u1 { + OK = 0, + ERROR = 1, +} + +pub struct SequenceSectionHeaderWriterResp { + status: SequenceSectionHeaderWriterStatus, + length: uN[ADDR_W] +} + +const LITERALS_MODE_BITS_OFFSET = u32:6; +const OFFSET_MODE_BITS_OFFSET = u32:4; +const MATCH_MODE_BITS_OFFSET = u32:2; +const LONGSEQ = u17:0x7F00; + +pub proc SequenceHeaderWriter { + type Req = SequenceSectionHeaderWriterReq; + type Resp = SequenceSectionHeaderWriterResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + type Status = SequenceSectionHeaderWriterStatus; + type Data = uN[DATA_W]; + type Length = uN[ADDR_W]; + req_r: chan in; + resp_s: chan out; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + config(req_r: chan in, resp_s: chan out, mem_wr_req_s: chan out, + mem_wr_data_s: chan out, mem_wr_resp_r: chan in) { + (req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r) + } + + init { } + + next(state: ()) { + let (req_tok, req) = recv(join(), req_r); + let sequence_count = req.conf.sequence_count; + + let compression_modes_byte = (req.conf.literals_mode as u8 << LITERALS_MODE_BITS_OFFSET) | + (req.conf.offset_mode as u8 << OFFSET_MODE_BITS_OFFSET) | + (req.conf.match_mode as u8 << MATCH_MODE_BITS_OFFSET); + + let (data, length) = if sequence_count == u17:0x0 { + // if (byte0 == 0): there are no sequences. The sequence section stops here + (Data:0, Length:1) + } else if sequence_count < u17:0x80 { + let b0 = checked_cast(sequence_count); + let data = (compression_modes_byte ++ b0) as Data; + (data, Length:2) + } else if sequence_count < LONGSEQ { + let b0 = checked_cast((sequence_count >> 8) + u17:128); + let b1 = checked_cast(sequence_count & u17:0xFF); + let data = (compression_modes_byte ++ b1 ++ b0) as Data; + (data, Length:3) + } else { + let b0 = u8:0xFF; + let sequence_count_decreased = sequence_count - LONGSEQ; + let b1 = checked_cast(sequence_count_decreased >> 8); + let b2 = checked_cast(sequence_count_decreased & u17:0xFF); + let data = (compression_modes_byte ++ b2 ++ b1 ++ b0) as Data; + (data, Length:4) + }; + + let mem_wr_req = MemWriterReq { addr: req.addr, length }; + let mem_wr_tok = send(req_tok, mem_wr_req_s, mem_wr_req); + + let mem_wr_data = MemWriterData { data, length, last: true }; + let mem_wr_data_tok = send(mem_wr_tok, mem_wr_data_s, mem_wr_data); + + let (req_tok, resp) = recv(mem_wr_data_tok, mem_wr_resp_r); + let status = if resp.status == MemWriterStatus::OKAY { Status::OK } else { Status::ERROR }; + let resp = Resp { status: status, length: length }; + send(req_tok, resp_s, resp); + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; + +proc SequenceHeaderWriterInst { + type Req = SequenceSectionHeaderWriterReq; + type Resp = SequenceSectionHeaderWriterResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + type Status = SequenceSectionHeaderWriterStatus; + type Data = uN[INST_DATA_W]; + type Length = uN[INST_ADDR_W]; + + config(req_r: chan in, resp_s: chan out, mem_wr_req_s: chan out, + mem_wr_data_s: chan out, mem_wr_resp_r: chan in) { + spawn SequenceHeaderWriter( + req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r); + } + + init { } + + next(state: ()) { } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:64; + +#[test_proc] +proc SequenceHeaderWriterTest { + type Req = SequenceSectionHeaderWriterReq; + type Resp = SequenceSectionHeaderWriterResp; + type Addr = uN[TEST_ADDR_W]; + type Length = uN[TEST_ADDR_W]; + type Status = SequenceSectionHeaderWriterStatus; + type SequenceConf = common::SequenceConf; + type CompressionMode = common::CompressionMode; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterRespStatus = mem_writer::MemWriterRespStatus; + terminator: chan out; + req_s: chan out; + resp_r: chan in; + mem_wr_req_r: chan in; + mem_wr_data_r: chan in; + mem_wr_resp_s: chan out; + + config(terminator: chan out) { + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn SequenceHeaderWriter( + req_r, resp_s, mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r); + + (terminator, req_s, resp_r, mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s) + } + + init { } + + next(state: ()) { + let tok = join(); + + // modes b2 b1 b0, length, config + let tests: (u32, u3, SequenceConf)[11] = [ + ( + u32:0x00, u3:1, + SequenceConf { + sequence_count: u17:0, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::PREDEFINED, + match_mode: CompressionMode::PREDEFINED, + }, + ), + ( + u32:0x00, u3:1, + SequenceConf { + sequence_count: u17:0, + literals_mode: CompressionMode::RLE, + offset_mode: CompressionMode::COMPRESSED, + match_mode: CompressionMode::REPEAT, + }, + ), + ( + u32:0xE4_01, u3:2, + SequenceConf { + sequence_count: u17:0x01, + literals_mode: CompressionMode::REPEAT, + offset_mode: CompressionMode::COMPRESSED, + match_mode: CompressionMode::RLE, + }, + ), + ( + u32:0xAC_7F, u3:2, + SequenceConf { + sequence_count: u17:0x7F, + literals_mode: CompressionMode::COMPRESSED, + offset_mode: CompressionMode::COMPRESSED, + match_mode: CompressionMode::REPEAT, + }, + ), + ( + u32:0x84_80_80, + u3:3, + SequenceConf { + // corner-case + sequence_count: u17:0x80, + literals_mode: CompressionMode::COMPRESSED, + offset_mode: CompressionMode::PREDEFINED, + match_mode: CompressionMode::RLE, + } + ), + ( + u32:0x84_81_80, u3:3, + SequenceConf { + sequence_count: u17:0x0081, + literals_mode: CompressionMode::COMPRESSED, + offset_mode: CompressionMode::PREDEFINED, + match_mode: CompressionMode::RLE, + }, + ), + ( + u32:0x18_FFFE, u3:3, + SequenceConf { + sequence_count: u17:0x7EFF, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::RLE, + match_mode: CompressionMode::COMPRESSED, + }, + ), + ( + u32:0x18_0000FF, u3:4, + SequenceConf { + sequence_count: u17:0x7F00, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::RLE, + match_mode: CompressionMode::COMPRESSED, + }, + ), + ( + u32:0x18_0100FF, u3:4, + SequenceConf { + sequence_count: u17:0x7F01, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::RLE, + match_mode: CompressionMode::COMPRESSED, + }, + ), + ( + u32:0x18_FF80FF, u3:4, + SequenceConf { + sequence_count: u17:0xFFFF, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::RLE, + match_mode: CompressionMode::COMPRESSED, + }, + ), + ( + u32:0x68_FFFFFF, u3:4, + SequenceConf { + sequence_count: u17:0x17EFF, + literals_mode: CompressionMode::RLE, + offset_mode: CompressionMode::COMPRESSED, + match_mode: CompressionMode::COMPRESSED, + }, + ), + ]; + const ADDR = uN[TEST_ADDR_W]:0xBEEF; + + let tok = + for ((_, (header, length, config)), tok): ((u32, (u32, u3, SequenceConf)), token) in + enumerate(tests) { + let tok = send(tok, req_s, Req { addr: ADDR, conf: config }); + + // first communicate, simulate memory writer actions + let (tok, recv_request) = recv(tok, mem_wr_req_r); + let (tok, recv_data) = recv(tok, mem_wr_data_r); + let tok = + send(tok, mem_wr_resp_s, MemWriterResp { status: MemWriterRespStatus::OKAY }); + let (tok, recv_status) = recv(tok, resp_r); + + // then assert + assert_eq(recv_request, MemWriterReq { addr: ADDR, length: length as u32 }); + assert_eq( + recv_data, + MemWriterData { data: header as u64, last: true, length: length as u32 }); + assert_eq(recv_status.status, Status::OK); + + tok + }(tok); + + // negative case: memory writer sends error + let tok = send( + tok, req_s, + Req { + addr: ADDR, + conf: SequenceConf { + sequence_count: u17:0, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::PREDEFINED, + match_mode: CompressionMode::PREDEFINED, + }, + }); + + let (tok, recv_request) = recv(tok, mem_wr_req_r); + let (tok, recv_data) = recv(tok, mem_wr_data_r); + let tok = send(tok, mem_wr_resp_s, MemWriterResp { status: MemWriterRespStatus::ERROR }); + let (tok, recv_status) = recv(tok, resp_r); + + assert_eq(recv_request, MemWriterReq { addr: ADDR, length: u32:1 }); + assert_eq(recv_data, MemWriterData { data: u64:0x00_00, last: true, length: u32:1 }); + assert_eq(recv_status.status, Status::ERROR); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_dec.x b/xls/modules/zstd/sequence_dec.x index 855d21b4a0..7724b1c85b 100644 --- a/xls/modules/zstd/sequence_dec.x +++ b/xls/modules/zstd/sequence_dec.x @@ -26,16 +26,17 @@ import xls.modules.zstd.ram_demux; import xls.modules.zstd.ram_mux; import xls.modules.zstd.refilling_shift_buffer; import xls.modules.zstd.fse_dec; -import xls.modules.zstd.shift_buffer; import xls.modules.zstd.fse_table_creator; -type SequenceExecutorPacket = common::SequenceExecutorPacket; +type SequenceExecutorPacket = common::SequenceExecutorPacket; +type CopyOrMatchContent = common::CopyOrMatchContent; type SequenceExecutorMessageType = common::SequenceExecutorMessageType; type BlockSyncData = common::BlockSyncData; type CommandConstructorData = common::CommandConstructorData; type CompressionMode = common::CompressionMode; +type Remainder = common::Remainder; enum SequenceDecoderStatus: u3 { OK = 0, @@ -53,22 +54,6 @@ pub struct SequenceDecoderResp { status: SequenceDecoderStatus, } -enum SequenceDecoderFSM: u3 { - IDLE = 0, - DECODE_SEQUENCE_HEADER = 1, - PREPARE_LL_TABLE = 2, - PREPARE_OF_TABLE = 3, - PREPARE_ML_TABLE = 4, - - ERROR = 7, -} - -struct SequenceDecoderState { - fsm: SequenceDecoderFSM, - req: SequenceDecoderReq, - conf_resp: sequence_conf_dec::SequenceConfDecoderResp, -} - struct FseLookupCtrlReq { ll_mode: CompressionMode, ml_mode: CompressionMode, @@ -87,14 +72,19 @@ struct FseLookupCtrlState { mode_valid: bool, cnt: u2, accuracy_logs: u7[3], + remainder: common::Remainder, } struct FseLookupCtrlInternalReq { cnt: u2, - is_rle: bool + is_rle: bool, + remainder: common::Remainder, } -type FseLookupCtrlInternalResp = u7; +struct FseLookupCtrlInternalResp { + accuracy_log: u7, + remainder: common::Remainder, +} pub proc FseLookupCtrlInternal { type Req = FseLookupCtrlInternalReq; @@ -135,16 +125,18 @@ pub proc FseLookupCtrlInternal { trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: Sent fse_demux req {:#x}", req.cnt); let (tok, demux_resp) = recv(tok, fse_demux_resp_r); trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: Received demux resp {:#x}", demux_resp); - let fld_req = FseLookupDecoderReq { is_rle: req.is_rle }; + let fld_req = FseLookupDecoderReq { is_rle: req.is_rle, remainder: req.remainder }; let tok = send(tok, fld_req_s, fld_req); trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: Sent FseLookupDecoder req: {:x}", fld_req); let (tok, fld_resp) = recv(tok, fld_resp_r); trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: Received FseLookupDecoder resp {:#x}", fld_resp); - let tok = send(tok, resp_s, fld_resp.accuracy_log as u7); + let tok = send(tok, resp_s, FseLookupCtrlInternalResp { + accuracy_log: fld_resp.accuracy_log as u7, + remainder: fld_resp.remainder, + }); } } - pub proc FseLookupCtrl { type Req = FseLookupCtrlReq; type Resp = FseLookupCtrlResp; @@ -198,7 +190,8 @@ pub proc FseLookupCtrl { mode: CompressionMode[3]:[req.ll_mode, req.of_mode, req.ml_mode], mode_valid: true, cnt: u2:0, - accuracy_logs: state.accuracy_logs // keep the accuracy logs from the previous block for "repeated" blocks + accuracy_logs: state.accuracy_logs, // keep the accuracy logs from the previous block for "repeated" blocks + ..state } } else { let is_rle = (state.mode[state.cnt] == CompressionMode::RLE); @@ -207,6 +200,8 @@ pub proc FseLookupCtrl { let is_repeated = (state.mode[state.cnt] == CompressionMode::REPEAT); let do_set = is_rle || is_compressed; + trace_fmt!("[FseLookupCtrl] State: {}", state); + match(state.cnt) { u2:0 => trace_fmt!("Handling LL"), u2:1 => trace_fmt!("Handling OF"), @@ -214,23 +209,30 @@ pub proc FseLookupCtrl { _ => trace_fmt!("Impossible case"), }; - let accuracy_log = if do_set { + let resp = if do_set { let tok = send(tok, flci_req_s, FseLookupCtrlInternalReq { cnt: state.cnt, - is_rle: is_rle + is_rle: is_rle, + remainder: state.remainder }); - let (tok, accuracy_log) = recv(tok, flci_resp_r); - accuracy_log + let (tok, resp) = recv(tok, flci_resp_r); + resp } else if is_predefined { - PREDEFINED_ACURACY_LOG[state.cnt] + FseLookupCtrlInternalResp { + accuracy_log: PREDEFINED_ACURACY_LOG[state.cnt], + remainder: state.remainder, + } } else if is_repeated { - state.accuracy_logs[state.cnt] + FseLookupCtrlInternalResp { + accuracy_log: state.accuracy_logs[state.cnt], + remainder: state.remainder, + } } else { - fail!("impossible_case", u7:0) + fail!("impossible_case", zero!()) }; - let accuracy_logs = update(state.accuracy_logs, state.cnt, accuracy_log); - trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: accuracy_log: {:#x}, accuracy_logs: {:#x}", accuracy_log, accuracy_logs); + let accuracy_logs = update(state.accuracy_logs, state.cnt, resp.accuracy_log); + trace_fmt!("[SequenceDecoderCtrl/FseLookupCtrl]: accuracy_log: {:#x}, accuracy_logs: {:#x}", resp.accuracy_log, accuracy_logs); if state.cnt >= u2:2 { let tok = send(tok, resp_s, FseLookupCtrlResp { @@ -240,7 +242,7 @@ pub proc FseLookupCtrl { }); State { accuracy_logs, ..zero!() } } else { - State { accuracy_logs, cnt: state.cnt + u2:1, ..state} + State { accuracy_logs, cnt: state.cnt + u2:1, remainder: resp.remainder, ..state} } } } @@ -275,154 +277,191 @@ pub proc FseLookupCtrlInst { next(state: ()) {} } -const TEST_FLC_AXI_ADDR_W = u32:32; +#[test_proc] +proc FseLookupCtrlTest { + type Req = FseLookupCtrlReq; + type Resp = FseLookupCtrlResp; -//#[test_proc] -//proc FseLookupCtrlTest { -// -// type Req = FseLookupCtrlReq; -// type Resp = FseLookupCtrlResp; -// -// type Addr = uN[TEST_FLC_AXI_ADDR_W]; -// -// type FseLookupDecoderReq = fse_lookup_dec::FseLookupDecoderReq; -// type FseLookupDecoderResp = fse_lookup_dec::FseLookupDecoderResp; -// type FseLookupDecoderStatus = fse_lookup_dec::FseLookupDecoderStatus; -// -// terminator: chan out; -// -// req_s: chan out; -// resp_r: chan in; -// fld_req_r: chan in; -// fld_resp_s: chan out; -// demux_req_r: chan in; -// demux_resp_s: chan<()> out; -// -// init {} -// -// config( -// terminator: chan out, -// ) { -// let (req_s, req_r) = chan("req"); -// let (resp_s, resp_r) = chan("resp"); -// let (fld_req_s, fld_req_r) = chan("fld_req"); -// let (fld_resp_s, fld_resp_r) = chan("fld_resp"); -// let (demux_req_s, demux_req_r) = chan("demux_req"); -// let (demux_resp_s, demux_resp_r) = chan<()>("demux_resp"); -// -// spawn FseLookupCtrl( -// req_r, resp_s, -// fld_req_s, fld_resp_r, -// demux_req_s, demux_resp_r, -// ); -// -// ( -// terminator, -// req_s, resp_r, -// fld_req_r, fld_resp_s, -// demux_req_r, demux_resp_s, -// ) -// } -// -// next(state: ()) { -// -// // Decode all the tables -// // --------------------- -// -// // Start -// let tok = join(); -// let tok = send(tok, req_s, Req { ll: true, of: true, ml: true, addr: Addr:0 }); -// -// // Select LL ( u2:0 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:0); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Select OF ( u2:1 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:1); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Select ML ( u2:2 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:2); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, _fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Stop -// let (tok, resp) = recv(tok, resp_r); -// assert_eq(resp, FseLookupCtrlResp {}); -// -// // Decode only LL and ML -// // --------------------- -// -// // Start -// let tok = join(); -// let tok = send(tok, req_s, Req { ll: true, of: false, ml: true, addr: Addr:0 }); -// -// // Select LL ( u2:0 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:0); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Select ML ( u2:2 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:2); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, _fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Stop -// let (tok, resp) = recv(tok, resp_r); -// assert_eq(resp, FseLookupCtrlResp {}); -// -// -// // Decode only OF -// // --------------------- -// -// // Start -// let tok = join(); -// let tok = send(tok, req_s, Req { ll: false, of: true, ml: false, addr: Addr:0 }); -// -// // Select OF ( u2:1 ) -// let (tok, demux_req) = recv(tok, demux_req_r); -// assert_eq(demux_req, u2:1); -// -// let tok = send(tok, demux_resp_s, ()); -// let (tok, fld_req) = recv(tok, fld_req_r); -// -// assert_eq(fld_req, zero!()); -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// // Stop -// let (tok, resp) = recv(tok, resp_r); -// assert_eq(resp, FseLookupCtrlResp {}); -// -// let tok = send(tok, terminator, true); -// } -//} + type FseLookupDecoderReq = fse_lookup_dec::FseLookupDecoderReq; + type FseLookupDecoderResp = fse_lookup_dec::FseLookupDecoderResp; + type FseLookupDecoderStatus = fse_lookup_dec::FseLookupDecoderStatus; + + terminator: chan out; + + req_s: chan out; + resp_r: chan in; + fld_req_r: chan in; + fld_resp_s: chan out; + demux_req_r: chan in; + demux_resp_s: chan<()> out; + + init {} + + config( + terminator: chan out, + ) { + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + let (fld_req_s, fld_req_r) = chan("fld_req"); + let (fld_resp_s, fld_resp_r) = chan("fld_resp"); + let (demux_req_s, demux_req_r) = chan("demux_req"); + let (demux_resp_s, demux_resp_r) = chan<()>("demux_resp"); + + spawn FseLookupCtrl( + req_r, resp_s, + fld_req_s, fld_resp_r, + demux_req_s, demux_resp_r, + ); + + ( + terminator, + req_s, resp_r, + fld_req_r, fld_resp_s, + demux_req_r, demux_resp_s, + ) + } + + next(state: ()) { + // Start + let tok = join(); + let tok = send(tok, req_s, Req { + ll_mode: CompressionMode::COMPRESSED, + ml_mode: CompressionMode::RLE, + of_mode: CompressionMode::COMPRESSED, + }); + + // Select LL ( u2:0 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:0); + + let tok = send(tok, demux_resp_s, ()); + let (tok, fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:9, + remainder: zero!(), + }); + + // Select OF ( u2:1 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:1); + + let tok = send(tok, demux_resp_s, ()); + let (tok, fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:9, + remainder: zero!(), + }); + + // Select ML ( u2:2 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:2); + + let tok = send(tok, demux_resp_s, ()); + let (tok, _fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:8, + remainder: zero!(), + }); + + // Stop + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, FseLookupCtrlResp { + ll_accuracy_log: u7:9, + ml_accuracy_log: u7:8, + of_accuracy_log: u7:9, + }); + + // Decode only LL and ML + + // Start + let tok = join(); + let tok = send(tok, req_s, Req { + ll_mode: CompressionMode::COMPRESSED, + ml_mode: CompressionMode::COMPRESSED, + of_mode: CompressionMode::REPEAT + }); + + // Select LL ( u2:0 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:0); + + let tok = send(tok, demux_resp_s, ()); + let (tok, fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:5, + remainder: zero!(), + + }); + + // Select ML ( u2:2 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:2); + + let tok = send(tok, demux_resp_s, ()); + let (tok, _fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:7, + remainder: zero!(), + }); + + // Stop + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, FseLookupCtrlResp { + ll_accuracy_log: u7:5, + ml_accuracy_log: u7:7, + of_accuracy_log: u7:9 + }); + + // Decode only OF + + // Start + let tok = join(); + let tok = send(tok, req_s, Req { + ll_mode: CompressionMode::PREDEFINED, + ml_mode: CompressionMode::PREDEFINED, + of_mode: CompressionMode::COMPRESSED + }); + + // Select OF ( u2:1 ) + let (tok, demux_req) = recv(tok, demux_req_r); + assert_eq(demux_req, u2:1); + + let tok = send(tok, demux_resp_s, ()); + let (tok, fld_req) = recv(tok, fld_req_r); + + assert_eq(fld_req, zero!()); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + accuracy_log: AccuracyLog:7, + remainder: zero!(), + }); + + // Stop + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, FseLookupCtrlResp { + ll_accuracy_log: u7:6, + ml_accuracy_log: u7:6, + of_accuracy_log: u7:7 + }); + + let tok = send(tok, terminator, true); + } +} pub proc SequenceDecoderCtrl< AXI_ADDR_W: u32, AXI_DATA_W: u32, @@ -431,8 +470,6 @@ pub proc SequenceDecoderCtrl< > { type Req = SequenceDecoderReq; type Resp = SequenceDecoderResp; - type State = SequenceDecoderState; - type FSM = SequenceDecoderFSM; type Status = SequenceDecoderStatus; type Addr = uN[AXI_ADDR_W]; @@ -661,174 +698,249 @@ const SDC_TEST_AXI_DATA_W = u32:64; const SDC_TEST_REFILLING_SB_DATA_W = {SDC_TEST_AXI_DATA_W}; const SDC_TEST_REFILLING_SB_LENGTH_W = refilling_shift_buffer::length_width(SDC_TEST_AXI_DATA_W); -//#[test_proc] -//proc SequenceDecoderCtrlTest { -// -// type Req = SequenceDecoderReq; -// type Resp = SequenceDecoderResp; -// type Status = SequenceDecoderStatus; -// -// type CompressionMode = common::CompressionMode; -// type Addr = uN[SDC_TEST_AXI_ADDR_W]; -// -// type SequenceConf = common::SequenceConf; -// type SequenceConfDecoderReq = sequence_conf_dec::SequenceConfDecoderReq; -// type SequenceConfDecoderResp = sequence_conf_dec::SequenceConfDecoderResp; -// type SequenceConfDecoderStatus = sequence_conf_dec::SequenceConfDecoderStatus; -// -// type FseLookupDecoderReq = fse_lookup_dec::FseLookupDecoderReq; -// type FseLookupDecoderResp = fse_lookup_dec::FseLookupDecoderResp; -// type FseLookupDecoderStatus = fse_lookup_dec::FseLookupDecoderStatus; -// -// type RefillingShiftBufferStart = refilling_shift_buffer::RefillStart; -// type RefillingShiftBufferError = refilling_shift_buffer::RefillingShiftBufferInput; -// type RefillingShiftBufferOutput = refilling_shift_buffer::RefillingShiftBufferOutput; -// type RefillingShiftBufferCtrl = refilling_shift_buffer::RefillingShiftBufferCtrl; -// -// type FseDecoderCtrl = fse_dec::FseDecoderCtrl; -// type FseDecoderFinish = fse_dec::FseDecoderFinish; -// -// terminator: chan out; -// -// sd_req_s: chan out; -// sd_resp_r: chan in; -// -// scd_req_r: chan in; -// scd_resp_s: chan out; -// -// fld_req_r: chan in; -// fld_resp_s: chan out; -// -// fse_demux_req_r: chan in; -// fse_demux_resp_s: chan<()> out; -// -// ll_demux_req_r: chan in; -// ll_demux_resp_s: chan<()> out; -// -// of_demux_req_r: chan in; -// of_demux_resp_s: chan<()> out; -// -// ml_demux_req_r: chan in; -// ml_demux_resp_s: chan<()> out; -// -// fd_rsb_start_req_r: chan in; -// fd_rsb_stop_flush_req_r: chan<()> in; -// fd_rsb_flushing_done_s: chan<()> out; -// -// fd_ctrl_r: chan in; -// fd_finish_s: chan out; -// -// init { } -// -// config(terminator: chan out) { -// let (sd_req_s, sd_req_r) = chan("sd_req"); -// let (sd_resp_s, sd_resp_r) = chan("sd_resp"); -// -// let (scd_req_s, scd_req_r) = chan("scd_req"); -// let (scd_resp_s, scd_resp_r) = chan("scd_resp"); -// -// let (fld_req_s, fld_req_r) = chan("fld_req"); -// let (fld_resp_s, fld_resp_r) = chan("fld_resp"); -// -// let (fse_demux_req_s, fse_demux_req_r) = chan("fse_demux_req"); -// let (fse_demux_resp_s, fse_demux_resp_r) = chan<()>("fse_demux_resp"); -// -// let (ll_demux_req_s, ll_demux_req_r) = chan("ll_demux_req"); -// let (ll_demux_resp_s, ll_demux_resp_r) = chan<()>("ll_demux_resp"); -// -// let (of_demux_req_s, of_demux_req_r) = chan("of_demux_req"); -// let (of_demux_resp_s, of_demux_resp_r) = chan<()>("of_demux_resp"); -// -// let (ml_demux_req_s, ml_demux_req_r) = chan("ml_demux_req"); -// let (ml_demux_resp_s, ml_demux_resp_r) = chan<()>("ml_demux_resp"); -// -// let (fd_rsb_start_req_s, fd_rsb_start_req_r) = chan("fd_rsb_start_req"); -// let (fd_rsb_stop_flush_req_s, fd_rsb_stop_flush_req_r) = chan<()>("fd_rsb_stop_flush_req"); -// let (fd_rsb_flushing_done_s, fd_rsb_flushing_done_r) = chan<()>("fd_rsb_flushing_done"); -// -// let (fd_ctrl_s, fd_ctrl_r) = chan("fd_ctrl"); -// let (fd_finish_s, fd_finish_r) = chan("fd_finish"); -// -// spawn SequenceDecoderCtrl< -// SDC_TEST_AXI_ADDR_W, SDC_TEST_AXI_DATA_W -// >( -// sd_req_r, sd_resp_s, -// scd_req_s, scd_resp_r, -// fld_req_s, fld_resp_r, -// fse_demux_req_s, fse_demux_resp_r, -// ll_demux_req_s, ll_demux_resp_r, -// of_demux_req_s, of_demux_resp_r, -// ml_demux_req_s, ml_demux_resp_r, -// fd_rsb_start_req_s, fd_rsb_stop_flush_req_s, fd_rsb_flushing_done_r, -// fd_ctrl_s, fd_finish_r, -// ); -// -// ( -// terminator, -// sd_req_s, sd_resp_r, -// scd_req_r, scd_resp_s, -// fld_req_r, fld_resp_s, -// fse_demux_req_r, fse_demux_resp_s, -// ll_demux_req_r, ll_demux_resp_s, -// of_demux_req_r, of_demux_resp_s, -// ml_demux_req_r, ml_demux_resp_s, -// fd_rsb_start_req_r, fd_rsb_stop_flush_req_r, fd_rsb_flushing_done_s, -// fd_ctrl_r, fd_finish_s, -// ) -// } -// -// next(state: ()) { -// let tok = join(); -// -// let tok = send(tok, sd_req_s, Req { -// start_addr: Addr:0x1000, -// end_addr: Addr:0x1012, -// }); -// -// let (tok, scd_req) = recv(tok, scd_req_r); -// assert_eq(scd_req, SequenceConfDecoderReq { addr: Addr: 0x1000 }); -// -// let scd_resp = SequenceConfDecoderResp { -// header: SequenceConf { -// sequence_count: u17:1, -// literals_mode: CompressionMode::PREDEFINED, -// offset_mode: CompressionMode::RLE, -// match_mode: CompressionMode::COMPRESSED, -// }, -// length: u3:5, -// status: SequenceConfDecoderStatus::OKAY -// }; -// let tok = send(tok, scd_resp_s, scd_resp); -// -// let (tok, demux_req) = recv(tok, fse_demux_req_r); -// assert_eq(demux_req, u2:2); -// let tok = send(tok, fse_demux_resp_s, ()); -// -// let (tok, fld_req) = recv(tok, fld_req_r); -// assert_eq(fld_req, FseLookupDecoderReq { -// addr: Addr:0x1005, -// }); -// -// let tok = send(tok, fld_resp_s, FseLookupDecoderResp {status: FseLookupDecoderStatus::OK}); -// -// let (tok, ll_demux) = recv(tok, ll_demux_req_r); -// assert_eq(ll_demux, u1:0); -// let tok = send(tok, ll_demux_resp_s, ()); -// -// let (tok, ml_demux) = recv(tok, ml_demux_req_r); -// assert_eq(ml_demux, u1:1); -// let tok = send(tok, ml_demux_resp_s, ()); -// -// let (tok, of_demux) = recv(tok, of_demux_req_r); -// assert_eq(of_demux, u1:1); -// let tok = send(tok, of_demux_resp_s, ()); -// -// let (tok, fd_ctrl) = recv(tok, fd_ctrl_r); -// assert_eq(fd_ctrl, zero!()); -// -// send(tok, terminator, true); -// } -//} +#[test_proc] +proc SequenceDecoderCtrlTest { + + type Req = SequenceDecoderReq; + type Resp = SequenceDecoderResp; + type Status = SequenceDecoderStatus; + + type CompressionMode = common::CompressionMode; + type Addr = uN[SDC_TEST_AXI_ADDR_W]; + + type SequenceConf = common::SequenceConf; + type SequenceConfDecoderReq = sequence_conf_dec::SequenceConfDecoderReq; + type SequenceConfDecoderResp = sequence_conf_dec::SequenceConfDecoderResp; + type SequenceConfDecoderStatus = sequence_conf_dec::SequenceConfDecoderStatus; + + type FseLookupDecoderReq = fse_lookup_dec::FseLookupDecoderReq; + type FseLookupDecoderResp = fse_lookup_dec::FseLookupDecoderResp; + type FseLookupDecoderStatus = fse_lookup_dec::FseLookupDecoderStatus; + + type RefillingShiftBufferStart = refilling_shift_buffer::RefillStart; + type RefillingShiftBufferError = refilling_shift_buffer::RefillingShiftBufferInput; + type RefillingShiftBufferOutput = refilling_shift_buffer::RefillingShiftBufferOutput; + type RefillingShiftBufferCtrl = refilling_shift_buffer::RefillingShiftBufferCtrl; + + type FseDecoderCtrl = fse_dec::FseDecoderCtrl; + type FseDecoderFinish = fse_dec::FseDecoderFinish; + + terminator: chan out; + + sd_req_s: chan out; + sd_resp_r: chan in; + + scd_req_r: chan in; + scd_resp_s: chan out; + + fld_req_r: chan in; + fld_resp_s: chan out; + + fld_demux_req_r: chan in; + fld_demux_resp_s: chan<()> out; + + ll_demux_req_r: chan in; + ll_demux_resp_s: chan<()> out; + + of_demux_req_r: chan in; + of_demux_resp_s: chan<()> out; + + ml_demux_req_r: chan in; + ml_demux_resp_s: chan<()> out; + + fd_rsb_start_req_r: chan in; + fd_rsb_stop_flush_req_r: chan<()> in; + fd_rsb_flushing_done_s: chan<()> out; + + fld_rsb_start_req_r: chan in; + fld_rsb_stop_flush_req_r: chan<()> in; + fld_rsb_flushing_done_s: chan<()> out; + + fd_ctrl_r: chan in; + fd_finish_s: chan out; + + init { } + + config(terminator: chan out) { + let (sd_req_s, sd_req_r) = chan("sd_req"); + let (sd_resp_s, sd_resp_r) = chan("sd_resp"); + + let (scd_req_s, scd_req_r) = chan("scd_req"); + let (scd_resp_s, scd_resp_r) = chan("scd_resp"); + + let (fld_req_s, fld_req_r) = chan("fld_req"); + let (fld_resp_s, fld_resp_r) = chan("fld_resp"); + + let (fld_demux_req_s, fld_demux_req_r) = chan("fld_demux_req"); + let (fld_demux_resp_s, fld_demux_resp_r) = chan<()>("fld_demux_resp"); + + let (ll_demux_req_s, ll_demux_req_r) = chan("ll_demux_req"); + let (ll_demux_resp_s, ll_demux_resp_r) = chan<()>("ll_demux_resp"); + + let (of_demux_req_s, of_demux_req_r) = chan("of_demux_req"); + let (of_demux_resp_s, of_demux_resp_r) = chan<()>("of_demux_resp"); + + let (ml_demux_req_s, ml_demux_req_r) = chan("ml_demux_req"); + let (ml_demux_resp_s, ml_demux_resp_r) = chan<()>("ml_demux_resp"); + + let (fd_rsb_start_req_s, fd_rsb_start_req_r) = chan("fd_rsb_start_req"); + let (fd_rsb_stop_flush_req_s, fd_rsb_stop_flush_req_r) = chan<()>("fd_rsb_stop_flush_req"); + let (fd_rsb_flushing_done_s, fd_rsb_flushing_done_r) = chan<()>("fd_rsb_flushing_done"); + + let (fld_rsb_start_req_s, fld_rsb_start_req_r) = chan("fld_rsb_start_req"); + let (fld_rsb_stop_flush_req_s, fld_rsb_stop_flush_req_r) = chan<()>("fld_rsb_stop_flush_req"); + let (fld_rsb_flushing_done_s, fld_rsb_flushing_done_r) = chan<()>("fld_rsb_flushing_done"); + + let (fd_ctrl_s, fd_ctrl_r) = chan("fd_ctrl"); + let (fd_finish_s, fd_finish_r) = chan("fd_finish"); + + spawn SequenceDecoderCtrl< + SDC_TEST_AXI_ADDR_W, SDC_TEST_AXI_DATA_W + >( + sd_req_r, sd_resp_s, + scd_req_s, scd_resp_r, + fld_req_s, fld_resp_r, + fld_demux_req_s, fld_demux_resp_r, + ll_demux_req_s, ll_demux_resp_r, + of_demux_req_s, of_demux_resp_r, + ml_demux_req_s, ml_demux_resp_r, + fd_rsb_start_req_s, fd_rsb_stop_flush_req_s, fd_rsb_flushing_done_r, + fld_rsb_start_req_s, fld_rsb_stop_flush_req_s, fld_rsb_flushing_done_r, + fd_ctrl_s, fd_finish_r + ); + + ( + terminator, + sd_req_s, sd_resp_r, + scd_req_r, scd_resp_s, + fld_req_r, fld_resp_s, + fld_demux_req_r, fld_demux_resp_s, + ll_demux_req_r, ll_demux_resp_s, + of_demux_req_r, of_demux_resp_s, + ml_demux_req_r, ml_demux_resp_s, + fd_rsb_start_req_r, fd_rsb_stop_flush_req_r, fd_rsb_flushing_done_s, + fld_rsb_start_req_r, fld_rsb_stop_flush_req_r, fld_rsb_flushing_done_s, + fd_ctrl_r, fd_finish_s + ) + } + + next(state: ()) { + let tok = join(); + + trace_fmt!("Sending SequenceDecoder request"); + let tok = send(tok, sd_req_s, Req { + start_addr: Addr:0x1000, + end_addr: Addr:0x1012, + sync: BlockSyncData { id: u32:1, last_block: false }, + literals_count: u20:1234, + }); + + let (tok, scd_req) = recv(tok, scd_req_r); + trace_fmt!("Received SequenceConfDecoder response"); + assert_eq(scd_req, SequenceConfDecoderReq { + addr: Addr: 0x1000 + }); + + let scd_resp = SequenceConfDecoderResp { + header: SequenceConf { + sequence_count: u17:1, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::RLE, + match_mode: CompressionMode::COMPRESSED, + }, + length: u3:5, + status: SequenceConfDecoderStatus::OKAY + }; + trace_fmt!("Sending SequenceConfDecoder response"); + let tok = send(tok, scd_resp_s, scd_resp); + + let (tok, fld_rsb_start_req) = recv(tok, fld_rsb_start_req_r); + trace_fmt!("Received RefillingShiftBuffer start request: {:#x}", + fld_rsb_start_req + ); + + let (tok, demux_req) = recv(tok, fld_demux_req_r); + trace_fmt!("Received FseLookupDecoder demux request: {:#x}", demux_req); + assert_eq(demux_req, u2:1); + + let tok = send(tok, fld_demux_resp_s, ()); + trace_fmt!("Sending FSELookupDecoder demux response {:#x}", ()); + + let (tok, fld_req) = recv(tok, fld_req_r); + trace_fmt!("Received FSELookupDecoder request"); + assert_eq(fld_req, FseLookupDecoderReq { + is_rle: true, + remainder: zero!() + }); + + trace_fmt!("Sending FSELookupDecoder response"); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + remainder: zero!(), + accuracy_log: AccuracyLog:8, + }); + + let (tok, demux_req) = recv(tok, fld_demux_req_r); + trace_fmt!("Received FseLookupDecoder demux request: {:#x}", demux_req); + assert_eq(demux_req, u2:2); + + let tok = send(tok, fld_demux_resp_s, ()); + trace_fmt!("Sending FSELookupDecoder demux response {:#x}", ()); + + let (tok, fld_req) = recv(tok, fld_req_r); + trace_fmt!("[TEST] Received FSELookupDecoder request"); + assert_eq(fld_req, FseLookupDecoderReq { + is_rle: false, + remainder: zero!() + }); + + trace_fmt!("Sending FSELookupDecoder response"); + let tok = send(tok, fld_resp_s, FseLookupDecoderResp { + status: FseLookupDecoderStatus::OK, + remainder: zero!(), + accuracy_log: AccuracyLog:7, + }); + + let (tok, _) = recv(tok, fld_rsb_stop_flush_req_r); + trace_fmt!("Received RefillingShiftBuffer stop flush"); + trace_fmt!("Sending RefillingShiftBuffer flushing done"); + let tok = send(tok, fld_rsb_flushing_done_s, ()); + + let (tok, ll_demux) = recv(tok, ll_demux_req_r); + trace_fmt!("Received LL demux request"); + assert_eq(ll_demux, u1:0); + trace_fmt!("Sending LL demux response"); + let tok = send(tok, ll_demux_resp_s, ()); + + let (tok, of_demux) = recv(tok, of_demux_req_r); + trace_fmt!("Received OF demux request"); + assert_eq(of_demux, u1:1); + trace_fmt!("Sending OF demux response"); + let tok = send(tok, of_demux_resp_s, ()); + + trace_fmt!("Received ML demux request"); + let (tok, ml_demux) = recv(tok, ml_demux_req_r); + assert_eq(ml_demux, u1:1); + trace_fmt!("Received ML demux response"); + let tok = send(tok, ml_demux_resp_s, ()); + + let (tok, fd_ctrl) = recv(tok, fd_ctrl_r); + trace_fmt!("Received Fse decoder ctrl"); + assert_eq(fd_ctrl, FseDecoderCtrl { + sync: BlockSyncData { + id: u32:1, + last_block: u1:0 + }, + sequences_count: u24:1, + literals_count: u20:1234, + of_acc_log: u7:8, + ll_acc_log: u7:6, + ml_acc_log: u7:7 + }); + + send(tok, terminator, true); + } +} pub proc SequenceDecoder< AXI_ADDR_W: u32, AXI_DATA_W: u32, AXI_DEST_W: u32, AXI_ID_W: u32, @@ -995,7 +1107,7 @@ pub proc SequenceDecoder< let (scd_mem_rd_req_s, scd_mem_rd_req_r) = chan("scd_mem_rd_req"); let (scd_mem_rd_resp_s, scd_mem_rd_resp_r) = chan("scd_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( scd_mem_rd_req_r, scd_mem_rd_resp_s, scd_axi_ar_s, scd_axi_r_r, ); @@ -1013,7 +1125,7 @@ pub proc SequenceDecoder< let (fld_mem_rd_req_s, fld_mem_rd_req_r) = chan("fld_mem_rd_req"); let (fld_mem_rd_resp_s, fld_mem_rd_resp_r) = chan("fld_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( fld_mem_rd_req_r, fld_mem_rd_resp_s, fld_axi_ar_s, fld_axi_r_r, ); @@ -1136,7 +1248,7 @@ pub proc SequenceDecoder< let (fd_mem_rd_req_s, fd_mem_rd_req_r) = chan("fd_mem_rd_req"); let (fd_mem_rd_resp_s, fd_mem_rd_resp_r) = chan("fd_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( fd_mem_rd_req_r, fd_mem_rd_resp_s, fd_axi_ar_s, fd_axi_r_r, ); @@ -1238,14 +1350,14 @@ pub proc SequenceDecoder< } const TEST_AXI_ADDR_W = u32:32; -const TEST_AXI_DATA_W = u32:64; +const TEST_AXI_DATA_W = common::AXI_DATA_W; const TEST_AXI_DEST_W = u32:8; const TEST_AXI_ID_W = u32:8; const TEST_INPUT_RAM_DATA_W = TEST_AXI_DATA_W; const TEST_INPUT_RAM_SIZE = u32:1024; const TEST_INPUT_RAM_ADDR_W = TEST_AXI_ADDR_W; -const TEST_INPUT_RAM_WORD_PARTITION_SIZE = TEST_INPUT_RAM_DATA_W / u32:8; +const TEST_INPUT_RAM_WORD_PARTITION_SIZE = u32:8; const TEST_INPUT_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_INPUT_RAM_WORD_PARTITION_SIZE, TEST_INPUT_RAM_DATA_W); const TEST_INPUT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; const TEST_INPUT_RAM_INITIALIZED = true; @@ -1295,78 +1407,42 @@ const SEQ_DEC_TESTCASES: (u32, u64[32], u32, SequenceExecutorPacket[64])[4] = [ u64:0x0000000000000002, u64:0x0, ... ], - u32:12, + u32:6, SequenceExecutorPacket[64]:[ SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, + msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0004, - content: u64:0x0, + content: CopyOrMatchContent:0x000b0005, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0005, - content: u64:0x000b, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0004, - content: u64:0x0, + content: CopyOrMatchContent:0x00010006, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0006, - content: u64:0x0001, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00320005, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0005, - content: u64:0x0032, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0006, - content: u64:0x0, + content: CopyOrMatchContent:0x003e0009, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0009, - content: u64:0x003e, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0009, - content: u64:0x0, + content: CopyOrMatchContent:0x003d0006, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0006, - content: u64:0x003d, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x001a, - content: u64:0x0043, + content: CopyOrMatchContent:0x0043001a, last: true, }, zero!(), ... @@ -1384,162 +1460,84 @@ const SEQ_DEC_TESTCASES: (u32, u64[32], u32, SequenceExecutorPacket[64])[4] = [ u64:0x6CBFAEE1A0DDEF00, u64:0x0, ... ], - u32:26, + u32:13, SequenceExecutorPacket[64]:[ SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, + msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x00030003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0003, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x000e0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x000e, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00230004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0023, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x00de0004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x00de, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x003a0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x003a, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x01100003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0110, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00b00004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x00b0, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00da0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x00da, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00440004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0044, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x013f0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x013f, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x001b0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x001b, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, + content: CopyOrMatchContent:0x00030004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0003, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0, - content: u64:0x0, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0031, + content: CopyOrMatchContent:0x00310004, last: true, }, zero!(), ... @@ -1557,126 +1555,66 @@ const SEQ_DEC_TESTCASES: (u32, u64[32], u32, SequenceExecutorPacket[64])[4] = [ u64:0x000000000000003E, u64:0x0, ... ], - u32:20, + u32:10, SequenceExecutorPacket[64]:[ SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, + msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0002, - content: u64:0x0, + content: CopyOrMatchContent:0x00040005, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0005, - content: u64:0x0004, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0003, - content: u64:0x0, + content: CopyOrMatchContent:0x000d0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x000d, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, + length: u64:0x0, + content: CopyOrMatchContent:0x00020003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0003, - content: u64:0x0002, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0003, - content: u64:0x0, + content: CopyOrMatchContent:0x000d0004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x000d, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0002, - content: u64:0x0, + content: CopyOrMatchContent:0x00170004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0017, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, + length: u64:0x0, + content: CopyOrMatchContent:0x00190003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0019, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, + length: u64:0x0, + content: CopyOrMatchContent:0x00210004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x0021, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x00200003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0020, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0006, - content: u64:0x0, + content: CopyOrMatchContent:0x001b0004, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x001b, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0004, - content: u64:0x000d, + length: u64:0x0, + content: CopyOrMatchContent:0x000d0004, last: true, }, zero!(), ... @@ -1693,179 +1631,65 @@ const SEQ_DEC_TESTCASES: (u32, u64[32], u32, SequenceExecutorPacket[64])[4] = [ u64:0xaca57e409b057, u64:0x0, ... ], - u32:18, + u32:9, SequenceExecutorPacket[64]:[ SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, + msg_type: SequenceExecutorMessageType::SEQUENCE, length: u64:0x0002, - content: u64:0x0, + content: CopyOrMatchContent:0x00040003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0004, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, + length: u64:0x0, + content: CopyOrMatchContent:0x00070003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0007, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0001, - content: u64:0x0, + content: CopyOrMatchContent:0x00090003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0009, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0005, - content: u64:0x0, + content: CopyOrMatchContent:0x00090003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0009, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: u64:0x0000, - content: u64:0x0, + length: u64:0x0, + content: CopyOrMatchContent:0x000b0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x000b, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0011, - content: u64:0x0, + content: CopyOrMatchContent:0x00120003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0012, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0004, - content: u64:0x0, + content: CopyOrMatchContent:0x00230003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0023, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0002, - content: u64:0x0, + content: CopyOrMatchContent:0x000a0003, last: false, }, SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x000a, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, length: u64:0x0002, - content: u64:0x0, - last: false, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: u64:0x0003, - content: u64:0x0034, + content: CopyOrMatchContent:0x00340003, last: true, }, zero!(), ... ] ), - // Test case N (WARNING: long test running time) - // 3 custom lookup tables with accuracy log 9, 8 and 9 - // decodecorpus -pdata.out -odata.in -s58745 --block-type=2 --content-size --literal-type=0 --max-block-size-log=7 - // ( - // u32:32, - // u64[32]:[ - // u64:0x0, u64:0x0, - // u64:0xFC0502602814A804, - // u64:0x505040131FF60604, - // u64:0xFE01C080140FE030, - // u64:0x4040E65B84521B01, - // u64:0x0, ... - // ], - // u32:7, - // SequenceExecutorPacket[64]:[ - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::LITERAL, - // length: u64:0x0005, - // content: u64:0x0, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::SEQUENCE, - // length: u64:0x0004, - // content: u64:0x0006, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::SEQUENCE, - // length: u64:0x0004, - // content: u64:0x0002, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::LITERAL, - // length: u64:0x0011, - // content: u64:0x0, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::SEQUENCE, - // length: u64:0x0004, - // content: u64:0x000a, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::LITERAL, - // length: u64:0x002b, - // content: u64:0x0, - // last: false, - // }, - // SequenceExecutorPacket { - // msg_type: SequenceExecutorMessageType::SEQUENCE, - // length: u64:0x0006, - // content: u64:0x0023, - // last: true, - // }, - // zero!(), ... - // ] - // ), ]; type Base = u16; @@ -2526,7 +2350,7 @@ proc SequenceDecoderTest { // COUNT THE AMOUNT OF LITERALS let (tok, literals_count) = for (i, (tok, literals_count)): (u32, (token, u20)) in u32:0..expected_len { let literals_count = match expected_data[i].msg_type { - SequenceExecutorMessageType::SEQUENCE => literals_count, + SequenceExecutorMessageType::SEQUENCE => literals_count + expected_data[i].length as u20, SequenceExecutorMessageType::LITERAL => literals_count + expected_data[i].length as u20, }; (tok, literals_count) @@ -2592,7 +2416,7 @@ proc SequenceDecoderTest { let expected = SequenceExecutorPacket { msg_type: SequenceExecutorMessageType::LITERAL, length: ADDITIONAL_LITERALS as u64, - content: u64:0x0, + content: CopyOrMatchContent:0x0, last: true, }; let (tok, recv_output) = recv(tok, fd_command_r); @@ -2608,5 +2432,4 @@ proc SequenceDecoderTest { send(tok, terminator, true); } - } diff --git a/xls/modules/zstd/sequence_encoder.x b/xls/modules/zstd/sequence_encoder.x new file mode 100644 index 0000000000..4a364843e4 --- /dev/null +++ b/xls/modules/zstd/sequence_encoder.x @@ -0,0 +1,1460 @@ +// Copyright 2025 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 contains SequenceEncoder proc implementation +// See steps 1-11 below for the functionality description +// +// NOTES: +// * only predefined compression tables +// * as of now the proc doesn't support long offsets (https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/compress/zstd_compress_sequences.c#L318-L329) +// * ZSTD library uses a single buffer for storing both the transforms and symbol encodings where each half of the buffer serves different purpose, we split that to two +// * This file contains an implementation of a SequenceEncoderBuffer for writing bitstreams, it's quite generic and can be used for other procs +// * The biggest offset was assumed to fit in 16-bits +// * this assumes DATA_W <= WIDER_BUS_DATA_W + +import std; + +import xls.examples.ram; +import xls.modules.zstd.common; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.axi_ram_reader; +import xls.modules.zstd.memory.axi_ram_writer; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.sequence_conf_enc; +import xls.modules.zstd.memory.mem_reader_data_upscaler; + +const WIDER_BUS_DATA_W = u32:64; + + +fn highbit(val: u32) -> u32 { + assert!(val != u32:0, "val is zero and thus has no highbit"); + u32:31 - clz(val) +} + +#[test] +fn test_highbit() { + assert_eq(highbit(u32:0x00_00_00_01), u32:0); + assert_eq(highbit(u32:0x00_0F_A5_CC), u32:19); + assert_eq(highbit(u32:0xFF_0F_A5_CC), u32:31); +} + +const LL_DELTA_CODE = u32:19; +const LL_TO_CODE = u6[64]:[ + u6:0, u6:1, u6:2, u6:3, u6:4, u6:5, u6:6, u6:7, + u6:8, u6:9, u6:10, u6:11, u6:12, u6:13, u6:14, u6:15, + u6:16, u6:16, u6:17, u6:17, u6:18, u6:18, u6:19, u6:19, + u6:20, u6:20, u6:20, u6:20, u6:21, u6:21, u6:21, u6:21, + u6:22, u6:22, u6:22, u6:22, u6:22, u6:22, u6:22, u6:22, + u6:23, u6:23, u6:23, u6:23, u6:23, u6:23, u6:23, u6:23, + u6:24, u6:24, u6:24, u6:24, u6:24, u6:24, u6:24, u6:24, + u6:24, u6:24, u6:24, u6:24, u6:24, u6:24, u6:24, u6:24 +]; + +// https://github.com/facebook/zstd/blob/5e7d721235e924b349b0e4b8b56860cf0e416394/lib/compress/zstd_compress_internal.h#L584 +fn ll_to_code(litLength: u32) -> u6 { + if litLength > u32:63 { (highbit(litLength) + LL_DELTA_CODE) as u6 } else { LL_TO_CODE[litLength] } +} + +#[test] +fn test_ll_to_code() { + assert_eq(ll_to_code(u32: 18), u6:17); // val from LUT + assert_eq(ll_to_code(u32: 63), u6:24); // val from LUT + assert_eq(ll_to_code(u32: 64), u6:25); // hbit=6, 6 + 19 = 25 + assert_eq(ll_to_code(u32: 255), u6:26); // hbit=7, 7 + 19 = 26 + assert_eq(ll_to_code(u32: 256), u6:27); // hbit=8, 8 + 19 = 27 + assert_eq(ll_to_code(u32: 0xFFFF_FFFF), u6:50); // hbit=31, 31 + 19 = 50 +} + +const ML_DELTA_CODE = u32:36; +const ML_TO_CODE = u7[128]:[ + u7:0, u7:1, u7:2, u7:3, u7:4, u7:5, u7:6, u7:7, u7:8, u7:9, u7:10, u7:11, u7:12, u7:13, u7:14, u7:15, + u7:16, u7:17, u7:18, u7:19, u7:20, u7:21, u7:22, u7:23, u7:24, u7:25, u7:26, u7:27, u7:28, u7:29, u7:30, u7:31, + u7:32, u7:32, u7:33, u7:33, u7:34, u7:34, u7:35, u7:35, u7:36, u7:36, u7:36, u7:36, u7:37, u7:37, u7:37, u7:37, + u7:38, u7:38, u7:38, u7:38, u7:38, u7:38, u7:38, u7:38, u7:39, u7:39, u7:39, u7:39, u7:39, u7:39, u7:39, u7:39, + u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, u7:40, + u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, u7:41, + u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, + u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42, u7:42 +]; + +// https://github.com/facebook/zstd/blob/5e7d721235e924b349b0e4b8b56860cf0e416394/lib/compress/zstd_compress_internal.h#L584 +fn ml_to_code(mlBase: u32) -> u7 { + if mlBase > u32:127 { (highbit(mlBase) + ML_DELTA_CODE) as u7 } else { ML_TO_CODE[mlBase] } +} + +#[test] +fn test_ml_to_code() { + assert_eq(ml_to_code(u32: 18), u7:18); // val from LUT + assert_eq(ml_to_code(u32: 127), u7:42); // val from LUT + assert_eq(ml_to_code(u32: 128), u7:43); // hbit=7, 7 + 36 = 43 + assert_eq(ml_to_code(u32: 255), u7:43); // hbit=7, 7 + 36 = 43 + assert_eq(ml_to_code(u32: 256), u7:44); // hbit=8, 8 + 36 = 44 + assert_eq(ml_to_code(u32: 0xFFFF_FFFF), u7:67); // hbit=31, 31 + 36 = 67 +} + +const LL_CODE_TO_LEN = u5[36]:[ + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:1, u5:1, u5:1, u5:1, u5:2, u5:2, u5:3, u5:3, + u5:4, u5:6, u5:7, u5:8, u5:9, u5:10, u5:11, u5:12, + u5:13, u5:14, u5:15, u5:16 +]; + +const ML_CODE_TO_LEN = u5[53]: [ + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, u5:0, + u5:1, u5:1, u5:1, u5:1, u5:2, u5:2, u5:3, u5:3, + u5:4, u5:4, u5:5, u5:7, u5:8, u5:9, u5:10, u5:11, + u5:12, u5:13, u5:14, u5:15, u5:16 +]; + +pub const SEQUENCE_RECORD_W = u32:48; +const SEQUENCE_RECORD_B = SEQUENCE_RECORD_W / u32:8; + +pub struct Sequence { + literals_len: u16, + offset: u16, + match_len: u16 +} + +fn sequence_to_codes(seq: Sequence) -> (u7, u6, u6) { + ( + ml_to_code(seq.match_len as u32), + ll_to_code(seq.literals_len as u32), + highbit(seq.offset as u32) as u6 + ) +} + +fn get_sequence_addr(base: uN[ADDR_W], count: u17, iter: uN[ADDR_W]) -> uN[ADDR_W] { + let incr = (count - u17:1) as uN[ADDR_W] - iter; + base + incr * SEQUENCE_RECORD_B as uN[ADDR_W] +} + +pub enum SequenceEncoderStatus: u1 { + OK = 0, + ERROR = 1, +} + +pub struct SequenceEncoderReq { + addr: uN[ADDR_W], + seq_addr: uN[ADDR_W], + seq_cnt: u17, +} + +pub struct SequenceEncoderResp { + status: SequenceEncoderStatus, + length: uN[ADDR_W] +} + +struct SequenceEncoderState { + active: bool, + req: SequenceEncoderReq, + iter: uN[ADDR_W], + ll_acc_log: u16, + ml_acc_log: u16, + of_acc_log: u16, + // see: https://github.com/facebook/zstd/blob/f9e26bb42bf2f2cd640829ea9deafbd398e6106f/lib/compress/zstd_compress_sequences.c#L311-L381 + ll_value: u16, + ml_value: u16, + of_value: u16, + bytes_written: uN[ADDR_W] +} + +fn deserialize_sequence(data: uN[SEQUENCE_RECORD_W]) -> Sequence { + Sequence { + literals_len: data[32:48], + offset: data[16:32], + match_len: data[0:16] + } +} + +pub fn serialize_sequence(seq: Sequence) -> uN[SEQUENCE_RECORD_W] { + seq.literals_len ++ seq.offset ++ seq.match_len +} + +struct Delta { + find_state: u32, + nb_bits: u32 +} + +pub fn serialize_tt(delta: Delta) -> uN[RAM_DATA_W] { + delta.find_state ++ delta.nb_bits +} + +fn deserialize_tt(data: uN[RAM_DATA_W]) -> Delta { + Delta { + find_state: data[32:64], + nb_bits: data[0:32] + } +} + +fn initial_value_address(tt: Delta) -> uN[RAM_ADDR_W] { + let nb_bits_out = (tt.nb_bits + (u32:1<> u32:16; + let value = (nb_bits_out << u32:16) - tt.nb_bits; + (value >> nb_bits_out) + tt.find_state +} + +fn next_value_address_nbits(tt:Delta, value: u16) -> (uN[RAM_ADDR_W], u5) { + let nb_bits_out = (tt.nb_bits + (value as u32)) >> u32:16; + ((value as u32 >> nb_bits_out) + tt.find_state, nb_bits_out as u5) +} + +fn add_bits(buff: uN[BUFF_W], value: uN[BUFF_W], len: uN[BUFF_SIZE_W], buff_size: uN[BUFF_SIZE_W]) -> uN[BUFF_W] { + if len == uN[BUFF_SIZE_W]:0 { + buff + } else { + let mask = (uN[BUFF_W]:1 << len) - uN[BUFF_W]:1; + let masked = value & mask; + (masked as uN[BUFF_W] << buff_size) | buff + } +} + +// generated with ZSTD: FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, DefaultMaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); +pub const OF_DEFAULT_CTABLE=u16[16]:[0x20,0x37,0x2e,0x25,0x33,0x2a,0x21,0x38,0x26,0x2f,0x2b,0x34,0x22,0x39,0x30,0x27,]; +pub const OF_DEFAULT_TTABLE=Delta[16]:[ + Delta { find_state: u32:0xffffffff, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x0, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x1, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x2, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x3, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x4, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x4, nb_bits: u32:0x4ffc0 }, + Delta { find_state: u32:0x6, nb_bits: u32:0x4ffc0 }, + Delta { find_state: u32:0x8, nb_bits: u32:0x4ffc0 }, + Delta { find_state: u32:0xb, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0xc, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0xd, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0xe, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0xf, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x10, nb_bits: u32:0x4ffe0 }, + Delta { find_state: u32:0x11, nb_bits: u32:0x4ffe0 } +]; + +// generated with ZSTD: FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); +pub const LL_DEFAULT_CTABLE=u16[32]:[0x40,0x41,0x56,0x6b,0x42,0x57,0x6c,0x58,0x6d,0x43,0x6e,0x44,0x59,0x5a,0x6f,0x45,0x70,0x46,0x5b,0x5c,0x71,0x47,0x72,0x48,0x5d,0x5e,0x73,0x49,0x74,0x5f,0x4a,0x75,]; +pub const LL_DEFAULT_TTABLE=Delta[32]:[ + Delta { find_state: u32:0xfffffffc, nb_bits: u32:0x4ff80 }, + Delta { find_state: u32:0x1, nb_bits: u32:0x4ffa0 }, + Delta { find_state: u32:0x5, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x7, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x9, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xb, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xd, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xf, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x11, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x13, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x15, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x17, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x19, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x1c, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1d, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1e, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1e, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x20, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x22, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x24, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x26, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x28, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x2a, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x2c, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x2e, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x2f, nb_bits: u32:0x4ffa0 }, + Delta { find_state: u32:0x33, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x36, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x37, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x38, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x39, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x3a, nb_bits: u32:0x5ffc0 } +]; + +// generated with ZSTD: FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); +pub const ML_DEFAULT_CTABLE=u16[32]:[0x40,0x41,0x56,0x6b,0x6c,0x42,0x57,0x6d,0x43,0x58,0x59,0x6e,0x44,0x6f,0x45,0x5a,0x5b,0x70,0x46,0x71,0x5c,0x47,0x72,0x5d,0x48,0x73,0x5e,0x49,0x74,0x5f,0x4a,0x75,]; +pub const ML_DEFAULT_TTABLE=Delta[32]:[ + Delta { find_state: u32:0xffffffff, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0xfffffffd, nb_bits: u32:0x4ff80 }, + Delta { find_state: u32:0x2, nb_bits: u32:0x4ffa0 }, + Delta { find_state: u32:0x6, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x8, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xa, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xc, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0xe, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x10, nb_bits: u32:0x5ff80 }, + Delta { find_state: u32:0x13, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x14, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x15, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x16, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x17, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x18, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x19, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1a, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1b, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1c, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1d, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1e, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x1f, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x20, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x21, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x22, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x23, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x24, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x25, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x26, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x27, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x28, nb_bits: u32:0x5ffc0 }, + Delta { find_state: u32:0x29, nb_bits: u32:0x5ffc0 } +]; + +struct SequenceEncoderBufferState { + flushing: bool, // is the flushing of the buffer in progress + pad: bool, // should pad the last write + addr: uN[ADDR_W], // destination + buffer: uN[BUFF_W], // buffer state (data) + buffer_size: uN[BUFF_SIZE_W], // buffer state (size) + bytes_written: uN[ADDR_W] // tracker for the total count of bytes written +} + +struct SequenceEncoderBufferInstr { + set_addr: bool, // set destination address in memory (i.e. where the data will be flushed to) + write: bool, // write data to buffer + flush: bool, // force flushing of data (only multiples of DATA_W, remainder will be left in a buffer) + pad: bool // flush the entire buffer (also the remainder) by padding it with zeros +} +const NOP = zero!(); + +struct SequenceEncoderBufferReq { + instr: SequenceEncoderBufferInstr, // currently processed instruction + write_data: uN[BUFF_W], // data to write (write instruction) + write_data_size: uN[BUFF_SIZE_W], // size of the data to write in **bits** (write instruction) + addr: uN[ADDR_W], // destination (set_addr instruction) +} + +struct SequenceEncoderBufferSync { + bytes_written: uN[ADDR_W] +} + +// A shift buffer for writing the encoded fse bitstream to memory +// It reads the data from the encoder (write) and periodically flushes part of data to the memory. +// The data is flushed at request (flush) and when the slack of the buffer is written to (which is last MINIMAL_SLACK bytes). +// When flushing without padding (flushing: true, pad: false), a remainder of at most DATA_W - 1 bits might be left in the buffer +// When flushing with padding (flushing: true, pad: true), entire buffer will be written to memory and the remaining bits will be padded with zeros +// +// Typical usage pattern +// 1. send set_addr command +// 2. keep sending data using write_command +// 3. on last write send also flush and pad commands +proc SequenceEncoderBuffer< + ADDR_W: u32, DATA_W: u32, BUFF_W: u32, + BUFF_SIZE_W: u32 = { std::clog2(BUFF_W + u32:1) } +> { + type State = SequenceEncoderBufferState; + type Req = SequenceEncoderBufferReq; + type Sync = SequenceEncoderBufferSync; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + init {zero!()} + + req_r: chan in; + sync_s: chan out; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + config( + req_r: chan in, + sync_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in + ) { + ( + req_r, sync_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ) + } + + next(state: State) { + type BuffSize = uN[BUFF_SIZE_W]; + type Addr = uN[ADDR_W]; + const DATA_B = DATA_W / u32:8; + const MINIMAL_SLACK = BuffSize:16 * BuffSize:6; + // it's the max data size the buffer can get from the encoder + // max ll/ml/of_value is 16 bit, max ll/ml/of is 16 bit + // the buffer receives at most 3 x zz_value and 3 x zz in a single write (thus 16 * 6) + let tok = join(); + + if !state.flushing { + let (tok, req) = recv(tok, req_r); + + // WRITE + let next_size = req.write_data_size + state.buffer_size; + let buffer = if req.instr.write { + trace_fmt!("[SequenceEncoderBuffer] Writing data from request {:#x} (size={})", req.write_data, req.write_data_size); + let buffer = add_bits(state.buffer, req.write_data, req.write_data_size, state.buffer_size); + trace_fmt!("[SequenceEncoderBuffer] buffer state: {:#b} (size={})", buffer, next_size); + buffer + } else { + state.buffer + }; + + // SET_ADDR + let addr = if req.instr.set_addr { + trace_fmt!("[SequenceEncoderBuffer] setting address {:#x}", req.addr); + req.addr + } else { + state.addr + }; + + // FLUSH or flushing condition met + let flush = (req.instr.flush || BUFF_W as BuffSize - next_size < MINIMAL_SLACK) && (req.instr.pad || state.buffer_size >= DATA_W as BuffSize); + let addr = if flush { + let length = if req.instr.pad { std::ceil_div(next_size as u32, u32:8) } else { (next_size as u32 / DATA_W) * DATA_B }; + let tok = send(tok, mem_wr_req_s, MemWriterReq{ + addr: addr, + length: length + }); + trace_fmt!("[SequenceEncoderBuffer] Flushing {} B to {:#x}", length, addr); + addr + length + } else { + let tok = send(tok, sync_s, Sync { bytes_written: Addr:0 }); + addr + }; + + State { + flushing: flush, + pad: req.instr.pad, + addr: addr, + buffer: buffer, + buffer_size: next_size, + bytes_written: Addr:0 + } + } else if state.buffer_size < DATA_W as BuffSize && state.pad { + let to_write = state.buffer[s32:0:DATA_W as s32]; + let length =std::ceil_div(state.buffer_size as u32, u32:8) as u32; + + trace_fmt!("[SequenceEncoderBuffer] writing {:#x}", to_write); + + + let tok = send(tok, mem_wr_data_s, MemWriterData { + data: to_write as uN[DATA_W], + length: length, + last: true + }); + let (tok, _) = recv(tok, mem_wr_resp_r); + let tok = send(tok, sync_s, Sync { bytes_written: length + state.bytes_written }); + + State { + flushing: false, + buffer: zero!(), + buffer_size: BuffSize:0, + bytes_written: Addr:0, + ..state + } + } else if state.buffer_size < DATA_W as BuffSize { + let (tok, _) = recv(tok, mem_wr_resp_r); + + let tok = send(tok, sync_s, Sync { bytes_written: state.bytes_written }); + + State { + bytes_written: Addr:0, + flushing: false, + ..state + } + } else { + let to_write = state.buffer[s32:0:DATA_W as s32]; + trace_fmt!("[SequenceEncoderBuffer] writing {:#x}", to_write); + let tok = send(tok, mem_wr_data_s, MemWriterData { + data: to_write, + length: DATA_B, + last: false + }); + + State { + buffer: state.buffer >> DATA_W, + buffer_size: state.buffer_size - DATA_W as BuffSize, + bytes_written: state.bytes_written + DATA_B, + ..state + } + } + } +} + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; +const INST_BUFF_W = u32: 1024; +const INST_BUFF_SIZE_W = std::clog2(INST_BUFF_W + u32:1); +proc SequenceEncoderBufferInst { + type Req = SequenceEncoderBufferReq; + type Sync = SequenceEncoderBufferSync; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + config( + req_r: chan in, + sync_s: chan out, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in + ) { + spawn SequenceEncoderBuffer + ( + req_r, sync_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ); + } + init {} + next(state:()) {} +} + +pub proc SequenceEncoder< + ADDR_W: u32, DATA_W: u32, RAM_ADDR_W: u32, + CTABLE_RAM_DATA_W: u32, CTABLE_RAM_NUM_PARTITIONS: u32, + TTABLE_RAM_DATA_W: u32, TTABLE_RAM_NUM_PARTITIONS: u32, + BUFF_W: u32, BUFF_SIZE_W: u32 = { std::clog2(BUFF_W + u32:1) } +> { + type Req = SequenceEncoderReq; + type Resp = SequenceEncoderResp; + type Status = SequenceEncoderStatus; + type State = SequenceEncoderState; + + type HeaderReq = sequence_conf_enc::SequenceSectionHeaderWriterReq; + type HeaderResp = sequence_conf_enc::SequenceSectionHeaderWriterResp; + type HeaderStatus = sequence_conf_enc::SequenceSectionHeaderWriterStatus; + type BufferReq = SequenceEncoderBufferReq; + type BufferSync = SequenceEncoderBufferSync; + type CompressionMode = common::CompressionMode; + + type CTableRamRdReq = ram::ReadReq; + type CTableRamRdResp = ram::ReadResp; + type TTableRamRdReq = ram::ReadReq; + type TTableRamRdResp = ram::ReadResp; + + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type WiderMemReaderResp = mem_reader::MemReaderResp; + + type MemReaderStatus = mem_reader::MemReaderStatus; + + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + init { zero!() } + + req_r: chan in; + resp_s: chan out; + + sh_req_s: chan out; + sh_resp_r: chan in; + + sb_req_s: chan out; + sb_sync_r: chan in; + + mem_rd_req_s: chan out; + mem_rd_resp_r: chan in; + + ml_ctable_buf_req_s: chan out; + ml_ctable_buf_resp_r: chan in; + ll_ctable_buf_req_s: chan out; + ll_ctable_buf_resp_r: chan in; + of_ctable_buf_req_s: chan out; + of_ctable_buf_resp_r: chan in; + ml_ttable_buf_req_s: chan out; + ml_ttable_buf_resp_r: chan in; + ll_ttable_buf_req_s: chan out; + ll_ttable_buf_resp_r: chan in; + of_ttable_buf_req_s: chan out; + of_ttable_buf_resp_r: chan in; + + + config( + req_r: chan in, + resp_s: chan out, + + mem_rd_req_s: chan out, + mem_rd_resp_r: chan in, + mem_wr_req_s: chan out, + mem_wr_data_s: chan out, + mem_wr_resp_r: chan in, + + ml_ctable_buf_req_s: chan out, + ml_ctable_buf_resp_r: chan in, + ll_ctable_buf_req_s: chan out, + ll_ctable_buf_resp_r: chan in, + of_ctable_buf_req_s: chan out, + of_ctable_buf_resp_r: chan in, + + ml_ttable_buf_req_s: chan out, + ml_ttable_buf_resp_r: chan in, + ll_ttable_buf_req_s: chan out, + ll_ttable_buf_resp_r: chan in, + of_ttable_buf_req_s: chan out, + of_ttable_buf_resp_r: chan in + ) { + let (sh_req_s, sh_req_r) = chan("sh_req"); + let (sh_resp_s, sh_resp_r) = chan("sh_resp"); + let (sb_req_s, sb_req_r) = chan("sb_req"); + let (sb_sync_s, sb_sync_r) = chan("sb_sync"); + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[u32:2]("n_mem_wr_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[u32:2]("n_mem_wr_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[u32:2]("n_mem_wr_resp"); + let (wider_mem_rd_resp_s, wider_mem_rd_resp_r) = chan("wider_mem_rd_resp"); + + + spawn mem_reader_data_upscaler::MemReaderDataUpscaler ( + mem_rd_resp_r, wider_mem_rd_resp_s + ); + + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + spawn sequence_conf_enc::SequenceHeaderWriter + ( + sh_req_r, sh_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0] + ); + + spawn SequenceEncoderBuffer + ( + sb_req_r, sb_sync_s, + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1] + ); + + ( + req_r, resp_s, + sh_req_s, sh_resp_r, + sb_req_s, sb_sync_r, + mem_rd_req_s, wider_mem_rd_resp_r, + ml_ctable_buf_req_s, ml_ctable_buf_resp_r, ll_ctable_buf_req_s, ll_ctable_buf_resp_r, of_ctable_buf_req_s, of_ctable_buf_resp_r, + ml_ttable_buf_req_s, ml_ttable_buf_resp_r, ll_ttable_buf_req_s, ll_ttable_buf_resp_r, of_ttable_buf_req_s, of_ttable_buf_resp_r + ) + } + + next(state: State) { + const DEFAULT_LL_ACC_LOG = u32:6; + const DEFAULT_ML_ACC_LOG = u32:6; + const DEFAULT_OF_ACC_LOG = u32:5; + const TT_FULL_MASK = all_ones!(); + const CT_FULL_MASK = all_ones!(); + type Addr = uN[ADDR_W]; + + let tok = join(); + if (!state.active) { + let (tok, req) = recv(tok, req_r); + trace_fmt!("[SequenceEncoder] Received request: {:#x}", req); + + // step 1. write the header + let tok = send(tok, sh_req_s, HeaderReq { + addr: req.addr, + conf: common::SequenceConf { + sequence_count: req.seq_cnt, + literals_mode: CompressionMode::PREDEFINED, + offset_mode: CompressionMode::PREDEFINED, + match_mode: CompressionMode::PREDEFINED + } + }); + let (tok, sh_resp) = recv(tok, sh_resp_r); + assert_eq(sh_resp.status, HeaderStatus::OK); + + if req.seq_cnt == u17:0 { + // corner case: no sequences + trace_fmt!("[SequenceEncoder] Warning! Called with seq_cnt=0"); + let resp = Resp { + status: Status::OK, + length: sh_resp.length + }; + let tok = send(tok, resp_s, resp); + zero!() + } else { + // TODO: get ll, ml, of acc logs from compression table + // TODO: write the compression table + // step 2. read the first sequence + let addr = get_sequence_addr(req.seq_addr, req.seq_cnt, u32:0); + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: addr, + length: SEQUENCE_RECORD_B + }); + let (tok, seq) = recv(tok, mem_rd_resp_r); + let serialized = seq.data; + let seq = deserialize_sequence(serialized as uN[SEQUENCE_RECORD_W]); + trace_fmt!("[SequenceEncoder] Serialized sequence {:#x} (at {:#x}) Deserialized sequence: {:#x}", serialized, addr, seq); + let (ml, ll, of) = sequence_to_codes(seq); + trace_fmt!("[SequenceEncoder] Received sequence[{:#x}]={:#x} (serialized={:#x}), encoded(ml={:#x}, ll={:#x}, of={:#x})", addr, seq, serialized, ml, ll, of); + + // step 3. read first delta info + let tok = send(tok, ll_ttable_buf_req_s, TTableRamRdReq { addr: ll as Addr, mask: TT_FULL_MASK }); + let tok = send(tok, ml_ttable_buf_req_s, TTableRamRdReq { addr: ml as Addr, mask: TT_FULL_MASK }); + let tok = send(tok, of_ttable_buf_req_s, TTableRamRdReq { addr: of as Addr, mask: TT_FULL_MASK }); + let (tok, ll_tt) = recv(tok, ll_ttable_buf_resp_r); + let (tok, ml_tt) = recv(tok, ml_ttable_buf_resp_r); + let (tok, of_tt) = recv(tok, of_ttable_buf_resp_r); + let ll_tt = deserialize_tt(ll_tt.data); + let ml_tt = deserialize_tt(ml_tt.data); + let of_tt = deserialize_tt(of_tt.data); + + let ll_value_addr = initial_value_address(ll_tt); + let ml_value_addr = initial_value_address(ml_tt); + let of_value_addr = initial_value_address(of_tt); + + // step 4. read the first symbol encoding + let tok = send(tok, ll_ctable_buf_req_s, CTableRamRdReq { addr: ll_value_addr, mask: CT_FULL_MASK}); + let tok = send(tok, ml_ctable_buf_req_s, CTableRamRdReq { addr: ml_value_addr, mask: CT_FULL_MASK}); + let tok = send(tok, of_ctable_buf_req_s, CTableRamRdReq { addr: of_value_addr, mask: CT_FULL_MASK}); + let (tok, ll_enc) = recv(tok, ll_ctable_buf_resp_r); + let (tok, ml_enc) = recv(tok, ml_ctable_buf_resp_r); + let (tok, of_enc) = recv(tok, of_ctable_buf_resp_r); + + trace_fmt!( + "[SequenceEncoder] Addresses: {:#x} {:#x} {:#x} Deltas: {:#x} {:#x} {:#x} Encoded: {:#x} {:#x} {:#x}", + ll_value_addr, ml_value_addr, of_value_addr, ll_tt, ml_tt, of_tt, ll_enc, ml_enc, of_enc + ); + + // step 5. write raw literal, match_len & offset + // order: + // - ll from sequence + // - ml from sequence + // - of from sequence + // https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/compress/zstd_compress_sequences.c#L314-L317 + // https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/compress/zstd_compress_sequences.c#L328 + + let write_size = uN[BUFF_SIZE_W]:0; + let to_write = add_bits(zero!(), seq.literals_len as uN[BUFF_W], LL_CODE_TO_LEN[ll] as uN[BUFF_SIZE_W], write_size); + let write_size = LL_CODE_TO_LEN[ll] as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, seq.match_len as uN[BUFF_W], ML_CODE_TO_LEN[ml] as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + ML_CODE_TO_LEN[ml] as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, seq.offset as uN[BUFF_W], of as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + of as uN[BUFF_SIZE_W]; + + let tok = send(tok, sb_req_s, BufferReq { + instr: SequenceEncoderBufferInstr {write: true, set_addr: true, ..NOP}, + write_data: to_write, + write_data_size: write_size, + addr: req.addr + sh_resp.length + }); + let (tok, sync) = recv(tok, sb_sync_r); + + // step 6. initialize state based on the last sequence read + // https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/common/fse.h#L443-L452 + State { + active: true, + req: req, + iter: Addr:1, + ll_acc_log: DEFAULT_LL_ACC_LOG as u16, + ml_acc_log: DEFAULT_ML_ACC_LOG as u16, + of_acc_log: DEFAULT_OF_ACC_LOG as u16, + ll_value: ll_enc.data, + ml_value: ml_enc.data, + of_value: of_enc.data, + bytes_written: sync.bytes_written + sh_resp.length + } + } + + } else if state.req.seq_cnt as Addr == state.iter { + // step 11. write the final encoded values + // order: + // - ml value + // - of value + // - ll value + // - end mark + // https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/compress/zstd_compress_sequences.c#L372-L380 + + let write_size = uN[BUFF_SIZE_W]:0; + let to_write = add_bits(zero!(), state.ml_value as uN[BUFF_W], state.ml_acc_log as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + state.ml_acc_log as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, state.of_value as uN[BUFF_W], state.of_acc_log as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + state.of_acc_log as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, state.ll_value as uN[BUFF_W], state.ll_acc_log as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + state.ll_acc_log as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, uN[BUFF_W]:1, uN[BUFF_SIZE_W]:1, write_size); // end mark + let write_size = write_size + uN[BUFF_SIZE_W]:1; + + + trace_fmt!("[SequenceEncoder] Sent (final) {:#x}", to_write); + let tok = send(tok, sb_req_s, BufferReq { + instr: SequenceEncoderBufferInstr { flush: true, pad: true, write: true, ..NOP}, + write_data: to_write, + write_data_size: write_size, + addr: uN[ADDR_W]:0 + }); + let (tok, sync) = recv(tok, sb_sync_r); + + let resp = Resp { + status: Status::OK, + length: state.bytes_written + sync.bytes_written + }; + let tok = send(tok, resp_s, resp); + zero!() + } else { + + // step 7. read next sequence + let addr = get_sequence_addr(state.req.seq_addr, state.req.seq_cnt, state.iter); + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: addr, + length: SEQUENCE_RECORD_B + }); + let (tok, seq) = recv(tok, mem_rd_resp_r); + let serialized = seq.data; + let seq = deserialize_sequence(serialized as uN[SEQUENCE_RECORD_W]); + let (ml, ll, of) = sequence_to_codes(seq); + trace_fmt!("[SequenceEncoder] Received sequence[{:#x}]={:#x} (serialized={:#x}), encoded(ml={:#x}, ll={:#x}, of={:#x})", addr, seq, serialized, ml, ll, of); + + // step 8. read delta info + let tok = send(tok, ll_ttable_buf_req_s, TTableRamRdReq { addr: ll as Addr, mask: TT_FULL_MASK }); + let tok = send(tok, ml_ttable_buf_req_s, TTableRamRdReq { addr: ml as Addr, mask: TT_FULL_MASK }); + let tok = send(tok, of_ttable_buf_req_s, TTableRamRdReq { addr: of as Addr, mask: TT_FULL_MASK }); + let (tok, ll_tt) = recv(tok, ll_ttable_buf_resp_r); + let (tok, ml_tt) = recv(tok, ml_ttable_buf_resp_r); + let (tok, of_tt) = recv(tok, of_ttable_buf_resp_r); + let ll_tt = deserialize_tt(ll_tt.data); + let ml_tt = deserialize_tt(ml_tt.data); + let of_tt = deserialize_tt(of_tt.data); + let (ll_value_addr, ll_nbits) = next_value_address_nbits(ll_tt, state.ll_value); + let (ml_value_addr, ml_nbits) = next_value_address_nbits(ml_tt, state.ml_value); + let (of_value_addr, of_nbits) = next_value_address_nbits(of_tt, state.of_value); + + // step 9. read next address + let tok = send(tok, ll_ctable_buf_req_s, CTableRamRdReq { addr: ll_value_addr, mask: CT_FULL_MASK}); + let tok = send(tok, ml_ctable_buf_req_s, CTableRamRdReq { addr: ml_value_addr, mask: CT_FULL_MASK}); + let tok = send(tok, of_ctable_buf_req_s, CTableRamRdReq { addr: of_value_addr, mask: CT_FULL_MASK}); + let (tok, ll_enc) = recv(tok, ll_ctable_buf_resp_r); + let (tok, ml_enc) = recv(tok, ml_ctable_buf_resp_r); + let (tok, of_enc) = recv(tok, of_ctable_buf_resp_r); + + trace_fmt!( + "[SequenceEncoder] Addresses: {:#x} {:#x} {:#x} Deltas: {:#x} {:#x} {:#x} Encoded: {:#x} {:#x} {:#x} nbits: {} {} {}", + ll_value_addr, ml_value_addr, of_value_addr, ll_tt, ml_tt, of_tt, ll_enc, ml_enc, of_enc, ll_nbits, ml_nbits, of_nbits + ); + + // step 10. write raw literal values and encoded symbols from previous iteration + // order: + // - of value + // - ml value + // - ll value + // - ll from sequence + // - ml from sequence + // - of from sequence + // https://github.com/facebook/zstd/blob/e128976193546dceb24249206a02ff8f444f7120/lib/compress/zstd_compress_sequences.c#L345-L368 + let write_size = uN[BUFF_SIZE_W]:0; + let to_write = add_bits(zero!(), state.of_value as uN[BUFF_W], of_nbits as uN[BUFF_SIZE_W], write_size); + let write_size = of_nbits as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, state.ml_value as uN[BUFF_W], ml_nbits as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + ml_nbits as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, state.ll_value as uN[BUFF_W], ll_nbits as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + ll_nbits as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, seq.literals_len as uN[BUFF_W], LL_CODE_TO_LEN[ll] as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + LL_CODE_TO_LEN[ll] as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, seq.match_len as uN[BUFF_W], ML_CODE_TO_LEN[ml] as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + ML_CODE_TO_LEN[ml] as uN[BUFF_SIZE_W]; + let to_write = add_bits(to_write, seq.offset as uN[BUFF_W], of as uN[BUFF_SIZE_W], write_size); + let write_size = write_size + of as uN[BUFF_SIZE_W]; + + let tok = send(tok, sb_req_s, BufferReq { + instr: SequenceEncoderBufferInstr { write: true, ..NOP}, + write_data: to_write, + write_data_size: write_size, + addr: uN[ADDR_W]:0 + }); + let (tok, sync) = recv(tok, sb_sync_r); + trace_fmt!("[SequenceEncoder] Sent {:#x}", to_write); + + State { + active: true, + iter: state.iter + Addr:1, + ll_value: ll_enc.data, + ml_value: ml_enc.data, + of_value: of_enc.data, + bytes_written: state.bytes_written + sync.bytes_written, + ..state + } + } + } +} + +const TEST_ADDR_W = u32:32; +const TEST_DATA_W = u32:64; +const TEST_DATA_W_DIV8 = TEST_DATA_W / u32:8; +const TEST_DEST_W = u32:8; +const TEST_ID_W = u32:8; +const TEST_WRITER_ID = u32:1; + +const TEST_RAM_DATA_W = TEST_DATA_W; +const TEST_RAM_SIZE = u32:4096; +const TEST_RAM_ADDR_W = TEST_ADDR_W; +const TEST_RAM_PARTITION_SIZE = u32:8; +const TEST_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_RAM_PARTITION_SIZE, TEST_RAM_DATA_W); +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; +const TEST_RAM_ASSERT_VALID_READ = true; + +const TEST_CT_DATA_W = u32:16; +const TEST_TT_DATA_W = u32:64; +const TEST_T_PARTITION_SIZE = u32:8; +const TEST_CT_NUM_PARTITIONS = ram::num_partitions(TEST_T_PARTITION_SIZE, TEST_CT_DATA_W); +const TEST_TT_NUM_PARTITIONS = ram::num_partitions(TEST_T_PARTITION_SIZE, TEST_TT_DATA_W); + +const TEST_BUFF_W = u32:256; +const TEST_BUFF_SIZE_W = std::clog2(TEST_BUFF_W + u32:1); + +const TEST_OUTPUT_ADDR = uN[TEST_ADDR_W]:0x100; +const TEST_SEQUENCES_CNT = u32:8; +const TEST_SEQUENCES = Sequence[TEST_SEQUENCES_CNT]:[ + Sequence { literals_len: u16:1, offset: u16:4, match_len: u16:0 }, + Sequence { literals_len: u16:0, offset: u16:5, match_len: u16:2 }, + Sequence { literals_len: u16:1, offset: u16:13, match_len: u16:1 }, + Sequence { literals_len: u16:0, offset: u16:7, match_len: u16:1 }, + Sequence { literals_len: u16:0, offset: u16:1, match_len: u16:0 }, + Sequence { literals_len: u16:0, offset: u16:11, match_len: u16:0 }, + Sequence { literals_len: u16:0, offset: u16:13, match_len: u16:0 }, + Sequence { literals_len: u16:0, offset: u16:25, match_len: u16:0 } +]; + +const EXPECTED_DATA_LEN = u32:19; +const EXPECTED_DATA = [ + // sequence header + u8:0x08, // sequence count + u8:0x00, // compression modes + // encoded sequences + u8:0x39, + u8:0x01, + u8:0x68, + u8:0x01, + u8:0x60, + u8:0x05, + u8:0x00, + u8:0x00, + u8:0xb0, + u8:0x0b, + u8:0x68, + u8:0x89, + u8:0xcb, + u8:0x5d, + u8:0x01, + u8:0xe0, + u8:0xae, +]; + +#[test_proc] +proc SequenceEncoderBufferTest { + type Req = SequenceEncoderBufferReq; + type Instr = SequenceEncoderBufferInstr; + type Sync = SequenceEncoderBufferSync; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + init {} + + req_s: chan out; + sync_r: chan in; + mem_wr_req_r: chan in; + mem_wr_data_r: chan in; + mem_wr_resp_s: chan out; + terminator: chan out; + + config(terminator: chan out) { + let (req_s, req_r) = chan("req"); + let (sync_s, sync_r) = chan("sync"); + + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + + spawn SequenceEncoderBuffer + ( + req_r, sync_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r + ); + + ( + req_s, sync_r, + mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s, + terminator + ) + } + + next(state: ()) { + type Addr = uN[TEST_ADDR_W]; + type Data = uN[TEST_BUFF_W]; + type RespData = uN[TEST_DATA_W]; + type Sz = uN[TEST_BUFF_SIZE_W]; + let tok = join(); + + // 1. set address + let tok = send(tok, req_s, Req { + instr: Instr { set_addr: true, ..NOP }, + addr: Addr:0xB16B00B5, + ..zero!() + }); + + // 2. send some data + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: Data:0b11010110, + write_data_size: Sz:8, + addr: Addr:0 + }); + let tok = send(tok, req_s, Req { + instr: Instr { write: true, flush: true, ..NOP }, // this flush shouldn't do anything + write_data: Data:0b110, + write_data_size: Sz:3, + addr: Addr:0 + }); + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: Data:0b1101110111010101010100001101110111010101010100000000000000000000, + write_data_size: Sz:64, + addr: Addr:0 + }); + // 3. force flush + let tok = send(tok, req_s, Req { + instr: Instr { flush: true, ..NOP }, + ..zero!() + }); + let (tok, req) = recv(tok, mem_wr_req_r); + assert_eq(req, MemWriterReq { + addr: Addr:0xB16B00B5, + length: Addr:8 + }); + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + data: RespData:0b10101010100001101110111010101010100000000000000000000_110_11010110, + length: Addr:8, + last: false + }); + let tok = send(tok, mem_wr_resp_s, zero!()); + // 4. send more data + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: all_ones!(), + write_data_size: TEST_BUFF_W as Sz - Sz:11 - Sz:96, // brings buffer to BUFF_W - SLACK size + addr: Addr:0 + }); + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: Data:0b1, + write_data_size: Sz:1, // causes the buffer to flush + addr: Addr:0 + }); + // 5. implicit flush + let (tok, req) = recv(tok, mem_wr_req_r); + trace_fmt!("{}", req); + assert_eq(req, MemWriterReq { + addr: Addr:0xB16B00BD, + length: Addr:16, + }); + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + data: RespData: 0b11111111111111111111111111111111111111111111111111111_11011101110, + length: Addr:8, + last: false + }); + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + data: RespData: 0xFFFFFFFFFFFFFFFF, + length: Addr:8, + last: false + }); + let tok = send(tok, mem_wr_resp_s, zero!()); + // 6. send more data + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: Data:0b10101110100010100101010101001111110101010100100001101010101010101, + write_data_size: Sz:65, + addr: Addr:0 + }); + let tok = send(tok, req_s, Req { + instr: Instr { write: true, ..NOP }, + write_data: Data:0b101010100100001101010101010101, + write_data_size: Sz:30, + addr: Addr:0 + }); + // 7. flush with padding + let tok = send(tok, req_s, Req { + instr: Instr { write: true, flush: true, pad: true, ..NOP }, + write_data: Data:0b111100101010100100001101010101010101, + write_data_size: Sz:36, + addr: Addr:0 + }); + + let (tok, req) = recv(tok, mem_wr_req_r); + assert_eq(req, MemWriterReq { + addr: Addr:0xb16b00cd, + length: Addr: 21 + }); + + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + data: RespData: 0b0101010100100001101010101010101_111111111111111111111111111111111, + length: Addr: 8, + last: false + }); + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + data: RespData: 0b101010100100001101010101010101_1010111010001010010101010100111111, + length: Addr: 8, + last: false + }); + + let (tok, data) = recv(tok, mem_wr_data_r); + assert_eq(data, MemWriterData { + // p - padding pppp + data: RespData: 0b0000_111100101010100100001101010101010101, + length: Addr: 5, + last: true + }); + send(tok, terminator, true); + } +} + +// #[test_proc] +proc SequenceEncoderPredefinedTest { + type Req = SequenceEncoderReq; + type Resp = SequenceEncoderResp; + type Addr = uN[TEST_ADDR_W]; + type Length = uN[TEST_ADDR_W]; + + type CTRamWrReq = ram::WriteReq; + type CTRamRdReq = ram::ReadReq; + type CTRamRdResp = ram::ReadResp; + type TTRamWrReq = ram::WriteReq; + type TTRamRdReq = ram::ReadReq; + type TTRamRdResp = ram::ReadResp; + type RamRdReq = ram::ReadReq; + type RamRdResp = ram::ReadResp; + type RamWrReq = ram::WriteReq; + type RamWrResp = ram::WriteResp; + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + type AxiAddr = uN[TEST_ADDR_W]; + type AxiData = uN[TEST_DATA_W]; + type AxiId = uN[TEST_ID_W]; + type AxiStrb = uN[TEST_DEST_W]; + type AxiLen = u8; + type AxiSize = axi::AxiAxSize; + type AxiBurst = axi::AxiAxBurst; + type AxiWriteResp = axi::AxiWriteResp; + + terminator: chan out; + req_s: chan out; + resp_r: chan in; + + mem_rd_req_s: chan out; + mem_rd_resp_r: chanin; + mem_wr_req_s: chan out; + mem_wr_data_s: chan out; + mem_wr_resp_r: chan in; + + ml_ctable_buf_wr_req_s: chan out; + ml_ctable_buf_wr_resp_r: chan in; + ll_ctable_buf_wr_req_s: chan out; + ll_ctable_buf_wr_resp_r: chan in; + of_ctable_buf_wr_req_s: chan out; + of_ctable_buf_wr_resp_r: chan in; + ml_ttable_buf_wr_req_s: chan out; + ml_ttable_buf_wr_resp_r: chan in; + ll_ttable_buf_wr_req_s: chan out; + ll_ttable_buf_wr_resp_r: chan in; + of_ttable_buf_wr_req_s: chan out; + of_ttable_buf_wr_resp_r: chan in; + + init {} + + config(terminator: chan out) { + let (input_ram_rd_req_s, input_ram_rd_req_r) = chan("input_ram_rd_req"); + let (input_ram_rd_resp_s, input_ram_rd_resp_r) = chan("input_ram_rd_resp"); + let (input_ram_wr_req_s, input_ram_wr_req_r) = chan("input_ram_wr_req"); + let (input_ram_wr_resp_s, input_ram_wr_resp_r) = chan("input_ram_wr_resp"); + let (ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_req_r) = chan("ll_ctable_ram_rd_req"); + let (ll_ctable_ram_rd_resp_s, ll_ctable_ram_rd_resp_r) = chan("ll_ctable_ram_rd_resp"); + let (ll_ctable_ram_wr_req_s, ll_ctable_ram_wr_req_r) = chan("ll_ctable_ram_wr_req"); + let (ll_ctable_ram_wr_resp_s, ll_ctable_ram_wr_resp_r) = chan("ll_ctable_ram_wr_resp"); + let (of_ctable_ram_rd_req_s, of_ctable_ram_rd_req_r) = chan("of_ctable_ram_rd_req"); + let (of_ctable_ram_rd_resp_s, of_ctable_ram_rd_resp_r) = chan("of_ctable_ram_rd_resp"); + let (of_ctable_ram_wr_req_s, of_ctable_ram_wr_req_r) = chan("of_ctable_ram_wr_req"); + let (of_ctable_ram_wr_resp_s, of_ctable_ram_wr_resp_r) = chan("of_ctable_ram_wr_resp"); + let (ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_req_r) = chan("ml_ctable_ram_rd_req"); + let (ml_ctable_ram_rd_resp_s, ml_ctable_ram_rd_resp_r) = chan("ml_ctable_ram_rd_resp"); + let (ml_ctable_ram_wr_req_s, ml_ctable_ram_wr_req_r) = chan("ml_ctable_ram_wr_req"); + let (ml_ctable_ram_wr_resp_s, ml_ctable_ram_wr_resp_r) = chan("ml_ctable_ram_wr_resp"); + + let (ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_req_r) = chan("ll_ttable_ram_rd_req"); + let (ll_ttable_ram_rd_resp_s, ll_ttable_ram_rd_resp_r) = chan("ll_ttable_ram_rd_resp"); + let (ll_ttable_ram_wr_req_s, ll_ttable_ram_wr_req_r) = chan("ll_ttable_ram_wr_req"); + let (ll_ttable_ram_wr_resp_s, ll_ttable_ram_wr_resp_r) = chan("ll_ttable_ram_wr_resp"); + let (of_ttable_ram_rd_req_s, of_ttable_ram_rd_req_r) = chan("of_ttable_ram_rd_req"); + let (of_ttable_ram_rd_resp_s, of_ttable_ram_rd_resp_r) = chan("of_ttable_ram_rd_resp"); + let (of_ttable_ram_wr_req_s, of_ttable_ram_wr_req_r) = chan("of_ttable_ram_wr_req"); + let (of_ttable_ram_wr_resp_s, of_ttable_ram_wr_resp_r) = chan("of_ttable_ram_wr_resp"); + let (ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_req_r) = chan("ml_ttable_ram_rd_req"); + let (ml_ttable_ram_rd_resp_s, ml_ttable_ram_rd_resp_r) = chan("ml_ttable_ram_rd_resp"); + let (ml_ttable_ram_wr_req_s, ml_ttable_ram_wr_req_r) = chan("ml_ttable_ram_wr_req"); + let (ml_ttable_ram_wr_resp_s, ml_ttable_ram_wr_resp_r) = chan("ml_ttable_ram_wr_resp"); + + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[2]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[2]("n_mem_rd_resp"); + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (mem_axi_ar_s, mem_axi_ar_r) = chan("mem_axi_ar"); + let (mem_axi_r_s, mem_axi_r_r) = chan("mem_axi_r"); + let (mem_axi_aw_s, mem_axi_aw_r) = chan("mem_axi_aw"); + let (mem_axi_w_s, mem_axi_w_r) = chan("mem_axi_w"); + let (mem_axi_b_s, mem_axi_b_r) = chan("mem_axi_b"); + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, + >( + input_ram_rd_req_r, input_ram_rd_resp_s, + input_ram_wr_req_r, input_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_CT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_CT_NUM_PARTITIONS + >( + ll_ctable_ram_rd_req_r, ll_ctable_ram_rd_resp_s, + ll_ctable_ram_wr_req_r, ll_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_CT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_CT_NUM_PARTITIONS + >( + ml_ctable_ram_rd_req_r, ml_ctable_ram_rd_resp_s, + ml_ctable_ram_wr_req_r, ml_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_CT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_CT_NUM_PARTITIONS + >( + of_ctable_ram_rd_req_r, of_ctable_ram_rd_resp_s, + of_ctable_ram_wr_req_r, of_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_TT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_TT_NUM_PARTITIONS + >( + ll_ttable_ram_rd_req_r, ll_ttable_ram_rd_resp_s, + ll_ttable_ram_wr_req_r, ll_ttable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_TT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_TT_NUM_PARTITIONS + >( + ml_ttable_ram_rd_req_r, ml_ttable_ram_rd_resp_s, + ml_ttable_ram_wr_req_r, ml_ttable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_TT_DATA_W, TEST_RAM_SIZE, TEST_T_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_RAM_ADDR_W, TEST_TT_NUM_PARTITIONS + >( + of_ttable_ram_rd_req_r, of_ttable_ram_rd_resp_s, + of_ttable_ram_wr_req_r, of_ttable_ram_wr_resp_s, + ); + + spawn axi_ram_reader::AxiRamReader< + TEST_ADDR_W, TEST_DATA_W, + TEST_DEST_W, TEST_ID_W, + TEST_RAM_SIZE, + >( + mem_axi_ar_r, mem_axi_r_s, + input_ram_rd_req_s, input_ram_rd_resp_r, + ); + + spawn axi_ram_writer::AxiRamWriter< + TEST_ADDR_W, TEST_DATA_W, TEST_ID_W, TEST_RAM_SIZE, + TEST_RAM_ADDR_W, TEST_RAM_NUM_PARTITIONS + > ( + mem_axi_aw_r, mem_axi_w_r, mem_axi_b_s, + input_ram_wr_req_s, input_ram_wr_resp_r + ); + + spawn mem_reader::MemReader< + TEST_DATA_W, TEST_ADDR_W, TEST_DEST_W, TEST_ID_W, + >( + mem_rd_req_r, mem_rd_resp_s, + mem_axi_ar_s, mem_axi_r_r, + ); + + spawn mem_writer::MemWriter( + mem_wr_req_r, mem_wr_data_r, + mem_axi_aw_s, mem_axi_w_s, mem_axi_b_r, + mem_wr_resp_s, + ); + + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn SequenceEncoder< + TEST_ADDR_W, TEST_DATA_W, TEST_RAM_ADDR_W, + TEST_CT_DATA_W, TEST_CT_NUM_PARTITIONS, + TEST_TT_DATA_W, TEST_TT_NUM_PARTITIONS, + TEST_BUFF_W + >( + req_r, resp_s, + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + ( + terminator, + req_s, resp_r, + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ml_ctable_ram_wr_req_s, ml_ctable_ram_wr_resp_r, ll_ctable_ram_wr_req_s, ll_ctable_ram_wr_resp_r, of_ctable_ram_wr_req_s, of_ctable_ram_wr_resp_r, + ml_ttable_ram_wr_req_s, ml_ttable_ram_wr_resp_r, ll_ttable_ram_wr_req_s, ll_ttable_ram_wr_resp_r, of_ttable_ram_wr_req_s, of_ttable_ram_wr_resp_r + ) + } + + next(state: ()) { + type Addr = uN[TEST_ADDR_W]; + const CTMASK = all_ones!(); + const TTMASK = all_ones!(); + let tok = join(); + + // setup test + // write default values to compression tables & transition tables + trace!("[TEST] Setting up the compression tables"); + + let tok = for ((i, v), tok) in enumerate(OF_DEFAULT_CTABLE) { + let tok = send(tok, of_ctable_buf_wr_req_s, CTRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, of_ctable_buf_wr_resp_r); + tok + }(tok); + + let tok = for ((i, v), tok) in enumerate(LL_DEFAULT_CTABLE) { + let tok = send(tok, ll_ctable_buf_wr_req_s, CTRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, ll_ctable_buf_wr_resp_r); + tok + }(tok); + + let tok = for ((i, v), tok) in enumerate(ML_DEFAULT_CTABLE) { + let tok = send(tok, ml_ctable_buf_wr_req_s, CTRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, ml_ctable_buf_wr_resp_r); + tok + }(tok); + + trace!("[TEST] Setting up the transform tables"); + + let tok = for ((i, tt), tok) in enumerate(OF_DEFAULT_TTABLE) { + let tok = send(tok, of_ttable_buf_wr_req_s, TTRamWrReq{addr: i, data: serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, of_ttable_buf_wr_resp_r); + tok + }(tok); + + let tok = for ((i, tt), tok) in enumerate(LL_DEFAULT_TTABLE) { + let tok = send(tok, ll_ttable_buf_wr_req_s, TTRamWrReq{addr: i, data: serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, ll_ttable_buf_wr_resp_r); + tok + }(tok); + + let tok = for ((i, tt), tok) in enumerate(ML_DEFAULT_TTABLE) { + let tok = send(tok, ml_ttable_buf_wr_req_s, TTRamWrReq{addr: i, data: serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, ml_ttable_buf_wr_resp_r); + tok + }(tok); + + // write sequences to memory + let tok = send(tok, mem_wr_req_s, MemWriterReq { + addr: Addr:0, + length: TEST_SEQUENCES_CNT * SEQUENCE_RECORD_B + }); + + let tok = for ((_, seq), tok) in enumerate(TEST_SEQUENCES) { + let data = u16:0 ++ serialize_sequence(seq); + trace_fmt!("[TEST] {:#x} serialized={:#x}", seq, data); + + let tok = send(tok, mem_wr_data_s, MemWriterData { + data: data, + length: SEQUENCE_RECORD_B, + last: false + }); + + tok + }(tok); + let (tok, _) = recv(tok, mem_wr_resp_r); + + // start encoding the sequences + let tok = send(tok, req_s, Req { + addr: TEST_OUTPUT_ADDR, + seq_addr: Addr:0, + seq_cnt: TEST_SEQUENCES_CNT as u17 + } + ); + trace!("[TEST] Running the encoding..."); + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp, SequenceEncoderResp { + status: SequenceEncoderStatus::OK, + length: EXPECTED_DATA_LEN + }); + trace!("[TEST] Encoding done, checking output..."); + + let tok = for ((i, expected), tok) in enumerate(EXPECTED_DATA) { + let tok = send(tok, mem_rd_req_s, MemReaderReq { + addr: TEST_OUTPUT_ADDR + i, + length: u32:1 + }); + let (tok, data) = recv(tok, mem_rd_resp_r); + + trace_fmt!("[TEST] Offset {:#x}, comparing {:#x} == {:#x}", TEST_OUTPUT_ADDR + i, expected, data.data as u8); + assert_eq(expected, data.data as u8); + tok + }(tok); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor.x b/xls/modules/zstd/sequence_executor.x deleted file mode 100644 index bcea49e1ca..0000000000 --- a/xls/modules/zstd/sequence_executor.x +++ /dev/null @@ -1,1245 +0,0 @@ -// Copyright 2024 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.zstd.common as common; -import xls.modules.zstd.memory.mem_writer as mem_writer; -import xls.modules.zstd.parallel_rams as parallel_rams; -import xls.modules.zstd.ram_printer as ram_printer; -import xls.examples.ram; - -// Configurable RAM parameters -pub const RAM_DATA_WIDTH = common::SYMBOL_WIDTH; -const RAM_NUM = u32:8; -const RAM_NUM_CLOG2 = std::clog2(RAM_NUM); - -type BlockData = common::BlockData; -type SequenceExecutorMessageType = common::SequenceExecutorMessageType; -type SequenceExecutorPacket = common::SequenceExecutorPacket; -type CopyOrMatchContent = common::CopyOrMatchContent; -type CopyOrMatchLength = common::CopyOrMatchLength; -type ZstdDecodedPacket = common::ZstdDecodedPacket; -type BlockPacketLength = common::BlockPacketLength; -type Offset = common::Offset; - -// Constants calculated from RAM parameters -const RAM_NUM_WIDTH = std::clog2(RAM_NUM); -pub const RAM_WORD_PARTITION_SIZE = RAM_DATA_WIDTH; -const RAM_ORDER_WIDTH = std::clog2(RAM_DATA_WIDTH); -pub const RAM_NUM_PARTITIONS = ram::num_partitions(RAM_WORD_PARTITION_SIZE, RAM_DATA_WIDTH); -const RAM_REQ_MASK_ALL = std::unsigned_max_value(); -const RAM_REQ_MASK_NONE = bits[RAM_NUM_PARTITIONS]:0; - -type RamOrder = bits[RAM_ORDER_WIDTH]; - -pub fn ram_size(hb_size_kb: u32) -> u32 { (hb_size_kb * u32:1024 * u32:8) / RAM_DATA_WIDTH / RAM_NUM } - -fn ram_addr_width(hb_size_kb: u32) -> u32 { std::clog2(ram_size(hb_size_kb)) } - -// RAM related constants common for tests -const TEST_HISTORY_BUFFER_SIZE_KB = u32:1; -const TEST_DATA_W = u32:64; -const TEST_ADDR_W = u32:16; -const TEST_RAM_SIZE = ram_size(TEST_HISTORY_BUFFER_SIZE_KB); -const TEST_RAM_ADDR_WIDTH = ram_addr_width(TEST_HISTORY_BUFFER_SIZE_KB); -pub const TEST_RAM_INITIALIZED = true; -pub const TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; - -type TestRamAddr = bits[TEST_RAM_ADDR_WIDTH]; -type TestWriteReq = ram::WriteReq; -type TestWriteResp = ram::WriteResp; -type TestReadReq = ram::ReadReq; -type TestReadResp = ram::ReadResp; - -type HistoryBufferPtr = parallel_rams::HistoryBufferPtr; -type RamWrRespHandlerData = parallel_rams::RamWrRespHandlerData; -type RamWrRespHandlerResp = parallel_rams::RamWrRespHandlerResp; -type RamRdRespHandlerData = parallel_rams::RamRdRespHandlerData; -type RamData = uN[RAM_DATA_WIDTH]; -type RamNumber = parallel_rams::RamNumber; -type RamReadStart = parallel_rams::RamReadStart; -type RamReadLen = parallel_rams::RamReadLen; - -enum SequenceExecutorStatus : u2 { - IDLE = 0, - LITERAL_WRITE = 1, - SEQUENCE_READ = 2, - SEQUENCE_WRITE = 3, -} - -struct SequenceExecutorState { - status: SequenceExecutorStatus, - // Packet handling - packet: SequenceExecutorPacket, - packet_valid: bool, - // History Buffer handling - hyp_ptr: HistoryBufferPtr, - real_ptr: HistoryBufferPtr, - hb_len: uN[RAM_ADDR_WIDTH + RAM_NUM_CLOG2], - // Repeat Offset handling - repeat_offsets: Offset[3], - repeat_req: bool, - seq_cnt: bool, - seq_pending: bool -} - -fn decode_literal_packet(packet: SequenceExecutorPacket) -> mem_writer::MemWriterDataPacket { - type MemWriterDataPacket = mem_writer::MemWriterDataPacket; - MemWriterDataPacket { - data: packet.content as uN[DATA_W], - length: packet.length as uN[ADDR_W], - last: packet.last - } -} - -#[test] -fn test_decode_literal_packet() { - const DATA_W = u32:64; - const ADDR_W = u32:16; - - type MemWriterDataPacket = mem_writer::MemWriterDataPacket; - - let content = CopyOrMatchContent:0xAA00_BB11_CC22_DD33; - let length = CopyOrMatchLength:8; - let last = false; - - assert_eq( - decode_literal_packet( - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length, - content, - last - } - ), - MemWriterDataPacket { - data: uN[DATA_W]:0xAA00BB11CC22DD33, - length: uN[ADDR_W]:8, - last: false - } - ) -} - -pub fn handle_repeated_offset_for_sequences - (seq: SequenceExecutorPacket, repeat_offsets: Offset[3], repeat_req: bool) - -> (SequenceExecutorPacket, Offset[3]) { - type Packet = SequenceExecutorPacket; - type Content = uN[RAM_DATA_WIDTH * u32:8]; - - let (offset, repeat_offsets) = if (seq.content <= Content:3) { - let idx = (seq.content - Content:1) as u32; - let idx = if (repeat_req) { - idx + u32:1 - } else { idx }; - - if (idx == u32:0) { - (repeat_offsets[0], repeat_offsets) - } else { - let offset = if idx < u32:3 { repeat_offsets[idx] } else { repeat_offsets[0] - Offset:1 }; - - let repeat_offsets = if idx > u32:1 { - update(repeat_offsets, u32:2, repeat_offsets[1]) - } else {repeat_offsets}; - let repeat_offsets = update(repeat_offsets, u32:1, repeat_offsets[0]); - let repeat_offsets = update(repeat_offsets, u32:0, offset); - - (offset, repeat_offsets) - } - } else { - let offset = (seq.content - Content:3) as Offset; - - let repeat_offsets = update(repeat_offsets, u32:2, repeat_offsets[1]); - let repeat_offsets = update(repeat_offsets, u32:1, repeat_offsets[0]); - let repeat_offsets = update(repeat_offsets, u32:0, offset); - - (offset, repeat_offsets) - }; - - ( - Packet { content: offset as Content, ..seq }, - repeat_offsets, - ) -} - -pub proc SequenceExecutor -{ - type MemWriterDataPacket = mem_writer::MemWriterDataPacket; - - input_r: chan in; - output_mem_wr_data_in_s: chan out; - ram_comp_input_s: chan> out; - ram_comp_output_r: chan> in; - ram_resp_input_s: chan out; - looped_channel_r: chan in; - rd_req_m0_s: chan> out; - rd_req_m1_s: chan> out; - rd_req_m2_s: chan> out; - rd_req_m3_s: chan> out; - rd_req_m4_s: chan> out; - rd_req_m5_s: chan> out; - rd_req_m6_s: chan> out; - rd_req_m7_s: chan> out; - wr_req_m0_s: chan> out; - wr_req_m1_s: chan> out; - wr_req_m2_s: chan> out; - wr_req_m3_s: chan> out; - wr_req_m4_s: chan> out; - wr_req_m5_s: chan> out; - wr_req_m6_s: chan> out; - wr_req_m7_s: chan> out; - - config( - input_r: chan in, - output_mem_wr_data_in_s: chan out, - looped_channel_r: chan in, - looped_channel_s: chan out, - rd_req_m0_s: chan> out, - rd_req_m1_s: chan> out, - rd_req_m2_s: chan> out, - rd_req_m3_s: chan> out, - rd_req_m4_s: chan> out, - rd_req_m5_s: chan> out, - rd_req_m6_s: chan> out, - rd_req_m7_s: chan> out, - rd_resp_m0_r: chan> in, - rd_resp_m1_r: chan> in, - rd_resp_m2_r: chan> in, - rd_resp_m3_r: chan> in, - rd_resp_m4_r: chan> in, - rd_resp_m5_r: chan> in, - rd_resp_m6_r: chan> in, - rd_resp_m7_r: chan> in, - wr_req_m0_s: chan> out, - wr_req_m1_s: chan> out, - wr_req_m2_s: chan> out, - wr_req_m3_s: chan> out, - wr_req_m4_s: chan> out, - wr_req_m5_s: chan> out, - wr_req_m6_s: chan> out, - wr_req_m7_s: chan> out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in - ) { - let (ram_comp_input_s, ram_comp_input_r) = chan, u32:1>("ram_comp_input"); - let (ram_comp_output_s, ram_comp_output_r) = chan, u32:1>("ram_comp_output"); - let (ram_resp_input_s, ram_resp_input_r) = chan("ram_resp_input"); - - spawn parallel_rams::RamWrRespHandler( - ram_comp_input_r, ram_comp_output_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r); - - spawn parallel_rams::RamRdRespHandler( - ram_resp_input_r, looped_channel_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, - rd_resp_m3_r, rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r); - - ( - input_r, output_mem_wr_data_in_s, - ram_comp_input_s, ram_comp_output_r, - ram_resp_input_s, looped_channel_r, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - ) - } - - init { - const_assert!(INIT_HB_PTR_RAM < RAM_NUM); - const_assert!(INIT_HB_PTR_ADDR <= (std::unsigned_max_value() as u32)); - - type RamAddr = bits[RAM_ADDR_WIDTH]; - let INIT_HB_PTR = HistoryBufferPtr { - number: INIT_HB_PTR_RAM as RamNumber, addr: INIT_HB_PTR_ADDR as RamAddr - }; - SequenceExecutorState { - status: SequenceExecutorStatus::IDLE, - packet: zero!(), - packet_valid: false, - hyp_ptr: INIT_HB_PTR, - real_ptr: INIT_HB_PTR, - hb_len: INIT_HB_LENGTH as uN[RAM_ADDR_WIDTH + RAM_NUM_CLOG2], - repeat_offsets: Offset[3]:[Offset:1, Offset:4, Offset:8], - repeat_req: false, - seq_cnt: false, - seq_pending: false - } - } - - next(state: SequenceExecutorState) { - let tok0 = join(); - type Status = SequenceExecutorStatus; - type State = SequenceExecutorState; - type MsgType = SequenceExecutorMessageType; - type Packet = SequenceExecutorPacket; - type ReadReq = ram::ReadReq; - type ReadResp = ram::ReadResp; - type WriteReq = ram::WriteReq; - type WriteResp = ram::WriteResp; - type HistoryBufferLength = uN[RAM_ADDR_WIDTH + RAM_NUM_CLOG2]; - - const ZERO_READ_REQS = ReadReq[RAM_NUM]:[zero!(), ...]; - const ZERO_WRITE_REQS = WriteReq[RAM_NUM]:[zero!(), ...]; - - // Recieve literals and sequences from the input channel ... - let do_recv_input = !state.packet_valid && state.status != Status::SEQUENCE_READ && - state.status != Status::SEQUENCE_WRITE; - let (tok1_0, input_packet, input_packet_valid) = - recv_if_non_blocking(tok0, input_r, do_recv_input, zero!()); - if input_packet_valid { - trace_fmt!("[SequenceExecutor]: received input: {:#x}", input_packet); - } else {}; - - // ... or our own sequences from the looped channel - let do_recv_ram = ( - state.status == Status::SEQUENCE_READ || - state.status == Status::SEQUENCE_WRITE - ); - - let (tok1_1, ram_packet, ram_packet_valid) = recv_if_non_blocking(tok0, looped_channel_r, do_recv_ram, zero!()); - - // Read RAM write completion, used for monitoring the real state - // of the RAM and eventually changing the state to IDLE. - // Going through the IDLE state is required for changing between - // Literals and Sequences (and the other way around) and between every - // Sequence read from the input (original sequence from the ZSTD stream). - let (tok1_2, wr_resp, wr_resp_valid) = - recv_non_blocking(tok0, ram_comp_output_r, zero!>()); - if wr_resp_valid { - trace_fmt!("[SequenceExecutor] Received completion update"); - } else { }; - - let real_ptr = if wr_resp_valid { wr_resp.ptr } else { state.real_ptr }; - let tok1 = join(tok1_0, tok1_1, tok1_2); - - // Since we either get data from input, from frame, or from state, - // we are always working on a single packet. The current state - // can be use to determine the source of the packet. - let (packet, packet_valid) = if input_packet_valid { - (input_packet, true) - } else if ram_packet_valid { - (ram_packet, true) - } else { - (state.packet, state.packet_valid) - }; - if packet_valid { - trace_fmt!("[SequenceExecutor] Handling packet {:#x} in {}", packet, state.status); - } else {}; - - // if we are in the IDLE state and have a valid packet stored in the state, - // or we have a new packet from the input go to the corresponding - // processing step immediately. (added to be able to process a single - // literal in one next() evaluation) - let status = match (state.status, packet_valid, packet.msg_type) { - (Status::IDLE, true, MsgType::LITERAL) => Status::LITERAL_WRITE, - (Status::IDLE, true, MsgType::SEQUENCE) => Status::SEQUENCE_READ, - _ => state.status, - }; - - let NO_VALID_PACKET_STATE = State { packet, packet_valid, real_ptr, ..state }; - let (write_reqs, read_reqs, read_start, read_len, new_state) = match ( - status, packet_valid, packet.msg_type - ) { - // Handling LITERAL_WRITE - (Status::LITERAL_WRITE, true, MsgType::LITERAL) => { - trace_fmt!("[SequenceExecutor] Handling LITERAL packet in LITERAL_WRITE step"); - let (write_reqs, new_hyp_ptr) = - parallel_rams::literal_packet_to_write_reqs(state.hyp_ptr, packet); - let new_repeat_req = packet.length == CopyOrMatchLength:0; - let hb_add = packet.length as HistoryBufferLength; - let new_hb_len = std::mod_pow2(state.hb_len + hb_add, RAM_SIZE_TOTAL as uN[RAM_ADDR_WIDTH + RAM_NUM_CLOG2]); - - ( - write_reqs, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, - State { - status: Status::LITERAL_WRITE, - packet: zero!(), - packet_valid: false, - hyp_ptr: new_hyp_ptr, - real_ptr, - repeat_offsets: state.repeat_offsets, - repeat_req: new_repeat_req, - hb_len: new_hb_len, - seq_cnt: false, - seq_pending: false - }, - ) - }, - (Status::LITERAL_WRITE, _, _) => { - let status = - if real_ptr == state.hyp_ptr { Status::IDLE } else { Status::LITERAL_WRITE }; - ( - ZERO_WRITE_REQS, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, - State { status, ..NO_VALID_PACKET_STATE }, - ) - }, - // Handling SEQUENCE_READ - (Status::SEQUENCE_READ, true, MsgType::SEQUENCE) => { - trace_fmt!("Handling SEQUENCE in SEQUENCE_READ state"); - let (packet, new_repeat_offsets) = if !state.seq_cnt { - handle_repeated_offset_for_sequences( - packet, state.repeat_offsets, state.repeat_req) - } else { - (packet, state.repeat_offsets) - }; - let (read_reqs, read_start, read_len, packet, packet_valid) = parallel_rams::sequence_packet_to_read_reqs< - HISTORY_BUFFER_SIZE_KB>( - state.hyp_ptr, packet, state.hb_len); - - ( - ZERO_WRITE_REQS, read_reqs, read_start, read_len, - SequenceExecutorState { - status: Status::SEQUENCE_WRITE, - packet, - packet_valid, - hyp_ptr: state.hyp_ptr, - real_ptr, - repeat_offsets: new_repeat_offsets, - repeat_req: false, - hb_len: state.hb_len, - seq_cnt: packet_valid, - seq_pending: true - }, - ) - }, - (Status::SEQUENCE_READ, _, _) => { - let ZERO_RETURN = (ZERO_WRITE_REQS, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, zero!()); - fail!("should_not_happen", (ZERO_RETURN)) - }, - // Handling SEQUENCE_WRITE - (Status::SEQUENCE_WRITE, true, MsgType::LITERAL) => { - trace_fmt!("Handling LITERAL in SEQUENCE_WRITE state: {}", status); - let (write_reqs, new_hyp_ptr) = - parallel_rams::literal_packet_to_write_reqs(state.hyp_ptr, packet); - let hb_add = packet.length as HistoryBufferLength; - let new_hb_len = std::mod_pow2(state.hb_len + hb_add, RAM_SIZE_TOTAL as uN[RAM_ADDR_WIDTH + RAM_NUM_CLOG2]); - - ( - write_reqs, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, - SequenceExecutorState { - status: zero!(), - packet: state.packet, - packet_valid: state.packet_valid, - hyp_ptr: new_hyp_ptr, - real_ptr, - repeat_offsets: state.repeat_offsets, - repeat_req: state.repeat_req, - hb_len: new_hb_len, - seq_cnt: state.seq_cnt, - seq_pending: false - }, - ) - }, - (Status::SEQUENCE_WRITE, _, _) => { - let status = if state.seq_pending { - Status::SEQUENCE_WRITE - } else if real_ptr == state.hyp_ptr { - Status::IDLE - } else if state.seq_cnt { - Status::SEQUENCE_READ - } else { - Status::SEQUENCE_WRITE - }; - ( - ZERO_WRITE_REQS, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, - State { status, ..NO_VALID_PACKET_STATE }, - ) - }, - // Handling IDLE - _ => { - let status = Status::IDLE; - ( - ZERO_WRITE_REQS, ZERO_READ_REQS, RamReadStart:0, RamReadLen:0, - State { status, ..NO_VALID_PACKET_STATE }, - ) - }, - }; - - let tok2_1 = send_if(tok1, wr_req_m0_s, (write_reqs[0]).mask != RAM_REQ_MASK_NONE, write_reqs[0]); - let tok2_2 = send_if(tok1, wr_req_m1_s, (write_reqs[1]).mask != RAM_REQ_MASK_NONE, write_reqs[1]); - let tok2_3 = send_if(tok1, wr_req_m2_s, (write_reqs[2]).mask != RAM_REQ_MASK_NONE, write_reqs[2]); - let tok2_4 = send_if(tok1, wr_req_m3_s, (write_reqs[3]).mask != RAM_REQ_MASK_NONE, write_reqs[3]); - let tok2_5 = send_if(tok1, wr_req_m4_s, (write_reqs[4]).mask != RAM_REQ_MASK_NONE, write_reqs[4]); - let tok2_6 = send_if(tok1, wr_req_m5_s, (write_reqs[5]).mask != RAM_REQ_MASK_NONE, write_reqs[5]); - let tok2_7 = send_if(tok1, wr_req_m6_s, (write_reqs[6]).mask != RAM_REQ_MASK_NONE, write_reqs[6]); - let tok2_8 = send_if(tok1, wr_req_m7_s, (write_reqs[7]).mask != RAM_REQ_MASK_NONE, write_reqs[7]); - - // Write to output ask for completion - let (do_write, wr_resp_handler_data) = parallel_rams::create_ram_wr_data(write_reqs, new_state.hyp_ptr); - if do_write { - trace_fmt!("[SequenceExecutor] Sending request to RamWrRespHandler: {:#x}", wr_resp_handler_data); - } else { }; - let tok2_9 = send_if(tok1, ram_comp_input_s, do_write, wr_resp_handler_data); - - let do_write_output = do_write || (packet.last && packet.msg_type == SequenceExecutorMessageType::LITERAL); - let output_mem_wr_data_in = decode_literal_packet(packet); - if do_write_output { - trace_fmt!("[SequenceExecutor] Sending output MemWriter data: {:#x}", output_mem_wr_data_in); - } else { }; - let tok2_10_1 = send_if(tok1, output_mem_wr_data_in_s, do_write_output, output_mem_wr_data_in); - - // Ask for response - let tok2_11 = send_if(tok1, rd_req_m0_s, (read_reqs[0]).mask != RAM_REQ_MASK_NONE, read_reqs[0]); - let tok2_12 = send_if(tok1, rd_req_m1_s, (read_reqs[1]).mask != RAM_REQ_MASK_NONE, read_reqs[1]); - let tok2_13 = send_if(tok1, rd_req_m2_s, (read_reqs[2]).mask != RAM_REQ_MASK_NONE, read_reqs[2]); - let tok2_14 = send_if(tok1, rd_req_m3_s, (read_reqs[3]).mask != RAM_REQ_MASK_NONE, read_reqs[3]); - let tok2_15 = send_if(tok1, rd_req_m4_s, (read_reqs[4]).mask != RAM_REQ_MASK_NONE, read_reqs[4]); - let tok2_16 = send_if(tok1, rd_req_m5_s, (read_reqs[5]).mask != RAM_REQ_MASK_NONE, read_reqs[5]); - let tok2_17 = send_if(tok1, rd_req_m6_s, (read_reqs[6]).mask != RAM_REQ_MASK_NONE, read_reqs[6]); - let tok2_18 = send_if(tok1, rd_req_m7_s, (read_reqs[7]).mask != RAM_REQ_MASK_NONE, read_reqs[7]); - - let (do_read, rd_resp_handler_data) = - parallel_rams::create_ram_rd_data - (read_reqs, read_start, read_len, packet.last, new_state.packet_valid); - if do_read { - trace_fmt!("[SequenceExecutor] Sending request to RamRdRespHandler: {:#x}", rd_resp_handler_data); - } else { }; - let tok2_19 = send_if(tok1, ram_resp_input_s, do_read, rd_resp_handler_data); - - new_state - } -} - -pub const ZSTD_HISTORY_BUFFER_SIZE_KB: u32 = u32:64; -pub const ZSTD_RAM_SIZE = parallel_rams::ram_size(ZSTD_HISTORY_BUFFER_SIZE_KB); -pub const ZSTD_RAM_ADDR_WIDTH = parallel_rams::ram_addr_width(ZSTD_HISTORY_BUFFER_SIZE_KB); -const ZSTD_AXI_DATA_W = u32:64; -const ZSTD_AXI_ADDR_W = u32:16; - -pub proc SequenceExecutorZstd { - type MemWriterDataPacket = mem_writer::MemWriterDataPacket; - - init { } - - config( - input_r: chan in, - output_mem_wr_data_in_s: chan out, - looped_channel_r: chan in, - looped_channel_s: chan out, - rd_req_m0_s: chan> out, - rd_req_m1_s: chan> out, - rd_req_m2_s: chan> out, - rd_req_m3_s: chan> out, - rd_req_m4_s: chan> out, - rd_req_m5_s: chan> out, - rd_req_m6_s: chan> out, - rd_req_m7_s: chan> out, - rd_resp_m0_r: chan> in, - rd_resp_m1_r: chan> in, - rd_resp_m2_r: chan> in, - rd_resp_m3_r: chan> in, - rd_resp_m4_r: chan> in, - rd_resp_m5_r: chan> in, - rd_resp_m6_r: chan> in, - rd_resp_m7_r: chan> in, - wr_req_m0_s: chan> out, - wr_req_m1_s: chan> out, - wr_req_m2_s: chan> out, - wr_req_m3_s: chan> out, - wr_req_m4_s: chan> out, - wr_req_m5_s: chan> out, - wr_req_m6_s: chan> out, - wr_req_m7_s: chan> out, - wr_resp_m0_r: chan in, - wr_resp_m1_r: chan in, - wr_resp_m2_r: chan in, - wr_resp_m3_r: chan in, - wr_resp_m4_r: chan in, - wr_resp_m5_r: chan in, - wr_resp_m6_r: chan in, - wr_resp_m7_r: chan in - ) { - spawn SequenceExecutor ( - input_r, output_mem_wr_data_in_s, - looped_channel_r, looped_channel_s, - rd_req_m0_s, rd_req_m1_s, rd_req_m2_s, rd_req_m3_s, - rd_req_m4_s, rd_req_m5_s, rd_req_m6_s, rd_req_m7_s, - rd_resp_m0_r, rd_resp_m1_r, rd_resp_m2_r, rd_resp_m3_r, - rd_resp_m4_r, rd_resp_m5_r, rd_resp_m6_r, rd_resp_m7_r, - wr_req_m0_s, wr_req_m1_s, wr_req_m2_s, wr_req_m3_s, - wr_req_m4_s, wr_req_m5_s, wr_req_m6_s, wr_req_m7_s, - wr_resp_m0_r, wr_resp_m1_r, wr_resp_m2_r, wr_resp_m3_r, - wr_resp_m4_r, wr_resp_m5_r, wr_resp_m6_r, wr_resp_m7_r - ); - } - - next (state: ()) { } -} - -const LITERAL_TEST_INPUT_DATA = SequenceExecutorPacket[8]:[ - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0xAA00_BB11_CC22_DD33, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x4477_3322_0088_CCFF, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:4, - content: CopyOrMatchContent:0x88AA_0022, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:4, - content: CopyOrMatchContent:0xFFEE_DD11, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x9DAF_8B41_C913_EFDA, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:8, - content: CopyOrMatchContent:0x157D_8C7E_B8B9_7CA3, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:0, - content: CopyOrMatchContent:0x0, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:0, - content: CopyOrMatchContent:0x0, - last: true - }, -]; - -const LITERAL_TEST_MEMORY_CONTENT:(TestRamAddr, RamData)[3][RAM_NUM] = [ - [ - (TestRamAddr:127, RamData:0x33), - (TestRamAddr:0, RamData:0xFF), - (TestRamAddr:1, RamData:0x22) - ], - [ - (TestRamAddr:127, RamData:0xDD), - (TestRamAddr:0, RamData:0xCC), - (TestRamAddr:1, RamData:0x00) - ], - [ - (TestRamAddr:127, RamData:0x22), - (TestRamAddr:0, RamData:0x88), - (TestRamAddr:1, RamData:0xAA) - ], - [ - (TestRamAddr:127, RamData:0xCC), - (TestRamAddr:0, RamData:0x00), - (TestRamAddr:1, RamData:0x88) - ], - [ - (TestRamAddr:127, RamData:0x11), - (TestRamAddr:0, RamData:0x22), - (TestRamAddr:1, RamData:0x11) - ], - [ - (TestRamAddr:127, RamData:0xBB), - (TestRamAddr:0, RamData:0x33), - (TestRamAddr:1, RamData:0xDD) - ], - [ - (TestRamAddr:127, RamData:0x00), - (TestRamAddr:0, RamData:0x77), - (TestRamAddr:1, RamData:0xEE) - ], - [ - (TestRamAddr:127, RamData:0xAA), - (TestRamAddr:0, RamData:0x44), - (TestRamAddr:1, RamData:0xFF) - ], -]; - -// #[test_proc] -// proc SequenceExecutorLiteralsTest { -// type MemWriterDataPacket = mem_writer::MemWriterDataPacket; -// terminator: chan out; - -// input_s: chan out; -// output_mem_wr_data_in_r: chan in; - -// print_start_s: chan<()> out; -// print_finish_r: chan<()> in; - -// ram_rd_req_s: chan[RAM_NUM] out; -// ram_rd_resp_r: chan[RAM_NUM] in; -// ram_wr_req_s: chan[RAM_NUM] out; -// ram_wr_resp_r: chan[RAM_NUM] in; - -// config(terminator: chan out) { -// let (input_s, input_r) = chan("input"); -// let (output_mem_wr_data_in_s, output_mem_wr_data_in_r) = chan("output_mem_wr_data_in"); - -// let (looped_channel_s, looped_channel_r) = chan("looped_channels"); - -// let (print_start_s, print_start_r) = chan<()>("print_start"); -// let (print_finish_s, print_finish_r) = chan<()>("print_finish"); - -// let (ram_rd_req_s, ram_rd_req_r) = chan[RAM_NUM]("ram_rd_req"); -// let (ram_rd_resp_s, ram_rd_resp_r) = chan[RAM_NUM]("ram_rd_resp"); -// let (ram_wr_req_s, ram_wr_req_r) = chan[RAM_NUM]("ram_wr_req"); -// let (ram_wr_resp_s, ram_wr_resp_r) = chan[RAM_NUM]("ram_wr_resp"); - -// let INIT_HB_PTR_ADDR = u32:127; -// spawn SequenceExecutor< -// TEST_HISTORY_BUFFER_SIZE_KB, -// TEST_DATA_W, TEST_ADDR_W, -// TEST_RAM_SIZE, -// TEST_RAM_ADDR_WIDTH, -// INIT_HB_PTR_ADDR, -// > ( -// input_r, output_mem_wr_data_in_s, -// looped_channel_r, looped_channel_s, -// ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], -// ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], -// ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], -// ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], -// ram_wr_req_s[0], ram_wr_req_s[1], ram_wr_req_s[2], ram_wr_req_s[3], -// ram_wr_req_s[4], ram_wr_req_s[5], ram_wr_req_s[6], ram_wr_req_s[7], -// ram_wr_resp_r[0], ram_wr_resp_r[1], ram_wr_resp_r[2], ram_wr_resp_r[3], -// ram_wr_resp_r[4], ram_wr_resp_r[5], ram_wr_resp_r[6], ram_wr_resp_r[7] -// ); - -// spawn ram_printer::RamPrinter< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_NUM_PARTITIONS, -// TEST_RAM_ADDR_WIDTH, RAM_NUM> -// (print_start_r, print_finish_s, ram_rd_req_s, ram_rd_resp_r); - -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[0], ram_rd_resp_s[0], ram_wr_req_r[0], ram_wr_resp_s[0]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[1], ram_rd_resp_s[1], ram_wr_req_r[1], ram_wr_resp_s[1]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[2], ram_rd_resp_s[2], ram_wr_req_r[2], ram_wr_resp_s[2]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[3], ram_rd_resp_s[3], ram_wr_req_r[3], ram_wr_resp_s[3]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[4], ram_rd_resp_s[4], ram_wr_req_r[4], ram_wr_resp_s[4]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[5], ram_rd_resp_s[5], ram_wr_req_r[5], ram_wr_resp_s[5]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[6], ram_rd_resp_s[6], ram_wr_req_r[6], ram_wr_resp_s[6]); -// spawn ram::RamModel< -// RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, -// TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> -// (ram_rd_req_r[7], ram_rd_resp_s[7], ram_wr_req_r[7], ram_wr_resp_s[7]); - -// ( -// terminator, -// input_s, output_mem_wr_data_in_r, -// print_start_s, print_finish_r, -// ram_rd_req_s, ram_rd_resp_r, -// ram_wr_req_s, ram_wr_resp_r -// ) -// } - -// init { } - -// next(state: ()) { -// let tok = join(); -// for (i, ()): (u32, ()) in u32:0..array_size(LITERAL_TEST_INPUT_DATA) { -// let tok = send(tok, input_s, LITERAL_TEST_INPUT_DATA[i]); -// // Don't receive when there's an empty literals packet which is not last -// if (LITERAL_TEST_INPUT_DATA[i].msg_type != SequenceExecutorMessageType::LITERAL || -// LITERAL_TEST_INPUT_DATA[i].length != CopyOrMatchLength:0 || -// LITERAL_TEST_INPUT_DATA[i].last) { -// let expected_mem_writer_data = decode_literal_packet(LITERAL_TEST_INPUT_DATA[i]); -// let (tok, recv_mem_writer_data) = recv(tok, output_mem_wr_data_in_r); -// assert_eq(expected_mem_writer_data, recv_mem_writer_data); -// } else {} -// }(()); - -// for (i, ()): (u32, ()) in u32:0..RAM_NUM { -// for (j, ()): (u32, ()) in u32:0..array_size(LITERAL_TEST_MEMORY_CONTENT[0]) { -// let addr = LITERAL_TEST_MEMORY_CONTENT[i][j].0; -// let tok = send(tok, ram_rd_req_s[i], TestReadReq { addr, mask: RAM_REQ_MASK_ALL }); -// let (tok, resp) = recv(tok, ram_rd_resp_r[i]); -// let expected = LITERAL_TEST_MEMORY_CONTENT[i][j].1; -// assert_eq(expected, resp.data); -// }(()); -// }(()); - -// // Print RAM content -// let tok = send(tok, print_start_s, ()); -// let (tok, _) = recv(tok, print_finish_r); - -// send(tok, terminator, true); -// } -// } - -const SEQUENCE_TEST_INPUT_SEQUENCES = SequenceExecutorPacket[11]: [ - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:9, - content: CopyOrMatchContent:13, - last: false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:1, - content: CopyOrMatchContent:7, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:1, - content: CopyOrMatchContent:8, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:5, - content: CopyOrMatchContent:13, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:3, - content: CopyOrMatchContent:3, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:1, - content: CopyOrMatchContent:1, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:0, - content: CopyOrMatchContent:0, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:1, - content: CopyOrMatchContent:3, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, - length: CopyOrMatchLength:0, - content: CopyOrMatchContent:0, - last:false - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:10, - content: CopyOrMatchContent:2, - last:true, - }, - SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, - length: CopyOrMatchLength:1, - content: CopyOrMatchContent:3, - last:false - }, -]; - -type TestMemWriterDataPacket = mem_writer::MemWriterDataPacket; -const SEQUENCE_TEST_EXPECTED_SEQUENCE_RESULTS:TestMemWriterDataPacket[11] = [ - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0x8C_7E_B8_B9_7C_A3_9D_AF, - length: uN[TEST_ADDR_W]:8, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0x7D, - length: uN[TEST_ADDR_W]:1, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB8, - length: uN[TEST_ADDR_W]:1, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB8, - length: uN[TEST_ADDR_W]:1, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB8_B9_7C_A3_9D, - length: uN[TEST_ADDR_W]:5, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB9_7C_A3, - length: uN[TEST_ADDR_W]:3, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB8, - length: uN[TEST_ADDR_W]:1, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0x7C, - length: uN[TEST_ADDR_W]:1, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0xB9_7C_A3_B8_B9_7C_A3_9D, - length: uN[TEST_ADDR_W]:8, - last: false - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0x7C_B8, - length: uN[TEST_ADDR_W]:2, - last: true - }, - TestMemWriterDataPacket { - data: uN[TEST_DATA_W]:0x9D, - length: uN[TEST_ADDR_W]:1, - last: false - } -]; - -#[test_proc] -proc SequenceExecutorSequenceTest { - type MemWriterDataPacket = mem_writer::MemWriterDataPacket; - terminator: chan out; - - input_s: chan out; - output_mem_wr_data_in_r: chan in; - - print_start_s: chan<()> out; - print_finish_r: chan<()> in; - - ram_rd_req_s: chan[RAM_NUM] out; - ram_rd_resp_r: chan[RAM_NUM] in; - ram_wr_req_s: chan[RAM_NUM] out; - ram_wr_resp_r: chan[RAM_NUM] in; - - config(terminator: chan out) { - let (input_s, input_r) = chan("input"); - let (output_mem_wr_data_in_s, output_mem_wr_data_in_r) = chan("output_mem_wr_data_in"); - - let (looped_channel_s, looped_channel_r) = chan("looped_channel"); - - let (print_start_s, print_start_r) = chan<()>("print_start"); - let (print_finish_s, print_finish_r) = chan<()>("print_finish"); - - let (ram_rd_req_s, ram_rd_req_r) = chan[RAM_NUM]("ram_rd_req"); - let (ram_rd_resp_s, ram_rd_resp_r) = chan[RAM_NUM]("ram_rd_resp"); - let (ram_wr_req_s, ram_wr_req_r) = chan[RAM_NUM]("ram_wr_req"); - let (ram_wr_resp_s, ram_wr_resp_r) = chan[RAM_NUM]("ram_wr_resp"); - - let INIT_HB_PTR_ADDR = u32:127; - spawn SequenceExecutor< - TEST_HISTORY_BUFFER_SIZE_KB, - TEST_DATA_W, TEST_ADDR_W, - TEST_RAM_SIZE, - TEST_RAM_ADDR_WIDTH, - INIT_HB_PTR_ADDR, - > ( - input_r, output_mem_wr_data_in_s, - looped_channel_r, looped_channel_s, - ram_rd_req_s[0], ram_rd_req_s[1], ram_rd_req_s[2], ram_rd_req_s[3], - ram_rd_req_s[4], ram_rd_req_s[5], ram_rd_req_s[6], ram_rd_req_s[7], - ram_rd_resp_r[0], ram_rd_resp_r[1], ram_rd_resp_r[2], ram_rd_resp_r[3], - ram_rd_resp_r[4], ram_rd_resp_r[5], ram_rd_resp_r[6], ram_rd_resp_r[7], - ram_wr_req_s[0], ram_wr_req_s[1], ram_wr_req_s[2], ram_wr_req_s[3], - ram_wr_req_s[4], ram_wr_req_s[5], ram_wr_req_s[6], ram_wr_req_s[7], - ram_wr_resp_r[0], ram_wr_resp_r[1], ram_wr_resp_r[2], ram_wr_resp_r[3], - ram_wr_resp_r[4], ram_wr_resp_r[5], ram_wr_resp_r[6], ram_wr_resp_r[7] - ); - - spawn ram_printer::RamPrinter< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_NUM_PARTITIONS, - TEST_RAM_ADDR_WIDTH, RAM_NUM> - (print_start_r, print_finish_s, ram_rd_req_s, ram_rd_resp_r); - - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[0], ram_rd_resp_s[0], ram_wr_req_r[0], ram_wr_resp_s[0]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[1], ram_rd_resp_s[1], ram_wr_req_r[1], ram_wr_resp_s[1]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[2], ram_rd_resp_s[2], ram_wr_req_r[2], ram_wr_resp_s[2]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[3], ram_rd_resp_s[3], ram_wr_req_r[3], ram_wr_resp_s[3]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[4], ram_rd_resp_s[4], ram_wr_req_r[4], ram_wr_resp_s[4]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[5], ram_rd_resp_s[5], ram_wr_req_r[5], ram_wr_resp_s[5]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[6], ram_rd_resp_s[6], ram_wr_req_r[6], ram_wr_resp_s[6]); - spawn ram::RamModel< - RAM_DATA_WIDTH, TEST_RAM_SIZE, RAM_WORD_PARTITION_SIZE, - TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_RAM_INITIALIZED> - (ram_rd_req_r[7], ram_rd_resp_s[7], ram_wr_req_r[7], ram_wr_resp_s[7]); - - ( - terminator, - input_s, output_mem_wr_data_in_r, - print_start_s, print_finish_r, - ram_rd_req_s, ram_rd_resp_r, ram_wr_req_s, ram_wr_resp_r - ) - } - - init { } - - next(state: ()) { - let tok = join(); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 0 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x2, - content: CopyOrMatchContent:0xcf95, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 1 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x4, - content: CopyOrMatchContent:0x5, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 2 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x1, - content: CopyOrMatchContent:0xc4, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 3 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x8, - content: CopyOrMatchContent:0x4, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 4 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x1, - content: CopyOrMatchContent:0x93, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 5 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x7, - content: CopyOrMatchContent:0x2, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 6 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x2, - content: CopyOrMatchContent:0x89ac, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 7 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x5, - content: CopyOrMatchContent:0xc, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 8 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x0, - content: CopyOrMatchContent:0x0, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 9 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x8, - content: CopyOrMatchContent:0xe, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 10 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x0, - content: CopyOrMatchContent:0x0, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 11 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x5, - content: CopyOrMatchContent:0x2, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 12 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x8, - content: CopyOrMatchContent:0x95a6_e608_e17d_50b9, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 13 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x3, - content: CopyOrMatchContent:0x32, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 14 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::LITERAL, // u1:0, - length: CopyOrMatchLength:0x0, - content: CopyOrMatchContent:0x0, - last: false, - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - trace_fmt!("----------------------- Packet 15 -----------------------"); - - let tok = send(tok, input_s, SequenceExecutorPacket { - msg_type: SequenceExecutorMessageType::SEQUENCE, // u1:1, - length: CopyOrMatchLength:0x1a, - content: CopyOrMatchContent:0x3, - last: true - }); - - let tok = send(tok, print_start_s, ()); - let (tok, _) = recv(tok, print_finish_r); - - send(tok, terminator, true); - } -} diff --git a/xls/modules/zstd/sequence_executor/BUILD b/xls/modules/zstd/sequence_executor/BUILD new file mode 100644 index 0000000000..9d796700f8 --- /dev/null +++ b/xls/modules/zstd/sequence_executor/BUILD @@ -0,0 +1,297 @@ +# Copyright 2025 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 ZSTD Sequence Executor + +load("@rules_hdl//place_and_route:build_defs.bzl", "place_and_route") +load("@rules_hdl//synthesis:build_defs.bzl", "benchmark_synth", "synthesize_rtl") +load("@rules_hdl//verilog:providers.bzl", "verilog_library") +load( + "//xls/build_rules:xls_build_defs.bzl", + "xls_benchmark_ir", + "xls_benchmark_verilog", + "xls_dslx_library", + "xls_dslx_test", + "xls_dslx_verilog", +) +load("//xls/common:openroad_warnings.bzl", "ASAP7_SUPPPRESSED_WARNINGS") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//xls:xls_users"], + licenses = ["notice"], +) + +CLOCK_PERIOD_PS = "750" + +COMMON_CODEGEN_ARGS = { + "delay_model": "asap7", + "reset": "rst", + "worst_case_throughput": "1", + "use_system_verilog": "false", + "clock_period_ps": CLOCK_PERIOD_PS, + "clock_margin_percent": "20", + "multi_proc": "true", + "materialize_internal_fifos": "true", +} + +xls_dslx_library( + name = "history_buffer_dslx", + srcs = ["history_buffer.x"], + deps = [ + "//xls/examples:ram_dslx", + ], +) + +xls_dslx_test( + name = "history_buffer_dslx_test", + library = ":history_buffer_dslx", + tags = ["manual"], +) + +xls_dslx_library( + name = "history_copy_executor_dslx", + srcs = [ + "history_copy_executor.x", + ], + deps = [ + "//xls/modules/zstd:common_dslx", + "//xls/modules/zstd/memory:mem_writer_dslx", + ":history_buffer_dslx", + ], +) + +xls_dslx_test( + name = "history_copy_executor_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = ":history_copy_executor_dslx", + tags = ["manual"], +) + +xls_dslx_library( + name = "join_output_dslx", + srcs = [ + "join_output.x", + ], + deps = [ + "//xls/modules/zstd:common_dslx", + "//xls/modules/zstd/memory:mem_writer_dslx", + ], +) + +xls_dslx_test( + name = "join_output_dslx_test", + library = ":join_output_dslx", + tags = ["manual"], +) + +xls_dslx_library( + name = "sequence_executor_ctrl_dslx", + srcs = [ + "sequence_executor_ctrl.x", + ], + deps = [ + "//xls/examples:ram_dslx", + "//xls/modules/zstd:common_dslx", + "//xls/modules/zstd:parallel_rams_dslx", + "//xls/modules/zstd:ram_printer_dslx", + "//xls/modules/zstd/memory:mem_writer_dslx", + ":join_output_dslx", + ":history_copy_executor_dslx", + ":literals_executor_dslx", + ], +) + +xls_dslx_test( + name = "sequence_executor_ctrl_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = ":sequence_executor_ctrl_dslx", + tags = ["manual"], +) + +xls_dslx_library( + name = "literals_prefetch_dslx", + srcs = [ + "literals_prefetch.x", + ], + deps = [ + "//xls/modules/zstd:common_dslx", + ], +) + +xls_dslx_test( + name = "literals_prefetch_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = ":literals_prefetch_dslx", + tags = ["manual"], +) + +xls_dslx_library( + name = "literals_executor_dslx", + srcs = [ + "literals_executor.x", + ], + deps = [ + "//xls/modules/zstd:common_dslx", + "//xls/modules/zstd/memory:mem_writer_dslx", + ":literals_prefetch_dslx", + ":history_buffer_dslx", + ], +) + +xls_dslx_test( + name = "literals_executor_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = ":literals_executor_dslx", + tags = ["manual"], +) + +LITERALS_EXECUTOR_CODEGEN_ARGS = COMMON_CODEGEN_ARGS | { + "module_name": "literals_executor", + "pipeline_stages": "4", + "worst_case_throughput": "2", +} + +xls_dslx_verilog( + name = "literals_executor_verilog", + codegen_args = LITERALS_EXECUTOR_CODEGEN_ARGS, + dslx_top = "LiteralsExecutorInst", + library = ":literals_executor_dslx", + tags = ["manual"], + verilog_file = "literals_executor.v", +) + +xls_benchmark_ir( + name = "literals_executor_opt_ir_benchmark", + src = ":literals_executor_verilog.opt.ir", + benchmark_ir_args = LITERALS_EXECUTOR_CODEGEN_ARGS, + tags = ["manual"], +) + +xls_benchmark_verilog( + name = "literals_executor_verilog_benchmark", + tags = ["manual"], + verilog_target = "literals_executor_verilog", +) + +verilog_library( + name = "literals_executor_lib", + srcs = [ + ":literals_executor.v", + ], + tags = ["manual"], +) + +synthesize_rtl( + name = "literals_executor_asap7", + standard_cells = "@org_theopenroadproject_asap7sc7p5t_28//:asap7-sc7p5t_rev28_rvt", + tags = ["manual"], + top_module = "literals_executor", + deps = [ + ":literals_executor_lib", + ], +) + +benchmark_synth( + name = "literals_executor_benchmark_synth", + synth_target = ":literals_executor_asap7", + tags = ["manual"], +) + +place_and_route( + name = "literals_executor_place_and_route_skip", + clock_period = CLOCK_PERIOD_PS, + core_padding_microns = 2, + min_pin_distance = "0.5", + placement_density = "0.30", + stop_after_step = "global_routing", + suppress_warnings = ASAP7_SUPPPRESSED_WARNINGS, + synthesized_rtl = ":literals_executor_asap7", + tags = ["manual"], + target_die_utilization_percentage = "10", +) + +xls_dslx_library( + name = "sequence_executor_dslx", + srcs = [ + "sequence_executor.x", + ], + deps = [ + "//xls/examples:ram_dslx", + "//xls/modules/zstd:common_dslx", + "//xls/modules/zstd:parallel_rams_dslx", + "//xls/modules/zstd:ram_printer_dslx", + "//xls/modules/zstd/memory:mem_writer_dslx", + ":history_buffer_dslx", + ":history_copy_executor_dslx", + ":literals_executor_dslx", + ":join_output_dslx", + ":sequence_executor_ctrl_dslx", + ], +) + +xls_dslx_test( + name = "sequence_executor_dslx_test", + dslx_test_args = { + "compare": "none", + }, + library = ":sequence_executor_dslx", + tags = ["manual"], +) + +SEQUENCE_EXECUTOR_CODEGEN_ARGS = COMMON_CODEGEN_ARGS | { + "module_name": "sequence_executor", + "clock_period_ps": "0", + "generator": "pipeline", + "delay_model": "asap7", + "worst_case_throughput": "2", + "pipeline_stages": "3", + "reset": "rst", + "reset_data_path": "true", + "reset_active_low": "false", + "reset_asynchronous": "true", + "flop_inputs": "false", + "flop_single_value_channels": "false", + "flop_outputs": "false", +} + +xls_dslx_verilog( + name = "sequence_executor_verilog", + codegen_args = SEQUENCE_EXECUTOR_CODEGEN_ARGS, + dslx_top = "SequenceExecutorZstd", + library = ":sequence_executor_dslx", + tags = ["manual"], + verilog_file = "sequence_executor.v", +) + +xls_benchmark_ir( + name = "sequence_executor_opt_ir_benchmark", + src = ":sequence_executor_verilog.opt.ir", + benchmark_ir_args = SEQUENCE_EXECUTOR_CODEGEN_ARGS, + tags = ["manual"], +) + +xls_benchmark_verilog( + name = "sequence_executor_verilog_benchmark", + tags = ["manual"], + verilog_target = "sequence_executor_verilog", +) diff --git a/xls/modules/zstd/sequence_executor/history_buffer.x b/xls/modules/zstd/sequence_executor/history_buffer.x new file mode 100644 index 0000000000..3fba83a340 --- /dev/null +++ b/xls/modules/zstd/sequence_executor/history_buffer.x @@ -0,0 +1,492 @@ +// Copyright 2025 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.examples.ram; + +pub struct HistoryBufferReq< + ADDR_W: u32, + DATA_W: u32, + NUM_PARTITIONS: u32> { + addr: uN[ADDR_W], + data: uN[DATA_W], + write_mask: uN[NUM_PARTITIONS], + read_mask: uN[NUM_PARTITIONS], +} + +pub struct HistoryBufferResp { + data: uN[DATA_W] +} + +pub type HistoryBufferWrComp = (); + +fn to_single_req< + P_ADDR_W: u32, P_DATA_W: u32, P_NUM_PARTITIONS: u32, S_ADDR_W: u32, S_DATA_W: u32> + (preq: HistoryBufferReq) -> + (ram::RWRamReq[P_NUM_PARTITIONS], u32[P_NUM_PARTITIONS], + bool[P_NUM_PARTITIONS], bool[P_NUM_PARTITIONS]) { + + let base = preq.addr / P_NUM_PARTITIONS; + let offset = preq.addr % P_NUM_PARTITIONS; + type RWRamReq = ram::RWRamReq; + const ZERO_REQS = RWRamReq[P_NUM_PARTITIONS]:[zero!(), ...]; + const ZERO_ORDER = u32[P_NUM_PARTITIONS]:[u32:0, ...]; + const ZERO_DO_SEND = bool[P_NUM_PARTITIONS]:[false, ...]; + const ZERO_DO_COMP = bool[P_NUM_PARTITIONS]:[false, ...]; + + unroll_for! (i, (reqs, poss, do_rd, do_wr)) : + (u32, (RWRamReq[P_NUM_PARTITIONS], u32[P_NUM_PARTITIONS], bool[P_NUM_PARTITIONS], + bool[P_NUM_PARTITIONS])) in u32:0..P_NUM_PARTITIONS { + let bank = (i - offset as u32) % P_NUM_PARTITIONS; + let data = preq.data[bank * u32:8 +: u8] as u8; + let addr = (base + (i < offset as u32) as uN[P_ADDR_W]) as uN[S_ADDR_W]; + let we = preq.write_mask[bank +: u1]; + let re = preq.read_mask[bank +: u1]; + + let req = ram::RWRamReq { + addr, data, we, re, + write_mask: (), + read_mask: (), + }; + + trace_fmt!("bank = {:#x}, data = {:#x}, addr = {:#x}, we = {:#x}, re = {:#x}", bank, data, addr, we, re); + + let reqs = update(reqs, i, req); + let poss = update(poss, i, bank as u32); + let do_rd = update(do_rd, i, re); + let do_wr = update(do_wr, i, we); + (reqs, poss, do_rd, do_wr) + }((ZERO_REQS, ZERO_ORDER, ZERO_DO_SEND, ZERO_DO_COMP)) +} + +const S_DATA_W = u32:8; +const P_ADDR_W = u32:32; + +#[test] +fn to_single_req_64bit_width_test() { + const P_DATA_W = u32:64; + const P_NUM_PARTITIONS = P_DATA_W / S_DATA_W; + const P_MASK_W = P_NUM_PARTITIONS; + const S_ADDR_W = S_DATA_W - std::clog2(P_NUM_PARTITIONS); + + type PAddr = uN[P_ADDR_W]; + type PData = uN[P_DATA_W]; + type PMask = uN[P_MASK_W]; + type SAddr = uN[S_ADDR_W]; + type SData = uN[S_DATA_W]; + + let req = HistoryBufferReq { + addr: PAddr:0, + data: PData:0x88_77_66_55_44_33_22_11, + write_mask: PMask:0b1111_1111, + read_mask: PMask:0b0000_0000, + }; + let (reqs, orders, _, _) = to_single_req(req); + let exp_reqs_1 = ram::RWRamReq[8]:[ + ram::RWRamReq { addr: SAddr:0, data: SData:0x11, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x22, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x33, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x44, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x55, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x66, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x77, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x88, write_mask: (), read_mask: (), we: true, re: false }, + ]; + trace_fmt!("Reqs: {}", reqs); + trace_fmt!("Orders: {}", orders); + assert_eq(reqs, exp_reqs_1); + + let req = HistoryBufferReq { + addr: PAddr:0x1, + data: PData:0xAA_BB_CC_DD_EE_FF_99_88, + write_mask: PMask:0b1111_1111, + read_mask: PMask:0b0000_0000, + }; + let (reqs, orders, _, _) = to_single_req(req); + let exp_reqs_2 = ram::RWRamReq[8]:[ + ram::RWRamReq { addr: SAddr:1, data: SData:0xAA, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x88, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x99, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0xFF, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0xEE, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0xDD, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0xCC, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0xBB, write_mask: (), read_mask: (), we: true, re: false }, + ]; + trace_fmt!("Reqs: {}", reqs); + trace_fmt!("Orders: {}", orders); + + assert_eq(reqs, exp_reqs_2); + + let req = HistoryBufferReq { + addr: PAddr:0xA, + data: PData:0x08_07_06_05_04_03_02_01, + write_mask: PMask:0b1111_1111, + read_mask: PMask:0b0000_0000, + }; + let (reqs, orders, _, _) = to_single_req(req); + let exp_reqs_3 = ram::RWRamReq[8]:[ + ram::RWRamReq { addr: SAddr:2, data: SData:0x07, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:2, data: SData:0x08, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x01, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x02, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x03, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x04, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x05, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x06, write_mask: (), read_mask: (), we: true, re: false }, + ]; + trace_fmt!("Reqs: {}", reqs); + trace_fmt!("Orders: {}", orders); + + assert_eq(reqs, exp_reqs_3); +} + +#[test] +fn to_single_req_128bit_width_test() { + const P_DATA_W = u32:128; + const P_NUM_PARTITIONS = P_DATA_W / S_DATA_W; + const P_MASK_W = P_NUM_PARTITIONS; + const S_ADDR_W = S_DATA_W - std::clog2(P_NUM_PARTITIONS); + + type PAddr = uN[P_ADDR_W]; + type PData = uN[P_DATA_W]; + type PMask = uN[P_MASK_W]; + type SAddr = uN[S_ADDR_W]; + type SData = uN[S_DATA_W]; + + let req = HistoryBufferReq { + addr: PAddr:0xA, + data: PData:0x10_0F_0E_0D_0C_0B_0A_09_08_07_06_05_04_03_02_01, + write_mask: PMask:0b1111_1111_1111_1111, + read_mask: PMask:0b0000_0000_0000_0000, + }; + let (reqs, orders, _, _) = to_single_req(req); + let exp_reqs = ram::RWRamReq[P_NUM_PARTITIONS]:[ + ram::RWRamReq { addr: SAddr:1, data: SData:0x07, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x08, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x09, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0A, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0B, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0C, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0D, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0E, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x0F, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:1, data: SData:0x10, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x01, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x02, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x03, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x04, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x05, write_mask: (), read_mask: (), we: true, re: false }, + ram::RWRamReq { addr: SAddr:0, data: SData:0x06, write_mask: (), read_mask: (), we: true, re: false }, + ]; + trace_fmt!("Reqs: {}", reqs); + trace_fmt!("Orders: {}", orders); + + assert_eq(reqs, exp_reqs); +} + +fn pack_response( + resps: ram::RWRamResp, poss: u32, data: uN[P_DATA_W]) -> uN[P_DATA_W]{ + bit_slice_update(data, poss as u32 * u32:8, resps.data) +} + +fn to_parallel_resp( + resps: ram::RWRamResp[8], poss: u32[8]) -> HistoryBufferResp { + let data = unroll_for! (i, data) : (u32, uN[P_DATA_W]) in u32:0..u32:8 { + pack_response(resps[i], poss[i], data) + }(uN[P_DATA_W]:0); + HistoryBufferResp { data } +} + +#[test] +fn to_parallel_resp_test() { + const P_DATA_W = u32:64; + const P_NUM_PARTITIONS = P_DATA_W / S_DATA_W; + const P_MASK_W = P_NUM_PARTITIONS; + const S_ADDR_W = S_DATA_W - std::clog2(P_NUM_PARTITIONS); + + type PAddr = uN[P_ADDR_W]; + type PData = uN[P_DATA_W]; + type PMask = uN[P_MASK_W]; + type SAddr = uN[S_ADDR_W]; + type SData = uN[S_DATA_W]; + + let resps_1 = ram::RWRamResp[8]:[ + ram::RWRamResp { data: SData:0x11 }, + ram::RWRamResp { data: SData:0x22 }, + ram::RWRamResp { data: SData:0x33 }, + ram::RWRamResp { data: SData:0x44 }, + ram::RWRamResp { data: SData:0x55 }, + ram::RWRamResp { data: SData:0x66 }, + ram::RWRamResp { data: SData:0x77 }, + ram::RWRamResp { data: SData:0x88 }, + ]; + let orders_1 = u32[8]:[ u32:0, u32:1, u32:2, u32:3, u32:4, u32:5, u32:6, u32:7 ]; + let resp = to_parallel_resp(resps_1, orders_1); + let exp_resp1 = HistoryBufferResp { data: PData:0x8877_6655_4433_2211 }; + assert_eq(resp, exp_resp1); + + let resps_2 = ram::RWRamResp[8]:[ + ram::RWRamResp { data: SData:0xAA }, + ram::RWRamResp { data: SData:0x88 }, + ram::RWRamResp { data: SData:0x99 }, + ram::RWRamResp { data: SData:0xFF }, + ram::RWRamResp { data: SData:0xEE }, + ram::RWRamResp { data: SData:0xDD }, + ram::RWRamResp { data: SData:0xCC }, + ram::RWRamResp { data: SData:0xBB }, + ]; + let orders_2 = u32[8]:[ u32:7, u32:0, u32:1, u32:2, u32:3, u32:4, u32:5, u32:6 ]; + let resp = to_parallel_resp(resps_2, orders_2); + let exp_resp2 = HistoryBufferResp { + data: PData:0xAA_BB_CC_DD_EE_FF_99_88, + }; + + trace_fmt!("resp: {:#x}", resp); + trace_fmt!("exp_resp2: {:#x}", exp_resp2); + + assert_eq(resp, exp_resp2); +} + +proc HistoryBuffer1rw< + RAM_DATA_W: u32, + RAM_ADDR_W: u32, + SINGLE_RAM_DATA_W: u32, + RAM_NUM_PARTITIONS: u32 = {RAM_DATA_W / SINGLE_RAM_DATA_W}, + SINGLE_RAM_ADDR_W: u32 = {RAM_ADDR_W - std::clog2(RAM_NUM_PARTITIONS)}, +> { + type InputReq = HistoryBufferReq; + type InputResp = HistoryBufferResp; + type InputWrComp = HistoryBufferWrComp; + + type OutputReq = ram::RWRamReq; + type OutputResp = ram::RWRamResp; + type OutputWrComp = (); + + req_r: chan in; + resp_s: chan out; + wr_comp_s: chan out; + + req_n_s: chan[RAM_NUM_PARTITIONS] out; + resp_n_r: chan[RAM_NUM_PARTITIONS] in; + wr_comp_n_r: chan[RAM_NUM_PARTITIONS] in; + + init {} + + config( + req_r: chan in, + resp_s: chan out, + wr_comp_s: chan out, + + req_n_s: chan[RAM_NUM_PARTITIONS] out, + resp_n_r: chan[RAM_NUM_PARTITIONS] in, + wr_comp_n_r: chan[RAM_NUM_PARTITIONS] in + ) { + ( + req_r, resp_s, wr_comp_s, + req_n_s, resp_n_r, wr_comp_n_r, + ) + } + + next(state: ()) { + const ZERO_RESP = zero!(); + const ZERO_WR_COMP = zero!(); + + let (req_tok, req) = recv(join(), req_r); + trace_fmt!("Received request to parallel ram: {:#x}" , req); + let (reqs, orders, do_rd, do_wr) = to_single_req(req); + + let (tok, resps_tok, comps_tok, resp_data) = + unroll_for! (i, (tok, all_resps, all_comps, data)): + (u32, (token, token, token, uN[RAM_DATA_W])) in u32:0..RAM_NUM_PARTITIONS { + + if (do_rd[i] | do_wr[i]) { trace_fmt!("Sending request to ram {}", i); }; + let tok_req = send_if(tok, req_n_s[i], (do_rd[i] | do_wr[i]), reqs[i]); + + if do_rd[i] { trace_fmt!("Waiting for read response from ram {}", i); }; + let (tok_resp, resp) = recv_if(tok_req, resp_n_r[i], do_rd[i], ZERO_RESP); + + let output_resp = pack_response(resp, orders[i], data); + + if do_wr[i] { trace_fmt!("Waiting for write completion from ram {}", i); }; + let (tok_comp, _) = recv_if(tok_req, wr_comp_n_r[i], do_wr[i], ZERO_WR_COMP); + + (tok, join(tok_resp, all_resps), join(tok_comp, all_comps), output_resp) + }((req_tok, req_tok, req_tok, uN[RAM_DATA_W]:0)); + + let resp = HistoryBufferResp { data: resp_data }; + + let (do_resp, do_wr_comp) = + unroll_for! (i, (do_read, do_write)) : (u32, (bool, bool)) in u32:0..RAM_NUM_PARTITIONS { + let new_do_rd = do_read | do_rd[i]; + let new_do_wr = do_write | do_wr[i]; + (new_do_rd, new_do_wr) + }((false, false)); + + if do_resp { trace_fmt!("Sending response {:#x}", resp);}; + let resp_tok = send_if(resps_tok, resp_s, do_resp, resp); + + if do_wr_comp { trace_fmt!("Sending completion"); }; + let resp_tok = send_if(comps_tok, wr_comp_s, do_wr_comp, ()); + } +} + +const TEST_RAM_DATA_W = u32:64; +const TEST_RAM_SIZE = u32:1024; +const TEST_NUM_PARTITIONS = TEST_RAM_DATA_W / S_DATA_W; +const TEST_SINGLE_RAM_ADDR_W = P_ADDR_W - std::clog2(TEST_NUM_PARTITIONS); +const TEST_SINGLE_RAM_SIZE = TEST_RAM_SIZE / S_DATA_W; +const TEST_RAM_MASK = TEST_NUM_PARTITIONS; + +#[test_proc] +proc HistoryBuffer1rwTest { + type InputReq = HistoryBufferReq; + type InputResp = HistoryBufferResp; + type InputWrComp = HistoryBufferWrComp; + + type OutputReq = ram::RWRamReq; + type OutputResp = ram::RWRamResp; + type OutputWrComp = (); + + type IAddr = uN[P_ADDR_W]; + type IData = uN[TEST_RAM_DATA_W]; + type IMask = uN[TEST_RAM_MASK]; + + terminator: chan out; + req_s: chan out; + resp_r: chan in; + wr_comp_r: chan in; + + init {} + + config(terminator: chan out) { + let (req_s, req_r) = chan("req"); + let (resp_s, resp_r) = chan("resp"); + let (wr_comp_s, wr_comp_r) = chan("wr_comp"); + + let (req_n_s, req_n_r) = chan[TEST_NUM_PARTITIONS]("req_n"); + let (resp_n_s, resp_n_r) = chan[TEST_NUM_PARTITIONS]("resp_n"); + let (wr_comp_n_s, wr_comp_n_r) = chan[TEST_NUM_PARTITIONS]("wr_comp_n"); + + unroll_for! (i, _) : (u32, ()) in u32:0..TEST_NUM_PARTITIONS { + spawn ram::SinglePortRamModel + (req_n_r[i], resp_n_s[i], wr_comp_n_s[i]); + }(()); + + spawn HistoryBuffer1rw< + TEST_RAM_DATA_W, P_ADDR_W, S_DATA_W + >( + req_r, resp_s, wr_comp_s, + req_n_s, resp_n_r, wr_comp_n_r, + ); + + (terminator, req_s, resp_r, wr_comp_r) + } + + next(state: ()) { + let tok = send(join(), req_s, InputReq { + addr: IAddr:0x4, + data: IData:0x88_77_66_55_44_33_22_11, + write_mask: IMask:0b1001_0101, + read_mask: IMask:0b0000_0000, + }); + let (tok, _) = recv(tok, wr_comp_r); + + let tok = send(join(), req_s, InputReq { + addr: IAddr:0x8, + data: IData:0x0, + read_mask: IMask:0b1111_1111, + write_mask: IMask:0b0000_0000, + }); + let (tok, resp) = recv(tok, resp_r); + trace_fmt!("Received response: {:#x}", resp); + assert_eq(resp, InputResp { + data: IData:0x00_00_00_00_88_00_00_55, + }); + + let tok = send(join(), req_s, InputReq { + addr: IAddr:0x9, + data: IData:0xAA_BB, + write_mask: IMask:0b0000_0011, + read_mask: IMask:0b0000_0000, + }); + let (tok, _) = recv(tok, wr_comp_r); + + let tok = send(join(), req_s, InputReq { + addr: IAddr:0x8, + data: IData:0x0, + read_mask: IMask:0b1111_1111, + write_mask: IMask:0b0000_0000, + }); + let (tok, resp) = recv(tok, resp_r); + trace_fmt!("Received response: {:#x}", resp); + assert_eq(resp, InputResp { + data: IData:0x00_00_00_00_88_AA_BB_55, + }); + + send(tok, terminator, true); + } +} + +pub proc HistoryBuffer< + RAM_DATA_W: u32, + RAM_ADDR_W: u32, + SINGLE_RAM_DATA_W: u32, + RAM_NUM_PARTITIONS: u32 = {RAM_DATA_W / SINGLE_RAM_DATA_W}, + SINGLE_RAM_ADDR_W: u32 = {RAM_ADDR_W - std::clog2(RAM_NUM_PARTITIONS)}, +> { + type InputReq = HistoryBufferReq; + type InputResp = HistoryBufferResp; + type InputWrComp = (); + + type OutputReq = ram::RWRamReq; + type OutputResp = ram::RWRamResp; + type OutputWrComp = (); + + init { } + + config( + req0_r: chan in, + resp0_s: chan out, + wr_comp0_s: chan out, + + req1_r: chan in, + resp1_s: chan out, + wr_comp1_s: chan out, + + req0n_s: chan[RAM_NUM_PARTITIONS] out, + resp0n_r: chan[RAM_NUM_PARTITIONS] in, + wr_comp0n_r: chan[RAM_NUM_PARTITIONS] in, + + req1n_s: chan[RAM_NUM_PARTITIONS] out, + resp1n_r: chan[RAM_NUM_PARTITIONS] in, + wr_comp1n_r: chan[RAM_NUM_PARTITIONS] in + ) { + spawn HistoryBuffer1rw ( + req0_r, resp0_s, wr_comp0_s, + req0n_s, resp0n_r, wr_comp0n_r, + ); + + spawn HistoryBuffer1rw ( + req1_r, resp1_s, wr_comp1_s, + req1n_s, resp1n_r, wr_comp1n_r, + ); + + () + } + + next(state: ()) { } +} diff --git a/xls/modules/zstd/sequence_executor/history_copy_executor.x b/xls/modules/zstd/sequence_executor/history_copy_executor.x new file mode 100644 index 0000000000..1bb5f5b782 --- /dev/null +++ b/xls/modules/zstd/sequence_executor/history_copy_executor.x @@ -0,0 +1,336 @@ +// Copyright 2025 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.zstd.common; +import xls.modules.zstd.sequence_executor.history_buffer; +import xls.modules.zstd.memory.mem_writer; + + +pub struct HistoryCopyExecutorReq { + max_possible_read: u32, + match_length: u16, + source_addr: uN[HB_ADDR_W], + dest_addr: uN[HB_ADDR_W], +} + +pub enum HistoryCopyExecutorStatus : u1 { + OK = 0, + ERROR = 1, +} + +pub struct HistoryCopyExecutorResp { + status: HistoryCopyExecutorStatus, +} + +struct HistoryCopyExecutorState { + max_possible_read: u32, + literals_left_to_send: u16, + source_addr: uN[HB_ADDR_W], + dest_addr: uN[HB_ADDR_W], + write_req: history_buffer::HistoryBufferReq, + sending: bool, +} + +pub proc HistoryCopyExecutor< + AXI_DATA_W: u32, AXI_ADDR_W: u32, + HB_DATA_W: u32, HB_ADDR_W: u32, + MAX_BYTES_PER_REQ: u32 = {AXI_DATA_W / u32:8}, + HB_NUM_PARTITIONS: u32 = {HB_DATA_W / u32:8}> { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type HistoryCopyExecutorState = HistoryCopyExecutorState; + type HistoryCopyExecutorReq = HistoryCopyExecutorReq; + + input_r: chan in; + resp_s: chan out; + hb_req_s: chan out; + hb_resp_r: chan in; + hb_comp_r: chan in; + output_mem_wr_data_in_s: chan out; + + config( + input_r: chan in, + resp_s: chan out, + hb_req_s: chan out, + hb_resp_r: chan in, + hb_comp_r: chan in, + output_mem_wr_data_in_s: chan out + ) { + ( + input_r, resp_s, + hb_req_s, hb_resp_r, hb_comp_r, + output_mem_wr_data_in_s, + ) + } + + init { + zero!() + } + + next(state: HistoryCopyExecutorState) { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + let tok = join(); + + let recv_req = state.literals_left_to_send == u16:0; + let (tok, req) = recv_if(tok, input_r, recv_req, zero!()); + if recv_req { + trace_fmt!("[HistoryReadExecutor] Received request: {:#x}", req); + } else {}; + + let state = if recv_req { + HistoryCopyExecutorState { + max_possible_read: req.max_possible_read, + literals_left_to_send: req.match_length, + source_addr: req.source_addr, + dest_addr: req.dest_addr, + ..zero!() + } + } else { + state + }; + + let bytes_to_read = std::min(state.max_possible_read, state.literals_left_to_send as u32); + let data_mask = std::unsigned_max_value() >> (MAX_BYTES_PER_REQ - bytes_to_read); + let hb_req = if state.sending { + state.write_req + } else { + HistoryBufferReq { + addr: state.source_addr, + read_mask: data_mask, + ..zero!() + } + }; + let tok = send(tok, hb_req_s, hb_req); + trace_fmt!("[HistoryCopyExecutor] Sending history buffer request: {:#x}", hb_req); + let (tok, _comp_resp) = recv_if(tok, hb_comp_r, state.sending, ()); + + let (tok, hb_resp) = recv_if(tok, hb_resp_r, !state.sending, zero!()); + if !state.sending { + trace_fmt!("[HistoryCopyExecutor] Received history buffer response: {:#x}", hb_resp); + } else {}; + + let write_req = HistoryBufferReq { + addr: state.dest_addr, + data: hb_resp.data, + write_mask: data_mask, + ..zero!() + }; + + let output_mem_write = MemWriterDataPacket { + data: hb_req.data, + length: bytes_to_read as uN[AXI_ADDR_W], + last: false, + }; + let tok = send_if(tok, output_mem_wr_data_in_s, state.sending, output_mem_write); + if state.sending { + trace_fmt!("[HistoryCopyExecutor] Sending output mem write: {:#x}", output_mem_write); + } else {}; + + let send_response = state.sending && (state.literals_left_to_send as u32 - bytes_to_read) == u32:0; + let response = HistoryCopyExecutorResp { + status: HistoryCopyExecutorStatus::OK, + }; + let tok = send_if(tok, resp_s, send_response, response); + if send_response { + trace_fmt!("[HistoryCopyExecutor] Sending response: {:#x}", response); + } else {}; + + let new_state = if state.sending { + HistoryCopyExecutorState { + max_possible_read: state.max_possible_read, + literals_left_to_send: state.literals_left_to_send - bytes_to_read as u16, + source_addr: state.source_addr, + dest_addr: state.dest_addr + bytes_to_read as uN[HB_ADDR_W], + write_req, + sending: false, + } + } else { + HistoryCopyExecutorState { + max_possible_read: state.max_possible_read, + literals_left_to_send: state.literals_left_to_send, + source_addr: state.source_addr + bytes_to_read as uN[HB_ADDR_W], + dest_addr: state.dest_addr, + write_req, + sending: true, + } + }; + + new_state + } +} + +const TEST_AXI_ADDR_W = u32:32; +const TEST_AXI_DATA_W = u32:64; +const TEST_HB_ADDR_W = u32:32; +const TEST_HB_DATA_W = u32:64; +const TEST_HB_NUM_PARTITIONS = TEST_HB_DATA_W / u32:8; + +#[test_proc] +proc HistoryCopyExecutorTest { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type HistoryCopyExecutorReq = HistoryCopyExecutorReq; + + terminator: chan out; + + input_s: chan out; + resp_r: chan in; + hb_req_r: chan in; + hb_resp_s: chan out; + hb_comp_s: chan out; + output_mem_write_r: chan in; + + config(terminator: chan out) { + let (input_s, input_r) = chan("input"); + let (resp_s, resp_r) = chan("response"); + let (hb_req_s, hb_req_r) = chan("hb_request"); + let (hb_resp_s, hb_resp_r) = chan("hb_response"); + let (hb_comp_s, hb_comp_r) = chan("hb_comp"); + let (output_mem_write_s, output_mem_write_r) = chan("output_mem_write"); + + spawn HistoryCopyExecutor( + input_r, resp_s, + hb_req_s, hb_resp_r, hb_comp_r, + output_mem_write_s, + ); + + ( + terminator, + input_s, + resp_r, + hb_req_r, hb_resp_s, hb_comp_s, + output_mem_write_r, + ) + } + + init { } + + next(state: ()) { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + let tok = join(); + + let tok = send(tok, input_s, HistoryCopyExecutorReq { + match_length: u16:23, + source_addr: u32:0x10, + dest_addr: u32:0x18, + max_possible_read: u32:8, + }); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x10, + data: u64:0x0, + write_mask: u8:0x0, + read_mask: u8:0xff, + }); + + let hb_read_resp = HistoryBufferResp{data: u64:0x0123456789abcdef}; + trace_fmt!("[HistoryCopyExecutorTest] Sending history buffer read response: {:x}", hb_read_resp); + let tok = send(tok, hb_resp_s, hb_read_resp); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x18, + data: u64:0x0123456789abcdef, + write_mask: u8:0xff, + read_mask: u8:0x0, + }); + let tok = send(tok, hb_comp_s, ()); + + let (tok, mem_write_req) = recv(tok, output_mem_write_r); + trace_fmt!("[HistoryCopyExecutorTest] Received mem write packet: {:x}", mem_write_req); + assert_eq(mem_write_req, MemWriterDataPacket { + data: u64:0x0123456789abcdef, + length: u32:0x8, + last: false, + }); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x18, + data: u64:0x0, + write_mask: u8:0x0, + read_mask: u8:0xff, + }); + + let hb_read_resp = HistoryBufferResp{data: u64:0xfedcba9876543210}; + trace_fmt!("[HistoryCopyExecutorTest] Sending history buffer read response: {:x}", hb_read_resp); + let tok = send(tok, hb_resp_s, hb_read_resp); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x20, + data: u64:0xfedcba9876543210, + write_mask: u8:0xff, + read_mask: u8:0x0, + }); + let tok = send(tok, hb_comp_s, ()); + + let (tok, mem_write_req) = recv(tok, output_mem_write_r); + trace_fmt!("[HistoryCopyExecutorTest] Received mem write packet: {:x}", mem_write_req); + assert_eq(mem_write_req, MemWriterDataPacket { + data: u64:0xfedcba9876543210, + length: u32:0x8, + last: false, + }); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x20, + data: u64:0x0, + write_mask: u8:0x0, + read_mask: u8:0x7f, + }); + + let hb_read_resp = HistoryBufferResp{data: u64:0x12341234123412}; + trace_fmt!("[HistoryCopyExecutorTest] Sending history buffer read response: {:x}", hb_read_resp); + let tok = send(tok, hb_resp_s, hb_read_resp); + + let (tok, hb_req) = recv(tok, hb_req_r); + trace_fmt!("[HistoryCopyExecutorTest] Received history buffer req: {:x}", hb_req); + assert_eq(hb_req, HistoryBufferReq { + addr: u32:0x28, + data: u64:0x12341234123412, + write_mask: u8:0x7f, + read_mask: u8:0x0, + }); + let tok = send(tok, hb_comp_s, ()); + + let (tok, mem_write_req) = recv(tok, output_mem_write_r); + trace_fmt!("[HistoryCopyExecutorTest] Received mem write packet: {:x}", mem_write_req); + assert_eq(mem_write_req, MemWriterDataPacket { + data: u64:0x12341234123412, + length: u32:0x7, + last: false, + }); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor/join_output.x b/xls/modules/zstd/sequence_executor/join_output.x new file mode 100644 index 0000000000..ccf5070b0f --- /dev/null +++ b/xls/modules/zstd/sequence_executor/join_output.x @@ -0,0 +1,243 @@ +// Copyright 2025 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.zstd.common as common; +import xls.modules.zstd.memory.mem_writer as mem_writer; + +pub struct JoinOutputReq { + literals_to_receive: u32, + copies_to_receive: u32, +} + +enum JoinOutputStatus : u2 { + IDLE = 0, + RECEIVING_LITERALS = 1, + RECEIVING_COPIES = 2, +} + +struct JoinOutputState { + status: JoinOutputStatus, + literals_to_receive: u32, + copies_to_receive: u32, +} + +pub proc JoinOutput { + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + join_output_req_r: chan in; + output_wr_data_0_r: chan in; + output_wr_data_1_r: chan in; + output_mem_wr_data_s: chan out; + + config( + join_output_req_r: chan in, + output_wr_data_0_r: chan in, + output_wr_data_1_r: chan in, + output_mem_wr_data_s: chan out + ) { + ( + join_output_req_r, + output_wr_data_0_r, + output_wr_data_1_r, + output_mem_wr_data_s + ) + } + + init { + zero!() + } + + next(state: JoinOutputState) { + let tok = join(); + + let recv_req = state.status == JoinOutputStatus::IDLE; + let (tok, req) = recv_if(tok, join_output_req_r, recv_req, zero!()); + if recv_req { + trace_fmt!("[JoinOutput] Received request: {:x}", req); + } else {}; + + let req_valid = req.literals_to_receive != u32:0 || req.copies_to_receive != u32:0; + let state = if recv_req && req_valid { + JoinOutputState { + status: if req.literals_to_receive > u32:0 { JoinOutputStatus::RECEIVING_LITERALS } else { JoinOutputStatus::RECEIVING_COPIES }, + literals_to_receive: req.literals_to_receive, + copies_to_receive: req.copies_to_receive, + } + } else { + state + }; + + let receive_literals = state.status == JoinOutputStatus::RECEIVING_LITERALS; + let (tok, data0) = recv_if(tok, output_wr_data_0_r, receive_literals, zero!()); + if receive_literals { + trace_fmt!("[JoinOutput] Received literals: {:x}", data0); + } else {}; + let literals_finished = receive_literals && state.literals_to_receive == data0.length as u32; + + let receive_copies = state.status == JoinOutputStatus::RECEIVING_COPIES; + let (tok, data1) = recv_if(tok, output_wr_data_1_r, receive_copies, zero!()); + if receive_copies { + trace_fmt!("[JoinOutput] Received copies: {:x}", data1); + } else {}; + + let data = if receive_literals { + MemWriterDataPacket { + data: data0.data, + length: data0.length, + last: data0.last, + } + } else { + MemWriterDataPacket { + data: data1.data, + length: data1.length, + last: data1.last, + } + }; + let tok = send_if(tok, output_mem_wr_data_s, receive_literals || receive_copies, data); + + let new_literals_to_receive = state.literals_to_receive - data0.length as u32; + let new_copies_to_receive = state.copies_to_receive - data1.length as u32; + let state = match state.status { + JoinOutputStatus::IDLE => zero!(), + JoinOutputStatus::RECEIVING_LITERALS => { + let status = if literals_finished && new_copies_to_receive > u32:0 { + JoinOutputStatus::RECEIVING_COPIES + } else if literals_finished { + JoinOutputStatus::IDLE + } else { + JoinOutputStatus::RECEIVING_LITERALS + }; + JoinOutputState { + status, + literals_to_receive: new_literals_to_receive, + copies_to_receive: new_copies_to_receive, + } + }, + JoinOutputStatus::RECEIVING_COPIES => { + JoinOutputState { + status: if new_copies_to_receive == u32:0 { + JoinOutputStatus::IDLE + } else { + JoinOutputStatus::RECEIVING_COPIES + }, + literals_to_receive: new_literals_to_receive, + copies_to_receive: new_copies_to_receive, + } + }, + _ => zero!(), + }; + + state + } +} + +const TEST_AXI_DATA_W = u32:64; +const TEST_AXI_ADDR_W = u32:16; + +#[test_proc] +proc JoinOutputTest { + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + terminator: chan out; + + join_output_req_s: chan out; + output_write_0_s: chan out; + output_write_1_s: chan out; + output_mem_wr_data_r: chan in; + + config(terminator: chan out) { + let (join_output_req_s, join_output_req_r) = chan("join_output_req"); + let (output_write_0_s, output_write_0_r) = chan("output_write_0"); + let (output_write_1_s, output_write_1_r) = chan("output_write_1"); + let (output_mem_wr_data_s, output_mem_wr_data_r) = chan("output_mem_wr_data"); + + spawn JoinOutput ( + join_output_req_r, + output_write_0_r, + output_write_1_r, + output_mem_wr_data_s, + ); + + ( + terminator, + join_output_req_s, + output_write_0_s, + output_write_1_s, + output_mem_wr_data_r, + ) + } + + init { } + + next(state: ()) { + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + let tok = join(); + + let join_output_req = JoinOutputReq { + literals_to_receive: u32:12, + copies_to_receive: u32:15, + }; + let tok = send(tok, join_output_req_s, join_output_req); + + // Process packets with literals + let literals_data = MemWriterDataPacket { + data: uN[TEST_AXI_DATA_W]:0x0102030405060708, + length: uN[TEST_AXI_ADDR_W]:8, + last: false, + }; + let tok = send(tok, output_write_0_s, literals_data); + + let (tok, output_data) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[JoinOutputTest] Received output data: {:x}", output_data); + assert_eq(output_data, literals_data); + + let literals_data = MemWriterDataPacket { + data: uN[TEST_AXI_DATA_W]:0x01020304, + length: uN[TEST_AXI_ADDR_W]:4, + last: false, + }; + let tok = send(tok, output_write_0_s, literals_data); + + let (tok, output_data) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[JoinOutputTest] Received output data: {:x}", output_data); + assert_eq(output_data, literals_data); + + // Process packets with history copies + let history_data = MemWriterDataPacket { + data: uN[TEST_AXI_DATA_W]:0x0102030405060708, + length: uN[TEST_AXI_ADDR_W]:8, + last: false, + }; + let tok = send(tok, output_write_1_s, history_data); + + let (tok, output_data) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[JoinOutputTest] Received output data: {:x}", output_data); + assert_eq(output_data, history_data); + + let history_data = MemWriterDataPacket { + data: uN[TEST_AXI_DATA_W]:0x01020304050607, + length: uN[TEST_AXI_ADDR_W]:7, + last: false, + }; + let tok = send(tok, output_write_1_s, history_data); + + let (tok, output_data) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[JoinOutputTest] Received output data: {:x}", output_data); + assert_eq(output_data, history_data); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor/literals_executor.x b/xls/modules/zstd/sequence_executor/literals_executor.x new file mode 100644 index 0000000000..12e483195e --- /dev/null +++ b/xls/modules/zstd/sequence_executor/literals_executor.x @@ -0,0 +1,417 @@ +// Copyright 2025 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.zstd.common as common; +import xls.modules.zstd.memory.mem_writer as mem_writer; +import xls.modules.zstd.sequence_executor.history_buffer as history_buffer; +import xls.modules.zstd.sequence_executor.literals_prefetch as literals_prefetch; + +pub struct LiteralsExecutorReq { + literal_length: u16, + start_addr: u32, + raw_literals: u64, + raw_literals_length: u32, +} + +pub enum LiteralsExecutorStatus : u1 { + OK = 0, + ERROR = 1, +} + +pub struct LiteralsExecutorResp { + status: LiteralsExecutorStatus, +} + +type LiteralsBufCtrl = common::LiteralsBufferCtrl; + +type SequenceExecutorMessageType = common::SequenceExecutorMessageType; +type CopyOrMatchLength = common::CopyOrMatchLength; + +fn last_data_mask(literals_len: u32) -> uN[AXI_DATA_BYTES_W] { + let remain = (literals_len % AXI_DATA_BYTES_W) as uN[AXI_DATA_BYTES_W]; + match remain { + uN[AXI_DATA_BYTES_W]:0 => std::unsigned_max_value(), + _ => std::unsigned_max_value() >> (AXI_DATA_BYTES_W - (literals_len as u32 % AXI_DATA_BYTES_W)), + } +} + +const TEST_AXI_DATA_W = u32:64; +const TEST_AXI_DATA_BYTES_W = TEST_AXI_DATA_W / u32:8; + +#[test] +fn test_last_data_mask() { + assert_eq(last_data_mask(u32:1), uN[TEST_AXI_DATA_BYTES_W]:0b00000001); + assert_eq(last_data_mask(u32:2), uN[TEST_AXI_DATA_BYTES_W]:0b00000011); + assert_eq(last_data_mask(u32:3), uN[TEST_AXI_DATA_BYTES_W]:0b00000111); + assert_eq(last_data_mask(u32:7), uN[TEST_AXI_DATA_BYTES_W]:0b01111111); + assert_eq(last_data_mask(u32:8), uN[TEST_AXI_DATA_BYTES_W]:0b11111111); + assert_eq(last_data_mask(u32:63), uN[TEST_AXI_DATA_BYTES_W]:0b01111111); + assert_eq(last_data_mask(u32:64), uN[TEST_AXI_DATA_BYTES_W]:0b11111111); + assert_eq(last_data_mask(u32:65), uN[TEST_AXI_DATA_BYTES_W]:0b00000001); +} + +struct LiteralsExecutorState { + iter: uN[ADDR_W], + end_addr: uN[ADDR_W], + last_mask: uN[DATA_BYTES_W] +} + +// Module responsible for fetching data from LiteralsBuffer and writing it to both HistoryBuffer and Output +pub proc LiteralsExecutor { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type SequenceExecutorPacket = common::SequenceExecutorPacket; + type Iter = uN[HB_ADDR_W]; + type State = LiteralsExecutorState; + + input_r: chan in; + resp_s: chan out; + + hb_req_s: chan out; + hb_resp_r: chan in; + hb_comp_r: chan in; + + lit_buf_ctrl_prefetch_s: chan out; + lit_buf_prefetch_out_r: chan in; + + mem_wr_s: chan out; + + config( + input_r: chan in, + resp_s: chan out, + hb_req_s: chan out, + hb_resp_r: chan in, + hb_comp_r: chan in, + lit_buf_ctrl_s: chan out, + lit_buf_out_r: chan in, + mem_wr_s: chan out, + ) { + let (lit_buf_ctrl_prefetch_s, lit_buf_ctrl_prefetch_r) = chan("lit_buf_ctrl_prefetch"); + let (lit_buf_prefetch_out_s, lit_buf_prefetch_out_r) = chan("lit_buf_prefetch_out"); + + spawn literals_prefetch::LiteralsPrefetch( + lit_buf_ctrl_prefetch_r, // LiteralsExecutor sends ctrl to LiteralsPrefetch + lit_buf_ctrl_s, // LiteralsPrefetch sends ctrl to LiteralsBuffer + lit_buf_out_r, // LiteralsPrefetch gets data from LiteralsBuffer + lit_buf_prefetch_out_s // LiteralsPrefetch sends data to LiteralsExecutor + ); + + ( + input_r, + resp_s, + hb_req_s, hb_resp_r, hb_comp_r, + lit_buf_ctrl_prefetch_s, lit_buf_prefetch_out_r, + mem_wr_s + ) + } + + init { zero!() } + + next(state: State) { + type Iter = uN[HB_ADDR_W]; + type State = LiteralsExecutorState; + + let tok = join(); + + let req_valid = state.iter == state.end_addr; + + let (tok, req) = recv_if(tok, input_r, req_valid, zero!()); + + let state = if req_valid { + trace_fmt!("[LiteralsExecutor] Received request: {}", req); + State { + iter: req.start_addr as Iter, + end_addr: req.start_addr as Iter + req.literal_length as Iter + req.raw_literals_length as Iter, + last_mask: last_data_mask(req.literal_length as u32), + } + } else { + state + }; + + // request literals from LiteralsBuffer + // done once per request on input + // length on input is u16, and the length requested from LiteralsBuffer is u32, + // so it's always possible to request the whole data. + let raw_literals = req.raw_literals_length != u32:0; + let tok = send_if(tok, lit_buf_ctrl_prefetch_s, req_valid && !raw_literals, LiteralsBufCtrl { + length: req.literal_length as u32, + // TODO we have no information whether this is the last request or not. + // We can extend `LiteralsExecutorReq` with such information in case it's needed. + last: true + }); + + let (tok, literals) = recv_if(tok, lit_buf_prefetch_out_r, !raw_literals, zero!()); + let literals = if raw_literals { + SequenceExecutorPacket { + msg_type: SequenceExecutorMessageType::LITERAL, + length: req.raw_literals_length as CopyOrMatchLength, + content: req.raw_literals as uN[AXI_DATA_W], + last: true, + } + } else { + literals + }; + + let last = state.iter + literals.length as Iter == state.end_addr; + + let wr_mask = if last { + state.last_mask + } else { + std::unsigned_max_value() + }; + + // write data to history buffer + let tok_hb = send(tok, hb_req_s, HistoryBufferReq { + addr: state.iter as uN[HB_ADDR_W], + data: literals.content as uN[HB_DATA_W], + write_mask: wr_mask, + read_mask: uN[AXI_DATA_BYTES_W]:0, + }); + let (tok_hb, _resp, _valid) = recv_if_non_blocking(tok_hb, hb_resp_r, false, zero!()); + let (tok_hb, _resp) = recv(tok_hb, hb_comp_r); + + // write data to output + let mem_packet = MemWriterDataPacket { + data: literals.content as uN[AXI_DATA_W], + length: literals.length as uN[AXI_ADDR_W], + last: last, + }; + let tok_out = send(tok, mem_wr_s, mem_packet); + trace_fmt!("[LiteralsExecutor] Sending output mem write: {:#x}", mem_packet); + + let tok = join(tok_out, tok_hb); + + let response = LiteralsExecutorResp { + status: LiteralsExecutorStatus::OK, + }; + send_if(tok, resp_s, last, response); + + // iterate further + State { + iter: state.iter + literals.length as Iter, + ..state + } + } +} + +const INST_HB_DATA_W = common::AXI_DATA_W; +const INST_HB_DATA_BYTES_W = common::AXI_DATA_W / u32:8; +const INST_HB_ADDR_W = u32:32; +const INST_AXI_DATA_W = common::AXI_DATA_W; +const INST_AXI_DATA_BYTES_W = common::AXI_DATA_W / u32:8; +const INST_AXI_ADDR_W = u32:32; +const INST_NUM_PARTITIONS = INST_HB_DATA_W / u32:8; + +proc LiteralsExecutorInst { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type SequenceExecutorPacket = common::SequenceExecutorPacket; + + input_r: chan in; + resp_s: chan out; + + hb_req_s: chan out; + hb_resp_r: chan in; + hb_comp_r: chan in; + + lit_buf_ctrl_s: chan out; + lit_buf_out_r: chan in; + + mem_wr_s: chan out; + + config( + input_r: chan in, + resp_s: chan out, + hb_req_s: chan out, + hb_resp_r: chan in, + hb_comp_r: chan in, + lit_buf_ctrl_s: chan out, + lit_buf_out_r: chan in, + mem_wr_s: chan out, + ) { + + spawn LiteralsExecutor( + input_r, resp_s, hb_req_s, hb_resp_r, hb_comp_r, lit_buf_ctrl_s, lit_buf_out_r, mem_wr_s); + ( + input_r, resp_s, + hb_req_s, hb_resp_r, hb_comp_r, + lit_buf_ctrl_s, lit_buf_out_r, + mem_wr_s + ) + } + + init { () } + + next(state: ()) {} +} + +#[test_proc] +proc LiteralsExecutorTest { + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type SequenceExecutorPacket = common::SequenceExecutorPacket; + + input_s: chan out; + resp_r: chan in; + hb_req_r: chan in; + hb_comp_s: chan out; + lit_buf_ctrl_r: chan in; + lit_buf_out_s: chan out; + mem_wr_r: chan in; + terminator: chan out; + + config (terminator: chan out) { + let (input_s, input_r) = chan("input"); + let (resp_s, resp_r) = chan("resp"); + let (hb_req_s, hb_req_r) = chan("hb_req"); + let (_hb_resp_s, hb_resp_r) = chan("hb_resp"); + let (hb_comp_s, hb_comp_r) = chan("hb_comp"); + let (lit_buf_ctrl_s, lit_buf_ctrl_r) = chan("lit_buf_ctrl"); + let (lit_buf_out_s, lit_buf_out_r) = chan("lit_buf_out"); + let (mem_wr_s, mem_wr_r) = chan("mem_wr"); + + spawn LiteralsExecutor( + input_r, + resp_s, + hb_req_s, + hb_resp_r, + hb_comp_r, + lit_buf_ctrl_s, + lit_buf_out_r, + mem_wr_s + ); + + (input_s, resp_r, hb_req_r, hb_comp_s, lit_buf_ctrl_r, lit_buf_out_s, mem_wr_r, terminator) + } + + init { } + + next (state: ()) { + let tok = join(); + let LITERAL_LENGTH = u16:5; + let HB_START_ADDR = u32:4; + let LITERALS_CONTENT = uN[common::AXI_DATA_W]:0xfedc009876; + + let tok = send(tok, input_s, LiteralsExecutorReq { + literal_length: LITERAL_LENGTH, + start_addr: HB_START_ADDR, + ..zero!() + }); + + // LiteralsPrefetch must request the literals from LiteralsBuffer. + let (tok, lit_buf_req) = recv(tok, lit_buf_ctrl_r); + assert_eq(lit_buf_req.length, u32:5); + assert_eq(lit_buf_req.last, true); + + // LiteralsBuffer sends 5 literals + let tok = send(tok, lit_buf_out_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:5, + content: LITERALS_CONTENT, + last: true + }); + + // It must write the literals to HistoryBuffer + let (tok_hb, hb_req) = recv(tok, hb_req_r); + assert_eq(hb_req.write_mask, uN[INST_HB_DATA_BYTES_W]:0b11111); + assert_eq(hb_req.data, LITERALS_CONTENT as uN[INST_AXI_DATA_W]); + assert_eq(hb_req.read_mask, uN[INST_HB_DATA_BYTES_W]:0); + assert_eq(hb_req.addr, HB_START_ADDR as uN[INST_HB_ADDR_W]); + + let tok_hb = send(tok_hb, hb_comp_s, ()); + + // it must write the literals to output + let (tok_mem, mem_out) = recv(tok, mem_wr_r); + assert_eq(mem_out.data, LITERALS_CONTENT as uN[INST_AXI_DATA_W]); + assert_eq(mem_out.length, LITERAL_LENGTH as u32); + + let tok = join(tok_mem, tok_hb, tok); + + // it must send a response + let (tok, resp) = recv(tok, resp_r); + assert_eq(resp.status, LiteralsExecutorStatus::OK); + + // second test, with larger data + let LITERAL_LENGTH = u16:3300; + let HB_START_ADDR = u32:0x100; + let tok = send(tok, input_s, LiteralsExecutorReq { + literal_length: LITERAL_LENGTH, + start_addr: HB_START_ADDR, + ..zero!() + }); + + // It must request literals from LiteralsBuffer + let (tok, lit_buf_req) = recv(tok, lit_buf_ctrl_r); + assert_eq(lit_buf_req.length, u32:3300); + assert_eq(lit_buf_req.last, true); + + // LiteralsBuffer sends the data + let tok_literals_send = for (i, tok_literals_send) in u16:0..(LITERAL_LENGTH / u16:8) { + send(tok_literals_send, lit_buf_out_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:8, + content: i as uN[INST_HB_DATA_W], + last: false + }) + }(tok); + + // LiteralsBuffer sends the remaining bytes + let tok_literals_send = send(tok_literals_send, lit_buf_out_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: (LITERAL_LENGTH % u16:8) as common::CopyOrMatchLength, + content: uN[INST_HB_DATA_W]:0xdead, + last: false + }); + + // It must write the literals to HistoryBuffer + let tok_hb = for (i, tok_hb) in u16:0..(LITERAL_LENGTH / u16:8) { + let (tok_hb, hb_req) = recv(tok_hb, hb_req_r); + assert_eq(hb_req.write_mask, std::unsigned_max_value()); + assert_eq(hb_req.read_mask, uN[INST_HB_DATA_BYTES_W]:0); + // increment by 8 as 8 bytes are written each time. + assert_eq(hb_req.addr, (HB_START_ADDR + (i as u32) * u32:8) as uN[INST_HB_ADDR_W]); + let tok_hb = send(tok_hb, hb_comp_s, ()); + tok_hb + }(tok); + + let (tok_hb, hb_req) = recv(tok_hb, hb_req_r); + assert_eq(hb_req.write_mask, uN[INST_HB_DATA_BYTES_W]:0b00001111); + assert_eq(hb_req.read_mask, uN[INST_HB_DATA_BYTES_W]:0); + assert_eq(hb_req.data, uN[INST_HB_DATA_W]:0xdead); + let tok_hb = send(tok_hb, hb_comp_s, ()); + + // it must write the literals to output + let tok_out = for (_i, tok_out) in u16:0..(LITERAL_LENGTH / u16:8) { + let (tok_out, data_packet) = recv(tok, mem_wr_r); + assert_eq(data_packet.length, uN[INST_HB_ADDR_W]:8); + assert_eq(data_packet.last, false); + tok_out + }(tok); + let (tok_out, data_packet) = recv(tok, mem_wr_r); + assert_eq(data_packet.length, (LITERAL_LENGTH % u16:8) as uN[INST_HB_ADDR_W]); + assert_eq(data_packet.last, true); + + let tok = join(tok_literals_send, tok_hb, tok_out); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor/literals_prefetch.x b/xls/modules/zstd/sequence_executor/literals_prefetch.x new file mode 100644 index 0000000000..63c636c8b6 --- /dev/null +++ b/xls/modules/zstd/sequence_executor/literals_prefetch.x @@ -0,0 +1,198 @@ +// Copyright 2025 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.zstd.common as common; + +type LiteralsBufCtrl = common::LiteralsBufferCtrl; + +struct PrefetchState { + sent: u32, + to_send: u32, +} + +pub proc LiteralsPrefetch { + type SequenceExecutorPacket = common::SequenceExecutorPacket; + + lit_buf_ctrl_r: chan in; + lit_buf_ctrl_s: chan out; + lit_buf_out_r: chan in; + lit_buf_out_s: chan out; + + config( + lit_buf_ctrl_r: chan in, + lit_buf_ctrl_s: chan out, + lit_buf_out_r: chan in, + lit_buf_out_s: chan out, + ) { + ( + lit_buf_ctrl_r, + lit_buf_ctrl_s, + lit_buf_out_r, + lit_buf_out_s + ) + } + + init { zero!() } + + next(state: PrefetchState) { + let tok = join(); + + let ready_for_req = state.sent == state.to_send; + + let (tok, req) = recv_if(tok, lit_buf_ctrl_r, ready_for_req, zero!()); + if ready_for_req { + trace_fmt!("[LiteralsPrefetch] Received request: {:x}", req); + } else {}; + + let state = if ready_for_req { + PrefetchState { + sent: u32:0, + to_send: req.length, + } + } else { + state + }; + + let lit_buf_req = LiteralsBufCtrl { + length: req.length, + ..req + }; + if ready_for_req { + trace_fmt!("[LiteralsPrefetch] Sending literals buffer request: {:x}", lit_buf_req); + } else {}; + let tok = send_if(tok, lit_buf_ctrl_s, ready_for_req, lit_buf_req); + + let (tok, literals) = recv(tok, lit_buf_out_r); + trace_fmt!("[LiteralsPrefetch] Sending literals: {:x}", literals); + let tok = send(tok, lit_buf_out_s, literals); + + let literals_sent = state.sent + literals.length as u32; + + PrefetchState { + sent: literals_sent, + ..state + } + } +} + +const TEST_DATA_W = u32:64; +const TEST_DATA_W_BYTES = TEST_DATA_W / u32:8; + +#[test_proc] +proc LiteralsPrefetchTest { + type SequenceExecutorPacket = common::SequenceExecutorPacket; + + lit_buf_ctrl0_s: chan out; + lit_buf_ctrl1_r: chan in; + lit_buf_out0_s: chan out; + lit_buf_out1_r: chan in; + terminator: chan out; + + config (terminator: chan out) { + let (lit_buf_ctrl0_s, lit_buf_ctrl0_r) = chan("ctrl_to_prefetch"); + let (lit_buf_ctrl1_s, lit_buf_ctrl1_r) = chan("ctrl_to_lit_buf"); + let (lit_buf_out0_s, lit_buf_out0_r) = chan("lit_buf_out0"); + let (lit_buf_out1_s, lit_buf_out1_r) = chan("lit_buf_out1"); + + spawn LiteralsPrefetch( + lit_buf_ctrl0_r, + lit_buf_ctrl1_s, + lit_buf_out0_r, + lit_buf_out1_s + ); + + (lit_buf_ctrl0_s, lit_buf_ctrl1_r, lit_buf_out0_s, lit_buf_out1_r, terminator) + } + + init { } + + next (state: ()) { + let tok = join(); + + // request a single literal + let tok = send(tok, lit_buf_ctrl0_s, LiteralsBufCtrl { + length: u32:1, + last: false + }); + + let (tok, req) = recv(tok, lit_buf_ctrl1_r); + assert_eq(req.length, u32:1); + assert_eq(req.last, false); + + let tok = send(tok, lit_buf_out0_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:1, + content: uN[TEST_DATA_W]:0x88, + last: true + }); + + // It must send 1 literal back as requested + let (tok, data) = recv(tok, lit_buf_out1_r); + assert_eq(data.msg_type, common::SequenceExecutorMessageType::LITERAL); + assert_eq(data.length, common::CopyOrMatchLength:1); + assert_eq(data.content, uN[TEST_DATA_W]:0x88); + + // Let's request more (17 literals). + let tok = send(tok, lit_buf_ctrl0_s, LiteralsBufCtrl { + length: u32:17, + last: true + }); + + // It must request 17 literals: + let (tok, req) = recv(tok, lit_buf_ctrl1_r); + assert_eq(req.length, u32:17); + assert_eq(req.last, true); + + // feed the prefetch with 17 literals as requested + let tok_feed = send(tok, lit_buf_out0_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:8, + content: uN[TEST_DATA_W]:0xffeeddccbbaafefd, + last: false + }); + let tok_feed = send(tok_feed, lit_buf_out0_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:8, + content: uN[TEST_DATA_W]:0x0102030405060708, + last: false + }); + let tok_feed = send(tok_feed, lit_buf_out0_s, SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: common::CopyOrMatchLength:1, + content: uN[TEST_DATA_W]:0x08, + last: true + }); + + // It must send 8, 8, 1 (17 in total) literals back as requested + let (tok_recv, data) = recv(tok, lit_buf_out1_r); + assert_eq(data.msg_type, common::SequenceExecutorMessageType::LITERAL); + assert_eq(data.length, common::CopyOrMatchLength:8); + // it must first send the literals that were prefetched eariler + assert_eq(data.content, uN[TEST_DATA_W]:0xffeeddccbbaafefd); + + let (tok_recv, data) = recv(tok, lit_buf_out1_r); + assert_eq(data.msg_type, common::SequenceExecutorMessageType::LITERAL); + assert_eq(data.length, common::CopyOrMatchLength:8); + assert_eq(data.content, uN[TEST_DATA_W]:0x0102030405060708); + + // the last literal + let (tok_recv, data) = recv(tok, lit_buf_out1_r); + assert_eq(data.msg_type, common::SequenceExecutorMessageType::LITERAL); + assert_eq(data.length, common::CopyOrMatchLength:1); + assert_eq(data.content, uN[TEST_DATA_W]:0x08); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor/sequence_executor.x b/xls/modules/zstd/sequence_executor/sequence_executor.x new file mode 100644 index 0000000000..f40e6fab20 --- /dev/null +++ b/xls/modules/zstd/sequence_executor/sequence_executor.x @@ -0,0 +1,352 @@ +// Copyright 2025 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.zstd.common as common; +import xls.modules.zstd.memory.mem_writer as mem_writer; +import xls.modules.zstd.parallel_rams as parallel_rams; +import xls.modules.zstd.ram_printer as ram_printer; + +import xls.modules.zstd.sequence_executor.join_output as join_output; +import xls.modules.zstd.sequence_executor.literals_executor as literals_executor; +import xls.modules.zstd.sequence_executor.history_copy_executor as history_copy_executor; +import xls.modules.zstd.sequence_executor.history_buffer as history_buffer; +import xls.modules.zstd.sequence_executor.sequence_executor_ctrl as sequence_executor_ctrl; +import xls.examples.ram; + +type BlockData = common::BlockData; +type CopyOrMatchContent = common::CopyOrMatchContent; +type CopyOrMatchLength = common::CopyOrMatchLength; +type ZstdDecodedPacket = common::ZstdDecodedPacket; +type BlockPacketLength = common::BlockPacketLength; +type Offset = common::Offset; +type SequenceExecutorMessageType = common::SequenceExecutorMessageType; +type JoinOutputReq = join_output::JoinOutputReq; +type LiteralsBufCtrl = common::LiteralsBufferCtrl; + +pub proc SequenceExecutor< + HISTORY_BUFFER_SIZE_KB: u32, + AXI_DATA_W: u32, + AXI_ADDR_W: u32, + HB_RAM_SIZE_TOTAL: u64, + HB_RAM_ADDR_W: u32, + HB_RAM_NUM: u32, + SINGLE_RAM_DATA_W: u32 = {u32:8}, + SINGLE_HB_RAM_ADDR_W: u32 = {HB_RAM_ADDR_W - std::clog2(HB_RAM_NUM)}, + AXI_DATA_BYTES_W: u32 = {AXI_DATA_W / u32:8}> +{ + type LiteralsExecutorReq = literals_executor::LiteralsExecutorReq; + type LiteralsExecutorResp = literals_executor::LiteralsExecutorResp; + type HistoryCopyExecutorReq = history_copy_executor::HistoryCopyExecutorReq; + type HistoryCopyExecutorResp = history_copy_executor::HistoryCopyExecutorResp; + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + type HistoryBufferReq = history_buffer::HistoryBufferReq; + type HistoryBufferResp = history_buffer::HistoryBufferResp; + type HistoryBufferComp = history_buffer::HistoryBufferWrComp; + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; + type SequenceExecutorPacket = common::SequenceExecutorPacket; + type RWRamWrComp = (); + + config( + input_r: chan in, + lit_buf_ctrl_s: chan out, + lit_buf_out_r: chan in, + rw_req_s_0: chan[HB_RAM_NUM] out, + rw_resp_r_0: chan[HB_RAM_NUM] in, + rw_wr_comp_r_0: chan[HB_RAM_NUM] in, + rw_req_s_1: chan[HB_RAM_NUM] out, + rw_resp_r_1: chan[HB_RAM_NUM] in, + rw_wr_comp_r_1: chan[HB_RAM_NUM] in, + output_mem_wr_data_s: chan out, + ) { + const CHANNEL_DEPTH = u32:32; + + let (lit_exec_req_s, lit_exec_req_r) = chan("literals_executor_req"); + let (lit_exec_resp_s, lit_exec_resp_r) = chan("literals_executor_resp"); + + let (lit_exec_hb_req_s, lit_exec_hb_req_r) = chan("literals_executor_history_buffer_req"); + let (lit_exec_hb_resp_s, lit_exec_hb_resp_r) = chan("literals_executor_history_buffer_resp"); + let (lit_exec_hb_comp_s, lit_exec_hb_comp_r) = chan("literals_executor_history_buffer_comp"); + + let (history_copy_exec_req_s, history_copy_exec_req_r) = chan("history_copy_executor_req"); + let (history_copy_exec_resp_s, history_copy_exec_resp_r) = chan("history_copy_executor_resp"); + + let (join_output_req_s, join_output_req_r) = chan("join_output_req"); + let (output_write_s, output_write_r) = chan[2]("output_write"); + + let (history_copy_hb_req_s, history_copy_hb_req_r) = chan("history_copy_history_buffer_req"); + let (history_copy_hb_resp_s, history_copy_hb_resp_r) = chan("history_copy_history_buffer_resp"); + let (history_copy_hb_comp_s, history_copy_hb_comp_r) = chan("history_copy_history_buffer_comp"); + + spawn sequence_executor_ctrl::SequenceExecutorCtrl< + HISTORY_BUFFER_SIZE_KB, + AXI_DATA_W, + HB_RAM_ADDR_W, + HB_RAM_SIZE_TOTAL, + HB_RAM_NUM, + >( + input_r, + join_output_req_s, + lit_exec_req_s, lit_exec_resp_r, + history_copy_exec_req_s, history_copy_exec_resp_r + ); + + spawn literals_executor::LiteralsExecutor< + AXI_DATA_W, AXI_ADDR_W, AXI_DATA_W, HB_RAM_ADDR_W + >( + lit_exec_req_r, + lit_exec_resp_s, + lit_exec_hb_req_s, + lit_exec_hb_resp_r, + lit_exec_hb_comp_r, + lit_buf_ctrl_s, + lit_buf_out_r, + output_write_s[0] + ); + + spawn history_copy_executor::HistoryCopyExecutor< + AXI_DATA_W, AXI_ADDR_W, AXI_DATA_W, HB_RAM_ADDR_W + >( + history_copy_exec_req_r, + history_copy_exec_resp_s, + history_copy_hb_req_s, + history_copy_hb_resp_r, + history_copy_hb_comp_r, + output_write_s[1] + ); + + spawn history_buffer::HistoryBuffer( + lit_exec_hb_req_r, lit_exec_hb_resp_s, lit_exec_hb_comp_s, + history_copy_hb_req_r, history_copy_hb_resp_s, history_copy_hb_comp_s, + rw_req_s_0, rw_resp_r_0, rw_wr_comp_r_0, + rw_req_s_1, rw_resp_r_1, rw_wr_comp_r_1, + ); + + spawn join_output::JoinOutput( + join_output_req_r, + output_write_r[0], + output_write_r[1], + output_mem_wr_data_s + ); + + () + } + + init { } + + next(state: ()) { } +} + +pub const ZSTD_SINGLE_RAM_DATA_W = u32:8; +pub const ZSTD_HISTORY_BUFFER_SIZE_KB = common::HISTORY_BUFFER_SIZE_KB; +pub const ZSTD_AXI_DATA_W = common::AXI_DATA_W; +pub const ZSTD_AXI_DATA_BYTES_W = ZSTD_AXI_DATA_W / u32:8; +pub const ZSTD_AXI_ADDR_W = common::AXI_ADDR_W; +pub const ZSTD_HB_RAM_NUM = ZSTD_AXI_DATA_W / ZSTD_SINGLE_RAM_DATA_W; +pub const ZSTD_HB_RAM_SIZE_TOTAL = ZSTD_HISTORY_BUFFER_SIZE_KB as u64 * u64:1024; +pub const ZSTD_HB_RAM_ADDR_W = ZSTD_AXI_ADDR_W; +pub const ZSTD_SINGLE_HB_RAM_ADDR_W = ZSTD_HB_RAM_ADDR_W - std::clog2(ZSTD_HB_RAM_NUM); + +pub proc SequenceExecutorZstd { + type SequenceExecutorPacket = common::SequenceExecutorPacket; + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; + type RWRamWrComp = (); + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + init { } + + config( + input_r: chan in, + lit_buf_ctrl_s: chan out, + lit_buf_out_r: chan in, + rw_req_s_0: chan[ZSTD_HB_RAM_NUM] out, + rw_resp_r_0: chan[ZSTD_HB_RAM_NUM] in, + rw_wr_comp_r_0: chan[ZSTD_HB_RAM_NUM] in, + rw_req_s_1: chan[ZSTD_HB_RAM_NUM] out, + rw_resp_r_1: chan[ZSTD_HB_RAM_NUM] in, + rw_wr_comp_r_1: chan[ZSTD_HB_RAM_NUM] in, + output_mem_wr_data_s: chan out, + ) { + spawn SequenceExecutor< + ZSTD_HISTORY_BUFFER_SIZE_KB, + ZSTD_AXI_DATA_W, + ZSTD_AXI_ADDR_W, + ZSTD_HB_RAM_SIZE_TOTAL, + ZSTD_HB_RAM_ADDR_W, + ZSTD_HB_RAM_NUM, + ZSTD_SINGLE_RAM_DATA_W, + >( + input_r, + lit_buf_ctrl_s, lit_buf_out_r, + rw_req_s_0, + rw_resp_r_0, + rw_wr_comp_r_0, + rw_req_s_1, + rw_resp_r_1, + rw_wr_comp_r_1, + output_mem_wr_data_s + ); + } + + next (state: ()) { } +} + +#[test_proc] +proc SequenceExecutorTest { + type SequenceExecutorPacket = common::SequenceExecutorPacket; + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; + type RWRamWrComp = (); + type MemWriterDataPacket = mem_writer::MemWriterDataPacket; + + terminator: chan out; + + input_s: chan out; + lit_buf_ctrl_r: chan in; + lit_buf_out_s: chan out; + rw_req_r_0: chan[ZSTD_HB_RAM_NUM] in; + rw_resp_s_0: chan[ZSTD_HB_RAM_NUM] out; + rw_wr_comp_s_0: chan[ZSTD_HB_RAM_NUM] out; + rw_req_r_1: chan[ZSTD_HB_RAM_NUM] in; + rw_resp_s_1: chan[ZSTD_HB_RAM_NUM] out; + rw_wr_comp_s_1: chan[ZSTD_HB_RAM_NUM] out; + output_mem_wr_data_r: chan in; + + config(terminator: chan out) { + let (input_s, input_r) = chan("input"); + + let (output_mem_wr_data_s, output_mem_wr_data_r) = chan("output_mem_wr_data"); + + let (rw_req_s_0, rw_req_r_0) = chan[ZSTD_HB_RAM_NUM]("rw_req_0"); + let (rw_resp_s_0, rw_resp_r_0) = chan[ZSTD_HB_RAM_NUM]("rw_resp_0"); + let (rw_wr_comp_s_0, rw_wr_comp_r_0) = chan[ZSTD_HB_RAM_NUM]("rw_wr_comp_0"); + + let (rw_req_s_1, rw_req_r_1) = chan[ZSTD_HB_RAM_NUM]("rw_req_1"); + let (rw_resp_s_1, rw_resp_r_1) = chan[ZSTD_HB_RAM_NUM]("rw_resp_1"); + let (rw_wr_comp_s_1, rw_wr_comp_r_1) = chan[ZSTD_HB_RAM_NUM]("rw_wr_comp_1"); + + let (lit_buf_ctrl_s, lit_buf_ctrl_r) = chan("lit_buf_ctrl"); + let (lit_buf_out_s, lit_buf_out_r) = chan("lit_buf_out"); + + spawn SequenceExecutor< + ZSTD_HISTORY_BUFFER_SIZE_KB, + ZSTD_AXI_DATA_W, + ZSTD_AXI_ADDR_W, + ZSTD_HB_RAM_SIZE_TOTAL, + ZSTD_HB_RAM_ADDR_W, + ZSTD_HB_RAM_NUM, + ZSTD_SINGLE_RAM_DATA_W, + > ( + input_r, + lit_buf_ctrl_s, lit_buf_out_r, + rw_req_s_0, + rw_resp_r_0, + rw_wr_comp_r_0, + rw_req_s_1, + rw_resp_r_1, + rw_wr_comp_r_1, + output_mem_wr_data_s, + ); + + ( + terminator, + input_s, + lit_buf_ctrl_r, lit_buf_out_s, + rw_req_r_0, rw_resp_s_0, rw_wr_comp_s_0, + rw_req_r_1, rw_resp_s_1, rw_wr_comp_s_1, + output_mem_wr_data_r, + ) + } + + init { } + + next(state: ()) { + let tok = join(); + + let literal_length = u64:0x8; + let literals_content = uN[ZSTD_AXI_DATA_W]:0x7060504030201000; + let packet = SequenceExecutorPacket{ + msg_type: SequenceExecutorMessageType::SEQUENCE, + length: literal_length, + content: uN[ZSTD_AXI_DATA_W]:0xb0010, + last: u1:0}; + let tok = send(tok, input_s, packet); + + let (tok, lit_buf_req) = recv(tok, lit_buf_ctrl_r); + trace_fmt!("[SequenceExecutorTest] Received literals buffer request: {:x}", lit_buf_req); + let literals_packet = SequenceExecutorPacket { + msg_type: common::SequenceExecutorMessageType::LITERAL, + length: literal_length as common::CopyOrMatchLength, + content: literals_content, + last: false, + }; + trace_fmt!("[SequenceExecutorTest] Sending literals packet: {:x}", literals_packet); + let tok = send(tok, lit_buf_out_s, literals_packet); + + // Expect 8 bytes write to history buffer from literals + unroll_for!(i, _) : (u32, ()) in u32:0..u32:8 { + let (tok, _data) = recv(tok, rw_req_r_0[i]); + send(tok, rw_wr_comp_s_0[i], ()); + }(()); + + // Expect output mem write from literals + let (tok, literal_packet) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[SequenceExecutorTest] Received mem write packet: {:x}", literal_packet); + // assert_eq(literal_packet.data, literals_content); + + // Expect 8 bytes read from history buffer for history copy + unroll_for!(i, _) : (u32, ()) in u32:0..u32:8 { + let (tok, _req) = recv(tok, rw_req_r_1[i]); + send(tok, rw_resp_s_1[i], RWRamResp { + data: i as uN[ZSTD_SINGLE_RAM_DATA_W] + }); + }(()); + + // Expect 8 bytes write to history buffer from history copy + unroll_for!(i, _) : (u32, ()) in u32:0..u32:8 { + let (tok, req) = recv(tok, rw_req_r_1[i]); + assert_eq(req.data, i as uN[ZSTD_SINGLE_RAM_DATA_W]); + send(tok, rw_wr_comp_s_1[i], ()); + }(()); + + // Expect 8 bytes read to history buffer from history copy + unroll_for!(i, _) : (u32, ()) in u32:0..u32:8 { + let (tok, _data) = recv(tok, rw_req_r_1[i]); + send(tok, rw_resp_s_1[i], RWRamResp { + data: i as uN[ZSTD_SINGLE_RAM_DATA_W] + uN[ZSTD_SINGLE_RAM_DATA_W]:0x10 + }); + }(()); + + // Expect 8 bytes write from history buffer for history copy + unroll_for!(i, _) : (u32, ()) in u32:0..u32:8 { + let (tok, req) = recv(tok, rw_req_r_1[i]); + trace_fmt!("Request: {:x}", req); + assert_eq(req.data, i as uN[ZSTD_SINGLE_RAM_DATA_W] + uN[ZSTD_SINGLE_RAM_DATA_W]:0x10); + send(tok, rw_wr_comp_s_1[i], ()); + }(()); + + // Expect output mem write from history copy + let (tok, history_copy_packet) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[SequenceExecutorTest] Received mem write packet: {:x}", history_copy_packet); + assert_eq(history_copy_packet.data, uN[ZSTD_AXI_DATA_W]:0x0706050403020100); + + // Expect output mem write from history copy + let (tok, history_copy_packet) = recv(tok, output_mem_wr_data_r); + trace_fmt!("[SequenceExecutorTest] Received mem write packet: {:x}", history_copy_packet); + assert_eq(history_copy_packet.data, uN[ZSTD_AXI_DATA_W]:0x1716151413121110); + + send(tok, terminator, true); + } +} diff --git a/xls/modules/zstd/sequence_executor/sequence_executor_ctrl.x b/xls/modules/zstd/sequence_executor/sequence_executor_ctrl.x new file mode 100644 index 0000000000..b6b6d0ad4e --- /dev/null +++ b/xls/modules/zstd/sequence_executor/sequence_executor_ctrl.x @@ -0,0 +1,249 @@ +// Copyright 2025 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.zstd.common as common; +import xls.modules.zstd.memory.mem_writer as mem_writer; +import xls.modules.zstd.sequence_executor.join_output as join_output; +import xls.modules.zstd.sequence_executor.literals_executor as literals_executor; +import xls.modules.zstd.sequence_executor.history_copy_executor as history_copy_executor; + +type Offset = common::Offset; +type SequenceExecutorPacket = common::SequenceExecutorPacket; +type SequenceExecutorMessageType = common::SequenceExecutorMessageType; +type JoinOutputReq = join_output::JoinOutputReq; + +struct SequenceExecutorPacketSimple { + literals: uN[common::AXI_DATA_W], + length: uN[64], + last: bool, +} + +struct SequenceExecutorPacketComp { + ll: uN[16], + ml: uN[16], + of: uN[16], + last: bool, +} + +fn seq_exec_packet_as_simple(packet: SequenceExecutorPacket) -> SequenceExecutorPacketSimple { + if packet.msg_type == SequenceExecutorMessageType::LITERAL { + SequenceExecutorPacketSimple { + length: packet.length as u64, + literals: packet.content as uN[common::AXI_DATA_W], + last: packet.last, + } + } else { + SequenceExecutorPacketSimple { + length: u64:0, + literals: uN[common::AXI_DATA_W]:0, + last: packet.last, + } + } +} + +fn seq_exec_packet_as_comp(packet: SequenceExecutorPacket) -> SequenceExecutorPacketComp { + if packet.msg_type == SequenceExecutorMessageType::SEQUENCE { + SequenceExecutorPacketComp { + ll: packet.length as u16, + ml: packet.content[0 +: u16], + of: packet.content[16 +: u16], + last: packet.last, + } + } else { + SequenceExecutorPacketComp { + ll: u16:0, + ml: u16:0, + of: u16:0, + last: packet.last, + } + } +} + +struct SequenceExecutorState { + repeat_offsets: Offset[3], + hb_addr: uN[RAM_ADDR_WIDTH], +} + +pub fn handle_repeated_offset_for_sequences + (seq: SequenceExecutorPacketComp, repeat_offsets: Offset[3]) + -> (SequenceExecutorPacketComp, Offset[3]) { + type Sequence = SequenceExecutorPacketComp; + + let (offset, repeat_offsets) = if (seq.of as Offset <= Offset:3) { + let idx = (seq.of as Offset - Offset:1) as u32; + let idx = if (seq.ll == u16:0) { + idx + u32:1 + } else { idx }; + + if (idx == u32:0) { + (repeat_offsets[0], repeat_offsets) + } else { + let offset = if idx < u32:3 { repeat_offsets[idx] } else { repeat_offsets[0] - Offset:1 }; + + let repeat_offsets = if idx > u32:1 { + update(repeat_offsets, u32:2, repeat_offsets[1]) + } else {repeat_offsets}; + let repeat_offsets = update(repeat_offsets, u32:1, repeat_offsets[0]); + let repeat_offsets = update(repeat_offsets, u32:0, offset); + + (offset, repeat_offsets) + } + } else { + let offset = (seq.of as Offset - Offset:3) as Offset; + + let repeat_offsets = update(repeat_offsets, u32:2, repeat_offsets[1]); + let repeat_offsets = update(repeat_offsets, u32:1, repeat_offsets[0]); + let repeat_offsets = update(repeat_offsets, u32:0, offset); + + (offset, repeat_offsets) + }; + + ( + Sequence { of: offset as u16, ..seq }, + repeat_offsets, + ) +} + +pub proc SequenceExecutorCtrl< + HISTORY_BUFFER_SIZE_KB: u32, + RAM_DATA_WIDTH: u32, + RAM_ADDR_WIDTH: u32, + RAM_SIZE_TOTAL: u64, + RAM_NUM: u32, + RAM_DATA_WIDTH_BYTES: u32 = {RAM_DATA_WIDTH / u32:8}, + INIT_HB_PTR_ADDR: u32 = {u32:0}, + INIT_HB_LENGTH: u64 = {u64:0}> +{ + type SequenceExecutorState = SequenceExecutorState; + type LiteralsExecutorReq = literals_executor::LiteralsExecutorReq; + type LiteralsExecutorResp = literals_executor::LiteralsExecutorResp; + type HistoryCopyExecutorReq = history_copy_executor::HistoryCopyExecutorReq; + type HistoryCopyExecutorResp = history_copy_executor::HistoryCopyExecutorResp; + + input_r: chan in; + join_output_req_s: chan out; + lit_exec_req_s: chan out; + lit_exec_resp_r: chan in; + history_copy_exec_req_s: chan out; + history_copy_exec_resp_r: chan in; + + config( + input_r: chan in, + join_output_req_s: chan out, + lit_exec_req_s: chan out, + lit_exec_resp_r: chan in, + history_copy_exec_req_s: chan out, + history_copy_exec_resp_r: chan in, + ) { + ( + input_r, + join_output_req_s, + lit_exec_req_s, lit_exec_resp_r, + history_copy_exec_req_s, history_copy_exec_resp_r, + ) + } + + init { + const_assert!(INIT_HB_LENGTH <= RAM_SIZE_TOTAL); + + SequenceExecutorState { + repeat_offsets: Offset[3]:[Offset:1, Offset:4, Offset:8], + hb_addr: INIT_HB_PTR_ADDR as uN[RAM_ADDR_WIDTH], + } + } + + next(state: SequenceExecutorState) { + let tok = join(); + + let (tok, packet) = recv(tok, input_r); + trace_fmt!("[SequenceExecutorCtrl] Received packet: {:x}", packet); + + // Converts received sequence packet to both simple and compressed version. + // In case of raw literals, the as_comp_packet is equal to zero!() + // and in case of a compressed sequence, as_simple_packet is zero!(). + let is_comp_packet = packet.msg_type == SequenceExecutorMessageType::SEQUENCE; + let as_simple_packet = seq_exec_packet_as_simple(packet); + let as_comp_packet = seq_exec_packet_as_comp(packet); + + // We can combine lengths from both packets here as the other one will be always 0 + let join_output_req = JoinOutputReq { + literals_to_receive: as_comp_packet.ll as u32 + as_simple_packet.length as u32, + copies_to_receive: as_comp_packet.ml as u32, + }; + let tok = send(tok, join_output_req_s, join_output_req); + + // Ignore handling repeat offsets if the compressed sequence is not valid + let handle_repeat_offsets = is_comp_packet && (as_comp_packet.of != u16:0 && as_comp_packet.ml != u16:0); + let (as_comp_packet, new_repeat_offsets) = if handle_repeat_offsets { + handle_repeated_offset_for_sequences(as_comp_packet, state.repeat_offsets) + } else { + (as_comp_packet, state.repeat_offsets) + }; + + // Send request to literals executor only if there are literals to handle + let lit_req_valid = as_comp_packet.ll != u16:0 || as_simple_packet.length != u64:0; + let literals_executor_req = LiteralsExecutorReq { + literal_length: as_comp_packet.ll, + start_addr: state.hb_addr as u32, + raw_literals: as_simple_packet.literals as u64, + raw_literals_length: as_simple_packet.length as u32, + }; + let tok = send_if(tok, lit_exec_req_s, lit_req_valid, literals_executor_req); + if lit_req_valid { + trace_fmt!("[SequenceExecutorCtrl] Sending request to literals executor: {:x}", literals_executor_req); + } else {}; + + let (tok, literals_executor_resp) = recv_if(tok, lit_exec_resp_r, lit_req_valid, zero!()); + if lit_req_valid { + trace_fmt!("[SequenceExecutorCtrl] Received response from literals executor: {:x}", literals_executor_resp); + } else {}; + + let history_copy_dest_addr = std::mod_pow2(state.hb_addr as u32 + as_comp_packet.ll as u32 + as_simple_packet.length as u32, RAM_SIZE_TOTAL as u32); + let history_copy_source_addr = if as_comp_packet.of as u32 > history_copy_dest_addr { + (RAM_SIZE_TOTAL as u32) - (as_comp_packet.of as u32 - history_copy_dest_addr) + } else { + history_copy_dest_addr - as_comp_packet.of as u32 + }; + trace_fmt!("[SequenceExecutorCtrl] History buffer base address: {:x}", state.hb_addr); + trace_fmt!("[SequenceExecutorCtrl] History copy source address: {:x}", history_copy_source_addr); + trace_fmt!("[SequenceExecutorCtrl] History copy dest address: {:x}", history_copy_dest_addr); + + // Send request to history copy executor only if there are history copies to handle + let history_copy_req_valid = as_comp_packet.ml != u16:0 && is_comp_packet; + let history_copy_executor_req = HistoryCopyExecutorReq { + max_possible_read: std::min(as_comp_packet.of as u32, RAM_DATA_WIDTH / u32:8), + match_length: as_comp_packet.ml, + source_addr: history_copy_source_addr as uN[RAM_ADDR_WIDTH], + dest_addr: history_copy_dest_addr as uN[RAM_ADDR_WIDTH], + }; + let tok = send_if(tok, history_copy_exec_req_s, history_copy_req_valid, history_copy_executor_req); + if history_copy_req_valid { + trace_fmt!("[SequenceExecutorCtrl] Sending request to history copy executor: {:x}", history_copy_executor_req); + } else {}; + + let (tok, history_copy_executor_resp) = recv_if(tok, history_copy_exec_resp_r, history_copy_req_valid, zero!()); + if history_copy_req_valid { + trace_fmt!("[SequenceExecutorCtrl] Received response from history copy executor: {:x}", history_copy_executor_resp); + } else {}; + + // Wrap current base address of the history buffer if it reaches the end of it + let new_hb_addr = std::mod_pow2(history_copy_dest_addr + as_comp_packet.ml as u32, RAM_SIZE_TOTAL as u32) as uN[RAM_ADDR_WIDTH]; + + SequenceExecutorState { + repeat_offsets: new_repeat_offsets, + hb_addr: new_hb_addr, + } + } +} diff --git a/xls/modules/zstd/shift_buffer.x b/xls/modules/zstd/shift_buffer.x index 4cf70d861f..96567d202a 100644 --- a/xls/modules/zstd/shift_buffer.x +++ b/xls/modules/zstd/shift_buffer.x @@ -68,9 +68,6 @@ pub proc ShiftBufferAligner< init {zero!()} next(state: State) { - // FIXME: Remove when https://github.com/google/xls/issues/1368 is resolved - type Inter = ShiftBufferPacket; - let tok = join(); let (tok0, data) = recv(tok, input_r); @@ -150,16 +147,16 @@ proc ShiftBufferAlignerTest { struct ShiftBufferStorageState { buffer: bits[BUFFER_WIDTH], // The storage element. - buffer_cnt: bits[LENGTH_WIDTH + u32:2], // Number of valid bits in the buffer. - read_ptr: bits[LENGTH_WIDTH + u32:2], // First occupied bit in the buffer when buffer_cnt > 0. - write_ptr: bits[LENGTH_WIDTH + u32:2], // First free bit in the buffer. + buffer_cnt: bits[LENGTH_WIDTH + u32:1], // Number of valid bits in the buffer. + read_ptr: bits[LENGTH_WIDTH + u32:1], // First occupied bit in the buffer when buffer_cnt > 0. + write_ptr: bits[LENGTH_WIDTH + u32:1], // First free bit in the buffer. cmd: ShiftBufferCtrl, // Received command of ShiftBufferCtrl type. cmd_valid: bool, // Field cmd is valid. } pub proc ShiftBufferStorage { type Buffer = bits[DATA_WIDTH * u32:3]; - type BufferLength = bits[LENGTH_WIDTH + u32:2]; // TODO: where does this "+ u32:2" come from? shouldn't it be number_of_bits_required_to_represent(DATA_WIDTH * u32:3)? + type BufferLength = bits[std::clog2(DATA_WIDTH * u32:3)]; type Data = bits[DATA_WIDTH]; type DataLength = bits[LENGTH_WIDTH]; type State = ShiftBufferStorageState; @@ -191,22 +188,16 @@ pub proc ShiftBufferStorage { type OutputPayload = ShiftBufferPacket; type OutputStatus = ShiftBufferStatus; type DataLength = bits[LENGTH_WIDTH]; - // trace_fmt!("state: {:#x}", state); const _MAX_BUFFER_CNT = (DATA_WIDTH * u32:3) as BufferLength; let shift_buffer_right = state.read_ptr >= (DATA_WIDTH as BufferLength); - // trace_fmt!("shift_buffer_right: {:#x}", shift_buffer_right); let shift_data_left = state.write_ptr >= (DATA_WIDTH as BufferLength) && !shift_buffer_right; - // trace_fmt!("shift_data_left: {:#x}", shift_data_left); let recv_new_input = state.write_ptr < (DATA_WIDTH * u32:2) as BufferLength; - // trace_fmt!("recv_new_input: {:#x}", recv_new_input); let has_enough_data = (state.cmd.length as BufferLength <= state.buffer_cnt); let send_response = state.cmd_valid && has_enough_data; - // trace_fmt!("send_response: {:#x}", send_response); let recv_new_cmd = !state.cmd_valid || send_response; - // trace_fmt!("recv_new_cmd: {:#x}", recv_new_cmd); let tok = join(); @@ -221,13 +212,6 @@ pub proc ShiftBufferStorage { state.write_ptr) }; - // if (shift_buffer_right) { - // trace_fmt!("Shifted data"); - // trace_fmt!("new_buffer: {:#x}", new_buffer); - // trace_fmt!("new_read_ptr: {}", new_read_ptr); - // trace_fmt!("new_write_ptr: {}", new_write_ptr); - // } else { () }; - // Handle incoming writes let (tok_input, wdata, wdata_valid) = recv_if_non_blocking(tok, inter, recv_new_input, zero!()); @@ -246,19 +230,10 @@ pub proc ShiftBufferStorage { (new_buffer, new_write_ptr) }; - // if (wdata_valid) { - // trace_fmt!("Received aligned data {:#x}", wdata); - // trace_fmt!("new_buffer: {:#x}", new_buffer); - // trace_fmt!("new_write_ptr: {}", new_write_ptr); - // } else { () }; - // Handle incoming reads let (tok_ctrl, new_cmd, new_cmd_valid) = recv_if_non_blocking(tok, ctrl, recv_new_cmd, state.cmd); - // if (new_cmd_valid) { - // trace_fmt!("Received new cmd: {}", new_cmd); - // } else {()}; let new_cmd_valid = if recv_new_cmd { new_cmd_valid } else { state.cmd_valid }; // Handle current read @@ -269,9 +244,6 @@ pub proc ShiftBufferStorage { data: math::mask((state.buffer >> state.read_ptr) as Data, state.cmd.length), }; - // trace_fmt!("rdata: {:#x}", rdata); - // trace_fmt!("new_read_ptr: {}", new_read_ptr); - (rdata, new_read_ptr) } else { (zero!(), new_read_ptr) @@ -279,9 +251,6 @@ pub proc ShiftBufferStorage { let tok = join(tok_input, tok_ctrl); send_if(tok, output, send_response, rdata); - // if (send_response) { - // trace_fmt!("Sent out rdata: {:#x}", rdata); - // } else {()}; let new_buffer_cnt = new_write_ptr - new_read_ptr; @@ -299,7 +268,7 @@ pub proc ShiftBufferStorage { } const STORAGE_TEST_DATA_WIDTH = u32:64; -const STORAGE_TEST_LENGTH_WIDTH = length_width(STORAGE_TEST_DATA_WIDTH); +const STORAGE_TEST_LENGTH_WIDTH = std::clog2(STORAGE_TEST_DATA_WIDTH + u32:1); const STORAGE_TEST_DATA_WIDTH_X2 = STORAGE_TEST_DATA_WIDTH * u32:2; #[test_proc] @@ -468,7 +437,7 @@ pub proc ShiftBuffer { const INST_DATA_WIDTH = u32:64; const INST_DATA_WIDTH_X2 = u32:128; -const INST_LENGTH_WIDTH = std::clog2(INST_DATA_WIDTH) + u32:1; +const INST_LENGTH_WIDTH = std::clog2(INST_DATA_WIDTH + u32:1); proc ShiftBufferInst { type Input = ShiftBufferPacket; @@ -520,7 +489,7 @@ proc ShiftBufferStorageInst { } const TEST_DATA_WIDTH = u32:64; -const TEST_LENGTH_WIDTH = std::clog2(TEST_DATA_WIDTH) + u32:1; // TODO: other places in the code use length_width(TEST_DATA_WIDTH) which is clog2(TEST_DATA_WIDTH + 1) instead, why clog2(TEST_DATA_WIDTH) + 1 here? +const TEST_LENGTH_WIDTH = std::clog2(TEST_DATA_WIDTH + u32:1); #[test_proc] proc ShiftBufferTest { diff --git a/xls/modules/zstd/zstd_dec.x b/xls/modules/zstd/zstd_dec.x index d22927ad33..867d372536 100644 --- a/xls/modules/zstd/zstd_dec.x +++ b/xls/modules/zstd/zstd_dec.x @@ -33,7 +33,8 @@ import xls.modules.zstd.raw_block_dec; import xls.modules.zstd.rle_block_dec; import xls.modules.zstd.comp_block_dec; import xls.modules.zstd.dec_mux; -import xls.modules.zstd.sequence_executor; +import xls.modules.zstd.sequence_executor.sequence_executor; +import xls.modules.zstd.sequence_executor.history_buffer; import xls.modules.zstd.huffman_literals_dec; import xls.modules.zstd.literals_buffer; import xls.modules.zstd.parallel_rams; @@ -58,7 +59,7 @@ enum ZstdDecoderInternalFsm: u4 { INVALID = 15, } -enum ZstdDecoderStatus: u5 { +pub enum ZstdDecoderStatus: u5 { IDLE = 0, RUNNING = 1, READ_CONFIG_OK = 2, @@ -933,8 +934,8 @@ pub proc ZstdDecoder< // AXI parameters AXI_DATA_W: u32, AXI_ADDR_W: u32, AXI_ID_W: u32, AXI_DEST_W: u32, // decoder parameters - REGS_N: u32, WINDOW_LOG_MAX: u32, - HB_ADDR_W: u32, HB_DATA_W: u32, HB_NUM_PARTITIONS: u32, HB_SIZE_KB: u32, + REGS_N: u32, + HB_ADDR_W: u32, HB_DATA_W: u32, HB_NUM_PARTITIONS: u32, HB_SIZE: u64, DPD_RAM_ADDR_W: u32, DPD_RAM_DATA_W: u32, DPD_RAM_NUM_PARTITIONS: u32, TMP_RAM_ADDR_W: u32, TMP_RAM_DATA_W: u32, TMP_RAM_NUM_PARTITIONS: u32, @@ -950,6 +951,9 @@ pub proc ZstdDecoder< AXI_CHAN_N: u32, FSE_MAX_ACCURACY_LOG: u32 = {common::FSE_MAX_ACCURACY_LOG}, + SINGLE_HB_RAM_ADDR_W: u32, + SINGLE_HB_RAM_DATA_W: u32, + // calculated parameters AXI_DATA_W_DIV8: u32 = {AXI_DATA_W / u32:8}, LOG2_REGS_N: u32 = {std::clog2(REGS_N)}, @@ -968,6 +972,8 @@ pub proc ZstdDecoder< LITERALS_BUFFER_RAM_DATA_W: u32 = {literals_buffer::RAM_DATA_WIDTH}, LITERALS_BUFFER_RAM_NUM_PARTITIONS: u32 = {literals_buffer::RAM_NUM_PARTITIONS}, LITERALS_BUFFER_RAM_WORD_PARTITION_SIZE: u32 = {LITERALS_BUFFER_RAM_DATA_W}, + + HB_RAM_REQ_DATA_W: u32 = {HB_DATA_W / u32:8}, > { type CsrAxiAr = axi::AxiAr; type CsrAxiR = axi::AxiR; @@ -987,6 +993,12 @@ pub proc ZstdDecoder< type MemAxiW = axi::AxiW; type MemAxiB = axi::AxiB; + type OutputMemAxiAr = axi::AxiAr; + type OutputMemAxiR = axi::AxiR; + type OutputMemAxiAw = axi::AxiAw; + type OutputMemAxiW = axi::AxiW; + type OutputMemAxiB = axi::AxiB; + type MemReaderReq = mem_reader::MemReaderReq; type MemReaderResp = mem_reader::MemReaderResp; type MemWriterReq = mem_writer::MemWriterReq; @@ -1006,7 +1018,7 @@ pub proc ZstdDecoder< type RleBlockDecoderReq = rle_block_dec::RleBlockDecoderReq; type RleBlockDecoderResp = rle_block_dec::RleBlockDecoderResp; - type SequenceExecutorPacket = common::SequenceExecutorPacket; + type SequenceExecutorPacket = common::SequenceExecutorPacket; type ZstdDecodedPacket = common::ZstdDecodedPacket; type RamRdReq = ram::ReadReq; @@ -1014,6 +1026,10 @@ pub proc ZstdDecoder< type RamWrReq = ram::WriteReq; type RamWrResp = ram::WriteResp; + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; + type RWRamWrComp = history_buffer::HistoryBufferWrComp; + type CompressBlockDecoderReq = comp_block_dec::CompressBlockDecoderReq; type CompressBlockDecoderResp = comp_block_dec::CompressBlockDecoderResp; @@ -1073,6 +1089,7 @@ pub proc ZstdDecoder< type LitBufRamRdResp = ram::ReadResp; type LitBufRamWrReq = ram::WriteReq; type LitBufRamWrResp = ram::WriteResp; + type LiteralsBufCtrl = common::LiteralsBufferCtrl; init {} @@ -1145,10 +1162,10 @@ pub proc ZstdDecoder< ml_fse_wr_req_s: chan out, ml_fse_wr_resp_r: chan in, - litbuf_rd_req_s: chan[u32:8] out, - litbuf_rd_resp_r: chan[u32:8] in, - litbuf_wr_req_s: chan[u32:8] out, - litbuf_wr_resp_r: chan[u32:8] in, + litbuf_rd_req_s: chan[common::LITERALS_IN_PACKET] out, + litbuf_rd_resp_r: chan[common::LITERALS_IN_PACKET] in, + litbuf_wr_req_s: chan[common::LITERALS_IN_PACKET] out, + litbuf_wr_resp_r: chan[common::LITERALS_IN_PACKET] in, // Huffman weights memory huffman_lit_weights_mem_rd_req_s: chan out, @@ -1183,43 +1200,17 @@ pub proc ZstdDecoder< huffman_lit_weights_fse_wr_resp_r: chan in, // AXI Output Writer (manager) - output_axi_aw_s: chan out, - output_axi_w_s: chan out, - output_axi_b_r: chan in, + output_axi_aw_s: chan out, + output_axi_w_s: chan out, + output_axi_b_r: chan in, // History Buffer - ram_rd_req_0_s: chan out, - ram_rd_req_1_s: chan out, - ram_rd_req_2_s: chan out, - ram_rd_req_3_s: chan out, - ram_rd_req_4_s: chan out, - ram_rd_req_5_s: chan out, - ram_rd_req_6_s: chan out, - ram_rd_req_7_s: chan out, - ram_rd_resp_0_r: chan in, - ram_rd_resp_1_r: chan in, - ram_rd_resp_2_r: chan in, - ram_rd_resp_3_r: chan in, - ram_rd_resp_4_r: chan in, - ram_rd_resp_5_r: chan in, - ram_rd_resp_6_r: chan in, - ram_rd_resp_7_r: chan in, - ram_wr_req_0_s: chan out, - ram_wr_req_1_s: chan out, - ram_wr_req_2_s: chan out, - ram_wr_req_3_s: chan out, - ram_wr_req_4_s: chan out, - ram_wr_req_5_s: chan out, - ram_wr_req_6_s: chan out, - ram_wr_req_7_s: chan out, - ram_wr_resp_0_r: chan in, - ram_wr_resp_1_r: chan in, - ram_wr_resp_2_r: chan in, - ram_wr_resp_3_r: chan in, - ram_wr_resp_4_r: chan in, - ram_wr_resp_5_r: chan in, - ram_wr_resp_6_r: chan in, - ram_wr_resp_7_r: chan in, + rw_req_s_0: chan[HB_NUM_PARTITIONS] out, + rw_resp_r_0: chan[HB_NUM_PARTITIONS] in, + rw_wr_comp_r_0: chan[HB_NUM_PARTITIONS] in, + rw_req_s_1: chan[HB_NUM_PARTITIONS] out, + rw_resp_r_1: chan[HB_NUM_PARTITIONS] in, + rw_wr_comp_r_1: chan[HB_NUM_PARTITIONS] in, notify_s: chan<()> out, ) { @@ -1259,7 +1250,7 @@ pub proc ZstdDecoder< let (fh_mem_rd_req_s, fh_mem_rd_req_r) = chan("fh_mem_rd_req"); let (fh_mem_rd_resp_s, fh_mem_rd_resp_r) = chan("fh_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( fh_mem_rd_req_r, fh_mem_rd_resp_s, fh_axi_ar_s, fh_axi_r_r, ); @@ -1267,7 +1258,7 @@ pub proc ZstdDecoder< let (fh_req_s, fh_req_r) = chan("fh_req"); let (fh_resp_s, fh_resp_r) = chan("fh_resp"); - spawn frame_header_dec::FrameHeaderDecoder( + spawn frame_header_dec::FrameHeaderDecoder( fh_mem_rd_req_s, fh_mem_rd_resp_r, fh_req_r, fh_resp_s, ); @@ -1277,7 +1268,7 @@ pub proc ZstdDecoder< let (bh_mem_rd_req_s, bh_mem_rd_req_r) = chan("bh_mem_rd_req"); let (bh_mem_rd_resp_s, bh_mem_rd_resp_r) = chan("bh_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( bh_mem_rd_req_r, bh_mem_rd_resp_s, bh_axi_ar_s, bh_axi_r_r, ); @@ -1295,7 +1286,7 @@ pub proc ZstdDecoder< let (raw_mem_rd_req_s, raw_mem_rd_req_r) = chan("raw_mem_rd_req"); let (raw_mem_rd_resp_s, raw_mem_rd_resp_r) = chan("raw_mem_rd_resp"); - spawn mem_reader::MemReader( + spawn mem_reader::MemReader( raw_mem_rd_req_r, raw_mem_rd_resp_s, raw_axi_ar_s, raw_axi_r_r, ); @@ -1320,7 +1311,8 @@ pub proc ZstdDecoder< ); // Compressed block decoder - + let (lit_buf_ctrl_s, lit_buf_ctrl_r) = chan("lit_buf_ctrl"); + let (lit_buf_out_s, lit_buf_out_r) = chan("lit_buf_out"); let (comp_block_req_s, comp_block_req_r) = chan("comp_block_req"); let (comp_block_resp_s, comp_block_resp_r) = chan("comp_block_resp"); @@ -1376,14 +1368,14 @@ pub proc ZstdDecoder< comp_axi_ram_ar_s[8], comp_axi_ram_r_r[8], comp_axi_ram_ar_s[9], comp_axi_ram_r_r[9], comp_axi_ram_ar_s[10], comp_axi_ram_r_r[10], - litbuf_rd_req_s[0], litbuf_rd_req_s[1], litbuf_rd_req_s[2], litbuf_rd_req_s[3], - litbuf_rd_req_s[4], litbuf_rd_req_s[5], litbuf_rd_req_s[6], litbuf_rd_req_s[7], - litbuf_rd_resp_r[0], litbuf_rd_resp_r[1], litbuf_rd_resp_r[2], litbuf_rd_resp_r[3], - litbuf_rd_resp_r[4], litbuf_rd_resp_r[5], litbuf_rd_resp_r[6], litbuf_rd_resp_r[7], - litbuf_wr_req_s[0], litbuf_wr_req_s[1], litbuf_wr_req_s[2], litbuf_wr_req_s[3], - litbuf_wr_req_s[4], litbuf_wr_req_s[5], litbuf_wr_req_s[6], litbuf_wr_req_s[7], - litbuf_wr_resp_r[0], litbuf_wr_resp_r[1], litbuf_wr_resp_r[2], litbuf_wr_resp_r[3], - litbuf_wr_resp_r[4], litbuf_wr_resp_r[5], litbuf_wr_resp_r[6], litbuf_wr_resp_r[7], + + litbuf_rd_req_s, + litbuf_rd_resp_r, + litbuf_wr_req_s, + litbuf_wr_resp_r, + + lit_buf_ctrl_r, lit_buf_out_s, + huffman_lit_weights_read_side_rd_req_s, huffman_lit_weights_read_side_rd_resp_r, huffman_lit_weights_write_side_wr_req_s, huffman_lit_weights_write_side_wr_resp_r, huffman_lit_prescan_mem_rd_req_s, huffman_lit_prescan_mem_rd_resp_r, @@ -1415,26 +1407,24 @@ pub proc ZstdDecoder< ); // Sequence Execution - let (seq_exec_looped_s, seq_exec_looped_r) = chan("seq_exec_looped"); - let (output_mem_wr_data_in_s, output_mem_wr_data_in_r) = chan("output_mem_wr_data_in"); - - spawn sequence_executor::SequenceExecutor( - seq_exec_input_r, output_mem_wr_data_in_s, - seq_exec_looped_r, seq_exec_looped_s, - ram_rd_req_0_s, ram_rd_req_1_s, ram_rd_req_2_s, ram_rd_req_3_s, - ram_rd_req_4_s, ram_rd_req_5_s, ram_rd_req_6_s, ram_rd_req_7_s, - ram_rd_resp_0_r, ram_rd_resp_1_r, ram_rd_resp_2_r, ram_rd_resp_3_r, - ram_rd_resp_4_r, ram_rd_resp_5_r, ram_rd_resp_6_r, ram_rd_resp_7_r, - ram_wr_req_0_s, ram_wr_req_1_s, ram_wr_req_2_s, ram_wr_req_3_s, - ram_wr_req_4_s, ram_wr_req_5_s, ram_wr_req_6_s, ram_wr_req_7_s, - ram_wr_resp_0_r, ram_wr_resp_1_r, ram_wr_resp_2_r, ram_wr_resp_3_r, - ram_wr_resp_4_r, ram_wr_resp_5_r, ram_wr_resp_6_r, ram_wr_resp_7_r - ); + let (output_mem_wr_data_in_s, output_mem_wr_data_in_r) = chan("output_mem_wr_data_in"); // Zstd Decoder Control let (output_mem_wr_req_s, output_mem_wr_req_r) = chan("output_mem_wr_req"); let (output_mem_wr_resp_s, output_mem_wr_resp_r) = chan("output_mem_wr_resp"); + spawn sequence_executor::SequenceExecutor( + seq_exec_input_r, + lit_buf_ctrl_s, lit_buf_out_r, + rw_req_s_0, + rw_resp_r_0, + rw_wr_comp_r_0, + rw_req_s_1, + rw_resp_r_1, + rw_wr_comp_r_1, + output_mem_wr_data_in_s, + ); + spawn mem_writer::MemWriter( output_mem_wr_req_r, output_mem_wr_data_in_r, output_axi_aw_s, output_axi_w_s, output_axi_b_r, output_mem_wr_resp_s @@ -1457,16 +1447,18 @@ pub proc ZstdDecoder< next (state: ()) { } } -const INST_AXI_DATA_W = u32:64; +const INST_AXI_DATA_W = common::AXI_DATA_W; const INST_AXI_ADDR_W = u32:32; const INST_AXI_ID_W = u32:4; const INST_AXI_DEST_W = u32:4; const INST_REGS_N = u32:16; -const INST_WINDOW_LOG_MAX = u32:30; -const INST_HB_ADDR_W = sequence_executor::ZSTD_RAM_ADDR_WIDTH; -const INST_HB_DATA_W = sequence_executor::RAM_DATA_WIDTH; -const INST_HB_NUM_PARTITIONS = sequence_executor::RAM_NUM_PARTITIONS; -const INST_HB_SIZE_KB = sequence_executor::ZSTD_HISTORY_BUFFER_SIZE_KB; +const INST_HB_ADDR_W = sequence_executor::ZSTD_HB_RAM_ADDR_W; +const INST_SINGLE_HB_ADDR_W = sequence_executor::ZSTD_SINGLE_HB_RAM_ADDR_W; +const INST_SINGLE_HB_DATA_W = u32:8; +const INST_HB_DATA_W = INST_AXI_DATA_W; +const INST_HB_NUM_PARTITIONS = sequence_executor::ZSTD_HB_RAM_NUM; +const INST_HB_SIZE_B = sequence_executor::ZSTD_HB_RAM_SIZE_TOTAL; +const HB_RAM_REQ_DATA_W = INST_HB_DATA_W / u32:8; const INST_LOG2_REGS_N = std::clog2(INST_REGS_N); const INST_AXI_DATA_W_DIV8 = INST_AXI_DATA_W / u32:8; @@ -1539,7 +1531,7 @@ const INST_HUFFMAN_WEIGHTS_TMP2_RAM_WORD_PARTITION_SIZE = INST_HUFFMAN_WEIGHTS_T const INST_HUFFMAN_WEIGHTS_TMP2_RAM_NUM_PARTITIONS = ram::num_partitions( INST_HUFFMAN_WEIGHTS_TMP2_RAM_WORD_PARTITION_SIZE, INST_HUFFMAN_WEIGHTS_TMP2_RAM_DATA_W); -const INST_HISTORY_BUFFER_SIZE_KB = u32:64; +const INST_HISTORY_BUFFER_SIZE_KB = common::HISTORY_BUFFER_SIZE_KB; const INST_AXI_CHAN_N = u32:11; // Literals buffer memory parameters @@ -1646,10 +1638,15 @@ proc ZstdDecoderInst { type MemAxiW = axi::AxiW; type MemAxiB = axi::AxiB; - type RamRdReq = ram::ReadReq; - type RamRdResp = ram::ReadResp; - type RamWrReq = ram::WriteReq; - type RamWrResp = ram::WriteResp; + type OutputMemAxiAr = axi::AxiAr; + type OutputMemAxiR = axi::AxiR; + type OutputMemAxiAw = axi::AxiAw; + type OutputMemAxiW = axi::AxiW; + type OutputMemAxiB = axi::AxiB; + + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; + type RWRamWrComp = history_buffer::HistoryBufferWrComp; type ZstdDecodedPacket = common::ZstdDecodedPacket; @@ -1778,10 +1775,10 @@ proc ZstdDecoderInst { ml_fse_wr_req_s: chan out, ml_fse_wr_resp_r: chan in, - litbuf_rd_req_s: chan[u32:8] out, - litbuf_rd_resp_r: chan[u32:8] in, - litbuf_wr_req_s: chan[u32:8] out, - litbuf_wr_resp_r: chan[u32:8] in, + litbuf_rd_req_s: chan[common::LITERALS_IN_PACKET] out, + litbuf_rd_resp_r: chan[common::LITERALS_IN_PACKET] in, + litbuf_wr_req_s: chan[common::LITERALS_IN_PACKET] out, + litbuf_wr_resp_r: chan[common::LITERALS_IN_PACKET] in, // Huffman prescan memory huffman_lit_prescan_mem_rd_req_s: chan out, @@ -1815,50 +1812,24 @@ proc ZstdDecoderInst { huffman_lit_weights_mem_wr_resp_r: chan in, // AXI Output Writer (manager) - output_axi_aw_s: chan out, - output_axi_w_s: chan out, - output_axi_b_r: chan in, + output_axi_aw_s: chan out, + output_axi_w_s: chan out, + output_axi_b_r: chan in, // History Buffer - ram_rd_req_0_s: chan out, - ram_rd_req_1_s: chan out, - ram_rd_req_2_s: chan out, - ram_rd_req_3_s: chan out, - ram_rd_req_4_s: chan out, - ram_rd_req_5_s: chan out, - ram_rd_req_6_s: chan out, - ram_rd_req_7_s: chan out, - ram_rd_resp_0_r: chan in, - ram_rd_resp_1_r: chan in, - ram_rd_resp_2_r: chan in, - ram_rd_resp_3_r: chan in, - ram_rd_resp_4_r: chan in, - ram_rd_resp_5_r: chan in, - ram_rd_resp_6_r: chan in, - ram_rd_resp_7_r: chan in, - ram_wr_req_0_s: chan out, - ram_wr_req_1_s: chan out, - ram_wr_req_2_s: chan out, - ram_wr_req_3_s: chan out, - ram_wr_req_4_s: chan out, - ram_wr_req_5_s: chan out, - ram_wr_req_6_s: chan out, - ram_wr_req_7_s: chan out, - ram_wr_resp_0_r: chan in, - ram_wr_resp_1_r: chan in, - ram_wr_resp_2_r: chan in, - ram_wr_resp_3_r: chan in, - ram_wr_resp_4_r: chan in, - ram_wr_resp_5_r: chan in, - ram_wr_resp_6_r: chan in, - ram_wr_resp_7_r: chan in, + rw_req_s_0: chan[INST_HB_NUM_PARTITIONS] out, + rw_resp_r_0: chan[INST_HB_NUM_PARTITIONS] in, + rw_wr_comp_r_0: chan[INST_HB_NUM_PARTITIONS] in, + rw_req_s_1: chan[INST_HB_NUM_PARTITIONS] out, + rw_resp_r_1: chan[INST_HB_NUM_PARTITIONS] in, + rw_wr_comp_r_1: chan[INST_HB_NUM_PARTITIONS] in, notify_s: chan<()> out, ) { spawn ZstdDecoder< INST_AXI_DATA_W, INST_AXI_ADDR_W, INST_AXI_ID_W, INST_AXI_DEST_W, - INST_REGS_N, INST_WINDOW_LOG_MAX, - INST_HB_ADDR_W, INST_HB_DATA_W, INST_HB_NUM_PARTITIONS, INST_HB_SIZE_KB, + INST_REGS_N, + INST_HB_ADDR_W, INST_HB_DATA_W, INST_HB_NUM_PARTITIONS, INST_HB_SIZE_B, INST_DPD_RAM_ADDR_W, INST_DPD_RAM_DATA_W, INST_DPD_RAM_NUM_PARTITIONS, INST_TMP_RAM_ADDR_W, INST_TMP_RAM_DATA_W, INST_TMP_RAM_NUM_PARTITIONS, @@ -1873,6 +1844,9 @@ proc ZstdDecoderInst { INST_HISTORY_BUFFER_SIZE_KB, INST_AXI_CHAN_N, INST_FSE_MAX_ACCURACY_LOG, + + INST_SINGLE_HB_ADDR_W, + INST_SINGLE_HB_DATA_W, >( csr_axi_aw_r, csr_axi_w_r, csr_axi_b_s, csr_axi_ar_r, csr_axi_r_s, fh_axi_ar_s, fh_axi_r_r, @@ -1906,14 +1880,8 @@ proc ZstdDecoderInst { huffman_lit_weights_fse_rd_req_s, huffman_lit_weights_fse_rd_resp_r, huffman_lit_weights_fse_wr_req_s, huffman_lit_weights_fse_wr_resp_r, output_axi_aw_s, output_axi_w_s, output_axi_b_r, - ram_rd_req_0_s, ram_rd_req_1_s, ram_rd_req_2_s, ram_rd_req_3_s, - ram_rd_req_4_s, ram_rd_req_5_s, ram_rd_req_6_s, ram_rd_req_7_s, - ram_rd_resp_0_r, ram_rd_resp_1_r, ram_rd_resp_2_r, ram_rd_resp_3_r, - ram_rd_resp_4_r, ram_rd_resp_5_r, ram_rd_resp_6_r, ram_rd_resp_7_r, - ram_wr_req_0_s, ram_wr_req_1_s, ram_wr_req_2_s, ram_wr_req_3_s, - ram_wr_req_4_s, ram_wr_req_5_s, ram_wr_req_6_s, ram_wr_req_7_s, - ram_wr_resp_0_r, ram_wr_resp_1_r, ram_wr_resp_2_r, ram_wr_resp_3_r, - ram_wr_resp_4_r, ram_wr_resp_5_r, ram_wr_resp_6_r, ram_wr_resp_7_r, + rw_req_s_0, rw_resp_r_0, rw_wr_comp_r_0, + rw_req_s_1, rw_resp_r_1, rw_wr_comp_r_1, notify_s, ); } diff --git a/xls/modules/zstd/zstd_dec_cocotb_cli.py b/xls/modules/zstd/zstd_dec_cocotb_cli.py new file mode 100644 index 0000000000..7e4052a045 --- /dev/null +++ b/xls/modules/zstd/zstd_dec_cocotb_cli.py @@ -0,0 +1,72 @@ +# Copyright 2025 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 sys +import cocotb +import os +import pathlib +from xls.modules.zstd.zstd_dec_cocotb_common import run_test, check_decoder_compliance +from xls.modules.zstd.zstd_dec_detailed_test import detailed_testing_routine + + +@cocotb.test(timeout_time=int(os.getenv("ZSTD_DEC_COCOTB_CLI_TIMEOUT", "5000")), timeout_unit="ms") +async def zstd_cli_test(dut): + input_name = os.getenv("ZSTD_DEC_COCOTB_CLI_INPUT") + print("input_name: ", input_name) + await detailed_testing_routine(dut, input_name) + + +def usage(): + print( + f"usage: {os.path.basename(sys.argv[0])} /abs/path/to/input.zst [timeout_is_ms]" + ) + sys.exit(1) + + +if __name__ == "__main__": + help = "-h" in sys.argv or "--help" in sys.argv + bad_params = len(sys.argv) not in (2, 3) + if bad_params or help: + usage() + + if not os.path.isabs(sys.argv[1]): + # bazel run changes the working dir to runfiles tree so relative paths won't work + print(f"error: '{sys.argv[1]}' is not absolute path") + usage() + + if not check_decoder_compliance(sys.argv[1]): + print(f"error: '{sys.argv[1]}' is not suitable for the decoder parameters") + sys.exit(1) + + # cocotb doesn't perserve global vars nor sys.argv + # we work it around by passing arguments through env + os.environ["ZSTD_DEC_COCOTB_CLI_INPUT"] = sys.argv[1] + + if len(sys.argv) == 3: + os.environ["ZSTD_DEC_COCOTB_CLI_TIMEOUT"] = sys.argv[2] + + test_module = [pathlib.Path(__file__).stem] + run_test( + test_module, + build_args=[ + "-Wno-fatal", + "-Wwarn-ASSIGNIN", + "--trace-fst", # trace in more space-efficient format than vcd + "--no-public-flat-rw", + "-O3", + "--assert", + ], + sim="verilator", + ) diff --git a/xls/modules/zstd/zstd_dec_cocotb_common.py b/xls/modules/zstd/zstd_dec_cocotb_common.py new file mode 100644 index 0000000000..343c4d77c3 --- /dev/null +++ b/xls/modules/zstd/zstd_dec_cocotb_common.py @@ -0,0 +1,899 @@ +# Copyright 2024 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 math +import enum +import tempfile +import sys +import os + +import cocotb +from cocotb import triggers +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, ClockCycles, Event, Edge +from cocotb.binary import BinaryValue +from cocotb.utils import get_sim_time +from cocotb_bus.scoreboard import Scoreboard + +from cocotbext.axi import axi_channels +from cocotbext.axi.axi_master import AxiMaster +from cocotbext.axi.axi_channels import ( + AxiAWBus, + AxiWBus, + AxiWMonitor, + AxiBBus, + AxiWriteBus, + AxiARBus, + AxiRBus, + AxiReadBus, + AxiBus, + AxiBTransaction, + AxiBSource, + AxiBSink, + AxiBMonitor, + AxiRTransaction, + AxiRSource, + AxiRSink, + AxiRMonitor, +) +from cocotbext.axi.axi_ram import AxiRam +from cocotbext.axi.sparse_memory import SparseMemory + +from pathlib import Path + +from xls.modules.zstd.cocotb.channel import XLSChannel, XLSChannelMonitor +import xls.modules.zstd.cocotb.utils as cocotb_utils +from xls.modules.zstd.zstd_test_debugger import debug_file +from xls.modules.zstd.cocotb import data_generator +from xls.modules.zstd.cocotb.memory import AxiRamFromFile +from xls.modules.zstd.cocotb import xlsstruct +from xls.modules.zstd.perf_report import report_test_result + +AXI_DATA_W = 64 +AXI_DATA_W_BYTES = AXI_DATA_W // 8 +MAX_ENCODED_FRAME_SIZE_B = 2**32 +NOTIFY_CHANNEL = "notify" +RESET_CHANNEL = "reset" + +CLOCK_PERIOD_PS = 750 + +# Override default widths of AXI response signals +signal_widths = {"bresp": 3} +axi_channels.AxiBBus._signal_widths = signal_widths +axi_channels.AxiBTransaction._signal_widths = signal_widths +axi_channels.AxiBSource._signal_widths = signal_widths +axi_channels.AxiBSink._signal_widths = signal_widths +axi_channels.AxiBMonitor._signal_widths = signal_widths +signal_widths = {"rresp": 3, "rlast": 1} +axi_channels.AxiRBus._signal_widths = signal_widths +axi_channels.AxiRTransaction._signal_widths = signal_widths +axi_channels.AxiRSource._signal_widths = signal_widths +axi_channels.AxiRSink._signal_widths = signal_widths +axi_channels.AxiRMonitor._signal_widths = signal_widths + + +@xlsstruct.xls_dataclass +class NotifyStruct(xlsstruct.XLSStruct): + pass + + +SYMBOL_W = 8 +NUM_OF_BITS_W = 8 +BASE_W = 16 + + +@xlsstruct.xls_dataclass +class FseTableRecord(xlsstruct.XLSStruct): + base: BASE_W + num_of_bits: NUM_OF_BITS_W + symbol: SYMBOL_W + + +PARALLEL_ACCESS_WIDTH = 8 +MAX_WEIGHT = 11 +WEIGHT_LOG = math.ceil(math.log2(MAX_WEIGHT + 1)) +VALID_W = 1 + + +@xlsstruct.xls_dataclass +class CodeBuilderOutput(xlsstruct.XLSStruct): + symbol_valid_7: VALID_W + symbol_valid_6: VALID_W + symbol_valid_5: VALID_W + symbol_valid_4: VALID_W + symbol_valid_3: VALID_W + symbol_valid_2: VALID_W + symbol_valid_1: VALID_W + symbol_valid_0: VALID_W + code_length_7: WEIGHT_LOG + code_length_6: WEIGHT_LOG + code_length_5: WEIGHT_LOG + code_length_4: WEIGHT_LOG + code_length_3: WEIGHT_LOG + code_length_2: WEIGHT_LOG + code_length_1: WEIGHT_LOG + code_length_0: WEIGHT_LOG + code_7: MAX_WEIGHT + code_6: MAX_WEIGHT + code_5: MAX_WEIGHT + code_4: MAX_WEIGHT + code_3: MAX_WEIGHT + code_2: MAX_WEIGHT + code_1: MAX_WEIGHT + code_0: MAX_WEIGHT + + +class CSR(enum.Enum): + """ + Maps the offsets to the ZSTD Decoder registers. + """ + + STATUS = 0 + START = 1 + INPUTBUFFER = 2 + OUTPUTBUFFER = 3 + + +class Status(enum.Enum): + """ + Codes for the Status register. + """ + + IDLE = 0x0 + RUNNING = 0x1 + READ_CONFIG_OK = 2 + FRAME_HEADER_OK = 3 + FRAME_HEADER_CORRUPTED = 4 + FRAME_HEADER_UNSUPPORTED_WINDOW_SIZE = 5 + BLOCK_HEADER_OK = 6 + BLOCK_HEADER_CORRUPTED = 7 + BLOCK_HEADER_MEMORY_ACCESS_ERROR = 8 + RAW_BLOCK_OK = 9 + RAW_BLOCK_ERROR = 10 + RLE_BLOCK_OK = 11 + CMP_BLOCK_OK = 12 + + +def check_decoder_compliance(file_path): + with open(file_path, mode='rb') as compressed_file: + # Unused magic number + compressed_file.seek(4) + + frame_header_descriptor = int.from_bytes(compressed_file.read(1)) + + # 6th bit of a frame header indicates if a window descriptor is present + SINGLE_SEGMENT_FLAG_MASK = 0b100000 + if frame_header_descriptor & SINGLE_SEGMENT_FLAG_MASK == 0: + # Calculate a required window_size for the encoded file + # and compare it with the ZSTD decoder history buffer size. + # Based on window_size calculation from: RFC 8878 + # https://datatracker.ietf.org/doc/html/rfc8878#name-window-descriptor + window_descriptor = int.from_bytes(compressed_file.read(1)) + + MANTISSA_BITS = 0b111 + mantissa = window_descriptor & MANTISSA_BITS + + EXPONENT_BITS = 0b11111000 + exponent = (window_descriptor & EXPONENT_BITS) >> 3 + + window_log = 10 + exponent + window_base = 1 << window_log + window_add = (window_base / 8) * mantissa + window_size = int(window_base + window_add) + + # This value represent the size of the history buffer for the tested + # instance of the ZSTD decoder, and should be in line with the value + # of `INST_HB_SIZE_KB` declared in the zstd_dec.x file. + HISTORY_BUFFER_SIZE = 64 * 1024 # 64 KB + + if window_size > HISTORY_BUFFER_SIZE: + print(f"error: required window size greater than the actual history buffer: {window_size} > {HISTORY_BUFFER_SIZE}") + return False + + return True + + +def check_ram_contents(mem, expected, name=""): + for i, value in enumerate(expected): + assert mem[i].value == value, f"[{name}] index: {i} value: {mem[i].value}, expected: {value}" + + +def print_fse_ram_contents(mem, name="", size=None): + for i in range(size): + data = FseTableRecord.from_int(mem[i].value) + print(f"{name} [{i}]: {data}") + + +def print_ram_contents(mem, name="", size=None): + for i in range(size): + print(f"{name} [{i}]\t: {hex(mem[i].value)}") + + +def fields_as_array(data, prefix, count): + return [getattr(data, f"{prefix}_{i}") for i in range(count)] + + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + event.set() + + monitor.add_callback(terminate_cb) + + +@cocotb.coroutine +async def set_handshake_event(clk, channel, event): + while True: + await RisingEdge(clk) + if channel.rdy.value and channel.vld.value: + event.set() + + +@cocotb.coroutine +async def get_handshake_event(dut, event, func): + while True: + await event.wait() + func() + event.clear() + + +def connect_axi_read_bus(dut, name=""): + axi_ar = "axi_ar" + axi_r = "axi_r" + + if name: + name += "_" + + bus_axi_ar = axi_channels.AxiARBus.from_prefix(dut, name + axi_ar) + bus_axi_r = axi_channels.AxiRBus.from_prefix(dut, name + axi_r) + + return axi_channels.AxiReadBus(bus_axi_ar, bus_axi_r) + + +def connect_axi_write_bus(dut, name=""): + axi_aw = "axi_aw" + axi_w = "axi_w" + axi_b = "axi_b" + + if name: + name += "_" + + bus_axi_aw = axi_channels.AxiAWBus.from_prefix(dut, name + axi_aw) + bus_axi_w = axi_channels.AxiWBus.from_prefix(dut, name + axi_w) + bus_axi_b = axi_channels.AxiBBus.from_prefix(dut, name + axi_b) + + return axi_channels.AxiWriteBus(bus_axi_aw, bus_axi_w, bus_axi_b) + + +def connect_axi_bus(dut, name=""): + bus_axi_read = connect_axi_read_bus(dut, name) + bus_axi_write = connect_axi_write_bus(dut, name) + + return axi_channels.AxiBus(bus_axi_write, bus_axi_read) + + +async def csr_write(cpu, csr, data): + if isinstance(data, int): + data = data.to_bytes(AXI_DATA_W_BYTES, byteorder="little") + assert len(data) <= AXI_DATA_W_BYTES + await cpu.write(csr.value * AXI_DATA_W_BYTES, data) + + +async def csr_read(cpu, csr): + return await cpu.read(csr.value * AXI_DATA_W_BYTES, AXI_DATA_W_BYTES) + + +async def test_csr(dut): + + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + await reset_dut(dut, 50) + + csr_bus = connect_axi_bus(dut, "csr") + + cpu = AxiMaster(csr_bus, dut.clk, dut.rst) + + await triggers.ClockCycles(dut.clk, 10) + i = 0 + for reg in CSR: + expected_src = bytearray.fromhex("0DF0AD8BEFBEADDE") + assert len(expected_src) >= AXI_DATA_W_BYTES + expected = expected_src[-AXI_DATA_W_BYTES:] + expected[0] += i + await csr_write(cpu, reg, expected) + read = await csr_read(cpu, reg) + assert ( + read.data == expected + ), "Expected data doesn't match contents of the {}".format(reg) + i += 1 + await triggers.ClockCycles(dut.clk, 10) + + +async def test_reset(dut): + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + await reset_dut(dut, 50) + + csr_bus = connect_axi_bus(dut, "csr") + cpu = AxiMaster(csr_bus, dut.clk, dut.rst) + + await triggers.ClockCycles(dut.clk, 10) + await start_decoder(cpu) + timeout = 10 + status = await csr_read(cpu, CSR.STATUS) + while (int.from_bytes(status.data, byteorder="little") == Status.IDLE.value) & ( + timeout != 0 + ): + status = await csr_read(cpu, CSR.STATUS) + timeout -= 1 + assert timeout != 0 + + await reset_dut(dut, 50) + await wait_for_idle(cpu, 10) + + await triggers.ClockCycles(dut.clk, 10) + + +async def configure_decoder(dut, cpu, ibuf_addr, obuf_addr): + status = await csr_read(cpu, CSR.STATUS) + if int.from_bytes(status.data, byteorder="little") != Status.IDLE.value: + await reset_dut(dut, 50) + await csr_write(cpu, CSR.INPUTBUFFER, ibuf_addr) + await csr_write(cpu, CSR.OUTPUTBUFFER, obuf_addr) + + +async def start_decoder(cpu): + await csr_write(cpu, CSR.START, 0x1) + + +async def wait_for_idle(cpu, timeout=100): + status = await csr_read(cpu, CSR.STATUS) + while (int.from_bytes(status.data, byteorder="little") != Status.IDLE.value) & ( + timeout != 0 + ): + status = await csr_read(cpu, CSR.STATUS) + timeout -= 1 + assert timeout != 0 + + +async def reset_dut(dut, rst_len=10): + dut.rst.setimmediatevalue(0) + await triggers.ClockCycles(dut.clk, rst_len) + dut.rst.setimmediatevalue(1) + await triggers.ClockCycles(dut.clk, rst_len) + dut.rst.setimmediatevalue(0) + + +def get_clock_time(clock: Clock): + return get_sim_time(units="step") / clock.period + + +def connect_xls_channel(dut, channel_name, xls_struct): + channel = XLSChannel(dut, channel_name, dut.clk, start_now=True) + monitor = XLSChannelMonitor(dut, channel_name, dut.clk, xls_struct) + + return (channel, monitor) + + +def prepare_test_environment(dut): + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + memory_bus = connect_axi_bus(dut, "memory") + csr_bus = connect_axi_bus(dut, "csr") + axi_buses = {"memory": memory_bus, "csr": csr_bus} + + cpu = AxiMaster(csr_bus, dut.clk, dut.rst) + + return (axi_buses, cpu, clock) + + +async def test_fse_lookup_decoder(dut, clock, expected_fse_lookups): + lookup_dec_resp_channel = XLSChannel( + dut.ZstdDecoder.xls_modules_zstd_sequence_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__SequenceDecoderCtrl_0__FseLookupCtrl_0_next_inst149, + "zstd_dec__flc_resp", + dut.clk, + ) + fse_lookup_resp_handshake = triggers.Event() + + block_cnt = 0 + + def func(): + nonlocal block_cnt + assert block_cnt <= len(expected_fse_lookups) + print_fse_ram_contents( + dut.ll_fse_ram.mem, "LL", size=len(expected_fse_lookups[block_cnt]["ll"]) + ) + print_fse_ram_contents( + dut.ml_fse_ram.mem, "ML", size=len(expected_fse_lookups[block_cnt]["ml"]) + ) + print_fse_ram_contents( + dut.of_fse_ram.mem, "OF", size=len(expected_fse_lookups[block_cnt]["of"]) + ) + check_ram_contents( + dut.ll_fse_ram.mem, [x.value for x in expected_fse_lookups[block_cnt]["ll"]] + ) + check_ram_contents( + dut.ml_fse_ram.mem, [x.value for x in expected_fse_lookups[block_cnt]["ml"]] + ) + check_ram_contents( + dut.of_fse_ram.mem, [x.value for x in expected_fse_lookups[block_cnt]["of"]] + ) + block_cnt += 1 + + cocotb.start_soon( + set_handshake_event(dut.clk, lookup_dec_resp_channel, fse_lookup_resp_handshake) + ) + cocotb.start_soon(get_handshake_event(dut, fse_lookup_resp_handshake, func)) + + +async def test_fse_lookup_decoder_for_huffman(dut, clock, expected_fse_lookups): + lookup_dec_resp_channel = XLSChannel( + dut.ZstdDecoder.xls_modules_zstd_comp_lookup_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanFseWeightsDecoder_0__CompLookupDecoder_0__64_8_16_1_15_8_32_1_7_9_8_1_8_16_1_next_inst5, + "zstd_dec__fse_table_finish__1", + dut.clk, + ) + fse_lookup_resp_handshake = triggers.Event() + + block_cnt = 0 + + def func(): + nonlocal block_cnt + assert block_cnt <= len(expected_fse_lookups) + print_fse_ram_contents( + dut.huffman_literals_weights_fse_ram_ram.mem, + f"HUFMMAN ({block_cnt})", + size=len(expected_fse_lookups[block_cnt]), + ) + check_ram_contents( + dut.huffman_literals_weights_fse_ram_ram.mem, + [x.value for x in expected_fse_lookups[block_cnt]], + ) + block_cnt += 1 + + cocotb.start_soon( + set_handshake_event(dut.clk, lookup_dec_resp_channel, fse_lookup_resp_handshake) + ) + cocotb.start_soon(get_handshake_event(dut, fse_lookup_resp_handshake, func)) + + +@cocotb.coroutine +async def await_state_cycle(clk, wire, func, startvals, endvals): + """Monitors a state signal and reports elapsed cycles between start and end states. + + This will continously observe a given state signal and after any of startvals, + and then endvals is matched with the value, report the elapsed cycles. + + For procs that have an FSM, use proper start state (the one used after IDLE) in startvals, + and a state that corresponds to sending the result back, or switching back to IDLE in endvals. + + Args: + wire: state signal to observe + func (Callable[[int], None]): Callback function to report the elapsed cycles + startvals (Iterable): values that define the start states + endvals (Iterable): values that define the end states + """ + while True: + while wire.value not in startvals: + await Edge(wire) + start = get_clock_time(clk) + while wire.value not in endvals: + await Edge(wire) + end = get_clock_time(clk) + func(end - start) + +async def report_fse_decoder_work(dut, clk): + fse_state = dut.ZstdDecoder.xls_modules_zstd_fse_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__FseDecoder_0__64_15_32_1_64_7_next_inst10.p2_____state_0__1 + start_states = [1] + end_states = [16] + + def report(value): + print(f'FSE Decoder finished after {value} cycles') + + cocotb.start_soon(await_state_cycle(clk, fse_state, report, start_states, end_states)) + +async def report_fse_table_creator_work(dut, clk): + state = dut.ZstdDecoder.xls_modules_zstd_fse_table_creator__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__FseLookupDecoder_0__CompLookupDecoder_0__FseTableCreator_0__8_16_1_15_32_1_9_8_1_8_16_1_next_inst16.p3_____state_0__1 + start_states = [1] + end_states = [11] + + def report(value): + print(f'FSE table creator finished after {value} cycles') + + cocotb.start_soon(await_state_cycle(clk, state, report, start_states, end_states)) + +def reverse_expected_huffman_codes(exp_codes): + def reverse_bits(value, max_bits): + bv = BinaryValue(value=value, n_bits=max_bits, bigEndian=False) + return int(BinaryValue(value=bv.binstr[::-1], n_bits=max_bits, bigEndian=False)) + + max_bits = max(d["length"] for d in exp_codes) + + codes = [] + for record in exp_codes: + codes += [ + { + "code": reverse_bits(record["code"], max_bits), + "length": record["length"], + "symbol": record["symbol"], + } + ] + return codes + + +async def test_huffman_codes(dut, clock, expected_codes): + WEIGHT_CODE_BUILDER_INST = ( + dut.ZstdDecoder.xls_modules_zstd_huffman_code_builder__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__WeightCodeBuilder_0_next_inst20 + ) + CODES_CHANNEL_NAME = "zstd_dec__code_builder_codes" + + codes_channel = XLSChannel( + WEIGHT_CODE_BUILDER_INST, CODES_CHANNEL_NAME, dut.clk + ) + huffman_code_handshake = triggers.Event() + + codes = [] + block_cnt = 0 + packet_cnt = 0 + symbol_cnt = 0 + + def func(): + nonlocal codes + nonlocal symbol_cnt + nonlocal packet_cnt + nonlocal block_cnt + + assert block_cnt <= 32 + codes_data = getattr(WEIGHT_CODE_BUILDER_INST, CODES_CHANNEL_NAME + '_data') + data = CodeBuilderOutput.from_int(codes_data.value) + + symbol_valid_array = fields_as_array(data, "symbol_valid", 8) + code_length_array = fields_as_array(data, "code_length", 8) + code_array = fields_as_array(data, "code", 8) + + for symbol_valid, code_length, code in zip( + symbol_valid_array, code_length_array, code_array + ): + if symbol_valid == 1: + codes += [{"symbol": symbol_cnt, "code": code, "length": code_length}] + symbol_cnt += 1 + packet_cnt += 1 + + if packet_cnt == 32: + assert codes == reverse_expected_huffman_codes(expected_codes[block_cnt]) + packet_cnt = 0 + symbol_cnt = 0 + block_cnt += 1 + codes = [] + + cocotb.start_soon( + set_handshake_event(dut.clk, codes_channel, huffman_code_handshake) + ) + cocotb.start_soon(get_handshake_event(dut, huffman_code_handshake, func)) + + +async def test_huffman_weights(dut, clock, expected_huffman_weights): + lookup_dec_resp_channel = XLSChannel( + dut.ZstdDecoder.xls_modules_zstd_huffman_ctrl__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanControlAndSequence_0__32_64_next_inst21, + "zstd_dec__weights_dec_resp", + dut.clk, + ) + huffman_weights_resp_handshake = triggers.Event() + + block_cnt = 0 + + def func(): + nonlocal block_cnt + assert block_cnt <= len(expected_huffman_weights) + print_ram_contents( + dut.huffman_literals_weights_mem_ram_ram.mem, + f"WEIGHTS ({block_cnt})", + size=64, + ) + check_ram_contents( + dut.huffman_literals_weights_mem_ram_ram.mem, + expected_huffman_weights[block_cnt], + ) + block_cnt += 1 + + cocotb.start_soon( + set_handshake_event( + dut.clk, lookup_dec_resp_channel, huffman_weights_resp_handshake + ) + ) + cocotb.start_soon(get_handshake_event(dut, huffman_weights_resp_handshake, func)) + + +async def check_status(dut, cpu, timeout=100): + (unused_notify_channel, notify_monitor) = connect_xls_channel( + dut, NOTIFY_CHANNEL, NotifyStruct + ) + notify_event = triggers.Event() + set_termination_event(notify_monitor, notify_event, 1) + + await notify_event.wait() + + status = None + while timeout != 0 and status != Status.IDLE: + status_reg = await csr_read(cpu, CSR.STATUS) + status = Status(int.from_bytes(status_reg.data, byteorder="little")) + timeout -= 1 + + assert status == Status.IDLE, ( + f"Decoder finished with non-idle status: {status.name}" + ) + + +async def check_output(expected_packet_count, memory, reference_memory, output_monitor, obuf_addr, clock, encoded_file): + # Read decoded frame in chunks of AXI_DATA_W length + # Compare against frame decompressed with the reference library + current_addr = obuf_addr + decode_start = get_clock_time(clock) + await output_monitor.wait() + decode_first_packet = get_clock_time(clock) + + for read_op in range(0, expected_packet_count): + decoded_bytes_index = (read_op * AXI_DATA_W_BYTES) + current_addr = obuf_addr + decoded_bytes_index + exp_mem_contents = int.from_bytes(reference_memory.read(current_addr, AXI_DATA_W_BYTES), byteorder="little") + mem_contents = (await output_monitor.recv()).wdata + if mem_contents != exp_mem_contents: + incorrect_byte_index = 0 + for byte_index in range(AXI_DATA_W_BYTES): + if (mem_contents >> (byte_index * 8) & 0xFF) != (exp_mem_contents >> (byte_index * 8) & 0xFF): + incorrect_byte_index = decoded_bytes_index + 7 - incorrect_byte_index + break + + debug_file(encoded_file, incorrect_byte_index, Path(encoded_file).name) + assert False, ( + "{} bytes of memory contents at address {} " + "don't match the expected contents:\n" + "{}\nvs\n{}" + ).format( + AXI_DATA_W_BYTES, + hex(current_addr), + hex(mem_contents), + hex(exp_mem_contents), + ) + + if read_op % 0x1000 == 0: + print(f'[cocotb] Got correct packet (addr: {hex(current_addr)}, data: {hex(mem_contents)}, clk: {get_clock_time(clock)})', file=sys.stderr) + + decode_last_packet = get_clock_time(clock) + return (decode_start, decode_first_packet, decode_last_packet) + +async def test_decoder(dut, axi_buses, cpu, clock, encoded_file): + """Test decoder with zstd-compressed data provided in `encoded_file` + + The output of the decoder is compared with the output of decodercorpus + using the same input file. + """ + assert check_decoder_compliance(encoded_file.name), (f"error: '{encoded_file.name}' is not suitable for the decoder parameters") + + memory_bus = axi_buses["memory"] + + mem_size = MAX_ENCODED_FRAME_SIZE_B + ibuf_addr = 0x0 + obuf_addr = mem_size // 2 + + await reset_dut(dut, 50) + + expected_decoded_frame = data_generator.DecompressFrame(encoded_file.read()) + reference_memory = SparseMemory(mem_size) + reference_memory.write(obuf_addr, expected_decoded_frame) + expected_packet_count = ( + len(expected_decoded_frame) + (AXI_DATA_W_BYTES - 1) + ) // AXI_DATA_W_BYTES + + # Initialise testbench memory with generated ZSTD frame + memory = AxiRamFromFile( + bus=memory_bus, clock=dut.clk, reset=dut.rst, path=encoded_file.name, size=mem_size + ) + + await configure_decoder(dut, cpu, ibuf_addr, obuf_addr) + output_monitor = AxiWMonitor(memory_bus.write.w, dut.clk, dut.rst) + await start_decoder(cpu) + + check_status_thread = await cocotb.start(check_status(dut,cpu)) + check_output_thread = await cocotb.start(check_output(expected_packet_count, memory, reference_memory, output_monitor, obuf_addr, clock, encoded_file.name)) + decode_times = await check_output_thread + (decode_start, decode_first_packet, decode_last_packet) = decode_times + await check_status_thread + decode_end = get_clock_time(clock) + + latency = decode_first_packet - decode_start + + duration = decode_end - decode_start + total_decoded_bytes = expected_packet_count * AXI_DATA_W_BYTES + bytes_per_clock = total_decoded_bytes / duration + CLOCK_PERIOD_PS = 750 + CLOCKS_PER_SECOND = 1e12 / CLOCK_PERIOD_PS + BYTES_IN_GIGABYTE = 1024 * 1024 * 1024 + gigabytes_per_second = bytes_per_clock * CLOCKS_PER_SECOND / BYTES_IN_GIGABYTE + + print(f"Duration: {duration} cycles") + print(f"Latency (clocks till first data): {latency} cycles") + print(f"Total decoded bytes: {total_decoded_bytes} bytes") + print(f"Decoding throughput: {gigabytes_per_second:.04f} GB/second") + + await ClockCycles(dut.clk, 20) + + return (duration, latency, total_decoded_bytes, gigabytes_per_second) + +async def wait_for_status(cpu, timeout=100): + status = None + while timeout != 0 and status != Status.IDLE: + status_reg = await csr_read(cpu, CSR.STATUS) + status = Status(int.from_bytes(status_reg.data, byteorder="little")) + timeout -= 1 + + return status + +async def expect_status(dut, cpu, expected_status, timeout=100): + (unused_notify_channel, notify_monitor) = connect_xls_channel( + dut, NOTIFY_CHANNEL, NotifyStruct + ) + notify_event = triggers.Event() + set_termination_event(notify_monitor, notify_event, 1) + await notify_event.wait() + + status = await wait_for_status(cpu) + assert status == expected_status, ( + f"Decoder finished with non-expected status: {status.name}" + ) + +async def test_decoder_status(dut, axi_buses, cpu, clock, encoded_file, expected_status): + """Test decoder with zstd-compressed data provided in `encoded_file` + + The output error of the decoder is compared with provided expected error. + """ + + memory_bus = axi_buses["memory"] + + mem_size = MAX_ENCODED_FRAME_SIZE_B + ibuf_addr = 0x0 + obuf_addr = mem_size // 2 + + await reset_dut(dut, 50) + + expected_decoded_frame = data_generator.DecompressFrame(encoded_file.read()) + reference_memory = SparseMemory(mem_size) + reference_memory.write(obuf_addr, expected_decoded_frame) + + # Initialise testbench memory with generated ZSTD frame + memory = AxiRamFromFile( + bus=memory_bus, clock=dut.clk, reset=dut.rst, path=encoded_file.name, size=mem_size + ) + + await configure_decoder(dut, cpu, ibuf_addr, obuf_addr) + await start_decoder(cpu) + + check_status_thread = await cocotb.start(expect_status(dut, cpu, expected_status)) + await check_status_thread + +async def randomized_testing_routine( + dut, + test_cases=1, + block_type=data_generator.BlockType.RANDOM, + literal_type=data_generator.LiteralType.RANDOM, + expected_fse_lookups=None, + expected_fse_huffman_lookups=None, + expected_huffman_weights=None, + expected_huffman_codes=None, +): + (axi_buses, cpu, clock) = prepare_test_environment(dut) + measurements = [] + frame_id = 0 + seed = 2 + for test_case in range(test_cases): + if expected_fse_lookups is not None: + await test_fse_lookup_decoder(dut, clock, expected_fse_lookups) + if expected_fse_huffman_lookups is not None: + await test_fse_lookup_decoder_for_huffman( + dut, clock, expected_fse_huffman_lookups + ) + if expected_huffman_codes is not None: + await test_huffman_codes(dut, clock, expected_huffman_codes) + if expected_huffman_weights is not None: + await test_huffman_weights(dut, clock, expected_huffman_weights) + + with tempfile.NamedTemporaryFile(delete=False) as input_file: + # Generate ZSTD frame to temporary file + data_generator.GenerateFrame(seed, block_type, input_file.name, literal_type) + print( + f"\nusing randomly generated (seed={seed}) input file for decoder: {input_file.name}\n" + ) + test_measurements = await test_decoder(dut, axi_buses, cpu, clock, input_file) + measurements.append(test_measurements) + + print("Decoding {} ZSTD frames done".format(block_type.name)) + for measurement in measurements: + report_test_result(f"{block_type.name}{frame_id}", measurement[0], measurement[1], measurement[2], measurement[3]) + frame_id += 1 + + +async def pregenerated_testing_routine( + dut, + pregenerated_path, + expected_fse_lookups=None, + expected_fse_huffman_lookups=None, + expected_huffman_weights=None, + expected_huffman_codes=None, +): + (axi_buses, cpu, clock) = prepare_test_environment(dut) + print( + f"\nusing pregenerated input file for decoder: {pregenerated_path}\n" + ) + await report_fse_decoder_work(dut, clock) + await report_sequence_executor_work(dut, clock) + await report_fse_table_creator_work(dut, clock) + + if expected_fse_lookups is not None: + await test_fse_lookup_decoder(dut, clock, expected_fse_lookups) + if expected_fse_huffman_lookups is not None: + await test_fse_lookup_decoder_for_huffman( + dut, clock, expected_fse_huffman_lookups + ) + if expected_huffman_codes is not None: + await test_huffman_codes(dut, clock, expected_huffman_codes) + if expected_huffman_weights is not None: + await test_huffman_weights(dut, clock, expected_huffman_weights) + + with open(pregenerated_path, 'rb') as input_file: + measurement = await test_decoder(dut, axi_buses, cpu, clock, input_file) + test_name = os.path.basename(pregenerated_path) + report_test_result(f"{test_name}", measurement[0], measurement[1], measurement[2], measurement[3]) + + +async def test_expected_status( + dut, + pregenerated_path, + expected_status +): + (axi_buses, cpu, clock) = prepare_test_environment(dut) + print(f"\nusing pregenerated input file for decoder: {pregenerated_path}\n") + await report_fse_decoder_work(dut, clock) + await report_fse_table_creator_work(dut, clock) + + with open(pregenerated_path, 'rb') as input_file: + measurement = await test_decoder_status(dut, axi_buses, cpu, clock, input_file, expected_status) + + +def run_test(test_module, build_args=[], sim="icarus"): + toplevel = "zstd_dec_wrapper" + verilog_sources = [ + "xls/modules/zstd/zstd_dec.v", + "xls/modules/zstd/rtl/xls_fifo_wrapper.sv", + "xls/modules/zstd/rtl/zstd_dec_wrapper.sv", + "xls/modules/zstd/axi_crossbar_wrapper.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_crossbar.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_crossbar_rd.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_crossbar_wr.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_crossbar_addr.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_register_rd.v", + "external/com_github_alexforencich_verilog_axi/rtl/axi_register_wr.v", + "external/com_github_alexforencich_verilog_axi/rtl/arbiter.v", + "external/com_github_alexforencich_verilog_axi/rtl/priority_encoder.v", + "xls/modules/zstd/rtl/ram_1r1w.sv", + "xls/modules/zstd/rtl/ram_2rw.sv", + ] + + if sim == "verilator": + # verilator-specific config + verilog_sources += "xls/modules/zstd/rtl/cocotb_public_vars.vlt", + + cocotb_utils.run_test(toplevel, test_module, verilog_sources, build_args=build_args, sim=sim) diff --git a/xls/modules/zstd/zstd_dec_cocotb_test.py b/xls/modules/zstd/zstd_dec_cocotb_test.py new file mode 100644 index 0000000000..b452a60e1d --- /dev/null +++ b/xls/modules/zstd/zstd_dec_cocotb_test.py @@ -0,0 +1,59 @@ +# Copyright 2024 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 cocotb +import pathlib +from xls.modules.zstd.cocotb import data_generator +from xls.modules.zstd.zstd_dec_cocotb_common import ( + randomized_testing_routine, + run_test, + test_csr, + test_reset, +) + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def zstd_csr_test(dut): + await test_csr(dut) + + +@cocotb.test(timeout_time=50, timeout_unit="ms") +async def zstd_reset_test(dut): + await test_reset(dut) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def zstd_raw_frames_test(dut): + test_cases = 5 + block_type = data_generator.BlockType.RAW + await randomized_testing_routine(dut, test_cases, block_type) + + +@cocotb.test(timeout_time=500, timeout_unit="ms") +async def zstd_rle_frames_test(dut): + test_cases = 5 + block_type = data_generator.BlockType.RLE + await randomized_testing_routine(dut, test_cases, block_type) + + +@cocotb.test(timeout_time=5000, timeout_unit="ms") +async def zstd_compressed_frames_test(dut): + test_cases = 1 + block_type = data_generator.BlockType.COMPRESSED + literal_type = data_generator.LiteralType.RAW + await randomized_testing_routine(dut, test_cases, block_type, literal_type) + + +if __name__ == "__main__": + test_module = [pathlib.Path(__file__).stem] + run_test(test_module, sim="icarus") diff --git a/xls/modules/zstd/zstd_dec_detailed_test.py b/xls/modules/zstd/zstd_dec_detailed_test.py new file mode 100644 index 0000000000..326cb5fd4a --- /dev/null +++ b/xls/modules/zstd/zstd_dec_detailed_test.py @@ -0,0 +1,693 @@ +import math +import cocotb +import os + +from pathlib import Path +from enum import IntEnum +from pprint import pformat + +from cocotb.utils import get_sim_time + +from cocotbext.axi.sparse_memory import SparseMemory +from cocotbext.axi.axi_channels import AxiWMonitor + +from xls.modules.zstd.cocotb import data_generator +from xls.modules.zstd.cocotb.channel import XLSChannel +from xls.modules.zstd.cocotb.xlsstruct import xls_dataclass, XLSStruct +from xls.modules.zstd.zstd_dec_cocotb_common import ( + configure_decoder, start_decoder, reset_dut, prepare_test_environment, + reverse_expected_huffman_codes, fields_as_array, print_fse_ram_contents, + check_status, check_output, get_clock_time, CLOCK_PERIOD_PS +) +from xls.modules.zstd.cocotb.memory import AxiRamFromFile +from xls.modules.zstd.perf_report import report_test_result + +def check_if_ram_contents_are_valid(mem, expected, name="") -> bool: + for i, value in enumerate(expected): + if mem[i].value != value: + print(f"[{name}] index: {i} value: {mem[i].value}, expected: {value}") + return False + return True + +def print_ram_contents(mem, name="", size=None): + for i in range(size): + print(f"{name} [{i}]\t: {hex(mem[i]) if not hasattr(mem[i], 'value') else hex(mem[i].value)}") + +def printc(*args, **kwargs): + GREEN = '\033[92m' + ENDC = '\033[0m' + print(GREEN, *args, ENDC, **kwargs) + +class BlockType(IntEnum): + RAW = 0, + RLE = 1, + COMPRESSED = 2, + RESERVED = 3, + +@xls_dataclass +class BlockHeader(XLSStruct): + last: 1 + btype: 2 + size: 21 + +@xls_dataclass +class BlockHeaderDecoderResp(XLSStruct): + status: 2 + header: BlockHeader.total_width + rle_symbol: 8 + +@xls_dataclass +class BlockHeaderDecoderReq(XLSStruct): + addr: 32 + +@xls_dataclass +class RawBlockDecoderReq(XLSStruct): + id: 32 + addr: 32 + length: 32 + last_block: 1 + +class RawBlockDecoderStatus(IntEnum): + OKAY = 0 + ERROR = 1 + +@xls_dataclass +class RawBlockDecoderResp(XLSStruct): + status: 1 + +@xls_dataclass +class RleBlockDecoderReq(XLSStruct): + id: 32 + symbol: 8 + length: 21 + last_block: 1 + +@xls_dataclass +class RleBlockDecoderResp(XLSStruct): + status: 1 + +@xls_dataclass +class CompressedBlockDecoderReq(XLSStruct): + addr: 32 + length: 21 + id: 32 + last_block: 1 + +@xls_dataclass +class CompressedBlockDecoderResp(XLSStruct): + status: 1 + +@xls_dataclass +class LiteralsHeaderDecoderReq(XLSStruct): + addr: 32 + +class LiteralsBlockType(IntEnum): + RAW = 0 + RLE = 1 + COMP = 2 + COMP_4 = 3 + TREELESS = 4 + TREELESS_4 = 5 + +@xls_dataclass +class LiteralsHeader(XLSStruct): + literal_type: 3 + regenerated_size: 20 + compressed_size: 20 + +@xls_dataclass +class LiteralsHeaderDecoderResp(XLSStruct): + header: LiteralsHeader.total_width + symbol: 8 + length: 3 + status: 1 + +@xls_dataclass +class SequenceConfDecoderReq(XLSStruct): + addr: 32 + +@xls_dataclass +class SequenceConf(XLSStruct): + sequence_count: 17 + literals_mode: 2 + offset_mode: 2 + match_mode: 2 + +@xls_dataclass +class SequenceConfDecoderResp(XLSStruct): + header: SequenceConf.total_width + length: 3 + status: 1 + +@xls_dataclass +class RawLiteralsDecoderReq(XLSStruct): + id: 32 + addr: 32 + length: 32 + literals_last: 1 + +@xls_dataclass +class RawLiteralsDecoderResp(XLSStruct): + status: 1 + +@xls_dataclass +class RleLiteralsDecoderReq(XLSStruct): + id: 32 + symbol: 8 + length: 20 + literals_last: 1 + +@xls_dataclass +class RleLiteralsDecoderResp(XLSStruct): + status: 1 + + +@xls_dataclass +class HuffmanControlAndSequenceCtrl(XLSStruct): + base_addr: 32 + len: 32 + new_config: 1 + multi_stream: 1 + id: 32 + literals_last: 1 + + +@xls_dataclass +class HuffmanControlAndSequenceResp(XLSStruct): + status: 1 + + +class CompressionMode(IntEnum): + PREDEFINED = 0 + RLE = 1 + COMPRESSED = 2 + REPEAT = 3 + +@xls_dataclass +class HuffmanWeightsDecoderReq(XLSStruct): + addr: 32 + +@xls_dataclass +class HuffmanWeightsDecoderResp(XLSStruct): + status: 1 + tree_description_size: 32 + +MAX_WEIGHT = 11 +WEIGHT_LOG = math.ceil(math.log2(MAX_WEIGHT + 1)) +VALID_W = 1 + +class WeightType(IntEnum): + RAW = 0 + FSE = 1 + +@xls_dataclass +class CodeBuilderOutput(XLSStruct): + symbol_valid_7: VALID_W + symbol_valid_6: VALID_W + symbol_valid_5: VALID_W + symbol_valid_4: VALID_W + symbol_valid_3: VALID_W + symbol_valid_2: VALID_W + symbol_valid_1: VALID_W + symbol_valid_0: VALID_W + code_length_7: WEIGHT_LOG + code_length_6: WEIGHT_LOG + code_length_5: WEIGHT_LOG + code_length_4: WEIGHT_LOG + code_length_3: WEIGHT_LOG + code_length_2: WEIGHT_LOG + code_length_1: WEIGHT_LOG + code_length_0: WEIGHT_LOG + code_7: MAX_WEIGHT + code_6: MAX_WEIGHT + code_5: MAX_WEIGHT + code_4: MAX_WEIGHT + code_3: MAX_WEIGHT + code_2: MAX_WEIGHT + code_1: MAX_WEIGHT + code_0: MAX_WEIGHT + + +@xls_dataclass +class HuffmanRawWeightsDecoderReq(XLSStruct): + addr: 32 + n_symbols: 8 + + +@xls_dataclass +class HuffmanRawWeightsDecoderResp(XLSStruct): + status: 1 + + +@xls_dataclass +class HuffmanFseWeightsDecoderReq(XLSStruct): + addr: 32 + length: 8 + + +@xls_dataclass +class HuffmanFseWeightsDecoderResp(XLSStruct): + status: 1 + + +class CompressionMode(IntEnum): + PREDEFINED = 0 + RLE = 1 + COMPRESSED = 2 + REPEAT = 3 + + +@xls_dataclass +class FseLookupCtrlReq(XLSStruct): + ll_mode: 2 + ml_mode: 2 + of_mode: 2 + + +@xls_dataclass +class FseLookupCtrlResp(XLSStruct): + ll_accuracy_log: 7 + ml_accuracy_log: 7 + of_accuracy_log: 7 + + +@xls_dataclass +class HuffmanDecoderStart(XLSStruct): + new_config: 1 + id: 32 + literals_last: 1 + last_stream: 1 + + +async def detailed_testing_routine(dut, + pregenerated_path, + expected_fse_huffman_lookups=None, + expected_huffman_weights=None, + expected_huffman_codes=None, + expected_fse_lookups=None +): + (axi_buses, cpu, clock) = prepare_test_environment(dut) + + encoded_file = Path(pregenerated_path) + + BLOCK_HEADER_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_block_header_dec__ZstdDecoderInst__ZstdDecoder_0__BlockHeaderDecoder_0__32_64_next_inst2 + BLOCK_HEADER_REQ_CHANNEL_NAME = "zstd_dec__bh_req" + BLOCK_HEADER_RESP_CHANNEL_NAME = "zstd_dec__bh_resp" + MAX_ENCODED_FRAME_SIZE_B = 2**32 + + RAW_BLOCK_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_raw_block_dec__ZstdDecoderInst__ZstdDecoder_0__RawBlockDecoder_0__32_64_next_inst133 + RAW_BLOCK_REQ_CHANNEL_NAME = "zstd_dec__raw_req" + RAW_BLOCK_RESP_CHANNEL_NAME = "zstd_dec__raw_resp" + + RLE_BLOCK_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_rle_block_dec__ZstdDecoderInst__ZstdDecoder_0__RleBlockDecoder_0__64_next_inst140 + RLE_BLOCK_REQ_CHANNEL_NAME = "zstd_dec__rle_req" + RLE_BLOCK_RESP_CHANNEL_NAME = "zstd_dec__rle_resp" + + COMPRESSED_BLOCK_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_comp_block_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__32_64_8_4_4_16_256_64_6_92_1_8_16_1_8_32_1_6_32_8_9_8_1_8_16_1_13_9_1_8_16_1_15_15_32_1_9_8_1_8_16_1_next_inst4 + COMPRESSED_BLOCK_REQ_CHANNEL_NAME = "zstd_dec__comp_block_req" + COMPRESSED_BLOCK_RESP_CHANNEL_NAME = "zstd_dec__comp_block_resp" + + LITERALS_HEADER_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_literals_block_header_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__LiteralsHeaderDecoder_0__32_64_next_inst32 + LITERALS_HEADER_REQ_CHANNEL_NAME = "zstd_dec__lit_header_req" + LITERALS_HEADER_RESP_CHANNEL_NAME = "zstd_dec__lit_header_resp" + + RAW_LITERALS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_raw_literals_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__RawLiteralsDecoder_0__32_64_next_inst134 + RAW_LITERALS_DECODER_REQ_CHANNEL_NAME = "zstd_dec__raw_lit_req" + RAW_LITERALS_DECODER_RESP_CHANNEL_NAME = "zstd_dec__raw_lit_resp" + + RLE_LITERALS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_rle_literals_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__RleLiteralsDecoder_0__64_next_inst141 + RLE_LITERALS_DECODER_REQ_CHANNEL_NAME = "zstd_dec__rle_lit_req" + RLE_LITERALS_DECODER_RESP_CHANNEL_NAME = "zstd_dec__rle_lit_resp" + + HUFFMAN_LITERALS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_ctrl__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanControlAndSequence_0__32_64_next_inst21 + HUFFMAN_LITERALS_DECODER_REQ_CHANNEL_NAME = "zstd_dec__huffman_lit_req" + HUFFMAN_LITERALS_DECODER_RESP_CHANNEL_NAME = "zstd_dec__huffman_lit_resp" + + HUFFMAN_LITERALS_DECODER_WEIGHTS_REQ_CHANNEL_NAME = "zstd_dec__weights_dec_req" + HUFFMAN_LITERALS_DECODER_WEIGHTS_RESP_CHANNEL_NAME = "zstd_dec__weights_dec_resp" + + HUFFMAN_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_decoder__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanDecoder_0_next_inst26 + HUFFMAN_DECODER_DONE_CHANNEL_NAME = "zstd_dec__decoder_done" + + HUFFMAN_LITERALS_WEIGHT_CODE_BUILDER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_code_builder__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__WeightCodeBuilder_0__256_8_32_7_next_inst20 + HUFFMAN_LITERALS_WEIGHT_CODES_CHANNEL_NAME = "zstd_dec__code_builder_codes" + + HUFFMAN_WEIGHTS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__32_64_4_8_16_1_8_32_1_9_8_1_8_16_1_6_32_8_next_inst28 + HUFFMAN_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME = "zstd_dec__decoded_weights_sel_req" + HUFFMAN_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME = "zstd_dec__decoded_weights_sel_resp" + + HUFFMAN_RAW_WEIGHTS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanRawWeightsDecoder_0__32_64_96_7_6_32_8_next_inst31 + HUFFMAN_RAW_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME = "zstd_dec__raw_weights_req" + HUFFMAN_RAW_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME = "zstd_dec__raw_weights_resp" + + HUFFMAN_FSE_WEIGHTS_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_weights_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanWeightsDecoder_0__HuffmanFseWeightsDecoder_0__32_64_4_8_16_1_8_32_1_64_7_9_8_1_8_16_1_6_32_8_next_inst29 + HUFFMAN_FSE_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME = "zstd_dec__fse_weights_req" + HUFFMAN_FSE_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME = "zstd_dec__fse_weights_resp" + + HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_INST = dut.ZstdDecoder.xls_modules_zstd_huffman_ctrl__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__LiteralsDecoder_0__HuffmanLiteralsDecoder_0__HuffmanControlAndSequence_0__HuffmanControlAndSequenceMultiStreamHandler_0__HuffmanControlAndSequenceInternal_0__32_next_inst23 + HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_REQ_CHANNEL_NAME = "zstd_dec__hcs_internal_req" + HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_RESP_CHANNEL_NAME = "zstd_dec__hcs_internal_resp" + + SEQUENCE_HEADER_DECODER_INST = dut.ZstdDecoder.xls_modules_zstd_sequence_conf_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__SequenceConfDecoder_0__32_64_next_inst143 + SEQUENCE_HEADER_REQ_CHANNEL_NAME = "zstd_dec__scd_req" + SEQUENCE_HEADER_RESP_CHANNEL_NAME = "zstd_dec__scd_resp" + + FSE_LOOKUP_CTRL_INST = dut.ZstdDecoder.xls_modules_zstd_sequence_dec__ZstdDecoderInst__ZstdDecoder_0__CompressBlockDecoder_0__SequenceDecoder_0__SequenceDecoderCtrl_0__FseLookupCtrl_0_next_inst147 + FSE_LOOKUP_CTRL_REQ_CHANNEL_NAME = "zstd_dec__flc_req" + FSE_LOOKUP_CTRL_RESP_CHANNEL_NAME = "zstd_dec__flc_resp" + + block_header_req = XLSChannel(BLOCK_HEADER_DECODER_INST, BLOCK_HEADER_REQ_CHANNEL_NAME, dut.clk) + block_header_resp = XLSChannel(BLOCK_HEADER_DECODER_INST, BLOCK_HEADER_RESP_CHANNEL_NAME, dut.clk) + + raw_block_req = XLSChannel(RAW_BLOCK_DECODER_INST, RAW_BLOCK_REQ_CHANNEL_NAME, dut.clk) + raw_block_resp = XLSChannel(RAW_BLOCK_DECODER_INST, RAW_BLOCK_RESP_CHANNEL_NAME, dut.clk) + + rle_block_req = XLSChannel(RLE_BLOCK_DECODER_INST, RLE_BLOCK_REQ_CHANNEL_NAME, dut.clk) + rle_block_resp = XLSChannel(RLE_BLOCK_DECODER_INST, RLE_BLOCK_RESP_CHANNEL_NAME, dut.clk) + + compressed_block_req = XLSChannel(COMPRESSED_BLOCK_DECODER_INST, COMPRESSED_BLOCK_REQ_CHANNEL_NAME, dut.clk) + compressed_block_resp = XLSChannel(COMPRESSED_BLOCK_DECODER_INST, COMPRESSED_BLOCK_RESP_CHANNEL_NAME, dut.clk) + + literals_header_req = XLSChannel(LITERALS_HEADER_DECODER_INST, LITERALS_HEADER_REQ_CHANNEL_NAME, dut.clk) + literals_header_resp = XLSChannel(LITERALS_HEADER_DECODER_INST, LITERALS_HEADER_RESP_CHANNEL_NAME, dut.clk) + + raw_literals_dec_req = XLSChannel(RAW_LITERALS_DECODER_INST, RAW_LITERALS_DECODER_REQ_CHANNEL_NAME, dut.clk) + raw_literals_dec_resp = XLSChannel(RAW_LITERALS_DECODER_INST, RAW_LITERALS_DECODER_RESP_CHANNEL_NAME, dut.clk) + + rle_literals_dec_req = XLSChannel(RLE_LITERALS_DECODER_INST, RLE_LITERALS_DECODER_REQ_CHANNEL_NAME, dut.clk) + rle_literals_dec_resp = XLSChannel(RLE_LITERALS_DECODER_INST, RLE_LITERALS_DECODER_RESP_CHANNEL_NAME, dut.clk) + + huffman_literals_dec_req = XLSChannel(HUFFMAN_LITERALS_DECODER_INST, HUFFMAN_LITERALS_DECODER_REQ_CHANNEL_NAME, dut.clk) + huffman_literals_dec_resp = XLSChannel(HUFFMAN_LITERALS_DECODER_INST, HUFFMAN_LITERALS_DECODER_RESP_CHANNEL_NAME, dut.clk) + + huffman_weights_req = XLSChannel(HUFFMAN_LITERALS_DECODER_INST, HUFFMAN_LITERALS_DECODER_WEIGHTS_REQ_CHANNEL_NAME, dut.clk) + huffman_weights_resp = XLSChannel(HUFFMAN_LITERALS_DECODER_INST, HUFFMAN_LITERALS_DECODER_WEIGHTS_RESP_CHANNEL_NAME, dut.clk) + + huffman_weights_sel_req = XLSChannel(HUFFMAN_WEIGHTS_DECODER_INST, HUFFMAN_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME, dut.clk) + huffman_weights_sel_resp = XLSChannel(HUFFMAN_WEIGHTS_DECODER_INST, HUFFMAN_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME, dut.clk) + + huffman_raw_weights_req = XLSChannel(HUFFMAN_RAW_WEIGHTS_DECODER_INST, HUFFMAN_RAW_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME, dut.clk) + huffman_raw_weights_resp = XLSChannel(HUFFMAN_RAW_WEIGHTS_DECODER_INST, HUFFMAN_RAW_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME, dut.clk) + + huffman_fse_weights_req = XLSChannel(HUFFMAN_FSE_WEIGHTS_DECODER_INST, HUFFMAN_FSE_WEIGHTS_DECODER_SEL_REQ_CHANNEL_NAME, dut.clk) + huffman_fse_weights_resp = XLSChannel(HUFFMAN_FSE_WEIGHTS_DECODER_INST, HUFFMAN_FSE_WEIGHTS_DECODER_SEL_RESP_CHANNEL_NAME, dut.clk) + + huffman_codes = XLSChannel(HUFFMAN_LITERALS_WEIGHT_CODE_BUILDER_INST, HUFFMAN_LITERALS_WEIGHT_CODES_CHANNEL_NAME, dut.clk) + huffman_done = XLSChannel(HUFFMAN_DECODER_INST, HUFFMAN_DECODER_DONE_CHANNEL_NAME, dut.clk) + + sequence_header_req = XLSChannel(SEQUENCE_HEADER_DECODER_INST, SEQUENCE_HEADER_REQ_CHANNEL_NAME, dut.clk) + sequence_header_resp = XLSChannel(SEQUENCE_HEADER_DECODER_INST, SEQUENCE_HEADER_RESP_CHANNEL_NAME, dut.clk) + + huffman_control_and_sequence_internal_req = XLSChannel(HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_INST, HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_REQ_CHANNEL_NAME, dut.clk) + huffman_control_and_sequence_internal_resp = XLSChannel(HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_INST, HUFFMAN_CONTROL_AND_SEQUENCE_INTERNAL_RESP_CHANNEL_NAME, dut.clk) + + fse_lookup_ctrl_req = XLSChannel(FSE_LOOKUP_CTRL_INST, FSE_LOOKUP_CTRL_REQ_CHANNEL_NAME, dut.clk) + fse_lookup_ctrl_resp = XLSChannel(FSE_LOOKUP_CTRL_INST, FSE_LOOKUP_CTRL_RESP_CHANNEL_NAME, dut.clk) + + await reset_dut(dut, 50) + + memory_bus = axi_buses["memory"] + mem_size = MAX_ENCODED_FRAME_SIZE_B + ibuf_addr = 0x0 + obuf_addr = mem_size // 2 + await reset_dut(dut, 50) + + AXI_DATA_W = 64 + AXI_DATA_W_BYTES = AXI_DATA_W // 8 + + # Initialise testbench memory with generated ZSTD frame + + with open(encoded_file, "rb") as f: + expected_decoded_frame = data_generator.DecompressFrame(f.read()) + reference_memory = SparseMemory(mem_size) + reference_memory.write(obuf_addr, expected_decoded_frame) + expected_packet_count = (len(expected_decoded_frame) + (AXI_DATA_W_BYTES - 1)) // AXI_DATA_W_BYTES + + memory = AxiRamFromFile( + bus=memory_bus, clock=dut.clk, reset=dut.rst, path=str(encoded_file), size=mem_size + ) + + await configure_decoder(dut, cpu, ibuf_addr, obuf_addr) + output_monitor = AxiWMonitor(memory_bus.write.w, dut.clk, dut.rst) + + check_status_thread = await cocotb.start(check_status(dut, cpu)) + check_output_thread = await cocotb.start(check_output(expected_packet_count, memory, reference_memory, output_monitor, obuf_addr, clock, encoded_file)) + + await start_decoder(cpu) + + score = 0 + block_cnt = 0 + expected_fse_count = 0 + expected_fse_huffman_count = 0 + expected_huffman_weights_count = 0 + expected_huffman_codes_count = 0 + + while True: + req = await block_header_req.recv_as(BlockHeaderDecoderReq) + score += 1 + printc(f"[block {block_cnt}] Requested block header, score: {score}") + + resp = await block_header_resp.recv_as(BlockHeaderDecoderResp) + block_header = BlockHeader.from_int(resp.header) + score += 1 + printc(f"[block {block_cnt}] Decoded block header: {block_header}, score {score}") + printc(f"SIM TIME: {get_sim_time(units='step')}") + + block_type = BlockType(block_header.btype) + match block_type: + case BlockType.RAW: + req = await raw_block_req.recv_as(RawBlockDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding a RAW block, score: {score}") + + resp = await raw_block_resp.recv_as(RawBlockDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded a RAW block, score: {score}") + + case BlockType.RLE: + req = await rle_block_req.recv_as(RleBlockDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding an RLE block, score: {score}") + + resp = await rle_block_resp.recv_as(RleBlockDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded an RLE block, score: {score}") + + case BlockType.COMPRESSED: + req = await compressed_block_req.recv_as(CompressedBlockDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding a COMPRESSED block, score: {score}") + + req = await literals_header_req.recv_as(LiteralsHeaderDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding a literals header, score: {score}") + + resp = await literals_header_resp.recv_as(LiteralsHeaderDecoderResp) + literal_header = LiteralsHeader.from_int(resp.header) + score +=1 + printc(f"[block {block_cnt}] Decoded a literals header: {literal_header}, score: {score}") + + literal_type = LiteralsBlockType(literal_header.literal_type) + match literal_type: + case LiteralsBlockType.RAW: + req = await raw_literals_dec_req.recv_as(RawLiteralsDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding RAW literals, score: {score}") + + resp = await raw_literals_dec_resp.recv_as(RawLiteralsDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded RAW literals, score: {score}") + + case LiteralsBlockType.RLE: + req = await rle_literals_dec_req.recv_as(RleLiteralsDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding RLE literals, score: {score}") + + resp = await rle_literals_dec_resp.recv_as(RleLiteralsDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded RLE literals, score: {score}") + + case LiteralsBlockType.COMP | LiteralsBlockType.TREELESS | LiteralsBlockType.COMP_4 | LiteralsBlockType.TREELESS_4: + req = await huffman_literals_dec_req.recv_as(HuffmanControlAndSequenceCtrl) + score +=1 + printc(f"SIM TIME: {get_sim_time(units='step')}") + + if not literal_type in [LiteralsBlockType.TREELESS, LiteralsBlockType.TREELESS_4]: + weight_dec_req = await huffman_weights_req.recv_as(HuffmanWeightsDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding COMPRESSED literals, score: {score}") + + sel_req = await huffman_weights_sel_req.recv() + score +=1 + + huffman_weights_type = WeightType(sel_req) + if huffman_weights_type == WeightType.RAW: + + req = await huffman_raw_weights_req.recv_as(HuffmanRawWeightsDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding RAW Huffman weights, score: {score}") + + resp = await huffman_raw_weights_resp.recv_as(HuffmanRawWeightsDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded RAW Huffman weights, score: {score}") + + else: + req = await huffman_fse_weights_req.recv_as(HuffmanFseWeightsDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding FSE Huffman weights, score: {score}") + + resp = await huffman_fse_weights_resp.recv_as(HuffmanFseWeightsDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded FSE Huffman weights, score: {score}") + + huffman_fse_mem = dut.huffman_literals_weights_fse_ram_ram.mem + if expected_fse_huffman_lookups is not None: + valid = check_if_ram_contents_are_valid(huffman_fse_mem, [x.value for x in expected_fse_huffman_lookups[expected_fse_huffman_count]], "huffman_fse") + if not valid: + print_fse_ram_contents(huffman_fse_mem, "huffman_fse_mem", len(expected_fse_huffman_lookups[expected_fse_huffman_count])) + print_fse_ram_contents(expected_fse_huffman_lookups[expected_fse_huffman_count], "expected_huffman_fse_mem", len(expected_fse_huffman_lookups[expected_fse_huffman_count])) + assert False, f"Huffman FSE table in block {block_cnt} is invalid" + expected_fse_huffman_count += 1 + printc(f"[block {block_cnt}] Verified FSE Huffman weights, score: {score}") + score +=1 + + score +=1 + printc(f"[block {block_cnt}] Decoded Huffman weights, score: {score}") + + huffman_mem = dut.huffman_literals_weights_mem_ram_ram.mem + if expected_huffman_weights is not None: + valid = check_if_ram_contents_are_valid(huffman_mem, expected_huffman_weights[expected_huffman_weights_count], "huffman_weights") + if not valid: + print_ram_contents(huffman_mem, "huffman_weights", len(expected_huffman_weights[expected_huffman_weights_count])) + printc("VS.") + print_ram_contents(expected_huffman_weights[expected_huffman_weights_count], "expected_huffman_weights", len(expected_huffman_weights[expected_huffman_weights_count])) + assert False, f"Huffman weights table in block {block_cnt} is invalid" + expected_huffman_weights_count += 1 + score +=1 + printc(f"[block {block_cnt}] Checked huffman weights, score: {score}") + + codes = [] + symbol_cnt = 0 + + j = 32 + while (j > 0): + data = await huffman_codes.recv_as(CodeBuilderOutput) + score +=1 + printc(f"[block {block_cnt}] Received huffman codes, score: {score}") + + symbol_valid_array = fields_as_array(data, "symbol_valid", 8) + code_length_array = fields_as_array(data, "code_length", 8) + code_array = fields_as_array(data, "code", 8) + for symbol_valid, code_length, code in zip(symbol_valid_array, code_length_array, code_array): + if symbol_valid == 1: + new_codes = [{"symbol": symbol_cnt, "code": code, "length": code_length}] + codes += new_codes + symbol_cnt += 1 + j -= 1 + + if expected_huffman_codes is not None: + if codes != reverse_expected_huffman_codes(expected_huffman_codes[expected_huffman_codes_count]): + by_codes = lambda d: d['symbol'] + printc(pformat(sorted(codes, key=by_codes))) + printc("VS.") + printc(pformat(sorted(reverse_expected_huffman_codes(expected_huffman_codes[expected_huffman_codes_count]), key=by_codes))) + assert False, f"Huffman weights table in block {block_cnt} is invalid" + expected_huffman_codes_count += 1 + score +=1 + printc(f"[block {block_cnt}] Checked huffman codes, score: {score}") + + resp = await huffman_literals_dec_resp.recv_as(HuffmanControlAndSequenceResp) + score +=1 + printc(f"[block {block_cnt}] Decoded Huffman literals, score: {score}") + + + req = await sequence_header_req.recv_as(SequenceConfDecoderReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding sequence header, score: {score}") + + resp = await sequence_header_resp.recv_as(SequenceConfDecoderResp) + header = SequenceConf.from_int(resp.header) + score +=1 + printc(f"[block {block_cnt}] Decoded sequence header, score: {score}") + + if header.sequence_count != 0: + req = await fse_lookup_ctrl_req.recv_as(FseLookupCtrlReq) + score +=1 + printc(f"[block {block_cnt}] Requested decoding FSE lookups, score: {score}") + + ll_mode = CompressionMode(req.ll_mode) + ml_mode = CompressionMode(req.ml_mode) + of_mode = CompressionMode(req.of_mode) + + req = await fse_lookup_ctrl_resp.recv_as(FseLookupCtrlResp) + score +=1 + printc(f"[block {block_cnt}] Decoded FSE lookups, score: {score}") + + if expected_fse_lookups is not None: + if ll_mode != CompressionMode.PREDEFINED: + printc(f"LL mode: {ll_mode}") + ll_mem = dut.ll_fse_ram.mem + if expected_fse_lookups is not None: + expected_ll_mem = expected_fse_lookups[expected_fse_count]["ll"] + valid = check_if_ram_contents_are_valid(ll_mem, [x.value for x in expected_ll_mem]) + if not valid: + print_fse_ram_contents(ll_mem, "ll_fse_mem", len(expected_ll_mem)) + printc("VS.") + print_fse_ram_contents(expected_ll_mem, "expected_ll_fse_mem", len(expected_ll_mem)) + assert False, f"LL FSE lookup table in block {block_cnt} is invalid" + + if of_mode != CompressionMode.PREDEFINED: + printc(f"OF mode: {of_mode}") + of_mem = dut.of_fse_ram.mem + expected_of_mem = expected_fse_lookups[expected_fse_count]["of"] + valid = check_if_ram_contents_are_valid(of_mem, [x.value for x in expected_of_mem]) + if not valid: + print_fse_ram_contents(of_mem, "of_fse_mem", len(expected_of_mem)) + printc("VS.") + print_fse_ram_contents(expected_of_mem, "expected_of_fse_mem", len(expected_of_mem)) + assert False, f"OF FSE lookup table in block {block_cnt} is invalid" + + if ml_mode != CompressionMode.PREDEFINED: + printc(f"ML mode: {ml_mode}") + ml_mem = dut.ml_fse_ram.mem + expected_ml_mem = expected_fse_lookups[expected_fse_count]["ml"] + valid = check_if_ram_contents_are_valid(ml_mem, [x.value for x in expected_ml_mem]) + if not valid: + print_fse_ram_contents(ml_mem, "ml_fse_mem", len(expected_ml_mem)) + printc("VS.") + print_fse_ram_contents(expected_ml_mem, "expected_of_fse_mem", len(expected_ml_mem)) + assert False, f"ML FSE lookup table in block {block_cnt} is invalid" + + expected_fse_count += 1 + + resp = await compressed_block_resp.recv_as(CompressedBlockDecoderResp) + score +=1 + printc(f"[block {block_cnt}] Decoded COMPRESSED block, score: {score}") + + case BlockType.RESERVED: + raise Exception("Decoded block header of type RESERVED.") + + block_cnt += 1 + + if block_header.last: + break + + decode_times = await check_output_thread + (decode_start, decode_first_packet, decode_last_packet) = decode_times + await check_status_thread + + decode_end = get_clock_time(clock) + latency = decode_first_packet - decode_start + duration = decode_end - decode_start + total_decoded_bytes = expected_packet_count * AXI_DATA_W_BYTES + bytes_per_clock = total_decoded_bytes / duration + BYTES_IN_GIGABYTE = 1024 * 1024 * 1024 + CLOCKS_PER_SECOND = 1e12 / CLOCK_PERIOD_PS + gigabytes_per_second = bytes_per_clock * CLOCKS_PER_SECOND / BYTES_IN_GIGABYTE + print(f"Duration: {duration} cycles") + print(f"Latency (clocks till first data): {latency} cycles") + print(f"Total decoded bytes: {total_decoded_bytes} bytes") + print(f"Decoding throughput: {gigabytes_per_second:.04f} GB/s") + + test_name = os.path.basename(pregenerated_path) + report_test_result(test_name, duration, latency, total_decoded_bytes, gigabytes_per_second) diff --git a/xls/modules/zstd/zstd_dec_ll_fse_default.mem b/xls/modules/zstd/zstd_dec_ll_fse_default.mem new file mode 100644 index 0000000000..fd3bfafa24 --- /dev/null +++ b/xls/modules/zstd/zstd_dec_ll_fse_default.mem @@ -0,0 +1,256 @@ +00000400 +00100400 +00200501 +00000503 +00000504 +00000506 +00000507 +00000509 +0000050a +0000050c +0000060e +00000510 +00000512 +00000513 +00000515 +00000516 +00000518 +00200519 +0000051a +0000061b +0000061d +0000061f +00200400 +00000401 +00000502 +00200504 +00000505 +00200507 +00000508 +0020050a +0000050b +0000060d +00200510 +00000511 +00200513 +00000514 +00200516 +00000517 +00000419 +00100419 +0020051a +0000061c +0000061e +00300400 +00100401 +00200502 +00200503 +00200505 +00200506 +00200508 +00200509 +0020050b +0020050c +0000060f +00200511 +00200512 +00200514 +00200515 +00200517 +00200518 +00000623 +00000622 +00000621 +00000620 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 diff --git a/xls/modules/zstd/zstd_dec_ml_fse_default.mem b/xls/modules/zstd/zstd_dec_ml_fse_default.mem new file mode 100644 index 0000000000..04b32295c8 --- /dev/null +++ b/xls/modules/zstd/zstd_dec_ml_fse_default.mem @@ -0,0 +1,256 @@ +00000600 +00000401 +00200502 +00000503 +00000505 +00000506 +00000508 +0000060a +0000060d +00000610 +00000613 +00000616 +00000619 +0000061c +0000061f +00000621 +00000623 +00000625 +00000627 +00000629 +0000062b +0000062d +00100401 +00000402 +00200503 +00000504 +00200506 +00000507 +00000609 +0000060c +0000060f +00000612 +00000615 +00000618 +0000061b +0000061e +00000620 +00000622 +00000624 +00000626 +00000628 +0000062a +0000062c +00200401 +00300401 +00100402 +00200504 +00200505 +00200507 +00200508 +0000060b +0000060e +00000611 +00000614 +00000617 +0000061a +0000061d +00000634 +00000633 +00000632 +00000631 +00000630 +0000062f +0000062e +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 diff --git a/xls/modules/zstd/zstd_dec_of_fse_default.mem b/xls/modules/zstd/zstd_dec_of_fse_default.mem new file mode 100644 index 0000000000..9d81689c66 --- /dev/null +++ b/xls/modules/zstd/zstd_dec_of_fse_default.mem @@ -0,0 +1,256 @@ +00000500 +00000406 +00000509 +0000050f +00000515 +00000503 +00000407 +0000050c +00000512 +00000517 +00000505 +00000408 +0000050e +00000514 +00000502 +00100407 +0000050b +00000511 +00000516 +00000504 +00100408 +0000050d +00000513 +00000501 +00100406 +0000050a +00000510 +0000051c +0000051b +0000051a +00000519 +00000518 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 +00000000 diff --git a/xls/modules/zstd/zstd_dec_test.x b/xls/modules/zstd/zstd_dec_test.x index 2db5105f38..7ea5e0d5db 100644 --- a/xls/modules/zstd/zstd_dec_test.x +++ b/xls/modules/zstd/zstd_dec_test.x @@ -17,7 +17,7 @@ import xls.examples.ram; import xls.modules.zstd.common; import xls.modules.zstd.memory.axi; import xls.modules.zstd.csr_config; -import xls.modules.zstd.sequence_executor; +import xls.modules.zstd.sequence_executor.sequence_executor; import xls.modules.zstd.memory.axi_ram_reader; import xls.modules.zstd.zstd_dec; import xls.modules.zstd.comp_block_dec; @@ -28,13 +28,13 @@ import xls.modules.zstd.parallel_rams; import xls.modules.zstd.literals_buffer; import xls.modules.zstd.fse_table_creator; import xls.modules.zstd.ram_mux; -// import xls.modules.zstd.zstd_frame_testcases as comp_frame; -// import xls.modules.zstd.data.comp_frame_huffman as comp_frame; -// import xls.modules.zstd.data.comp_frame_fse_comp as comp_frame; -// import xls.modules.zstd.data.comp_frame_fse_repeated as comp_frame; -import xls.modules.zstd.data.comp_frame; -const TEST_WINDOW_LOG_MAX = u32:30; +import xls.modules.zstd.data.comp_frame_huffman; +import xls.modules.zstd.data.comp_frame_huffman_fse; +import xls.modules.zstd.data.comp_frame_fse_comp; +import xls.modules.zstd.data.comp_frame_fse_repeated; +import xls.modules.zstd.data.comp_frame; +import xls.modules.zstd.data.comp_frame_unsupported_window; const TEST_AXI_DATA_W = u32:64; const TEST_AXI_ADDR_W = u32:32; @@ -46,14 +46,15 @@ const TEST_REGS_N = u32:5; const TEST_LOG2_REGS_N = std::clog2(TEST_REGS_N); const TEST_HB_RAM_N = u32:8; -const TEST_HB_ADDR_W = sequence_executor::ZSTD_RAM_ADDR_WIDTH; -const TEST_HB_DATA_W = sequence_executor::RAM_DATA_WIDTH; -const TEST_HB_NUM_PARTITIONS = sequence_executor::RAM_NUM_PARTITIONS; -const TEST_HB_SIZE_KB = sequence_executor::ZSTD_HISTORY_BUFFER_SIZE_KB; -const TEST_HB_RAM_SIZE = sequence_executor::ZSTD_RAM_SIZE; -const TEST_HB_RAM_WORD_PARTITION_SIZE = sequence_executor::RAM_WORD_PARTITION_SIZE; -const TEST_HB_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = sequence_executor::TEST_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR; -const TEST_HB_RAM_INITIALIZED = sequence_executor::TEST_RAM_INITIALIZED; +const TEST_HB_ADDR_W = sequence_executor::ZSTD_HB_RAM_ADDR_W; +const TEST_HB_SINGLE_HB_RAM_ADDR_W = sequence_executor::ZSTD_SINGLE_HB_RAM_ADDR_W; +const TEST_HB_DATA_W = sequence_executor::ZSTD_AXI_DATA_W; +const TEST_HB_NUM_PARTITIONS = sequence_executor::ZSTD_HB_RAM_NUM; +const TEST_HB_SIZE_B = sequence_executor::ZSTD_HISTORY_BUFFER_SIZE_KB as u64 * u64:1024; +const TEST_HB_RAM_SIZE = sequence_executor::ZSTD_HB_RAM_SIZE_TOTAL as u32; +const TEST_HB_RAM_WORD_PARTITION_SIZE = sequence_executor::ZSTD_SINGLE_RAM_DATA_W; +const TEST_HB_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_HB_RAM_INITIALIZED = true; const TEST_HB_RAM_ASSERT_VALID_READ:bool = false; const TEST_RAM_DATA_W:u32 = TEST_AXI_DATA_W; @@ -153,8 +154,9 @@ fn csr_addr(c: zstd_dec::Csr) -> uN[TEST_AXI_ADDR_W] { (c as uN[TEST_AXI_ADDR_W]) << 3 } -#[test_proc] -proc ZstdDecoderTest { +type TestFrames = common::DataArray[1]; + +proc ZstdDecoderTester { type CsrAxiAr = axi::AxiAr; type CsrAxiR = axi::AxiR; type CsrAxiAw = axi::AxiAw; @@ -173,10 +175,8 @@ proc ZstdDecoderTest { type MemAxiW = axi::AxiW; type MemAxiB = axi::AxiB; - type RamRdReqHB = ram::ReadReq; - type RamRdRespHB = ram::ReadResp; - type RamWrReqHB = ram::WriteReq; - type RamWrRespHB = ram::WriteResp; + type RWRamReq = ram::RWRamReq; + type RWRamResp = ram::RWRamResp; type RamRdReq = ram::ReadReq; type RamRdResp = ram::ReadResp; @@ -258,7 +258,8 @@ proc ZstdDecoderTest { type LitBufRamWrReq = ram::WriteReq; type LitBufRamWrResp = ram::WriteResp; - terminator: chan out; + start_r: chan<()> in; + finished_s: chan out; csr_axi_aw_s: chan out; csr_axi_w_s: chan out; @@ -288,11 +289,6 @@ proc ZstdDecoderTest { output_axi_w_r: chan in; output_axi_b_s: chan out; - hb_ram_rd_req_r: chan[8] in; - hb_ram_rd_resp_s: chan[8] out; - hb_ram_wr_req_r: chan[8] in; - hb_ram_wr_resp_s: chan[8] out; - ll_sel_test_req_s: chan out; ll_sel_test_resp_r: chan<()> in; ll_def_test_rd_req_s: chan out; @@ -318,7 +314,7 @@ proc ZstdDecoderTest { init {} - config(terminator: chan out) { + config(start_r: chan<()> in, finished_s: chan out) { let (csr_axi_aw_s, csr_axi_aw_r) = chan("csr_axi_aw"); let (csr_axi_w_s, csr_axi_w_r) = chan("csr_axi_w"); @@ -351,10 +347,13 @@ proc ZstdDecoderTest { let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); - let (hb_ram_rd_req_s, hb_ram_rd_req_r) = chan[8]("hb_ram_rd_req"); - let (hb_ram_rd_resp_s, hb_ram_rd_resp_r) = chan[8]("hb_ram_rd_resp"); - let (hb_ram_wr_req_s, hb_ram_wr_req_r) = chan[8]("hb_ram_wr_req"); - let (hb_ram_wr_resp_s, hb_ram_wr_resp_r) = chan[8]("hb_ram_wr_resp"); + let (hb_ram_rd_req_s_0, hb_ram_rd_req_r_0) = chan[8]("hb_ram_rd_req_0"); + let (hb_ram_rd_resp_s_0, hb_ram_rd_resp_r_0) = chan[8]("hb_ram_rd_resp_0"); + let (hb_ram_wr_comp_s_0, hb_ram_wr_comp_r_0) = chan<()>[8]("hb_ram_rd_resp_0"); + + let (hb_ram_rd_req_s_1, hb_ram_rd_req_r_1) = chan[8]("hb_ram_rd_req_1"); + let (hb_ram_rd_resp_s_1, hb_ram_rd_resp_r_1) = chan[8]("hb_ram_rd_resp_1"); + let (hb_ram_wr_comp_s_1, hb_ram_wr_comp_r_1) = chan<()>[8]("hb_ram_rd_resp_1"); let (notify_s, notify_r) = chan<()>("notify"); @@ -597,8 +596,8 @@ proc ZstdDecoderTest { spawn zstd_dec::ZstdDecoder< TEST_AXI_DATA_W, TEST_AXI_ADDR_W, TEST_AXI_ID_W, TEST_AXI_DEST_W, - TEST_REGS_N, TEST_WINDOW_LOG_MAX, - TEST_HB_ADDR_W, TEST_HB_DATA_W, TEST_HB_NUM_PARTITIONS, TEST_HB_SIZE_KB, + TEST_REGS_N, + TEST_HB_ADDR_W, TEST_HB_DATA_W, TEST_HB_NUM_PARTITIONS, TEST_HB_SIZE_B, TEST_DPD_RAM_ADDR_W, TEST_DPD_RAM_DATA_W, TEST_DPD_RAM_NUM_PARTITIONS, TEST_TMP_RAM_ADDR_W, TEST_TMP_RAM_DATA_W, TEST_TMP_RAM_NUM_PARTITIONS, @@ -611,6 +610,9 @@ proc ZstdDecoderTest { TEST_HUFFMAN_WEIGHTS_FSE_RAM_ADDR_W, TEST_HUFFMAN_WEIGHTS_FSE_RAM_DATA_W, TEST_HUFFMAN_WEIGHTS_FSE_RAM_NUM_PARTITIONS, HISTORY_BUFFER_SIZE_KB, AXI_CHAN_N, TEST_FSE_MAX_ACCURACY_LOG, + + TEST_HB_SINGLE_HB_RAM_ADDR_W, + TEST_HB_RAM_WORD_PARTITION_SIZE, >( csr_axi_aw_r, csr_axi_w_r, csr_axi_b_s, csr_axi_ar_r, csr_axi_r_s, fh_axi_ar_s, fh_axi_r_r, @@ -650,24 +652,21 @@ proc ZstdDecoderTest { output_axi_aw_s, output_axi_w_s, output_axi_b_r, // RAMs for SequenceExecutor - hb_ram_rd_req_s[0], hb_ram_rd_req_s[1], hb_ram_rd_req_s[2], hb_ram_rd_req_s[3], - hb_ram_rd_req_s[4], hb_ram_rd_req_s[5], hb_ram_rd_req_s[6], hb_ram_rd_req_s[7], - hb_ram_rd_resp_r[0], hb_ram_rd_resp_r[1], hb_ram_rd_resp_r[2], hb_ram_rd_resp_r[3], - hb_ram_rd_resp_r[4], hb_ram_rd_resp_r[5], hb_ram_rd_resp_r[6], hb_ram_rd_resp_r[7], - hb_ram_wr_req_s[0], hb_ram_wr_req_s[1], hb_ram_wr_req_s[2], hb_ram_wr_req_s[3], - hb_ram_wr_req_s[4], hb_ram_wr_req_s[5], hb_ram_wr_req_s[6], hb_ram_wr_req_s[7], - hb_ram_wr_resp_r[0], hb_ram_wr_resp_r[1], hb_ram_wr_resp_r[2], hb_ram_wr_resp_r[3], - hb_ram_wr_resp_r[4], hb_ram_wr_resp_r[5], hb_ram_wr_resp_r[6], hb_ram_wr_resp_r[7], + hb_ram_rd_req_s_0, hb_ram_rd_resp_r_0, hb_ram_wr_comp_r_0, + hb_ram_rd_req_s_1, hb_ram_rd_resp_r_1, hb_ram_wr_comp_r_1, notify_s, ); unroll_for! (i, ()): (u32, ()) in u32:0..u32:8 { - spawn ram::RamModel< - TEST_HB_DATA_W, TEST_HB_RAM_SIZE, TEST_HB_RAM_WORD_PARTITION_SIZE, - TEST_HB_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_HB_RAM_INITIALIZED, - TEST_HB_RAM_ASSERT_VALID_READ - >(hb_ram_rd_req_r[i], hb_ram_rd_resp_s[i], hb_ram_wr_req_r[i], hb_ram_wr_resp_s[i]); + spawn ram::RamModel2RW< + TEST_HB_RAM_WORD_PARTITION_SIZE, TEST_HB_RAM_SIZE, + TEST_HB_RAM_WORD_PARTITION_SIZE, TEST_HB_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, + TEST_HB_SINGLE_HB_RAM_ADDR_W, TEST_HB_NUM_PARTITIONS + >( + hb_ram_rd_req_r_0[i], hb_ram_rd_resp_s_0[i], hb_ram_wr_comp_s_0[i], + hb_ram_rd_req_r_1[i], hb_ram_rd_resp_s_1[i], hb_ram_wr_comp_s_1[i] + ) }(()); @@ -702,14 +701,13 @@ proc ZstdDecoderTest { >(raw_axi_ar_r, raw_axi_r_s, raw_ram_rd_req_s, raw_ram_rd_resp_r); ( - terminator, + start_r, finished_s, csr_axi_aw_s, csr_axi_w_s, csr_axi_b_r, csr_axi_ar_s, csr_axi_r_r, fh_axi_ar_r, fh_axi_r_s, fh_ram_wr_req_s, fh_ram_wr_resp_r, bh_axi_ar_r, bh_axi_r_s, bh_ram_wr_req_s, bh_ram_wr_resp_r, raw_axi_ar_r, raw_axi_r_s, raw_ram_wr_req_s, raw_ram_wr_resp_r, comp_ram_wr_req_s, comp_ram_wr_resp_r, output_axi_aw_r, output_axi_w_r, output_axi_b_s, - hb_ram_rd_req_r, hb_ram_rd_resp_s, hb_ram_wr_req_r, hb_ram_wr_resp_s, ll_sel_test_req_s, ll_sel_test_resp_r, ll_def_test_rd_req_s, ll_def_test_rd_resp_r, ll_def_test_wr_req_s, ll_def_test_wr_resp_r, of_sel_test_req_s, of_sel_test_resp_r, @@ -721,10 +719,12 @@ proc ZstdDecoderTest { } next (state: ()) { + let tok = join(); + let (tok, _) = recv(tok, start_r); + trace_fmt!("Test start"); - let frames_count = array_size(comp_frame::FRAMES); + let frames_count = array_size(FRAMES); - let tok = join(); // FILL THE LL DEFAULT RAM trace_fmt!("Filling LL default FSE table"); @@ -779,7 +779,7 @@ proc ZstdDecoderTest { let tok = unroll_for! (test_i, tok): (u32, token) in u32:0..frames_count { trace_fmt!("Loading testcase {:x}", test_i + u32:1); - let frame = comp_frame::FRAMES[test_i]; + let frame = FRAMES[test_i]; let tok = for (i, tok): (u32, token) in u32:0..frame.array_length { let req = RamWrReq { addr: i as uN[TEST_RAM_ADDR_W], @@ -839,7 +839,7 @@ proc ZstdDecoderTest { }); let (tok, _) = recv(tok, csr_axi_b_r); - let decomp_frame = comp_frame::DECOMPRESSED_FRAMES[test_i]; + let decomp_frame = DECOMPRESSED_FRAMES[test_i]; // Test ZstdDecoder memory output interface // Mock the output memory buffer as a DSLX array // It is required to handle AXI write transactions and to write the incoming data to @@ -858,7 +858,7 @@ proc ZstdDecoderTest { // The maximal number if beats in AXI burst transaction let MAX_AXI_TRANSFERS = u32:256; // Actual size of decompressed payload for current test - let DECOMPRESSED_BYTES = comp_frame::DECOMPRESSED_FRAMES[test_i].length; + let DECOMPRESSED_BYTES = DECOMPRESSED_FRAMES[test_i].length; trace_fmt!("ZstdDecTest: Start receiving output"); let (tok, final_output_memory, final_output_memory_id, final_transfered_bytes) = for (axi_transaction, (tok, output_memory, output_memory_id, transfered_bytes)): @@ -868,6 +868,36 @@ proc ZstdDecoderTest { trace_fmt!("ZstdDecTest: Handle AXI Write transaction #{}", axi_transaction); let (tok, axi_aw) = recv(tok, output_axi_aw_r); trace_fmt!("ZstdDecTest: Received AXI AW: {:#x}", axi_aw); + + let tok = send(tok, csr_axi_ar_s, CsrAxiAr { + addr: csr_addr(zstd_dec::Csr::STATUS), + id: uN[TEST_AXI_ID_W]:0, + size: axi::AxiAxSize::MAX_4B_TRANSFER, + len: u8:0, + burst: axi::AxiAxBurst::FIXED, + cache: axi::AxiArCache::DEV_BUF, + prot: u3:0, + qos: u4:0, + region: u4:0 + }); + let (tok, csr_response) = recv(tok, csr_axi_r_r); + trace_fmt!("ZstdDecTest: Received Csr status {:#x}", csr_response); + + let csr_status_data = csr_response.data as u5; + let csr_status = csr_status_data as zstd_dec::ZstdDecoderStatus; + let valid_state = match (csr_status) { + zstd_dec::ZstdDecoderStatus::FRAME_HEADER_CORRUPTED => false, + zstd_dec::ZstdDecoderStatus::FRAME_HEADER_UNSUPPORTED_WINDOW_SIZE => false, + zstd_dec::ZstdDecoderStatus::BLOCK_HEADER_CORRUPTED => false, + zstd_dec::ZstdDecoderStatus::BLOCK_HEADER_MEMORY_ACCESS_ERROR => false, + zstd_dec::ZstdDecoderStatus::RAW_BLOCK_ERROR => false, + _ => true + }; + + if !valid_state { + send(tok, finished_s, csr_status); + } else {}; + let (tok, internal_output_memory, internal_output_memory_id, internal_transfered_bytes) = for (axi_transfer, (tok, out_mem, out_mem_id, transf_bytes)): (u32, (token, uN[TEST_AXI_DATA_W][TEST_MOCK_OUTPUT_RAM_SIZE], u32, u32)) @@ -913,6 +943,168 @@ proc ZstdDecoderTest { tok }(tok); - send(tok, terminator, true); + send(tok, finished_s, zstd_dec::ZstdDecoderStatus::IDLE); + } +} + +#[test_proc] +proc UnsupportedWindowSizeTest { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + const FRAMES = comp_frame_unsupported_window::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame_unsupported_window::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::FRAME_HEADER_UNSUPPORTED_WINDOW_SIZE); + } +} + +#[test_proc] +proc RawLiteralsPredefinedSequencesTest { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + const FRAMES = comp_frame::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::IDLE); + } +} + +#[test_proc] +proc RleLiteralsRepeatedSequencesTest { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + + const FRAMES = comp_frame_fse_repeated::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame_fse_repeated::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::IDLE); + } +} + +// Tests with the `_skip` suffix are disabled in CI +// due to high memory usage and can be re-enabled +// when the DSLX interpreter becomes more memory-efficient. + +#[test_proc] +proc RawHuffmanLiteralsPredefinedSequencesTest_skip { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + const FRAMES = comp_frame_huffman::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame_huffman::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::IDLE); + } +} + +#[test_proc] +proc FseHuffmanLiteralsPredefinedSequencesTest_skip { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + const FRAMES = comp_frame_huffman_fse::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame_huffman_fse::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::IDLE); + } +} + +#[test_proc] +proc RawHuffmanLiteralsCompressedSequencesTest_skip { + terminator: chan out; + start_s: chan<()> out; + finished_r: chan in; + + init {} + + config (terminator: chan out,) { + + const FRAMES = comp_frame_fse_comp::FRAMES; + const DECOMPRESSED_FRAMES = comp_frame_fse_comp::DECOMPRESSED_FRAMES; + + let (start_s, start_r) = chan<()>("start"); + let (finished_s, finished_r) = chan("finished"); + + spawn ZstdDecoderTester(start_r, finished_s); + (terminator, start_s, finished_r) + } + + next(state: ()) { + let tok = send(join(), start_s, ()); + let (tok, result) = recv(tok, finished_r); + send(tok, terminator, result == zstd_dec::ZstdDecoderStatus::IDLE); } } diff --git a/xls/modules/zstd/zstd_enc.x b/xls/modules/zstd/zstd_enc.x new file mode 100644 index 0000000000..77a27f47c8 --- /dev/null +++ b/xls/modules/zstd/zstd_enc.x @@ -0,0 +1,952 @@ +// Copyright 2025 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 contains SIMPLIFIED implementation of ZstdEncoder +// for now assuming the following things +// 1. single frame +// 2. write N blocks of the same size (last is of different size) +// 3. the block data is RAW => so the produced file is just data + headers (1 + N headers) + +import std; + +import xls.examples.ram; +import xls.modules.zstd.match_finder; +import xls.modules.zstd.mem_copy; +import xls.modules.zstd.rle_block_encoder; +import xls.modules.zstd.frame_header_dec; +import xls.modules.zstd.frame_header_enc; +import xls.modules.zstd.block_header; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.common; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.block_size; +import xls.modules.zstd.comp_block_enc; + +pub enum ZstdEncodeRespStatus : u1 { + ERROR=0, + OK=1 +} + +pub struct ZstdEncodeParams { + enable_rle: bool, + enable_compressed: bool +} + +pub struct ZstdEncodeReq { + input_offset: uN[ADDR_W], // bytes + data_size: uN[DATA_W], + output_offset: uN[ADDR_W], // bytes + max_block_size: uN[DATA_W], // + params: ZstdEncodeParams +} + +pub struct ZstdEncodeResp { + status: ZstdEncodeRespStatus, + written_bytes: uN[ADDR_W], +} + +struct ZstdEncoderBlockWriterConf { + bytes_left: u32, + input_offset: uN[ADDR_W], + output_offset: uN[ADDR_W], + max_block_size: uN[DATA_W], + params: ZstdEncodeParams +} + +struct ZstdEncoderBlockWriterState { + active: bool, + written_bytes: uN[ADDR_W], + conf: ZstdEncoderBlockWriterConf, +} + +struct ZstdEncoderBlockWriterResp { + status: ZstdEncodeRespStatus, + length: uN[ADDR_W], +} + +const BLOCK_HEADER_LENGTH_BYTES = u32:3; +const ZSTD_WINDOW_ABSOLUTEMIN = u64:1024; + +pub proc ZstdEncoderBlockWriter { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + type Resp = ZstdEncoderBlockWriterResp; + type State = ZstdEncoderBlockWriterState; + type Conf = ZstdEncoderBlockWriterConf; + type Status = ZstdEncodeRespStatus; + + type BlockHeader = block_header::BlockHeader; + type BlockHeaderWriterReq = block_header::BlockHeaderWriterReq; + type BlockHeaderWriterResp = block_header::BlockHeaderWriterResp; + type BlockHeaderWriterStatus = block_header::BlockHeaderWriterStatus; + + type RawMemcopyReq = mem_copy::RawMemcopyReq; + type RawMemcopyResp = mem_copy::RawMemcopyResp; + type RawMemcopyRespStatus = mem_copy::RawMemcopyStatus; + + type RleBlockEncoderReq = rle_block_encoder::RleBlockEncoderReq; + type RleBlockEncoderResp = rle_block_encoder::RleBlockEncoderResp; + type RleBlockEncoderStatus = rle_block_encoder::RleBlockEncoderStatus; + + type CompressBlockEncoderReq = comp_block_enc::CompressBlockEncoderReq; + type CompressBlockEncoderResp = comp_block_enc::CompressBlockEncoderResp; + type CompressBlockEncoderStatus = comp_block_enc::CompressBlockEncoderStatus; + + type Addr = uN[ADDR_W]; + type Data = uN[DATA_W]; + type BlockType = common::BlockType; + type BlockSize = common::BlockSize; + + // parent I/O + conf_r: chan in; + resp_s: chan out; + + // block header + bhw_req_s: chan out; + bhw_resp_r: chan in; + + // block types + raw_req_s: chan out; + raw_resp_r: chan in; + rle_req_s: chan out; + rle_resp_r: chan in; + cbe_req_s: chan out; + cbe_resp_r: chan in; + + // general memory writing + rle_mem_wr_req_s: chan out; + rle_mem_wr_data_s: chan out; + rle_mem_wr_resp_r: chan in; + + init { zero!() } + config( + conf_r: chan in, + resp_s: chan out, + bhw_req_s: chan out, + bhw_resp_r: chan in, + raw_req_s: chan out, + raw_resp_r: chan in, + rle_req_s: chan out, + rle_resp_r: chan in, + cbe_req_s: chan out, + cbe_resp_r: chan in, + rle_mem_wr_req_s: chan out, + rle_mem_wr_data_s: chan out, + rle_mem_wr_resp_r: chan in + ) { + ( + conf_r, resp_s, + bhw_req_s, bhw_resp_r, + raw_req_s, raw_resp_r, + rle_req_s, rle_resp_r, + cbe_req_s, cbe_resp_r, + rle_mem_wr_req_s, rle_mem_wr_data_s, rle_mem_wr_resp_r + ) + } + next(state: State) { + if !state.active { + let (tok, conf) = recv(join(), conf_r); + State { + active: true, + conf: conf, + written_bytes: Addr:0, + } + } else { + let tok = join(); + let conf = state.conf; + let size = block_size::get_block_size(conf.bytes_left, conf.max_block_size as BlockSize); + // BlockSize calculation + // 1. Limit BlockSize value to rfc-defined and parameter-based max value, + // and reduce it further in case there's not much data left to compress + // * done by get_block_size + // 2. Try to split the input data by half or by fourth (TODO) + // * use samples of data from the beginning, middle and the end of the input + // * zstd C implementation uses 512 bytes from each of these parts + // * fingerprint comparison - calculate differences between the regions and split in halves + // in case the beginning and end differ significantly (with a threshold) + // * repeat the operation to split in fourths + // * the result is BlockSize, one of 32/64/96/128 KB depending on the differences in fingerprints + // * see `ZSTD_splitBlock_fromBorders` and `compareFingerprints` in zstd for reference + // * https://github.com/facebook/zstd/blob/d654fca78690fa15cceb8058ac47454d914a0e63/lib/compress/zstd_preSplit.c#L198 + // * https://github.com/facebook/zstd/blob/d654fca78690fa15cceb8058ac47454d914a0e63/lib/compress/zstd_preSplit.c#L110 + let last_block: bool = state.conf.bytes_left <= size as u32; + + // step 1: choose block type + let ( + tok, + btype, + rle_symbol + ) = + + if conf.params.enable_compressed { + (tok, BlockType::COMPRESSED, u8: 0) + } else if conf.params.enable_rle { + let tok = send(tok, rle_req_s, RleBlockEncoderReq { + addr: conf.input_offset, + length: size as uN[ADDR_W] + }); + + let (tok, rle_resp) = recv(tok, rle_resp_r); + let btype = if rle_resp.status == RleBlockEncoderStatus::OK { + BlockType::RLE + } else { + BlockType::RAW + }; + + (tok, btype, rle_resp.symbol) + } else { + (tok, BlockType::RAW, u8: 0) + }; + + // step 2: write block content + let block_content_offset = conf.output_offset + BLOCK_HEADER_LENGTH_BYTES; + let (tok2, blwr_status, block_content_size, block_header_size_field) = match btype { + BlockType::RLE => { + let tok2 = send(tok, rle_mem_wr_req_s, MemWriterReq { + addr: block_content_offset, length: Addr:1 + }); + let tok2 = send(tok2, rle_mem_wr_data_s, MemWriterData { + data: rle_symbol as Data, + length: Addr:1, + last: true + }); + trace_fmt!("writing rle pair: {:#x} -> {:#x} (symbol: {:#x} size: {})", conf.input_offset, block_content_offset, rle_symbol, size); + let (tok2, rle_resp) = recv(tok2, rle_mem_wr_resp_r); + let out_status = if rle_resp.status == MemWriterStatus::OKAY { Status::OK } else { Status::ERROR }; + (tok2, out_status, Addr:1, size as Addr) + }, + BlockType::RAW => { + let tok2 = send(tok, raw_req_s, RawMemcopyReq { + lit_addr: conf.input_offset, + lit_cnt: size as u32, + out_addr: block_content_offset + }); + trace_fmt!("raw copying: {:#x} -> {:#x} (size: {})", conf.input_offset, block_content_offset, size); + let (tok2, memcpy_resp) = recv(tok2, raw_resp_r); + trace_fmt!("received raw copy resp"); + let out_status = if memcpy_resp.status == RawMemcopyRespStatus::OK { Status::OK } else { Status::ERROR }; + (tok2, out_status, size as Addr, size as Addr) + }, + BlockType::COMPRESSED => { + let tok2 = send(tok, cbe_req_s, CompressBlockEncoderReq { + addr: conf.input_offset, + out_addr: block_content_offset, + size: size as Addr + }); + let (tok2, cbe_resp) = recv(tok2, cbe_resp_r); + let out_status = if cbe_resp.status == CompressBlockEncoderStatus::OK { Status::OK } else { Status::ERROR }; + (tok2, out_status, cbe_resp.length, cbe_resp.length) + }, + _ => { + trace_fmt!("Unsupported block type"); + (tok, Status::ERROR, Addr:0, Addr:0) + } + }; + + // step 3: write block header + let block_header_req = BlockHeaderWriterReq{ + addr: conf.output_offset, + header: BlockHeader { + last: last_block, + size: block_header_size_field as u21, + btype: btype + } + }; + let tok1 = send_if(tok, bhw_req_s, blwr_status == Status::OK, block_header_req); + trace_fmt!("writing block header to {:#x} == {}", conf.output_offset, block_header_req); + + let (tok1, bhw_resp) = recv_if(tok1, bhw_resp_r, blwr_status == Status::OK, zero!()); + + let status = if blwr_status == Status::OK && bhw_resp.status == BlockHeaderWriterStatus::OKAY { + Status::OK + } else { + trace_fmt!("failed writing block: {} {}", bhw_resp, blwr_status); + Status::ERROR + }; + + let written_bytes = block_content_size + BLOCK_HEADER_LENGTH_BYTES; + let total_written_bytes = state.written_bytes + written_bytes as Addr; + if last_block || status != ZstdEncodeRespStatus::OK { + let tok = send(join(tok1, tok2), resp_s, Resp {status, length: total_written_bytes}); + zero!() + } else { + State { + active: true, + written_bytes: total_written_bytes, + conf: Conf { + bytes_left: conf.bytes_left - size as u32, + input_offset: conf.input_offset as Addr + size as Addr, + output_offset: conf.output_offset as Addr + written_bytes as Addr, + ..conf + } + } + } + } + } +} + +pub proc ZstdEncoder< + ADDR_W: u32, DATA_W: u32, + // rle + RLE_HEURISTIC_SAMPLE_COUNT: u32, + // compressed blocks params + HB_SIZE: u32, HB_DATA_W: u32, HB_OFFSET_W: u32, HB_RAM_ADDR_W: u32, HB_RAM_DATA_W: u32, HB_RAM_NUM: u32, HB_RAM_NUM_PARTITIONS: u32, + HT_SIZE: u32, HT_KEY_W: u32, HT_VALUE_W: u32, HT_SIZE_W: u32, HT_HASH_W: u32, HT_RAM_DATA_W: u32, HT_RAM_NUM_PARTITIONS: u32, + MIN_SEQ_LEN: u32, LITERALS_BUFFER_AXI_ADDR: u32, SEQUENCE_BUFFER_AXI_ADDR: u32, + FSE_TABLE_RAM_ADDR_W: u32, FSE_CTABLE_RAM_DATA_W: u32, FSE_TTABLE_RAM_DATA_W: u32, + FSE_CTABLE_RAM_NUM_PARTITIONS: u32, FSE_TTABLE_RAM_NUM_PARTITIONS: u32, + FSE_BITSTREAM_BUFFER_W: u32 +> { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + + type Req = ZstdEncodeReq; + type Resp = ZstdEncodeResp; + type ZstdEncoderBlockWriterConf = ZstdEncoderBlockWriterConf; + type ZstdEncoderBlockWriterResp = ZstdEncoderBlockWriterResp; + type Status = ZstdEncodeRespStatus; + + type FrameHeader = frame_header_dec::FrameHeader; + type FrameHeaderEncoderReq = frame_header_enc::FrameHeaderEncoderReq; + type FrameHeaderEncoderResp = frame_header_enc::FrameHeaderEncoderResp; + type FrameHeaderEncoderStatus = frame_header_enc::FrameHeaderEncoderStatus; + + type BlockHeader = block_header::BlockHeader; + type BlockHeaderWriterReq = block_header::BlockHeaderWriterReq; + type BlockHeaderWriterResp = block_header::BlockHeaderWriterResp; + type BlockHeaderWriterStatus = block_header::BlockHeaderWriterStatus; + + type RawMemcopyReq = mem_copy::RawMemcopyReq; + type RawMemcopyResp = mem_copy::RawMemcopyResp; + type RawMemcopyRespStatus = mem_copy::RawMemcopyStatus; + + type RleBlockEncoderReq = rle_block_encoder::RleBlockEncoderReq; + type RleBlockEncoderResp = rle_block_encoder::RleBlockEncoderResp; + type RleBlockEncoderStatus = rle_block_encoder::RleBlockEncoderStatus; + + type CompressBlockEncoderReq = comp_block_enc::CompressBlockEncoderReq; + type CompressBlockEncoderResp = comp_block_enc::CompressBlockEncoderResp; + type CompressBlockEncoderStatus = comp_block_enc::CompressBlockEncoderStatus; + + type MfResp = match_finder::MatchFinderResp; + type MfReq = match_finder::MatchFinderReq; + type MfRespStatus = match_finder::MatchFinderRespStatus; + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + + type CTableRamRdReq = ram::ReadReq; + type CTableRamRdResp = ram::ReadResp; + type TTableRamRdReq = ram::ReadReq; + type TTableRamRdResp = ram::ReadResp; + + // from + enc_req: chan in; + enc_resp_s: chan out; + + // communication + conf_s: chan out; + bw_resp_r: chan in; + fhw_req_s: chan out; + fhw_resp_r: chan in; + + init { } + + config( + enc_req_r: chan in, + enc_resp_s: chan out, + + // writers + fhw_mem_wr_req_s: chan out, + fhw_mem_wr_data_s: chan out, + fhw_mem_wr_resp_r: chan in, + bhw_mem_wr_req_s: chan out, + bhw_mem_wr_data_s: chan out, + bhw_mem_wr_resp_r: chan in, + braw_mem_wr_req_s: chan out, + braw_mem_wr_data_s: chan out, + braw_mem_wr_resp_r: chan in, + brle_mem_wr_req_s: chan out, + brle_mem_wr_data_s: chan out, + brle_mem_wr_resp_r: chan in, + bcomp_lhw_mem_wr_req_s: chan out, + bcomp_lhw_mem_wr_data_s: chan out, + bcomp_lhw_mem_wr_resp_r: chan in, + bcomp_le_mem_wr_req_s: chan out, + bcomp_le_mem_wr_data_s: chan out, + bcomp_le_mem_wr_resp_r: chan in, + bcomp_se_mem_wr_req_s: chan out, + bcomp_se_mem_wr_data_s: chan out, + bcomp_se_mem_wr_resp_r: chan in, + bcomp_mf_buf_mem_wr_req_s: chan out, + bcomp_mf_buf_mem_wr_data_s: chan out, + bcomp_mf_buf_mem_wr_resp_r: chan in, + + // readers + braw_mem_rd_req_s: chan out, + braw_mem_rd_resp_r: chan in, + brle_mem_rd_req_s: chan out, + brle_mem_rd_resp_r: chan in, + // should be a separate buffer + bcomp_mf_mem_rd_req_s: chan out, + bcomp_mf_mem_rd_resp_r: chan in, + bcomp_mf_buf_mem_rd_req_s: chan out, + bcomp_mf_buf_mem_rd_resp_r: chan in, + + // buffers (match finder, history buffer, hash table) + hb_ram_rd_req_s: chan[HB_RAM_NUM] out, + hb_ram_rd_resp_r: chan[HB_RAM_NUM] in, + hb_ram_wr_req_s: chan[HB_RAM_NUM] out, + hb_ram_wr_resp_r: chan[HB_RAM_NUM] in, + ht_ram_rd_req_s: chan out, + ht_ram_rd_resp_r: chan in, + ht_ram_wr_req_s: chan out, + ht_ram_wr_resp_r: chanin, + ml_ctable_ram_rd_req_s: chan out, + ml_ctable_ram_rd_resp_r: chan in, + ll_ctable_ram_rd_req_s: chan out, + ll_ctable_ram_rd_resp_r: chan in, + of_ctable_ram_rd_req_s: chan out, + of_ctable_ram_rd_resp_r: chan in, + ml_ttable_ram_rd_req_s: chan out, + ml_ttable_ram_rd_resp_r: chan in, + ll_ttable_ram_rd_req_s: chan out, + ll_ttable_ram_rd_resp_r: chan in, + of_ttable_ram_rd_req_s: chan out, + of_ttable_ram_rd_resp_r: chan in + ) { + // internal + let (conf_s, conf_r) = chan("conf"); + let (bw_resp_s, bw_resp_r) = chan("bw_resp"); + + // headers + let (fhw_req_s, fhw_req_r) = chan("bhw_req"); + let (fhw_resp_s, fhw_resp_r) = chan("bhw_resp"); + let (bhw_req_s, bhw_req_r) = chan("bhw_req"); + let (bhw_resp_s, bhw_resp_r) = chan("bhw_resp"); + + // block types + let (raw_req_s, raw_req_r) = chan("braw_req"); + let (raw_resp_s, raw_resp_r) = chan("braw_resp"); + let (rle_req_s, rle_req_r) = chan("brle_req"); + let (rle_resp_s, rle_resp_r) = chan("brle_resp"); + let (cbe_req_s, cbe_req_r) = chan("cbe_req"); + let (cbe_resp_s, cbe_resp_r) = chan("cbe_resp"); + + spawn ZstdEncoderBlockWriter + ( + conf_r, bw_resp_s, + bhw_req_s, bhw_resp_r, + raw_req_s, raw_resp_r, + rle_req_s, rle_resp_r, + cbe_req_s, cbe_resp_r, + brle_mem_wr_req_s, brle_mem_wr_data_s, brle_mem_wr_resp_r + ); + + spawn frame_header_enc::FrameHeaderEncoder + ( + fhw_req_r, fhw_resp_s, + fhw_mem_wr_req_s, fhw_mem_wr_data_s, fhw_mem_wr_resp_r + ); + + spawn block_header::BlockHeaderWriter + ( + bhw_req_r, bhw_resp_s, + bhw_mem_wr_req_s, bhw_mem_wr_data_s, bhw_mem_wr_resp_r + ); + + spawn mem_copy::RawMemcopy + ( + raw_req_r, raw_resp_s, + braw_mem_rd_req_s, braw_mem_rd_resp_r, + braw_mem_wr_req_s, braw_mem_wr_data_s, braw_mem_wr_resp_r + ); + + spawn rle_block_encoder::RleBlockEncoder + ( + rle_req_r, rle_resp_s, + brle_mem_rd_req_s, brle_mem_rd_resp_r + ); + + spawn comp_block_enc::CompressBlockEncoder< + ADDR_W, DATA_W, + HB_SIZE, HB_DATA_W, HB_OFFSET_W, HB_RAM_ADDR_W, HB_RAM_DATA_W, HB_RAM_NUM, HB_RAM_NUM_PARTITIONS, + HT_SIZE, HT_KEY_W, HT_VALUE_W, HT_SIZE_W, HT_HASH_W, HT_RAM_DATA_W, HT_RAM_NUM_PARTITIONS, + MIN_SEQ_LEN, LITERALS_BUFFER_AXI_ADDR, SEQUENCE_BUFFER_AXI_ADDR, + FSE_TABLE_RAM_ADDR_W, FSE_CTABLE_RAM_DATA_W, FSE_TTABLE_RAM_DATA_W, + FSE_CTABLE_RAM_NUM_PARTITIONS, FSE_TTABLE_RAM_NUM_PARTITIONS, + FSE_BITSTREAM_BUFFER_W + > ( + cbe_req_r, cbe_resp_s, + bcomp_mf_mem_rd_req_s, bcomp_mf_mem_rd_resp_r, + bcomp_mf_buf_mem_rd_req_s, bcomp_mf_buf_mem_rd_resp_r, + bcomp_mf_buf_mem_wr_req_s, bcomp_mf_buf_mem_wr_data_s, bcomp_mf_buf_mem_wr_resp_r, + hb_ram_rd_req_s, hb_ram_rd_resp_r, + hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, + ht_ram_wr_req_s, ht_ram_wr_resp_r, + bcomp_lhw_mem_wr_req_s, bcomp_lhw_mem_wr_data_s, bcomp_lhw_mem_wr_resp_r, + bcomp_le_mem_wr_req_s, bcomp_le_mem_wr_data_s, bcomp_le_mem_wr_resp_r, + bcomp_se_mem_wr_req_s, bcomp_se_mem_wr_data_s, bcomp_se_mem_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + ( + enc_req_r, enc_resp_s, + conf_s, bw_resp_r, + fhw_req_s, fhw_resp_r + ) + } + + next(state: ()) { + let (tok, request) = recv(join(), enc_req); + let _window_size = ZSTD_WINDOW_ABSOLUTEMIN; // TODO: Calculate the window size based on the frame content + trace_fmt!("writing frame header to {:#x}", request.output_offset); + + let tok = send(tok, fhw_req_s, FrameHeaderEncoderReq { + addr: request.output_offset, + window_log: u5:22, // TODO: Calculate window log based on window size + src_size: request.data_size as u64, + dict_id: u32:0, + max_block_size: request.max_block_size as u64, + provide_dict_id: false, + provide_checksum: false, + provide_content_size: true, + provide_window_size: true, + }); + let (tok, fhw_resp) = recv(tok, fhw_resp_r); + trace_fmt!("written frame header {:#x}", fhw_resp); + + if (fhw_resp.status != FrameHeaderEncoderStatus::OKAY) { + trace_fmt!("failed writing frame header"); + send(tok, enc_resp_s, ZstdEncodeResp{ + status: ZstdEncodeRespStatus::ERROR, + written_bytes: uN[ADDR_W]:0 + }); + } else { + let tok = send(tok, conf_s, ZstdEncoderBlockWriterConf { + bytes_left: request.data_size as u32, + input_offset: request.input_offset, + output_offset: request.output_offset + fhw_resp.length as uN[ADDR_W], + max_block_size: request.max_block_size, + params: request.params + }); + let (tok, bw_resp) = recv(tok, bw_resp_r); + let resp = ZstdEncodeResp{ + status: bw_resp.status, + written_bytes: fhw_resp.length as uN[ADDR_W] + bw_resp.length, + }; + send(tok, enc_resp_s, resp); + }; + } +} + + +const INST_ADDR_W = u32:32; +const INST_DATA_W = u32:64; +const INST_RLE_HEURISTIC_SAMPLE_COUNT = u32:8; +const INST_DATA_W_LOG2 = std::clog2(INST_DATA_W + u32:1); +const INST_DEST_W = u32:8; +const INST_ID_W = u32:8; + +// sequence encoding +const INST_MIN_SEQ_LEN = u32:3; +const INST_HT_SIZE = u32:512; +const INST_HT_SIZE_W = std::clog2(INST_HT_SIZE + u32:1); +const INST_HT_KEY_W = u32:32; +const INST_HT_VALUE_W = INST_HT_KEY_W + INST_ADDR_W; +const INST_HT_HASH_W = std::clog2(INST_HT_SIZE); +const INST_HT_RAM_DATA_W = INST_HT_VALUE_W + u32:1; +const INST_HT_RAM_WORD_PARTITION_SIZE = u32:1; +const INST_HT_RAM_NUM_PARTITIONS = ram::num_partitions(INST_HT_RAM_WORD_PARTITION_SIZE, INST_HT_RAM_DATA_W); +const INST_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const INST_HT_RAM_INITIALIZED = true; + +const INST_LITERALS_BUFFER_AXI_ADDR = u32:0x10000; +const INST_SEQUENCE_BUFFER_AXI_ADDR = u32:0x20000; +const INST_HB_DATA_W = u32:64; +const INST_HB_SIZE = u32:1024; +const INST_HB_OFFSET_W = std::clog2(INST_HB_SIZE); +const INST_HB_RAM_NUM = u32:8; +const INST_HB_RAM_SIZE = INST_HB_SIZE / INST_HB_RAM_NUM; +const INST_HB_RAM_DATA_W = INST_HB_DATA_W / INST_HB_RAM_NUM; +const INST_HB_RAM_ADDR_W = std::clog2(INST_HB_RAM_SIZE); +const INST_HB_RAM_PARTITION_SIZE = INST_HB_RAM_DATA_W; +const INST_HB_RAM_NUM_PARTITIONS = ram::num_partitions(INST_HB_RAM_PARTITION_SIZE, INST_HB_RAM_DATA_W); +const INST_FSE_TABLE_RAM_ADDR_W = u32:32; +const INST_FSE_CTABLE_RAM_DATA_W = u32:16; +const INST_FSE_TTABLE_RAM_DATA_W = u32:64; +const INST_FSE_TTABLE_RAM_PARTITION_SIZE = u32:8; +const INST_FSE_TABLE_PARTITION_SIZE = u32:8; +const INST_FSE_CTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(INST_FSE_TABLE_PARTITION_SIZE, INST_FSE_CTABLE_RAM_DATA_W); +const INST_FSE_TTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(INST_FSE_TABLE_PARTITION_SIZE, INST_FSE_TTABLE_RAM_DATA_W); +const INST_FSE_BITSTREAM_BUFFER_W = u32:1024; + +proc ZstdEncoderInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + type CTableRamRdReq = ram::ReadReq; + type CTableRamRdResp = ram::ReadResp; + type TTableRamRdReq = ram::ReadReq; + type TTableRamRdResp = ram::ReadResp; + type Req = ZstdEncodeReq; + type Resp = ZstdEncodeResp; + + init {} + + config( + enc_req_r: chan in, + enc_resp_s: chan out, + fhw_mem_wr_req_s: chan out, + fhw_mem_wr_data_s: chan out, + fhw_mem_wr_resp_r: chan in, + bhw_mem_wr_req_s: chan out, + bhw_mem_wr_data_s: chan out, + bhw_mem_wr_resp_r: chan in, + braw_mem_wr_req_s: chan out, + braw_mem_wr_data_s: chan out, + braw_mem_wr_resp_r: chan in, + brle_mem_wr_req_s: chan out, + brle_mem_wr_data_s: chan out, + brle_mem_wr_resp_r: chan in, + bcomp_lhw_mem_wr_req_s: chan out, + bcomp_lhw_mem_wr_data_s: chan out, + bcomp_lhw_mem_wr_resp_r: chan in, + bcomp_le_output_mem_wr_req_s: chan out, + bcomp_le_output_mem_wr_data_s: chan out, + bcomp_le_output_mem_wr_resp_r: chan in, + bcomp_se_output_mem_wr_req_s: chan out, + bcomp_se_output_mem_wr_data_s: chan out, + bcomp_se_output_mem_wr_resp_r: chan in, + bcomp_mf_buf_mem_wr_req_s: chan out, + bcomp_mf_buf_mem_wr_data_s: chan out, + bcomp_mf_buf_mem_wr_resp_r: chan in, + braw_mem_rd_req_s: chan out, + braw_mem_rd_resp_r: chan in, + brle_mem_rd_req_s: chan out, + brle_mem_rd_resp_r: chan in, + bcomp_mf_mem_rd_req_s: chan out, + bcomp_mf_mem_rd_resp_r: chan in, + bcomp_mf_buf_mem_rd_req_s: chan out, + bcomp_mf_buf_mem_rd_resp_r: chan in, + hb_ram_rd_req_s: chan[INST_HB_RAM_NUM] out, + hb_ram_rd_resp_r: chan[INST_HB_RAM_NUM] in, + hb_ram_wr_req_s: chan[INST_HB_RAM_NUM] out, + hb_ram_wr_resp_r: chan[INST_HB_RAM_NUM] in, + ht_ram_rd_req_s: chan out, + ht_ram_rd_resp_r: chan in, + ht_ram_wr_req_s: chan out, + ht_ram_wr_resp_r: chanin, + ml_ctable_ram_rd_req_s: chan out, + ml_ctable_ram_rd_resp_r: chan in, + ll_ctable_ram_rd_req_s: chan out, + ll_ctable_ram_rd_resp_r: chan in, + of_ctable_ram_rd_req_s: chan out, + of_ctable_ram_rd_resp_r: chan in, + ml_ttable_ram_rd_req_s: chan out, + ml_ttable_ram_rd_resp_r: chan in, + ll_ttable_ram_rd_req_s: chan out, + ll_ttable_ram_rd_resp_r: chan in, + of_ttable_ram_rd_req_s: chan out, + of_ttable_ram_rd_resp_r: chan in + ) { + spawn ZstdEncoder ( + enc_req_r, enc_resp_s, + fhw_mem_wr_req_s, fhw_mem_wr_data_s, fhw_mem_wr_resp_r, + bhw_mem_wr_req_s, bhw_mem_wr_data_s, bhw_mem_wr_resp_r, + braw_mem_wr_req_s,braw_mem_wr_data_s,braw_mem_wr_resp_r, + brle_mem_wr_req_s,brle_mem_wr_data_s,brle_mem_wr_resp_r, + bcomp_lhw_mem_wr_req_s, bcomp_lhw_mem_wr_data_s, bcomp_lhw_mem_wr_resp_r, + bcomp_le_output_mem_wr_req_s, bcomp_le_output_mem_wr_data_s, bcomp_le_output_mem_wr_resp_r, + bcomp_se_output_mem_wr_req_s, bcomp_se_output_mem_wr_data_s, bcomp_se_output_mem_wr_resp_r, + bcomp_mf_buf_mem_wr_req_s, bcomp_mf_buf_mem_wr_data_s, bcomp_mf_buf_mem_wr_resp_r, + braw_mem_rd_req_s, braw_mem_rd_resp_r, + brle_mem_rd_req_s, brle_mem_rd_resp_r, + bcomp_mf_mem_rd_req_s, bcomp_mf_mem_rd_resp_r, + bcomp_mf_buf_mem_rd_req_s, bcomp_mf_buf_mem_rd_resp_r, + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + } + + next(state: ()) { } +} + + +const COCOTB_ADDR_W = u32:32; +const COCOTB_DATA_W = u32:32; +const COCOTB_RLE_HEURISTIC_SAMPLE_COUNT = u32:8; +const COCOTB_DATA_W_LOG2 = std::clog2(COCOTB_DATA_W + u32:1); +const COCOTB_DEST_W = u32:8; +const COCOTB_ID_W = u32:8; +const COCOTB_RAM_PARTITION_SIZE = COCOTB_DATA_W / u32:8; +const COCOTB_MEM_WRITER_ID = u32:0; + +// sequence encoding +const COCOTB_MIN_SEQ_LEN = u32:3; +const COCOTB_HT_SIZE = u32:512; +const COCOTB_HT_SIZE_W = std::clog2(COCOTB_HT_SIZE + u32:1); +const COCOTB_HT_KEY_W = u32:32; +const COCOTB_HT_VALUE_W = COCOTB_HT_KEY_W + COCOTB_ADDR_W; +const COCOTB_HT_HASH_W = std::clog2(COCOTB_HT_SIZE); +const COCOTB_HT_RAM_DATA_W = COCOTB_HT_VALUE_W + u32:1; +const COCOTB_HT_RAM_WORD_PARTITION_SIZE = u32:1; +const COCOTB_HT_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_HT_RAM_WORD_PARTITION_SIZE, COCOTB_HT_RAM_DATA_W); +const COCOTB_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const COCOTB_HT_RAM_INITIALIZED = true; + +const COCOTB_LITERALS_BUFFER_AXI_ADDR = u32:0x10000; +const COCOTB_SEQUENCE_BUFFER_AXI_ADDR = u32:0x20000; +const COCOTB_HB_DATA_W = u32:64; +const COCOTB_HB_SIZE = u32:1024; +const COCOTB_HB_OFFSET_W = std::clog2(COCOTB_HB_SIZE); +const COCOTB_HB_RAM_NUM = u32:8; +const COCOTB_HB_RAM_SIZE = COCOTB_HB_SIZE / COCOTB_HB_RAM_NUM; +const COCOTB_HB_RAM_DATA_W = COCOTB_HB_DATA_W / COCOTB_HB_RAM_NUM; +const COCOTB_HB_RAM_ADDR_W = std::clog2(COCOTB_HB_RAM_SIZE); +const COCOTB_HB_RAM_PARTITION_SIZE = COCOTB_HB_RAM_DATA_W; +const COCOTB_HB_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_HB_RAM_PARTITION_SIZE, COCOTB_HB_RAM_DATA_W); +const COCOTB_FSE_TABLE_RAM_ADDR_W = u32:32; +const COCOTB_FSE_CTABLE_RAM_DATA_W = u32:16; +const COCOTB_FSE_TTABLE_RAM_DATA_W = u32:64; +const COCOTB_FSE_TTABLE_RAM_PARTITION_SIZE = u32:8; +const COCOTB_FSE_TABLE_PARTITION_SIZE = u32:8; +const COCOTB_FSE_CTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_FSE_TABLE_PARTITION_SIZE, COCOTB_FSE_CTABLE_RAM_DATA_W); +const COCOTB_FSE_TTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(COCOTB_FSE_TABLE_PARTITION_SIZE, COCOTB_FSE_TTABLE_RAM_DATA_W); +const COCOTB_FSE_BITSTREAM_BUFFER_W = u32:1024; + +proc ZstdEncoderCocotbInst { + type MemReaderReq = mem_reader::MemReaderReq; + type MemReaderResp = mem_reader::MemReaderResp; + type MemWriterReq = mem_writer::MemWriterReq; + type MemWriterData = mem_writer::MemWriterDataPacket; + type MemWriterResp = mem_writer::MemWriterResp; + type MemWriterStatus = mem_writer::MemWriterRespStatus; + type HistoryBufferRamRdReq = ram::ReadReq; + type HistoryBufferRamRdResp = ram::ReadResp; + type HistoryBufferRamWrReq = ram::WriteReq; + type HistoryBufferRamWrResp = ram::WriteResp; + type HashTableRamRdReq = ram::ReadReq; + type HashTableRamRdResp = ram::ReadResp; + type HashTableRamWrReq = ram::WriteReq; + type HashTableRamWrResp = ram::WriteResp; + type CTableRamRdReq = ram::ReadReq; + type CTableRamRdResp = ram::ReadResp; + type TTableRamRdReq = ram::ReadReq; + type TTableRamRdResp = ram::ReadResp; + type CTableRamWrReq = ram::WriteReq; + type CTableRamWrResp = ram::WriteResp; + type TTableRamWrReq = ram::WriteReq; + type TTableRamWrResp = ram::WriteResp; + type Req = ZstdEncodeReq; + type Resp = ZstdEncodeResp; + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + init {} + + ml_ctable_ram_wr_req_s: chan out; + ml_ctable_ram_wr_resp_r: chan in; + ll_ctable_ram_wr_req_s: chan out; + ll_ctable_ram_wr_resp_r: chan in; + of_ctable_ram_wr_req_s: chan out; + of_ctable_ram_wr_resp_r: chan in; + ml_ttable_ram_wr_req_s: chan out; + ml_ttable_ram_wr_resp_r: chan in; + ll_ttable_ram_wr_req_s: chan out; + ll_ttable_ram_wr_resp_r: chan in; + of_ttable_ram_wr_req_s: chan out; + of_ttable_ram_wr_resp_r: chan in; + + config( + enc_req_r: chan in, + enc_resp_s: chan out, + axi_aw_s: chan out, + axi_w_s: chan out, + axi_b_r: chan in, + axi_ar_s: chan out, + axi_r_r: chan in, + hb_ram_rd_req_s: chan[COCOTB_HB_RAM_NUM] out, + hb_ram_rd_resp_r: chan[COCOTB_HB_RAM_NUM] in, + hb_ram_wr_req_s: chan[COCOTB_HB_RAM_NUM] out, + hb_ram_wr_resp_r: chan[COCOTB_HB_RAM_NUM] in, + ht_ram_rd_req_s: chan out, + ht_ram_rd_resp_r: chan in, + ht_ram_wr_req_s: chan out, + ht_ram_wr_resp_r: chanin, + ml_ctable_ram_rd_req_s: chan out, + ml_ctable_ram_rd_resp_r: chan in, + ll_ctable_ram_rd_req_s: chan out, + ll_ctable_ram_rd_resp_r: chan in, + of_ctable_ram_rd_req_s: chan out, + of_ctable_ram_rd_resp_r: chan in, + ml_ttable_ram_rd_req_s: chan out, + ml_ttable_ram_rd_resp_r: chan in, + ll_ttable_ram_rd_req_s: chan out, + ll_ttable_ram_rd_resp_r: chan in, + of_ttable_ram_rd_req_s: chan out, + of_ttable_ram_rd_resp_r: chan in, + ml_ctable_ram_wr_req_s: chan out, + ml_ctable_ram_wr_resp_r: chan in, + ll_ctable_ram_wr_req_s: chan out, + ll_ctable_ram_wr_resp_r: chan in, + of_ctable_ram_wr_req_s: chan out, + of_ctable_ram_wr_resp_r: chan in, + ml_ttable_ram_wr_req_s: chan out, + ml_ttable_ram_wr_resp_r: chan in, + ll_ttable_ram_wr_req_s: chan out, + ll_ttable_ram_wr_resp_r: chan in, + of_ttable_ram_wr_req_s: chan out, + of_ttable_ram_wr_resp_r: chan in + ){ + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[8]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[8]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[8]("n_resp"); + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[4]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[4]("n_mem_rd_resp"); + + spawn mem_reader::MemReader< + COCOTB_DATA_W, COCOTB_ADDR_W, COCOTB_DEST_W, COCOTB_ID_W, + >( + mem_rd_req_r, mem_rd_resp_s, + axi_ar_s, axi_r_r, + ); + spawn mem_writer::MemWriter< + COCOTB_ADDR_W, COCOTB_DATA_W, COCOTB_DEST_W, COCOTB_ID_W, COCOTB_MEM_WRITER_ID + >( + mem_wr_req_r, mem_wr_data_r, + axi_aw_s, axi_w_s, axi_b_r, + mem_wr_resp_s + ); + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn ZstdEncoder ( + enc_req_r, enc_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3], + n_mem_wr_req_s[4], n_mem_wr_data_s[4], n_mem_wr_resp_r[4], + n_mem_wr_req_s[5], n_mem_wr_data_s[5], n_mem_wr_resp_r[5], + n_mem_wr_req_s[6], n_mem_wr_data_s[6], n_mem_wr_resp_r[6], + n_mem_wr_req_s[7], n_mem_wr_data_s[7], n_mem_wr_resp_r[7], + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + n_mem_rd_req_s[3], n_mem_rd_resp_r[3], + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + ( + ml_ctable_ram_wr_req_s, ml_ctable_ram_wr_resp_r, + ll_ctable_ram_wr_req_s, ll_ctable_ram_wr_resp_r, + of_ctable_ram_wr_req_s, of_ctable_ram_wr_resp_r, + ml_ttable_ram_wr_req_s, ml_ttable_ram_wr_resp_r, + ll_ttable_ram_wr_req_s, ll_ttable_ram_wr_resp_r, + of_ttable_ram_wr_req_s, of_ttable_ram_wr_resp_r + ) + } + + next(state: ()) { + let tok = join(); + send_if(tok, ml_ctable_ram_wr_req_s, false, zero!()); + send_if(tok, ll_ctable_ram_wr_req_s, false, zero!()); + send_if(tok, of_ctable_ram_wr_req_s, false, zero!()); + send_if(tok, ml_ttable_ram_wr_req_s, false, zero!()); + send_if(tok, ll_ttable_ram_wr_req_s, false, zero!()); + send_if(tok, of_ttable_ram_wr_req_s, false, zero!()); + recv_if(tok, ml_ctable_ram_wr_resp_r, false, zero!()); + recv_if(tok, ll_ctable_ram_wr_resp_r, false, zero!()); + recv_if(tok, of_ctable_ram_wr_resp_r, false, zero!()); + recv_if(tok, ml_ttable_ram_wr_resp_r, false, zero!()); + recv_if(tok, ll_ttable_ram_wr_resp_r, false, zero!()); + recv_if(tok, of_ttable_ram_wr_resp_r, false, zero!()); + } +} diff --git a/xls/modules/zstd/zstd_enc_cocotb_test.py b/xls/modules/zstd/zstd_enc_cocotb_test.py new file mode 100644 index 0000000000..923307950f --- /dev/null +++ b/xls/modules/zstd/zstd_enc_cocotb_test.py @@ -0,0 +1,259 @@ +#!/usr/bin/env python +# Copyright 2025 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 random +import cocotb +import cocotbext.axi.axi_channels as axi + +from inspect import currentframe +from pathlib import Path +from cocotb.clock import Clock +from cocotb.triggers import Event, RisingEdge +from xls.modules.zstd.cocotb.channel import ( + XLSChannel, + XLSChannelDriver, + XLSChannelMonitor, +) +from xls.modules.zstd.cocotb.memory import AxiRamFromArray +from xls.modules.zstd.cocotb.utils import reset, run_test, connect_axi_bus +from xls.modules.zstd.cocotb.xlsstruct import XLSStruct, xls_dataclass +from xls.modules.zstd.cocotb.data_generator import DecompressFrame + + +DATA_W = 32 +ADDR_W = 32 +PARAMS_W = 1 +STATUS_W = 1 +LAST_W = 1 +STATUS_W = 1 +ERROR_W = 1 +ID_W = 4 +DEST_W = 4 +HT_SIZE_W = 10 + +MEM_SIZE = 0x100000 +OBUF_ADDR = 0x1000 +INPUT_RANGE = (0, 10) +INPUT_SIZE = 0x1000 + +signal_widths = {"bresp": 3} +axi.AxiBBus._signal_widths = signal_widths +axi.AxiBTransaction._signal_widths = signal_widths +axi.AxiBSource._signal_widths = signal_widths +axi.AxiBSink._signal_widths = signal_widths +axi.AxiBMonitor._signal_widths = signal_widths +signal_widths = {"rresp": 3, "rlast": 1} +axi.AxiRBus._signal_widths = signal_widths +axi.AxiRTransaction._signal_widths = signal_widths +axi.AxiRSource._signal_widths = signal_widths +axi.AxiRSink._signal_widths = signal_widths +axi.AxiRMonitor._signal_widths = signal_widths + +@xls_dataclass +class Req(XLSStruct): + input_offset: ADDR_W + data_size: DATA_W + output_offset: ADDR_W + max_block_size: DATA_W + enable_rle: PARAMS_W + enable_compressed: PARAMS_W + +@xls_dataclass +class Resp(XLSStruct): + status: STATUS_W + written_bytes: ADDR_W + +def set_termination_event(monitor, event, transactions): + def terminate_cb(_): + if monitor.stats.received_transactions == transactions: + event.set() + monitor.add_callback(terminate_cb) + +def generate_random_bytes(): + return bytearray([random.randint(*INPUT_RANGE) for _ in range(INPUT_SIZE)]) + +def generate_single_byte(): + return bytearray([0x42 for _ in range(INPUT_SIZE)]) + +async def testcase(dut, params, input_data, max_block_size = 128): + dut.rst.setimmediatevalue(0) + clock = Clock(dut.clk, 10, units="us") + cocotb.start_soon(clock.start()) + + # setup input data + memory = AxiRamFromArray(connect_axi_bus(dut, "memory"), dut.clk, dut.rst, arr=input_data, size=MEM_SIZE) + req = Req( + input_offset=0x0, + data_size=len(input_data), + output_offset=OBUF_ADDR, + max_block_size=max_block_size, + **params + ) + + # channels + ch_resp = XLSChannel(dut, "resp_s", dut.clk, start_now=True) + drv_req = XLSChannelDriver(dut, "req_r", dut.clk) + # mon_req = XLSChannelMonitor(dut, "req_r", dut.clk, Req) + # mon_resp = XLSChannelMonitor(dut, "resp_s", dut.clk, Resp) + terminate = Event() + # set_termination_event(mon_resp, terminate, 1) + + # run benchmark + await reset(dut.clk, dut.rst, cycles=10) + await cocotb.start(drv_req.send(req)) + + while True: + await RisingEdge(dut.clk) + if ch_resp.rdy.value and ch_resp.vld.value: + resp = Resp.from_int(ch_resp.data.value.integer) + break; + + with open("input.bin", "wb") as f: + f.write(input_data) + + mem_contents = memory.read(OBUF_ADDR, resp.written_bytes) + with open("result.zst", "wb") as f: + f.write(mem_contents) + + dctx = DecompressFrame(mem_contents) + + for i in range(len(dctx)): + print(f"comparing {hex(dctx[i])}=={hex(input_data[i])}") + assert dctx[i] == input_data[i] + +PREGENERATED_FILES_DIR = '../xls/modules/zstd/data/' + +async def testcase_pregenerated(dut, filename, max_block_size, params): + with open(PREGENERATED_FILES_DIR + filename, "rb") as f: + input_data = f.read() + input_data = bytearray(input_data) + await testcase( + dut, + params, + input_data, + max_block_size + ) + +@cocotb.test(timeout_time=1000, timeout_unit="ms") +async def raw_block_test(dut): + await testcase( + dut, + params={ + "enable_rle": False, + "enable_compressed": False + }, + input_data=generate_random_bytes() + ) + +@cocotb.test(timeout_time=1000, timeout_unit="ms") +async def rle_block_test(dut): + await testcase( + dut, + params={ + "enable_rle": True, + "enable_compressed": False + }, + input_data=generate_single_byte() + ) + +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def comp_block_test(dut): + random.seed(42) # for reproducibility + await testcase( + dut, + params={ + "enable_rle": False, + "enable_compressed": True + }, + input_data=generate_random_bytes(), + max_block_size=0x400 + ) + +def parse_decl(frame): + fname = frame.f_code.co_name + tokens = fname.split("_") + filename = f"enc_{tokens[0]}_{tokens[1]}" + max_block_size = int(tokens[3][:-1]) + mode = tokens[4] + params = { + "enable_rle": mode == "rle", + "enable_compressed": mode == "compressed" + } + return filename, max_block_size, params + +# pregenerated testcases +# convention: +# pregenerated_B_block_B_ +# input_size should match one of the input sizes available in xls/modules/zstd/data +# mode should be one of: +# - compressed +# - rle +# - raw +# it is then parsed and a test with specified params is run + +# RAW +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_2000B_block_100B_raw(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_2000B_block_500B_raw(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) + +# COMPRESSED +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_200B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_200B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_200B_block_500B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_300B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_300B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_300B_block_500B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_500B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_500B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1024B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1024B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1024B_block_500B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1030B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1030B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=10000, timeout_unit="ms") +async def pregenerated_1030B_block_500B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=30000, timeout_unit="ms") +async def pregenerated_2000B_block_10B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=20000, timeout_unit="ms") +async def pregenerated_2000B_block_100B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) +@cocotb.test(timeout_time=20000, timeout_unit="ms") +async def pregenerated_2000B_block_500B_compressed(dut): await testcase_pregenerated(dut, *parse_decl(currentframe())) + + +if __name__ == "__main__": + toplevel = "zstd_enc_wrapper" + verilog_sources = [ + "xls/modules/zstd/zstd_enc_cocotb.v", + "xls/modules/zstd/rtl/zstd_enc_wrapper.sv", + "xls/modules/zstd/rtl/xls_fifo_wrapper.sv", + "xls/modules/zstd/rtl/ram_1r1w.sv" + ] + + test_module=[Path(__file__).stem] + run_test(toplevel, test_module, verilog_sources) diff --git a/xls/modules/zstd/zstd_enc_ll_ctable_default.mem b/xls/modules/zstd/zstd_enc_ll_ctable_default.mem new file mode 100644 index 0000000000..222e904767 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_ll_ctable_default.mem @@ -0,0 +1,4096 @@ +0040 +0041 +0056 +006b +0042 +0057 +006c +0058 +006d +0043 +006e +0044 +0059 +005a +006f +0045 +0070 +0046 +005b +005c +0071 +0047 +0072 +0048 +005d +005e +0073 +0049 +0074 +005f +004a +0075 +004b +0060 +0061 +0076 +004c +0077 +004d +0062 +0063 +0078 +004e +0079 +004f +0064 +0065 +007a +0050 +007b +0051 +0066 +0067 +0052 +0068 +0053 +0069 +0054 +006a +0055 +007f +007e +007d +007c +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 diff --git a/xls/modules/zstd/zstd_enc_ll_ttable_default.mem b/xls/modules/zstd/zstd_enc_ll_ttable_default.mem new file mode 100644 index 0000000000..f141a627c0 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_ll_ttable_default.mem @@ -0,0 +1,4096 @@ +fffffffc0004ff80 +000000010004ffa0 +000000050005ff80 +000000070005ff80 +000000090005ff80 +0000000b0005ff80 +0000000d0005ff80 +0000000f0005ff80 +000000110005ff80 +000000130005ff80 +000000150005ff80 +000000170005ff80 +000000190005ff80 +0000001c0005ffc0 +0000001d0005ffc0 +0000001e0005ffc0 +0000001e0005ff80 +000000200005ff80 +000000220005ff80 +000000240005ff80 +000000260005ff80 +000000280005ff80 +0000002a0005ff80 +0000002c0005ff80 +0000002e0005ff80 +0000002f0004ffa0 +000000330005ff80 +000000360005ffc0 +000000370005ffc0 +000000380005ffc0 +000000390005ffc0 +0000003a0005ffc0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 diff --git a/xls/modules/zstd/zstd_enc_ml_ctable_default.mem b/xls/modules/zstd/zstd_enc_ml_ctable_default.mem new file mode 100644 index 0000000000..09fbe15ca8 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_ml_ctable_default.mem @@ -0,0 +1,4096 @@ +0040 +0041 +0056 +006b +006c +0042 +0057 +006d +0043 +0058 +0059 +006e +0044 +006f +0045 +005a +005b +0070 +0046 +0071 +005c +0047 +0072 +005d +0048 +0073 +005e +0049 +0074 +005f +004a +0075 +0060 +004b +0076 +0061 +004c +0077 +0062 +004d +0078 +0063 +004e +0064 +004f +0065 +0050 +0066 +0051 +0067 +0052 +0068 +0053 +0069 +0054 +006a +0055 +007f +007e +007d +007c +007b +007a +0079 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 diff --git a/xls/modules/zstd/zstd_enc_ml_ttable_default.mem b/xls/modules/zstd/zstd_enc_ml_ttable_default.mem new file mode 100644 index 0000000000..fb2e7c108d --- /dev/null +++ b/xls/modules/zstd/zstd_enc_ml_ttable_default.mem @@ -0,0 +1,4096 @@ +ffffffff0005ffc0 +fffffffd0004ff80 +000000020004ffa0 +000000060005ff80 +000000080005ff80 +0000000a0005ff80 +0000000c0005ff80 +0000000e0005ff80 +000000100005ff80 +000000130005ffc0 +000000140005ffc0 +000000150005ffc0 +000000160005ffc0 +000000170005ffc0 +000000180005ffc0 +000000190005ffc0 +0000001a0005ffc0 +0000001b0005ffc0 +0000001c0005ffc0 +0000001d0005ffc0 +0000001e0005ffc0 +0000001f0005ffc0 +000000200005ffc0 +000000210005ffc0 +000000220005ffc0 +000000230005ffc0 +000000240005ffc0 +000000250005ffc0 +000000260005ffc0 +000000270005ffc0 +000000280005ffc0 +000000290005ffc0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 diff --git a/xls/modules/zstd/zstd_enc_of_ctable_default.mem b/xls/modules/zstd/zstd_enc_of_ctable_default.mem new file mode 100644 index 0000000000..71bc826795 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_of_ctable_default.mem @@ -0,0 +1,4096 @@ +0020 +0037 +002e +0025 +0033 +002a +0021 +0038 +0026 +002f +002b +0034 +0022 +0039 +0030 +0027 +0035 +002c +0023 +003a +0031 +0028 +0036 +002d +0024 +0032 +0029 +003f +003e +003d +003c +003b +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 +0000 diff --git a/xls/modules/zstd/zstd_enc_of_ttable_default.mem b/xls/modules/zstd/zstd_enc_of_ttable_default.mem new file mode 100644 index 0000000000..ff12034818 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_of_ttable_default.mem @@ -0,0 +1,4096 @@ +ffffffff0004ffe0 +000000000004ffe0 +000000010004ffe0 +000000020004ffe0 +000000030004ffe0 +000000040004ffe0 +000000040004ffc0 +000000060004ffc0 +000000080004ffc0 +0000000b0004ffe0 +0000000c0004ffe0 +0000000d0004ffe0 +0000000e0004ffe0 +0000000f0004ffe0 +000000100004ffe0 +000000110004ffe0 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 +0000000000000000 diff --git a/xls/modules/zstd/zstd_enc_test.x b/xls/modules/zstd/zstd_enc_test.x new file mode 100644 index 0000000000..bcb5574337 --- /dev/null +++ b/xls/modules/zstd/zstd_enc_test.x @@ -0,0 +1,1467 @@ +// Copyright 2025 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.examples.ram; +import xls.modules.zstd.zstd_enc; +import xls.modules.zstd.memory.axi; +import xls.modules.zstd.memory.axi_ram_reader; +import xls.modules.zstd.memory.axi_ram_writer; +import xls.modules.zstd.mem_copy; +import xls.modules.zstd.memory.mem_writer; +import xls.modules.zstd.memory.mem_reader; +import xls.modules.zstd.common; +import xls.modules.zstd.mem_writer_simple_arbiter; +import xls.modules.zstd.mem_reader_simple_arbiter; +import xls.modules.zstd.sequence_encoder; + +const TEST_ADDR_W = u32:32; +const TEST_AXI_ADDR_W = u32:32; +const TEST_AXI_DATA_W = u32:32; +const TEST_AXI_DEST_W = u32:8; +const TEST_AXI_ID_W = u32:4; + +const TEST_WRITER_ID = u32:3; + +const TEST_RAM_DATA_W = TEST_AXI_DATA_W; +const TEST_RAM_WORD_PARTITION_SIZE = u32:8; +const TEST_RAM_NUM_PARTITIONS = TEST_RAM_DATA_W / TEST_RAM_WORD_PARTITION_SIZE; +const TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_RAM_INITIALIZED = true; +const TEST_RAM_ASSERT_VALID_READ = true; + +const TEST_INPUT_SIZE = u32:100; +const TEST_INPUT_SIZE_BYTES = TEST_INPUT_SIZE * (TEST_RAM_DATA_W / u32:8); +const TEST_OUTPUT_SIZE = u32:103; + +// The expected output data was generated with zstd as a single block. +// Let's test with a single block first, then TODO: +// * generate new reference output with zstd, with more than one block +// * change the block size here +const TEST_MAX_BLOCK_SIZE = u32:0x1000; +const TEST_RLE_HEURISTIC_SAMPLE_COUNT = u32:8; +// sequence encoding +const TEST_MIN_SEQ_LEN = u32:3; +const TEST_HT_SIZE = u32:512; +const TEST_HT_SIZE_W = std::clog2(TEST_HT_SIZE + u32:1); +const TEST_HT_KEY_W = u32:32; +const TEST_HT_VALUE_W = TEST_HT_KEY_W + TEST_ADDR_W; +const TEST_HT_HASH_W = std::clog2(TEST_HT_SIZE); +const TEST_HT_RAM_DATA_W = TEST_HT_VALUE_W + u32:1; +const TEST_HT_RAM_WORD_PARTITION_SIZE = u32:1; +const TEST_HT_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_HT_RAM_WORD_PARTITION_SIZE, TEST_HT_RAM_DATA_W); +const TEST_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_HT_RAM_INITIALIZED = true; + +const TEST_HB_DATA_W = u32:64; +const TEST_HB_SIZE = u32:1024; +const TEST_HB_OFFSET_W = std::clog2(TEST_HB_SIZE); +const TEST_HB_RAM_NUM = u32:8; +const TEST_HB_RAM_SIZE = TEST_HB_SIZE / TEST_HB_RAM_NUM; +const TEST_HB_RAM_DATA_W = TEST_HB_DATA_W / TEST_HB_RAM_NUM; +const TEST_HB_RAM_ADDR_W = std::clog2(TEST_HB_RAM_SIZE); +const TEST_HB_RAM_PARTITION_SIZE = TEST_HB_RAM_DATA_W; +const TEST_HB_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_HB_RAM_PARTITION_SIZE, TEST_HB_RAM_DATA_W); +const TEST_HB_RAM_SIMULTANEOUS_RW_BEHAVIOR = ram::SimultaneousReadWriteBehavior::READ_BEFORE_WRITE; +const TEST_HB_RAM_INITIALIZED = true; +const TEST_FSE_TABLE_RAM_ADDR_W = u32:32; +const TEST_FSE_CTABLE_RAM_DATA_W = u32:16; +const TEST_FSE_TTABLE_RAM_DATA_W = u32:64; +const TEST_FSE_TTABLE_RAM_PARTITION_SIZE = u32:8; +const TEST_FSE_TABLE_PARTITION_SIZE = u32:8; +const TEST_FSE_CTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_FSE_TABLE_PARTITION_SIZE, TEST_FSE_CTABLE_RAM_DATA_W); +const TEST_FSE_TTABLE_RAM_NUM_PARTITIONS = ram::num_partitions(TEST_FSE_TABLE_PARTITION_SIZE, TEST_FSE_TTABLE_RAM_DATA_W); +const TEST_FSE_BITSTREAM_BUFFER_W = u32:1024; + + +type ZstdEncodeRespStatus = zstd_enc::ZstdEncodeRespStatus; + +type TestReadReq = ram::ReadReq; +type TestWriteReq = ram::WriteReq; +type TestReadResp = ram::ReadResp; +type TestWriteResp = ram::WriteResp; +type TestMemReaderReq = mem_reader::MemReaderReq; +type TestMemReaderResp = mem_reader::MemReaderResp; +type TestMemWriterReq = mem_writer::MemWriterReq; +type TestMemWriterData = mem_writer::MemWriterDataPacket; +type TestMemWriterResp = mem_writer::MemWriterResp; +type TestMemWriterStatus = mem_writer::MemWriterRespStatus; +type TestHistoryBufferRamRdReq = ram::ReadReq; +type TestHistoryBufferRamRdResp = ram::ReadResp; +type TestHistoryBufferRamWrReq = ram::WriteReq; +type TestHistoryBufferRamWrResp = ram::WriteResp; +type TestHashTableRamRdReq = ram::ReadReq; +type TestHashTableRamRdResp = ram::ReadResp; +type TestHashTableRamWrReq = ram::WriteReq; +type TestHashTableRamWrResp = ram::WriteResp; +type TestCTableRamRdReq = ram::ReadReq; +type TestCTableRamRdResp = ram::ReadResp; +type TestTTableRamRdReq = ram::ReadReq; +type TestTTableRamRdResp = ram::ReadResp; +type TestCTableRamWrReq = ram::WriteReq; +type TestTTableRamWrReq = ram::WriteReq; +type TestCTableRamWrResp = ram::WriteResp; +type TestTTableRamWrResp = ram::WriteResp; + +type TestZstdEncodeReq = zstd_enc::ZstdEncodeReq; +type TestZstdEncodeResp = zstd_enc::ZstdEncodeResp; + +const TEST_INPUT_DATA = u32[TEST_INPUT_SIZE]:[ + u32:0xD945_50A5, u32:0xA20C_D8D3, u32:0xB0BE_D046, u32:0xF83C_6D26, u32:0xFAE4_B0C4, + u32:0x9A78_91C4, u32:0xFDA0_9B1E, u32:0x5E66_D76D, u32:0xCB7D_76CB, u32:0x4033_5F2F, + u32:0x2128_9B0B, u32:0xD263_365F, u32:0xD989_DD81, u32:0xE4CB_45C9, u32:0x0425_06B6, + u32:0x5D31_107C, u32:0x2282_7A67, u32:0xCAC7_0C94, u32:0x23A9_5FD8, u32:0x6122_BBC3, + u32:0x1F99_F3D0, u32:0xA70C_FB34, u32:0x3812_5EF2, u32:0x9157_61BC, u32:0x171A_C1B1, + + u32:0xDE6F_1B08, u32:0x420D_F1AF, u32:0xAEE9_F51B, u32:0xB31E_E3A3, u32:0x66AC_09D6, + u32:0x18E9_9703, u32:0xEE87_1E7A, u32:0xB63D_47DE, u32:0x59BF_4F52, u32:0x94D8_5636, + u32:0x2B81_34EE, u32:0x6711_9968, u32:0xFB2B_F8CB, u32:0x173F_CB1B, u32:0xFB94_3A67, + u32:0xF40B_714F, u32:0x383B_82FE, u32:0xA692_055E, u32:0x58A6_2110, u32:0x0185_B5E0, + u32:0x9DF0_9C22, u32:0x54CA_DB57, u32:0xC626_097F, u32:0xEA04_3110, u32:0xF11C_4D36, + + u32:0xB8CC_FAB0, u32:0x7801_3B20, u32:0x8189_BF9C, u32:0xE380_A505, u32:0x4672_AE34, + u32:0x1CD5_1B3A, u32:0x5F95_EE9E, u32:0xBC5C_9931, u32:0xBCE6_50D2, u32:0xC10D_0544, + u32:0x5AB4_DEA1, u32:0x5E20_3394, u32:0x7FDA_0CA1, u32:0x6FEC_112E, u32:0x107A_2F81, + u32:0x86CA_4491, u32:0xEA68_0EB7, u32:0x50F1_AA22, u32:0x3F47_F2CA, u32:0xE407_92F7, + u32:0xF35C_EEE0, u32:0x1D6B_E819, u32:0x3FA7_05FA, u32:0x08BB_A499, u32:0x7C0C_4812, + + u32:0xF5A5_3D5C, u32:0x079A_BE16, u32:0xACA1_F84B, u32:0x4D2B_9402, u32:0x45B1_28FD, + u32:0x2C7C_CBA5, u32:0x6874_FC32, u32:0x95A0_8288, u32:0xFB13_E707, u32:0x61F9_2FEF, + u32:0xF6E3_DAFC, u32:0xDBA0_0A80, u32:0xBB84_831B, u32:0xAD63_2520, u32:0xEFB3_D817, + u32:0xD190_C435, u32:0x9064_1E4F, u32:0x0839_3D28, u32:0x1C07_874C, u32:0xBBEB_D633, + u32:0xB0A9_C751, u32:0x83B9_A340, u32:0x028A_FF8A, u32:0xB4ED_EE5C, u32:0xD700_BD9C, +]; + +// zstd -0 --no-check input.bin -o output.zst +// xxd -e -c4 output.zst +const TEST_EXPECTED_SIZE = TEST_OUTPUT_SIZE; +const TEST_LITERALS_BUFFER_AXI_ADDR = TEST_EXPECTED_SIZE * u32:2; +const TEST_SEQUENCE_BUFFER_AXI_ADDR = TEST_EXPECTED_SIZE * u32:4; +const TEST_RAM_SIZE = TEST_EXPECTED_SIZE * u32:5; + +const TEST_EXPECTED = u32[TEST_EXPECTED_SIZE]:[ + // FH - frame header, BH - block header, BB - block content + // Magic_Number BHFH FHFH BBBB BHBH BBBB BBBB BBBB ... + u32:0xFD2F_B528, u32:0x0090_6040, u32:0xA500_0C81, u32:0xD3D9_4550, u32:0x46A2_0CD8, + u32:0x26B0_BED0, u32:0xC4F8_3C6D, u32:0xC4FA_E4B0, u32:0x1E9A_7891, u32:0x6DFD_A09B, + u32:0xCB5E_66D7, u32:0x2FCB_7D76, u32:0x0B40_335F, u32:0x5F21_289B, u32:0x81D2_6336, + u32:0xC9D9_89DD, u32:0xB6E4_CB45, u32:0x7C04_2506, u32:0x675D_3110, u32:0x9422_827A, + u32:0xD8CA_C70C, u32:0xC323_A95F, u32:0xD061_22BB, u32:0x341F_99F3, u32:0xF2A7_0CFB, + u32:0xBC38_125E, u32:0xB191_5761, u32:0x0817_1AC1, u32:0xAFDE_6F1B, u32:0x1B42_0DF1, + u32:0xA3AE_E9F5, u32:0xD6B3_1EE3, u32:0x0366_AC09, u32:0x7A18_E997, u32:0xDEEE_871E, + u32:0x52B6_3D47, u32:0x3659_BF4F, u32:0xEE94_D856, u32:0x682B_8134, u32:0xCB67_1199, + u32:0x1BFB_2BF8, u32:0x6717_3FCB, u32:0x4FFB_943A, u32:0xFEF4_0B71, u32:0x5E38_3B82, + u32:0x10A6_9205, u32:0xE058_A621, u32:0x2201_85B5, u32:0x579D_F09C, u32:0x7F54_CADB, + u32:0x10C6_2609, u32:0x36EA_0431, u32:0xB0F1_1C4D, u32:0x20B8_CCFA, u32:0x9C78_013B, + u32:0x0581_89BF, u32:0x34E3_80A5, u32:0x3A46_72AE, u32:0x9E1C_D51B, u32:0x315F_95EE, + u32:0xD2BC_5C99, u32:0x44BC_E650, u32:0xA1C1_0D05, u32:0x945A_B4DE, u32:0xA15E_2033, + u32:0x2E7F_DA0C, u32:0x816F_EC11, u32:0x9110_7A2F, u32:0xB786_CA44, u32:0x22EA_680E, + u32:0xCA50_F1AA, u32:0xF73F_47F2, u32:0xE0E4_0792, u32:0x19F3_5CEE, u32:0xFA1D_6BE8, + u32:0x993F_A705, u32:0x1208_BBA4, u32:0x5C7C_0C48, u32:0x16F5_A53D, u32:0x4B07_9ABE, + u32:0x02AC_A1F8, u32:0xFD4D_2B94, u32:0xA545_B128, u32:0x322C_7CCB, u32:0x8868_74FC, + u32:0x0795_A082, u32:0xEFFB_13E7, u32:0xFC61_F92F, u32:0x80F6_E3DA, u32:0x1BDB_A00A, + u32:0x20BB_8483, u32:0x17AD_6325, u32:0x35EF_B3D8, u32:0x4FD1_90C4, u32:0x2890_641E, + u32:0x4C08_393D, u32:0x331C_0787, u32:0x51BB_EBD6, u32:0x40B0_A9C7, u32:0x8A83_B9A3, + u32:0x5C02_8AFF, u32:0x9CB4_EDEE, u32:0x00D7_00BD, +]; + +// touch empty.txt +// zstd --no-check empty.txt -o empty.zst +// xxd -e empty.zst +const TEST_EMPTY_EXPECTED_SIZE = u32:3; +const TEST_EMPTY_EXPECTED = u32[TEST_EMPTY_EXPECTED_SIZE]:[ + // Magic_Number // FH FHFH + u32:0xFD2F_B528, u32:0x0001_6000, u32:0x0 +]; + +// decodecorpus -p./ -o./ -n1 --block-type=1 --content-size -s35766 (after hard-coding certain values) +// xxd -e -c4 z000000 +const TEST_RLE_INPUT_SIZE = u32:64; +const TEST_RLE_INPUT_SIZE_BYTES = TEST_RLE_INPUT_SIZE * (TEST_RAM_DATA_W / u32:8); +const TEST_RLE_INPUT_DATA = u32[TEST_RLE_INPUT_SIZE]:[ + u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, u32: 0xa3a3a3a3, + u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, u32: 0x4d4d4d4d, + u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, u32: 0x4f4f4f4f, + u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, u32: 0x14141414, + u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, u32: 0xf6f6f6f6, + u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, u32: 0xe0e0e0e0, + u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, u32: 0x5b5b5b5b, + u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, u32: 0x61616161, +]; +// xxd -e -c4 z000000.zst +const TEST_RLE_EXPECTED_SIZE = u32:10; +const TEST_RLE_EXPECTED = u32[TEST_RLE_EXPECTED_SIZE]:[ + // block indexes 1 2 1 1 1 3 2 2 2 + // Magic_Number BHFHFHFH BHBBBHBH BHBBBHBH + u32: 0xfd2fb528, u32:0x02000060, u32:0x02a30001, u32:0x024d0001, + // 4 3 3 3 5 4 4 4 6 5 5 5 7 6 6 6 + // BHBBBHBH BHBBBHBH BHBBBHBH BHBBBHBH + u32: 0x024f0001, u32:0x02140001, u32:0x02f60001, u32:0x02e00001, + // 8 7 7 7 8 8 8 + // BHBBBHBH --BBBHBH + u32: 0x035b0001, u32:0x00610001 +]; + + +// How the input data below came to be: +// 1. encode some random data +// 2. try to decode it with zstd +// 3. see if it produces correct output +// 00000000: fd2fb528 01142820 00b5d000 f00db16b (./. (......k... +// 00000010: beefb105 beefbaad ffbeefdd cafebabe ................ +// 00000020: dabbad00 603a0002 5d757018 ce400000 ......:`.pu]..@. +// 00000030: eefeedfa 000ff1ce 0000 .......... +const TEST_COMPRESSED_PREDEFINED_INPUT_SIZE = u32:10; +const TEST_COMPRESSED_PREDEFINED_INPUT_SIZE_BYTES = TEST_COMPRESSED_PREDEFINED_INPUT_SIZE * (TEST_RAM_DATA_W / u32:8); +const TEST_COMPRESSED_PREDEFINED_INPUT = u32[TEST_COMPRESSED_PREDEFINED_INPUT_SIZE]:[ + u32:0xB16B00B5, u32:0xB105F00D, u32:0xBAADBEEF, u32:0xBADDBEEF, u32:0xBEEFBEEF, + u32:0xFFBEEFFF, u32:0xCAFEBABE, u32:0xDABBAD00, u32:0xFEEDFACE, u32:0x0FF1CEEE +]; +const TEST_COMPRESS_PREDEFINED_EXPECTED_SIZE = u32:16; +const TEST_COMPRESS_PREDEFINED_EXPECTED = [ + // S - sequences + // L - literals + // SH - sequence header + // magic number BHBHBHBH LLLLLLLL LLLLLLLL + u32:0xfd2fb528, u32:0x01142820, u32: 0x00b5d000, u32:0xf00db16b, + // LLLLLLLL LLLLLLLL LLLLLLLL LLLLLLLL + u32:0xbeefb105, u32:0xbeefbaad, u32:0xffbeefdd, u32:0xcafebabe, + // LLLLLLLL SSSSSHSH BHSSSSSS LLBHBHBH + u32:0xdabbad00, u32:0x603a0002, u32:0x55757018, u32:0xce400000, + // LLLLLLLL SHLLLLLL SH + u32:0xeefeedfa, u32:0x000ff1ce, u32:0x00 // no sequences in this block (only header) +]; + + +#[test_proc] +proc ZstdEncoderTestEmpty { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + input_wr_req_s: chan out; + input_wr_resp_r: chan in; + output_rd_req_s: chan out; + output_rd_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + // IO for Encoder <-> test + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + // IO for input RAM + let (input_rd_req_s, input_rd_req_r) = chan("input_rd_req"); + let (input_rd_resp_s, input_rd_resp_r) = chan("input_rd_resp"); + let (input_wr_req_s, input_wr_req_r) = chan("input_wr_req"); + let (input_wr_resp_s, input_wr_resp_r) = chan("input_wr_resp"); + // IO for AxiRamReader <-> MemReader + let (input_axi_ar_s, input_axi_ar_r) = chan("input_axi_ar"); + let (input_axi_r_s, input_axi_r_r) = chan("input_axi_r"); + // IO for MemReader <-> Encoder + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + // IO for output RAM + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (output_wr_req_s, output_wr_req_r) = chan("output_wr_req"); + let (output_wr_resp_s, output_wr_resp_r) = chan("output_wr_resp"); + // IO for AxiRamWriter <-> MemWriter + let (output_axi_aw_s, output_axi_aw_r) = chan("output_axi_aw"); + let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); + let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); + // IO for MemWriter <-> Encoder + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[8]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[8]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[8]("n_resp"); + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[4]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[4]("n_mem_rd_resp"); + let (hb_ram_rd_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_req"); + let (_, hb_ram_rd_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_resp"); + let (hb_ram_wr_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_req"); + let (_, hb_ram_wr_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_resp"); + let (ht_ram_rd_req_s, _) = chan("ht_ram_rd_req"); + let (_, ht_ram_rd_resp_r) = chan("ht_ram_rd_resp"); + let (ht_ram_wr_req_s, _) = chan("ht_ram_wr_req"); + let (_, ht_ram_wr_resp_r) = chan("ht_ram_wr_resp"); + let (ml_ctable_ram_rd_req_s, _) = chan("ml_ctable_ram_rd_req"); + let (_, ml_ctable_ram_rd_resp_r) = chan("ml_ctable_ram_rd_resp"); + let (ll_ctable_ram_rd_req_s, _) = chan("ll_ctable_ram_rd_req"); + let (_, ll_ctable_ram_rd_resp_r) = chan("ll_ctable_ram_rd_resp"); + let (of_ctable_ram_rd_req_s, _) = chan("of_ctable_ram_rd_req"); + let (_, of_ctable_ram_rd_resp_r) = chan("of_ctable_ram_rd_resp"); + let (ml_ttable_ram_rd_req_s, _) = chan("ml_ttable_ram_rd_req"); + let (_, ml_ttable_ram_rd_resp_r) = chan("ml_ttable_ram_rd_resp"); + let (ll_ttable_ram_rd_req_s, _) = chan("ll_ttable_ram_rd_req"); + let (_, ll_ttable_ram_rd_resp_r) = chan("ll_ttable_ram_rd_resp"); + let (of_ttable_ram_rd_req_s, _) = chan("of_ttable_ram_rd_req"); + let (_, of_ttable_ram_rd_resp_r) = chan("of_ttable_ram_rd_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, TEST_RAM_ASSERT_VALID_READ, TEST_AXI_ADDR_W + >( + input_rd_req_r, input_rd_resp_s, + input_wr_req_r, input_wr_resp_s + ); + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_ADDR_W + >( + output_rd_req_r, output_rd_resp_s, output_wr_req_r, output_wr_resp_s + ); + spawn axi_ram_reader::AxiRamReader< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_RAM_SIZE + >( + input_axi_ar_r, input_axi_r_s, + input_rd_req_s, input_rd_resp_r + ); + spawn axi_ram_writer::AxiRamWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_ID_W, TEST_RAM_SIZE, TEST_ADDR_W, TEST_RAM_NUM_PARTITIONS, + >( + output_axi_aw_r, output_axi_w_r, output_axi_b_s, + output_wr_req_s, output_wr_resp_r + ); + + spawn mem_reader::MemReader( + mem_rd_req_r, mem_rd_resp_s, + input_axi_ar_s, input_axi_r_r + ); + spawn mem_writer::MemWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_WRITER_ID + >( + mem_wr_req_r, mem_wr_data_r, + output_axi_aw_s, output_axi_w_s, output_axi_b_r, + mem_wr_resp_s + ); + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn zstd_enc::ZstdEncoder< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, + TEST_RLE_HEURISTIC_SAMPLE_COUNT, + TEST_HB_SIZE, TEST_HB_DATA_W, TEST_HB_OFFSET_W, TEST_HB_RAM_ADDR_W, TEST_HB_RAM_DATA_W, TEST_HB_RAM_NUM, TEST_HB_RAM_NUM_PARTITIONS, + TEST_HT_SIZE, TEST_HT_KEY_W, TEST_HT_VALUE_W, TEST_HT_SIZE_W, TEST_HT_HASH_W, TEST_HT_RAM_DATA_W, TEST_HT_RAM_NUM_PARTITIONS, + TEST_MIN_SEQ_LEN, TEST_LITERALS_BUFFER_AXI_ADDR, TEST_SEQUENCE_BUFFER_AXI_ADDR, + TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_DATA_W, TEST_FSE_TTABLE_RAM_DATA_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS, + TEST_FSE_BITSTREAM_BUFFER_W + >( + enc_req_r, enc_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3], + n_mem_wr_req_s[4], n_mem_wr_data_s[4], n_mem_wr_resp_r[4], + n_mem_wr_req_s[5], n_mem_wr_data_s[5], n_mem_wr_resp_r[5], + n_mem_wr_req_s[6], n_mem_wr_data_s[6], n_mem_wr_resp_r[6], + n_mem_wr_req_s[7], n_mem_wr_data_s[7], n_mem_wr_resp_r[7], + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + n_mem_rd_req_s[3], n_mem_rd_resp_r[3], + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + (input_wr_req_s, input_wr_resp_r, output_rd_req_s, output_rd_resp_r, enc_req_s, enc_resp_r, terminator) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // write ZEROS to RAM + let tok = for ((i, _data), tok): ((u32, u32), token) in enumerate(TEST_INPUT_DATA) { + let tok = send(tok, input_wr_req_s, TestWriteReq { + addr: i as Addr, + data: u32:0, + mask: all_ones!(), + }); + let (tok, _) = recv(tok, input_wr_resp_r); + tok + }(join()); + + trace_fmt!("Request: encode data of size 0"); + let tok = send(tok, enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: uN[TEST_RAM_DATA_W]:0, + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: TEST_MAX_BLOCK_SIZE, + params: zero!() + }); + let (tok, resp) = recv(tok, enc_resp_r); + assert_eq(resp.status, ZstdEncodeRespStatus::OK); + + // read state of output RAM + let tok = for ((i, expected_val), tok): ((u32, u32), token) in enumerate(TEST_EMPTY_EXPECTED) { + let tok = send(tok, output_rd_req_s, TestReadReq { + addr: i as Addr, + mask: all_ones!(), + }); + let (tok, data) = recv(tok, output_rd_resp_r); + + if (data.data != expected_val) { + trace_fmt!("at index {} the expected value is {:#x}, the outcome is {:#x}", i, expected_val, data.data); + } else { }; + + assert_eq([i, data.data], [i, expected_val]); + tok + }(join()); + send(join(), terminator, true); + } +} + +proc ZstdEncoderTestBase { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + init { } + + write_fse_tables_req_r: chan<()> in; + write_fse_tables_resp_s: chan<()> out; + ll_ctable_ram_wr_req_s: chan out; + ll_ctable_ram_wr_resp_r: chan in; + of_ctable_ram_wr_req_s: chan out; + of_ctable_ram_wr_resp_r: chan in; + ml_ctable_ram_wr_req_s: chan out; + ml_ctable_ram_wr_resp_r: chan in; + ll_ttable_ram_wr_req_s: chan out; + ll_ttable_ram_wr_resp_r: chan in; + of_ttable_ram_wr_req_s: chan out; + of_ttable_ram_wr_resp_r: chan in; + ml_ttable_ram_wr_req_s: chan out; + ml_ttable_ram_wr_resp_r: chan in; + + config( + write_fse_tables_req_r: chan<()> in, + write_fse_tables_resp_s: chan<()> out, + input_wr_req_r: chan in, + input_wr_resp_s: chan out, + output_rd_req_r: chan in, + output_rd_resp_s: chan out, + enc_req_r: chan in, + enc_resp_s: chan out + ) { + // IO for input RAM + let (input_rd_req_s, input_rd_req_r) = chan("input_rd_req"); + let (input_rd_resp_s, input_rd_resp_r) = chan("input_rd_resp"); + // IO for AxiRamReader <-> MemReader + let (input_axi_ar_s, input_axi_ar_r) = chan("input_axi_ar"); + let (input_axi_r_s, input_axi_r_r) = chan("input_axi_r"); + // IO for MemReader <-> Encoder + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + // IO for output RAM + let (output_wr_req_s, output_wr_req_r) = chan("output_wr_req"); + let (output_wr_resp_s, output_wr_resp_r) = chan("output_wr_resp"); + + // IO for AxiRamWriter <-> MemWriter + let (output_axi_aw_s, output_axi_aw_r) = chan("output_axi_aw"); + let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); + let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); + + // IO for MemWriter <-> Encoder + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[7]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[7]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[7]("n_resp"); + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[3]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[3]("n_mem_rd_resp"); + let (hb_ram_rd_req_s, hb_ram_rd_req_r) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_req"); + let (hb_ram_rd_resp_s, hb_ram_rd_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_resp"); + let (hb_ram_wr_req_s, hb_ram_wr_req_r) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_req"); + let (hb_ram_wr_resp_s, hb_ram_wr_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_resp"); + let (ht_ram_rd_req_s, ht_ram_rd_req_r) = chan("ht_ram_rd_req"); + let (ht_ram_rd_resp_s, ht_ram_rd_resp_r) = chan("ht_ram_rd_resp"); + let (ht_ram_wr_req_s, ht_ram_wr_req_r) = chan("ht_ram_wr_req"); + let (ht_ram_wr_resp_s, ht_ram_wr_resp_r) = chan("ht_ram_wr_resp"); + let (ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_req_r) = chan("ml_ctable_ram_rd_req"); + let (ml_ctable_ram_rd_resp_s, ml_ctable_ram_rd_resp_r) = chan("ml_ctable_ram_rd_resp"); + let (ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_req_r) = chan("ll_ctable_ram_rd_req"); + let (ll_ctable_ram_rd_resp_s, ll_ctable_ram_rd_resp_r) = chan("ll_ctable_ram_rd_resp"); + let (of_ctable_ram_rd_req_s, of_ctable_ram_rd_req_r) = chan("of_ctable_ram_rd_req"); + let (of_ctable_ram_rd_resp_s, of_ctable_ram_rd_resp_r) = chan("of_ctable_ram_rd_resp"); + let (ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_req_r) = chan("ml_ttable_ram_rd_req"); + let (ml_ttable_ram_rd_resp_s, ml_ttable_ram_rd_resp_r) = chan("ml_ttable_ram_rd_resp"); + let (ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_req_r) = chan("ll_ttable_ram_rd_req"); + let (ll_ttable_ram_rd_resp_s, ll_ttable_ram_rd_resp_r) = chan("ll_ttable_ram_rd_resp"); + let (of_ttable_ram_rd_req_s, of_ttable_ram_rd_req_r) = chan("of_ttable_ram_rd_req"); + let (of_ttable_ram_rd_resp_s, of_ttable_ram_rd_resp_r) = chan("of_ttable_ram_rd_resp"); + let (ll_ctable_ram_wr_req_s, ll_ctable_ram_wr_req_r) = chan("ll_ctable_ram_wr_req"); + let (ll_ctable_ram_wr_resp_s, ll_ctable_ram_wr_resp_r) = chan("ll_ctable_ram_wr_resp"); + let (of_ctable_ram_wr_req_s, of_ctable_ram_wr_req_r) = chan("of_ctable_ram_wr_req"); + let (of_ctable_ram_wr_resp_s, of_ctable_ram_wr_resp_r) = chan("of_ctable_ram_wr_resp"); + let (ml_ctable_ram_wr_req_s, ml_ctable_ram_wr_req_r) = chan("ml_ctable_ram_wr_req"); + let (ml_ctable_ram_wr_resp_s, ml_ctable_ram_wr_resp_r) = chan("ml_ctable_ram_wr_resp"); + let (ll_ttable_ram_wr_req_s, ll_ttable_ram_wr_req_r) = chan("ll_ttable_ram_wr_req"); + let (ll_ttable_ram_wr_resp_s, ll_ttable_ram_wr_resp_r) = chan("ll_ttable_ram_wr_resp"); + let (of_ttable_ram_wr_req_s, of_ttable_ram_wr_req_r) = chan("of_ttable_ram_wr_req"); + let (of_ttable_ram_wr_resp_s, of_ttable_ram_wr_resp_r) = chan("of_ttable_ram_wr_resp"); + let (ml_ttable_ram_wr_req_s, ml_ttable_ram_wr_req_r) = chan("ml_ttable_ram_wr_req"); + let (ml_ttable_ram_wr_resp_s, ml_ttable_ram_wr_resp_r) = chan("ml_ttable_ram_wr_resp"); + // MatchFinder buffer + let (buf_rd_req_s, buf_rd_req_r) = chan("buf_rd_req"); + let (buf_rd_resp_s, buf_rd_resp_r) = chan("buf_rd_resp"); + let (buf_wr_req_s, buf_wr_req_r) = chan("buf_wr_req"); + let (buf_wr_resp_s, buf_wr_resp_r) = chan("buf_wr_resp"); + let (buf_axi_aw_s, buf_axi_aw_r) = chan("buf_axi_aw"); + let (buf_axi_w_s, buf_axi_w_r) = chan("buf_axi_w"); + let (buf_axi_b_s, buf_axi_b_r) = chan("buf_axi_b"); + let (buf_axi_ar_s, buf_axi_ar_r) = chan("buf_axi_ar"); + let (buf_axi_r_s, buf_axi_r_r) = chan("buf_axi_r"); + let (buf_mem_wr_req_s, buf_mem_wr_req_r) = chan("buf_mem_wr_req"); + let (buf_mem_wr_data_s, buf_mem_wr_data_r) = chan("buf_mem_wr_data"); + let (buf_mem_wr_resp_s, buf_mem_wr_resp_r) = chan("buf_mem_wr_resp"); + let (buf_mem_rd_req_s, buf_mem_rd_req_r) = chan("buf_mem_rd_req"); + let (buf_mem_rd_resp_s, buf_mem_rd_resp_r) = chan("buf_mem_rd_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, TEST_RAM_ASSERT_VALID_READ, TEST_AXI_ADDR_W + >( + input_rd_req_r, input_rd_resp_s, + input_wr_req_r, input_wr_resp_s + ); + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_ADDR_W + >( + output_rd_req_r, output_rd_resp_s, + output_wr_req_r, output_wr_resp_s + ); + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_ADDR_W + >( + buf_rd_req_r, buf_rd_resp_s, + buf_wr_req_r, buf_wr_resp_s + ); + + + spawn axi_ram_reader::AxiRamReader< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_RAM_SIZE + >( + buf_axi_ar_r, buf_axi_r_s, + buf_rd_req_s, buf_rd_resp_r + ); + + spawn axi_ram_writer::AxiRamWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_ID_W, TEST_RAM_SIZE, TEST_ADDR_W, TEST_RAM_NUM_PARTITIONS, + >( + buf_axi_aw_r, buf_axi_w_r, buf_axi_b_s, + buf_wr_req_s, buf_wr_resp_r + ); + + spawn mem_reader::MemReader( + buf_mem_rd_req_r, buf_mem_rd_resp_s, + buf_axi_ar_s, buf_axi_r_r + ); + spawn mem_writer::MemWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_WRITER_ID + >( + buf_mem_wr_req_r, buf_mem_wr_data_r, + buf_axi_aw_s, buf_axi_w_s, buf_axi_b_r, + buf_mem_wr_resp_s + ); + + spawn axi_ram_reader::AxiRamReader< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_RAM_SIZE + >( + input_axi_ar_r, input_axi_r_s, + input_rd_req_s, input_rd_resp_r + ); + spawn axi_ram_writer::AxiRamWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_ID_W, TEST_RAM_SIZE, TEST_ADDR_W, TEST_RAM_NUM_PARTITIONS, + >( + output_axi_aw_r, output_axi_w_r, output_axi_b_s, + output_wr_req_s, output_wr_resp_r + ); + + spawn mem_reader::MemReader( + mem_rd_req_r, mem_rd_resp_s, + input_axi_ar_s, input_axi_r_r + ); + spawn mem_writer::MemWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_WRITER_ID + >( + mem_wr_req_r, mem_wr_data_r, + output_axi_aw_s, output_axi_w_s, output_axi_b_r, + mem_wr_resp_s + ); + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn ram::RamModel< + TEST_HT_RAM_DATA_W, TEST_HT_SIZE, TEST_HT_RAM_WORD_PARTITION_SIZE, + TEST_HT_RAM_SIMULTANEOUS_READ_WRITE_BEHAVIOR, TEST_HT_RAM_INITIALIZED + >( + ht_ram_rd_req_r, ht_ram_rd_resp_s, + ht_ram_wr_req_r, ht_ram_wr_resp_s + ); + + unroll_for! (i, _) : (u32, ()) in u32:0..u32:8 { + spawn ram::RamModel< + TEST_HB_RAM_DATA_W, TEST_HB_RAM_SIZE, TEST_HB_RAM_PARTITION_SIZE, + TEST_HB_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_HB_RAM_INITIALIZED + >( + hb_ram_rd_req_r[i], hb_ram_rd_resp_s[i], + hb_ram_wr_req_r[i], hb_ram_wr_resp_s[i], + ); + }(()); + + spawn ram::RamModel< + TEST_FSE_CTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS + >( + ll_ctable_ram_rd_req_r, ll_ctable_ram_rd_resp_s, + ll_ctable_ram_wr_req_r, ll_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_FSE_CTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS + >( + ml_ctable_ram_rd_req_r, ml_ctable_ram_rd_resp_s, + ml_ctable_ram_wr_req_r, ml_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_FSE_CTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS + >( + of_ctable_ram_rd_req_r, of_ctable_ram_rd_resp_s, + of_ctable_ram_wr_req_r, of_ctable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_FSE_TTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS + >( + ll_ttable_ram_rd_req_r, ll_ttable_ram_rd_resp_s, + ll_ttable_ram_wr_req_r, ll_ttable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_FSE_TTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS + >( + ml_ttable_ram_rd_req_r, ml_ttable_ram_rd_resp_s, + ml_ttable_ram_wr_req_r, ml_ttable_ram_wr_resp_s, + ); + + spawn ram::RamModel< + TEST_FSE_TTABLE_RAM_DATA_W, TEST_RAM_SIZE, TEST_FSE_TABLE_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS + >( + of_ttable_ram_rd_req_r, of_ttable_ram_rd_resp_s, + of_ttable_ram_wr_req_r, of_ttable_ram_wr_resp_s, + ); + + spawn zstd_enc::ZstdEncoder< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, + TEST_RLE_HEURISTIC_SAMPLE_COUNT, + TEST_HB_SIZE, TEST_HB_DATA_W, TEST_HB_OFFSET_W, TEST_HB_RAM_ADDR_W, TEST_HB_RAM_DATA_W, TEST_HB_RAM_NUM, TEST_HB_RAM_NUM_PARTITIONS, + TEST_HT_SIZE, TEST_HT_KEY_W, TEST_HT_VALUE_W, TEST_HT_SIZE_W, TEST_HT_HASH_W, TEST_HT_RAM_DATA_W, TEST_HT_RAM_NUM_PARTITIONS, + TEST_MIN_SEQ_LEN, TEST_LITERALS_BUFFER_AXI_ADDR, TEST_SEQUENCE_BUFFER_AXI_ADDR, + TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_DATA_W, TEST_FSE_TTABLE_RAM_DATA_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS, + TEST_FSE_BITSTREAM_BUFFER_W + >( + enc_req_r, enc_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3], + n_mem_wr_req_s[4], n_mem_wr_data_s[4], n_mem_wr_resp_r[4], + n_mem_wr_req_s[5], n_mem_wr_data_s[5], n_mem_wr_resp_r[5], + n_mem_wr_req_s[6], n_mem_wr_data_s[6], n_mem_wr_resp_r[6], + buf_mem_wr_req_s, buf_mem_wr_data_s, buf_mem_wr_resp_r, + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + buf_mem_rd_req_s, buf_mem_rd_resp_r, + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + + ( + write_fse_tables_req_r, write_fse_tables_resp_s, + ll_ctable_ram_wr_req_s, ll_ctable_ram_wr_resp_r, + of_ctable_ram_wr_req_s, of_ctable_ram_wr_resp_r, + ml_ctable_ram_wr_req_s, ml_ctable_ram_wr_resp_r, + ll_ttable_ram_wr_req_s, ll_ttable_ram_wr_resp_r, + of_ttable_ram_wr_req_s, of_ttable_ram_wr_resp_r, + ml_ttable_ram_wr_req_s, ml_ttable_ram_wr_resp_r + ) + } + + next(state: ()) { + const CTMASK = all_ones!(); + const TTMASK = all_ones!(); + let tok = join(); + let (tok, _) = recv(tok, write_fse_tables_req_r); + + trace!("[TEST] Setting up the compression tables"); + + let tok = for ((i, v), tok) in enumerate(sequence_encoder::OF_DEFAULT_CTABLE) { + let tok = send(tok, of_ctable_ram_wr_req_s, TestCTableRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, of_ctable_ram_wr_resp_r); + tok + }(tok); + + let tok = for ((i, v), tok) in enumerate(sequence_encoder::LL_DEFAULT_CTABLE) { + let tok = send(tok, ll_ctable_ram_wr_req_s, TestCTableRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, ll_ctable_ram_wr_resp_r); + tok + }(tok); + + let tok = for ((i, v), tok) in enumerate(sequence_encoder::ML_DEFAULT_CTABLE) { + let tok = send(tok, ml_ctable_ram_wr_req_s, TestCTableRamWrReq{addr: i, data: v, mask: CTMASK}); + let (tok, _) = recv(tok, ml_ctable_ram_wr_resp_r); + tok + }(tok); + + trace!("[TEST] Setting up the transform tables"); + + let tok = for ((i, tt), tok) in enumerate(sequence_encoder::OF_DEFAULT_TTABLE) { + let tok = send(tok, of_ttable_ram_wr_req_s, TestTTableRamWrReq{addr: i, data: sequence_encoder::serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, of_ttable_ram_wr_resp_r); + tok + }(tok); + + let tok = for ((i, tt), tok) in enumerate(sequence_encoder::LL_DEFAULT_TTABLE) { + let tok = send(tok, ll_ttable_ram_wr_req_s, TestTTableRamWrReq{addr: i, data: sequence_encoder::serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, ll_ttable_ram_wr_resp_r); + tok + }(tok); + + let tok = for ((i, tt), tok) in enumerate(sequence_encoder::ML_DEFAULT_TTABLE) { + let tok = send(tok, ml_ttable_ram_wr_req_s, TestTTableRamWrReq{addr: i, data: sequence_encoder::serialize_tt(tt), mask: TTMASK}); + let (tok, _) = recv(tok, ml_ttable_ram_wr_resp_r); + tok + }(tok); + let tok = send(tok, write_fse_tables_resp_s, ()); + } +} + + +#[test_proc] +proc ZstdEncoderRawTest { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + input_wr_req_s: chan out; + input_wr_resp_r: chan in; + output_rd_req_s: chan out; + output_rd_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + let (input_wr_req_s, input_wr_req_r) = chan("input_wr_req"); + let (input_wr_resp_s, input_wr_resp_r) = chan("input_wr_resp"); + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + + let (_, stub0_r) = chan<()>("stub0"); + let (stub1_s, _) = chan<()>("stub1"); + + spawn ZstdEncoderTestBase ( + stub0_r, stub1_s, + input_wr_req_r, input_wr_resp_s, + output_rd_req_r, output_rd_resp_s, + enc_req_r, enc_resp_s + ); + + ( + input_wr_req_s, input_wr_resp_r, + output_rd_req_s, output_rd_resp_r, + enc_req_s, enc_resp_r, + terminator + ) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // write input data to RAM + let tok = for ((i, data), tok): ((u32, u32), token) in enumerate(TEST_INPUT_DATA) { + let tok = send(tok, input_wr_req_s, TestWriteReq { + addr: i as Addr, + data: data, + mask: all_ones!(), + }); + let (tok, _) = recv(tok, input_wr_resp_r); + tok + }(join()); + + trace_fmt!("Request: encode data of size: {:#x} bytes", TEST_INPUT_SIZE_BYTES); + // send request to encoder + let tok = send(tok, enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: TEST_INPUT_SIZE_BYTES as uN[TEST_RAM_DATA_W], + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: TEST_MAX_BLOCK_SIZE, + params: zero!() + }); + let (tok, resp) = recv(tok, enc_resp_r); + assert_eq(resp.status, ZstdEncodeRespStatus::OK); + + // read state of output RAM + let tok = for ((i, expected_val), tok): ((u32, u32), token) in enumerate(TEST_EXPECTED) { + let tok = send(tok, output_rd_req_s, TestReadReq { + addr: i as Addr, + mask: all_ones!(), + }); + let (tok, data) = recv(tok, output_rd_resp_r); + + if (data.data != expected_val) { + trace_fmt!("at index {} the expected value is {:#x}, the outcome is {:#x}", i, expected_val, data.data); + } else { }; + + assert_eq(data.data, expected_val); + tok + }(join()); + + send(join(), terminator, true); + } +} + +// Faulty MemReader used to test reponses of the Encoder in case memory read fails. +proc MemReaderFaultResponder { + type Req = mem_reader::MemReaderReq; + type Resp = mem_reader::MemReaderResp; + type Status = mem_reader::MemReaderStatus; + + req_r: chan in; + resp_s: chan out; + + config( + req_r: chan in, + resp_s: chan out, + ) { + (req_r, resp_s) + } + + init {} + next(state: ()) { + let (tok, _req) = recv(join(), req_r); + let tok = send(tok, resp_s, Resp { + status: Status::ERROR, + data: uN[TEST_AXI_DATA_W]:0, + length: uN[TEST_AXI_ADDR_W]:0, + last: true, + }); + } +} + +#[test_proc] +proc ZstdEncoderReadFaultTest { + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + output_rd_req_s: chan out; + output_rd_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + // IO for Encoder <-> test + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + // IO for MemReader <-> Encoder + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + // IO for output RAM + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (output_wr_req_s, output_wr_req_r) = chan("output_wr_req"); + let (output_wr_resp_s, output_wr_resp_r) = chan("output_wr_resp"); + // IO for AxiRamWriter <-> MemWriter + let (output_axi_aw_s, output_axi_aw_r) = chan("output_axi_aw"); + let (output_axi_w_s, output_axi_w_r) = chan("output_axi_w"); + let (output_axi_b_s, output_axi_b_r) = chan("output_axi_b"); + // IO for MemWriter <-> Encoder + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[8]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[8]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[8]("n_resp"); + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[4]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[4]("n_mem_rd_resp"); + let (hb_ram_rd_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_req"); + let (_, hb_ram_rd_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_resp"); + let (hb_ram_wr_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_req"); + let (_, hb_ram_wr_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_resp"); + let (ht_ram_rd_req_s, _) = chan("ht_ram_rd_req"); + let (_, ht_ram_rd_resp_r) = chan("ht_ram_rd_resp"); + let (ht_ram_wr_req_s, _) = chan("ht_ram_wr_req"); + let (_, ht_ram_wr_resp_r) = chan("ht_ram_wr_resp"); + let (ml_ctable_ram_rd_req_s, _) = chan("ml_ctable_ram_rd_req"); + let (_, ml_ctable_ram_rd_resp_r) = chan("ml_ctable_ram_rd_resp"); + let (ll_ctable_ram_rd_req_s, _) = chan("ll_ctable_ram_rd_req"); + let (_, ll_ctable_ram_rd_resp_r) = chan("ll_ctable_ram_rd_resp"); + let (of_ctable_ram_rd_req_s, _) = chan("of_ctable_ram_rd_req"); + let (_, of_ctable_ram_rd_resp_r) = chan("of_ctable_ram_rd_resp"); + let (ml_ttable_ram_rd_req_s, _) = chan("ml_ttable_ram_rd_req"); + let (_, ml_ttable_ram_rd_resp_r) = chan("ml_ttable_ram_rd_resp"); + let (ll_ttable_ram_rd_req_s, _) = chan("ll_ttable_ram_rd_req"); + let (_, ll_ttable_ram_rd_resp_r) = chan("ll_ttable_ram_rd_resp"); + let (of_ttable_ram_rd_req_s, _) = chan("of_ttable_ram_rd_req"); + let (_, of_ttable_ram_rd_resp_r) = chan("of_ttable_ram_rd_resp"); + + spawn MemReaderFaultResponder( + mem_rd_req_r, mem_rd_resp_s, + ); + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, + TEST_RAM_ASSERT_VALID_READ, TEST_ADDR_W + >( + output_rd_req_r, output_rd_resp_s, + output_wr_req_r, output_wr_resp_s + ); + spawn axi_ram_writer::AxiRamWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_ID_W, TEST_RAM_SIZE, TEST_ADDR_W, TEST_RAM_NUM_PARTITIONS, + >( + output_axi_aw_r, output_axi_w_r, output_axi_b_s, + output_wr_req_s, output_wr_resp_r + ); + spawn mem_writer::MemWriter< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_WRITER_ID + >( + mem_wr_req_r, mem_wr_data_r, + output_axi_aw_s, output_axi_w_s, output_axi_b_r, + mem_wr_resp_s + ); + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn zstd_enc::ZstdEncoder< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, + TEST_RLE_HEURISTIC_SAMPLE_COUNT, + TEST_HB_SIZE, TEST_HB_DATA_W, TEST_HB_OFFSET_W, TEST_HB_RAM_ADDR_W, TEST_HB_RAM_DATA_W, TEST_HB_RAM_NUM, TEST_HB_RAM_NUM_PARTITIONS, + TEST_HT_SIZE, TEST_HT_KEY_W, TEST_HT_VALUE_W, TEST_HT_SIZE_W, TEST_HT_HASH_W, TEST_HT_RAM_DATA_W, TEST_HT_RAM_NUM_PARTITIONS, + TEST_MIN_SEQ_LEN, TEST_LITERALS_BUFFER_AXI_ADDR, TEST_SEQUENCE_BUFFER_AXI_ADDR, + TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_DATA_W, TEST_FSE_TTABLE_RAM_DATA_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS, + TEST_FSE_BITSTREAM_BUFFER_W + >( + enc_req_r, enc_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3], + n_mem_wr_req_s[4], n_mem_wr_data_s[4], n_mem_wr_resp_r[4], + n_mem_wr_req_s[5], n_mem_wr_data_s[5], n_mem_wr_resp_r[5], + n_mem_wr_req_s[6], n_mem_wr_data_s[6], n_mem_wr_resp_r[6], + n_mem_wr_req_s[7], n_mem_wr_data_s[7], n_mem_wr_resp_r[7], + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + n_mem_rd_req_s[3], n_mem_rd_resp_r[3], + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + ( + output_rd_req_s, output_rd_resp_r, + enc_req_s, enc_resp_r, + terminator + ) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // send request to encoder + let tok = send(join(), enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: TEST_INPUT_SIZE as uN[TEST_RAM_DATA_W], + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: TEST_MAX_BLOCK_SIZE, + params: zero!() + }); + let (tok, resp) = recv(tok, enc_resp_r); + + // expect error due to the faulty (on purpose) MemReader + assert_eq(resp.status, ZstdEncodeRespStatus::ERROR); + + send(join(), terminator, true); + } +} + +// Faulty MemWriter used to test reponses of the Encoder in case memory write fails. +proc MemWriterFaultResponder { + req_r: chan in; + data_r: chan in; + resp_s: chan out; + + config( + req_r: chan in, + data_r: chan in, + resp_s: chan out, + ) { + (req_r, data_r, resp_s) + } + + init {} + next(state: ()) { + let (tok, _req) = recv(join(), req_r); + let (tok, _data) = recv(tok, data_r); + let tok = send(tok, resp_s, TestMemWriterResp { + status: TestMemWriterStatus::ERROR, + }); + } +} + +#[test_proc] +proc ZstdEncoderWriteFaultTest { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + input_wr_req_s: chan out; + input_wr_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + // IO for Encoder <-> test + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + // IO for input RAM + let (input_rd_req_s, input_rd_req_r) = chan("input_rd_req"); + let (input_rd_resp_s, input_rd_resp_r) = chan("input_rd_resp"); + let (input_wr_req_s, input_wr_req_r) = chan("input_wr_req"); + let (input_wr_resp_s, input_wr_resp_r) = chan("input_wr_resp"); + // IO for AxiRamReader <-> MemReader + let (input_axi_ar_s, input_axi_ar_r) = chan("input_axi_ar"); + let (input_axi_r_s, input_axi_r_r) = chan("input_axi_r"); + // IO for MemWriter <-> Encoder + let (mem_wr_req_s, mem_wr_req_r) = chan("mem_wr_req"); + let (mem_wr_data_s, mem_wr_data_r) = chan("mem_wr_data"); + let (mem_wr_resp_s, mem_wr_resp_r) = chan("mem_wr_resp"); + // IO for MemReader <-> Encoder + let (mem_rd_req_s, mem_rd_req_r) = chan("mem_rd_req"); + let (mem_rd_resp_s, mem_rd_resp_r) = chan("mem_rd_resp"); + + spawn ram::RamModel< + TEST_RAM_DATA_W, TEST_RAM_SIZE, TEST_RAM_WORD_PARTITION_SIZE, + TEST_RAM_SIMULTANEOUS_RW_BEHAVIOR, TEST_RAM_INITIALIZED, TEST_RAM_ASSERT_VALID_READ, TEST_AXI_ADDR_W + >( + input_rd_req_r, input_rd_resp_s, + input_wr_req_r, input_wr_resp_s + ); + + + + spawn axi_ram_reader::AxiRamReader< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, TEST_AXI_DEST_W, TEST_AXI_ID_W, TEST_RAM_SIZE + >( + input_axi_ar_r, input_axi_r_s, + input_rd_req_s, input_rd_resp_r + ); + + spawn mem_reader::MemReader( + mem_rd_req_r, mem_rd_resp_s, + input_axi_ar_s, input_axi_r_r + ); + + // faulty MemWriter + spawn MemWriterFaultResponder( + mem_wr_req_r, mem_wr_data_r, mem_wr_resp_s + ); + + let (n_mem_wr_req_s, n_mem_wr_req_r) = chan[8]("n_req"); + let (n_mem_wr_data_s, n_mem_wr_data_r) = chan[8]("n_data"); + let (n_mem_wr_resp_s, n_mem_wr_resp_r) = chan[8]("n_resp"); + let (n_mem_rd_req_s, n_mem_rd_req_r) = chan[4]("n_mem_rd_req"); + let (n_mem_rd_resp_s, n_mem_rd_resp_r) = chan[4]("n_mem_rd_resp"); + let (hb_ram_rd_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_req"); + let (_, hb_ram_rd_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_rd_resp"); + let (hb_ram_wr_req_s, _) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_req"); + let (_, hb_ram_wr_resp_r) = chan[TEST_HB_RAM_NUM]("hb_ram_wr_resp"); + let (ht_ram_rd_req_s, _) = chan("ht_ram_rd_req"); + let (_, ht_ram_rd_resp_r) = chan("ht_ram_rd_resp"); + let (ht_ram_wr_req_s, _) = chan("ht_ram_wr_req"); + let (_, ht_ram_wr_resp_r) = chan("ht_ram_wr_resp"); + let (ml_ctable_ram_rd_req_s, _) = chan("ml_ctable_ram_rd_req"); + let (_, ml_ctable_ram_rd_resp_r) = chan("ml_ctable_ram_rd_resp"); + let (ll_ctable_ram_rd_req_s, _) = chan("ll_ctable_ram_rd_req"); + let (_, ll_ctable_ram_rd_resp_r) = chan("ll_ctable_ram_rd_resp"); + let (of_ctable_ram_rd_req_s, _) = chan("of_ctable_ram_rd_req"); + let (_, of_ctable_ram_rd_resp_r) = chan("of_ctable_ram_rd_resp"); + let (ml_ttable_ram_rd_req_s, _) = chan("ml_ttable_ram_rd_req"); + let (_, ml_ttable_ram_rd_resp_r) = chan("ml_ttable_ram_rd_resp"); + let (ll_ttable_ram_rd_req_s, _) = chan("ll_ttable_ram_rd_req"); + let (_, ll_ttable_ram_rd_resp_r) = chan("ll_ttable_ram_rd_resp"); + let (of_ttable_ram_rd_req_s, _) = chan("of_ttable_ram_rd_req"); + let (_, of_ttable_ram_rd_resp_r) = chan("of_ttable_ram_rd_resp"); + + spawn mem_writer_simple_arbiter::MemWriterSimpleArbiter + ( + n_mem_wr_req_r, n_mem_wr_data_r, n_mem_wr_resp_s, + mem_wr_req_s, mem_wr_data_s, mem_wr_resp_r, + ); + + spawn mem_reader_simple_arbiter::MemReaderSimpleArbiter ( + n_mem_rd_req_r, n_mem_rd_resp_s, + mem_rd_req_s, mem_rd_resp_r, + ); + + spawn zstd_enc::ZstdEncoder< + TEST_AXI_ADDR_W, TEST_AXI_DATA_W, + TEST_RLE_HEURISTIC_SAMPLE_COUNT, + TEST_HB_SIZE, TEST_HB_DATA_W, TEST_HB_OFFSET_W, TEST_HB_RAM_ADDR_W, TEST_HB_RAM_DATA_W, TEST_HB_RAM_NUM, TEST_HB_RAM_NUM_PARTITIONS, + TEST_HT_SIZE, TEST_HT_KEY_W, TEST_HT_VALUE_W, TEST_HT_SIZE_W, TEST_HT_HASH_W, TEST_HT_RAM_DATA_W, TEST_HT_RAM_NUM_PARTITIONS, + TEST_MIN_SEQ_LEN, TEST_LITERALS_BUFFER_AXI_ADDR, TEST_SEQUENCE_BUFFER_AXI_ADDR, + TEST_FSE_TABLE_RAM_ADDR_W, TEST_FSE_CTABLE_RAM_DATA_W, TEST_FSE_TTABLE_RAM_DATA_W, TEST_FSE_CTABLE_RAM_NUM_PARTITIONS, TEST_FSE_TTABLE_RAM_NUM_PARTITIONS, + TEST_FSE_BITSTREAM_BUFFER_W + >( + enc_req_r, enc_resp_s, + n_mem_wr_req_s[0], n_mem_wr_data_s[0], n_mem_wr_resp_r[0], + n_mem_wr_req_s[1], n_mem_wr_data_s[1], n_mem_wr_resp_r[1], + n_mem_wr_req_s[2], n_mem_wr_data_s[2], n_mem_wr_resp_r[2], + n_mem_wr_req_s[3], n_mem_wr_data_s[3], n_mem_wr_resp_r[3], + n_mem_wr_req_s[4], n_mem_wr_data_s[4], n_mem_wr_resp_r[4], + n_mem_wr_req_s[5], n_mem_wr_data_s[5], n_mem_wr_resp_r[5], + n_mem_wr_req_s[6], n_mem_wr_data_s[6], n_mem_wr_resp_r[6], + n_mem_wr_req_s[7], n_mem_wr_data_s[7], n_mem_wr_resp_r[7], + n_mem_rd_req_s[0], n_mem_rd_resp_r[0], + n_mem_rd_req_s[1], n_mem_rd_resp_r[1], + n_mem_rd_req_s[2], n_mem_rd_resp_r[2], + n_mem_rd_req_s[3], n_mem_rd_resp_r[3], + hb_ram_rd_req_s, hb_ram_rd_resp_r, hb_ram_wr_req_s, hb_ram_wr_resp_r, + ht_ram_rd_req_s, ht_ram_rd_resp_r, ht_ram_wr_req_s, ht_ram_wr_resp_r, + ml_ctable_ram_rd_req_s, ml_ctable_ram_rd_resp_r, + ll_ctable_ram_rd_req_s, ll_ctable_ram_rd_resp_r, + of_ctable_ram_rd_req_s, of_ctable_ram_rd_resp_r, + ml_ttable_ram_rd_req_s, ml_ttable_ram_rd_resp_r, + ll_ttable_ram_rd_req_s, ll_ttable_ram_rd_resp_r, + of_ttable_ram_rd_req_s, of_ttable_ram_rd_resp_r + ); + + ( + input_wr_req_s, input_wr_resp_r, + enc_req_s, enc_resp_r, + terminator + ) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // write input data to RAM + let tok = for ((i, data), tok): ((u32, u32), token) in enumerate(TEST_INPUT_DATA) { + let tok = send(tok, input_wr_req_s, TestWriteReq { + addr: i as Addr, + data: data, + mask: all_ones!(), + }); + let (tok, _) = recv(tok, input_wr_resp_r); + tok + }(join()); + + // send request to encoder + let tok = send(tok, enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: TEST_INPUT_SIZE as uN[TEST_RAM_DATA_W], + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: TEST_MAX_BLOCK_SIZE, + params: zero!() + }); + let (tok, resp) = recv(tok, enc_resp_r); + + // expect error due to the faulty (on purpose) MemWriter + assert_eq(resp.status, ZstdEncodeRespStatus::ERROR); + + send(join(), terminator, true); + } +} + +#[test_proc] +proc ZstdEncoderRleBlockTest { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + input_wr_req_s: chan out; + input_wr_resp_r: chan in; + output_rd_req_s: chan out; + output_rd_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + let (input_wr_req_s, input_wr_req_r) = chan("input_wr_req"); + let (input_wr_resp_s, input_wr_resp_r) = chan("input_wr_resp"); + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + let (_, stub0_r) = chan<()>("stub0"); + let (stub1_s, _) = chan<()>("stub1"); + + spawn ZstdEncoderTestBase ( + stub0_r, stub1_s, + input_wr_req_r, input_wr_resp_s, + output_rd_req_r, output_rd_resp_s, + enc_req_r, enc_resp_s + ); + + ( + input_wr_req_s, input_wr_resp_r, + output_rd_req_s, output_rd_resp_r, + enc_req_s, enc_resp_r, + terminator + ) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // write input data to RAM + let tok = for ((i, data), tok): ((u32, u32), token) in enumerate(TEST_RLE_INPUT_DATA) { + let tok = send(tok, input_wr_req_s, TestWriteReq { + addr: i as Addr, + data: data, + mask: all_ones!(), + }); + let (tok, _) = recv(tok, input_wr_resp_r); + tok + }(join()); + + trace_fmt!("Request: encode data of size: {:#x} bytes", TEST_RLE_INPUT_SIZE_BYTES); + // send request to encoder + let tok = send(tok, enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: TEST_RLE_INPUT_SIZE_BYTES as uN[TEST_RAM_DATA_W], + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: u32:32, + params: zstd_enc::ZstdEncodeParams { + enable_rle: true, + enable_compressed: false + } + }); + let (tok, resp) = recv(tok, enc_resp_r); + assert_eq(resp.status, ZstdEncodeRespStatus::OK); + + // read state of output RAM + let tok = for ((i, expected_val), tok): ((u32, u32), token) in enumerate(TEST_RLE_EXPECTED) { + let tok = send(tok, output_rd_req_s, TestReadReq { + addr: i as Addr, + mask: all_ones!(), + }); + let (tok, data) = recv(tok, output_rd_resp_r); + + if (data.data != expected_val) { + trace_fmt!("at index {} the expected value is {:#x}, the outcome is {:#x}", i, expected_val, data.data); + } else { }; + + assert_eq(data.data, expected_val); + tok + }(join()); + + send(join(), terminator, true); + } +} + +#[test_proc] +proc ZstdEncoderRawLiteralsPredefinedSequencesTest { + type AxiAr = axi::AxiAr; + type AxiR = axi::AxiR; + type AxiAw = axi::AxiAw; + type AxiW = axi::AxiW; + type AxiB = axi::AxiB; + + write_fse_tables_req_s: chan<()> out; + write_fse_tables_resp_r: chan<()> in; + input_wr_req_s: chan out; + input_wr_resp_r: chan in; + output_rd_req_s: chan out; + output_rd_resp_r: chan in; + enc_req_s: chan out; + enc_resp_r: chan in; + terminator: chan out; + + init { } + + config(terminator: chan out) { + let (input_wr_req_s, input_wr_req_r) = chan("input_wr_req"); + let (input_wr_resp_s, input_wr_resp_r) = chan("input_wr_resp"); + let (output_rd_req_s, output_rd_req_r) = chan("output_rd_req"); + let (output_rd_resp_s, output_rd_resp_r) = chan("output_rd_resp"); + let (enc_req_s, enc_req_r) = chan("enc_req"); + let (enc_resp_s, enc_resp_r) = chan("enc_resp"); + let (write_fse_tables_req_s, write_fse_tables_req_r) = chan<()>("write_fse_tables_req"); + let (write_fse_tables_resp_s, write_fse_tables_resp_r) = chan<()>("write_fse_tables_resp"); + + spawn ZstdEncoderTestBase ( + write_fse_tables_req_r, write_fse_tables_resp_s, + input_wr_req_r, input_wr_resp_s, + output_rd_req_r, output_rd_resp_s, + enc_req_r, enc_resp_s + ); + + ( + write_fse_tables_req_s, write_fse_tables_resp_r, + input_wr_req_s, input_wr_resp_r, + output_rd_req_s, output_rd_resp_r, + enc_req_s, enc_resp_r, + terminator + ) + } + + next(state: ()) { + type Addr = bits[TEST_ADDR_W]; + + // write input data to RAM + let tok = for ((i, data), tok): ((u32, u32), token) in enumerate(TEST_COMPRESSED_PREDEFINED_INPUT) { + let tok = send(tok, input_wr_req_s, TestWriteReq { + addr: i as Addr, + data: data, + mask: all_ones!(), + }); + let (tok, _) = recv(tok, input_wr_resp_r); + tok + }(join()); + + // write fse tables + let tok = send(tok, write_fse_tables_req_s, ()); + let (tok, _) = recv(tok, write_fse_tables_resp_r); + + trace_fmt!("Request: encode data of size: {:#x} bytes", TEST_COMPRESSED_PREDEFINED_INPUT_SIZE_BYTES); + // send request to encoder + let tok = send(tok, enc_req_s, TestZstdEncodeReq{ + input_offset: uN[TEST_ADDR_W]:0, + data_size: TEST_COMPRESSED_PREDEFINED_INPUT_SIZE_BYTES as uN[TEST_RAM_DATA_W], + output_offset: uN[TEST_ADDR_W]:0, + max_block_size: u32:32, + params: zstd_enc::ZstdEncodeParams { + enable_rle: false, + enable_compressed: true + } + }); + let (tok, resp) = recv(tok, enc_resp_r); + assert_eq(resp.status, ZstdEncodeRespStatus::OK); + + // read state of output RAM + let tok = for ((i, expected_val), tok): ((u32, u32), token) in enumerate(TEST_COMPRESS_PREDEFINED_EXPECTED) { + let tok = send(tok, output_rd_req_s, TestReadReq { + addr: i as Addr, + mask: all_ones!(), + }); + let (tok, data) = recv(tok, output_rd_resp_r); + + if (data.data != expected_val) { + trace_fmt!("at index {} the expected value is {:#x}, the outcome is {:#x}", i, expected_val, data.data); + } else { }; + + assert_eq(data.data, expected_val); + tok + }(join()); + + send(join(), terminator, true); + } +} diff --git a/xls/modules/zstd/zstd_frame_dslx.py b/xls/modules/zstd/zstd_frame_dslx.py new file mode 100644 index 0000000000..c5ad2e177b --- /dev/null +++ b/xls/modules/zstd/zstd_frame_dslx.py @@ -0,0 +1,155 @@ +# Copyright 2024 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. + +"""ZSTD test frame generator for DSLX tests. + +This module interacts with the data_generator module and underlying +Decodecorpus in order to generate inputs and expected outputs for the ZSTD +Decoder tests in DSLX. + +It generates the ZSTD frame and then decodes it with the reference ZSTD +library. Both the encoded frame and decoded data are written to a DSLX file by +converting raw bytes of the frame and decoded data into DSLX structures. + +Resulting file can be included in the ZSTD Decoder DSLX test and used as the +inputs and expected output for the testbench. +""" + +import argparse +import math +import random +import tempfile +import pathlib + +from xls.modules.zstd.cocotb import data_generator + + +def GenerateTestData(seed, btype): + with tempfile.NamedTemporaryFile() as tmp: + data_generator.GenerateFrame(seed, btype, tmp.name) + tmp.seek(0) + return tmp.read() + + +def Bytes2DSLX(frames, bytes_per_word, array_name): + """Converts a list of byte frames to a DSLX constant array declaration. + + Args: + frames (List[bytes]): List of byte sequences representing frames. + bytes_per_word (int): Number of bytes per word in the output format. + array_name (str): Name of the resulting DSLX constant array. + + Returns: + str: A string containing the DSLX constant array declaration. + """ + frames_hex = [] + maxlen = max(len(frame) for frame in frames) + maxlen_size = math.ceil(maxlen / bytes_per_word) + bits_per_word = bytes_per_word * 8 + for i, frame in enumerate(frames): + frame_hex = [] + for i in range(0, len(frame), bytes_per_word): + # reverse byte order to make them little endian + word = bytes(reversed(frame[i : i + bytes_per_word])).hex() + frame_hex.append(f"uN[{bits_per_word}]:0x{word}") + + array_length = len(frame_hex) + if len(frame) < maxlen: + frame_hex += [f"uN[{bits_per_word}]:0x0", "..."] + + frame_array = ( + f"DataArray<{bits_per_word}, {maxlen_size}>{{\n" + f" length: u32:{len(frame)},\n" + f" array_length: u32:{array_length},\n" + f" data: uN[{bits_per_word}][{maxlen_size}]:[{', '.join(frame_hex)}]\n" + f"}}" + ) + frames_hex.append(frame_array) + + frames_str = ",\n".join(frames_hex) + frames_array = ( + f"pub const {array_name}:DataArray<\n" + f" u32:{bits_per_word},\n" + f" u32:{maxlen_size}\n" + f">[{len(frames_hex)}] = [{frames_str}];\n" + ) + return frames_array + + +def GenerateDataStruct(): + return ( + "pub struct DataArray{\n" + " data: uN[BITS_PER_WORD][LENGTH],\n" + " length: u32,\n" + " array_length: u32\n" + "}\n" + ) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-n", help="Number of testcases to generate", type=int, default=1 + ) + parser.add_argument( + "--seed", help="Seed for the testcases generator", type=int, default=0 + ) + parser.add_argument( + "--btype", + help=( + "Block types allowed in the generated testcases. If multiple block types " + "are supplied, generated testcases will cycle through them" + ), + type=data_generator.BlockType.from_string, + choices=list(data_generator.BlockType), + default=data_generator.BlockType.RANDOM, + nargs="+", + ) + parser.add_argument( + "-o", + "--output", + help="Filename of the DSLX output file", + type=pathlib.Path, + default=pathlib.Path("frames_test_data.x"), + ) + parser.add_argument( + "--bytes-per-word", + help="Width of a word in memory, in bytes", + type=int, + default=8, + ) + args = parser.parse_args() + + random.seed(args.seed) + byte_frames = [ + GenerateTestData(random.randrange(2**32), args.btype[i % len(args.btype)]) + for i in range(args.n) + ] + with open(args.output, "w") as dslx_output: + dslx_output.write(GenerateDataStruct()) + + dslx_frames = Bytes2DSLX(byte_frames, args.bytes_per_word, "FRAMES") + dslx_output.write(dslx_frames) + + byte_frames_decompressed = list( + map(data_generator.DecompressFrame, byte_frames) + ) + dslx_frames_decompressed = Bytes2DSLX( + byte_frames_decompressed, args.bytes_per_word, "DECOMPRESSED_FRAMES" + ) + dslx_output.write(dslx_frames_decompressed) + + +if __name__ == "__main__": + main() diff --git a/xls/modules/zstd/zstd_test_debugger.py b/xls/modules/zstd/zstd_test_debugger.py new file mode 100644 index 0000000000..95c26a49ad --- /dev/null +++ b/xls/modules/zstd/zstd_test_debugger.py @@ -0,0 +1,743 @@ +# Copyright 2025 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. + +"""ZSTD test debugger for cocotb tests. + +This module iterates over given ZSTD-encoded file and finds +the executed sequence which is decoded into the nth byte +specified with `--byte` flag. It skips decoding literals +and executing sequences, because it only cares about how +much data is decoded in each block and from which sequence +comes given decoded byte. + +For ZSTD reference, see https://www.rfc-editor.org/rfc/rfc8878.html +""" + +import argparse +import pathlib +import sys +from enum import Enum + +class BlockType(Enum): + RAW_BLOCK = 0 + RLE_BLOCK = 1 + COMPRESSED_BLOCK = 2 + +class BlockHeader: + def __init__(self, last_block, block_type, block_content_size): + self.last_block = last_block + self.block_type = block_type + self.block_content_size = block_content_size + +class LiteralsBlockType(Enum): + RAW_LITERALS_BLOCK = 0 + RLE_LITERALS_BLOCK = 1 + COMPRESSED_LITERALS_BLOCK = 2 + TREELESS_LITERALS_BLOCK = 3 + +class LiteralsSectionHeader: + def __init__(self, block_type, regenerated_size, compressed_size = 0, has_four_streams = False): + self.block_type = block_type + self.regenerated_size = regenerated_size + self.compressed_size = compressed_size + self.has_four_streams = has_four_streams + +def read_magic_number(encoded_file): + magic_number = int.from_bytes(encoded_file.read(4)) + print(f"Magic number: {hex(magic_number)}") + +def read_frame_header(encoded_file): + frame_header_descriptor = int.from_bytes(encoded_file.read(1)) + print(f"Frame header descriptor: {hex(frame_header_descriptor)}") + + # 6th bit of a frame header indicates if a window descriptor is present + SINGLE_SEGMENT_FLAG_MASK = 0b100000 + if frame_header_descriptor & SINGLE_SEGMENT_FLAG_MASK == 0: + # Calculate a required window_size for the encoded file + # and compare it with the ZSTD decoder history buffer size. + # Based on window_size calculation from: RFC 8878 + # https://datatracker.ietf.org/doc/html/rfc8878#name-window-descriptor + window_descriptor = int.from_bytes(encoded_file.read(1)) + + MANTISSA_BITS = 0b111 + mantissa = window_descriptor & MANTISSA_BITS + + EXPONENT_BITS = 0b11111000 + exponent = (window_descriptor & EXPONENT_BITS) >> 3 + + window_log = 10 + exponent + window_base = 1 << window_log + window_add = (window_base / 8) * mantissa + window_size = int(window_base + window_add) + print(f"Required window size: {window_size} bytes") + + DICTIONARY_ID_MASK = 0b11 + if frame_header_descriptor & DICTIONARY_ID_MASK != 0: + dictionary_id_size = 2 ** ((frame_header_descriptor & DICTIONARY_ID_MASK) - 1) + dictionary_id = encoded_file.read(dictionary_id_size) + print(f"Dictionary ID: {dictionary_id.hex()}") + + frame_content_size_flag = frame_header_descriptor >> 6 + if frame_content_size_flag == 0: + fcs_field_size = (frame_header_descriptor & SINGLE_SEGMENT_FLAG_MASK) != 0 + else: + fcs_field_size = 2 ** frame_content_size_flag + + if fcs_field_size != 0: + frame_content_size = int.from_bytes(encoded_file.read(fcs_field_size), byteorder="little") + print(f"Frame content used bytes: {fcs_field_size}") + print(f"Frame content size: {frame_content_size}") + +def read_block_header(encoded_file, block_starting_byte_index): + encoded_file.seek(block_starting_byte_index) + block_header_bytes = encoded_file.read(3) + block_header = int.from_bytes(block_header_bytes, byteorder="little") + + LAST_BLOCK_FLAG_MASK = 0b1 + last_block_flag = block_header & LAST_BLOCK_FLAG_MASK + + BLOCK_TYPE_FLAG_MASK = 0b110 + block_type_flag = (block_header & BLOCK_TYPE_FLAG_MASK) >> 1 + + block_size = block_header >> 3 + block_content_size = block_size + if block_type_flag == BlockType.RLE_BLOCK: + block_content_size = 1 + + return BlockHeader(last_block_flag, block_type_flag, block_content_size) + +def find_block_containing_byte_index(encoded_file, byte_index): + current_byte_index = encoded_file.tell() + while current_byte_index < byte_index: + last_block_starting_byte_index = current_byte_index + block_header = read_block_header(encoded_file, current_byte_index) + print(f"Block at {last_block_starting_byte_index}:") + print(f" Last block flag: {block_header.last_block}") + print(f" Block content type: {block_header.block_type}") + print(f" Block content size: {block_header.block_content_size}") + current_byte_index = encoded_file.tell() + block_header.block_content_size + encoded_file.seek(current_byte_index) + + print(f"Block containing index is located at position {last_block_starting_byte_index}") + + return last_block_starting_byte_index + +def read_literals_section_header(encoded_file): + literal_section_header = encoded_file.read(1) + + LITERALS_BLOCK_TYPE_MASK = 0b11 + literals_block_type = LiteralsBlockType(literal_section_header[0] & LITERALS_BLOCK_TYPE_MASK) + + size_format = (literal_section_header[0] >> 2) & 0b11 + if (literals_block_type == LiteralsBlockType.RAW_LITERALS_BLOCK or + literals_block_type == LiteralsBlockType.RLE_LITERALS_BLOCK): + + if size_format == 0b00 or size_format == 0b10: + regenerated_size = literal_section_header[0] >> 3 + + return LiteralsSectionHeader(literals_block_type, regenerated_size) + + if size_format == 0b01: + literal_section_header_second_byte = encoded_file.read(1) + + regenerated_size = (literal_section_header[0] >> 4) + (literal_section_header_second_byte[0] << 4) + + return LiteralsSectionHeader(literals_block_type, regenerated_size) + + if size_format == 0b11: + literal_section_header_remaining_bytes = encoded_file.read(2) + + regenerated_size = ((literal_section_header[0] >> 4) + + (literal_section_header_remaining_bytes[0] << 4) + + (literal_section_header_remaining_bytes[1] << 12)) + + return LiteralsSectionHeader(literals_block_type, regenerated_size) + + if (literals_block_type == LiteralsBlockType.COMPRESSED_LITERALS_BLOCK or + literals_block_type == LiteralsBlockType.TREELESS_LITERALS_BLOCK): + + if size_format == 0b00 or size_format == 0b01: + literal_section_header_remaining_bytes = encoded_file.read(2) + + regenerated_size = (literal_section_header[0] >> 4) + ((literal_section_header_remaining_bytes[0] & 0b111111) << 4) + compressed_size = (literal_section_header_remaining_bytes[0] >> 6) + (literal_section_header_remaining_bytes[1] << 2) + has_four_streams = size_format == 0b01 + + return LiteralsSectionHeader(literals_block_type, regenerated_size, compressed_size, has_four_streams) + + if size_format == 0b10: + literal_section_header_remaining_bytes = encoded_file.read(3) + + regenerated_size = ((literal_section_header[0] >> 4) + + (literal_section_header_remaining_bytes[0] << 4) + + ((literal_section_header_remaining_bytes[1] & 0b11) << 12)) + compressed_size = ((literal_section_header_remaining_bytes[1] >> 2) + + (literal_section_header_remaining_bytes[2] << 6)) + has_four_streams = True + + return LiteralsSectionHeader(literals_block_type, regenerated_size, compressed_size, has_four_streams) + + if size_format == 0b11: + literal_section_header_remaining_bytes = encoded_file.read(4) + + regenerated_size = ((literal_section_header[0] >> 4) + + (literal_section_header_remaining_bytes[0] << 4) + + ((literal_section_header_remaining_bytes[1] & 0b111111) << 12)) + compressed_size = ((literal_section_header_remaining_bytes[1] >> 6) + + (literal_section_header_remaining_bytes[2] << 2) + + (literal_section_header_remaining_bytes[3] << 10)) + has_four_streams = True + + return LiteralsSectionHeader(literals_block_type, regenerated_size, compressed_size, has_four_streams) + +class SymbolCompressionMode(Enum): + PREDEFINED_MODE = 0 + RLE_MODE = 1 + FSE_COMPRESSED_MODE = 2 + REPEAT_MODE = 3 + +# The predefined FSE distribution tables for PREDEFINED_MODE +# https://datatracker.ietf.org/doc/html/rfc8878#name-default-distributions +LITERALS_LENGTH_DEFAULT_DIST = [ + 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, -1, -1, -1, -1] +MATCH_LENGTHS_DEFAULT_DIST = [ + 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1] +OFFSET_CODES_DEFAULT_DIST = [ + 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1] + +class SequencesSectionHeader: + def __init__(self, num_of_sequences = 0, symbol_compression_modes = 0): + self.num_of_sequences = num_of_sequences + + self.literal_lengths_mode = SymbolCompressionMode(symbol_compression_modes >> 6) + self.offsets_mode = SymbolCompressionMode((symbol_compression_modes >> 4) & 0b11) + self.match_lengths_mode = SymbolCompressionMode((symbol_compression_modes >> 2) & 0b11) + +def read_sequences_section_header(encoded_file): + byte0 = encoded_file.read(1)[0] + if byte0 == 0: + return SequencesSectionHeader() + + num_of_sequences = 0 + if byte0 < 128: + num_of_sequences = byte0 + elif byte0 < 255: + byte1 = encoded_file.read(1)[0] + num_of_sequences = ((byte0 - 128) << 8) + byte1 + elif byte0 == 255: + remaining_bytes = encoded_file.read(2) + byte1 = remaining_bytes[0] + byte2 = remaining_bytes[1] + num_of_sequences = byte1 + (byte2 << 8) + 0x7F00 + + symbol_compression_modes = encoded_file.read(1)[0] + + return SequencesSectionHeader(num_of_sequences, symbol_compression_modes) + +class BitReader: + def __init__(self, file): + self.file = file + self.byte_pos = file.tell() + self.current_byte = None + self.bitpos = 0 + + def read_bits(self, n): + if self.current_byte == None: + self.current_byte = self.file.read(1)[0] + + result = 0 + bits_read = 0 + while bits_read < n: + remaining_bits_in_byte = 8 - self.bitpos + bits_to_take = min(n - bits_read, remaining_bits_in_byte) + mask = (1 << bits_to_take) - 1 + bits = (self.current_byte >> self.bitpos) & mask + result |= bits << bits_read + bits_read += bits_to_take + self.bitpos += bits_to_take + if self.bitpos == 8: + self.current_byte = self.file.read(1)[0] + self.byte_pos += 1 + self.bitpos = 0 + + return result + + def rewind_bits(self, n): + self.bitpos -= n + while self.bitpos < 0: + self.byte_pos -= 1 + self.bitpos += 8 + + self.file.seek(self.byte_pos) + self.current_byte = self.file.read(1)[0] + + def read_previous_bits(self, n): + self.rewind_bits(n) + bits = self.read_bits(n) + self.rewind_bits(n) + return bits + +# Explanation of FSE tables can be found here +# https://datatracker.ietf.org/doc/html/rfc8878#name-fse +class FSETable(): + def __init__(self, accuracy_log, num_symbols, symbol_frequencies): + self.accuracy_log = accuracy_log + + table_size = 1 << accuracy_log + self.symbols = [0] * table_size + self.num_of_bits = [0] * table_size + self.baseline = [0] * table_size + self.current_state = 0 + + MAX_SYMBOLS = 255 + state = [0] * MAX_SYMBOLS + + # Allocate positions for 'less than 1' probability symbols starting at the end + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-12 + last_element_index = table_size + for symbol_index in range(num_symbols): + if symbol_frequencies[symbol_index] == -1: + last_element_index -= 1 + self.symbols[last_element_index] = symbol_index + state[symbol_index] = 1 + + symbol_table_position = 0 + symbol_table_position_step = (table_size >> 1) + (table_size >> 3) + 3 + table_size_mask = table_size - 1 + for symbol_index in range(num_symbols): + # Skip if already occupied by less than 1 + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-15 + if (symbol_frequencies[symbol_index] <= 0): + continue + + state[symbol_index] = symbol_frequencies[symbol_index] + + # A symbol occupies as many positions as its probability + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-18 + for index in range(symbol_frequencies[symbol_index]): + self.symbols[symbol_table_position] = symbol_index + + # Calculating symbol table position + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-15 + symbol_table_position = (symbol_table_position + symbol_table_position_step) & table_size_mask + while symbol_table_position >= last_element_index: + symbol_table_position = (symbol_table_position + symbol_table_position_step) & table_size_mask + + # Assigning symbols baselines + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-19 + for index in range(table_size): + symbol = self.symbols[index] + state_value = state[symbol] + state[symbol] += 1 + self.num_of_bits[index] = accuracy_log - highest_set_bit(state_value) + self.baseline[index] = (state_value << self.num_of_bits[index]) - table_size + + def update_table_state(self, bit_reader: BitReader): + # Updating FSE table state + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-21 + bits = self.num_of_bits[self.current_state] + value = bit_reader.read_previous_bits(bits) + self.current_state = self.baseline[self.current_state] + value + + def get_symbol(self): + return self.symbols[self.current_state] + +class RLETable(): + def __init__(self, symbol): + self.symbol = symbol + self.accuracy_log = 0 + + def update_table_state(self, bit_reader: BitReader): + self.nop = 0 + + def get_symbol(self): + return self.symbol + +def highest_set_bit(num): + if num == 0: + return -1 + + return num.bit_length() - 1 + +def fill_mask(num_of_bits): + return (1 << num_of_bits) - 1 + +def use_less_bits_if_needed(bits, + decoded_value, + bit_reader, + remaining_probabilities): + # Find if the value can be stored with lower num of bits + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-4 + lower_bits = bits - 1 + lower_bits_mask = fill_mask(lower_bits) + cutoff = fill_mask(bits) - remaining_probabilities - 1 + low = decoded_value & lower_bits_mask + if low < cutoff: + bit_reader.rewind_bits(1) + return low + elif decoded_value > lower_bits_mask: + return decoded_value - cutoff + + return decoded_value + +# Reading FSE table +def read_fse_table(encoded_file): + bit_reader = BitReader(encoded_file) + accuracy_log = bit_reader.read_bits(4) + 5 + + remaining_probabilities = 1 << accuracy_log + MAX_SYMBOLS = 255 + distribution_table = [0] * MAX_SYMBOLS + current_symbol = 0 + while remaining_probabilities > 0: + # Read value for symbol with highest possible num of bits + bits = highest_set_bit(remaining_probabilities + 1) + 1 + decoded_value = bit_reader.read_bits(bits) + decoded_value = use_less_bits_if_needed(bits, decoded_value, bit_reader, remaining_probabilities) + + symbol_probability = decoded_value - 1 + distribution_table[current_symbol] = symbol_probability + remaining_probabilities -= abs(symbol_probability) + + current_symbol += 1 + + # Handle 0 value probabilities + # https://datatracker.ietf.org/doc/html/rfc8878#section-4.1.1-7 + if symbol_probability == 0: + repeat = bit_reader.read_bits(2) + + while repeat > 0: + for _ in range(repeat): + distribution_table[current_symbol] = 0 + current_symbol += 1 + + if repeat == 3: + repeat = bit_reader.read_bits(2) + else: + repeat = 0 + + # Reset encoded file reader by skipping over remaining bits + if bit_reader.bitpos == 0: + encoded_file.seek(encoded_file.tell() - 1) + + return FSETable(accuracy_log, current_symbol, distribution_table) + +# Sequences baselines and extra bits +# https://datatracker.ietf.org/doc/html/rfc8878#name-sequence-codes-for-lengths- +LITERALS_LENGTH_BASELINES = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 22, 24, 28, + 32, 40, 48, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536] +LITERALS_LENGTH_NUM_OF_BITS = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 3, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] +MATCH_LENGTH_BASELINES = [ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 37, 39, 41, 43, 47, 51, 59, 67, 83, 99, + 131, 259, 515, 1027, 2051, 4099, 8195, 16387, 32771, 65539] +MATCH_LENGTH_NUM_OF_BITS = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 2, 2, 3, 3, 4, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + +class DecodedSequence(): + def __init__(self, literal_length, offset_length, match_length): + self.literal_length = literal_length + self.offset_length = offset_length + self.match_length = match_length + + def __str__(self): + return f"LL:{self.literal_length}, OF:{self.offset_length}, ML:{self.match_length}" + +def decode_sequence(bit_reader: BitReader, + literal_lengths_fse_table, + offsets_fse_table, + match_lengths_fse_table, + last_sequence): + of_code = offsets_fse_table.get_symbol() + ll_code = literal_lengths_fse_table.get_symbol() + ml_code = match_lengths_fse_table.get_symbol() + + offset = (1 << of_code) + bit_reader.read_previous_bits(of_code) + match_length = MATCH_LENGTH_BASELINES[ml_code] + bit_reader.read_previous_bits(MATCH_LENGTH_NUM_OF_BITS[ml_code]) + literal_length = LITERALS_LENGTH_BASELINES[ll_code] + bit_reader.read_previous_bits(LITERALS_LENGTH_NUM_OF_BITS[ll_code]) + + if not last_sequence: + literal_lengths_fse_table.update_table_state(bit_reader) + match_lengths_fse_table.update_table_state(bit_reader) + offsets_fse_table.update_table_state(bit_reader) + + return DecodedSequence(literal_length, offset, match_length) + +def decode_sequences(encoded_file, + num_sequences, + last_block_byte_index, + literal_lengths_fse_table, + offsets_fse_table, + match_lengths_fse_table): + encoded_file.seek(last_block_byte_index) + last_block_byte = encoded_file.read(1)[0] + encoded_file.seek(last_block_byte_index) + bit_reader = BitReader(encoded_file) + padding = highest_set_bit(last_block_byte) + if padding > 0: + bit_reader.read_bits(padding) + + literal_lengths_fse_table.current_state = bit_reader.read_previous_bits(literal_lengths_fse_table.accuracy_log) + offsets_fse_table.current_state = bit_reader.read_previous_bits(offsets_fse_table.accuracy_log) + match_lengths_fse_table.current_state = bit_reader.read_previous_bits(match_lengths_fse_table.accuracy_log) + + decoded_sequences = [] + for sequence in range(num_sequences): + decoded_sequences.append(decode_sequence(bit_reader, literal_lengths_fse_table, offsets_fse_table, match_lengths_fse_table, sequence == (num_sequences - 1))) + + return decoded_sequences + +# Calculating repeat offsets +# https://datatracker.ietf.org/doc/html/rfc8878#name-repeat-offsets +repeat_offsets = [1, 4, 8] +def handle_repeated_offsets(decoded_sequence): + global repeat_offsets + offset = -1 + + if decoded_sequence.offset_length > 3: + # Simple case where we subtract 3 from the offset + # https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.4-4.1 + offset = decoded_sequence.offset_length - 3 + + repeat_offsets[2] = repeat_offsets[1] + repeat_offsets[1] = repeat_offsets[0] + repeat_offsets[0] = offset + elif decoded_sequence.literal_length != 0: + # Rotate repeated offsets + # https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.5-8 + if decoded_sequence.offset_length == 1: + offset == repeat_offsets[0] + else: + if decoded_sequence.offset_length == 3: + repeat_offsets[2] = repeat_offsets[1] + + repeat_offsets[1] = repeat_offsets[0] + repeat_offsets[0] = offset + else: + # Special case when LL is 0, then repeat offsets are shifted by one + # https://datatracker.ietf.org/doc/html/rfc8878#section-3.1.1.5-3 + offset_index = decoded_sequence.offset_length + + if offset_index < 3: + offset = repeat_offsets[offset_index] + else: + # 'an offset_value of 3 means Repeated_Offset1 - 1_byte' + offset = repeat_offsets[0] - 1 + + if offset_index > 1: + repeat_offsets[2] = repeat_offsets[1] + + repeat_offsets[1] = repeat_offsets[0] + repeat_offsets[0] = offset + + decoded_sequence.offset_length = offset + + +literal_lengths_fse_table = None +offsets_fse_table = None +match_lengths_fse_table = None +block_cnt = 0 + +def debug_block(encoded_file, current_decoded_data_size, searched_for_byte_index, test_name): + global block_cnt + global literal_lengths_fse_table + global offsets_fse_table + global match_lengths_fse_table + + block_starting_byte_index = encoded_file.tell() + block_header = read_block_header(encoded_file, block_starting_byte_index) + + print(f"Debugging {block_cnt} block at {block_starting_byte_index}") + print("Block:") + print(f" Block content size: {block_header.block_content_size}") + last_block_byte_index = encoded_file.tell() + block_header.block_content_size - 1 + print(f" Block last byte: {last_block_byte_index}") + + current_byte_index = encoded_file.tell() + literals_section_header = read_literals_section_header(encoded_file) + literals_section_header_size = encoded_file.tell() - current_byte_index + + print(f" Literals header size: {literals_section_header_size}") + print(f" Literals block type: {literals_section_header.block_type}") + print(f" Compressed size: {literals_section_header.compressed_size}") + print(f" Has four streams: {literals_section_header.has_four_streams}") + + literals_section_content_size = 0 + if literals_section_header.block_type == LiteralsBlockType.RAW_LITERALS_BLOCK: + literals_section_content_size = literals_section_header.regenerated_size + literals_block = encoded_file.read(literals_section_content_size) + + if literals_section_header.block_type == LiteralsBlockType.RLE_LITERALS_BLOCK: + print(f" Literals block contains a single byte which should be repeated {literals_section_header.regenerated_size} times") + literals_section_content_size = 1 + literals_block = encoded_file.read(literals_section_content_size) + + if literals_section_header.block_type == LiteralsBlockType.COMPRESSED_LITERALS_BLOCK: + literals_section_content_size = literals_section_header.compressed_size + literals_block = encoded_file.read(literals_section_content_size) + + if literals_section_header.block_type == LiteralsBlockType.TREELESS_LITERALS_BLOCK: + literals_section_content_size = literals_section_header.compressed_size + literals_block = encoded_file.read(literals_section_content_size) + + print(f" Literals section content size {literals_section_content_size}") + + sequences_block_content_size = block_header.block_content_size - literals_section_content_size - literals_section_header_size + print(f" Sequences block content size: {sequences_block_content_size}") + + sequences_section_header = read_sequences_section_header(encoded_file) + print(f" Num of sequences: {sequences_section_header.num_of_sequences}") + print(f" Literal lengths mode: {sequences_section_header.literal_lengths_mode}") + print(f" Offsets mode: {sequences_section_header.offsets_mode}") + print(f" Match lengths mode: {sequences_section_header.match_lengths_mode}") + + if sequences_section_header.num_of_sequences == 0: + return literals_section_header.regenerated_size + + # Order of values matches: literal lengths, offsets and match lengths + # Default distribution lengths and accuracies used by the PREDEFINED_MODE + # https://datatracker.ietf.org/doc/html/rfc8878#name-default-distributions + # LL OF ML + # Lengths: 36 29 53 + # Accuracies: 6 5 6 + + if sequences_section_header.literal_lengths_mode == SymbolCompressionMode.PREDEFINED_MODE: + literal_lengths_fse_table = FSETable(6, 36, LITERALS_LENGTH_DEFAULT_DIST) + elif sequences_section_header.literal_lengths_mode == SymbolCompressionMode.RLE_MODE: + literal_lengths_fse_table = RLETable(encoded_file.read(1)[0]) + elif sequences_section_header.literal_lengths_mode == SymbolCompressionMode.FSE_COMPRESSED_MODE: + literal_lengths_fse_table = read_fse_table(encoded_file) + + if sequences_section_header.offsets_mode == SymbolCompressionMode.PREDEFINED_MODE: + offsets_fse_table = FSETable(5, 29, OFFSET_CODES_DEFAULT_DIST) + elif sequences_section_header.offsets_mode == SymbolCompressionMode.RLE_MODE: + offsets_fse_table = RLETable(encoded_file.read(1)[0]) + elif sequences_section_header.offsets_mode == SymbolCompressionMode.FSE_COMPRESSED_MODE: + offsets_fse_table = read_fse_table(encoded_file) + + if sequences_section_header.match_lengths_mode == SymbolCompressionMode.PREDEFINED_MODE: + match_lengths_fse_table = FSETable(6, 53, MATCH_LENGTHS_DEFAULT_DIST) + elif sequences_section_header.match_lengths_mode == SymbolCompressionMode.RLE_MODE: + match_lengths_fse_table = RLETable(encoded_file.read(1)[0]) + elif sequences_section_header.match_lengths_mode == SymbolCompressionMode.FSE_COMPRESSED_MODE: + match_lengths_fse_table = read_fse_table(encoded_file) + + print(f" LL accuracy log: {literal_lengths_fse_table.accuracy_log}") + print(f" OF accuracy log: {offsets_fse_table.accuracy_log}") + print(f" ML accuracy log: {match_lengths_fse_table.accuracy_log}") + + decoded_sequences = decode_sequences(encoded_file, + sequences_section_header.num_of_sequences, + last_block_byte_index, + literal_lengths_fse_table, + offsets_fse_table, + match_lengths_fse_table) + + total_literal_lengths = 0 + total_match_lengths = 0 + for (index, decoded_sequence) in enumerate(decoded_sequences): + + comes_from_match = False + comes_from_literal = False + if current_decoded_data_size + decoded_sequence.match_length >= searched_for_byte_index: + comes_from_match = True + elif current_decoded_data_size + decoded_sequence.match_length + decoded_sequence.literal_length >= searched_for_byte_index: + comes_from_literal = True + + total_literal_lengths += decoded_sequence.literal_length + total_match_lengths += decoded_sequence.match_length + current_decoded_data_size += decoded_sequence.literal_length + decoded_sequence.match_length + + handle_repeated_offsets(decoded_sequence) + + if current_decoded_data_size >= searched_for_byte_index: + insert_vertical_separation() + + if comes_from_match: + origin = "history match" + elif comes_from_literal: + origin = "literal copying" + else: + origin = "" + + print(f"** Byte {searched_for_byte_index} comes from the block {block_cnt} from sequence {index} from the block at byte index {block_starting_byte_index}") + print(f"** The copied value comes from {origin} part of the sequence: ") + print(f"** LL: {decoded_sequence.literal_length} OF: {decoded_sequence.offset_length} ML: {decoded_sequence.match_length} (after handling repeated offsets)") + print(f"|| {test_name:>15} | 0x{searched_for_byte_index:016X} | {block_cnt:>15} | {index:>20} | {str(decoded_sequence):>30} | {origin:>15} ||\n") + + block_cnt += 1 + return (literals_section_header.regenerated_size + total_literal_lengths + total_match_lengths, True) + + decoded_content_size = literals_section_header.regenerated_size + total_match_lengths + + print(f" Total match lengths: {total_match_lengths}") + print(f" Literals size: {literals_section_header.regenerated_size}") + print(f" Decoded content size: {decoded_content_size}") + + encoded_file.seek(last_block_byte_index + 1) + + block_cnt += 1 + return (decoded_content_size, block_header.last_block) + +def insert_vertical_separation(): + print() + +def debug_file(file_path, byte_index, test_name): + with open(file_path, "rb") as encoded_file: + read_magic_number(encoded_file) + read_frame_header(encoded_file) + insert_vertical_separation() + + total_decoded_content_size = 0 + finished = False + while not finished: + print(f"Currently decoded {total_decoded_content_size} bytes of data") + decoded_content_size, finished = debug_block(encoded_file, total_decoded_content_size, byte_index, test_name) + total_decoded_content_size += decoded_content_size + finished = finished or total_decoded_content_size >= byte_index + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--file", + help="Filename of the tested ZSTD encoded file", + type=pathlib.Path, + required=True + ) + parser.add_argument( + "--name", + help="Test name", + default="name" + ) + parser.add_argument( + "--byte", + help="Byte which information will be printed", + type=int, + required=True + ) + args = parser.parse_args() + debug_file(args.file, args.byte, args.name) + +if __name__ == "__main__": + main() diff --git a/xls/passes/lazy_query_engine.h b/xls/passes/lazy_query_engine.h index d4301235ea..8a73799852 100644 --- a/xls/passes/lazy_query_engine.h +++ b/xls/passes/lazy_query_engine.h @@ -188,6 +188,9 @@ class LazyQueryEngine : public internal::CacheableQueryEngine { const LazyNodeInfo& info() const { return qe_info(); } std::optional> GetInfo(Node* node) const { + if (!IsTracked(node)) { + return std::nullopt; + } return info_.GetInfo(node); }