Basic support in tgt-pcb for reading footprint files.

When a black-box item requests a specific footprint, we need to
read a file (<footprint>.fp) that contains the actual details
about that footprint. Support parse of that file and use the
loaded Element to generate the footprint for the item.
This commit is contained in:
Stephen Williams 2011-12-26 23:05:52 -08:00
parent a95d64b7de
commit 5451a4830f
10 changed files with 543 additions and 5 deletions

4
.gitignore vendored
View File

@ -29,6 +29,10 @@ Makefile
/_pli_types.h /_pli_types.h
config.h config.h
/tgt-pcb/pcb_config.h /tgt-pcb/pcb_config.h
/tgt-pcb/fp.cc
/tgt-pcb/fp.h
/tgt-pcb/fp.output
/tgt-pcb/fp_lex.cc
/tgt-vvp/vvp_config.h /tgt-vvp/vvp_config.h
/tgt-vhdl/vhdl_config.h /tgt-vhdl/vhdl_config.h
/vpi/vpi_config.h /vpi/vpi_config.h

View File

@ -34,6 +34,8 @@ CXX = @CXX@
INSTALL = @INSTALL@ INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@ INSTALL_DATA = @INSTALL_DATA@
LEX = @LEX@
YACC = @YACC@
ifeq (@srcdir@,.) ifeq (@srcdir@,.)
INCLUDE_PATH = -I. -I.. INCLUDE_PATH = -I. -I..
@ -45,7 +47,7 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@
CFLAGS = @WARNING_FLAGS@ @CFLAGS@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
O = pcb.o scope.o show_netlist.o show_pcb.o O = pcb.o scope.o show_netlist.o show_pcb.o footprint.o fp.o fp_lex.o
all: dep pcb.tgt all: dep pcb.tgt
@ -74,6 +76,13 @@ dep:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o
mv $*.d dep mv $*.d dep
fp_lex.cc: $(srcdir)/fp.lex
$(LEX) -s -ofp_lex.cc $(srcdir)/fp.lex
fp.cc fp.h: $(srcdir)/fp.y
$(YACC) --verbose -t -d -o fp.cc $(srcdir)/fp.y
mv fp.cc.h fp.h 2>/dev/null || mv fp.hh fp.h
ifeq (@WIN32@,yes) ifeq (@WIN32@,yes)
TGTLDFLAGS=-L.. -livl TGTLDFLAGS=-L.. -livl
TGTDEPLIBS=../libivl.a TGTDEPLIBS=../libivl.a

89
tgt-pcb/footprint.cc Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "version_base.h"
# include "version_tag.h"
# include "pcb_config.h"
# include "pcb_priv.h"
# include "fp_api.h"
# include <iostream>
using namespace std;
map<string,fp_element_t> footprints;
static int check_footprint(element_data_t*elem);
/*
* Scan the element list and collect footprints needed.
*/
int load_footprints(void)
{
for (map<string,element_data_t*>::const_iterator cur = element_list.begin()
; cur != element_list.end() ; ++ cur) {
check_footprint(cur->second);
}
return 0;
}
/*
* The fpparse funciton calls back the callback_fp_element function
* for each Element that it parses. The check_footprint function
* stores in the cur_footprint variable the name of the footprint that
* we are trying to find in the file. The callback uses that name to
* store the Element into the footprints map.
*/
static string cur_footprint = "";
void callback_fp_element(const struct fp_element_t&cur_elem)
{
assert(cur_footprint != "");
footprints[cur_footprint] = cur_elem;
cur_footprint = "";
}
static int check_footprint(element_data_t*elem)
{
if (elem->footprint == "") {
cerr << "No footprint defined for \"" << elem->description << "\"." << endl;
return -1;
}
map<string,fp_element_t>::iterator match = footprints.find(elem->footprint);
if (match != footprints.end())
return 0;
string fpname = elem->footprint + ".fp";
cur_footprint = elem->footprint;
int rc = parse_fp_file(fpname);
if (rc != 0) {
cerr << "parse_fp_file(" << fpname << ") returns rc=" << rc << endl;
return rc;
}
match = footprints.find(elem->footprint);
if (match == footprints.end()) {
cerr << "Unable to locate footprint " << elem->footprint << "." << endl;
return -2;
}
return 0;
}

