libbsdl: scaffold + working BSDL parser (struct + JSON, C ABI)
Standalone LGPL-2.1 parser for BSDL (IEEE 1149.1), shared by essim and bs_explorer. The parser is ported from the Viveris JTAG Core loader, decoupled from jtag_core, and extended with two extractions the original lacks: - PIN_MAP_STRING -> per-port physical package pin, scalar and vector; - TAP_SCAN_* -> TAP signal roles (TDI/TDO/TMS/TCK/TRST). Exposes a stable C ABI (bsdl_parse_file/buffer -> bsdl_t, bsdl_to_json) with a dependency-free JSON serializer and a bsdl2json CLI. CMake builds a versioned shared library with install/export rules for find_package(bsdl). Verified against m2gl010t, xcku040 and xcku15p (100% pin mapping, correct IDCODEs and TAP roles); api and parse regression tests pass, clean build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
90
tests/test_api.c
Normal file
90
tests/test_api.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* libbsdl - API test: exercises the lifecycle + JSON layer.
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bsdl/bsdl.h"
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
#define CHECK(cond) do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
||||
failures++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bsdl_opts_t opts;
|
||||
bsdl_t model;
|
||||
char* json;
|
||||
|
||||
/* version is reported and matches the compiled-in macro */
|
||||
CHECK(bsdl_version() != NULL);
|
||||
CHECK(strcmp(bsdl_version(), BSDL_VERSION_STRING) == 0);
|
||||
|
||||
/* defaults are sane */
|
||||
bsdl_opts_default(&opts);
|
||||
CHECK(opts.sort_pins_by_name == 0);
|
||||
CHECK(opts.log == NULL);
|
||||
CHECK(opts.log_user == NULL);
|
||||
|
||||
/* defined behaviour on bad input */
|
||||
CHECK(bsdl_parse_file(NULL, &opts) == NULL);
|
||||
CHECK(bsdl_parse_file("/nonexistent/does-not-exist.bsd", NULL) == NULL);
|
||||
CHECK(bsdl_to_json(NULL) == NULL);
|
||||
bsdl_free(NULL); /* must be NULL-safe */
|
||||
bsdl_string_free(NULL); /* must be NULL-safe */
|
||||
|
||||
/* JSON layer over a hand-built model (independent of the parser) */
|
||||
{
|
||||
static bsdl_pin_t pins[1];
|
||||
static bsdl_instr_t instrs[1];
|
||||
memset(&model, 0, sizeof(model));
|
||||
memset(pins, 0, sizeof(pins));
|
||||
memset(instrs, 0, sizeof(instrs));
|
||||
|
||||
pins[0].name = "TCK";
|
||||
pins[0].dir = BSDL_DIR_IN;
|
||||
pins[0].physical_pin = "W20";
|
||||
pins[0].tap_role = BSDL_TAP_TCK;
|
||||
pins[0].in_bit = -1;
|
||||
pins[0].out_bit = -1;
|
||||
pins[0].ctrl_bit = -1;
|
||||
|
||||
instrs[0].name = "IDCODE";
|
||||
instrs[0].opcode = "001001";
|
||||
|
||||
model.entity = "DEMO";
|
||||
model.src_filename = "demo.bsd";
|
||||
model.idcode = 0x12345678UL;
|
||||
model.idcode_mask = 0xFFFFFFFFUL;
|
||||
model.instruction_length = 6;
|
||||
model.pins = pins;
|
||||
model.pin_count = 1;
|
||||
model.instructions = instrs;
|
||||
model.instruction_count = 1;
|
||||
|
||||
json = bsdl_to_json(&model);
|
||||
CHECK(json != NULL);
|
||||
if (json) {
|
||||
CHECK(strstr(json, "\"entity\":\"DEMO\"") != NULL);
|
||||
CHECK(strstr(json, "\"physical_pin\":\"W20\"") != NULL);
|
||||
CHECK(strstr(json, "\"tap_role\":\"tck\"") != NULL);
|
||||
CHECK(strstr(json, "\"idcode\":\"0x12345678\"") != NULL);
|
||||
CHECK(strstr(json, "\"name\":\"IDCODE\"") != NULL);
|
||||
bsdl_string_free(json);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures) {
|
||||
fprintf(stderr, "%d check(s) failed\n", failures);
|
||||
return 1;
|
||||
}
|
||||
printf("all API checks passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user