diff --git a/.forgejo/workflows/deps.yml b/.forgejo/workflows/deps.yml deleted file mode 100644 index b29723c..0000000 --- a/.forgejo/workflows/deps.yml +++ /dev/null @@ -1,77 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-later -# See Notices.txt for copyright information -on: - workflow_call: - outputs: - cache-primary-key: - value: ${{ jobs.deps.outputs.cache-primary-key }} - -jobs: - deps: - runs-on: debian-12 - outputs: - cache-primary-key: ${{ steps.restore-deps.outputs.cache-primary-key }} - steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 - with: - fetch-depth: 0 - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - id: restore-deps - with: - path: deps - key: ${{ github.repository }}-deps-${{ runner.os }}-${{ hashFiles('.forgejo/workflows/deps.yml') }} - lookup-only: true - - name: Install Apt packages - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - apt-get update -qq - apt-get install -qq \ - bison \ - build-essential \ - ccache \ - clang \ - cvc5 \ - flex \ - gawk \ - g++ \ - git \ - libboost-filesystem-dev \ - libboost-python-dev \ - libboost-system-dev \ - libffi-dev \ - libreadline-dev \ - lld \ - pkg-config \ - python3 \ - python3-click \ - tcl-dev \ - zlib1g-dev - - name: Install Firtool - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - mkdir -p deps - wget -O deps/firrtl.tar.gz https://github.com/llvm/circt/releases/download/firtool-1.86.0/firrtl-bin-linux-x64.tar.gz - sha256sum -c - <<<'bf6f4ab18ae76f135c944efbd81e25391c31c1bd0617c58ab0592640abefee14 deps/firrtl.tar.gz' - tar -C deps -xvaf deps/firrtl.tar.gz - rm -rf deps/firtool - mv deps/firtool-1.86.0 deps/firtool - - name: Get SymbiYosys - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --branch=yosys-0.45 https://git.libre-chip.org/mirrors/sby deps/sby - - name: Build Z3 - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --recursive --branch=z3-4.13.3 https://git.libre-chip.org/mirrors/z3 deps/z3 - (cd deps/z3; PYTHON=python3 ./configure --prefix=/usr/local) - make -C deps/z3/build -j"$(nproc)" - - name: Build Yosys - if: steps.restore-deps.outputs.cache-hit != 'true' - run: | - git clone --depth=1 --recursive --branch=0.45 https://git.libre-chip.org/mirrors/yosys deps/yosys - make -C deps/yosys -j"$(nproc)" - - uses: https://git.libre-chip.org/mirrors/cache/save@v3 - if: steps.restore-deps.outputs.cache-hit != 'true' - with: - path: deps - key: ${{ steps.restore-deps.outputs.cache-primary-key }} diff --git a/.forgejo/workflows/test.yml b/.forgejo/workflows/test.yml index 775a503..88dda29 100644 --- a/.forgejo/workflows/test.yml +++ b/.forgejo/workflows/test.yml @@ -3,56 +3,16 @@ on: [push, pull_request] jobs: - deps: - runs-on: debian-12 - uses: ./.forgejo/workflows/deps.yml test: runs-on: debian-12 - needs: deps + container: + image: git.libre-chip.org/libre-chip/fayalite-deps:latest steps: - - uses: https://git.libre-chip.org/mirrors/checkout@v3 + - uses: actions/checkout@v3 with: fetch-depth: 0 - run: | scripts/check-copyright.sh - - run: | - apt-get update -qq - apt-get install -qq \ - bison \ - build-essential \ - ccache \ - clang \ - cvc5 \ - flex \ - gawk \ - git \ - libboost-filesystem-dev \ - libboost-python-dev \ - libboost-system-dev \ - libffi-dev \ - libreadline-dev \ - lld \ - pkg-config \ - python3 \ - python3-click \ - tcl-dev \ - z3 \ - zlib1g-dev - - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain 1.89.0 - source "$HOME/.cargo/env" - echo "$PATH" >> "$GITHUB_PATH" - - uses: https://git.libre-chip.org/mirrors/cache/restore@v3 - with: - path: deps - key: ${{ needs.deps.outputs.cache-primary-key }} - fail-on-cache-miss: true - - run: | - make -C deps/z3/build install - make -C deps/sby install - make -C deps/yosys install - export PATH="$(realpath deps/firtool/bin):$PATH" - echo "$PATH" >> "$GITHUB_PATH" - uses: https://git.libre-chip.org/mirrors/rust-cache@v2 with: save-if: ${{ github.ref == 'refs/heads/master' }} diff --git a/Cargo.lock b/Cargo.lock index 2e1df0c..b16095a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,18 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] +version = 4 [[package]] name = "allocator-api2" @@ -93,6 +81,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bitflags" version = "2.6.0" @@ -172,6 +166,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2348487adcd4631696ced64ccdb40d38ac4d31cae7f2eec8817fcea1b9d1c43c" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.5.18" @@ -207,6 +210,7 @@ name = "cpu" version = "0.1.0" dependencies = [ "fayalite", + "serde", ] [[package]] @@ -300,20 +304,22 @@ checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "fayalite" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5" dependencies = [ + "base64", "bitvec", "blake3", "clap", + "clap_complete", "ctor", "eyre", "fayalite-proc-macros", "fayalite-visit-gen", - "hashbrown", + "hashbrown 0.15.5", "jobslot", "num-bigint", "num-traits", - "os_pipe", + "ordered-float", "petgraph", "serde", "serde_json", @@ -325,7 +331,7 @@ dependencies = [ [[package]] name = "fayalite-proc-macros" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5" dependencies = [ "fayalite-proc-macros-impl", ] @@ -333,7 +339,7 @@ dependencies = [ [[package]] name = "fayalite-proc-macros-impl" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5" dependencies = [ "base16ct", "num-bigint", @@ -348,7 +354,7 @@ dependencies = [ [[package]] name = "fayalite-visit-gen" version = "0.3.0" -source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#bd75fdfefd642f6dd2210cfb003fa63f9dce114e" +source = "git+https://git.libre-chip.org/libre-chip/fayalite.git?branch=master#0b77d1bea0af932a40fd221daf65d5a9b7d62bc5" dependencies = [ "indexmap", "prettyplease", @@ -366,6 +372,12 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "funty" version = "2.0.0" @@ -384,13 +396,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasip2", ] [[package]] @@ -398,9 +411,16 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -431,7 +451,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.14.5", "serde", ] @@ -449,16 +469,16 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobslot" -version = "0.2.19" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe10868679d7a24c2c67d862d0e64a342ce9aef7cdde9ce8019bd35d353d458d" +checksum = "58715c67c327da7f1558708348d68c207fd54900c4ae0529e29305d04d795b8c" dependencies = [ "cfg-if", "derive_destructure2", "getrandom", "libc", "scopeguard", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -514,22 +534,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] -name = "os_pipe" -version = "1.2.1" +name = "ordered-float" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" dependencies = [ - "libc", - "windows-sys 0.59.0", + "num-traits", + "rand", + "serde", ] [[package]] name = "petgraph" -version = "0.6.5" -source = "git+https://github.com/programmerjake/petgraph.git?rev=258ea8071209a924b73fe96f9f87a3b7b45cbc9f#258ea8071209a924b73fe96f9f87a3b7b45cbc9f" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", + "hashbrown 0.15.5", "indexmap", + "serde", ] [[package]] @@ -560,12 +584,37 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core", + "serde", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "serde", +] + [[package]] name = "rustix" version = "0.38.37" @@ -728,10 +777,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] [[package]] name = "which" @@ -745,6 +797,12 @@ dependencies = [ "winsafe", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.52.0" @@ -763,6 +821,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -833,6 +900,12 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + [[package]] name = "wyz" version = "0.5.1" @@ -841,23 +914,3 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml index 57ca631..a3e74f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ rust-version = "1.89.0" [workspace.dependencies] fayalite = { git = "https://git.libre-chip.org/libre-chip/fayalite.git", version = "0.3.0", branch = "master" } +serde = { version = "1.0.202", features = ["derive"] } [profile.dev] opt-level = 1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..03fad1d --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ + +# Libre-Chip's CPU + + + +# Funding + +## NLnet Grants + +* [Libre-Chip CPU with proof of No Spectre bugs](https://nlnet.nl/project/Libre-Chip-proof/) 2024-12-324 [(progress)](https://git.libre-chip.org/libre-chip/grant-tracking/src/branch/master/nlnet-2024-12-324/progress.md) + +This project was funded through the [NGI0 Commons Fund](https://nlnet.nl/commonsfund), a fund established by [NLnet](https://nlnet.nl/) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [DG Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement № [101135429](https://cordis.europa.eu/project/id/101135429). Additional funding is made available by the [Swiss State Secretariat for Education, Research and Innovation](https://www.sbfi.admin.ch/sbfi/en/home.html) (SERI). diff --git a/crates/cpu/Cargo.toml b/crates/cpu/Cargo.toml index 16ec0b9..4dd85d8 100644 --- a/crates/cpu/Cargo.toml +++ b/crates/cpu/Cargo.toml @@ -16,3 +16,4 @@ version.workspace = true [dependencies] fayalite.workspace = true +serde.workspace = true diff --git a/crates/cpu/README.md b/crates/cpu/README.md new file mode 120000 index 0000000..fe84005 --- /dev/null +++ b/crates/cpu/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/crates/cpu/src/config.rs b/crates/cpu/src/config.rs index 4e66010..ed3b814 100644 --- a/crates/cpu/src/config.rs +++ b/crates/cpu/src/config.rs @@ -8,9 +8,10 @@ use crate::{ }, }; use fayalite::prelude::*; +use serde::{Deserialize, Serialize}; use std::num::NonZeroUsize; -#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] #[non_exhaustive] pub struct UnitConfig { pub kind: UnitKind, @@ -27,12 +28,14 @@ impl UnitConfig { } } -#[derive(Clone, Eq, PartialEq, Hash, Debug)] +#[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] #[non_exhaustive] pub struct CpuConfig { pub units: Vec, pub out_reg_num_width: usize, pub fetch_width: NonZeroUsize, + pub max_branches_per_fetch: NonZeroUsize, + pub fetch_width_in_bytes: NonZeroUsize, /// default value for [`UnitConfig::max_in_flight`] pub default_unit_max_in_flight: NonZeroUsize, pub rob_size: NonZeroUsize, @@ -46,6 +49,18 @@ impl CpuConfig { }; v }; + pub const DEFAULT_MAX_BRANCHES_PER_FETCH: NonZeroUsize = { + let Some(v) = NonZeroUsize::new(1) else { + unreachable!(); + }; + v + }; + pub const DEFAULT_FETCH_WIDTH_IN_BYTES: NonZeroUsize = { + let Some(v) = NonZeroUsize::new(4) else { + unreachable!(); + }; + v + }; pub const DEFAULT_UNIT_MAX_IN_FLIGHT: NonZeroUsize = { let Some(v) = NonZeroUsize::new(8) else { unreachable!(); @@ -57,6 +72,8 @@ impl CpuConfig { units, out_reg_num_width: Self::DEFAULT_OUT_REG_NUM_WIDTH, fetch_width: Self::DEFAULT_FETCH_WIDTH, + max_branches_per_fetch: Self::DEFAULT_MAX_BRANCHES_PER_FETCH, + fetch_width_in_bytes: Self::DEFAULT_FETCH_WIDTH_IN_BYTES, default_unit_max_in_flight: Self::DEFAULT_UNIT_MAX_IN_FLIGHT, rob_size, } @@ -117,3 +134,12 @@ impl CpuConfig { [self.non_const_unit_nums().len()] } } + +#[hdl(get(|c| c.fetch_width.get()))] +pub type CpuConfigFetchWidth> = DynSize; + +#[hdl(get(|c| c.max_branches_per_fetch.get()))] +pub type CpuConfigMaxBranchesPerFetch> = DynSize; + +#[hdl(get(|c| c.fetch_width_in_bytes.get()))] +pub type CpuConfigFetchWidthInBytes> = DynSize; diff --git a/crates/cpu/src/instruction.rs b/crates/cpu/src/instruction.rs index dad8087..c410b56 100644 --- a/crates/cpu/src/instruction.rs +++ b/crates/cpu/src/instruction.rs @@ -5,6 +5,7 @@ use fayalite::{ expr::ops::{ArrayLiteral, ExprPartialEq}, intern::Interned, prelude::*, + sim::value::SimValuePartialEq, }; use std::{fmt, marker::PhantomData, ops::Range}; @@ -181,6 +182,12 @@ impl ExprPartialEq for OutputIntegerMode { } } +impl SimValuePartialEq for OutputIntegerMode { + fn sim_value_eq(this: &SimValue, other: &SimValue) -> bool { + SimValue::opaque(this) == SimValue::opaque(other) + } +} + pub const MOP_IMM_WIDTH: usize = 34; pub const MOP_MIN_REG_WIDTH: usize = 8; pub const COMMON_MOP_SRC_LEN: usize = 3; diff --git a/crates/cpu/src/lib.rs b/crates/cpu/src/lib.rs index bae3720..a00b668 100644 --- a/crates/cpu/src/lib.rs +++ b/crates/cpu/src/lib.rs @@ -2,6 +2,7 @@ // See Notices.txt for copyright information pub mod config; pub mod instruction; +pub mod next_pc; pub mod reg_alloc; pub mod register; pub mod unit; diff --git a/crates/cpu/src/next_pc.rs b/crates/cpu/src/next_pc.rs new file mode 100644 index 0000000..e4195ba --- /dev/null +++ b/crates/cpu/src/next_pc.rs @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// See Notices.txt for copyright information + +//! [Next-Instruction Logic](https://git.libre-chip.org/libre-chip/grant-tracking/issues/10) +//! +//! The basic idea here is that there's a `next_pc` stage that sends predicted fetch PCs to the `fetch` stage, +//! the `fetch` stage's outputs eventually end up in the `decode` stage, +//! after the `decode` stage there's a `post_decode` stage (that may run in the same clock cycle as `decode`) +//! that checks that the fetched instructions' kinds match the predicted instruction kinds and that feeds +//! information back to the `fetch` stage to cancel fetches that need to be predicted differently. + +use crate::{config::CpuConfig, util::array_vec::ArrayVec}; +use fayalite::prelude::*; +use fayalite::util::ready_valid::ReadyValid; +use std::collections::{HashMap, VecDeque}; + +#[hdl] +pub enum PredictedCond { + Taken, + Fallthrough, +} + +#[hdl] +pub struct PredictedFallthrough {} + +#[hdl] +pub enum BranchPredictionKind { + Branch(HdlOption), + IndirectBranch(HdlOption), + Call(HdlOption), + IndirectCall(HdlOption), + Ret(HdlOption), +} + +#[hdl(get(|c| c.max_branches_per_fetch.get() - 1))] +pub type NextPcPredictionMaxBranchesBeforeLast> = DynSize; + +#[hdl(no_static)] +pub struct NextPcPrediction> { + pub fetch_pc: UInt<64>, + pub async_interrupt: Bool, + pub branches_before_last: ArrayVec< + BranchPredictionKind, + NextPcPredictionMaxBranchesBeforeLast, + >, + pub last_branch: HdlOption>, + pub last_branch_target_pc: UInt<64>, +} + +#[hdl] +pub struct NextPcToFetchInterfaceInner { + pub next_fetch_pc: UInt<64>, + pub fetch_block_id: UInt<8>, + pub in_progress_fetches_to_cancel: UInt<8>, +} + +#[hdl(no_static)] +pub struct NextPcToFetchInterface> { + pub inner: ReadyValid, + pub config: C, +} + +#[hdl] +/// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] since the actual instruction definition isn't finalized yet. This will be replaced at a later point. +pub enum WipDecodedInsnKind { + NonBranch, + Branch(UInt<64>), + BranchCond(UInt<64>), + IndirectBranch, + IndirectBranchCond, + Call(UInt<64>), + CallCond(UInt<64>), + IndirectCall, + IndirectCallCond, + Ret, + RetCond, + /// not actually an instruction read from memory, covers stuff like external interrupts, page faults, memory errors, and so on. + Interrupt(UInt<64>), +} + +#[hdl] +/// WIP version of decoded instruction just good enough to represent stuff needed for [`next_pc()`] since the actual instruction definition isn't finalized yet. This will be replaced at a later point. +pub struct WipDecodedInsn { + pub fetch_block_id: UInt<8>, + pub id: UInt<12>, + pub pc: UInt<64>, + pub kind: WipDecodedInsnKind, +} + +#[hdl(no_static)] +/// handles updating speculative branch predictor state (e.g. branch histories) when instructions retire, +/// as well as updating state when a branch instruction is mis-speculated. +pub struct NextPcToRetireInterface> { + // TODO: add needed fields + pub config: C, +} + +#[hdl(no_static)] +pub struct DecodeToPostDecodeInterface> { + // TODO: add needed fields + pub config: C, +} + +#[hdl(no_static)] +pub struct PostDecodeOutputInterface> { + // TODO: add needed fields + pub config: C, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] +enum BranchPredictionState { + StronglyNotTaken, + #[default] + WeaklyNotTaken, + WeaklyTaken, + StronglyTaken, +} + +impl BranchPredictionState { + #[must_use] + fn is_taken(self) -> bool { + match self { + Self::StronglyNotTaken => false, + Self::WeaklyNotTaken => false, + Self::WeaklyTaken => true, + Self::StronglyTaken => true, + } + } + #[must_use] + fn towards_taken(self) -> Self { + match self { + Self::StronglyNotTaken => Self::WeaklyNotTaken, + Self::WeaklyNotTaken => Self::WeaklyTaken, + Self::WeaklyTaken => Self::StronglyTaken, + Self::StronglyTaken => Self::StronglyTaken, + } + } + #[must_use] + fn towards_not_taken(self) -> Self { + match self { + Self::StronglyNotTaken => Self::StronglyNotTaken, + Self::WeaklyNotTaken => Self::StronglyNotTaken, + Self::WeaklyTaken => Self::WeaklyNotTaken, + Self::StronglyTaken => Self::WeaklyTaken, + } + } +} + +struct NextPcState { + call_stack: Vec, + branch_target_buffer: HashMap, + history: VecDeque, + speculative_history_len: usize, + branch_predictor: Box<[BranchPredictionState; Self::BRANCH_PREDICTOR_SIZE]>, +} + +impl NextPcState { + const BRANCH_PREDICTOR_LOG2_SIZE: usize = 8; + const BRANCH_PREDICTOR_SIZE: usize = 1 << Self::BRANCH_PREDICTOR_LOG2_SIZE; + fn branch_predictor_index(&self, pc: u64) -> usize { + let mut history = 0u64; + for i in 0..Self::BRANCH_PREDICTOR_LOG2_SIZE { + history <<= 1; + if self.history.get(i).copied().unwrap_or(false) { + history |= 1; + } + } + let mut t = history; + t ^= t.rotate_left(5) & !pc.rotate_right(3); + t ^= pc; + t ^= !t.rotate_left(2) & t.rotate_left(4); + let mut retval = 0; + for i in (0..Self::BRANCH_PREDICTOR_LOG2_SIZE).step_by(Self::BRANCH_PREDICTOR_LOG2_SIZE) { + retval ^= t >> i; + } + retval as usize % Self::BRANCH_PREDICTOR_SIZE + } +} + +impl Default for NextPcState { + fn default() -> Self { + Self { + call_stack: Default::default(), + branch_target_buffer: Default::default(), + history: Default::default(), + speculative_history_len: Default::default(), + branch_predictor: vec![Default::default(); Self::BRANCH_PREDICTOR_SIZE] + .try_into() + .expect("has right size"), + } + } +} + +#[hdl_module(extern)] +pub fn next_pc(config: PhantomConst) { + #[hdl] + let cd: ClockDomain = m.input(); + m.extern_module_simulation_fn((cd,), |(cd,), mut sim| async move { + sim.resettable( + cd, + |mut sim: ExternModuleSimulationState| async move { NextPcState::default() }, + |mut sim: ExternModuleSimulationState, mut state| async move {}, + ) + .await; + }); +} diff --git a/crates/cpu/src/reg_alloc/unit_free_regs_tracker.rs b/crates/cpu/src/reg_alloc/unit_free_regs_tracker.rs index d19cf2a..a7bf687 100644 --- a/crates/cpu/src/reg_alloc/unit_free_regs_tracker.rs +++ b/crates/cpu/src/reg_alloc/unit_free_regs_tracker.rs @@ -120,10 +120,7 @@ pub fn unit_free_regs_tracker( #[cfg(test)] mod tests { use super::*; - use fayalite::{ - cli::FormalMode, firrtl::ExportOptions, - module::transform::simplify_enums::SimplifyEnumsKind, testing::assert_formal, - }; + use fayalite::{firrtl::ExportOptions, module::transform::simplify_enums::SimplifyEnumsKind}; use std::num::NonZero; fn test_unit_free_regs_tracker( diff --git a/crates/cpu/src/unit.rs b/crates/cpu/src/unit.rs index d6cd1d6..b71f79a 100644 --- a/crates/cpu/src/unit.rs +++ b/crates/cpu/src/unit.rs @@ -15,6 +15,7 @@ use fayalite::{ intern::{Intern, Interned}, prelude::*, }; +use serde::{Deserialize, Serialize}; pub mod alu_branch; pub mod unit_base; @@ -36,7 +37,7 @@ macro_rules! all_units { } ) => { $(#[$enum_meta])* - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)] $vis enum $UnitKind { $( $(#[$variant_meta])* diff --git a/crates/cpu/src/util/array_vec.rs b/crates/cpu/src/util/array_vec.rs index 761f53f..4af5663 100644 --- a/crates/cpu/src/util/array_vec.rs +++ b/crates/cpu/src/util/array_vec.rs @@ -1,147 +1,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later // See Notices.txt for copyright information -use fayalite::{ - expr::ops::{ExprCastTo, ExprIndex, ExprPartialEq, ExprPartialOrd}, - int::SizeType, - intern::{Intern, Interned}, - prelude::*, - ty::{MatchVariantWithoutScope, StaticType, TypeProperties}, -}; -use std::{marker::PhantomData, ops::Index}; +use fayalite::{expr::ops::ExprIndex, int::UIntInRangeInclusiveType, prelude::*}; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct Length { - ty: UInt, - _phantom: PhantomData, -} - -impl Length { - pub fn new(max: Max::SizeType) -> Self { - Self { - ty: UInt::range_inclusive(0..=Max::as_usize(max)), - _phantom: PhantomData, - } - } - pub fn ty(self) -> UInt { - self.ty - } - pub fn zero(self) -> Expr { - Self::from_uint_unchecked(self.ty.zero()) - } - pub fn from_uint_unchecked(v: impl ToExpr) -> Expr { - Expr::from_canonical(Expr::canonical(v.to_expr())) - } - pub fn cast_from_uint_unchecked( - self, - v: impl ToExpr>, - ) -> Expr { - Self::from_uint_unchecked(v.to_expr().cast_to(self.ty)) - } - pub fn as_uint(this: impl ToExpr) -> Expr { - let this = this.to_expr(); - this.cast_to(Expr::ty(this).ty) - } -} - -impl ExprCastTo> for Length { - fn cast_to(src: Expr, to_type: UIntType) -> Expr> { - Expr::::from_canonical(Expr::canonical(src)).cast_to(to_type) - } -} - -#[allow(non_upper_case_globals)] -pub const Length: __LengthWithoutGenerics = __LengthWithoutGenerics {}; - -#[non_exhaustive] -pub struct __LengthWithoutGenerics {} - -impl Index for __LengthWithoutGenerics { - type Output = Length; - - fn index(&self, max: M) -> &Self::Output { - Interned::into_inner(Length::new(max).intern_sized()) - } -} - -impl Type for Length { - type BaseType = UInt; - type MaskType = Bool; - type MatchVariant = Expr; - type MatchActiveScope = (); - type MatchVariantAndInactiveScope = MatchVariantWithoutScope; - type MatchVariantsIter = std::iter::Once; - fn match_variants( - this: Expr, - source_location: SourceLocation, - ) -> Self::MatchVariantsIter { - let _ = source_location; - std::iter::once(MatchVariantWithoutScope(this)) - } - - fn mask_type(&self) -> Self::MaskType { - Bool - } - - fn canonical(&self) -> CanonicalType { - self.ty.canonical() - } - - fn from_canonical(canonical_type: CanonicalType) -> Self { - let ty = ::from_canonical(canonical_type); - if let Some(known_max) = Max::KNOWN_VALUE { - assert_eq!(ty, UInt::range_inclusive(0..=known_max)); - } - Self { - ty, - _phantom: PhantomData, - } - } - - fn source_location() -> SourceLocation { - SourceLocation::caller() - } -} - -impl StaticType for Length { - const TYPE: Self = Self { - ty: UInt { - width: Max::VALUE.next_power_of_two().ilog2() as usize, - }, - _phantom: PhantomData, - }; - const MASK_TYPE: Self::MaskType = Bool; - const TYPE_PROPERTIES: TypeProperties = { - let mut p = >::TYPE_PROPERTIES; - p.bit_width = Self::TYPE.ty.width; - p - }; - const MASK_TYPE_PROPERTIES: TypeProperties = Bool::TYPE_PROPERTIES; -} - -impl ExprPartialEq for Length { - fn cmp_eq(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_eq(Self::as_uint(rhs)) - } - fn cmp_ne(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_ne(Self::as_uint(rhs)) - } -} - -impl ExprPartialOrd for Length { - fn cmp_lt(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_lt(Self::as_uint(rhs)) - } - fn cmp_le(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_le(Self::as_uint(rhs)) - } - fn cmp_gt(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_gt(Self::as_uint(rhs)) - } - fn cmp_ge(lhs: Expr, rhs: Expr) -> Expr { - Self::as_uint(lhs).cmp_ge(Self::as_uint(rhs)) - } -} +#[hdl] +pub type Length = UIntInRangeInclusiveType, Max>; /// like [`std::vec::Vec`], except with a [`Expr`] for [`len()`][`Self::len()`] and a fixed capacity #[hdl] @@ -156,7 +19,7 @@ impl ArrayVec { #[hdl] ArrayVec { elements: self.elements.uninit(), - len: self.len.zero(), + len: 0u8.cast_to(self.len), } } pub fn element(self) -> T { @@ -176,7 +39,7 @@ impl ArrayVec { let elements = elements.to_expr(); let len = len.to_expr(); assert_eq!( - Length::new(N::from_usize(Expr::ty(elements).len())), + Length[N::from_usize(Expr::ty(elements).len())], Expr::ty(len), "len type mismatch", ); @@ -191,7 +54,7 @@ impl ArrayVec { } pub fn is_empty(this: impl ToExpr) -> Expr { let len = Self::len(this); - len.cmp_eq(Expr::ty(len).zero()) + len.cmp_eq(0u8) } pub fn capacity(self) -> usize { self.elements.len() @@ -207,7 +70,7 @@ impl ArrayVec { let this = this.to_expr(); for (index, element) in this.elements.into_iter().enumerate() { #[hdl] - if index.cmp_lt(Length::as_uint(this.len)) { + if index.cmp_lt(this.len) { f(index, element); } } diff --git a/crates/cpu/tests/expected/reg_alloc.vcd b/crates/cpu/tests/expected/reg_alloc.vcd index ee343b4..f69c9a7 100644 --- a/crates/cpu/tests/expected/reg_alloc.vcd +++ b/crates/cpu/tests/expected/reg_alloc.vcd @@ -16832,38 +16832,6 @@ $upscope $end $upscope $end $enddefinitions $end $dumpvars -0vg -0wg -0xg -0yg -0zg -0{g -0|g -0}g -0~g -0!h -0"h -0#h -0$h -0%h -0&h -0'h -0(h -0)h -0*h -0+h -0,h -0-h -0.h -0/h -00h -01h -02h -03h -04h -05h -06h -07h b0 (_ b0 ia b0 )_ @@ -17370,6 +17338,26 @@ b0 ga b0 Jd b0 ha b0 Kd +b0 Ld +b0 Nd +b0 Md +b0 Od +0Pd +0Qd +0Rd +0Sd +0Td +0Ud +0Vd +0Wd +0Xd +0Yd +0Zd +0[d +0\d +0]d +0^d +0_d 0`d 0ad 0bd @@ -17386,438 +17374,6 @@ b0 Kd 0md 0nd 0od -b0 8h -0Hh -0Xh -0hh -0xh -0*i -0:i -0Ji -0Zi -b0 9h -0Ih -0Yh -0ih -0yh -0+i -0;i -0Ki -0[i -b0 :h -0Jh -0Zh -0jh -0zh -0,i -0i -0Ni -0^i -b0 =h -0Mh -0]h -0mh -0}h -0/i -0?i -0Oi -0_i -b0 >h -0Nh -0^h -0nh -0~h -00i -0@i -0Pi -0`i -b0 ?h -0Oh -0_h -0oh -0!i -01i -0Ai -0Qi -0ai -b0 @h -0Ph -0`h -0ph -0"i -02i -0Bi -0Ri -0bi -b0 Ah -0Qh -0ah -0qh -0#i -03i -0Ci -0Si -0ci -b0 Bh -0Rh -0bh -0rh -0$i -04i -0Di -0Ti -0di -b0 Ch -0Sh -0ch -0sh -0%i -05i -0Ei -0Ui -0ei -b0 Dh -0Th -0dh -0th -0&i -06i -0Fi -0Vi -0fi -b0 Eh -0Uh -0eh -0uh -0'i -07i -0Gi -0Wi -0gi -b0 Fh -0Vh -0fh -0vh -0(i -08i -0Hi -0Xi -0hi -b0 Gh -0Wh -0gh -0wh -0)i -09i -0Ii -0Yi -0ii -b0 Df -0Tf -0df -0tf -0&g -06g -0Fg -0Vg -0fg -b0 Ef -0Uf -0ef -0uf -0'g -07g -0Gg -0Wg -0gg -b0 Ff -0Vf -0ff -0vf -0(g -08g -0Hg -0Xg -0hg -b0 Gf -0Wf -0gf -0wf -0)g -09g -0Ig -0Yg -0ig -b0 Hf -0Xf -0hf -0xf -0*g -0:g -0Jg -0Zg -0jg -b0 If -0Yf -0if -0yf -0+g -0;g -0Kg -0[g -0kg -b0 Jf -0Zf -0jf -0zf -0,g -0g -0Ng -0^g -0ng -b0 Mf -0]f -0mf -0}f -0/g -0?g -0Og -0_g -0og -b0 Nf -0^f -0nf -0~f -00g -0@g -0Pg -0`g -0pg -b0 Of -0_f -0of -0!g -01g -0Ag -0Qg -0ag -0qg -b0 Pf -0`f -0pf -0"g -02g -0Bg -0Rg -0bg -0rg -b0 Qf -0af -0qf -0#g -03g -0Cg -0Sg -0cg -0sg -b0 Rf -0bf -0rf -0$g -04g -0Dg -0Tg -0dg -0tg -b0 Sf -0cf -0sf -0%g -05g -0Eg -0Ug -0eg -0ug -b0 ji -0zi -0,j -0j -0Nj -0^j -0nj -0~j -00k -b0 mi -0}i -0/j -0?j -0Oj -0_j -0oj -0!k -01k -b0 ni -0~i -00j -0@j -0Pj -0`j -0pj -0"k -02k -b0 oi -0!j -01j -0Aj -0Qj -0aj -0qj -0#k -03k -b0 pi -0"j -02j -0Bj -0Rj -0bj -0rj -0$k -04k -b0 qi -0#j -03j -0Cj -0Sj -0cj -0sj -0%k -05k -b0 ri -0$j -04j -0Dj -0Tj -0dj -0tj -0&k -06k -b0 si -0%j -05j -0Ej -0Uj -0ej -0uj -0'k -07k -b0 ti -0&j -06j -0Fj -0Vj -0fj -0vj -0(k -08k -b0 ui -0'j -07j -0Gj -0Wj -0gj -0wj -0)k -09k -b0 vi -0(j -08j -0Hj -0Xj -0hj -0xj -0*k -0:k -b0 wi -0)j -09j -0Ij -0Yj -0ij -0yj -0+k -0;k -b0 xi -0*j -0:j -0Jj -0Zj -0jj -0zj -0,k -0g +0Ng +0^g +0ng +b0 Mf +0]f +0mf +0}f +0/g +0?g +0Og +0_g +0og +b0 Nf +0^f +0nf +0~f +00g +0@g +0Pg +0`g +0pg +b0 Of +0_f +0of +0!g +01g +0Ag +0Qg +0ag +0qg +b0 Pf +0`f +0pf +0"g +02g +0Bg +0Rg +0bg +0rg +b0 Qf +0af +0qf +0#g +03g +0Cg +0Sg +0cg +0sg +b0 Rf +0bf +0rf +0$g +04g +0Dg +0Tg +0dg +0tg +b0 Sf +0cf +0sf +0%g +05g +0Eg +0Ug +0eg +0ug +0vg +0wg +0xg +0yg +0zg +0{g +0|g +0}g +0~g +0!h +0"h +0#h +0$h +0%h +0&h +0'h +0(h +0)h +0*h +0+h +0,h +0-h +0.h +0/h +00h +01h +02h +03h +04h +05h +06h +07h +b0 8h +0Hh +0Xh +0hh +0xh +0*i +0:i +0Ji +0Zi +b0 9h +0Ih +0Yh +0ih +0yh +0+i +0;i +0Ki +0[i +b0 :h +0Jh +0Zh +0jh +0zh +0,i +0i +0Ni +0^i +b0 =h +0Mh +0]h +0mh +0}h +0/i +0?i +0Oi +0_i +b0 >h +0Nh +0^h +0nh +0~h +00i +0@i +0Pi +0`i +b0 ?h +0Oh +0_h +0oh +0!i +01i +0Ai +0Qi +0ai +b0 @h +0Ph +0`h +0ph +0"i +02i +0Bi +0Ri +0bi +b0 Ah +0Qh +0ah +0qh +0#i +03i +0Ci +0Si +0ci +b0 Bh +0Rh +0bh +0rh +0$i +04i +0Di +0Ti +0di +b0 Ch +0Sh +0ch +0sh +0%i +05i +0Ei +0Ui +0ei +b0 Dh +0Th +0dh +0th +0&i +06i +0Fi +0Vi +0fi +b0 Eh +0Uh +0eh +0uh +0'i +07i +0Gi +0Wi +0gi +b0 Fh +0Vh +0fh +0vh +0(i +08i +0Hi +0Xi +0hi +b0 Gh +0Wh +0gh +0wh +0)i +09i +0Ii +0Yi +0ii +b0 ji +0zi +0,j +0j +0Nj +0^j +0nj +0~j +00k +b0 mi +0}i +0/j +0?j +0Oj +0_j +0oj +0!k +01k +b0 ni +0~i +00j +0@j +0Pj +0`j +0pj +0"k +02k +b0 oi +0!j +01j +0Aj +0Qj +0aj +0qj +0#k +03k +b0 pi +0"j +02j +0Bj +0Rj +0bj +0rj +0$k +04k +b0 qi +0#j +03j +0Cj +0Sj +0cj +0sj +0%k +05k +b0 ri +0$j +04j +0Dj +0Tj +0dj +0tj +0&k +06k +b0 si +0%j +05j +0Ej +0Uj +0ej +0uj +0'k +07k +b0 ti +0&j +06j +0Fj +0Vj +0fj +0vj +0(k +08k +b0 ui +0'j +07j +0Gj +0Wj +0gj +0wj +0)k +09k +b0 vi +0(j +08j +0Hj +0Xj +0hj +0xj +0*k +0:k +b0 wi +0)j +09j +0Ij +0Yj +0ij +0yj +0+k +0;k +b0 xi +0*j +0:j +0Jj +0Zj +0jj +0zj +0,k +0