OpenCores
URL https://opencores.org/ocsvn/lxp32/lxp32/trunk

Subversion Repositories lxp32

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /lxp32/trunk/tools/src/wigen
    from Rev 2 to Rev 9
    Reverse comparison

Rev 2 → Rev 9

/CMakeLists.txt
1,7 → 1,7
cmake_minimum_required(VERSION 3.3.0)
 
add_executable(wigen generator.cpp main.cpp range.cpp)
 
# Install
 
install(TARGETS wigen DESTINATION .)
cmake_minimum_required(VERSION 3.3.0)
 
add_executable(wigen generator.cpp main.cpp range.cpp)
 
# Install
 
install(TARGETS wigen DESTINATION .)
/generator.cpp
1,625 → 1,625
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module implements members of the Generator class.
*/
 
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include "generator.h"
 
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <cctype>
#include <ctime>
 
Generator::Generator():
_masters(1),
_slaves(1),
_addrWidth(32),
_portSize(32),
_portGranularity(32),
_entityName("intercon"),
_pipelinedArbiter(false),
_registeredFeedback(false),
_unsafeDecoder(false) {}
 
void Generator::setMasters(int i) {
if(i<1) throw std::runtime_error("Invalid number of masters");
_masters=i;
}
 
void Generator::setSlaves(int i) {
if(i<1) throw std::runtime_error("Invalid number of slaves");
_slaves=i;
}
 
void Generator::setAddrWidth(int i) {
if(i<1) throw std::runtime_error("Invalid address width");
_addrWidth=i;
}
 
void Generator::setSlaveAddrWidth(int i) {
if(i<1) throw std::runtime_error("Invalid slave address width");
_slaveAddrWidth=i;
}
 
void Generator::setPortSize(int i) {
if(i!=8&&i!=16&&i!=32&&i!=64)
throw std::runtime_error("Invalid port size: 8, 16, 32 or 64 expected");
_portSize=i;
}
 
void Generator::setPortGranularity(int i) {
if(i!=8&&i!=16&&i!=32&&i!=64)
throw std::runtime_error("Invalid port granularity: 8, 16, 32 or 64 expected");
_portGranularity=i;
}
 
void Generator::setEntityName(const std::string &str) try {
if(str.empty()) throw std::exception();
// First character must be a letter
if(!std::isalpha(str[0])) throw std::exception();
// Subsequent characters can be letters, digits or underscores
for(std::size_t i=1;i<str.size();i++)
if(!std::isalnum(str[i])&&str[i]!='_') throw std::exception();
_entityName=str;
}
catch(std::exception &) {
throw std::runtime_error("Invalid entity name");
}
 
void Generator::setPipelinedArbiter(bool b) {
_pipelinedArbiter=b;
}
 
void Generator::setRegisteredFeedback(bool b) {
_registeredFeedback=b;
}
 
void Generator::setUnsafeDecoder(bool b) {
_unsafeDecoder=b;
}
 
int Generator::masters() const {
return _masters;
}
 
int Generator::slaves() const {
return _slaves;
}
 
int Generator::addrWidth() const {
return _addrWidth;
}
 
int Generator::slaveAddrWidth() const {
return _slaveAddrWidth;
}
 
int Generator::portSize() const {
return _portSize;
}
 
int Generator::portGranularity() const {
return _portGranularity;
}
 
std::string Generator::entityName() const {
return _entityName;
}
 
bool Generator::pipelinedArbiter() const {
return _pipelinedArbiter;
}
 
bool Generator::registeredFeedback() const {
return _registeredFeedback;
}
 
bool Generator::unsafeDecoder() const {
return _unsafeDecoder;
}
 
void Generator::generate(const std::string &filename) {
prepare();
std::ofstream out(filename,std::ios_base::out);
if(!out) throw std::runtime_error("Cannot open \""+filename+"\"");
writeBanner(out);
writePreamble(out);
writeEntity(out);
writeArchitecture(out);
}
 
/*
* Private members
*/
 
void Generator::prepare() {
_fallbackSlave=false;
if(slaves()<(1<<(addrWidth()-slaveAddrWidth()))&&!unsafeDecoder())
_fallbackSlave=true;
_mastersRange.assign(masters()-1,0);
if(_fallbackSlave) _slavesRange.assign(slaves(),0);
else _slavesRange.assign(slaves()-1,0);
int q=portSize()/portGranularity();
switch(q) {
case 1:
_addrRange.assign(addrWidth()-1,0);
break;
case 2:
if(addrWidth()<=1) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,1);
_selRange.assign(1,0);
break;
case 4:
if(addrWidth()<=2) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,2);
_selRange.assign(3,0);
break;
case 8:
if(addrWidth()<=3) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,3);
_selRange.assign(7,0);
break;
default:
throw std::runtime_error("Invalid port size/granularity combination");
}
if(slaveAddrWidth()>addrWidth()) throw std::runtime_error("Invalid slave address width");
if(slaves()>(1<<(addrWidth()-slaveAddrWidth()))) throw std::runtime_error("Invalid slave address width");
if(slaveAddrWidth()<=_addrRange.low()) throw std::runtime_error("Invalid slave address width");
_slaveAddrRange.assign(slaveAddrWidth()-1,_addrRange.low());
if(slaves()>1) {
_slaveDecoderRange.assign(_addrRange.high(),slaveAddrWidth());
if(unsafeDecoder()) {
int requiredSize=0;
while((1<<requiredSize)<slaves()) requiredSize++;
_slaveDecoderRange.assign(_slaveDecoderRange.low()+requiredSize-1,
_slaveDecoderRange.low());
}
}
_dataRange.assign(portSize()-1,0);
}
 
void Generator::writeBanner(std::ostream &os) {
auto t=std::time(NULL);
char szTime[256];
auto r=std::strftime(szTime,256,"%c",std::localtime(&t));
if(r==0) szTime[0]='\0';
os<<"---------------------------------------------------------------------"<<std::endl;
os<<"-- Simple WISHBONE interconnect"<<std::endl;
os<<"--"<<std::endl;
os<<"-- Generated by wigen at "<<szTime<<std::endl;
os<<"--"<<std::endl;
os<<"-- Configuration:"<<std::endl;
os<<"-- Number of masters: "<<masters()<<std::endl;
os<<"-- Number of slaves: "<<slaves()<<std::endl;
os<<"-- Master address width: "<<addrWidth()<<std::endl;
os<<"-- Slave address width: "<<slaveAddrWidth()<<std::endl;
os<<"-- Port size: "<<portSize()<<std::endl;
os<<"-- Port granularity: "<<portGranularity()<<std::endl;
os<<"-- Entity name: "<<entityName()<<std::endl;
os<<"-- Pipelined arbiter: "<<(pipelinedArbiter()?"yes":"no")<<std::endl;
os<<"-- Registered feedback: "<<(registeredFeedback()?"yes":"no")<<std::endl;
os<<"-- Unsafe slave decoder: "<<(unsafeDecoder()?"yes":"no")<<std::endl;
os<<"--"<<std::endl;
os<<"-- Command line:"<<std::endl;
os<<"-- wigen -e "<<entityName();
if(pipelinedArbiter()) os<<" -p";
if(registeredFeedback()) os<<" -r";
if(unsafeDecoder()) os<<" -u";
os<<" "<<masters()<<" "<<slaves()<<" "<<addrWidth()<<" "<<slaveAddrWidth();
os<<" "<<portSize()<<" "<<portGranularity()<<std::endl;
os<<"---------------------------------------------------------------------"<<std::endl;
os<<std::endl;
}
 
