r4502 - in developers/werner: . greg greg/tests

werner at docs.openmoko.org werner at docs.openmoko.org
Thu Jun 26 07:01:11 CEST 2008


Author: werner
Date: 2008-06-26 07:01:10 +0200 (Thu, 26 Jun 2008)
New Revision: 4502

Added:
   developers/werner/greg/
   developers/werner/greg/Makefile
   developers/werner/greg/README
   developers/werner/greg/cpp.c
   developers/werner/greg/cpp.h
   developers/werner/greg/dr.pl
   developers/werner/greg/greg.c
   developers/werner/greg/greg.h
   developers/werner/greg/lang.l
   developers/werner/greg/lang.y
   developers/werner/greg/pcf50633.greg
   developers/werner/greg/reg.h
   developers/werner/greg/tests/
   developers/werner/greg/tests/Common
   developers/werner/greg/tests/Makefile
   developers/werner/greg/tests/field
   developers/werner/greg/tests/reg
   developers/werner/greg/tests/value
   developers/werner/greg/tests/width
Log:
greg is a processor for register definitions. It can be used to pretty-print
register dumps. Work in progress.



Added: developers/werner/greg/Makefile
===================================================================
--- developers/werner/greg/Makefile	                        (rev 0)
+++ developers/werner/greg/Makefile	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,52 @@
+CFLAGS_WARN=-Wall -Wshadow -Wstrict-prototypes -Wmissing-prototypes \
+	    -Wmissing-declarations
+CFLAGS=-g -DCPP='"cpp"' $(CFLAGS_WARN)
+SLOPPY=-Wno-unused -Wno-implicit-function-declaration -Wno-missing-prototypes \
+       -Wno-missing-declarations
+LDLIBS=-lfl
+
+OBJS=greg.o lex.yy.o y.tab.o cpp.o
+
+.PHONY:		all dep depend clean spotless test tests
+
+# ----- Build -----------------------------------------------------------------
+
+all:		greg
+
+greg:		$(OBJS)
+
+lex.yy.c:	lang.l y.tab.h
+		$(LEX) lang.l
+
+lex.yy.o:	lex.yy.c y.tab.h
+		$(CC) -c $(CFLAGS) $(SLOPPY) lex.yy.c
+
+y.tab.c y.tab.h: lang.y
+		$(YACC) $(YYFLAGS) -d lang.y
+
+y.tab.o:	y.tab.c
+		$(CC) -c $(CFLAGS) $(SLOPPY) y.tab.c
+
+# ----- Dependencies ----------------------------------------------------------
+
+dep depend .depend: lex.yy.c y.tab.h y.tab.c
+		$(CPP) $(CFLAGS) -MM -MG *.c >.depend || \
+		  { rm -f .depend; exit 1; }
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+# ----- Cleanup ---------------------------------------------------------------
+
+clean:
+		rm -f lex.yy.c y.tab.h y.tab.c
+		rm -f $(OBJS) .depend
+
+spotless:	clean
+		rm -f greg
+
+# ----- Tests -----------------------------------------------------------------
+
+test tests:	greg
+		$(MAKE) -C tests

Added: developers/werner/greg/README
===================================================================
--- developers/werner/greg/README	                        (rev 0)
+++ developers/werner/greg/README	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,109 @@
+"greg" reads a general register description and can then produce output based
+on this description, or answer queries.
+
+Example: it can pretty-print a register dump.
+
+./greg pcf50633.greg reg_id reg_value ...
+
+Where reg_id is the identifier of the register, e.g., "13" for GPIOCTL,
+and reg_value is the value of that register. Note that reg_id is a
+case-sensitive string, while reg_value is a number in the usual C
+syntax.
+
+
+Known issues
+------------
+
+- output format should be easier to read
+- value names in pcf50633.greg are often unsuitable for identifier generation
+  (should align them properly with what we use in u-boot and kernel)
+- "pretty-print" is hard to read
+- unique() should use rb-trees
+- greg.c should use unique(), to accelerate lookups
+
+
+dr.pl
+-----
+
+dr.pl is a wrapper for "greg". It processes dumps like the one produced by
+the following function (in u-boot):
+
+
+static void dump_pmu(void)
+{
+	int i, j;
+
+	for (i = 0; i != 0x70; i += 16) {
+		printf("%02x:", i);
+		for (j = 0; j != 16; j++)
+			printf(" %02x", pcf50633_reg_read(i+j));
+		printf("\n");
+	}
+}
+
+
+Example register dump (with titles):
+
+
+in LED loop, with battery.
+
+00: 13 84 00 00 00 00 00 00 f0 40 00 00 00 d3 aa 4a
+10: 15 44 ff 01 00 00 00 00 02 08 6b 01 00 0a 1b 02
+20: 00 22 2f 01 00 22 00 00 2f 00 05 20 11 18 00 18
+30: 00 00 00 00 00 15 00 15 00 18 00 00 00 ff 3f 00
+40: 00 07 00 00 28 19 ff ff 00 01 10 33 20 50 19 00
+50: 00 08 00 00 00 0b 00 f0 00 13 14 17 04 19 05 08
+60: 7f 7f 3f 07 3f 1f ff 00 00 00 00 00 00 00 00 00
+
+in LED loop, no battery. (LED on)
+
+00: 13 84 00 00 00 00 00 00 f0 40 00 00 00 d3 aa 4a
+10: 15 44 bf 01 00 00 00 00 03 08 6b 01 00 0a 1b 02
+20: 00 22 2f 01 00 22 00 00 2f 00 05 20 11 18 00 18
+30: 00 00 00 00 00 15 00 15 00 18 00 00 00 ff 3f 00
+40: 00 07 00 00 28 19 ff ff 00 01 10 33 20 d0 19 00
+50: 00 08 00 00 00 0b 00 f0 00 41 14 17 04 19 05 08
+60: 7f 7f 3f 07 3f 1f ff 00 00 00 00 00 00 00 00 00
+
+
+If these two dumps are sent to the standard input of dr.pl, it will
+output the difference between them:
+
+
+----- in LED loop, no battery. (LED on) ---------------------------------------
+--- _a  2008-06-26 01:52:33.000000000 -0300
++++ _b  2008-06-26 01:52:33.000000000 -0300
+@@ -1,11 +1,11 @@
+-18 BVMCTL = 0x02 -- BVM control
++18 BVMCTL = 0x03 -- BVM control
+     bvmlow -- BAT voltage is lower than Vth(batok)
+-       0 (0x0)
++       1 (0x1)
+     bvmlvl -- Vth(batok)
+        001 (0x1): 2_80V
+     bvmdisdb -- 62ms debounce filter
+        0 (0x0): enabled
+-4d MBCS3 = 0x50 -- MBC charger status 3
++4d MBCS3 = 0xd0 -- MBC charger status 3
+     usblim_play -- USB current limiting in USB-to-SYS path
+        0 (0x0)
+     usblim_chg -- USB current limiting in USB-to-BAT path
+@@ -21,7 +21,7 @@
+     vbatstat -- battery voltage > Vbatcond
+        1 (0x1)
+     vres -- battery voltage > Vth(RES)
+-       0 (0x0)
+-59 RTCSC = 0x13 -- RTC second value
++       1 (0x1)
++59 RTCSC = 0x41 -- RTC second value
+     sec -- current seconds, BCD
+-       001.0011 (0x13)
++       100.0001 (0x41)
+
+
+If more than two dumps are input to dr.pl, it will produce the
+difference between the first and the second, then the second and
+the third, and so on.
+
+If only one dump is input to dr.pl, it will pretty-print all
+registers.

