Skip to content

Commit

Permalink
Extract WireDeclaration from WireSource
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Jan 3, 2024
1 parent 5fc7d62 commit 2d8f728
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 46 deletions.
6 changes: 3 additions & 3 deletions src/codegen_fallback.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{iter::zip, ops::Deref};

use crate::{ast::{Module, IdentifierType}, instantiation::{InstantiatedModule, RealWireDataSource, StateInitialValue, ConnectToPathElem}, linker::{NamedUUID, get_builtin_uuid}, typing::ConcreteType, tokenizer::get_token_type_name, flattening::WireSource, value::Value};
use crate::{ast::{Module, IdentifierType}, instantiation::{InstantiatedModule, RealWireDataSource, StateInitialValue, ConnectToPathElem}, linker::{NamedUUID, get_builtin_uuid}, typing::ConcreteType, tokenizer::get_token_type_name, flattening::{Instantiation, WireDeclaration}, value::Value};

fn get_type_name_size(id : NamedUUID) -> u64 {
if id == get_builtin_uuid("int") {
Expand Down Expand Up @@ -67,9 +67,9 @@ pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule) -> String
program_text.push_str(");\n");

for (_id, w) in &instance.wires {
if let WireSource::NamedWire{read_only : _, identifier_type, name : _, name_token : _} = &md.flattened.instantiations[w.original_wire].extract_wire().inst {
if let Instantiation::WireDeclaration(wire_decl) = &md.flattened.instantiations[w.original_wire] {
// Don't print named inputs and outputs, already did that in interface
match identifier_type {
match wire_decl.identifier_type {
IdentifierType::Input | IdentifierType::Output => {continue;}
IdentifierType::Local | IdentifierType::State | IdentifierType::Generative => {}
}
Expand Down
87 changes: 63 additions & 24 deletions src/flattening.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ pub struct InterfacePort {

#[derive(Debug)]
pub enum WireSource {
NamedWire{read_only : bool, identifier_type : IdentifierType, name : Box<str>, name_token : Option<usize>},
WireRead{from_wire : FlatID}, // Used to add a span to the reference of a wire.
//SubModuleOutput{submodule : FlatID, port_idx : usize},
UnaryOp{op : Operator, right : FlatID},
BinaryOp{op : Operator, left : FlatID, right : FlatID},
ArrayAccess{arr : FlatID, arr_idx : FlatID},
Expand All @@ -69,17 +69,40 @@ pub struct WireInstance {
pub inst : WireSource
}

#[derive(Debug)]
pub struct WireDeclaration {
pub typ : Type,
pub typ_span : Span,
pub read_only : bool,
pub identifier_type : IdentifierType,
pub name : Box<str>,
pub name_token : Option<usize>
}
impl WireDeclaration {
pub fn get_full_decl_span(&self) -> Span {
let name_pos = self.name_token.unwrap(); // Temporary, name_token should always be present for proper declarations.
Span(self.typ_span.0, name_pos)
}
}

#[derive(Debug)]
pub enum Instantiation {
SubModule{module_uuid : NamedUUID, name : Box<str>, typ_span : Span, interface_wires : Vec<InterfacePort>},
WireDeclaration(WireDeclaration),
Wire(WireInstance),
Connection(Connection),
Error
}

impl Instantiation {
#[track_caller]
pub fn extract_wire(&self) -> &WireInstance {
let Self::Wire(w) = self else {panic!("extract_wire on not a wire!")};
let Self::Wire(w) = self else {panic!("extract_wire on not a wire! Found {self:?}")};
w
}
#[track_caller]
pub fn extract_wire_declaration(&self) -> &WireDeclaration {
let Self::WireDeclaration(w) = self else {panic!("extract_wire on not a WireDeclaration! Found {self:?}")};
w
}
}
Expand Down Expand Up @@ -121,7 +144,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
}
// May also error, for example when array accesses happen on non-array types
fn get_connectionwrite_type(&self, cw : &ConnectionWrite) -> Option<&Type> {
let mut current_type = &self.instantiations[cw.root].extract_wire().typ;
let mut current_type = &self.instantiations[cw.root].extract_wire_declaration().typ;
for p in &cw.path {
match p {
ConnectionWritePathElement::ArrayIdx{idx, idx_span} => {
Expand All @@ -138,10 +161,10 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {

let did_typecheck_fail = self.typecheck(connection.from, &expected_type, "connection");

let assign_to_root = self.instantiations[connection.to.root].extract_wire();
let assign_to_root = self.instantiations[connection.to.root].extract_wire_declaration();
let from_wire = self.instantiations[connection.from].extract_wire();
if assign_to_root.is_compiletime && !from_wire.is_compiletime {
let decl_info = error_info(assign_to_root.span, self.errors.file, "Declared here");
if assign_to_root.identifier_type == IdentifierType::Generative && !from_wire.is_compiletime {
let decl_info = error_info(assign_to_root.get_full_decl_span(), self.errors.file, "Declared here");
self.errors.error_with_info(from_wire.span, "Assignments to compile-time variables must themselves be known at compile time", vec![decl_info]);
return None;
}
Expand All @@ -151,22 +174,19 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Some(())
}
fn alloc_module_interface(&self, name : Box<str>, module : &Module, module_uuid : NamedUUID, typ_span : Span) -> Instantiation {
let interface_wires = module.interface.interface_wires.iter().map(|port| {
let interface_wires = module.interface.interface_wires.iter().enumerate().map(|(port_idx, port)| {
let identifier_type = if port.is_input {
IdentifierType::Input
} else {
IdentifierType::Output
};
let id = self.instantiations.alloc(Instantiation::Wire(WireInstance{
let id = self.instantiations.alloc(Instantiation::WireDeclaration(WireDeclaration{
typ: port.typ.clone(),
is_compiletime : false,
span : typ_span,
inst : WireSource::NamedWire{
read_only : !port.is_input,
identifier_type,
name : format!("{}_{}", &module.link_info.name, &port.port_name).into_boxed_str(),
name_token : None
}
typ_span,
read_only : !port.is_input,
identifier_type,
name : format!("{}_{}", &module.link_info.name, &port.port_name).into_boxed_str(),
name_token : None
}));
InterfacePort{is_input : port.is_input, id}
}).collect();
Expand Down Expand Up @@ -231,8 +251,9 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
let single_connection_side = match expr {
Expression::Named(LocalOrGlobal::Local(l)) => {
let from_wire = self.decl_to_flat_map[*l].unwrap();
let prev_decl = self.instantiations[from_wire].extract_wire();
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : prev_decl.typ.clone(), is_compiletime : prev_decl.is_compiletime, span, inst : WireSource::WireRead{from_wire}}))
let Instantiation::WireDeclaration(WireDeclaration { typ, typ_span:_, read_only:_, identifier_type, name:_, name_token:_ }) = &self.instantiations[from_wire] else {unreachable!("Reference to a wire MUST refer to a WireDeclaration, found {:?} instead", &self.instantiations[from_wire])};
let is_compiletime = *identifier_type == IdentifierType::Generative;
self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : typ.clone(), is_compiletime, span, inst : WireSource::WireRead{from_wire}}))
}
Expression::Named(LocalOrGlobal::Global(g)) => {
let r = self.module.link_info.global_references[*g];
Expand Down Expand Up @@ -290,7 +311,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Some(match expr {
AssignableExpression::Named{local_idx} => {
let root = self.decl_to_flat_map[*local_idx].unwrap();
let WireSource::NamedWire{read_only, identifier_type : _, name : _, name_token : _} = &self.instantiations[root].extract_wire().inst else {
let Instantiation::WireDeclaration(WireDeclaration{read_only, identifier_type : _, name : _, name_token : _, typ : _, typ_span : _}) = &self.instantiations[root] else {
unreachable!("Attempting to assign to a Instantiation::PlainWire")
};
if *read_only {
Expand Down Expand Up @@ -352,8 +373,14 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Named::Type(_) => {
assert!(decl.identifier_type != IdentifierType::Input);
assert!(decl.identifier_type != IdentifierType::Output);
let is_compiletime = decl.identifier_type == IdentifierType::Generative;
Instantiation::Wire(WireInstance{typ, is_compiletime, span : typ_span, inst : WireSource::NamedWire{read_only : false, identifier_type : decl.identifier_type, name : decl.name.clone(), name_token : Some(decl.name_token)}})
Instantiation::WireDeclaration(WireDeclaration{
typ,
typ_span,
read_only : false,
identifier_type : decl.identifier_type,
name : decl.name.clone(),
name_token : Some(decl.name_token)
})
}
}
} else {
Expand Down Expand Up @@ -401,7 +428,11 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {

for (field, to_i) in zip(outputs, to) {
let Some(write_side) = self.flatten_assignable_expr(&to_i.expr, condition) else {return;};
self.create_connection(Connection{num_regs : to_i.num_regs, from: field.id, to: write_side, condition});

// temporary
let module_port_wire_decl = self.instantiations[field.id].extract_wire_declaration();
let module_port_proxy = self.instantiations.alloc(Instantiation::Wire(WireInstance{typ : module_port_wire_decl.typ.clone(), is_compiletime : module_port_wire_decl.identifier_type == IdentifierType::Generative, span : *func_span, inst : WireSource::WireRead { from_wire: field.id }}));
self.create_connection(Connection{num_regs : to_i.num_regs, from: module_port_proxy, to: write_side, condition});
}
},
Statement::Assign{to, expr : non_func_expr, eq_sign_position : _} => {
Expand Down Expand Up @@ -507,7 +538,14 @@ impl FlattenedModule {
};

let typ = context.map_to_type(&decl.typ.0, &module.link_info.global_references);
let wire_id = context.instantiations.alloc(Instantiation::Wire(WireInstance{typ : typ.clone(), is_compiletime : false, span : decl.typ.1, inst : WireSource::NamedWire{read_only: is_input, identifier_type : decl.identifier_type, name : decl.name.clone(), name_token : Some(decl.name_token)}}));
let wire_id = context.instantiations.alloc(Instantiation::WireDeclaration(WireDeclaration{
typ : typ.clone(),
typ_span : decl.typ.1,
read_only: is_input,
identifier_type : decl.identifier_type,
name : decl.name.clone(),
name_token : Some(decl.name_token)
}));

interface.interface_wires.push(FlattenedInterfacePort { wire_id, is_input, typ, port_name: decl.name.clone(), span: decl.span });
context.decl_to_flat_map[decl_id] = Some(wire_id);
Expand Down Expand Up @@ -571,6 +609,7 @@ impl FlattenedModule {
}
};
match &self.instantiations[item] {
Instantiation::WireDeclaration(_) => {}
Instantiation::Wire(wire) => {
match &wire.inst {
WireSource::WireRead{from_wire} => {
Expand Down Expand Up @@ -600,7 +639,7 @@ impl FlattenedModule {
// Now produce warnings from the unused list
for (id, inst) in &self.instantiations {
if !is_instance_used_map[id] {
if let Instantiation::Wire(WireInstance{typ : _, is_compiletime : _, span : _, inst : WireSource::NamedWire { read_only : _, identifier_type : _, name : _, name_token : Some(name_token)}}) = inst {
if let Instantiation::WireDeclaration(WireDeclaration{typ : _, typ_span : _, read_only : _, identifier_type : _, name : _, name_token : Some(name_token)}) = inst {
self.errors.warn_basic(Span::from(*name_token), "Unused Variable: This variable does not affect the output ports of this module");
}
}
Expand Down
47 changes: 28 additions & 19 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{rc::Rc, ops::Deref, cell::RefCell};

use num::BigInt;

use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Operator, Module, IdentifierType, Span}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWritePathElement, WireSource, WireInstance, Connection, ConnectionWritePathElementComputed}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid}, value::{Value, compute_unary_op, compute_binary_op}};
use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Operator, Module, IdentifierType, Span}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWritePathElement, WireSource, WireInstance, Connection, ConnectionWritePathElementComputed, WireDeclaration}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid}, value::{Value, compute_unary_op, compute_binary_op}};

pub mod latency;

Expand Down Expand Up @@ -125,14 +125,17 @@ enum SubModuleOrWire {
}

impl SubModuleOrWire {
#[track_caller]
fn extract_wire(&self) -> WireID {
let Self::Wire(result) = self else {panic!("Failed wire extraction! Is {self:?} instead")};
*result
}
#[track_caller]
fn extract_submodule(&self) -> SubModuleID {
let Self::SubModule(result) = self else {panic!("Failed SubModule extraction! Is {self:?} instead")};
*result
}
#[track_caller]
fn extract_generation_value(&self) -> &Value {
let Self::CompileTimeValue(result) = self else {panic!("Failed GenerationValue extraction! Is {self:?} instead")};
result
Expand Down Expand Up @@ -282,13 +285,6 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
}
fn compute_compile_time(&self, wire_inst : &WireSource, typ : &ConcreteType) -> Option<Value> {
Some(match wire_inst {
WireSource::NamedWire{read_only, identifier_type: _, name : _, name_token : _} => {
/*Do nothing (in fact re-initializes the wire to 'empty'), just corresponds to wire declaration*/
if *read_only {
todo!("Modules can't be computed at compile time yet");
}
typ.get_initial_val(self.linker)
}
&WireSource::WireRead{from_wire} => {
self.get_generation_value(from_wire)?.clone()
}
Expand Down Expand Up @@ -335,18 +331,8 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
}
fn wire_to_real_wire(&mut self, w: &WireInstance, typ : ConcreteType, original_wire : FlatID) -> Option<WireID> {
let (name, source) = match &w.inst {
WireSource::NamedWire{read_only, identifier_type, name, name_token : _} => {
let source = if *read_only {
RealWireDataSource::ReadOnly
} else {
// TODO initial value
let is_state = if *identifier_type == IdentifierType::State{StateInitialValue::State{initial_value: Value::Unset}} else {StateInitialValue::Combinatorial};
RealWireDataSource::Multiplexer{is_state, sources : Vec::new()}
};
(Some(name.clone()), source)
}
&WireSource::WireRead{from_wire} => {
let WireSource::NamedWire{read_only:_, identifier_type:_, name:_, name_token:_} = &self.module.flattened.instantiations[from_wire].extract_wire().inst else {unreachable!("WireReads must point to a NamedWire!")};
let Instantiation::WireDeclaration(WireDeclaration{typ:_, typ_span:_, read_only:_, identifier_type:_, name:_, name_token:_}) = &self.module.flattened.instantiations[from_wire] else {unreachable!("WireReads must point to a NamedWire!")};
return Some(self.generation_state[from_wire].extract_wire())
}
&WireSource::UnaryOp{op, right} => {
Expand Down Expand Up @@ -390,6 +376,29 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
}).collect();
SubModuleOrWire::SubModule(self.submodules.alloc(SubModule { original_flat: original_wire, instance, wires : interface_real_wires, name : name.clone()}))
}
Instantiation::WireDeclaration(wire_decl) => {
let Some(typ) = self.concretize_type(&wire_decl.typ, wire_decl.typ_span) else {
return; // Exit early, do not produce invalid wires in InstantiatedModule
};
if wire_decl.identifier_type == IdentifierType::Generative {
/*Do nothing (in fact re-initializes the wire to 'empty'), just corresponds to wire declaration*/
if wire_decl.read_only {
todo!("Modules can't be computed at compile time yet");
}
let initial_value = typ.get_initial_val(self.linker);
assert!(initial_value.is_of_type(&typ));
SubModuleOrWire::CompileTimeValue(initial_value)
} else {
let source = if wire_decl.read_only {
RealWireDataSource::ReadOnly
} else {
// TODO initial value
let is_state = if wire_decl.identifier_type == IdentifierType::State{StateInitialValue::State{initial_value: Value::Unset}} else {StateInitialValue::Combinatorial};
RealWireDataSource::Multiplexer{is_state, sources : Vec::new()}
};
SubModuleOrWire::Wire(self.wires.alloc(RealWire{ name: wire_decl.name.clone(), typ, original_wire, source}))
}
}
Instantiation::Wire(w) => {
let Some(typ) = self.concretize_type(&w.typ, w.span) else {
return; // Exit early, do not produce invalid wires in InstantiatedModule
Expand Down

0 comments on commit 2d8f728

Please sign in to comment.