diff --git a/t1rocketemu/.gitignore b/t1rocketemu/.gitignore deleted file mode 100644 index 9f970225a..000000000 --- a/t1rocketemu/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ \ No newline at end of file diff --git a/t1rocketemu/.rustfmt.toml b/t1rocketemu/.rustfmt.toml deleted file mode 100644 index bf1a32fd3..000000000 --- a/t1rocketemu/.rustfmt.toml +++ /dev/null @@ -1,4 +0,0 @@ -hard_tabs = false -tab_spaces = 2 -chain_width = 100 -struct_lit_width = 50 diff --git a/t1rocketemu/Cargo.lock b/t1rocketemu/Cargo.lock deleted file mode 100644 index d4454b9ac..000000000 --- a/t1rocketemu/Cargo.lock +++ /dev/null @@ -1,610 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - -[[package]] -name = "common" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "spike_rs", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libloading" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "offline" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "common", - "libloading", - "num-bigint", - "serde", - "serde_json", - "spike_rs", - "tracing", - "tracing-subscriber", - "xmas-elf", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.4", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "serde" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "spike_rs" -version = "0.1.0" -dependencies = [ - "anyhow", - "libc", - "tracing", - "xmas-elf", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "xmas-elf" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c49817e78342f7f30a181573d82ff55b88a35f86ccaf07fc64b3008f56d1c6" -dependencies = [ - "zero", -] - -[[package]] -name = "zero" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe21bcc34ca7fe6dd56cc2cb1261ea59d6b93620215aefb5ea6032265527784" diff --git a/t1rocketemu/Cargo.toml b/t1rocketemu/Cargo.toml deleted file mode 100644 index a4278981a..000000000 --- a/t1rocketemu/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[workspace] -resolver = "2" -members = [ - "test_common", - "spike_rs", - "offline", -] -exclude = [ - "spike_interfaces" -] - -[workspace.package] -version = "0.1.0" - -[workspace.dependencies] -anyhow = "1.0.79" -clap = { version = "4.4.18", features = ["derive"] } -tracing = "0.1.40" -tracing-subscriber = { version = "0.3", features = ["env-filter", "ansi"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -num-bigint = "0.4.6" diff --git a/t1rocketemu/offline/Cargo.toml b/t1rocketemu/offline/Cargo.toml deleted file mode 100644 index 2824a161e..000000000 --- a/t1rocketemu/offline/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "offline" -version = "0.1.0" -edition = "2021" - -[dependencies] -clap = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -anyhow = { workspace = true } -serde = { workspace = true } -serde_json = { workspace = true } -num-bigint = { workspace = true } - -libloading = "0.8.1" -xmas-elf = "0.9.1" - -common = { path = "../test_common" } -spike_rs = { path = "../spike_rs" } diff --git a/t1rocketemu/offline/default.nix b/t1rocketemu/offline/default.nix deleted file mode 100644 index 9c31c6387..000000000 --- a/t1rocketemu/offline/default.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ lib -, rustPlatform -, libspike -, libspike_interfaces -, rtlDesignMetadata -}: - - -rustPlatform.buildRustPackage { - name = "vcs-offline-checker"; - buildAndTestSubdir = "./offline"; - - src = with lib.fileset; toSource { - root = ../.; - fileset = unions [ - ../spike_rs - ../offline - ../test_common - ../Cargo.lock - ../Cargo.toml - ]; - }; - - env = { - SPIKE_LIB_DIR = "${libspike}/lib"; - SPIKE_INTERFACES_LIB_DIR = "${libspike_interfaces}/lib"; - DESIGN_VLEN = rtlDesignMetadata.vlen; - DESIGN_DLEN = rtlDesignMetadata.dlen; - SPIKE_ISA_STRING = rtlDesignMetadata.march; - }; - - cargoLock = { - lockFile = ../Cargo.lock; - }; -} diff --git a/t1rocketemu/offline/src/difftest.rs b/t1rocketemu/offline/src/difftest.rs deleted file mode 100644 index d8ce0a225..000000000 --- a/t1rocketemu/offline/src/difftest.rs +++ /dev/null @@ -1,106 +0,0 @@ -use common::spike_runner::SpikeRunner; -use std::path::Path; - -use common::rtl_config::RTLConfig; -use common::CommonArgs; - -use crate::dut::Dut; -use crate::json_events::*; - -pub struct Difftest { - runner: SpikeRunner, - dut: Dut, - - #[allow(dead_code)] - config: RTLConfig, -} - -impl Difftest { - pub fn new(args: CommonArgs) -> Self { - let config = RTLConfig { vlen: args.vlen, dlen: args.dlen }; - Self { - runner: SpikeRunner::new(&args, true), - dut: Dut::new(Path::new( - &args.log_file.expect("difftest must be run with a log file"), - )), - config, - } - } - - pub fn diff(&mut self) -> anyhow::Result<()> { - self.runner.check_and_clear_fence(); - - let event = self.dut.step()?; - - match event { - JsonEvents::SimulationStart { cycle } => { - self.runner.cycle = *cycle; - Ok(()) - } - JsonEvents::SimulationStop { reason, cycle } => { - anyhow::bail!("error: simulation stopped at cycle {cycle}, reason {reason}") - } - JsonEvents::SimulationEnd { cycle } => { - anyhow::bail!("simulation quit successfullly cycle {cycle}"); - } - JsonEvents::RegWrite { idx, data, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_reg_write(&RegWriteEvent { idx: *idx, data: *data, cycle: *cycle }) - } - JsonEvents::RegWriteWait { idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_reg_write_wait(&RegWriteWaitEvent { idx: *idx, cycle: *cycle }) - } - JsonEvents::FregWrite { idx, data, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_freg_write(&RegWriteEvent { idx: *idx, data: *data, cycle: *cycle }) - } - JsonEvents::FregWriteWait { idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_freg_write_wait(&RegWriteWaitEvent { idx: *idx, cycle: *cycle }) - } - JsonEvents::Issue { idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_issue(&IssueEvent { idx: *idx, cycle: *cycle }) - } - JsonEvents::MemoryWrite { mask, data, lsu_idx, address, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_memory_write(&MemoryWriteEvent { - mask: mask.clone(), - data: data.clone(), - lsu_idx: *lsu_idx, - address: *address, - cycle: *cycle, - }) - } - JsonEvents::LsuEnq { enq, cycle } => { - self.runner.cycle = *cycle; - self.runner.update_lsu_idx(&LsuEnqEvent { enq: *enq, cycle: *cycle }) - } - JsonEvents::VrfWrite { issue_idx, vd, offset, mask, data, lane, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_vrf_write(&VrfWriteEvent { - issue_idx: *issue_idx, - vd: *vd, - offset: *offset, - mask: mask.clone(), - data: data.clone(), - lane: *lane, - cycle: *cycle, - }) - } - JsonEvents::CheckRd { data, issue_idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.check_rd(&CheckRdEvent { data: *data, issue_idx: *issue_idx, cycle: *cycle }) - } - JsonEvents::VrfScoreboard { count, issue_idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.vrf_scoreboard(&VrfScoreboardEvent { - count: *count, - issue_idx: *issue_idx, - cycle: *cycle, - }) - } - } - } -} diff --git a/t1rocketemu/offline/src/dut.rs b/t1rocketemu/offline/src/dut.rs deleted file mode 100644 index f3e5d20f7..000000000 --- a/t1rocketemu/offline/src/dut.rs +++ /dev/null @@ -1,49 +0,0 @@ -use anyhow::Context; -use std::io::BufRead; -use std::path::Path; - -use crate::json_events::JsonEvents; - -#[derive(Debug)] -pub struct Dut { - events: Vec, - idx: u32, -} - -impl Dut { - fn read_json(path: &Path) -> anyhow::Result> { - let file = std::fs::File::open(path).unwrap(); - let reader = std::io::BufReader::new(file); - - let mut events = Vec::new(); - - for (i, line) in reader.lines().enumerate() { - let line = line.expect("line read error"); - if line.starts_with("{") { - // ignore illegal lines - let event: JsonEvents = serde_json::from_str(&line) - .with_context(|| format!("parsing {} line {}", path.display(), i + 1))?; - events.push(event); - } - } - - Ok(events) - } - - pub fn new(path: &Path) -> Self { - let events = Self::read_json(path).unwrap(); - let idx = 0; - Self { events, idx } - } - - pub fn step(&mut self) -> anyhow::Result<&JsonEvents> { - let event = match self.events.get(self.idx as usize) { - Some(event) => event, - None => anyhow::bail!("error: simulation stopped with no more events"), - }; - - self.idx += 1; - - Ok(event) - } -} diff --git a/t1rocketemu/offline/src/json_events.rs b/t1rocketemu/offline/src/json_events.rs deleted file mode 100644 index 6a324a37c..000000000 --- a/t1rocketemu/offline/src/json_events.rs +++ /dev/null @@ -1,574 +0,0 @@ -use common::spike_runner::SpikeRunner; -use num_bigint::BigUint; -use serde::{Deserialize, Deserializer}; -use spike_rs::spike_event::LSU_IDX_DEFAULT; -use tracing::{debug, info}; - -fn str_to_vec_u8<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let bigint = BigUint::parse_bytes(s.trim_start().as_bytes(), 16) - .ok_or_else(|| serde::de::Error::custom("Failed to parse BigUint from hex string"))?; - Ok(bigint.to_bytes_le()) -} - -fn str_to_vec_bool<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let bigint = BigUint::parse_bytes(s.trim_start().as_bytes(), 16) - .ok_or_else(|| serde::de::Error::custom("Failed to parse BigUint from hex string"))?; - let bytes = bigint.to_bytes_le(); - let bools = bytes.iter().flat_map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)).collect(); - - Ok(bools) -} - -fn str_to_u32<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let value = - u32::from_str_radix(s.trim_start_matches(' '), 16).map_err(serde::de::Error::custom)?; - - Ok(value) -} - -fn mask_display(mask: &Vec) -> String { - mask.into_iter().map(|&b| if b { '1' } else { '0' }).collect() -} - -#[derive(Deserialize, Debug)] -#[serde(tag = "event")] -pub(crate) enum JsonEvents { - SimulationStart { - cycle: u64, - }, - SimulationEnd { - cycle: u64, - }, - SimulationStop { - reason: u8, - cycle: u64, - }, - RegWrite { - idx: u8, - #[serde(deserialize_with = "str_to_u32", default)] - data: u32, - cycle: u64, - }, - RegWriteWait { - idx: u8, - cycle: u64, - }, - FregWrite { - idx: u8, - #[serde(deserialize_with = "str_to_u32", default)] - data: u32, - cycle: u64, - }, - FregWriteWait { - idx: u8, - cycle: u64, - }, - Issue { - idx: u8, - cycle: u64, - }, - LsuEnq { - enq: u32, - cycle: u64, - }, - VrfWrite { - issue_idx: u8, - vd: u32, - offset: u32, - #[serde(deserialize_with = "str_to_vec_bool", default)] - mask: Vec, - #[serde(deserialize_with = "str_to_vec_u8", default)] - data: Vec, - lane: u32, - cycle: u64, - }, - MemoryWrite { - #[serde(deserialize_with = "str_to_vec_bool", default)] - mask: Vec, - #[serde(deserialize_with = "str_to_vec_u8", default)] - data: Vec, - lsu_idx: u8, - #[serde(deserialize_with = "str_to_u32", default)] - address: u32, - cycle: u64, - }, - CheckRd { - #[serde(deserialize_with = "str_to_u32", default)] - data: u32, - issue_idx: u8, - cycle: u64, - }, - VrfScoreboard { - count: u32, - issue_idx: u8, - cycle: u64, - }, -} - -pub struct RegWriteEvent { - pub idx: u8, - pub data: u32, - pub cycle: u64, -} - -pub struct RegWriteWaitEvent { - pub idx: u8, - pub cycle: u64, -} - -pub struct IssueEvent { - pub idx: u8, - pub cycle: u64, -} - -pub struct LsuEnqEvent { - pub enq: u32, - pub cycle: u64, -} - -pub struct VrfWriteEvent { - pub lane: u32, - pub vd: u32, - pub offset: u32, - pub mask: Vec, - pub data: Vec, - pub issue_idx: u8, - pub cycle: u64, -} - -pub struct MemoryWriteEvent { - pub mask: Vec, - pub data: Vec, - pub lsu_idx: u8, - pub address: u32, - pub cycle: u64, -} - -pub struct VrfScoreboardEvent { - pub count: u32, - pub issue_idx: u8, - pub cycle: u64, -} - -pub struct CheckRdEvent { - pub data: u32, - pub issue_idx: u8, - pub cycle: u64, -} - -pub(crate) trait JsonEventRunner { - fn peek_reg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()>; - - fn peek_reg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()>; - - fn peek_freg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()>; - - fn peek_freg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()>; - - fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()>; - - fn update_lsu_idx(&mut self, lsu_enq: &LsuEnqEvent) -> anyhow::Result<()>; - - fn peek_vrf_write(&mut self, vrf_write: &VrfWriteEvent) -> anyhow::Result<()>; - - fn vrf_scoreboard(&mut self, vrf_scoreboard: &VrfScoreboardEvent) -> anyhow::Result<()>; - - fn peek_memory_write(&mut self, memory_write: &MemoryWriteEvent) -> anyhow::Result<()>; - - fn check_and_clear_fence(&mut self); - - fn check_rd(&mut self, check_rd: &CheckRdEvent) -> anyhow::Result<()>; - - fn retire(&mut self, cycle: u64, issue_idx: u8) -> anyhow::Result<()>; -} - -impl JsonEventRunner for SpikeRunner { - fn peek_reg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()> { - let cycle = reg_write.cycle; - let idx = reg_write.idx; - let data = reg_write.data; - - if let Some(board_data) = self.rf_board[idx as usize] { - info!( - "[{cycle}] RegWrite: Hit board! idx={idx}, rtl data={data:#x}, board data={board_data:#x}", - ); - - assert!( - data == board_data, - "rtl data({data:#x}) should be equal to board data({board_data:#x})" - ); - - self.rf_board[idx as usize] = None; - - return Ok(()); - } - - let se = self.find_reg_se(); - - info!( - "[{cycle}] RegWrite: rtl idx={idx}, data={data:#x}; se idx={}, data={:#x} ({})", - se.rd_idx, - se.rd_bits, - se.describe_insn() - ); - - assert!( - idx as u32 == se.rd_idx, - "rtl idx({idx}) should be equal to spike idx({})", - se.rd_idx - ); - assert!( - data == se.rd_bits, - "rtl data({data:#x}) should be equal to spike data({:#x})", - se.rd_bits - ); - - Ok(()) - } - - fn peek_reg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()> { - let cycle = reg_write.cycle; - let idx = reg_write.idx; - - let se = self.find_reg_se(); - - info!( - "[{cycle}] RegWriteWait: rtl idx={idx}; se idx={}, data={:#x} ({})", - se.rd_idx, - se.rd_bits, - se.describe_insn() - ); - - assert!( - idx as u32 == se.rd_idx, - "rtl idx({idx}) should be equal to spike idx({})", - se.rd_idx - ); - - self.rf_board[idx as usize] = Some(se.rd_bits); - - Ok(()) - } - - fn peek_freg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()> { - let cycle = reg_write.cycle; - let idx = reg_write.idx; - let data = reg_write.data; - - if let Some(board_data) = self.frf_board[idx as usize] { - info!( - "[{cycle}] FregWrite: Hit board! idx={idx}, rtl data={data:#x}, board data={board_data:#x}", - ); - - assert!( - data == board_data, - "rtl data({data:#x}) should be equal to board data({board_data:#x})" - ); - - self.frf_board[idx as usize] = None; - - return Ok(()); - } - - let se = self.find_freg_se(); - - info!( - "[{cycle}] FregWrite: rtl idx={idx}, data={data:#x}; se idx={}, data={:#x} ({})", - se.rd_idx, - se.rd_bits, - se.describe_insn() - ); - - assert!( - idx as u32 == se.rd_idx, - "rtl idx({idx}) should be equal to spike idx({})", - se.rd_idx - ); - assert!( - data == se.rd_bits, - "rtl data({data:#x}) should be equal to spike data({:#x})", - se.rd_bits - ); - - Ok(()) - } - - fn peek_freg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()> { - let cycle = reg_write.cycle; - let idx = reg_write.idx; - - let se = self.find_freg_se(); - - info!( - "[{cycle}] FregWriteWait: rtl idx={idx}; se idx={}, data={:#x} ({})", - se.rd_idx, - se.rd_bits, - se.describe_insn() - ); - - assert!( - idx as u32 == se.rd_idx, - "rtl idx({idx}) should be equal to spike idx({})", - se.rd_idx - ); - - self.frf_board[idx as usize] = Some(se.rd_bits); - - Ok(()) - } - - fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()> { - let mut se = self.find_v_se(); // ensure the front of queue is a new un-issued se - - let cycle = issue.cycle; - let idx = issue.idx; - - se.issue_idx = idx as u8; - - info!("[{cycle}] Issue: issue_idx={idx} ({})", se.describe_insn()); - - self.commit_queue.push_front(se); - - Ok(()) - } - - fn update_lsu_idx(&mut self, lsu_enq: &LsuEnqEvent) -> anyhow::Result<()> { - let enq = lsu_enq.enq; - assert!(enq > 0, "enq should be greater than 0"); - let cycle = lsu_enq.cycle; - - if let Some(se) = self - .commit_queue - .iter_mut() - .rev() - .find(|se| (se.is_vload() || se.is_vstore()) && se.lsu_idx == LSU_IDX_DEFAULT) - { - let index = enq.trailing_zeros() as u8; - se.lsu_idx = index; - info!( - "[{cycle}] UpdateLSUIdx: instr ({}) is allocated with lsu_idx: {index}", - se.describe_insn() - ); - } - Ok(()) - } - - fn peek_vrf_write(&mut self, vrf_write: &VrfWriteEvent) -> anyhow::Result<()> { - let cycle = vrf_write.cycle; - let vlen_in_bytes = self.vlen / 8; - let lane_number = self.dlen / 32; - let record_idx_base = (vrf_write.vd * vlen_in_bytes - + (vrf_write.lane + lane_number * vrf_write.offset) * 4) as usize; - - let mut retire_issue: Option = None; - - if let Some(se) = - self.commit_queue.iter_mut().rev().find(|se| se.issue_idx == vrf_write.issue_idx) - { - debug!( - "[{}] VrfWrite: lane={}, vd={}, idx_base={}, issue_idx={}, offset={}, mask={}, data={:x?} ({})", - vrf_write.cycle, - vrf_write.lane, - record_idx_base, - vrf_write.vd, - vrf_write.issue_idx, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data, - se.describe_insn() - ); - - if let Some(unretired_writes) = se.vrf_access_record.unretired_writes { - assert!( - unretired_writes > 0, - "[{}] unretired_writes should be greater than 0, issue_idx={} ({})", - vrf_write.cycle, - vrf_write.issue_idx, - se.describe_insn() - ); - if unretired_writes == 1 { - retire_issue = Some(vrf_write.issue_idx); - } - se.vrf_access_record.unretired_writes = Some(unretired_writes - 1); - } else { - se.vrf_access_record.retired_writes += 1; - } - - vrf_write.mask.iter().enumerate().filter(|(_, &mask)| mask).for_each(|(offset, _)| { - let written_byte = *vrf_write.data.get(offset).unwrap_or(&0); - - if let Some(record) = se.vrf_access_record.all_writes.get_mut(&(record_idx_base + offset)) { - assert_eq!( - record.byte, - written_byte, - "[{}] {offset}th byte incorrect ({:#02x} record != {written_byte:#02x} written) \ - for vrf write (lane={}, vd={}, offset={}, mask={}, data={:x?}) \ - issue_idx={} [vrf_idx={}] (disasm: {}, pc: {:#x}, bits: {:#x})", - vrf_write.cycle, - record.byte, - vrf_write.lane, - vrf_write.vd, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data, - se.issue_idx, - record_idx_base + offset, - se.disasm, - se.pc, - se.inst_bits - ); - record.executed = true; - } else { - debug!( - "[{}] cannot find vrf write record, maybe not changed (lane={}, vd={}, idx={}, offset={}, mask={}, data={:x?})", - vrf_write.cycle, - vrf_write.lane, - vrf_write.vd, - record_idx_base + offset, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data - ); - } - }) - } else { - info!( - "[{cycle}] RecordRFAccess: rtl detect vrf write on lane={}, vd={} \ - with no matched se (issue_idx={}), \ - maybe from committed load insn", - vrf_write.lane, vrf_write.vd, vrf_write.issue_idx - ); - } - - if let Some(issue_idx) = retire_issue { - self.retire(cycle, issue_idx).unwrap(); - } - - Ok(()) - } - - fn peek_memory_write(&mut self, memory_write: &MemoryWriteEvent) -> anyhow::Result<()> { - let data = memory_write.data.to_owned(); - let mask = memory_write.mask.to_owned(); - let cycle = memory_write.cycle; - let base_addr = memory_write.address; - let lsu_idx = memory_write.lsu_idx; - - if let Some(se) = self.commit_queue.iter_mut().find(|se| se.lsu_idx == lsu_idx) { - info!("[{cycle}] MemoryWrite: address={base_addr:#x}, size={}, data={data:x?}, mask={}, pc = {:#x}, disasm = {}", data.len(), mask_display(&mask), se.pc, se.disasm); - // compare with spike event record - mask.iter().enumerate() - .filter(|(_, &mask)| mask) - .for_each(|(offset, _)| { - let byte_addr = base_addr + offset as u32; - let data_byte = *data.get(offset).unwrap_or(&0); - let mem_write = - se.mem_access_record.all_writes.get_mut(&byte_addr).unwrap_or_else(|| { - panic!("[{cycle}] cannot find mem write of byte_addr {byte_addr:#x}") - }); - let single_mem_write_val = mem_write.writes[mem_write.num_completed_writes].val; - mem_write.num_completed_writes += 1; - assert_eq!(single_mem_write_val, data_byte, "[{cycle}] expect mem write of byte {single_mem_write_val:#02x}, actual byte {data_byte:#02x} (byte_addr={byte_addr:#x}, pc = {:#x}, disasm = {})", se.pc, se.disasm); - }); - return Ok(()); - } - - panic!("[{cycle}] cannot find se with instruction lsu_idx={lsu_idx}") - } - - fn vrf_scoreboard(&mut self, vrf_scoreboard: &VrfScoreboardEvent) -> anyhow::Result<()> { - let count = vrf_scoreboard.count; - let issue_idx = vrf_scoreboard.issue_idx; - let cycle = vrf_scoreboard.cycle; - - let mut should_retire: Option = None; - - if let Some(se) = self.commit_queue.iter_mut().rev().find(|se| se.issue_idx == issue_idx) { - assert!( - se.vrf_access_record.retired_writes <= count, - "[{cycle}] retired_writes({}) should be less than count({count}), issue_idx={issue_idx} ({})", - se.vrf_access_record.retired_writes, se.describe_insn() - ); - - // if instruction writes rd, it will retire in check_rd() - if count == se.vrf_access_record.retired_writes && !se.is_rd_written && !se.is_fd_written { - should_retire = Some(issue_idx); - } - // if all writes are committed, retire the se - se.vrf_access_record.unretired_writes = Some(count - se.vrf_access_record.retired_writes); - - info!( - "[{cycle}] VrfScoreboardReport: count={count}, issue_idx={issue_idx}, retired={} ({})", - se.vrf_access_record.retired_writes, - se.describe_insn() - ); - } else { - panic!("[{cycle}] cannot find se with instruction issue_idx={issue_idx}"); - } - - if let Some(issue_idx) = should_retire { - self.retire(cycle, issue_idx).unwrap(); - } - - Ok(()) - } - - /// after update, if instructions before fence are cleared, fence is also cleared - fn check_and_clear_fence(&mut self) { - if !self.commit_queue.is_empty() { - let se = self.commit_queue.back().unwrap(); - - if se.is_vfence() && self.commit_queue.len() == 1 { - self.commit_queue.pop_back(); - } - } - } - - fn check_rd(&mut self, check_rd: &CheckRdEvent) -> anyhow::Result<()> { - let data = check_rd.data; - let cycle = check_rd.cycle; - let issue_idx = check_rd.issue_idx; - - let se = - self.commit_queue.iter_mut().find(|se| se.issue_idx == issue_idx).unwrap_or_else(|| { - panic!("[{cycle}] cannot find se with instruction issue_idx={issue_idx}") - }); - - info!("[{cycle}] CheckRd: issue_idx={issue_idx}, data={data:x?}"); - - se.check_rd(data).expect("Failed to check_rd"); - - self.retire(cycle, issue_idx).unwrap(); - - Ok(()) - } - - fn retire(&mut self, cycle: u64, issue_idx: u8) -> anyhow::Result<()> { - if let Some(idx) = self.commit_queue.iter().position(|se| se.issue_idx == issue_idx) { - if let Some(se) = self.commit_queue.remove(idx) { - info!( - "[{cycle}] Retire: retire se with issue_idx={issue_idx}, ({})", - se.describe_insn() - ); - se.check_is_ready_for_commit(cycle).unwrap(); - } else { - panic!("[{cycle}] Retire: cannot remove se with instruction issue_idx={issue_idx}") - } - } else { - panic!("[{cycle}] Retire: cannot find se with instruction issue_idx={issue_idx}") - } - Ok(()) - } -} diff --git a/t1rocketemu/offline/src/main.rs b/t1rocketemu/offline/src/main.rs deleted file mode 100644 index c9382462d..000000000 --- a/t1rocketemu/offline/src/main.rs +++ /dev/null @@ -1,57 +0,0 @@ -mod difftest; -mod dut; -mod json_events; - -use clap::Parser; -use tracing::info; - -use common::spike_runner::SpikeRunner; -use common::CommonArgs; - -use crate::difftest::Difftest; - -fn run_spike(args: &CommonArgs) -> anyhow::Result<()> { - let mut count: u64 = 0; - - let spike = SpikeRunner::new(args, true); - loop { - count += 1; - if count % 1000000 == 0 { - info!("count = {}", count); - } - match spike.exec() { - Ok(_) => {} - Err(_) => { - info!("total v instrucions count = {}", count); - info!("Simulation quit graceful"); - return Ok(()); - } - }; - } -} - -fn main() -> anyhow::Result<()> { - // parse args - let args = CommonArgs::parse(); - - args.setup_logger()?; - - // if there is no log file, just run spike and quit - if args.log_file.is_none() { - run_spike(&args)?; - return Ok(()); - } - - // if there is a log file, run difftest - let mut diff = Difftest::new(args); - - loop { - match diff.diff() { - Ok(_) => {} - Err(e) => { - info!("{}", e); - return Ok(()); - } - } - } -} diff --git a/t1rocketemu/spike_rs/Cargo.toml b/t1rocketemu/spike_rs/Cargo.toml deleted file mode 100644 index 411d44f72..000000000 --- a/t1rocketemu/spike_rs/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "spike_rs" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = { workspace = true } -tracing = { workspace = true } -libc = "0.2.155" -xmas-elf = "0.9.1" diff --git a/t1rocketemu/spike_rs/build.rs b/t1rocketemu/spike_rs/build.rs deleted file mode 100644 index a67a4ba1f..000000000 --- a/t1rocketemu/spike_rs/build.rs +++ /dev/null @@ -1,24 +0,0 @@ -use std::env; - -fn main() { - println!( - "cargo::rustc-link-search=native={}", - env::var("SPIKE_LIB_DIR").expect("SPIKE_LIB_DIR should be set") - ); - println!("cargo::rustc-link-lib=static=riscv"); - println!("cargo::rustc-link-lib=static=softfloat"); - println!("cargo::rustc-link-lib=static=disasm"); - println!("cargo::rustc-link-lib=static=fesvr"); - println!("cargo::rustc-link-lib=static=fdt"); - - println!( - "cargo::rustc-link-search=native={}", - env::var("SPIKE_INTERFACES_LIB_DIR").expect("SPIKE_INTERFACES_LIB_DIR should be set") - ); - println!("cargo::rustc-link-lib=static=spike_interfaces"); - - println!("cargo::rerun-if-env-changed=SPIKE_LIB_DIR"); - println!("cargo::rerun-if-env-changed=SPIKE_INTERFACES_LIB_DIR"); - - println!("cargo::rustc-link-lib=stdc++"); -} diff --git a/t1rocketemu/spike_rs/src/lib.rs b/t1rocketemu/spike_rs/src/lib.rs deleted file mode 100644 index 5dd021b0b..000000000 --- a/t1rocketemu/spike_rs/src/lib.rs +++ /dev/null @@ -1,278 +0,0 @@ -pub mod spike_event; -pub mod util; - -use libc::c_char; -use std::ffi::{CStr, CString}; -use tracing::trace; - -pub fn clip(binary: u32, a: i32, b: i32) -> u32 { - assert!(a <= b, "a should be less than or equal to b"); - let nbits = b - a + 1; - let mask = if nbits >= 32 { - u32::MAX - } else { - (1 << nbits) - 1 - }; - (binary >> a) & mask -} - -pub struct Spike { - spike: *mut (), - pub mem: Vec, - pub size: usize, -} - -unsafe impl Send for Spike {} - -extern "C" fn default_addr_to_mem(target: *mut (), addr: u64) -> *mut u8 { - let spike = target as *mut Spike; - let addr = addr as usize; - unsafe { - let spike: &mut Spike = &mut *spike; - let ptr = spike.mem.as_mut_ptr().offset(addr as isize); - ptr - } -} - -type FfiCallback = extern "C" fn(*mut (), u64) -> *mut u8; - -impl Spike { - // we need to have a boxed SpikeCObject, since its pointer will be passed to C to perform FFI call - pub fn new(set: &str, lvl: &str, lane_number: usize, mem_size: usize) -> Box { - let set = CString::new(set).unwrap(); - let lvl = CString::new(lvl).unwrap(); - let spike = unsafe { spike_new(set.as_ptr(), lvl.as_ptr(), lane_number) }; - let mut self_: Box = Box::new(Spike { spike, mem: vec![0; mem_size], size: mem_size }); - - // TODO: support customized ffi - let ffi_target: *mut Spike = &mut *self_; - unsafe { - spike_register_callback(ffi_target as *mut (), default_addr_to_mem); - } - - self_ - } - - pub fn get_proc(&self) -> Processor { - let processor = unsafe { spike_get_proc(self.spike) }; - Processor { processor } - } - - pub fn load_bytes_to_mem( - &mut self, - addr: usize, - len: usize, - bytes: Vec, - ) -> anyhow::Result<()> { - trace!("ld: addr: 0x{:x}, len: 0x{:x}", addr, len); - assert!(addr + len <= self.size); - - let dst = &mut self.mem[addr..addr + len]; - for (i, byte) in bytes.iter().enumerate() { - dst[i] = *byte; - } - - Ok(()) - } - - pub fn mem_byte_on_addr(&self, addr: usize) -> anyhow::Result { - Ok(self.mem[addr]) - } -} - -impl Drop for Spike { - fn drop(&mut self) { - unsafe { spike_destruct(self.spike) } - } -} - -pub struct Processor { - processor: *mut (), -} - -impl Processor { - pub fn disassemble(&self) -> String { - let bytes = unsafe { proc_disassemble(self.processor) }; - let c_str = unsafe { CStr::from_ptr(bytes as *mut c_char) }; - format!("{}", c_str.to_string_lossy()) - } - - pub fn reset(&self) { - unsafe { proc_reset(self.processor) } - } - - pub fn get_state(&self) -> State { - let state = unsafe { proc_get_state(self.processor) }; - State { state } - } - - pub fn func(&self) -> u64 { - unsafe { proc_func(self.processor) } - } - - pub fn get_insn(&self) -> u32 { - unsafe { proc_get_insn(self.processor) as u32 } - } - - pub fn get_vreg_data(&self, idx: u32, offset: u32) -> u8 { - unsafe { proc_get_vreg_data(self.processor, idx, offset) } - } - - pub fn get_rs1(&self) -> u32 { - unsafe { proc_get_rs1(self.processor) } - } - - pub fn get_rs2(&self) -> u32 { - unsafe { proc_get_rs2(self.processor) } - } - - pub fn get_rd(&self) -> u32 { - unsafe { proc_get_rd(self.processor) } - } - - // vu - pub fn vu_get_vtype(&self) -> u32 { - unsafe { proc_vu_get_vtype(self.processor) as u32 } - } - - pub fn vu_get_vxrm(&self) -> u32 { - unsafe { proc_vu_get_vxrm(self.processor) } - } - - pub fn vu_get_vnf(&self) -> u32 { - unsafe { proc_vu_get_vnf(self.processor) } - } - - pub fn vu_get_vill(&self) -> bool { - unsafe { proc_vu_get_vill(self.processor) } - } - - pub fn vu_get_vxsat(&self) -> bool { - unsafe { proc_vu_get_vxsat(self.processor) } - } - - pub fn vu_get_vl(&self) -> u32 { - unsafe { proc_vu_get_vl(self.processor) } - } - - pub fn vu_get_vstart(&self) -> u16 { - unsafe { proc_vu_get_vstart(self.processor) } - } -} - -impl Drop for Processor { - fn drop(&mut self) { - unsafe { proc_destruct(self.processor) } - } -} - -pub struct State { - state: *mut (), -} - -impl State { - pub fn set_pc(&self, pc: u64) { - unsafe { state_set_pc(self.state, pc) } - } - - pub fn get_pc(&self) -> u64 { - unsafe { state_get_pc(self.state) } - } - - pub fn handle_pc(&self, pc: u64) -> anyhow::Result<()> { - match unsafe { state_handle_pc(self.state, pc) } { - 0 => Ok(()), - _ => Err(anyhow::anyhow!("Error handling pc")), - } - } - - pub fn get_reg(&self, idx: u32, is_fp: bool) -> u32 { - unsafe { state_get_reg(self.state, idx, is_fp) } - } - - pub fn get_reg_write_size(&self) -> u32 { - unsafe { state_get_reg_write_size(self.state) } - } - - pub fn get_reg_write_index(&self, index: u32) -> u32 { - unsafe { state_get_reg_write_index(self.state, index) } - } - - pub fn get_mem_write_size(&self) -> u32 { - unsafe { state_get_mem_write_size(self.state) } - } - - pub fn get_mem_write(&self, index: u32) -> (u32, u64, u8) { - let addr = unsafe { state_get_mem_write_addr(self.state, index) }; - let value = unsafe { state_get_mem_write_value(self.state, index) }; - let size_by_byte = unsafe { state_get_mem_write_size_by_byte(self.state, index) }; - (addr, value, size_by_byte) - } - - pub fn get_mem_read_size(&self) -> u32 { - unsafe { state_get_mem_read_size(self.state) } - } - - pub fn get_mem_read(&self, index: u32) -> (u32, u8) { - let addr = unsafe { state_get_mem_read_addr(self.state, index) }; - let size_by_byte = unsafe { state_get_mem_read_size_by_byte(self.state, index) }; - (addr, size_by_byte) - } - - pub fn set_mcycle(&self, mcycle: usize) { - unsafe { state_set_mcycle(self.state, mcycle) } - } - - pub fn clear(&self) { - unsafe { state_clear(self.state) } - } -} - -impl Drop for State { - fn drop(&mut self) { - unsafe { state_destruct(self.state) } - } -} - -#[link(name = "spike_interfaces")] -extern "C" { - pub fn spike_register_callback(target: *mut (), callback: FfiCallback); - fn spike_new(set: *const c_char, lvl: *const c_char, lane_number: usize) -> *mut (); - fn spike_get_proc(spike: *mut ()) -> *mut (); - fn spike_destruct(spike: *mut ()); - fn proc_disassemble(proc: *mut ()) -> *mut c_char; - fn proc_reset(proc: *mut ()); - fn proc_get_state(proc: *mut ()) -> *mut (); - fn proc_func(proc: *mut ()) -> u64; - fn proc_get_insn(proc: *mut ()) -> u64; - fn proc_get_vreg_data(proc: *mut (), vreg_idx: u32, vreg_offset: u32) -> u8; - fn proc_get_rs1(proc: *mut ()) -> u32; - fn proc_get_rs2(proc: *mut ()) -> u32; - fn proc_get_rd(proc: *mut ()) -> u32; - - fn proc_vu_get_vtype(proc: *mut ()) -> u64; - fn proc_vu_get_vxrm(proc: *mut ()) -> u32; - fn proc_vu_get_vnf(proc: *mut ()) -> u32; - fn proc_vu_get_vill(proc: *mut ()) -> bool; - fn proc_vu_get_vxsat(proc: *mut ()) -> bool; - fn proc_vu_get_vl(proc: *mut ()) -> u32; - fn proc_vu_get_vstart(proc: *mut ()) -> u16; - - fn proc_destruct(proc: *mut ()); - fn state_set_pc(state: *mut (), pc: u64); - fn state_get_pc(state: *mut ()) -> u64; - fn state_get_reg(state: *mut (), index: u32, is_fp: bool) -> u32; - fn state_get_reg_write_size(state: *mut ()) -> u32; - fn state_get_reg_write_index(state: *mut (), index: u32) -> u32; - fn state_get_mem_write_size(state: *mut ()) -> u32; - fn state_get_mem_write_addr(state: *mut (), index: u32) -> u32; - fn state_get_mem_write_value(state: *mut (), index: u32) -> u64; - fn state_get_mem_write_size_by_byte(state: *mut (), index: u32) -> u8; - fn state_get_mem_read_size(state: *mut ()) -> u32; - fn state_get_mem_read_addr(state: *mut (), index: u32) -> u32; - fn state_get_mem_read_size_by_byte(state: *mut (), index: u32) -> u8; - fn state_handle_pc(state: *mut (), pc: u64) -> u64; - fn state_set_mcycle(state: *mut (), mcycle: usize); - fn state_clear(state: *mut ()); - fn state_destruct(state: *mut ()); -} diff --git a/t1rocketemu/spike_rs/src/spike_event.rs b/t1rocketemu/spike_rs/src/spike_event.rs deleted file mode 100644 index f91932760..000000000 --- a/t1rocketemu/spike_rs/src/spike_event.rs +++ /dev/null @@ -1,530 +0,0 @@ -use std::collections::HashMap; -use tracing::trace; -use Default; - -use crate::clip; -use crate::Spike; - -#[derive(Debug, Clone)] -pub struct SingleMemWrite { - pub val: u8, - pub executed: bool, // set to true when rtl execute this mem access -} - -#[derive(Debug, Clone)] -pub struct SingleMemRead { - pub val: u8, - pub executed: bool, // set to true when rtl execute this mem access -} - -#[derive(Debug, Clone)] -pub struct MemWriteRecord { - pub writes: Vec, - pub num_completed_writes: usize, -} - -#[derive(Debug, Clone)] -pub struct MemReadRecord { - pub reads: Vec, - pub num_completed_reads: usize, -} - -#[derive(Debug, Clone)] -pub struct SingleVrfWrite { - pub byte: u8, - pub executed: bool, // set to true when rtl execute this mem access -} - -#[derive(Default, Debug, Clone)] -pub struct VdWriteRecord { - vd_bytes: Vec, -} - -#[derive(Default, Debug, Clone)] -pub struct MemAccessRecord { - pub all_writes: HashMap, - pub all_reads: HashMap, -} - -#[derive(Default, Debug, Clone)] -pub struct VrfAccessRecord { - pub all_writes: HashMap, - pub unretired_writes: Option, - pub retired_writes: u32, -} - -pub const LSU_IDX_DEFAULT: u8 = 0xff; -pub const ISSUE_IDX_DEFAULT: u8 = 0xff; - -#[derive(Default, Debug, Clone)] -pub struct SpikeEvent { - pub do_log_vrf: bool, - - // index - pub lsu_idx: u8, - pub issue_idx: u8, - - // instruction - pub disasm: String, - pub pc: u64, - pub inst_bits: u32, - - // scalar to vector interface(used for driver) - pub rs1: u32, - pub rs2: u32, - pub rs1_bits: u32, - pub rs2_bits: u32, - pub rd_idx: u32, - - // vtype - pub vtype: u32, - pub vxrm: u32, - pub vnf: u32, - - // other CSR - pub vill: bool, - pub vxsat: bool, - pub vl: u32, - pub vstart: u16, - - // rd - pub rd_bits: u32, - - // mutable states - pub is_rd_written: bool, - pub is_fd_written: bool, - pub vd_write_record: VdWriteRecord, - pub mem_access_record: MemAccessRecord, - pub vrf_access_record: VrfAccessRecord, - - pub is_quit_inst: bool, -} - -impl SpikeEvent { - pub fn new(spike: &Spike, do_log_vrf: bool) -> Self { - let proc = spike.get_proc(); - let state = proc.get_state(); - let inst_bits = proc.get_insn(); - - let opcode = clip(inst_bits, 0, 6); - let width = clip(inst_bits, 12, 14); - - let is_rs_fp = opcode == 0b1010111 && width == 0b101/* OPFVF */; - // early return vsetvl scalar instruction - - // rs1, rs2 - let (rs1, rs2) = (proc.get_rs1(), proc.get_rs2()); - - SpikeEvent { - do_log_vrf, - - lsu_idx: LSU_IDX_DEFAULT, - issue_idx: ISSUE_IDX_DEFAULT, - - disasm: spike.get_proc().disassemble(), - pc: proc.get_state().get_pc(), - inst_bits, - - rs1, - rs2, - rs1_bits: state.get_reg(rs1, is_rs_fp), - rs2_bits: state.get_reg(rs2, is_rs_fp), - rd_idx: proc.get_rd(), - - vtype: proc.vu_get_vtype(), - vxrm: proc.vu_get_vxrm(), - vnf: proc.vu_get_vnf(), - - vill: proc.vu_get_vill(), - vxsat: proc.vu_get_vxsat(), - vl: proc.vu_get_vl(), - vstart: proc.vu_get_vstart(), - - rd_bits: Default::default(), - - is_rd_written: false, - is_fd_written: false, - vd_write_record: Default::default(), - mem_access_record: Default::default(), - vrf_access_record: Default::default(), - - is_quit_inst: false, - } - } - - pub fn opcode(&self) -> u32 { - clip(self.inst_bits, 0, 6) - } - - pub fn width(&self) -> u32 { - clip(self.inst_bits, 12, 14) - } - - pub fn rs1(&self) -> u32 { - clip(self.inst_bits, 15, 19) - } - - pub fn csr(&self) -> u32 { - clip(self.inst_bits, 20, 31) - } - - pub fn funct6(&self) -> u32 { - clip(self.inst_bits, 26, 31) - } - - pub fn mop(&self) -> u32 { - clip(self.inst_bits, 26, 27) - } - - pub fn lumop(&self) -> u32 { - clip(self.inst_bits, 20, 24) - } - - pub fn vm(&self) -> bool { - clip(self.inst_bits, 25, 25) != 0 - } - - // check whether the instruction is a vector load - pub fn is_vload(&self) -> bool { - self.opcode() == 0b0000111 && self.width().wrapping_sub(1) & 0b100 != 0 - } - - // check whether the instruction is a vector store - pub fn is_vstore(&self) -> bool { - self.opcode() == 0b0100111 && self.width().wrapping_sub(1) & 0b100 != 0 - } - - pub fn is_v(&self) -> bool { - (self.opcode() == 0b1010111 || self.is_vload() || self.is_vstore()) && !self.is_vsetvl() - } - - pub fn is_vsetvl(&self) -> bool { - self.opcode() == 0b1010111 && self.width() == 0b111 - } - - pub fn is_scalar(&self) -> bool { - !self.is_v() - } - - // check whether the instruction is a scalar load - pub fn is_load(&self) -> bool { - self.opcode() == 0b0000011 || self.is_cl() - } - - // check whether the instruction is a scalar store - pub fn is_store(&self) -> bool { - self.opcode() == 0b0100011 || self.is_cw() - } - - pub fn is_whole(&self) -> bool { - self.mop() == 0 && self.lumop() == 8 - } - - pub fn is_widening(&self) -> bool { - self.opcode() == 0b1010111 && (self.funct6() >> 4) == 0b11 - } - - pub fn is_mask_vd(&self) -> bool { - self.opcode() == 0b1010111 && (self.funct6() >> 4) == 0b11 - } - - pub fn is_exit(&self) -> bool { - self.is_quit_inst - } - - pub fn is_vfence(&self) -> bool { - self.is_exit() // only exit instruction is treated as fence now - } - - pub fn is_rd_fp(&self) -> bool { - (self.opcode() == 0b1010111) - && (self.rs1 == 0) - && (self.funct6() == 0b010000) - && self.vm() - && (self.width() == 0b001) - } - - pub fn c_op(&self) -> u32 { - clip(self.inst_bits, 0, 1) - } - - pub fn c_func3(&self) -> u32 { - clip(self.inst_bits, 13, 15) - } - - pub fn is_cl(&self) -> bool { - ( self.c_op() == 0b00 && self.c_func3() & 0b100 == 0 ) || /* c.lw */ - ( self.c_op() == 0b10 && self.c_func3() & 0b100 == 0 ) /* c.lwsp */ - } - - pub fn is_cw(&self) -> bool { - ( self.c_op() == 0b00 && self.c_func3() & 0b100 != 0 ) || /* c.sw */ - ( self.c_op() == 0b10 && self.c_func3() & 0b100 != 0 ) /* c.swsp */ - } - - pub fn vlmul(&self) -> u32 { - clip(self.vtype, 0, 2) - } - - pub fn vma(&self) -> bool { - clip(self.vtype, 7, 7) != 0 - } - - pub fn vta(&self) -> bool { - clip(self.vtype, 6, 6) != 0 - } - - pub fn vsew(&self) -> u32 { - clip(self.vtype, 3, 5) - } - - pub fn vcsr(&self) -> u32 { - self.vxsat as u32 | self.vxrm << 1 - } - - pub fn describe_insn(&self) -> String { - format!( - "pc={:#x}, disasm='{}', bits={:#x}", - self.pc, self.disasm, self.inst_bits - ) - } - - pub fn get_vrf_write_range(&self, vlen_in_bytes: u32) -> anyhow::Result<(u32, u32)> { - if self.is_vstore() { - return Ok((0, 0)); - } - - if self.is_vload() { - let vd_bytes_start = self.rd_idx * vlen_in_bytes; - if self.is_whole() { - return Ok((vd_bytes_start, vlen_in_bytes * (1 + self.vnf))); - } - let len = if self.vlmul() & 0b100 != 0 { - vlen_in_bytes * (1 + self.vnf) - } else { - (vlen_in_bytes * (1 + self.vnf)) << self.vlmul() - }; - return Ok((vd_bytes_start, len)); - } - - let vd_bytes_start = self.rd_idx * vlen_in_bytes; - - if self.is_mask_vd() { - return Ok((vd_bytes_start, vlen_in_bytes)); - } - - let len = if self.vlmul() & 0b100 != 0 { - vlen_in_bytes >> (8 - self.vlmul()) - } else { - vlen_in_bytes << self.vlmul() - }; - - Ok(( - vd_bytes_start, - if self.is_widening() { len * 2 } else { len }, - )) - } - - pub fn pre_log_arch_changes(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - if self.do_log_vrf { - // record the vrf writes before executing the insn - let proc = spike.get_proc(); - self.rd_bits = proc.get_state().get_reg(self.rd_idx, false); - let (start, len) = self.get_vrf_write_range(vlen).unwrap(); - self.vd_write_record.vd_bytes.resize(len as usize, 0u8); - for i in 0..len { - let offset = start + i; - let vreg_index = offset / vlen; - let vreg_offset = offset % vlen; - let cur_byte = proc.get_vreg_data(vreg_index, vreg_offset); - self.vd_write_record.vd_bytes[i as usize] = cur_byte; - } - } - - Ok(()) - } - - pub fn log_arch_changes(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - if self.do_log_vrf { - self.log_vrf_write(spike, vlen).unwrap(); - self.log_reg_write(spike).unwrap(); - } - self.log_mem_write(spike).unwrap(); - self.log_mem_read(spike).unwrap(); - - Ok(()) - } - - fn log_vrf_write(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - let proc = spike.get_proc(); - // record vrf writes - // note that we do not need log_reg_write to find records, we just decode the - // insn and compare bytes - let vlen_in_bytes = vlen / 8; - let (start, len) = self.get_vrf_write_range(vlen_in_bytes).unwrap(); - trace!("vrf write range: start: {start}, len: {len}"); - for i in 0..len { - let offset = start + i; - let origin_byte = self.vd_write_record.vd_bytes[i as usize]; - let vreg_index = offset / vlen_in_bytes; - let vreg_offset = offset % vlen_in_bytes; - let cur_byte = proc.get_vreg_data(vreg_index, vreg_offset); - if origin_byte != cur_byte { - self - .vrf_access_record - .all_writes - .entry(offset as usize) - .or_insert(SingleVrfWrite { byte: cur_byte, executed: false }); - trace!( - "SpikeVRFChange: vrf={:?}, change_from={origin_byte}, change_to={cur_byte}, vrf_idx={offset}", - vec![offset / vlen_in_bytes, offset % vlen_in_bytes], - ); - } else { - trace!( - "SpikeVRFChange: vrf={:?}, change_from={origin_byte}, not changed, vrf_idx={offset}", - vec![offset / vlen_in_bytes, offset % vlen_in_bytes], - ); - } - } - Ok(()) - } - - pub fn log_reg_write(&mut self, spike: &Spike) -> anyhow::Result<()> { - let proc = spike.get_proc(); - let state = proc.get_state(); - // in spike, log_reg_write is arrange: - // xx0000 <- x - // xx0001 <- f - // xx0010 <- vreg - // xx0011 <- vec - // xx0100 <- csr - let reg_write_size = state.get_reg_write_size(); - // TODO: refactor it. - (0..reg_write_size).for_each(|idx| { - let rd_idx_type = state.get_reg_write_index(idx); - match rd_idx_type & 0xf { - 0b0000 => { - // scalar rf - self.rd_idx = rd_idx_type >> 4; - if self.rd_idx != 0 { - let data = state.get_reg(self.rd_idx, false); - self.is_rd_written = true; - self.rd_bits = data; - trace!( - "ScalarRFChange: idx={:#02x}, data={:08x}", - self.rd_idx, - self.rd_bits - ); - } - } - 0b0001 => { - self.rd_idx = rd_idx_type >> 4; - let data = state.get_reg(self.rd_idx, true); - self.is_fd_written = true; - self.rd_bits = data; - trace!( - "FloatRFChange: idx={:#02x}, data={:08x}", - self.rd_idx, - self.rd_bits - ); - } - _ => trace!( - "UnknownRegChange, idx={:#02x}, spike detect unknown reg change", - self.rd_idx - ), - } - }); - - Ok(()) - } - - pub fn log_mem_write(&mut self, spike: &Spike) -> anyhow::Result<()> { - let proc = spike.get_proc(); - let state = proc.get_state(); - - let mem_write_size = state.get_mem_write_size(); - (0..mem_write_size).for_each(|i| { - let (addr, value, size) = state.get_mem_write(i); - (0..size).for_each(|offset| { - self - .mem_access_record - .all_writes - .entry(addr + offset as u32) - .or_insert(MemWriteRecord { writes: vec![], num_completed_writes: 0 }) - .writes - .push(SingleMemWrite { - val: (value >> (offset * 8)) as u8, - executed: false, - }); - }); - if addr == 0x4000_0000 && value == 0xdead_beef { - self.is_quit_inst = true; - trace!("SpikeQuit: detected quit instruction"); - } - trace!("SpikeMemWrite: addr={addr:x}, value={value:x}, size={size}"); - }); - - Ok(()) - } - - fn log_mem_read(&mut self, spike: &Spike) -> anyhow::Result<()> { - let proc = spike.get_proc(); - let state = proc.get_state(); - - let mem_read_size = state.get_mem_read_size(); - (0..mem_read_size).for_each(|i| { - let (addr, size) = state.get_mem_read(i); - let mut value = 0; - (0..size).for_each(|offset| { - let byte = spike.mem_byte_on_addr(addr as usize + offset as usize).unwrap(); - value |= (byte as u64) << (offset * 8); - // record the read - self - .mem_access_record - .all_reads - .entry(addr + offset as u32) - .or_insert(MemReadRecord { reads: vec![], num_completed_reads: 0 }) - .reads - .push(SingleMemRead { val: byte, executed: false }); - }); - trace!("SpikeMemRead: addr={addr:08x}, value={value:08x}, size={size}"); - }); - - Ok(()) - } - - pub fn check_rd(&self, data: u32) -> anyhow::Result<()> { - // TODO: rtl should indicate whether resp_bits_data is valid - if self.is_rd_written { - assert_eq!( - data, self.rd_bits, - "expect to write rd[{}] = {}, actual {}", - self.rd_idx, self.rd_bits, data - ); - } - - Ok(()) - } - - pub fn check_is_ready_for_commit(&self, cycle: u64) -> anyhow::Result<()> { - for (addr, record) in &self.mem_access_record.all_writes { - assert_eq!( - record.num_completed_writes, - record.writes.len(), - "[{cycle}] expect to write mem {addr:#x}, not executed when commit, issue_idx={} ({})", - self.issue_idx, - self.describe_insn(), - ); - } - for (idx, record) in &self.vrf_access_record.all_writes { - assert!( - record.executed, - "[{cycle}] expect to write vrf {idx}, not executed when commit, issue_idx={} ({})", - self.issue_idx, - self.describe_insn() - ); - } - - Ok(()) - } -} diff --git a/t1rocketemu/spike_rs/src/util.rs b/t1rocketemu/spike_rs/src/util.rs deleted file mode 100644 index 6ded0eec5..000000000 --- a/t1rocketemu/spike_rs/src/util.rs +++ /dev/null @@ -1,65 +0,0 @@ -use crate::Spike; -use std::fs::File; -use std::io::Read; -use std::path::Path; -use xmas_elf::program::{ProgramHeader, Type}; -use xmas_elf::{header, ElfFile}; - -pub fn load_elf(spike: &mut Spike, fname: &Path) -> anyhow::Result { - let mut file = File::open(fname).unwrap(); - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer).unwrap(); - - let elf_file = ElfFile::new(&buffer).unwrap(); - - let header = elf_file.header; - assert_eq!(header.pt2.machine().as_machine(), header::Machine::RISC_V); - assert_eq!(header.pt1.class(), header::Class::ThirtyTwo); - - for ph in elf_file.program_iter() { - if let ProgramHeader::Ph32(ph) = ph { - if ph.get_type() == Ok(Type::Load) { - let offset = ph.offset as usize; - let size = ph.file_size as usize; - let addr = ph.virtual_addr as usize; - - let slice = &buffer[offset..offset + size]; - spike.load_bytes_to_mem(addr, size, slice.to_vec()).unwrap(); - } - } - } - - Ok(header.pt2.entry_point()) -} - -// todo: unify load_elf and load_elf_to_buffer -pub fn load_elf_to_buffer(mem: &mut [u8], fname: &Path) -> anyhow::Result { - let mut file = File::open(fname).unwrap(); - let mut buffer = Vec::new(); - file.read_to_end(&mut buffer).unwrap(); - - let elf_file = ElfFile::new(&buffer).unwrap(); - - let header = elf_file.header; - assert_eq!(header.pt2.machine().as_machine(), header::Machine::RISC_V); - assert_eq!(header.pt1.class(), header::Class::ThirtyTwo); - - for ph in elf_file.program_iter() { - if let ProgramHeader::Ph32(ph) = ph { - if ph.get_type() == Ok(Type::Load) { - let offset = ph.offset as usize; - let size = ph.file_size as usize; - let addr = ph.virtual_addr as usize; - - let slice = &buffer[offset..offset + size]; - - let dst: &mut _ = &mut mem[addr..addr + size]; - for (i, byte) in slice.iter().enumerate() { - dst[i] = *byte; - } - } - } - } - - Ok(header.pt2.entry_point()) -} diff --git a/t1rocketemu/test_common/Cargo.toml b/t1rocketemu/test_common/Cargo.toml deleted file mode 100644 index d5b3f32aa..000000000 --- a/t1rocketemu/test_common/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "common" -version.workspace = true -edition = "2021" - -[dependencies] -spike_rs = { path = "../spike_rs" } -clap = { workspace = true } -tracing = { workspace = true } -tracing-subscriber = { workspace = true } -anyhow = { workspace = true } diff --git a/t1rocketemu/test_common/src/lib.rs b/t1rocketemu/test_common/src/lib.rs deleted file mode 100644 index e9690d3a2..000000000 --- a/t1rocketemu/test_common/src/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -use anyhow::Result; -use clap::Parser; -use spike_rs::Spike; -use std::path::PathBuf; -use tracing::Level; -use tracing_subscriber::{EnvFilter, FmtSubscriber}; - -pub mod rtl_config; -pub mod spike_runner; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -pub struct CommonArgs { - /// Path to the ELF file - #[arg(long)] - pub elf_file: PathBuf, - - /// Path to the log file - #[arg(long)] - pub log_file: Option, - - /// Log level: trace, debug, info, warn, error - #[arg(long, default_value = "info")] - pub log_level: String, - - /// vlen config - #[arg(long, default_value = env!("DESIGN_VLEN"))] - pub vlen: u32, - - /// dlen config - #[arg(long, default_value = env!("DESIGN_DLEN"))] - pub dlen: u32, - - /// ISA config - #[arg(long, default_value = env!("SPIKE_ISA_STRING"))] - pub set: String, -} - -pub static MEM_SIZE: usize = 1usize << 32; - -impl CommonArgs { - pub fn to_spike_c_handler(&self) -> Box { - let lvl = "M"; - - Spike::new(&self.set, lvl, (self.dlen / 32) as usize, MEM_SIZE) - } - - pub fn setup_logger(&self) -> Result<()> { - // setup log - let log_level: Level = self.log_level.parse()?; - let global_logger = FmtSubscriber::builder() - .with_env_filter(EnvFilter::from_default_env()) - .with_max_level(log_level) - .without_time() - .with_target(false) - .with_ansi(true) - .compact() - .finish(); - tracing::subscriber::set_global_default(global_logger) - .expect("internal error: fail to setup log subscriber"); - Ok(()) - } -} diff --git a/t1rocketemu/test_common/src/rtl_config.rs b/t1rocketemu/test_common/src/rtl_config.rs deleted file mode 100644 index 0daf72624..000000000 --- a/t1rocketemu/test_common/src/rtl_config.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub struct RTLConfig { - pub vlen: u32, - pub dlen: u32, -} - -// TODO: read from json - -impl RTLConfig { - pub fn xlen(&self) -> u32 { - 32 // TODO: configurable - } - - pub fn vlen_in_bytes(&self) -> u32 { - self.vlen / 8 - } - - pub fn lane_num(&self) -> u32 { - self.dlen / self.xlen() - } -} diff --git a/t1rocketemu/test_common/src/spike_runner.rs b/t1rocketemu/test_common/src/spike_runner.rs deleted file mode 100644 index 40b293185..000000000 --- a/t1rocketemu/test_common/src/spike_runner.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::collections::VecDeque; -use std::path::Path; -use tracing::debug; - -use spike_rs::spike_event::SpikeEvent; -use spike_rs::util::load_elf; -use spike_rs::Spike; - -use crate::CommonArgs; - -pub struct SpikeRunner { - spike: Box, - - /// commit queue - /// in the spike thread, spike should detech if this queue is full, if not - /// full, execute until a vector instruction, record the behavior of this - /// instruction, and send to commit queue. - /// Note: - /// - The event issued earliest is at the back of the queue - /// - The queue may contain at most one unissued event. If so, the unissued event must be at the - /// front of the queue, and it must be a fence - pub commit_queue: VecDeque, - - /// vector queue to arrange the order of vector instructions, because of the register write - /// dependency, the vector instruction should be issued in order. - pub vector_queue: VecDeque, - - /// scalar queue to arrange the order of scalar reg write instructions - pub scalar_queue: VecDeque, - - /// float queue to arrange the order of scalar freg write instructions - pub float_queue: VecDeque, - - /// config for v extension - pub vlen: u32, - pub dlen: u32, - - /// implement the get_t() for mcycle csr update - pub cycle: u64, - - pub do_log_vrf: bool, - - // register file scoreboard - pub rf_board: Vec>, - // float reg file scoreboard - pub frf_board: Vec>, -} - -impl SpikeRunner { - pub fn new(args: &CommonArgs, do_log_vrf: bool) -> Self { - // load the elf file - // initialize spike - let mut spike = args.to_spike_c_handler(); - - let entry_addr = load_elf(&mut spike, Path::new(&args.elf_file)).unwrap(); - - // initialize processor - let proc = spike.get_proc(); - let state = proc.get_state(); - proc.reset(); - state.set_pc(entry_addr); - - SpikeRunner { - spike, - commit_queue: VecDeque::new(), - vector_queue: VecDeque::new(), - scalar_queue: VecDeque::new(), - float_queue: VecDeque::new(), - vlen: args.vlen, - dlen: args.dlen, - cycle: 0, - do_log_vrf, - rf_board: vec![None; 32], - frf_board: vec![None; 32], - } - } - - pub fn load_elf(&mut self, fname: &Path) -> anyhow::Result { - load_elf(&mut *self.spike, fname) - } - - // just execute one instruction for non-difftest - pub fn exec(&self) -> anyhow::Result<()> { - let spike = &self.spike; - let proc = spike.get_proc(); - let state = proc.get_state(); - - let new_pc = proc.func(); - - state.handle_pc(new_pc).unwrap(); - - Ok(()) - } - - // execute the spike processor for one instruction and record - // the spike event for difftest - pub fn spike_step(&mut self) -> SpikeEvent { - let spike = &self.spike; - let proc = self.spike.get_proc(); - let state = proc.get_state(); - - let mcycle = self.cycle as usize; - state.set_mcycle(0); - - let mut event = SpikeEvent::new(spike, self.do_log_vrf); - state.clear(); - - let new_pc = if event.is_v() || event.is_exit() { - // inst is v / quit - debug!( - "SpikeStep: spike run vector insn ({}), mcycle={mcycle}", - event.describe_insn(), - ); - event.pre_log_arch_changes(spike, self.vlen).unwrap(); - let new_pc_ = proc.func(); - event.log_arch_changes(spike, self.vlen).unwrap(); - new_pc_ - } else { - // inst is scalar - debug!( - "SpikeStep: spike run scalar insn ({}), mcycle={mcycle}", - event.describe_insn(), - ); - let new_pc_ = proc.func(); - event.log_mem_write(spike).unwrap(); - event.log_reg_write(spike).unwrap(); - new_pc_ - }; - - state.handle_pc(new_pc).unwrap(); - - event - } - - pub fn find_reg_se(&mut self) -> SpikeEvent { - if !self.scalar_queue.is_empty() { - // return the back (oldest) scalar insn - self.scalar_queue.pop_back().unwrap() - } else { - // else, loop until find a se, and push the se to the front - loop { - let se = self.spike_step(); - if se.is_scalar() && se.is_rd_written { - return se; - } else if se.is_scalar() && se.is_fd_written { - self.float_queue.push_front(se.clone()); - } else if se.is_v() { - self.vector_queue.push_front(se.clone()); - } - } - } - } - - pub fn find_freg_se(&mut self) -> SpikeEvent { - if !self.float_queue.is_empty() { - // return the back (oldest) float insn - self.float_queue.pop_back().unwrap() - } else { - // else, loop until find a se, and push the se to the front - loop { - let se = self.spike_step(); - if se.is_scalar() && se.is_rd_written { - self.scalar_queue.push_front(se.clone()); - } else if se.is_scalar() && se.is_fd_written { - return se; - } else if se.is_v() { - self.vector_queue.push_front(se.clone()); - } - } - } - } - - pub fn find_v_se(&mut self) -> SpikeEvent { - if !self.vector_queue.is_empty() { - // return the back (oldest) vector insn - self.vector_queue.pop_back().unwrap() - } else { - // else, loop until find a se, and push the se to the front - loop { - let se = self.spike_step(); - if se.is_scalar() && se.is_rd_written { - self.scalar_queue.push_front(se.clone()); - } else if se.is_scalar() && se.is_fd_written { - self.float_queue.push_front(se.clone()); - } else if se.is_v() { - return se; - } - } - } - } -}