Added: developers/werner/greg/cpp.c
===================================================================
--- developers/werner/greg/cpp.c	                        (rev 0)
+++ developers/werner/greg/cpp.c	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,214 @@
+/*
+ * cpp.c - CPP subprocess
+ *
+ * Written 2002-2004, 2006, 2008 by Werner Almesberger
+ * Copyright 2002,2003 California Institute of Technology
+ * Copyright 2004, 2006 Werner Almesberger
+ * Copyright 2008 by OpenMoko, Inc.
+ *
+ * Distributed under GPLv2, or any later version.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "cpp.h"
+
+
+const char *cpp_command = CPP;
+
+static pid_t cpp_pid;
+static int cpp_argc = 0;
+static const char **cpp_argv = NULL;
+static int real_stdin = -1;
+
+
+void add_cpp_arg(const char *arg)
+{
+    if (!cpp_argc)
+	cpp_argc = 1;
+    cpp_argv = realloc(cpp_argv,sizeof(const char *)*(cpp_argc+1));
+    if (!cpp_argv) {
+	perror("realloc");
+	exit(1);
+    }
+    if (cpp_argc == 1)
+	cpp_argv[0] = cpp_command;
+    if (arg) {
+	arg = strdup(arg);
+	if (!arg) {
+	    perror("strdup");
+	    exit(1);
+	}
+    }
+    cpp_argv[cpp_argc++] = arg;
+}
+
+
+void add_cpp_Wp(const char *arg)
+{
+    char *tmp = strdup(arg);
+    char *curr,*end;
+
+    if (!tmp) {
+	perror("strdup");
+	exit(1);
+    }
+    curr = tmp;
+    do {
+	end = strchr(curr,',');
+	if (end)
+	    *end++ = 0;
+	add_cpp_arg(curr);
+	curr = end;
+    }
+    while (end);
+    free(tmp);
+}
+
+
+static void kill_cpp(void)
+{
+    if (cpp_pid)
+	(void) kill(cpp_pid,SIGTERM);
+}
+
+
+static void run_cpp(const char *name,int fd,int close_fd)
+{
+    char **arg;
+    int fds[2];
+
+    if (pipe(fds) < 0) {
+        perror("pipe");
+        exit(1);
+    }
+    if (name)
+	add_cpp_arg(name);
+    add_cpp_arg(NULL);
+    cpp_pid = fork();
+    if (cpp_pid < 0) {
+        perror("fork");
+        exit(1);
+    }
+    if (!cpp_pid) {
+	if (close(fds[0]) < 0) {
+	    perror("close");
+	    exit(1);
+	}
+	if (close_fd != -1 && close(close_fd) < 0) {
+	    perror("close");
+	    exit(1);
+	}
+	if (fd != -1 && dup2(fd,0) < 0) {
+	    perror("dup2");
+	    exit(1);
+	}
+	if (dup2(fds[1],1) < 0) {
+	    perror("dup2");
+	    exit(1);
+	}
+	if (execvp(cpp_command,(char **) cpp_argv) < 0) {
+	  /* prototype is weird */
+	    perror(cpp_command);
+	    exit(1);
+	}
+	/* not reached */
+    }
+    if (close(fds[1]) < 0) {
+	perror("close");
+	exit(1);
+    }
+    real_stdin = dup(0);
+    if (real_stdin < 0) {
+	perror("dup");
+	exit(1);
+    }
+    if (fd != -1 && close(fd) < 0) {
+	perror("close");
+	exit(1);
+    }
+    if (dup2(fds[0],0) < 0) {
+	perror("dup2");
+	exit(1);
+    }
+    for (arg = (char **) cpp_argv+1; *arg; arg++)
+	free(*arg);
+    free(cpp_argv);
+    cpp_argv = NULL;
+    cpp_argc = 0;
+}
+
+
+void run_cpp_on_file(const char *name)
+{
+    run_cpp(name,name ? -1 : 0,-1);
+    atexit(kill_cpp);
+}
+
+
+void run_cpp_on_string(const char *str)
+{
+    int fds[2];
+    pid_t pid;
+    int left,wrote;
+
+    if (pipe(fds) < 0) {
+        perror("pipe");
+        exit(1);
+    }
+    run_cpp(NULL,fds[0],fds[1]);
+    pid = fork();
+    if (pid < 0) {
+	perror("fork");
+	exit(1);
+    }
+    if (!pid) {
+	for (left = strlen(str); left; left -= wrote) {
+	    wrote = write(fds[1],str,left);
+	    if (wrote < 0)
+		break; /* die silently */
+	    str += wrote;
+	}
+	exit(0);
+    }
+    if (close(fds[1]) < 0) {
+	perror("close");
+	exit(1);
+    }
+    atexit(kill_cpp);
+}
+
+
+void reap_cpp(void)
+{
+    int status;
+
+    cpp_pid = 0;
+    if (waitpid(cpp_pid,&status,0) < 0) {
+	perror("waitpid");
+	exit(1);
+    }
+    if (!status) {
+	if (dup2(real_stdin,0) < 0) {
+	    perror("dup2");
+	    exit(1);
+	}
+	return;
+    }
+    if (WIFEXITED(status))
+	exit(WEXITSTATUS(status));
+    if (WIFSIGNALED(status))
+	fprintf(stderr,"cpp terminated with signal %d\n",WTERMSIG(status));
+    else
+	fprintf(stderr,"cpp terminated with incomprehensible status %d\n",
+	  status);
+    exit(1);
+}

Added: developers/werner/greg/cpp.h
===================================================================
--- developers/werner/greg/cpp.h	                        (rev 0)
+++ developers/werner/greg/cpp.h	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,24 @@
+/*
+ * cpp.h - CPP subprocess
+ *
+ * Written 2002,2003,2008 by Werner Almesberger
+ * Copyright 2002,2003 Caltech Netlab FAST project
+ * Copyright 2008 by OpenMoko, Inc.
+ *
+ * Distributed under GPLv2, or any later version.
+ *
+ */
+
+#ifndef CPP_H
+#define CPP_H
+
+
+extern const char *cpp_command;
+
+void add_cpp_arg(const char *arg);
+void add_cpp_Wp(const char *arg);
+void run_cpp_on_file(const char *name); /* NULL for stdin */
+void run_cpp_on_string(const char *str);
+void reap_cpp(void);
+
+#endif /* CPP_H */

Added: developers/werner/greg/dr.pl
===================================================================
--- developers/werner/greg/dr.pl	                        (rev 0)
+++ developers/werner/greg/dr.pl	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+$run = 0;
+
+
+sub flush
+{
+    local ($single) = @_;
+    if (++$run > 2) {
+	undef @a;
+	undef @b;
+	for ($i = 0; $i != 0x70; $i++) {
+	    next if $i == 0x2c || $i == 0x51 || $i == 0x58 || $i == 0x6f;
+	    if ($l[$i] != $v[$i]) {
+		push(@a, sprintf("%02x", $i), "0x".$l[$i]);
+		push(@b, sprintf("%02x", $i), "0x".$v[$i]);
+	    }
+	}
+	print "----- ".$title." ".("-" x (72-length $title))."\n";
+	if ($single) {
+	    system("./greg pcf50633.greg ".join(" ", @a));
+	} else {
+	    system("./greg pcf50633.greg >_a ".join(" ", @a));
+	    system("./greg pcf50633.greg >_b ".join(" ", @b));
+	    system("diff -u _a _b");
+	}
+    }
+    @l = @v;
+    undef @v;
+}
+
+
+while (<>) {
+    chop;
+    next if /^\s*$/;
+    &flush(0) if /^00:/;
+    if (!/^..:/) {
+	$title = $_;
+	next;
+    }
+    @r = split " ";
+    $b = hex shift @r;
+    for ($i = 0; $i != 16; $i++) {
+	die unless defined $r[$i];
+	$v[$b+$i] = $r[$i];
+    }
+}
+&flush(0);
+
+&flush(1) if $run == 2;


