UNPKG

teroshdl

Version:

Backend for terosHDL IDE

446 lines (414 loc) 14.8 kB
// 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 Codes = require('./codes'); const ParserLib = require('../parser/factory'); const General = require('../general/general'); const fs = require('fs'); class Vhdl_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.VHDL, ''); parser.init(); let structure = await parser.get_all(src, '}{}'); if (structure === undefined) { return undefined; } let vunit = false; if (options !== null) { vunit = options['type'] === Codes.TYPESTESTBENCH.VUNIT; } let space = this.indet_1; let str = header; str += "library ieee;\nuse ieee.std_logic_1164.all;\nuse ieee.numeric_std.all;\n"; str += '\n'; if (vunit === true) { str += this.set_Vunit_Libraries(); str += '\n'; } if (vunit === true) { str += this.set_Vunit_Entity(structure['entity']); str += '\n'; } else { str += this.set_Entity(structure['entity']); str += '\n'; } str += this.set_Architecture(structure['architecture'], structure['entity']); str += '\n'; if (vunit === false) { str += this.set_Component(space, structure['entity']['name'], structure['generics'], structure['ports']); } str += '\n'; str += this.set_Constants(space, structure['generics']); str += '\n'; str += ' -- Ports\n'; str += this.set_Signals(space, structure['ports']); str += '\n'; str += 'begin\n'; str += '\n'; str += this.set_Instance(space, structure['entity']['name'], structure['generics'], structure['ports'], vunit); str += '\n'; if (vunit === true) { str += this.set_Vunit_Process(space); str += '\n'; } str += this.set_Clk_Process(space); str += '\n'; str += 'end;\n'; return str; } set_Vunit_Libraries() { var str = ''; str += 'library src_lib;\n'; str += '--\n'; str += 'library vunit_lib;\n'; str += 'context vunit_lib.vunit_context;\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 += 'entity ' + m['name'] + '_tb is\n'; str += 'end;\n'; return str; } set_Vunit_Entity(m) { var str = ''; str += 'entity ' + m['name'] + '_tb is\n'; str += this.indet_1 + 'generic (runner_cfg : string);\n'; str += 'end;\n'; return str; } set_Architecture(m, n) { var str = ''; str += 'architecture bench of ' + n['name'] + '_tb is\n'; return str; } set_Constants(space, m) { var str = ''; str += space + '-- Clock period\n'; str += space + 'constant clk_period : time := 5 ns;\n'; str += space + '-- Generics\n'; for (let x = 0; x < m.length; ++x) { var normalized_type = m[x]['type'].replace(/\s/g, '').toLowerCase(); if (m[x]['default_value'] !== "" || m[x]['default_value'] !== undefined) { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + ' := '+ m[x]['default_value'] +';\n'; }else{ if (normalized_type === "integer") { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + ' := 0;\n'; } else if (normalized_type === "signed" || normalized_type === "unsigned") { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + " := (others => '0');\n"; } else if (normalized_type === "string") { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + ' := "";\n'; } else if (normalized_type === "boolean") { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + ' := false;\n'; } else { str += space + 'constant ' + m[x]['name'] + ' : ' + m[x]['type'] + ';\n'; } } } return str; } set_Signals(space, m) { var str = ''; for (let x = 0; x < m.length; ++x) { str += space + 'signal ' + m[x]['name'] + ' : ' + m[x]['type'] + ';\n'; } return str; } set_Component(space, name, generics, ports) { var str = ''; //Component name str += this.indet_1 + 'component ' + name + '\n'; //Generics if (generics.length > 0) { str += this.indet_2 + 'generic (\n'; for (let x = 0; x < generics.length - 1; ++x) { str += this.indet_3 + generics[x]['name'] + ' : ' + generics[x]['type'] + ';\n'; } str += this.indet_3 + generics[generics.length - 1]['name'] + ' : ' + generics[generics.length - 1]['type'] + '\n'; str += this.indet_2 + ');\n'; } //Ports if (ports.length > 0) { str += this.indet_2 + ' port (\n'; for (let x = 0; x < ports.length - 1; ++x) { str += this.indet_3 + ports[x]['name'] + ' : ' + ports[x]['direction'] + ' ' + ports[x]['type'] + ';\n'; } str += this.indet_3 + ports[ports.length - 1]['name'] + ' : ' + ports[ports.length - 1]['direction'] + ' ' + ports[ports.length - 1]['type'] + '\n'; str += this.indet_2 + ');\n'; } //End component str += this.indet_1 + 'end component;\n'; return str; } set_Mix_Component(space, name, generics, ports) { var str = ''; //Component name str += this.indet_1 + 'component ' + name + '\n'; //Generics if (generics.length > 0) { str += this.indet_2 + 'generic (\n'; for (let x = 0; x < generics.length - 1; ++x) { let type = this.__vhdl_types(generics[x]['type'],true); str += this.indet_3 + generics[x]['name'] + ' : ' + type + generics[x]['default_value'] + ';\n'; } let type = this.__vhdl_types(generics[generics.length - 1]['type'],true); str += this.indet_3 + generics[generics.length - 1]['name'] + ' : ' + type + generics[generics.length - 1]['default_value'] + '\n'; str += this.indet_2 + ');\n'; } //Ports if (ports.length > 0) { str += this.indet_2 + ' port (\n'; for (let x = 0; x < ports.length - 1; ++x) { let port = this.__vhdl_ports(ports[x]['direction']); let type = this.__vhdl_types(ports[x]['type']); str += this.indet_3 + ports[x]['name'] + ' : ' + port + ' ' + type + ';\n'; } let port = this.__vhdl_ports(ports[ports.length - 1]['direction']); let type = this.__vhdl_types(ports[ports.length - 1]['type']); str += this.indet_3 + ports[ports.length - 1]['name'] + ' : ' + port + ' ' + type + '\n'; str += this.indet_2 + ');\n'; } //End component str += this.indet_1 + 'end component;\n'; return str; } __vhdl_ports(port){ let out_port=""; if (port === 'input') { out_port = 'in'; } else if (port === 'output'){ out_port = 'out'; } else if (port === 'inout'){ out_port = 'inout'; } return out_port; } __vhdl_types(type,generic=false){ let out_type=""; if ((type === '' || type === 'wire') && generic !== true) { out_type = 'std_logic'; } else if (type.includes('[') ){ out_type = type.replace('[','(').replace(']',')').replace('wire', ''); out_type = `std_logic_vector ${out_type.replace(':',' downto ')}`; }else{ out_type = type; } return out_type; } set_Instance(space, name, generics, ports, vunit, vhdl2008) { var str = ''; //Instance name if (vunit !== undefined && vunit === true) { str += this.indet_1 + name + '_inst : entity src_lib.' + name + '\n'; } else if (vhdl2008 !== undefined && vhdl2008 === true) { str += this.indet_1 + name + '_inst : entity work.' + name + '\n'; } else { str += this.indet_1 + name + '_inst : ' + name + '\n'; } //Generics if (generics.length > 0) { str += this.indet_2 + 'generic map (\n'; for (let x = 0; x < generics.length - 1; ++x) { str += this.indet_3 + generics[x]['name'] + ' => ' + generics[x]['name'] + ',\n'; } str += this.indet_3 + generics[generics.length - 1]['name'] + ' => ' + generics[generics.length - 1]['name'] + '\n'; str += this.indet_2 + ')\n'; } //Ports if (ports.length > 0) { str += this.indet_2 + 'port map (\n'; for (let x = 0; x < ports.length - 1; ++x) { str += this.indet_3 + ports[x]['name'] + ' => ' + ports[x]['name'] + ',\n'; } str += this.indet_3 + ports[ports.length - 1]['name'] + ' => ' + ports[ports.length - 1]['name'] + '\n'; str += this.indet_2 + ');\n'; } return str; } set_Vunit_Process() { var str = ''; str += this.indet_1 + 'main : process\n'; str += this.indet_1 + 'begin\n'; str += this.indet_2 + 'test_runner_setup(runner, runner_cfg);\n'; str += this.indet_2 + 'while test_suite loop\n'; str += this.indet_3 + 'if run("test_alive") then\n'; str += this.indet_4 + 'info("Hello world test_alive");\n'; str += this.indet_4 + 'wait for 100 * clk_period;\n'; str += this.indet_4 + 'test_runner_cleanup(runner);\n'; str += this.indet_4 + '\n'; str += this.indet_3 + 'elsif run("test_0") then\n'; str += this.indet_4 + 'info("Hello world test_0");\n'; str += this.indet_4 + 'wait for 100 * clk_period;\n'; str += this.indet_4 + 'test_runner_cleanup(runner);\n'; str += this.indet_3 + 'end if;\n'; str += this.indet_2 + 'end loop;\n'; str += this.indet_1 + 'end process main;\n'; return str; } set_Clk_Process(space) { var str = ''; str += '-- ' + space + "clk_process : process\n"; str += '-- ' + space + "begin\n"; str += '-- ' + space + this.indet_0 + "clk <= '1';\n"; str += '-- ' + space + this.indet_0 + "wait for clk_period/2;\n"; str += '-- ' + space + this.indet_0 + "clk <= '0';\n"; str += '-- ' + space + this.indet_0 + "wait for clk_period/2;\n"; str += '-- ' + space + "end process clk_process;\n"; return str; } } class Vhdl_component extends Vhdl_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(0); this.indet_2 = base.repeat(1); this.indet_3 = base.repeat(2); this.indet_4 = base.repeat(3); } else { let base = ' '; this.indet_0 = base.repeat(0); this.indet_1 = base.repeat(0); this.indet_2 = base.repeat(1); this.indet_3 = base.repeat(2); this.indet_4 = base.repeat(3); } let parser = new ParserLib.ParserFactory; let lang; if (options['type'] === Codes.TYPESCOMPONENTS.MIX_COMPONENT || options['type'] === Codes.TYPESCOMPONENTS.MIX_INSTANCE) { lang = General.LANGUAGES.VERILOG; }else{ lang = General.LANGUAGES.VHDL; } parser = await parser.getParser(lang, ''); parser.init(); let structure = await parser.get_all(src, '}{}'); if (structure === undefined) { return undefined; } if (options === null) { return ""; } var component = ""; if (options['type'] === Codes.TYPESCOMPONENTS.COMPONENT) { component = this.set_Component(' ', structure['entity']['name'], structure['generics'], structure['ports'], false); } else if (options['type'] === Codes.TYPESCOMPONENTS.MIX_COMPONENT) { component = this.set_Mix_Component(' ', structure['entity']['name'], structure['generics'], structure['ports'], false); } else if (options['type'] === Codes.TYPESCOMPONENTS.INSTANCE) { component = this.set_Instance(' ', structure['entity']['name'], structure['generics'], structure['ports'], false, false); } else if (options['type'] === Codes.TYPESCOMPONENTS.INSTANCE_VHDL2008 || options['type'] === Codes.TYPESCOMPONENTS.MIX_INSTANCE) { component = this.set_Instance(' ', structure['entity']['name'], structure['generics'], structure['ports'], false, true); } else if (options['type'] === Codes.TYPESCOMPONENTS.SIGNALS) { component = this.set_Signals(' ', structure['ports']); } else { // eslint-disable-next-line no-console console.log("error"); } return component; } } //*****************************************************************************/ //***************************** Exports ***************************************/ //*****************************************************************************/ module.exports = { Vhdl_editor: Vhdl_editor, Vhdl_component: Vhdl_component };