void Generator::writePreamble(std::ostream &os) {
os<<"library ieee;"<<std::endl;
os<<"use ieee.std_logic_1164.all;"<<std::endl;
os<<std::endl;
}
 
void Generator::writeEntity(std::ostream &os) {
os<<"entity "<<entityName()<<" is"<<std::endl;
os<<"\tport("<<std::endl;
os<<"\t\tclk_i: in std_logic;"<<std::endl;
os<<"\t\trst_i: in std_logic;"<<std::endl;
os<<std::endl;
for(int i=0;i<masters();i++) {
os<<"\t\ts"<<i<<"_cyc_i: in std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_stb_i: in std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_we_i: in std_logic;"<<std::endl;
if(_selRange.valid())
os<<"\t\ts"<<i<<"_sel_i: in std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"\t\ts"<<i<<"_cti_i: in std_logic_vector(2 downto 0);"<<std::endl;
os<<"\t\ts"<<i<<"_bte_i: in std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"\t\ts"<<i<<"_ack_o: out std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_adr_i: in std_logic_vector("<<_addrRange.toString()<<");"<<std::endl;
os<<"\t\ts"<<i<<"_dat_i: in std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<"\t\ts"<<i<<"_dat_o: out std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
}
for(int i=0;i<slaves();i++) {
os<<"\t\tm"<<i<<"_cyc_o: out std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_stb_o: out std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_we_o: out std_logic;"<<std::endl;
if(_selRange.valid())
os<<"\t\tm"<<i<<"_sel_o: out std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"\t\tm"<<i<<"_cti_o: out std_logic_vector(2 downto 0);"<<std::endl;
os<<"\t\tm"<<i<<"_bte_o: out std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"\t\tm"<<i<<"_ack_i: in std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_adr_o: out std_logic_vector("<<_slaveAddrRange.toString()<<");"<<std::endl;
os<<"\t\tm"<<i<<"_dat_o: out std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<"\t\tm"<<i<<"_dat_i: in std_logic_vector("<<_dataRange.toString()<<")";
if(i!=slaves()-1) os<<";"<<std::endl<<std::endl;
else os<<std::endl;
}
os<<"\t);"<<std::endl;
os<<"end entity;"<<std::endl;
os<<std::endl;
}
 
void Generator::writeArchitecture(std::ostream &os) {
os<<"architecture rtl of "<<entityName()<<" is"<<std::endl;
os<<std::endl;
if(masters()>1) {
os<<"signal request: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
os<<"signal grant_next: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
os<<"signal grant: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
if(!pipelinedArbiter()) {
os<<"signal grant_reg: std_logic_vector("<<
_mastersRange.toString()<<"):=(others=>\'0\');"<<std::endl;
}
os<<std::endl;
}
if(slaves()>1) {
os<<"signal select_slave: std_logic_vector("<<
_slavesRange.toString()<<");"<<std::endl;
os<<std::endl;
}
os<<"signal cyc_mux: std_logic;"<<std::endl;
os<<"signal stb_mux: std_logic;"<<std::endl;
os<<"signal we_mux: std_logic;"<<std::endl;
if(_selRange.valid())
os<<"signal sel_mux: std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"signal cti_mux: std_logic_vector(2 downto 0);"<<std::endl;
os<<"signal bte_mux: std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"signal adr_mux: std_logic_vector("<<_addrRange.toString()<<");"<<std::endl;
os<<"signal wdata_mux: std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
os<<"signal ack_mux: std_logic;"<<std::endl;
os<<"signal rdata_mux: std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
os<<"begin"<<std::endl;
os<<std::endl;
if(masters()>1) writeArbiter(os);
writeMasterMux(os);
writeMasterDemux(os);
writeSlaveMux(os);
writeSlaveDemux(os);
os<<"end architecture;"<<std::endl;
}
 