Property changes on: developers/werner/greg/dr.pl
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/greg/greg.c
===================================================================
--- developers/werner/greg/greg.c	                        (rev 0)
+++ developers/werner/greg/greg.c	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,123 @@
+/*
+ * greg.c - Generalized register processor
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "reg.h"
+#include "cpp.h"
+#include "greg.h"
+
+
+static int show_reserved = 0;
+
+
+static const char *num_to_binary(unsigned long long num, int bits)
+{
+	static char buf[32+8+1];
+	char *p = buf;
+	int i;
+
+	for (i = bits-1; i >= 0; i--) {
+		*p++ = (num >> i) & 1 ? '1' : '0';
+		if (i && !(i & 3))
+			*p++ = '.';
+	}
+	*p = 0;
+	return buf;
+}
+
+
+static void print_value(const struct value *v, unsigned long long n)
+{
+	switch (v->type) {
+	case vt_none:
+		break;
+	case vt_list:
+		printf(": %s",
+		    v->u.list[n].name ? v->u.list[n].name : "RESERVED");
+		if (v->u.list[n].comment)
+			printf(" -- %s", v->u.list[n].comment);
+		break;
+	case vt_formula:
+		printf(": %d+%d*%llu = %llu", v->u.formula.b, v->u.formula.a, n,
+		     v->u.formula.b+(unsigned long long) v->u.formula.a*n);
+		if (v->u.formula.unit)
+			printf(" %s", v->u.formula.unit);
+		break;
+	default:
+		abort();
+	}
+}
+
+
+static void print_field(const struct field *field, unsigned long long value)
+{
+	printf("    %s", field->name ? field->name : "(reserved)");
+	if (field->comment)
+		printf(" -- %s", field->comment);
+	putchar('\n');
+	printf("\t%s (0x%0*llx)", num_to_binary(value, field->bits),
+	    (field->bits+3) >> 2, value);
+	print_value(&field->value, value);
+	putchar('\n');
+}
+
+
+static void print(const char *id, unsigned long long value)
+{
+	const struct reg *reg;
+	const struct field *field;
+
+	for (reg = regs; reg; reg = reg->next)
+		if (!strcmp(reg->id, id))
+			break;
+	if (!reg) {
+		fprintf(stderr, "register \"%s\" not found\n", id);
+		exit(1);
+	}
+	printf("%s %s = 0x%0*llx",
+	    reg->id, reg->name, (reg->bits+3) >> 2, value);
+	if (reg->comment)
+		printf(" -- %s", reg->comment);
+	putchar('\n');
+	for (field = reg->fields; field; field = field->next) {
+		if (field->name || show_reserved)
+			print_field(field, value & ((1ULL << field->bits)-1));
+		value >>= field->bits;
+	}
+}
+
+
+static void usage(const char *name)
+{
+	fprintf(stderr, "usage: %s regdef-file [reg value ...]\n", name);
+	exit(1);
+}
+
+
+int main(int argc,char **argv)
+{
+	int i;
+
+	if (argc < 2 || (argc & 1))
+		usage(*argv);
+	run_cpp_on_file(argv[1]);
+	(void) yyparse();
+	for (i = 2; i != argc; i += 2)
+		print(argv[i], strtoull(argv[i+1], NULL, 0));
+	return 0;
+	
+}

Added: developers/werner/greg/greg.h
===================================================================
--- developers/werner/greg/greg.h	                        (rev 0)
+++ developers/werner/greg/greg.h	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,23 @@
+/*
+ * greg.h - Generalized register processor
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef GREG_H
+#define GREG_H
+
+int yyparse(void);
+
+void __attribute__((noreturn)) yyerrorf(const char *fmt,...)
+  __attribute__((format(printf,1,2)));
+void __attribute__((noreturn)) yyerror(const char *s);
+
+#endif /* !GREG_H */

Added: developers/werner/greg/lang.l
===================================================================
--- developers/werner/greg/lang.l	                        (rev 0)
+++ developers/werner/greg/lang.l	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,115 @@
+%{
+/*
+ * lang.l - Input language of the generalized register processor
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "y.tab.h"
+
+#include "greg.h"
+
+
+static int lineno = 1;
+static int col0 = 1; /* token starts in the first column */
+
+
+static char *unique(const char *s)
+{
+	static struct node {
+		char *s;
+		struct node *left, *right;
+	} *root = NULL;
+	struct node **n = &root;
+	int cmp;
+
+	while (*n) {
+		cmp = strcmp((*n)->s, s);
+		if (!cmp)
+			return (*n)->s;
+		n = cmp < 0 ? &(*n)->left : &(*n)->right;
+	}
+	*n = malloc(sizeof(struct node));
+	if (!*n) {
+		perror("malloc");
+		exit(1);
+	}
+	(*n)->s = strdup(s);
+	if (!(*n)->s) {
+		perror("strdup");
+		exit(1);
+	}
+	(*n)->left = (*n)->right = NULL;
+	return (*n)->s;
+}
+
+%}
+
+%%
+
+"%"[0-9]+		{ yylval.num = strtoul(yytext+1, NULL, 10);
+			  col0 = 0;
+			  return TOK_BITS; }
+
+_			return '_';
+
+[A-Za-z0-9_]+		{ int token = col0 ? TOK_REG : TOK_ID;
+			  col0 = 0;
+			  yylval.s = unique(yytext);
+			  return token; }
+
+\"[^\"\n\t]*\"		{ yylval.s = strdup(yytext+1);
+			  if (!yylval.s) {
+				perror("strdup");
+				exit(1);
+			  }
+			  *strrchr(yylval.s,'"') = 0;
+			  return STRING; }
+
+[\t ]*			col0 = 0;
+
+((;|"//")[^\n]*)?\n	{ col0 = 1;
+			  lineno++; }
+
+^#\ [0-9]+\ \"[^"]*\"(\ [0-9]+)*\n {
+			  lineno = strtol(yytext+2, NULL, 0);
+			  col0 = 1; }
+
+
+.			{ col0 = 0;
+			  return *yytext; }
+
+
+%%
+
+
+void __attribute__((noreturn)) yyerrorf(const char *fmt,...)
+{
+	va_list ap;
+
+	//if (!isatty(fileno(yyin)))
+	fprintf(stderr,"%d: ", lineno);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, " near \"%s\"\n", yytext);
+	exit(1);
+}
+
+
+void __attribute__((noreturn)) yyerror(const char *s)
+{
+	yyerrorf("%s", s);
+}

