User
@5025F_gpiotest.svf 帮我实现完整的流式读取
Cursor
让我先查看SVF文件中大SDR命令的具体格式:
现在我理解了SVF文件的结构。让我实现完整的流式读取:
c
/**
* @file svf_parser.c
* @brief SVF文件解析器(完整流式读取版)
* @author SVF Player Project
* @date 2025
*
* 支持任意大小的SDR命令,通过流式读取实现
*/
#include "svf_parser.h"
#include "jtag.h"
#include "delay.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/* 调试开关 */
#define SVF_DEBUG 0
/* 解析器上下文 */
static SVF_Context svf_ctx;
/* 缓冲区定义 */
#define CMD_BUFFER_SIZE 256 /* 命令头部缓冲区 */
#define CHUNK_SIZE 64 /* 数据块大小(字节)*/
#define HEX_READ_SIZE 256 /* 每次读取的hex字符数 */
static char cmd_buffer[CMD_BUFFER_SIZE];
static char hex_buffer[HEX_READ_SIZE + 16];
static uint8_t chunk_tdi[CHUNK_SIZE];
static uint8_t chunk_tdo[CHUNK_SIZE];
static uint8_t chunk_expected[CHUNK_SIZE];
static uint8_t chunk_mask[CHUNK_SIZE];
static char error_desc[64];
/* 内部函数声明 */
static int SVF_HexCharToValue(char c);
static void SVF_SkipWhitespace(const char **str);
static int SVF_ParseNumber(const char **str, uint32_t *value);
static int SVF_ParseFloat(const char **str, float *value);
static int SVF_ParseKeyword(const char **str, char *keyword, int max_len);
/**
* @brief 十六进制字符转数值
*/
static int SVF_HexCharToValue(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return -1;
}
/**
* @brief 解析十六进制字符串到字节数组(内存中的字符串)
*/
static void SVF_ParseHexToBytes(const char *hex_str, int hex_len,
uint8_t *buffer, uint32_t byte_count)
{
memset(buffer, 0, byte_count);
if (hex_len <= 0 || hex_str == NULL) return;
int buf_idx = 0;
int nibble_pos = 0;
for (int i = hex_len - 1; i >= 0 && buf_idx < (int)byte_count; i--) {
char c = hex_str[i];
if (isspace((unsigned char)c)) continue;
int val = SVF_HexCharToValue(c);
if (val < 0) continue;
if (nibble_pos == 0) {
buffer[buf_idx] = (uint8_t)val;
nibble_pos = 1;
} else {
buffer[buf_idx] |= (uint8_t)(val << 4);
buf_idx++;
nibble_pos = 0;
}
}
}
/**
* @brief 从文件读取一个字符
*/
static char SVF_FileReadChar(FIL *file)
{
char c;
UINT br;
if (f_read(file, &c, 1, &br) == FR_OK && br > 0) {
return c;
}
return '\0';
}
/**
* @brief 初始化SVF解析器
*/
void SVF_Parser_Init(void)
{
memset(&svf_ctx, 0, sizeof(SVF_Context));
svf_ctx.end_dr = TAP_IDLE;
svf_ctx.end_ir = TAP_IDLE;
svf_ctx.frequency = 1000000;
error_desc[0] = '\0';
}
/**
* @brief 在文件中搜索字符串,返回找到的位置
*/
static int SVF_SearchInFile(FIL *file, const char *target, uint32_t *found_pos)
{
uint32_t start_pos = f_tell(file);
int target_len = strlen(target);
int match_idx = 0;
char c;
while ((c = SVF_FileReadChar(file)) != '\0') {
if (toupper((unsigned char)c) == toupper((unsigned char)target[match_idx])) {
if (match_idx == 0) {
*found_pos = f_tell(file) - 1;
}
match_idx++;
if (match_idx == target_len) {
return 1; /* 找到 */
}
} else {
match_idx = 0;
}
}
f_lseek(file, start_pos);
return 0; /* 未找到 */
}
/**
* @brief 统计文件中两个位置之间的有效hex字符数
*/
static uint32_t SVF_CountHexChars(FIL *file, uint32_t start_pos, uint32_t end_pos)
{
uint32_t saved_pos = f_tell(file);
uint32_t count = 0;
char c;
f_lseek(file, start_pos);
while (f_tell(file) < end_pos) {
c = SVF_FileReadChar(file);
if (c == '\0') break;
if (SVF_HexCharToValue(c) >= 0) {
count++;
}
}
f_lseek(file, saved_pos);
return count;
}
/**
* @brief 从文件指定范围读取hex数据并转换为字节(流式,从末尾开始)
* @param file: 文件指针
* @param hex_start: hex数据起始位置
* @param hex_end: hex数据结束位置(')'的位置)
* @param buffer: 输出缓冲区
* @param byte_count: 需要读取的字节数
* @param byte_offset: 从第几个字节开始(从LSB端计数)
* @return 实际读取的字节数
*/
static uint32_t SVF_ReadHexFromFile(FIL *file, uint32_t hex_start, uint32_t hex_end,
uint8_t *buffer, uint32_t byte_count, uint32_t byte_offset)
{
memset(buffer, 0, byte_count);
uint32_t saved_pos = f_tell(file);
/* 需要跳过的nibble数(从末尾算) */
uint32_t skip_nibbles = byte_offset * 2;
/* 需要读取的nibble数 */
uint32_t need_nibbles = byte_count * 2;
/* 从hex_end-1开始向前扫描 */
uint32_t pos = hex_end - 1;
uint32_t nibbles_skipped = 0;
uint32_t nibbles_read = 0;
int buf_idx = 0;
int nibble_in_byte = 0; /* 0=低nibble, 1=高nibble */
while (pos >= hex_start && nibbles_read < need_nibbles) {
f_lseek(file, pos);
char c = SVF_FileReadChar(file);
int val = SVF_HexCharToValue(c);
if (val >= 0) {
if (nibbles_skipped < skip_nibbles) {
/* 跳过这些nibble */
nibbles_skipped++;
} else {
/* 存储这个nibble */
if (nibble_in_byte == 0) {
buffer[buf_idx] = (uint8_t)val;
nibble_in_byte = 1;
} else {
buffer[buf_idx] |= (uint8_t)(val << 4);
buf_idx++;
nibble_in_byte = 0;
}
nibbles_read++;
}
}
if (pos == 0) break;
pos--;
}
f_lseek(file, saved_pos);
return (nibbles_read + 1) / 2;
}
/**
* @brief 执行大的SDR命令(真正的流式处理)
*/
static SVF_Result SVF_ExecuteLargeSDR(FIL *file, uint32_t bit_count)
{
JTAG_Result jtag_result;
uint32_t byte_count = (bit_count + 7) / 8;
printf("SDR %lu bits (%lu bytes) streaming...\r\n", bit_count, byte_count);
/* 保存当前位置 */
uint32_t cmd_start_pos = f_tell(file);
/* 搜索 TDI ( */
uint32_t tdi_pos;
if (!SVF_SearchInFile(file, "TDI", &tdi_pos)) {
sprintf(error_desc, "TDI not found in SDR");
return SVF_ERROR_SYNTAX;
}
/* 跳过 "TDI" 和空白,找到 '(' */
f_lseek(file, tdi_pos + 3);
char c;
while ((c = SVF_FileReadChar(file)) != '\0') {
if (c == '(') break;
if (!isspace((unsigned char)c)) {
sprintf(error_desc, "Expected '(' after TDI");
return SVF_ERROR_SYNTAX;
}
}
uint32_t hex_start = f_tell(file); /* '(' 后的位置 */
/* 找到匹配的 ')' */
int paren_depth = 1;
uint32_t hex_end = hex_start;
while ((c = SVF_FileReadChar(file)) != '\0') {
if (c == '(') paren_depth++;
else if (c == ')') {
paren_depth--;
if (paren_depth == 0) {
hex_end = f_tell(file) - 1; /* ')' 的位置 */
break;
}
}
}
if (paren_depth != 0) {
sprintf(error_desc, "Unmatched parenthesis");
return SVF_ERROR_SYNTAX;
}
/* 跳过到命令结束(分号) */
while ((c = SVF_FileReadChar(file)) != '\0' && c != ';') {
if (c == '\n') svf_ctx.line_number++;
}
printf(" Hex data: pos %lu - %lu\r\n", hex_start, hex_end);
/* 进入DRSHIFT状态 */
jtag_result = JTAG_GotoState(TAP_DRSHIFT);
if (jtag_result != JTAG_OK) {
sprintf(error_desc, "Cannot enter DRSHIFT");
return SVF_ERROR_JTAG;
}
/* 分块处理 */
uint32_t bits_remaining = bit_count;
uint32_t byte_offset = 0;
uint32_t chunk_bits = CHUNK_SIZE * 8;
uint32_t progress_step = byte_count / 20;
if (progress_step < 1000) progress_step = 1000;
uint32_t last_progress = 0;
while (bits_remaining > 0) {
uint32_t this_bits = (bits_remaining > chunk_bits) ? chunk_bits : bits_remaining;
uint32_t this_bytes = (this_bits + 7) / 8;
uint8_t is_last = (bits_remaining <= chunk_bits);
/* 从文件读取hex数据 */
SVF_ReadHexFromFile(file, hex_start, hex_end,
chunk_tdi, this_bytes, byte_offset);
#if SVF_DEBUG
if (byte_offset < 64) {
printf(" Chunk[%lu]: ", byte_offset);
for (int i = this_bytes - 1; i >= 0; i--) {
printf("%02X", chunk_tdi[i]);
}
printf("\r\n");
}
#endif
/* JTAG移位 */
jtag_result = JTAG_ShiftBits(chunk_tdi, NULL, this_bits, is_last ? 1 : 0);
if (jtag_result != JTAG_OK) {
sprintf(error_desc, "JTAG shift error");
return SVF_ERROR_JTAG;
}
bits_remaining -= this_bits;
byte_offset += this_bytes;
/* 进度显示 */
if (byte_offset - last_progress >= progress_step) {
printf(" %lu / %lu bytes (%lu%%)\r\n",
byte_offset, byte_count, (byte_offset * 100) / byte_count);
last_progress = byte_offset;
}
}
/* 移到结束状态 */
JTAG_GotoState(svf_ctx.end_dr);
printf(" SDR complete\r\n");
return SVF_OK;
}
/**
* @brief 执行小的SIR/SDR命令
*/
static SVF_Result SVF_ExecuteSmallShift(uint32_t bit_count, const char *params, uint8_t is_ir)
{
const char *p = params;
uint32_t byte_count = (bit_count + 7) / 8;
if (byte_count > CHUNK_SIZE) {
sprintf(error_desc, "Data too large");
return SVF_ERROR_BUFFER_OVERFLOW;
}
/* 初始化 */
memset(chunk_tdi, is_ir ? 0xFF : 0x00, byte_count);
memset(chunk_expected, 0, byte_count);
memset(chunk_mask, 0xFF, byte_count);
uint8_t has_tdo = 0;
#if SVF_DEBUG
printf("%s %lu bits\r\n", is_ir ? "SIR" : "SDR", bit_count);
#endif
/* 解析参数 */
while (*p) {
char key[8];
SVF_SkipWhitespace(&p);
if (!SVF_ParseKeyword(&p, key, sizeof(key))) break;
SVF_SkipWhitespace(&p);
if (*p == '(') {
p++;
const char *hex_start = p;
int depth = 1;
while (*p && depth > 0) {
if (*p == '(') depth++;
else if (*p == ')') depth--;
if (depth > 0) p++;
}
int hex_len = p - hex_start;
if (*p == ')') p++;
uint8_t *target = NULL;
if (strcmp(key, "TDI") == 0) {
target = chunk_tdi;
} else if (strcmp(key, "TDO") == 0) {
target = chunk_expected;
has_tdo = 1;
} else if (strcmp(key, "MASK") == 0) {
target = chunk_mask;
}
if (target) {
SVF_ParseHexToBytes(hex_start, hex_len, target, byte_count);
#if SVF_DEBUG
printf(" %s: 0x", key);
for (int i = byte_count - 1; i >= 0; i--) printf("%02X", target[i]);
printf("\r\n");
#endif
}
}
}
/* 执行JTAG */
JTAG_Result jr;
if (is_ir) {
jr = JTAG_ShiftIR(chunk_tdi, has_tdo ? chunk_tdo : NULL, bit_count, svf_ctx.end_ir);
} else {
jr = JTAG_ShiftDR(chunk_tdi, has_tdo ? chunk_tdo : NULL, bit_count, svf_ctx.end_dr);
}
if (jr != JTAG_OK) {
sprintf(error_desc, "JTAG %s error %d", is_ir ? "IR" : "DR", jr);
return SVF_ERROR_JTAG;
}
if (has_tdo) {
if (JTAG_CompareTDO(chunk_tdo, chunk_expected, chunk_mask, bit_count) != JTAG_OK) {
sprintf(error_desc, "%s TDO mismatch", is_ir ? "IR" : "DR");
return SVF_ERROR_TDO_MISMATCH;
}
}
return SVF_OK;
}
/**
* @brief 读取完整命令到缓冲区(用于小命令)
*/
static int SVF_ReadSmallCommand(FIL *file)
{
int len = 0;
char c;
uint8_t in_comment = 0;
uint8_t last_space = 1;
while ((c = SVF_FileReadChar(file)) != '\0') {
if (c == '\n') {
svf_ctx.line_number++;
if (in_comment) in_comment = 0;
}
if (c == '!') { in_comment = 1; continue; }
if (in_comment) continue;
if (c == ';') {
cmd_buffer[len] = '\0';
return len;
}
if (isspace((unsigned char)c)) {
if (!last_space && len > 0 && len < CMD_BUFFER_SIZE - 1) {
cmd_buffer[len++] = ' ';
}
last_space = 1;
continue;
}
last_space = 0;
if (len < CMD_BUFFER_SIZE - 1) {
cmd_buffer[len++] = c;
}
}
cmd_buffer[len] = '\0';
return len;
}
/**
* @brief 主解析函数
*/
SVF_Result SVF_Parse_File(FIL *file)
{
SVF_Result result;
svf_ctx.file = file;
svf_ctx.line_number = 1;
svf_ctx.cmd_count = 0;
svf_ctx.sir_count = 0;
svf_ctx.sdr_count = 0;
f_lseek(file, 0);
printf("=== SVF Parsing Start ===\r\n");
while (1) {
/* 保存命令开始位置 */
uint32_t cmd_pos = f_tell(file);
/* 读取命令头部(判断命令类型和大小) */
int len = SVF_ReadSmallCommand(file);
if (len == 0 && f_eof(file)) break;
if (len == 0) continue;
const char *p = cmd_buffer;
char keyword[16];
SVF_SkipWhitespace(&p);
if (!SVF_ParseKeyword(&p, keyword, sizeof(keyword))) continue;
/* SDR 命令 */
if (strcmp(keyword, "SDR") == 0) {
uint32_t bit_count;
SVF_SkipWhitespace(&p);
if (!SVF_ParseNumber(&p, &bit_count)) continue;
svf_ctx.sdr_count++;
/* 判断是否为大命令 */
uint32_t byte_count = (bit_count + 7) / 8;
if (byte_count > CHUNK_SIZE) {
/* 大命令:回退到命令开始位置,重新流式处理 */
f_lseek(file, cmd_pos);
/* 跳过 "SDR xxx" 部分 */
char c;
while ((c = SVF_FileReadChar(file)) != '\0') {
if (isdigit((unsigned char)c)) {
/* 跳过数字 */
while ((c = SVF_FileReadChar(file)) != '\0' && isdigit((unsigned char)c));
break;
}
}
result = SVF_ExecuteLargeSDR(file, bit_count);
} else {
result = SVF_ExecuteSmallShift(bit_count, p, 0);
}
if (result != SVF_OK) {
printf("Error line %lu: %s\r\n", svf_ctx.line_number, error_desc);
return result;
}
}
/* SIR 命令 */
else if (strcmp(keyword, "SIR") == 0) {
uint32_t bit_count;
SVF_SkipWhitespace(&p);
if (!SVF_ParseNumber(&p, &bit_count)) continue;
svf_ctx.sir_count++;
result = SVF_ExecuteSmallShift(bit_count, p, 1);
if (result != SVF_OK) {
printf("Error line %lu: %s\r\n", svf_ctx.line_number, error_desc);
return result;
}
}
/* RUNTEST 命令 */
else if (strcmp(keyword, "RUNTEST") == 0) {
uint32_t tck_count = 0;
float sec_time = 0;
JTAG_TapState run_state = TAP_IDLE;
while (*p) {
char key[16];
SVF_SkipWhitespace(&p);
if (!SVF_ParseKeyword(&p, key, sizeof(key))) break;
if (strcmp(key, "IDLE") == 0) { run_state = TAP_IDLE; continue; }
if (strcmp(key, "RESET") == 0) { run_state = TAP_RESET; continue; }
if (strcmp(key, "DRPAUSE") == 0) { run_state = TAP_DRPAUSE; continue; }
if (strcmp(key, "IRPAUSE") == 0) { run_state = TAP_IRPAUSE; continue; }
char *endptr;
float fval = strtof(key, &endptr);
if (endptr != key) {
SVF_SkipWhitespace(&p);
char unit[8];
if (SVF_ParseKeyword(&p, unit, sizeof(unit))) {
if (strcmp(unit, "TCK") == 0) tck_count = (uint32_t)fval;
else if (strcmp(unit, "SEC") == 0) sec_time = fval;
else if (strcmp(unit, "MS") == 0) sec_time = fval / 1000.0f;
else if (strcmp(unit, "US") == 0) sec_time = fval / 1000000.0f;
}
}
}
JTAG_GotoState(run_state);
if (tck_count > 0) JTAG_RunTest(tck_count);
if (sec_time > 0) JTAG_Wait(sec_time);
}
/* STATE 命令 */
else if (strcmp(keyword, "STATE") == 0) {
while (*p) {
char state_name[16];
SVF_SkipWhitespace(&p);
if (!SVF_ParseKeyword(&p, state_name, sizeof(state_name))) break;
JTAG_GotoState(JTAG_StateFromName(state_name));
}
}
/* FREQUENCY 命令 */
else if (strcmp(keyword, "FREQUENCY") == 0) {
float freq;
SVF_SkipWhitespace(&p);
if (SVF_ParseFloat(&p, &freq)) {
char unit[8];
SVF_SkipWhitespace(&p);
if (SVF_ParseKeyword(&p, unit, sizeof(unit))) {
if (strcmp(unit, "HZ") == 0) svf_ctx.frequency = (uint32_t)freq;
else if (strcmp(unit, "KHZ") == 0) svf_ctx.frequency = (uint32_t)(freq * 1000);
else if (strcmp(unit, "MHZ") == 0) svf_ctx.frequency = (uint32_t)(freq * 1000000);
} else {
svf_ctx.frequency = (uint32_t)freq;
}
JTAG_SetFrequency(svf_ctx.frequency);
printf("Freq: %lu Hz\r\n", svf_ctx.frequency);
}
}
/* ENDDR/ENDIR */
else if (strcmp(keyword, "ENDDR") == 0) {
char state[16];
SVF_SkipWhitespace(&p);
if (SVF_ParseKeyword(&p, state, sizeof(state))) {
svf_ctx.end_dr = JTAG_StateFromName(state);
}
}
else if (strcmp(keyword, "ENDIR") == 0) {
char state[16];
SVF_SkipWhitespace(&p);
if (SVF_ParseKeyword(&p, state, sizeof(state))) {
svf_ctx.end_ir = JTAG_StateFromName(state);
}
}
/* HDR/HIR/TDR/TIR */
else if (strcmp(keyword, "HDR") == 0) {
SVF_SkipWhitespace(&p);
SVF_ParseNumber(&p, &svf_ctx.hdr_length);
}
else if (strcmp(keyword, "HIR") == 0) {
SVF_SkipWhitespace(&p);
SVF_ParseNumber(&p, &svf_ctx.hir_length);
}
else if (strcmp(keyword, "TDR") == 0) {
SVF_SkipWhitespace(&p);
SVF_ParseNumber(&p, &svf_ctx.tdr_length);
}
else if (strcmp(keyword, "TIR") == 0) {
SVF_SkipWhitespace(&p);
SVF_ParseNumber(&p, &svf_ctx.tir_length);
}
svf_ctx.cmd_count++;
if (svf_ctx.cmd_count % 20 == 0) {
printf("Cmds: %lu\r\n", svf_ctx.cmd_count);
}
}
printf("=== SVF Complete ===\r\n");
printf("Total: %lu cmds (SIR:%lu SDR:%lu)\r\n",
svf_ctx.cmd_count, svf_ctx.sir_count, svf_ctx.sdr_count);
return SVF_OK;
}
/* 辅助函数 */
static void SVF_SkipWhitespace(const char **str)
{
while (**str && isspace((unsigned char)**str)) (*str)++;
}
static int SVF_ParseNumber(const char **str, uint32_t *value)
{
const char *p = *str;
SVF_SkipWhitespace(&p);
char *endptr;
*value = strtoul(p, &endptr, 10);
if (endptr == p) return 0;
*str = endptr;
return 1;
}
static int SVF_ParseFloat(const char **str, float *value)
{
const char *p = *str;
SVF_SkipWhitespace(&p);
char *endptr;
*value = strtof(p, &endptr);
if (endptr == p) return 0;
*str = endptr;
return 1;
}
static int SVF_ParseKeyword(const char **str, char *keyword, int max_len)
{
const char *p = *str;
int len = 0;
SVF_SkipWhitespace(&p);
while (*p && (isalnum((unsigned char)*p) || *p == '_')) {
if (len < max_len - 1) {
keyword[len++] = toupper((unsigned char)*p);
}
p++;
}
keyword[len] = '\0';
*str = p;
return len > 0;
}
void SVF_GetStats(uint32_t *cmd_count, uint32_t *sir_count, uint32_t *sdr_count)
{
if (cmd_count) *cmd_count = svf_ctx.cmd_count;
if (sir_count) *sir_count = svf_ctx.sir_count;
if (sdr_count) *sdr_count = svf_ctx.sdr_count;
}
const char* SVF_GetLastError(void)
{
return error_desc;
}
我已经实现了完整的流式读取。主要特点:
流式处理实现
核心函数 SVF_ReadHexFromFile()
c
/* 从文件中读取hex数据,从末尾向前处理 */
/* 支持任意偏移量,实现分块读取 */
static uint32_t SVF_ReadHexFromFile(FIL *file,
uint32_t hex_start, /* hex数据起始位置 */
uint32_t hex_end, /* hex数据结束位置 */
uint8_t *buffer, /* 输出缓冲区 */
uint32_t byte_count, /* 本次读取字节数 */
uint32_t byte_offset) /* 从第几字节开始 */
大SDR命令处理流程
- 定位
TDI (的位置 - 找到匹配的
)确定数据范围 - 分块处理:
- 每次读取64字节(512位)
- 从hex数据末尾向前读取(MSB→LSB转换)
- 发送到JTAG
- 显示进度
内存使用
| 缓冲区 | 大小 |
|---|---|
| cmd_buffer | 256字节 |
| hex_buffer | 272字节 |
| chunk_tdi/tdo/expected/mask | 4×64=256字节 |
| 总计 | ~800字节 |
对于你的SVF文件
SDR 4661672 TDI (FFFFFFFF0000007A...);
- 4661672位 = 582709字节
- 分成约9105个64字节块处理
- 每块独立从文件读取,不需要全部加载到RAM
运行时输出示例:
SDR 4661672 bits (582709 bytes) streaming...
Hex data: pos 12345 - 1234567
29000 / 582709 bytes (5%)
58000 / 582709 bytes (10%)
...
SDR complete
c
/* 从文件中读取hex数据,从末尾向前处理 */
/* 支持任意偏移量,实现分块读取 */
static uint32_t SVF_ReadHexFromFile(FIL *file,
uint32_t hex_start, /* hex数据起始位置 */
uint32_t hex_end, /* hex数据结束位置 */
uint8_t *buffer, /* 输出缓冲区 */
uint32_t byte_count, /* 本次读取字节数 */
uint32_t byte_offset) /* 从第几字节开始 */
plaintext
SDR 4661672 TDI (FFFFFFFF0000007A...);
plaintext
SDR 4661672 bits (582709 bytes) streaming...
Hex data: pos 12345 - 1234567
29000 / 582709 bytes (5%)
58000 / 582709 bytes (10%)
...
SDR complete