89
tgt-pcb/fp.lex Normal file
View File

@ -0,0 +1,89 @@
%option prefix="fp"
%option never-interactive
%option noinput
%option nounput
%option noyywrap
%option reentrant
%{
/*
* Copyright (C) 2011 Stephen Williams (steve@icarus.com)
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
# include "fp_api.h"
# include "fp.h"
# define YY_DECL int yylex(YYSTYPE*yylvalp, YYLTYPE*yyllocp, yyscan_t yyscanner)
%}
SPACE [ \t\f\r]
%%
/* Skip comment lines */
"#".* { ; }
/* Skip white space */
{SPACE} { ; }
"\n" { yyllocp->first_line += 1; }
"Element" { return K_ELEMENT; }
"Pad" { return K_PAD; }
"0x"[0-9a-fA-F]+ {
yylvalp->integer = strtoul(yytext+2,0,10);
return INTEGER;
}
"0"[0-7]* {
yylvalp->integer = strtoul(yytext,0,8);
return INTEGER;
}
[1-9][0-9]* {
yylvalp->integer = strtoul(yytext,0,10);
return INTEGER;
}
"\""[^\"]*"\"" {
size_t len = strlen(yytext)-2;
char*tmp = new char[len+1];
memcpy(tmp, yytext+1, len);
tmp[len] = 0;
yylvalp->text = tmp;
return STRING;
}
/* Isolated characters are tokens */
. { return yytext[0]; }
%%
yyscan_t prepare_fp_lexor(FILE*fd)
{
yyscan_t scanner;
yylex_init(&scanner);
yyrestart(fd, scanner);
return scanner;
}
void destroy_fp_lexor(yyscan_t scanner)
{
yylex_destroy(scanner);
}

200
tgt-pcb/fp.y Normal file
View File

@ -0,0 +1,200 @@
%name-prefix="fp"
%pure-parser
%lex-param {yyscan_t yyscanner}
%parse-param {yyscan_t yyscanner}
%parse-param {const char*file_path}
%{
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include "fp_api.h"
# include "pcb_priv.h"
using namespace std;
/* Recent version of bison expect that the user supply a
YYLLOC_DEFAULT macro that makes up a yylloc value from existing
values. I need to supply an explicit version to account for the
text field, that otherwise won't be copied. */
# define YYLLOC_DEFAULT(Current, Rhs, N) do { \
(Current).first_line = (Rhs)[1].first_line; \
} while (0)
static void yyerror(YYLTYPE*yylloc, yyscan_t scanner, const char*file_path, const char*msg)
{
fprintf(stderr, "%s\n", msg);
}
extern yyscan_t prepare_fp_lexor(FILE*fd);
extern void destroy_fp_lexor(yyscan_t scanner);
extern int fplex(union YYSTYPE*yylvalp, YYLTYPE*yylloc, yyscan_t scanner);
static fp_pad_t cur_pad;
static fp_element_t cur_element;
%}
%union {
long integer;
char*text;
};
%token <text> STRING
%token <integer> INTEGER
%token K_ELEMENT
%token K_PAD
%type <integer> integer
%%
file_items : file_items file_item | file_item ;
file_item : element ;
element
: K_ELEMENT element_header '(' element_items ')'
{ callback_fp_element(cur_element); }
;
element_header
: '[' INTEGER STRING STRING STRING integer integer integer integer integer integer STRING ']'
{ cur_element.nflags = $2;
cur_element.description = $3; delete[]$3;
cur_element.name = $4; delete[]$4;
cur_element.value = $5; delete[]$5;
cur_element.mx = $6;
cur_element.my = $7;
cur_element.tx = $8;
cur_element.ty = $9;
cur_element.tdir = $10;
cur_element.tscale = $11;
cur_element.tsflags = $12; delete[]$12;
cur_element.pads.clear();
}
| '[' error ']'
{ errormsg(@2, "Error in element header\n");
yyerrok;
cur_element.nflags = 0;
cur_element.description = "";
cur_element.name = "";
cur_element.value = "";
cur_element.mx = 0;
cur_element.my = 0;
cur_element.tx = 0;
cur_element.ty = 0;
cur_element.tdir = 0;
cur_element.tscale = 0;
cur_element.tsflags = "";
cur_element.pads.clear();
}
;
element_items
: element_items element_item
| element_item
;
element_item
: pad { cur_element.pads[cur_pad.name] = cur_pad; }
;
integer
: INTEGER { $$ = $1; }
| '-' INTEGER { $$ = -$2; }
;
pad
: K_PAD '[' integer integer integer integer integer integer integer STRING STRING STRING ']'
{ cur_pad.rx1 = $3;
cur_pad.ry1 = $4;
cur_pad.rx2 = $5;
cur_pad.ry2 = $6;
cur_pad.thickness = $7;
cur_pad.clearance = $8;
cur_pad.mask = $9;
cur_pad.name = $10; delete[]$10;
cur_pad.number = $11; delete[]$11;
cur_pad.sflags = $12; delete[]$12;
}
| K_PAD '[' error ']'
{ errormsg(@3, "Error in pad header\n");
yyerrok;
cur_pad.rx1 = 0;
cur_pad.ry1 = 0;
cur_pad.rx2 = 0;
cur_pad.ry2 = 0;
cur_pad.thickness = 0;
cur_pad.clearance = 0;
cur_pad.mask = 0;
cur_pad.name = "";
cur_pad.number = "";
cur_pad.sflags = "";
}
;
%%
static string parse_file_path;
int parse_fp_errors = 0;
int parse_fp_sorrys = 0;
void errormsg(const YYLTYPE&loc, const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: error: ", parse_file_path.c_str(), loc.first_line);
vfprintf(stderr, fmt, ap);
va_end(ap);
parse_fp_errors += 1;
}
void sorrymsg(const YYLTYPE&loc, const char*fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf(stderr, "%s:%d: sorry: ", parse_file_path.c_str(), loc.first_line);
vfprintf(stderr, fmt, ap);
va_end(ap);
parse_fp_sorrys += 1;
}
int parse_fp_file(const string&file_path)
{
FILE*fd = fopen(file_path.c_str(), "r");
if (fd == 0) {
perror(file_path.c_str());
return -1;
}
parse_file_path = file_path;
parse_fp_errors = 0;
parse_fp_sorrys = 0;
yyscan_t scanner = prepare_fp_lexor(fd);
int rc = yyparse(scanner, file_path.c_str());
fclose(fd);
destroy_fp_lexor(scanner);
return rc;
}

68
tgt-pcb/fp_api.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef __fp_api_H
#define __fp_api_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
# include <string>
/*
* This is the interface function that the user invokes to parse a
* footprint file. The argument is the path to the element.
*/
extern int parse_fp_file(const std::string&file_path);
typedef void*yyscan_t;
/*
* The yyltype supports the passing of detailed source file location
* information between the lexical analyzer and the parser. Defining
* YYLTYPE compels the lexor to use this type and not something other.
*/
struct yyltype {
unsigned first_line;
yyltype() { first_line = 1; }
};
# define YYLTYPE struct yyltype
/*
* Use this function during parse to generate error messages. The "loc"
* is the location of the token that triggered the error, and the fmt
* is printf-style format.
*/
extern void errormsg(const YYLTYPE&loc, const char*fmt, ...) __attribute__((format (printf, 2, 3)));
extern void sorrymsg(const YYLTYPE&loc, const char*fmt, ...) __attribute__((format (printf, 2, 3)));
extern void callback_fp_element(const struct fp_element_t&);
/*
* Set this to a non-zero value to enable parser debug output.
*/
//extern int yydebug;
/*
* The parser counts the errors that is handed in the parse_errors
* variable. For a clean compile, this value should not change. (The
* caller sets its initial value.) The sorrys are the count of
* unsupported constructs that are encountered.
*/
//extern int parse_errors;
extern int parse_fp_sorrys;
#endif

View File

@ -64,6 +64,8 @@ int target_design(ivl_design_t des)
} }
} }
load_footprints();
assert(pcb_path); assert(pcb_path);
show_pcb(pcb_path); show_pcb(pcb_path);

