mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Add compiler/decompiler for lightbar bytecode programs.
BUG=none
BRANCH=ToT
TEST=manual
make BOARD=samus
for i in extra/lightbar/programs/[g-z]*.bin; do
./build/samus/util/lbcc -d $i /tmp/x.lbs
./build/samus/util/lbcc /tmp/x.lbs /tmp/x.bin
cmp $i /tmp/x.bin
done
Change-Id: I86c014c425e917ecafadd1c6845fcf2e5b4edbb7
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/220244
This commit is contained in:
committed by
chrome-internal-fetch
parent
af3d103dbc
commit
87762fa699
@@ -988,23 +988,8 @@ static struct lb_program cur_prog;
|
||||
static struct lb_program next_prog;
|
||||
static uint8_t pc;
|
||||
|
||||
enum lb_color {
|
||||
LB_COL_RED,
|
||||
LB_COL_GREEN,
|
||||
LB_COL_BLUE,
|
||||
LB_COL_ALL
|
||||
};
|
||||
|
||||
enum lb_control {
|
||||
LB_CONT_COLOR0,
|
||||
LB_CONT_COLOR1,
|
||||
LB_CONT_PHASE,
|
||||
LB_CONT_MAX
|
||||
};
|
||||
|
||||
static uint8_t led_desc[NUM_LEDS][LB_CONT_MAX][3];
|
||||
static uint32_t lb_ramp_delay;
|
||||
|
||||
/* Get one byte of data pointed to by the pc and advance
|
||||
* the pc forward.
|
||||
*/
|
||||
@@ -1261,33 +1246,26 @@ static uint32_t lightbyte_CYCLE(void)
|
||||
|
||||
#undef GET_INTERP_VALUE
|
||||
|
||||
#define OPCODE_TABLE \
|
||||
OP(JUMP), \
|
||||
OP(DELAY), \
|
||||
OP(SET_BRIGHTNESS), \
|
||||
OP(SET_COLOR), \
|
||||
OP(SET_DELAY_TIME), \
|
||||
OP(RAMP_ONCE), \
|
||||
OP(CYCLE_ONCE), \
|
||||
OP(CYCLE),
|
||||
|
||||
#define OP(X) X
|
||||
#include "lightbar_opcode_list.h"
|
||||
enum lightbyte_opcode {
|
||||
OPCODE_TABLE
|
||||
LIGHTBAR_OPCODE_TABLE
|
||||
HALT,
|
||||
MAX_OPCODE
|
||||
};
|
||||
#undef OP
|
||||
|
||||
#define OP(X) lightbyte_ ## X
|
||||
#include "lightbar_opcode_list.h"
|
||||
static uint32_t (*lightbyte_dispatch[])(void) = {
|
||||
OPCODE_TABLE
|
||||
LIGHTBAR_OPCODE_TABLE
|
||||
};
|
||||
#undef OP
|
||||
|
||||
#define OP(X) # X
|
||||
#include "lightbar_opcode_list.h"
|
||||
static const char * const lightbyte_names[] = {
|
||||
OPCODE_TABLE
|
||||
LIGHTBAR_OPCODE_TABLE
|
||||
"HALT"
|
||||
};
|
||||
#undef OP
|
||||
|
||||
@@ -1037,6 +1037,7 @@ struct lightbar_params_v1 {
|
||||
|
||||
/* Lightbyte program. */
|
||||
#define LB_PROG_LEN 192
|
||||
#define LB_PROG_MAX_OPERANDS 4
|
||||
struct lb_program {
|
||||
uint8_t size;
|
||||
uint8_t data[LB_PROG_LEN];
|
||||
|
||||
@@ -19,6 +19,21 @@ enum lightbar_sequence {
|
||||
};
|
||||
#undef LBMSG
|
||||
|
||||
/* Bytecode field constants */
|
||||
enum lb_color {
|
||||
LB_COL_RED,
|
||||
LB_COL_GREEN,
|
||||
LB_COL_BLUE,
|
||||
LB_COL_ALL
|
||||
};
|
||||
|
||||
enum lb_control {
|
||||
LB_CONT_COLOR0,
|
||||
LB_CONT_COLOR1,
|
||||
LB_CONT_PHASE,
|
||||
LB_CONT_MAX
|
||||
};
|
||||
|
||||
/* Request a preset sequence from the lightbar task. */
|
||||
void lightbar_sequence(enum lightbar_sequence s);
|
||||
|
||||
|
||||
15
include/lightbar_opcode_list.h
Normal file
15
include/lightbar_opcode_list.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* Copyright (c) 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.
|
||||
*
|
||||
* This defines a list of lightbar opcodes for programmable sequences.
|
||||
*/
|
||||
#define LIGHTBAR_OPCODE_TABLE \
|
||||
OP(JUMP), \
|
||||
OP(DELAY), \
|
||||
OP(SET_BRIGHTNESS), \
|
||||
OP(SET_COLOR), \
|
||||
OP(SET_DELAY_TIME), \
|
||||
OP(RAMP_ONCE), \
|
||||
OP(CYCLE_ONCE), \
|
||||
OP(CYCLE),
|
||||
@@ -6,7 +6,7 @@
|
||||
# Host tools build
|
||||
#
|
||||
|
||||
host-util-bin=ectool lbplay burn_my_ec stm32mon ec_sb_firmware_update
|
||||
host-util-bin=ectool lbplay burn_my_ec stm32mon ec_sb_firmware_update lbcc
|
||||
|
||||
comm-objs=$(util-lock-objs:%=lock/%) comm-host.o comm-dev.o
|
||||
ifeq ($(CHIP),mec1322)
|
||||
|
||||
602
util/lbcc.c
Normal file
602
util/lbcc.c
Normal file
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
* Copyright (c) 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[LB_PROG_LEN]; /* does program jump here? */
|
||||
static int is_instruction[LB_PROG_LEN]; /* instruction or operand? */
|
||||
static char *label[LB_PROG_LEN]; /* labels we've seen */
|
||||
static char *reloc_label[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 MAX_WORDS (2 + LB_PROG_MAX_OPERANDS)
|
||||
|
||||
struct safe_lb_program {
|
||||
struct lb_program p;
|
||||
uint8_t zeros[LB_PROG_MAX_OPERANDS];
|
||||
} __packed;
|
||||
|
||||
#define OP(X) X
|
||||
#include "lightbar_opcode_list.h"
|
||||
enum lightbyte_opcode {
|
||||
LIGHTBAR_OPCODE_TABLE
|
||||
HALT,
|
||||
MAX_OPCODE
|
||||
};
|
||||
#undef OP
|
||||
|
||||
static const char const *opcode_sym[] = {
|
||||
"jump", "wait", "bright", "color",
|
||||
"step", "ramp.1", "cycle.1", "cycle",
|
||||
"halt",
|
||||
};
|
||||
BUILD_ASSERT(ARRAY_SIZE(opcode_sym) == MAX_OPCODE);
|
||||
|
||||
static const char const *control_sym[] = {
|
||||
"beg", "end", "phase", "<invalid>"
|
||||
};
|
||||
static const char const *color_sym[] = {
|
||||
"r", "g", "b", "rgb"
|
||||
};
|
||||
|
||||
static void read_binary(FILE *fp, struct safe_lb_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, 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 > LB_PROG_LEN) {
|
||||
Warning("Truncating input at %d bytes\n", LB_PROG_LEN);
|
||||
prog->zeros[0] = 0;
|
||||
got = LB_PROG_LEN;
|
||||
} else {
|
||||
prog->p.size = got;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns number of operands required by an opcode */
|
||||
static int num_operands(uint8_t cmd, uint8_t *arg)
|
||||
{
|
||||
int operands = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case JUMP:
|
||||
case SET_BRIGHTNESS:
|
||||
operands = 1;
|
||||
break;
|
||||
|
||||
case DELAY:
|
||||
case SET_DELAY_TIME:
|
||||
operands = 4;
|
||||
break;
|
||||
|
||||
case SET_COLOR:
|
||||
if ((arg[0] & 0x03) == LB_COL_ALL)
|
||||
operands = 4;
|
||||
else
|
||||
operands = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return operands;
|
||||
}
|
||||
|
||||
static uint32_t val32(uint8_t *ptr)
|
||||
{
|
||||
uint32_t val;
|
||||
val = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
|
||||
return val;
|
||||
}
|
||||
|
||||
/* 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, arg);
|
||||
|
||||
/* 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:
|
||||
fprintf(fp, "\tL00%02x\n", arg[0]);
|
||||
break;
|
||||
case DELAY:
|
||||
case SET_DELAY_TIME:
|
||||
fprintf(fp, "\t%d\n", val32(arg));
|
||||
break;
|
||||
case SET_BRIGHTNESS:
|
||||
fprintf(fp, "\t%d\n", arg[0]);
|
||||
break;
|
||||
case SET_COLOR:
|
||||
led = arg[0] >> 4;
|
||||
control = (arg[0] >> 2) & 0x03;
|
||||
color = arg[0] & 0x03;
|
||||
fprintf(fp, "\t");
|
||||
if (led >= NUM_LEDS)
|
||||
fprintf(fp, "all");
|
||||
else
|
||||
fprintf(fp, "%d", led);
|
||||
fprintf(fp, ".%s", control_sym[control]);
|
||||
fprintf(fp, ".%s", color_sym[color]);
|
||||
if (color == LB_COL_ALL)
|
||||
fprintf(fp, "\t0x%02x 0x%02x 0x%02x\n",
|
||||
arg[1], arg[2], arg[3]);
|
||||
else
|
||||
fprintf(fp, "\t0x%02x\n", arg[1]);
|
||||
break;
|
||||
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 disassemble_prog(FILE *fp, struct safe_lb_program *prog)
|
||||
{
|
||||
int i;
|
||||
uint8_t *ptr, targ;
|
||||
|
||||
/* 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];
|
||||
if (ptr[0] == JUMP) {
|
||||
targ = ptr[1];
|
||||
is_jump_target[targ] = 1;
|
||||
}
|
||||
i += num_operands(*ptr, ptr + 1);
|
||||
}
|
||||
|
||||
/* 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 < 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, 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)strtoul(w, &e, 0);
|
||||
if (!e || !*e)
|
||||
elt[i].is_num = 1;
|
||||
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Decode color arg. Return 0 if bogus, number of additional args if okay. */
|
||||
static int is_color_arg(char *buf, uint32_t *valp)
|
||||
{
|
||||
struct parse_s token[MAX_WORDS];
|
||||
uint8_t led, control, color, val;
|
||||
int i;
|
||||
int rv = 1;
|
||||
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
/* There should be three terms, separated with '.' */
|
||||
i = split_line(buf, ".,", token, MAX_WORDS);
|
||||
if (i != 3)
|
||||
return 0;
|
||||
|
||||
if (!strcmp("all", token[0].word)) {
|
||||
led = NUM_LEDS;
|
||||
} else if (token[0].is_num) {
|
||||
led = token[0].val;
|
||||
} else {
|
||||
Error("Invalid LED \"%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;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
val = ((led & 0xF) << 4) | ((control & 0x3) << 2) | (color & 0x3);
|
||||
|
||||
*valp = val;
|
||||
if (color == LB_COL_ALL)
|
||||
rv = 3;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void fixup_symbols(struct safe_lb_program *prog)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < LB_PROG_LEN; i++) {
|
||||
if (reloc_label[i]) {
|
||||
/* Looking for reloc label */
|
||||
for (j = 0; j < LB_PROG_LEN; j++) {
|
||||
if (label[j] && !strcmp(label[j],
|
||||
reloc_label[i])) {
|
||||
prog->p.data[i] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= LB_PROG_LEN)
|
||||
Error("Can't find label %s from line %d\n", j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void compile(FILE *fp, struct safe_lb_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 >= 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:
|
||||
/* 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 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 DELAY:
|
||||
case SET_DELAY_TIME:
|
||||
/* 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:
|
||||
/* one magic word, then one or three more 8-bit args */
|
||||
i = is_color_arg(token[wnum].word, &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;
|
||||
while (i--) {
|
||||
/* and the others */
|
||||
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 > 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_lb_program safe_prog;
|
||||
int opt_decode = 0;
|
||||
int c;
|
||||
int errorcnt = 0;
|
||||
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, "\nUsage: %s [options] ...\n\n", 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;
|
||||
}
|
||||
Reference in New Issue
Block a user