teroshdl
Version:
Backend for terosHDL IDE
352 lines (325 loc) • 10.4 kB
JavaScript
// Copyright 2020-2021 Teros Technology
//
// Ismael Perez Rojo
// Carlos Alberto Ruiz Naranjo
// Alfredo Saez
//
// This file is part of Colibri.
//
// Colibri is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Colibri is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Colibri. If not, see <https://www.gnu.org/licenses/>.
const General = require('../general/general');
const Codes = require('./codes');
const ParserLib = require('../parser/factory');
const fs = require('fs');
class Verilog_editor {
constructor() { }
get_header(header_file_path) {
if (header_file_path === undefined || header_file_path === '') {
return '';
}
try {
let header_f = fs.readFileSync(header_file_path, 'utf8');
let lines = header_f.split(/\r?\n/g);
let header = '';
for (let i = 0; i < lines.length; i++) {
const element = lines[i];
header += `// ${element}\n`;
}
return header + '\n';
}
catch (e) {
// eslint-disable-next-line no-console
console.log(e);
return '';
}
}
async generate(src, options) {
let header = '';
if (options !== undefined) {
header = this.get_header(options.header_file_path);
}
this.indet_0 = '';
this.indet_1 = '';
this.indet_2 = '';
this.indet_3 = '';
if (options !== undefined && options.indent_char !== undefined) {
let base = options.indent_char;
this.indet_0 = base.repeat(0);
this.indet_1 = base.repeat(1);
this.indet_2 = base.repeat(2);
this.indet_3 = base.repeat(3);
this.indet_4 = base.repeat(4);
}
else {
let base = ' ';
this.indet_0 = base.repeat(0);
this.indet_1 = base.repeat(1);
this.indet_2 = base.repeat(2);
this.indet_3 = base.repeat(3);
this.indet_4 = base.repeat(4);
}
let parser = new ParserLib.ParserFactory;
parser = await parser.getParser(General.LANGUAGES.VERILOG, '');
let structure = await parser.get_all(src, '}{}');
if (structure === undefined) {
return undefined;
}
let vunit = false;
let version = General.VERILOGSTANDARS.VERILOG2001;
if (options !== null) {
vunit = options['type'] === Codes.TYPESTESTBENCH.VUNIT;
version = options['version'];
}
let space = this.indet_1;
let str = header;
if (vunit === true) {
str += this.set_vunit_libraries();
str += '\n';
}
str += this.set_entity(structure['entity']);
str += '\n';
str += this.set_constants(space, structure['generics']);
str += '\n';
str += ' // Ports\n';
str += this.set_signals_tb(space, structure['ports']);
str += '\n';
str += this.set_instance2001(space, structure['entity']['name'], structure['generics'], structure['ports']);
str += '\n';
if (vunit === true) {
str += this.set_vunit_process(space);
str += '\n';
} else {
str += this.set_main(space);
str += '\n';
}
str += this.set_clk_process(space, structure['ports']);
str += '\n';
str += 'endmodule\n';
return str;
}
set_vunit_libraries() {
var str = '';
str += '`include "vunit_defines.svh"\n';
return str;
}
set_libraries(m) {
var str = '';
for (let x = 0; x < m.length; ++x) {
str += `use ${m[x]['name']};\n`;
}
return str;
}
set_entity(m) {
var str = '';
str += `module ${m['name']}_tb;\n`;
return str;
}
set_constants(space, m) {
var str = '';
str += `${space}// Parameters\n`;
for (let x = 0; x < m.length; ++x) {
if (m[x]['default_value'] !== "" || m[x]['default_value'] !== undefined) {
str += `${space}localparam ${m[x]['type']} ${m[x]['name']} = ${m[x]['default_value']};\n`;
}else{
str += `${space}localparam ${m[x]['type']} ${m[x]['name']} = 1;\n`;
}
}
return str;
}
set_signals_tb(space, m) {
var str = '';
for (let x = 0; x < m.length; ++x) {
if (m[x]['type'] === '') {
if (m[x]['direction'] === "input") {
str += `${space}reg ${m[x]['name']} = 0;\n`;
} else {
str += `${space}wire ${m[x]['name']};\n`;
}
}
else {
const regex = /\[(.*?)\]/;
let type = m[x]['type'].match(regex);
if (type === null) {
type = '';
} else {
type = type[0];
}
if (m[x]['direction'] === "input") {
if (type === '') {
str += `${space}reg ${type} ${m[x]['name']} = 0;\n`;
} else {
str += `${space}reg ${type} ${m[x]['name']};\n`;
}
} else {
str += `${space}wire ${type} ${m[x]['name']};\n`;
}
}
}
return str;
}
set_signals(space, m) {
var str = '';
for (let x = 0; x < m.length; ++x) {
if (m[x]['type'] === '') {
str += `${space}reg r_${m[x]['name']};\n`;
}
else {
const regex = /\[(.*?)\]/;
let type = m[x]['type'].match(regex);
if (type === null) {
type = '';
} else {
type = type[0];
}
str += `${space}reg ${type} r_${m[x]['name']};\n`;
}
}
return str;
}
set_instance(space, name, generics, ports) {
var str = '';
//Instance name
str += `${space}${name}\n`;
//Parameters
if (generics.length > 0) {
str += `${this.indet_1}#(\n`;
for (let x = 0; x < generics.length - 1; ++x) {
str += `${this.indet_2}${generics[x]['name']},\n`;
}
str += `${this.indet_2}${generics[generics.length - 1]['name']}\n`;
str += `${this.indet_2})\n`;
}
//Ports
if (ports.length > 0) {
str += `${space} ${name}_dut (\n`;
for (let x = 0; x < ports.length - 1; ++x) {
str += `${this.indet_2}${ports[x]['name']},\n`;
}
str += `${this.indet_2}${ports[ports.length - 1]['name']}\n`;
str += `${this.indet_1});\n`;
}
return str;
}
set_instance2001(space, name, generics, ports) {
var str = '';
//Instance name
str += `${space}${name} \n`;
//Parameters
if (generics.length > 0) {
str += `${space}#(\n`;
for (let x = 0; x < generics.length - 1; ++x) {
str += `${this.indet_2}.${generics[x]['name']}(${generics[x]['name']} ),\n`;
}
str += `${this.indet_2}.${generics[generics.length - 1]['name']} (
${generics[generics.length - 1]['name']} )\n`;
str += `${this.indet_1})\n`;
}
//Ports
if (ports.length > 0) {
str += `${space}${name}_dut (\n`;
for (let x = 0; x < ports.length - 1; ++x) {
str += `${this.indet_2}.${ports[x]['name']} (${ports[x]['name']} ),\n`;
}
str += `${this.indet_2}.${ports[ports.length - 1]['name']} ( ${ports[ports.length - 1]['name']})\n`;
str += `${space});\n`;
}
return str;
}
set_vunit_process(space) {
var str = '';
str += `${space}\`TEST_SUITE begin\n`;
str += `${this.indet_2}// It is possible to create a basic test bench without any test cases\n`;
str += `${this.indet_2}$display("Hello world");\n`;
str += `${space}end\n`;
return str;
}
set_main(space) {
var str = '';
str += `${space}initial begin\n`;
str += `${this.indet_2}begin\n`;
str += `${this.indet_3}$finish;\n`;
str += `${this.indet_2}end\n`;
str += `${space}end\n`;
return str;
}
set_clk_process(space, ports) {
var str = '';
for (let x = 0; x < ports.length; ++x) {
let is_clk = (ports[x]["direction"] === "input") &&
(ports[x]["name"].includes("clk") || ports[x]["name"].includes("clock"));
if (is_clk === true) {
str += `${space}always\n`;
str += `${this.indet_2}#5 ${ports[x]["name"]} = ! ${ports[x]["name"]} ;\n`;
}
}
return str;
}
}
class Verilog_component extends Verilog_editor {
async generate(src, options) {
this.indet_0 = '';
this.indet_1 = '';
this.indet_2 = '';
this.indet_3 = '';
if (options !== undefined && options.indent_char !== undefined) {
let base = options.indent_char;
this.indet_0 = base.repeat(0);
this.indet_1 = base.repeat(1);
this.indet_2 = base.repeat(2);
this.indet_3 = base.repeat(3);
this.indet_4 = base.repeat(4);
}
else {
let base = ' ';
this.indet_0 = base.repeat(0);
this.indet_1 = base.repeat(1);
this.indet_2 = base.repeat(2);
this.indet_3 = base.repeat(3);
this.indet_4 = base.repeat(4);
}
let parser = new ParserLib.ParserFactory;
let lang;
if (options['type'] === Codes.TYPESCOMPONENTS.MIX_COMPONENT ||
options['type'] === Codes.TYPESCOMPONENTS.MIX_INSTANCE) {
lang = General.LANGUAGES.VHDL;
}else{
lang = General.LANGUAGES.VERILOG;
}
parser = await parser.getParser(lang, '');
let structure = await parser.get_all(src, '}{}');
if (structure === undefined) {
return undefined;
}
if (options === null) { return ""; }
var component = "";
if (options['type'] === Codes.TYPESCOMPONENTS.COMPONENT ||
options['type'] === Codes.TYPESCOMPONENTS.MIX_COMPONENT) {
component = "";
} else if (options['type'] === Codes.TYPESCOMPONENTS.INSTANCE ||
options['type'] === Codes.TYPESCOMPONENTS.MIX_INSTANCE) {
component = this.set_instance2001(this.indet_1, structure['entity']['name'],
structure['generics'], structure['ports'], false);
} else if (options['type'] === Codes.TYPESCOMPONENTS.SIGNALS) {
component = this.set_signals(this.indet_1, structure['ports']);
}
return component;
}
}
//*****************************************************************************/
//***************************** Exports ***************************************/
//*****************************************************************************/
module.exports = {
Verilog_editor: Verilog_editor,
Verilog_component: Verilog_component
};