use std::error::Error;
use linked_hash_map::LinkedHashMap;
use crate::element::Element;
use crate::vhdl::vhdl_error::VhdlError;
use crate::vhdl::keywords::*;
use crate::vhdl::design_unit::DesignUnit;
use crate::vhdl::entity::Entity;
use crate::vhdl::block_declarative_list::BlockDeclarativeList;
use crate::vhdl::constant_declaration::ConstantDeclaration;
use crate::vhdl::signal_declaration::SignalDeclaraion;
use crate::vhdl::concurrent_statement::ConcurrentStatement;
use crate::vhdl::signal_assignment::SignalAssignment;
use crate::vhdl::instance::Instance;
use crate::vhdl::process::Process;
use crate::vhdl::entity_interface_binding::EntityInterfaceBinding;
use crate::vhdl::generic::Generic;
use crate::vhdl::generic_binding::GenericBinding;
use crate::vhdl::match_index::MatchIndex;
pub struct Architecture {
name : String,
entity : Entity,
declarations : BlockDeclarativeList,
instances : LinkedHashMap< String, Instance >,
statements : Vec< Box< dyn ConcurrentStatement > >
}
impl Architecture {
pub fn new( name : & str, entity : & Entity ) -> Architecture {
Architecture { name : name.to_string(), entity : ( * entity ).clone(),
declarations : BlockDeclarativeList::new(), instances : LinkedHashMap::new(),
statements : Vec::new() }
}
pub fn add_constant_declaration( & mut self, constant : & ConstantDeclaration ) {
self.entity.add_missing_library_use( constant.get_data_type() );
self.declarations.add_constant( constant );
}
pub fn add_signal_declaration( & mut self, signal : & SignalDeclaraion ) {
println!( "add_signal_declaration: {}", signal.get_name() );
self.entity.add_missing_library_use( signal.get_data_type() );
self.declarations.add_signal( signal );
}
pub fn add_signal_declaration_list( & mut self, signal_list : & Vec< SignalDeclaraion > ) {
for signal in signal_list {
self.add_signal_declaration( signal );
}
}
pub fn add_signal_assignment( & mut self, signal_assignment : SignalAssignment ) {
self.statements.push( Box::< SignalAssignment >::new( signal_assignment ) );
}
pub fn add_instance( & mut self, instance : Instance ) {
self.instances.insert( instance.get_name().to_string(), instance );
}
pub fn add_process( & mut self, process : Process ) {
self.statements.push( Box::< Process >::new( process ) );
}
pub fn connect_instance_to_entity( & mut self, name : & str ) -> Result< (), VhdlError > {
println!( "Architecture::connect_instance_to_entity" );
self.requires_instance( name )?;
self.instances.get_mut( name ).unwrap().connect_to_entity( & self.entity );
Ok(())
}
pub fn connect_instance_to_instance( & mut self, inst_name_a : & str, inst_name_b: & str )
-> Result< (), VhdlError > {
println!( "Architecture::connect_instance_to_instance {} {}", inst_name_a, inst_name_b );
let matches;
{
self.requires_instance( inst_name_a )?;
self.requires_instance( inst_name_b )?;
let inst_a : & Instance = self.instances.get( inst_name_a ).unwrap();
let inst_b : & Instance = self.instances.get( inst_name_b ).unwrap();
matches = inst_a.get_instance_interface_matches( & inst_b );
}
let mut connection_signal_lists : Vec< Vec< SignalDeclaraion > > = Vec::new();
{
for ( a, _ ) in & matches {
let inst : & mut Instance = self.instances.get_mut( inst_name_a ).unwrap();
let interface_a : & EntityInterfaceBinding = & inst.get_interfaces()[ * a ];
let signal_list = interface_a.get_connection_signal_list( inst_name_a, inst_name_b );
inst.connect_interface_by_index_to_signal_list( * a, & signal_list );
connection_signal_lists.push( signal_list );
}
}
{
for ( i, ( _, b ) ) in matches.iter().enumerate() {
let inst : & mut Instance = self.instances.get_mut( inst_name_b ).unwrap();
inst.connect_interface_by_index_to_signal_list( * b, & connection_signal_lists[ i ] );
}
}
{
for signal_list in & connection_signal_lists {
self.add_signal_declaration_list( signal_list );
}
}
Ok(())
}
pub fn connect_instance_to_instance_by_interface( & mut self,
inst_name_a : & str, inst_name_b: & str,
if_name_a : & str, if_name_b : & str )
-> Result< (), VhdlError > {
println!( "Architecture::connect_instance_to_instance_by_interface {} {} {} {}", inst_name_a, inst_name_b, if_name_a, if_name_b );
let match_index;
{
self.requires_instance( inst_name_a )?;
self.requires_instance( inst_name_b )?;
let inst_a : & Instance = self.instances.get( inst_name_a ).unwrap();
let inst_b : & Instance = self.instances.get( inst_name_b ).unwrap();
self.requires_interface_in_instance( inst_a, if_name_a )?;
self.requires_interface_in_instance( inst_b, if_name_b )?;
if ! inst_b.contains_interface( if_name_b ) {
return Err( VhdlError::new( & format!( "error: Interface {:?} not found in instance {:?} of architecture {:?}!",
if_name_a, inst_name_a, self.name ) ) );
}
let interface_a = inst_a.get_interface_by_name( if_name_a ).unwrap();
let interface_b = inst_b.get_interface_by_name( if_name_b ).unwrap();
match_index = interface_a.get_instance_matching( interface_b );
println!( "match_index : {}", match_index );
if match_index == crate::vhdl::match_index::NONE {
return Err( VhdlError::new( & format!( "error: Interface classes of {:?} and {:?} do not match!",
if_name_a, if_name_b ) ) );
}
}
let connection_signal_list : Vec< SignalDeclaraion >;
{
let inst : & mut Instance = self.instances.get_mut( inst_name_a ).unwrap();
let interface_a : & EntityInterfaceBinding = & inst.get_interface_by_name( if_name_a ).unwrap();
let signal_list = interface_a.get_connection_signal_list( inst_name_a, inst_name_b );
inst.connect_interface_by_name_to_signal_list( if_name_a, & signal_list );
connection_signal_list = signal_list;
}
{
let inst : & mut Instance = self.instances.get_mut( inst_name_b ).unwrap();
inst.connect_interface_by_name_to_signal_list( if_name_b, & connection_signal_list );
}
{
self.add_signal_declaration_list( & connection_signal_list );
}
Ok(())
}
pub fn connect_instance_unbound_by_name( & mut self, instance : & str )
-> Result< (), VhdlError > {
println!( "connect_instance_unbound_by_name" );
self.requires_instance( instance )?;
let mut matches : Vec< ( String, String ) > = Vec::new();
{
let inst : Instance = ( * self.instances.get( instance ).unwrap() ).clone();
for generic in & inst.get_unbound_generics() {
let outer = self.get_instance_generic_match( generic );
matches.push( ( generic.get_inner().clone(), outer ) );
}
}
let inst : & mut Instance = self.instances.get_mut( instance ).unwrap();
for ( inner, outer ) in matches {
if ! outer.is_empty() {
inst.connect_generic( & inner, & outer )?;
}
}
Ok(())
}
pub fn connect_instance_to_port_by_name( & mut self, instance : & str, inner : & str,
outer : & str ) -> Result< (), Box< dyn Error > > {
let instance : & mut Instance = self.get_instance_mut( instance )?;
instance.connect_to_port( inner, outer )?;
Ok(())
}
pub fn connect_instance_to_signal_by_name( & mut self, instance : & str, inner : & str,
outer : & str ) -> Result< (), Box< dyn Error > > {
{
let inst : & mut Instance = self.get_instance_mut( instance )?;
inst.connect_to_port( inner, outer )?;
}
{
let inst : & Instance = self.get_instance( instance )?;
let data_type = inst.get_port_data_type_by_name( inner ).unwrap().clone();
self.add_signal_declaration( & SignalDeclaraion::new( outer, & data_type ) );
}
Ok(())
}
fn get_instance( & self, instance : & str ) -> Result< & Instance, VhdlError > {
match self.instances.get( instance ) {
Some( instance ) => Ok( instance ),
None => Err( VhdlError::new( & format!(
"error: Architecture {:?} does not contain instance {:?}", self.name,
instance ) ) )
}
}
fn get_instance_mut( & mut self, instance : & str ) -> Result< & mut Instance, VhdlError > {
match self.instances.get_mut( instance ) {
Some( instance ) => Ok( instance ),
None => Err( VhdlError::new( & format!(
"error: Architecture {:?} does not contain instance {:?}", self.name,
instance ) ) )
}
}
fn requires_instance( & self, name : & str ) -> Result< (), VhdlError > {
if ! self.instances.contains_key( name ) {
return Err( VhdlError::new( & format!( "error: Instance {:?} not found in architecture {:?}!",
name, self.name ) ) );
}
Ok(())
}
fn requires_interface_in_instance( & self, inst : & Instance, name : & str ) -> Result< (), VhdlError > {
if ! inst.contains_interface( name ) {
return Err( VhdlError::new( & format!( "error: Interface {:?} not found in instance {:?} of architecture {:?}!",
name, inst.get_name(), self.name ) ) );
}
Ok(())
}
fn get_instance_generic_match( & self, binding : & GenericBinding ) -> String {
let constants = self.declarations.get_constants();
let mut constant_match = MatchIndex::new();
for ( idx, constant ) in constants.iter().enumerate() {
constant_match.update( idx,
self.get_generic_constant_match_strength( binding, constant) );
}
let generics = self.entity.get_generics();
let mut generic_match = MatchIndex::new();
for ( idx, generic ) in generics.iter().enumerate() {
generic_match.update( idx,
self.get_generic_generic_match_strength( binding, generic ) );
}
if constant_match.strength > generic_match.strength {
return constants[ constant_match.index ].get_name().clone();
}
else if generic_match.strength > 0 {
return generics[ generic_match.index ].get_name().clone();
}
return String::new();
}
fn get_generic_constant_match_strength( & self, _binding : & GenericBinding,
_constant : & ConstantDeclaration ) -> u32 {
return 0;
}
fn get_generic_generic_match_strength( & self, binding : & GenericBinding,
generic : & Generic ) -> u32 {
let binding_name = binding.get_inner().to_string().to_lowercase();
let generic_name = generic.get_name().to_string().to_lowercase();
let data_type_match : bool = binding.get_data_type() == generic.get_data_type();
let name_match : bool = binding_name == generic_name;
let binding_in_generic = generic_name.contains( & binding_name );
let generic_in_binding = binding_name.contains( & generic_name );
if ! data_type_match {
return 0;
}
if name_match {
return 3;
}
else if binding_in_generic || generic_in_binding {
return 2;
}
return 1;
}
}
impl Element for Architecture {
fn to_source_code( & self, indent : usize ) -> String {
let mut source = self.entity.to_source_code( indent );
source.push_str( "\n" );
let indent_str = crate::util::indent( indent );
source.push_str( & format!( "{}{} {} {} {} {}\n", indent_str, ARCHITECTURE, self.name, OF,
self.entity.get_name(), IS ) );
source.push_str( & self.declarations.to_source_code( indent + 1 ) );
source.push_str( & format!( "{}{}\n", indent_str, BEGIN ) );
for ( _name, instance ) in & self.instances {
source.push_str( & instance.to_source_code( indent + 1 ) );
}
for statement in & self.statements {
source.push_str( & statement.to_source_code( indent + 1 ) );
}
source.push_str( & format!( "{}{} {} {};\n", indent_str, END, ARCHITECTURE, self.name ) );
return source;
}
}
impl DesignUnit for Architecture {
}
#[cfg(test)]
mod tests {
use super::*;
const NAME : &'static str = "rtl";
const ENTITY : &'static str = "test";
const ENTITY_TEST : &'static str = "entity test is\nbegin\nend entity test;\n\n";
const HEADER : &'static str = "architecture rtl of test is\n";
const BEGIN : &'static str = "begin\n";
const END : &'static str = "end architecture rtl;\n";
const SIGNAL_DECLARATION : &'static str = " signal signal_1 : boolean;\n";
const SIGNAL_ASSIGNMENT : &'static str = " s1: signal_1 <= true;\n";
const CONSTANT_DECLARATION : &'static str = " constant const_1 : integer := 12;\n";
#[test]
fn architecture_frame() {
let architecture = Architecture::new( NAME, & Entity::new( ENTITY ) );
assert_eq!( architecture.to_source_code( 0 ),
format!( "{}{}{}{}", ENTITY_TEST, HEADER, BEGIN, END ) );
}
#[test]
fn architecture_with_signal_declaration() {
let mut architecture = Architecture::new( NAME, & Entity::new( ENTITY ) );
architecture.add_signal_declaration( & SignalDeclaraion::new( "signal_1", "boolean" ) );
assert_eq!( architecture.to_source_code( 0 ),
format!( "{}{}{}{}{}", ENTITY_TEST, HEADER, SIGNAL_DECLARATION, BEGIN, END ) );
}
#[test]
fn architecture_with_signal_declaration_and_assignment() {
let mut architecture = Architecture::new( NAME, & Entity::new( ENTITY ) );
architecture.add_signal_declaration( & SignalDeclaraion::new( "signal_1", "boolean" ) );
architecture.add_signal_assignment( SignalAssignment::new_with_label( "s1", "signal_1", "true" ) );
assert_eq!( architecture.to_source_code( 0 ),
format!( "{}{}{}{}{}{}", ENTITY_TEST, HEADER, SIGNAL_DECLARATION, BEGIN, SIGNAL_ASSIGNMENT, END )
);
}
#[test]
fn architecture_with_constant_declaration_and_assignment() {
let mut architecture = Architecture::new( NAME, & Entity::new( ENTITY ) );
architecture.add_constant_declaration( & ConstantDeclaration::new( "const_1", "integer", "12" ) );
assert_eq!( architecture.to_source_code( 0 ),
format!( "{}{}{}{}{}", ENTITY_TEST, HEADER, CONSTANT_DECLARATION, BEGIN, END ) );
}
#[test]
fn connect_instance_to_instance() {
let mut _architecture = Architecture::new( NAME, & Entity::new( ENTITY ) );
}
}