trunk/src/lib/util/plaparse.c
| r241932 | r241933 | |
| 61 | 61 | character stream |
| 62 | 62 | -------------------------------------------------*/ |
| 63 | 63 | |
| 64 | | static UINT32 suck_number(const UINT8 **cursrc, const UINT8 *srcend) |
| 64 | static UINT32 suck_number(const UINT8 **src, const UINT8 *srcend) |
| 65 | 65 | { |
| 66 | 66 | UINT32 value = 0; |
| 67 | | (*cursrc)++; |
| 68 | 67 | |
| 69 | 68 | // find first digit |
| 70 | | while (*cursrc < srcend && !iscrlf(**cursrc) && !isdigit(**cursrc)) |
| 71 | | (*cursrc)++; |
| 72 | | if (*cursrc >= srcend) |
| 73 | | return 0; |
| 69 | while (*src < srcend && !iscrlf(**src) && !isdigit(**src)) |
| 70 | (*src)++; |
| 74 | 71 | |
| 75 | 72 | // loop over and accumulate digits |
| 76 | | while (isdigit(**cursrc)) |
| 73 | while (*src < srcend && isdigit(**src)) |
| 77 | 74 | { |
| 78 | | value = value * 10 + (**cursrc) - '0'; |
| 79 | | (*cursrc)++; |
| 75 | value = value * 10 + (**src) - '0'; |
| 76 | (*src)++; |
| 80 | 77 | } |
| 81 | 78 | |
| 82 | 79 | return value; |
| r241932 | r241933 | |
| 92 | 89 | process_terms - process input/output matrix |
| 93 | 90 | -------------------------------------------------*/ |
| 94 | 91 | |
| 95 | | static bool process_terms(jed_data *data, const UINT8 **cursrc, const UINT8 *srcend, parse_info *pinfo) |
| 92 | static bool process_terms(jed_data *data, const UINT8 **src, const UINT8 *srcend, parse_info *pinfo) |
| 96 | 93 | { |
| 97 | 94 | UINT32 curinput = 0; |
| 98 | 95 | UINT32 curoutput = 0; |
| 99 | 96 | bool outputs = false; |
| 97 | |
| 98 | // symbols for 0, 1, dont_care, no_meaning |
| 99 | // PLA format documentation also describes them as simply 0, 1, 2, 3 |
| 100 | static const char symbols[] = { "01-~" }; |
| 100 | 101 | |
| 101 | | while (*cursrc < srcend && **cursrc != '.' && **cursrc != '#') |
| 102 | while (*src < srcend && **src != '.' && **src != '#') |
| 102 | 103 | { |
| 103 | | switch (**cursrc) |
| 104 | if (!outputs) |
| 104 | 105 | { |
| 105 | | case '-': |
| 106 | | if (!outputs) |
| 107 | | { |
| 108 | | curinput++; |
| 106 | // and-matrix |
| 107 | if (strrchr(symbols, **src)) |
| 108 | curinput++; |
| 109 | |
| 110 | switch (**src) |
| 111 | { |
| 112 | case '0': |
| 113 | jed_set_fuse(data, data->numfuses++, 0); |
| 109 | 114 | jed_set_fuse(data, data->numfuses++, 1); |
| 115 | |
| 116 | if (LOG_PARSE) printf("01"); |
| 117 | break; |
| 118 | |
| 119 | case '1': |
| 110 | 120 | jed_set_fuse(data, data->numfuses++, 1); |
| 121 | jed_set_fuse(data, data->numfuses++, 0); |
| 111 | 122 | |
| 123 | if (LOG_PARSE) printf("10"); |
| 124 | break; |
| 125 | |
| 126 | // anything goes |
| 127 | case '-': |
| 128 | jed_set_fuse(data, data->numfuses++, 1); |
| 129 | jed_set_fuse(data, data->numfuses++, 1); |
| 130 | |
| 112 | 131 | if (LOG_PARSE) printf("11"); |
| 113 | | } |
| 114 | | break; |
| 132 | break; |
| 115 | 133 | |
| 116 | | case '~': |
| 117 | | if (!outputs) |
| 118 | | { |
| 119 | | curinput++; |
| 120 | | // this product term is inhibited |
| 134 | // this product term is inhibited |
| 135 | case '~': |
| 121 | 136 | jed_set_fuse(data, data->numfuses++, 0); |
| 122 | 137 | jed_set_fuse(data, data->numfuses++, 0); |
| 123 | 138 | |
| 124 | 139 | if (LOG_PARSE) printf("00"); |
| 125 | | } |
| 126 | | break; |
| 140 | break; |
| 127 | 141 | |
| 128 | | case '1': |
| 129 | | if (outputs) |
| 142 | case ' ': case '\t': |
| 143 | if (curinput > 0) |
| 144 | { |
| 145 | outputs = true; |
| 146 | if (LOG_PARSE) printf(" "); |
| 147 | } |
| 148 | break; |
| 149 | |
| 150 | default: |
| 151 | break; |
| 152 | } |
| 153 | } |
| 154 | else |
| 155 | { |
| 156 | // or-matrix |
| 157 | if (strrchr(symbols, **src)) |
| 158 | { |
| 159 | curoutput++; |
| 160 | if (**src == '1') |
| 130 | 161 | { |
| 131 | | curoutput++; |
| 132 | 162 | jed_set_fuse(data, data->numfuses++, 0); |
| 133 | | |
| 134 | 163 | if (LOG_PARSE) printf("0"); |
| 135 | 164 | } |
| 136 | 165 | else |
| 137 | 166 | { |
| 138 | | curinput++; |
| 167 | // write 1 for anything else |
| 139 | 168 | jed_set_fuse(data, data->numfuses++, 1); |
| 140 | | jed_set_fuse(data, data->numfuses++, 0); |
| 141 | | |
| 142 | | if (LOG_PARSE) printf("10"); |
| 143 | | } |
| 144 | | break; |
| 145 | | |
| 146 | | case '0': |
| 147 | | if (outputs) |
| 148 | | { |
| 149 | | curoutput++; |
| 150 | | jed_set_fuse(data, data->numfuses++, 1); |
| 151 | | |
| 152 | 169 | if (LOG_PARSE) printf("1"); |
| 153 | 170 | } |
| 154 | | else |
| 155 | | { |
| 156 | | curinput++; |
| 157 | | jed_set_fuse(data, data->numfuses++, 0); |
| 158 | | jed_set_fuse(data, data->numfuses++, 1); |
| 159 | | |
| 160 | | if (LOG_PARSE) printf("01"); |
| 161 | | } |
| 162 | | break; |
| 163 | | |
| 164 | | case ' ': case '\t': |
| 165 | | if (curinput > 0 && !outputs) |
| 166 | | { |
| 167 | | outputs = true; |
| 168 | | if (LOG_PARSE) printf(" "); |
| 169 | | } |
| 170 | | break; |
| 171 | | |
| 172 | | default: |
| 173 | | break; |
| 171 | } |
| 174 | 172 | } |
| 175 | 173 | |
| 176 | | if (iscrlf(**cursrc) && outputs) |
| 174 | if (iscrlf(**src) && outputs) |
| 177 | 175 | { |
| 178 | 176 | outputs = false; |
| 179 | 177 | if (LOG_PARSE) printf("\n"); |
| r241932 | r241933 | |
| 185 | 183 | curoutput = 0; |
| 186 | 184 | } |
| 187 | 185 | |
| 188 | | (*cursrc)++; |
| 186 | (*src)++; |
| 189 | 187 | } |
| 190 | 188 | |
| 191 | 189 | return true; |
| r241932 | r241933 | |
| 197 | 195 | process_field - process a single field |
| 198 | 196 | -------------------------------------------------*/ |
| 199 | 197 | |
| 200 | | static bool process_field(jed_data *data, const UINT8 **cursrc, const UINT8 *srcend, parse_info *pinfo) |
| 198 | static bool process_field(jed_data *data, const UINT8 **src, const UINT8 *srcend, parse_info *pinfo) |
| 201 | 199 | { |
| 202 | | (*cursrc)++; |
| 203 | | |
| 204 | | switch (**cursrc) |
| 200 | // valid keywords |
| 201 | static const char *const keywords[] = { "i", "o", "p", "phase", "e", "\0" }; |
| 202 | enum |
| 205 | 203 | { |
| 204 | KW_INPUTS = 0, |
| 205 | KW_OUTPUTS, |
| 206 | KW_TERMS, |
| 207 | KW_PHASE, |
| 208 | KW_END, |
| 209 | |
| 210 | KW_INVALID |
| 211 | }; |
| 212 | |
| 213 | // find keyword |
| 214 | char dest[0x10]; |
| 215 | memset(dest, 0, ARRAY_LENGTH(dest)); |
| 216 | const UINT8 *seek = *src; |
| 217 | int destptr = 0; |
| 218 | |
| 219 | while (seek < srcend && isalpha(*seek) && destptr < ARRAY_LENGTH(dest) - 1) |
| 220 | { |
| 221 | dest[destptr] = tolower(*seek); |
| 222 | seek++; |
| 223 | destptr++; |
| 224 | } |
| 225 | |
| 226 | UINT8 find = 0; |
| 227 | while (strlen(keywords[find]) && strcmp(dest, keywords[find])) |
| 228 | find++; |
| 229 | |
| 230 | if (find == KW_INVALID) |
| 231 | return false; |
| 232 | |
| 233 | (*src) += strlen(keywords[find]); |
| 234 | |
| 235 | // handle it |
| 236 | switch (find) |
| 237 | { |
| 206 | 238 | // number of inputs |
| 207 | | case 'i': case 'I': |
| 208 | | pinfo->inputs = suck_number(cursrc, srcend); |
| 239 | case KW_INPUTS: |
| 240 | pinfo->inputs = suck_number(src, srcend); |
| 209 | 241 | if (pinfo->inputs == 0 || pinfo->inputs >= (JED_MAX_FUSES/2)) |
| 210 | 242 | return false; |
| 211 | 243 | |
| r241932 | r241933 | |
| 213 | 245 | break; |
| 214 | 246 | |
| 215 | 247 | // number of outputs |
| 216 | | case 'o': case 'O': |
| 217 | | pinfo->outputs = suck_number(cursrc, srcend); |
| 248 | case KW_OUTPUTS: |
| 249 | pinfo->outputs = suck_number(src, srcend); |
| 218 | 250 | if (pinfo->outputs == 0 || pinfo->outputs >= (JED_MAX_FUSES/2)) |
| 219 | 251 | return false; |
| 220 | 252 | |
| 221 | 253 | if (LOG_PARSE) printf("Outputs: %u\n", pinfo->outputs); |
| 222 | 254 | break; |
| 223 | 255 | |
| 224 | | case 'p': case 'P': |
| 225 | | // output polarity (optional) |
| 226 | | if (tolower((*cursrc)[1]) == 'h' && tolower((*cursrc)[2]) == 'a' && tolower((*cursrc)[3]) == 's' && tolower((*cursrc)[4]) == 'e') |
| 256 | // number of product terms (optional) |
| 257 | case KW_TERMS: |
| 258 | pinfo->terms = suck_number(src, srcend); |
| 259 | if (pinfo->terms == 0 || pinfo->terms >= (JED_MAX_FUSES/2)) |
| 260 | return false; |
| 261 | |
| 262 | if (LOG_PARSE) printf("Terms: %u\n", pinfo->terms); |
| 263 | break; |
| 264 | |
| 265 | // output polarity (optional) |
| 266 | case KW_PHASE: |
| 267 | if (LOG_PARSE) printf("Phase...\n"); |
| 268 | while (*src < srcend && !iscrlf(**src) && pinfo->xorptr < (JED_MAX_FUSES/2)) |
| 227 | 269 | { |
| 228 | | if (LOG_PARSE) printf("Phase...\n"); |
| 229 | | while (*cursrc < srcend && !iscrlf(**cursrc) && pinfo->xorptr < (JED_MAX_FUSES/2)) |
| 270 | if (**src == '0' || **src == '1') |
| 230 | 271 | { |
| 231 | | if (**cursrc == '0' || **cursrc == '1') |
| 232 | | { |
| 233 | | // 0 is negative |
| 234 | | if (**cursrc == '0') |
| 235 | | pinfo->xorval[pinfo->xorptr/32] |= 1 << (pinfo->xorptr & 31); |
| 236 | | pinfo->xorptr++; |
| 237 | | } |
| 238 | | |
| 239 | | (*cursrc)++; |
| 272 | // 0 is negative |
| 273 | if (**src == '0') |
| 274 | pinfo->xorval[pinfo->xorptr/32] |= 1 << (pinfo->xorptr & 31); |
| 275 | pinfo->xorptr++; |
| 240 | 276 | } |
| 277 | (*src)++; |
| 241 | 278 | } |
| 242 | | |
| 243 | | // or number of product terms (optional) |
| 244 | | else |
| 245 | | { |
| 246 | | pinfo->terms = suck_number(cursrc, srcend); |
| 247 | | if (pinfo->terms == 0 || pinfo->terms >= (JED_MAX_FUSES/2)) |
| 248 | | return false; |
| 249 | | |
| 250 | | if (LOG_PARSE) printf("Terms: %u\n", pinfo->terms); |
| 251 | | } |
| 252 | 279 | break; |
| 253 | 280 | |
| 254 | 281 | // end of file (optional) |
| 255 | | case 'e': case 'E': |
| 282 | case KW_END: |
| 256 | 283 | if (LOG_PARSE) printf("End of file\n"); |
| 257 | 284 | break; |
| 258 | | |
| 259 | | default: |
| 260 | | return false; |
| 261 | 285 | } |
| 262 | 286 | |
| 263 | 287 | return true; |
| r241932 | r241933 | |
| 272 | 296 | |
| 273 | 297 | int pla_parse(const void *data, size_t length, jed_data *result) |
| 274 | 298 | { |
| 275 | | const UINT8 *cursrc = (const UINT8 *)data; |
| 276 | | const UINT8 *srcend = cursrc + length; |
| 299 | const UINT8 *src = (const UINT8 *)data; |
| 300 | const UINT8 *srcend = src + length; |
| 277 | 301 | |
| 278 | 302 | parse_info pinfo; |
| 279 | 303 | memset(&pinfo, 0, sizeof(pinfo)); |
| r241932 | r241933 | |
| 281 | 305 | result->numfuses = 0; |
| 282 | 306 | memset(result->fusemap, 0, sizeof(result->fusemap)); |
| 283 | 307 | |
| 284 | | while (cursrc < srcend) |
| 308 | while (src < srcend) |
| 285 | 309 | { |
| 286 | | switch (*cursrc) |
| 310 | switch (*src) |
| 287 | 311 | { |
| 288 | 312 | // comment line |
| 289 | 313 | case '#': |
| 290 | | while (cursrc < srcend && !iscrlf(*cursrc)) |
| 291 | | cursrc++; |
| 314 | while (src < srcend && !iscrlf(*src)) |
| 315 | src++; |
| 292 | 316 | break; |
| 293 | 317 | |
| 294 | 318 | // keyword |
| 295 | 319 | case '.': |
| 296 | | if (!process_field(result, &cursrc, srcend, &pinfo)) |
| 320 | src++; |
| 321 | if (!process_field(result, &src, srcend, &pinfo)) |
| 297 | 322 | return JEDERR_INVALID_DATA; |
| 298 | 323 | break; |
| 299 | 324 | |
| 300 | 325 | // terms |
| 301 | 326 | case '0': case '1': case '-': case '~': |
| 302 | | if (!process_terms(result, &cursrc, srcend, &pinfo)) |
| 327 | if (!process_terms(result, &src, srcend, &pinfo)) |
| 303 | 328 | return JEDERR_INVALID_DATA; |
| 304 | 329 | break; |
| 305 | 330 | |
| 306 | 331 | default: |
| 307 | | cursrc++; |
| 332 | src++; |
| 308 | 333 | break; |
| 309 | 334 | } |
| 310 | 335 | } |