Skip to content

Commit

Permalink
prepare for configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronKutch committed Feb 22, 2024
1 parent 2bbc2fc commit 4e68662
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 70 deletions.
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Starlight

This is a DSL (Domain Specific Language) that can describe combinational
logic and temporal logic. This allows RTL (Register Transfer Level)
descriptions in ordinary Rust code with all the features that Rust provides.
This provides an HDL (Hardware Design Language), combinational and temporal
logic simulator and optimizer, and general purpose router for FPGAs and
more. The HDL is special in that it is written in ordinary Rust code with
all the features that Rust provides.

This crate still has a considerable amount of WIP stuff needed to evolve
into a proper HDL (Hardware Description Language).
Most of the MVP features of this crate are ready, except for the `Router`
which is still a WIP and has a lot of `todo!()`;

See the documentation of `awint`/`awint_dag` which is used as the backend
for this. `awint` is the base library that operations are modeled off of.
Expand All @@ -15,6 +16,11 @@
optimize, evaluate, and retroactively change values in the `DAG` for various
purposes.

There are several features on this crate that enable `awint` features. The
`u32_ptrs` feature reduces the memory consumption of the algorithms
significantly, but limits the number of possible internal references to
about 4 billion, which the largest circuits might not fit in.

```rust
use std::num::NonZeroUsize;
use starlight::{awi, dag, Epoch, EvalAwi, LazyAwi};
Expand Down Expand Up @@ -70,7 +76,7 @@
// if we later retroactively assign this to an unequal value, the
// `assert_assertions_strict` call will error and show the location of the
// assertion that errored
dag::assert_eq!(Awi::from(&input), awi!(0101));
mimick::assert_eq!(Awi::from(&input), awi!(0101));

// step the state machine forward
m.update(&input).unwrap();
Expand Down Expand Up @@ -123,6 +129,7 @@

```rust
use starlight::{dag, awi, Epoch, EvalAwi};

use dag::*;

let epoch = Epoch::new();
Expand Down
11 changes: 6 additions & 5 deletions starlight/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// NOTE: remember to update the README when updating this

//! This is a DSL (Domain Specific Language) that can describe combinational
//! logic and temporal logic. This allows RTL (Register Transfer Level)
//! descriptions in ordinary Rust code with all the features that Rust provides.
//! This provides an HDL (Hardware Design Language), combinational and temporal
//! logic simulator and optimizer, and general purpose router for FPGAs and
//! more. The HDL is special in that it is written in ordinary Rust code with
//! all the features that Rust provides.
//!
//! This crate still has a considerable amount of WIP stuff needed to evolve
//! into a proper HDL (Hardware Description Language).
//! Most of the MVP features of this crate are ready, except for the `Router`
//! which is still a WIP and has a lot of `todo!()`;
//!
//! See the documentation of `awint`/`awint_dag` which is used as the backend
//! for this. `awint` is the base library that operations are modeled off of.
Expand Down
2 changes: 1 addition & 1 deletion starlight/src/route.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod routing;
use std::num::NonZeroU32;

use awint::awint_dag::triple_arena::ptr_struct;
pub use cedge::{CEdge, ChannelWidths, Programmability, SelectorLut, SelectorValue};
pub use cedge::{CEdge, ChannelWidths, Programmability, SelectorLut};
pub use channel::{Channeler, Referent};
pub use cnode::CNode;
pub use config::{Config, Configurator};
Expand Down
61 changes: 10 additions & 51 deletions starlight/src/route/cedge.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{
cmp::max,
fmt::Write,
num::{NonZeroU32, NonZeroU64, NonZeroUsize},
num::{NonZeroU32, NonZeroU64},
};