Added: developers/werner/greg/lang.y
===================================================================
--- developers/werner/greg/lang.y	                        (rev 0)
+++ developers/werner/greg/lang.y	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,261 @@
+%{
+/*
+ * lang.y - Input language of the generalized register processor
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "reg.h"
+#include "greg.h"
+
+
+struct reg *regs = NULL;
+
+static int bits = 8;	/* bits per register */
+static int bit;		/* current bit */
+
+static struct reg *reg; /* current register */
+static struct field *field; /* current field */
+static struct value_list *list; /* current value list slot */
+
+
+#define alloc_type(t)	((t *) alloc(sizeof(t)))
+
+
+static void *alloc(size_t size)
+{
+	void *tmp = malloc(size);
+
+	if (tmp)
+		return tmp;
+	perror("malloc");
+	exit(1);
+}
+
+
+static int number(char *s)
+{
+	char *end;
+	int tmp;
+
+	tmp = strtol(s, &end, 0);
+	if (*end || tmp < 0)
+		yyerrorf("bad number \"%s\"", s);
+	return tmp;
+}
+
+
+static void add_field(const char *name, int size, const char *comment)
+{
+	struct field *tmp = alloc_type(struct field);
+	const struct field *f;
+
+	if (name)
+		for (f = reg->fields; f; f= f->next)
+			if (f->name == name)
+				yyerrorf("duplicate field name \"%s\"", name);
+	if (bit)
+		field->next = tmp;
+	else
+		reg->fields = tmp;
+	field = tmp;
+	field->name = name;
+	field->comment = comment;
+	field->bits = size;
+	field->next = NULL;
+	bit += size;
+	if (bit > bits)
+		yyerrorf("too many bits (%d > %d)", bit, bits);
+}
+
+
+static void add_value(const char *name, const char *comment)
+{
+	const struct value_list *l;
+
+	if (name)
+		for (l = field->value.u.list; l != list; l++)
+			if (l->name == name)
+				yyerrorf("duplicate value name \"%s\"", name);
+	list->name = name;
+	list->comment = comment;
+	list++;
+}
+
+
+%}
+
+%union {
+	unsigned num;
+	char *s;
+};
+
+
+%token	<num>	TOK_BITS
+%token	<s>	TOK_REG TOK_ID STRING
+
+%type	<s>	opt_string opt_id
+
+%%
+
+all:
+	| all item
+	;
+
+item:
+	TOK_BITS
+		{
+			bits = $1;
+		}
+	| register
+	;
+
+register:
+	TOK_REG TOK_ID opt_string
+		{
+			struct reg **next;
+
+			for (next = &regs; *next; next = &(*next)->next) {
+				if ((*next)->id == $1)
+					yyerrorf(
+					    "duplicate register ID \"%s\"", $1);
+				if ((*next)->name == $2)
+					yyerrorf(
+					    "duplicate register name \"%s\"",
+					     $2);
+			}
+			*next = reg = alloc_type(struct reg);
+			reg->id = $1;
+			reg->name = $2;
+			reg->comment = $3;
+			reg->bits = bits;
+			reg->fields = NULL;
+			reg->next = NULL;
+			bit = 0;
+		}
+	    fields
+		{
+			if (bit && bit < bits)
+				yyerrorf("not enough bits (%d < %d)",
+				    bit, bits);
+			reg++;
+		}
+	;
+
+fields:
+	| fields field
+	;
+
+field:
+	'_'
+		{
+			add_field(NULL, 1, NULL);
+		}
+	| '_' '[' TOK_ID ']'
+		{
+			add_field(NULL, number($3), NULL);
+		}
+	| TOK_ID opt_string
+		{
+			add_field($1, 1, $2);
+		}
+	    opt_values
+	| TOK_ID '[' TOK_ID ']' opt_string
+		{
+			add_field($1, number($3), $5);
+		}
+	    opt_values
+	;
+
+opt_values:
+		{
+			field->value.type = vt_none;
+		}
+	| '{'
+		{
+			field->value.type = vt_list;
+			field->value.u.list = list =
+			    alloc(sizeof(*list)*(1 << field->bits));
+		}
+	    values '}'
+		{
+			int want = 1 << field->bits;
+
+			if (list != field->value.u.list+want)
+				yyerrorf("not enough values (%d < %d)",
+				    (int) (list-field->value.u.list), want);
+		}
+	| '<' TOK_ID '+' TOK_ID '*' opt_id '>'
+		{
+			field->value.type = vt_formula;
+			field->value.u.formula.b = number($2);
+			field->value.u.formula.a = number($4);
+			field->value.u.formula.unit = $6;
+		}
+	;
+
+opt_id:
+		{
+			$$ = NULL;
+		}
+	| TOK_ID
+		{
+			$$ = $1;
+		}
+	;
+
+values:
+ 	| values
+		{
+			int want = 1 << field->bits;
+
+			if (list == field->value.u.list+want)
+				yyerrorf("too many values (expected %d)", want);
+		}
+	   value
+	;
+
+value:
+	'_'
+		{
+			add_value(NULL, NULL);
+		}
+	| TOK_ID opt_string
+		{
+			add_value($1, $2);
+		}
+	;
+
+opt_string:
+		{
+			$$ = NULL;
+		}
+	| opt_string STRING
+		{
+			if (!$1)
+				$$ = $2;
+			else {
+				size_t len1 = strlen($1);
+				size_t len2 = strlen($2);
+
+				$$ = alloc(len1+len2+1);
+				memcpy($$, $1, len1);
+				memcpy($$+len1, $2, len2+1);
+				free($1);
+				free($2);
+			}
+		}
+	;

Added: developers/werner/greg/pcf50633.greg
===================================================================
--- developers/werner/greg/pcf50633.greg	                        (rev 0)
+++ developers/werner/greg/pcf50633.greg	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,735 @@
+/*
+ * NXP PCF50633 register definitions
+ */
+
+
+#define S(s) #s
+
+
+/* ----- Identification ---------------------------------------------------- */
+
+
+00 VERSION	"Version ID"
+01 VARIANT	"Version ID"
+
+
+/* ----- On/Off Control (OOC) ---------------------------------------------- */
+
+
+0c OOCSHDWN	"OOC shutdown"
+	go_stby		{ no_action transition_to_Standby }
+	_
+	totrst		{ no_action reset_timeout }
+	coldboot	{ no_coldboot coldboot }
+	_[4]
+
+0d OOCWAKE	"OOC wake-up"
+	onkey_wake
+	exton1_wake
+	exton2_wake
+	exton3_wake
+	rtc_wake
+	_
+	usb_wake
+	adp_wake
+
+#define DEBOUNCE { none 5ms 14ms 62ms }
+
+0e OOCTIM1	"OOC debounce 1"
+	exton1_deb[2]	DEBOUNCE
+	exton2_deb[2]	DEBOUNCE
+	exton3_deb[2]	DEBOUNCE
+	shdwn_deb[2]	DEBOUNCE
+
+0f OOCTIM2	"OOC debounce 2 (STANDBY)"
+	onkey_deb[3]	"debounce time for nONKEY"
+			{ none 5ms 14ms 62ms 200ms 500ms 1000ms 2000ms }
+	actphdel[2]	"delay between activation phases"
+			{ 5ms 10ms 15ms 20ms }
+	hcrstdel[2]	"delay between selected activation phase and host "
+			"controller reset"
+			{ 3ms 6ms 13ms 26ms }
+	almon		"ambient light monitor"
+
+#define EXTON_MODE { wake_on_falling_edge wake_on_rising_edge \
+		     wake_on_falling_8s_timeout_on_rising \
+		     wake_on_rising_8s_timeout_on_falling }
+
+10 OOCMODE	"OOC mode"
+	exton1_mode[2]	"EXTON1 mode selection"	EXTON_MODE
+	exton2_mode[2]	"EXTON2 mode selection"	EXTON_MODE
+	exton3_mode[2]	"EXTON3 mode selection"	EXTON_MODE
+	onkey_mode[2]	"ONKEY mode selection"
+			{ wake_on_falling_edge
+		          wake_on_falling_8s_timeout_if_low_1s
+			  wake_on_falling_8s_timeout_on_rising
+			  _ }
+
+11 OOCCTL	"OOC control"
+	actphrst[2]	"selects activity phase to which host controller "
+			"reset is related"
+			{ phase_1 phase_2 phase_3 phase_4 }
+	actclk32on	"CLK32K output in Active state"
+	heatbeat	{ KEEPACT_required_DC_high
+			  KEEPACT_requires_toggling }
+	usbbatchk	{ disabled "Vbat status has no effect on state machine"
+			  enabled "Vbat > Vth(batok) to go to Standby state" }
+	_
+	stbclk32on	"CLK32K output in Standby state"
+	_
+
+12 OOCSTAT	"OOC status"
+	onkey		"ONKEY above threshold"
+	exton1		"EXTON1 above threshold"
+	exton2		"EXTON2 above threshold"
+	exton3		"EXTON3 above threshold"
+	bubpres		"Vbubat above Vth(bubpres)"
+	sysok		"Vsys above Vth(sysok)"
+	batok		"Vbat above Vth(batok)"
+	tmpok		"die_below_Tth_die"
+
+
+/* ----- Interrupt Controller (INT) ---------------------------------------- */
+
+
+02 INT1		"Interrupt 1"
+	adpins		"ADAPTSNS has risen above Vth(adaptpres)"
+	adprem		"ADAPTSNS has dropped below Vth(adaptpres)"
+	usbins		"USBx has risen above Vth(usbpres)"
+	usbrem		"USBx has dropped below Vth(usbpres)"
+	_[2]
+	rtcalarm	"RTC alarm time expired"
+	second		"RTC periodic one second interrupt"
+
+03 INT2		"Interrupt 2"
+	onkeyr		"rising edge on nONKEY"
+	onkeyf		"falling edge on nONKEY"
+	exton1r		"rising edge on EXTON1"
+	exton1f		"falling edge on EXTON1"
+	exton2r		"rising edge on EXTON2"
+	exton2f		"falling edge on EXTON2"
+	exton3r		"rising edge on EXTON3"
+	exton3f		"falling edge on EXTON3"
+
+04 INT3		"Interrupt 3"
+	batfull		"battery is fully charged"
+	chghalt		"charger has entered HALT mode"
+	thlimon		"charger has activated thermal-loop current limiting "
+			"in the USB-to-SYS path"
+	thlimoff	"charger has deactivated thermal-loop current "
+			"limiting in the USB-to-SYS path"
+	usblimon	"charger has activated USB current limiting "
+			"in the USB-to-SYS path"
+	usblimoff	"charger has deactivated USB current limiting "
+			"in the USB-to-SYS path"
+	adcrdy		"ADC conversion completed"
+	onkey1s		"nONKEY low for at least 1 second"
+
+05 INT4		"Interrupt 4"
+	lowsys		"SYS voltage fallen below Vth(sysok)"
+	lowbat		"BAT voltage fallen below Vth(batok)"
+	hightmp		"Tth(die) exceeded"
+	autopwrfail	"AUTO output voltage below 90% of target"
+	dwn1pwrfail	"DOWN1 output voltage below 90% of target"
+	dwn2pwrfail	"DOWN2 output voltage below 90% of target"
+	ledpwrfail	"LED output current below 90% of target"
+	ledovp		"overvoltage detected at output of LED converter"
+
+06 INT5		"Interrupt 5"
+	ldo1pwrfail	"LDO1 output voltage below 90% of target"
+	ldo2pwrfail	"LDO2 output voltage below 90% of target"
+	ldo3pwrfail	"LDO3 output voltage below 90% of target"
+	ldo4pwrfail	"LDO4 output voltage below 90% of target"
+	ldo5pwrfail	"LDO5 output voltage below 90% of target"
+	ldo6pwrfail	"LDO6 output voltage below 90% of target"
+	hcldopwrfail	"HCLDO output voltage below 90% of target"
+	hcldoovl	"overload (Io > 350mA) detected in HCLDO regulator"
+
+07 INT1MASK	"Interrupt mask 1"
+	adpinsm
+	adpremm
+	usbinsm
+	usbremm
+	_[2]
+	rtcalarmm
+	secondm
+
+08 INT2MASK	"Interrupt mask 2"
+	onkeyrm
+	onkeyfm
+	exton1rm
+	exton1fm
+	exton2rm
+	exton2fm
+	exton3rm
+	exton3fm
+
+09 INT3MASK	"Interrupt mask 3"
+	batfullm
+	chghaltm
+	thlimonm
+	thlimoffm
+	usblimonm
+	usblimoffm
+	adcrdym
+	onkey1sm
+
+0a INT4MASK	"Interrupt mask 4"
+	lowsysm
+	lowbatm
+	hightmpm
+	autopwrfailm
+	dwn1pwrfailm
+	dwn2pwrfailm
+	ledpwrfailm
+	ledovpm
+
+0b INT5MASK	"Interrupt mask 5"
+	ldo1pwrfailm
+	ldo2pwrfailm
+	ldo3pwrfailm
+	ldo4pwrfailm
+	ldo5pwrfailm
+	ldo6pwrfailm
+	hcldopwrfailm
+	hcldoovlm
+
+
+/* ----- General Purpose Input/Output (GPIO/GPO) --------------------------- */
+
+
+13 GPIOCTL	"GPIO I/O mode control"
+	gpio1dir	"GPIO1 I/O mode"
+			{ output input }
+	gpio2dir	"GPIO2 I/O mode"
+			{ output input }
+	gpio3dir	"GPIO3 I/O mode"
+			{ output input }
+	_[5]
+
+#define GPIOxCFG(x)							\
+    GPIO##x##CFG "GPIO" S(x) " signal selection"			\
+	gpio##x##sel[3]	"GPIO" S(x) " output signal selection"		\
+			{ fixed_0 _ sysok battery_charging mobile_mode	\
+			  usbpres actph##x fixed_1 }			\
+	gpio##x##pol	"GPIO" S(x) " output signal polarity"		\
+			{ no_inversion inversion }			\
+	_[4]
+
+14 GPIOxCFG(1)
+15 GPIOxCFG(2)
+16 GPIOxCFG(3)
+
+17 GPOCFG	"GPO signal selection"
+	gposel[3]	"GPO output signal selection"
+			{ fixed_0 led_nfet sysok clk32k mobile_mode
+			  usbpres actph4 fixed_1 }
+	gpopol		"GPO output signal polarity"
+			{ no_inversion inversion }
+	_[4]
+
+
+/* ----- System Voltage Monitor (SVM) -------------------------------------- */
+
+
+19 SVMCTL	"SVM control"
+	svmlow		"SYS voltage is lower than Vth(sysok)"
+	svmlvl[3]	"Vth(sysok)"
+			{ _ 2_80V 2_90V 3_00V 3_10V 3_20V 3_30V 3_40V }
+	svmdisdb	"62ms debounce filter"
+			{ enabled disabled }
+	_[3]
+
+
+/* ----- Battery Voltage Monitor (BVM) ------------------------------------- */
+
+
+18 BVMCTL	"BVM control"
+	bvmlow		"BAT voltage is lower than Vth(batok)"
+	bvmlvl[3]	"Vth(batok)"
+			{ _ 2_80V 2_90V 3_00V 3_10V 3_20V 3_30V 3_40V }
+	bvmdisdb	"62ms debounce filter"
+			{ enabled disabled }
+	_[3]
+
+
+/* ----- Power Supply Module (PSM) ----------------------------------------- */
+
+
+3b STBYCTL1	"LDO Standby control"
+	ldo1_ena_stb	"LDO1 in ON in Standby"
+	_
+	ldo2_ena_stb	"LDO2 in ON in Standby"
+	_
+	ldo3_ena_stb	"LDO3 in ON in Standby"
+	_
+	ldo4_ena_stb	"LDO4 in ON in Standby"
+	_
+
+3c STBYCTL2	"LDO Standby control"
+	ldo5_ena_stb	"LDO5 in ON in Standby"
+	_
+	ldo6_ena_stb	"LDO6 in ON in Standby"
+	_
+	hcldo_ena_stb	"HCLDO in ON in Standby"
+	_
+	memldo_ena_stb	"MEMLDO in ON in Standby"
+	_
+
+#define DEBPF(REG, reg)							\
+	reg##_debpf[2]	S(REG) " power failure debounce time"		\
+			{ none 1ms 10ms 100ms }
+
+#define STAT(REG, reg)							\
+	reg##_pwrok	S(REG) " > 90% of target"
+
+3d DEBPF1	"Power fail debounce 1"
+	DEBPF(AUTO, auto)
+	DEBPF(DOWN1, down1)
+	DEBPF(DOWN2, down2)
+	DEBPF(LED, led)
+
+3e DEBPF2	"Power fail debounce 2"
+	DEBPF(LDO1, ldo1)
+	DEBPF(LDO2, ldo2)
+	DEBPF(LDO3, ldo3)
+	DEBPF(LDO4, ldo4)
+
+3f DEBPF3	"Power fail debounce 3"
+	DEBPF(LDO5, ldo5)
+	DEBPF(LDO6, ldo6)
+	DEBPF(HCLDO, hcldo)
+	_[2]
+
+41 DCDCSTAT	"DC-to-DC converter status"
+	STAT(AUTO, auto)
+	STAT(DOWN1, down1)
+	STAT(DOWN2, down2)
+	STAT(LED, led)
+	_[4]
+
+42 LDOSTAT	"LDO status"
+	STAT(LDO1, ldo1)
+	STAT(LDO2, ldo2)
+	STAT(LDO3, ldo3)
+	STAT(LDO4, ldo4)
+	STAT(LDO5, ldo5)
+	STAT(LDO6, ldo6)
+	STAT(HCLDO, hcldo)
+	hcldo_ovl	"HCLDO is in overload mode"
+
+
+/* ----- AUTO, DOWN1 and DOWN2 converters ---------------------------------- */
+
+
+#define DC_OUT(reg)							\
+	reg##_out[8]	"Vo(prog) [1800mV,3800mV]"			\
+			<625+25* mV>
+	
+#define ENA(reg)							\
+	reg##_on	{ off on }					\
+	reg##_p1c	{ off on_gpio1 "ON when GPIO1 = 1" }		\
+	reg##_p2c	{ off on_gpio2 "ON when GPIO2 = 1" }		\
+	reg##_p3c	{ off on_gpio3 "ON when GPIO3 = 1" }		\
+	reg##_ena_act[2] "selects activation phase"			\
+			{ actph1 actph2 actph3 actph4 }			\
+	_[2]
+
+#define MXC(reg)							\
+	reg##_maxc[6]	"Ii(max)"					\
+			<0+40* mA>					\
+	reg##_maxcmod	"current limit mode"				\
+			{ start_up always }				\
+	_
+
+#define DOWNxCTL(x)							\
+	down##x##pwmonly { pfm_pwm "automatic PFM-PWM selection"	\
+			  pwm "converter operates in PWM mode" }	\
+	down##x##_dvmstep[4]						\
+			"DVM step time, 32768 Hz"			\
+			<0+30* us>					\
+	_[3]
+
+#define LDO_OUT(reg)							\
+	reg##_out[5]	"Vo(prog)"					\
+			<900+100* mV>					\
+	reg##_swmod	{ linear_reg switch }				\
+	_[2]
+
+
+1a AUTOOUT	"AUTO output voltage select (STANDBY)"
+	DC_OUT(auto)
+
+1b AUTOENA	"AUTO output enable (STANDBY)"
+	ENA(auto)
+
+1c AUTOCTL	"AUTO control register (STANDBY)"
+	autopwmonly	{ pfm_pwm "automatic PFM-PWM selection"
+			  pwm "converter operates in PWM mode" }
+	auto_mod	{ auto_up_down down_only }
+	_[6]
+
+1d AUTOMXC	"AUTO maximum current (STANDBY)"
+	MXC(auto)
+
+1e DOWN1OUT	"DOWN1 output voltage select (STANDBY)"
+	DC_OUT(down1)
+
+1f DOWN1ENA	"DOWN1 output enable (STANDBY)"
+	ENA(down1)
+
+20 DOWN1CTL	"DOWN1 control (STANDBY)"
+	DOWNxCTL(1)
+
+21 DOWN1MXC	"DOWN1 maximum current (STANDBY)"
+	MXC(down1)
+
+22 DOWN2OUT	"DOWN2 output voltage select (STANDBY)"
+	DC_OUT(down2)
+
+23 DOWN2ENA	"DOWN2 output enable (STANDBY)"
+	ENA(down2)
+
+24 DOWN2CTL	"DOWN2 control (STANDBY)"
+	DOWNxCTL(2)
+
+25 DOWN2MXC	"DOWN2 maximum current (STANDBY)"
+	MXC(down2)
+
+26 MEMLDOOUT	"MEMLDO output voltage select (STANDBY)"
+	LDO_OUT(memldo)
+
+27 MEMLDOENA	"MEMLDO output enable (STANDBY)"
+	ENA(memldo)
+
+84 DCDCPFM	"DCDC force PFM control (NOPOWER)"
+	autopfm		"force AUTO temporarily to PFM mode"
+	down1pfm	"force DOWN1 temporarily to PFM mode"
+	down2pfm	"force DOWN2 temporarily to PFM mode"
+	_[5]
+
+
+/* ----- LED boost converter & Ambient Light Monitor (ALM) ----------------- */
+
+
+28 LEDOUT	"LED output voltage select (STANDBY)"
+	led_out[6]	 "Iled = Vledfb/Rsense"
+		// x000  x001  x010  x011  x100  x101  x110  x111
+		{     _   2mV     _  10mV     _     _     _     _	// 000x
+		   27mV     _  37mV     _     _     _  56mV     _	// 001x
+		      _     _  81mV     _     _     _ 113mV     _	// 010x
+		      _     _ 149mV     _     _     _ 196mV     _	// 011x
+		      _     _ 250mV     _     _     _ 318mV     _	// 100x
+		      _     _ 401mV     _     _     _ 501mV     _	// 101x
+		      _     _ 626mV     _     _     _ 778mV     _	// 110x
+		      _     _ 961mV     _     _     _     _ 1250mV }	// 111x
+	_[2]
+// TODO: complete the table
+// TODO: find a way to programatically generate tables
+// maybe do it like tcsim does, { code }
+
+29 LEDENA	"LED output enable (STANDBY)"
+	ENA(led)
+
+2a LEDCTL	"LED control (STANDBY)"
+	led_ovpon	"overvoltage protection"
+	led_ovprs	"reset overvoltage protection"
+	led_ocp		"OCP limit"
+			{ 1000mA 500mA }
+	_[5]
+
+2b LEDDIM	"LED ramp control (STANDBY)"
+	led_dimstep[8]	"tdimstep=16*led_dimstep/32768s"
+			<0+488* us>
+
+4f ALMGAIN	"Ambient lighting gain factor (STANDBY)"
+	alm_gain[5]	"ambient light processing gain factor"
+	_[3]
+
+50 ALMDATA	"Ambient light intensity data (STANDBY)"
+	alm_data[8]
+
+
+/* ----- Linear regulators ------------------------------------------------- */
+
+
+#define LDOxOUT(LDO, ldo)						\
+    LDO##OUT	S(LDO) " output voltage select (STANDBY)"		\
+	LDO_OUT(reg)
+
+#define LDOxENA(LDO, ldo)						\
+    LDO##ENA	S(LDO) " output enable (STANDBY)"			\
+	ENA(ldo)
+
+
+2d LDOxOUT(LDO1, ldo1)
+2e LDOxENA(LDO1, ldo1)
+
+2f LDOxOUT(LDO2, ldo2)
+30 LDOxENA(LDO2, ldo2)
+
+31 LDOxOUT(LDO3, ldo3)
+32 LDOxENA(LDO3, ldo3)
+
+33 LDOxOUT(LDO4, ldo4)
+34 LDOxENA(LDO4, ldo4)
+
+35 LDOxOUT(LDO5, ldo5)
+36 LDOxENA(LDO5, ldo5)
+
+37 LDOxOUT(LDO6, ldo6)
+38 LDOxENA(LDO6, ldo6)
+
+39 LDOxOUT(HCLDO, hcldo)
+3a LDOxENA(HCLDO, hcldo)
+
+40 HCLDOOVL	"HCLDO overload protection"
+	hcldo_debovl[2]	"overload detecton debounce time"
+			{ none 1ms 10ms 100ms }
+	_[6]
+
+
+/* ----- Main Battery Charger (MBC) ---------------------------------------- */
+
+
+43 MBCC1	"MBC charger control 1"
+	chgena		"charger enabled"
+	autostop	"stop charging when current falls below cutoffcur"
+	autores		"resume charging then Vbat < Vth(RES), 96% of vmax"
+	resume		"resume if in Battery Full"
+	restart		"restart if in Halt"
+	prewdtime	"maximum charging time during Precharge phase"
+			{ 30min 60min }
+	wdtime[2]	"maximum charging time after Precharge phase"
+			{ 1h 2h 4h 6h }
+
+44 MBCC2	"MBC charger control 2"
+	vbatcond[2]	{ 2_7V 2_85V 3_0V 3_15V }
+	vmax[4]		"Vbat(float)prog"
+			<4000+20* mV>
+	_
+	vresdebtime	"debounce time for Vth(RES)"
+			{ 32s 64s }
+
+45 MBCC3	"MBC charger control 3"
+	prechgcur[8]	"pre-charge current level, N/255*Ich(ref)"
+
+46 MBCC4	"MBC charger control 4"
+	fstchgcur1[8]	"fast charge current level in adapter Fast Charge "
+			"phase, N/255*Ich(ref)"
+
+47 MBCC5	"MBC charger control 5"
+	fstchgcur2[8]	"fast charge current level in USB Fast Charge "
+			"phase, N/255*Ich(ref)"
+
+48 MBCC6	"MBC charger control 6"
+	cutoffcur[5]	"cutoff current level (full in CV), 1/32*Ichg"
+	_[3]
+
+49 MBCC7	"MBC charger control 7"
+	usbdevstat[2]	"USB device status setting (STANDBY)"
+			{ 100mA 500mA 1000mA suspend }
+	batttempena	"battery temperature is measured and impacts the "
+			"MBC state machine"
+	_[3]
+	batsysimax[2]	"maximum BAT-SYS current when ideal diode is conducting"
+			{ 1_6A 1_8A 2_0A 2_2A }
+
+4a MBCC8	"MBC charger control 8"
+	ntclvt[4]	"NTC voltage level for battery high temperature "
+			"threshold"
+			<600+50* mV>
+	usbenasus	"USB-SYS switch enabled in USB suspend, "
+			"ideal diode disabled"
+	_[3]
+
+4b MBCS1	"MBC charger status 1"
+	usbpres		"Vusb > Vth(usbpres)"
+	usbok		"Vusb > Vbat+dVusbok"
+	adaptpres	"Vadaptsns > Vth(adaptpres)"
+	adaptok		"Vsys > Vbat+dVadaptok"
+	tbatstat[2]	"battery temperature status indication"
+			{ within_window above_window below_window undefined }
+	prewdtexp	"watchdog timer expired during pre-charging"
+	wdtexp		"watchdog timer expired after pre-charging"
+
+4c MBCS2	"MBC charger status 2"
+	mbcmod[4]	"main MBC operating modes and charge phases"
+			{ play_only usb_precharge usb_precharge_wait
+			  usb_fast_charge usb_fast_charge_wait usb_suspend
+			  adapter_precharge adapter_precharge_wait
+			  adapter_fast_charge adapter_fast_charge_wait
+			  battery_full halt _ _ _ _ }
+	chgstat[2]	"charger connection status"
+			{ no_charger adapter usb  adapter_and_usb }
+	resstat		"charging has resumed automatically"
+	_
+
+4d MBCS3	"MBC charger status 3"
+	usblim_play	"USB current limiting in USB-to-SYS path"
+	usblim_chg	"USB current limiting in USB-to-BAT path"
+	tlim_play	"temperature limiting in USB-to-SYS path"
+	tlim_chg	"temperature limiting in USB-to-BAT or SYS-BAT path"
+	ilim		"battery charge current > cutoffcur level"
+	vlim		"battery voltage equals vmax level"
+	vbatstat	"battery voltage > Vbatcond"
+	vres		"battery voltage > Vth(RES)"
+
+
+/* ----- Backup Battery Charger (BBC) -------------------------------------- */
+
+
+4e BBCCTL	"Backup battery charger control"
+	bbce	"enable backup battery charger (STANDBY)"
+	bbcr	"bypass output resistor"
+	bbcc[2]	"backup battery charge current, Ich(BUBAT)"
+		{ 50uA 100uA 200uA 400uA }
+	bbcv	"limiting voltage for backup battery charger Vlim(BUBAT)"
+		{ 2_5V 3_0V }
+	_[3]
+
+
+/* ----- 10-bit Analog-to-Digital Converter (ADC) -------------------------- */
+
+
+54 ADCC1	"A/D converter control 1"
+	adcstart	"ADC conversion start command"
+	adcres		"ADC resolution"	
+			{ 10bit 8bit }
+	adc_av[2]	"measurement averaging"
+			{ none 4_samples 8_samples 16_samples }
+	adcinmux[4]	"ADC input selection"
+			{ batsns_r "BATSNS via resistive divider"
+			  batsns_sub "BATSNS via subtractor"
+			  adcin2_r "ADCIN2 via resistive divider"
+			  adcin2_sub "ADCIN2 via subtractor"
+			  _
+			  _
+			  battemp "BATTEMP"
+			  adcin1 "ADCIN1"
+			  _ _ _ _ _ _ _ _ }
+
+53 ADCC2	"A/C converter control 2"
+	adcratioen[2]	"ratiometric measurement"
+			{ none "no ratiometric mode measurement"
+			  battemp "BATTEMP only"
+			  adcin1 "ADCIN1 only"
+			  battemp_adcin "BATTEMP and ADCIN1" }
+	adcratioset	"ratiometric settling time"
+			{ 10us 100us }
+	_[5]
+
+52 ADCC3	"A/C converter control 3"
+	accswen		"enable biasing for ratiometric measurement on ADCIN1"
+	_
+	ntcswen		"enable biasing for ratiometric measurement on BATTEMP"
+	_
+	adcdivsel	"resistive divider type"
+			{ by_3 by_2 }
+	_[3]
+
+55 ADCS1	"A/D converter status 1"
+	adcdat1h[8]	"8 most significant bits of the (first) ADC result"
+
+56 ADCS2	"A/D converter status 2"
+	adcdat2h[8]	"8 most significant bits of the second ADC result"
+
+57 ADCS3	"A/D converter status 3"
+	adcdat1l[2]	"2 least significant bits of the (first) ADC result"
+	adcdat2l[2]	"2 least significant bits of the second ADC result"
+	adcrefmux[3]	"ADC reference selection"
+			{ ntcsw accws 2_0V visa
+			  _ _ _ 2_0V_again }
+	adcrdy		"ADC conversion is completed"
+
+
+/* ----- Real-time clock (RTC) --------------------------------------------- */
+
+
+#define WEEKDAYS { sun mon tue wed thu fri sat _ }
+
+#define MONTHS					\
+	{ _   jan feb mar apr may jun jul	\
+	  aug sep _   _   _   _   _   _		\
+	  oct nov dec _   _   _   _   _		\
+	  _   _   _   _   _   _   _   _ }
+
+
+59 RTCSC	"RTC second value"
+	sec[7]		"current seconds, BCD"
+	_
+
+5a RTCMN	"RTC minute value"
+	min[7]		"current minutes, BCD"
+	_
+
+5b RTCHR	"RTC hour value"
+	hour[6]		"current hours, BCD"
+	_[2]
+
+5c RTCWD	"RTC day-of-week value"
+	wkday[3]	"current day-of-week"
+			WEEKDAYS
+	_[5]
+
+5d RTCDT	"RTC day value"
+	day[5]		"current day value, BCD, 01-based"
+	_[3]
+
+5e RTCMT	"RTC month value"
+	month[5]	"current month value"
+			MONTHS
+	_[3]
+
+5f RTCYR	"RTC year value"
+	year[8]		"current year, BCD"
+
+60 RTCSCA	"RTC second alarm value"
+	seca[7]		"alarm seconds, BCD"
+	_
+
+61 RTCMNA	"RTC minute alarm value"
+	mina[7]		"alarm minutes, BCD"
+	_
+
+62 RTCHRA	"RTC hour alarm value"
+	houra[6]	"alarm hours, BCD"
+	_[2]
+
+63 RTCWDA	"RTC weekday alarm value"
+	wkdaya[3]	"alarm day-of-week"
+			WEEKDAYS
+	_[5]
+
+64 RTCDTA	"RTC day alarm value"
+	daya[5]		"alarm day value, BCD, 01-based"
+	_[3]
+
+65 RTCMTA	"RTC month alarm value"
+	montha[5]	"alarm month value"
+			MONTHS
+	_[3]
+
+66 RTCYRA	"RTC year alarm value"
+	yeara[8]	"alarm year, BCD"
+
+
+/* ----- General Purpose Memory (GPM) -------------------------------------- */
+
+
+#define MEMBYTE(n)							\
+	MEMBYTE##n "General purpose memory byte " S(n)			\
+		membyte##n[8]
+
+
+67 MEMBYTE(0)
+68 MEMBYTE(1)
+69 MEMBYTE(2)
+6a MEMBYTE(3)
+6b MEMBYTE(4)
+6c MEMBYTE(5)
+6d MEMBYTE(6)
+6e MEMBYTE(7)
+
+
+/* ------------------------------------------------------------------------- */

Added: developers/werner/greg/reg.h
===================================================================
--- developers/werner/greg/reg.h	                        (rev 0)
+++ developers/werner/greg/reg.h	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,55 @@
+/*
+ * lang.y - Input language of the generalized register pretty-printer
+ *
+ * Copyright (C) 2008 by OpenMoko, Inc.
+ * Written by Werner Almesberger <werner at openmoko.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+
+#ifndef REG_H
+#define REG_H
+
+
+struct reg {
+	const char *id;		/* technical register ID */
+	const char *name;	/* human-readable register name */
+	const char *comment;	/* description or NULL */
+	int bits;		/* register width in bits */
+	struct field *fields;	/* list of fields, always non-NULL */
+	struct reg *next;	/* next register */
+};
+
+struct value {
+	enum { vt_none, vt_list, vt_formula } type;
+	union {
+		struct value_list {
+			const char *name;
+			const char *comment;
+		} *list;
+		struct {
+			int a;			/* aX+b */
+			int b;
+			const char *unit;	/* unit name, may be NULL */
+		} formula;
+	} u;
+};
+
+struct field {
+	const char *name;	/* human-readable field name */
+	const char *comment;	/* description or NULL */
+	int bits;		/* field size in bits */
+	struct value value;
+	struct field *next;	/* next field */
+};
+
+
+extern struct reg *regs;
+
+
+#endif /* !REG_H */