View File

@ -48,10 +48,40 @@ extern std::list<struct nexus_data*> nexus_list;
struct element_data_t { struct element_data_t {
std::string description; std::string description;
std::string value; std::string value;
std::string footprint;
}; };
extern std::map <std::string, element_data_t*> element_list; extern std::map <std::string, element_data_t*> element_list;
extern int load_footprints(void);
struct fp_pad_t {
long rx1, ry1;
long rx2, ry2;
int thickness;
int clearance;
int mask;
std::string name;
std::string number;
std::string sflags;
};
struct fp_element_t {
long nflags;
std::string description;
std::string name;
std::string value;
long mx, my;
long tx, ty;
int tdir;
int tscale;
std::string tsflags;
std::map<std::string,fp_pad_t> pads;
};
extern std::map<std::string,fp_element_t> footprints;
extern void show_netlist(const char*net_path); extern void show_netlist(const char*net_path);
extern void show_pcb(const char*pcb_path); extern void show_pcb(const char*pcb_path);

View File

@ -162,6 +162,16 @@ static void black_box(ivl_scope_t scope, const map<string,attr_value>&attrs)
default: default:
assert(0); assert(0);
} }
} else if (name == "footprint") {
ivl_expr_t exp = ivl_parameter_expr(par);
switch (ivl_expr_type(exp)) {
case IVL_EX_STRING:
elem_data->footprint = ivl_expr_string(exp);
break;
default:
assert(0);
}
} }
} }

