mirror of https://github.com/YosysHQ/abc.git
New command %gen.
This commit is contained in:
parent
3109172462
commit
6cab944535
|
|
@ -32,6 +32,7 @@ ABC_NAMESPACE_IMPL_START
|
|||
|
||||
static int Abc_CommandReadWlc ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandWriteWlc ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandGenWlc ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandPs ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandCone ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
static int Abc_CommandAbs ( Abc_Frame_t * pAbc, int argc, char ** argv );
|
||||
|
|
@ -79,6 +80,7 @@ void Wlc_Init( Abc_Frame_t * pAbc )
|
|||
{
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%read", Abc_CommandReadWlc, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%write", Abc_CommandWriteWlc, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%gen", Abc_CommandGenWlc, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%ps", Abc_CommandPs, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%cone", Abc_CommandCone, 0 );
|
||||
Cmd_CommandAdd( pAbc, "Word level", "%abs", Abc_CommandAbs, 0 );
|
||||
|
|
@ -305,6 +307,119 @@ usage:
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**Function********************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
||||
Description []
|
||||
|
||||
SideEffects []
|
||||
|
||||
SeeAlso []
|
||||
|
||||
******************************************************************************/
|
||||
int Abc_CommandGenWlc( Abc_Frame_t * pAbc, int argc, char ** argv )
|
||||
{
|
||||
extern int miniver_translate(const char *input, char *out, size_t cap);
|
||||
char * pFileName = NULL;
|
||||
int c, fVerbose = 0;
|
||||
Extra_UtilGetoptReset();
|
||||
while ( ( c = Extra_UtilGetopt( argc, argv, "Fvh" ) ) != EOF )
|
||||
{
|
||||
switch ( c )
|
||||
{
|
||||
case 'F':
|
||||
if ( globalUtilOptind >= argc )
|
||||
{
|
||||
Abc_Print( -1, "Command line switch \"-L\" should be followed by a file name.\n" );
|
||||
goto usage;
|
||||
}
|
||||
pFileName = argv[globalUtilOptind];
|
||||
globalUtilOptind++;
|
||||
break;
|
||||
case 'v':
|
||||
fVerbose ^= 1;
|
||||
break;
|
||||
case 'h':
|
||||
goto usage;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
if ( argc != globalUtilOptind + 1 ) {
|
||||
printf( "The input string is not given on the command line.\n" );
|
||||
goto usage;
|
||||
}
|
||||
else {
|
||||
int Size = 10000;
|
||||
char * pStr = argv[globalUtilOptind];
|
||||
char * pOutStr = ABC_CALLOC( char, Size+1 );
|
||||
int RetValue = miniver_translate( pStr, pOutStr, Size );
|
||||
if ( !RetValue ) {
|
||||
if ( fVerbose )
|
||||
printf( "Entered Verilog design:\n%s", pOutStr );
|
||||
if ( pFileName ) {
|
||||
FILE * pFile = fopen( pFileName, "wb" );
|
||||
if ( pFile == NULL )
|
||||
printf( "Cannot open output file \"%s\".\n", pFileName );
|
||||
else {
|
||||
fprintf( pFile, "// Design generated from mini-Verilog string: %s\n\n%s\n", pStr, pOutStr );
|
||||
fclose( pFile );
|
||||
printf( "Dumped the design generated from mini-Verilog string \"%s\" into file \"%s\".\n", pStr, pFileName );
|
||||
}
|
||||
}
|
||||
else {
|
||||
Wlc_Ntk_t * pNtk = Wlc_ReadVer( NULL, pOutStr, 0 );
|
||||
if ( pNtk ) {
|
||||
Wlc_AbcUpdateNtk( pAbc, pNtk );
|
||||
//printf( "Read current design using %%read <file.v>\n" );
|
||||
}
|
||||
else {
|
||||
printf( "The following design in Verilog, which was generated from string \"%s\",\n", pStr );
|
||||
printf( "cannot be read into ABC due to the known limitations of command \"%%read\".\n" );
|
||||
printf( "Please try the following \"%%gen -F <file.v> <string>; %%yosys -b <file.v>; &ps\".\n" );
|
||||
printf( "Generated design:\n%s\n", pOutStr );
|
||||
}
|
||||
}
|
||||
}
|
||||
ABC_FREE( pOutStr );
|
||||
}
|
||||
return 0;
|
||||
usage:
|
||||
Abc_Print( -2, "\nusage: %%gen [-F file] [-vh] \"<mini_verilog_string>\"\n" );
|
||||
Abc_Print( -2, "\t generates the design from a mini-Verilog string\n" );
|
||||
Abc_Print( -2, "\t-F file : optional file name to save the design in standard Verilog [default = unused]\n" );
|
||||
Abc_Print( -2, "\t-v : toggle printing verbose information [default = %s]\n", fVerbose? "yes": "no" );
|
||||
Abc_Print( -2, "\t-h : print the command usage\n");
|
||||
Abc_Print( -2, "\n" );
|
||||
Abc_Print( -2, "A mini-Verilog design is a single string. Any spaces/tabs/newlines are ignored.\n" );
|
||||
Abc_Print( -2, "The string is split into clauses by semicolons ';'.\n" );
|
||||
Abc_Print( -2, "\n" );
|
||||
Abc_Print( -2, "Clause kinds (first character):\n" );
|
||||
Abc_Print( -2, " - 'm<name>' : module name (appear once)\n" );
|
||||
Abc_Print( -2, " - '{i|o|w}[s]<number><id_list>' : input/output/wire declarations\n" );
|
||||
Abc_Print( -2, " where optional 's' = signed, <number> = bit-width (>0), <id_list> = id[,id]*\n" );
|
||||
Abc_Print( -2, " Examples: i4a,b -> input [3:0] a, b;\n" );
|
||||
Abc_Print( -2, " is8x,y -> input signed [7:0] x, y;\n" );
|
||||
Abc_Print( -2, " w1t -> wire t; (width 1 prints without [0:0])\n" );
|
||||
Abc_Print( -2, " - '{o|w}[s]<number><id>=<expr>' : declaration with assignment\n" );
|
||||
Abc_Print( -2, " Examples: o8z=a*b -> output [7:0] z; assign z = a*b;\n" );
|
||||
Abc_Print( -2, " w4t=a+b -> wire [3:0] t; assign t = a+b;\n" );
|
||||
Abc_Print( -2, "\n" );
|
||||
Abc_Print( -2, "Default names:\n" );
|
||||
Abc_Print( -2, " - Outputs: if an 'o...' assignment omits a name (e.g., 'o8=<expr>'), the output name defaults to 'o'.\n" );
|
||||
Abc_Print( -2, " - Inputs: if an 'i...' clause omits names (e.g., 'i4'), a single input is declared with an\n" );
|
||||
Abc_Print( -2, " auto-generated unsigned name 'a', then 'b', then 'c', ... in the order of appearance (skipping\n" );
|
||||
Abc_Print( -2, " names already used). This allows for specifying a 4-bit multiplier 'mul' as: 'mmul;i4;i4;o8=a*b'.\n" );
|
||||
Abc_Print( -2, "\n" );
|
||||
Abc_Print( -2, "Notes:\n" );
|
||||
Abc_Print( -2, " * Only a single, non-hierarchical, combinational module is supported.\n" );
|
||||
Abc_Print( -2, " * Whitespace anywhere is ignored before parsing (handled internally).\n" );
|
||||
Abc_Print( -2, " * RHS expressions are passed through verbatim (must be in valid Verilog).\n" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**Function********************************************************************
|
||||
|
||||
Synopsis []
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ SRC += src/misc/util/utilBridge.c \
|
|||
src/misc/util/utilFile.c \
|
||||
src/misc/util/utilIsop.c \
|
||||
src/misc/util/utilLinear.c \
|
||||
src/misc/util/utilMiniver.c \
|
||||
src/misc/util/utilNam.c \
|
||||
src/misc/util/utilPrefix.cpp \
|
||||
src/misc/util/utilPth.c \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,523 @@
|
|||
/**CFile****************************************************************
|
||||
|
||||
FileName [utilMiniver.c]
|
||||
|
||||
SystemName [ABC: Logic synthesis and verification system.]
|
||||
|
||||
PackageName [Handling counter-examples.]
|
||||
|
||||
Synopsis [Handling counter-examples.]
|
||||
|
||||
Author [Alan Mishchenko]
|
||||
|
||||
Affiliation [UC Berkeley]
|
||||
|
||||
Date [Ver. 1.0. Started - June 20, 2005.]
|
||||
|
||||
Revision [$Id: utilMiniver.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "misc/util/abc_global.h"
|
||||
|
||||
ABC_NAMESPACE_IMPL_START
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// DECLARATIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define MINIVER_LIBRARY_ONLY
|
||||
|
||||
#define MAXSIG 1024
|
||||
#define MAXSTR 65536
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// FUNCTION DEFINITIONS ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
char name[128];
|
||||
int width;
|
||||
int is_signed;
|
||||
} decl_t;
|
||||
|
||||
typedef struct {
|
||||
char lhs[128];
|
||||
char rhs[4096];
|
||||
} asn_t;
|
||||
|
||||
// Parsing/collection context (encapsulates all state)
|
||||
typedef struct {
|
||||
char modname[128];
|
||||
decl_t inputs[MAXSIG]; int ni;
|
||||
decl_t outputs[MAXSIG]; int no;
|
||||
decl_t wires[MAXSIG]; int nw;
|
||||
asn_t assigns[MAXSIG]; int na;
|
||||
int next_auto_in; // next index for auto-generated input names ('a' + idx)
|
||||
} mv_ctx;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Remove all ASCII whitespace from 's' into 'out'.
|
||||
static void strip_ws(const char *s, char *out) {
|
||||
while (*s) {
|
||||
if (!isspace((unsigned char)*s)) {
|
||||
*out++ = *s;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
*out = 0;
|
||||
}
|
||||
|
||||
static int is_ident_start(char c) {
|
||||
return isalpha((unsigned char)c) || c == '_' || c == '$';
|
||||
}
|
||||
|
||||
static int is_ident_char(char c) {
|
||||
return isalnum((unsigned char)c) || c == '_' || c == '$';
|
||||
}
|
||||
|
||||
// Parse a non-negative decimal integer from 's'; store value in *v and chars consumed in *nch.
|
||||
static int parse_uint(const char *s, int *v, int *nch) {
|
||||
int i = 0;
|
||||
int d = 0;
|
||||
if (!isdigit((unsigned char)s[0])) return 0;
|
||||
while (isdigit((unsigned char)s[i])) {
|
||||
d = d * 10 + (s[i] - '0');
|
||||
++i;
|
||||
}
|
||||
*v = d;
|
||||
*nch = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if a name is already used in any declaration.
|
||||
static int name_exists(mv_ctx *ctx, const char *name) {
|
||||
for (int i = 0; i < ctx->ni; ++i) if (!strcmp(ctx->inputs[i].name, name)) return 1;
|
||||
for (int i = 0; i < ctx->no; ++i) if (!strcmp(ctx->outputs[i].name, name)) return 1;
|
||||
for (int i = 0; i < ctx->nw; ++i) if (!strcmp(ctx->wires[i].name, name)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate next auto input name: 'a','b','c',... then 'a0','a1',... if 26 exhausted.
|
||||
static void gen_auto_in_name(mv_ctx *ctx, char *out, size_t out_sz) {
|
||||
// try single letters first
|
||||
for (; ctx->next_auto_in < 26; ++ctx->next_auto_in) {
|
||||
char cand[3] = {(char)('a' + ctx->next_auto_in), 0, 0};
|
||||
if (!name_exists(ctx, cand)) { strncpy(out, cand, out_sz-1); out[out_sz-1]=0; ++ctx->next_auto_in; return; }
|
||||
}
|
||||
// fallback to aN form
|
||||
for (int n = 0;; ++n) {
|
||||
char cand[32];
|
||||
snprintf(cand, sizeof(cand), "a%d", n);
|
||||
if (!name_exists(ctx, cand)) { strncpy(out, cand, out_sz-1); out[out_sz-1]=0; return; }
|
||||
}
|
||||
}
|
||||
|
||||
// Add (or deduplicate) declaration into an array.
|
||||
static void add_decl(decl_t *arr, int *cnt, const char *name, int w, int sg) {
|
||||
for (int k = 0; k < *cnt; ++k) {
|
||||
if (!strcmp(arr[k].name, name)) return;
|
||||
}
|
||||
strncpy(arr[*cnt].name, name, sizeof(arr[*cnt].name) - 1);
|
||||
arr[*cnt].width = w;
|
||||
arr[*cnt].is_signed = sg;
|
||||
++(*cnt);
|
||||
}
|
||||
|
||||
// Record an assignment; returns non-zero on overflow.
|
||||
static int add_asn(mv_ctx *ctx, const char *lhs, const char *rhs) {
|
||||
if (ctx->na >= MAXSIG) {
|
||||
printf("Too many assignments.\n");
|
||||
return 1;
|
||||
}
|
||||
strncpy(ctx->assigns[ctx->na].lhs, lhs, sizeof(ctx->assigns[ctx->na].lhs) - 1);
|
||||
strncpy(ctx->assigns[ctx->na].rhs, rhs, sizeof(ctx->assigns[ctx->na].rhs) - 1);
|
||||
++ctx->na;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Append formatted text to user-provided buffer with capacity checks.
|
||||
// On insufficient capacity, print message and return 1; otherwise 0.
|
||||
static int out_cat(char **p, size_t *left, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int need = vsnprintf(NULL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
if (need < 0 || (size_t)need >= *left) {
|
||||
printf("Output exceeds buffer capacity.\n");
|
||||
return 1;
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
int wrote = vsnprintf(*p, *left, fmt, ap);
|
||||
va_end(ap);
|
||||
*p += wrote;
|
||||
*left -= (size_t)wrote;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emit declarations into the output buffer.
|
||||
static int print_decl_to_buf(char **p, size_t *left, const char *kw, decl_t *arr, int n) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int w = arr[i].width;
|
||||
int sg = arr[i].is_signed;
|
||||
const char *id = arr[i].name;
|
||||
if (w == 1) {
|
||||
if (out_cat(p, left, " %s %s%s;\n", kw, sg ? "signed " : "", id)) return 1;
|
||||
} else {
|
||||
if (out_cat(p, left, " %s %s[%d:0] %s;\n", kw, sg ? "signed " : "", w - 1, id)) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add spaces around every alphanumeric/underscore sequence for readability.
|
||||
// Example: "a*b+16'b0" -> " a * b + 16 ' b0 "
|
||||
static void format_rhs_readable(const char *in, char *out, size_t cap) {
|
||||
size_t o = 0;
|
||||
for (size_t i = 0; in[i]; ) {
|
||||
unsigned char c = (unsigned char)in[i];
|
||||
if (isalnum(c) || c == '_') {
|
||||
// start of a token
|
||||
if (o + 1 >= cap) { if (o) out[o-1] = 0; else if (cap) out[0] = 0; return; }
|
||||
out[o++] = ' ';
|
||||
// copy token
|
||||
size_t j = i;
|
||||
while (in[j] && (isalnum((unsigned char)in[j]) || in[j] == '_')) {
|
||||
if (o + 1 >= cap) { out[o-1] = 0; return; }
|
||||
out[o++] = in[j++];
|
||||
}
|
||||
if (o + 1 >= cap) { out[o-1] = 0; return; }
|
||||
out[o++] = ' ';
|
||||
i = j;
|
||||
} else {
|
||||
if (o + 1 >= cap) { if (o) out[o-1] = 0; else if (cap) out[0] = 0; return; }
|
||||
out[o++] = in[i++];
|
||||
}
|
||||
}
|
||||
if (o < cap) out[o] = 0; else if (cap) out[cap-1] = 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Parsing helpers that quote offending clauses
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef int (*emit_fn)(mv_ctx *, const char *, int, int);
|
||||
|
||||
static int emit_in(mv_ctx *ctx, const char *id, int w, int sg) {
|
||||
add_decl(ctx->inputs, &ctx->ni, id, w, sg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_wi(mv_ctx *ctx, const char *id, int w, int sg) {
|
||||
add_decl(ctx->wires, &ctx->nw, id, w, sg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Split an identifier list like "a,b,c" and emit each item. Quotes 'clause' in diagnostics.
|
||||
static int split_ids(mv_ctx *ctx, const char *clause, const char *s, emit_fn emit, int w, int sg) {
|
||||
char buf[128];
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0;; ++i) {
|
||||
char c = s[i];
|
||||
if (c == ',' || c == 0) {
|
||||
if (j == 0) {
|
||||
printf("Syntax error: empty identifier in expression \"%s\".\n", clause);
|
||||
return 1;
|
||||
}
|
||||
buf[j] = 0;
|
||||
if (emit(ctx, buf, w, sg)) return 1;
|
||||
j = 0;
|
||||
if (c == 0) break;
|
||||
} else {
|
||||
if (j >= 120) {
|
||||
printf("Identifier too long in expression \"%s\".\n", clause);
|
||||
return 1;
|
||||
}
|
||||
if (!((j ? is_ident_char(c) : is_ident_start(c)))) {
|
||||
printf("Illegal identifier in expression \"%s\".\n", clause);
|
||||
return 1;
|
||||
}
|
||||
buf[j++] = c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse one clause (already whitespace-stripped). On error, prints a message including the clause.
|
||||
static int parse_clause(mv_ctx *ctx, const char *q) {
|
||||
if (!q || !*q) return 0;
|
||||
|
||||
if (q[0] == 'm') {
|
||||
if (!is_ident_start(q[1])) {
|
||||
printf("Syntax error after 'm' in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
int i = 1;
|
||||
while (q[i] && is_ident_char(q[i])) ++i;
|
||||
if (q[i]) {
|
||||
printf("Garbage after module name in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
size_t n = (size_t)(i - 1);
|
||||
if (n >= sizeof(ctx->modname)) n = sizeof(ctx->modname) - 1;
|
||||
strncpy(ctx->modname, q + 1, n);
|
||||
ctx->modname[n] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (q[0] != 'i' && q[0] != 'o' && q[0] != 'w') {
|
||||
printf("Unknown clause start in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int kind = q[0];
|
||||
int i = 1;
|
||||
int sg = 0;
|
||||
int w = 0;
|
||||
int nconsumed = 0;
|
||||
|
||||
if (q[i] == 's') {
|
||||
sg = 1;
|
||||
++i;
|
||||
}
|
||||
if (!parse_uint(q + i, &w, &nconsumed)) {
|
||||
printf("Width expected in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
i += nconsumed;
|
||||
if (w <= 0) {
|
||||
printf("Non-positive width in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *eq = strchr(q + i, '=');
|
||||
|
||||
if (kind == 'i') {
|
||||
// Support unnamed inputs: 'i4' -> auto-generate one input named a,b,c,...
|
||||
if (!q[i]) {
|
||||
char auto_name[32];
|
||||
gen_auto_in_name(ctx, auto_name, sizeof(auto_name));
|
||||
add_decl(ctx->inputs, &ctx->ni, auto_name, w, sg);
|
||||
return 0;
|
||||
}
|
||||
if (eq) {
|
||||
printf("Unexpected '=' in input clause in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
return split_ids(ctx, q, q + i, emit_in, w, sg);
|
||||
}
|
||||
|
||||
if (kind == 'w' && !eq) {
|
||||
if (!q[i]) {
|
||||
printf("Identifiers expected for wires in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
return split_ids(ctx, q, q + i, emit_wi, w, sg);
|
||||
}
|
||||
|
||||
if (!eq) {
|
||||
printf("Assignment expected in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Parse the LHS name for 'o' or 'w'. For 'o', allow omitted name (defaults to "o").
|
||||
char lhs[128];
|
||||
int lj = 0;
|
||||
for (int k = i; k < (int)(eq - q); ++k) {
|
||||
char c = q[k];
|
||||
if (!lj && kind == 'o' && !is_ident_start(c)) {
|
||||
lhs[0] = 'o';
|
||||
lhs[1] = 0;
|
||||
goto lhs_done;
|
||||
}
|
||||
if (!(lj ? is_ident_char(c) : is_ident_start(c))) {
|
||||
printf("Illegal LHS identifier in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
if (lj >= 120) {
|
||||
printf("Identifier too long in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
lhs[lj++] = c;
|
||||
}
|
||||
if (lj == 0) {
|
||||
if (kind == 'o') {
|
||||
lhs[0] = 'o';
|
||||
lhs[1] = 0;
|
||||
} else {
|
||||
printf("Wire assignment needs a name in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
lhs[lj] = 0;
|
||||
}
|
||||
lhs_done:;
|
||||
const char *rhs = eq + 1;
|
||||
if (!*rhs) {
|
||||
printf("Empty RHS expression in expression \"%s\".\n", q);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (kind == 'o') add_decl(ctx->outputs, &ctx->no, lhs, w, sg);
|
||||
if (kind == 'w') add_decl(ctx->wires, &ctx->nw, lhs, w, sg);
|
||||
return add_asn(ctx, lhs, rhs);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Public API
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Translate a raw mini-Verilog string 'input' into standard Verilog.
|
||||
// The function strips whitespace internally, parses, and writes into 'out' (cap bytes).
|
||||
// Returns 0 on success, 1 on error. Errors are printed (no exit()).
|
||||
int miniver_translate(const char *input, char *out, size_t cap) {
|
||||
if (!input || !out || cap == 0) {
|
||||
printf("Invalid arguments.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Step 1: strip whitespace (per spec).
|
||||
char flat[MAXSTR];
|
||||
strip_ws(input, flat);
|
||||
if (!*flat) {
|
||||
printf("Empty input.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Step 2: parse clauses into a context.
|
||||
mv_ctx *ctx = (mv_ctx*)calloc(1, sizeof(mv_ctx));
|
||||
if (!ctx) {
|
||||
printf("Out of memory.\n");
|
||||
return 1;
|
||||
}
|
||||
strncpy(ctx->modname, "top", sizeof(ctx->modname) - 1);
|
||||
ctx->next_auto_in = 0;
|
||||
|
||||
// Make a modifiable copy to split on semicolons.
|
||||
char *buf = (char*)malloc(strlen(flat) + 1);
|
||||
if (!buf) {
|
||||
printf("Out of memory.\n");
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
strcpy(buf, flat);
|
||||
|
||||
char *s = buf;
|
||||
while (*s) {
|
||||
char *semi = strchr(s, ';');
|
||||
if (semi) *semi = 0;
|
||||
if (parse_clause(ctx, s)) {
|
||||
free(buf);
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
if (!semi) break;
|
||||
s = semi + 1;
|
||||
}
|
||||
free(buf);
|
||||
|
||||
if (!*ctx->modname) {
|
||||
printf("Module name missing.\n");
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
if (ctx->no == 0) {
|
||||
printf("At least one output with assignment is required.\n");
|
||||
free(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Step 3: emit Verilog into caller buffer.
|
||||
char *p = out;
|
||||
size_t left = cap;
|
||||
|
||||
if (out_cat(&p, &left, "module %s (", ctx->modname)) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
for (int i = 0; i < ctx->ni; ++i) {
|
||||
if (out_cat(&p, &left, "%s%s", i ? ", " : "", ctx->inputs[i].name)) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < ctx->no; ++i) {
|
||||
if (out_cat(&p, &left, "%s%s", (ctx->ni || i) ? ", " : "", ctx->outputs[i].name)) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
}
|
||||
if (out_cat(&p, &left, ");\n")) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
|
||||
if (print_decl_to_buf(&p, &left, "input", ctx->inputs, ctx->ni)) { free(ctx); return 1; }
|
||||
if (print_decl_to_buf(&p, &left, "output", ctx->outputs, ctx->no)) { free(ctx); return 1; }
|
||||
if (print_decl_to_buf(&p, &left, "wire", ctx->wires, ctx->nw)) { free(ctx); return 1; }
|
||||
|
||||
for (int i = 0; i < ctx->na; ++i) {
|
||||
char rhs_sp[8192];
|
||||
format_rhs_readable(ctx->assigns[i].rhs, rhs_sp, sizeof(rhs_sp));
|
||||
if (out_cat(&p, &left, " assign %s = %s;\n", ctx->assigns[i].lhs, rhs_sp)) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
}
|
||||
if (out_cat(&p, &left, "endmodule\n")) {
|
||||
free(ctx); return 1;
|
||||
}
|
||||
|
||||
*p = 0;
|
||||
free(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Optional CLI wrapper (define MINIVER_LIBRARY_ONLY to omit main)
|
||||
// -----------------------------------------------------------------------------
|
||||
#ifndef MINIVER_LIBRARY_ONLY
|
||||
int main(int argc, char **argv) {
|
||||
char in[MAXSTR] = {0};
|
||||
|
||||
if (argc >= 2) {
|
||||
size_t L = strlen(argv[1]);
|
||||
if (L >= MAXSTR - 1) {
|
||||
printf("Input too long.\n");
|
||||
return 1;
|
||||
}
|
||||
strcpy(in, argv[1]);
|
||||
} else {
|
||||
size_t off = 0;
|
||||
int c = 0;
|
||||
while ((c = fgetc(stdin)) != EOF) {
|
||||
if (off >= MAXSTR - 1) {
|
||||
printf("Input too long.\n");
|
||||
return 1;
|
||||
}
|
||||
in[off++] = (char)c;
|
||||
}
|
||||
in[off] = 0;
|
||||
}
|
||||
|
||||
char out[10240];
|
||||
int rc = miniver_translate(in, out, sizeof(out));
|
||||
if (!rc) {
|
||||
printf("%s", out);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
/// END OF FILE ///
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
ABC_NAMESPACE_IMPL_END
|
||||
|
||||
|
|
@ -1278,6 +1278,16 @@ static inline Vec_Int_t * Vec_IntInvert( Vec_Int_t * p, int Fill )
|
|||
Vec_IntWriteEntry( vRes, Entry, i );
|
||||
return vRes;
|
||||
}
|
||||
static inline Vec_Int_t * Vec_IntInvertSize( Vec_Int_t * p, int Size, int Fill )
|
||||
{
|
||||
Vec_Int_t * vMap = Vec_IntAlloc( 0 );
|
||||
Vec_IntFill( vMap, Size, Fill );
|
||||
int i, k;
|
||||
Vec_IntForEachEntry( p, i, k )
|
||||
if ( i != Fill )
|
||||
Vec_IntWriteEntry( vMap, i, k );
|
||||
return vMap;
|
||||
}
|
||||
|
||||
/**Function*************************************************************
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue