From 3febc9072a6856013a90243083971387dffd5bb5 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Mon, 14 Jan 2013 19:26:15 -0300 Subject: [PATCH] ubb-patgen/ubb-patgen.c (dma_pattern): move pattern parser to parse_pattern ... and introduce pattern multipliers {} --- ubb-patgen/ubb-patgen.c | 92 ++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 25 deletions(-) diff --git a/ubb-patgen/ubb-patgen.c b/ubb-patgen/ubb-patgen.c index b62ce1e..8f0d927 100644 --- a/ubb-patgen/ubb-patgen.c +++ b/ubb-patgen/ubb-patgen.c @@ -287,27 +287,71 @@ static void send_buffer(const struct mmcclk *clk, } -static int dma_pattern(const struct mmcclk *clk, +static void *parse_pattern(const char *s, int *nibbles) +{ + uint8_t *buf = physmem_malloc(4095); /* maximum block size */ + int n = 0; + uint8_t v = 0; + char *end; + unsigned long i; + + memset(buf, 0, 4095); + while (*s) { + char ch[2] = { *s, 0 }; + + v = strtoul(ch, &end, 16); + if (*end) { + fprintf(stderr, "\"%c\" is not a hex digit\n", *s); + exit(1); + } + if (s[1] == '{') { + i = strtoul(s+2, &end, 0); + if (!*end) { + fprintf(stderr, "unterminated range\n"); + exit(1); + } + if (*end != '}' || end == s+2) { + fprintf(stderr, "invalid range \"%.*s\"\n", + end-s, s+1); + exit(1); + } + s = end+1; + } else { + i = 1; + s++; + } + while (i) { + if (n == 8192-64-1) { + fprintf(stderr, "pattern is too long\n"); + exit(1); + } + buf[n >> 1] |= v << 4*(~n & 1); + n++; + i--; + } + } + /* pad to multiples of 32 bytes */ + while (n & 63) { + buf[n >> 1] |= v << 4*(~n & 1); + n++; + } + *nibbles = n; + return buf; +} + + +static void dma_pattern(const struct mmcclk *clk, const char *pattern, uint32_t mask) { - int n = strlen(pattern); - int rounded = (n+63) & ~63; - uint8_t *buf = physmem_malloc(rounded >> 1); - int i; + const uint8_t *buf; + int n; - if (!n) - return 1; - - memset(buf, 0, rounded); - for (i = 0; i != rounded; i++) { - char ch[2] = { pattern[i < n ? i : n-1], 0 }; - char *end; - - buf[i >> 1] |= strtoul(ch, &end, 16) << 4*(~i & 1); - if (*end) - return 0; + if (!*pattern) { + fprintf(stderr, "pattern is empty\n"); + exit(1); } - + buf = parse_pattern(pattern, &n); + dma_init(); /* Initial static state: the first pattern. */ @@ -317,18 +361,16 @@ static int dma_pattern(const struct mmcclk *clk, PDDATS = (buf[0] >> 4) << 10; PDDIRS = mask; - send_buffer(clk, buf, rounded, mask); + send_buffer(clk, buf, n, mask); /* Final static state: the last pattern. */ - PDDATC = ~((buf[(rounded >> 1)-1] & 0xf) << 10) & mask; - PDDATS = (buf[(rounded >> 1)-1] & 0xf) << 10; + PDDATC = ~((buf[(n >> 1)-1] & 0xf) << 10) & mask; + PDDATS = (buf[(n >> 1)-1] & 0xf) << 10; PDFUNC = mask; dma_cleanup(); - - return 1; } @@ -396,6 +438,7 @@ static void usage(const char *name) " \"+\" selects a frequency >= the specified one, \"-\" one <=.\n" " Without +/-, the closest available frequency is selected.\n" "Pattern: hex digits corresponding to 1 for DAT0, 2 for DAT1, etc.\n" +" {n} repeats the preceding digit n times, e.g., 1{3} is equivalent to 111.\n" , name, name); exit(1); } @@ -482,9 +525,8 @@ int main(int argc, char **argv) mmcclk_start(&clk); if (pattern) - if (!dma_pattern(&clk, pattern, - UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3)) - usage(*argv); + dma_pattern(&clk, pattern, + UBB_DAT0 | UBB_DAT1 | UBB_DAT2 | UBB_DAT3); if (nanosleep(&active_ns, NULL)) perror("nanosleep");