summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/plaparse.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/plaparse.cpp')
-rw-r--r--src/lib/util/plaparse.cpp364
1 files changed, 364 insertions, 0 deletions
diff --git a/src/lib/util/plaparse.cpp b/src/lib/util/plaparse.cpp
new file mode 100644
index 00000000000..74bc8edcc69
--- /dev/null
+++ b/src/lib/util/plaparse.cpp
@@ -0,0 +1,364 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles, hap
+/***************************************************************************
+
+ plaparse.h
+
+ Simple parser for Berkeley standard PLA files into raw fusemaps.
+ It supports no more than one output matrix, and is limited to
+ keywords: i, o, p, phase, e
+
+***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "jedparse.h"
+#include "plaparse.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_PARSE 0
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct parse_info
+{
+ UINT32 inputs; /* number of input columns */
+ UINT32 outputs; /* number of output columns */
+ UINT32 terms; /* number of terms */
+ UINT32 xorval[JED_MAX_FUSES/64]; /* output polarity */
+ UINT32 xorptr;
+};
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ iscrlf - is a line feed character
+-------------------------------------------------*/
+
+static bool iscrlf(char c)
+{
+ return (c == 13 || c == 10);
+}
+
+
+/*-------------------------------------------------
+ suck_number - read a decimal value from the
+ character stream
+-------------------------------------------------*/
+
+static UINT32 suck_number(const UINT8 **src, const UINT8 *srcend)
+{
+ UINT32 value = 0;
+
+ // find first digit
+ while (*src < srcend && !iscrlf(**src) && !isdigit(**src))
+ (*src)++;
+
+ // loop over and accumulate digits
+ while (*src < srcend && isdigit(**src))
+ {
+ value = value * 10 + (**src) - '0';
+ (*src)++;
+ }
+
+ return value;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ process_terms - process input/output matrix
+-------------------------------------------------*/
+
+static bool process_terms(jed_data *data, const UINT8 **src, const UINT8 *srcend, parse_info *pinfo)
+{
+ UINT32 curinput = 0;
+ UINT32 curoutput = 0;
+ bool outputs = false;
+
+ // symbols for 0, 1, dont_care, no_meaning
+ // PLA format documentation also describes them as simply 0, 1, 2, 3
+ static const char symbols[] = { "01-~" };
+
+ while (*src < srcend && **src != '.' && **src != '#')
+ {
+ if (!outputs)
+ {
+ // and-matrix
+ if (strrchr(symbols, **src))
+ curinput++;
+
+ switch (**src)
+ {
+ case '0':
+ jed_set_fuse(data, data->numfuses++, 0);
+ jed_set_fuse(data, data->numfuses++, 1);
+
+ if (LOG_PARSE) printf("01");
+ break;
+
+ case '1':
+ jed_set_fuse(data, data->numfuses++, 1);
+ jed_set_fuse(data, data->numfuses++, 0);
+
+ if (LOG_PARSE) printf("10");
+ break;
+
+ // anything goes
+ case '-':
+ jed_set_fuse(data, data->numfuses++, 1);
+ jed_set_fuse(data, data->numfuses++, 1);
+
+ if (LOG_PARSE) printf("11");
+ break;
+
+ // this product term is inhibited
+ case '~':
+ jed_set_fuse(data, data->numfuses++, 0);
+ jed_set_fuse(data, data->numfuses++, 0);
+
+ if (LOG_PARSE) printf("00");
+ break;
+
+ case ' ': case '\t':
+ if (curinput > 0)
+ {
+ outputs = true;
+ if (LOG_PARSE) printf(" ");
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // or-matrix
+ if (strrchr(symbols, **src))
+ {
+ curoutput++;
+ if (**src == '1')
+ {
+ jed_set_fuse(data, data->numfuses++, 0);
+ if (LOG_PARSE) printf("0");
+ }
+ else
+ {
+ // write 1 for anything else
+ jed_set_fuse(data, data->numfuses++, 1);
+ if (LOG_PARSE) printf("1");
+ }
+ }
+ }
+
+ if (iscrlf(**src) && outputs)
+ {
+ outputs = false;
+ if (LOG_PARSE) printf("\n");
+
+ if (curinput != pinfo->inputs || curoutput != pinfo->outputs)
+ return false;
+
+ curinput = 0;
+ curoutput = 0;
+ }
+
+ (*src)++;
+ }
+
+ return true;
+}
+
+
+
+/*-------------------------------------------------
+ process_field - process a single field
+-------------------------------------------------*/
+
+static bool process_field(jed_data *data, const UINT8 **src, const UINT8 *srcend, parse_info *pinfo)
+{
+ // valid keywords
+ static const char *const keywords[] = { "i", "o", "p", "phase", "e", "\0" };
+ enum
+ {
+ KW_INPUTS = 0,
+ KW_OUTPUTS,
+ KW_TERMS,
+ KW_PHASE,
+ KW_END,
+
+ KW_INVALID
+ };
+
+ // find keyword
+ char dest[0x10];
+ memset(dest, 0, ARRAY_LENGTH(dest));
+ const UINT8 *seek = *src;
+ int destptr = 0;
+
+ while (seek < srcend && isalpha(*seek) && destptr < ARRAY_LENGTH(dest) - 1)
+ {
+ dest[destptr] = tolower(*seek);
+ seek++;
+ destptr++;
+ }
+
+ UINT8 find = 0;
+ while (strlen(keywords[find]) && strcmp(dest, keywords[find]))
+ find++;
+
+ if (find == KW_INVALID)
+ return false;
+
+ (*src) += strlen(keywords[find]);
+
+ // handle it
+ switch (find)
+ {
+ // number of inputs
+ case KW_INPUTS:
+ pinfo->inputs = suck_number(src, srcend);
+ if (pinfo->inputs == 0 || pinfo->inputs >= (JED_MAX_FUSES/2))
+ return false;
+
+ if (LOG_PARSE) printf("Inputs: %u\n", pinfo->inputs);
+ break;
+
+ // number of outputs
+ case KW_OUTPUTS:
+ pinfo->outputs = suck_number(src, srcend);
+ if (pinfo->outputs == 0 || pinfo->outputs >= (JED_MAX_FUSES/2))
+ return false;
+
+ if (LOG_PARSE) printf("Outputs: %u\n", pinfo->outputs);
+ break;
+
+ // number of product terms (optional)
+ case KW_TERMS:
+ pinfo->terms = suck_number(src, srcend);
+ if (pinfo->terms == 0 || pinfo->terms >= (JED_MAX_FUSES/2))
+ return false;
+
+ if (LOG_PARSE) printf("Terms: %u\n", pinfo->terms);
+ break;
+
+ // output polarity (optional)
+ case KW_PHASE:
+ if (LOG_PARSE) printf("Phase...\n");
+ while (*src < srcend && !iscrlf(**src) && pinfo->xorptr < (JED_MAX_FUSES/2))
+ {
+ if (**src == '0' || **src == '1')
+ {
+ // 0 is negative
+ if (**src == '0')
+ pinfo->xorval[pinfo->xorptr/32] |= 1 << (pinfo->xorptr & 31);
+ pinfo->xorptr++;
+ }
+ (*src)++;
+ }
+ break;
+
+ // end of file (optional)
+ case KW_END:
+ if (LOG_PARSE) printf("End of file\n");
+ break;
+ }
+
+ return true;
+}
+
+
+
+/*-------------------------------------------------
+ pla_parse - parse a Berkeley standard PLA file
+ that has been loaded raw into memory
+-------------------------------------------------*/
+
+/**
+ * @fn int pla_parse(const void *data, size_t length, jed_data *result)
+ *
+ * @brief Pla parse.
+ *
+ * @param data The data.
+ * @param length The length.
+ * @param [out] result If non-null, the result.
+ *
+ * @return An int.
+ */
+
+int pla_parse(const void *data, size_t length, jed_data *result)
+{
+ const UINT8 *src = (const UINT8 *)data;
+ const UINT8 *srcend = src + length;
+
+ parse_info pinfo;
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ result->numfuses = 0;
+ memset(result->fusemap, 0, sizeof(result->fusemap));
+
+ while (src < srcend)
+ {
+ switch (*src)
+ {
+ // comment line
+ case '#':
+ while (src < srcend && !iscrlf(*src))
+ src++;
+ break;
+
+ // keyword
+ case '.':
+ src++;
+ if (!process_field(result, &src, srcend, &pinfo))
+ return JEDERR_INVALID_DATA;
+ break;
+
+ // terms
+ case '0': case '1': case '-': case '~':
+ if (!process_terms(result, &src, srcend, &pinfo))
+ return JEDERR_INVALID_DATA;
+ break;
+
+ default:
+ src++;
+ break;
+ }
+ }
+
+ // write output polarity
+ if (pinfo.xorptr > 0)
+ {
+ if (LOG_PARSE) printf("Polarity: ");
+
+ for (int i = 0; i < pinfo.outputs; i++)
+ {
+ int bit = pinfo.xorval[i/32] >> (i & 31) & 1;
+ jed_set_fuse(result, result->numfuses++, bit);
+ if (LOG_PARSE) printf("%d", bit);
+ }
+ if (LOG_PARSE) printf("\n");
+ }
+
+ return JEDERR_NONE;
+}