diff options
Diffstat (limited to 'util/lbcc.c')
-rw-r--r-- | util/lbcc.c | 691 |
1 files changed, 0 insertions, 691 deletions
diff --git a/util/lbcc.c b/util/lbcc.c deleted file mode 100644 index 4a3633153e..0000000000 --- a/util/lbcc.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright 2014 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include <errno.h> -#include <stdarg.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "compile_time_macros.h" -#include "ec_commands.h" -#include "lb_common.h" -#include "lightbar.h" - -static const char usage[] = - "\n" - "Usage: %s [OPTIONS] [INFILE [OUTFILE]]\n" - "\n" - "This compiles or decompiles the lightbar programmable bytecode.\n" - "\n" - "Options:\n" - " -d Decode binary to ascii\n" - " -v Decode output should be verbose\n" - "\n"; - -/* globals */ -static int hit_errors; -static int opt_verbose; -static int is_jump_target[EC_LB_PROG_LEN]; /* does program jump here? */ -static int is_instruction[EC_LB_PROG_LEN]; /* instruction or operand? */ -static char *label[EC_LB_PROG_LEN]; /* labels we've seen */ -static char *reloc_label[EC_LB_PROG_LEN]; /* put label target here */ - -static void Error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fprintf(stderr, "ERROR: "); - vfprintf(stderr, format, ap); - va_end(ap); - hit_errors++; -} - -static void Warning(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - fprintf(stderr, "Warning: "); - vfprintf(stderr, format, ap); - va_end(ap); -} - -/* The longest line should have a label, an opcode, and the max operands */ -#define LB_PROG_MAX_OPERANDS 4 -#define MAX_WORDS (2 + LB_PROG_MAX_OPERANDS) - -struct safe_lightbar_program { - struct lightbar_program p; - uint8_t zeros[LB_PROG_MAX_OPERANDS]; -} __packed; - -#define OP(NAME, BYTES, MNEMONIC) NAME, -#include "lightbar_opcode_list.h" -enum lightbyte_opcode { - LIGHTBAR_OPCODE_TABLE - MAX_OPCODE -}; -#undef OP - -#define OP(NAME, BYTES, MNEMONIC) BYTES, -#include "lightbar_opcode_list.h" -static const int num_operands[] = { - LIGHTBAR_OPCODE_TABLE -}; -#undef OP - -#define OP(NAME, BYTES, MNEMONIC) MNEMONIC, -#include "lightbar_opcode_list.h" -static const char * const opcode_sym[] = { - LIGHTBAR_OPCODE_TABLE -}; -#undef OP - -static const char * const control_sym[] = { - "beg", "end", "phase", "<invalid>" -}; -static const char * const color_sym[] = { - "r", "g", "b", "<invalid>" -}; - -static void read_binary(FILE *fp, struct safe_lightbar_program *prog) -{ - int got; - - memset(prog, 0, sizeof(*prog)); - - /* Read up to one more byte than we need, so we know if it's too big */ - got = fread(prog->p.data, 1, EC_LB_PROG_LEN + 1, fp); - if (got < 1) { - Error("Unable to read any input: "); - if (feof(fp)) - fprintf(stderr, "EOF\n"); - else if (ferror(fp)) - fprintf(stderr, "%s\n", strerror(errno)); - else - fprintf(stderr, "no idea why.\n"); - } else if (got > EC_LB_PROG_LEN) { - Warning("Truncating input at %d bytes\n", EC_LB_PROG_LEN); - prog->zeros[0] = 0; - got = EC_LB_PROG_LEN; - } else { - prog->p.size = got; - } -} - -static uint32_t val32(uint8_t *ptr) -{ - uint32_t val; - val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]; - return val; -} - -static int is_jump(uint8_t op) -{ - /* TODO: probably should be a field in the opcode list */ - return op >= JUMP && op <= JUMP_IF_CHARGING; -} - -static void print_led_set(FILE *fp, uint8_t led) -{ - int i, first = 1; - - fprintf(fp, "{"); - for (i = 0; i < NUM_LEDS; i++) - if (led & BIT(i)) { - if (!first) - fprintf(fp, ","); - fprintf(fp, "%d", i); - first = 0; - } - fprintf(fp, "}"); -} - -/* returns number of operands consumed */ -static int print_op(FILE *fp, uint8_t addr, uint8_t cmd, uint8_t *arg) -{ - uint8_t led, color, control; - int i, operands; - - operands = num_operands[cmd]; - - /* assume valid instruction for now */ - is_instruction[addr] = 1; - - if (opt_verbose) { - fprintf(fp, "%02x: %02x", addr, cmd); - for (i = 0; i < LB_PROG_MAX_OPERANDS; i++) - if (i < operands) - fprintf(fp, " %02x", arg[i]); - else - fprintf(fp, " "); - fprintf(fp, "\t"); - } - if (is_jump_target[addr]) - fprintf(fp, "L00%02x:", addr); - fprintf(fp, "\t"); - - if (cmd < MAX_OPCODE) - fprintf(fp, "%s", opcode_sym[cmd]); - - switch (cmd) { - case JUMP: - case JUMP_IF_CHARGING: - fprintf(fp, "\tL00%02x\n", arg[0]); - break; - case JUMP_BATTERY: - fprintf(fp, "\tL00%02x L00%02x\n", arg[0], arg[1]); - break; - case SET_WAIT_DELAY: - case SET_RAMP_DELAY: - fprintf(fp, "\t%d\n", val32(arg)); - break; - case SET_BRIGHTNESS: - fprintf(fp, "\t%d\n", arg[0]); - break; - case SET_COLOR_SINGLE: - led = arg[0] >> 4; - control = (arg[0] >> 2) & 0x03; - color = arg[0] & 0x03; - fprintf(fp, "\t"); - - print_led_set(fp, led); - fprintf(fp, ".%s", control_sym[control]); - fprintf(fp, ".%s", color_sym[color]); - fprintf(fp, "\t0x%02x\n", arg[1]); - break; - case SET_COLOR_RGB: - led = arg[0] >> 4; - control = (arg[0] >> 2) & 0x03; - fprintf(fp, "\t"); - - print_led_set(fp, led); - fprintf(fp, ".%s", control_sym[control]); - fprintf(fp, "\t0x%02x 0x%02x 0x%02x\n", arg[1], arg[2], arg[3]); - break; - case ON: - case OFF: - case WAIT: - case GET_COLORS: - case SWAP_COLORS: - case RAMP_ONCE: - case CYCLE_ONCE: - case CYCLE: - case HALT: - fprintf(fp, "\n"); - break; - default: - fprintf(fp, "-- invalid opcode 0x%02x --\n", cmd); - is_instruction[addr] = 0; - hit_errors++; - } - - return operands; -} - -static void set_jump_target(uint8_t targ) -{ - if (targ >= EC_LB_PROG_LEN) { - Warning("program jumps to 0x%02x, " - "which out of bounds\n", targ); - return; - } - is_jump_target[targ] = 1; -} - -static void disassemble_prog(FILE *fp, struct safe_lightbar_program *prog) -{ - int i; - uint8_t *ptr, op; - - /* Scan the program once to identify all the jump targets, - * so we can print the labels when we encounter them. */ - for (i = 0; i < prog->p.size; i++) { - ptr = &prog->p.data[i]; - op = *ptr; - if (is_jump(op)) - set_jump_target(ptr[1]); - if (op == JUMP_BATTERY) - set_jump_target(ptr[2]); - i += num_operands[op]; - } - - /* Now disassemble */ - for (i = 0; i < prog->p.size; i++) { - ptr = &prog->p.data[i]; - i += print_op(fp, i, *ptr, ptr + 1); - } - - /* Finally, make sure the program doesn't jump to any location other - * than a valid instruction */ - for (i = 0; i < EC_LB_PROG_LEN; i++) - if (is_jump_target[i] && !is_instruction[i]) { - Warning("program jumps to 0x%02x, " - "which is not a valid instruction\n", i); - } -} - -/* We'll split each line into an array of these. */ -struct parse_s { - char *word; - int is_num; - uint32_t val; -}; - -/* Fills in struct, returns number of words found. Note that pointers are only - * copied. The strings they point to are not duplicated. */ -static int split_line(char *buf, const char *delim, struct parse_s *elt, - int max) -{ - char *w, *ptr, *buf_savetok; - int i; - char *e = 0; - - memset(elt, 0, max * sizeof(*elt)); - - for (ptr = buf, i = 0; - i < max && (w = strtok_r(ptr, delim, &buf_savetok)) != 0; - ptr = 0, i++) { - elt[i].word = w; - elt[i].val = (uint32_t)strtoull(w, &e, 0); - if (!e || !*e) - elt[i].is_num = 1; - - } - - return i; -} - -/* Decode led set. Return 0 if bogus, 1 if okay. */ -static int is_led_set(char *buf, uint8_t *valp) -{ - uint8_t led = 0; - unsigned long int next_led; - char *ptr; - - if (!buf) - return 0; - - if (*buf != '{') - return 0; - - buf++; - for (;;) { - next_led = strtoull(buf, &ptr, 0); - if (buf == ptr) { - if (buf[0] == '}' && buf[1] == 0) { - *valp = led; - return 1; - } else - return 0; - } - - if (next_led >= NUM_LEDS) - return 0; - - led |= 1 << next_led; - - buf = ptr; - if (*buf == ',') - buf++; - } -} - -/* Decode color arg based on expected control param sections. - * Return 0 if bogus, 1 if okay. - */ -static int is_color_arg(char *buf, int expected, uint32_t *valp) -{ - struct parse_s token[MAX_WORDS]; - uint8_t led, control, color; - int i; - - if (!buf) - return 0; - - /* There should be three terms, separated with '.' */ - i = split_line(buf, ".", token, MAX_WORDS); - if (i != expected) - return 0; - - if (!is_led_set(token[0].word, &led)) { - Error("Invalid LED set \"%s\"\n", token[0].word); - return 0; - } - - for (i = 0; i < LB_CONT_MAX; i++) - if (!strcmp(token[1].word, control_sym[i])) { - control = i; - break; - } - if (i >= LB_CONT_MAX) - return 0; - - if (expected == 3) { - for (i = 0; i < ARRAY_SIZE(color_sym); i++) - if (!strcmp(token[2].word, color_sym[i])) { - color = i; - break; - } - if (i >= ARRAY_SIZE(color_sym)) - return 0; - } else - color = 0; - - - *valp = ((led & 0xF) << 4) | ((control & 0x3) << 2) | (color & 0x3); - return 1; -} - -static void fixup_symbols(struct safe_lightbar_program *prog) -{ - int i, j; - - for (i = 0; i < EC_LB_PROG_LEN; i++) { - if (reloc_label[i]) { - /* Looking for reloc label */ - for (j = 0; j < EC_LB_PROG_LEN; j++) { - if (label[j] && !strcmp(label[j], - reloc_label[i])) { - prog->p.data[i] = j; - break; - } - } - if (j >= EC_LB_PROG_LEN) - Error("Can't find label %s\n", reloc_label[i]); - } - } -} - - -static void compile(FILE *fp, struct safe_lightbar_program *prog) -{ - char buf[128]; - struct parse_s token[MAX_WORDS]; - char *s; - int line = 0, chopping = 0; - uint8_t addr = 0; - int opcode; - int wnum, wordcnt; - int i; - - while (fgets(buf, sizeof(buf), fp)) { - - /* We truncate lines that are too long */ - s = strchr(buf, '\n'); - if (chopping) { - if (s) - chopping = 0; - continue; - } - - /* Got something to look at */ - line++; - if (!s) { - chopping = 1; - Warning("truncating line %d\n", line); - } - - /* Ignore comments */ - s = strchr(buf, '#'); - if (s) - *s = '\0'; - - wordcnt = split_line(buf, " \t\n", token, MAX_WORDS); - if (!wordcnt) - continue; - - wnum = 0; - - /* A label must be the first word, ends with a ':' (no spaces - * before it), and doesn't start with a ':' */ - s = strchr(token[0].word, ':'); - if (s && s[1] == '\0' && s != token[0].word) { - *s = '\0'; - label[addr] = strdup(token[0].word); - wnum++; - } - - /* How about an opcode? */ - for (opcode = 0; opcode < MAX_OPCODE; opcode++) - if (!strcasecmp(token[wnum].word, opcode_sym[opcode])) - break; - - if (opcode >= MAX_OPCODE) { - Error("Unrecognized opcode \"%s\"" - " at line %d\n", token[wnum].word, line); - continue; - } - - /* Do we even have a place to write this opcode? */ - if (addr >= EC_LB_PROG_LEN) { - Error("out of program space at line %d\n", line); - break; - } - - /* Got an opcode. Save it! */ - prog->p.data[addr++] = opcode; - wnum++; - - /* Now we need operands. */ - switch (opcode) { - case JUMP: - case JUMP_IF_CHARGING: - /* a label */ - if (token[wnum].word) - reloc_label[addr++] = strdup(token[wnum].word); - else - Error("Missing jump target at line %d\n", line); - break; - case JUMP_BATTERY: - /* two labels*/ - if (token[wnum].word) - reloc_label[addr++] = strdup(token[wnum].word); - else { - Error("Missing first jump target " - "at line %d\n", line); - break; - } - wnum++; - if (token[wnum].word) - reloc_label[addr++] = strdup(token[wnum].word); - else - Error("Missing second jump target " - "at line %d\n", line); - break; - - case SET_BRIGHTNESS: - /* one 8-bit arg */ - if (token[wnum].is_num) - prog->p.data[addr++] = token[wnum].val; - else - Error("Missing/invalid arg at line %d\n", line); - break; - - case SET_WAIT_DELAY: - case SET_RAMP_DELAY: - /* one 32-bit arg */ - if (token[wnum].is_num) { - prog->p.data[addr++] = - (token[wnum].val >> 24) & 0xff; - prog->p.data[addr++] = - (token[wnum].val >> 16) & 0xff; - prog->p.data[addr++] = - (token[wnum].val >> 8) & 0xff; - prog->p.data[addr++] = - token[wnum].val & 0xff; - } else { - Error("Missing/invalid arg at line %d\n", line); - } - break; - - case SET_COLOR_SINGLE: - /* one magic word, then one more 8-bit arg */ - i = is_color_arg(token[wnum].word, 3, &token[wnum].val); - if (!i) { - Error("Missing/invalid arg at line %d\n", line); - break; - } - /* save the magic number */ - prog->p.data[addr++] = token[wnum++].val; - /* and the color immediate */ - if (token[wnum].is_num) { - prog->p.data[addr++] = - token[wnum++].val; - } else { - Error("Missing/Invalid arg " - "at line %d\n", line); - break; - } - break; - case SET_COLOR_RGB: - /* one magic word, then three more 8-bit args */ - i = is_color_arg(token[wnum].word, 2, &token[wnum].val); - if (!i) { - Error("Missing/invalid arg at line %d\n", line); - break; - } - /* save the magic number */ - prog->p.data[addr++] = token[wnum++].val; - /* and the color immediates */ - for (i = 0; i < 3; i++) { - if (token[wnum].is_num) { - prog->p.data[addr++] = - token[wnum++].val; - } else { - Error("Missing/Invalid arg " - "at line %d\n", line); - break; - } - } - break; - - default: - /* No args needed */ - break; - } - - /* Did we run past the end? */ - if (addr > EC_LB_PROG_LEN) { - Error("out of program space at line %d\n", line); - break; - } - } - if (ferror(fp)) - Error("problem while reading input: %s\n", strerror(errno)); - - if (!hit_errors) - fixup_symbols(prog); - - if (!hit_errors) - prog->p.size = addr; - - if (!prog->p.size) - Error("input file produced no output bytes\n"); -} - -int main(int argc, char *argv[]) -{ - struct safe_lightbar_program safe_prog; - int opt_decode = 0; - int c; - int errorcnt = 0; - const char *infile, *outfile; - FILE *ifp, *ofp; - - char *progname = strrchr(argv[0], '/'); - if (progname) - progname++; - else - progname = argv[0]; - - opterr = 0; /* quiet, you */ - while ((c = getopt(argc, argv, ":dv")) != -1) { - switch (c) { - case 'd': - opt_decode = 1; - break; - case 'v': - opt_verbose = 1; - break; - - case '?': - fprintf(stderr, "%s: unrecognized switch: -%c\n", - progname, optopt); - errorcnt++; - break; - case ':': - fprintf(stderr, "%s: missing argument to -%c\n", - progname, optopt); - errorcnt++; - break; - default: - errorcnt++; - break; - } - } - - if (errorcnt) { - fprintf(stderr, usage, progname); - exit(1); - } - - if (argc - optind > 0) { - infile = argv[optind]; - ifp = fopen(infile, "rb"); - if (!ifp) { - fprintf(stderr, - "%s: Unable to open %s for reading: %s\n", - progname, infile, strerror(errno)); - exit(1); - } - } else { - infile = "stdin"; - ifp = stdin; - } - - if (argc - optind > 1) { - outfile = argv[optind + 1]; - ofp = fopen(outfile, "wb"); - if (!ofp) { - fprintf(stderr, - "%s: Unable to open %s for writing: %s\n", - progname, outfile, strerror(errno)); - exit(1); - } - } else { - outfile = "stdout"; - ofp = stdout; - } - - if (opt_decode) { - read_binary(ifp, &safe_prog); - fclose(ifp); - if (hit_errors) - return 1; - fprintf(ofp, "# %s\n", infile); - disassemble_prog(ofp, &safe_prog); - fclose(ofp); - } else { - memset(&safe_prog, 0, sizeof(safe_prog)); - compile(ifp, &safe_prog); - fclose(ifp); - if (!hit_errors) { - if (1 != fwrite(safe_prog.p.data, - safe_prog.p.size, 1, ofp)) - Error("%s: Unable to write to %s: %s\n", - progname, outfile, strerror(errno)); - else - fprintf(stderr, "0x%02x bytes written to %s\n", - safe_prog.p.size, outfile); - } - fclose(ofp); - } - - return hit_errors; -} |