summaryrefslogtreecommitdiff
path: root/util/lbcc.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /util/lbcc.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14345.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
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;
-}