void Generator::writeArbiter(std::ostream &os) {
os<<"-- ARBITER"<<std::endl;
os<<"-- Selects the active master. Masters with lower port numbers"<<std::endl;
os<<"-- have higher priority. Ongoing cycles are not interrupted."<<std::endl;
os<<std::endl;
os<<"request<=";
for(int i=_mastersRange.high();i>=_mastersRange.low();i--) {
os<<"s"<<i<<"_cyc_i";
if(i>0) os<<'&';
}
os<<';'<<std::endl<<std::endl;
os<<"grant_next<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<decodedLiteral(i,masters());
os<<" when request("<<i<<")=\'1\' else"<<std::endl;
}
os<<"\t(others=>\'0\');"<<std::endl;
os<<std::endl;
if(!pipelinedArbiter()) {
os<<"grant<=grant_reg when (request and grant_reg)/=";
os<<binaryLiteral(0,masters());
os<<" else grant_next;"<<std::endl;
os<<std::endl;
os<<"process (clk_i) is"<<std::endl;
os<<"begin"<<std::endl;
os<<"\tif rising_edge(clk_i) then"<<std::endl;
os<<"\t\tif rst_i=\'1\' then"<<std::endl;
os<<"\t\t\tgrant_reg<=(others=>\'0\');"<<std::endl;
os<<"\t\telse"<<std::endl;
os<<"\t\t\tgrant_reg<=grant;"<<std::endl;
os<<"\t\tend if;"<<std::endl;
os<<"\tend if;"<<std::endl;
os<<"end process;"<<std::endl;
os<<std::endl;
}
else {
os<<"process (clk_i) is"<<std::endl;
os<<"begin"<<std::endl;
os<<"\tif rising_edge(clk_i) then"<<std::endl;
os<<"\t\tif rst_i=\'1\' then"<<std::endl;
os<<"\t\t\tgrant<=(others=>\'0\');"<<std::endl;
os<<"\t\telsif (request and grant)="<<binaryLiteral(0,masters())<<" then"<<std::endl;
os<<"\t\t\tgrant<=grant_next;"<<std::endl;
os<<"\t\tend if;"<<std::endl;
os<<"\tend if;"<<std::endl;
os<<"end process;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeMasterMux(std::ostream &os) {
os<<"-- MASTER->SLAVE MUX"<<std::endl;
os<<std::endl;
if(masters()>1) {
os<<"cyc_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_cyc_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
os<<"stb_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_stb_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
os<<"we_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_we_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
if(_selRange.valid()) {
os<<"sel_mux_gen: for i in sel_mux'range generate"<<std::endl;
os<<"\tsel_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_sel_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
if(registeredFeedback()) {
os<<"cti_mux_gen: for i in cti_mux'range generate"<<std::endl;
os<<"\tcti_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_cti_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
os<<"bte_mux_gen: for i in bte_mux'range generate"<<std::endl;
os<<"\tbte_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_bte_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
os<<"adr_mux_gen: for i in adr_mux'range generate"<<std::endl;
os<<"\tadr_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_adr_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
os<<"wdata_mux_gen: for i in wdata_mux'range generate"<<std::endl;
os<<"\twdata_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_dat_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
else { // just one master
os<<"cyc_mux<=s0_cyc_i;"<<std::endl;
os<<"stb_mux<=s0_stb_i;"<<std::endl;
os<<"we_mux<=s0_we_i;"<<std::endl;
if(_selRange.valid()) os<<"sel_mux<=s0_sel_i;"<<std::endl;
if(registeredFeedback()) {
os<<"cti_mux<=s0_cti_i;"<<std::endl;
os<<"bte_mux<=s0_bte_i;"<<std::endl;
}
os<<"adr_mux<=s0_adr_i;"<<std::endl;
os<<"wdata_mux<=s0_dat_i;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeMasterDemux(std::ostream &os) {
os<<"-- MASTER->SLAVE DEMUX"<<std::endl;
os<<std::endl;
if(slaves()>1) {
os<<"select_slave<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<'\t';
os<<decodedLiteral(i,_slavesRange.length());
os<<" when adr_mux("<<_slaveDecoderRange.toString()<<")=";
os<<binaryLiteral(i,_slaveDecoderRange.length())<<" else"<<std::endl;
}
if(_fallbackSlave) {
os<<'\t'<<decodedLiteral(slaves(),_slavesRange.length())<<
"; -- fallback slave"<<std::endl;
}
else os<<"\t(others=>'-');"<<std::endl;
os<<std::endl;
for(int i=0;i<slaves();i++) {
os<<'m'<<i<<"_cyc_o<=cyc_mux and select_slave("<<i<<");"<<std::endl;
os<<'m'<<i<<"_stb_o<=stb_mux and select_slave("<<i<<");"<<std::endl;
os<<'m'<<i<<"_we_o<=we_mux;"<<std::endl;
if(_selRange.valid()) os<<'m'<<i<<"_sel_o<=sel_mux;"<<std::endl;
if(registeredFeedback()) {
os<<'m'<<i<<"_cti_o<=cti_mux;"<<std::endl;
os<<'m'<<i<<"_bte_o<=bte_mux;"<<std::endl;
}
os<<'m'<<i<<"_adr_o<=adr_mux(m"<<i<<"_adr_o'range);"<<std::endl;
os<<'m'<<i<<"_dat_o<=wdata_mux;"<<std::endl;
os<<std::endl;
}
}
else { // just one slave
os<<"m0_cyc_o<=cyc_mux;"<<std::endl;
os<<"m0_stb_o<=stb_mux;"<<std::endl;
os<<"m0_we_o<=we_mux;"<<std::endl;
if(_selRange.valid()) os<<"m0_sel_o<=sel_mux;"<<std::endl;
if(registeredFeedback()) {
os<<"m0_cti_o<=cti_mux;"<<std::endl;
os<<"m0_bte_o<=bte_mux;"<<std::endl;
}
os<<"m0_adr_o<=adr_mux(m0_adr_o'range);"<<std::endl;
os<<"m0_dat_o<=wdata_mux;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeSlaveMux(std::ostream &os) {
os<<"-- SLAVE->MASTER MUX"<<std::endl;
os<<std::endl;
if(slaves()>1) {
os<<"ack_mux<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<'\t';
os<<"(m"<<i<<"_ack_i and select_slave("<<i<<"))";
if(i<slaves()-1||_fallbackSlave) os<<" or"<<std::endl;
else os<<';'<<std::endl;
}
if(_fallbackSlave) {
os<<"\t(cyc_mux and stb_mux and select_slave("<<slaves()<<
")); -- fallback slave"<<std::endl;
}
os<<std::endl;
os<<"rdata_mux_gen: for i in rdata_mux'range generate"<<std::endl;
os<<"\trdata_mux(i)<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<"\t\t";
os<<"(m"<<i<<"_dat_i(i) and select_slave("<<i<<"))";
if(i<slaves()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
else { // just one slave
os<<"ack_mux<=m0_ack_i;"<<std::endl;
os<<"rdata_mux<=m0_dat_i;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeSlaveDemux(std::ostream &os) {
os<<"-- SLAVE->MASTER DEMUX"<<std::endl;
os<<std::endl;
if(masters()>1) {
for(int i=0;i<masters();i++) {
os<<'s'<<i<<"_ack_o<=ack_mux and grant("<<i<<");"<<std::endl;
os<<'s'<<i<<"_dat_o<=rdata_mux;"<<std::endl;
os<<std::endl;
}
}
else { // just one master
os<<"s0_ack_o<=ack_mux;"<<std::endl;
os<<"s0_dat_o<=rdata_mux;"<<std::endl;
os<<std::endl;
}
}
 
std::string Generator::binaryLiteral(int value,int n) {
std::ostringstream oss;
oss.put('\"');
for(int i=n-1;i>=0;i--) {
if(value>=static_cast<int>(sizeof(int)*8)) oss.put('0');
else if((value>>i)&1) oss.put('1');
else oss.put('0');
}
oss.put('\"');
return oss.str();
}
 
std::string Generator::decodedLiteral(int value,int n) {
std::ostringstream oss;
oss.put('\"');
for(int i=n-1;i>=0;i--) {
if(value==i) oss.put('1');
else oss.put('0');
}
oss.put('\"');
return oss.str();
}
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module implements members of the Generator class.
*/
 
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
 
#include "generator.h"
 
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <cctype>
#include <ctime>
 
Generator::Generator():
_masters(1),
_slaves(1),
_addrWidth(32),
_portSize(32),
_portGranularity(32),
_entityName("intercon"),
_pipelinedArbiter(false),
_registeredFeedback(false),
_unsafeDecoder(false) {}
 
void Generator::setMasters(int i) {
if(i<1) throw std::runtime_error("Invalid number of masters");
_masters=i;
}
 
void Generator::setSlaves(int i) {
if(i<1) throw std::runtime_error("Invalid number of slaves");
_slaves=i;
}
 
void Generator::setAddrWidth(int i) {
if(i<1) throw std::runtime_error("Invalid address width");
_addrWidth=i;
}
 
void Generator::setSlaveAddrWidth(int i) {
if(i<1) throw std::runtime_error("Invalid slave address width");
_slaveAddrWidth=i;
}
 
void Generator::setPortSize(int i) {
if(i!=8&&i!=16&&i!=32&&i!=64)
throw std::runtime_error("Invalid port size: 8, 16, 32 or 64 expected");
_portSize=i;
}
 
void Generator::setPortGranularity(int i) {
if(i!=8&&i!=16&&i!=32&&i!=64)
throw std::runtime_error("Invalid port granularity: 8, 16, 32 or 64 expected");
_portGranularity=i;
}
 
void Generator::setEntityName(const std::string &str) try {
if(str.empty()) throw std::exception();
// First character must be a letter
if(!std::isalpha(str[0])) throw std::exception();
// Subsequent characters can be letters, digits or underscores
for(std::size_t i=1;i<str.size();i++)
if(!std::isalnum(str[i])&&str[i]!='_') throw std::exception();
_entityName=str;
}
catch(std::exception &) {
throw std::runtime_error("Invalid entity name");
}
 
void Generator::setPipelinedArbiter(bool b) {
_pipelinedArbiter=b;
}
 
void Generator::setRegisteredFeedback(bool b) {
_registeredFeedback=b;
}
 
void Generator::setUnsafeDecoder(bool b) {
_unsafeDecoder=b;
}
 
int Generator::masters() const {
return _masters;
}
 
int Generator::slaves() const {
return _slaves;
}
 
int Generator::addrWidth() const {
return _addrWidth;
}
 
int Generator::slaveAddrWidth() const {
return _slaveAddrWidth;
}
 
int Generator::portSize() const {
return _portSize;
}
 
int Generator::portGranularity() const {
return _portGranularity;
}
 
std::string Generator::entityName() const {
return _entityName;
}
 
bool Generator::pipelinedArbiter() const {
return _pipelinedArbiter;
}
 
bool Generator::registeredFeedback() const {
return _registeredFeedback;
}
 
bool Generator::unsafeDecoder() const {
return _unsafeDecoder;
}
 
void Generator::generate(const std::string &filename) {
prepare();
std::ofstream out(filename,std::ios_base::out);
if(!out) throw std::runtime_error("Cannot open \""+filename+"\"");
writeBanner(out);
writePreamble(out);
writeEntity(out);
writeArchitecture(out);
}
 
/*
* Private members
*/
 
void Generator::prepare() {
_fallbackSlave=false;
if(slaves()<(1<<(addrWidth()-slaveAddrWidth()))&&!unsafeDecoder())
_fallbackSlave=true;
_mastersRange.assign(masters()-1,0);
if(_fallbackSlave) _slavesRange.assign(slaves(),0);
else _slavesRange.assign(slaves()-1,0);
int q=portSize()/portGranularity();
switch(q) {
case 1:
_addrRange.assign(addrWidth()-1,0);
break;
case 2:
if(addrWidth()<=1) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,1);
_selRange.assign(1,0);
break;
case 4:
if(addrWidth()<=2) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,2);
_selRange.assign(3,0);
break;
case 8:
if(addrWidth()<=3) throw std::runtime_error("Invalid master address width");
_addrRange.assign(addrWidth()-1,3);
_selRange.assign(7,0);
break;
default:
throw std::runtime_error("Invalid port size/granularity combination");
}
if(slaveAddrWidth()>addrWidth()) throw std::runtime_error("Invalid slave address width");
if(slaves()>(1<<(addrWidth()-slaveAddrWidth()))) throw std::runtime_error("Invalid slave address width");
if(slaveAddrWidth()<=_addrRange.low()) throw std::runtime_error("Invalid slave address width");
_slaveAddrRange.assign(slaveAddrWidth()-1,_addrRange.low());
if(slaves()>1) {
_slaveDecoderRange.assign(_addrRange.high(),slaveAddrWidth());
if(unsafeDecoder()) {
int requiredSize=0;
while((1<<requiredSize)<slaves()) requiredSize++;
_slaveDecoderRange.assign(_slaveDecoderRange.low()+requiredSize-1,
_slaveDecoderRange.low());
}
}
_dataRange.assign(portSize()-1,0);
}
 
void Generator::writeBanner(std::ostream &os) {
auto t=std::time(NULL);
char szTime[256];
auto r=std::strftime(szTime,256,"%c",std::localtime(&t));
if(r==0) szTime[0]='\0';
os<<"---------------------------------------------------------------------"<<std::endl;
os<<"-- Simple WISHBONE interconnect"<<std::endl;
os<<"--"<<std::endl;
os<<"-- Generated by wigen at "<<szTime<<std::endl;
os<<"--"<<std::endl;
os<<"-- Configuration:"<<std::endl;
os<<"-- Number of masters: "<<masters()<<std::endl;
os<<"-- Number of slaves: "<<slaves()<<std::endl;
os<<"-- Master address width: "<<addrWidth()<<std::endl;
os<<"-- Slave address width: "<<slaveAddrWidth()<<std::endl;
os<<"-- Port size: "<<portSize()<<std::endl;
os<<"-- Port granularity: "<<portGranularity()<<std::endl;
os<<"-- Entity name: "<<entityName()<<std::endl;
os<<"-- Pipelined arbiter: "<<(pipelinedArbiter()?"yes":"no")<<std::endl;
os<<"-- Registered feedback: "<<(registeredFeedback()?"yes":"no")<<std::endl;
os<<"-- Unsafe slave decoder: "<<(unsafeDecoder()?"yes":"no")<<std::endl;
os<<"--"<<std::endl;
os<<"-- Command line:"<<std::endl;
os<<"-- wigen -e "<<entityName();
if(pipelinedArbiter()) os<<" -p";
if(registeredFeedback()) os<<" -r";
if(unsafeDecoder()) os<<" -u";
os<<" "<<masters()<<" "<<slaves()<<" "<<addrWidth()<<" "<<slaveAddrWidth();
os<<" "<<portSize()<<" "<<portGranularity()<<std::endl;
os<<"---------------------------------------------------------------------"<<std::endl;
os<<std::endl;
}
 
void Generator::writePreamble(std::ostream &os) {
os<<"library ieee;"<<std::endl;
os<<"use ieee.std_logic_1164.all;"<<std::endl;
os<<std::endl;
}
 
void Generator::writeEntity(std::ostream &os) {
os<<"entity "<<entityName()<<" is"<<std::endl;
os<<"\tport("<<std::endl;
os<<"\t\tclk_i: in std_logic;"<<std::endl;
os<<"\t\trst_i: in std_logic;"<<std::endl;
os<<std::endl;
for(int i=0;i<masters();i++) {
os<<"\t\ts"<<i<<"_cyc_i: in std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_stb_i: in std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_we_i: in std_logic;"<<std::endl;
if(_selRange.valid())
os<<"\t\ts"<<i<<"_sel_i: in std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"\t\ts"<<i<<"_cti_i: in std_logic_vector(2 downto 0);"<<std::endl;
os<<"\t\ts"<<i<<"_bte_i: in std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"\t\ts"<<i<<"_ack_o: out std_logic;"<<std::endl;
os<<"\t\ts"<<i<<"_adr_i: in std_logic_vector("<<_addrRange.toString()<<");"<<std::endl;
os<<"\t\ts"<<i<<"_dat_i: in std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<"\t\ts"<<i<<"_dat_o: out std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
}
for(int i=0;i<slaves();i++) {
os<<"\t\tm"<<i<<"_cyc_o: out std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_stb_o: out std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_we_o: out std_logic;"<<std::endl;
if(_selRange.valid())
os<<"\t\tm"<<i<<"_sel_o: out std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"\t\tm"<<i<<"_cti_o: out std_logic_vector(2 downto 0);"<<std::endl;
os<<"\t\tm"<<i<<"_bte_o: out std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"\t\tm"<<i<<"_ack_i: in std_logic;"<<std::endl;
os<<"\t\tm"<<i<<"_adr_o: out std_logic_vector("<<_slaveAddrRange.toString()<<");"<<std::endl;
os<<"\t\tm"<<i<<"_dat_o: out std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<"\t\tm"<<i<<"_dat_i: in std_logic_vector("<<_dataRange.toString()<<")";
if(i!=slaves()-1) os<<";"<<std::endl<<std::endl;
else os<<std::endl;
}
os<<"\t);"<<std::endl;
os<<"end entity;"<<std::endl;
os<<std::endl;
}
 
void Generator::writeArchitecture(std::ostream &os) {
os<<"architecture rtl of "<<entityName()<<" is"<<std::endl;
os<<std::endl;
if(masters()>1) {
os<<"signal request: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
os<<"signal grant_next: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
os<<"signal grant: std_logic_vector("<<
_mastersRange.toString()<<");"<<std::endl;
if(!pipelinedArbiter()) {
os<<"signal grant_reg: std_logic_vector("<<
_mastersRange.toString()<<"):=(others=>\'0\');"<<std::endl;
}
os<<std::endl;
}
if(slaves()>1) {
os<<"signal select_slave: std_logic_vector("<<
_slavesRange.toString()<<");"<<std::endl;
os<<std::endl;
}
os<<"signal cyc_mux: std_logic;"<<std::endl;
os<<"signal stb_mux: std_logic;"<<std::endl;
os<<"signal we_mux: std_logic;"<<std::endl;
if(_selRange.valid())
os<<"signal sel_mux: std_logic_vector("<<_selRange.toString()<<");"<<std::endl;
if(registeredFeedback()) {
os<<"signal cti_mux: std_logic_vector(2 downto 0);"<<std::endl;
os<<"signal bte_mux: std_logic_vector(1 downto 0);"<<std::endl;
}
os<<"signal adr_mux: std_logic_vector("<<_addrRange.toString()<<");"<<std::endl;
os<<"signal wdata_mux: std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
os<<"signal ack_mux: std_logic;"<<std::endl;
os<<"signal rdata_mux: std_logic_vector("<<_dataRange.toString()<<");"<<std::endl;
os<<std::endl;
os<<"begin"<<std::endl;
os<<std::endl;
if(masters()>1) writeArbiter(os);
writeMasterMux(os);
writeMasterDemux(os);
writeSlaveMux(os);
writeSlaveDemux(os);
os<<"end architecture;"<<std::endl;
}
 
void Generator::writeArbiter(std::ostream &os) {
os<<"-- ARBITER"<<std::endl;
os<<"-- Selects the active master. Masters with lower port numbers"<<std::endl;
os<<"-- have higher priority. Ongoing cycles are not interrupted."<<std::endl;
os<<std::endl;
os<<"request<=";
for(int i=_mastersRange.high();i>=_mastersRange.low();i--) {
os<<"s"<<i<<"_cyc_i";
if(i>0) os<<'&';
}
os<<';'<<std::endl<<std::endl;
os<<"grant_next<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<decodedLiteral(i,masters());
os<<" when request("<<i<<")=\'1\' else"<<std::endl;
}
os<<"\t(others=>\'0\');"<<std::endl;
os<<std::endl;
if(!pipelinedArbiter()) {
os<<"grant<=grant_reg when (request and grant_reg)/=";
os<<binaryLiteral(0,masters());
os<<" else grant_next;"<<std::endl;
os<<std::endl;
os<<"process (clk_i) is"<<std::endl;
os<<"begin"<<std::endl;
os<<"\tif rising_edge(clk_i) then"<<std::endl;
os<<"\t\tif rst_i=\'1\' then"<<std::endl;
os<<"\t\t\tgrant_reg<=(others=>\'0\');"<<std::endl;
os<<"\t\telse"<<std::endl;
os<<"\t\t\tgrant_reg<=grant;"<<std::endl;
os<<"\t\tend if;"<<std::endl;
os<<"\tend if;"<<std::endl;
os<<"end process;"<<std::endl;
os<<std::endl;
}
else {
os<<"process (clk_i) is"<<std::endl;
os<<"begin"<<std::endl;
os<<"\tif rising_edge(clk_i) then"<<std::endl;
os<<"\t\tif rst_i=\'1\' then"<<std::endl;
os<<"\t\t\tgrant<=(others=>\'0\');"<<std::endl;
os<<"\t\telsif (request and grant)="<<binaryLiteral(0,masters())<<" then"<<std::endl;
os<<"\t\t\tgrant<=grant_next;"<<std::endl;
os<<"\t\tend if;"<<std::endl;
os<<"\tend if;"<<std::endl;
os<<"end process;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeMasterMux(std::ostream &os) {
os<<"-- MASTER->SLAVE MUX"<<std::endl;
os<<std::endl;
if(masters()>1) {
os<<"cyc_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_cyc_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
os<<"stb_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_stb_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
os<<"we_mux<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<'\t';
os<<"(s"<<i<<"_we_i and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<std::endl;
if(_selRange.valid()) {
os<<"sel_mux_gen: for i in sel_mux'range generate"<<std::endl;
os<<"\tsel_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_sel_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
if(registeredFeedback()) {
os<<"cti_mux_gen: for i in cti_mux'range generate"<<std::endl;
os<<"\tcti_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_cti_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
os<<"bte_mux_gen: for i in bte_mux'range generate"<<std::endl;
os<<"\tbte_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_bte_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
os<<"adr_mux_gen: for i in adr_mux'range generate"<<std::endl;
os<<"\tadr_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_adr_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
os<<"wdata_mux_gen: for i in wdata_mux'range generate"<<std::endl;
os<<"\twdata_mux(i)<=";
for(int i=0;i<masters();i++) {
if(i>0) os<<"\t\t";
os<<"(s"<<i<<"_dat_i(i) and grant("<<i<<"))";
if(i<masters()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
else { // just one master
os<<"cyc_mux<=s0_cyc_i;"<<std::endl;
os<<"stb_mux<=s0_stb_i;"<<std::endl;
os<<"we_mux<=s0_we_i;"<<std::endl;
if(_selRange.valid()) os<<"sel_mux<=s0_sel_i;"<<std::endl;
if(registeredFeedback()) {
os<<"cti_mux<=s0_cti_i;"<<std::endl;
os<<"bte_mux<=s0_bte_i;"<<std::endl;
}
os<<"adr_mux<=s0_adr_i;"<<std::endl;
os<<"wdata_mux<=s0_dat_i;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeMasterDemux(std::ostream &os) {
os<<"-- MASTER->SLAVE DEMUX"<<std::endl;
os<<std::endl;
if(slaves()>1) {
os<<"select_slave<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<'\t';
os<<decodedLiteral(i,_slavesRange.length());
os<<" when adr_mux("<<_slaveDecoderRange.toString()<<")=";
os<<binaryLiteral(i,_slaveDecoderRange.length())<<" else"<<std::endl;
}
if(_fallbackSlave) {
os<<'\t'<<decodedLiteral(slaves(),_slavesRange.length())<<
"; -- fallback slave"<<std::endl;
}
else os<<"\t(others=>'-');"<<std::endl;
os<<std::endl;
for(int i=0;i<slaves();i++) {
os<<'m'<<i<<"_cyc_o<=cyc_mux and select_slave("<<i<<");"<<std::endl;
os<<'m'<<i<<"_stb_o<=stb_mux and select_slave("<<i<<");"<<std::endl;
os<<'m'<<i<<"_we_o<=we_mux;"<<std::endl;
if(_selRange.valid()) os<<'m'<<i<<"_sel_o<=sel_mux;"<<std::endl;
if(registeredFeedback()) {
os<<'m'<<i<<"_cti_o<=cti_mux;"<<std::endl;
os<<'m'<<i<<"_bte_o<=bte_mux;"<<std::endl;
}
os<<'m'<<i<<"_adr_o<=adr_mux(m"<<i<<"_adr_o'range);"<<std::endl;
os<<'m'<<i<<"_dat_o<=wdata_mux;"<<std::endl;
os<<std::endl;
}
}
else { // just one slave
os<<"m0_cyc_o<=cyc_mux;"<<std::endl;
os<<"m0_stb_o<=stb_mux;"<<std::endl;
os<<"m0_we_o<=we_mux;"<<std::endl;
if(_selRange.valid()) os<<"m0_sel_o<=sel_mux;"<<std::endl;
if(registeredFeedback()) {
os<<"m0_cti_o<=cti_mux;"<<std::endl;
os<<"m0_bte_o<=bte_mux;"<<std::endl;
}
os<<"m0_adr_o<=adr_mux(m0_adr_o'range);"<<std::endl;
os<<"m0_dat_o<=wdata_mux;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeSlaveMux(std::ostream &os) {
os<<"-- SLAVE->MASTER MUX"<<std::endl;
os<<std::endl;
if(slaves()>1) {
os<<"ack_mux<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<'\t';
os<<"(m"<<i<<"_ack_i and select_slave("<<i<<"))";
if(i<slaves()-1||_fallbackSlave) os<<" or"<<std::endl;
else os<<';'<<std::endl;
}
if(_fallbackSlave) {
os<<"\t(cyc_mux and stb_mux and select_slave("<<slaves()<<
")); -- fallback slave"<<std::endl;
}
os<<std::endl;
os<<"rdata_mux_gen: for i in rdata_mux'range generate"<<std::endl;
os<<"\trdata_mux(i)<=";
for(int i=0;i<slaves();i++) {
if(i>0) os<<"\t\t";
os<<"(m"<<i<<"_dat_i(i) and select_slave("<<i<<"))";
if(i<slaves()-1) os<<" or"<<std::endl;
else os<<";"<<std::endl;
}
os<<"end generate;"<<std::endl;
os<<std::endl;
}
else { // just one slave
os<<"ack_mux<=m0_ack_i;"<<std::endl;
os<<"rdata_mux<=m0_dat_i;"<<std::endl;
os<<std::endl;
}
}
 
void Generator::writeSlaveDemux(std::ostream &os) {
os<<"-- SLAVE->MASTER DEMUX"<<std::endl;
os<<std::endl;
if(masters()>1) {
for(int i=0;i<masters();i++) {
os<<'s'<<i<<"_ack_o<=ack_mux and grant("<<i<<");"<<std::endl;
os<<'s'<<i<<"_dat_o<=rdata_mux;"<<std::endl;
os<<std::endl;
}
}
else { // just one master
os<<"s0_ack_o<=ack_mux;"<<std::endl;
os<<"s0_dat_o<=rdata_mux;"<<std::endl;
os<<std::endl;
}
}
 
std::string Generator::binaryLiteral(int value,int n) {
std::ostringstream oss;
oss.put('\"');
for(int i=n-1;i>=0;i--) {
if(value>=static_cast<int>(sizeof(int)*8)) oss.put('0');
else if((value>>i)&1) oss.put('1');
else oss.put('0');
}
oss.put('\"');
return oss.str();
}
 
std::string Generator::decodedLiteral(int value,int n) {
std::ostringstream oss;
oss.put('\"');
for(int i=n-1;i>=0;i--) {
if(value==i) oss.put('1');
else oss.put('0');
}
oss.put('\"');
return oss.str();
}
/generator.h
1,86 → 1,86
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module defines the Generator class which generates
* WISHBONE interconnect VHDL description based on provided
* parameters.
*/
 
#ifndef GENERATOR_H_INCLUDED
#define GENERATOR_H_INCLUDED
 
#include "range.h"
 
#include <iostream>
#include <string>
 
class Generator {
int _masters;
int _slaves;
int _addrWidth;
int _slaveAddrWidth;
int _portSize;
int _portGranularity;
std::string _entityName;
bool _pipelinedArbiter;
bool _registeredFeedback;
bool _unsafeDecoder;
Range _mastersRange;
Range _slavesRange;
Range _addrRange;
Range _slaveAddrRange;
Range _slaveDecoderRange;
Range _dataRange;
Range _selRange;
bool _fallbackSlave;
public:
Generator();
 
void setMasters(int i);
void setSlaves(int i);
void setAddrWidth(int i);
void setSlaveAddrWidth(int i);
void setPortSize(int i);
void setPortGranularity(int i);
void setEntityName(const std::string &str);
void setPipelinedArbiter(bool b);
void setRegisteredFeedback(bool b);
void setUnsafeDecoder(bool b);
int masters() const;
int slaves() const;
int addrWidth() const;
int slaveAddrWidth() const;
int portSize() const;
int portGranularity() const;
std::string entityName() const;
bool pipelinedArbiter() const;
bool registeredFeedback() const;
bool unsafeDecoder() const;
void generate(const std::string &filename);
 
private:
void prepare();
void writeBanner(std::ostream &os);
void writePreamble(std::ostream &os);
void writeEntity(std::ostream &os);
void writeArchitecture(std::ostream &os);
void writeArbiter(std::ostream &os);
void writeMasterMux(std::ostream &os);
void writeMasterDemux(std::ostream &os);
void writeSlaveMux(std::ostream &os);
void writeSlaveDemux(std::ostream &os);
 
static std::string binaryLiteral(int value,int n);
static std::string decodedLiteral(int value,int n);
};
 
#endif
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module defines the Generator class which generates
* WISHBONE interconnect VHDL description based on provided
* parameters.
*/
 
#ifndef GENERATOR_H_INCLUDED
#define GENERATOR_H_INCLUDED
 
#include "range.h"
 
#include <iostream>
#include <string>
 
class Generator {
int _masters;
int _slaves;
int _addrWidth;
int _slaveAddrWidth;
int _portSize;
int _portGranularity;
std::string _entityName;
bool _pipelinedArbiter;
bool _registeredFeedback;
bool _unsafeDecoder;
Range _mastersRange;
Range _slavesRange;
Range _addrRange;
Range _slaveAddrRange;
Range _slaveDecoderRange;
Range _dataRange;
Range _selRange;
bool _fallbackSlave;
public:
Generator();
 
void setMasters(int i);
void setSlaves(int i);
void setAddrWidth(int i);
void setSlaveAddrWidth(int i);
void setPortSize(int i);
void setPortGranularity(int i);
void setEntityName(const std::string &str);
void setPipelinedArbiter(bool b);
void setRegisteredFeedback(bool b);
void setUnsafeDecoder(bool b);
int masters() const;
int slaves() const;
int addrWidth() const;
int slaveAddrWidth() const;
int portSize() const;
int portGranularity() const;
std::string entityName() const;
bool pipelinedArbiter() const;
bool registeredFeedback() const;
bool unsafeDecoder() const;
void generate(const std::string &filename);
 
private:
void prepare();
void writeBanner(std::ostream &os);
void writePreamble(std::ostream &os);
void writeEntity(std::ostream &os);
void writeArchitecture(std::ostream &os);
void writeArbiter(std::ostream &os);
void writeMasterMux(std::ostream &os);
void writeMasterDemux(std::ostream &os);
void writeSlaveMux(std::ostream &os);
void writeSlaveDemux(std::ostream &os);
 
static std::string binaryLiteral(int value,int n);
static std::string decodedLiteral(int value,int n);
};
 
#endif
/main.cpp
1,128 → 1,128
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* Main translation unit for the WISHBONE interconnect generator.
*/
 
#include "generator.h"
 
#include <iostream>
#include <string>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
 
static void displayUsage(std::ostream &os,const char *program) {
os<<std::endl;
os<<"Usage:"<<std::endl;
os<<" "<<program<<" [ option(s) ] <nm> <ns> <ma> <sa> <ps> [ <pg> ]"<<std::endl<<std::endl;
os<<" <nm> Number of masters"<<std::endl;
os<<" <ns> Number of slaves"<<std::endl;
os<<" <ma> Master address width"<<std::endl;
os<<" <sa> Slave address width"<<std::endl;
os<<" <ps> Port size"<<std::endl;
os<<" <pg> Port granularity, default: port size"<<std::endl;
os<<std::endl;
os<<"Options:"<<std::endl;
os<<" -e <entity> Entity name, default: \"intercon\""<<std::endl;
os<<" -h, --help Display a short help message"<<std::endl;
os<<" -o <file> Output file name, default: \"<entity>.vhd\""<<std::endl;
os<<" -p Generate pipelined arbiter"<<std::endl;
os<<" -r Generate registered feedback signals"<<std::endl;
os<<" -u Generate unsafe slave decoder"<<std::endl;
}
 
int main(int argc,char *argv[]) try {
std::cout<<"WISHBONE interconnect generator"<<std::endl;
std::cout<<"Copyright (c) 2016 by Alex I. Kuznetsov"<<std::endl;
if(argc<=1) {
displayUsage(std::cout,argv[0]);
return 0;
}
Generator gen;
std::string outputFileName;
int mainArg=0;
for(int i=1;i<argc;i++) {
if(argv[i][0]=='-') {
if(!strcmp(argv[i],"-e")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
return EXIT_FAILURE;
}
gen.setEntityName(argv[i]);
}
else if(!strcmp(argv[i],"-h")||!strcmp(argv[i],"--help")) {
displayUsage(std::cout,argv[0]);
return 0;
}
else if(!strcmp(argv[i],"-o")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
return EXIT_FAILURE;
}
outputFileName=argv[i];
}
else if(!strcmp(argv[i],"-p")) {
gen.setPipelinedArbiter(true);
}
else if(!strcmp(argv[i],"-r")) {
gen.setRegisteredFeedback(true);
}
else if(!strcmp(argv[i],"-u")) {
gen.setUnsafeDecoder(true);
}
else throw std::runtime_error(std::string("Unrecognized option: \"")+argv[i]+"\"");
}
else {
if(mainArg>5) throw std::runtime_error("Too many arguments");
int value;
try {
value=std::stoi(argv[i],nullptr,0);
}
catch(std::exception &) {
throw std::runtime_error("Invalid value");
}
switch(mainArg) {
case 0:
gen.setMasters(value);
break;
case 1:
gen.setSlaves(value);
break;
case 2:
gen.setAddrWidth(value);
break;
case 3:
gen.setSlaveAddrWidth(value);
break;
case 4:
gen.setPortSize(value);
break;
case 5:
gen.setPortGranularity(value);
break;
}
mainArg++;
}
}
if(mainArg<5) throw std::runtime_error("Too few arguments");
if(mainArg==5) gen.setPortGranularity(gen.portSize());
if(outputFileName.empty()) outputFileName=gen.entityName()+".vhd";
gen.generate(outputFileName);
}
catch(std::exception &ex) {
std::cerr<<"Error: "<<ex.what()<<std::endl;
return EXIT_FAILURE;
}
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* Main translation unit for the WISHBONE interconnect generator.
*/
 
#include "generator.h"
 
#include <iostream>
#include <string>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
 
static void displayUsage(std::ostream &os,const char *program) {
os<<std::endl;
os<<"Usage:"<<std::endl;
os<<" "<<program<<" [ option(s) ] <nm> <ns> <ma> <sa> <ps> [ <pg> ]"<<std::endl<<std::endl;
os<<" <nm> Number of masters"<<std::endl;
os<<" <ns> Number of slaves"<<std::endl;
os<<" <ma> Master address width"<<std::endl;
os<<" <sa> Slave address width"<<std::endl;
os<<" <ps> Port size"<<std::endl;
os<<" <pg> Port granularity, default: port size"<<std::endl;
os<<std::endl;
os<<"Options:"<<std::endl;
os<<" -e <entity> Entity name, default: \"intercon\""<<std::endl;
os<<" -h, --help Display a short help message"<<std::endl;
os<<" -o <file> Output file name, default: \"<entity>.vhd\""<<std::endl;
os<<" -p Generate pipelined arbiter"<<std::endl;
os<<" -r Generate registered feedback signals"<<std::endl;
os<<" -u Generate unsafe slave decoder"<<std::endl;
}
 
int main(int argc,char *argv[]) try {
std::cout<<"WISHBONE interconnect generator"<<std::endl;
std::cout<<"Copyright (c) 2016 by Alex I. Kuznetsov"<<std::endl;
if(argc<=1) {
displayUsage(std::cout,argv[0]);
return 0;
}
Generator gen;
std::string outputFileName;
int mainArg=0;
for(int i=1;i<argc;i++) {
if(argv[i][0]=='-') {
if(!strcmp(argv[i],"-e")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
return EXIT_FAILURE;
}
gen.setEntityName(argv[i]);
}
else if(!strcmp(argv[i],"-h")||!strcmp(argv[i],"--help")) {
displayUsage(std::cout,argv[0]);
return 0;
}
else if(!strcmp(argv[i],"-o")) {
if(++i==argc) {
displayUsage(std::cerr,argv[0]);
return EXIT_FAILURE;
}
outputFileName=argv[i];
}
else if(!strcmp(argv[i],"-p")) {
gen.setPipelinedArbiter(true);
}
else if(!strcmp(argv[i],"-r")) {
gen.setRegisteredFeedback(true);
}
else if(!strcmp(argv[i],"-u")) {
gen.setUnsafeDecoder(true);
}
else throw std::runtime_error(std::string("Unrecognized option: \"")+argv[i]+"\"");
}
else {
if(mainArg>5) throw std::runtime_error("Too many arguments");
int value;
try {
value=std::stoi(argv[i],nullptr,0);
}
catch(std::exception &) {
throw std::runtime_error("Invalid value");
}
switch(mainArg) {
case 0:
gen.setMasters(value);
break;
case 1:
gen.setSlaves(value);
break;
case 2:
gen.setAddrWidth(value);
break;
case 3:
gen.setSlaveAddrWidth(value);
break;
case 4:
gen.setPortSize(value);
break;
case 5:
gen.setPortGranularity(value);
break;
}
mainArg++;
}
}
if(mainArg<5) throw std::runtime_error("Too few arguments");
if(mainArg==5) gen.setPortGranularity(gen.portSize());
if(outputFileName.empty()) outputFileName=gen.entityName()+".vhd";
gen.generate(outputFileName);
}
catch(std::exception &ex) {
std::cerr<<"Error: "<<ex.what()<<std::endl;
return EXIT_FAILURE;
}
/range.cpp
1,52 → 1,52
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module implements members of the Range class.
*/
 
#include "range.h"
 
#include <stdexcept>
 
Range::Range(): _valid(false) {}
 
Range::Range(int h,int l): _high(h),_low(l),_valid(true) {
if(l>h) throw std::runtime_error("Invalid range");
}
 
void Range::assign(int h,int l) {
if(l>h) throw std::runtime_error("Invalid range");
_high=h;
_low=l;
_valid=true;
}
 
void Range::clear() {
_valid=false;
}
 
bool Range::valid() const {
return _valid;
}
 
int Range::high() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _high;
}
 
int Range::low() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _low;
}
 
int Range::length() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _high-_low+1;
}
 
std::string Range::toString() const {
if(!_valid) throw std::runtime_error("Invalid range");
return std::to_string(_high)+" downto "+std::to_string(_low);
}
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module implements members of the Range class.
*/
 
#include "range.h"
 
#include <stdexcept>
 
Range::Range(): _valid(false) {}
 
Range::Range(int h,int l): _high(h),_low(l),_valid(true) {
if(l>h) throw std::runtime_error("Invalid range");
}
 
void Range::assign(int h,int l) {
if(l>h) throw std::runtime_error("Invalid range");
_high=h;
_low=l;
_valid=true;
}
 
void Range::clear() {
_valid=false;
}
 
bool Range::valid() const {
return _valid;
}
 
int Range::high() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _high;
}
 
int Range::low() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _low;
}
 
int Range::length() const {
if(!_valid) throw std::runtime_error("Invalid range");
return _high-_low+1;
}
 
std::string Range::toString() const {
if(!_valid) throw std::runtime_error("Invalid range");
return std::to_string(_high)+" downto "+std::to_string(_low);
}
/range.h
1,33 → 1,33
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module defines the Range class which represents
* VHDL array ranges.
*/
 
#ifndef RANGE_H_INCLUDED
#define RANGE_H_INCLUDED
 
#include <string>
 
class Range {
int _high;
int _low;
bool _valid;
public:
Range();
Range(int h,int l);
void assign(int h,int l);
void clear();
bool valid() const;
int high() const;
int low() const;
int length() const;
std::string toString() const;
};
 
#endif
/*
* Copyright (c) 2016 by Alex I. Kuznetsov.
*
* Part of the LXP32 CPU IP core.
*
* This module defines the Range class which represents
* VHDL array ranges.
*/
 
#ifndef RANGE_H_INCLUDED
#define RANGE_H_INCLUDED
 
#include <string>
 
class Range {
int _high;
int _low;
bool _valid;
public:
Range();
Range(int h,int l);
void assign(int h,int l);
void clear();
bool valid() const;
int high() const;
int low() const;
int length() const;
std::string toString() const;
};
 
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.