Added: developers/werner/greg/tests/Common
===================================================================
--- developers/werner/greg/tests/Common	                        (rev 0)
+++ developers/werner/greg/tests/Common	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+
+fail()
+{
+    echo FAILED "($SCRIPT)" 1>&2
+    cat _out 1>&2
+    exit 1
+}
+
+
+process()
+{
+    echo -n "$1: " 1>&2
+    shift
+    ../greg - "$@" >_out 2>&1
+}
+
+
+greg()
+{
+    process "$@" || fail
+}
+
+
+greg_fail()
+{
+    process "$@" && fail
+}
+
+
+expect()
+{
+    if ! diff -u - _out >_tmp; then
+	echo FAILED "($SCRIPT)" 1>&2
+	cat _tmp
+	exit
+    fi
+    rm -f _out _tmp
+    echo PASSED 1>&2
+    passed=`expr ${passed:-0} + 1`
+}

Added: developers/werner/greg/tests/Makefile
===================================================================
--- developers/werner/greg/tests/Makefile	                        (rev 0)
+++ developers/werner/greg/tests/Makefile	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,11 @@
+.PHONY:	tests clean
+
+# Explicitly enumerate the lower case letters to escape localization weirdness.
+
+tests:
+	for n in [abcdefghijklmnopqrstuvwxyz]*; do \
+	  SCRIPT=$$n PATH=.:$$PATH . ./$$n; done; \
+	  echo "Passed all $$passed tests" 2>&1
+
+clean:
+	rm -f _*