use awint::{
Expand All @@ -21,53 +21,22 @@ use crate::{
Error, SuspendedEpoch,
};

#[derive(Debug, Clone, Copy)]
pub enum SelectorValue {
Dynam,
ConstUnknown,
Const(bool),
}

/// The selector can use its configuration bits to arbitrarily select from any
/// of the `SelectorValues` in a power-of-two array.
#[derive(Debug, Clone)]
pub struct SelectorLut {
inx_config: Vec<PConfig>,
// The `Awi` is broken up into pairs of bits used to indicate the
// following states in incrementing order: dynamic, const unknown, const zero,
// const one. The sources only correspond to `SelectorValue::Dynam`, and so this can be used to
// determine where the gaps are.
awi: Awi,
}

impl SelectorLut {
pub fn get_selector_value(&self, bit_i: usize) -> SelectorValue {
debug_assert!(bit_i < (isize::MAX as usize));
let start = bit_i << 1;
debug_assert!((bit_i << 1) < self.awi.bw());
match (
self.awi.get(start).unwrap(),
self.awi.get(start.wrapping_add(1)).unwrap(),
) {
(false, false) => SelectorValue::Dynam,
(true, false) => SelectorValue::ConstUnknown,
(b, true) => SelectorValue::Const(b),
}
pub fn inx_config(&self) -> &[PConfig] {
&self.inx_config
}

pub fn verify_integrity(&self, sources_len: usize) -> Result<(), Error> {
// TODO
let pow_len = 1usize << self.inx_config.len();
if pow_len.checked_mul(2).unwrap() != self.awi.bw() {
return Err(Error::OtherStr("problem with `SelectorLut` validation"));
}
let mut dynam_len = 0;
for i in 0..pow_len {
if let SelectorValue::Dynam = self.get_selector_value(i) {
dynam_len += 1;
}
}
if dynam_len != sources_len {
if pow_len != sources_len {
return Err(Error::OtherStr("problem with `SelectorLut` validation"));
}
Ok(())
Expand Down Expand Up @@ -409,19 +378,8 @@ impl<PCNode: Ptr, PCEdge: Ptr> Channeler<PCNode, PCEdge> {
);
} else {
// should be a full selector
let mut awi = Awi::zero(NonZeroUsize::new(2 << inp.len()).unwrap());
for (i, lut_bit) in lut.iter().copied().enumerate() {
let i = i << 1;
for lut_bit in lut.iter().copied() {
match lut_bit {
DynamicValue::ConstUnknown => {
awi.set(i, true).unwrap();
}
DynamicValue::Const(b) => {
awi.set(i.wrapping_add(1), true).unwrap();
if b {
awi.set(i, true).unwrap();
}
}
DynamicValue::Dynam(p) => {
let (p_equiv, p_cnode) = channeler.translate(ensemble, p);
if configurator.find(p_equiv).is_some() {
Expand All @@ -431,15 +389,16 @@ impl<PCNode: Ptr, PCEdge: Ptr> Channeler<PCNode, PCEdge> {
}
sources.push(p_cnode.unwrap());
}
// target ensemble is not correct
DynamicValue::ConstUnknown | DynamicValue::Const(_) => {
unreachable!()
}
}
}
channeler.make_cedge(
&sources,
p_self,
Programmability::SelectorLut(SelectorLut {
inx_config: config,
awi,
}),
Programmability::SelectorLut(SelectorLut { inx_config: config }),
NonZeroU32::new(1).unwrap(),
);
}
Expand Down
76 changes: 72 additions & 4 deletions starlight/src/route/config.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use awint::awint_dag::triple_arena::OrdArena;
use awint::{awint_dag::triple_arena::OrdArena, Awi};

use super::PConfig;
use crate::{
ensemble::{Ensemble, PBack, PExternal},
epoch::get_current_epoch,
route::Router,
route::{EdgeKind, EmbeddingKind, PConfig, Programmability, Router},
Error, LazyAwi,
};

Expand Down Expand Up @@ -90,9 +89,78 @@ impl Configurator {
}

impl Router {
/// Requires that the target epoch be resumed and is the active epoch
pub fn config_target(&self) -> Result<(), Error> {
todo!()
}

/*pub fn ensemble_config_target(&self, ensemble: &mut Ensemble) -> Result<(), Error> {
Ok(())
}*/

/// Sets all the configurations derived from final embeddings
pub(crate) fn set_configurations(&mut self) -> Result<(), Error> {
//
// assumes that all config `value`s are set to `None` and we only route once,
// otherwise we have to set them all to `None` at the start because it is used
// to detect if there are contradictions

for embedding in self.embeddings.vals() {
match embedding.program {
EmbeddingKind::Node(_) => {
// follow the `SelectorLut`s of the hyperpath
for path in embedding.target_hyperpath.paths() {
for edge in path.edges() {
match edge.kind {
EdgeKind::Transverse(q_cedge, source_i) => {
let cedge = self.target_channeler.cedges.get(q_cedge).unwrap();
match cedge.programmability() {
// no-op with respect to configuration
Programmability::TNode => (),
// there are identity like cases where we might want to
// traverse these kinds
Programmability::StaticLut(_) => todo!(),
Programmability::ArbitraryLut(_) => todo!(),
Programmability::SelectorLut(selector_lut) => {
let inx_config = selector_lut.inx_config();
assert!(source_i < (1 << inx_config.len()));
let i = Awi::from_usize(source_i);
for (inx_i, p_config) in
inx_config.iter().copied().enumerate()
{
let value = &mut self
.configurator
.configurations
.get_val_mut(p_config)
.unwrap()
.value;
let desired_value = Some(i.get(inx_i).unwrap());
if value.is_some() && (*value != desired_value) {
// means hyperpaths or base embeddings are
// conflicting
panic!(
"bug in router, a configuration bit has \
already been set and contradicts another \
desired configuration"
);
}
*value = desired_value;
}
}
// the hyperpath should be fully lowered
Programmability::Bulk(_) => unreachable!(),
}
}
// the hyperpath should be fully lowered into base level traversals
EdgeKind::Concentrate | EdgeKind::Dilute => unreachable!(),
}
}
}
}
// need lowering to and configuration setting of `ArbitraryLut`s
EmbeddingKind::Edge(_) => todo!(),
}
}

Ok(())
}
}
Expand Down
22 changes: 19 additions & 3 deletions starlight/src/route/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct Mapping {
pub struct Router {
target_ensemble: Ensemble,
pub(crate) target_channeler: Channeler<QCNode, QCEdge>,
pub(crate) configurator: Configurator,
program_ensemble: Ensemble,
pub(crate) program_channeler: Channeler<PCNode, PCEdge>,
// `ThisEquiv` `PBack` mapping from program to target
Expand Down Expand Up @@ -105,6 +106,7 @@ impl Router {
let mut router = Self::new_from_channelers(
target_epoch,
target_channeler,
configurator,
program_epoch,
program_channeler,
);
Expand Down Expand Up @@ -160,12 +162,14 @@ impl Router {
pub fn new_from_channelers(
target_epoch: &SuspendedEpoch,
target_channeler: Channeler<QCNode, QCEdge>,
configurator: &Configurator,
program_epoch: &SuspendedEpoch,
program_channeler: Channeler<PCNode, PCEdge>,
) -> Self {
Self {
target_ensemble: target_epoch.ensemble(|ensemble| ensemble.clone()),
target_channeler,
configurator: configurator.clone(),
program_ensemble: program_epoch.ensemble(|ensemble| ensemble.clone()),
program_channeler,
mappings: OrdArena::new(),
Expand Down Expand Up @@ -695,9 +699,21 @@ impl Router {
.get_val(bit)
.unwrap()
.p_self_equiv;
let q_cnode = self.target_channeler().find_channeler_cnode(bit).unwrap();
todo!()
//self.target_channeler().cnodes.get_val(q_cnode).unwrap().
if let Some(p_config) = self.configurator.find(bit) {
let value = self
.configurator
.configurations
.get_val(p_config)
.unwrap()
.value;
let value = value.unwrap_or(false);
res.set(bit_i, value).unwrap();
} else {
return Err(Error::OtherStr(
"`get_config({config:#?})`: `config` is not registered as \
configurable in the configurator",
));
}
}
}
} else {
Expand Down
10 changes: 10 additions & 0 deletions starlight/src/route/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,16 @@ If nothing is found by the root, then the connection is impossible if the `start
absolute, otherwise those need to be moved.
*/

// TODO make it so that the retry does not have to retry the entire level but
// only a part of it, probably want to keep track of the most recent common
// ancestor of all the edges to the node before the most recent or second most
// recent supernode that we have encountered (?).

// or, perhaps make a virtual valley embedding that starts from second most
// recent and ends at the next node we couldn't reach, and then restart with the
// new backbone to repair suboptimalities from the virtual embedding start and
// finish

/// Assumes that `start` and `end` are on the same level, and `max_backbone_lvl`
/// is at least one level above the leval that the `start` and `end` are on.
/// Returns `true` if the routing was successful, leaving the path information
Expand Down

0 comments on commit 4e68662

Please sign in to comment.