Skip to content

Commit

Permalink
Added basic fallback Verilog generation
Browse files Browse the repository at this point in the history
VonTum committed Dec 15, 2023
1 parent 04e11ae commit 8e5f52c
Showing 12 changed files with 291 additions and 123 deletions.
7 changes: 7 additions & 0 deletions src/arena_alloc.rs
Original file line number Diff line number Diff line change
@@ -254,6 +254,9 @@ impl<T, IndexMarker : UUIDMarker> ListAllocator<T, IndexMarker> {
pub fn alloc(&self, v : T) -> UUID<IndexMarker> {
UUID(self.data.alloc(v), PhantomData)
}
pub fn get_next_alloc_id(&self) -> UUID<IndexMarker> {
UUID(self.data.len(), PhantomData)
}
pub fn iter<'a>(&'a self) -> ListAllocIterator<'a, T, IndexMarker> {
self.into_iter()
}
@@ -356,6 +359,10 @@ impl<T, IndexMarker : UUIDMarker> FlatAlloc<T, IndexMarker> {
pub fn new() -> Self {
Self{data : Vec::new(), _ph : PhantomData}
}
pub fn get_next_alloc_id(&self) -> UUID<IndexMarker> {
let uuid = self.data.len();
UUID(uuid, PhantomData)
}
pub fn alloc(&mut self, value : T) -> UUID<IndexMarker> {
let uuid = self.data.len();
self.data.push(value);
3 changes: 2 additions & 1 deletion src/ast.rs
Original file line number Diff line number Diff line change
@@ -86,7 +86,8 @@ impl Display for Operator {
#[derive(Debug,Clone)]
pub enum Value {
Bool(bool),
Integer(BigUint)
Integer(BigUint),
Invalid
}

#[derive(Debug,Clone)]
4 changes: 4 additions & 0 deletions src/block_vector.rs
Original file line number Diff line number Diff line change
@@ -50,6 +50,10 @@ impl<T, const BLOCK_SIZE : usize> BlockVec<T, BLOCK_SIZE> {
allocated_id
}

pub fn len(&self) -> usize {
self.length.get()
}

pub fn iter<'s>(&'s self) -> BlockVecIter<'s, T, BLOCK_SIZE> {
self.into_iter()
}
56 changes: 1 addition & 55 deletions src/codegen.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ impl GenerationContext {
Self{global_ctx}
}

pub fn to_circt(&self, instance : &InstantiatedModule) {
pub fn to_circt(&self) {
let ctx = *self.global_ctx.deref();
//moore_circt::hw::
let module = moore_circt::ModuleOp::new(ctx);
@@ -29,11 +29,6 @@ impl GenerationContext {
let mut builder = Builder::new(mod_ctx);
builder.set_insertion_point_to_start(module.block());

//let mut wire_names = instance.wires.iter().map(|a| builder.)
for (id, w) in &instance.wires {

}

//mlir_builder.set_loc(span_to_loc(mod_ctx, hir.span()));
//mlir_builder.set_insertion_point_to_end(self.into_mlir.block());

@@ -80,53 +75,4 @@ pub fn to_calyx(md : &Module, flattened : &FlattenedModule, linker : &Linker) {
let res : CalyxResult<()> = backend.emit(ctx: &ir::Context, file: &mut OutputFile)
}
pub fn gen_verilog_code(md : &Module, flattened : &FlattenedModule, linker : &Linker) {
let mut cur_wire_id : usize = 0;
let mut wire_names = flattened.wires.map(&mut |_id, _| {
let name = format!("w_{cur_wire_id}");
cur_wire_id += 1;
name
});
let mut cur_inst_id : usize = 0;
let mut instance_names = flattened.instantiations.map(&mut |_id, _| {
let name = format!("inst_{cur_inst_id}");
cur_inst_id += 1;
name
});
let file = &linker.files[md.link_info.file];
for (idx, v) in md.declarations.iter().enumerate() {
let name = file.file_text[v.name.clone()].to_owned();
match &flattened.local_map[idx].wire_or_instance {
crate::flattening::WireOrInstantiation::Wire(w_idx) => {
wire_names[*w_idx] = name;
},
crate::flattening::WireOrInstantiation::Instantiation(i_idx) => {
instance_names[*i_idx] = name;
},
crate::flattening::WireOrInstantiation::Other(_) => {},
}
}
println!("Module {} {{", &file.file_text[file.tokens[md.link_info.name_token].get_range()]);
for (id, w) in &flattened.wires {
println!("\twire {:?} {};", w.typ, &wire_names[id]);
}
println!();
for (id, i) in &flattened.instantiations {
println!("\tinstantiation {:?} {};", i, &instance_names[id]);
}
println!();
for conn in &flattened.connections {
let regs = "reg ".repeat(conn.num_regs as usize);
if conn.condition != WireID::INVALID {
}
println!("\t·{regs}{:?} {};", i, &instance_names[id]);
}
println!("}}")
}
*/
141 changes: 141 additions & 0 deletions src/codegen_fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::{iter::zip, ops::Deref};

use crate::{ast::{Module, Value}, instantiation::{InstantiatedModule, RealWireDataSource, StateInitialValue, ConnectToPathElem}, linker::{Linker, NamedUUID, get_builtin_uuid}, arena_alloc::UUID, typing::ConcreteType, tokenizer::get_token_type_name};

fn get_type_name_size(id : NamedUUID) -> u64 {
if id == get_builtin_uuid("int") {
32 // TODO concrete int sizes
} else if id == get_builtin_uuid("bool") {
1 // TODO concrete int sizes
} else {
println!("TODO Named Structs Size");
1 // todo!() // Named structs are not implemented yet
}
}

fn arr_str(sz : u64) -> String {
format!("[{}:0]", sz - 1)
}

fn typ_to_verilog_array(typ : &ConcreteType) -> String {
match typ {
ConcreteType::Named(id) => {
let sz = get_type_name_size(*id);
if sz == 1 {
String::new()
} else {
arr_str(sz)
}
}
ConcreteType::Array(arr) => {
let (sub_typ, size) = arr.deref();
typ_to_verilog_array(sub_typ) + &arr_str(*size)
}
}
}

pub fn value_to_str(value : &Value) -> String {
match value {
Value::Bool(b) => if *b {"1'b1"} else {"1'b0"}.to_owned(),
Value::Integer(v) => v.to_string(),
Value::Invalid => "INVALID".to_owned()
}
}

pub fn gen_verilog_code(md : &Module, instance : &InstantiatedModule, linker : &Linker) -> Option<String> {
let mut program_text : String = format!("module {}(\n\tinput clk, \n", md.link_info.name);
for (port, real_port) in zip(&md.interface.interface_wires, &instance.interface) {
if real_port.id == UUID::INVALID {return None;}
let wire = &instance.wires[real_port.id];
program_text.push_str(if port.is_input {"\tinput"} else {"\toutput"});
program_text.push_str(&typ_to_verilog_array(&wire.typ));
program_text.push(' ');
program_text.push_str(&wire.name);
program_text.push_str(",\n");
}
program_text.push_str(");\n");

for (id, w) in &instance.wires {
let wire_or_reg = if let RealWireDataSource::Multiplexer{is_state: initial_value, sources} = &w.source {
if let StateInitialValue::NotState = initial_value {
"/*mux_wire*/ reg"
} else {
"reg"
}
} else {"wire"};

program_text.push_str(wire_or_reg);
program_text.push_str(&typ_to_verilog_array(&w.typ));
program_text.push(' ');
program_text.push_str(&w.name);
program_text.push_str(";\n");
}

for (id, sm) in &instance.submodules {
program_text.push_str(&sm.instance.name);
program_text.push(' ');
program_text.push_str(&sm.name);
program_text.push_str("(\n.clk(clk)");
for (port, wire) in zip(&sm.instance.interface, &sm.wires) {
program_text.push_str(",\n.");
program_text.push_str(&sm.instance.wires[port.id].name);
program_text.push('(');
program_text.push_str(&instance.wires[*wire].name);
program_text.push_str(")");
}
program_text.push_str("\n);\n");
}

for (id, w) in &instance.wires {
match &w.source {
RealWireDataSource::ReadOnly => {}
RealWireDataSource::Multiplexer { is_state, sources } => {
let output_name = w.name.deref();
match is_state {
StateInitialValue::NotState => {
program_text.push_str(&format!("/*always_comb*/ always @(*) begin\n\t{output_name} <= 1'bX; // Not defined when not valid\n"));
}
StateInitialValue::State { initial_value } => {
program_text.push_str(&format!("/*always_ff*/ always @(posedge clk) begin\n"));
}
}
for s in sources {
let mut path = String::new();
for path_elem in &s.path {
match path_elem {
ConnectToPathElem::ArrayConnection { idx_wire } => {
path.push('[');
path.push_str(&instance.wires[*idx_wire].name);
path.push(']');
}
}
}
let from_name = instance.wires[s.from.from].name.deref();
if s.from.condition != UUID::INVALID {
let cond = instance.wires[s.from.condition].name.deref();
program_text.push_str(&format!("\tif({cond}) begin {output_name}{path} <= {from_name}; end\n"));
} else {
program_text.push_str(&format!("\t{output_name}{path} <= {from_name};\n"));
}
}
program_text.push_str("end\n");
}
RealWireDataSource::UnaryOp { op, right } => {
program_text.push_str(&format!("assign {} = {}{};\n", w.name, get_token_type_name(op.op_typ), instance.wires[*right].name));
}
RealWireDataSource::BinaryOp { op, left, right } => {
program_text.push_str(&format!("assign {} = {} {} {};\n", w.name, instance.wires[*left].name, get_token_type_name(op.op_typ), instance.wires[*right].name));
}
RealWireDataSource::ArrayAccess { arr, arr_idx } => {
program_text.push_str(&format!("assign {} = {}[{}];\n", w.name, instance.wires[*arr].name, instance.wires[*arr_idx].name));
}
RealWireDataSource::Constant { value } => {
program_text.push_str(&format!("assign {} = {};\n", w.name, value_to_str(value)));
}
}
}

program_text.push_str("endmodule\n");

Some(program_text)
}
2 changes: 1 addition & 1 deletion src/dev_aid/syntax_highlighting.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

use std::{ops::Range, path::{PathBuf, Path}};
use std::{ops::Range, path::PathBuf};

use crate::{ast::*, tokenizer::*, parser::*, linker::{PreLinker, FileData, Links, NamedUUID, Named, Linkable, Linker, FileUUIDMarker, FileUUID}, arena_alloc::ArenaVector};

45 changes: 27 additions & 18 deletions src/flattening.rs
Original file line number Diff line number Diff line change
@@ -43,8 +43,8 @@ pub struct InterfacePort {

#[derive(Debug)]
pub enum Instantiation {
SubModule{module_uuid : NamedUUID, typ_span : Span, interface_wires : Vec<InterfacePort>},
PlainWire{read_only : bool, typ : Type, decl_id : Option<DeclID>},
SubModule{module_uuid : NamedUUID, name : Box<str>, typ_span : Span, interface_wires : Vec<InterfacePort>},
PlainWire{read_only : bool, identifier_type : IdentifierType, typ : Type, decl_id : Option<DeclID>},
UnaryOp{typ : Type, op : Operator, right : SpanFlatID},
BinaryOp{typ : Type, op : Operator, left : SpanFlatID, right : SpanFlatID},
ArrayAccess{typ : Type, arr : SpanFlatID, arr_idx : SpanFlatID},
@@ -55,8 +55,8 @@ pub enum Instantiation {
impl Instantiation {
pub fn get_type(&self) -> &Type {
match self {
Instantiation::SubModule{module_uuid : _, typ_span : _, interface_wires : _} => panic!("This is not a struct!"),
Instantiation::PlainWire{read_only: _, typ, decl_id : _} => typ,
Instantiation::SubModule{module_uuid : _, name : _, typ_span : _, interface_wires : _} => panic!("This is not a struct!"),
Instantiation::PlainWire{read_only: _, identifier_type : _, typ, decl_id : _} => typ,
Instantiation::UnaryOp{typ, op : _, right : _} => typ,
Instantiation::BinaryOp{typ, op : _, left : _, right : _} => typ,
Instantiation::ArrayAccess{typ, arr : _, arr_idx : _} => typ,
@@ -67,14 +67,14 @@ impl Instantiation {

pub fn iter_sources<F : FnMut(FlatID) -> ()>(&self, mut f : F) {
match self {
Instantiation::SubModule { module_uuid : _, typ_span : _, interface_wires } => {
Instantiation::SubModule { module_uuid : _, name : _, typ_span : _, interface_wires } => {
for port in interface_wires {
if port.is_input {
f(port.id);
}
}
}
Instantiation::PlainWire { read_only : _, typ : _, decl_id : _ } => {}
Instantiation::PlainWire { read_only : _, identifier_type : _, typ : _, decl_id : _ } => {}
Instantiation::UnaryOp { typ : _, op : _, right } => {f(right.0);}
Instantiation::BinaryOp { typ : _, op : _, left, right } => {f(left.0); f(right.0);}
Instantiation::ArrayAccess { typ : _, arr, arr_idx } => {f(arr.0); f(arr_idx.0)}
@@ -141,12 +141,17 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {

Some(())
}
fn alloc_module_interface(&self, module : &Module, module_uuid : NamedUUID, typ_span : Span) -> Instantiation {
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| {
InterfacePort{is_input : port.is_input, id : self.instantiations.alloc(Instantiation::PlainWire { read_only : !port.is_input, typ: port.typ.clone(), decl_id : None })}
let identifier_type = if port.is_input {
IdentifierType::Input
} else {
IdentifierType::Output
};
InterfacePort{is_input : port.is_input, id : self.instantiations.alloc(Instantiation::PlainWire { read_only : !port.is_input, identifier_type, typ: port.typ.clone(), decl_id : None })}
}).collect();

Instantiation::SubModule{module_uuid, typ_span, interface_wires}
Instantiation::SubModule{name, module_uuid, typ_span, interface_wires}
}
fn desugar_func_call(&self, func_and_args : &[SpanExpression], closing_bracket_pos : usize, condition : FlatID) -> Option<(&Module, &[InterfacePort])> {
let (name_expr, name_expr_span) = &func_and_args[0]; // Function name is always there
@@ -158,7 +163,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
let module_ref = self.module.link_info.global_references[*g];

let dependency = self.linker.try_get_module(module_ref, &self.errors)?;
let new_module_interface = self.alloc_module_interface(dependency, module_ref.1, *name_expr_span);
let new_module_interface = self.alloc_module_interface(dependency.link_info.name.clone(), dependency, module_ref.1, *name_expr_span);
self.instantiations.alloc(new_module_interface)
}
_other => {
@@ -167,7 +172,7 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
}
};
let func_instantiation = &self.instantiations[func_instantiation_id];
let Instantiation::SubModule{module_uuid, typ_span, interface_wires} = func_instantiation else {unreachable!("It should be proven {func_instantiation:?} was a Module!");};
let Instantiation::SubModule{module_uuid, name, typ_span, interface_wires} = func_instantiation else {unreachable!("It should be proven {func_instantiation:?} was a Module!");};
let Named::Module(md) = &self.linker.links.globals[*module_uuid] else {unreachable!("UUID Should be a module!");};
let (inputs, output_range) = md.interface.get_function_sugar_inputs_outputs();

@@ -260,13 +265,15 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
Some(match expr {
AssignableExpression::Named{local_idx} => {
let root = self.decl_to_flat_map[*local_idx];
if let Instantiation::PlainWire { read_only : false, typ : _, decl_id } = &self.instantiations[root] {
ConnectionWrite{root, path : Vec::new(), span : *span}
} else {
let Instantiation::PlainWire { read_only, identifier_type : _, typ : _, decl_id } = &self.instantiations[root] else {
unreachable!("Attempting to assign to a Instantiation::PlainWire")
};
if *read_only {
let decl_info = error_info(self.module.declarations[*local_idx].span, self.errors.file, "Declared here");
self.errors.error_with_info(*span, "Cannot Assign to Read-Only value", vec![decl_info]);
return None
}
ConnectionWrite{root, path : Vec::new(), span : *span}
}
AssignableExpression::ArrayIndex(arr_box) => {
let (arr, idx, bracket_span) = arr_box.deref();
@@ -311,14 +318,16 @@ impl<'l, 'm, 'fl> FlatteningContext<'l, 'm, 'fl> {
}
Named::Module(md) => {
if let Type::Named(name) = typ {
self.alloc_module_interface(md, name, typ_span)
self.alloc_module_interface(decl.name.clone(), md, name, typ_span)
} else {
todo!("Implement submodule arrays");
//Instantiation::Error
}
}
Named::Type(_) => {
Instantiation::PlainWire{read_only : decl.identifier_type == IdentifierType::Input, typ, decl_id : Some(*decl_id)}
assert!(decl.identifier_type != IdentifierType::Input);
assert!(decl.identifier_type != IdentifierType::Output);
Instantiation::PlainWire{read_only : false, identifier_type : decl.identifier_type, typ, decl_id : Some(*decl_id)}
}
}
};
@@ -467,7 +476,7 @@ impl FlattenedModule {
};

let (wire_id, typ) = if let Some(typ) = context.map_to_type(&decl.typ.0, &module.link_info.global_references) {
let wire_id = context.instantiations.alloc(Instantiation::PlainWire { read_only: is_input, typ : typ.clone(), decl_id : Some(decl_id)});
let wire_id = context.instantiations.alloc(Instantiation::PlainWire { read_only: is_input, identifier_type : decl.identifier_type, typ : typ.clone(), decl_id : Some(decl_id)});
(wire_id, typ)
} else {
(UUID::INVALID, Type::Named(UUID::INVALID))
@@ -549,7 +558,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::PlainWire { read_only : _, typ : _, decl_id : Some(decl_id) } = inst {
if let Instantiation::PlainWire { read_only : _, identifier_type, typ : _, decl_id : Some(decl_id) } = inst {
self.errors.warn_basic(Span::from(md.declarations[*decl_id].name_token), "Unused Variable: This variable does not affect the output ports of this module");
}
}
100 changes: 63 additions & 37 deletions src/instantiation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{rc::Rc, ops::Deref, cell::RefCell};

use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Value, Operator, Module}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWrite, ConnectionWritePathElement, InterfacePort}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid, NamedUUID}};
use num::{BigUint, FromPrimitive};

use crate::{arena_alloc::{UUID, UUIDMarker, FlatAlloc}, ast::{Value, Operator, Module, IdentifierType}, typing::{ConcreteType, Type}, flattening::{FlatID, Instantiation, FlatIDMarker, ConnectionWrite, ConnectionWritePathElement}, errors::ErrorCollector, linker::{Linker, get_builtin_uuid}};

pub mod latency;

@@ -16,9 +18,9 @@ pub type SubModuleID = UUID<SubModuleIDMarker>;

#[derive(Debug)]
pub struct ConnectFrom {
num_regs : i64,
from : WireID,
condition : WireID
pub num_regs : i64,
pub from : WireID,
pub condition : WireID
}

#[derive(Debug)]
@@ -32,10 +34,16 @@ pub struct MultiplexerSource {
pub from : ConnectFrom
}

#[derive(Debug)]
pub enum StateInitialValue {
NotState,
State{initial_value : Option<Value>}
}

#[derive(Debug)]
pub enum RealWireDataSource {
ReadOnly,
Multiplexer{sources : Vec<MultiplexerSource>},
Multiplexer{is_state : StateInitialValue, sources : Vec<MultiplexerSource>},
UnaryOp{op : Operator, right : WireID},
BinaryOp{op : Operator, left : WireID, right : WireID},
ArrayAccess{arr : WireID, arr_idx : WireID},
@@ -46,7 +54,7 @@ impl RealWireDataSource {
fn iter_sources_with_min_latency<F : FnMut(WireID, i64) -> ()>(&self, mut f : F) {
match self {
RealWireDataSource::ReadOnly => {}
RealWireDataSource::Multiplexer { sources } => {
RealWireDataSource::Multiplexer { is_state, sources } => {
for s in sources {
f(s.from.from, s.from.num_regs);
f(s.from.condition, 0);
@@ -70,10 +78,11 @@ impl RealWireDataSource {

#[derive(Debug)]
pub struct RealWire {
source : RealWireDataSource,
original_wire : FlatID,
typ : ConcreteType,
latency : i64
pub source : RealWireDataSource,
pub original_wire : FlatID,
pub typ : ConcreteType,
pub latency : i64,
pub name : Box<str>
}

#[derive(Debug,Clone,Copy)]
@@ -85,13 +94,15 @@ pub struct InstantiatedInterfacePort {

#[derive(Debug)]
pub struct SubModule {
original_flat : FlatID,
instance : Rc<InstantiatedModule>,
wires : Vec<WireID>
pub original_flat : FlatID,
pub instance : Rc<InstantiatedModule>,
pub wires : Vec<WireID>,
pub name : Box<str>
}

#[derive(Debug)]
pub struct InstantiatedModule {
pub name : Box<str>, // Unique name involving all template arguments
pub interface : Vec<InstantiatedInterfacePort>,
pub wires : FlatAlloc<RealWire, WireIDMarker>,
pub submodules : FlatAlloc<SubModule, SubModuleIDMarker>,
@@ -120,7 +131,6 @@ struct InstantiationContext<'fl, 'l> {
instance_map : FlatAlloc<SubModuleOrWire, FlatIDMarker>,
wires : FlatAlloc<RealWire, WireIDMarker>,
submodules : FlatAlloc<SubModule, SubModuleIDMarker>,
interface : Vec<InstantiatedInterfacePort>,
errors : ErrorCollector,

module : &'fl Module,
@@ -129,8 +139,12 @@ struct InstantiationContext<'fl, 'l> {

impl<'fl, 'l> InstantiationContext<'fl, 'l> {
fn compute_constant(&self, wire : FlatID) -> Value {
let Instantiation::Constant { typ : _, value } = &self.module.flattened.instantiations[wire] else {todo!()};
value.clone()
if let Instantiation::Constant { typ : _, value } = &self.module.flattened.instantiations[wire] {
value.clone()
} else {
println!("TODO HIT");
Value::Integer(BigUint::from_u64(3333333).unwrap())
}
}
fn concretize_type(&self, typ : &Type) -> ConcreteType {
match typ {
@@ -171,50 +185,46 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
todo!();
}

let RealWire{latency : _, typ : _, original_wire: _, source : RealWireDataSource::Multiplexer { sources }} = &mut self.wires[self.instance_map[to.root].extract_wire()] else {unreachable!("Should only be a writeable wire here")};
let RealWire{name : _, latency : _, typ : _, original_wire: _, source : RealWireDataSource::Multiplexer { is_state: initial_value, sources }} = &mut self.wires[self.instance_map[to.root].extract_wire()] else {unreachable!("Should only be a writeable wire here")};

sources.push(MultiplexerSource{from, path : new_path})
}
fn add_wire(&mut self, typ : &Type, original_wire : FlatID, source : RealWireDataSource) -> SubModuleOrWire {
SubModuleOrWire::Wire(self.wires.alloc(RealWire{ latency : i64::MIN /* Invalid */, typ : self.concretize_type(typ), original_wire, source}))
fn add_wire(&mut self, name : Option<Box<str>>, typ : &Type, original_wire : FlatID, source : RealWireDataSource) -> SubModuleOrWire {
let name = name.unwrap_or_else(|| {format!("_{}", self.wires.get_next_alloc_id().get_hidden_value()).into_boxed_str()});
SubModuleOrWire::Wire(self.wires.alloc(RealWire{ name, latency : i64::MIN /* Invalid */, typ : self.concretize_type(typ), original_wire, source}))
}
fn compute_absolute_latencies(&mut self) {




}


fn instantiate_flattened_module(&mut self) {
for (original_wire, inst) in &self.module.flattened.instantiations {
let instance_to_add : SubModuleOrWire = match inst {
Instantiation::SubModule{module_uuid, typ_span, interface_wires} => {
Instantiation::SubModule{module_uuid, name, typ_span, interface_wires} => {
let instance = self.linker.instantiate(*module_uuid);
let interface_real_wires = interface_wires.iter().map(|port| {
self.instance_map[port.id].extract_wire()
}).collect();
SubModuleOrWire::SubModule(self.submodules.alloc(SubModule { original_flat: original_wire, instance, wires : interface_real_wires}))
SubModuleOrWire::SubModule(self.submodules.alloc(SubModule { original_flat: original_wire, instance, wires : interface_real_wires, name : name.clone()}))
},
Instantiation::PlainWire{read_only, typ, decl_id} => {
Instantiation::PlainWire{read_only, identifier_type, typ, decl_id} => {
let source = if *read_only {
RealWireDataSource::ReadOnly
} else {
RealWireDataSource::Multiplexer {sources : Vec::new()}
// TODO initial value
let is_state = if *identifier_type == IdentifierType::State {StateInitialValue::State { initial_value: None }} else {StateInitialValue::NotState};
RealWireDataSource::Multiplexer {is_state, sources : Vec::new()}
};
self.add_wire(typ, original_wire, source)
self.add_wire(decl_id.map(|id| self.module.declarations[id].name.clone()), typ, original_wire, source)
},
Instantiation::UnaryOp{typ, op, right} => {
self.add_wire(typ, original_wire, RealWireDataSource::UnaryOp{op: *op, right: self.instance_map[right.0].extract_wire() })
self.add_wire(None, typ, original_wire, RealWireDataSource::UnaryOp{op: *op, right: self.instance_map[right.0].extract_wire() })
},
Instantiation::BinaryOp{typ, op, left, right} => {
self.add_wire(typ, original_wire, RealWireDataSource::BinaryOp{op: *op, left: self.instance_map[left.0].extract_wire(), right: self.instance_map[right.0].extract_wire() })
self.add_wire(None, typ, original_wire, RealWireDataSource::BinaryOp{op: *op, left: self.instance_map[left.0].extract_wire(), right: self.instance_map[right.0].extract_wire() })
},
Instantiation::ArrayAccess{typ, arr, arr_idx} => {
self.add_wire(typ, original_wire, RealWireDataSource::ArrayAccess{arr: self.instance_map[arr.0].extract_wire(), arr_idx: self.instance_map[arr_idx.0].extract_wire() })
self.add_wire(None, typ, original_wire, RealWireDataSource::ArrayAccess{arr: self.instance_map[arr.0].extract_wire(), arr_idx: self.instance_map[arr_idx.0].extract_wire() })
},
Instantiation::Constant{typ, value} => {
self.add_wire(typ, original_wire, RealWireDataSource::Constant{value : value.clone() })
self.add_wire(None, typ, original_wire, RealWireDataSource::Constant{value : value.clone() })
},
Instantiation::Error => {unreachable!()},
};
@@ -235,6 +245,21 @@ impl<'fl, 'l> InstantiationContext<'fl, 'l> {
self.process_connection(&conn.to, conn_from);
}
}

fn make_interface(&self) -> Vec<InstantiatedInterfacePort> {
self.module.interface.interface_wires.iter().map(|port| {
let real_interface_wire = if port.wire_id != UUID::INVALID {
self.instance_map[port.wire_id].extract_wire()
} else {
UUID::INVALID
};
InstantiatedInterfacePort {
id: real_interface_wire,
is_input: port.is_input,
absolute_latency: i64::MIN, // INVALID
}
}).collect()
}
}


@@ -258,18 +283,19 @@ impl InstantiationList {
instance_map : module.flattened.instantiations.iter().map(|(_, _)| SubModuleOrWire::Unnasigned).collect(),
wires : FlatAlloc::new(),
submodules : FlatAlloc::new(),
interface : Vec::new(),
module : module,
linker : linker,
errors : ErrorCollector::new(module.flattened.errors.file)
};

context.instantiate_flattened_module();
let interface = context.make_interface();

cache_borrow.push(Rc::new(InstantiatedModule{
name : module.link_info.name.clone(),
wires : context.wires,
submodules : context.submodules,
interface : context.interface,
interface,
errors : context.errors
}));
}
3 changes: 3 additions & 0 deletions src/linker.rs
Original file line number Diff line number Diff line change
@@ -179,6 +179,9 @@ impl Links {
pub fn get_obj_by_name(&self, name : &str) -> Option<&Named> {
self.global_namespace.get(name).map(|id| &self.globals[*id])
}
pub fn get_obj_id(&self, name : &str) -> Option<NamedUUID> {
self.global_namespace.get(name).map(|id| *id)
}
}

// Represents the fully linked set of all files. Incremental operations such as adding and removing files can be performed
51 changes: 40 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -11,17 +11,34 @@ mod instantiation;
#[cfg(feature = "codegen")]
mod codegen;

mod codegen_fallback;

mod typing;

mod dev_aid;
mod linker;

use std::env;
use std::{env, ops::Deref};
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use ast::Module;
use codegen_fallback::gen_verilog_code;
use dev_aid::syntax_highlighting::*;
use linker::Named;
use linker::{Named, Linker, NamedUUID};

fn codegen_to_file(linker : &Linker, id : NamedUUID, md : &Module) {
let inst = linker.instantiate(id);

let module_name = md.link_info.name.deref();
println!("Generating Verilog for {module_name}:");
// gen_ctx.to_circt();
let Some(code) = gen_verilog_code(md, &inst, &linker) else {println!("Error"); return;};

let mut out_file = File::create(format!("verilog_output/{module_name}.v")).unwrap();
write!(out_file, "{}", code).unwrap()
}

fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
let mut args = env::args();
@@ -31,6 +48,7 @@ fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
let mut file_paths : Vec<PathBuf> = Vec::new();
let mut is_lsp = false;
let mut codegen = None;
let mut codegen_all = false;
let mut settings = SyntaxHighlightSettings{
show_tokens : false
};
@@ -43,6 +61,9 @@ fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
"--codegen" => {
codegen = Some(args.next().expect("Expected a module name after --codegen"));
}
"--codegen-all" => {
codegen_all = true;
}
"--tokens" => {
settings.show_tokens = true;
}
@@ -57,9 +78,11 @@ fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
return dev_aid::lsp::lsp_main(25000);
}
if file_paths.len() == 0 {
// Quick debug file
// Quick debugging
file_paths.push(PathBuf::from("resetNormalizer.sus"));
//file_paths.push(PathBuf::from("multiply_add.sus"));
file_paths.push(PathBuf::from("multiply_add.sus"));
codegen_all = true;
//codegen = Some("first_bit_idx_6".to_owned());
}

let (linker, paths_arena) = compile_all(file_paths);
@@ -69,21 +92,27 @@ fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
syntax_highlight_file(&linker, id, &settings);
}

#[cfg(feature = "codegen")]
// #[cfg(feature = "codegen")]
if let Some(module_name) = codegen {
let gen_ctx = codegen::GenerationContext::new();

let Some(named_obj) = linker.links.get_obj_by_name(&module_name) else {
//let gen_ctx = codegen::GenerationContext::new();
let Some(id) = linker.links.get_obj_id(&module_name) else {
panic!("Module {module_name} does not exist!");
};

let Named::Module(md) = named_obj else {
let Named::Module(md) = &linker.links.globals[id] else {
panic!("{module_name} is not a Module!");
};


codegen_to_file(&linker, id, md);
}

//gen_ctx.to_circt();
if codegen_all {
for (id, obj) in &linker.links.globals {
if let Named::Module(md) = obj {
codegen_to_file(&linker, id, md);
}
}
}

Ok(())
1 change: 1 addition & 0 deletions src/typing.rs
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ impl Value {
match self {
Value::Bool(_) => Type::Named(get_builtin_uuid("bool")),
Value::Integer(_) => Type::Named(get_builtin_uuid("int")),
Value::Invalid => Type::Named(UUID::INVALID),
}
}
}
1 change: 1 addition & 0 deletions verilog_output/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.v

0 comments on commit 8e5f52c

Please sign in to comment.