Added: developers/werner/greg/tests/field
===================================================================
--- developers/werner/greg/tests/field	                        (rev 0)
+++ developers/werner/greg/tests/field	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,93 @@
+#!/bin/sh
+. ./Common
+
+# -----------------------------------------------------------------------------
+
+greg "named field without comment" foo 0x12 <<EOF
+foo bar
+	blah[8]
+EOF
+
+expect <<EOF
+foo bar = 0x12
+    blah
+	0001.0010 (0x12)
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "named field with comment" bar 52 <<EOF
+bar blah
+	foo[8] "field blah"
+EOF
+
+expect <<EOF
+bar blah = 0x34
+    foo -- field blah
+	0011.0100 (0x34)
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "anonymous field without comment" bar 0x55 <<EOF
+bar foo
+	_[5]
+	bar[3]
+EOF
+
+expect <<EOF
+bar foo = 0x55
+    bar
+	010 (0x2)
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "anonymous field with comment" foo 0xaa <<EOF
+foo blah
+	bar[5]
+	_[3]
+EOF
+
+expect <<EOF
+foo blah = 0xaa
+    bar
+	0.1010 (0x0a)
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "fields don't fill register" <<EOF
+foo bar
+	blah[4]
+	_[3]
+EOF
+
+expect <<EOF
+4: not enough bits (7 < 8) near ""
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "fields exceed register" <<EOF
+foo bar
+	_[3]
+	blah[7]
+EOF
+
+expect <<EOF
+4: too many bits (10 > 8) near ""
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "duplicate field name" <<EOF
+bar blah
+	foo
+	_[6]
+	foo
+EOF
+
+expect <<EOF
+5: duplicate field name "foo" near ""
+EOF


Property changes on: developers/werner/greg/tests/field
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/greg/tests/reg
===================================================================
--- developers/werner/greg/tests/reg	                        (rev 0)
+++ developers/werner/greg/tests/reg	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,54 @@
+#!/bin/sh
+. ./Common
+
+# -----------------------------------------------------------------------------
+
+greg "8 bit register, no comment" foo 0x12 <<EOF
+foo bar
+EOF
+
+expect <<EOF
+foo bar = 0x12
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "8 bit register, with comment" bar 52 <<EOF
+bar blah "hello"
+EOF
+
+expect <<EOF
+bar blah = 0x34 -- hello
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "duplicate register ID" <<EOF
+foo bar
+foo blah
+EOF
+
+expect <<EOF
+3: duplicate register ID "foo" near ""
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "duplicate register name" <<EOF
+foo blah
+bar blah
+EOF
+
+expect <<EOF
+3: duplicate register name "blah" near ""
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "duplicate register comment" <<EOF
+foo bar "blah"
+bar foo "blah"
+EOF
+
+expect <<EOF
+EOF


Property changes on: developers/werner/greg/tests/reg
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/greg/tests/value
===================================================================
--- developers/werner/greg/tests/value	                        (rev 0)
+++ developers/werner/greg/tests/value	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,88 @@
+#!/bin/sh
+. ./Common
+
+# -----------------------------------------------------------------------------
+
+greg "named value without comment" foo 2 <<EOF
+foo bar
+	blah[2] { zero one two three }
+	_[6]
+EOF
+
+expect <<EOF
+foo bar = 0x02
+    blah
+	10 (0x2): two
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "named value with comment" foo 0x40 <<EOF
+foo bar
+	_[6]
+	blah[2] { zero "null" one "eins" two "zwei" three "drei" }
+EOF
+
+expect <<EOF
+foo bar = 0x40
+    blah
+	01 (0x1): one -- eins
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "anonymus value without comment" foo 3 <<EOF
+foo bar
+	blah[2] { zero one two _ }
+	_[6]
+EOF
+
+expect <<EOF
+foo bar = 0x03
+    blah
+	11 (0x3): RESERVED
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "anonymus value with comment (error)" foo 0 <<EOF
+foo bar
+	_[5]
+	blah[3] { _ "zero" one two _ _ _ _ _ }
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "not enough values" <<EOF
+foo bar
+	blah[3] { a b c d e f }
+	_[5]
+EOF
+
+expect <<EOF
+2: not enough values (6 < 8) near "}"
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "too many values" <<EOF
+foo bar
+	_[6]
+	blah[2] { 1 2 3 4 5 }
+EOF
+
+expect <<EOF
+3: too many values (expected 4) near "5"
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg_fail "duplicate value name" <<EOF
+bar blah
+	_[6]
+	foo[2] { a b a c }
+EOF
+
+expect <<EOF
+3: duplicate value name "a" near "c"
+EOF


Property changes on: developers/werner/greg/tests/value
___________________________________________________________________
Name: svn:executable
   + *

Added: developers/werner/greg/tests/width
===================================================================
--- developers/werner/greg/tests/width	                        (rev 0)
+++ developers/werner/greg/tests/width	2008-06-26 05:01:10 UTC (rev 4502)
@@ -0,0 +1,68 @@
+#!/bin/sh
+. ./Common
+
+# -----------------------------------------------------------------------------
+
+greg "4 bit register" foo 0x8 <<EOF
+%4
+foo bar
+EOF
+
+expect <<EOF
+foo bar = 0x8
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "5 bit register" foo 8 <<EOF
+%5
+foo bar
+EOF
+
+expect <<EOF
+foo bar = 0x08
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "8 bit register" foo 9 <<EOF
+%8
+foo bar
+EOF
+
+expect <<EOF
+foo bar = 0x09
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "16 bit register" foo 0x8765 <<EOF
+%16
+foo foo
+EOF
+
+expect <<EOF
+foo foo = 0x8765
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "32 bit register" bar 0x87654321 <<EOF
+%32
+bar bar
+EOF
+
+expect <<EOF
+bar bar = 0x87654321
+EOF
+
+# -----------------------------------------------------------------------------
+
+greg "64 bit register" foo 0x123456789abcdef0 <<EOF
+%64
+foo bar
+EOF
+
+expect <<EOF
+foo bar = 0x123456789abcdef0
+EOF


Property changes on: developers/werner/greg/tests/width
___________________________________________________________________
Name: svn:executable
   + *





More information about the commitlog mailing list