View File

@ -28,6 +28,7 @@ static void show_pcb_header(FILE*fpcb)
fprintf(fpcb, "Grid[100.0 0 0 1]\n"); fprintf(fpcb, "Grid[100.0 0 0 1]\n");
} }
static void show_pcb_element(FILE*fpcb, const string&refdes, element_data_t*elem);
void show_pcb(const char*pcb_path) void show_pcb(const char*pcb_path)
{ {
@ -44,9 +45,17 @@ void show_pcb(const char*pcb_path)
for (map<string,element_data_t*>::const_iterator cur = element_list.begin() for (map<string,element_data_t*>::const_iterator cur = element_list.begin()
; cur != element_list.end() ; ++ cur) { ; cur != element_list.end() ; ++ cur) {
const string&refdes = cur->first; show_pcb_element(fpcb, cur->first, cur->second);
const string&descr = cur->second->description; }
const string&value = cur->second->value;
fclose(fpcb);
}
static void show_pcb_element(FILE*fpcb, const string&refdes, element_data_t*elem)
{
string descr = elem->description;
const string&value = elem->value;
if (elem->footprint == "") {
fprintf(fpcb, "Element[\"\" \"%s\" \"%s\" \"%s\"", fprintf(fpcb, "Element[\"\" \"%s\" \"%s\" \"%s\"",
descr.c_str(), refdes.c_str(), value.c_str()); descr.c_str(), refdes.c_str(), value.c_str());
@ -60,7 +69,35 @@ void show_pcb(const char*pcb_path)
// from a library. // from a library.
fprintf(fpcb, "(\n"); fprintf(fpcb, "(\n");
fprintf(fpcb, ")\n"); fprintf(fpcb, ")\n");
return;
} }
fclose(fpcb); fp_element_t&foot = footprints[elem->footprint];
if (descr == "")
descr = foot.description;
fprintf(fpcb, "Element[0x%lx \"%s\" \"%s\" \"%s\"",
foot.nflags, descr.c_str(), refdes.c_str(), value.c_str());
fprintf(fpcb, " %ld %ld", foot.mx, foot.my);
fprintf(fpcb, " %ld %ld %d %d \"%s\"", foot.tx, foot.ty, foot.tdir,
foot.tscale, foot.tsflags.c_str());
fprintf(fpcb, "]\n(\n");
for (map<string,fp_pad_t>::const_iterator cur = foot.pads.begin()
; cur != foot.pads.end() ; ++ cur) {
fprintf(fpcb, "Pad[%ld %ld %ld %ld %d %d %d \"%s\" \"%s\" \"%s\"]\n",
cur->second.rx1,
cur->second.ry1,
cur->second.rx2,
cur->second.ry2,
cur->second.thickness,
cur->second.clearance,
cur->second.mask,
cur->second.name.c_str(),
cur->second.number.c_str(),
cur->second.sflags.c_str());
}
fprintf(fpcb, ")\n");
} }