From 4481e0d9f1bd792f88faa2a37b4c7da4edc798d7 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Fri, 6 Oct 2023 20:01:40 +0100 Subject: [PATCH 01/24] half way to f64 --- poetry.lock | 156 +++++++++++--------------- pyproject.toml | 1 - riscemu/config.py | 1 + riscemu/core/__init__.py | 4 +- riscemu/core/cpu.py | 2 +- riscemu/core/{float32.py => float.py} | 134 +++++++++++----------- riscemu/core/mmu.py | 4 + riscemu/core/registers.py | 25 +++-- riscemu/instructions/RV32F.py | 2 +- riscemu/instructions/__init__.py | 2 + riscemu/riscemu_main.py | 12 ++ snitch/regs.py | 6 +- test/test_RV32F.py | 4 +- test/test_float32.py | 12 +- test/test_regs.py | 4 +- 15 files changed, 180 insertions(+), 189 deletions(-) rename riscemu/core/{float32.py => float.py} (52%) diff --git a/poetry.lock b/poetry.lock index 1b0f9c3..04ac05e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2,34 +2,34 @@ [[package]] name = "black" -version = "23.7.0" +version = "23.9.1" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, - {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, - {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, - {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, - {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, - {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, - {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, - {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, - {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, - {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, - {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, + {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, + {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, + {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, + {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, + {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, + {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, + {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, + {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, + {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, + {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, ] [package.dependencies] @@ -39,7 +39,7 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -127,30 +127,31 @@ files = [ [[package]] name = "filelock" -version = "3.12.2" +version = "3.12.4" description = "A platform independent file lock." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.12.4-py3-none-any.whl", hash = "sha256:08c21d87ded6e2b9da6728c3dff51baf1dcecf973b768ef35bcbc3447edb9ad4"}, + {file = "filelock-3.12.4.tar.gz", hash = "sha256:2e6f249f1f3654291606e046b09f1fd5eac39b360664c27f5aad072012f8bcbd"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +typing = ["typing-extensions (>=4.7.1)"] [[package]] name = "identify" -version = "2.5.27" +version = "2.5.30" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, - {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, + {file = "identify-2.5.30-py2.py3-none-any.whl", hash = "sha256:afe67f26ae29bab007ec21b03d4114f41316ab9dd15aa8736a167481e108da54"}, + {file = "identify-2.5.30.tar.gz", hash = "sha256:f302a4256a15c849b91cfcdcec052a8ce914634b2f77ae87dad29cd749f2d88d"}, ] [package.extras] @@ -208,14 +209,14 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -232,14 +233,14 @@ files = [ [[package]] name = "platformdirs" -version = "3.10.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.extras] @@ -248,14 +249,14 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] @@ -264,14 +265,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.3.3" +version = "3.4.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"}, - {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"}, + {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, + {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, ] [package.dependencies] @@ -281,33 +282,6 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "psutil" -version = "5.9.5" -description = "Cross-platform lib for process and system monitoring in Python." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, - {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, - {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, - {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, - {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, - {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, - {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, - {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, -] - -[package.extras] -test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] - [[package]] name = "pyelftools" version = "0.29" @@ -322,14 +296,14 @@ files = [ [[package]] name = "pytest" -version = "7.4.0" +version = "7.4.2" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] @@ -395,20 +369,20 @@ files = [ [[package]] name = "setuptools" -version = "68.1.2" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, - {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "tomli" @@ -424,26 +398,26 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] name = "virtualenv" -version = "20.24.3" +version = "20.24.5" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.3-py3-none-any.whl", hash = "sha256:95a6e9398b4967fbcb5fef2acec5efaf9aa4972049d9ae41f95e0972a683fd02"}, - {file = "virtualenv-20.24.3.tar.gz", hash = "sha256:e5c3b4ce817b0b328af041506a2a299418c98747c4b1e68cb7527e74ced23efc"}, + {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, + {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, ] [package.dependencies] @@ -452,10 +426,10 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "f45ae83e9aa1bfe7b1036da1d85cd9124f5f293d926bc20c37fbb97c52a03efa" +content-hash = "52c6ac0d4ad940d610fb2df7674277b3f913f00ecc8b9b0a0c70a98b63daac1d" diff --git a/pyproject.toml b/pyproject.toml index 305fc85..fc55c6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ riscemu = "riscemu.__main__:main" [tool.poetry.dependencies] python = "^3.8" pyelftools = "^0.29" -psutil = "^5.9.5" [tool.poetry.group.dev.dependencies] black = "^23.7.0" diff --git a/riscemu/config.py b/riscemu/config.py index 35edf27..2f1ea9b 100644 --- a/riscemu/config.py +++ b/riscemu/config.py @@ -21,6 +21,7 @@ class RunConfig: verbosity: int = 0 slowdown: float = 1 unlimited_registers: bool = False + flen: int = 32 # runtime config use_libc: bool = False ignore_exit_code: bool = False diff --git a/riscemu/core/__init__.py b/riscemu/core/__init__.py index 6d55aaf..746aead 100644 --- a/riscemu/core/__init__.py +++ b/riscemu/core/__init__.py @@ -29,7 +29,7 @@ # base classes from .flags import MemoryFlags from .int32 import UInt32, Int32 -from .float32 import Float32 +from .float import BaseFloat, Float32, Float64 from .rtclock import RTClock from .instruction import Instruction, Immediate, InstructionWithEncoding from .instruction_context import InstructionContext @@ -66,7 +66,9 @@ MemoryFlags, UInt32, Int32, + BaseFloat, Float32, + Float64, RTClock, Instruction, Immediate, diff --git a/riscemu/core/cpu.py b/riscemu/core/cpu.py index a2dcd0c..078be40 100644 --- a/riscemu/core/cpu.py +++ b/riscemu/core/cpu.py @@ -55,7 +55,7 @@ def __init__( conf: RunConfig, ): self.mmu = mmu - self.regs = Registers(conf.unlimited_registers) + self.regs = Registers(conf.unlimited_registers, conf.flen) self.conf = conf self.instruction_sets = set() diff --git a/riscemu/core/float32.py b/riscemu/core/float.py similarity index 52% rename from riscemu/core/float32.py rename to riscemu/core/float.py index 9440b84..429d175 100644 --- a/riscemu/core/float32.py +++ b/riscemu/core/float.py @@ -1,14 +1,18 @@ import struct -from ctypes import c_float -from typing import Union, Any +from ctypes import c_float, c_double +from typing import Union, Any, ClassVar +from abc import ABC, abstractmethod bytes_t = bytes -class Float32: +class BaseFloat(ABC): __slots__ = ("_val",) - _val: c_float + _type: ClassVar[type[c_float | c_double]] + _struct_fmt_str: ClassVar[str] + + _val: c_float | c_double @property def value(self) -> float: @@ -22,73 +26,67 @@ def bytes(self) -> bytes: """ The values bit representation (as a bytes object) """ - return struct.pack(" int: - """ - The values bit representation as an int (for easy bit manipulation) - """ - return int.from_bytes(self.bytes, byteorder="little") + return struct.pack("<" + self._struct_fmt_str, self.value) @classmethod - def from_bytes(cls, val: Union[int, bytes_t, bytearray]): - if isinstance(val, int): - val = struct.unpack("!f", struct.pack("!I", val))[0] - return Float32(val) + def from_bytes(cls, val: Union[bytes_t, bytearray]): + return BaseFloat(val) def __init__( - self, val: Union[float, c_float, "Float32", bytes_t, bytearray, int] = 0 + self, val: Union[float, c_float, "BaseFloat", bytes_t, bytearray, int] = 0 ): if isinstance(val, (float, int)): - self._val = c_float(val) - elif isinstance(val, c_float): - self._val = c_float(val.value) + self._val = self._type(val) + elif isinstance(val, c_float | c_double): + self._val = self._type(val.value) elif isinstance(val, (bytes, bytearray)): - self._val = c_float(struct.unpack(" bool: if isinstance(other, (float, int)): return self.value == other - elif isinstance(other, Float32): + elif isinstance(other, BaseFloat): return self.value == other.value return False @@ -114,22 +112,22 @@ def __hash__(self): return hash(self.value) def __gt__(self, other: Any): - if isinstance(other, Float32): + if isinstance(other, BaseFloat): other = other.value return self.value > other def __lt__(self, other: Any): - if isinstance(other, Float32): + if isinstance(other, BaseFloat): other = other.value return self.value < other def __le__(self, other: Any): - if isinstance(other, Float32): + if isinstance(other, BaseFloat): other = other.value return self.value <= other def __ge__(self, other: Any): - if isinstance(other, Float32): + if isinstance(other, BaseFloat): other = other.value return self.value >= other @@ -161,40 +159,34 @@ def __rfloordiv__(self, other: Any): def __rmod__(self, other: Any): return self.__class__(other) % self - def __rand__(self, other: Any): - return self.__class__(other) & self - - def __ror__(self, other: Any): - return self.__class__(other) | self - - def __rxor__(self, other: Any): - return self.__class__(other) ^ self - - # bytewise operators: + @classmethod + def bitcast(cls, f: "BaseFloat") -> "BaseFloat": + """ + bitcast the struct up or down to another type. - def __and__(self, other: Union["Float32", float, int]): - if isinstance(other, float): - other = Float32(other) - if isinstance(other, Float32): - other = other.bits - return self.from_bytes(self.bits & other) + Use Float64.bitcast(Float32(...)) to bitcast a f32 to f64 + """ + return cls.from_bytes((b"\x00\x00\x00\x00\x00\x00\x00\x00" + f.bytes)[-struct.calcsize(cls._struct_fmt_str):]) - def __or__(self, other: Union["Float32", float]): - if isinstance(other, float): - other = Float32(other) - if isinstance(other, Float32): - other = other.bits - return self.from_bytes(self.bits | other) + @classmethod + def flen_to_cls(cls, bits: int) -> type['BaseFloat']: + if bits == 32: + return Float32 + if bits == 64: + return Float64 + raise ValueError(f"Unsupported flen: {bits}") - def __xor__(self, other: Union["Float32", float]): - if isinstance(other, float): - other = Float32(other) - if isinstance(other, Float32): - other = other.bits - return self.from_bytes(self.bits ^ other) - def __lshift__(self, other: int): - return self.from_bytes(self.bits << other) +class Float32(BaseFloat): + _type = c_float + _struct_fmt_str = 'f' - def __rshift__(self, other: int): - return self.from_bytes(self.bits >> other) + @classmethod + def bitcast(cls, f: "BaseFloat") -> "BaseFloat": + if isinstance(f, Float32): + return f + + +class Float64(BaseFloat): + _type = c_double + _struct_fmt_str = 'd' diff --git a/riscemu/core/mmu.py b/riscemu/core/mmu.py index 2890f87..d4931e2 100644 --- a/riscemu/core/mmu.py +++ b/riscemu/core/mmu.py @@ -17,6 +17,7 @@ InstructionContext, Int32, Float32, + Float64, InvalidAllocationException, MemoryAccessException, ) @@ -215,6 +216,9 @@ def read_int(self, addr: int) -> Int32: def read_float(self, addr: int) -> Float32: return Float32(self.read(addr, 4)) + def read_double(self, addr: int) -> Float64: + return Float64(self.read(addr, 8)) + def translate_address(self, address: T_AbsoluteAddress) -> str: sec = self.get_sec_containing(address) if not sec: diff --git a/riscemu/core/registers.py b/riscemu/core/registers.py index 293b3ce..46b1f89 100644 --- a/riscemu/core/registers.py +++ b/riscemu/core/registers.py @@ -9,7 +9,7 @@ from ..helpers import * -from . import Int32, Float32 +from . import Int32, BaseFloat, Float32, Float64 class Registers: @@ -84,9 +84,14 @@ class Registers: "fa7", } - def __init__(self, infinite_regs: bool = False): + flen: int + _float_type: type[BaseFloat] + + def __init__(self, infinite_regs: bool = False, flen: int = 32): self.vals: dict[str, Int32] = defaultdict(UInt32) - self.float_vals: dict[str, Float32] = defaultdict(Float32) + self.flen = flen + self._float_type = BaseFloat.flen_to_cls(flen) + self.float_vals: dict[str, BaseFloat] = defaultdict(self._float_type) self.last_set = None self.last_read = None @@ -169,7 +174,7 @@ def _reg_repr(self, reg: str, name_len=4, fmt="08X"): return FMT_GRAY + txt + FMT_NONE return txt - def set(self, reg: str, val: "Int32", mark_set: bool = True) -> bool: + def set(self, reg: str, val: Int32, mark_set: bool = True) -> bool: """ Set a register content to val :param reg: The register to set @@ -194,7 +199,7 @@ def set(self, reg: str, val: "Int32", mark_set: bool = True) -> bool: self.vals[reg] = val.unsigned() return True - def get(self, reg: str, mark_read: bool = True) -> "Int32": + def get(self, reg: str, mark_read: bool = True) -> Int32: """ Returns the contents of register reg :param reg: The register name @@ -213,17 +218,17 @@ def get(self, reg: str, mark_read: bool = True) -> "Int32": self.last_read = reg return self.vals[reg] - def get_f(self, reg: str, mark_read: bool = True) -> "Float32": + def get_f(self, reg: str, mark_read: bool = True) -> BaseFloat: if not self.infinite_regs and reg not in self.float_regs: raise RuntimeError("Invalid float register: {}".format(reg)) if mark_read: self.last_read = reg return self.float_vals[reg] - def set_f(self, reg: str, val: Union[float, "Float32"]): + def set_f(self, reg: str, val: Union[float, BaseFloat]): if not self.infinite_regs and reg not in self.float_regs: raise RuntimeError("Invalid float register: {}".format(reg)) - self.float_vals[reg] = Float32(val) + self.float_vals[reg] = self._float_type(val) @staticmethod def named_registers(): @@ -234,8 +239,8 @@ def named_registers(): return ["zero", "ra", "sp", "gp", "tp", "fp"] def __repr__(self): - return "".format( - "float" if self.supports_floats else "nofloat", + return "".format( + self.flen, "{" + ", ".join(self._reg_repr("a{}".format(i), 2, "0x") for i in range(8)) + "}", diff --git a/riscemu/instructions/RV32F.py b/riscemu/instructions/RV32F.py index 052b44c..3753aac 100644 --- a/riscemu/instructions/RV32F.py +++ b/riscemu/instructions/RV32F.py @@ -392,7 +392,7 @@ def instruction_fmv_x_w(self, ins: Instruction): | x[rd] = sext(f[rs1][31:0]) """ rd, rs = self.parse_rd_rs(ins) - self.regs.set(rd, UInt32(self.regs.get_f(rs).bits)) + self.regs.set(rd, UInt32(self.regs.get_f(rs).bytes)) def instruction_feq_s(self, ins: Instruction): """ diff --git a/riscemu/instructions/__init__.py b/riscemu/instructions/__init__.py index 04c614c..51925f0 100644 --- a/riscemu/instructions/__init__.py +++ b/riscemu/instructions/__init__.py @@ -19,6 +19,8 @@ } __all__ = [ + Instruction, + InstructionSet, InstructionSetDict, RV32I, RV32M, diff --git a/riscemu/riscemu_main.py b/riscemu/riscemu_main.py index b3172b2..381e9ca 100644 --- a/riscemu/riscemu_main.py +++ b/riscemu/riscemu_main.py @@ -118,6 +118,14 @@ def register_all_arguments(self, parser: argparse.ArgumentParser): nargs="?", ) + parser.add_argument( + "--flen", + type=int, + help="hardware FLEN, either 32 or 64", + nargs="?", + default=32, + ) + parser.add_argument( "-v", "--verbose", @@ -169,6 +177,9 @@ def parse_argv(self, argv: List[str]): if not hasattr(args, "ins"): setattr(args, "ins", {k: True for k in self.available_ins_sets}) + if args.flen not in (32, 64): + raise ValueError("Cannot have flen other than 32 or 64!") + # create RunConfig self.cfg = self.create_config(args) @@ -214,6 +225,7 @@ def create_config(self, args: argparse.Namespace) -> RunConfig: verbosity=args.verbose, use_libc=args.options["libc"], ignore_exit_code=args.options["ignore_exit_code"], + flen=args.flen, ) for k, v in dict(cfg_dict).items(): if v is None: diff --git a/snitch/regs.py b/snitch/regs.py index 0ec6f28..e8311c6 100644 --- a/snitch/regs.py +++ b/snitch/regs.py @@ -1,5 +1,5 @@ from typing import Dict, List, Tuple -from riscemu.core import Registers, MMU, Float32 +from riscemu.core import Registers, MMU, BaseFloat from dataclasses import dataclass @@ -63,7 +63,7 @@ def __init__( self.streams[reg] = stream_def super().__init__(infinite_regs) - def get_f(self, reg, mark_read=True) -> "Float32": + def get_f(self, reg, mark_read=True) -> "BaseFloat": if not self.enabled or reg not in self.streams: return super().get_f(reg, mark_read) @@ -82,7 +82,7 @@ def get_f(self, reg, mark_read=True) -> "Float32": stream.pos += 1 return val - def set_f(self, reg, val: "Float32", mark_set=True) -> bool: + def set_f(self, reg, val: "BaseFloat", mark_set=True) -> bool: if not self.enabled or reg not in self.streams: return super().set_f(reg, mark_set) diff --git a/test/test_RV32F.py b/test/test_RV32F.py index d5d758d..f50f832 100644 --- a/test/test_RV32F.py +++ b/test/test_RV32F.py @@ -2,7 +2,7 @@ from riscemu.instructions.RV32F import RV32F from riscemu.core.registers import Registers from riscemu.core import ProgramLoader, CPU -from riscemu.core.float32 import Float32 +from riscemu.core.float import BaseFloat from riscemu.core.int32 import Int32 from riscemu.core.simple_instruction import SimpleInstruction @@ -39,6 +39,6 @@ def test_cvt_instructions(): assert 42.0 == cpu.regs.get_f("fa0") ins = MockInstruction("fcvt.w.s", ("a1", "fa1"), None, None) - cpu.regs.set_f("fa1", Float32(42.0)) + cpu.regs.set_f("fa1", BaseFloat(42.0)) RV32F(cpu).instruction_fcvt_w_s(ins) assert Int32(42) == cpu.regs.get("a1") diff --git a/test/test_float32.py b/test/test_float32.py index d592acc..35d40fe 100644 --- a/test/test_float32.py +++ b/test/test_float32.py @@ -1,25 +1,25 @@ import math -from riscemu.core import Float32 +from riscemu.core import BaseFloat # pi encoded as a 32bit little endian float PI_BYTES_LE = b"\xdb\x0fI@" def test_float_serialization(): - assert Float32(PI_BYTES_LE) == Float32(math.pi) - assert Float32(math.pi).bytes == PI_BYTES_LE + assert BaseFloat(PI_BYTES_LE) == BaseFloat(math.pi) + assert BaseFloat(math.pi).bytes == PI_BYTES_LE def test_random_float_ops(): - val = Float32(5) + val = BaseFloat(5) assert val**2 == 25 assert val // 2 == 2 assert val * 3 == 15 assert val - 2 == 3 assert val * val == 25 - assert Float32(9) ** 0.5 == 3 + assert BaseFloat(9) ** 0.5 == 3 def test_float_from_raw_int_conversion(): - assert Float32.from_bytes(1084227584) == Float32(5.0) + assert BaseFloat.from_bytes(1084227584) == BaseFloat(5.0) diff --git a/test/test_regs.py b/test/test_regs.py index b977ae0..4c00b29 100644 --- a/test/test_regs.py +++ b/test/test_regs.py @@ -1,7 +1,7 @@ import pytest from riscemu.core.registers import Registers -from riscemu.core import Float32 +from riscemu.core import BaseFloat def test_float_regs(): @@ -9,7 +9,7 @@ def test_float_regs(): # uninitialized register is zero assert r.get_f("fs0") == 0 # get/set - val = Float32(3.14) + val = BaseFloat(3.14) r.set_f("fs0", val) assert r.get_f("fs0") == val From 20637eed2038e08b0a2fd3186c6900012153298b Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Fri, 6 Oct 2023 20:00:28 +0100 Subject: [PATCH 02/24] got it mostly working now --- examples/estimate-cpu-freq.asm | 2 +- riscemu/config.py | 2 +- riscemu/core/__init__.py | 78 ++-- riscemu/core/float.py | 29 +- riscemu/core/registers.py | 2 +- riscemu/debug.py | 2 +- riscemu/instructions/RV32D.py | 20 + riscemu/instructions/RV32F.py | 487 +----------------------- riscemu/instructions/RV_Debug.py | 11 +- riscemu/instructions/__init__.py | 22 +- riscemu/instructions/float_base.py | 388 +++++++++++++++++++ riscemu/instructions/instruction_set.py | 8 +- riscemu/riscemu_main.py | 4 +- test/filecheck/rv32f-conv.asm | 10 +- test/test_RV32F.py | 96 ++++- test/test_float32.py | 25 -- test/test_float_impl.py | 46 +++ test/test_regs.py | 13 +- 18 files changed, 648 insertions(+), 597 deletions(-) create mode 100644 riscemu/instructions/RV32D.py create mode 100644 riscemu/instructions/float_base.py delete mode 100644 test/test_float32.py create mode 100644 test/test_float_impl.py diff --git a/examples/estimate-cpu-freq.asm b/examples/estimate-cpu-freq.asm index b088caa..0b982d5 100644 --- a/examples/estimate-cpu-freq.asm +++ b/examples/estimate-cpu-freq.asm @@ -61,7 +61,7 @@ measure_loop: fcvt.s.w ft1, t0 // ft1 = 1k fdiv.s ft2, ft2, ft1 // ft2 = kins/sec - printf "executed {} instructions in {:.4f} seconds ({:.2f}ki/s)", s0, ft0, ft2 + printf "executed {} instructions in {:.4f32} seconds ({:.2f32}ki/s)", s0, ft0, ft2 mv ra, s4 ret diff --git a/riscemu/config.py b/riscemu/config.py index 2f1ea9b..cef17aa 100644 --- a/riscemu/config.py +++ b/riscemu/config.py @@ -21,7 +21,7 @@ class RunConfig: verbosity: int = 0 slowdown: float = 1 unlimited_registers: bool = False - flen: int = 32 + flen: int = 64 # runtime config use_libc: bool = False ignore_exit_code: bool = False diff --git a/riscemu/core/__init__.py b/riscemu/core/__init__.py index 746aead..c1968d4 100644 --- a/riscemu/core/__init__.py +++ b/riscemu/core/__init__.py @@ -47,43 +47,43 @@ from .usermode_cpu import UserModeCPU __all__ = [ - T_RelativeAddress, - T_AbsoluteAddress, - T_ParserOpts, - NUMBER_SYMBOL_PATTERN, - ParseException, - NumberFormatException, - MemoryAccessException, - OutOfMemoryException, - LinkerException, - LaunchDebuggerException, - RiscemuBaseException, - InvalidRegisterException, - InvalidAllocationException, - InvalidSyscallException, - UnimplementedInstruction, - INS_NOT_IMPLEMENTED, - MemoryFlags, - UInt32, - Int32, - BaseFloat, - Float32, - Float64, - RTClock, - Instruction, - Immediate, - InstructionWithEncoding, - InstructionContext, - MemorySection, - Program, - ProgramLoader, - PrivModes, - MMU, - CSR, - Registers, - CPU, - SimpleInstruction, - InstructionMemorySection, - BinaryDataMemorySection, - UserModeCPU, + "T_RelativeAddress", + "T_AbsoluteAddress", + "T_ParserOpts", + "NUMBER_SYMBOL_PATTERN", + "ParseException", + "NumberFormatException", + "MemoryAccessException", + "OutOfMemoryException", + "LinkerException", + "LaunchDebuggerException", + "RiscemuBaseException", + "InvalidRegisterException", + "InvalidAllocationException", + "InvalidSyscallException", + "UnimplementedInstruction", + "INS_NOT_IMPLEMENTED", + "MemoryFlags", + "UInt32", + "Int32", + "BaseFloat", + "Float32", + "Float64", + "RTClock", + "Instruction", + "Immediate", + "InstructionWithEncoding", + "InstructionContext", + "MemorySection", + "Program", + "ProgramLoader", + "PrivModes", + "MMU", + "CSR", + "Registers", + "CPU", + "SimpleInstruction", + "InstructionMemorySection", + "BinaryDataMemorySection", + "UserModeCPU", ] diff --git a/riscemu/core/float.py b/riscemu/core/float.py index 429d175..a73d30f 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -30,7 +30,7 @@ def bytes(self) -> bytes: @classmethod def from_bytes(cls, val: Union[bytes_t, bytearray]): - return BaseFloat(val) + return cls(val) def __init__( self, val: Union[float, c_float, "BaseFloat", bytes_t, bytearray, int] = 0 @@ -41,8 +41,7 @@ def __init__( self._val = self._type(val.value) elif isinstance(val, (bytes, bytearray)): self._val = self._type(struct.unpack("<" + self._struct_fmt_str, val)[0]) - self._val = self._type(struct.unpack("<" + self._struct_fmt_str, val)[0]) - elif isinstance(val, BaseFloat): + elif isinstance(val, self.__class__): self._val = val._val else: raise ValueError( @@ -105,9 +104,6 @@ def __repr__(self): def __str__(self): return str(self.value) - def __format__(self, format_spec: str): - return self.value.__format__(format_spec) - def __hash__(self): return hash(self.value) @@ -134,6 +130,12 @@ def __ge__(self, other: Any): def __bool__(self): return bool(self.value) + def __int__(self): + return int(self.value) + + def __float__(self): + return self.value + def __pow__(self, power, modulo=None): if modulo is not None: raise ValueError("Float32 pow with modulo unsupported") @@ -163,9 +165,12 @@ def __rmod__(self, other: Any): def bitcast(cls, f: "BaseFloat") -> "BaseFloat": """ bitcast the struct up or down to another type. + Fills upper bits with zero. Use Float64.bitcast(Float32(...)) to bitcast a f32 to f64 """ + if isinstance(f, cls): + return f return cls.from_bytes((b"\x00\x00\x00\x00\x00\x00\x00\x00" + f.bytes)[-struct.calcsize(cls._struct_fmt_str):]) @classmethod @@ -176,16 +181,18 @@ def flen_to_cls(cls, bits: int) -> type['BaseFloat']: return Float64 raise ValueError(f"Unsupported flen: {bits}") + def __format__(self, spec: str): + if spec[-2:] == '32': + return Float32.bitcast(self).__format__(spec[:-2]) + if spec[-2:] == '64': + return Float64.bitcast(self).__format__(spec[:-2]) + return format(self.value, spec) + class Float32(BaseFloat): _type = c_float _struct_fmt_str = 'f' - @classmethod - def bitcast(cls, f: "BaseFloat") -> "BaseFloat": - if isinstance(f, Float32): - return f - class Float64(BaseFloat): _type = c_double diff --git a/riscemu/core/registers.py b/riscemu/core/registers.py index 46b1f89..7b34efd 100644 --- a/riscemu/core/registers.py +++ b/riscemu/core/registers.py @@ -228,7 +228,7 @@ def get_f(self, reg: str, mark_read: bool = True) -> BaseFloat: def set_f(self, reg: str, val: Union[float, BaseFloat]): if not self.infinite_regs and reg not in self.float_regs: raise RuntimeError("Invalid float register: {}".format(reg)) - self.float_vals[reg] = self._float_type(val) + self.float_vals[reg] = self._float_type.bitcast(val) @staticmethod def named_registers(): diff --git a/riscemu/debug.py b/riscemu/debug.py index 4f43419..5bab0a0 100644 --- a/riscemu/debug.py +++ b/riscemu/debug.py @@ -64,7 +64,7 @@ def cont(verbose=False): def step(): try: - cpu.step() + cpu.step(verbose=True) except LaunchDebuggerException: return diff --git a/riscemu/instructions/RV32D.py b/riscemu/instructions/RV32D.py new file mode 100644 index 0000000..ced3558 --- /dev/null +++ b/riscemu/instructions/RV32D.py @@ -0,0 +1,20 @@ +""" +RiscEmu (c) 2023 Anton Lydike + +SPDX-License-Identifier: MIT + +This file contains copious amounts of docstrings that were all taken +from https://msyksphinz-self.github.io/riscv-isadoc/html/rvfd.html +(all the docstrings on the instruction methods documenting the opcodes +and their function) +""" +from typing import Tuple + +from .instruction_set import InstructionSet, Instruction +from .float_base import FloatArithBase +from riscemu.core import INS_NOT_IMPLEMENTED, Float32, Int32, UInt32, Float64 + + +class RV32D(FloatArithBase[Float64]): + flen = 64 + _float_cls = Float64 diff --git a/riscemu/instructions/RV32F.py b/riscemu/instructions/RV32F.py index 3753aac..a3d4065 100644 --- a/riscemu/instructions/RV32F.py +++ b/riscemu/instructions/RV32F.py @@ -8,331 +8,14 @@ (all the docstrings on the instruction methods documenting the opcodes and their function) """ -from typing import Tuple +from .instruction_set import Instruction +from .float_base import FloatArithBase +from riscemu.core import Float32, Int32, UInt32 -from .instruction_set import InstructionSet, Instruction -from riscemu.core import INS_NOT_IMPLEMENTED, Float32, Int32, UInt32 - -class RV32F(InstructionSet): - def instruction_fmadd_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |rs3 |00 |rs2 |rs1 |rm |rd |10000|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fmadd.s rd,rs1,rs2,rs3 - - :Description: - | Perform single-precision fused multiply addition. - - :Implementation: - | f[rd] = f[rs1]×f[rs2]+f[rs3] - - """ - rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) - self.regs.set_f(rd, rs1 * rs2 + rs3) - - def instruction_fmsub_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |rs3 |00 |rs2 |rs1 |rm |rd |10001|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fmsub.s rd,rs1,rs2,rs3 - - :Description: - | Perform single-precision fused multiply addition. - - :Implementation: - | f[rd] = f[rs1]×f[rs2]-f[rs3] - """ - rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) - self.regs.set_f(rd, rs1 * rs2 - rs3) - - def instruction_fnmsub_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |rs3 |00 |rs2 |rs1 |rm |rd |10010|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fnmsub.s rd,rs1,rs2,rs3 - - :Description: - | Perform single-precision fused multiply addition. - - :Implementation: - | f[rd] = -f[rs1]×f[rs2]+f[rs3] - """ - rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) - self.regs.set_f(rd, -rs1 * rs2 + rs3) - - def instruction_fnmadd_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |rs3 |00 |rs2 |rs1 |rm |rd |10011|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fnmadd.s rd,rs1,rs2,rs3 - - :Description: - | Perform single-precision fused multiply addition. - - :Implementation: - | f[rd] = -f[rs1]×f[rs2]-f[rs3] - """ - rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) - self.regs.set_f(rd, -rs1 * rs2 - rs3) - - def instruction_fadd_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00000|00 |rs2 |rs1 |rm |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fadd.s rd,rs1,rs2 - - :Description: - | Perform single-precision floating-point addition. - - :Implementation: - | f[rd] = f[rs1] + f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - rs1 + rs2, - ) - - def instruction_fsub_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00001|00 |rs2 |rs1 |rm |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fsub.s rd,rs1,rs2 - - :Description: - | Perform single-precision floating-point subtraction. - - :Implementation: - | f[rd] = f[rs1] - f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - rs1 - rs2, - ) - - def instruction_fmul_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00010|00 |rs2 |rs1 |rm |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fmul.s rd,rs1,rs2 - - :Description: - | Perform single-precision floating-point multiplication. - - :Implementation: - | f[rd] = f[rs1] × f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - rs1 * rs2, - ) - - def instruction_fdiv_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00011|00 |rs2 |rs1 |rm |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fdiv.s rd,rs1,rs2 - - :Description: - | Perform single-precision floating-point division. - - :Implementation: - | f[rd] = f[rs1] / f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - rs1 / rs2, - ) - - def instruction_fsqrt_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |01011|00 |00000|rs1 |rm |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fsqrt.s rd,rs1 - - :Description: - | Perform single-precision square root. - - :Implementation: - | f[rd] = sqrt(f[rs1]) - """ - rd, rs = self.parse_rd_rs(ins) - self.regs.set_f(rd, self.regs.get_f(rs) ** 0.5) - - def instruction_fsgnj_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00100|00 |rs2 |rs1 |000 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fsgnj.s rd,rs1,rs2 - - :Description: - | Produce a result that takes all bits except the sign bit from rs1. - | The result’s sign bit is rs2’s sign bit. - - :Implementation: - | f[rd] = {f[rs2][31], f[rs1][30:0]} - """ - INS_NOT_IMPLEMENTED(ins) - - def instruction_fsgnjn_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00100|00 |rs2 |rs1 |001 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - - :Format: - | fsgnjn.s rd,rs1,rs2 - - :Description: - | Produce a result that takes all bits except the sign bit from rs1. - | The result’s sign bit is opposite of rs2’s sign bit. - - :Implementation: - | f[rd] = {~f[rs2][31], f[rs1][30:0]} - """ - INS_NOT_IMPLEMENTED(ins) - - def instruction_fsgnjx_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00100|00 |rs2 |rs1 |010 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fsgnjx.s rd,rs1,rs2 - - :Description: - | Produce a result that takes all bits except the sign bit from rs1. - | The result’s sign bit is XOR of sign bit of rs1 and rs2. - - :Implementation: - | f[rd] = {f[rs1][31] ^ f[rs2][31], f[rs1][30:0]} - """ - INS_NOT_IMPLEMENTED(ins) - - def instruction_fmin_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00101|00 |rs2 |rs1 |000 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fmin.s rd,rs1,rs2 - - :Description: - | Write the smaller of single precision data in rs1 and rs2 to rd. - - :Implementation: - | f[rd] = min(f[rs1], f[rs2]) - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - Float32( - min( - rs1.value, - rs2.value, - ) - ), - ) - - def instruction_fmax_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |00101|00 |rs2 |rs1 |001 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fmax.s rd,rs1,rs2 - - :Description: - | Write the larger of single precision data in rs1 and rs2 to rd. - - :Implementation: - | f[rd] = max(f[rs1], f[rs2]) - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set_f( - rd, - Float32( - max( - rs1.value, - rs2.value, - ) - ), - ) +class RV32F(FloatArithBase[Float32]): + flen = 32 + _float_cls = Float32 def instruction_fcvt_w_s(self, ins: Instruction): """ @@ -372,7 +55,7 @@ def instruction_fcvt_wu_s(self, ins: Instruction): | x[rd] = sext(u32_{f32}(f[rs1])) """ rd, rs = self.parse_rd_rs(ins) - self.regs.set(rd, UInt32(self.regs.get_f(rs).value)) + self.regs.set(rd, UInt32(int(self.regs.get_f(rs).value))) def instruction_fmv_x_w(self, ins: Instruction): """ @@ -392,95 +75,7 @@ def instruction_fmv_x_w(self, ins: Instruction): | x[rd] = sext(f[rs1][31:0]) """ rd, rs = self.parse_rd_rs(ins) - self.regs.set(rd, UInt32(self.regs.get_f(rs).bytes)) - - def instruction_feq_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |10100|00 |rs2 |rs1 |010 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | feq.s rd,rs1,rs2 - - :Description: - | Performs a quiet equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. - | Only signaling NaN inputs cause an Invalid Operation exception. - | The result is 0 if either operand is NaN. - - :Implementation: - | x[rd] = f[rs1] == f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set(rd, Int32(rs1 == rs2)) - - def instruction_flt_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |10100|00 |rs2 |rs1 |001 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | flt.s rd,rs1,rs2 - - :Description: - | Performs a quiet less comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. - | Only signaling NaN inputs cause an Invalid Operation exception. - | The result is 0 if either operand is NaN. - - :Implementation: - | x[rd] = f[rs1] < f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set(rd, Int32(rs1 < rs2)) - - def instruction_fle_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |10100|00 |rs2 |rs1 |000 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fle.s rd,rs1,rs2 - - :Description: - | Performs a quiet less or equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. - | Only signaling NaN inputs cause an Invalid Operation exception. - | The result is 0 if either operand is NaN. - - :Implementation: - | x[rd] = f[rs1] <= f[rs2] - """ - rd, rs1, rs2 = self.parse_rd_rs_rs(ins) - self.regs.set(rd, Int32(rs1 <= rs2)) - - def instruction_fclass_s(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |11100|00 |00000|rs1 |001 |rd |10100|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | fclass.s rd,rs1 - - :Description: - | Examines the value in floating-point register rs1 and writes to integer register rd a 10-bit mask that indicates the class of the floating-point number. - | The format of the mask is described in [classify table]_. - | The corresponding bit in rd will be set if the property is true and clear otherwise. - | All other bits in rd are cleared. Note that exactly one bit in rd will be set. - - :Implementation: - | x[rd] = classifys(f[rs1]) - """ - INS_NOT_IMPLEMENTED(ins) + self.regs.set(rd, UInt32(self.regs.get_f(rs).bytes[-4:])) def instruction_fcvt_s_w(self, ins: Instruction): """ @@ -542,68 +137,4 @@ def instruction_fmv_w_x(self, ins: Instruction): | f[rd] = x[rs1][31:0] """ rd, rs = self.parse_rd_rs(ins) - self.regs.set_f(rd, Float32.from_bytes(self.regs.get(rs).unsigned_value)) - - def instruction_flw(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+-----+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+-----+-----+---+ - |imm[11:0] |rs1 |010 |rd |00001|11 | - +-----+-----+-----+-----+-----+-----+-----+---+ - - :Format: - | flw rd,offset(rs1) - - :Description: - | Load a single-precision floating-point value from memory into floating-point register rd. - - :Implementation: - | f[rd] = M[x[rs1] + sext(offset)][31:0] - """ - rd, addr = self.parse_mem_ins(ins) - self.regs.set_f(rd, self.mmu.read_float(addr.value)) - - def instruction_fsw(self, ins: Instruction): - """ - +-----+-----+-----+-----+-----+--------+-----+---+ - |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| - +-----+-----+-----+-----+-----+--------+-----+---+ - |imm[11:5] |rs2 |rs1 |010 |imm[4:0]|01001|11 | - +-----+-----+-----+-----+-----+--------+-----+---+ - - :Format: - | fsw rs2,offset(rs1) - - :Description: - | Store a single-precision value from floating-point register rs2 to memory. - - :Implementation: - | M[x[rs1] + sext(offset)] = f[rs2][31:0] - """ - rs, addr = self.parse_mem_ins(ins) - val = self.regs.get_f(rs) - self.mmu.write(addr.value, 4, bytearray(val.bytes)) - - def parse_rd_rs(self, ins: Instruction) -> Tuple[str, str]: - assert len(ins.args) == 2 - return ins.get_reg(0), ins.get_reg(1) - - def parse_rd_rs_rs(self, ins: Instruction) -> Tuple[str, Float32, Float32]: - assert len(ins.args) == 3 - return ( - ins.get_reg(0), - self.regs.get_f(ins.get_reg(1)), - self.regs.get_f(ins.get_reg(2)), - ) - - def parse_rd_rs_rs_rs( - self, ins: Instruction - ) -> Tuple[str, Float32, Float32, Float32]: - assert len(ins.args) == 4 - return ( - ins.get_reg(0), - self.regs.get_f(ins.get_reg(1)), - self.regs.get_f(ins.get_reg(2)), - self.regs.get_f(ins.get_reg(3)), - ) + self.regs.set_f(rd, Float32.from_bytes(self.regs.get(rs).to_bytes())) diff --git a/riscemu/instructions/RV_Debug.py b/riscemu/instructions/RV_Debug.py index a898dcb..e78bebd 100644 --- a/riscemu/instructions/RV_Debug.py +++ b/riscemu/instructions/RV_Debug.py @@ -1,6 +1,7 @@ from typing import Union from .instruction_set import InstructionSet, Instruction +from ..core import BaseFloat, Int32, Float32 class RV_Debug(InstructionSet): @@ -21,6 +22,10 @@ def instruction_print_float(self, ins: Instruction): reg = ins.get_reg(0) print("register {} contains value {}".format(reg, self.regs.get_f(reg).value)) + def instruction_print_float_s(self, ins: Instruction): + reg = ins.get_reg(0) + print("register {} contains value {}".format(reg, Float32.bitcast(self.regs.get_f(reg)).value)) + def instruction_print_uint(self, ins: Instruction): reg = ins.get_reg(0) print( @@ -43,7 +48,7 @@ def instruction_print_uhex(self, ins: Instruction): ) ) - def smart_get_reg(self, reg_name: str) -> Union[int, float]: + def smart_get_reg(self, reg_name: str) -> Union[Int32, BaseFloat]: if reg_name[0] == "f": - return self.regs.get_f(reg_name).value - return self.regs.get(reg_name).value + return self.regs.get_f(reg_name) + return self.regs.get(reg_name) diff --git a/riscemu/instructions/__init__.py b/riscemu/instructions/__init__.py index 51925f0..5714ca3 100644 --- a/riscemu/instructions/__init__.py +++ b/riscemu/instructions/__init__.py @@ -11,21 +11,23 @@ from .RV32I import RV32I from .RV32A import RV32A from .RV32F import RV32F +from .RV32D import RV32D from .RV_Debug import RV_Debug from .Zicsr import Zicsr InstructionSetDict = { - v.__name__: v for v in [RV32I, RV32M, RV32A, RV32F, Zicsr, RV_Debug] + v.__name__: v for v in [RV32I, RV32M, RV32A, RV32F, RV32D, Zicsr, RV_Debug] } __all__ = [ - Instruction, - InstructionSet, - InstructionSetDict, - RV32I, - RV32M, - RV32A, - RV32F, - Zicsr, - RV_Debug, + "Instruction", + "InstructionSet", + "InstructionSetDict", + "RV32I", + "RV32M", + "RV32A", + "RV32F", + "RV32D", + "Zicsr", + "RV_Debug", ] diff --git a/riscemu/instructions/float_base.py b/riscemu/instructions/float_base.py new file mode 100644 index 0000000..71cdbe4 --- /dev/null +++ b/riscemu/instructions/float_base.py @@ -0,0 +1,388 @@ +from typing import ClassVar, Generic, TypeVar, Tuple, Iterable, Callable + +from .instruction_set import InstructionSet, Instruction +from riscemu.core import BaseFloat, CPU, INS_NOT_IMPLEMENTED, UInt32 + +_FloatT = TypeVar('_FloatT', bound=BaseFloat) + + +class FloatArithBase(Generic[_FloatT], InstructionSet): + flen: ClassVar[int] + _float_cls: ClassVar[type[BaseFloat]] + + def __init__(self, cpu: CPU): + assert cpu.regs.flen >= self.flen, "{} implies cpu flen of at least {}".format(self.__class__.__name__, + self.flen) + super().__init__(cpu) + + def base_fmadd(self, ins: Instruction): + """ + :Format: + | fmadd.{s,d,q} rd,rs1,rs2,rs3 + + :Description: + | Perform fused multiply addition. + + :Implementation: + | f[rd] = f[rs1]×f[rs2]+f[rs3] + + """ + rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) + self.regs.set_f(rd, rs1 * rs2 + rs3) + + def base_fmsub(self, ins: Instruction): + """ + :Format: + | fmsub.{s,d,q} rd,rs1,rs2,rs3 + + :Description: + | Perform fused multiply subtraction. + + :Implementation: + | f[rd] = f[rs1]×f[rs2]-f[rs3] + """ + rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) + self.regs.set_f(rd, rs1 * rs2 - rs3) + + def base_fnmsub(self, ins: Instruction): + """ + :Format: + | fnmsub.{s,d,q} rd,rs1,rs2,rs3 + + :Description: + | Perform fused negated multiply addition. + + :Implementation: + | f[rd] = -f[rs1]×f[rs2]+f[rs3] + """ + rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) + self.regs.set_f(rd, -rs1 * rs2 + rs3) + + def base_fnmadd(self, ins: Instruction): + """ + :Format: + | fnmadd.{s,d,q} rd,rs1,rs2,rs3 + + :Description: + | Perform single-precision fused negated multiply addition. + + :Implementation: + | f[rd] = -f[rs1]×f[rs2]-f[rs3] + """ + rd, rs1, rs2, rs3 = self.parse_rd_rs_rs_rs(ins) + self.regs.set_f(rd, -rs1 * rs2 - rs3) + + def base_fadd(self, ins: Instruction): + """ + +-----+-----+-----+-----+-----+-----+-----+---+ + |31-27|26-25|24-20|19-15|14-12|11-7 |6-2 |1-0| + +-----+-----+-----+-----+-----+-----+-----+---+ + |00000|00 |rs2 |rs1 |rm |rd |10100|11 | + +-----+-----+-----+-----+-----+-----+-----+---+ + + + :Format: + | fadd.s rd,rs1,rs2 + + :Description: + | Perform single-precision floating-point addition. + + :Implementation: + | f[rd] = f[rs1] + f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + rs1 + rs2, + ) + + def base_fsub(self, ins: Instruction): + """ + :Format: + | fsub.{s,d,q} rd,rs1,rs2 + + :Description: + | Perform single-precision floating-point subtraction. + + :Implementation: + | f[rd] = f[rs1] - f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + rs1 - rs2, + ) + + def base_fmul(self, ins: Instruction): + """ + :Format: + | fmul.{s,d,q} rd,rs1,rs2 + + :Description: + | Perform floating-point multiplication. + + :Implementation: + | f[rd] = f[rs1] × f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + rs1 * rs2, + ) + + def base_fdiv(self, ins: Instruction): + """ + :Format: + | fdiv.{s,d,q} rd,rs1,rs2 + + :Description: + | Perform floating-point division. + + :Implementation: + | f[rd] = f[rs1] / f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + rs1 / rs2, + ) + + def base_fsqrt(self, ins: Instruction): + """ + :Format: + | fsqrt.{s,d,q} rd,rs1 + + :Description: + | Perform single-precision square root. + + :Implementation: + | f[rd] = sqrt(f[rs1]) + """ + rd, rs = self.parse_rd_rs(ins) + self.regs.set_f(rd, self._float_cls.bitcast(self.regs.get_f(rs)) ** 0.5) + + def base_fsgnj(self, ins: Instruction): + """ + :Format: + | fsgnj.{s,d,q} rd,rs1,rs2 + + :Description: + | Produce a result that takes all bits except the sign bit from rs1. + | The result’s sign bit is rs2’s sign bit. + + :Implementation: + | f[rd] = {f[rs2][31], f[rs1][30:0]} + """ + INS_NOT_IMPLEMENTED(ins) + + def base_fsgnjn(self, ins: Instruction): + """ + :Format: + | fsgnjn.{s,d,q} rd,rs1,rs2 + + :Description: + | Produce a result that takes all bits except the sign bit from rs1. + | The result’s sign bit is opposite of rs2’s sign bit. + + :Implementation: + | f[rd] = {~f[rs2][31], f[rs1][30:0]} + """ + INS_NOT_IMPLEMENTED(ins) + + def base_fsgnjx(self, ins: Instruction): + """ + :Format: + | fsgnjx.{s,d,q} rd,rs1,rs2 + + :Description: + | Produce a result that takes all bits except the sign bit from rs1. + | The result’s sign bit is XOR of sign bit of rs1 and rs2. + + :Implementation: + | f[rd] = {f[rs1][31] ^ f[rs2][31], f[rs1][30:0]} + """ + INS_NOT_IMPLEMENTED(ins) + + def base_fmin(self, ins: Instruction): + """ + :Format: + | fmin.{s,d,q} rd,rs1,rs2 + + :Description: + | Write the smaller of rs1 and rs2 to rd. + + :Implementation: + | f[rd] = min(f[rs1], f[rs2]) + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + min( + rs1, + rs2, + ), + ) + + def base_fmax(self, ins: Instruction): + """ + :Format: + | fmax.{s,d,q} rd,rs1,rs2 + + :Description: + | Write the larger of rs1 and rs2 to rd. + + :Implementation: + | f[rd] = max(f[rs1], f[rs2]) + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set_f( + rd, + max( + rs1, + rs2, + ), + ) + + def base_feq(self, ins: Instruction): + """ + :Format: + | feq.{s,d,q} rd,rs1,rs2 + + :Description: + | Performs a quiet equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. + | Only signaling NaN inputs cause an Invalid Operation exception. + | The result is 0 if either operand is NaN. + + :Implementation: + | x[rd] = f[rs1] == f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set(rd, UInt32(rs1 == rs2)) + + def base_flt(self, ins: Instruction): + """ + :Format: + | flt.{s,d,q} rd,rs1,rs2 + + :Description: + | Performs a quiet less comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. + | Only signaling NaN inputs cause an Invalid Operation exception. + | The result is 0 if either operand is NaN. + + :Implementation: + | x[rd] = f[rs1] < f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set(rd, UInt32(rs1 < rs2)) + + def base_fle(self, ins: Instruction): + """ + :Format: + | fle.{s,d,q} rd,rs1,rs2 + + :Description: + | Performs a quiet less or equal comparison between floating-point registers rs1 and rs2 and record the Boolean result in integer register rd. + | Only signaling NaN inputs cause an Invalid Operation exception. + | The result is 0 if either operand is NaN. + + :Implementation: + | x[rd] = f[rs1] <= f[rs2] + """ + rd, rs1, rs2 = self.parse_rd_rs_rs(ins) + self.regs.set(rd, UInt32(rs1 <= rs2)) + + def base_fclass(self, ins: Instruction): + """ + :Format: + | fclass.{s,d,q} rd,rs1 + + :Description: + | Examines the value in floating-point register rs1 and writes to integer register rd a 10-bit mask that indicates the class of the floating-point number. + | The format of the mask is described in [classify table]_. + | The corresponding bit in rd will be set if the property is true and clear otherwise. + | All other bits in rd are cleared. Note that exactly one bit in rd will be set. + + :Implementation: + | x[rd] = classifys(f[rs1]) + """ + INS_NOT_IMPLEMENTED(ins) + + def base_load(self, ins: Instruction): + """ + :Format: + | fl{w,d,q} rd,offset(rs1) + + :Description: + | Load a floating-point value from memory into floating-point register rd. + + :Implementation: + | f[rd] = M[x[rs1] + sext(offset)][31:0] + """ + rd, addr = self.parse_mem_ins(ins) + bytes = self.mmu.read(addr.value, self.flen // 8) + self.regs.set_f(rd, self._float_cls(bytes)) + + def base_save(self, ins: Instruction): + """:Format: + | fs{w,d,q} rs2,offset(rs1) + + :Description: + | Store a value from floating-point register rs2 to memory. + + :Implementation: + | M[x[rs1] + sext(offset)] = f[rs2][31:0] + """ + rs, addr = self.parse_mem_ins(ins) + val = self._float_cls.bitcast(self.regs.get_f(rs)) + self.mmu.write(addr.value, self.flen // 8, bytearray(val.bytes)) + + def get_instructions(self) -> Iterable[Tuple[str, Callable[[Instruction], None]]]: + yield from super().get_instructions() + + qual = {32: 's', 64: 'd', 128: 'q'}.get(self.flen) + load_save_qual = {32: 'w', 64: 'd', 128: 'q'}.get(self.flen) + + yield from ( + ('fmadd.' + qual, self.base_fmadd), + ('fmsub.' + qual, self.base_fmsub), + ('fnmsub.' + qual, self.base_fnmsub), + ('fnmadd.' + qual, self.base_fnmadd), + ('fadd.' + qual, self.base_fadd), + ('fsub.' + qual, self.base_fnmadd), + ('fmul.' + qual, self.base_fmul), + ('fdiv.' + qual, self.base_fdiv), + ('fsqrt.' + qual, self.base_fsqrt), + ('fsgnj.' + qual, self.base_fsgnj), + ('fsgnjn.' + qual, self.base_fsgnjn), + ('fsgnjx.' + qual, self.base_fsgnjx), + ('fmin.' + qual, self.base_fmin), + ('fmax.' + qual, self.base_fmax), + ('feq.' + qual, self.base_feq), + ('flt.' + qual, self.base_flt), + ('fle.' + qual, self.base_fle), + ('fl' + load_save_qual, self.base_load), + ('fs' + load_save_qual, self.base_save), + ) + + def parse_rd_rs(self, ins: Instruction) -> Tuple[str, str]: + assert len(ins.args) == 2 + return ins.get_reg(0), ins.get_reg(1) + + def parse_rd_rs_rs(self, ins: Instruction) -> Tuple[str, _FloatT, _FloatT]: + assert len(ins.args) == 3 + return ( + ins.get_reg(0), + self._float_cls.bitcast(self.regs.get_f(ins.get_reg(1))), + self._float_cls.bitcast(self.regs.get_f(ins.get_reg(2))), + ) + + def parse_rd_rs_rs_rs( + self, ins: Instruction + ) -> Tuple[str, _FloatT, _FloatT, _FloatT]: + assert len(ins.args) == 4 + return ( + ins.get_reg(0), + self._float_cls.bitcast(self.regs.get_f(ins.get_reg(1))), + self._float_cls.bitcast(self.regs.get_f(ins.get_reg(2))), + self._float_cls.bitcast(self.regs.get_f(ins.get_reg(3))), + ) diff --git a/riscemu/instructions/instruction_set.py b/riscemu/instructions/instruction_set.py index ec28988..1c56ab6 100644 --- a/riscemu/instructions/instruction_set.py +++ b/riscemu/instructions/instruction_set.py @@ -4,12 +4,12 @@ SPDX-License-Identifier: MIT """ -from typing import Tuple, Callable, Dict, Union +from typing import Tuple, Callable, Dict, Union, Iterable from abc import ABC from ..core.exceptions import ASSERT_LEN -from ..core import Instruction, Int32, UInt32, Immediate, CPU +from ..core import Instruction, Int32, UInt32, Immediate, CPU, Registers class InstructionSet(ABC): @@ -39,7 +39,7 @@ def load(self) -> Dict[str, Callable[["Instruction"], None]]: """ return {name: ins for name, ins in self.get_instructions()} - def get_instructions(self): + def get_instructions(self) -> Iterable[Tuple[str, Callable[[Instruction], None]]]: """ Returns a list of all valid instruction names included in this instruction set @@ -128,7 +128,7 @@ def mmu(self): return self.cpu.mmu @property - def regs(self): + def regs(self) -> Registers: return self.cpu.regs def __repr__(self): diff --git a/riscemu/riscemu_main.py b/riscemu/riscemu_main.py index 381e9ca..5e2ccc0 100644 --- a/riscemu/riscemu_main.py +++ b/riscemu/riscemu_main.py @@ -121,9 +121,9 @@ def register_all_arguments(self, parser: argparse.ArgumentParser): parser.add_argument( "--flen", type=int, - help="hardware FLEN, either 32 or 64", + help="hardware FLEN, either 32 or 64. Defaults to 64", nargs="?", - default=32, + default=64, ) parser.add_argument( diff --git a/test/filecheck/rv32f-conv.asm b/test/filecheck/rv32f-conv.asm index 52cdb7e..1e4f75d 100644 --- a/test/filecheck/rv32f-conv.asm +++ b/test/filecheck/rv32f-conv.asm @@ -7,7 +7,7 @@ main: // test fcvt.s.wu li a1, -2 fcvt.s.wu fa0, a1 - print.float fa0 + print.float.s fa0 // CHECK: register fa0 contains value 4294967296.0 li a1, 2 fcvt.s.wu fa0, a1 @@ -17,11 +17,11 @@ main: // test fcvt.s.w li a1, -2 fcvt.s.w fa0, a1 - print.float fa0 + print.float.s fa0 // CHECK: register fa0 contains value -2.0 li a1, 2 fcvt.s.w fa0, a1 - print.float fa0 + print.float.s fa0 // CHECK-NEXT: register fa0 contains value 2.0 // test fmv.s.x @@ -39,11 +39,11 @@ main: // test fmv.w.x li a1, 1073741824 fmv.w.x fa0, a1 - print.float fa0 + print.float.s fa0 // CHECK-NEXT: register fa0 contains value 2.0 li a1, 3221225472 fmv.w.x fa0, a1 - print.float fa0 + print.float.s fa0 // CHECK-NEXT: register fa0 contains value -2.0 ret diff --git a/test/test_RV32F.py b/test/test_RV32F.py index f50f832..49d6a12 100644 --- a/test/test_RV32F.py +++ b/test/test_RV32F.py @@ -1,12 +1,17 @@ -from typing import Iterable from riscemu.instructions.RV32F import RV32F -from riscemu.core.registers import Registers -from riscemu.core import ProgramLoader, CPU -from riscemu.core.float import BaseFloat -from riscemu.core.int32 import Int32 -from riscemu.core.simple_instruction import SimpleInstruction +from riscemu.core import CPU, Float32, Int32, SimpleInstruction, Registers, BaseFloat +def is_close(a0: float | int | BaseFloat, a1: float | int | BaseFloat): + """ + Compares if two numbers are close to 7 digits. + This should be close enough to catch any real erros but ignore + floating point rounding issues. + """ + diff = abs(float(a0 - a1)) + mag = max(abs(float(a0)), abs(float(a1))) + return (mag / 1e7) > diff + class MockInstruction(SimpleInstruction): ... @@ -16,12 +21,8 @@ class MockRegisters(Registers): class MockCPU(CPU): - def __init__(self): - self.regs = MockRegisters(True) - - @classmethod - def get_loaders(cls) -> "Iterable[type[ProgramLoader]]": - assert False + def __init__(self, flen: int=32): + self.regs = MockRegisters(True, flen) def run(self, verbose: bool = False): assert False @@ -30,7 +31,7 @@ def step(self, verbose: bool = False): assert False -def test_cvt_instructions(): +def test_fcvt_instructions(): cpu = MockCPU() ins = MockInstruction("fcvt.s.w", ("fa0", "a0"), None, None) @@ -39,6 +40,73 @@ def test_cvt_instructions(): assert 42.0 == cpu.regs.get_f("fa0") ins = MockInstruction("fcvt.w.s", ("a1", "fa1"), None, None) - cpu.regs.set_f("fa1", BaseFloat(42.0)) + cpu.regs.set_f("fa1", Float32(42.0)) RV32F(cpu).instruction_fcvt_w_s(ins) assert Int32(42) == cpu.regs.get("a1") + + +def test_single_precision_on_flen64(): + cpu = MockCPU(flen=64) + + cpu.regs.set_f('ft0', Float32(100)) + cpu.regs.set_f('ft1', Float32(3)) + # instruction doing ft2 <- ft1 ft2 + + ins = MockInstruction("", ("ft2", "ft0", "ft1"), None, None) + + # div + RV32F(cpu).base_fdiv(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0/3)) + + # multiplication + RV32F(cpu).base_fmul(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 * 3)) + + # fadd + RV32F(cpu).base_fadd(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 + 3)) + + # fsub + RV32F(cpu).base_fsub(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 - 3)) + + # fmin + RV32F(cpu).base_fmin(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), min(100.0, 3)) + + # fmax + RV32F(cpu).base_fmax(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), max(100.0, 3)) + +def test_single_precision_on_flen32(): + cpu = MockCPU(flen=32) + + cpu.regs.set_f('ft0', Float32(100)) + cpu.regs.set_f('ft1', Float32(3)) + # instruction doing ft2 <- ft1 ft2 + + ins = MockInstruction("", ("ft2", "ft0", "ft1"), None, None) + + # div + RV32F(cpu).base_fdiv(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0/3)) + + # multiplication + RV32F(cpu).base_fmul(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 * 3)) + + # fadd + RV32F(cpu).base_fadd(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 + 3)) + + # fsub + RV32F(cpu).base_fsub(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 - 3)) + + # fmin + RV32F(cpu).base_fmin(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), min(100.0, 3)) + + # fmax + RV32F(cpu).base_fmax(ins) + assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), max(100.0, 3)) diff --git a/test/test_float32.py b/test/test_float32.py deleted file mode 100644 index 35d40fe..0000000 --- a/test/test_float32.py +++ /dev/null @@ -1,25 +0,0 @@ -import math - -from riscemu.core import BaseFloat - -# pi encoded as a 32bit little endian float -PI_BYTES_LE = b"\xdb\x0fI@" - - -def test_float_serialization(): - assert BaseFloat(PI_BYTES_LE) == BaseFloat(math.pi) - assert BaseFloat(math.pi).bytes == PI_BYTES_LE - - -def test_random_float_ops(): - val = BaseFloat(5) - assert val**2 == 25 - assert val // 2 == 2 - assert val * 3 == 15 - assert val - 2 == 3 - assert val * val == 25 - assert BaseFloat(9) ** 0.5 == 3 - - -def test_float_from_raw_int_conversion(): - assert BaseFloat.from_bytes(1084227584) == BaseFloat(5.0) diff --git a/test/test_float_impl.py b/test/test_float_impl.py new file mode 100644 index 0000000..be2b387 --- /dev/null +++ b/test/test_float_impl.py @@ -0,0 +1,46 @@ +import math + +from riscemu.core import Float32, Float64 + +# pi encoded as a 32bit little endian float +PI_BYTES_LE = b"\xdb\x0fI@" + + +def test_float_serialization(): + assert Float32(PI_BYTES_LE) == Float32(math.pi) + assert Float32(math.pi).bytes == PI_BYTES_LE + + +def test_float_bitcast(): + f32_pi = Float32(math.pi) + f64_pi32 = Float64.bitcast(f32_pi) + assert f32_pi.bytes == Float32.bitcast(f64_pi32).bytes + + f64_pi = Float64(math.pi) + f32_pi64 = Float32.bitcast(f64_pi) + assert f64_pi.bytes[-4:] == f32_pi64.bytes + assert Float64.bitcast(f32_pi64).bytes[:4] == b"\x00\x00\x00\x00" + + +def test_random_float_ops32(): + val = Float32(5) + assert val**2 == 25 + assert val // 2 == 2 + assert val * 3 == 15 + assert val - 2 == 3 + assert val * val == 25 + assert Float32(9) ** 0.5 == 3 + + +def test_random_float_ops64(): + val = Float64(5) + assert val**2 == 25 + assert val // 2 == 2 + assert val * 3 == 15 + assert val - 2 == 3 + assert val * val == 25 + assert Float64(9) ** 0.5 == 3 + + +def test_float_from_raw_bytes_conversion(): + assert Float32.from_bytes(b'\x00\x00\xa0@') == Float32(5.0) diff --git a/test/test_regs.py b/test/test_regs.py index 4c00b29..e2a414a 100644 --- a/test/test_regs.py +++ b/test/test_regs.py @@ -1,7 +1,7 @@ import pytest from riscemu.core.registers import Registers -from riscemu.core import BaseFloat +from riscemu.core import Float32 def test_float_regs(): @@ -9,10 +9,19 @@ def test_float_regs(): # uninitialized register is zero assert r.get_f("fs0") == 0 # get/set - val = BaseFloat(3.14) + val = Float32(3.14) r.set_f("fs0", val) assert r.get_f("fs0") == val +def test_float_regs_flen64(): + r = Registers(flen=64) + # uninitialized register is zero + assert r.get_f("fs0") == 0 + # get/set + val = Float32(3.14) + r.set_f("fs0", val) + assert Float32.bitcast(r.get_f("fs0")) == val + def test_unlimited_regs_works(): r = Registers(infinite_regs=True) From 82560eb891ef60e63797e37dbe6e1616e5449141 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 18:37:14 +0100 Subject: [PATCH 03/24] black --- riscemu/core/float.py | 16 ++++++---- riscemu/instructions/RV_Debug.py | 6 +++- riscemu/instructions/float_base.py | 51 +++++++++++++++--------------- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/riscemu/core/float.py b/riscemu/core/float.py index a73d30f..4eb2398 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -171,10 +171,14 @@ def bitcast(cls, f: "BaseFloat") -> "BaseFloat": """ if isinstance(f, cls): return f - return cls.from_bytes((b"\x00\x00\x00\x00\x00\x00\x00\x00" + f.bytes)[-struct.calcsize(cls._struct_fmt_str):]) + return cls.from_bytes( + (b"\x00\x00\x00\x00\x00\x00\x00\x00" + f.bytes)[ + -struct.calcsize(cls._struct_fmt_str) : + ] + ) @classmethod - def flen_to_cls(cls, bits: int) -> type['BaseFloat']: + def flen_to_cls(cls, bits: int) -> type["BaseFloat"]: if bits == 32: return Float32 if bits == 64: @@ -182,18 +186,18 @@ def flen_to_cls(cls, bits: int) -> type['BaseFloat']: raise ValueError(f"Unsupported flen: {bits}") def __format__(self, spec: str): - if spec[-2:] == '32': + if spec[-2:] == "32": return Float32.bitcast(self).__format__(spec[:-2]) - if spec[-2:] == '64': + if spec[-2:] == "64": return Float64.bitcast(self).__format__(spec[:-2]) return format(self.value, spec) class Float32(BaseFloat): _type = c_float - _struct_fmt_str = 'f' + _struct_fmt_str = "f" class Float64(BaseFloat): _type = c_double - _struct_fmt_str = 'd' + _struct_fmt_str = "d" diff --git a/riscemu/instructions/RV_Debug.py b/riscemu/instructions/RV_Debug.py index e78bebd..b33cac3 100644 --- a/riscemu/instructions/RV_Debug.py +++ b/riscemu/instructions/RV_Debug.py @@ -24,7 +24,11 @@ def instruction_print_float(self, ins: Instruction): def instruction_print_float_s(self, ins: Instruction): reg = ins.get_reg(0) - print("register {} contains value {}".format(reg, Float32.bitcast(self.regs.get_f(reg)).value)) + print( + "register {} contains value {}".format( + reg, Float32.bitcast(self.regs.get_f(reg)).value + ) + ) def instruction_print_uint(self, ins: Instruction): reg = ins.get_reg(0) diff --git a/riscemu/instructions/float_base.py b/riscemu/instructions/float_base.py index 71cdbe4..f6b3b51 100644 --- a/riscemu/instructions/float_base.py +++ b/riscemu/instructions/float_base.py @@ -3,7 +3,7 @@ from .instruction_set import InstructionSet, Instruction from riscemu.core import BaseFloat, CPU, INS_NOT_IMPLEMENTED, UInt32 -_FloatT = TypeVar('_FloatT', bound=BaseFloat) +_FloatT = TypeVar("_FloatT", bound=BaseFloat) class FloatArithBase(Generic[_FloatT], InstructionSet): @@ -11,8 +11,9 @@ class FloatArithBase(Generic[_FloatT], InstructionSet): _float_cls: ClassVar[type[BaseFloat]] def __init__(self, cpu: CPU): - assert cpu.regs.flen >= self.flen, "{} implies cpu flen of at least {}".format(self.__class__.__name__, - self.flen) + assert cpu.regs.flen >= self.flen, "{} implies cpu flen of at least {}".format( + self.__class__.__name__, self.flen + ) super().__init__(cpu) def base_fmadd(self, ins: Instruction): @@ -339,29 +340,29 @@ def base_save(self, ins: Instruction): def get_instructions(self) -> Iterable[Tuple[str, Callable[[Instruction], None]]]: yield from super().get_instructions() - qual = {32: 's', 64: 'd', 128: 'q'}.get(self.flen) - load_save_qual = {32: 'w', 64: 'd', 128: 'q'}.get(self.flen) + qual = {32: "s", 64: "d", 128: "q"}.get(self.flen) + load_save_qual = {32: "w", 64: "d", 128: "q"}.get(self.flen) yield from ( - ('fmadd.' + qual, self.base_fmadd), - ('fmsub.' + qual, self.base_fmsub), - ('fnmsub.' + qual, self.base_fnmsub), - ('fnmadd.' + qual, self.base_fnmadd), - ('fadd.' + qual, self.base_fadd), - ('fsub.' + qual, self.base_fnmadd), - ('fmul.' + qual, self.base_fmul), - ('fdiv.' + qual, self.base_fdiv), - ('fsqrt.' + qual, self.base_fsqrt), - ('fsgnj.' + qual, self.base_fsgnj), - ('fsgnjn.' + qual, self.base_fsgnjn), - ('fsgnjx.' + qual, self.base_fsgnjx), - ('fmin.' + qual, self.base_fmin), - ('fmax.' + qual, self.base_fmax), - ('feq.' + qual, self.base_feq), - ('flt.' + qual, self.base_flt), - ('fle.' + qual, self.base_fle), - ('fl' + load_save_qual, self.base_load), - ('fs' + load_save_qual, self.base_save), + ("fmadd." + qual, self.base_fmadd), + ("fmsub." + qual, self.base_fmsub), + ("fnmsub." + qual, self.base_fnmsub), + ("fnmadd." + qual, self.base_fnmadd), + ("fadd." + qual, self.base_fadd), + ("fsub." + qual, self.base_fnmadd), + ("fmul." + qual, self.base_fmul), + ("fdiv." + qual, self.base_fdiv), + ("fsqrt." + qual, self.base_fsqrt), + ("fsgnj." + qual, self.base_fsgnj), + ("fsgnjn." + qual, self.base_fsgnjn), + ("fsgnjx." + qual, self.base_fsgnjx), + ("fmin." + qual, self.base_fmin), + ("fmax." + qual, self.base_fmax), + ("feq." + qual, self.base_feq), + ("flt." + qual, self.base_flt), + ("fle." + qual, self.base_fle), + ("fl" + load_save_qual, self.base_load), + ("fs" + load_save_qual, self.base_save), ) def parse_rd_rs(self, ins: Instruction) -> Tuple[str, str]: @@ -377,7 +378,7 @@ def parse_rd_rs_rs(self, ins: Instruction) -> Tuple[str, _FloatT, _FloatT]: ) def parse_rd_rs_rs_rs( - self, ins: Instruction + self, ins: Instruction ) -> Tuple[str, _FloatT, _FloatT, _FloatT]: assert len(ins.args) == 4 return ( From 436b4775e172281434ad0ce2ebfa58943a241034 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 18:38:51 +0100 Subject: [PATCH 04/24] add psutil ass a dev dependency --- poetry.lock | 39 ++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/poetry.lock b/poetry.lock index 04ac05e..0b18d9a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -282,6 +282,33 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "psutil" +version = "5.9.5" +description = "Cross-platform lib for process and system monitoring in Python." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + [[package]] name = "pyelftools" version = "0.29" @@ -330,6 +357,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -337,8 +365,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -355,6 +390,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -362,6 +398,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -432,4 +469,4 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "52c6ac0d4ad940d610fb2df7674277b3f913f00ecc8b9b0a0c70a98b63daac1d" +content-hash = "101d1d8488b76556b4759b1ab9d4fff1fa806629960a2d8a89596ae800ff162c" diff --git a/pyproject.toml b/pyproject.toml index fc55c6c..8636caf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ pytest = "^7.4.0" filecheck = "^0.0.23" lit = "^16.0.6" pre-commit = "^3.3.3" +psutil = "^5.9.5" [build-system] requires = ["poetry-core"] From aa37a49aa286b6029c8fc06dad91398866c48e04 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 18:39:56 +0100 Subject: [PATCH 05/24] black test --- test/test_RV32F.py | 36 +++++++++++++++++++----------------- test/test_float_impl.py | 2 +- test/test_regs.py | 1 + 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/test/test_RV32F.py b/test/test_RV32F.py index 49d6a12..bc782fc 100644 --- a/test/test_RV32F.py +++ b/test/test_RV32F.py @@ -12,6 +12,7 @@ def is_close(a0: float | int | BaseFloat, a1: float | int | BaseFloat): mag = max(abs(float(a0)), abs(float(a1))) return (mag / 1e7) > diff + class MockInstruction(SimpleInstruction): ... @@ -21,7 +22,7 @@ class MockRegisters(Registers): class MockCPU(CPU): - def __init__(self, flen: int=32): + def __init__(self, flen: int = 32): self.regs = MockRegisters(True, flen) def run(self, verbose: bool = False): @@ -48,65 +49,66 @@ def test_fcvt_instructions(): def test_single_precision_on_flen64(): cpu = MockCPU(flen=64) - cpu.regs.set_f('ft0', Float32(100)) - cpu.regs.set_f('ft1', Float32(3)) + cpu.regs.set_f("ft0", Float32(100)) + cpu.regs.set_f("ft1", Float32(3)) # instruction doing ft2 <- ft1 ft2 ins = MockInstruction("", ("ft2", "ft0", "ft1"), None, None) # div RV32F(cpu).base_fdiv(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0/3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 / 3)) # multiplication RV32F(cpu).base_fmul(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 * 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 * 3)) # fadd RV32F(cpu).base_fadd(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 + 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 + 3)) # fsub RV32F(cpu).base_fsub(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 - 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 - 3)) # fmin RV32F(cpu).base_fmin(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), min(100.0, 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), min(100.0, 3)) # fmax RV32F(cpu).base_fmax(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), max(100.0, 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), max(100.0, 3)) + def test_single_precision_on_flen32(): cpu = MockCPU(flen=32) - cpu.regs.set_f('ft0', Float32(100)) - cpu.regs.set_f('ft1', Float32(3)) + cpu.regs.set_f("ft0", Float32(100)) + cpu.regs.set_f("ft1", Float32(3)) # instruction doing ft2 <- ft1 ft2 ins = MockInstruction("", ("ft2", "ft0", "ft1"), None, None) # div RV32F(cpu).base_fdiv(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0/3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 / 3)) # multiplication RV32F(cpu).base_fmul(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 * 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 * 3)) # fadd RV32F(cpu).base_fadd(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 + 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 + 3)) # fsub RV32F(cpu).base_fsub(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), (100.0 - 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), (100.0 - 3)) # fmin RV32F(cpu).base_fmin(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), min(100.0, 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), min(100.0, 3)) # fmax RV32F(cpu).base_fmax(ins) - assert is_close(Float32.bitcast(cpu.regs.get_f('ft2')), max(100.0, 3)) + assert is_close(Float32.bitcast(cpu.regs.get_f("ft2")), max(100.0, 3)) diff --git a/test/test_float_impl.py b/test/test_float_impl.py index be2b387..48e7b1e 100644 --- a/test/test_float_impl.py +++ b/test/test_float_impl.py @@ -43,4 +43,4 @@ def test_random_float_ops64(): def test_float_from_raw_bytes_conversion(): - assert Float32.from_bytes(b'\x00\x00\xa0@') == Float32(5.0) + assert Float32.from_bytes(b"\x00\x00\xa0@") == Float32(5.0) diff --git a/test/test_regs.py b/test/test_regs.py index e2a414a..afb6976 100644 --- a/test/test_regs.py +++ b/test/test_regs.py @@ -13,6 +13,7 @@ def test_float_regs(): r.set_f("fs0", val) assert r.get_f("fs0") == val + def test_float_regs_flen64(): r = Registers(flen=64) # uninitialized register is zero From 3ca2fe959ad21979def777d66a9422a9b019f664 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 18:50:35 +0100 Subject: [PATCH 06/24] fix python 3.8 compat --- test/test_RV32F.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_RV32F.py b/test/test_RV32F.py index bc782fc..e55468f 100644 --- a/test/test_RV32F.py +++ b/test/test_RV32F.py @@ -1,8 +1,10 @@ +from typing import Union + from riscemu.instructions.RV32F import RV32F from riscemu.core import CPU, Float32, Int32, SimpleInstruction, Registers, BaseFloat -def is_close(a0: float | int | BaseFloat, a1: float | int | BaseFloat): +def is_close(a0: Union[float, int, BaseFloat], a1: Union[float, int, BaseFloat]): """ Compares if two numbers are close to 7 digits. This should be close enough to catch any real erros but ignore From b3794ec2264e496f4f3194de7edf31a18f09b7e3 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 18:56:35 +0100 Subject: [PATCH 07/24] fix python 3.8 compat again --- riscemu/core/float.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscemu/core/float.py b/riscemu/core/float.py index 4eb2398..a4f88f9 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -1,7 +1,7 @@ import struct from ctypes import c_float, c_double from typing import Union, Any, ClassVar -from abc import ABC, abstractmethod +from abc import ABC bytes_t = bytes @@ -9,7 +9,7 @@ class BaseFloat(ABC): __slots__ = ("_val",) - _type: ClassVar[type[c_float | c_double]] + _type: ClassVar[type[Union[c_float, c_double]]] _struct_fmt_str: ClassVar[str] _val: c_float | c_double From 910203df2c6320b3a0f1dbec6829c6c716417f3f Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 19:01:10 +0100 Subject: [PATCH 08/24] fix python 3.8 compat again? --- riscemu/core/float.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscemu/core/float.py b/riscemu/core/float.py index a4f88f9..b93506d 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -1,6 +1,6 @@ import struct from ctypes import c_float, c_double -from typing import Union, Any, ClassVar +from typing import Union, Any, ClassVar, Type from abc import ABC bytes_t = bytes @@ -9,7 +9,7 @@ class BaseFloat(ABC): __slots__ = ("_val",) - _type: ClassVar[type[Union[c_float, c_double]]] + _type: ClassVar[Type[Union[c_float, c_double]]] _struct_fmt_str: ClassVar[str] _val: c_float | c_double From 31769c60c1dfbc3f2d0e8810e8da7afbb75c7ea6 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 19:03:23 +0100 Subject: [PATCH 09/24] fix python 3.8 compat again?! --- riscemu/core/float.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscemu/core/float.py b/riscemu/core/float.py index b93506d..b5170d9 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -12,7 +12,7 @@ class BaseFloat(ABC): _type: ClassVar[Type[Union[c_float, c_double]]] _struct_fmt_str: ClassVar[str] - _val: c_float | c_double + _val: Union[c_float, c_double] @property def value(self) -> float: From bcdafbbb5fe944362be2737da97c906d5bb388ba Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 19:06:07 +0100 Subject: [PATCH 10/24] fix python 3.8 compat again?!! --- riscemu/core/float.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/riscemu/core/float.py b/riscemu/core/float.py index b5170d9..56b6efa 100644 --- a/riscemu/core/float.py +++ b/riscemu/core/float.py @@ -37,7 +37,7 @@ def __init__( ): if isinstance(val, (float, int)): self._val = self._type(val) - elif isinstance(val, c_float | c_double): + elif isinstance(val, (c_float, c_double)): self._val = self._type(val.value) elif isinstance(val, (bytes, bytearray)): self._val = self._type(struct.unpack("<" + self._struct_fmt_str, val)[0]) @@ -178,7 +178,7 @@ def bitcast(cls, f: "BaseFloat") -> "BaseFloat": ) @classmethod - def flen_to_cls(cls, bits: int) -> type["BaseFloat"]: + def flen_to_cls(cls, bits: int) -> Type["BaseFloat"]: if bits == 32: return Float32 if bits == 64: From da377c0d97a0c2e6ad28b0e637cede4bc798ebcf Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 19:08:29 +0100 Subject: [PATCH 11/24] fix python 3.8 compat again?!!! --- riscemu/core/registers.py | 4 ++-- riscemu/instructions/float_base.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/riscemu/core/registers.py b/riscemu/core/registers.py index 7b34efd..3729f9b 100644 --- a/riscemu/core/registers.py +++ b/riscemu/core/registers.py @@ -5,7 +5,7 @@ """ from collections import defaultdict -from typing import Union +from typing import Union, Type from ..helpers import * @@ -85,7 +85,7 @@ class Registers: } flen: int - _float_type: type[BaseFloat] + _float_type: Type[BaseFloat] def __init__(self, infinite_regs: bool = False, flen: int = 32): self.vals: dict[str, Int32] = defaultdict(UInt32) diff --git a/riscemu/instructions/float_base.py b/riscemu/instructions/float_base.py index f6b3b51..f2b9634 100644 --- a/riscemu/instructions/float_base.py +++ b/riscemu/instructions/float_base.py @@ -1,4 +1,4 @@ -from typing import ClassVar, Generic, TypeVar, Tuple, Iterable, Callable +from typing import ClassVar, Generic, TypeVar, Tuple, Iterable, Callable, Type from .instruction_set import InstructionSet, Instruction from riscemu.core import BaseFloat, CPU, INS_NOT_IMPLEMENTED, UInt32 @@ -8,7 +8,7 @@ class FloatArithBase(Generic[_FloatT], InstructionSet): flen: ClassVar[int] - _float_cls: ClassVar[type[BaseFloat]] + _float_cls: ClassVar[Type[BaseFloat]] def __init__(self, cpu: CPU): assert cpu.regs.flen >= self.flen, "{} implies cpu flen of at least {}".format( From 1a18d86a214a991984892b64dd1602259ea56dff Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 19:35:19 +0100 Subject: [PATCH 12/24] add changelog --- CHANGELOG.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbec701..e067e0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,20 @@ # Changelog -# 2.2.2 +## 2.2.3 + + - Feature: Adding support for 64 bit floating point operations + - BugFix: Fix `__all__` to now properly work (use name strings instead of values) + +## 2.2.2 - Dev: Add `__all__` to `riscemu.{core,instructions,decoder}` modules to make pyright in other projects happy - Perf: very minor fix related to not converting values twice when loaded from memory -# 2.2.1 +## 2.2.1 Version bump to re-trigger CI run. -# 2.2.0 +## 2.2.0 - Feature: Added Zicsr extension and with that support for CSRs - Feature: Starting to add support for Snitch architecture (Xssr) From 64800195932ef2ec5cea6db972cbd536a615013a Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Mon, 9 Oct 2023 20:59:20 +0100 Subject: [PATCH 13/24] initial version of frep, untested --- snitch/frep.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 snitch/frep.py diff --git a/snitch/frep.py b/snitch/frep.py new file mode 100644 index 0000000..c27aadd --- /dev/null +++ b/snitch/frep.py @@ -0,0 +1,69 @@ +from typing import List, Type, Union, Set + +from riscemu.config import RunConfig +from riscemu.core import UserModeCPU +from riscemu.instructions import InstructionSet, Instruction, RV32F + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class FrepState: + rep_count: int + ins_count: int + + stagger_max: int + stagger_mask: int + + +class FrepEnabledCpu(UserModeCPU): + repeat: Union[FrepState, None] + allowed_ins: Set[str] + + def __init__(self, instruction_sets: List[Type["InstructionSet"]], conf: RunConfig): + self.repeats = None + + self.allowed_ins = set(x for x, y in RV32F(self).get_instructions()) + self.allowed_ins.union(set(x for x, y in Xfrep(self).get_instructions())) + + super().__init__(instruction_sets, conf) + + def step(self, verbose: bool = False, depth: int = 0): + if self.repeats is None: + assert ( + self.mmu.read_ins(self.pc).name in self.allowed_ins + ), "must be a float ins" + super().step(verbose=verbose) + return + + if depth > 1: + raise RuntimeError("frep depth exceeded?") + + # get the spec + spec: FrepState = self.repeats + self.repeats = None + + pc = self.pc + for _ in range(spec.rep_count + 1): + self.pc = pc + c0 = self.cycle + while self.cycle < c0 + spec.ins_count: + self.step(verbose=verbose, depth=depth + 1) + + +class Xfrep(InstructionSet): + def instruction_frep_o(self, ins: Instruction): + self.frep(ins) + + def instruction_frep_i(self, ins: Instruction): + self.frep(ins) + + def frep(self, ins: Instruction): + assert isinstance(self.cpu, FrepEnabledCpu) + assert len(ins.args) == 4 + self.cpu.repeats = FrepState( + rep_count=self.regs.get(ins.get_reg(0)).unsigned_value, + ins_count=ins.get_imm(1).abs_value.value, + stagger_max=ins.get_imm(2).abs_value.value, + stagger_mask=ins.get_imm(3).abs_value.value, + ) From ec1c896e0a8cd36cfc7d98cfcaa508fd167c1ed6 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 10:11:46 +0100 Subject: [PATCH 14/24] implement a real version of frep --- snitch/frep.py | 53 +++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/snitch/frep.py b/snitch/frep.py index c27aadd..47c3c8c 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -1,4 +1,4 @@ -from typing import List, Type, Union, Set +from typing import List, Type, Union, Set, Literal from riscemu.config import RunConfig from riscemu.core import UserModeCPU @@ -11,9 +11,7 @@ class FrepState: rep_count: int ins_count: int - - stagger_max: int - stagger_mask: int + mode: Literal["inner", "outer"] class FrepEnabledCpu(UserModeCPU): @@ -22,48 +20,51 @@ class FrepEnabledCpu(UserModeCPU): def __init__(self, instruction_sets: List[Type["InstructionSet"]], conf: RunConfig): self.repeats = None - + # only floating point instructions are allowed inside an frep! self.allowed_ins = set(x for x, y in RV32F(self).get_instructions()) - self.allowed_ins.union(set(x for x, y in Xfrep(self).get_instructions())) super().__init__(instruction_sets, conf) - def step(self, verbose: bool = False, depth: int = 0): + def step(self, verbose: bool = False): if self.repeats is None: - assert ( - self.mmu.read_ins(self.pc).name in self.allowed_ins - ), "must be a float ins" - super().step(verbose=verbose) - return - - if depth > 1: - raise RuntimeError("frep depth exceeded?") - + super().step() # get the spec spec: FrepState = self.repeats self.repeats = None + instructions = [ + self.mmu.read_ins(self.pc + i * self.INS_XLEN) + for i in range(spec.ins_count) + ] + pc = self.pc - for _ in range(spec.rep_count + 1): - self.pc = pc - c0 = self.cycle - while self.cycle < c0 + spec.ins_count: - self.step(verbose=verbose, depth=depth + 1) + if spec.mode == "outer": + for _ in range(spec.rep_count + 1): + for ins in instructions: + self.run_instruction(ins) + elif spec.mode == "inner": + for ins in instructions: + for _ in range(spec.rep_count + 1): + self.run_instruction(ins) + + self.pc = pc + (spec.ins_count * self.INS_XLEN) class Xfrep(InstructionSet): def instruction_frep_o(self, ins: Instruction): - self.frep(ins) + self.frep(ins, "outer") def instruction_frep_i(self, ins: Instruction): - self.frep(ins) + self.frep(ins, "inner") - def frep(self, ins: Instruction): + def frep(self, ins: Instruction, mode: Literal["inner", "outer"]): assert isinstance(self.cpu, FrepEnabledCpu) assert len(ins.args) == 4 + assert ins.get_imm(2).abs_value.value == 0, "staggering not supported yet" + assert ins.get_imm(3).abs_value.value == 0, "staggering not supported yet" + self.cpu.repeats = FrepState( rep_count=self.regs.get(ins.get_reg(0)).unsigned_value, ins_count=ins.get_imm(1).abs_value.value, - stagger_max=ins.get_imm(2).abs_value.value, - stagger_mask=ins.get_imm(3).abs_value.value, + mode=mode, ) From 8cce6a873ee7898371a0d8f8ef1b03a712efdd8c Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 11:04:39 +0100 Subject: [PATCH 15/24] adding tests, fixing bugs --- riscemu/core/usermode_cpu.py | 4 +- snitch/__main__.py | 10 ++-- snitch/frep.py | 22 ++++++++- snitch/regs.py | 6 --- snitch/xssr.py | 2 +- test/filecheck/snitch/frep_only.asm | 17 +++++++ test/filecheck/snitch/xssr_only.asm | 69 +++++++++++++++++++++++++++ test/filecheck/snitch_simple.asm | 74 ----------------------------- 8 files changed, 115 insertions(+), 89 deletions(-) create mode 100644 test/filecheck/snitch/frep_only.asm create mode 100644 test/filecheck/snitch/xssr_only.asm delete mode 100644 test/filecheck/snitch_simple.asm diff --git a/riscemu/core/usermode_cpu.py b/riscemu/core/usermode_cpu.py index 8f1c83f..b792d9e 100644 --- a/riscemu/core/usermode_cpu.py +++ b/riscemu/core/usermode_cpu.py @@ -64,9 +64,7 @@ def step(self, verbose: bool = False): self.cycle += 1 ins = self.mmu.read_ins(self.pc) if verbose: - print( - FMT_CPU + " Running 0x{:08X}:{} {}".format(self.pc, FMT_NONE, ins) - ) + print(FMT_CPU + " 0x{:08X}:{} {}".format(self.pc, FMT_NONE, ins)) self.pc += self.INS_XLEN self.run_instruction(ins) except RiscemuBaseException as ex: diff --git a/snitch/__main__.py b/snitch/__main__.py index b0f28d5..4033caa 100644 --- a/snitch/__main__.py +++ b/snitch/__main__.py @@ -8,18 +8,20 @@ import sys from .regs import StreamingRegs -from .xssr import RV32_Xssr_pseudo +from .xssr import Xssr_pseudo +from .frep import FrepEnabledCpu, Xfrep from riscemu.riscemu_main import RiscemuMain class SnitchMain(RiscemuMain): - def configure_cpu(self): - super().configure_cpu() + def instantiate_cpu(self): + self.cpu = FrepEnabledCpu(self.selected_ins_sets, self.cfg) self.cpu.regs = StreamingRegs(self.cpu.mmu) + self.configure_cpu() def register_all_isas(self): super().register_all_isas() - self.available_ins_sets.update({"Xssr": RV32_Xssr_pseudo}) + self.available_ins_sets.update({"Xssr": Xssr_pseudo, "Xfrep": Xfrep}) if __name__ == "__main__": diff --git a/snitch/frep.py b/snitch/frep.py index 47c3c8c..876fc50 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -1,5 +1,6 @@ from typing import List, Type, Union, Set, Literal +from riscemu.colors import FMT_CPU, FMT_NONE from riscemu.config import RunConfig from riscemu.core import UserModeCPU from riscemu.instructions import InstructionSet, Instruction, RV32F @@ -27,7 +28,8 @@ def __init__(self, instruction_sets: List[Type["InstructionSet"]], conf: RunConf def step(self, verbose: bool = False): if self.repeats is None: - super().step() + super().step(verbose=verbose) + return # get the spec spec: FrepState = self.repeats self.repeats = None @@ -37,6 +39,22 @@ def step(self, verbose: bool = False): for i in range(spec.ins_count) ] + if verbose: + print( + FMT_CPU + + "┌────── floating point repetition ({}) {} times".format( + spec.mode, spec.rep_count + 1 + ) + ) + for i, ins in enumerate(instructions): + print( + FMT_CPU + + "│ 0x{:08X}:{} {}".format( + self.pc + i * self.INS_XLEN, FMT_NONE, ins + ) + ) + print(FMT_CPU + "└────── end of floating point repetition" + FMT_NONE) + pc = self.pc if spec.mode == "outer": for _ in range(spec.rep_count + 1): @@ -46,6 +64,8 @@ def step(self, verbose: bool = False): for ins in instructions: for _ in range(spec.rep_count + 1): self.run_instruction(ins) + else: + raise RuntimeError(f"Unknown frep mode: {spec.mode}") self.pc = pc + (spec.ins_count * self.INS_XLEN) diff --git a/snitch/regs.py b/snitch/regs.py index e8311c6..b0269ca 100644 --- a/snitch/regs.py +++ b/snitch/regs.py @@ -76,9 +76,6 @@ def get_f(self, reg, mark_read=True) -> "BaseFloat": addr = stream.base + (stream.pos * stream.stride) val = self.mem.read_float(addr) # increment pos - print( - "stream: got val {} from addr 0x{:x}, stream {}".format(val, addr, stream) - ) stream.pos += 1 return val @@ -92,8 +89,5 @@ def set_f(self, reg, val: "BaseFloat", mark_set=True) -> bool: addr = stream.base + (stream.pos * stream.stride) self.mem.write(addr, 4, bytearray(val.bytes)) - print( - "stream: wrote val {} into addr 0x{:x}, stream {}".format(val, addr, stream) - ) stream.pos += 1 return True diff --git a/snitch/xssr.py b/snitch/xssr.py index 1c90d1a..982af51 100644 --- a/snitch/xssr.py +++ b/snitch/xssr.py @@ -3,7 +3,7 @@ from .regs import StreamingRegs, StreamDef, StreamMode -class RV32_Xssr_pseudo(InstructionSet): +class Xssr_pseudo(InstructionSet): def instruction_ssr_enable(self, ins: Instruction): self._stream.enabled = True diff --git a/test/filecheck/snitch/frep_only.asm b/test/filecheck/snitch/frep_only.asm new file mode 100644 index 0000000..a79e7d2 --- /dev/null +++ b/test/filecheck/snitch/frep_only.asm @@ -0,0 +1,17 @@ +.text +.globl main +main: + li t0, 0 + fcvt.s.w ft0, t0 + li t0, 1 + fcvt.s.w ft1, t0 + + printf "ft0 = {}, ft1 = {}", ft0, ft1 + // repeat 100 times + li t0, 99 + frep.i t0, 1, 0, 0 + fadd.s ft0, ft0, ft1 // add one + printf "100 * 1 = {}", ft1 + + li a0, 0 + ret diff --git a/test/filecheck/snitch/xssr_only.asm b/test/filecheck/snitch/xssr_only.asm new file mode 100644 index 0000000..092f8be --- /dev/null +++ b/test/filecheck/snitch/xssr_only.asm @@ -0,0 +1,69 @@ +// RUN: python3 -m snitch %s -o libc | filecheck %s + +.data + +vec0: +.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 +vec1: +.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 +dest: +.space 40 + +.text +.globl main + +main: + // ssr config + ssr.configure 0, 10, 4 + ssr.configure 1, 10, 4 + ssr.configure 2, 10, 4 + + la a0, vec0 + ssr.read a0, 0, 0 + + la a0, vec1 + ssr.read a0, 1, 0 + + la a0, dest + ssr.write a0, 2, 0 + + ssr.enable + + // set up loop + li a0, 10 +loop: + fadd.s ft2, ft0, ft1 + + addi a0, a0, -1 + bne a0, zero, loop + + // end of loop: + ssr.disable + + // check values were written correctly: + la t0, vec0 + la t1, vec1 + li a0, 40 +loop2: + add s0, t0, a0 + add s1, t1, a0 + // load vec0 element + flw ft0, 0(s0) + // load vec1 element + flw ft1, 0(s1) + // assert ft1 - ft0 == ft0 + fsub.s ft2, ft1, ft0 + feq.s s0, ft2, ft0 + beq zero, s0, fail + + addi a0, a0, -4 + bne a0, zero, loop2 + + ret + +fail: + printf "failed {} != {} (at {})", ft0, ft1, a0 + li a0, -1 + ret + +// CHECK: [CPU] Program exited with code 0 diff --git a/test/filecheck/snitch_simple.asm b/test/filecheck/snitch_simple.asm deleted file mode 100644 index 3cdab19..0000000 --- a/test/filecheck/snitch_simple.asm +++ /dev/null @@ -1,74 +0,0 @@ -// RUN: python3 -m snitch %s -o libc | filecheck %s - -.data - -vec0: -.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 -vec1: -.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 -dest: -.space 40 - -.text -.globl main - -main: - // ssr config - ssr.configure 0, 10, 4 - ssr.configure 1, 10, 4 - ssr.configure 2, 10, 4 - - la a0, vec0 - ssr.read a0, 0, 0 - - la a0, vec1 - ssr.read a0, 1, 0 - - la a0, dest - ssr.write a0, 2, 0 - - ssr.enable - - // set up loop - li a0, 100 -loop: - fadd.s ft2, ft0, ft1 - - addi a0, a0, -1 - bne a0, zero, loop - - // end of loop: - ssr.disable - - ret - -//CHECK: stream: got val 0.0 from addr 0x80148, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=0) -//CHECK_NEXT: stream: got val 0.0 from addr 0x80170, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=0) -//CHECK_NEXT: stream: wrote val 0.0 into addr 0x80198, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=0) -//CHECK_NEXT: stream: got val 1.0 from addr 0x8014c, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=1) -//CHECK_NEXT: stream: got val 1.0 from addr 0x80174, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=1) -//CHECK_NEXT: stream: wrote val 2.0 into addr 0x8019c, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=1) -//CHECK_NEXT: stream: got val 2.0 from addr 0x80150, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=2) -//CHECK_NEXT: stream: got val 2.0 from addr 0x80178, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=2) -//CHECK_NEXT: stream: wrote val 4.0 into addr 0x801a0, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=2) -//CHECK_NEXT: stream: got val 3.0 from addr 0x80154, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=3) -//CHECK_NEXT: stream: got val 3.0 from addr 0x8017c, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=3) -//CHECK_NEXT: stream: wrote val 6.0 into addr 0x801a4, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=3) -//CHECK_NEXT: stream: got val 4.0 from addr 0x80158, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=4) -//CHECK_NEXT: stream: got val 4.0 from addr 0x80180, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=4) -//CHECK_NEXT: stream: wrote val 8.0 into addr 0x801a8, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=4) -//CHECK_NEXT: stream: got val 5.0 from addr 0x8015c, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=5) -//CHECK_NEXT: stream: got val 5.0 from addr 0x80184, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=5) -//CHECK_NEXT: stream: wrote val 10.0 into addr 0x801ac, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=5) -//CHECK_NEXT: stream: got val 6.0 from addr 0x80160, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=6) -//CHECK_NEXT: stream: got val 6.0 from addr 0x80188, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=6) -//CHECK_NEXT: stream: wrote val 12.0 into addr 0x801b0, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=6) -//CHECK_NEXT: stream: got val 7.0 from addr 0x80164, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=7) -//CHECK_NEXT: stream: got val 7.0 from addr 0x8018c, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=7) -//CHECK_NEXT: stream: wrote val 14.0 into addr 0x801b4, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=7) -//CHECK_NEXT: stream: got val 8.0 from addr 0x80168, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=8) -//CHECK_NEXT: stream: got val 8.0 from addr 0x80190, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=8) -//CHECK_NEXT: stream: wrote val 16.0 into addr 0x801b8, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=8) -//CHECK_NEXT: stream: got val 9.0 from addr 0x8016c, stream StreamDef(base=524616, bound=10, stride=4, mode=, dim=0, pos=9) -//CHECK_NEXT: stream: got val 9.0 from addr 0x80194, stream StreamDef(base=524656, bound=10, stride=4, mode=, dim=0, pos=9) -//CHECK_NEXT: stream: wrote val 18.0 into addr 0x801bc, stream StreamDef(base=524696, bound=10, stride=4, mode=, dim=0, pos=9) From a67b28652b39bcd460b543ee82014e34b5a7de94 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 11:34:59 +0100 Subject: [PATCH 16/24] fix some snitch tests --- riscemu/core/registers.py | 4 +-- snitch/frep.py | 2 +- snitch/regs.py | 8 ++--- test/filecheck/snitch/frep_only.asm | 11 +++++-- test/filecheck/snitch/xssr_only.asm | 50 ++++++++++++++++------------- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/riscemu/core/registers.py b/riscemu/core/registers.py index 3729f9b..c1084f3 100644 --- a/riscemu/core/registers.py +++ b/riscemu/core/registers.py @@ -218,11 +218,9 @@ def get(self, reg: str, mark_read: bool = True) -> Int32: self.last_read = reg return self.vals[reg] - def get_f(self, reg: str, mark_read: bool = True) -> BaseFloat: + def get_f(self, reg: str) -> BaseFloat: if not self.infinite_regs and reg not in self.float_regs: raise RuntimeError("Invalid float register: {}".format(reg)) - if mark_read: - self.last_read = reg return self.float_vals[reg] def set_f(self, reg: str, val: Union[float, BaseFloat]): diff --git a/snitch/frep.py b/snitch/frep.py index 876fc50..b9a2765 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -66,7 +66,7 @@ def step(self, verbose: bool = False): self.run_instruction(ins) else: raise RuntimeError(f"Unknown frep mode: {spec.mode}") - + self.cycle += (spec.rep_count + 1) * spec.ins_count self.pc = pc + (spec.ins_count * self.INS_XLEN) diff --git a/snitch/regs.py b/snitch/regs.py index b0269ca..9331948 100644 --- a/snitch/regs.py +++ b/snitch/regs.py @@ -63,9 +63,9 @@ def __init__( self.streams[reg] = stream_def super().__init__(infinite_regs) - def get_f(self, reg, mark_read=True) -> "BaseFloat": + def get_f(self, reg) -> "BaseFloat": if not self.enabled or reg not in self.streams: - return super().get_f(reg, mark_read) + return super().get_f(reg) # do the streaming stuff: stream = self.streams[reg] @@ -79,9 +79,9 @@ def get_f(self, reg, mark_read=True) -> "BaseFloat": stream.pos += 1 return val - def set_f(self, reg, val: "BaseFloat", mark_set=True) -> bool: + def set_f(self, reg, val: "BaseFloat") -> bool: if not self.enabled or reg not in self.streams: - return super().set_f(reg, mark_set) + return super().set_f(reg, val) stream = self.streams[reg] assert stream.mode is StreamMode.WRITE diff --git a/test/filecheck/snitch/frep_only.asm b/test/filecheck/snitch/frep_only.asm index a79e7d2..ad2c0c6 100644 --- a/test/filecheck/snitch/frep_only.asm +++ b/test/filecheck/snitch/frep_only.asm @@ -1,17 +1,24 @@ +// RUN: python3 -m snitch %s -o libc -v | filecheck %s + .text .globl main main: + // load constants li t0, 0 fcvt.s.w ft0, t0 li t0, 1 fcvt.s.w ft1, t0 - printf "ft0 = {}, ft1 = {}", ft0, ft1 // repeat 100 times li t0, 99 frep.i t0, 1, 0, 0 fadd.s ft0, ft0, ft1 // add one - printf "100 * 1 = {}", ft1 + // print result to stdout + printf "100 * 1 = {}", ft0 +// CHECK: 100 * 1 = 100.0 + // return 0 li a0, 0 ret + +// CHECK-NEXT: [CPU] Program exited with code 0 diff --git a/test/filecheck/snitch/xssr_only.asm b/test/filecheck/snitch/xssr_only.asm index 092f8be..1366b6b 100644 --- a/test/filecheck/snitch/xssr_only.asm +++ b/test/filecheck/snitch/xssr_only.asm @@ -1,4 +1,4 @@ -// RUN: python3 -m snitch %s -o libc | filecheck %s +// RUN: python3 -m snitch %s -o libc -v | filecheck %s .data @@ -30,40 +30,44 @@ main: ssr.enable // set up loop - li a0, 10 + li a0, 10 loop: - fadd.s ft2, ft0, ft1 + fadd.s ft2, ft0, ft1 - addi a0, a0, -1 - bne a0, zero, loop + addi a0, a0, -1 + bne a0, zero, loop // end of loop: ssr.disable // check values were written correctly: - la t0, vec0 - la t1, vec1 - li a0, 40 + la t0, vec0 + la t1, vec1 + la t2, dest + li a0, 36 loop2: - add s0, t0, a0 - add s1, t1, a0 - // load vec0 element - flw ft0, 0(s0) - // load vec1 element - flw ft1, 0(s1) - // assert ft1 - ft0 == ft0 - fsub.s ft2, ft1, ft0 - feq.s s0, ft2, ft0 - beq zero, s0, fail - - addi a0, a0, -4 - bne a0, zero, loop2 + add s0, t0, a0 + add s1, t1, a0 + add s2, t2, a0 + + // load vec0, vec1 and dest elements + flw ft0, 0(s0) + flw ft1, 0(s1) + flw ft2, 0(s2) + + // assert ft2 == ft1 + ft2 + fadd.s ft3, ft1, ft0 + feq.s s0, ft2, ft3 + beq zero, s0, fail + + addi a0, a0, -4 + bne a0, zero, loop2 ret fail: - printf "failed {} != {} (at {})", ft0, ft1, a0 - li a0, -1 + printf "failed {} + {} != {} (at {})", ft0, ft1, ft2, a0 + li a0, -1 ret // CHECK: [CPU] Program exited with code 0 From 878d13f761aef40a2a838c2dbbb111b6c92ced26 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 11:42:59 +0100 Subject: [PATCH 17/24] rebase on top of flen64 changes --- snitch/__main__.py | 2 +- snitch/frep.py | 8 +++++--- snitch/regs.py | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/snitch/__main__.py b/snitch/__main__.py index 4033caa..dbe5593 100644 --- a/snitch/__main__.py +++ b/snitch/__main__.py @@ -16,12 +16,12 @@ class SnitchMain(RiscemuMain): def instantiate_cpu(self): self.cpu = FrepEnabledCpu(self.selected_ins_sets, self.cfg) - self.cpu.regs = StreamingRegs(self.cpu.mmu) self.configure_cpu() def register_all_isas(self): super().register_all_isas() self.available_ins_sets.update({"Xssr": Xssr_pseudo, "Xfrep": Xfrep}) + self.available_ins_sets.pop("RV32D", None) if __name__ == "__main__": diff --git a/snitch/frep.py b/snitch/frep.py index b9a2765..f8710cd 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -3,10 +3,12 @@ from riscemu.colors import FMT_CPU, FMT_NONE from riscemu.config import RunConfig from riscemu.core import UserModeCPU -from riscemu.instructions import InstructionSet, Instruction, RV32F +from riscemu.instructions import InstructionSet, Instruction, RV32F, RV32D from dataclasses import dataclass +from snitch.regs import StreamingRegs + @dataclass(frozen=True) class FrepState: @@ -20,12 +22,12 @@ class FrepEnabledCpu(UserModeCPU): allowed_ins: Set[str] def __init__(self, instruction_sets: List[Type["InstructionSet"]], conf: RunConfig): + super().__init__(instruction_sets, conf) + self.regs = StreamingRegs(self.mmu, infinite_regs=conf.unlimited_registers) self.repeats = None # only floating point instructions are allowed inside an frep! self.allowed_ins = set(x for x, y in RV32F(self).get_instructions()) - super().__init__(instruction_sets, conf) - def step(self, verbose: bool = False): if self.repeats is None: super().step(verbose=verbose) diff --git a/snitch/regs.py b/snitch/regs.py index 9331948..2f1a4d6 100644 --- a/snitch/regs.py +++ b/snitch/regs.py @@ -61,7 +61,7 @@ def __init__( stream_def = StreamDef() self.dm_by_id.append(stream_def) self.streams[reg] = stream_def - super().__init__(infinite_regs) + super().__init__(infinite_regs, flen=32) def get_f(self, reg) -> "BaseFloat": if not self.enabled or reg not in self.streams: From 1042bd4b3621f73481fa3cdb79b11e09e1449939 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 11:58:36 +0100 Subject: [PATCH 18/24] add test for frep+ssr --- test/filecheck/snitch/ssr_frep.asm | 73 +++++++++++++++++++ .../snitch/{xssr_only.asm => ssr_only.asm} | 0 2 files changed, 73 insertions(+) create mode 100644 test/filecheck/snitch/ssr_frep.asm rename test/filecheck/snitch/{xssr_only.asm => ssr_only.asm} (100%) diff --git a/test/filecheck/snitch/ssr_frep.asm b/test/filecheck/snitch/ssr_frep.asm new file mode 100644 index 0000000..ec02d4a --- /dev/null +++ b/test/filecheck/snitch/ssr_frep.asm @@ -0,0 +1,73 @@ +// RUN: python3 -m snitch %s -o libc -v | filecheck %s + +.data + +vec0: +.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 +vec1: +.word 0x0, 0x3f800000, 0x40000000, 0x40400000, 0x40800000, 0x40a00000, 0x40c00000, 0x40e00000, 0x41000000, 0x41100000 +dest: +.space 40 +expected: +.word 0x0, 0x3e800000, 0x3f800000, 0x40100000, 0x40800000, 0x40c80000, 0x41100000, 0x41440000, 0x41800000, 0x41a20000 + +.text +.globl main + +main: + // ssr config + ssr.configure 0, 10, 4 + ssr.configure 1, 10, 4 + ssr.configure 2, 10, 4 + + // ft0 streams from vec0 + la a0, vec0 + ssr.read a0, 0, 0 + + // ft1 streams from vec1 + la a0, vec1 + ssr.read a0, 1, 0 + + // ft2 streams to dest + la a0, dest + ssr.write a0, 2, 0 + + li a0, 9 + // some constant to divide by + li t0, 4 + fcvt.s.w ft3, t0 + ssr.enable + + frep.o a0, 2, 0, 0 + fmul.s ft4, ft0, ft1 // ft3 = vec0[i] * vec1[i] + fdiv.s ft2, ft4, ft3 // dest[i] = ft3 / 4 + + // stop ssr + ssr.disable + + // check values were written correctly: + la t0, dest + la t1, expected + li a0, 36 +loop: + add s0, t0, a0 + add s1, t1, a0 + + // load vec0, vec1 and dest elements + flw ft0, 0(s0) + flw ft1, 0(s1) + + // assert ft0 == ft1 (expected[i] == dest[i]) + feq.s s0, ft0, ft1 + beq zero, s0, fail + + addi a0, a0, -4 + bge a0, zero loop + + li a0, 0 + ret + +fail: + printf "Assertion failure: {} != {} (at {})", ft0, ft1, a0 + li a0, -1 + ret diff --git a/test/filecheck/snitch/xssr_only.asm b/test/filecheck/snitch/ssr_only.asm similarity index 100% rename from test/filecheck/snitch/xssr_only.asm rename to test/filecheck/snitch/ssr_only.asm From fa79d6b990853ec447bb836ffd2db8817e66cee2 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 12:00:37 +0100 Subject: [PATCH 19/24] fix frep+ssr test --- test/filecheck/snitch/ssr_frep.asm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/filecheck/snitch/ssr_frep.asm b/test/filecheck/snitch/ssr_frep.asm index ec02d4a..dbe0e65 100644 --- a/test/filecheck/snitch/ssr_frep.asm +++ b/test/filecheck/snitch/ssr_frep.asm @@ -71,3 +71,5 @@ fail: printf "Assertion failure: {} != {} (at {})", ft0, ft1, a0 li a0, -1 ret + +// CHECK: [CPU] Program exited with code 0 From b395ff093cf7f1cc31d08769ab93329e2f61b4bd Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 13:32:32 +0100 Subject: [PATCH 20/24] add changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e067e0e..a6937af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Changelog -## 2.2.3 +## Upcoming + - Feature: Added `Xfrep` extension for the snitch emulator getting us closer to full snitch emulation - Feature: Adding support for 64 bit floating point operations - BugFix: Fix `__all__` to now properly work (use name strings instead of values) From f356a561b78493aab8e95312a5ce3457d54bbd18 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Tue, 10 Oct 2023 15:26:53 +0100 Subject: [PATCH 21/24] remove unused import --- riscemu/core/registers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/riscemu/core/registers.py b/riscemu/core/registers.py index d30e093..947003c 100644 --- a/riscemu/core/registers.py +++ b/riscemu/core/registers.py @@ -5,7 +5,7 @@ """ from collections import defaultdict -from typing import Union, Type +from typing import Type from ..helpers import * From 14c760dac3e8215f22a26d6b4cb5f90d8bf4a4ea Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Wed, 11 Oct 2023 10:30:45 +0100 Subject: [PATCH 22/24] add assertion to frep --- snitch/frep.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/snitch/frep.py b/snitch/frep.py index f8710cd..24222bf 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -41,6 +41,13 @@ def step(self, verbose: bool = False): for i in range(spec.ins_count) ] + for ins in instructions: + if ins.name not in self.allowed_ins: + # TODO: wrap in a nicer error type + raise RuntimeError( + "Forbidden instruction inside frep loop: {}".format(ins) + ) + if verbose: print( FMT_CPU From 8df142a450eb2d231bf9a973421c7a77c9c6b238 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Wed, 11 Oct 2023 16:35:36 +0100 Subject: [PATCH 23/24] upgrade xssr to work with 32 and 64 bit flen --- snitch/__main__.py | 2 -- snitch/frep.py | 6 +++++- snitch/regs.py | 8 +++++--- test/filecheck/snitch/frep_only.asm | 2 +- test/filecheck/snitch/ssr_frep.asm | 2 +- test/filecheck/snitch/ssr_only.asm | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/snitch/__main__.py b/snitch/__main__.py index dbe5593..4324b88 100644 --- a/snitch/__main__.py +++ b/snitch/__main__.py @@ -7,7 +7,6 @@ """ import sys -from .regs import StreamingRegs from .xssr import Xssr_pseudo from .frep import FrepEnabledCpu, Xfrep from riscemu.riscemu_main import RiscemuMain @@ -21,7 +20,6 @@ def instantiate_cpu(self): def register_all_isas(self): super().register_all_isas() self.available_ins_sets.update({"Xssr": Xssr_pseudo, "Xfrep": Xfrep}) - self.available_ins_sets.pop("RV32D", None) if __name__ == "__main__": diff --git a/snitch/frep.py b/snitch/frep.py index 24222bf..c8167b3 100644 --- a/snitch/frep.py +++ b/snitch/frep.py @@ -23,10 +23,14 @@ class FrepEnabledCpu(UserModeCPU): def __init__(self, instruction_sets: List[Type["InstructionSet"]], conf: RunConfig): super().__init__(instruction_sets, conf) - self.regs = StreamingRegs(self.mmu, infinite_regs=conf.unlimited_registers) + self.regs = StreamingRegs( + mem=self.mmu, infinite_regs=conf.unlimited_registers, flen=conf.flen + ) self.repeats = None # only floating point instructions are allowed inside an frep! self.allowed_ins = set(x for x, y in RV32F(self).get_instructions()) + if conf.flen > 32: + self.allowed_ins.union(x for x, y in RV32D(self).get_instructions()) def step(self, verbose: bool = False): if self.repeats is None: diff --git a/snitch/regs.py b/snitch/regs.py index 2f1a4d6..ec2cb0e 100644 --- a/snitch/regs.py +++ b/snitch/regs.py @@ -52,6 +52,7 @@ def __init__( mem: MMU, xssr_regs: Tuple[str] = ("ft0", "ft1", "ft2"), infinite_regs: bool = False, + flen: int = 64, ): self.mem = mem self.enabled = False @@ -61,7 +62,7 @@ def __init__( stream_def = StreamDef() self.dm_by_id.append(stream_def) self.streams[reg] = stream_def - super().__init__(infinite_regs, flen=32) + super().__init__(infinite_regs=infinite_regs, flen=flen) def get_f(self, reg) -> "BaseFloat": if not self.enabled or reg not in self.streams: @@ -74,7 +75,7 @@ def get_f(self, reg) -> "BaseFloat": # TODO: Check overflow # TODO: repetition addr = stream.base + (stream.pos * stream.stride) - val = self.mem.read_float(addr) + val = self._float_type(self.mem.read(addr, self.flen // 8)) # increment pos stream.pos += 1 return val @@ -87,7 +88,8 @@ def set_f(self, reg, val: "BaseFloat") -> bool: assert stream.mode is StreamMode.WRITE addr = stream.base + (stream.pos * stream.stride) - self.mem.write(addr, 4, bytearray(val.bytes)) + data = val.bytes + self.mem.write(addr + (self.flen // 8) - len(data), len(data), bytearray(data)) stream.pos += 1 return True diff --git a/test/filecheck/snitch/frep_only.asm b/test/filecheck/snitch/frep_only.asm index ad2c0c6..447c638 100644 --- a/test/filecheck/snitch/frep_only.asm +++ b/test/filecheck/snitch/frep_only.asm @@ -1,4 +1,4 @@ -// RUN: python3 -m snitch %s -o libc -v | filecheck %s +// RUN: python3 -m snitch %s -o libc -v| filecheck %s .text .globl main diff --git a/test/filecheck/snitch/ssr_frep.asm b/test/filecheck/snitch/ssr_frep.asm index dbe0e65..d266c5b 100644 --- a/test/filecheck/snitch/ssr_frep.asm +++ b/test/filecheck/snitch/ssr_frep.asm @@ -1,4 +1,4 @@ -// RUN: python3 -m snitch %s -o libc -v | filecheck %s +// RUN: python3 -m snitch %s -o libc -v --flen 32 | filecheck %s .data diff --git a/test/filecheck/snitch/ssr_only.asm b/test/filecheck/snitch/ssr_only.asm index 1366b6b..d10d762 100644 --- a/test/filecheck/snitch/ssr_only.asm +++ b/test/filecheck/snitch/ssr_only.asm @@ -1,4 +1,4 @@ -// RUN: python3 -m snitch %s -o libc -v | filecheck %s +// RUN: python3 -m snitch %s -o libc -v --flen 32 | filecheck %s .data From 8164878a27d5adc55570e42ca6bcd65728d77ea3 Mon Sep 17 00:00:00 2001 From: Anton Lydike Date: Wed, 11 Oct 2023 16:37:33 +0100 Subject: [PATCH 24/24] fixed error in result printing --- test/filecheck/snitch/frep_only.asm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/filecheck/snitch/frep_only.asm b/test/filecheck/snitch/frep_only.asm index 447c638..106af7f 100644 --- a/test/filecheck/snitch/frep_only.asm +++ b/test/filecheck/snitch/frep_only.asm @@ -1,4 +1,4 @@ -// RUN: python3 -m snitch %s -o libc -v| filecheck %s +// RUN: python3 -m snitch %s -o libc -v | filecheck %s .text .globl main @@ -15,7 +15,7 @@ main: fadd.s ft0, ft0, ft1 // add one // print result to stdout - printf "100 * 1 = {}", ft0 + printf "100 * 1 = {:f32}", ft0 // CHECK: 100 * 1 = 100.0 // return 0 li a0, 0