summaryrefslogtreecommitdiff
path: root/util/lbcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/lbcc.c')
-rw-r--r--util/lbcc.c691
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;
-}