1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
// Filename: lib.rs
// Version: 0.8
// Date: 15-09-2021 (DD-MM-YYYY)
// Library: gpcas_cpu_model
//
// Copyright (c) 2021 Kai Rese
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
//! Defines the structure of an abstract CPU model and some helpful functions for working with it,
//! as well as the corresponding file structure.
//!
//! Any application working with the model should use the structs and definitions in this crate
//! to ensure compatibility.
#![warn(missing_docs)]
pub mod component_config;
mod legacy;
use gpcas_base::file::{deserialize_upgrade_from, DeserializeFunction, GpcasFileStruct};
use serde::{Deserialize, Serialize};
/// The configuration of an abstract CPU model.
#[derive(Default, Deserialize, Serialize)]
pub struct CPUModel {
/// The maximum supported vector size of the model in bits.
pub max_vector_size: usize,
/// The ALU latency of each instruction class.
pub execution_latencies: InstructionLatencies,
/// Configuration for the fetch stage of the front end.
pub fetch_config: component_config::FetchConfig,
/// Configuration for the memory controller.
pub memory_controller_config: component_config::MemoryControllerConfig,
/// Caches of the memory hierarchy.
pub caches: Vec<component_config::CacheConfig>,
/// The amount of parallel decoders.
pub decoder_count: usize,
/// Configuration of the register file.
pub reg_file_config: component_config::RegisterFileConfig,
/// Configuration of schedulers.
pub schedulers: Vec<component_config::SchedulerConfig>,
/// Configuration for each pipeline from front end to the last stage.
pub pipelines: Vec<component_config::PipelineConfig>,
}
/// Defines the amount of clock cycles each instruction type needs.
///
/// The fields of this struct are used to selectively overwrite default values. If a field is
/// `None`, the default value is used.
///
/// A value of zero means that the type isn't supported in a pipeline. By default, all types are
/// supported.
#[derive(Default, Deserialize, Serialize)]
pub struct InstructionLatencies {
/// Typically takes multiple, but few clock cycles.
pub integer_multiply: Option<u16>,
/// Takes many clock cycles, usually dependent on the operand size.
pub integer_divide: Option<u16>,
/// Combination of add- and mul-operation.
pub integer_multiply_add: Option<u16>,
/// Completes fast, but needs a shifter.
pub integer_shift: Option<u16>,
/// Might take longer than floating point multiplication.
pub float_add: Option<u16>,
/// Usually as fast as integer multiplication.
pub float_multiply: Option<u16>,
/// Takes many clock cycles, usually dependent on the operand size.
pub float_divide: Option<u16>,
/// Might need multiple execution ports if a design has separate add- and mul-pipes.
pub float_multiply_add: Option<u16>,
}
impl CPUModel {
/// Creates a new model without components and default global values.
pub fn new() -> Self {
CPUModel {
max_vector_size: 128,
execution_latencies: InstructionLatencies::default(),
fetch_config: component_config::FetchConfig::default(),
memory_controller_config: component_config::MemoryControllerConfig::default(),
caches: Vec::new(),
decoder_count: 1,
reg_file_config: Default::default(),
schedulers: Vec::new(),
pipelines: Vec::new(),
}
}
}
impl InstructionLatencies {
/// Transforms the object into an array conforming to the [`gpcas_base::instruction_type`]
/// definition as array indices.
pub fn as_array(&self) -> [u16; 14] {
[
// register moves
1,
// moves
1,
// simple
1,
// integer add
1,
self.integer_multiply.unwrap_or(default_latencies::INT_MUL),
self.integer_divide.unwrap_or(default_latencies::INT_DIV),
self.integer_multiply_add
.unwrap_or(default_latencies::INT_MUL_ADD),
self.integer_shift.unwrap_or(default_latencies::INT_SHIFT),
self.float_add.unwrap_or(default_latencies::FLOAT_ADD),
self.float_multiply.unwrap_or(default_latencies::FLOAT_MUL),
self.float_divide.unwrap_or(default_latencies::FLOAT_DIV),
self.float_multiply_add
.unwrap_or(default_latencies::FLOAT_MUL_ADD),
// branches
1,
// jumps
1,
]
}
}
impl GpcasFileStruct for CPUModel {
const FILE_IDENTIFIER: &'static str = "gpcas::cpu_model";
const CURRENT_FILE_VERSION: usize = 1;
const COMPATIBLE_VERSIONS: &'static [(usize, DeserializeFunction<CPUModel>)] =
&[(0, deserialize_upgrade_from::<legacy::CPUModelV0, CPUModel>)];
}
/// The default latency in clock cycles for all instruction types.
///
/// Types not mentioned in here either share their value with another one, or are hardcoded to one
/// clock cycle.
pub mod default_latencies {
/// Typically takes multiple, but few clock cycles.
pub const INT_MUL: u16 = 3;
/// Takes many clock cycles, usually dependent on the operand size.
pub const INT_DIV: u16 = 22;
/// Combination of add- and mul-operation.
pub const INT_MUL_ADD: u16 = 3;
/// Completes fast, but needs a shifter.
pub const INT_SHIFT: u16 = 1;
/// Might take longer than floating point multiplication.
pub const FLOAT_ADD: u16 = 4;
/// Usually as fast as integer multiplication.
pub const FLOAT_MUL: u16 = 3;
/// Takes many clock cycles, usually dependent on the operand size.
pub const FLOAT_DIV: u16 = 22;
/// Might take multiple ports if a design has separate add- and mul-pipes.
pub const FLOAT_MUL_ADD: u16 = 5;
}